Skip to main content

cxx_qt_lib/
serde_impl.rs

1// SPDX-FileCopyrightText: 2025 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
2// SPDX-FileContributor: Joshua Booth <joshua.n.booth@gmail.com>
3//
4// SPDX-License-Identifier: MIT OR Apache-2.0
5use crate::{QList, QListElement, QSet, QSetElement, QStringList, QVector, QVectorElement};
6use cxx::ExternType;
7use serde::de::{SeqAccess, Visitor};
8use serde::{Deserialize, Deserializer, Serialize, Serializer};
9use std::fmt::{self, Formatter};
10use std::marker::PhantomData;
11
12/// Serializes and deserializes a list-like container by iterating over values.
13macro_rules! seq_impl {
14    ($t:ident, $element:ident, $insert:expr) => {
15        impl<T> Serialize for $t<T>
16        where
17            T: $element + Serialize,
18        {
19            fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
20                serializer.collect_seq(self.iter())
21            }
22        }
23
24        impl<'de, T> Deserialize<'de> for $t<T>
25        where
26            T: $element + Deserialize<'de> + ExternType<Kind = cxx::kind::Trivial>,
27        {
28            fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
29                struct SeqVisitor<T: $element> {
30                    marker: PhantomData<$t<T>>,
31                }
32
33                impl<'de, T> Visitor<'de> for SeqVisitor<T>
34                where
35                    T: $element + Deserialize<'de> + ExternType<Kind = cxx::kind::Trivial>,
36                {
37                    type Value = $t<T>;
38
39                    fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
40                        formatter.write_str("a sequence")
41                    }
42
43                    #[inline]
44                    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
45                    where
46                        A: SeqAccess<'de>,
47                    {
48                        let mut values = Self::Value::default();
49                        if let Some(size_hint) = seq.size_hint() {
50                            values.reserve_usize(size_hint);
51                        }
52                        while let Some(value) = seq.next_element()? {
53                            $insert(&mut values, value);
54                        }
55                        Ok(values)
56                    }
57                }
58
59                let visitor = SeqVisitor {
60                    marker: PhantomData,
61                };
62                deserializer.deserialize_seq(visitor)
63            }
64        }
65    };
66}
67
68seq_impl!(QList, QListElement, QList::append);
69seq_impl!(QSet, QSetElement, QSet::insert);
70seq_impl!(QVector, QVectorElement, QVector::append);
71
72/// Like seq_impl, but for Qt classes that dereference to a container.
73macro_rules! deref_impl {
74    ($t:ty) => {
75        impl Serialize for $t {
76            fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
77                (**self).serialize(serializer)
78            }
79        }
80
81        impl<'de> Deserialize<'de> for $t {
82            fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
83                struct SeqVisitor;
84
85                impl<'de> Visitor<'de> for SeqVisitor {
86                    type Value = $t;
87
88                    fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
89                        formatter.write_str("a sequence")
90                    }
91
92                    #[inline]
93                    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
94                    where
95                        A: SeqAccess<'de>,
96                    {
97                        let mut list = Self::Value::default();
98                        let values = &mut *list;
99                        if let Some(size_hint) = seq.size_hint() {
100                            values.reserve_usize(size_hint);
101                        }
102                        while let Some(value) = seq.next_element()? {
103                            values.append(value);
104                        }
105                        Ok(list)
106                    }
107                }
108
109                let visitor = SeqVisitor;
110                deserializer.deserialize_seq(visitor)
111            }
112        }
113    };
114}
115
116deref_impl!(QStringList);
117
118#[cfg(test)]
119pub fn roundtrip<T>(value: &T) -> T
120where
121    T: Serialize + serde::de::DeserializeOwned,
122{
123    let serialized = serde_json::to_value(value).expect("error serializing value");
124    match serde_json::from_value(serialized) {
125        Ok(deserialized) => deserialized,
126        Err(e) => panic!(
127            "error deserializing {}: {e}",
128            serde_json::to_value(value).unwrap()
129        ),
130    }
131}