clone_macro/lib.rs
1//! A simple macro to make cloning data before passing it into a `move` closure or block.
2//!
3//! This macro is intentionally designed to be compatible with
4//! `rustfmt` formatting.
5//!
6//! You can use this macro throughout your crate without needing to explicitly
7//! import it every time as follows:
8//! ```ignore
9//! #[macro_use]
10//! extern crate clone_macro;
11//!
12//! /* ... */
13//!
14//! clone!(/* ... */);
15//! ```
16//!
17//! Otherwise, you can `use` it as normal.
18//! ```rust
19//! use clone_macro::clone;
20//!
21//! /* ... */
22//! clone!(/* ... */);
23//! ```
24//!
25//! # Syntax
26//! The `clone!` macro takes a comma separated list of either one of two forms
27//! which can have an optional `mut` prefix modifier, followed by an arbitrary
28//! expression.
29//!
30//! For example, the following is a valid call
31//! ```rust
32//! # use clone_macro::clone;
33//!
34//! let a = 1;
35//! let b = 2;
36//!
37//! clone!([mut a, b], ());
38//! ```
39//!
40//! and desugars down to:
41//! ```rust
42//! let a = 1;
43//! let b = 2;
44//!
45//! {
46//! let mut a = a.clone();
47//! let b = b.clone();
48//!
49//! ()
50//! };
51//! ```
52//!
53//! The clone list can also take a second form, which is an arbitrary expression
54//! followed by `as` and the name of the variable. For example:
55//! ```rust
56//! # use clone_macro::clone;
57//!
58//! let s = "Hello, there!";
59//!
60//! clone!([{ s.len() } as len], move || {
61//! assert_eq!(len, "Hello, there!".len());
62//! });
63//! ```
64//!
65//! The above desugars into:
66//! ```rust
67//! # use clone_macro::clone;
68//!
69//! let s = "Hello, there!";
70//!
71//! {
72//! let len = "Hello, there!".len();
73//!
74//! move || {
75//! assert_eq!(len, "Hello, there!".len());
76//! }
77//! };
78//! ```
79//!
80//! This macro is most useful when the second argument is a closure, and is what
81//! it is intended to work with, though not strictly so.
82//!
83//! All forms mentioned above can be mixed and matched, including adding a `mut` modifier
84//! for the second form as:
85//! ```rust,ignore
86//! mut { $expr } as $ident
87//! ```
88//!
89//! # Examples
90//! ## Basic Usage
91//!
92//! ```rust
93//! use clone_macro::clone;
94//!
95//! let s = "You are a beautiful being!".to_string();
96//!
97//! let c = clone!([s], move || {
98//! println!("{s}");
99//! });
100//!
101//! c();
102//!
103//! // `s` wasn't directly moved, rather, cloned first, then moved; therefore,
104//! // we can still use `s`
105//! assert_eq!(s.as_str(), "You are a beautiful being!");
106//! ```
107//!
108//! We can also declare the cloned `move` as `mut`:
109//! ```rust
110//! use clone_macro::clone;
111//!
112//! let a = 7;
113//! let b = 0;
114//! let d = 12;
115//!
116//! let mut c = clone!([a, mut b, d], move || {
117//! b = 42 - a - d;
118//!
119//! println!("a + b + d = {}", a + b + d);
120//! });
121//!
122//! c();
123//!
124//! assert_eq!(a, 7);
125//! assert_eq!(b, 0);
126//! assert_eq!(d, 12);
127//! ```
128//!
129//! ## Advanced Usage
130//! We can clone arbitrary expressions:
131//! ```rust
132//! use clone_macro::clone;
133//!
134//! struct MyStruct {
135//! some_field: String,
136//! }
137//!
138//! let s = MyStruct {
139//! some_field: "Beyond measure.".to_string(),
140//! };
141//!
142//! let mut c = clone!([{ s.some_field } as some_field, mut { s.some_field } as mut_some_field], move || {
143//! mut_some_field.clear();
144//!
145//! assert!(mut_some_field.is_empty());
146//!
147//! assert_eq!(some_field.as_str(), "Beyond measure.");
148//! });
149//!
150//! c();
151//!
152//! assert_eq!(s.some_field.as_str(), "Beyond measure.");
153//! ```
154
155/// Please see the crate documentation for syntax and examples, but in a jist, the
156/// syntax is as follows:
157///
158/// ```ignore
159/// clone!([$($(mut)? $FORM)*], $expr);
160/// ```
161///
162/// where `$FORM` is one of either:
163/// - `ident`
164/// - `{ $expr } as ident`
165#[macro_export]
166macro_rules! clone {
167 () => {};
168 ([$($tt:tt)*], $expr:expr) => {{
169 $crate::clone!($($tt)*);
170 $expr
171 }};
172 ($(,)? mut { $expr:expr } as $ident:ident $($tt:tt)*) => {
173 let mut $ident = ::core::clone::Clone::clone(&$expr);
174 $crate::clone!($($tt)*);
175 };
176 ($(,)? mut $ident:ident $($tt:tt)*) => {
177 let mut $ident = ::core::clone::Clone::clone(&$ident);
178 $crate::clone!($($tt)*);
179 };
180 ($(,)? { $expr:expr } as $ident:ident $($tt:tt)*) => {
181 let $ident = ::core::clone::Clone::clone(&$expr);
182 $crate::clone!($($tt)*);
183 };
184 ($(,)? $ident:ident $($tt:tt)*) => {
185 let $ident = ::core::clone::Clone::clone(&$ident);
186 $crate::clone!($($tt)*);
187 };
188 ($(,)?) => {};
189}