enclose/
lib.rs

1//Copyright (c) 2019-2025 #UlinProject Denis Kotlyarov (Денис Котляров)
2
3//-----------------------------------------------------------------------------
4//Licensed under the Apache License, Version 2.0 (the "License");
5//you may not use this file except in compliance with the License.
6//You may obtain a copy of the License at
7
8//	   http://www.apache.org/licenses/LICENSE-2.0
9
10//Unless required by applicable law or agreed to in writing, software
11//distributed under the License is distributed on an "AS IS" BASIS,
12//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13//See the License for the specific language governing permissions and
14// limitations under the License.
15//-----------------------------------------------------------------------------
16
17// or
18
19//-----------------------------------------------------------------------------
20//Permission is hereby granted, free of charge, to any person obtaining a copy
21//of this software and associated documentation files (the "Software"), to deal
22//in the Software without restriction, including without limitation the rights
23//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24//copies of the Software, and to permit persons to whom the Software is
25//furnished to do so, subject to the following conditions:
26
27//The above copyright notice and this permission notice shall be included in all
28//copies or substantial portions of the Software.
29
30//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
33//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
36//SOFTWARE.
37
38// #Ulin Project 1819 2025
39
40/*!
41A convenient macro, for cloning values into a closure.
42
43### Use
44
45Just use it!
46
47```rust
48use enclose::enclose;
49
50fn main() {
51	let clone_data = 0;
52	let add_data = 100;
53
54	my_enclose( enclose!((mut clone_data, add_data) || {
55		// (mut clone_data, add_data) ->
56		// let mut clone_data = clone_data.clone();
57		// let add_data = add_data.clone();
58
59		println!("#0 {:?}", clone_data);
60		clone_data += add_data;
61		println!("#1 {:?}", clone_data);
62
63		assert_eq!(clone_data, 100);
64	}));
65
66	assert_eq!(clone_data, 0);
67}
68
69fn my_enclose<F: FnOnce() -> R, R>(a: F) -> R {
70	a()
71}
72```
73
74### MutexUse
75
76Creating closures for a multi-threaded environment, no extra lines!
77
78```rust
79use std::sync::Arc;
80use std::sync::Mutex;
81use std::thread;
82
83use enclose::enclose;
84
85fn main() {
86	let mutex_data = Arc::new(Mutex::new( 0 ));
87	let thread = thread::spawn( enclose!((mutex_data => d) move || {
88		// (mutex_data => d) ->
89		// let d = mutex_data.clone();
90
91		let mut lock = match d.lock() {
92			Ok(a) => a,
93			Err(e) => e.into_inner(),
94		};
95		*lock += 1;
96	}));
97
98	thread.join().unwrap();
99	{
100		let lock = match mutex_data.lock() {
101			Ok(a) => a,
102			Err(e) => e.into_inner(),
103		};
104		assert_eq!(*lock, 1);
105	}
106}
107```
108
109### ArcMutexUse
110
111A more complex example of using an enclose macro in a multi-threaded environment.
112
113```rust
114use std::sync::Arc;
115use std::sync::Mutex;
116use std::sync::RwLock;
117use std::thread;
118
119use enclose::enclose;
120
121fn main() {
122	let data1 = Arc::new(Mutex::new( 0 ));
123	let data2 = Arc::new(RwLock::new( (0, 2, 3, 4) ));
124
125	let count_thread = 5;
126	let mut waits = Vec::with_capacity(count_thread);
127
128	for _a in 0..count_thread {
129		waits.push({
130			thread::spawn( enclose!((data1, data2) move || {
131				// (data1, data2) ->
132				// let data1 = data1.clone();
133				// let data2 = data2.clone();
134
135				let mut v_lock = match data1.lock() {
136					Ok(a) => a,
137					Err(e) => e.into_inner(),
138				};
139				*v_lock += 1;
140
141				drop( data2 ); // ignore warning
142			}))
143		});
144	}
145	for a in waits {
146		a.join().unwrap();
147	}
148
149
150	{
151		// Check data1_lock
152		let data1_lock = match data1.lock() {
153			Ok(a) => a,
154			Err(e) => e.into_inner(),
155		};
156		assert_eq!(*data1_lock, 5);
157	}
158
159	{
160		// Check data2_lock
161		let data2_lock = match data2.write() {
162			Ok(a) => a,
163			Err(e) => e.into_inner(),
164		};
165		assert_eq!(*data2_lock, (0, 2, 3, 4));
166	}
167}
168```
169
170### EasyCopy
171
172Using copy instead of clone.
173
174```rust
175use enclose::enclose;
176use std::sync::Arc;
177
178fn main() {
179	let clone_data = Arc::new(0);
180	let add_data = Arc::new(100);
181
182	my_enclose( enclose!((mut *clone_data, *add_data) || {
183		// (mut *clone_data, *add_data)
184		// let mut clone_data = *clone_data;
185		// let add_data = *add_data;
186
187		println!("#0 {:?}", clone_data);
188		clone_data += add_data;
189		println!("#1 {:?}", clone_data);
190
191		assert_eq!(clone_data, 100);
192	}));
193
194	assert_eq!(*clone_data, 0);
195}
196
197fn my_enclose<F: FnOnce() -> R, R>(a: F) -> R {
198	a()
199}
200```
201
202*/
203
204#![no_std]
205#![allow(clippy::tabs_in_doc_comments)]
206#![allow(clippy::needless_doctest_main)]
207
208mod var;
209
210/// A macro for creating a closure, as well as cloning,
211/// copying values into the closure.
212///
213/// ## Args Support
214///
215/// A list of all possible arguments that can be written, separated by commas,
216/// in the arguments to the macro.
217///
218/// ### `.clone()` operation
219/// ```code
220/// // (a => mut b: String) will be converted to (let mut b: String = a.clone();)
221/// // (b => mut b)
222/// // (a => b: usize)
223/// // (a => b)
224/// // (mut a: String)
225/// // (mut a)
226/// // (a: String)
227/// // (a)
228/// ```
229///
230/// ### `*copy` operation
231/// ```code
232/// // (*a => mut b: &str) will be converted to (let mut b: &str = *a;)
233/// // (*a => mut b)
234/// // (*a => b: &str)
235/// // (*a => b)
236/// // (mut *a: &str)
237/// // (mut *a)
238/// // (*a: &str)
239/// // (*a)
240/// ```
241///
242/// ### `let ref mut a = b;` (`ref`) operation
243/// ```code
244/// // (ref mut a: String) will be converted to (let ref mut a: String = a;)
245/// // (ref mut a)
246/// // (ref a: String)
247/// // (ref a)
248/// // (ref a => mut b: String)
249/// // (ref a => mut b)
250/// // (ref a => b: String)
251/// // (ref a => b)
252/// ```
253///
254/// ### `(1+1)` (expr) operation
255/// ```code
256/// // (@(1+1) => mut b: usize) will be converted to (let mut b: usize = (1+1);)
257/// // (@(1+1) => mut b)
258/// // (@(1+1) => b: usize)
259/// // (@(1+1) => b)
260/// ```
261///
262/// ### `let a = b;` (move) operation
263/// ```code
264/// // (move a => mut b: String) will be converted to (let mut b: String = a;)
265/// // (move a => mut b)
266/// // (move a => mut b)
267/// // (move a => b: String)
268/// // (move a => b)
269/// // (move mut a: String)
270/// // (move mut a)
271/// // (move a: String)
272/// // (move a)
273/// ```
274///
275/// ### `{println!("test");}` (run) operation
276/// ```code
277/// // { panic!("12"); }
278/// ```
279///
280/// ## Example
281///
282/// ### JustUse
283///
284/// ```rust
285/// use enclose::enclose;
286///
287///fn main() {
288///	let clone_data = 0;
289///	let add_data = 100;
290///
291///	my_enclose(enclose!((mut clone_data, add_data) || {
292///		// (mut clone_data, add_data) ->
293///		// let mut clone_data = clone_data.clone();
294///		// let add_data = add_data.clone();
295///
296///		println!("#0 {:?}", clone_data);
297///		clone_data += add_data;
298///		println!("#1 {:?}", clone_data);
299///
300///		assert_eq!(clone_data, 100);
301///	}));
302///
303///	assert_eq!(clone_data, 0);
304///}
305///
306///#[inline]
307///fn my_enclose<F: FnOnce() -> R, R>(a: F) -> R {
308///	a()
309///}
310///```
311///
312/// ### Expr
313///
314///```rust
315///use enclose::enclose;
316///use std::sync::Arc;
317///
318///fn main() {
319///	let clone_data = Arc::new(0);
320///	let add_data = Arc::new(100);
321///
322///	// I also note that any expressions can be used, but the main thing is to
323///	// put the @ symbol at the beginning of the variable, and not forget to assign
324///	// a new name to the variable using =>.
325///	my_enclose(
326///		enclose!((@*clone_data => mut clone_data: usize, @*(add_data.clone()) => add_data) || {
327///			// (@*clone_data => mut clone_data, @*(add_data.clone()) => add_data) ->
328///			// let mut clone_data = *clone_data;
329///			// let add_data = *(add_data.clone());
330///
331///			println!("#0 {:?}", clone_data);
332///			clone_data += add_data;
333///			println!("#1 {:?}", clone_data);
334///
335///			assert_eq!(clone_data, 100);
336///		}),
337///	);
338///
339///	assert_eq!(*clone_data, 0);
340///}
341///
342///#[inline]
343///fn my_enclose<F: FnOnce() -> R, R>(a: F) -> R {
344///	a()
345///}
346/// ```
347///
348#[macro_export]
349macro_rules! enclose {
350	[
351		// (a, b) async || true
352		( $($enc_args:tt)* ) async move || $($b:tt)*
353	] => {{ // async, empty args
354		$crate::enclose_var! {
355			$( $enc_args )*
356		}
357		async move || $($b)*
358	}};
359	[
360		// (a, b) async move |c, d| true
361		( $($enc_args:tt)* ) async move | $($args:tt),* | $($b:tt)*
362	] => {{ // async, args
363		$crate::enclose_var! {
364			$( $enc_args )*
365		}
366		async move | $($args),* | $($b)*
367	}};
368	[
369		// (a, b) async || true
370		( $($enc_args:tt)* ) async || $($b:tt)*
371	] => {{ // async, empty args
372		$crate::enclose_var! {
373			$( $enc_args )*
374		}
375		async || $($b)*
376	}};
377	[
378		// (a, b) async |c, d| true
379		( $($enc_args:tt)* ) async | $($args:tt),* | $($b:tt)*
380	] => {{ // async, args
381		$crate::enclose_var! {
382			$( $enc_args )*
383		}
384		async | $($args),* | $($b)*
385	}};
386	[
387		// (a, b) move || true
388		( $($enc_args:tt)* ) move || $($b:tt)*
389	] => {{ // move, empty args
390		$crate::enclose_var! {
391			$( $enc_args )*
392		}
393		move || $($b)*
394	}};
395	[
396		// (a, b) move |c, d| true
397		( $($enc_args:tt)* ) move | $($args:tt),* | $($b:tt)*
398	] => {{ // move, args
399		$crate::enclose_var! {
400			$( $enc_args )*
401		}
402		move | $($args),* | $($b)*
403	}};
404	[
405		// (a, b) || true
406		( $($enc_args:tt)* ) || $($b:tt)*
407	] => {{ // empty args
408		|| {
409			$crate::enclose_var! {
410				$( $enc_args )*
411			}
412
413			$($b)*
414		}
415	}};
416	[
417		// (a, b) |c, d| true
418		( $($enc_args:tt)* ) | $($args:tt),* | $($b:tt)*
419	] => {{ // args
420		| $($args),* | {
421			$crate::enclose_var! {
422				$( $enc_args )*
423			}
424
425			$($b)*
426		}
427	}};
428
429	[
430		// (a, b) true
431		( $($enc_args:tt)* ) $($all:tt)*
432	] => {{ // empty
433		$crate::enclose_var! {
434			$( $enc_args )*
435		}
436		$($all)*
437	}};
438
439	/*[ $($unk:tt)+ ] => {
440		compile_error!("Undefined entry or unsupported arguments, please double-check input.");
441	};*/
442	[] => {};
443}
444
445/// A macro for creating a closure, as well as cloning,
446/// copying values into the closure.
447///
448/// Alternative short record `enclose`.
449pub use enclose as enc;