zvariant/
owned_value.rs

1use serde::{Deserialize, Deserializer, Serialize};
2use std::{borrow::Borrow, collections::HashMap, hash::BuildHasher};
3
4use crate::{
5    Array, Dict, NoneValue, ObjectPath, Optional, OwnedObjectPath, Signature, Str, Structure, Type,
6    Value,
7};
8
9#[cfg(unix)]
10use crate::Fd;
11
12#[cfg(feature = "gvariant")]
13use crate::Maybe;
14
15// FIXME: Replace with a generic impl<T: TryFrom<Value>> TryFrom<OwnedValue> for T?
16// https://github.com/dbus2/zbus/issues/138
17
18/// Owned [`Value`](enum.Value.html)
19#[derive(Debug, PartialEq, Serialize, Type)]
20pub struct OwnedValue(pub(crate) Value<'static>);
21
22impl OwnedValue {
23    /// Attempt to clone the value.
24    pub fn try_clone(&self) -> Result<Self, crate::Error> {
25        self.0.try_clone().map(Self)
26    }
27
28    pub(crate) fn into_inner(self) -> Value<'static> {
29        self.0
30    }
31
32    pub(crate) fn inner(&self) -> &Value<'_> {
33        &self.0
34    }
35}
36
37macro_rules! ov_try_from {
38    ($to:ty) => {
39        impl TryFrom<OwnedValue> for $to {
40            type Error = crate::Error;
41
42            fn try_from(v: OwnedValue) -> Result<Self, Self::Error> {
43                <$to>::try_from(v.0)
44            }
45        }
46    };
47}
48
49macro_rules! ov_try_from_ref {
50    ($to:ty) => {
51        impl<'a> TryFrom<&'a OwnedValue> for $to {
52            type Error = crate::Error;
53
54            fn try_from(v: &'a OwnedValue) -> Result<Self, Self::Error> {
55                <$to>::try_from(&v.0)
56            }
57        }
58    };
59}
60
61ov_try_from!(u8);
62ov_try_from!(bool);
63ov_try_from!(i16);
64ov_try_from!(u16);
65ov_try_from!(i32);
66ov_try_from!(u32);
67ov_try_from!(i64);
68ov_try_from!(u64);
69ov_try_from!(f64);
70ov_try_from!(String);
71ov_try_from!(Signature);
72ov_try_from!(ObjectPath<'static>);
73ov_try_from!(OwnedObjectPath);
74ov_try_from!(Array<'static>);
75ov_try_from!(Dict<'static, 'static>);
76#[cfg(feature = "gvariant")]
77ov_try_from!(Maybe<'static>);
78ov_try_from!(Str<'static>);
79ov_try_from!(Structure<'static>);
80#[cfg(unix)]
81ov_try_from!(Fd<'static>);
82
83ov_try_from_ref!(u8);
84ov_try_from_ref!(bool);
85ov_try_from_ref!(i16);
86ov_try_from_ref!(u16);
87ov_try_from_ref!(i32);
88ov_try_from_ref!(u32);
89ov_try_from_ref!(i64);
90ov_try_from_ref!(u64);
91ov_try_from_ref!(f64);
92ov_try_from_ref!(&'a str);
93ov_try_from_ref!(&'a Signature);
94ov_try_from_ref!(&'a ObjectPath<'a>);
95ov_try_from_ref!(&'a Array<'a>);
96ov_try_from_ref!(&'a Dict<'a, 'a>);
97ov_try_from_ref!(&'a Str<'a>);
98ov_try_from_ref!(&'a Structure<'a>);
99#[cfg(feature = "gvariant")]
100ov_try_from_ref!(&'a Maybe<'a>);
101#[cfg(unix)]
102ov_try_from_ref!(&'a Fd<'a>);
103
104impl<'a, T> TryFrom<OwnedValue> for Vec<T>
105where
106    T: TryFrom<Value<'a>>,
107    T::Error: Into<crate::Error>,
108{
109    type Error = crate::Error;
110
111    fn try_from(value: OwnedValue) -> Result<Self, Self::Error> {
112        if let Value::Array(v) = value.0 {
113            Self::try_from(v)
114        } else {
115            Err(crate::Error::IncorrectType)
116        }
117    }
118}
119
120#[cfg(feature = "enumflags2")]
121impl<'a, F> TryFrom<OwnedValue> for enumflags2::BitFlags<F>
122where
123    F: enumflags2::BitFlag,
124    F::Numeric: TryFrom<Value<'a>, Error = crate::Error>,
125{
126    type Error = crate::Error;
127
128    fn try_from(value: OwnedValue) -> Result<Self, Self::Error> {
129        Self::try_from(value.0)
130    }
131}
132
133impl<'k, 'v, K, V, H> TryFrom<OwnedValue> for HashMap<K, V, H>
134where
135    K: crate::Basic + TryFrom<Value<'k>> + std::hash::Hash + std::cmp::Eq,
136    V: TryFrom<Value<'v>>,
137    H: BuildHasher + Default,
138    K::Error: Into<crate::Error>,
139    V::Error: Into<crate::Error>,
140{
141    type Error = crate::Error;
142
143    fn try_from(value: OwnedValue) -> Result<Self, Self::Error> {
144        if let Value::Dict(v) = value.0 {
145            Self::try_from(v)
146        } else {
147            Err(crate::Error::IncorrectType)
148        }
149    }
150}
151
152impl<K, V, H> From<HashMap<K, V, H>> for OwnedValue
153where
154    K: Type + Into<Value<'static>> + std::hash::Hash + std::cmp::Eq,
155    V: Type + Into<Value<'static>>,
156    H: BuildHasher + Default,
157{
158    fn from(value: HashMap<K, V, H>) -> Self {
159        Self(value.into())
160    }
161}
162
163impl<'a, T> TryFrom<OwnedValue> for Optional<T>
164where
165    T: TryFrom<Value<'a>> + NoneValue + PartialEq<<T as NoneValue>::NoneType>,
166    T::Error: Into<crate::Error>,
167{
168    type Error = crate::Error;
169
170    fn try_from(value: OwnedValue) -> Result<Self, Self::Error> {
171        Self::try_from(value.0)
172    }
173}
174
175impl<V> From<Optional<V>> for OwnedValue
176where
177    V: Into<Value<'static>> + NoneValue<NoneType = V>,
178{
179    fn from(v: Optional<V>) -> OwnedValue {
180        Self(Value::from(v))
181    }
182}
183
184// tuple conversions in `structure` module for avoiding code-duplication.
185
186impl<'a> TryFrom<Value<'a>> for OwnedValue {
187    type Error = crate::Error;
188
189    fn try_from(v: Value<'a>) -> crate::Result<Self> {
190        // TODO: add into_owned, avoiding copy if already owned..
191        v.try_to_owned()
192    }
193}
194
195impl<'a> TryFrom<&Value<'a>> for OwnedValue {
196    type Error = crate::Error;
197
198    fn try_from(v: &Value<'a>) -> crate::Result<Self> {
199        v.try_to_owned()
200    }
201}
202
203macro_rules! to_value {
204    ($from:ty, $variant:ident) => {
205        impl<'a> From<$from> for OwnedValue {
206            fn from(v: $from) -> Self {
207                OwnedValue(<Value<'static>>::$variant(v.to_owned()))
208            }
209        }
210    };
211}
212
213to_value!(u8, U8);
214to_value!(bool, Bool);
215to_value!(i16, I16);
216to_value!(u16, U16);
217to_value!(i32, I32);
218to_value!(u32, U32);
219to_value!(i64, I64);
220to_value!(u64, U64);
221to_value!(f64, F64);
222to_value!(Str<'a>, Str);
223to_value!(ObjectPath<'a>, ObjectPath);
224
225impl From<Signature> for OwnedValue {
226    fn from(v: Signature) -> Self {
227        OwnedValue(<Value<'static>>::Signature(v))
228    }
229}
230
231macro_rules! try_to_value {
232    ($from:ty) => {
233        impl<'a> TryFrom<$from> for OwnedValue {
234            type Error = crate::Error;
235
236            fn try_from(v: $from) -> crate::Result<Self> {
237                OwnedValue::try_from(<Value<'a>>::from(v))
238            }
239        }
240    };
241}
242
243try_to_value!(Array<'a>);
244try_to_value!(Dict<'a, 'a>);
245#[cfg(feature = "gvariant")]
246try_to_value!(Maybe<'a>);
247try_to_value!(Structure<'a>);
248#[cfg(unix)]
249try_to_value!(Fd<'a>);
250
251impl From<OwnedValue> for Value<'_> {
252    fn from(v: OwnedValue) -> Self {
253        v.into_inner()
254    }
255}
256
257impl<'o> TryFrom<&'o OwnedValue> for Value<'o> {
258    type Error = crate::Error;
259
260    fn try_from(v: &'o OwnedValue) -> crate::Result<Value<'o>> {
261        v.inner().try_clone()
262    }
263}
264
265impl std::ops::Deref for OwnedValue {
266    type Target = Value<'static>;
267
268    fn deref(&self) -> &Self::Target {
269        &self.0
270    }
271}
272
273impl<'a> Borrow<Value<'a>> for OwnedValue {
274    fn borrow(&self) -> &Value<'a> {
275        &self.0
276    }
277}
278
279impl<'de> Deserialize<'de> for OwnedValue {
280    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
281    where
282        D: Deserializer<'de>,
283    {
284        Value::deserialize(deserializer)
285            .and_then(|v| v.try_to_owned().map_err(serde::de::Error::custom))
286    }
287}
288
289impl Clone for OwnedValue {
290    /// Clone the value.
291    ///
292    /// # Panics
293    ///
294    /// This method can only fail on Unix platforms for [`Value::Fd`] variant containing an
295    /// [`Fd::Owned`] variant. This happens when the current process exceeds the limit on maximum
296    /// number of open file descriptors.
297    fn clone(&self) -> Self {
298        Self(self.0.clone())
299    }
300}
301
302#[cfg(test)]
303mod tests {
304    use std::{collections::HashMap, error::Error};
305
306    use crate::{serialized::Context, to_bytes, OwnedValue, Value, LE};
307
308    #[cfg(feature = "enumflags2")]
309    #[test]
310    fn bitflags() -> Result<(), Box<dyn Error>> {
311        #[repr(u32)]
312        #[enumflags2::bitflags]
313        #[derive(Copy, Clone, Debug)]
314        pub enum Flaggy {
315            One = 0x1,
316            Two = 0x2,
317        }
318
319        let v = Value::from(0x2u32);
320        let ov: OwnedValue = v.try_into()?;
321        assert_eq!(<enumflags2::BitFlags<Flaggy>>::try_from(ov)?, Flaggy::Two);
322        Ok(())
323    }
324
325    #[test]
326    fn from_value() -> Result<(), Box<dyn Error>> {
327        let v = Value::from("hi!");
328        let ov: OwnedValue = v.try_into()?;
329        assert_eq!(<&str>::try_from(&ov)?, "hi!");
330        Ok(())
331    }
332
333    #[test]
334    fn serde() -> Result<(), Box<dyn Error>> {
335        let ec = Context::new_dbus(LE, 0);
336        let ov: OwnedValue = Value::from("hi!").try_into()?;
337        let ser = to_bytes(ec, &ov)?;
338        let (de, parsed): (Value<'_>, _) = ser.deserialize()?;
339        assert_eq!(<&str>::try_from(&de)?, "hi!");
340        assert_eq!(parsed, ser.len());
341        Ok(())
342    }
343
344    #[test]
345    fn map_conversion() -> Result<(), Box<dyn Error>> {
346        let mut map = HashMap::<String, String>::new();
347        map.insert("one".to_string(), "1".to_string());
348        map.insert("two".to_string(), "2".to_string());
349        let value = OwnedValue::from(map.clone());
350        // Now convert back
351        let map2 = <HashMap<String, String>>::try_from(value)?;
352        assert_eq!(map, map2);
353
354        Ok(())
355    }
356}