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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
//! A macro to easily create immutable builders.
//!
//! The [builder pattern](https://en.wikipedia.org/wiki/Builder_pattern) is encouraged
//! in the Rust language, in particular as a strategy to emulate named and optional arguments,
//! which are intentionally not supported by Rust.
//! However creating all the builder machinery can lead to boilerplate code, in particular when the
//! generated data is complex and multi-layered.
//! The usual builder pattern is based on mutation and generally turns compile-time checks that
//! the final object is complete to a runtime verification. Assemblist allows you to create fluent
//! immutable builders structured as method chains like in:
//! ```rust
//! fn define_movie<'a>(name: &'a str)
//! .released_in(release_year: usize)
//! .directed_by(director_name: &'a str) -> Movie
//! {
//! Movie {
//! name: name.to_string(),
//! release_year,
//! director_name: director_name.to_string(),
//! }
//! }
//! ```
//! You can then just call it as it was declared:
//! ```rust
//! let movie = define_movie("The Lobster")
//! .released_in(2015)
//! .directed_by("Yorgos Lanthimos");
//! ```
use Tree;
use ;
use parse_macro_input;
/**
* The point of this crate. Allows to generate fluent immutable builders based on method chains.
*
* The argument of the `assemblist!` macro is a scope containing one or more method chains.
* A method chain is similar to a function except that its name and argument list are split into multiple sections.
* Behind the scene, `assemblist!` actually creates as many distinct methods and generates their respective result
* type automatically.
* ```rust
* assemblist! {
* fn define_movie<'a>(name: &'a str)
* .released_in(release_year: usize)
* .directed_by(director_name: &'a str) -> Movie
* {
* Movie {
* name: name.to_string(),
* release_year,
* director_name: director_name.to_string(),
* }
* }
* }
* ```
*
* You can then just call method chains as they are declared:
* ```rust
* let movie = define_movie("The Lobster")
* .released_in(2015)
* .directed_by("Yorgos Lanthimos");
* ```
*
* Multiple method chains can be declared inside the same `assemblist!{ … }` block:
* ```rust
* assemblist! {
* fn f1(/*args*/).f2(/*args*/).f3(/*args*/) { /* code */ }
* fn g1(/*args*/).g2(/*args*/) { /* code */ }
* fn h1(/*args*/).h2(/*args*/).h3(/*args*/).h4(/*args*/) { /* code */ }
* }
* ```
*
* ## Use builders with any function body
*
* Contrary to many alternative crates, in Assemblist, builder patterns are not generated from
* annotations on a struct to build, but by directly declaring method chains as if they were basic
* constructions of the Rust language. In addition to making their use obvious, this pattern
* allows for much more flexibility in the implementation. In fact, you do not even need to build
* something. For example you may just want to decompose an existing function in order to clarify
* the purpose of its parameters (enclosing macro is omitted):
* ```rust
* pub fn replace_in<'a>(text: &'a str)
* .occurrences_of(pattern: &'a str)
* .with(replacement: &'a str)
* .at_most(n: usize)
* .times() -> String
* {
* text.replacen(pattern, replacement, n)
* }
* ```
* You can actually include arbitrary complex code.
*
* ## Declare alternatives
*
* The builder pattern is a very expressive method to offer alternatives to users of a library.
* They can start with a common function name and then choose which subsequent method makes sense for
* their specific case. Assemblist aknowledges this possibility by offering the alternative syntax:
* ```rust
* fn new_http_request_to(url: Uri)
* .from<'a>(user_agent: &'a str)
* .with_authorization(authorization: HttpAuthorization).{
*
* fn as_get() -> GetHttpRequest {
* GetHttpRequest {
* url,
* user_agent: user_agent.to_string(),
* authorization,
* }
* }
*
* fn as_post().{
* fn with_text_body(body: String) -> PostHttpRequest {
* PostHttpRequest {
* url,
* user_agent: user_agent.to_string(),
* authorization,
* body: HttpBody::Text(body),
* }
* }
*
* fn with_json_body(json: JsonValue) -> PostHttpRequest {
* PostHttpRequest {
* url,
* user_agent: user_agent.to_string(),
* authorization,
* body: HttpBody::Json(json),
* }
* }
* }
* }
* ```
* Chaining with a `.{ … }` block gives you the possibility to define alternatives. Inside such a block,
* each possible continuation starts with the `fn` keyword and can itself be a method chain, possibly
* including other alternatives recursively. Each branch of the corresponding tree of method chains
* can provide a distinct implementation and even return a distinct type:
* ```rust
* let get_request = new_http_request_to(Uri::from_static("http://www.croco-paradise.tv"))
* .from("FireFox")
* .with_authorization(HttpAuthorization::None)
* .as_get();
*
* let post_request = new_http_request_to(Uri::from_static("http://www.croco-paradise.tv"))
* .from("FireFox")
* .with_authorization(HttpAuthorization::Bearer("sometoken3456=".to_string()))
* .as_post()
* .with_text_body("Hello world".to_string());
* ```
*
* ## Use method chains in inherent implementations
*
* You can either declare method chains as root items, as shown in previous examples, or declare them
* inside inherent implementations:
* ```rust
* struct Calculation;
*
* assemblist! {
* impl Calculation {
* pub fn add(a: isize).to(b: isize) -> isize { a + b }
* pub fn remove(a: isize).from(b: isize) -> isize { a - b }
* }
* }
* ```
* It is even possible to declare multiple inherent implementations inside the same `assemblist!`
* macro invocation and to mix them with root method chains.
*
* ## How to document your chains
*
* It is possible to document individually each method inside your method chain. You just need to
* separate consecutive descriptions by a sequence `---`. Descriptions are assigned to methods in
* the same order:
*
* ```rust
* /// Start creating a movie by providing its title.
* ///---
* /// Provide the movies release year.
* ///---
* /// Provide the director's name and return the complete movie.
* fn define_movie<'a>(name: &'a str)
* .released_in(release_year: usize)
* .directed_by(director_name: &'a str) -> Movie { /* code */ }
* ```
*
* In case of alternatives, you can insert documentation blocks in front of
* each possible continuation. The mechanism described earlier applies
* recursively so you can include consecutive descriptions separated by a sequence `---`
* if your continuation contains multiple methods.
*
* ```rust
* /// Start creating an http request by providing an uri.
* ///---
* /// Provide a user agent.
* ///---
* /// Provide the authorization.
* fn new_http_request_to(url: Uri)
* .from<'a>(user_agent: &'a str)
* .with_authorization(authorization: HttpAuthorization).{
*
* /// Specify the request is a PATCH.
* ///---
* /// Provide a json body and return the request.
* fn as_patch().with_json_body(json: JsonValue) -> PatchHttpRequest { /* code */ }
*
* /// Specify the request is a PATCH.
* fn as_post().{
*
* /// Provide a text body and return the request.
* fn with_text_body(body: String) -> PostHttpRequest { /* code */ }
*
* /// Provide a json body and return the request.
* fn with_json_body(json: JsonValue) -> PostHttpRequest { /* code */ }
* }
* }
* ```
*
* ## Current limitations
*
* ### No implicit lifetimes
*
* Assemblist does not handle implicit lifetimes for now so you must declare them explicitely. Each method
* inside the method chain can carry its own lifetimes:
* ```rust
* fn pour_items_from<'a, T>(source: &'a mut Vec<T>)
* .starting_at(n: usize)
* .into<'b>(destination: &'b mut Vec<T>)
* {
* for item in source.drain(n..) {
* destination.push(item);
* }
* }
* ```
*
* ### No patterns for arguments
*
* You cannot use patterns for methods arguments as in `f((a, b): (usize, bool))` or in `g(ref r: f64)`. If
* you need to do this, just use plain argument names and destructure them inside the body:
* ```rust
* fn f(pair: (usize, bool)).g(x: f64) {
* let (a, b) = pair;
* let ref r = x;
* }
* ```
*
* ### No `self` arguments
*
* For now, method chains inside inherent implementations cannot declare a `self` argument. Only "static"
* methods are allowed. So this example fails to compile:
* ```compile_fail
* struct MyInt(isize);
*
* assemblist! {
* impl MyInt {
* fn is_between(&self, a: isize).and(b: isize) { a <= self.0 && self.0 <= b }
* }
* }
* ```
*/