Skip to main content

telltale_language/ast/
role_ops.rs

1use super::*;
2
3// Validation implementations for role types.
4impl RoleParam {
5    /// Validate role parameter for safety constraints.
6    pub fn validate(&self) -> RoleValidationResult<()> {
7        match self {
8            RoleParam::Static(count) => {
9                if *count > MAX_ROLE_COUNT {
10                    return Err(RoleValidationError::CountOverflow {
11                        count: *count,
12                        max: MAX_ROLE_COUNT,
13                    });
14                }
15                Ok(())
16            }
17            RoleParam::Symbolic(_) => Ok(()),
18            RoleParam::Runtime => Ok(()),
19        }
20    }
21
22    /// Validate role parameter in combination with an index.
23    pub fn validate_with_index(&self, index: &RoleIndex) -> RoleValidationResult<()> {
24        match (self, index) {
25            (RoleParam::Static(count), RoleIndex::Concrete(idx)) => {
26                if *idx >= *count {
27                    return Err(RoleValidationError::IndexOverflow {
28                        index: *idx,
29                        max: *count - 1,
30                    });
31                }
32                Ok(())
33            }
34            (RoleParam::Static(count), RoleIndex::Range(range)) => {
35                if let (RangeExpr::Concrete(_), RangeExpr::Concrete(end)) =
36                    (&range.start, &range.end)
37                {
38                    if *end > *count {
39                        return Err(RoleValidationError::IndexOverflow {
40                            index: *end,
41                            max: *count,
42                        });
43                    }
44                }
45                Ok(())
46            }
47            _ => Ok(()),
48        }
49    }
50
51    /// Create a safe static role parameter.
52    pub fn safe_static(count: u32) -> RoleValidationResult<Self> {
53        if count > MAX_ROLE_COUNT {
54            return Err(RoleValidationError::CountOverflow {
55                count,
56                max: MAX_ROLE_COUNT,
57            });
58        }
59        Ok(RoleParam::Static(count))
60    }
61}
62
63impl RoleIndex {
64    /// Validate role index for safety constraints.
65    pub fn validate(&self) -> RoleValidationResult<()> {
66        match self {
67            RoleIndex::Concrete(index) => {
68                if *index > MAX_ROLE_INDEX {
69                    return Err(RoleValidationError::IndexOverflow {
70                        index: *index,
71                        max: MAX_ROLE_INDEX,
72                    });
73                }
74                Ok(())
75            }
76            RoleIndex::Symbolic(_) | RoleIndex::Wildcard => Ok(()),
77            RoleIndex::Range(range) => range.validate(),
78        }
79    }
80
81    /// Create a safe concrete index.
82    pub fn safe_concrete(index: u32) -> RoleValidationResult<Self> {
83        if index > MAX_ROLE_INDEX {
84            return Err(RoleValidationError::IndexOverflow {
85                index,
86                max: MAX_ROLE_INDEX,
87            });
88        }
89        Ok(RoleIndex::Concrete(index))
90    }
91}
92
93impl RoleRange {
94    /// Validate role range for safety constraints.
95    pub fn validate(&self) -> RoleValidationResult<()> {
96        self.start.validate()?;
97        self.end.validate()?;
98
99        if let (RangeExpr::Concrete(start), RangeExpr::Concrete(end)) = (&self.start, &self.end) {
100            if start >= end {
101                return Err(RoleValidationError::InvalidRange {
102                    start: *start,
103                    end: *end,
104                });
105            }
106
107            let range_size = end - start;
108            if range_size > MAX_RANGE_COUNT {
109                return Err(RoleValidationError::RangeSizeOverflow {
110                    size: range_size,
111                    max: MAX_RANGE_COUNT,
112                });
113            }
114        }
115
116        Ok(())
117    }
118
119    /// Create a safe concrete range.
120    pub fn safe_concrete(start: u32, end: u32) -> RoleValidationResult<Self> {
121        let range = RoleRange {
122            start: RangeExpr::Concrete(start),
123            end: RangeExpr::Concrete(end),
124        };
125        range.validate()?;
126        Ok(range)
127    }
128}
129
130impl RangeExpr {
131    /// Validate range expression for safety constraints.
132    pub fn validate(&self) -> RoleValidationResult<()> {
133        match self {
134            RangeExpr::Concrete(value) => {
135                if *value > MAX_ROLE_INDEX {
136                    return Err(RoleValidationError::IndexOverflow {
137                        index: *value,
138                        max: MAX_ROLE_INDEX,
139                    });
140                }
141                Ok(())
142            }
143            RangeExpr::Symbolic(_) => Ok(()),
144        }
145    }
146}
147
148/// Runtime bounds checker for dynamic roles.
149pub struct RoleBoundsChecker {
150    max_count: u32,
151    max_index: u32,
152}
153
154impl Default for RoleBoundsChecker {
155    fn default() -> Self {
156        Self {
157            max_count: MAX_ROLE_COUNT,
158            max_index: MAX_ROLE_INDEX,
159        }
160    }
161}
162
163impl RoleBoundsChecker {
164    /// Create a new bounds checker with custom limits.
165    pub fn new(max_count: u32, max_index: u32) -> Self {
166        Self {
167            max_count,
168            max_index,
169        }
170    }
171
172    /// Check if a runtime role count is within bounds.
173    pub fn check_count(&self, count: u32) -> RoleValidationResult<()> {
174        if count > self.max_count {
175            return Err(RoleValidationError::CountOverflow {
176                count,
177                max: self.max_count,
178            });
179        }
180        Ok(())
181    }
182
183    /// Check if a runtime role index is within bounds.
184    pub fn check_index(&self, index: u32) -> RoleValidationResult<()> {
185        if index > self.max_index {
186            return Err(RoleValidationError::IndexOverflow {
187                index,
188                max: self.max_index,
189            });
190        }
191        Ok(())
192    }
193
194    /// Check if a runtime range is within bounds.
195    pub fn check_range(&self, start: u32, end: u32) -> RoleValidationResult<()> {
196        if start >= end {
197            return Err(RoleValidationError::InvalidRange { start, end });
198        }
199
200        if end > self.max_index {
201            return Err(RoleValidationError::IndexOverflow {
202                index: end,
203                max: self.max_index,
204            });
205        }
206
207        let range_size = end - start;
208        if range_size > MAX_RANGE_COUNT {
209            return Err(RoleValidationError::RangeSizeOverflow {
210                size: range_size,
211                max: MAX_RANGE_COUNT,
212            });
213        }
214
215        Ok(())
216    }
217}
218
219impl std::fmt::Display for RoleIndex {
220    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
221        match self {
222            RoleIndex::Concrete(index) => write!(f, "{}", index),
223            RoleIndex::Symbolic(name) => write!(f, "{}", name),
224            RoleIndex::Wildcard => write!(f, "*"),
225            RoleIndex::Range(range) => write!(f, "{}", range),
226        }
227    }
228}
229
230impl std::fmt::Display for RoleRange {
231    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
232        write!(f, "{}..{}", self.start, self.end)
233    }
234}
235
236impl std::fmt::Display for RangeExpr {
237    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
238        match self {
239            RangeExpr::Concrete(value) => write!(f, "{}", value),
240            RangeExpr::Symbolic(name) => write!(f, "{}", name),
241        }
242    }
243}
244
245impl std::fmt::Display for RoleParam {
246    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
247        match self {
248            RoleParam::Static(count) => write!(f, "{}", count),
249            RoleParam::Symbolic(name) => write!(f, "{}", name),
250            RoleParam::Runtime => write!(f, "*"),
251        }
252    }
253}