Skip to main content

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