Skip to main content

qtbridge_runtime/
qmodelitem.rs

1// Copyright (C) 2026 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only
3
4use std::collections::HashMap;
5
6use qtbridge_type_lib::QVariant;
7
8use crate::{QVariantConvertible};
9
10fn option_to_qvariant<T: QVariantConvertible>(value: Option<&T>) -> QVariant {
11    value.map(<T>::to_qvariant)
12            .unwrap_or_default()
13}
14
15/// Trait representing a single item in an item model.
16///
17/// This trait is implemented automatically by `#[derive(QModelItem)]`
18/// for structs and tuple structs and an implementation for primitive types
19/// and tuples is provided. It allows QtBridge to use the type in item models.
20///
21/// # Typical usage
22/// Normally, you should **not implement this manually**. Use
23/// `#[derive(QModelItem)]` on your struct:
24///
25/// ```rust, ignore
26/// #[derive(QModelItem)]
27/// struct Person {
28///     name: String,
29///     age: u32,
30/// }
31/// ```
32///
33/// # Manual Implementation
34/// If your struct contains fields that **cannot be converted to `QVariant`**,
35/// you need to implement `QModelItem` manually. Only include fields that
36/// are known to QtBridge in the `getN` and `setN` methods, and adjust
37/// `role_names()` accordingly.
38///
39/// Example:
40///
41/// ```rust
42///
43/// use std::collections::HashMap;
44/// use qtbridge::QModelItem;
45///
46/// struct CustomType {
47///     data: Vec<u8>, // cannot be directly converted to QVariant
48///     name: String,
49/// }
50///
51/// impl QModelItem for CustomType {
52///     type T0 = String;
53///     type T1 = ();
54///     type T2 = ();
55///     type T3 = ();
56///     type T4 = ();
57///     type T5 = ();
58///     type T6 = ();
59///     type T7 = ();
60///     type T8 = ();
61///     type T9 = ();
62///     type T10 = ();
63///     type T11 = ();
64///     type T12 = ();
65///     type T13 = ();
66///     type T14 = ();
67///
68///     fn get0(&self) -> Option<&String> {
69///         Some(&self.name)
70///     }
71///
72///     fn set0(&mut self, value: String) {
73///         self.name = value;
74///     }
75///
76///     fn role_names() -> HashMap<i32, String> {
77///         let roles = [(0x0, "name".into())];
78///         roles.into()
79///     }
80/// }
81/// ```
82pub trait QModelItem {
83    // TODO: When associated type defaults become stable, set () as default type.
84    // https://github.com/rust-lang/rust/issues/29661
85    type T0 : QVariantConvertible;
86    type T1 : QVariantConvertible;
87    type T2 : QVariantConvertible;
88    type T3 : QVariantConvertible;
89    type T4 : QVariantConvertible;
90    type T5 : QVariantConvertible;
91    type T6 : QVariantConvertible;
92    type T7 : QVariantConvertible;
93    type T8 : QVariantConvertible;
94    type T9 : QVariantConvertible;
95    type T10 : QVariantConvertible;
96    type T11 : QVariantConvertible;
97    type T12 : QVariantConvertible;
98    type T13 : QVariantConvertible;
99    type T14 : QVariantConvertible;
100
101    fn get0(&self) -> Option<&Self::T0> { None }
102    fn get1(&self) -> Option<&Self::T1> { None }
103    fn get2(&self) -> Option<&Self::T2> { None }
104    fn get3(&self) -> Option<&Self::T3> { None }
105    fn get4(&self) -> Option<&Self::T4> { None }
106    fn get5(&self) -> Option<&Self::T5> { None }
107    fn get6(&self) -> Option<&Self::T6> { None }
108    fn get7(&self) -> Option<&Self::T7> { None }
109    fn get8(&self) -> Option<&Self::T8> { None }
110    fn get9(&self) -> Option<&Self::T9> { None }
111    fn get10(&self) -> Option<&Self::T10> { None }
112    fn get11(&self) -> Option<&Self::T11> { None }
113    fn get12(&self) -> Option<&Self::T12> { None }
114    fn get13(&self) -> Option<&Self::T13> { None }
115    fn get14(&self) -> Option<&Self::T14> { None }
116
117    fn set0(&mut self, _value: Self::T0) {}
118    fn set1(&mut self, _value: Self::T1) {}
119    fn set2(&mut self, _value: Self::T2) {}
120    fn set3(&mut self, _value: Self::T3) {}
121    fn set4(&mut self, _value: Self::T4) {}
122    fn set5(&mut self, _value: Self::T5) {}
123    fn set6(&mut self, _value: Self::T6) {}
124    fn set7(&mut self, _value: Self::T7) {}
125    fn set8(&mut self, _value: Self::T8) {}
126    fn set9(&mut self, _value: Self::T9) {}
127    fn set10(&mut self, _value: Self::T10) {}
128    fn set11(&mut self, _value: Self::T11) {}
129    fn set12(&mut self, _value: Self::T12) {}
130    fn set13(&mut self, _value: Self::T13) {}
131    fn set14(&mut self, _value: Self::T14) {}
132
133    #[doc(hidden)]
134    fn get_role(&self, id: i32) -> QVariant
135    {
136        match id {
137            0 => option_to_qvariant(self.get0()),
138            1 => option_to_qvariant(self.get1()),
139            2 => option_to_qvariant(self.get2()),
140            3 => option_to_qvariant(self.get3()),
141            4 => option_to_qvariant(self.get4()),
142            5 => option_to_qvariant(self.get5()),
143            6 => option_to_qvariant(self.get6()),
144            7 => option_to_qvariant(self.get7()),
145            8 => option_to_qvariant(self.get8()),
146            9 => option_to_qvariant(self.get9()),
147            10 => option_to_qvariant(self.get10()),
148            11 => option_to_qvariant(self.get11()),
149            12 => option_to_qvariant(self.get12()),
150            13 => option_to_qvariant(self.get13()),
151            14 => option_to_qvariant(self.get14()),
152            _ => QVariant::default(),
153        }
154    }
155
156    #[doc(hidden)]
157    fn set_role(&mut self, id: i32, value: &QVariant) -> bool
158    {
159        match id {
160            0 => <Self::T0>::try_from_qvariant(value).map(|val| self.set0(val)),
161            1 => <Self::T1>::try_from_qvariant(value).map(|val| self.set1(val)),
162            2 => <Self::T2>::try_from_qvariant(value).map(|val| self.set2(val)),
163            3 => <Self::T3>::try_from_qvariant(value).map(|val| self.set3(val)),
164            4 => <Self::T4>::try_from_qvariant(value).map(|val| self.set4(val)),
165            5 => <Self::T5>::try_from_qvariant(value).map(|val| self.set5(val)),
166            6 => <Self::T6>::try_from_qvariant(value).map(|val| self.set6(val)),
167            7 => <Self::T7>::try_from_qvariant(value).map(|val| self.set7(val)),
168            8 => <Self::T8>::try_from_qvariant(value).map(|val| self.set8(val)),
169            9 => <Self::T9>::try_from_qvariant(value).map(|val| self.set9(val)),
170            10 => <Self::T10>::try_from_qvariant(value).map(|val| self.set10(val)),
171            11 => <Self::T11>::try_from_qvariant(value).map(|val| self.set11(val)),
172            12 => <Self::T12>::try_from_qvariant(value).map(|val| self.set12(val)),
173            13 => <Self::T13>::try_from_qvariant(value).map(|val| self.set13(val)),
174            14 => <Self::T14>::try_from_qvariant(value).map(|val| self.set14(val)),
175            _ =>  return false,
176        }.is_ok()
177    }
178
179    fn role_names() -> HashMap<i32, String>;
180}
181
182macro_rules! impl_qmodel_item_for_primitive {
183    ($t:ty) => {
184        impl QModelItem for $t {
185            type T0 = $t;
186            type T1 = ();
187            type T2 = ();
188            type T3 = ();
189            type T4 = ();
190            type T5 = ();
191            type T6 = ();
192            type T7 = ();
193            type T8 = ();
194            type T9 = ();
195            type T10 = ();
196            type T11 = ();
197            type T12 = ();
198            type T13 = ();
199            type T14 = ();
200
201            fn get0(&self) -> Option<&Self::T0> {
202                Some(self)
203            }
204
205            fn set0(&mut self, value: Self::T0) {
206                *self = value;
207            }
208            fn role_names() -> HashMap<i32, String> {
209                let roles = [(0x0, "value".into())];
210                roles.into()
211            }
212        }
213    };
214}
215
216impl_qmodel_item_for_primitive!(i8);
217impl_qmodel_item_for_primitive!(i16);
218impl_qmodel_item_for_primitive!(i32);
219impl_qmodel_item_for_primitive!(i64);
220impl_qmodel_item_for_primitive!(u8);
221impl_qmodel_item_for_primitive!(u16);
222impl_qmodel_item_for_primitive!(u32);
223impl_qmodel_item_for_primitive!(u64);
224impl_qmodel_item_for_primitive!(f32);
225impl_qmodel_item_for_primitive!(f64);
226impl_qmodel_item_for_primitive!(bool);
227impl_qmodel_item_for_primitive!(String);
228
229impl<T0, T1> QModelItem for (T0, T1)
230where
231    T0: QVariantConvertible,
232    T1: QVariantConvertible
233{
234    type T0 = T0;
235    type T1 = T1;
236    type T2 = ();
237    type T3 = ();
238    type T4 = ();
239    type T5 = ();
240    type T6 = ();
241    type T7 = ();
242    type T8 = ();
243    type T9 = ();
244    type T10 = ();
245    type T11 = ();
246    type T12 = ();
247    type T13 = ();
248    type T14 = ();
249
250    fn get0(&self) -> Option<&Self::T0> { Some(&self.0) }
251    fn get1(&self) -> Option<&Self::T1> { Some(&self.1) }
252    fn set0(&mut self, value: Self::T0) { self.0 = value; }
253    fn set1(&mut self, value: Self::T1) { self.1 = value; }
254
255    fn role_names() -> HashMap<i32, String> {
256        let roles= [
257            (0x0, "_0".into()),
258            (0x1, "_1".into()),
259        ];
260        roles.into()
261    }
262}
263
264impl<T0, T1, T2> QModelItem for (T0, T1, T2)
265where
266    T0: QVariantConvertible,
267    T1: QVariantConvertible,
268    T2: QVariantConvertible
269{
270    type T0 = T0;
271    type T1 = T1;
272    type T2 = T2;
273    type T3 = ();
274    type T4 = ();
275    type T5 = ();
276    type T6 = ();
277    type T7 = ();
278    type T8 = ();
279    type T9 = ();
280    type T10 = ();
281    type T11 = ();
282    type T12 = ();
283    type T13 = ();
284    type T14 = ();
285
286    fn get0(&self) -> Option<&Self::T0> { Some(&self.0) }
287    fn get1(&self) -> Option<&Self::T1> { Some(&self.1) }
288    fn get2(&self) -> Option<&Self::T2> { Some(&self.2) }
289    fn set0(&mut self, value: Self::T0) { self.0 = value; }
290    fn set1(&mut self, value: Self::T1) { self.1 = value; }
291    fn set2(&mut self, value: Self::T2) { self.2 = value; }
292
293    fn role_names() -> HashMap<i32, String> {
294        let roles= [
295            (0x0, "_0".into()),
296            (0x1, "_1".into()),
297            (0x2, "_2".into()),
298        ];
299        roles.into()
300    }
301}
302
303impl<T0, T1, T2, T3> QModelItem for (T0, T1, T2, T3)
304where
305    T0: QVariantConvertible,
306    T1: QVariantConvertible,
307    T2: QVariantConvertible,
308    T3: QVariantConvertible
309{
310    type T0 = T0;
311    type T1 = T1;
312    type T2 = T2;
313    type T3 = T3;
314    type T4 = ();
315    type T5 = ();
316    type T6 = ();
317    type T7 = ();
318    type T8 = ();
319    type T9 = ();
320    type T10 = ();
321    type T11 = ();
322    type T12 = ();
323    type T13 = ();
324    type T14 = ();
325
326    fn get0(&self) -> Option<&Self::T0> { Some(&self.0) }
327    fn get1(&self) -> Option<&Self::T1> { Some(&self.1) }
328    fn get2(&self) -> Option<&Self::T2> { Some(&self.2) }
329    fn get3(&self) -> Option<&Self::T3> { Some(&self.3) }
330    fn set0(&mut self, value: Self::T0) { self.0 = value; }
331    fn set1(&mut self, value: Self::T1) { self.1 = value; }
332    fn set2(&mut self, value: Self::T2) { self.2 = value; }
333    fn set3(&mut self, value: Self::T3) { self.3 = value; }
334
335    fn role_names() -> HashMap<i32, String> {
336        let roles= [
337            (0x0, "_0".into()),
338            (0x1, "_1".into()),
339            (0x2, "_2".into()),
340            (0x3, "_3".into()),
341        ];
342        roles.into()
343    }
344}
345
346impl<T0, T1, T2, T3, T4> QModelItem for (T0, T1, T2, T3, T4)
347where
348    T0: QVariantConvertible,
349    T1: QVariantConvertible,
350    T2: QVariantConvertible,
351    T3: QVariantConvertible,
352    T4: QVariantConvertible
353{
354    type T0 = T0;
355    type T1 = T1;
356    type T2 = T2;
357    type T3 = T3;
358    type T4 = T4;
359    type T5 = ();
360    type T6 = ();
361    type T7 = ();
362    type T8 = ();
363    type T9 = ();
364    type T10 = ();
365    type T11 = ();
366    type T12 = ();
367    type T13 = ();
368    type T14 = ();
369
370    fn get0(&self) -> Option<&Self::T0> { Some(&self.0) }
371    fn get1(&self) -> Option<&Self::T1> { Some(&self.1) }
372    fn get2(&self) -> Option<&Self::T2> { Some(&self.2) }
373    fn get3(&self) -> Option<&Self::T3> { Some(&self.3) }
374    fn get4(&self) -> Option<&Self::T4> { Some(&self.4) }
375    fn set0(&mut self, value: Self::T0) { self.0 = value; }
376    fn set1(&mut self, value: Self::T1) { self.1 = value; }
377    fn set2(&mut self, value: Self::T2) { self.2 = value; }
378    fn set3(&mut self, value: Self::T3) { self.3 = value; }
379    fn set4(&mut self, value: Self::T4) { self.4 = value; }
380
381    fn role_names() -> HashMap<i32, String> {
382        let roles= [
383            (0x0, "_0".into()),
384            (0x1, "_1".into()),
385            (0x2, "_2".into()),
386            (0x3, "_3".into()),
387            (0x4, "_4".into()),
388        ];
389        roles.into()
390    }
391}
392
393impl<T0, T1, T2, T3, T4, T5> QModelItem for (T0, T1, T2, T3, T4, T5)
394where
395    T0: QVariantConvertible,
396    T1: QVariantConvertible,
397    T2: QVariantConvertible,
398    T3: QVariantConvertible,
399    T4: QVariantConvertible,
400    T5: QVariantConvertible
401{
402    type T0 = T0;
403    type T1 = T1;
404    type T2 = T2;
405    type T3 = T3;
406    type T4 = T4;
407    type T5 = T5;
408    type T6 = ();
409    type T7 = ();
410    type T8 = ();
411    type T9 = ();
412    type T10 = ();
413    type T11 = ();
414    type T12 = ();
415    type T13 = ();
416    type T14 = ();
417
418    fn get0(&self) -> Option<&Self::T0> { Some(&self.0) }
419    fn get1(&self) -> Option<&Self::T1> { Some(&self.1) }
420    fn get2(&self) -> Option<&Self::T2> { Some(&self.2) }
421    fn get3(&self) -> Option<&Self::T3> { Some(&self.3) }
422    fn get4(&self) -> Option<&Self::T4> { Some(&self.4) }
423    fn get5(&self) -> Option<&Self::T5> { Some(&self.5) }
424    fn set0(&mut self, value: Self::T0) { self.0 = value; }
425    fn set1(&mut self, value: Self::T1) { self.1 = value; }
426    fn set2(&mut self, value: Self::T2) { self.2 = value; }
427    fn set3(&mut self, value: Self::T3) { self.3 = value; }
428    fn set4(&mut self, value: Self::T4) { self.4 = value; }
429    fn set5(&mut self, value: Self::T5) { self.5 = value; }
430
431    fn role_names() -> HashMap<i32, String> {
432        let roles= [
433            (0x0, "_0".into()),
434            (0x1, "_1".into()),
435            (0x2, "_2".into()),
436            (0x3, "_3".into()),
437            (0x4, "_4".into()),
438            (0x5, "_5".into()),
439        ];
440        roles.into()
441    }
442}
443
444#[cfg(test)]
445macro_rules! test_tuple_index {
446    ($tuple:expr, $set:ident, $get:ident, $field:tt, $value:expr) => {{
447        $tuple.$set($value);
448        assert_eq!(*$tuple.$get().unwrap(), $value);
449        assert_eq!(*$tuple.$get().unwrap(), $tuple.$field);
450    }};
451}
452
453#[cfg(test)]
454macro_rules! assert_role_name {
455    ($type:ty, $idx:expr, $expected:expr) => {
456        assert_eq!(
457            <$type>::role_names().get(&$idx).unwrap(),
458            $expected
459        );
460    };
461}
462
463#[test]
464fn test_tuple_implementation() {
465    let mut tuple2: (i32, i32) = (1, 1);
466    assert_eq!(<(i32, i32)>::role_names().len(), 2);
467    assert_role_name!((i32, i32), 0, "_0");
468    assert_role_name!((i32, i32), 1, "_1");
469    test_tuple_index!(tuple2, set0, get0, 0, 42);
470    test_tuple_index!(tuple2, set1, get1, 1, 43);
471
472    let mut tuple3: (i32, i32, i32) = (1, 1, 1);
473    assert_eq!(<(i32, i32, i32)>::role_names().len(), 3);
474    assert_role_name!((i32, i32, i32), 0, "_0");
475    assert_role_name!((i32, i32, i32), 1, "_1");
476    assert_role_name!((i32, i32, i32), 2, "_2");
477    test_tuple_index!(tuple3, set0, get0, 0, 42);
478    test_tuple_index!(tuple3, set1, get1, 1, 43);
479    test_tuple_index!(tuple3, set2, get2, 2, 44);
480
481    let mut tuple4: (i32, i32, i32, i32) = (1, 1, 1, 1);
482    assert_eq!(<(i32, i32, i32, i32)>::role_names().len(), 4);
483    assert_role_name!((i32, i32, i32, i32), 0, "_0");
484    assert_role_name!((i32, i32, i32, i32), 1, "_1");
485    assert_role_name!((i32, i32, i32, i32), 2, "_2");
486    assert_role_name!((i32, i32, i32, i32), 3, "_3");
487    test_tuple_index!(tuple4, set0, get0, 0, 42);
488    test_tuple_index!(tuple4, set1, get1, 1, 43);
489    test_tuple_index!(tuple4, set2, get2, 2, 44);
490    test_tuple_index!(tuple4, set3, get3, 3, 45);
491
492    let mut tuple5: (i32, i32, i32, i32, i32) = (1, 1, 1, 1, 1);
493    assert_eq!(<(i32, i32, i32, i32, i32)>::role_names().len(), 5);
494    assert_role_name!((i32, i32, i32, i32, i32), 0, "_0");
495    assert_role_name!((i32, i32, i32, i32, i32), 1, "_1");
496    assert_role_name!((i32, i32, i32, i32, i32), 2, "_2");
497    assert_role_name!((i32, i32, i32, i32, i32), 3, "_3");
498    assert_role_name!((i32, i32, i32, i32, i32), 4, "_4");
499    test_tuple_index!(tuple5, set0, get0, 0, 42);
500    test_tuple_index!(tuple5, set1, get1, 1, 43);
501    test_tuple_index!(tuple5, set2, get2, 2, 44);
502    test_tuple_index!(tuple5, set3, get3, 3, 45);
503    test_tuple_index!(tuple5, set4, get4, 4, 46);
504
505    let mut tuple6: (i32, i32, i32, i32, i32, i32) = (1, 1, 1, 1, 1, 1);
506    assert_eq!(<(i32, i32, i32, i32, i32, i32)>::role_names().len(), 6);
507    assert_role_name!((i32, i32, i32, i32, i32, i32), 0, "_0");
508    assert_role_name!((i32, i32, i32, i32, i32, i32), 1, "_1");
509    assert_role_name!((i32, i32, i32, i32, i32, i32), 2, "_2");
510    assert_role_name!((i32, i32, i32, i32, i32, i32), 3, "_3");
511    assert_role_name!((i32, i32, i32, i32, i32, i32), 4, "_4");
512    assert_role_name!((i32, i32, i32, i32, i32, i32), 5, "_5");
513    test_tuple_index!(tuple6, set0, get0, 0, 42);
514    test_tuple_index!(tuple6, set1, get1, 1, 43);
515    test_tuple_index!(tuple6, set2, get2, 2, 44);
516    test_tuple_index!(tuple6, set3, get3, 3, 45);
517    test_tuple_index!(tuple6, set4, get4, 4, 46);
518    test_tuple_index!(tuple6, set5, get5, 5, 47);
519}