1use crc::{Crc, CRC_32_ISO_HDLC};
2use rustc_hash::FxHashMap;
3
4#[derive(Debug, Clone, Default)]
6pub struct Scheme<'a> {
7 pub builtins: FxHashMap<&'a str, BuiltinConstructor<'a>>,
8 pub types: FxHashMap<&'a str, Constructor<'a>>,
9 pub boxed_types: FxHashMap<&'a str, Vec<&'a str>>,
10 pub functions: FxHashMap<&'a str, Constructor<'a>>,
11}
12
13impl<'a> Scheme<'a> {
14 pub fn compute_all_ids(&self) -> FxHashMap<u32, (ConstructorKind, &Constructor<'a>)> {
16 let mut ids = FxHashMap::with_capacity_and_hasher(
17 self.types.len() + self.functions.len(),
18 Default::default(),
19 );
20
21 for ty in self.types.values() {
22 ids.insert(ty.compute_tl_id(), (ConstructorKind::Type, ty));
23 }
24
25 for func in self.functions.values() {
26 ids.insert(func.compute_tl_id(), (ConstructorKind::Function, func));
27 }
28
29 ids
30 }
31
32 pub fn validate(&self) -> Result<(), ValidationError> {
34 for ty in self.types.values() {
35 self.check_constructor(ty)?;
36 }
37 for func in self.functions.values() {
38 self.check_constructor(func)?;
39 }
40 Ok(())
41 }
42
43 pub fn find_constructor(&self, name: &str) -> Option<(ConstructorKind, &Constructor<'a>)> {
45 if let Some(constructor) = self.get_type_variant(name) {
46 Some((ConstructorKind::Type, constructor))
47 } else {
48 self.get_function(name)
49 .map(|constructor| (ConstructorKind::Function, constructor))
50 }
51 }
52
53 pub fn get_type_variant(&self, name: &str) -> Option<&Constructor<'a>> {
55 self.types.get(name)
56 }
57
58 pub fn get_function(&self, name: &str) -> Option<&Constructor<'a>> {
60 self.functions.get(name)
61 }
62
63 fn check_constructor(&self, decl: &Constructor<'a>) -> Result<(), ValidationError> {
64 for (i, field) in decl.fields.iter().enumerate() {
65 let prev_fields = &decl.fields[..i];
66 self.check_type(&field.ty, &decl.type_parameters, prev_fields)?;
67 }
68
69 if !self.boxed_types.contains_key(decl.output.ty)
70 && !decl
71 .type_parameters
72 .iter()
73 .any(|field| field.name == Some(decl.output.ty))
74 {
75 return Err(ValidationError::UnknownType(decl.output.to_string()));
76 }
77
78 if let Some(ty_param) = &decl.output.ty_param {
79 self.check_type(ty_param, &decl.type_parameters, &[])?;
80 }
81
82 Ok(())
83 }
84
85 fn check_type(
86 &self,
87 ty: &Type<'a>,
88 type_parameters: &[Field<'a>],
89 prev_fields: &[Field<'a>],
90 ) -> Result<(), ValidationError> {
91 match ty {
92 Type::Int => {}
93 Type::Named { ty } => {
94 if !self.is_declared(ty)
95 && !type_parameters.iter().any(|field| field.name == Some(ty))
96 {
97 return Err(ValidationError::UnknownType(ty.to_string()));
98 }
99 }
100 Type::Generic { ty, ty_param } => {
101 if !self.is_declared(ty)
102 && !type_parameters.iter().any(|field| field.name == Some(ty))
103 {
104 return Err(ValidationError::UnknownType(ty.to_string()));
105 }
106 self.check_type(ty_param, type_parameters, &[])?;
107 }
108 Type::Flagged {
109 flags_field, ty, ..
110 } => {
111 prev_fields
112 .iter()
113 .find(|field| field.name == Some(flags_field))
114 .ok_or_else(|| ValidationError::UnknownField(flags_field.to_string()))?;
115 self.check_type(ty, type_parameters, prev_fields)?;
116 }
117 Type::Repeated { ty, .. } => {
118 for field in ty {
119 self.check_type(&field.ty, type_parameters, prev_fields)?;
120 }
121 }
122 }
123
124 Ok(())
125 }
126
127 fn is_declared(&self, ty: &str) -> bool {
128 self.types.contains_key(ty)
129 || self.boxed_types.contains_key(ty)
130 || self.builtins.contains_key(ty)
131 }
132}
133
134#[derive(Debug, Copy, Clone, Eq, PartialEq)]
136pub struct BuiltinConstructor<'a> {
137 pub variant: &'a str,
138 pub tl_id: Option<u32>,
139 pub output: &'a str,
140}
141
142#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
143pub enum ConstructorKind {
144 Type,
145 Function,
146}
147
148impl std::fmt::Display for ConstructorKind {
149 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
150 match self {
151 ConstructorKind::Type => write!(f, "type"),
152 ConstructorKind::Function => write!(f, "function"),
153 }
154 }
155}
156
157#[derive(Debug, Clone, Eq, PartialEq)]
159pub struct Constructor<'a> {
160 pub variant: &'a str,
161 pub tl_id: Option<u32>,
162 pub type_parameters: Vec<Field<'a>>,
163 pub fields: Vec<Field<'a>>,
164 pub output: OutputType<'a>,
165}
166
167impl Constructor<'_> {
168 pub fn as_normalized(&self) -> String {
169 NormalizedConstructor(self).to_string()
170 }
171
172 pub fn compute_tl_id(&self) -> u32 {
173 use std::fmt::Write;
174
175 if let Some(id) = self.tl_id {
176 return id;
177 }
178
179 struct Checksum<'a>(crc::Digest<'a, u32>);
180
181 impl Write for Checksum<'_> {
182 #[inline(always)]
183 fn write_str(&mut self, s: &str) -> std::fmt::Result {
184 self.0.update(s.as_bytes());
185 Ok(())
186 }
187 }
188
189 let mut checksum = Checksum(CRC.digest());
190 write!(&mut checksum, "{}", NormalizedConstructor(self)).unwrap();
191
192 checksum.0.finalize()
193 }
194}
195
196struct NormalizedConstructor<'c, 'a>(&'c Constructor<'a>);
197
198impl std::fmt::Display for NormalizedConstructor<'_, '_> {
199 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
200 self.0.variant.fmt(f)?;
201
202 for ty in &self.0.type_parameters {
203 f.write_fmt(format_args!(" {{{ty}}}"))?;
204 }
205
206 for field in &self.0.fields {
207 f.write_fmt(format_args!(" {field}"))?
208 }
209
210 f.write_fmt(format_args!(" = {}", self.0.output))
211 }
212}
213
214#[derive(Debug, Clone, Eq, PartialEq)]
215pub struct Field<'a> {
216 pub name: Option<&'a str>,
217 pub ty: Type<'a>,
218}
219
220impl std::fmt::Display for Field<'_> {
221 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
222 if let Some(name) = self.name {
223 f.write_fmt(format_args!("{name}:{}", self.ty))
224 } else {
225 self.ty.fmt(f)
226 }
227 }
228}
229
230#[derive(Debug, Clone, Eq, PartialEq)]
231pub struct OutputType<'a> {
232 pub ty: &'a str,
233 pub ty_param: Option<Box<Type<'a>>>,
234}
235
236impl std::fmt::Display for OutputType<'_> {
237 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
238 match &self.ty_param {
239 None => f.write_str(self.ty),
240 Some(ty_param) => f.write_fmt(format_args!("{} {ty_param}", self.ty)),
241 }
242 }
243}
244
245#[derive(Debug, Clone, Eq, PartialEq)]
246pub enum Type<'a> {
247 Int,
249 Named { ty: &'a str },
251 Generic {
253 ty: &'a str,
254 ty_param: Box<Type<'a>>,
255 },
256 Flagged {
258 flags_field: &'a str,
259 bit: u8,
260 ty: Box<Type<'a>>,
261 },
262 Repeated {
264 multiplicity: Option<u32>,
265 ty: Vec<Field<'a>>,
266 },
267}
268
269impl std::fmt::Display for Type<'_> {
270 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
271 match self {
272 Self::Int => f.write_str("#"),
273
274 Self::Named { ty } => f.write_str(ty),
275
276 Self::Generic { ty, ty_param } => f.write_fmt(format_args!("{ty} {ty_param}")),
277
278 Self::Flagged {
279 flags_field,
280 bit,
281 ty,
282 } => f.write_fmt(format_args!("{flags_field}.{bit}?{ty}")),
283
284 Self::Repeated { multiplicity, ty } => {
285 if let Some(multiplicity) = multiplicity {
286 f.write_fmt(format_args!("{multiplicity} * [ "))?
287 } else {
288 f.write_str("[ ")?
289 }
290
291 for ty in ty {
292 f.write_fmt(format_args!("{ty} "))?
293 }
294
295 f.write_str("]")
296 }
297 }
298 }
299}
300
301#[derive(thiserror::Error, Debug)]
302pub enum ValidationError {
303 #[error("unknown field: {0}")]
304 UnknownField(String),
305 #[error("unknown type: {0}")]
306 UnknownType(String),
307}
308
309static CRC: Crc<u32> = Crc::<u32>::new(&CRC_32_ISO_HDLC);