zvariant/
from_value.rs

1#[cfg(feature = "gvariant")]
2use crate::Maybe;
3use crate::{
4    Array, Dict, Error, NoneValue, ObjectPath, Optional, OwnedObjectPath, OwnedSignature,
5    Signature, Str, Structure, Value,
6};
7
8#[cfg(unix)]
9use crate::Fd;
10
11use std::{collections::HashMap, hash::BuildHasher};
12
13macro_rules! value_try_from {
14    ($kind:ident, $to:ty) => {
15        impl<'a> TryFrom<Value<'a>> for $to {
16            type Error = Error;
17
18            fn try_from(value: Value<'a>) -> Result<Self, Self::Error> {
19                if let Value::$kind(value) = value {
20                    Ok(value.into())
21                } else {
22                    Err(Error::IncorrectType)
23                }
24            }
25        }
26    };
27}
28
29macro_rules! value_try_from_ref {
30    ($kind:ident, $to:ty) => {
31        impl<'a> TryFrom<&'a Value<'_>> for &'a $to {
32            type Error = Error;
33
34            fn try_from(value: &'a Value<'_>) -> Result<Self, Self::Error> {
35                if let Value::$kind(value) = value {
36                    Ok(value)
37                } else {
38                    Err(Error::IncorrectType)
39                }
40            }
41        }
42    };
43}
44
45macro_rules! value_try_from_ref_clone {
46    ($kind:ident, $to:ty) => {
47        impl<'a> TryFrom<&Value<'a>> for $to {
48            type Error = Error;
49
50            fn try_from(value: &Value<'a>) -> Result<Self, Self::Error> {
51                if let Value::$kind(value) = value {
52                    Ok(value.clone().into())
53                } else {
54                    Err(Error::IncorrectType)
55                }
56            }
57        }
58    };
59}
60
61macro_rules! value_try_from_all {
62    ($from:ident, $to:ty) => {
63        value_try_from!($from, $to);
64        value_try_from_ref!($from, $to);
65        value_try_from_ref_clone!($from, $to);
66    };
67}
68
69value_try_from_all!(U8, u8);
70value_try_from_all!(Bool, bool);
71value_try_from_all!(I16, i16);
72value_try_from_all!(U16, u16);
73value_try_from_all!(I32, i32);
74value_try_from_all!(U32, u32);
75value_try_from_all!(I64, i64);
76value_try_from_all!(U64, u64);
77value_try_from_all!(F64, f64);
78
79value_try_from_all!(Str, Str<'a>);
80value_try_from_all!(Signature, Signature<'a>);
81value_try_from_all!(ObjectPath, ObjectPath<'a>);
82value_try_from!(Str, String);
83value_try_from_ref!(Str, str);
84
85macro_rules! value_try_from_ref_try_clone {
86    ($kind:ident, $to:ty) => {
87        impl<'a> TryFrom<&Value<'a>> for $to {
88            type Error = Error;
89
90            fn try_from(value: &Value<'a>) -> Result<Self, Self::Error> {
91                if let Value::$kind(value) = value {
92                    value.try_clone().map_err(Into::into)
93                } else {
94                    Err(Error::IncorrectType)
95                }
96            }
97        }
98    };
99}
100
101value_try_from!(Structure, Structure<'a>);
102value_try_from_ref!(Structure, Structure<'a>);
103value_try_from_ref_try_clone!(Structure, Structure<'a>);
104
105value_try_from!(Dict, Dict<'a, 'a>);
106value_try_from_ref!(Dict, Dict<'a, 'a>);
107value_try_from_ref_try_clone!(Dict, Dict<'a, 'a>);
108
109value_try_from!(Array, Array<'a>);
110value_try_from_ref!(Array, Array<'a>);
111value_try_from_ref_try_clone!(Array, Array<'a>);
112
113#[cfg(feature = "gvariant")]
114value_try_from!(Maybe, Maybe<'a>);
115#[cfg(feature = "gvariant")]
116value_try_from_ref!(Maybe, Maybe<'a>);
117#[cfg(feature = "gvariant")]
118value_try_from_ref_try_clone!(Maybe, Maybe<'a>);
119
120#[cfg(unix)]
121value_try_from!(Fd, Fd<'a>);
122#[cfg(unix)]
123value_try_from_ref!(Fd, Fd<'a>);
124#[cfg(unix)]
125value_try_from_ref_try_clone!(Fd, Fd<'a>);
126
127impl TryFrom<&Value<'_>> for String {
128    type Error = Error;
129
130    fn try_from(value: &Value<'_>) -> Result<Self, Self::Error> {
131        Ok(<&str>::try_from(value)?.into())
132    }
133}
134
135impl<'a, T> TryFrom<Value<'a>> for Vec<T>
136where
137    T: TryFrom<Value<'a>>,
138    T::Error: Into<crate::Error>,
139{
140    type Error = Error;
141
142    fn try_from(value: Value<'a>) -> Result<Self, Self::Error> {
143        if let Value::Array(v) = value {
144            Self::try_from(v)
145        } else {
146            Err(Error::IncorrectType)
147        }
148    }
149}
150
151impl TryFrom<Value<'_>> for OwnedObjectPath {
152    type Error = Error;
153
154    fn try_from(value: Value<'_>) -> Result<Self, Self::Error> {
155        ObjectPath::try_from(value).map(OwnedObjectPath::from)
156    }
157}
158
159impl TryFrom<Value<'_>> for OwnedSignature {
160    type Error = Error;
161
162    fn try_from(value: Value<'_>) -> Result<Self, Self::Error> {
163        Signature::try_from(value).map(OwnedSignature::from)
164    }
165}
166
167// tuple conversions in `structure` module for avoiding code-duplication.
168
169#[cfg(feature = "enumflags2")]
170impl<'a, F> TryFrom<Value<'a>> for enumflags2::BitFlags<F>
171where
172    F: enumflags2::BitFlag,
173    F::Numeric: TryFrom<Value<'a>, Error = Error>,
174{
175    type Error = Error;
176
177    fn try_from(value: Value<'a>) -> Result<Self, Self::Error> {
178        Self::from_bits(F::Numeric::try_from(value)?)
179            .map_err(|_| Error::Message("Failed to convert to bitflags".into()))
180    }
181}
182
183impl<'a, K, V, H> TryFrom<Value<'a>> for HashMap<K, V, H>
184where
185    K: crate::Basic + TryFrom<Value<'a>> + std::hash::Hash + std::cmp::Eq,
186    V: TryFrom<Value<'a>>,
187    H: BuildHasher + Default,
188    K::Error: Into<crate::Error>,
189    V::Error: Into<crate::Error>,
190{
191    type Error = crate::Error;
192
193    fn try_from(value: Value<'a>) -> Result<Self, Self::Error> {
194        if let Value::Dict(v) = value {
195            Self::try_from(v)
196        } else {
197            Err(crate::Error::IncorrectType)
198        }
199    }
200}
201
202impl<'a, T> TryFrom<Value<'a>> for Optional<T>
203where
204    T: TryFrom<Value<'a>> + NoneValue + PartialEq<<T as NoneValue>::NoneType>,
205    T::Error: Into<crate::Error>,
206{
207    type Error = crate::Error;
208
209    fn try_from(value: Value<'a>) -> Result<Self, Self::Error> {
210        T::try_from(value).map_err(Into::into).map(|value| {
211            if value == T::null_value() {
212                Optional::from(None)
213            } else {
214                Optional::from(Some(value))
215            }
216        })
217    }
218}
219
220// This would be great but somehow it conflicts with some blanket generic implementations from
221// core:
222//
223// impl<'a, T> TryFrom<Value<'a>> for Option<T>
224//
225// TODO: this could be useful
226// impl<'a, 'b, T> TryFrom<&'a Value<'b>> for Vec<T>
227// impl<'a, 'b, K, V, H> TryFrom<&'a Value<'v>> for HashMap<K, V, H>
228// and more..