with_macro/
lib.rs

1//! The `with` macro.
2//!
3//! This is a macro that takes an object and lets you call methods on that object without naming it.
4//! The first argument is an expression that will be assigned to a variable in let binding. To make
5//! that binding mutable, prepend `mut` to the expression.
6//! Calling a function that starts with a `.` will be converted into a method call using this
7//! variable.
8//!
9//! The supported forms are:
10//! - `.method(args..)`
11//! - `let pat = .method(args..);`
12//! - `var = .method(args..);`
13//!
14//! Anything else will be evaluated unmodified as an expression.
15//!
16//! # Example
17//! ```
18//! use with_macro::with;
19//!
20//! let vec = with! {
21//!     mut Vec::new() =>
22//!         .push(1)
23//!         .push(42)
24//!         .push(-13)
25//!         let l = .len();
26//!         assert_eq!(l, 3);
27//! };
28//!
29//! assert_eq!(vec, [1, 42, -13]);
30//! ```
31
32/// The `with` macro.
33///
34/// See the module documentation for more details.
35#[macro_export]
36macro_rules! with {
37    // mut expr => ...
38    (mut $obj:expr => $($body:tt)*) => ({
39        let mut obj = $obj;
40        $crate::with!(@parse obj $($body)*);
41        obj
42    });
43
44    // expr => ...
45    ($obj:expr => $($body:tt)*) => ({
46        let obj = $obj;
47        $crate::with!(@parse obj $($body)*);
48        obj
49    });
50
51    // termination rule
52    (@parse $obj:ident) => ();
53
54    // .method(args..)
55    (@parse $obj:ident . $method:ident ( $($args:expr),* ) $($tail:tt)*) => {
56        $obj.$method($($args),*);
57        $crate::with!(@parse $obj $($tail)*)
58    };
59
60    // let pat = .method(args..);
61    (@parse $obj:ident let $var:pat = . $method:ident ( $($args:expr),* ) ; $($tail:tt)*) => {
62        let $var = $obj.$method($($args),*);
63        $crate::with!(@parse $obj $($tail)*)
64    };
65
66    // var = .method(args..);
67    (@parse $obj:ident $var:ident = . $method:ident ( $($args:expr),* ) ; $($tail:tt)*) => {
68        $var = $obj.$method($($args),*);
69        $crate::with!(@parse $obj $($tail)*)
70    };
71
72    // arbitrary expresion
73    (@parse $obj:ident $exp:expr ; $($tail:tt)*) => {
74        $exp;
75        $crate::with!(@parse $obj $($tail)*)
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use std::cell::Cell;
82
83    #[derive(Debug, PartialEq, Eq)]
84    struct Foo(Cell<i32>);
85
86    impl Foo {
87        fn new(val: i32) -> Self {
88            Foo(Cell::new(val))
89        }
90
91        fn get_val(&self) -> i32 {
92            self.0.get()
93        }
94
95        fn set_val(&self, val: i32) {
96            self.0.set(val)
97        }
98
99        fn add(&self, n: i32) {
100            self.0.set(self.0.get() + n)
101        }
102
103        fn mul(&self, n: i32) {
104            self.0.set(self.0.get() * n)
105        }
106    }
107
108    #[test]
109    fn basic() {
110        let a;
111        let foo = with! {
112            Foo::new(0) =>
113                .set_val(10)
114                .mul(2)
115                a = .get_val();
116                .add(1)
117                let n = .get_val();
118                assert_eq!(n, 21);
119                .mul(2)
120        };
121
122        assert_eq!(a, 20);
123        assert_eq!(foo.get_val(), 42);
124    }
125
126    #[test]
127    fn mutable() {
128        let vec = with! {
129            mut Vec::new() =>
130                .push(1)
131                .push(42)
132                .push(-13)
133                let l = .len();
134                assert_eq!(l, 3);
135        };
136
137        assert_eq!(vec, [1, 42, -13]);
138    }
139
140    #[test]
141    fn nested() {
142        let vec = with! {
143            mut Vec::new() =>
144                .push(with!{
145                    Foo::new(3) =>
146                })
147                .push(with!{
148                    Foo::new(0) =>
149                        .set_val(10)
150                        .add(3)
151                })
152        };
153
154        assert_eq!(vec, [Foo::new(3), Foo::new(13)]);
155    }
156}