use cxx::{type_id, ExternType};
use std::fmt;
use std::mem::MaybeUninit;
use crate::{QMetaTypeType, QObjectMutPtr};
#[cxx::bridge]
mod ffi {
unsafe extern "C++" {
include!("cxx-qt-lib/qstring.h");
type QString = crate::QString;
include!("cxx-qt-lib/qvariant.h");
}
unsafe extern "C++" {
type QVariant = super::QVariant;
fn clear(&mut self);
#[rust_name = "is_null"]
fn isNull(&self) -> bool;
#[rust_name = "is_valid"]
fn isValid(&self) -> bool;
#[doc(hidden)]
#[rust_name = "user_type"]
fn userType(&self) -> i32;
}
#[namespace = "rust::cxxqtlib1"]
unsafe extern "C++" {
include!("cxx-qt-lib/common.h");
#[doc(hidden)]
#[rust_name = "qvariant_drop"]
fn drop(variant: &mut QVariant);
#[doc(hidden)]
#[rust_name = "qvariant_default"]
fn construct() -> QVariant;
#[doc(hidden)]
#[rust_name = "qvariant_clone"]
fn construct(variant: &QVariant) -> QVariant;
#[doc(hidden)]
#[rust_name = "qvariant_eq"]
fn operatorEq(a: &QVariant, b: &QVariant) -> bool;
#[doc(hidden)]
#[rust_name = "qvariant_to_debug_qstring"]
fn toDebugQString(variant: &QVariant) -> QString;
}
#[namespace = "rust::cxxqtlib1::qvariant"]
unsafe extern "C++" {
#[doc(hidden)]
#[rust_name = "qvariant_type_name"]
fn qvariantTypeName(variant: &QVariant) -> &[u8];
}
}
#[repr(C)]
pub struct QVariant {
_data: MaybeUninit<f64>,
#[cfg(cxxqt_qt_version_major = "5")]
_space: MaybeUninit<u32>,
#[cfg(cxxqt_qt_version_major = "6")]
_space: MaybeUninit<[usize; 3]>,
}
impl Clone for QVariant {
fn clone(&self) -> Self {
ffi::qvariant_clone(self)
}
}
impl Default for QVariant {
fn default() -> Self {
ffi::qvariant_default()
}
}
impl Drop for QVariant {
fn drop(&mut self) {
ffi::qvariant_drop(self)
}
}
impl<T> From<&T> for QVariant
where
T: QVariantValue,
{
fn from(value: &T) -> Self {
T::construct(value)
}
}
impl QVariant {
pub fn type_id(&self) -> QMetaTypeType {
self.user_type().into()
}
pub fn type_name(&self) -> &str {
let slice = ffi::qvariant_type_name(self);
std::str::from_utf8(slice).expect("QVariant type name is not valid UTF-8")
}
pub fn value<T: QVariantValue>(&self) -> Option<T> {
if T::can_convert(self) {
Some(T::value_or_default(self))
} else {
None
}
}
pub fn value_or_default<T: QVariantValue>(&self) -> T {
T::value_or_default(self)
}
}
impl std::cmp::PartialEq for QVariant {
fn eq(&self, other: &Self) -> bool {
ffi::qvariant_eq(self, other)
}
}
impl fmt::Debug for QVariant {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
ffi::qvariant_to_debug_qstring(self).fmt(f)
}
}
pub trait QVariantValue {
fn can_convert(variant: &QVariant) -> bool;
fn construct(value: &Self) -> QVariant;
fn value_or_default(variant: &QVariant) -> Self;
}
macro_rules! impl_qvariant_value {
( $typeName:ty, $module:ident ) => {
mod $module;
impl QVariantValue for $typeName {
fn can_convert(variant: &QVariant) -> bool {
$module::can_convert(variant)
}
fn construct(value: &Self) -> QVariant {
$module::construct(value)
}
fn value_or_default(variant: &QVariant) -> Self {
$module::value_or_default(variant)
}
}
};
}
impl_qvariant_value!(bool, qvariant_bool);
impl_qvariant_value!(f32, qvariant_f32);
impl_qvariant_value!(f64, qvariant_f64);
impl_qvariant_value!(i8, qvariant_i8);
impl_qvariant_value!(i16, qvariant_i16);
impl_qvariant_value!(i32, qvariant_i32);
impl_qvariant_value!(i64, qvariant_i64);
impl_qvariant_value!(crate::QByteArray, qvariant_qbytearray);
impl_qvariant_value!(crate::QDate, qvariant_qdate);
#[cfg(not(target_os = "emscripten"))]
impl_qvariant_value!(crate::QDateTime, qvariant_qdatetime);
impl_qvariant_value!(crate::QJsonArray, qvariant_qjsonarray);
impl_qvariant_value!(crate::QJsonObject, qvariant_qjsonobject);
impl_qvariant_value!(crate::QJsonValue, qvariant_qjsonvalue);
impl_qvariant_value!(crate::QLine, qvariant_qline);
impl_qvariant_value!(crate::QLineF, qvariant_qlinef);
impl_qvariant_value!(crate::QModelIndex, qvariant_qmodelindex);
impl_qvariant_value!(crate::QObjectMutPtr, qvariant_qobjectmutptr);
impl_qvariant_value!(crate::QPersistentModelIndex, qvariant_qpersistentmodelindex);
impl_qvariant_value!(crate::QPoint, qvariant_qpoint);
impl_qvariant_value!(crate::QPointF, qvariant_qpointf);
impl_qvariant_value!(crate::QRect, qvariant_qrect);
impl_qvariant_value!(crate::QRectF, qvariant_qrectf);
impl_qvariant_value!(crate::QSize, qvariant_qsize);
impl_qvariant_value!(crate::QSizeF, qvariant_qsizef);
impl_qvariant_value!(crate::QString, qvariant_qstring);
impl_qvariant_value!(crate::QStringList, qvariant_qstringlist);
impl_qvariant_value!(crate::QTime, qvariant_qtime);
impl_qvariant_value!(crate::QUrl, qvariant_qurl);
impl_qvariant_value!(crate::QUuid, qvariant_quuid);
impl_qvariant_value!(
crate::QHash<crate::QHashPair_QString_QVariant>,
qvariant_qvarianthash
);
impl_qvariant_value!(crate::QList<bool>, qvariant_qlist_bool);
impl_qvariant_value!(crate::QList<f32>, qvariant_qlist_f32);
impl_qvariant_value!(crate::QList<f64>, qvariant_qlist_f64);
impl_qvariant_value!(crate::QList<i8>, qvariant_qlist_i8);
impl_qvariant_value!(crate::QList<i16>, qvariant_qlist_i16);
impl_qvariant_value!(crate::QList<i32>, qvariant_qlist_i32);
impl_qvariant_value!(crate::QList<i64>, qvariant_qlist_i64);
impl_qvariant_value!(crate::QList<u8>, qvariant_qlist_u8);
impl_qvariant_value!(crate::QList<u16>, qvariant_qlist_u16);
impl_qvariant_value!(crate::QList<u32>, qvariant_qlist_u32);
impl_qvariant_value!(crate::QList<u64>, qvariant_qlist_u64);
impl_qvariant_value!(crate::QList<QObjectMutPtr>, qvariant_qlist_qobjectmutptr);
impl_qvariant_value!(crate::QList<crate::QString>, qvariant_qlist_qstring);
impl_qvariant_value!(crate::QList<QVariant>, qvariant_qvariantlist);
impl_qvariant_value!(
crate::QMap<crate::QMapPair_QString_QVariant>,
qvariant_qvariantmap
);
impl_qvariant_value!(u8, qvariant_u8);
impl_qvariant_value!(u16, qvariant_u16);
impl_qvariant_value!(u32, qvariant_u32);
impl_qvariant_value!(u64, qvariant_u64);
#[cfg(feature = "qt_gui")]
impl_qvariant_value!(crate::QColor, qvariant_qcolor);
#[cfg(feature = "qt_gui")]
impl_qvariant_value!(crate::QFont, qvariant_qfont);
#[cfg(feature = "qt_gui")]
impl_qvariant_value!(crate::QImage, qvariant_qimage);
#[cfg(feature = "qt_gui")]
impl_qvariant_value!(crate::QPen, qvariant_qpen);
#[cfg(feature = "qt_gui")]
impl_qvariant_value!(crate::QPolygon, qvariant_qpolygon);
#[cfg(feature = "qt_gui")]
impl_qvariant_value!(crate::QPolygonF, qvariant_qpolygonf);
#[cfg(feature = "qt_gui")]
impl_qvariant_value!(crate::QQuaternion, qvariant_qquaternion);
#[cfg(feature = "qt_gui")]
impl_qvariant_value!(crate::QRegion, qvariant_qregion);
#[cfg(feature = "qt_gui")]
impl_qvariant_value!(crate::QVector2D, qvariant_qvector2d);
#[cfg(feature = "qt_gui")]
impl_qvariant_value!(crate::QVector3D, qvariant_qvector3d);
#[cfg(feature = "qt_gui")]
impl_qvariant_value!(crate::QVector4D, qvariant_qvector4d);
unsafe impl ExternType for QVariant {
type Id = type_id!("QVariant");
type Kind = cxx::kind::Trivial;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{QList, QString};
#[test]
fn test_type_name() {
let variant = QVariant::from(&true);
assert_eq!(variant.type_name(), "bool");
let variant = QVariant::from(&123_i32);
assert_eq!(variant.type_name(), "int");
let variant = QVariant::from(&0.25f32);
assert_eq!(variant.type_name(), "float");
let variant = QVariant::from(&0.75f64);
assert_eq!(variant.type_name(), "double");
let variant = QVariant::from(&QList::<i32>::from_iter(&[1, 2, 3]));
assert_eq!(variant.type_name(), "QList<int>");
let variant = QVariant::from(&QString::from("ABC"));
assert_eq!(variant.type_name(), "QString");
}
#[test]
fn qvariant_type_name_invalid() {
let variant = QVariant::default();
assert!(!variant.is_valid());
assert_eq!(variant.type_name(), "");
}
}