zvariant/
owned_value.rs

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