checked_rs_macro_impl/item/
struct_item.rs

1use syn::{parse::Parse, parse_quote};
2
3use crate::{
4    params::{
5        kw, AsSoftOrHard, BehaviorArg, DerivedTraits, NumberArg, NumberKind, Params, SemiOrComma,
6    },
7    range_seq::RangeSeq,
8};
9
10pub mod field;
11
12pub use field::*;
13
14pub struct ClampedStructItem {
15    pub pound: syn::Token![#],
16    pub bracket: syn::token::Bracket,
17    pub integer: NumberKind,
18    pub as_soft_or_hard: Option<AsSoftOrHard>,
19    pub integer_semi: Option<SemiOrComma>,
20    pub derived_traits: Option<DerivedTraits>,
21    pub derived_semi: Option<SemiOrComma>,
22    pub default_kw: Option<kw::default>,
23    pub default_eq: Option<syn::Token![=]>,
24    pub default_val: Option<NumberArg>,
25    pub default_semi: Option<SemiOrComma>,
26    pub behavior_kw: kw::behavior,
27    pub behavior_eq: syn::Token![=],
28    pub behavior_val: BehaviorArg,
29    pub behavior_semi: Option<SemiOrComma>,
30    pub vis: Option<syn::Visibility>,
31    pub struct_token: syn::Token![struct],
32    pub ident: syn::Ident,
33    pub field: ClampedStructField,
34    pub final_semi: Option<syn::Token![;]>,
35}
36
37impl Parse for ClampedStructItem {
38    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
39        let pound = input.parse()?;
40
41        let content;
42        let bracket = syn::bracketed!(content in input);
43        let integer = content.parse()?;
44        let mut as_soft_or_hard = None;
45        let mut integer_semi = None;
46        let mut derived_traits = None;
47        let mut derived_semi = None;
48        let mut default_kw = None;
49        let mut default_eq = None;
50        let mut default_val = None;
51        let mut default_semi = None;
52        let mut behavior_kw = None;
53        let mut behavior_eq = None;
54        let mut behavior_val = None;
55        let mut behavior_semi = None;
56        let mut vis = None;
57
58        if !content.is_empty() {
59            if content.peek(syn::Token![as]) {
60                as_soft_or_hard = Some(content.parse()?);
61            }
62
63            if !content.is_empty() {
64                integer_semi = Some(content.parse()?);
65
66                while !content.is_empty() {
67                    if content.peek(kw::derive) {
68                        derived_traits = Some(content.parse()?);
69                        derived_semi = if content.peek(syn::Token![;]) {
70                            Some(content.parse()?)
71                        } else {
72                            None
73                        };
74                    }
75
76                    if content.peek(kw::default) {
77                        default_kw = Some(content.parse()?);
78                        default_eq = Some(content.parse()?);
79                        default_val = Some(content.parse()?);
80                        default_semi = if content.peek(syn::Token![;]) {
81                            Some(content.parse()?)
82                        } else {
83                            None
84                        };
85                    }
86
87                    if content.peek(kw::behavior) {
88                        behavior_kw = Some(content.parse()?);
89                        behavior_eq = Some(content.parse()?);
90                        behavior_val = Some(content.parse()?);
91                        behavior_semi = if content.peek(syn::Token![;]) {
92                            Some(content.parse()?)
93                        } else {
94                            None
95                        };
96                    }
97                }
98            }
99        }
100
101        if input.peek(syn::Token![pub]) {
102            vis = Some(input.parse()?);
103        }
104
105        Ok(Self {
106            pound,
107            bracket,
108            integer,
109            as_soft_or_hard,
110            integer_semi,
111            derived_traits,
112            derived_semi,
113            default_kw,
114            default_eq,
115            default_val,
116            default_semi,
117            behavior_kw: behavior_kw.unwrap_or_else(|| parse_quote!(behavior)),
118            behavior_eq: behavior_eq.unwrap_or_else(|| parse_quote!(=)),
119            behavior_val: behavior_val.unwrap_or_else(|| parse_quote!(Panic)),
120            behavior_semi,
121            vis,
122            struct_token: input.parse()?,
123            ident: input.parse()?,
124            field: input.parse()?,
125            final_semi: if input.is_empty() {
126                None
127            } else {
128                Some(input.parse()?)
129            },
130        })
131    }
132}
133
134impl ClampedStructItem {
135    pub fn params(&self) -> syn::Result<Params> {
136        let kind = self.integer;
137        let (mut lower_limit, mut upper_limit) = NumberArg::LIMITS_INIT.clone();
138
139        let mut range_seq = RangeSeq::new(kind);
140
141        for range in self.field.ranges.iter() {
142            range_seq.insert(range.to_value_range(kind)?)?;
143
144            let start = range.start_arg(kind);
145            let end = range.end_arg(kind);
146
147            lower_limit = lower_limit.map_or_else(
148                || Some(start.clone()),
149                |lower_limit| Some(lower_limit.min(&start, kind)),
150            );
151
152            upper_limit = upper_limit.map_or_else(
153                || Some(end.clone()),
154                |upper_limit| Some(upper_limit.max(&end, kind)),
155            );
156        }
157
158        Ok(Params {
159            integer: self.integer,
160            derived_traits: self.derived_traits.clone(),
161            vis: self.vis.clone().unwrap_or(syn::Visibility::Inherited),
162            ident: self.ident.clone(),
163            as_soft_or_hard: self.as_soft_or_hard.clone(),
164            default_val: self.default_val.as_ref().map(|arg| arg.into_value(kind)),
165            behavior: self.behavior_val.clone(),
166            lower_limit_val: lower_limit
167                .or_else(|| Some(NumberArg::new_min_constant(kind)))
168                .map(|arg| arg.into_value(kind))
169                .unwrap(),
170            upper_limit_val: upper_limit
171                .or_else(|| Some(NumberArg::new_max_constant(kind)))
172                .map(|arg| arg.into_value(kind))
173                .unwrap(),
174            full_coverage: !range_seq.has_gaps(),
175            exact_values: None,
176            valid_ranges: Some(range_seq.uniq_ranges()),
177        })
178    }
179}