1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial
3
4use pyo3::prelude::*;
5use pyo3::types::{IntoPyDict, PyDict};
6
7pub struct PyValue(pub slint_interpreter::Value);
8struct PyValueRef<'a>(&'a slint_interpreter::Value);
9
10impl IntoPy<PyObject> for PyValue {
11 fn into_py(self, py: Python<'_>) -> PyObject {
12 // Share the conversion code below that operates on the reference
13 self.to_object(py).into_py(py)
14 }
15}
16
17impl ToPyObject for PyValue {
18 fn to_object(&self, py: Python<'_>) -> PyObject {
19 PyValueRef(&self.0).to_object(py)
20 }
21}
22
23impl<'a> IntoPy<PyObject> for PyValueRef<'a> {
24 fn into_py(self, py: Python<'_>) -> PyObject {
25 // Share the conversion code below that operates on the reference
26 self.to_object(py).into_py(py)
27 }
28}
29
30impl<'a> ToPyObject for PyValueRef<'a> {
31 fn to_object(&self, py: Python<'_>) -> PyObject {
32 match &self.0 {
33 slint_interpreter::Value::Void => ().into_py(py),
34 slint_interpreter::Value::Number(num) => num.into_py(py),
35 slint_interpreter::Value::String(str) => str.into_py(py),
36 slint_interpreter::Value::Bool(b) => b.into_py(py),
37 slint_interpreter::Value::Image(image) => {
38 crate::image::PyImage::from(image).into_py(py)
39 }
40 slint_interpreter::Value::Model(model) => {
41 crate::models::PyModelShared::rust_into_js_model(model)
42 .unwrap_or_else(|| crate::models::ReadOnlyRustModel::from(model).into_py(py))
43 }
44 slint_interpreter::Value::Struct(structval) => structval
45 .iter()
46 .map(|(name, val)| (name.to_string().into_py(py), PyValueRef(val).into_py(py)))
47 .into_py_dict(py)
48 .into_py(py),
49 slint_interpreter::Value::Brush(brush) => {
50 crate::brush::PyBrush::from(brush.clone()).into_py(py)
51 }
52 v @ _ => {
53 eprintln!("Python: conversion from slint to python needed for {:#?} and not implemented yet", v);
54 ().into_py(py)
55 }
56 }
57 }
58}
59
60impl FromPyObject<'_> for PyValue {
61 fn extract(ob: &PyAny) -> PyResult<Self> {
62 if ob.is_none() {
63 return Ok(slint_interpreter::Value::Void.into());
64 }
65
66 let interpreter_val = ob
67 .extract::<bool>()
68 .map(|b| slint_interpreter::Value::Bool(b))
69 .or_else(|_| {
70 ob.extract::<&'_ str>().map(|s| slint_interpreter::Value::String(s.into()))
71 })
72 .or_else(|_| ob.extract::<f64>().map(|num| slint_interpreter::Value::Number(num)))
73 .or_else(|_| {
74 ob.extract::<PyRef<'_, crate::image::PyImage>>()
75 .map(|pyimg| slint_interpreter::Value::Image(pyimg.image.clone()))
76 })
77 .or_else(|_| {
78 ob.extract::<PyRef<'_, crate::brush::PyBrush>>()
79 .map(|pybrush| slint_interpreter::Value::Brush(pybrush.brush.clone()))
80 })
81 .or_else(|_| {
82 ob.extract::<PyRef<'_, crate::brush::PyColor>>()
83 .map(|pycolor| slint_interpreter::Value::Brush(pycolor.color.clone().into()))
84 })
85 .or_else(|_| {
86 ob.extract::<PyRef<'_, crate::models::PyModelBase>>()
87 .map(|pymodel| slint_interpreter::Value::Model(pymodel.as_model()))
88 })
89 .or_else(|_| {
90 ob.extract::<PyRef<'_, crate::models::ReadOnlyRustModel>>()
91 .map(|rustmodel| slint_interpreter::Value::Model(rustmodel.0.clone()))
92 })
93 .or_else(|_| {
94 ob.extract::<&PyDict>().and_then(|dict| {
95 let dict_items: Result<Vec<(String, slint_interpreter::Value)>, PyErr> = dict
96 .iter()
97 .map(|(name, pyval)| {
98 let name = name.extract::<&str>()?.to_string();
99 let slintval: PyValue = pyval.extract()?;
100 Ok((name, slintval.0))
101 })
102 .collect::<Result<Vec<(_, _)>, PyErr>>();
103 Ok(slint_interpreter::Value::Struct(slint_interpreter::Struct::from_iter(
104 dict_items?.into_iter(),
105 )))
106 })
107 })?;
108
109 Ok(PyValue(interpreter_val))
110 }
111}
112impl From<slint_interpreter::Value> for PyValue {
113 fn from(value: slint_interpreter::Value) -> Self {
114 Self(value)
115 }
116}
117