copy_impl/
lib.rs

1//Copyright (c) 2021-2024 #UlinProject (Denis Kotlyarov)
2
3
4//-----------------------------------------------------------------------------
5//Licensed under the Apache License, Version 2.0 (the "License");
6//you may not use this file except in compliance with the License.
7//You may obtain a copy of the License at
8
9//	   http://www.apache.org/licenses/LICENSE-2.0
10
11//Unless required by applicable law or agreed to in writing, software
12//distributed under the License is distributed on an "AS IS" BASIS,
13//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14//See the License for the specific language governing permissions and
15// limitations under the License.
16//-----------------------------------------------------------------------------
17
18// or
19
20//-----------------------------------------------------------------------------
21//Permission is hereby granted, free of charge, to any person obtaining a copy
22//of this software and associated documentation files (the "Software"), to deal
23//in the Software without restriction, including without limitation the rights
24//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
25//copies of the Software, and to permit persons to whom the Software is
26//furnished to do so, subject to the following conditions:
27
28//The above copyright notice and this permission notice shall be included in all
29//copies or substantial portions of the Software.
30
31//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
37//SOFTWARE.
38
39/*!
40Macro for effortlessly duplicating impl block code across various types in Rust.
41
42## Example:
43
44```rust
45use std::{error::Error, fmt::Write};
46use copy_impl::copy_impl;
47
48struct CustomNum<T>(T);
49struct UncheckedCustomNum<T>(T);
50
51copy_impl! {
52	impl (CustomNum<i8>),
53	impl (CustomNum<i16>),
54	impl (CustomNum<i32>),
55	impl (UncheckedCustomNum<i8>),
56	impl (UncheckedCustomNum<i16>) {
57		pub fn write_to(&self, mut w: impl Write) -> Result<(), std::fmt::Error> {
58			write!(w, "{}", self.0)
59		}
60	}
61}
62
63fn main() -> Result<(), Box<dyn Error>> {
64	let mut tbuff = String::new();
65	CustomNum(1i8).write_to(&mut tbuff)?;
66	CustomNum(2i16).write_to(&mut tbuff)?;
67	CustomNum(3i32).write_to(&mut tbuff)?;
68	
69	UncheckedCustomNum(4i8).write_to(&mut tbuff)?;
70	UncheckedCustomNum(5i16).write_to(&mut tbuff)?;
71	// UncheckedCustomNum(6i32).write_to(&mut tbuff)?;
72	/*
73		no method named `write_to` found for struct `UncheckedCustomNum<i32>` in the current scope
74		the method was found for
75		- `UncheckedCustomNum<i8>`
76		- `UncheckedCustomNum<i16>`
77	*/
78	
79	assert_eq!(tbuff, "12345");
80	
81	Ok(())
82}
83```
84
85*/
86
87#![no_std]
88
89///
90/// Macro for easily copying impl block code for different types.
91/// ```rust
92/// use std::{error::Error, fmt::Write};
93/// use copy_impl::copy_impl;
94/// 
95/// struct CustomNum<T>(T);
96/// struct UncheckedCustomNum<T>(T);
97/// 
98/// copy_impl! {
99/// 	impl (CustomNum<i8>),
100/// 	impl (CustomNum<i16>),
101/// 	impl (CustomNum<i32>),
102/// 	impl (UncheckedCustomNum<i8>),
103/// 	impl (UncheckedCustomNum<i16>) {
104/// 		pub fn write_to(&self, mut w: impl Write) -> Result<(), std::fmt::Error> {
105/// 			write!(w, "{}", self.0)
106/// 		}
107/// 	}
108/// }
109/// ```
110#[macro_export]
111macro_rules! copy_impl {
112	[ /* COLD_START */
113		impl $(<$($p_impl:tt)*>)? ($($impl:tt)*) $(where ($($where:tt)*))?
114		
115		$($all:tt)*
116	] => {
117		$crate::copy_impl! {
118			[ // the COLD_START!
119				[
120					/* COPY_IMPL_DATA */
121					[ 
122						[ $($($p_impl)*)? ] // <T>
123						[ $($impl)* ] // impldata
124						[ $($($where)*)? ]
125					]
126				]
127			]
128			
129			$($all)*
130		}
131	};
132	
133	[ /* HOT_CONTINUE */
134		[
135			[
136				/* COPY_IMPL_DATA */
137				$($all_copy_impl_data:tt)+
138			]
139		]
140		
141		, impl $(<$($p_impl:tt)*>)? ($($impl:tt)*) $(where ($($where:tt)*))?
142		
143		$($all:tt)*
144	] => {
145		$crate::copy_impl! {
146			[
147				[
148					/* COPY_IMPL_DATA */
149					$($all_copy_impl_data)+
150					
151					[ 
152						[ $($($p_impl)*)? ] // <T>
153						[ $($impl)* ] // impldata
154						[ $($($where)*)? ]
155					]
156					/* all */
157				]
158			]
159			
160			$($all)*
161		}
162	};
163	
164	[ /* skip (,) */
165		[
166			[
167				/* COPY_IMPL_DATA */
168				$($all_copy_impl_data:tt)*
169			]
170		]
171		,
172		
173		$($all:tt)*
174	] => {
175		$crate::copy_impl! {
176			[
177				[
178					/* COPY_IMPL_DATA */
179					$($all_copy_impl_data)*
180				]
181			]
182			
183			$($all)*
184		}
185	};
186	
187	[ // END HEADERS(IMPL), the CODE!
188		[
189			[ /* COPY_IMPL_DATA */
190				$([
191					[ $($p_impl:tt)* ]
192					[ $($impl:tt)* ]
193					[ $($where:tt)* ]
194				])+
195			]
196		]
197		{ $($code:tt)* }
198		
199		$(
200			; $($all:tt)*
201		)?
202	] => {
203		$crate::__internal_make_copy_impl! {
204			[]
205			[$($code)*] ->
206			
207			$([
208				[$($p_impl)*] // <T>
209				[$($impl)*] // impldata
210				[$($where)*]
211			])+
212		}
213		
214		$(
215			$crate::copy_impl! {
216				$($all)*
217			}
218		)?
219	};
220	
221	[ $(;)? ] => {};
222	
223	[ /* UNK */ $($all:tt)+ ] => {
224		compile_error!(stringify!(
225			$($all)+
226		));
227	}
228}
229
230#[macro_export]
231#[doc(hidden)]
232macro_rules! __internal_make_copy_impl {
233	[
234		[
235			/* RARRAY */
236			$($rarray:tt)*
237		]
238		[$($code:tt)*] ->
239		
240		[ [$($p_impl:tt)*][$($impl:tt)*][$($where:tt)*] ]
241		$($unk:tt)*
242	] => {
243		$crate::__internal_make_copy_impl! {
244			[
245				$($rarray)*
246				[
247					[$($p_impl)*]
248					[$($impl)*]
249					[$($where)*]
250					[$($code)*]
251				]
252			]
253			[$($code)*] ->
254			
255			$($unk)*
256		}
257	};
258	[
259		[
260			$([
261				[$($p_impl:tt)*]
262				[$($impl:tt)*]
263				[$($where:tt)*]
264				[$($code:tt)*]
265			])*
266		]
267		[$($_code:tt)*] ->
268	] => {
269		$(
270			impl $(<$($p_impl)*>)? $($impl)* $(where $($where)*)? {
271				$($code)*
272			}
273		)*
274	}
275}