zvariant/
owned_value.rs

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