While nom can result in quite elegant code IMO, it only gives us deserialization. If we want to add serialization, we have to write at least an equal amount of code that does the manual serialization part. For a large part of the code base, this essentially consists of reversing match statements with little but repetitive differences spread throughout. I'm proposing to use the binrw crate to eliminate some of that boilerplate.
use binrw::binrw;
#[derive(Debug, PartialEq)]
#[binrw]
#[brw(repr = u8)]
enum Test {
A = 1,
B = 2,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn valid() {
use binrw::{BinRead, io::Cursor};
let mut cursor = Cursor::new(&[1]);
let test = Test::read(&mut cursor).unwrap();
assert_eq!(test, Test::A);
}
#[test]
#[should_panic]
fn invalid() {
use binrw::{BinRead, io::Cursor};
let mut cursor = Cursor::new(&[0]);
Test::read(&mut cursor).unwrap();
}
}
for more complex data_structures, binrw still has options for writing manual readers and writers.
Moreover, writing code based on kaitai specs will also be almost as easy since the resulting macro-annotated datastructures look very similar to a kaitai spec file IMO.
While
nom
can result in quite elegant code IMO, it only gives us deserialization. If we want to add serialization, we have to write at least an equal amount of code that does the manual serialization part. For a large part of the code base, this essentially consists of reversing match statements with little but repetitive differences spread throughout. I'm proposing to use the binrw crate to eliminate some of that boilerplate.for more complex data_structures,
binrw
still has options for writing manual readers and writers.Moreover, writing code based on kaitai specs will also be almost as easy since the resulting macro-annotated datastructures look very similar to a kaitai spec file IMO.