pytauri_core/ext_mod_impl/lib/
rect.rs

1use pyo3::{prelude::*, types::PyTuple};
2
3/// see also: [tauri::Rect]
4#[pyclass(frozen)]
5pub struct Rect {
6    // use `Py<T>` to avoid creating new obj every time visiting the field,
7    // see: <https://pyo3.rs/v0.23.4/faq.html#pyo3get-clones-my-field>
8    #[pyo3(get)]
9    pub position: Py<Position>,
10    #[pyo3(get)]
11    pub size: Py<Size>,
12}
13
14impl Rect {
15    pub(crate) fn from_tauri(py: Python<'_>, rect: tauri::Rect) -> PyResult<Self> {
16        let position = Position::from_tauri(py, rect.position)?
17            .into_pyobject(py)?
18            .unbind();
19        let size = Size::from_tauri(py, rect.size)?.into_pyobject(py)?.unbind();
20        Ok(Self { position, size })
21    }
22
23    #[expect(dead_code)] // TODO
24    pub(crate) fn to_tauri(&self, py: Python<'_>) -> PyResult<tauri::Rect> {
25        let ret = tauri::Rect {
26            position: self.position.get().to_tauri(py)?,
27            size: self.size.get().to_tauri(py)?,
28        };
29        Ok(ret)
30    }
31}
32
33#[pymethods]
34impl Rect {
35    #[new]
36    #[pyo3(signature = (*, position, size))]
37    fn __new__(position: Py<Position>, size: Py<Size>) -> Self {
38        Self { position, size }
39    }
40}
41
42/// See also: [tauri::Position]
43#[pyclass(frozen)]
44pub enum Position {
45    #[expect(private_interfaces)]
46    Physical(PhysicalPositionI32),
47    #[expect(private_interfaces)]
48    Logical(LogicalPositionF64),
49}
50
51impl Position {
52    pub(crate) fn from_tauri(py: Python<'_>, position: tauri::Position) -> PyResult<Self> {
53        let ret = match position {
54            tauri::Position::Physical(pos) => {
55                Position::Physical(PhysicalPositionI32::from_tauri(py, pos)?)
56            }
57            tauri::Position::Logical(pos) => {
58                Position::Logical(LogicalPositionF64::from_tauri(py, pos)?)
59            }
60        };
61        Ok(ret)
62    }
63
64    pub(crate) fn to_tauri(&self, py: Python<'_>) -> PyResult<tauri::Position> {
65        match self {
66            Position::Physical(pos) => pos.to_tauri(py).map(tauri::Position::Physical),
67            Position::Logical(pos) => pos.to_tauri(py).map(tauri::Position::Logical),
68        }
69    }
70}
71
72/// see also: [tauri::Size]
73#[pyclass(frozen)]
74pub enum Size {
75    #[expect(private_interfaces)]
76    Physical(PhysicalSizeU32),
77    #[expect(private_interfaces)]
78    Logical(LogicalSizeF64),
79}
80
81impl Size {
82    pub(crate) fn from_tauri(py: Python<'_>, size: tauri::Size) -> PyResult<Self> {
83        let ret = match size {
84            tauri::Size::Physical(size) => Size::Physical(PhysicalSizeU32::from_tauri(py, size)?),
85            tauri::Size::Logical(size) => Size::Logical(LogicalSizeF64::from_tauri(py, size)?),
86        };
87        Ok(ret)
88    }
89
90    pub(crate) fn to_tauri(&self, py: Python<'_>) -> PyResult<tauri::Size> {
91        match self {
92            Size::Physical(size) => size.to_tauri(py).map(tauri::Size::Physical),
93            Size::Logical(size) => size.to_tauri(py).map(tauri::Size::Logical),
94        }
95    }
96}
97
98macro_rules! position {
99    ($vis:vis, $name:ident, $ty:ty => $from_tauri:ident, $to_tauri:ident, $tauri_ty:ty) => {
100        /// See also: [tauri::PhysicalPosition] and [tauri::LogicalPosition]
101        ///
102        /// `(x, y)`
103        #[derive(FromPyObject, IntoPyObject, IntoPyObjectRef)]
104        #[pyo3(transparent)]
105        $vis struct $name($vis Py<PyTuple>);
106
107        impl $name {
108            #[allow(dead_code)]
109            $vis fn $from_tauri(
110                py: Python<'_>,
111                value: $tauri_ty,
112            ) -> PyResult<Self> {
113                let x_y: ($ty, $ty) = (value.x, value.y); // typing assertion
114                Ok(Self(x_y.into_pyobject(py)?.unbind()))
115            }
116
117            #[allow(dead_code)]
118            $vis fn $to_tauri(
119                &self,
120                py: Python<'_>,
121            ) -> PyResult<$tauri_ty> {
122                let (x, y): ($ty, $ty) = self.0.extract(py)?;
123                type TauriTy = $tauri_ty; // convert to expr `TauriTy`
124                Ok(TauriTy { x, y })
125            }
126        }
127    };
128}
129
130macro_rules! size {
131    ($vis:vis, $name:ident, $ty:ty => $from_tauri:ident, $to_tauri:ident, $tauri_ty:ty) => {
132        /// See also: [tauri::PhysicalSize] and [tauri::LogicalSize]
133        ///
134        /// `(width, height)`
135        #[derive(FromPyObject, IntoPyObject, IntoPyObjectRef)]
136        #[pyo3(transparent)]
137        $vis struct $name($vis Py<PyTuple>);
138
139        impl $name {
140            #[allow(dead_code)]
141            $vis fn $from_tauri(
142                py: Python<'_>,
143                value: $tauri_ty,
144            ) -> PyResult<Self> {
145                let width_height: ($ty, $ty) = (value.width, value.height); // typing assertion
146                Ok(Self(width_height.into_pyobject(py)?.unbind()))
147            }
148
149            #[allow(dead_code)]
150            $vis fn $to_tauri(
151                &self,
152                py: Python<'_>,
153            ) -> PyResult<$tauri_ty> {
154                let (width, height): ($ty, $ty) = self.0.extract(py)?;
155                type TauriTy = $tauri_ty; // convert to expr `TauriTy`
156                Ok(TauriTy { width, height })
157            }
158        }
159    };
160}
161
162position!(pub(crate), PhysicalPositionF64, f64 => from_tauri, to_tauri, tauri::PhysicalPosition::<f64>);
163position!(pub(crate), PhysicalPositionI32, i32 => from_tauri, to_tauri, tauri::PhysicalPosition::<i32>);
164position!(pub(crate), LogicalPositionF64, f64 => from_tauri, to_tauri, tauri::LogicalPosition::<f64>);
165size!(pub(crate), PhysicalSizeU32, u32 => from_tauri, to_tauri, tauri::PhysicalSize::<u32>);
166size!(pub(crate), LogicalSizeF64, f64 => from_tauri, to_tauri, tauri::LogicalSize::<f64>);