diff --git a/zbus/src/lib.rs b/zbus/src/lib.rs index c3ec6bf47..6100c4936 100644 --- a/zbus/src/lib.rs +++ b/zbus/src/lib.rs @@ -1057,4 +1057,19 @@ mod tests { event.notify(1); } } + + #[test] + #[ignore] + fn issue_466() { + #[crate::dbus_proxy(interface = "org.Some.Thing1", assume_defaults = true)] + trait MyGreeter { + fn foo( + &self, + arg: &(u32, zbus::zvariant::Value<'_>), + ) -> zbus::Result<(u32, zbus::zvariant::OwnedValue)>; + + #[dbus_proxy(property)] + fn bar(&self) -> zbus::Result<(u32, zbus::zvariant::OwnedValue)>; + } + } } diff --git a/zvariant/src/array.rs b/zvariant/src/array.rs index f5c8b8a42..0b29555c6 100644 --- a/zvariant/src/array.rs +++ b/zvariant/src/array.rs @@ -60,10 +60,23 @@ impl<'a> Array<'a> { } /// Get all the elements. - pub fn get(&self) -> &[Value<'a>] { + pub fn inner(&self) -> &[Value<'a>] { &self.elements } + /// Get the value at the given index. + pub fn get(&'a self, idx: usize) -> Result> + where + V: ?Sized + TryFrom<&'a Value<'a>>, + >>::Error: Into, + { + self.elements + .get(idx) + .map(|v| v.downcast_ref::()) + .transpose() + .map_err(Into::into) + } + /// Get the number of elements. pub fn len(&self) -> usize { self.elements.len() @@ -138,7 +151,7 @@ pub(crate) fn array_display_fmt( let bytes = leading .iter() .map(|v| { - *v.downcast_ref::() + v.downcast_ref::() .expect("item must have a signature of a byte") }) .collect::>(); @@ -231,7 +244,7 @@ impl<'a> std::ops::Deref for Array<'a> { type Target = [Value<'a>]; fn deref(&self) -> &Self::Target { - self.get() + self.inner() } } diff --git a/zvariant/src/dict.rs b/zvariant/src/dict.rs index 792c0e4e0..bead69a9b 100644 --- a/zvariant/src/dict.rs +++ b/zvariant/src/dict.rs @@ -1,7 +1,7 @@ use std::{ - collections::{BTreeSet, HashMap}, + collections::{BTreeMap, HashMap}, fmt::{Display, Write}, - hash::BuildHasher, + hash::{BuildHasher, Hash}, }; use serde::ser::{Serialize, SerializeSeq, SerializeStruct, Serializer}; @@ -17,7 +17,7 @@ use crate::{value_display_fmt, Basic, DynamicType, Error, Signature, Type, Value /// [`HashMap`]: https://doc.rust-lang.org/std/collections/struct.HashMap.html #[derive(Debug, Hash, PartialEq, PartialOrd, Eq, Ord)] pub struct Dict<'k, 'v> { - entries: BTreeSet>, + map: BTreeMap, Value<'v>>, key_signature: Signature<'k>, value_signature: Signature<'v>, // should use a separate lifetime or everything should use the same but API break. @@ -32,7 +32,7 @@ impl<'k, 'v> Dict<'k, 'v> { let signature = create_signature(&key_signature, &value_signature); Self { - entries: BTreeSet::new(), + map: BTreeMap::new(), key_signature, value_signature, signature, @@ -56,7 +56,7 @@ impl<'k, 'v> Dict<'k, 'v> { check_child_value_signature!(self.key_signature, key.value_signature(), "key"); check_child_value_signature!(self.value_signature, value.value_signature(), "value"); - self.entries.insert(DictEntry { key, value }); + self.map.insert(key, value); Ok(()) } @@ -64,41 +64,29 @@ impl<'k, 'v> Dict<'k, 'v> { /// Add a new entry. pub fn add(&mut self, key: K, value: V) -> Result<(), Error> where - K: Basic + Into> + std::hash::Hash + std::cmp::Eq, + K: Basic + Into> + Ord, V: Into> + DynamicType, { check_child_value_signature!(self.key_signature, K::signature(), "key"); check_child_value_signature!(self.value_signature, value.dynamic_signature(), "value"); - self.entries.insert(DictEntry { - key: Value::new(key), - value: Value::new(value), - }); + self.map.insert(Value::new(key), Value::new(value)); Ok(()) } /// Get the value for the given key. - pub fn get<'d, K, V>(&'d self, key: &K) -> Result, Error> + pub fn get<'d, K, V>(&'d self, key: &'k K) -> Result, Error> where 'd: 'k + 'v, - K: ?Sized + std::cmp::Eq + 'k, - V: ?Sized, - &'k K: TryFrom<&'k Value<'k>>, - &'v V: TryFrom<&'v Value<'v>>, + &'k K: TryInto>, + <&'k K as TryInto>>::Error: Into, + V: TryFrom<&'v Value<'v>>, + >>::Error: Into, { - for entry in &self.entries { - let entry_key = entry.key.downcast_ref::().ok_or(Error::IncorrectType)?; - if *entry_key == *key { - return entry - .value - .downcast_ref() - .ok_or(Error::IncorrectType) - .map(Some); - } - } + let key: Value<'_> = key.try_into().map_err(Into::into)?; - Ok(None) + self.map.get(&key).map(|v| v.downcast_ref()).transpose() } /// Get the signature of this `Dict`. @@ -121,10 +109,15 @@ impl<'k, 'v> Dict<'k, 'v> { key_signature: self.key_signature.to_owned(), value_signature: self.value_signature.to_owned(), signature: self.signature.to_owned(), - entries: self - .entries + map: self + .map .iter() - .map(|v| v.try_to_owned().map(Into::into)) + .map(|(k, v)| { + Ok(( + k.try_to_owned().map(Into::into)?, + v.try_to_owned().map(Into::into)?, + )) + }) .collect::>()?, }) } @@ -132,13 +125,13 @@ impl<'k, 'v> Dict<'k, 'v> { /// Try to clone the `Dict`. pub fn try_clone(&self) -> Result { let entries = self - .entries + .map .iter() - .map(|v| v.try_clone()) - .collect::>()?; + .map(|(k, v)| Ok((k.try_clone()?, v.try_clone()?))) + .collect::>()?; Ok(Self { - entries, + map: entries, key_signature: self.key_signature.clone(), value_signature: self.value_signature.clone(), signature: self.signature.clone(), @@ -151,7 +144,7 @@ impl<'k, 'v> Dict<'k, 'v> { let value_signature = signature.slice(3..signature.len() - 1); Self { - entries: BTreeSet::new(), + map: BTreeMap::new(), key_signature, value_signature, signature, @@ -172,7 +165,7 @@ pub(crate) fn dict_display_fmt( f: &mut std::fmt::Formatter<'_>, type_annotate: bool, ) -> std::fmt::Result { - if dict.entries.is_empty() { + if dict.map.is_empty() { if type_annotate { write!(f, "@{} ", dict.full_signature())?; } @@ -183,13 +176,13 @@ pub(crate) fn dict_display_fmt( // Annotate only the first entry as the rest will be of the same type. let mut type_annotate = type_annotate; - for (i, entry) in dict.entries.iter().enumerate() { - value_display_fmt(&entry.key, f, type_annotate)?; + for (i, (key, value)) in dict.map.iter().enumerate() { + value_display_fmt(key, f, type_annotate)?; f.write_str(": ")?; - value_display_fmt(&entry.value, f, type_annotate)?; + value_display_fmt(value, f, type_annotate)?; type_annotate = false; - if i + 1 < dict.entries.len() { + if i + 1 < dict.map.len() { f.write_str(", ")?; } } @@ -205,105 +198,94 @@ impl<'k, 'v> Serialize for Dict<'k, 'v> { where S: Serializer, { - let mut seq = serializer.serialize_seq(Some(self.entries.len()))?; - for entry in &self.entries { - seq.serialize_element(entry)?; + let mut seq = serializer.serialize_seq(Some(self.map.len()))?; + for (key, value) in self.map.iter() { + seq.serialize_element(&DictEntry { key, value })?; } seq.end() } } -// Conversion of Dict to HashMap -impl<'k, 'v, K, V, H> TryFrom> for HashMap -where - K: Basic + TryFrom> + std::hash::Hash + std::cmp::Eq, - V: TryFrom>, - H: BuildHasher + Default, - K::Error: Into, - V::Error: Into, -{ - type Error = Error; - - fn try_from(v: Dict<'k, 'v>) -> Result { - let mut map = HashMap::default(); - for e in v.entries.into_iter() { - let key = if let Value::Value(v) = e.key { - K::try_from(*v) - } else { - K::try_from(e.key) - } - .map_err(Into::into)?; - - let value = if let Value::Value(v) = e.value { - V::try_from(*v) - } else { - V::try_from(e.value) +// Conversion of Dict to Map types +macro_rules! from_dict { + ($ty:ident ) => { + impl<'k, 'v, K, V $(, $typaram)*> TryFrom> for $ty + where + K: Basic + TryFrom> $(+ $kbound1 $(+ $kbound2)*)*, + V: TryFrom>, + K::Error: Into, + V::Error: Into, + $($typaram: BuildHasher + Default,)* + { + type Error = Error; + + fn try_from(v: Dict<'k, 'v>) -> Result { + v.map.into_iter().map(|(key, value)| { + let key = if let Value::Value(v) = key { + K::try_from(*v) + } else { + K::try_from(key) + } + .map_err(Into::into)?; + + let value = if let Value::Value(v) = value { + V::try_from(*v) + } else { + V::try_from(value) + } + .map_err(Into::into)?; + + Ok((key, value)) + }).collect::>() } - .map_err(Into::into)?; - - map.insert(key, value); } - Ok(map) - } + }; } +from_dict!(HashMap); +from_dict!(BTreeMap); // TODO: this could be useful // impl<'d, 'k, 'v, K, V, H> TryFrom<&'d Dict<'k, 'v>> for HashMap<&'k K, &'v V, H> // Conversion of Hashmap to Dict -impl<'k, 'v, K, V, H> From> for Dict<'k, 'v> -where - K: Type + Into> + std::hash::Hash + std::cmp::Eq, - V: Type + Into>, - H: BuildHasher + Default, -{ - fn from(value: HashMap) -> Self { - let entries = value - .into_iter() - .map(|(key, value)| DictEntry { - key: Value::new(key), - value: Value::new(value), - }) - .collect(); - let key_signature = K::signature(); - let value_signature = V::signature(); - let signature = create_signature(&key_signature, &value_signature); - - Self { - entries, - key_signature, - value_signature, - signature, +macro_rules! to_dict { + ($ty:ident ) => { + impl<'k, 'v, K, V $(, $typaram)*> From<$ty> for Dict<'k, 'v> + where + K: Type + Into>, + V: Type + Into>, + $($typaram: BuildHasher,)* + { + fn from(value: $ty) -> Self { + let entries = value + .into_iter() + .map(|(key, value)| (Value::new(key), Value::new(value))) + .collect(); + let key_signature = K::signature(); + let value_signature = V::signature(); + let signature = create_signature(&key_signature, &value_signature); + + Self { + map: entries, + key_signature, + value_signature, + signature, + } + } } - } -} - -// TODO: Conversion of Dict from/to BTreeMap - -#[derive(Debug, Hash, PartialOrd, Ord, PartialEq, Eq)] -struct DictEntry<'k, 'v> { - key: Value<'k>, - value: Value<'v>, + }; } +to_dict!(HashMap); +to_dict!(BTreeMap); -impl<'k, 'v> DictEntry<'k, 'v> { - fn try_to_owned(&self) -> crate::Result> { - Ok(DictEntry { - key: self.key.try_to_owned().map(Into::into)?, - value: self.value.try_to_owned().map(Into::into)?, - }) - } - - fn try_clone(&self) -> Result { - Ok(Self { - key: self.key.try_clone()?, - value: self.value.try_clone()?, - }) - } +#[derive(Debug)] +struct DictEntry<'kref, 'k, 'vref, 'v> { + key: &'kref Value<'k>, + value: &'vref Value<'v>, } -impl<'k, 'v> Serialize for DictEntry<'k, 'v> { +impl Serialize for DictEntry<'_, '_, '_, '_> { fn serialize(&self, serializer: S) -> Result where S: Serializer, diff --git a/zvariant/src/from_value.rs b/zvariant/src/from_value.rs index e55fc109a..46093a341 100644 --- a/zvariant/src/from_value.rs +++ b/zvariant/src/from_value.rs @@ -28,10 +28,10 @@ macro_rules! value_try_from { macro_rules! value_try_from_ref { ($kind:ident, $to:ty) => { - impl<'a> TryFrom<&'a Value<'a>> for &'a $to { + impl<'a> TryFrom<&'a Value<'_>> for &'a $to { type Error = Error; - fn try_from(value: &'a Value<'a>) -> Result { + fn try_from(value: &'a Value<'_>) -> Result { if let Value::$kind(value) = value { Ok(value) } else { @@ -44,10 +44,10 @@ macro_rules! value_try_from_ref { macro_rules! value_try_from_ref_clone { ($kind:ident, $to:ty) => { - impl<'a> TryFrom<&'a Value<'a>> for $to { + impl<'a> TryFrom<&Value<'a>> for $to { type Error = Error; - fn try_from(value: &'a Value<'_>) -> Result { + fn try_from(value: &Value<'a>) -> Result { if let Value::$kind(value) = value { Ok(value.clone().into()) } else { @@ -84,10 +84,10 @@ value_try_from_ref!(Str, str); macro_rules! value_try_from_ref_try_clone { ($kind:ident, $to:ty) => { - impl<'a> TryFrom<&'a Value<'a>> for $to { + impl<'a> TryFrom<&Value<'a>> for $to { type Error = Error; - fn try_from(value: &'a Value<'_>) -> Result { + fn try_from(value: &Value<'a>) -> Result { if let Value::$kind(value) = value { value.try_clone().map_err(Into::into) } else { @@ -124,10 +124,10 @@ value_try_from_ref!(Fd, Fd<'a>); #[cfg(unix)] value_try_from_ref_try_clone!(Fd, Fd<'a>); -impl<'a> TryFrom<&'a Value<'a>> for String { +impl TryFrom<&Value<'_>> for String { type Error = Error; - fn try_from(value: &'a Value<'_>) -> Result { + fn try_from(value: &Value<'_>) -> Result { Ok(<&str>::try_from(value)?.into()) } } diff --git a/zvariant/src/lib.rs b/zvariant/src/lib.rs index 4eaf33185..c771fd4aa 100644 --- a/zvariant/src/lib.rs +++ b/zvariant/src/lib.rs @@ -116,7 +116,7 @@ pub mod export { #[allow(clippy::disallowed_names)] mod tests { use std::{ - collections::HashMap, + collections::{BTreeMap, HashMap}, net::{IpAddr, Ipv4Addr, Ipv6Addr}, }; @@ -684,8 +684,8 @@ mod tests { if let Value::Array(array) = v { assert_eq!(*array.element_signature(), "y"); assert_eq!(array.len(), 2); - assert_eq!(array.get()[0], Value::U8(77)); - assert_eq!(array.get()[1], Value::U8(88)); + assert_eq!(array.get(0).unwrap(), Some(77u8)); + assert_eq!(array.get(1).unwrap(), Some(88u8)); } else { panic!(); } @@ -781,8 +781,8 @@ mod tests { if let Value::Array(array) = v { assert_eq!(*array.element_signature(), "s"); assert_eq!(array.len(), 4); - assert_eq!(array.get()[0], Value::new("Hello")); - assert_eq!(array.get()[1], Value::new("World")); + assert_eq!(array[0], Value::new("Hello")); + assert_eq!(array[1], Value::new("World")); } else { panic!(); } @@ -888,7 +888,7 @@ mod tests { if let Value::Array(array) = v.try_clone().unwrap() { assert_eq!(*array.element_signature(), "(yu(xbxas)s)"); assert_eq!(array.len(), 1); - let r = &array.get()[0]; + let r = &array[0]; if let Value::Structure(r) = r { let fields = r.fields(); assert_eq!(fields[0], Value::U8(u8::max_value())); @@ -900,8 +900,8 @@ mod tests { assert_eq!(fields[2], Value::I64(i64::max_value())); if let Value::Array(as_) = &fields[3] { assert_eq!(as_.len(), 2); - assert_eq!(as_.get()[0], Value::new("Hello")); - assert_eq!(as_.get()[1], Value::new("World")); + assert_eq!(as_[0], Value::new("Hello")); + assert_eq!(as_[1], Value::new("World")); } else { panic!(); } @@ -928,7 +928,7 @@ mod tests { if let Value::Array(array) = v { assert_eq!(*array.element_signature(), "(yu(xbxas)s)"); assert_eq!(array.len(), 1); - let r = &array.get()[0]; + let r = &array.get(0).unwrap().unwrap(); if let Value::Structure(r) = r { let fields = r.fields(); assert_eq!(fields[0], Value::U8(u8::max_value())); @@ -940,8 +940,8 @@ mod tests { assert_eq!(fields[2], Value::I64(i64::max_value())); if let Value::Array(as_) = &fields[3] { assert_eq!(as_.len(), 2); - assert_eq!(as_.get()[0], Value::new("Hello")); - assert_eq!(as_.get()[1], Value::new("World")); + assert_eq!(as_.get(0).unwrap(), Some("Hello")); + assert_eq!(as_.get(1).unwrap(), Some("World")); } else { panic!(); } @@ -1132,17 +1132,21 @@ mod tests { assert_eq!(encoded.len(), 48); // Convert it back let dict: Dict<'_, '_> = v.try_into().unwrap(); - let map: HashMap = dict.try_into().unwrap(); + let map: HashMap = dict.try_clone().unwrap().try_into().unwrap(); assert_eq!(map[&1], "123"); assert_eq!(map[&2], "456"); // Also decode it back let v = encoded.deserialize().unwrap().0; if let Value::Dict(dict) = v { - assert_eq!(dict.get::(&1).unwrap().unwrap(), "123"); - assert_eq!(dict.get::(&2).unwrap().unwrap(), "456"); + assert_eq!(dict.get::(&1).unwrap().unwrap(), "123"); + assert_eq!(dict.get::(&2).unwrap().unwrap(), "456"); } else { panic!(); } + // Convert it to a BTreeMap too. + let map: BTreeMap = dict.try_into().unwrap(); + assert_eq!(map[&1], "123"); + assert_eq!(map[&2], "456"); #[cfg(feature = "gvariant")] { @@ -1186,16 +1190,21 @@ mod tests { let v: Value<'_> = encoded.deserialize().unwrap().0; if let Value::Dict(dict) = v { assert_eq!( - *dict.get::<_, Value<'_>>("hello").unwrap().unwrap(), + dict.get::<&str, Value<'_>>(&"hello").unwrap().unwrap(), Value::new("there") ); assert_eq!( - *dict.get::<_, Value<'_>>("bye").unwrap().unwrap(), + dict.get::<_, Value<'_>>(&"bye").unwrap().unwrap(), Value::new("now") ); // Try converting to a HashMap - let map = >>::try_from(dict).unwrap(); + let map = >>::try_from(dict.try_clone().unwrap()).unwrap(); + assert_eq!(map["hello"], Value::new("there")); + assert_eq!(map["bye"], Value::new("now")); + + // Try converting to a BTreeMap + let map = >>::try_from(dict).unwrap(); assert_eq!(map["hello"], Value::new("there")); assert_eq!(map["bye"], Value::new("now")); } else { @@ -1688,10 +1697,7 @@ mod tests { Value::Maybe(maybe) => assert_eq!(maybe.get().unwrap(), mn), #[cfg(feature = "option-as-array")] Value::Array(array) => { - assert_eq!( - i16::try_from(array.get()[0].try_clone().unwrap()).unwrap(), - 16i16 - ) + assert_eq!(i16::try_from(array[0].try_clone().unwrap()).unwrap(), 16i16) } _ => panic!("unexpected value {decoded:?}"), } @@ -1750,7 +1756,7 @@ mod tests { match &v { Value::Array(array) => { assert_eq!( - String::try_from(array.get()[0].try_clone().unwrap()).unwrap(), + String::try_from(array[0].try_clone().unwrap()).unwrap(), ms.unwrap() ) } @@ -1771,7 +1777,7 @@ mod tests { #[cfg(feature = "option-as-array")] Value::Array(array) => { assert_eq!( - String::try_from(array.get()[0].try_clone().unwrap()).unwrap(), + String::try_from(array[0].try_clone().unwrap()).unwrap(), ms.unwrap() ) } diff --git a/zvariant/src/maybe.rs b/zvariant/src/maybe.rs index 54dbd1401..1bbc4942d 100644 --- a/zvariant/src/maybe.rs +++ b/zvariant/src/maybe.rs @@ -65,12 +65,15 @@ impl<'a> Maybe<'a> { } /// Get the inner value as a concrete type - pub fn get(self) -> core::result::Result, Error> + pub fn get(&'a self) -> core::result::Result, Error> where - T: TryFrom>, + T: ?Sized + TryFrom<&'a Value<'a>>, + >>::Error: Into, { self.value - .map(|v| v.downcast().ok_or(Error::IncorrectType)) + .as_ref() + .as_ref() + .map(|v| v.downcast_ref()) .transpose() } diff --git a/zvariant/src/signature.rs b/zvariant/src/signature.rs index 9371d96e9..8d965536c 100644 --- a/zvariant/src/signature.rs +++ b/zvariant/src/signature.rs @@ -363,8 +363,8 @@ impl<'a> Type for Signature<'a> { } } -impl<'a, 'b> From<&'b Signature<'a>> for Signature<'a> { - fn from(signature: &'b Signature<'a>) -> Signature<'a> { +impl<'a> From<&Signature<'a>> for Signature<'a> { + fn from(signature: &Signature<'a>) -> Signature<'a> { signature.clone() } } diff --git a/zvariant/src/str.rs b/zvariant/src/str.rs index 916e1fe1b..7d01add72 100644 --- a/zvariant/src/str.rs +++ b/zvariant/src/str.rs @@ -179,8 +179,8 @@ impl<'a> From> for String { } } -impl<'a> From<&'a Str<'a>> for &'a str { - fn from(value: &'a Str<'a>) -> &'a str { +impl<'a> From<&'a Str<'_>> for &'a str { + fn from(value: &'a Str<'_>) -> &'a str { value.as_str() } } diff --git a/zvariant/src/value.rs b/zvariant/src/value.rs index f58453265..f9062f12a 100644 --- a/zvariant/src/value.rs +++ b/zvariant/src/value.rs @@ -356,15 +356,16 @@ impl<'a> Value<'a> { /// # Examples /// /// ``` - /// use zvariant::{Result, Value}; + /// use zvariant::{Error, Result, Value}; /// /// fn value_vec_to_type_vec<'a, T>(values: Vec>) -> Result> /// where /// T: TryFrom>, + /// >>::Error: Into, /// { /// let mut res = vec![]; /// for value in values.into_iter() { - /// res.push(value.downcast().unwrap()); + /// res.push(value.downcast()?); /// } /// /// Ok(res) @@ -386,34 +387,37 @@ impl<'a> Value<'a> { /// [`Value::Value`]: enum.Value.html#variant.Value /// [`TryFrom`]: https://doc.rust-lang.org/std/convert/trait.TryFrom.html /// [`From`]: https://doc.rust-lang.org/std/convert/trait.From.html - pub fn downcast(self) -> Option + pub fn downcast(self) -> Result where T: TryFrom>, + >>::Error: Into, { if let Value::Value(v) = self { - T::try_from(*v).ok() + T::try_from(*v) } else { - T::try_from(self).ok() + T::try_from(self) } + .map_err(Into::into) } - /// Try to get a reference to the underlying type `T`. + /// Try to get the underlying type `T`. /// - /// Same as [`downcast`] except it doesn't consume `self` and get a reference to the underlying - /// value. + /// Same as [`downcast`] except it doesn't consume `self` and hence requires + /// `T: TryFrom<&Value<_>>`. /// /// # Examples /// /// ``` - /// use zvariant::{Result, Value}; + /// use zvariant::{Error, Result, Value}; /// /// fn value_vec_to_type_vec<'a, T>(values: &'a Vec>) -> Result> /// where /// &'a T: TryFrom<&'a Value<'a>>, + /// <&'a T as TryFrom<&'a Value<'a>>>::Error: Into, /// { /// let mut res = vec![]; /// for value in values.into_iter() { - /// res.push(value.downcast_ref().unwrap()); + /// res.push(value.downcast_ref()?); /// } /// /// Ok(res) @@ -433,16 +437,17 @@ impl<'a> Value<'a> { /// ``` /// /// [`downcast`]: enum.Value.html#method.downcast - pub fn downcast_ref(&'a self) -> Option<&'a T> + pub fn downcast_ref(&'a self) -> Result where - T: ?Sized, - &'a T: TryFrom<&'a Value<'a>>, + T: ?Sized + TryFrom<&'a Value<'a>>, + >>::Error: Into, { if let Value::Value(v) = self { - <&T>::try_from(v).ok() + ::try_from(v) } else { - <&T>::try_from(self).ok() + ::try_from(self) } + .map_err(Into::into) } } @@ -927,6 +932,14 @@ impl<'a> Type for Value<'a> { } } +impl<'a> TryFrom<&Value<'a>> for Value<'a> { + type Error = crate::Error; + + fn try_from(value: &Value<'a>) -> crate::Result> { + value.try_clone() + } +} + #[cfg(test)] mod tests { use std::collections::HashMap; diff --git a/zvariant_derive/src/value.rs b/zvariant_derive/src/value.rs index dffe22456..b95717c15 100644 --- a/zvariant_derive/src/value.rs +++ b/zvariant_derive/src/value.rs @@ -101,7 +101,8 @@ fn impl_struct( Some(quote! { where #( - #type_params: ::std::convert::TryFrom<#zv::Value<#value_lifetime>> + #zv::Type + #type_params: ::std::convert::TryFrom<#zv::Value<#value_lifetime>> + #zv::Type, + <#type_params as ::std::convert::TryFrom<#zv::Value<#value_lifetime>>>::Error: ::std::convert::Into<#zv::Error> ),* }), Some(quote! { @@ -134,8 +135,7 @@ fn impl_struct( fields .remove(stringify!(#field_names)) .ok_or_else(|| #zv::Error::IncorrectType)? - .downcast() - .ok_or_else(|| #zv::Error::IncorrectType)? + .downcast()? ),* }) }, @@ -155,11 +155,7 @@ fn impl_struct( ::std::result::Result::Ok(Self { #( - #field_names: - fields - .remove(0) - .downcast() - .ok_or_else(|| #zv::Error::IncorrectType)? + #field_names: fields.remove(0).downcast()? ),* }) },