Skip to content

Commit

Permalink
Add fluent setters, that can be used for chaining setters, like in mo…
Browse files Browse the repository at this point in the history
…dern Rust
  • Loading branch information
GamePad64 committed Mar 30, 2022
1 parent e540fd4 commit 1d73c9a
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 4 deletions.
19 changes: 16 additions & 3 deletions src/generate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub enum GenMode {
GetCopy,
Set,
GetMut,
SetFluent
}

impl GenMode {
Expand All @@ -26,27 +27,28 @@ impl GenMode {
GetCopy => "get_copy",
Set => "set",
GetMut => "get_mut",
SetFluent => "set_fluent"
}
}

pub fn prefix(self) -> &'static str {
match self {
Get | GetCopy | GetMut => "",
Set => "set_",
Set | SetFluent => "set_",
}
}

pub fn suffix(self) -> &'static str {
match self {
Get | GetCopy | Set => "",
Get | GetCopy | Set | SetFluent => "",
GetMut => "_mut",
}
}

fn is_get(self) -> bool {
match self {
GenMode::Get | GenMode::GetCopy | GenMode::GetMut => true,
GenMode::Set => false,
GenMode::Set | SetFluent => false,
}
}
}
Expand Down Expand Up @@ -191,6 +193,17 @@ pub fn implement(field: &Field, params: &GenParams) -> TokenStream2 {
}
}
}
GenMode::SetFluent => {
quote! {
#(#doc)*
#[inline(always)]
#visibility fn #fn_name(self, val: #ty) -> Self {
let mut moved_out = self;
moved_out.#field_name = val;
moved_out
}
}
}
},
// Don't need to do anything.
None => quote! {},
Expand Down
17 changes: 17 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,23 @@ pub fn setters(input: TokenStream) -> TokenStream {
gen.into()
}

#[proc_macro_derive(FluentSetters, attributes(set_fluent, getset))]
#[proc_macro_error]
pub fn fluent_setters(input: TokenStream) -> TokenStream {
// Parse the string representation
let ast: DeriveInput = syn::parse(input).expect_or_abort("Couldn't parse for setters");
let params = GenParams {
mode: GenMode::SetFluent,
global_attr: parse_global_attr(&ast.attrs, GenMode::SetFluent),
};

// Build the impl
let gen = produce(&ast, &params);

// Return the generated impl
gen.into()
}

fn parse_global_attr(attrs: &[syn::Attribute], mode: GenMode) -> Option<Meta> {
attrs
.iter()
Expand Down
129 changes: 129 additions & 0 deletions tests/fluent_setters.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#[macro_use]
extern crate getset;

use crate::submodule::other::{Generic, Plain, Where};

// For testing `pub(super)`
mod submodule {
// For testing `pub(in super::other)`
pub mod other {
#[derive(FluentSetters, Default)]
#[set_fluent]
pub struct Plain {
/// A doc comment.
/// Multiple lines, even.
private_accessible: usize,

/// A doc comment.
#[set_fluent = "pub"]
public_accessible: usize,

/// This field is used for testing chaining.
#[set_fluent = "pub"]
second_public_accessible: bool,
// /// A doc comment.
// #[set_fluent = "pub(crate)"]
// crate_accessible: usize,

// /// A doc comment.
// #[set_fluent = "pub(super)"]
// super_accessible: usize,

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

#[derive(FluentSetters, Default)]
#[set_fluent]
pub struct Generic<T: Copy + Clone + Default> {
/// A doc comment.
/// Multiple lines, even.
private_accessible: T,

/// A doc comment.
#[set_fluent = "pub"]
public_accessible: T,
// /// A doc comment.
// #[set_fluent = "pub(crate)"]
// crate_accessible: usize,

// /// A doc comment.
// #[set_fluent = "pub(super)"]
// super_accessible: usize,

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

#[derive(FluentSetters, Default)]
#[set_fluent]
pub struct Where<T>
where
T: Copy + Clone + Default,
{
/// A doc comment.
/// Multiple lines, even.
private_accessible: T,

/// A doc comment.
#[set_fluent = "pub"]
public_accessible: T,
// /// A doc comment.
// #[set_fluent = "pub(crate)"]
// crate_accessible: usize,

// /// A doc comment.
// #[set_fluent = "pub(super)"]
// super_accessible: usize,

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

#[test]
fn test_plain() {
let mut val = Plain::default();
val.set_private_accessible(1);
}

#[test]
fn test_generic() {
let mut val = Generic::default();
val.set_private_accessible(1);
}

#[test]
fn test_where() {
let mut val = Where::default();
val.set_private_accessible(1);
}
}
}

#[test]
fn test_plain() {
let mut val = Plain::default();
val.set_public_accessible(1);
}

#[test]
fn test_generic() {
let mut val = Generic::default();
val.set_public_accessible(1);
}

#[test]
fn test_where() {
let mut val = Where::default();
val.set_public_accessible(1);
}

#[test]
fn test_chaining() {
let mut val = Plain::default();
val.set_public_accessible(1)
.set_second_public_accessible(true);
}
10 changes: 9 additions & 1 deletion tests/raw_identifiers.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#[macro_use]
extern crate getset;

#[derive(CopyGetters, Default, Getters, MutGetters, Setters)]
#[derive(CopyGetters, Default, Getters, MutGetters, Setters, FluentSetters)]
struct RawIdentifiers {
#[get]
r#type: usize,
Expand All @@ -15,6 +15,8 @@ struct RawIdentifiers {
r#const: usize,
#[get_copy = "with_prefix"]
r#if: usize,
#[set_fluent]
r#else: usize,
// Ensure having no gen mode doesn't break things.
#[allow(dead_code)]
r#loop: usize,
Expand Down Expand Up @@ -55,3 +57,9 @@ fn test_get_copy_with_prefix() {
let val = RawIdentifiers::default();
let _ = val.get_if();
}

#[test]
fn test_set_fluent() {
let mut val = RawIdentifiers::default();
let _ = val.set_else(42);
}

0 comments on commit 1d73c9a

Please sign in to comment.