1#![deny(warnings, missing_docs, clippy::all, rustdoc::broken_intra_doc_links)]
11
12#[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 () => {};
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}