diff --git a/src/generate.rs b/src/generate.rs index 1748e74..db1f28c 100644 --- a/src/generate.rs +++ b/src/generate.rs @@ -201,3 +201,64 @@ pub fn implement(field: &Field, params: &GenParams) -> TokenStream2 { None => quote! {}, } } + +pub fn implement_for_unnamed(field: &Field, params: &GenParams) -> TokenStream2 { + let doc = field.attrs.iter().filter(|v| v.meta.path().is_ident("doc")); + let attr = field + .attrs + .iter() + .filter_map(|v| parse_attr(v, params.mode)) + .last() + .or_else(|| params.global_attr.clone()); + let ty = field.ty.clone(); + let visibility = parse_visibility(attr.as_ref(), params.mode.name()); + + match attr { + // Generate nothing for skipped field + Some(meta) if meta.path().is_ident("skip") => quote! {}, + Some(_) => match params.mode { + GenMode::Get => { + let fn_name = Ident::new("get", Span::call_site()); + quote! { + #(#doc)* + #[inline(always)] + #visibility fn #fn_name(&self) -> &#ty { + &self.0 + } + } + } + GenMode::GetCopy => { + let fn_name = Ident::new("get", Span::call_site()); + quote! { + #(#doc)* + #[inline(always)] + #visibility fn #fn_name(&self) -> #ty { + self.0 + } + } + } + GenMode::Set => { + let fn_name = Ident::new("set", Span::call_site()); + quote! { + #(#doc)* + #[inline(always)] + #visibility fn #fn_name(&mut self, val: #ty) -> &mut Self { + self.0 = val; + self + } + } + } + GenMode::GetMut => { + let fn_name = Ident::new("get_mut", Span::call_site()); + quote! { + #(#doc)* + #[inline(always)] + #visibility fn #fn_name(&mut self) -> &mut #ty { + &mut self.0 + } + } + } + }, + None => quote! {}, + } +} diff --git a/src/lib.rs b/src/lib.rs index d090868..7bca668 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -173,6 +173,28 @@ impl Foo { } } ``` + +For a unary struct (a tuple struct with a single field), +the macro generates the `get`, `get_mut`, and `set` functions to +provide a getter, a mutable getter, and a setter, respectively. + +```rust +use getset::{Getters, MutGetters, CopyGetters, Setters}; + +#[derive(Setters, Getters, MutGetters)] +struct UnaryTuple(#[getset(set, get, get_mut)] i32); + +let mut tup = UnaryTuple(42); +assert_eq!(tup.get(), &42); +assert_eq!(tup.get_mut(), &mut 42); +tup.set(43); +assert_eq!(tup.get(), &43); + +#[derive(CopyGetters)] +struct CopyUnaryTuple(#[getset(get_copy)] i32); + +let tup = CopyUnaryTuple(42); +``` */ #[macro_use] @@ -305,11 +327,27 @@ fn produce(ast: &DeriveInput, params: &GenParams) -> TokenStream2 { // Is it a struct? if let syn::Data::Struct(DataStruct { ref fields, .. }) = ast.data { - let generated = fields.iter().map(|f| generate::implement(f, params)); + // Handle unary struct + if matches!(fields, syn::Fields::Unnamed(_)) { + if fields.len() != 1 { + abort_call_site!("Only support unary struct!"); + } + // This unwrap is safe because we know there is exactly one field + let field = fields.iter().next().unwrap(); + let generated = generate::implement_for_unnamed(field, params); - quote! { - impl #impl_generics #name #ty_generics #where_clause { - #(#generated)* + quote! { + impl #impl_generics #name #ty_generics #where_clause { + #generated + } + } + } else { + let generated = fields.iter().map(|f| generate::implement(f, params)); + + quote! { + impl #impl_generics #name #ty_generics #where_clause { + #(#generated)* + } } } } else { diff --git a/tests/unary_tuple.rs b/tests/unary_tuple.rs new file mode 100644 index 0000000..2c90bd0 --- /dev/null +++ b/tests/unary_tuple.rs @@ -0,0 +1,39 @@ +use getset::{CopyGetters, Getters, MutGetters, Setters}; + +#[test] +fn test_unary_tuple() { + #[derive(Setters, Getters, MutGetters)] + struct UnaryTuple(#[getset(set, get, get_mut)] i32); + + let mut tup = UnaryTuple(42); + assert_eq!(tup.get(), &42); + assert_eq!(tup.get_mut(), &mut 42); + tup.set(43); + assert_eq!(tup.get(), &43); + + #[derive(CopyGetters)] + struct CopyUnaryTuple(#[getset(get_copy)] i32); + + let tup = CopyUnaryTuple(42); + assert_eq!(tup.get(), 42); +} + +#[test] +fn test_unary_tuple_with_attrs() { + #[derive(Setters, Getters, MutGetters)] + #[getset(set, get, get_mut)] + struct UnaryTuple(i32); + + let mut tup = UnaryTuple(42); + assert_eq!(tup.get(), &42); + assert_eq!(tup.get_mut(), &mut 42); + tup.set(43); + assert_eq!(tup.get(), &43); + + #[derive(CopyGetters)] + #[getset(get_copy)] + struct CopyUnaryTuple(i32); + + let tup = CopyUnaryTuple(42); + assert_eq!(tup.get(), 42); +}