Skip to content

Commit

Permalink
Merge pull request #23 from Hoverbear/with_prefix
Browse files Browse the repository at this point in the history
Add with_prefix option for getters
  • Loading branch information
Hoverbear authored Mar 7, 2019
2 parents 7b00ca8 + 4ad017b commit 262e842
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 12 deletions.
10 changes: 8 additions & 2 deletions src/generate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,18 @@ pub fn implement(field: &Field, mode: GenMode, params: GenParams) -> TokenStream
}
}
},
// `#[get = "pub"]` or `#[set = "pub"]`
// `#[get = "pub with_prefix"]` or `#[set = "pub"]`
Some(Meta::NameValue(MetaNameValue {
lit: Lit::Str(ref s),
..
})) => {
let visibility = Ident::new(&s.value(), s.span());
let tokens = s.value();
let visibility =
if let Some(t) = tokens.split(" ").find(|v| *v != "with_prefix") {
Some(Ident::new(&t, s.span()))
} else {
None
};
match mode {
GenMode::Get => {
quote! {
Expand Down
67 changes: 61 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ Getset, we're ready to go!
A procedural macro for generating the most basic getters and setters on fields.
Getters are generated as `fn field(&self) -> &type`, while setters are generated as `fn field(&mut self, val: type)`.
Getters are generated as `fn field(&self) -> &type`, while setters are generated
as `fn field(&mut self, val: type)`.
These macros are not intended to be used on fields which require custom logic inside of their setters and getters. Just write your own in that case!
These macros are not intended to be used on fields which require custom logic
inside of their setters and getters. Just write your own in that case!
```rust
#[macro_use]
Expand All @@ -31,6 +33,26 @@ fn main() {
assert_eq!(*foo.private(), 2);
}
```
For some purposes, it's useful to have the `get_` prefix on the getters for
either legacy of compatability reasons. It is done with `get-prefix`.
```rust
#[macro_use]
extern crate getset;
#[derive(Getters, Default)]
pub struct Foo {
#[get = "pub with_prefix"]
field: bool,
}
fn main() {
let mut foo = Foo::default();
let val = foo.get_field();
}
```
*/

extern crate proc_macro;
Expand All @@ -41,24 +63,55 @@ extern crate proc_macro2;

use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use syn::{DataStruct, DeriveInput, Field};
use syn::{Attribute, DataStruct, DeriveInput, Field, Ident, Lit, Meta};

mod generate;
use generate::{GenMode, GenParams};

#[proc_macro_derive(Getters, attributes(get))]
fn attr_name(attr: &Attribute) -> Option<Ident> {
attr.interpret_meta().map(|v| v.name())
}

/// Some users want legacy/compatability.
/// (Getters are often prefixed with `get_`)
fn has_prefix_attr(f: &Field) -> bool {
let inner = f
.attrs
.iter()
.filter(|v| attr_name(v).expect("Could not get attribute") == "get")
.last()
.and_then(|v| v.parse_meta().ok());
match inner {
Some(Meta::NameValue(meta)) => {
if let Lit::Str(lit) = meta.lit {
// Naive tokenization to avoid a possible visibility mod named `with_prefix`.
lit.value()
.split(" ")
.find(|v| *v == "with_prefix")
.is_some()
} else {
false
}
}
_ => false,
}
}

#[proc_macro_derive(Getters, attributes(get, with_prefix))]
pub fn getters(input: TokenStream) -> TokenStream {
// Parse the string representation
let ast = syn::parse(input).expect("Couldn't parse for getters");

// Build the impl
let gen = produce(&ast, |f| {
let prefix = if has_prefix_attr(f) { "get_" } else { "" };

generate::implement(
f,
GenMode::Get,
GenParams {
attribute_name: "get",
fn_name_prefix: "",
fn_name_prefix: prefix,
fn_name_suffix: "",
},
)
Expand All @@ -74,12 +127,14 @@ pub fn mut_getters(input: TokenStream) -> TokenStream {
let ast = syn::parse(input).expect("Couldn't parse for getters");
// Build the impl
let gen = produce(&ast, |f| {
let prefix = if has_prefix_attr(f) { "get_" } else { "" };

generate::implement(
f,
GenMode::GetMut,
GenParams {
attribute_name: "get_mut",
fn_name_prefix: "",
fn_name_prefix: prefix,
fn_name_suffix: "_mut",
},
)
Expand Down
31 changes: 27 additions & 4 deletions tests/getters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use submodule::other::{Generic, Plain, Where};

// For testing `pub(super)`
mod submodule {
// For testing `pub(in super::other)`
// For testing `pub(super::other)`
pub mod other {
#[derive(Getters)]
pub struct Plain {
Expand All @@ -26,15 +26,25 @@ mod submodule {
// super_accessible: usize,

// /// A doc comment.
// #[get = "pub(in super::other)"]
// #[get = "pub(super::other)"]
// scope_accessible: usize,

// Prefixed getter.
#[get = "with_prefix"]
private_prefixed: usize,

// Prefixed getter.
#[get = "pub with_prefix"]
public_prefixed: usize,
}

impl Default for Plain {
fn default() -> Plain {
Plain {
private_accessible: 17,
public_accessible: 18,
private_prefixed: 19,
public_prefixed: 20,
}
}
}
Expand All @@ -58,7 +68,7 @@ mod submodule {
// super_accessible: usize,

// /// A doc comment.
// #[get = "pub(in super::other)"]
// #[get = "pub(super::other)"]
// scope_accessible: usize,
}

Expand All @@ -84,7 +94,7 @@ mod submodule {
// super_accessible: usize,

// /// A doc comment.
// #[get = "pub(in super::other)"]
// #[get = "pub(super::other)"]
// scope_accessible: usize,
}

Expand All @@ -105,6 +115,13 @@ mod submodule {
let val = Where::<usize>::default();
val.private_accessible();
}

#[test]
fn test_prefixed_plain() {
let val = Plain::default();
assert_eq!(19, *val.get_private_prefixed());
}

}
}

Expand All @@ -125,3 +142,9 @@ fn test_where() {
let val = Where::<usize>::default();
assert_eq!(usize::default(), *val.public_accessible());
}

#[test]
fn test_prefixed_plain() {
let val = Plain::default();
assert_eq!(20, *val.get_public_prefixed());
}

0 comments on commit 262e842

Please sign in to comment.