Skip to main content

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::fmt;
8use std::mem::MaybeUninit;
9
10use crate::QMetaTypeType;
11
12#[cxx::bridge]
13mod ffi {
14    unsafe extern "C++" {
15        include!("cxx-qt-lib/qstring.h");
16        type QString = crate::QString;
17
18        include!("cxx-qt-lib/qvariant.h");
19    }
20
21    unsafe extern "C++" {
22        type QVariant = super::QVariant;
23
24        /// Convert this variant to type `QMetaType::UnknownType` and free up any resources used.
25        fn clear(&mut self);
26        /// Returns `true` if this is a null variant, `false` otherwise.
27        ///
28        /// In Qt 6, a value is considered null if it contains no initialized value or a null pointer.
29        /// In Qt 5, a value is additionally considered null if the variant contains an object of a builtin type with an `is_null` method that returned `true` for that object.
30        #[rust_name = "is_null"]
31        fn isNull(&self) -> bool;
32        /// Returns `true` if the storage type of this variant is not `QMetaType::UnknownType`; otherwise returns `false`.
33        #[rust_name = "is_valid"]
34        fn isValid(&self) -> bool;
35
36        #[doc(hidden)]
37        #[rust_name = "user_type"]
38        fn userType(&self) -> i32;
39    }
40
41    #[namespace = "rust::cxxqtlib1"]
42    unsafe extern "C++" {
43        include!("cxx-qt-lib/common.h");
44
45        #[doc(hidden)]
46        #[rust_name = "qvariant_drop"]
47        fn drop(variant: &mut QVariant);
48        #[doc(hidden)]
49        #[rust_name = "qvariant_default"]
50        fn construct() -> QVariant;
51        #[doc(hidden)]
52        #[rust_name = "qvariant_clone"]
53        fn construct(variant: &QVariant) -> QVariant;
54        #[doc(hidden)]
55        #[rust_name = "qvariant_eq"]
56        fn operatorEq(a: &QVariant, b: &QVariant) -> bool;
57        #[doc(hidden)]
58        #[rust_name = "qvariant_to_debug_qstring"]
59        fn toDebugQString(variant: &QVariant) -> QString;
60    }
61}
62
63/// The `QVariant` class acts like a union for the most common Qt data types.
64///
65/// Qt Documentation: [QVariant]("https://doc.qt.io/qt/qvariant.html#details")
66#[repr(C)]
67pub struct QVariant {
68    /// The layout has changed between Qt 5 and Qt 6
69    ///
70    /// Qt5 `QVariant` has one member, which contains three `uint`s (but they are optimised to a size of 8) and a union
71    /// Qt6 `QVariant` has one member, which contains three pointers and a union (pointer largest)
72    _data: MaybeUninit<f64>,
73
74    #[cfg(cxxqt_qt_version_major = "5")]
75    _space: MaybeUninit<u32>,
76    #[cfg(cxxqt_qt_version_major = "6")]
77    _space: MaybeUninit<[usize; 3]>,
78}
79
80impl Clone for QVariant {
81    /// Constructs a copy of the variant passed as the argument to `self`'s constructor.
82    fn clone(&self) -> Self {
83        ffi::qvariant_clone(self)
84    }
85}
86
87impl Default for QVariant {
88    /// Constructs an invalid variant.
89    fn default() -> Self {
90        ffi::qvariant_default()
91    }
92}
93
94impl Drop for QVariant {
95    /// Destroys the `QVariant` and the contained object.
96    fn drop(&mut self) {
97        ffi::qvariant_drop(self)
98    }
99}
100
101impl<T> From<&T> for QVariant
102where
103    T: QVariantValue,
104{
105    /// Constructs a `QVariant` from a value of `T`.
106    fn from(value: &T) -> Self {
107        T::construct(value)
108    }
109}
110
111// Note we can't use impl Into or TryInto for QVariant here as it conflicts
112//
113// note: conflicting implementation in crate `core`:
114// - impl<T, U> TryInto<U> for T
115//   where U: TryFrom<T>;
116impl QVariant {
117    /// Returns the storage type of the value stored in the variant.
118    pub fn type_id(&self) -> QMetaTypeType {
119        self.user_type().into()
120    }
121
122    /// Returns the stored value converted to the template type `T`, or `None` if the type cannot be converted to `T`.
123    ///
124    /// Note that this first calls [`can_convert`](QVariantValue::can_convert).
125    pub fn value<T: QVariantValue>(&self) -> Option<T> {
126        if T::can_convert(self) {
127            Some(T::value_or_default(self))
128        } else {
129            None
130        }
131    }
132
133    /// Returns the stored value converted to the template type `T`, or a default-constructed value if the type cannot be converted to `T`.
134    ///
135    /// For most value types, a default-constructed value simply means that a value is created using the default constructor (e.g. an empty string for [`QString`](crate::QString)). Primitive types like `i32` and `f64` are initialized to 0.
136    ///
137    /// Note that this calls Qt's `QVariant::value` method, without performance loss.
138    /// Whereas `value` first calls [`can_convert`](QVariantValue::can_convert).
139    pub fn value_or_default<T: QVariantValue>(&self) -> T {
140        T::value_or_default(self)
141    }
142}
143
144impl std::cmp::PartialEq for QVariant {
145    /// Returns `true` if `self` and `other` are equal, otherwise returns `false`.
146    ///
147    /// `QVariant` uses the equality operator of the type contained to check for equality.
148    ///
149    /// Variants of different types will always compare as not equal with a few exceptions:
150    ///
151    /// - If both types are numeric types (integers and floatins point numbers) Qt will compare those types using standard C++ type promotion rules.
152    /// - If one type is numeric and the other one a [`QString`](crate::QString), Qt will try to convert the `QString` to a matching numeric type and if successful compare those.
153    /// - If both variants contain pointers to `QObject` derived types, `QVariant` will check whether the types are related and point to the same object.
154    ///
155    /// The result of the function is not affected by the result of [`is_null`](QVariant::is_null), which means that two values can be equal even if one of them is null and another is not.
156    fn eq(&self, other: &Self) -> bool {
157        ffi::qvariant_eq(self, other)
158    }
159}
160
161impl fmt::Debug for QVariant {
162    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
163        ffi::qvariant_to_debug_qstring(self).fmt(f)
164    }
165}
166
167/// Trait implementation for a value in a [`QVariant`].
168pub trait QVariantValue {
169    fn can_convert(variant: &QVariant) -> bool;
170    fn construct(value: &Self) -> QVariant;
171    fn value_or_default(variant: &QVariant) -> Self;
172}
173
174macro_rules! impl_qvariant_value {
175    ( $typeName:ty, $module:ident ) => {
176        mod $module;
177
178        impl QVariantValue for $typeName {
179            fn can_convert(variant: &QVariant) -> bool {
180                $module::can_convert(variant)
181            }
182
183            fn construct(value: &Self) -> QVariant {
184                $module::construct(value)
185            }
186
187            fn value_or_default(variant: &QVariant) -> Self {
188                $module::value_or_default(variant)
189            }
190        }
191    };
192}
193
194impl_qvariant_value!(bool, qvariant_bool);
195impl_qvariant_value!(f32, qvariant_f32);
196impl_qvariant_value!(f64, qvariant_f64);
197impl_qvariant_value!(i8, qvariant_i8);
198impl_qvariant_value!(i16, qvariant_i16);
199impl_qvariant_value!(i32, qvariant_i32);
200impl_qvariant_value!(i64, qvariant_i64);
201impl_qvariant_value!(crate::QByteArray, qvariant_qbytearray);
202impl_qvariant_value!(crate::QDate, qvariant_qdate);
203#[cfg(not(target_os = "emscripten"))]
204impl_qvariant_value!(crate::QDateTime, qvariant_qdatetime);
205impl_qvariant_value!(crate::QLine, qvariant_qline);
206impl_qvariant_value!(crate::QLineF, qvariant_qlinef);
207impl_qvariant_value!(crate::QModelIndex, qvariant_qmodelindex);
208impl_qvariant_value!(crate::QPersistentModelIndex, qvariant_qpersistentmodelindex);
209impl_qvariant_value!(crate::QPoint, qvariant_qpoint);
210impl_qvariant_value!(crate::QPointF, qvariant_qpointf);
211impl_qvariant_value!(crate::QRect, qvariant_qrect);
212impl_qvariant_value!(crate::QRectF, qvariant_qrectf);
213impl_qvariant_value!(crate::QSize, qvariant_qsize);
214impl_qvariant_value!(crate::QSizeF, qvariant_qsizef);
215impl_qvariant_value!(crate::QString, qvariant_qstring);
216impl_qvariant_value!(crate::QStringList, qvariant_qstringlist);
217impl_qvariant_value!(crate::QTime, qvariant_qtime);
218impl_qvariant_value!(crate::QUrl, qvariant_qurl);
219impl_qvariant_value!(crate::QUuid, qvariant_quuid);
220impl_qvariant_value!(
221    crate::QHash<crate::QHashPair_QString_QVariant>,
222    qvariant_qvarianthash
223);
224impl_qvariant_value!(crate::QList<QVariant>, qvariant_qvariantlist);
225impl_qvariant_value!(
226    crate::QMap<crate::QMapPair_QString_QVariant>,
227    qvariant_qvariantmap
228);
229impl_qvariant_value!(u8, qvariant_u8);
230impl_qvariant_value!(u16, qvariant_u16);
231impl_qvariant_value!(u32, qvariant_u32);
232impl_qvariant_value!(u64, qvariant_u64);
233
234#[cfg(feature = "qt_gui")]
235impl_qvariant_value!(crate::QColor, qvariant_qcolor);
236#[cfg(feature = "qt_gui")]
237impl_qvariant_value!(crate::QFont, qvariant_qfont);
238#[cfg(feature = "qt_gui")]
239impl_qvariant_value!(crate::QImage, qvariant_qimage);
240#[cfg(feature = "qt_gui")]
241impl_qvariant_value!(crate::QPen, qvariant_qpen);
242#[cfg(feature = "qt_gui")]
243impl_qvariant_value!(crate::QPolygon, qvariant_qpolygon);
244#[cfg(feature = "qt_gui")]
245impl_qvariant_value!(crate::QPolygonF, qvariant_qpolygonf);
246#[cfg(feature = "qt_gui")]
247impl_qvariant_value!(crate::QQuaternion, qvariant_qquaternion);
248#[cfg(feature = "qt_gui")]
249impl_qvariant_value!(crate::QRegion, qvariant_qregion);
250#[cfg(feature = "qt_gui")]
251impl_qvariant_value!(crate::QVector2D, qvariant_qvector2d);
252#[cfg(feature = "qt_gui")]
253impl_qvariant_value!(crate::QVector3D, qvariant_qvector3d);
254#[cfg(feature = "qt_gui")]
255impl_qvariant_value!(crate::QVector4D, qvariant_qvector4d);
256
257// Safety:
258//
259// Static checks on the C++ side to ensure the size is the same.
260unsafe impl ExternType for QVariant {
261    type Id = type_id!("QVariant");
262    type Kind = cxx::kind::Trivial;
263}