using/lib.rs
1//! This crate provides the [`using`] macro designed to simplify writing and using builders by
2//! providing [method cascading](https://en.wikipedia.org/wiki/Method_cascading):
3//!
4//! ```
5//! # use using::using;
6//! #[derive(Debug, Copy, Clone)]
7//! struct Vec3 {
8//! x: f32,
9//! y: f32,
10//! z: f32,
11//! }
12//!
13//! #[derive(Default, Debug, Copy, Clone)]
14//! struct Vec3Builder {
15//! x: Option<f32>,
16//! y: Option<f32>,
17//! z: Option<f32>,
18//! }
19//!
20//! impl Vec3Builder {
21//! pub fn x(&mut self, x: f32) {
22//! self.x = Some(x);
23//! }
24//!
25//! pub fn y(&mut self, y: f32) {
26//! self.y = Some(y);
27//! }
28//!
29//! pub fn z(&mut self, z: f32) {
30//! self.z = Some(z);
31//! }
32//!
33//! //this also works with `self` instead of `&mut self`
34//! pub fn build(&mut self) -> Vec3 {
35//! Vec3 {
36//! x: self.x.unwrap(),
37//! y: self.y.unwrap(),
38//! z: self.z.unwrap(),
39//! }
40//! }
41//! }
42//!
43//! let vec3 = using!(Vec3Builder::default() => {
44//! .x(4.27);
45//! .y(9.71);
46//! .z(13.37);
47//! .build()
48//! });
49//!
50//! // Generated code:
51//! //
52//! // let vec3 = {
53//! // let mut target = Vec3Builder::default();
54//! // target.x(4.27);
55//! // target.y(9.71);
56//! // target.z(13.37);
57//! // target.build()
58//! // };
59//! ```
60//!
61//! The idea is that instead of implementing builders as fluid interfaces that allow method
62//! chaining (i.e. each method returning `&mut Self` or `Self`), we implement our builder with
63//! simple setter methods and use it with the [`using`] macro, which gives us the ergonomics of
64//! conventional builders without having to implement the builder as a fluid interface.
65//!
66//! The macro is not bound to builders: it has no requirements on the type, therefore we can use it
67//! on basically anything:
68//!
69//! ```
70//! # use std::collections::HashMap;
71//! # use using::using;
72//! let map = using!(HashMap::new() => {
73//! .insert("a", 41);
74//! .insert("b", 971);
75//! });
76//! ```
77//!
78//! ```
79//! # use using::using;
80//! let hello_world = using!(Vec::new() => {
81//! .push("Hello");
82//! .push("World!");
83//! .join(", ")
84//! });
85//! assert_eq!(hello_world, "Hello, World!");
86//! ```
87//!
88//! # Motivation
89//!
90//! The idea for this crate came from implementing the builder pattern in a personal project. In
91//! Rust, there are three main approaches for designing builder structs:
92//!
93//! * All methods taking `self` and returning `Self`:
94//!
95//! ```ignore
96//! impl SomeBuilder {
97//! pub fn new() -> Self { ... }
98//! pub fn x(self, arg: T) -> Self { ... }
99//! pub fn y(self, arg: U) -> Self { ... }
100//! pub fn z(self, arg: V) -> Self { ... }
101//! pub fn build(self) -> Something { ... }
102//! }
103//! ```
104//!
105//! The advantage of this method is that when building the final object, the fields can be moved
106//! out of the builder. One disadvantage of this method is that using the builder in more
107//! complicated ways can become quite verbose: if a method must be called inside an `if`
108//! statement or a loop or if the builder must be passed to a function, the builder has to be
109//! stored in a mutable variable and re-assigned everytime:
110//!
111//! ```ignore
112//! let mut builder = SomeBuilder::new()
113//! .x(...)
114//! .y(...);
115//! if some_condition {
116//! builder = builder.z(...);
117//! }
118//! if some_other_condition {
119//! builder = some_function(builder);
120//! }
121//! let thing = builder.build();
122//! ```
123//!
124//! Also, the builder methods are quite verbose since they have to return `self`.
125//!
126//! * All methods taking `&mut self` and returning `&mut Self`:
127//!
128//! ```ignore
129//! impl SomeBuilder {
130//! pub fn new() -> Self { ... }
131//! pub fn x(&mut self, arg: T) -> &mut Self { ... }
132//! pub fn y(&mut self, arg: U) -> &mut Self { ... }
133//! pub fn z(&mut self, arg: V) -> &mut Self { ... }
134//! pub fn build(&mut self) -> Something { ... }
135//! }
136//! ```
137//!
138//! This improves the disadvantage of the first method with respect to more complicated
139//! use-cases, because there are no re-assignments:
140//!
141//! ```ignore
142//! let mut builder = SomeBuilder::new()
143//! .x(...)
144//! .y(...);
145//! if some_condition {
146//! builder.z(...);
147//! }
148//! if some_other_condition {
149//! some_function(&mut builder);
150//! }
151//! let thing = builder.build();
152//! ```
153//!
154//! However, with this method, the `build` method cannot take `self`, otherwise method chaining
155//! does not work (except we require a call to `clone` or something similar, which is not really
156//! intuitive). Therefore, we cannot just move out of `self`, so we might end up in situations
157//! where we have to clone objects to be put into the final objects or we have to move out of the
158//! builder and leave the builder in a state where calling `build` again would have a different
159//! behavior, which, again, is unintuitive.
160//!
161//! * Combining the two approaches above, e.g. by implementing methods `xyz` and `with_xyz`, where
162//! `xyz` takes `&mut self` and `with_xyz` takes `self`. This combines the advantages of both
163//! methods, but it makes defining the builder even more verbose and also requires at least one
164//! of the two methods for each field to have a longer name.
165//!
166//! A problem shared amongst all the approaches above is that having conditionals or loops around
167//! calls to the builder break method chaining.
168//!
169//! The idea of this crate comes from the observation that the main reason builders are usually
170//! designed as fluid interfaces is that we want to express the pattern "here is an object and I
171//! want to call these methods on it" without explicitly defining the variable or referencing it
172//! everytime. Therefore, we introduce a hypothetical language construct that does exactly that:
173//!
174//! ```ignore
175//! let thing = using builder @ SomeBuilder::new() {
176//! x(...);
177//! y(...);
178//! if some_condition {
179//! z(...);
180//! }
181//! if some_other_condition {
182//! some_function(&mut builder);
183//! }
184//! build()
185//! };
186//! ```
187//!
188//! This hypothetical `using` expression takes an expression of any type (with an optional
189//! @-binding) and a block expression. Inside that block, every public method and every public
190//! field of that type is in the local scope of that block. With that, the example above would be
191//! equivalent to:
192//!
193//! ```ignore
194//! let thing = {
195//! let mut builder = SomeBuilder::new();
196//! builder.x(...);
197//! builder.y(...);
198//! if some_condition {
199//! builder.z(...);
200//! }
201//! if some_other_condition {
202//! some_function(&mut builder);
203//! }
204//! builder.build()
205//! };
206//! ```
207//!
208//! This is also known as [Method cascading](https://en.wikipedia.org/wiki/Method_cascading) and is
209//! an actual feature in some languages, notably Pascal and Visual Basic (initiated with the
210//! keyword `with`; we only chose `using` because the crate name was free ¯\\\_(ツ)\_/¯).
211//!
212//! The [`using`] macro emulates this behavior, with some restrictions due to the way macros are
213//! interpreted, e.g. in the context of macros, we do not know the type of the given expression and
214//! its public symbols, therefore we have to prefix method calls with a dot. Also, this way of
215//! accessing members does not work in all contexts; for details, see the documentation of
216//! [`using`].
217//!
218//! Writing builders with the [`using`] macro can be done by just defining a simple setter method
219//! for each field, making the code for builder very concise. If the to-be-constructed struct is
220//! simple enough, this could even make defining a builder obsolete. Also, the `build` method can
221//! now take both `self` or `&mut self` without breaking method chaining, which is usually a
222//! drawback of defining builders taking `&mut self`.
223
224#![cfg_attr(not(test), no_std)]
225
226/// A macro that provides method cascading for an object.
227///
228/// # Usage
229///
230/// ```plain
231/// using!(expression => { ... })
232///
233/// using!(identifier @ expression => { ... })
234/// ```
235///
236/// Binds `expression` to a mutable variable (called "target") that can be manipulated inside the
237/// block with expressions starting with a dot (called "target expressions"). The target variable
238/// can be explicitly named with an @-binding. If the block does not contain a trailing expression,
239/// the target is returned instead.
240///
241/// Target expression are a sequence of field accessess (e.g. `.x`) and method calls (e.g.
242/// `.push(10)`) and can only be used in blocks, let statements, bodies of if expressions, match
243/// expressions, and loops. They cannot be used in the conditional expressions and also not in
244/// compound expressions, e.g. `.last().unwrap() + 1` is not valid. For details see below.
245///
246/// Besides the target expressions, every statement and expression can be used inside the block,
247/// which also allows nesting [`using`] macros.
248///
249/// # Examples:
250///
251/// ```
252/// # use using::using;
253/// let hello_world = using!(Vec::new() => {
254/// .push("Hello");
255/// .push("World!");
256/// .join(", ")
257/// });
258/// assert_eq!(hello_world, "Hello, World!");
259///
260/// // Generated code:
261/// //
262/// // let hello_world = {
263/// // let mut target = Vec::new();
264/// // target.push("Hello");
265/// // target.push("World!");
266/// // target.join(", ")
267/// // };
268/// ```
269///
270/// More complicated example with `for`, `if`, and `let`:
271///
272/// ```
273/// # use using::using;
274/// let vec = using!(Vec::new() => {
275/// for i in 0..10 {
276/// if i % 2 == 0 {
277/// .push(i);
278/// }
279/// }
280/// let sum = .iter().sum();
281/// .push(sum);
282/// });
283/// assert_eq!(&vec[..], [ 0, 2, 4, 6, 8, 20 ]);
284/// ```
285///
286/// # Syntax:
287///
288/// This section explains the syntax in a BNF-like form to clarify the details and where target
289/// expressions can be used. The symbols `IDENTIFIER`, `Statement`, `Expression`,
290/// `BlockExpression`, `Pattern`, `GenericArgs`, `CallParams`, and `Type` are defined in [The Rust
291/// Reference](https://doc.rust-lang.org/stable/reference/). The syntax of the macro is defined by:
292///
293/// ```plain
294/// "using" "!" "(" Expression "=>" UsingBlock ")"
295///
296/// "using" "!" "(" IDENTIFIER "@" Expression "=>" UsingBlock ")"
297/// ```
298///
299/// A `UsingBlock` is an extension of Rusts `BlockExpression`: it is a block surrounded by curly
300/// braces, containing a sequence of `UsingStatement`s followed by an optional `UsingExpression`.
301///
302/// A `UsingStatement` is either a `Statement` or one of the following:
303///
304/// ```plain
305/// UsingExpression ";"
306///
307/// "let" IDENTIFIER ( ":" Type )? = UsingExpression ";"
308/// ```
309///
310/// A `UsingExpression` is either an `Expression` or one of the following:
311///
312/// ```plain
313/// UsingBlock
314///
315/// // This defines the "target expressions"
316/// ( "." IDENTIFIER | "." IDENTIFIER ( "::" GenericArgs )? "(" CallParams? ")" )+
317///
318/// "if" Expression UsingBlock ( "else" "if" Expression UsingBlock )* ( "else" UsingBlock )?
319///
320/// "match" Expression "{" ( Pattern ( "if" Expression )? => ( UsingBlock | UsingExpression "," ) )* "}"
321///
322/// "loop" UsingBlock
323///
324/// "while" Pattern "in" Expression UsingBlock
325///
326/// "for" Pattern "in" Expression UsingBlock
327/// ```
328#[macro_export]
329macro_rules! using {
330 ($target:expr => { $( $t:tt )* }) => {
331 {
332 #[allow(unused_mut)]
333 let mut target = $target;
334 $crate::using_impl!(target root empty { $($t)* })
335 }
336 };
337 ($id:ident @ $target:expr => { $( $t:tt )* }) => {
338 {
339 #[allow(unused_mut)]
340 let mut $id = $target;
341 $crate::using_impl!($id root empty { $($t)* })
342 }
343 };
344}
345
346#[doc(hidden)]
347#[macro_export]
348macro_rules! using_impl {
349 ($target:ident $scope:ident maybe_trailing_exp ($id:ident) { }) => {
350 $id
351 };
352
353 ($target:ident $scope:ident maybe_trailing_exp ($id:ident) { ; $($rest:tt)* }) => {
354 $crate::using_impl!($target $scope empty { $($rest)* })
355 };
356
357 ($target:ident $scope:ident maybe_trailing_exp ($id:ident) { $($rest:tt)* }) => {
358 $crate::using_impl!($target $scope empty { $($rest)* })
359 };
360
361
362
363 ($target:ident root empty { }) => {
364 $target
365 };
366
367 ($target:ident block empty { }) => {
368 #[allow(unreachable_code)]
369 ()
370 };
371
372 ($target:ident $scope:ident empty { ; $($rest:tt)* }) => {
373 {
374 ;
375 $crate::using_impl!($target $scope empty { $($rest)* })
376 }
377 };
378
379
380
381 ($target:ident $scope:ident empty { . $($rest:tt)* }) => {
382 $crate::using_impl!($target $scope in_exp ($target) { . $($rest)* })
383 };
384
385 ($target:ident $scope:ident in_exp ($exp:expr) { . $name:ident $( ::<$($ty:ty),* $(,)?> )? ( $($args:expr),* $(,)? ) $($rest:tt)* }) => {
386 $crate::using_impl!($target $scope in_exp ($exp.$name$(::<$($ty),*>)*($($args),*)) { $($rest)* })
387 };
388
389 ($target:ident $scope:ident in_exp ($exp:expr) { . $name:ident $($rest:tt)* }) => {
390 $crate::using_impl!($target $scope in_exp ($exp.$name) { $($rest)* })
391 };
392
393 ($target:ident $scope:ident in_exp ($exp:expr) { }) => {
394 $exp
395 };
396
397 ($target:ident $scope:ident in_exp ($exp:expr) { ; $($rest:tt)* }) => {
398 {
399 $exp;
400 $crate::using_impl!($target $scope empty { $($rest)* })
401 }
402 };
403
404 ($target:ident $scope:ident in_exp ($exp:expr) { . $name:ident = $value:expr; $($rest:tt)* }) => {
405 {
406 $exp.$name = $value;
407 $crate::using_impl!($target $scope empty { $($rest)* })
408 }
409 };
410
411
412
413 ($target:ident $scope:ident empty { { $($block:tt)* } }) => {
414 $crate::using_impl!($target block empty { $($block)* })
415 };
416
417 ($target:ident $scope:ident empty { { $($block:tt)* } $($rest:tt)* }) => {
418 {
419 $crate::using_impl!($target block empty { $($block)* });
420 $crate::using_impl!($target $scope empty { $($rest)* })
421 }
422 };
423
424
425
426 ($target:ident $scope:ident empty { let $($rest:tt)* }) => {
427 $crate::using_impl!($target $scope in_let () { $($rest)* })
428 };
429
430 ($target:ident $scope:ident in_let
431 ($($pattern:tt)*)
432 { = $($rest:tt)* }
433 ) => {
434 $crate::using_impl!($target $scope in_let_exp ($($pattern)*) (_) () { $($rest)* })
435 };
436
437 ($target:ident $scope:ident in_let
438 ($($pattern:tt)*)
439 { : $ty:ty = $($rest:tt)* }
440 ) => {
441 $crate::using_impl!($target $scope in_let_exp ($($pattern)*) ($ty) () { $($rest)* })
442 };
443
444 ($target:ident $scope:ident in_let
445 ($($pattern:tt)*)
446 { $t:tt $($rest:tt)* }
447 ) => {
448 $crate::using_impl!($target $scope in_let ($($pattern)* $t) { $($rest)* })
449 };
450
451 ($target:ident $scope:ident in_let_exp
452 ($pattern:pat)
453 ($ty:ty)
454 ($($exp:tt)*)
455 { ; $($rest:tt)* }
456 ) => {
457 {
458 let $pattern: $ty = $crate::using_impl!($target block empty { $($exp)* });
459 $crate::using_impl!($target $scope empty { $($rest)* })
460 }
461 };
462
463 ($target:ident $scope:ident in_let_exp
464 ($pattern:pat)
465 ($ty:ty)
466 ($($exp:tt)*)
467 { $t:tt $($rest:tt)* }
468 ) => {
469 $crate::using_impl!($target $scope in_let_exp ($pattern) ($ty) ($($exp)* $t) { $($rest)* })
470 };
471
472
473
474 ($target:ident $scope:ident empty { if $($rest:tt)* }) => {
475 $crate::using_impl!($target $scope in_if () () () { $($rest)* })
476 };
477
478 ($target:ident $scope:ident in_if
479 ($($if_curr:tt)*)
480 ()
481 ()
482 { { $($body:tt)* } $($rest:tt)* }
483 ) => {
484 $crate::using_impl!($target $scope in_if_next
485 ()
486 (($($if_curr)*) { $($body)* })
487 ()
488 { $($rest)* }
489 )
490 };
491
492 ($target:ident $scope:ident in_if
493 ($($if_curr:tt)*)
494 ($($if_first:tt)*)
495 ($($if_rest:tt)*)
496 { { $($body:tt)* } $($rest:tt)* }
497 ) => {
498 $crate::using_impl!($target $scope in_if_next
499 ()
500 ($($if_first)*)
501 ($($if_rest)* (($($if_curr)*) { $($body)* }))
502 { $($rest)* }
503 )
504 };
505
506 ($target:ident $scope:ident in_if
507 ($($if_curr:tt)*)
508 ($($if_first:tt)*)
509 ($($if_rest:tt)*)
510 { $t:tt $($rest:tt)* }
511 ) => {
512 $crate::using_impl!($target $scope in_if
513 ($($if_curr)* $t)
514 ($($if_first)*)
515 ($($if_rest)*)
516 { $($rest)* }
517 )
518 };
519
520 ($target:ident $scope:ident in_if_next
521 ()
522 ($($if_first:tt)*)
523 ($($if_rest:tt)*)
524 { else if $($rest:tt)* }
525 ) => {
526 $crate::using_impl!($target $scope in_if
527 ()
528 ($($if_first)*)
529 ($($if_rest)*)
530 { $($rest)* }
531 )
532 };
533
534 ($target:ident $scope:ident in_if_next
535 ()
536 (($($if_first_cond:tt)*) { $($if_first_body:tt)* })
537 ($( (($($if_rest_cond:tt)*) { $($if_rest_body:tt)* }) )*)
538 { else { $($body:tt)* } $($rest:tt)* }
539 ) => {
540 {
541 let _tmp = if $($if_first_cond)* {
542 $crate::using_impl!($target block empty { $($if_first_body)* })
543 } $( else if $($if_rest_cond)* {
544 $crate::using_impl!($target block empty { $($if_rest_body)* })
545 } )* else {
546 $crate::using_impl!($target block empty { $($body)* })
547 };
548 $crate::using_impl!($target $scope maybe_trailing_exp (_tmp) { $($rest)* })
549 }
550 };
551
552 ($target:ident $scope:ident in_if_next
553 ()
554 (($($if_first_cond:tt)*) { $($if_first_body:tt)* })
555 ($( (($($if_rest_cond:tt)*) { $($if_rest_body:tt)* }) )*)
556 { $($rest:tt)* }
557 ) => {
558 {
559 if $($if_first_cond)* {
560 $crate::using_impl!($target block empty { $($if_first_body)* })
561 } $( else if $($if_rest_cond)* {
562 $crate::using_impl!($target block empty { $($if_rest_body)* })
563 } )*
564 $crate::using_impl!($target $scope empty { $($rest)* })
565 }
566 };
567
568
569
570 ($target:ident $scope:ident empty { match $($rest:tt)* }) => {
571 $crate::using_impl!($target $scope in_match () { $($rest)* })
572 };
573
574 ($target:ident $scope:ident in_match
575 ($($match_cond:tt)*)
576 { { $($body:tt)* } $($rest:tt)* }
577 ) => {
578 $crate::using_impl!($target $scope in_match_body ($($match_cond)*) () { { $($body)* } $($rest)* })
579 };
580
581 ($target:ident $scope:ident in_match
582 ($($match_cond:tt)*)
583 { $t:tt $($rest:tt)* }
584 ) => {
585 $crate::using_impl!($target $scope in_match ($($match_cond)* $t) { $($rest)* })
586 };
587
588 ($target:ident $scope:ident in_match_body
589 ($($match_cond:tt)*)
590 ($($match_cases:tt)*)
591 { { $pattern:pat $( if $guard:expr )? => . $($body:tt)* } $($rest:tt)* }
592 ) => {
593 $crate::using_impl!($target $scope in_match_body_in_exp
594 ($($match_cond)*)
595 ($($match_cases)*)
596 (($pattern) $($guard)*)
597 (.)
598 { { $($body)* } $($rest)* }
599 )
600 };
601
602 ($target:ident $scope:ident in_match_body_in_exp
603 ($($match_cond:tt)*)
604 ($($match_cases:tt)*)
605 (($match_pattern:pat) $($match_guard:expr)?)
606 ($($match_exp:tt)*)
607 { { , $($body:tt)* } $($rest:tt)* }
608 ) => {
609 $crate::using_impl!($target $scope in_match_body
610 ($($match_cond)*)
611 ($($match_cases)* ($match_pattern $( if $match_guard )* => { $($match_exp)* }))
612 { { $($body)* } $($rest)* }
613 )
614 };
615
616 ($target:ident $scope:ident in_match_body_in_exp
617 ($($match_cond:tt)*)
618 ($($match_cases:tt)*)
619 (($match_pattern:pat) $($match_guard:expr)?)
620 ($($match_exp:tt)*)
621 { { } $($rest:tt)* }
622 ) => {
623 $crate::using_impl!($target $scope in_match_body
624 ($($match_cond)*)
625 ($($match_cases)* ($match_pattern $( if $match_guard )* => { $($match_exp)* }))
626 { { } $($rest)* }
627 )
628 };
629
630 ($target:ident $scope:ident in_match_body_in_exp
631 ($($match_cond:tt)*)
632 ($($match_cases:tt)*)
633 (($match_pattern:pat) $($match_guard:expr)?)
634 ($($match_exp:tt)*)
635 { { $t:tt $($body:tt)* } $($rest:tt)* }
636 ) => {
637 $crate::using_impl!($target $scope in_match_body_in_exp
638 ($($match_cond)*)
639 ($($match_cases)*)
640 (($match_pattern) $($match_guard)*)
641 ($($match_exp)* $t)
642 { { $($body)* } $($rest)* }
643 )
644 };
645
646 ($target:ident $scope:ident in_match_body
647 ($($match_cond:tt)*)
648 ($($match_cases:tt)*)
649 { { $pattern:pat $( if $guard:expr )? => { $($exp:tt)* }, $($body:tt)* } $($rest:tt)* }
650 ) => {
651 $crate::using_impl!($target $scope in_match_body
652 ($($match_cond)*)
653 ($($match_cases)* ($pattern $( if $guard )* => { $($exp)* }))
654 { { $($body)* } $($rest)* }
655 )
656 };
657
658 ($target:ident $scope:ident in_match_body
659 ($($match_cond:tt)*)
660 ($($match_cases:tt)*)
661 { { $pattern:pat $( if $guard:expr )? => { $($exp:tt)* } $($body:tt)* } $($rest:tt)* }
662 ) => {
663 $crate::using_impl!($target $scope in_match_body
664 ($($match_cond)*)
665 ($($match_cases)* ($pattern $( if $guard )* => { $($exp)* }))
666 { { $($body)* } $($rest)* }
667 )
668 };
669
670 ($target:ident $scope:ident in_match_body
671 ($($match_cond:tt)*)
672 ($($match_cases:tt)*)
673 { { $pattern:pat $( if $guard:expr )? => $exp:expr, $($body:tt)* } $($rest:tt)* }
674 ) => {
675 $crate::using_impl!($target $scope in_match_body
676 ($($match_cond)*)
677 ($($match_cases)* ($pattern $( if $guard )* => { $exp }))
678 { { $($body)* } $($rest)* }
679 )
680 };
681
682 ($target:ident $scope:ident in_match_body
683 ($($match_cond:tt)*)
684 ($($match_cases:tt)*)
685 { { $pattern:pat $( if $guard:expr )? => $exp:expr } $($rest:tt)* }
686 ) => {
687 $crate::using_impl!($target $scope in_match_body
688 ($($match_cond)*)
689 ($($match_cases)* ($pattern $( if $guard )* => { $exp }))
690 { { } $($rest)* }
691 )
692 };
693
694 ($target:ident $scope:ident in_match_body
695 ($($match_cond:tt)*)
696 ($( ($pattern:pat $( if $guard:expr )? => { $($exp:tt)* }) )*)
697 { { } $($rest:tt)* }
698 ) => {
699 {
700 let _tmp = match $($match_cond)* {
701 $( $pattern $( if $guard )* => { $crate::using_impl!($target block empty { $($exp)* }) }, )*
702 };
703 $crate::using_impl!($target $scope maybe_trailing_exp (_tmp) { $($rest)* })
704 }
705 };
706
707
708
709 ($target:ident $scope:ident empty { loop { $($body:tt)* } $($rest:tt)* }) => {
710 {
711 let _tmp = loop {
712 $crate::using_impl!($target block empty { $($body)* })
713 };
714 $crate::using_impl!($target $scope maybe_trailing_exp (_tmp) { $($rest)* })
715 }
716 };
717
718
719
720 ($target:ident $scope:ident empty { while $($rest:tt)* }) => {
721 $crate::using_impl!($target $scope in_while () { $($rest)* })
722 };
723
724 ($target:ident $scope:ident in_while
725 ($($while_cond:tt)*)
726 { { $($body:tt)* } $($rest:tt)* }
727 ) => {
728 {
729 while $($while_cond)* {
730 $crate::using_impl!($target block empty { $($body)* })
731 }
732 $crate::using_impl!($target $scope empty { $($rest)* })
733 }
734 };
735
736 ($target:ident $scope:ident in_while
737 ($($while_cond:tt)*)
738 { $t:tt $($rest:tt)* }
739 ) => {
740 $crate::using_impl!($target $scope in_while ($($while_cond)* $t) { $($rest)* })
741 };
742
743
744
745 ($target:ident $scope:ident empty { for $for_pattern:pat in $($rest:tt)* }) => {
746 $crate::using_impl!($target $scope in_for ($for_pattern) () { $($rest)* })
747 };
748
749 ($target:ident $scope:ident in_for
750 ($for_pattern:pat)
751 ($($for_exp:tt)*)
752 { { $($body:tt)* } $($rest:tt)* }
753 ) => {
754 {
755 for $for_pattern in $($for_exp)* {
756 $crate::using_impl!($target block empty { $($body)* })
757 }
758 $crate::using_impl!($target $scope empty { $($rest)* })
759 }
760 };
761
762 ($target:ident $scope:ident in_for
763 ($for_pattern:pat)
764 ($($for_exp:tt)*)
765 { $t:tt $($rest:tt)* }
766 ) => {
767 $crate::using_impl!($target $scope in_for ($for_pattern) ($($for_exp)* $t) { $($rest)* })
768 };
769
770
771
772 ($target:ident $scope:ident empty { $st:stmt; $($rest:tt)* }) => {
773 {
774 $st
775 $crate::using_impl!($target $scope empty { $($rest)* })
776 }
777 };
778
779 ($target:ident $scope:ident empty { $exp:expr }) => {
780 $exp
781 };
782}
783
784#[cfg(test)]
785mod tests {
786 use crate::using;
787
788 #[test]
789 fn simple() {
790 let vec = using!(Vec::new() => {
791 .push(1);
792 .push(2);
793 .push(3);
794 .push(4);
795 .push(5);
796 });
797 assert_eq!(vec.iter().sum::<i32>(), 15);
798 }
799
800 #[test]
801 fn simple_expr() {
802 let sum = using!(Vec::new() => {
803 .push(1);
804 .push(2);
805 .push(3);
806 .push(4);
807 .push(5);
808 .iter().sum::<i32>()
809 });
810 assert_eq!(sum, 15);
811 }
812
813 #[test]
814 fn block_expr() {
815 let sum: i32 = using!(Vec::new() => {
816 .push(1);
817 {
818 .push(2);
819 .push(3);
820 }
821 .push(4);
822 {
823 .push(5);
824 .iter().sum()
825 }
826 });
827 assert_eq!(sum, 15);
828 }
829
830 #[test]
831 fn if_expr() {
832 for i in 0..3 {
833 let res = using!(Vec::new() => {
834 if let 0 = i {
835 .push(0);
836 } else if i == 1 {
837 .push(1);
838 } else {
839 .push(2);
840 }
841 .pop().unwrap()
842 });
843 assert_eq!(res, i);
844 }
845 }
846
847 #[test]
848 fn match_expr() {
849 for i in 0..9 {
850 let res = using!(vec @ Vec::new() => {
851 match i {
852 0 => .push(0),
853 1 => vec.push(1),
854 2 => { .push(2) }
855 3 => { .push(3) },
856 4 if true => .push(4),
857 5 if true => vec.push(5),
858 6 if true => { .push(6) }
859 7 if true => { .push(7) },
860 _ => { .push(8) }
861 }
862 .pop().unwrap()
863 });
864 assert_eq!(res, i);
865 }
866 }
867
868 #[test]
869 fn loop_expr() {
870 let sum: i32 = using!(Vec::new() => {
871 let mut i = 1;
872 loop {
873 if i > 5 {
874 break;
875 }
876 .push(i);
877 i += 1;
878 }
879 .iter().sum()
880 });
881 assert_eq!(sum, 15);
882 }
883
884 #[test]
885 fn while_loop() {
886 let sum: i32 = using!(Vec::new() => {
887 let mut i = 1;
888 while i <= 5 {
889 .push(i);
890 i += 1;
891 }
892 .iter().sum()
893 });
894 assert_eq!(sum, 15);
895 }
896
897 #[test]
898 fn while_let() {
899 let sum: i32 = using!(Vec::new() => {
900 let mut i = 1;
901 while let Some(_) = (i <= 5).then_some(i) {
902 .push(i);
903 i += 1;
904 }
905 .iter().sum()
906 });
907 assert_eq!(sum, 15);
908 }
909
910 #[test]
911 fn for_loop() {
912 let sum: i32 = using!(Vec::new() => {
913 for i in 1..=5 {
914 .push(i);
915 }
916 .iter().sum()
917 });
918 assert_eq!(sum, 15);
919 }
920
921 #[test]
922 fn if_in_for() {
923 let sum: i32 = using!(Vec::new() => {
924 for i in 1..=10 {
925 if i % 2 == 0 {
926 .push(i);
927 }
928 }
929 .iter().sum()
930 });
931 assert_eq!(sum, 30);
932 }
933
934 #[test]
935 fn let_exp() {
936 let sum: i32 = using!(Vec::new() => {
937 .push(1);
938 .push(2);
939 .push(3);
940 let sum = .iter().sum();
941 .push(sum);
942 let res = { .pop().unwrap() };
943 2 * res
944 });
945 assert_eq!(sum, 12);
946 }
947
948 #[test]
949 fn let_complex() {
950 let res = using!(Vec::new() => {
951 .push(2);
952 .push(3);
953 .push(5);
954 let a = loop { let x = .last().unwrap(); break *x };
955 let b = if a < 10 { .first().is_some() } else { .is_empty() };
956 let c = match b { true => .len(), false => 0 };
957 (a, b, c)
958 });
959 assert_eq!(res, (5, true, 3));
960 }
961
962 #[test]
963 fn nested_using() {
964 let sum: i32 = using!(Vec::new() => {
965 .push(1);
966 .push(2);
967 .push(3);
968 .push(4);
969 .push(5);
970 .push(using!(Vec::new() => {
971 .push(2);
972 .push(3);
973 .iter().product()
974 }));
975 .iter().sum()
976 });
977 assert_eq!(sum, 21);
978 }
979}