Skip to main content

qtbridge_runtime/
qmetatype_compatible.rs

1// Copyright (C) 2026 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only
3
4use std::cell::RefCell;
5use std::rc::Rc;
6
7use qtbridge_type_lib::{QList, QList_QString, QMetaType, QObject, QObjectList, QObjectMutPtr, QString};
8
9#[cfg(feature = "serde_json")]
10use qtbridge_type_lib::{QJsonArray, QJsonValue};
11
12use crate::{QMetaTypeGet, QObjectHolder, QmlElement};
13
14/// Enables a type to be used as a meta call argument and to be convertible from/to QVariant.
15///
16/// Implemented for:
17/// - Primitive numeric types and `bool`
18/// - [`String`]
19/// - [`Vec<T>`] where `T` is one of the above
20/// - [`Rc<RefCell<T>>`] where `T` implements [`QObjectHolder`]
21/// - [`Vec<Rc<RefCell<T>>>`] where `T` implements [`QmlElement`]
22///
23pub trait QMetaTypeCompatible {
24    type CompatibleType: QMetaTypeGet;
25
26    fn to_compatible(&self) -> Self::CompatibleType;
27    /// Converts the compatible representation back into `Self`.
28    ///
29    /// # Safety
30    ///
31    /// For `QObject`-backed types the compatible representation is a raw
32    /// `QObject*` that is dereferenced: the caller must guarantee it points
33    /// to a live `QObject`.
34    unsafe fn from_compatible(from: &Self::CompatibleType) -> Self;
35    fn compatible_qmetatype() -> QMetaType {
36        Self::CompatibleType::get_qmetatype()
37    }
38}
39
40macro_rules! impl_primitive_direct {
41    ($($t:ty),*) => {
42        $(impl QMetaTypeCompatible for $t {
43            type CompatibleType = $t;
44            fn to_compatible(&self) -> Self::CompatibleType { *self }
45            unsafe fn from_compatible(from: &Self::CompatibleType) -> Self { *from }
46        })*
47    }
48}
49impl_primitive_direct!(bool, i8, u8, i16, u16, i32, u32, i64, u64, f32, f64);
50
51macro_rules! impl_primitive_convert {
52    ($($t:ty => $compat:ty),*) => {
53        $(impl QMetaTypeCompatible for $t {
54            type CompatibleType = $compat;
55            fn to_compatible(&self) -> Self::CompatibleType { *self as $compat }
56            unsafe fn from_compatible(from: &Self::CompatibleType) -> Self { *from as Self }
57        })*
58    }
59}
60#[cfg(target_pointer_width = "64")]
61impl_primitive_convert!(
62    isize => i64,
63    usize => u64
64);
65#[cfg(target_pointer_width = "32")]
66impl_primitive_convert!(
67    isize => i32,
68    usize => u32
69);
70
71// The CompatibleType pointer is safe single-threaded: arguments outlive delivery on
72// the emitting stack frame, and no collection point runs between a return
73// value leaving Rust and the engine taking ownership. Revisit when signals
74// can cross threads.
75macro_rules! impl_vec_direct {
76    ($($t:ty),*) => {
77        $(impl QMetaTypeCompatible for Vec<$t> {
78            type CompatibleType = QList<$t>;
79            fn to_compatible(&self) -> Self::CompatibleType { self.into_iter().collect() }
80            unsafe fn from_compatible(from: &Self::CompatibleType) -> Self { from.into() }
81        })*
82    }
83}
84impl_vec_direct!(bool, i8, u8, i16, u16, i32, u32, i64, u64, f32, f64);
85
86macro_rules! impl_vec_convert {
87    ($($t:ty => $compat:ty),*) => {
88        $(impl QMetaTypeCompatible for Vec<$t> {
89            type CompatibleType = QList<$compat>;
90            fn to_compatible(&self) -> Self::CompatibleType {
91                self.iter()
92                    .map(|arg| *arg as $compat)
93                    .collect()
94            }
95            unsafe fn from_compatible(from: &Self::CompatibleType) -> Self {
96                from.iter()
97                    .map(|arg| *arg as $t)
98                    .collect()
99            }
100        })*
101    }
102}
103#[cfg(target_pointer_width = "64")]
104impl_vec_convert!(
105    isize => i64,
106    usize => u64
107);
108#[cfg(target_pointer_width = "32")]
109impl_vec_convert!(
110    isize => i32,
111    usize => u32
112);
113
114impl QMetaTypeCompatible for String {
115    type CompatibleType = QString;
116    fn to_compatible(&self) -> QString { self.into() }
117    unsafe fn from_compatible(from: &QString) -> String { from.into() }
118}
119
120impl QMetaTypeCompatible for Vec<String> {
121    type CompatibleType = QList_QString;
122
123    fn to_compatible(&self) -> Self::CompatibleType {
124        self.iter()
125            .map(QString::from)
126            .collect()
127    }
128
129    unsafe fn from_compatible(from: &Self::CompatibleType) -> Self {
130        from.iter()
131            .map(String::from)
132            .collect()
133    }
134}
135
136impl<T: QObjectHolder> QMetaTypeCompatible for Rc<RefCell<T>> {
137    type CompatibleType = *mut QObject;
138
139    fn to_compatible(&self) -> *mut QObject {
140        T::rc_ref_cell_to_qobject(self).cast_mut()
141    }
142
143    unsafe fn from_compatible(from: &*mut QObject) -> Self {
144        unsafe { T::qobject_to_rc_ref_cell(*from) }
145    }
146
147    fn compatible_qmetatype() -> QMetaType {
148        <T as QObjectHolder>::get_qobject_ptr_qmetatype()
149    }
150}
151
152// The compatible pointers share the in-flight guarantee of Rc<RefCell<T>> above.
153impl<T: QmlElement> QMetaTypeCompatible for Vec<Rc<RefCell<T>>> {
154    type CompatibleType = QObjectList;
155
156    fn to_compatible(&self) -> QObjectList {
157        self.iter()
158            .map(|rc| unsafe { QObjectMutPtr::from_raw(T::rc_ref_cell_to_qobject(rc).cast_mut()) })
159            .collect()
160    }
161
162    unsafe fn from_compatible(from: &QObjectList) -> Self {
163        from.iter()
164            .map(|ptr| unsafe { T::qobject_to_rc_ref_cell(ptr.as_mut_ptr()) })
165            .collect()
166    }
167}
168
169#[cfg(feature = "serde_json")]
170impl QMetaTypeCompatible for serde_json::Value {
171    type CompatibleType = QJsonValue;
172    fn to_compatible(&self) -> QJsonValue { crate::serde_tools::serde_to_qjsonvalue(self) }
173    unsafe fn from_compatible(from: &QJsonValue) -> serde_json::Value { crate::serde_tools::qjsonvalue_to_serde(from) }
174}
175
176#[cfg(feature = "serde_json")]
177impl QMetaTypeCompatible for Vec<serde_json::Value> {
178    type CompatibleType = QJsonArray;
179    fn to_compatible(&self) -> QJsonArray { crate::serde_tools::serde_to_qjsonarray(self) }
180    unsafe fn from_compatible(from: &QJsonArray) -> Vec<serde_json::Value> {
181        from.iter()
182            .map(|jv| crate::serde_tools::qjsonvalue_to_serde(&jv))
183            .collect()
184    }
185}