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