checked_rs_macro_impl/
enum_impl.rs

1use std::collections::HashSet;
2
3use convert_case::{Case, Casing};
4use proc_macro2::{Span, TokenStream};
5use quote::{format_ident, quote, ToTokens};
6use syn::parse_quote;
7
8use crate::{
9    common_impl::{
10        define_guard, impl_binary_op, impl_conversions, impl_deref, impl_other_compare,
11        impl_other_eq, impl_self_cmp, impl_self_eq,
12    },
13    hard_impl,
14    item::enum_item::{ClampedEnumItem, ClampedEnumVariant, ClampedEnumVariantField},
15    params::{DerivedTraits, NumberArg, NumberKind, NumberValue, Params},
16    range_seq::RangeSeq,
17};
18
19pub fn define_mod(
20    params: &Params,
21    parsed_variants: &syn::punctuated::Punctuated<ClampedEnumVariant, syn::Token![,]>,
22) -> syn::Result<TokenStream> {
23    let kind = params.integer;
24    let integer = &params.integer;
25    let behavior = &params.behavior;
26
27    let vis = &params.vis;
28    let ident = &params.ident;
29    let mod_ident = params.mod_ident();
30    let value_ident = params.value_ident();
31
32    let implementations = TokenStream::from_iter(vec![
33        impl_deref(ident, params),
34        impl_conversions(ident, params),
35        impl_self_eq(ident),
36        impl_self_cmp(ident),
37        impl_other_eq(ident, params),
38        impl_other_compare(ident, params),
39        impl_binary_op(
40            ident,
41            params,
42            format_ident!("Add"),
43            format_ident!("add"),
44            behavior,
45            None,
46        ),
47        impl_binary_op(
48            ident,
49            params,
50            format_ident!("Sub"),
51            format_ident!("sub"),
52            behavior,
53            None,
54        ),
55        impl_binary_op(
56            ident,
57            params,
58            format_ident!("Mul"),
59            format_ident!("mul"),
60            behavior,
61            None,
62        ),
63        impl_binary_op(
64            ident,
65            params,
66            format_ident!("Div"),
67            format_ident!("div"),
68            behavior,
69            None,
70        ),
71        impl_binary_op(
72            ident,
73            params,
74            format_ident!("Rem"),
75            format_ident!("rem"),
76            behavior,
77            None,
78        ),
79        impl_binary_op(
80            ident,
81            params,
82            format_ident!("BitAnd"),
83            format_ident!("bitand"),
84            behavior,
85            None,
86        ),
87        impl_binary_op(
88            ident,
89            params,
90            format_ident!("BitOr"),
91            format_ident!("bitor"),
92            behavior,
93            None,
94        ),
95        impl_binary_op(
96            ident,
97            params,
98            format_ident!("BitXor"),
99            format_ident!("bitxor"),
100            behavior,
101            None,
102        ),
103    ]);
104
105    let mut exact_items = Vec::with_capacity(parsed_variants.len());
106    let mut range_items = Vec::with_capacity(parsed_variants.len());
107    let mut nested_enum_items = Vec::with_capacity(parsed_variants.len());
108    let mut from_nested_enum_impls = Vec::with_capacity(parsed_variants.len());
109
110    let mut variants = Vec::with_capacity(parsed_variants.len());
111
112    let mut factory_methods = Vec::with_capacity(parsed_variants.len());
113    let mut matches_methods = Vec::with_capacity(parsed_variants.len());
114    let mut from_exact_cases = Vec::with_capacity(parsed_variants.len());
115    let mut from_range_cases = Vec::with_capacity(parsed_variants.len());
116    let mut from_nested_cases = Vec::with_capacity(parsed_variants.len());
117    let mut as_primitive_cases = Vec::with_capacity(parsed_variants.len());
118
119    let mut has_catchall = false;
120
121    for variant in parsed_variants.iter() {
122        let variant_ident = &variant.ident;
123        let variant_as_snake_case = variant_ident.to_string().to_case(Case::Snake);
124
125        let default_val = variant.default_val.as_ref();
126
127        match &variant.field {
128            ClampedEnumVariantField::Values { values, .. } => {
129                let other_ident = params.other_ident(variant_ident);
130                let literal_values = values
131                    .iter()
132                    .map(|arg| arg.into_literal_as_tokens(kind))
133                    .collect::<Vec<_>>();
134
135                let default_impl = if let Some(default_val) = default_val {
136                    quote! {
137                        impl Default for #value_ident<#other_ident> {
138                            #[inline(always)]
139                            fn default() -> Self {
140                                Self::new(#default_val).unwrap()
141                            }
142                        }
143                    }
144                } else {
145                    TokenStream::new()
146                };
147
148                exact_items.push(quote! {
149                    #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize)]
150                    pub struct #other_ident;
151
152                    unsafe impl ExactValues<#integer> for #other_ident {
153                        const VALUES: &'static [#integer] = &[
154                            #(#literal_values),*
155                        ];
156                    }
157
158                    #default_impl
159                });
160
161                variants.push(quote! {
162                    #variant_ident(#value_ident<#other_ident>),
163                });
164
165                let factory_ident = format_ident!("new_{}", &variant_as_snake_case);
166
167                if values.len() == 1 {
168                    let val = &values[0];
169
170                    factory_methods.push(quote! {
171                        #[inline(always)]
172                        pub fn #factory_ident() -> Self {
173                            #ident::#variant_ident(#value_ident::from_primitive(#val).unwrap())
174                        }
175                    });
176                } else {
177                    factory_methods.push(quote! {
178                        #[inline(always)]
179                        pub fn #factory_ident(val: #integer) -> anyhow::Result<Self> {
180                            Ok(#ident::#variant_ident(#value_ident::from_primitive(val)?))
181                        }
182                    });
183                }
184
185                let matches_method_ident = format_ident!("is_{}", &variant_as_snake_case);
186
187                matches_methods.push(quote! {
188                    #[inline(always)]
189                    pub fn #matches_method_ident(&self) -> bool {
190                        matches!(self, #ident::#variant_ident(_))
191                    }
192                });
193
194                from_exact_cases.push(quote! {
195                    #(#literal_values)|* => #ident::#variant_ident(#value_ident(val, std::marker::PhantomData)),
196                });
197
198                as_primitive_cases.push(quote! {
199                    #ident::#variant_ident(val) => val.as_primitive(),
200                });
201            }
202            ClampedEnumVariantField::Ranges { values, .. } => {
203                let kind = *integer;
204                let other_ident = params.other_ident(variant_ident);
205
206                let variant_limits = variant.field.limits(kind, None, None)?;
207
208                let lower_limit_val = variant_limits.first_val(kind);
209                let upper_limit_val = variant_limits.last_val(kind);
210
211                let mut literal_args = Vec::with_capacity(values.len());
212                let mut range_seq = RangeSeq::with_capacity(kind, values.len());
213                let mut is_catchall = false;
214
215                if values.len() == 1 {
216                    let range = &values[0];
217
218                    if range.is_full_range() {
219                        is_catchall = true;
220                        has_catchall = true;
221                    }
222
223                    let range = range.to_value_range(kind)?;
224
225                    literal_args.push(range.clone());
226                    range_seq.insert(range)?;
227                } else {
228                    for range in values {
229                        if range.is_full_range() {
230                            return Err(syn::Error::new(
231                                Span::call_site(),
232                                "Cannot have a catch-all range in a range that contains other ranges",
233                            ));
234                        }
235
236                        let range = range.to_value_range(kind)?;
237
238                        literal_args.push(range.clone());
239                        range_seq.insert(range)?;
240                    }
241                }
242
243                range_items.push(hard_impl::define_mod(
244                    &Params {
245                        integer: kind,
246                        derived_traits: params.derived_traits.clone(),
247                        vis: parse_quote!(pub),
248                        ident: other_ident.clone(),
249                        as_soft_or_hard: Some(parse_quote!(as Hard)),
250                        default_val: default_val.map(|arg| arg.into_value(kind)),
251                        behavior: behavior.clone(),
252                        lower_limit_val,
253                        upper_limit_val,
254                        full_coverage: !range_seq.has_gaps(),
255                        exact_values: None,
256                        valid_ranges: Some(range_seq.uniq_ranges()),
257                    },
258                    &range_seq
259                        .all_ranges()
260                        .into_iter()
261                        .map(|range| range.into())
262                        .collect(),
263                )?);
264
265                variants.push(quote! {
266                    #variant_ident(#other_ident),
267                });
268
269                let factory_ident = format_ident!("new_{}", &variant_as_snake_case);
270
271                factory_methods.push(quote! {
272                    #[inline(always)]
273                    pub fn #factory_ident(val: #integer) -> anyhow::Result<Self> {
274                        Ok(#ident::#variant_ident(#other_ident::from_primitive(val)?))
275                    }
276                });
277
278                let matches_method_ident = format_ident!("is_{}", &variant_as_snake_case);
279
280                matches_methods.push(quote! {
281                    #[inline(always)]
282                    pub fn #matches_method_ident(&self) -> bool {
283                        matches!(self, #ident::#variant_ident(_))
284                    }
285                });
286
287                if is_catchall {
288                    let min = params.first_uniq_val();
289                    let max = params.last_uniq_val();
290
291                    from_range_cases.push(quote! {
292                        #min..=#max => #ident::#variant_ident(unsafe { #other_ident::new_unchecked(val) }),
293                    });
294                } else {
295                    from_range_cases.push(quote! {
296                        #(#literal_args)|* => #ident::#variant_ident(unsafe { #other_ident::new_unchecked(val) }),
297                    });
298                }
299
300                as_primitive_cases.push(quote! {
301                    #ident::#variant_ident(val) => val.as_primitive(),
302                });
303            }
304            ClampedEnumVariantField::ClampedEnum {
305                value_range,
306                variants: nested_variants,
307                ..
308            } => {
309                let kind = *integer;
310                let other_ident = params.other_ident(variant_ident);
311
312                let variant_lower_limit = value_range
313                    .as_ref()
314                    .map(|range| range.0.first_val(kind))
315                    .unwrap_or_else(|| NumberArg::new_min_constant(kind).into_value(kind));
316                let variant_upper_limit = value_range
317                    .as_ref()
318                    .map(|range| range.0.last_val(kind))
319                    .unwrap_or_else(|| NumberArg::new_max_constant(kind).into_value(kind));
320
321                let mut exacts = HashSet::with_capacity(nested_variants.len());
322                let mut range_seq = RangeSeq::with_capacity(kind, nested_variants.len());
323
324                nested_enum_items.push(define_mod(
325                    &Params {
326                        integer: *integer,
327                        derived_traits: params.derived_traits.clone(),
328                        vis: parse_quote!(pub),
329                        ident: other_ident.clone(),
330                        as_soft_or_hard: None,
331                        default_val: default_val.map(|arg| arg.into_value(kind)),
332                        behavior: behavior.clone(),
333                        lower_limit_val: variant_lower_limit,
334                        upper_limit_val: variant_upper_limit,
335                        full_coverage: ClampedEnumItem::check_coverage(
336                            Some(&mut exacts),
337                            Some(&mut range_seq),
338                            Some(variant_lower_limit),
339                            Some(variant_upper_limit),
340                            kind,
341                            nested_variants.iter(),
342                        )?,
343                        exact_values: if exacts.is_empty() {
344                            None
345                        } else {
346                            let mut exact_values = exacts.iter().copied().collect::<Vec<_>>();
347                            exact_values.sort_unstable();
348                            exact_values.dedup();
349                            Some(exact_values)
350                        },
351                        valid_ranges: if range_seq.is_empty() {
352                            None
353                        } else {
354                            Some(range_seq.uniq_ranges())
355                        },
356                    },
357                    nested_variants,
358                )?);
359
360                from_nested_enum_impls.push(quote! {
361                    impl From<#other_ident> for #ident {
362                        #[inline(always)]
363                        fn from(val: #other_ident) -> Self {
364                            #ident::#variant_ident(val)
365                        }
366                    }
367                });
368
369                variants.push(quote! {
370                    #variant_ident(#other_ident),
371                });
372
373                let factory_ident = format_ident!("new_{}", &variant_as_snake_case);
374
375                factory_methods.push(quote! {
376                    #[inline(always)]
377                    pub fn #factory_ident(val: #integer) -> anyhow::Result<Self> {
378                        Ok(#ident::#variant_ident(#other_ident::from_primitive(val)?))
379                    }
380                });
381
382                let matches_method_ident = format_ident!("is_{}", &variant_as_snake_case);
383
384                matches_methods.push(quote! {
385                    #[inline(always)]
386                    pub fn #matches_method_ident(&self) -> bool {
387                        matches!(self, #ident::#variant_ident(_))
388                    }
389                });
390
391                if !exacts.is_empty() {
392                    let literal_values = exacts.iter().collect::<Vec<_>>();
393
394                    from_nested_cases.push(quote! {
395                        #(#literal_values)|* => #ident::#variant_ident(#value_ident::new(val).unwrap()),
396                    });
397                }
398
399                if !range_seq.is_empty() {
400                    let literal_ranges = range_seq
401                        .all_ranges()
402                        .into_iter()
403                        .map(|range| {
404                            let start = range.start();
405                            let end = range.end();
406
407                            quote! {
408                                #start..=#end
409                            }
410                        })
411                        .collect::<Vec<_>>();
412
413                    from_range_cases.push(quote! {
414                        #(#literal_ranges)|* => #ident::#variant_ident(unsafe { #other_ident::new_unchecked(val) }),
415                    });
416                }
417
418                as_primitive_cases.push(quote! {
419                    #ident::#variant_ident(val) => val.as_primitive(),
420                });
421            }
422        }
423    }
424
425    let lower_limit = params.lower_limit_token();
426    let upper_limit = params.upper_limit_token();
427    let default_val = params.default_val_token();
428
429    let guard_ident = params.guard_ident();
430    let def_guard = define_guard(ident, &guard_ident, params);
431
432    let def_value_item = define_value_item(
433        &params.derived_traits,
434        &value_ident,
435        params.integer,
436        &params.lower_limit_val,
437        &params.upper_limit_val,
438    );
439
440    let mut traits = params
441        .derived_traits
442        .as_ref()
443        .map(|x| {
444            let mut traits = Vec::with_capacity(x.traits.len());
445
446            traits.extend(
447                x.traits
448                    .iter()
449                    .filter(|ty| {
450                        let ty = ty
451                            .path
452                            .segments
453                            .last()
454                            .unwrap()
455                            .to_token_stream()
456                            .to_string();
457
458                        match ty.as_str() {
459                            "Clone" | "Copy" => false,
460                            _ => true,
461                        }
462                    })
463                    .cloned(),
464            );
465
466            traits
467        })
468        .unwrap_or(Vec::with_capacity(2));
469
470    traits.extend(vec![parse_quote!(Clone), parse_quote!(Copy)]);
471
472    let exact_values_trait_impl = if let Some(values) = &params.exact_values {
473        Some(quote! {
474            unsafe impl ExactValues<#integer> for #ident {
475                const VALUES: &'static [#integer] = &[
476                    #(#values),*
477                ];
478            }
479        })
480    } else {
481        None
482    };
483
484    let valid_ranges_trait_impl = if let Some(ranges) = &params.valid_ranges {
485        Some(quote! {
486            unsafe impl RangeValues<#integer> for #ident {
487                const VALID_RANGES: &'static [ValueRangeInclusive<#integer>] = &[
488                    #(ValueRangeInclusive(#ranges)),*
489                ];
490            }
491        })
492    } else {
493        None
494    };
495
496    let op_behavior_params_method = match (&exact_values_trait_impl, &valid_ranges_trait_impl) {
497        (None, None) => {
498            return Err(syn::Error::new(
499                Span::call_site(),
500                "Clamped enums must have at least one variant",
501            ));
502        }
503        // only exact values
504        (Some(..), None) => {
505            quote! {
506                #[inline(always)]
507                pub(self) fn op_behavior_params(&self) -> OpBehaviorParams<#integer> {
508                    OpBehaviorParams::ExactsOnly(<#ident as ExactValues<#integer>>::VALUES)
509                }
510            }
511        }
512        // only ranges
513        (None, Some(..)) => {
514            quote! {
515                #[inline(always)]
516                pub(self) fn op_behavior_params(&self) -> OpBehaviorParams<#integer> {
517                    let ranges = <#ident as RangeValues<#integer>>::VALID_RANGES;
518
519                    if ranges.len() == 1 {
520                        let range = &ranges[0];
521
522                        OpBehaviorParams::Simple {
523                            min: range.first_val(),
524                            max: range.last_val(),
525                        }
526                    } else {
527                        let min = ranges.first().unwrap().first_val();
528                        let max = ranges.last().unwrap().last_val();
529
530                        OpBehaviorParams::RangesOnly(ranges)
531                    }
532                }
533            }
534        }
535        // exact values and ranges
536        (Some(..), Some(..)) => {
537            quote! {
538                #[inline(always)]
539                pub(self) fn op_behavior_params(&self) -> OpBehaviorParams<#integer> {
540                    OpBehaviorParams::ExactsAndRanges {
541                        exacts: <#ident as ExactValues<#integer>>::VALUES,
542                        ranges: <#ident as RangeValues<#integer>>::VALID_RANGES,
543                    }
544                }
545            }
546        }
547    };
548
549    let catchall_case_is_needed = {
550        let lower_limit_val = params.lower_limit_val;
551        let upper_limit_val = params.upper_limit_val;
552        let lowest_val_of_kind = NumberArg::new_min_constant(kind).into_value(kind);
553        let highest_val_of_kind = NumberArg::new_max_constant(kind).into_value(kind);
554
555        if lower_limit_val > lowest_val_of_kind {
556            true
557        } else if upper_limit_val < highest_val_of_kind {
558            true
559        } else if !has_catchall {
560            true
561        } else if !params.full_coverage {
562            true
563        } else {
564            false
565        }
566    };
567
568    let catchall_case = if catchall_case_is_needed {
569        Some(quote! {
570            _ => anyhow::bail!("value is not allowed"),
571        })
572    } else if kind == NumberKind::USize {
573        Some(quote! {
574            usize::MAX.. => unreachable!(),
575        })
576    } else {
577        None
578    };
579
580    let const_catchall_case = if catchall_case_is_needed {
581        Some(quote! {
582            _ => panic!("value is not allowed"),
583        })
584    } else if kind == NumberKind::USize {
585        Some(quote! {
586            usize::MAX.. => unreachable!(),
587        })
588    } else {
589        None
590    };
591
592    Ok(quote! {
593        #vis mod #mod_ident {
594            use super::*;
595
596            #[derive(#(#traits),*)]
597            pub enum #ident {
598                #(#variants)*
599            }
600
601            #[inline(always)]
602            const fn const_from_primitive(val: #integer) -> #ident {
603                match val {
604                    #(#from_exact_cases)*
605                    #(#from_range_cases)*
606                    #const_catchall_case
607                }
608            }
609
610            impl #ident {
611                #[inline(always)]
612                pub fn new(val: #integer) -> Option<Self> {
613                    match <Self as ClampedInteger<#integer>>::from_primitive(val) {
614                        Ok(val) => Some(val),
615                        Err(e) => None,
616                    }
617                }
618
619                #[inline(always)]
620                pub const unsafe fn new_unchecked(val: #integer) -> Self {
621                    const_from_primitive(val)
622                }
623
624                #op_behavior_params_method
625
626                #(#factory_methods)*
627
628                #(#matches_methods)*
629
630                #[inline(always)]
631                pub fn validate(value: #integer) -> ::anyhow::Result<()> {
632                    <Self as ClampedInteger<#integer>>::from_primitive(value)?;
633                    Ok(())
634                }
635
636                #[inline(always)]
637                pub fn modify<'a>(&'a mut self) -> #guard_ident<'a> {
638                    #guard_ident::new(self)
639                }
640            }
641
642
643            impl InherentLimits<#integer> for #ident {
644                const MIN_INT: #integer = #lower_limit;
645                const MAX_INT: #integer = #upper_limit;
646                const MIN: #ident = const_from_primitive(#lower_limit);
647                const MAX: #ident = const_from_primitive(#upper_limit);
648
649                #[inline(always)]
650                fn is_zero(&self) -> bool {
651                    self.into_primitive() == 0
652                }
653
654                #[inline(always)]
655                fn is_negative(&self) -> bool {
656                    self.into_primitive() < 0
657                }
658
659                #[inline(always)]
660                fn is_positive(&self) -> bool {
661                    self.into_primitive() > 0
662                }
663            }
664
665            impl InherentBehavior for #ident {
666                type Behavior = #behavior;
667            }
668
669            unsafe impl ClampedInteger<#integer> for #ident {
670                #[inline(always)]
671                fn from_primitive(val: #integer) -> ::anyhow::Result<Self> {
672                    Ok(match val {
673                        #(#from_exact_cases)*
674                        #(#from_range_cases)*
675                        #catchall_case
676                    })
677                }
678
679                #[inline(always)]
680                fn as_primitive(&self) -> &#integer {
681                    match &*self {
682                        #(#as_primitive_cases)*
683                    }
684                }
685            }
686
687            #exact_values_trait_impl
688
689            #valid_ranges_trait_impl
690
691            unsafe impl ClampedEnum<#integer> for #ident {}
692
693            impl Default for #ident {
694                #[inline(always)]
695                fn default() -> Self {
696                    <Self as ClampedInteger<#integer>>::from_primitive(#default_val).unwrap()
697                }
698            }
699
700            #implementations
701
702            #def_value_item
703
704            #(#exact_items)*
705
706            #(#range_items)*
707
708            #(#nested_enum_items)*
709
710            #(#from_nested_enum_impls)*
711
712            #def_guard
713        }
714
715        #vis use #mod_ident::#ident;
716    })
717}
718
719fn define_value_item(
720    derived_traits: &Option<DerivedTraits>,
721    value_item_ident: &syn::Ident,
722    integer: NumberKind,
723    lower_limit: &NumberValue,
724    upper_limit: &NumberValue,
725) -> TokenStream {
726    let mut traits = derived_traits
727        .as_ref()
728        .map(|x| {
729            let mut traits = Vec::with_capacity(x.traits.len());
730
731            traits.extend(
732                x.traits
733                    .iter()
734                    .filter(|ty| {
735                        let ty = ty
736                            .path
737                            .segments
738                            .last()
739                            .unwrap()
740                            .to_token_stream()
741                            .to_string();
742
743                        match ty.as_str() {
744                            "Debug" | "Clone" | "Copy" | "PartialEq" | "Eq" | "PartialOrd"
745                            | "Ord" => false,
746                            _ => true,
747                        }
748                    })
749                    .cloned(),
750            );
751
752            traits
753        })
754        .unwrap_or(Vec::with_capacity(6));
755
756    traits.extend(vec![
757        parse_quote!(Clone),
758        parse_quote!(Copy),
759        parse_quote!(PartialEq),
760        parse_quote!(Eq),
761        parse_quote!(PartialOrd),
762        parse_quote!(Ord),
763    ]);
764
765    quote! {
766        #[derive(#(#traits),*)]
767        pub struct #value_item_ident<T: ExactValues<#integer>>(pub(self) #integer, pub(self) std::marker::PhantomData<T>);
768
769
770        impl<T: ExactValues<#integer>> #value_item_ident<T> {
771            #[inline(always)]
772            pub const unsafe fn new_unchecked(val: #integer) -> Self {
773                Self(val, std::marker::PhantomData)
774            }
775        }
776
777        impl<T: ExactValues<#integer>> InherentLimits<#integer> for #value_item_ident<T> {
778            const MIN_INT: #integer = #lower_limit;
779            const MAX_INT: #integer = #upper_limit;
780            const MIN: Self = Self(#lower_limit, std::marker::PhantomData);
781            const MAX: Self = Self(#upper_limit, std::marker::PhantomData);
782
783            #[inline(always)]
784            fn is_zero(&self) -> bool {
785                self.0 == 0
786            }
787
788            #[inline(always)]
789            fn is_negative(&self) -> bool {
790                self.0 < 0
791            }
792
793            #[inline(always)]
794            fn is_positive(&self) -> bool {
795                self.0 > 0
796            }
797        }
798
799        impl<T: ExactValues<#integer>> Default for #value_item_ident<T> {
800            #[inline(always)]
801            fn default() -> Self {
802                Self(T::VALUES[0], std::marker::PhantomData)
803            }
804        }
805
806        impl<T: ExactValues<#integer>> std::fmt::Debug for #value_item_ident<T> {
807            #[inline(always)]
808            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
809                self.0.fmt(f)
810            }
811        }
812
813        impl<T: ExactValues<#integer>> std::fmt::Display for #value_item_ident<T> {
814            #[inline(always)]
815            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
816                self.0.fmt(f)
817            }
818        }
819
820        impl<T: ExactValues<#integer>> std::ops::Deref for #value_item_ident<T> {
821            type Target = #integer;
822
823            #[inline(always)]
824            fn deref(&self) -> &Self::Target {
825                &self.0
826            }
827        }
828
829        impl<T: ExactValues<#integer>> AsRef<#integer> for #value_item_ident<T> {
830            #[inline(always)]
831            fn as_ref(&self) -> &#integer {
832                &self.0
833            }
834        }
835
836        impl<T: ExactValues<#integer>> From<#value_item_ident<T>> for #integer {
837            #[inline(always)]
838            fn from(val: #value_item_ident<T>) -> Self {
839                val.0
840            }
841        }
842
843        unsafe impl<T: ExactValues<#integer>> ClampedInteger<#integer> for #value_item_ident<T> {
844            #[inline(always)]
845            fn from_primitive(val: #integer) -> anyhow::Result<Self> {
846                if T::contains_value(val) {
847                    Ok(Self(val, std::marker::PhantomData))
848                } else {
849                    Err(anyhow::anyhow!("value is not allowed"))
850                }
851            }
852
853            #[inline(always)]
854            fn as_primitive(&self) -> &#integer {
855                &self.0
856            }
857        }
858    }
859}