Skip to content

Commit

Permalink
Merge pull request #98 from jason-hchsieh/feat-unary-struct
Browse files Browse the repository at this point in the history
Unary tuple struct getter/setter
  • Loading branch information
jbaublitz authored Jan 19, 2025
2 parents ad3b221 + 3aa7fbd commit bf93ed0
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 4 deletions.
61 changes: 61 additions & 0 deletions src/generate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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! {},
}
}
46 changes: 42 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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 {
Expand Down
39 changes: 39 additions & 0 deletions tests/unary_tuple.rs
Original file line number Diff line number Diff line change
@@ -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);
}

0 comments on commit bf93ed0

Please sign in to comment.