checked_rs_macro_impl/
soft_impl.rs

1use proc_macro2::TokenStream;
2use quote::{format_ident, quote, ToTokens};
3use syn::parse_quote;
4
5use crate::{
6    common_impl::{
7        define_guard, impl_binary_op, impl_conversions, impl_deref, impl_other_compare,
8        impl_other_eq, impl_self_cmp, impl_self_eq,
9    },
10    params::{NumberArg, NumberValueRange, Params},
11};
12
13pub fn define_mod(params: &Params, ranges: &Vec<NumberValueRange>) -> syn::Result<TokenStream> {
14    let integer = &params.integer;
15
16    let vis = &params.vis;
17    let ident = &params.ident;
18    let mod_ident = params.mod_ident();
19
20    let implementations = TokenStream::from_iter(vec![
21        impl_deref(ident, params),
22        impl_conversions(ident, params),
23        impl_self_eq(ident),
24        impl_self_cmp(ident),
25        impl_other_eq(ident, params),
26        impl_other_compare(ident, params),
27        impl_binary_op(
28            ident,
29            params,
30            format_ident!("Add"),
31            format_ident!("add"),
32            &params.behavior,
33            Some((
34                NumberArg::new_min_constant(*integer),
35                NumberArg::new_max_constant(*integer),
36            )),
37        ),
38        impl_binary_op(
39            ident,
40            params,
41            format_ident!("Sub"),
42            format_ident!("sub"),
43            &params.behavior,
44            Some((
45                NumberArg::new_min_constant(*integer),
46                NumberArg::new_max_constant(*integer),
47            )),
48        ),
49        impl_binary_op(
50            ident,
51            params,
52            format_ident!("Mul"),
53            format_ident!("mul"),
54            &params.behavior,
55            Some((
56                NumberArg::new_min_constant(*integer),
57                NumberArg::new_max_constant(*integer),
58            )),
59        ),
60        impl_binary_op(
61            ident,
62            params,
63            format_ident!("Div"),
64            format_ident!("div"),
65            &params.behavior,
66            Some((
67                NumberArg::new_min_constant(*integer),
68                NumberArg::new_max_constant(*integer),
69            )),
70        ),
71        impl_binary_op(
72            ident,
73            params,
74            format_ident!("Rem"),
75            format_ident!("rem"),
76            &params.behavior,
77            Some((
78                NumberArg::new_min_constant(*integer),
79                NumberArg::new_max_constant(*integer),
80            )),
81        ),
82        impl_binary_op(
83            ident,
84            params,
85            format_ident!("BitAnd"),
86            format_ident!("bitand"),
87            &params.behavior,
88            Some((
89                NumberArg::new_min_constant(*integer),
90                NumberArg::new_max_constant(*integer),
91            )),
92        ),
93        impl_binary_op(
94            ident,
95            params,
96            format_ident!("BitOr"),
97            format_ident!("bitor"),
98            &params.behavior,
99            Some((
100                NumberArg::new_min_constant(*integer),
101                NumberArg::new_max_constant(*integer),
102            )),
103        ),
104        impl_binary_op(
105            ident,
106            params,
107            format_ident!("BitXor"),
108            format_ident!("bitxor"),
109            &params.behavior,
110            Some((
111                NumberArg::new_min_constant(*integer),
112                NumberArg::new_max_constant(*integer),
113            )),
114        ),
115    ]);
116
117    let behavior = &params.behavior;
118    let lower_limit = params.lower_limit_token();
119    let upper_limit = params.upper_limit_token();
120    let default_val = params.default_val_token();
121
122    let guard_ident = params.guard_ident();
123    let def_guard = define_guard(ident, &guard_ident, params);
124
125    let mut traits = params
126        .derived_traits
127        .as_ref()
128        .map(|x| {
129            let mut traits = Vec::with_capacity(x.traits.len());
130
131            traits.extend(
132                x.traits
133                    .iter()
134                    .filter(|ty| {
135                        let ty = ty
136                            .path
137                            .segments
138                            .last()
139                            .unwrap()
140                            .to_token_stream()
141                            .to_string();
142
143                        match ty.as_str() {
144                            "Clone" | "Copy" => false,
145                            _ => true,
146                        }
147                    })
148                    .cloned(),
149            );
150
151            traits
152        })
153        .unwrap_or(Vec::with_capacity(2));
154
155    traits.extend(vec![parse_quote!(Clone), parse_quote!(Copy)]);
156
157    let clamp_trait_impl = {
158        let mut valid_ranges = Vec::with_capacity(ranges.len());
159
160        for value_range in ranges {
161            let first_val = value_range.first_val();
162            let last_val = value_range.last_val();
163
164            valid_ranges.push(quote! {
165                ValueRangeInclusive(#first_val..=#last_val),
166            });
167        }
168
169        quote! {
170            unsafe impl RangeValues<#integer> for #ident {
171                const VALID_RANGES: &'static [ValueRangeInclusive<#integer>] = &[
172                    #(#valid_ranges)*
173                ];
174            }
175
176            unsafe impl SoftClamp<#integer> for #ident {}
177        }
178    };
179
180    Ok(quote! {
181        #vis mod #mod_ident {
182            use super::*;
183
184            #[derive(#(#traits),*)]
185            pub struct #ident(#integer);
186
187            impl #ident {
188                /// Creates a new instance or `None` if it would be invalid.
189                #[inline(always)]
190                pub fn new(val: #integer) -> Option<Self> {
191                    match #ident::validate(val) {
192                        Ok(v) => Some(Self(v)),
193                        Err(..) => None,
194                    }
195                }
196
197                #[inline(always)]
198                pub const fn new_unchecked(val: #integer) -> Self {
199                    Self(val)
200                }
201
202                pub(self) fn op_behavior_params(&self) -> OpBehaviorParams<#integer> {
203                    let ranges = <#ident as RangeValues<#integer>>::VALID_RANGES;
204
205                    if ranges.len() == 1 {
206                        let range = &ranges[0];
207
208                        OpBehaviorParams::Simple {
209                            min: range.first_val(),
210                            max: range.last_val(),
211                        }
212                    } else {
213                        let min = ranges.first().unwrap().first_val();
214                        let max = ranges.last().unwrap().last_val();
215
216                        OpBehaviorParams::RangesOnly(ranges)
217                    }
218                }
219
220                #[inline(always)]
221                pub fn rand() -> Self {
222                    loop {
223                        if let Ok(v) = Self::validate(rand::random::<#integer>()) {
224                            return Self::from_primitive(v).unwrap();
225                        }
226                    }
227                }
228
229                #[inline(always)]
230                pub fn validate(val: #integer) -> ::anyhow::Result<#integer, ClampError<#integer>> {
231                    let ranges = <#ident as RangeValues<#integer>>::VALID_RANGES;
232
233                    if ranges.len() == 1 {
234                        let range = &ranges[0];
235                        let min = range.first_val();
236                        let max = range.last_val();
237
238                        if val < min {
239                            Err(ClampError::TooSmall { val, min })
240                        } else if val > max {
241                            Err(ClampError::TooLarge { val, max })
242                        } else {
243                            Ok(val)
244                        }
245                    } else {
246                        for (i, range) in ranges.iter().enumerate() {
247                            if range.contains(val) {
248                                return Ok(val);
249                            }
250
251                            let min = range.first_val();
252
253                            if i == 0 && val < min {
254                                return Err(ClampError::TooSmall { val, min });
255                            }
256
257                            if i == ranges.len() - 1 {
258                                let max = range.last_val();
259                                return Err(ClampError::TooLarge { val, max });
260                            }
261
262                            let left_range = range;
263                            let right_range = &ranges[i + 1];
264
265                            let left_max = left_range.last_val();
266                            let right_min = right_range.first_val();
267
268                            if val > left_max && val < right_min {
269                                return Err(ClampError::OutOfBounds {
270                                    val,
271                                    left_min: left_range.first_val(),
272                                    left_max,
273                                    right_min,
274                                    right_max: right_range.last_val(),
275                                });
276                            }
277                        }
278
279                        unreachable!("all error cases should be covered by loop");
280                    }
281                }
282
283                #[inline(always)]
284                pub fn is_valid(&self) -> bool {
285                    Self::validate(self.0).is_ok()
286                }
287
288                #[inline(always)]
289                pub fn set(&mut self, value: #integer) -> ::anyhow::Result<(), ClampError<#integer>> {
290                    self.0 = Self::validate(value)?;
291                    Ok(())
292                }
293
294                #[inline(always)]
295                pub fn set_unchecked(&mut self, value: #integer) {
296                    self.0 = value;
297                }
298
299                #[inline(always)]
300                pub fn get(&self) -> &#integer {
301                    &self.0
302                }
303
304                #[inline(always)]
305                pub fn get_mut(&mut self) -> &mut #integer {
306                    &mut self.0
307                }
308
309                #[inline(always)]
310                pub fn modify<'a>(&'a mut self) -> #guard_ident<'a> {
311                    #guard_ident::new(self)
312                }
313            }
314
315
316            impl InherentLimits<#integer> for #ident {
317                const MIN_INT: #integer = #lower_limit;
318                const MAX_INT: #integer = #upper_limit;
319                const MIN: Self = Self(Self::MIN_INT);
320                const MAX: Self = Self(Self::MAX_INT);
321
322                #[inline(always)]
323                fn is_zero(&self) -> bool {
324                    self.0 == 0
325                }
326
327                #[inline(always)]
328                fn is_negative(&self) -> bool {
329                    self.0 < 0
330                }
331
332                #[inline(always)]
333                fn is_positive(&self) -> bool {
334                    self.0 > 0
335                }
336            }
337
338            impl InherentBehavior for #ident {
339                type Behavior = #behavior;
340            }
341
342            unsafe impl ClampedInteger<#integer> for #ident {
343                #[inline(always)]
344                fn from_primitive(n: #integer) -> ::anyhow::Result<Self> {
345                    Ok(Self(n))
346                }
347
348                #[inline(always)]
349                fn as_primitive(&self) -> &#integer {
350                    &self.0
351                }
352            }
353
354            #clamp_trait_impl
355
356            impl Default for #ident {
357                #[inline(always)]
358                fn default() -> Self {
359                    Self(#default_val)
360                }
361            }
362
363            impl std::ops::DerefMut for #ident {
364                #[inline(always)]
365                fn deref_mut(&mut self) -> &mut Self::Target {
366                    &mut self.0
367                }
368            }
369
370
371            impl AsMut<#integer> for #ident {
372                #[inline(always)]
373                fn as_mut(&mut self) -> &mut #integer {
374                    &mut self.0
375                }
376            }
377
378            #implementations
379
380            #def_guard
381        }
382
383        #vis use #mod_ident::#ident;
384    })
385}