portus/lang/
serialize.rs

1use super::ast::Op;
2use super::datapath::{Bin, Event, Instr, Reg};
3use super::{Error, Result};
4use crate::serialize::u32_to_u8s;
5
6/// Serialize a Bin to bytes for transfer to the datapath
7impl Bin {
8    pub fn serialize(&self) -> Result<Vec<u8>> {
9        let b = self.clone();
10        let ists = b
11            .instrs
12            .into_iter()
13            .flat_map(std::iter::IntoIterator::into_iter);
14        b.events
15            .into_iter()
16            .flat_map(std::iter::IntoIterator::into_iter)
17            .chain(ists)
18            .collect()
19    }
20}
21/// pub struct Event {
22///     flag_idx: u32,
23///     num_flag_instrs: u32,
24///     body_idx: u32,
25///     num_body_instrs: u32
26/// }
27/// Emit each of the four fields of `datapath::Event` as a `u32`. This implies
28/// that the maximum number of instructions is 1024, but we limit this value in libccp.
29/// The number of flag instructions is further limited by the maximum expression
30/// depth (the number of temporary registers), which is 8.
31///
32/// serialization format:
33///
34/// |----------------|-----------------|----------------|-----------------|
35/// | flag instr idx | num flag instrs | body instr idx | num body instrs |
36/// | u32            | u32             | u32            | u32             |
37/// |----------------|-----------------|----------------|-----------------|
38impl IntoIterator for Event {
39    type Item = Result<u8>;
40    type IntoIter = ::std::vec::IntoIter<Result<u8>>;
41
42    fn into_iter(self) -> Self::IntoIter {
43        let v = &mut [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
44        u32_to_u8s(&mut v[0..=3], self.flag_idx);
45        u32_to_u8s(&mut v[4..=7], self.num_flag_instrs);
46        u32_to_u8s(&mut v[8..=11], self.body_idx);
47        u32_to_u8s(&mut v[12..=15], self.num_body_instrs);
48        v.iter()
49            .map(|u| Ok(*u))
50            .collect::<Vec<Result<u8>>>()
51            .into_iter()
52    }
53}
54
55/// pub struct Instr {
56///     res: Reg,
57///     op: Op,
58///     left: Reg,
59///     right: Reg,
60/// }
61///
62/// serialization format: (16 B)
63/// |---------|------------|---------------|----------|-------------|----------|--------------|
64/// |Opcode   |Result Type |Result Register|Left Type |Left Register|Right Type|Right Register|
65/// |u8       |u8          |u32            |u8        |u32          |u8        |u32           |
66/// |---------|------------|---------------|----------|-------------|----------|--------------|
67impl IntoIterator for Instr {
68    type Item = Result<u8>;
69    type IntoIter = ::std::vec::IntoIter<Result<u8>>;
70
71    fn into_iter(self) -> Self::IntoIter {
72        let op = vec![Ok(serialize_op(self.op))];
73        op.into_iter()
74            .chain(self.res)
75            .chain(self.left)
76            .chain(self.right)
77            .collect::<Vec<Result<u8>>>() // annoying that this collect is necessary, otherwise Self::IntoIter is unreadable
78            .into_iter()
79    }
80}
81
82fn serialize_op(o: Op) -> u8 {
83    match o {
84        Op::Add => 0,
85        Op::And => unreachable!(),
86        Op::Bind => 1,
87        Op::Def => 2,
88        Op::Div => 3,
89        Op::Equiv => 4,
90        Op::Ewma => 5,
91        Op::Gt => 6,
92        Op::If => 7,
93        Op::Lt => 8,
94        Op::Max => 9,
95        Op::MaxWrap => 10,
96        Op::Min => 11,
97        Op::Mul => 12,
98        Op::NotIf => 13,
99        Op::Or => unreachable!(),
100        Op::Sub => 14,
101    }
102}
103
104impl IntoIterator for Reg {
105    type Item = Result<u8>;
106    type IntoIter = ::std::vec::IntoIter<Result<u8>>;
107
108    fn into_iter(self) -> Self::IntoIter {
109        let reg = match self {
110            Reg::Control(i, _, is_volatile) => {
111                if i > 15 {
112                    Err(Error::from(format!(
113                        "Control Register index too big (max 15): {:?}",
114                        i
115                    )))
116                } else {
117                    // VOLATILE_CONTROL_REG 8
118                    // NONVOLATILE_CONTROL_REG 0
119                    Ok((if is_volatile { 8u8 } else { 0u8 }, u32::from(i)))
120                }
121            }
122            Reg::ImmBool(bl) => Ok((1u8, bl as u32)),
123            Reg::ImmNum(num) => {
124                if num == u64::max_value() || num < (1 << 31) {
125                    Ok((1u8, num as u32))
126                } else {
127                    Err(Error::from(format!(
128                        "ImmNum too big (max 32 bits): {:?}",
129                        num
130                    )))
131                }
132            }
133            Reg::Implicit(i, _) => {
134                if i > 5 {
135                    Err(Error::from(format!(
136                        "Implicit Register index too big (max 5): {:?}",
137                        i
138                    )))
139                } else {
140                    Ok((2u8, u32::from(i)))
141                }
142            }
143            Reg::Local(i, _) => {
144                if i > 5 {
145                    Err(Error::from(format!(
146                        "Local Register index too big (max 5): {:?}",
147                        i
148                    )))
149                } else {
150                    Ok((3u8, u32::from(i)))
151                }
152            }
153            Reg::Primitive(i, _) => {
154                if i > 15 {
155                    Err(Error::from(format!(
156                        "Primitive Register index too big (max 15): {:?}",
157                        i
158                    )))
159                } else {
160                    Ok((4u8, u32::from(i)))
161                }
162            }
163            Reg::Report(i, _, is_volatile) => {
164                if i > 15 {
165                    Err(Error::from(format!(
166                        "Report Register index too big (max 15): {:?}",
167                        i
168                    )))
169                } else {
170                    // in libccp:
171                    // VOLATILE_REPORT_REG is type #5
172                    // NONVOLATILE_REPORT_REG is typ #6
173                    // so, here, we differentiate between variables marked by the volatile keyword.
174                    Ok((if is_volatile { 5u8 } else { 6u8 }, u32::from(i)))
175                }
176            }
177            Reg::Tmp(i, _) => {
178                if i > 15 {
179                    Err(Error::from(format!(
180                        "Tmp Register index too big (max 15): {:?}",
181                        i
182                    )))
183                } else {
184                    Ok((7u8, u32::from(i)))
185                }
186            }
187            Reg::None => unreachable!(),
188        };
189
190        reg.map(|(typ, idx)| {
191            let v = &mut [typ, 0, 0, 0, 0];
192            u32_to_u8s(&mut v[1..5], idx);
193            v.iter()
194                .map(|u| Ok(*u))
195                .collect::<Vec<Result<u8>>>()
196                .into_iter()
197        })
198        .unwrap_or_else(|e| vec![Err(e)].into_iter())
199    }
200}
201
202impl Reg {
203    pub fn deserialize(_buf: &[u8]) -> Self {
204        unimplemented!()
205    }
206}
207
208#[cfg(test)]
209mod tests {
210    use crate::lang;
211    use crate::lang::ast::Op;
212    use crate::lang::datapath::{Bin, Event, Instr, Reg, Type};
213    #[test]
214    fn do_ser() {
215        // make a Bin to serialize
216        let b = Bin {
217            events: vec![Event {
218                flag_idx: 1,
219                num_flag_instrs: 1,
220                body_idx: 2,
221                num_body_instrs: 1,
222            }],
223            instrs: vec![
224                Instr {
225                    res: Reg::Report(6, Type::Num(Some(0)), true),
226                    op: Op::Def,
227                    left: Reg::Report(6, Type::Num(Some(0)), true),
228                    right: Reg::ImmNum(0),
229                },
230                Instr {
231                    res: Reg::Implicit(0, Type::Bool(None)),
232                    op: Op::Bind,
233                    left: Reg::Implicit(0, Type::Bool(None)),
234                    right: Reg::ImmBool(true),
235                },
236                Instr {
237                    res: Reg::Report(6, Type::Num(Some(0)), true),
238                    op: Op::Bind,
239                    left: Reg::Report(6, Type::Num(Some(0)), true),
240                    right: Reg::ImmNum(4),
241                },
242            ],
243        };
244
245        let v = b.serialize().expect("serialize");
246        assert_eq!(
247            v,
248            vec![
249                // event description
250                0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00,
251                0x00, 0x00, // def reg::report(6) <- 0
252                0x02, 0x05, 0x06, 0x00, 0x00, 0x00, 0x05, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
253                0x00, 0x00, // reg::eventFlag <- 1
254                0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00,
255                0x00, 0x00, // def reg::report(6) <- 0
256                0x01, 0x05, 0x06, 0x00, 0x00, 0x00, 0x05, 0x06, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00,
257                0x00, 0x00,
258            ]
259        );
260    }
261
262    #[test]
263    fn do_ser_max_imm() {
264        // make an InstrBytes to serialize
265        let b = Instr {
266            res: Reg::Tmp(0, Type::Num(None)),
267            op: Op::Add,
268            left: Reg::ImmNum(0x3fff_ffff),
269            right: Reg::ImmNum(0x3fff_ffff),
270        };
271
272        let v = b
273            .into_iter()
274            .collect::<lang::Result<Vec<u8>>>()
275            .expect("serialize");
276        assert_eq!(
277            v,
278            vec![
279                0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0x3f, 0x01, 0xff, 0xff,
280                0xff, 0x3f,
281            ]
282        );
283    }
284
285    #[test]
286    fn do_ser_def_max_imm() {
287        // make a Bin to serialize
288        let b = Instr {
289            res: Reg::Report(2, Type::Num(Some(u64::max_value())), true),
290            op: Op::Def,
291            left: Reg::Report(2, Type::Num(Some(u64::max_value())), true),
292            right: Reg::ImmNum(u64::max_value()),
293        };
294
295        let v = b
296            .into_iter()
297            .collect::<lang::Result<Vec<u8>>>()
298            .expect("serialize");
299        assert_eq!(
300            v,
301            vec![
302                0x02, 0x05, 0x02, 0x00, 0x00, 0x00, 0x05, 0x02, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff,
303                0xff, 0xff,
304            ]
305        );
306    }
307}