basics.rs
Overview
This file defines several Rust structs with automatically generated setter methods using the derive_setters procedural macro. These setters facilitate building and modifying struct instances in a fluent style. The file demonstrates various features of the derive_setters macro including delegate setters, prefix customization, option stripping, type conversion via Into, and boolean flag setters.
The purpose is to showcase and test different setter generation capabilities on simple data structures, enabling ergonomic and concise mutation of fields.
Structs and Their Functionalities
BasicStruct
struct BasicStruct {
a: u32,
b: u32,
c: u32,
}
Purpose: A simple struct with three
u32fields.Setters: Generated using
derive_setterswith custom delegate types.The field
ahas its setter renamed totest.Delegates generate additional setters on other structs targeting
BasicStruct's fields.
Usage:
let s = BasicStruct::default().test(30).b(10).c(20);
assert_eq!(s, BasicStruct { a: 30, b: 10, c: 20 });
Implementation detail: Uses
#[setters(generate_delegates(...))]attributes to generate delegate setter methods on other structs.
BasicDelegateField
struct BasicDelegateField {
x: BasicStruct,
}
Purpose: Wraps
BasicStructin fieldx.Setters: Generated delegate setters that operate on
x's fields (i.e.,BasicStructsetters are exposed onBasicDelegateField).Example:
let d = BasicDelegateField::default().b(15).test(10);
assert_eq!(d, BasicDelegateField { x: BasicStruct { a: 10, b: 15, c: 0 } });
BasicDelegateMethod
struct BasicDelegateMethod {
x: Option<BasicStruct>,
}
Purpose: Holds an optional
BasicStruct.Setters: Delegated setters that call method
get_x()to lazily initialize and return mutable reference toBasicStruct.Method Explanation:
fn get_x(&mut self) -> &mut BasicStruct {
if self.x.is_none() {
self.x = Some(BasicStruct::default());
}
self.x.as_mut().unwrap()
}
This method ensures
xis always initialized before returning mutable reference.Usage:
let d = BasicDelegateMethod::default().b(15).test(10);
assert_eq!(d, BasicDelegateMethod { x: Some(BasicStruct { a: 10, b: 15, c: 0 }) });
PrefixBasicDelegateField
struct PrefixBasicDelegateField {
x: BasicStruct,
}
Purpose: Similar to
BasicDelegateFieldbut delegate setters have prefixwith_(e.g.,with_b,with_test).Setters: Generated with prefix to avoid name clashes.
Example:
let p = PrefixBasicDelegateField::default().with_b(15).with_test(10);
assert_eq!(p, PrefixBasicDelegateField { x: BasicStruct { a: 10, b: 15, c: 0 } });
GenericStruct<'a, T>
struct GenericStruct<'a, T> {
a: Option<&'a T>,
b: Option<&'a T>,
c: T,
}
Purpose: Generic struct with optional references and a value field.
Setters: Generated for all fields.
Usage:
let g = GenericStruct::default().a(Some(&30)).b(Some(&10)).c(20);
assert_eq!(g, GenericStruct { a: Some(&30), b: Some(&10), c: 20 });
This example demonstrates setters for generic structs, including
Optionand reference types.
StripOptionStruct
struct StripOptionStruct {
a: Option<u32>,
b: Option<u32>,
c: Option<u32>,
d: u32,
}
Purpose: Struct with several optional fields.
Setters: Uses
#[setters(strip_option)]which allows settingOption<T>fields by passingTdirectly (the setter wraps it inSome()).Example:
let s = StripOptionStruct::default().a(3).b(42).c(43).d(7);
assert_eq!(s, StripOptionStruct { a: Some(3), b: Some(42), c: Some(43), d: 7 });
This simplifies usage by removing the need to wrap values manually in
Some.
IntoStruct<'a>
struct IntoStruct<'a> {
a: Cow<'a, str>,
b: Option<Cow<'a, str>>,
}
Purpose: Holds a
Cow(Clone-on-write) string and an optionalCowstring.Setters: Uses
#[setters(into, strip_option)]to automatically convert input types withIntotrait and stripOption.Usage:
let testb = "testb".to_string();
let i = IntoStruct::default().a("testa").b(&testb);
assert_eq!(i, IntoStruct { a: "testa".into(), b: Some("testb".into()) });
Allows passing
&str,String, orCow<str>types seamlessly.
WithStruct
struct WithStruct {
a: u32,
b: u32,
c: u32,
}
Purpose: Struct with prefix
with_for setters.Setters: Uses
#[setters(prefix = "with_")]with individual renaming for fieldatotest.Example:
let w = WithStruct::default().test(30).with_b(10).with_c(20);
assert_eq!(w, WithStruct { a: 30, b: 10, c: 20 });
BoolStruct
struct BoolStruct {
a: bool,
b: bool,
c: bool,
}
Purpose: Struct with boolean fields.
Setters: Uses
#[setters(bool)]which generates setters that toggle booleans without parameters.Usage:
let b = BoolStruct::default().a().c();
assert_eq!(b, BoolStruct { a: true, b: false, c: true });
Calling
.a()setsatotrue. This applies similarly to other boolean fields.
Tests
Each struct is accompanied by one or more #[test] functions validating the behavior of generated setters. These demonstrate method chaining, option stripping, delegation, and prefixing features.
Implementation Details and Algorithms
The file heavily relies on the
derive_settersprocedural macro to generate setter methods, which reduces boilerplate.Delegation is configured using
#[setters(generate_delegates(...))]attributes specifying delegate types and the target field or method.Option stripping and
Intoconversion are enabled via macro attributes likestrip_optionandinto.Boolean setters are generated without parameters and set the fields to
truefor fluent toggling.Lazy initialization in
BasicDelegateMethoduses an explicit methodget_xto create the inner struct on demand.
Interaction with Other Parts of the System
This file primarily demonstrates and tests features of the
derive_settersmacro, which must be provided externally.The generated setters facilitate ergonomic struct construction and mutation, which may be used elsewhere in the application where these or similar structs are involved.
The
Cowtype usage inIntoStructallows flexible ownership models for string data, potentially interacting with string handling elsewhere.The delegate pattern shown here can be applied when embedding complex structs inside wrappers, allowing caller code to transparently set inner data.
Diagram: Structs and Setter Delegation Relationships
classDiagram
class BasicStruct {
+a: u32
+b: u32
+c: u32
+test()
+b()
+c()
}
class BasicDelegateField {
+x: BasicStruct
+test()
+b()
+c()
}
class BasicDelegateMethod {
+x: Option<BasicStruct>
+get_x()
+test()
+b()
+c()
}
class PrefixBasicDelegateField {
+x: BasicStruct
+with_test()
+with_b()
+with_c()
}
BasicDelegateField --> BasicStruct : delegates setters
BasicDelegateMethod --> BasicStruct : delegates setters via get_x()
PrefixBasicDelegateField --> BasicStruct : delegates setters with prefix 'with_'
class GenericStruct {
+a: Option<&T>
+b: Option<&T>
+c: T
+a()
+b()
+c()
}
class StripOptionStruct {
+a: Option<u32>
+b: Option<u32>
+c: Option<u32>
+d: u32
+a()
+b()
+c()
+d()
}
class IntoStruct {
+a: Cow<str>
+b: Option<Cow<str>>
+a()
+b()
}
class WithStruct {
+a: u32
+b: u32
+c: u32
+test()
+with_b()
+with_c()
}
class BoolStruct {
+a: bool
+b: bool
+c: bool
+a()
+b()
+c()
}
Summary of Key Attributes and Macros
#[derive(Setters)]: Generates setter methods for struct fields.#[setters(rename = "...")]: Renames the generated setter method.#[setters(prefix = "...")]: Adds a prefix to all generated setters.#[setters(strip_option)]: Allows settingOption<T>fields directly withT.#[setters(into)]: Converts setter argument types usingInto.#[setters(bool)]: Generates parameterless setters that set boolean fields totrue.#[setters(generate_delegates(...))]: Generates setters on another struct that delegate to a field/method returning the target struct.
For detailed explanations of procedural macros and their usage, see the derive_setters topic.
Usage Example Snippet
let mut s = BasicStruct::default()
.test(5) // sets field a
.b(10)
.c(15);
let mut d = BasicDelegateField::default()
.test(5) // delegated to inner BasicStruct
.b(10);
This snippet illustrates fluent and chained setter invocations enabled by the macros.
This file is a comprehensive demonstration of automatic setter generation techniques applied to various Rust structs, emphasizing delegation, genericity, option handling, and boolean toggling.