protospec_build/coder/
decode.rs

1use super::*;
2use crate::asg::*;
3use std::{collections::HashMap, sync::Arc};
4
5#[derive(Debug)]
6pub enum Constructable {
7    Struct {
8        name: String,
9        items: Vec<(String, usize)>,
10    },
11    Tuple(Vec<usize>),
12    TaggedTuple {
13        name: String,
14        items: Vec<usize>,
15    },
16    TaggedEnum {
17        name: String,
18        discriminant: String,
19        values: Vec<usize>,
20    },
21    TaggedEnumStruct {
22        name: String,
23        discriminant: String,
24        values: Vec<(String, usize)>,
25    },
26}
27
28#[derive(Debug)]
29pub enum Instruction {
30    Eval(usize, Expression),
31    Construct(usize, Constructable),
32    // source, new_stream, len constraint
33    Constrict(Target, usize, usize),
34    WrapStream(Target, usize, Arc<Transform>, Vec<usize>), // stream, new stream, transformer, arguments
35    ConditionalWrapStream(
36        usize,
37        Vec<Instruction>,
38        Target,
39        usize,
40        Arc<Transform>,
41        Vec<usize>,
42    ), // condition, prelude, stream, new stream, transformer, arguments
43
44    DecodeForeign(Target, usize, Arc<ForeignType>, Vec<usize>),
45    DecodeRef(Target, usize, String, Vec<usize>),
46    DecodeRepr(String, PrimitiveType, usize, Target),
47    DecodePrimitive(Target, usize, PrimitiveType),
48    DecodePrimitiveArray(Target, usize, PrimitiveType, Option<usize>),
49    DecodeReprArray(Target, usize, String, PrimitiveType, Option<usize>),
50    // target, register of length
51    Skip(Target, usize),
52
53    // register representing: internal stream, end index, terminator, output handle, inner
54    Loop(
55        Target,
56        Option<usize>,
57        Option<usize>,
58        usize,
59        Vec<Instruction>,
60    ),
61    LoopOutput(usize, usize), // output handle, item
62    Conditional(usize, usize, usize, Vec<Instruction>), // target, interior_register, condition, if_true
63    ConditionalPredicate(usize, Vec<Instruction>), // target, interior_register, condition, if_true
64    /// returns from decoder early
65    Return(usize),
66    Error(String),
67}
68
69#[derive(Debug)]
70pub struct Context {
71    pub register_count: usize,
72    pub field_register_map: HashMap<String, usize>,
73    pub instructions: Vec<Instruction>,
74    pub name: String,
75}
76
77impl Context {
78    fn alloc_register(&mut self) -> usize {
79        let x = self.register_count;
80        self.register_count += 1;
81        x
82    }
83}
84
85impl Context {
86    pub fn new() -> Context {
87        Context {
88            name: String::new(),
89            instructions: vec![],
90            field_register_map: HashMap::new(),
91            register_count: 0,
92        }
93    }
94
95    pub fn decode_field_top(&mut self, field: &Arc<Field>) {
96        assert!(field.toplevel);
97        self.name = field.name.clone();
98        let mut value = self.decode_field(Target::Direct, field);
99        match &*field.type_.borrow() {
100            Type::Foreign(_) => (),
101            Type::Container(_) => (),
102            Type::Enum(_) => (),
103            Type::Bitfield(_) => (),
104            _ => {
105                if let Some(old_value) = value {
106                    let extra_value = self.alloc_register();
107                    self.instructions.push(Instruction::Construct(
108                        extra_value,
109                        Constructable::TaggedTuple {
110                            name: field.name.clone(),
111                            items: vec![old_value],
112                        },
113                    ));
114                    value = Some(extra_value);
115                }
116            }
117        }
118        if let Some(value) = value {
119            self.instructions.push(Instruction::Return(
120                value,
121            ));    
122        }
123    }
124
125    fn decode_field_condition(&mut self, field: &Arc<Field>) -> Option<usize> {
126        if let Some(condition) = field.condition.borrow().as_ref() {
127            let value = self.alloc_register();
128            self.instructions
129                .push(Instruction::Eval(value, condition.clone()));
130            Some(value)
131        } else {
132            None
133        }
134    }
135
136    /// return of `None` means interior container
137    pub fn decode_field(&mut self, source: Target, field: &Arc<Field>) -> Option<usize> {
138        let field_condition = self.decode_field_condition(field);
139        let start = self.instructions.len();
140        
141        let emitted = self.decode_field_unconditional(source, field);
142
143        if let Some(field_condition) = field_condition {
144            if emitted.is_none() {
145                unimplemented!("cannot have interior containers with field conditional");
146            }
147            let target = self.alloc_register();
148            let drained = self.instructions.drain(start..).collect();
149            self.instructions.push(Instruction::Conditional(
150                target,
151                emitted.unwrap(),
152                field_condition,
153                drained,
154            ));
155            Some(target)
156        } else {
157            emitted
158        }
159    }
160
161    fn decode_field_unconditional(&mut self, mut source: Target, field: &Arc<Field>) -> Option<usize> {
162        let mut new_streams = vec![];
163
164        for transform in field.transforms.borrow().iter().rev() {
165            let condition = if let Some(condition) = &transform.condition {
166                let value = self.alloc_register();
167                self.instructions
168                    .push(Instruction::Eval(value, condition.clone()));
169                Some(value)
170            } else {
171                None
172            };
173
174            let argument_start = self.instructions.len();
175            let mut args = vec![];
176            for arg in transform.arguments.iter() {
177                let r = self.alloc_register();
178                self.instructions.push(Instruction::Eval(r, arg.clone()));
179                args.push(r);
180            }
181            let new_stream = self.alloc_register();
182            new_streams.push(new_stream);
183
184            if let Some(condition) = condition {
185                let drained = self.instructions.drain(argument_start..).collect();
186                self.instructions.push(Instruction::ConditionalWrapStream(
187                    condition,
188                    drained,
189                    source,
190                    new_stream,
191                    transform.transform.clone(),
192                    args,
193                ));
194            } else {
195                self.instructions.push(Instruction::WrapStream(
196                    source,
197                    new_stream,
198                    transform.transform.clone(),
199                    args,
200                ));
201            }
202            source = Target::Stream(new_stream);
203        }
204
205        //todo: assert condition matching actual presence
206        let emitted = match &*field.type_.borrow() {
207            Type::Container(c) => {
208                let buf_target = if let Some(length) = &c.length {
209                    //todo: use limited stream
210                    let len_register = self.alloc_register();
211                    self.instructions
212                        .push(Instruction::Eval(len_register, length.clone()));
213                    let buf = self.alloc_register();
214                    self.instructions
215                        .push(Instruction::Constrict(source, buf, len_register));
216                    Target::Stream(buf)
217                } else {
218                    source
219                };
220                if c.is_enum.get() {
221                    for (name, child) in c.items.iter() {
222                        let condition = self.decode_field_condition(child);
223                        let start = self.instructions.len();
224                        let decoded = self.decode_field_unconditional(buf_target, child);
225                        let target = self.alloc_register();
226                        
227                        let subtype = child.type_.borrow();
228                        match &*subtype {
229                            Type::Container(c) => {
230                                let mut values = vec![];
231                                for (subname, subchild) in c.flatten_view() {
232                                    if subchild.is_pad.get() || matches!(&*subchild.type_.borrow(), Type::Container(_)) {
233                                        continue;
234                                    }
235    
236                                    values.push((
237                                        subname.clone(),
238                                        *self
239                                            .field_register_map
240                                            .get(&subname)
241                                            .expect("missing field in field_register_map"),
242                                    ));
243                                }
244
245                                self.instructions.push(Instruction::Construct(target, Constructable::TaggedEnumStruct {
246                                    name: field.name.clone(),
247                                    discriminant: name.clone(),
248                                    values,
249                                }));
250                            },
251                            _ => {
252                                let decoded = decoded.expect("enum discriminant was proper interior container, which is illegal");
253                                self.instructions.push(Instruction::Construct(target, Constructable::TaggedEnum {
254                                    name: field.name.clone(),
255                                    discriminant: name.clone(),
256                                    values: vec![decoded],
257                                }));
258                            },
259                        }
260
261                        if let Some(condition) = condition {
262                            self.instructions.push(Instruction::Return(target));
263                            let drained = self.instructions.drain(start..).collect();
264                            self.instructions.push(Instruction::ConditionalPredicate(
265                                condition,
266                                drained,
267                            ));
268                        } else {
269                            return Some(target);
270                        }
271                    }
272                    self.instructions.push(Instruction::Error(format!("no enum conditions matched for {}", field.name)));
273                    None
274                } else {
275                    for (name, child) in c.items.iter() {
276                        let decoded = self.decode_field(buf_target, child);
277                        if let Some(decoded) = decoded {
278                            self.field_register_map.insert(name.clone(), decoded);
279                        }
280                    }
281                    if field.toplevel {
282                        let emitted = self.alloc_register();
283                        let mut items = vec![];
284                        for (name, child) in c.flatten_view() {
285                            if child.is_pad.get() || matches!(&*child.type_.borrow(), Type::Container(_)) {
286                                continue;
287                            }
288                            items.push((
289                                name.clone(),
290                                *self
291                                    .field_register_map
292                                    .get(&name)
293                                    .expect("missing field in field_register_map"),
294                            ));
295                        }
296                        self.instructions.push(Instruction::Construct(
297                            emitted,
298                            Constructable::Struct {
299                                name: field.name.clone(),
300                                items,
301                            },
302                        ));
303                        Some(emitted)
304                    } else {
305                        None
306                    }
307                }
308            }
309            _ => self.decode_type(source, field),
310        };
311
312        emitted
313    }
314
315    pub fn decode_type(&mut self, source: Target, field: &Arc<Field>) -> Option<usize> {
316        let output = self.alloc_register();
317        Some(match &*field.type_.borrow() {
318            Type::Container(_) => unimplemented!(),
319            Type::Array(c) => {
320                if field.is_pad.get() {
321                    let array_type = field.type_.borrow();
322                    let array_type = match &*array_type {
323                        Type::Array(a) => &**a,
324                        _ => panic!("invalid type for pad"),
325                    };
326                    let len = array_type.length.value.as_ref().cloned().unwrap();
327                    let length_register = self.alloc_register();
328                    self.instructions.push(Instruction::Eval(length_register, len));
329                    self.instructions.push(Instruction::Skip(source, length_register));
330                    return None;
331                }
332                let terminator = if c.length.expandable && c.length.value.is_some() {
333                    let len = c.length.value.as_ref().cloned().unwrap();
334                    let r = self.alloc_register();
335                    self.instructions.push(Instruction::Eval(r, len));
336                    Some(r)
337                } else {
338                    None
339                };
340
341                let len = if c.length.expandable {
342                    None
343                } else {
344                    let len = c.length.value.as_ref().cloned().unwrap();
345                    let r = self.alloc_register();
346                    self.instructions.push(Instruction::Eval(r, len));
347                    Some(r)
348                };
349
350                if c.element.condition.borrow().is_none()
351                    && c.element.transforms.borrow().len() == 0
352                    && terminator.is_none()
353                {
354                    let type_ = c.element.type_.borrow();
355                    let type_ = type_.resolved();
356                    match &*type_ {
357                        // todo: const-length type optimizations for container/array/foreign
358                        Type::Container(_) | Type::Array(_) | Type::Foreign(_) | Type::Ref(_) => (),
359                        Type::Enum(x) => {
360                            self.instructions.push(Instruction::DecodeReprArray(
361                                source,
362                                output,
363                                field.name.clone(),
364                                PrimitiveType::Scalar(x.rep.clone()),
365                                len,
366                            ));
367                            return Some(output);
368                        }
369                        Type::Bitfield(x) => {
370                            self.instructions.push(Instruction::DecodeReprArray(
371                                source,
372                                output,
373                                field.name.clone(),
374                                PrimitiveType::Scalar(x.rep.clone()),
375                                len,
376                            ));
377                            return Some(output);
378                        }
379                        Type::Scalar(x) => {
380                            self.instructions.push(Instruction::DecodePrimitiveArray(
381                                source,
382                                output,
383                                PrimitiveType::Scalar(*x),
384                                len,
385                            ));
386                            return Some(output);
387                        }
388                        Type::F32 => {
389                            self.instructions.push(Instruction::DecodePrimitiveArray(
390                                source,
391                                output,
392                                PrimitiveType::F32,
393                                len,
394                            ));
395                            return Some(output);
396                        }
397                        Type::F64 => {
398                            self.instructions.push(Instruction::DecodePrimitiveArray(
399                                source,
400                                output,
401                                PrimitiveType::F64,
402                                len,
403                            ));
404                            return Some(output);
405                        }
406                        Type::Bool => {
407                            self.instructions.push(Instruction::DecodePrimitiveArray(
408                                source,
409                                output,
410                                PrimitiveType::Bool,
411                                len,
412                            ));
413                            return Some(output);
414                        }
415                    }
416                }
417
418                let current_pos = self.instructions.len();
419                let item = self.decode_field(source, &c.element);
420                if item.is_none() {
421                    unimplemented!("cannot have inline container inside array");
422                }
423                self.instructions
424                    .push(Instruction::LoopOutput(output, item.unwrap()));
425                let drained = self.instructions.drain(current_pos..).collect();
426                self.instructions
427                    .push(Instruction::Loop(source, len, terminator, output, drained));
428                output
429            }
430            Type::Enum(e) => {
431                self.instructions.push(Instruction::DecodeRepr(
432                    field.name.clone(),
433                    PrimitiveType::Scalar(e.rep.clone()),
434                    output,
435                    source,
436                ));
437                output
438            }
439            Type::Bitfield(e) => {
440                self.instructions.push(Instruction::DecodeRepr(
441                    field.name.clone(),
442                    PrimitiveType::Scalar(e.rep.clone()),
443                    output,
444                    source,
445                ));
446                output
447            }
448            Type::Scalar(s) => {
449                self.instructions.push(Instruction::DecodePrimitive(
450                    source,
451                    output,
452                    PrimitiveType::Scalar(*s),
453                ));
454                output
455            }
456            Type::F32 => {
457                self.instructions.push(Instruction::DecodePrimitive(
458                    source,
459                    output,
460                    PrimitiveType::F32,
461                ));
462                output
463            }
464            Type::F64 => {
465                self.instructions.push(Instruction::DecodePrimitive(
466                    source,
467                    output,
468                    PrimitiveType::F64,
469                ));
470                output
471            }
472            Type::Bool => {
473                self.instructions.push(Instruction::DecodePrimitive(
474                    source,
475                    output,
476                    PrimitiveType::Bool,
477                ));
478                output
479            }
480            Type::Foreign(f) => {
481                self.instructions.push(Instruction::DecodeForeign(
482                    source,
483                    output,
484                    f.clone(),
485                    vec![],
486                ));
487                output
488            }
489            Type::Ref(r) => {
490                let mut args = vec![];
491                for arg in r.arguments.iter() {
492                    let r = self.alloc_register();
493                    self.instructions.push(Instruction::Eval(r, arg.clone()));
494                    args.push(r);
495                }
496                if let Type::Foreign(f) = &*r.target.type_.borrow() {
497                    self.instructions.push(Instruction::DecodeForeign(
498                        source,
499                        output,
500                        f.clone(),
501                        args,
502                    ));
503                } else {
504                    self.instructions.push(Instruction::DecodeRef(
505                        source,
506                        output,
507                        r.target.name.clone(),
508                        args,
509                    ));
510                }
511                output
512            }
513        })
514    }
515}