diff --git a/glib-macros/src/value_delegate_derive.rs b/glib-macros/src/value_delegate_derive.rs index a37be46c2d5f..f151fe99a37d 100644 --- a/glib-macros/src/value_delegate_derive.rs +++ b/glib-macros/src/value_delegate_derive.rs @@ -123,7 +123,9 @@ pub fn impl_value_delegate(input: ValueDelegateInput) -> syn::Result quote!(#delegated_ty::from(this)), + DeriveMode::From => { + quote!(<#delegated_ty as std::convert::From<_>>::from(this)) + } DeriveMode::Private => quote!(this.0), }; @@ -132,7 +134,7 @@ pub fn impl_value_delegate(input: ValueDelegateInput) -> syn::Result) -> #crate_ident::value::Value { if let Some(this) = s { - Some(&#delegate_value).to_value() + #crate_ident::value::ToValue::to_value(&Some(&#delegate_value)) } else { #crate_ident::value::ToValueOptional::to_value_optional(None::<&#delegated_ty>) } @@ -142,24 +144,28 @@ pub fn impl_value_delegate(input: ValueDelegateInput) -> syn::Result quote!(#ident::from(#delegated_ty::from_value(value))), - DeriveMode::Private => quote!(#ident(#delegated_ty::from_value(value))), + DeriveMode::From => { + quote!(#ident::from(<#delegated_ty as #crate_ident::value::FromValue<'a>>::from_value(value))) + } + DeriveMode::Private => { + quote!(#ident(<#delegated_ty as #crate_ident::value::FromValue<'a>>::from_value(value))) + } }; let res = quote! { impl #crate_ident::types::StaticType for #ident { fn static_type() -> glib::types::Type { - #delegated_ty::static_type() + <#delegated_ty as #crate_ident::types::StaticType>::static_type() } } impl #crate_ident::value::ToValue for #ident { fn to_value(&self) -> #crate_ident::value::Value { let this = self; - #delegate_value.to_value() + #crate_ident::value::ToValue::to_value(&#delegate_value) } fn value_type(&self) -> #crate_ident::types::Type { let this = self; - #delegate_value.value_type() + #crate_ident::value::ToValue::value_type(&#delegate_value) } } @@ -179,7 +185,7 @@ pub fn impl_value_delegate(input: ValueDelegateInput) -> syn::Result::BuilderFn; fn param_spec_builder() -> Self::BuilderFn { - #delegated_ty::param_spec_builder() + <#delegated_ty as #crate_ident::HasParamSpec>::param_spec_builder() } } }; diff --git a/glib-macros/tests/value_delegate_derive.rs b/glib-macros/tests/value_delegate_derive.rs new file mode 100644 index 000000000000..22d28190b915 --- /dev/null +++ b/glib-macros/tests/value_delegate_derive.rs @@ -0,0 +1,73 @@ +use glib::{value::FromValue, HasParamSpec, StaticType, ToValue}; + +#[test] +fn higher_level_types() { + #[derive(Debug, glib::ValueDelegate)] + pub struct MyVec(Vec); + + #[derive(Debug, glib::ValueDelegate)] + #[value_delegate(from = Option)] + struct MyVecManualFrom(Vec); + + impl From> for MyVecManualFrom { + fn from(v: Option) -> Self { + Self(v.into_iter().collect::>()) + } + } + impl<'a> From<&'a MyVecManualFrom> for Option { + fn from(v: &'a MyVecManualFrom) -> Self { + v.0.iter().next().cloned() + } + } + + let vec = vec!["foo".to_string(), "bar".to_string()]; + let vec_value = vec.to_value(); + let my_vec_value = MyVec(vec.clone()).to_value(); + + assert_eq!(MyVec::static_type(), Vec::::static_type()); + assert_eq!( + vec_value.get::>().unwrap(), + my_vec_value.get::>().unwrap(), + ); + assert_eq!(vec_value.value_type(), my_vec_value.value_type()); + assert_eq!(unsafe { Vec::::from_value(&vec_value) }, unsafe { + MyVec::from_value(&vec_value).0 + }); + assert_eq!( + unsafe { Vec::::from_value(&my_vec_value) }, + unsafe { MyVec::from_value(&my_vec_value).0 } + ); + + let opt = Some("foo".to_string()); + let opt_value = opt.to_value(); + let my_vec_manual_from_value = MyVecManualFrom::from(opt).to_value(); + + assert_eq!( + MyVecManualFrom::static_type(), + Option::::static_type() + ); + assert_eq!( + opt_value.get::>().unwrap(), + my_vec_manual_from_value.get::>().unwrap(), + ); + assert_eq!( + opt_value.value_type(), + my_vec_manual_from_value.value_type() + ); + assert_eq!( + unsafe { + Option::::from_value(&opt_value) + .into_iter() + .collect::>() + }, + unsafe { MyVecManualFrom::from_value(&opt_value).0 } + ); + assert_eq!( + unsafe { + Option::::from_value(&my_vec_manual_from_value) + .into_iter() + .collect::>() + }, + unsafe { MyVecManualFrom::from_value(&my_vec_manual_from_value).0 } + ); +}