1#[cfg(feature = "gvariant")]
2use crate::Maybe;
3use crate::{
4 Array, Dict, Error, ObjectPath, OwnedObjectPath, OwnedSignature, Signature, Str, Structure,
5 Value,
6};
7
8#[cfg(unix)]
9use crate::Fd;
10
11use std::{collections::HashMap, convert::TryFrom, 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<'a>> for &'a $to {
32 type Error = Error;
33
34 fn try_from(value: &'a Value<'a>) -> 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<&'a Value<'a>> for $to {
48 type Error = Error;
49
50 fn try_from(value: &'a Value<'_>) -> 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#[cfg(unix)]
79value_try_from_all!(Fd, Fd);
80
81value_try_from_all!(Str, Str<'a>);
82value_try_from_all!(Signature, Signature<'a>);
83value_try_from_all!(ObjectPath, ObjectPath<'a>);
84value_try_from_all!(Structure, Structure<'a>);
85value_try_from_all!(Dict, Dict<'a, 'a>);
86value_try_from_all!(Array, Array<'a>);
87#[cfg(feature = "gvariant")]
88value_try_from_all!(Maybe, Maybe<'a>);
89
90value_try_from!(Str, String);
91value_try_from_ref!(Str, str);
92value_try_from_ref_clone!(Str, String);
93
94impl<'a, T> TryFrom<Value<'a>> for Vec<T>
95where
96 T: TryFrom<Value<'a>>,
97 T::Error: Into<crate::Error>,
98{
99 type Error = Error;
100
101 fn try_from(value: Value<'a>) -> Result<Self, Self::Error> {
102 if let Value::Array(v: Array<'_>) = value {
103 Self::try_from(v)
104 } else {
105 Err(Error::IncorrectType)
106 }
107 }
108}
109
110impl TryFrom<Value<'_>> for OwnedObjectPath {
111 type Error = Error;
112
113 fn try_from(value: Value<'_>) -> Result<Self, Self::Error> {
114 ObjectPath::try_from(value).map(op:OwnedObjectPath::from)
115 }
116}
117
118impl TryFrom<Value<'_>> for OwnedSignature {
119 type Error = Error;
120
121 fn try_from(value: Value<'_>) -> Result<Self, Self::Error> {
122 Signature::try_from(value).map(op:OwnedSignature::from)
123 }
124}
125
126// tuple conversions in `structure` module for avoiding code-duplication.
127
128#[cfg(feature = "enumflags2")]
129impl<'a, F> TryFrom<Value<'a>> for enumflags2::BitFlags<F>
130where
131 F: enumflags2::BitFlag,
132 F::Numeric: TryFrom<Value<'a>, Error = Error>,
133{
134 type Error = Error;
135
136 fn try_from(value: Value<'a>) -> Result<Self, Self::Error> {
137 Self::from_bits(F::Numeric::try_from(value)?)
138 .map_err(|_| Error::Message("Failed to convert to bitflags".into()))
139 }
140}
141
142impl<'a, K, V, H> TryFrom<Value<'a>> for HashMap<K, V, H>
143where
144 K: crate::Basic + TryFrom<Value<'a>> + std::hash::Hash + std::cmp::Eq,
145 V: TryFrom<Value<'a>>,
146 H: BuildHasher + Default,
147 K::Error: Into<crate::Error>,
148 V::Error: Into<crate::Error>,
149{
150 type Error = crate::Error;
151
152 fn try_from(value: Value<'a>) -> Result<Self, Self::Error> {
153 if let Value::Dict(v: Dict<'_, '_>) = value {
154 Self::try_from(v)
155 } else {
156 Err(crate::Error::IncorrectType)
157 }
158 }
159}
160
161// This would be great but somehow it conflicts with some blanket generic implementations from
162// core:
163//
164// impl<'a, T> TryFrom<Value<'a>> for Option<T>
165//
166// TODO: this could be useful
167// impl<'a, 'b, T> TryFrom<&'a Value<'b>> for Vec<T>
168// impl<'a, 'b, K, V, H> TryFrom<&'a Value<'v>> for HashMap<K, V, H>
169// and more..
170