1
use merc_aterm::ATerm;
2
use merc_aterm::ATermRead;
3
use merc_aterm::ATermStreamable;
4
use merc_aterm::ATermWrite;
5
use merc_utilities::MercError;
6

            
7
/// Stores the five sections of an mCRL2 data specification as raw terms, enabling lossless
8
/// round-trip serialization of binary formats that embed a data specification.
9
#[derive(Default)]
10
pub struct DataSpecification {
11
    sorts: Vec<ATerm>,
12
    aliases: Vec<ATerm>,
13
    constructors: Vec<ATerm>,
14
    mappings: Vec<ATerm>,
15
    equations: Vec<ATerm>,
16
}
17

            
18
impl ATermStreamable for DataSpecification {
19
101
    fn write<W: ATermWrite>(&self, writer: &mut W) -> Result<(), MercError> {
20
101
        writer.write_aterm_iter(self.sorts.iter().cloned())?;
21
101
        writer.write_aterm_iter(self.aliases.iter().cloned())?;
22
101
        writer.write_aterm_iter(self.constructors.iter().cloned())?;
23
101
        writer.write_aterm_iter(self.mappings.iter().cloned())?;
24
101
        writer.write_aterm_iter(self.equations.iter().cloned())?;
25
101
        Ok(())
26
101
    }
27

            
28
108
    fn read<R: ATermRead>(reader: &mut R) -> Result<Self, MercError>
29
108
    where
30
108
        Self: Sized,
31
    {
32
108
        let sorts = reader.read_aterm_iter()?.collect::<Result<Vec<ATerm>, _>>()?;
33
108
        let aliases = reader.read_aterm_iter()?.collect::<Result<Vec<ATerm>, _>>()?;
34
108
        let constructors = reader.read_aterm_iter()?.collect::<Result<Vec<ATerm>, _>>()?;
35
108
        let mappings = reader.read_aterm_iter()?.collect::<Result<Vec<ATerm>, _>>()?;
36
108
        let equations = reader.read_aterm_iter()?.collect::<Result<Vec<ATerm>, _>>()?;
37

            
38
108
        Ok(DataSpecification {
39
108
            sorts,
40
108
            aliases,
41
108
            constructors,
42
108
            mappings,
43
108
            equations,
44
108
        })
45
108
    }
46
}
47

            
48
#[cfg(test)]
49
mod tests {
50
    use merc_aterm::ATerm;
51
    use merc_aterm::ATermStreamable;
52
    use merc_aterm::ATermWrite;
53
    use merc_aterm::BinaryATermReader;
54
    use merc_aterm::BinaryATermWriter;
55

            
56
    use super::DataSpecification;
57

            
58
    #[test]
59
1
    fn test_data_specification_roundtrip() {
60
        // Populate every section, including an empty one, to exercise the length-prefixed framing.
61
1
        let spec = DataSpecification {
62
1
            sorts: vec![ATerm::from_string("SortId(Nat)").unwrap()],
63
1
            aliases: Vec::new(),
64
1
            constructors: vec![ATerm::from_string("c").unwrap(), ATerm::from_string("d").unwrap()],
65
1
            mappings: vec![ATerm::from_string("f(a)").unwrap()],
66
1
            equations: vec![ATerm::from_string("eq(x, y)").unwrap()],
67
1
        };
68

            
69
1
        let mut stream: Vec<u8> = Vec::new();
70
1
        let mut writer = BinaryATermWriter::new(&mut stream).unwrap();
71
1
        spec.write(&mut writer).unwrap();
72
1
        ATermWrite::flush(&mut writer).unwrap();
73
1
        drop(writer); // Release the mutable borrow on the stream.
74

            
75
1
        let mut reader = BinaryATermReader::new(&stream[..]).unwrap();
76
1
        let read = DataSpecification::read(&mut reader).unwrap();
77

            
78
1
        assert_eq!(read.sorts, spec.sorts);
79
1
        assert_eq!(read.aliases, spec.aliases);
80
1
        assert_eq!(read.constructors, spec.constructors);
81
1
        assert_eq!(read.mappings, spec.mappings);
82
1
        assert_eq!(read.equations, spec.equations);
83
1
    }
84
}