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
//! A simple macro to make cloning data before passing it into a `move` closure or block.
//!
//! This macro is intentionally designed to be compatible with
//! `rustfmt` formatting.
//!
//! You can use this macro throughout your crate without needing to explicitly
//! import it every time as follows:
//! ```ignore
//! #[macro_use]
//! extern crate clone_macro;
//!
//! /* ... */
//!
//! clone!(/* ... */);
//! ```
//!
//! Otherwise, you can `use` it as normal.
//! ```rust
//! use clone_macro::clone;
//!
//! /* ... */
//! clone!(/* ... */);
//! ```
//!
//! # Syntax
//! The `clone!` macro takes a comma separated list of either one of two forms
//! which can have an optional `mut` prefix modifier, followed by an arbitrary
//! expression.
//!
//! For example, the following is a valid call
//! ```rust
//! # use clone_macro::clone;
//!
//! let a = 1;
//! let b = 2;
//!
//! clone!([mut a, b], ());
//! ```
//!
//! and desugars down to:
//! ```rust
//! let a = 1;
//! let b = 2;
//!
//! {
//! let mut a = a.clone();
//! let b = b.clone();
//!
//! ()
//! };
//! ```
//!
//! The clone list can also take a second form, which is an arbitrary expression
//! followed by `as` and the name of the variable. For example:
//! ```rust
//! # use clone_macro::clone;
//!
//! let s = "Hello, there!";
//!
//! clone!([{ s.len() } as len], move || {
//! assert_eq!(len, "Hello, there!".len());
//! });
//! ```
//!
//! The above desugars into:
//! ```rust
//! # use clone_macro::clone;
//!
//! let s = "Hello, there!";
//!
//! {
//! let len = "Hello, there!".len();
//!
//! move || {
//! assert_eq!(len, "Hello, there!".len());
//! }
//! };
//! ```
//!
//! This macro is most useful when the second argument is a closure, and is what
//! it is intended to work with, though not strictly so.
//!
//! All forms mentioned above can be mixed and matched, including adding a `mut` modifier
//! for the second form as:
//! ```rust,ignore
//! mut { $expr } as $ident
//! ```
//!
//! # Examples
//! ## Basic Usage
//!
//! ```rust
//! use clone_macro::clone;
//!
//! let s = "You are a beautiful being!".to_string();
//!
//! let c = clone!([s], move || {
//! println!("{s}");
//! });
//!
//! c();
//!
//! // `s` wasn't directly moved, rather, cloned first, then moved; therefore,
//! // we can still use `s`
//! assert_eq!(s.as_str(), "You are a beautiful being!");
//! ```
//!
//! We can also declare the cloned `move` as `mut`:
//! ```rust
//! use clone_macro::clone;
//!
//! let a = 7;
//! let b = 0;
//! let d = 12;
//!
//! let mut c = clone!([a, mut b, d], move || {
//! b = 42 - a - d;
//!
//! println!("a + b + d = {}", a + b + d);
//! });
//!
//! c();
//!
//! assert_eq!(a, 7);
//! assert_eq!(b, 0);
//! assert_eq!(d, 12);
//! ```
//!
//! ## Advanced Usage
//! We can clone arbitrary expressions:
//! ```rust
//! use clone_macro::clone;
//!
//! struct MyStruct {
//! some_field: String,
//! }
//!
//! let s = MyStruct {
//! some_field: "Beyond measure.".to_string(),
//! };
//!
//! let mut c = clone!([{ s.some_field } as some_field, mut { s.some_field } as mut_some_field], move || {
//! mut_some_field.clear();
//!
//! assert!(mut_some_field.is_empty());
//!
//! assert_eq!(some_field.as_str(), "Beyond measure.");
//! });
//!
//! c();
//!
//! assert_eq!(s.some_field.as_str(), "Beyond measure.");
//! ```
/// Please see the crate documentation for syntax and examples, but in a jist, the
/// syntax is as follows:
/// ```ignore
/// clone!([$($(mut)? $FORM)*], $expr);
/// ```
///
/// where `$FORM` is one of either:
/// - `ident`
/// - `{ $expr } as ident`
#[macro_export]
macro_rules! clone {
() => {};
([$($tt:tt)*], $expr:expr) => {{
clone!($($tt)*);
$expr
}};
($(,)? mut { $expr:expr } as $ident:ident $($tt:tt)*) => {
let mut $ident = ::core::clone::Clone::clone(&$expr);
clone!($($tt)*);
};
($(,)? mut $ident:ident $($tt:tt)*) => {
let mut $ident = ::core::clone::Clone::clone(&$ident);
clone!($($tt)*);
};
($(,)? { $expr:expr } as $ident:ident $($tt:tt)*) => {
let $ident = ::core::clone::Clone::clone(&$expr);
clone!($($tt)*);
};
($(,)? $ident:ident $($tt:tt)*) => {
let $ident = ::core::clone::Clone::clone(&$ident);
clone!($($tt)*);
};
($(,)?) => {};
}