cloned/
lib.rs

1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under both the MIT license found in the
5 * LICENSE-MIT file in the root directory of this source tree and the Apache
6 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
7 * of this source tree.
8 */
9
10#![deny(warnings, missing_docs, clippy::all, rustdoc::broken_intra_doc_links)]
11
12//! See examples for what code you can write with cloned macro.
13//!
14//! # Examples
15//!
16//! ```
17//! # use cloned::cloned;
18//! struct A {
19//!     x: String,
20//!     y: String,
21//!     z: String,
22//! }
23//! impl A {
24//!     fn foo(&self) {
25//!         cloned!(self.x, self.y, self.z);
26//!         (move || {
27//!             println!("{} {} {}", x, y, z);
28//!         })();
29//!     }
30//! }
31//! # fn main () {}
32//! ```
33//!
34//! It also supports setting a local alias:
35//! ```
36//! # use cloned::cloned;
37//! # fn main () {
38//! let foo = 42;
39//! cloned!(foo as bar);
40//! assert!(foo == bar);
41//! # }
42//! ```
43
44/// See crate's documentation
45#[macro_export]
46macro_rules! cloned {
47    ($i:ident as $alias:ident) => {
48        let $alias = $i.clone();
49    };
50    (mut $i:ident as $alias:ident) => {
51        let mut $alias = $i.clone();
52    };
53    ($i:ident as $alias:ident, $($tt:tt)*) => {
54        cloned!($i as $alias);
55        cloned!($($tt)*);
56    };
57    (mut $i:ident as $alias:ident, $($tt:tt)*) => {
58        cloned!(mut $i as $alias);
59        cloned!($($tt)*);
60    };
61    ($this:ident . $i:ident as $alias:ident) => {
62        let $alias = $this.$i.clone();
63    };
64    (mut $this:ident . $i:ident as $alias:ident) => {
65        let mut $alias = $this.$i.clone();
66    };
67    ($this:ident . $i:ident as $alias:ident, $($tt:tt)*) => {
68        cloned!($this . $i as $alias);
69        cloned!($($tt)*);
70    };
71    (mut $this:ident . $i:ident as $alias:ident, $($tt:tt)*) => {
72        cloned!(mut $this . $i as $alias);
73        cloned!($($tt)*);
74    };
75
76    ($i:ident) => {
77        cloned!($i as $i)
78    };
79    (mut $i:ident) => {
80        cloned!(mut $i as $i)
81    };
82    ($i:ident, $($tt:tt)*) => {
83        cloned!($i as $i);
84        cloned!($($tt)*);
85    };
86    (mut $i:ident, $($tt:tt)*) => {
87        cloned!(mut $i);
88        cloned!($($tt)*);
89    };
90
91    ($this:ident . $i:ident) => {
92        cloned!($this.$i as $i)
93    };
94    (mut $this:ident . $i:ident) => {
95        let mut $i = $this.$i.clone();
96    };
97    ($this:ident . $i:ident, $($tt:tt)*) => {
98        cloned!($this . $i as $i);
99        cloned!($($tt)*);
100    };
101    (mut $this:ident . $i:ident, $($tt:tt)*) => {
102        cloned!(mut $this . $i);
103        cloned!($($tt)*);
104    };
105
106    // Handle trailing ','
107    () => {};
108}
109
110#[cfg(test)]
111mod tests {
112    struct A {
113        x: String,
114    }
115
116    impl A {
117        #[allow(clippy::let_and_return)]
118        fn foo(&self) -> String {
119            cloned!(self.x);
120            x
121        }
122    }
123
124    #[test]
125    fn test() {
126        let a = A {
127            x: "I am a struct".into(),
128        };
129        let y: String = "that can".into();
130        let z: String = "talk a lot".into();
131        {
132            cloned!(a.x, y, mut z);
133            let _ = a.foo();
134            assert_eq!(&format!("{x} {y} {z}"), "I am a struct that can talk a lot");
135            z = String::new();
136            assert_eq!(z, "");
137        }
138    }
139
140    #[test]
141    #[allow(unused_variables, unused_assignments)]
142    fn test_mut() {
143        let a = 1;
144        let b = 2;
145        let c = A {
146            x: "foo".to_string(),
147        };
148
149        cloned!(mut a);
150        a += 1;
151        cloned!(mut a, b);
152        a += 1;
153        cloned!(a, mut b);
154        b += 1;
155        cloned!(mut c.x);
156        x += "bar";
157        cloned!(c.x, mut a);
158        a += 1;
159        cloned!(a, mut c.x);
160        x += "bar";
161    }
162
163    #[test]
164    fn trailing_comma() {
165        let a = 1;
166        let b = 2;
167
168        cloned!(a, b,);
169
170        assert_eq!((a, b), (1, 2))
171    }
172
173    #[test]
174    fn trailing_comma_mut() {
175        let a = 1;
176        let b = 2;
177
178        cloned!(a, mut b,);
179
180        b += 2;
181
182        assert_eq!((a, b), (1, 4))
183    }
184
185    #[test]
186    #[allow(unused_variables, unused_mut)]
187    fn aliases() {
188        let a = 1;
189        let b = 2;
190        let c = A {
191            x: "foo".to_string(),
192        };
193
194        cloned!(a as a2);
195        cloned!(a as a2,);
196        cloned!(mut a as a2);
197        cloned!(mut a as a2,);
198        cloned!(c.x as x2);
199        cloned!(c.x as x2,);
200        cloned!(mut c.x as x2);
201        cloned!(mut c.x as x2,);
202
203        cloned!(a, a as a2);
204        cloned!(a, a as a2,);
205        cloned!(a, mut a as a2);
206        cloned!(a, mut a as a2,);
207        cloned!(a, c.x as x2);
208        cloned!(a, c.x as x2,);
209        cloned!(a, mut c.x as x2);
210        cloned!(a, mut c.x as x2,);
211    }
212}