Skip to main content

cba/baccarat/
define.rs

1#[macro_export]
2/// Implement a transparent wrapper around an inner type:
3///
4/// Implements Deref, DerefMut, FromStr, Display, Debug, PartialEq, Serialize, Deserialize.
5///
6/// # Example
7/// ```rust
8/// use cba::define_transparent_wrapper;
9///
10/// #[cfg(feature = "serde")]
11/// define_transparent_wrapper!(
12///     #[derive(Copy)]
13///     Count: u16 = 1
14/// );
15/// ```
16macro_rules! define_transparent_wrapper {
17    ($(#[$meta:meta])* $name:ident: $(#[$inner_meta:meta])* $inner:path $(= $default:expr)?) => {
18        $(#[$meta])*
19        #[derive(Debug, PartialEq)]
20        pub struct $name($(#[$inner_meta])* pub $inner);
21
22        $(
23            impl Default for $name {
24                fn default() -> Self {
25                    $name($default)
26                }
27            }
28        )?
29
30        // Conversions
31        impl From<$name> for $inner {
32            fn from(c: $name) -> Self {
33                c.0
34            }
35        }
36        impl From<$inner> for $name {
37            fn from(c: $inner) -> Self {
38                Self(c)
39            }
40        }
41
42        impl std::ops::Deref for $name {
43            type Target = $inner;
44            fn deref(&self) -> &Self::Target { &self.0 }
45        }
46        impl std::ops::DerefMut for $name {
47            fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
48        }
49    };
50}
51
52#[macro_export]
53/// Implement a restricted wrapper around an inner type:
54///
55/// Implements Deref, PartialEq, Clone, Debug, Serialize.
56///
57/// # Example
58/// ```rust
59/// use cba::define_restricted_wrapper;
60///
61/// #[cfg(feature = "serde")] {
62///     define_restricted_wrapper!(Percentage: u16 = 100);
63///     impl Percentage {
64///         pub fn new(value: u16) -> Self {
65///             if value <= 100 { Self(value) } else { Self(100) }
66///         }
67///     }
68/// }
69///
70/// ```
71macro_rules! define_restricted_wrapper {
72    ($(#[$meta:meta])* $name:ident: $(#[$inner_meta:meta])* $inner:path $(= $default:expr)?) => {
73        $(#[$meta])*
74        #[derive(Debug, PartialEq)]
75        pub struct $name($(#[$inner_meta])* $inner);
76
77        impl $name {
78            pub fn inner(&self) -> $inner {
79                self.0.clone()
80            }
81        }
82
83        $(
84            impl Default for $name {
85                fn default() -> Self {
86                    $name($default)
87                }
88            }
89        )?
90
91        impl From<$name> for $inner {
92            fn from(c: $name) -> Self {
93                c.0
94            }
95        }
96
97        impl std::ops::Deref for $name {
98            type Target = $inner;
99            fn deref(&self) -> &Self::Target { &self.0 }
100        }
101    };
102}
103
104#[macro_export]
105/// Implement a wrapper around a container type (i.e. HashMap).
106/// Implements the Deref, DerefMut, Default and IntoIterator/FromIterator traits and the new function.
107///
108/// ```rust
109/// use cba::define_collection_wrapper;
110/// pub struct Module {};
111/// define_collection_wrapper!(
112///     #[cfg_attr(feature = "serde", derive(Debug, serde::Serialize, serde::Deserialize))]
113///     Modules: std::collections::HashMap<String, Module>
114/// );
115/// ```
116macro_rules! define_collection_wrapper {
117    ($(#[$meta:meta])* $name:ident: $(#[$inner_meta:meta])* $inner:path) => {
118        $(#[$meta])*
119        pub struct $name($(#[$inner_meta])* $inner);
120
121        impl $name {
122            pub fn new() -> Self {
123                Self(<$inner>::new())
124            }
125        }
126
127        impl std::ops::Deref for $name {
128            type Target = $inner;
129
130            fn deref(&self) -> &Self::Target {
131                &self.0
132            }
133        }
134
135        impl std::ops::DerefMut for $name {
136            fn deref_mut(&mut self) -> &mut Self::Target {
137                &mut self.0
138            }
139        }
140
141        impl Default for $name {
142            fn default() -> Self {
143                Self(<$inner>::new())
144            }
145        }
146
147        impl From<$name> for $inner {
148            fn from(c: $name) -> Self {
149                c.0
150            }
151        }
152        impl From<$inner> for $name {
153            fn from(c: $inner) -> Self {
154                Self(c)
155            }
156        }
157
158        impl IntoIterator for $name {
159            type Item = <$inner as IntoIterator>::Item;
160            type IntoIter = <$inner as IntoIterator>::IntoIter;
161
162            fn into_iter(self) -> Self::IntoIter {
163                self.0.into_iter()
164            }
165        }
166
167        impl<'a> IntoIterator for &'a $name {
168            type Item = <&'a $inner as IntoIterator>::Item;
169            type IntoIter = <&'a $inner as IntoIterator>::IntoIter;
170
171            fn into_iter(self) -> Self::IntoIter {
172                (&self.0).into_iter()
173            }
174        }
175
176        // impl<'a> IntoIterator for &'a mut $name {
177        //     type Item = <&'a mut $inner as IntoIterator>::Item;
178        //     type IntoIter = <&'a mut $inner as IntoIterator>::IntoIter;
179
180        //     fn into_iter(self) -> Self::IntoIter {
181        //         (&mut self.0).into_iter()
182        //     }
183        // }
184
185        impl FromIterator<<$inner as IntoIterator>::Item> for $name {
186            fn from_iter<I: IntoIterator<Item = <$inner as IntoIterator>::Item>>(iter: I) -> Self {
187                Self(iter.into_iter().collect())
188            }
189        }
190    };
191}
192
193// would be kinda neat if rust supported pub ident: value, and value defines the type as well as sets the default.
194#[macro_export]
195macro_rules! define_const_default {
196    (
197        $(#[$meta:meta])*
198        $vis:vis struct $Name:ident {
199            $(
200                $(#[$field_meta:meta])*
201                $ivis:vis $field:ident : $ty:ty $(= $default:expr)?
202            ),* $(,)?
203        }
204    ) => {
205        $(#[$meta])*
206        $vis struct $Name {
207            $(
208                $(#[$field_meta])*
209                $ivis $field: $ty,
210            )*
211        }
212
213        impl $Name {
214            pub const DEFAULT: Self = Self {
215                $(
216                    $field: define_const_default!(@default $ty $(, $default)?),
217                )*
218            };
219        }
220
221        impl Default for $Name {
222            fn default() -> Self {
223                Self::DEFAULT
224            }
225        }
226    };
227
228    (@default $ty:ty, $default:expr) => {
229        $default
230    };
231
232    (@default $ty:ty) => {
233        <$ty>::DEFAULT
234    };
235}
236
237/// ```
238/// use cba::auto_impl;
239///
240/// #[derive(Debug)]
241/// pub struct InputUI {};
242///
243/// #[derive(Debug)]
244/// pub struct PromptOverlay(InputUI, usize);
245///
246/// auto_impl!(PromptOverlay => 0: Deref => InputUI; DerefMut);
247/// ```
248#[macro_export]
249macro_rules! auto_impl {
250    ($name:ident : $($trait:ident $(=> $target:ty)? $(= $val:expr)?);+ $(;)?) => {
251        $(
252            auto_impl!(@dispatch $name, 0, $trait $(, $target)? $(, $val)?);
253        )+
254    };
255
256    ($name:ident => $field:tt : $($trait:ident $(=> $target:ty)? $(= $val:expr)?);+ $(;)?) => {
257        $(
258            auto_impl!(@dispatch $name, $field, $trait $(, $target)? $(, $val)?);
259        )+
260    };
261
262    // ===== dispatch =====
263
264    (@dispatch $name:ident, $field:tt, Default, $val:expr) => {
265        impl Default for $name {
266            fn default() -> Self {
267                $val
268            }
269        }
270    };
271
272    (@dispatch $name:ident, $field:tt, $trait:ident) => {
273        auto_impl!(@impl $name, $field, $trait, <Self as std::ops::Deref>::Target);
274    };
275
276    (@dispatch $name:ident, $field:tt, $trait:ident, $target:ty) => {
277        auto_impl!(@impl $name, $field, $trait, $target);
278    };
279
280    // ===== impls =====
281
282    (@impl $name:ident, $field:tt, Deref, $target:ty) => {
283        impl std::ops::Deref for $name {
284            type Target = $target;
285
286            fn deref(&self) -> &Self::Target {
287                &self.$field
288            }
289        }
290    };
291
292    (@impl $name:ident, $field:tt, DerefMut, $target:ty) => {
293        impl std::ops::DerefMut for $name {
294            fn deref_mut(&mut self) -> &mut $target {
295                &mut self.$field
296            }
297        }
298    };
299
300    (@impl $name:ident, $field:tt, From, $inner:ty) => {
301        impl From<$inner> for $name {
302            fn from(value: $inner) -> Self {
303                Self(value)
304            }
305        }
306    };
307
308    (@impl $name:ident, $field:tt, Into, $inner:ty) => {
309        impl Into<$inner> for $name {
310            fn into(self) -> $inner {
311                self.$field
312            }
313        }
314    };
315
316    (@impl $name:ident, $field:tt, Display, $inner:ty) => {
317        impl std::fmt::Display for $name
318        where
319        $inner: std::fmt::Display,
320        {
321            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
322                std::fmt::Display::fmt(&self.$field, f)
323            }
324        }
325    };
326
327    (@impl $name:ident, $field:tt, FromStr, $inner:ty) => {
328        impl std::str::FromStr for $name
329        where
330        $inner: std::str::FromStr,
331        {
332            type Err = <$inner as std::str::FromStr>::Err;
333
334            fn from_str(s: &str) -> Result<Self, Self::Err> {
335                <$inner as std::str::FromStr>::from_str(s).map(Self)
336            }
337        }
338    };
339
340    (@impl $name:ident, $field:tt, IntoIterator, $inner:ty) => {
341        impl IntoIterator for $name
342        where
343        $inner: IntoIterator,
344        {
345            type Item = <$inner as IntoIterator>::Item;
346            type IntoIter = <$inner as IntoIterator>::IntoIter;
347
348            fn into_iter(self) -> Self::IntoIter {
349                self.$field.into_iter()
350            }
351        }
352
353        impl<'a> IntoIterator for &'a $name
354        where
355        &'a $inner: IntoIterator,
356        {
357            type Item = <&'a $inner as IntoIterator>::Item;
358            type IntoIter = <&'a $inner as IntoIterator>::IntoIter;
359
360            fn into_iter(self) -> Self::IntoIter {
361                (&self.$field).into_iter()
362            }
363        }
364
365        impl<'a> IntoIterator for &'a mut $name
366        where
367        &'a mut $inner: IntoIterator,
368        {
369            type Item = <&'a mut $inner as IntoIterator>::Item;
370            type IntoIter = <&'a mut $inner as IntoIterator>::IntoIter;
371
372            fn into_iter(self) -> Self::IntoIter {
373                (&mut self.$field).into_iter()
374            }
375        }
376    };
377
378    (@impl $name:ident, $field:tt, FromIterator, $inner:ty) => {
379        impl<T> std::iter::FromIterator<T> for $name
380        where
381        $inner: std::iter::FromIterator<T>,
382        {
383            fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
384                Self(<$inner as std::iter::FromIterator<T>>::from_iter(iter))
385            }
386        }
387    };
388}