diff --git a/ambassador/src/delegate_shared.rs b/ambassador/src/delegate_shared.rs index 056f754..3742196 100644 --- a/ambassador/src/delegate_shared.rs +++ b/ambassador/src/delegate_shared.rs @@ -1,4 +1,4 @@ -use crate::util::{error, process_results}; +use crate::util::error; use itertools::Itertools; use proc_macro2::{Ident, TokenStream as TokenStream2}; use quote::ToTokens; @@ -101,8 +101,8 @@ pub(super) fn delegate_macro( } let iter = delegate_attributes.map(|attr| delegate_single(input, attr)); - let res = process_results(iter, |iter| iter.flatten().collect()); - res.unwrap_or_else(|x| x.to_compile_error()) + iter.flat_map(|x| x.unwrap_or_else(|err| err.to_compile_error())) + .collect() } pub(super) fn trait_info(trait_path_full: &syn::Path) -> Result<(&Ident, impl ToTokens + '_)> { diff --git a/ambassador/src/derive.rs b/ambassador/src/derive.rs index bb70514..3a01c0b 100644 --- a/ambassador/src/derive.rs +++ b/ambassador/src/derive.rs @@ -126,18 +126,22 @@ impl delegate_shared::DelegateTarget for DelegateTarget { type DelegateArgs = delegate_shared::DelegateArgs; +fn unknown_field(target: &syn::Member) -> Result { + error!( + target.span(), + "Unknown field specified as \"target\" value in #[delegate] attribute" + ) +} + /// Select the correct field_ident based on the `target`. -pub fn get_field<'a>( +fn get_field<'a>( target: &syn::Member, field_idents: &'a [(syn::Member, syn::Type)], ) -> Result<&'a (syn::Member, syn::Type)> { let field = field_idents.iter().find(|n| n.0 == *target); match field { Some(field) => Ok(field), - None => error!( - target.span(), - "Unknown field specified as \"target\" value in #[delegate] attribute" - ), + None => unknown_field(target), } } @@ -207,11 +211,13 @@ fn delegate_single_attr( } } } - (Field(field), SingleFieldStruct {..}) => return error!( - field.span(), - "\"target\" value on #[delegate] attribute can not be specified for structs with a single field" - ), - (TrgNone, SingleFieldStruct {field_ident, field_type}) => { + (trg, SingleFieldStruct {field_ident, field_type}) => { + match trg { + Field(f) if f != field_ident => { + unknown_field(f)?; + } + _ => {} + } if !args.inhibit_automatic_where_clause { add_auto_where_clause(&mut where_clause, &trait_path_full, field_type); } diff --git a/ambassador/src/lib.rs b/ambassador/src/lib.rs index e9f2ba7..3012cd5 100644 --- a/ambassador/src/lib.rs +++ b/ambassador/src/lib.rs @@ -780,8 +780,5 @@ pub fn delegatable_trait_remote(_attr: TokenStream, item: TokenStream) -> TokenS let original_item: syn::ItemTrait = syn::parse(item).unwrap(); let register_trait = build_register_trait(&original_item); - let expanded = quote! { - #register_trait - }; - TokenStream::from(expanded) + TokenStream::from(register_trait) } diff --git a/ambassador/tests/run-pass/struct_single_field_target.rs b/ambassador/tests/run-pass/struct_single_field_target.rs new file mode 100644 index 0000000..bb07c06 --- /dev/null +++ b/ambassador/tests/run-pass/struct_single_field_target.rs @@ -0,0 +1,27 @@ +extern crate ambassador; + +use ambassador::{delegatable_trait, Delegate}; + +#[delegatable_trait] +pub trait Shout { + fn shout(&self, input: &str) -> String; +} + +pub struct Cat; + +impl Shout for Cat { + fn shout(&self, input: &str) -> String { + format!("{} - meow!", input) + } +} + +#[derive(Delegate)] +#[delegate(Shout, target = "inner")] +pub struct WrappedCat { + inner: Cat, +} + +pub fn main() { + let foo_animal = WrappedCat { inner: Cat }; + println!("{}", foo_animal.shout("BAR")); +}