1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/*!
This package provides a coherent set of manual accessor macros.
While a number of packages exist to simplify the addition of accessors to Rust structures and enumerations
these are often derive macros that come with a trade-off between flexibility and control. Jemmy takes a
different and more flexible approach. It provides a set of very simple leaf macros and then aggregate
macros that build common patterns from these building blocks. For example, you can add `get_and_set`
methods for a simple field, or `with_get_and_set` to include an initializer as well. You can use the
`get_set_and_unset` for optional fields which produces `foo() -> Option<&T>`, `set_foo(T)`, and `unset_foo()`
methods rather than a setter that takes an `Option<T>`.
In general most users will use the combination macros such as `with_get_and_set` or `get_set_and_unset`;
however, as these are directly built upon the individual accessor macros `get`, `set`, `unset`, `with`,
and so forth it becomes easy to customize the set of methods a type provides.
The name Jemmy was chosen for this crate as the common name for a small pry-bar or crowbar used in burglary,
a very direct form of *manual access*.
## Example 1 - Structures
The following shows the basics of the macros for generating accessors for the fields of a structure. This
will provide initializers, getters and setters for the `number_on_street` and `street_1` fields. A getter,
setter (value) and unsetter (`None`) will be provided for the `street_2` field.
```
use jemmy::*;
#[derive(Default)]
pub struct Address {
number_on_street: u32,
street_1: String,
street_2: Option<String>,
// ...
}
impl Address {
with!(pub number_on_street => u32);
get!(pub number_on_street => copy u32);
set!(pub number_on_street => u32);
with_get_and_set!(pub street_1 => into String);
get_set_and_unset!(pub street_2 => String);
}
```
Typically here's the *constructor rules of thumb*:
1. If an instance **can** be generated by default (actually [`Default`]) it **should**.
2. If not, or for *explicit construction*, anything **required** for construction should be a parameter
to a `new` or `new_` associated function that either returns `Self` or `Result<Self, Error>`.
3. Optional things that *initialize* an instance before use but after construction should have a
`with_` method.
4. Anything else should have a *get*ter and *set*ter (and maybe *un-set*ter) method.
One way to combine a builder-like pattern into a type rather than have a separate type (if doing so adds
no significant value) is to separate the notion of *construction* and *initialization* as the list above
does. Thus, construction is the process of creating an instance, initialization ensures that instance is in
a valid state and ready to use. For example, in the following the construction process does not raise errors
because all it does is verifies the existence of a vehicle. The initialization process on the other hand
*may* result in errors.
```rust,ignore
let car: Car = Default::default()
.with_vin(MY_CAR_VEHICLE_ID_NUMBER),
.with_fuel(Capacity::Full),
.initialize()?;
assert_eq!(car.vin(), MY_CAR_VEHICLE_ID_NUMBER);
assert_eq!(car.make(), "Subaru");
```
## Example 2 - Enums
The following shows the basics of the macros for generating accessors for the variants of an enum. For
each variant an `is_variant` predicate and `as_variant` cast methods are provided.
```rust
# pub struct Address(String);
use jemmy::*;
pub enum TypedAddress {
Home(Address),
Work(Address),
Other(Address),
}
impl TypedAddress {
is_variant!(Home => Address);
as_variant!(Home => Address);
is_as_variant!(Work => Address);
is_as_variant!(Other => Address);
}
```
## Standard Forms
The following are the primary forms supported by the macros in the crate; the first is the form of
all field macros, the second is the form of all variant macros.
1. `(viz Name [, function_name] => [ field_name, ] [ keywords ] [ Type ])`
2. `(viz Variant [, function_name] [ => Type ])`
The elements of these forms are described below.
1. **viz**; the vizibility specifier for the generated method.
2. for field macros:
1. **Name**; the public name of the field, this will be the *core* name of the method with any
prefix/suffix required.
2. **function_name**; (optional) where the method name needs to be overridden on a per-method
basis this allows for the specification of the *core* name of the method.
3. **field name**; (optional) when the visible name of the field is different from its field
name you may specify both.
4. **keywords** (optional):
1. **copy**; denotes that the field type implements `Copy` and the generatted method will
return a value rather than a reference.
2. **into**; will generate a setter method that takes a parameter of type `Into<T>` rather
than the typical `T`.
3. **optional**; denotes that the field is an `Option<T>` not `T` which affects all getters
and setters.
5. **Type**; (optional) the type of the field, specifically `T`, *do not* specify `Option<T>` or
`Into<T>` if using the corresponding keywords.
3. for enum macros:
1. **Variant**; the variant's identifier within the enum.
2. **function_name**; (optional) where the method name needs to be overridden on a per-method
basis this allows for the specification of the *core* name of the method.
3. **keywords** (optional):
1. **copy**; denotes that the field type implements `Copy` and the generatted method will
return a value rather than a reference.
2. **value**; TBD (**const**).
4. **Type**; (optional) the type of any value of the variant.
*/