Skip to main content

telltale_language/ast/
role_ops.rs

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