Skip to content

Commit 439548f

Browse files
committed
former : standalone constructors
1 parent 3a152e1 commit 439548f

File tree

11 files changed

+1072
-847
lines changed

11 files changed

+1072
-847
lines changed

module/core/former/Readme.md

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,113 @@ Where `former` significantly simplifies complex scenarios is in building collect
192192

193193
`former` provides different subform attributes (`#[ subform_collection ]`, `#[ subform_entry ]`, `#[ subform_scalar ]`) for various collection and nesting patterns.
194194

195+
## Standalone Constructors
196+
197+
For scenarios where you want a direct constructor function instead of always starting with `YourType::former()`, `former` offers standalone constructors.
198+
199+
* **Enable:** Add `#[ standalone_constructors ]` to your struct or enum definition.
200+
* **Function Name:** A function named after your type (in snake_case) will be generated (e.g., `my_struct()` for `struct MyStruct`). For enums, functions are named after variants (e.g., `my_variant()` for `enum E { MyVariant }`).
201+
* **Arguments:** By default, the constructor takes no arguments and returns the `Former` type.
202+
* **Specify Arguments:** Mark specific fields with `#[ arg_for_constructor ]` to make them required arguments for the standalone constructor.
203+
* **Return Type (Option 2 Logic):**
204+
* If **all** fields of the struct/variant are marked with `#[ arg_for_constructor ]`, the standalone constructor returns the instance directly (`Self`).
205+
* If **zero or some** fields are marked, the standalone constructor returns the `Former` type, pre-initialized with the provided arguments.
206+
207+
**Example: Struct Standalone Constructors**
208+
209+
```rust
210+
# #[ cfg( any( not( feature = "derive_former" ), not( feature = "enabled" ) ) ) ]
211+
# fn main() {}
212+
# #[ cfg( all( feature = "derive_former", feature = "enabled" ) ) ]
213+
# fn main()
214+
# {
215+
use former::Former;
216+
217+
#[ derive( Debug, PartialEq, Former ) ]
218+
#[ standalone_constructors ] // Enable standalone constructors
219+
pub struct ServerConfig
220+
{
221+
#[ arg_for_constructor ] // This field is a constructor arg
222+
host : String,
223+
#[ arg_for_constructor ] // This field is also a constructor arg
224+
port : u16,
225+
timeout : Option< u32 >, // This field is NOT a constructor arg
226+
}
227+
228+
// Not all fields are args, so `server_config` returns the Former
229+
let config_former = server_config( "localhost".to_string(), 8080u16 ); // Added u16 suffix
230+
231+
// Set the remaining field and form
232+
let config = config_former
233+
.timeout( 5000u32 ) // Added u32 suffix
234+
.form();
235+
236+
assert_eq!( config.host, "localhost" );
237+
assert_eq!( config.port, 8080u16 ); // Added u16 suffix
238+
assert_eq!( config.timeout, Some( 5000u32 ) ); // Added u32 suffix
239+
240+
#[ derive( Debug, PartialEq, Former ) ]
241+
#[ standalone_constructors ]
242+
pub struct Point
243+
{
244+
#[ arg_for_constructor ]
245+
x : i32,
246+
#[ arg_for_constructor ]
247+
y : i32,
248+
}
249+
250+
// ALL fields are args, so `point` returns Self directly
251+
let p = point( 10, 20 );
252+
assert_eq!( p.x, 10 );
253+
assert_eq!( p.y, 20 );
254+
# }
255+
```
256+
257+
**Example: Enum Standalone Constructors**
258+
259+
```rust
260+
# #[ cfg( any( not( feature = "derive_former" ), not( feature = "enabled" ) ) ) ]
261+
# fn main() {}
262+
# #[ cfg( all( feature = "derive_former", feature = "enabled" ) ) ]
263+
# fn main()
264+
# {
265+
use former::Former;
266+
267+
#[ derive( Debug, PartialEq, Former ) ]
268+
#[ standalone_constructors ]
269+
pub enum Message
270+
{
271+
Quit, // Unit variant constructor `quit()` returns Self
272+
Write // Tuple variant constructor `write()` returns Former
273+
{
274+
#[ arg_for_constructor ] // Only this field is an arg
275+
text : String,
276+
urgent : bool, // Not an arg
277+
},
278+
Move // Struct variant constructor `move_point()` returns Self
279+
{
280+
#[ arg_for_constructor ]
281+
x : i32,
282+
#[ arg_for_constructor ]
283+
y : i32,
284+
}
285+
}
286+
287+
// Unit variant - returns Self
288+
let m1 = quit();
289+
assert_eq!( m1, Message::Quit );
290+
291+
// Tuple variant - not all fields are args, returns Former
292+
let m2_former = write( "hello".to_string() );
293+
let m2 = m2_former.urgent( true ).form();
294+
assert_eq!( m2, Message::Write { text: "hello".to_string(), urgent: true } );
295+
296+
// Struct variant - all fields are args, returns Self
297+
let m3 = r#move( 1, 2 ); // Use raw identifier `r#move` as `move` is a keyword
298+
assert_eq!( m3, Message::Move { x: 1, y: 2 } );
299+
# }
300+
```
301+
195302
## Key Features Overview
196303

197304
* **Automatic Builder Generation:** `#[ derive( Former ) ]` for structs and enums.

module/core/former/advanced.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -814,19 +814,31 @@ Apply these directly above the `struct` or `enum` definition.
814814
* Prints the code generated by the `Former` derive macro to the console during compilation. Useful for understanding the macro's output or debugging issues.
815815
* *Example:* `#[ derive( Former ) ] #[ debug ] struct MyStruct { ... }`
816816

817+
* **`#[ standalone_constructors ]`**
818+
* Generates top-level constructor functions for the struct or enum variants.
819+
* For structs, generates `fn my_struct( ... )`. For enums, generates `fn my_variant( ... )` for each variant.
820+
* Arguments and return type depend on `#[ arg_for_constructor ]` attributes on fields (see below and Option 2 logic in Readme).
821+
* *Example:* `#[ derive( Former ) ] #[ standalone_constructors ] struct MyStruct { ... }`
822+
817823
### Field-Level / Variant-Level Attributes
818824

819-
Apply these directly above fields within a struct or variants within an enum.
825+
Apply these directly above fields within a struct or fields within an enum variant.
820826

821827
**General Field Control:**
822828

823829
* **`#[ former( default = expression ) ]`**
824830
* Provides a default value for the field if its setter is not called during the building process. The `expression` must evaluate to a value assignable to the field's type.
825831
* *Example:* `#[ former( default = 10 ) ] count : i32;`, `#[ former( default = "guest".to_string() ) ] user : String;`
826832

833+
* **`#[ arg_for_constructor ]`**
834+
* Marks a field as a required argument for the standalone constructor generated by `#[ standalone_constructors ]`.
835+
* Affects the constructor's signature and return type (see Option 2 logic in Readme).
836+
* Cannot be applied directly to enum variants, only to fields *within* variants.
837+
* *Example:* `#[ arg_for_constructor ] field_a : i32;`
838+
827839
**Scalar Field Control:** (Applies to simple fields or variants marked `#[scalar]`)
828840

829-
* **`#[ scalar ]`** (Implicit for simple struct fields, required for tuple/unit enum variants to get a direct constructor)
841+
* **`#[ scalar ]`** (Implicit for simple struct fields, required for tuple/unit enum variants to get a direct *associated method* constructor)
830842
* Ensures a standard setter method (`.field_name( value )`) or a direct constructor (`Enum::variant_name( value )`) is generated.
831843
* **Arguments:**
832844
* `name = new_setter_name`: Renames the setter method (e.g., `#[ scalar( name = set_field ) ]`).

0 commit comments

Comments
 (0)