cxx_qt_lib/core/qvariant/
mod.rs

1// SPDX-FileCopyrightText: 2021 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
2// SPDX-FileContributor: Andrew Hayzen <andrew.hayzen@kdab.com>
3// SPDX-FileContributor: Gerhard de Clercq <gerhard.declercq@kdab.com>
4//
5// SPDX-License-Identifier: MIT OR Apache-2.0
6use cxx::{type_id, ExternType};
7use std::mem::MaybeUninit;
8
9#[cxx::bridge]
10mod ffi {
11    unsafe extern "C++" {
12        include!("cxx-qt-lib/qvariant.h");
13        type QVariant = super::QVariant;
14
15        /// Convert this variant to type QMetaType::UnknownType and free up any resources used.
16        fn clear(self: &mut QVariant);
17        /// Returns true if this is a null variant, false otherwise.
18        #[rust_name = "is_null"]
19        fn isNull(self: &QVariant) -> bool;
20        /// Returns true if the storage type of this variant is not QMetaType::UnknownType; otherwise returns false.
21        #[rust_name = "is_valid"]
22        fn isValid(self: &QVariant) -> bool;
23    }
24
25    #[namespace = "rust::cxxqtlib1"]
26    unsafe extern "C++" {
27        include!("cxx-qt-lib/common.h");
28
29        #[doc(hidden)]
30        #[rust_name = "qvariant_drop"]
31        fn drop(variant: &mut QVariant);
32        #[doc(hidden)]
33        #[rust_name = "qvariant_default"]
34        fn construct() -> QVariant;
35        #[doc(hidden)]
36        #[rust_name = "qvariant_clone"]
37        fn construct(variant: &QVariant) -> QVariant;
38        #[doc(hidden)]
39        #[rust_name = "qvariant_eq"]
40        fn operatorEq(a: &QVariant, b: &QVariant) -> bool;
41    }
42}
43
44/// The QVariant class acts like a union for the most common Qt data types.
45#[repr(C)]
46pub struct QVariant {
47    /// The layout has changed between Qt 5 and Qt 6
48    ///
49    /// Qt5 QVariant has one member, which contains three uints (but they are optimised to a size of 8) and a union
50    /// Qt6 QVariant has one member, which contains three pointers and a union (pointer largest)
51    _data: MaybeUninit<f64>,
52
53    // Compiler optimisations reduce the size of the uint to a ushort
54    #[cfg(cxxqt_qt_version_major = "5")]
55    _type: MaybeUninit<u16>,
56    #[cfg(cxxqt_qt_version_major = "5")]
57    _is_shared: MaybeUninit<u16>,
58    #[cfg(cxxqt_qt_version_major = "5")]
59    _is_null: MaybeUninit<u16>,
60
61    #[cfg(cxxqt_qt_version_major = "6")]
62    _is_shared: MaybeUninit<usize>,
63    #[cfg(cxxqt_qt_version_major = "6")]
64    _is_null: MaybeUninit<usize>,
65    #[cfg(cxxqt_qt_version_major = "6")]
66    _packed_type: MaybeUninit<usize>,
67}
68
69impl Clone for QVariant {
70    /// Constructs a copy of the variant, p, passed as the argument to this constructor.
71    fn clone(&self) -> Self {
72        ffi::qvariant_clone(self)
73    }
74}
75
76impl Default for QVariant {
77    /// Constructs an invalid variant.
78    fn default() -> Self {
79        ffi::qvariant_default()
80    }
81}
82
83impl Drop for QVariant {
84    /// Destroys the QVariant and the contained object.
85    fn drop(&mut self) {
86        ffi::qvariant_drop(self)
87    }
88}
89
90impl<T> From<&T> for QVariant
91where
92    T: QVariantValue,
93{
94    /// Constructs a QVariant from a value of T
95    fn from(value: &T) -> Self {
96        T::construct(value)
97    }
98}
99
100// Note we can't use impl Into or TryInto for QVariant here as it conflicts
101//
102// note: conflicting implementation in crate `core`:
103// - impl<T, U> TryInto<U> for T
104//   where U: TryFrom<T>;
105impl QVariant {
106    /// Returns the stored value converted to the template type T
107    /// if QVariant::canConvert is true otherwise returns None
108    pub fn value<T: QVariantValue>(&self) -> Option<T> {
109        if T::can_convert(self) {
110            Some(T::value_or_default(self))
111        } else {
112            None
113        }
114    }
115
116    /// Returns the stored value converted to the template type T
117    ///
118    /// If the value cannot be converted, a default-constructed value will be returned.
119    ///
120    /// Note that this calls the `QVariant::value` method, without performance loss.
121    /// Whereas `value` first calls `QVariant::canConvert`.
122    pub fn value_or_default<T: QVariantValue>(&self) -> T {
123        T::value_or_default(self)
124    }
125}
126
127impl std::cmp::PartialEq for QVariant {
128    fn eq(&self, other: &Self) -> bool {
129        ffi::qvariant_eq(self, other)
130    }
131}
132
133pub trait QVariantValue {
134    fn can_convert(variant: &QVariant) -> bool;
135    fn construct(value: &Self) -> QVariant;
136    fn value_or_default(variant: &QVariant) -> Self;
137}
138
139macro_rules! impl_qvariant_value {
140    ( $typeName:ty, $module:ident ) => {
141        mod $module;
142
143        impl QVariantValue for $typeName {
144            fn can_convert(variant: &QVariant) -> bool {
145                $module::can_convert(variant)
146            }
147
148            fn construct(value: &Self) -> QVariant {
149                $module::construct(value)
150            }
151
152            fn value_or_default(variant: &QVariant) -> Self {
153                $module::value_or_default(variant)
154            }
155        }
156    };
157}
158
159impl_qvariant_value!(bool, qvariant_bool);
160impl_qvariant_value!(f32, qvariant_f32);
161impl_qvariant_value!(f64, qvariant_f64);
162impl_qvariant_value!(i8, qvariant_i8);
163impl_qvariant_value!(i16, qvariant_i16);
164impl_qvariant_value!(i32, qvariant_i32);
165impl_qvariant_value!(i64, qvariant_i64);
166impl_qvariant_value!(crate::QByteArray, qvariant_qbytearray);
167#[cfg(feature = "qt_gui")]
168impl_qvariant_value!(crate::QColor, qvariant_qcolor);
169impl_qvariant_value!(crate::QDate, qvariant_qdate);
170#[cfg(not(target_os = "emscripten"))]
171impl_qvariant_value!(crate::QDateTime, qvariant_qdatetime);
172impl_qvariant_value!(crate::QModelIndex, qvariant_qmodelindex);
173impl_qvariant_value!(crate::QPersistentModelIndex, qvariant_qpersistentmodelindex);
174impl_qvariant_value!(crate::QPoint, qvariant_qpoint);
175impl_qvariant_value!(crate::QPointF, qvariant_qpointf);
176impl_qvariant_value!(crate::QRect, qvariant_qrect);
177impl_qvariant_value!(crate::QRectF, qvariant_qrectf);
178impl_qvariant_value!(crate::QSize, qvariant_qsize);
179impl_qvariant_value!(crate::QSizeF, qvariant_qsizef);
180impl_qvariant_value!(crate::QString, qvariant_qstring);
181impl_qvariant_value!(crate::QStringList, qvariant_qstringlist);
182impl_qvariant_value!(crate::QTime, qvariant_qtime);
183impl_qvariant_value!(crate::QUrl, qvariant_qurl);
184impl_qvariant_value!(u8, qvariant_u8);
185impl_qvariant_value!(u16, qvariant_u16);
186impl_qvariant_value!(u32, qvariant_u32);
187impl_qvariant_value!(u64, qvariant_u64);
188
189// Safety:
190//
191// Static checks on the C++ side to ensure the size is the same.
192unsafe impl ExternType for QVariant {
193    type Id = type_id!("QVariant");
194    type Kind = cxx::kind::Trivial;
195}