wiwi_macro_decl/
with_cloned.rs

1#[macro_export]
2macro_rules! with_cloned {
3	($($stuff:tt)*) => {
4		// hide potential distracting implementation details in docs
5		$crate::__with_cloned_impl! { $($stuff)* }
6	}
7}
8
9/// implementation detail only, do not use
10#[doc(hidden)]
11#[macro_export]
12macro_rules! __with_cloned_impl {
13	{ _ in $($stuff:tt)* } => {
14		{
15			// easier "removing" of the macro, eg. in case it's like, in some
16			// heavily nested code, cause agh that's pain to remove and sometimes
17			// you just want to keep prototyping or whatever you're doing :p
18			$($stuff)*
19		}
20	};
21
22	{ mut $($thing:ident),+ in $($stuff:tt)* } => {
23		{
24			$(
25				// we only support specifying mut for all or nothing, so this is for
26				// when caller is using mut for some but not all vars need to be mut
27				#[allow(unused_mut)]
28				let mut $thing = ::core::clone::Clone::clone(&$thing);
29			)+
30			$($stuff)*
31		}
32	};
33
34	{ $($thing:ident),+ in $($stuff:tt)* } => {
35		{
36			$(
37				let $thing = ::core::clone::Clone::clone(&$thing);
38			)+
39			$($stuff)*
40		}
41	};
42}
43
44#[macro_export]
45macro_rules! with_cloned_2 {
46	($($stuff:tt)*) => {
47		// hide potential distracting implementation details in docs
48		$crate::__with_cloned_impl_2! { $($stuff)* }
49	}
50}
51
52#[doc(hidden)]
53#[macro_export]
54macro_rules! __with_cloned_impl_2 {
55	{ $(,)? in $($stuff:tt)* } => {
56		{
57			$($stuff)*
58		}
59	};
60
61	{ $(,)? _ $($rest:tt)* } => {
62		{
63			$crate::__with_cloned_impl_2! { $($rest)* }
64		}
65	};
66
67	{ $(,)? mut &$thing:ident $($rest:tt)* } => {
68		{
69			let mut $thing = ::core::clone::Clone::clone($thing);
70			$crate::__with_cloned_impl_2! { $($rest)* }
71		}
72	};
73
74	{ $(,)? mut $thing:ident $($rest:tt)* } => {
75		{
76			let mut $thing = ::core::clone::Clone::clone(&$thing);
77			$crate::__with_cloned_impl_2! { $($rest)* }
78		}
79	};
80
81	{ $(,)? &$thing:ident $($rest:tt)* } => {
82		{
83			let $thing = ::core::clone::Clone::clone($thing);
84			$crate::__with_cloned_impl_2! { $($rest)* }
85		}
86	};
87
88	{ $(,)? $thing:ident $($rest:tt)* } => {
89		{
90			let $thing = ::core::clone::Clone::clone(&$thing);
91			$crate::__with_cloned_impl_2! { $($rest)* }
92		}
93	};
94}
95
96#[macro_export]
97macro_rules! with_cloned_3 {
98	($($stuff:tt)*) => {
99		// hide potential distracting implementation details in docs
100		$crate::__with_cloned_impl_3! { $($stuff)* }
101	}
102}
103
104#[doc(hidden)]
105#[macro_export]
106macro_rules! __with_cloned_impl_3 {
107	{ _ => $rest:expr } => {
108		$rest
109	};
110
111	// arbitrary complex expr, with seperate ident
112
113	{ mut $name:ident = $thing:expr => $rest:expr } => {
114		{
115			let mut $name = ::core::clone::Clone::clone(&$thing);
116			$rest
117		}
118	};
119
120	{ $name:ident = $thing:expr => $rest:expr } => {
121		{
122			let $name = ::core::clone::Clone::clone(&$thing);
123			$rest
124		}
125	};
126
127	{ mut $name:ident = $thing:expr, $($rest:tt)* } => {
128		{
129			let mut $name = ::core::clone::Clone::clone(&$thing);
130			$crate::__with_cloned_impl_3! { $($rest)* }
131		}
132	};
133
134	{ $name:ident = $thing:expr, $($rest:tt)* } => {
135		{
136			let $name = ::core::clone::Clone::clone(&$thing);
137			$crate::__with_cloned_impl_3! { $($rest)* }
138		}
139	};
140
141	// deref once
142
143	{ mut *$thing:ident => $rest:expr } => {
144		{
145			let mut $thing = ::core::clone::Clone::clone($thing);
146			$rest
147		}
148	};
149
150	{ *$thing:ident => $rest:expr } => {
151		{
152			let $thing = ::core::clone::Clone::clone($thing);
153			$rest
154		}
155	};
156
157	{ mut *$thing:ident, $($rest:tt)* } => {
158		{
159			let mut $thing = ::core::clone::Clone::clone($thing);
160			$crate::__with_cloned_impl_3! { $($rest)* }
161		}
162	};
163
164	{ *$thing:ident, $($rest:tt)* } => {
165		{
166			let $thing = ::core::clone::Clone::clone($thing);
167			$crate::__with_cloned_impl_3! { $($rest)* }
168		}
169	};
170
171	// deref twice
172
173	{ mut **$thing:ident => $rest:expr } => {
174		{
175			let mut $thing = ::core::clone::Clone::clone(*$thing);
176			$rest
177		}
178	};
179
180	{ **$thing:ident => $rest:expr } => {
181		{
182			let $thing = ::core::clone::Clone::clone(*$thing);
183			$rest
184		}
185	};
186
187	{ mut **$thing:ident, $($rest:tt)* } => {
188		{
189			let mut $thing = ::core::clone::Clone::clone(*$thing);
190			$crate::__with_cloned_impl_3! { $($rest)* }
191		}
192	};
193
194	{ **$thing:ident, $($rest:tt)* } => {
195		{
196			let $thing = ::core::clone::Clone::clone(*$thing);
197			$crate::__with_cloned_impl_3! { $($rest)* }
198		}
199	};
200
201	// simple ident (a la original `with_cloned!`)
202
203	{ mut $thing:ident => $rest:expr } => {
204		{
205			let mut $thing = ::core::clone::Clone::clone(&$thing);
206			$rest
207		}
208	};
209
210	{ $thing:ident => $rest:expr } => {
211		{
212			let $thing = ::core::clone::Clone::clone(&$thing);
213			$rest
214		}
215	};
216
217	{ mut $thing:ident, $($rest:tt)* } => {
218		{
219			let mut $thing = ::core::clone::Clone::clone(&$thing);
220			$crate::__with_cloned_impl_3! { $($rest)* }
221		}
222	};
223
224	{ $thing:ident, $($rest:tt)* } => {
225		{
226			let $thing = ::core::clone::Clone::clone(&$thing);
227			$crate::__with_cloned_impl_3! { $($rest)* }
228		}
229	};
230}
231
232#[macro_export]
233macro_rules! with_cloned_4 {
234	($($stuff:tt)*) => {
235		// hide potential distracting implementation details in docs
236		$crate::__with_cloned_impl_4! { $($stuff)* }
237	}
238}
239
240#[doc(hidden)]
241#[macro_export]
242macro_rules! __with_cloned_impl_4 {
243	// dud case
244	{ _ => $expr:expr } => { $expr };
245
246	// api, arbitrary expr with provided ident, more args
247	{ mut $item:ident = $expr:expr, $($rest:tt)* } => {
248		$crate::__with_cloned_impl_4! { @impl mut { $item } { $($expr)* }, $($rest)* }
249	};
250	{ $item:ident = $expr:expr, $($rest:tt)* } => {
251		$crate::__with_cloned_impl_4! { @impl { $item } { $($expr)* }, $($rest)* }
252	};
253
254	// api, arbitrary expr with provided ident, final arg
255	{ mut $item:ident = $expr:expr => $body:expr } => {
256		$crate::__with_cloned_impl_4! { @impl mut { $item } { $expr } => $body }
257	};
258	{ $item:ident = $expr:expr => $body:expr } => {
259		$crate::__with_cloned_impl_4! { @impl { $item } { $expr } => $body }
260	};
261
262	// api, parens wrapped arbitrary expr
263	{ mut ($($expr:tt)*) $($rest:tt)* } => {
264		$crate::__with_cloned_impl_4! { @impl mut {} { $($expr)* } { $($expr)* } $($rest)* }
265	};
266	{ ($($expr:tt)*) $($rest:tt)* } => {
267		$crate::__with_cloned_impl_4! { @impl {} { $($expr)* } { $($expr)* } $($rest)* }
268	};
269
270	// api, one deref
271	{ mut *$item:ident $($rest:tt)* } => {
272		$crate::__with_cloned_impl_4! { @impl mut { $item } { *$item } $($rest)* }
273	};
274	{ *$item:ident $($rest:tt)* } => {
275		$crate::__with_cloned_impl_4! { @impl { $item } { *$item } $($rest)* }
276	};
277
278	// api, two derefs
279	{ mut **$item:ident $($rest:tt)* } => {
280		$crate::__with_cloned_impl_4! { @impl mut { $item } { **$item } $($rest)* }
281	};
282	{ **$item:ident $($rest:tt)* } => {
283		$crate::__with_cloned_impl_4! { @impl { $item } { **$item } $($rest)* }
284	};
285
286	// api, field access
287	{ mut $parent:ident.$item:ident $($rest:tt)* } => {
288		$crate::__with_cloned_impl_4! { @impl mut { $item } { $parent.$item } $($rest)* }
289	};
290	{ $parent:ident.$item:ident $($rest:tt)* } => {
291		$crate::__with_cloned_impl_4! { @impl { $item } { $parent.$item } $($rest)* }
292	};
293
294	// api, ident
295	{ mut $item:ident $($rest:tt)* } => {
296		$crate::__with_cloned_impl_4! { @impl mut { $item } { $item } $($rest)* }
297	};
298	{ $item:ident $($rest:tt)* } => {
299		$crate::__with_cloned_impl_4! { @impl { $item } { $item } $($rest)* }
300	};
301
302	// impl, base case, more args
303	{ @impl mut { $item:ident } { $expr:expr }, $($rest:tt)* } => {
304		{
305			let mut $item = ::core::clone::Clone::clone(&$expr);
306			$crate::__with_cloned_impl_4! { $($rest)* }
307		}
308	};
309	{ @impl { $item:ident } { $expr:expr }, $($rest:tt)* } => {
310		{
311			let $item = ::core::clone::Clone::clone(&$expr);
312			$crate::__with_cloned_impl_4! { $($rest)* }
313		}
314	};
315
316	// impl, base case, final arg
317	{ @impl mut { $item:ident } { $expr:expr } => $body:expr } => {
318		{
319			let mut $item = ::core::clone::Clone::clone(&$expr);
320			$body
321		}
322	};
323	{ @impl { $item:ident } { $expr:expr } => $body:expr } => {
324		{
325			let $item = ::core::clone::Clone::clone(&$expr);
326			$body
327		}
328	};
329
330	// impl, ident
331	{ @impl mut {} { $item:ident } { $expr:expr } $($rest:tt)* } => {
332		$crate::__with_cloned_impl_4! { @impl mut { $item } { $expr } $($rest)* }
333	};
334	{ @impl {} { $item:ident } { $expr:expr } $($rest:tt)* } => {
335		$crate::__with_cloned_impl_4! { @impl { $item } { $expr } $($rest)* }
336	};
337
338	// impl, deref
339	{ @impl mut {} { *$($item_rest:tt)* } { $expr:expr } $($rest:tt)* } => {
340		$crate::__with_cloned_impl_4! { @impl mut {} { $($item_rest)* } { $expr } $($rest)* }
341	};
342	{ @impl {} { *$($item_rest:tt)* } { $expr:expr } $($rest:tt)* } => {
343		$crate::__with_cloned_impl_4! { @impl {} { $($item_rest)* } { $expr } $($rest)* }
344	};
345
346	// impl, `as_ref` case
347	{ @impl mut {} { $item:ident.as_ref() $($item_rest:tt)* } { $expr:expr } $($rest:tt)* } => {
348		$crate::__with_cloned_impl_4! { @impl mut {} { $item $($item_rest)* } { $expr } $($rest)* }
349	};
350	{ @impl {} { $item:ident.as_ref() $($item_rest:tt)* } { $expr:expr } $($rest:tt)* } => {
351		$crate::__with_cloned_impl_4! { @impl {} { $item $($item_rest)* } { $expr } $($rest)* }
352	};
353
354	// impl, `as_mut` case
355	{ @impl mut {} { $item:ident.as_mut() $($item_rest:tt)* } { $expr:expr } $($rest:tt)* } => {
356		$crate::__with_cloned_impl_4! { @impl mut {} { $item $($item_rest)* } { $expr } $($rest)* }
357	};
358	{ @impl {} { $item:ident.as_mut() $($item_rest:tt)* } { $expr:expr } $($rest:tt)* } => {
359		$crate::__with_cloned_impl_4! { @impl {} { $item $($item_rest)* } { $expr } $($rest)* }
360	};
361
362	// impl, fn call
363	{ @impl mut {} { $item:ident($($args:tt)*) $($item_rest:tt)* } { $expr:expr } $($rest:tt)* } => {
364		$crate::__with_cloned_impl_4! { @impl mut {} { $item $($item_rest)* } { $expr } $($rest)* }
365	};
366	{ @impl {} { $item:ident($($args:tt)*) $($item_rest:tt)* } { $expr:expr } $($rest:tt)* } => {
367		$crate::__with_cloned_impl_4! { @impl {} { $item $($item_rest)* } { $expr } $($rest)* }
368	};
369
370	// impl, field access
371	{ @impl mut {} { $parent:ident.$($item_rest:tt)* } { $expr:expr } $($rest:tt)* } => {
372		$crate::__with_cloned_impl_4! { @impl mut {} { $($item_rest)* } { $expr } $($rest)* }
373	};
374	{ @impl {} { $parent:ident.$($item_rest:tt)* } { $expr:expr } $($rest:tt)* } => {
375		$crate::__with_cloned_impl_4! { @impl {} { $($item_rest)* } { $expr } $($rest)* }
376	};
377
378	// impl, short circuit op
379	{ @impl mut {} { $item:ident? $($item_rest:tt)* } { $expr:expr } $($rest:tt)* } => {
380		$crate::__with_cloned_impl_4! { @impl mut {} { $item $($item_rest)* } { $expr } $($rest)* }
381	};
382	{ @impl {} { $item:ident? $($item_rest:tt)* } { $expr:expr } $($rest:tt)* } => {
383		$crate::__with_cloned_impl_4! { @impl {} { $item $($item_rest)* } { $expr } $($rest)* }
384	};
385
386	// impl, parens wrapped expr
387	{ @impl mut {} { ($($item:tt)*) $($item_rest:tt)* } { $expr:expr } $($rest:tt)* } => {
388		$crate::__with_cloned_impl_4! { @impl mut {} { $($item)* $($item_rest)* } { $expr } $($rest)* }
389	};
390	{ @impl {} { ($($item:tt)*) $($item_rest:tt)* } { $expr:expr } $($rest:tt)* } => {
391		$crate::__with_cloned_impl_4! { @impl {} { $($item)* $($item_rest)* } { $expr } $($rest)* }
392	};
393
394	{} => { compile_error! { "uwu" } };
395}
396
397// #[cfg(test)]
398// mod tests {
399// 	extern crate rand;
400//
401// 	use crate::prelude_std::*;
402// 	use super::*;
403// 	use rand::thread_rng;
404// 	use rand::distributions::uniform::SampleRange;
405// 	use std::sync::Mutex;
406// 	use std::thread;
407//
408// 	#[test]
409// 	fn it_works() {
410// 		let thing = Arc::new(Mutex::new(5));
411//
412// 		let join_handles = (1..=5)
413// 			// no need to use clone on everything, so the macro does work as expected
414// 			.map(|i| with_cloned! { thing in
415// 				thread::spawn(move || {
416// 					thread::sleep(std::time::Duration::from_millis((0..1000).sample_single(&mut thread_rng())));
417// 					*thing.lock().unwrap() *= i;
418// 				})
419// 			})
420// 			.collect::<Vec<_>>();
421// 		let expected_result = 5 * 1 * 2 * 3 * 4 * 5;
422//
423// 		// but we still run it through to make sure we get expected result still,
424// 		// and nothing else weird went wrong or something
425// 		join_handles.into_iter().for_each(|t| t.join().unwrap());
426// 		assert_eq!(expected_result, *thing.lock().unwrap());
427// 	}
428// }