diff options
Diffstat (limited to 'matrix-lang/src/binary/mod.rs')
-rw-r--r-- | matrix-lang/src/binary/mod.rs | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/matrix-lang/src/binary/mod.rs b/matrix-lang/src/binary/mod.rs new file mode 100644 index 0000000..53b3fe5 --- /dev/null +++ b/matrix-lang/src/binary/mod.rs @@ -0,0 +1,154 @@ +use crate::prelude::*; +use std::io::{self, Read, Write}; + +mod serialize; +mod deserialize; +mod prim; + +pub struct Program { + version: u8, + fun: Rc<Function> +} + +const PROGRAM_HEADER: [u8; 5] = [0x00, 0x4d, 0x41, 0x54, 0x0a]; + +impl Program { + pub fn load(body: &str) -> Result<Option<Rc<Function>>> { + let mut bytes = body.as_bytes(); + if bytes.len() < 6 { + return Ok(None) + } + let header = &bytes[0..5]; + if header != &PROGRAM_HEADER { + return Ok(None) + } + let mut s = ProgramDeserializer::from(&mut bytes); + let program = <Self>::deserialize(&mut s)?; + s.finish()?; + Ok(Some(program.fun.clone())) + } + + pub fn save<W: Write>(fun: Rc<Function>, w: &mut W) -> Result<()> { + let mut s = ProgramSerializer::from(w); + let p = Program { + version: 0, + fun + }; + s.serialize(&p)?; + s.finish()?; + Ok(()) + } +} + +pub trait Primitive : Sized { + fn write<W: Write>(&self, w: &mut W) -> io::Result<()>; + fn read<R: Read>(r: &mut R) -> io::Result<Self>; +} + +pub trait Serialize : Sized { + fn serialize<S: Serializer>(&self, s: &mut S) -> Result<()>; +} + +pub trait Serializer : Sized { + fn serialize<S: Serialize>(&mut self, val: &S) -> Result<()> { + val.serialize(self) + } + fn write<P: Primitive>(&mut self, val: P) -> Result<()>; +} + +pub trait Deserialize : Sized { + fn deserialize<S: Deserializer>(s: &mut S) -> Result<Self>; +} + +pub trait Deserializer : Sized { + fn deserialize<D: Deserialize>(&mut self) -> Result<D> { + D::deserialize(self) + } + fn read<P: Primitive>(&mut self) -> Result<P>; +} + +macro_rules! error { + ($($arg:tt)*) => { + exception!(BINARY_EXCEPTION, $($arg)*) + }; +} + +pub struct ProgramSerializer<'w, W: Write> { + writer: &'w mut W, + checksum: u64, +} + +impl<'w, W: Write> ProgramSerializer<'w, W> { + fn finish(self) -> Result<()> { + let bytes = self.checksum.to_le_bytes(); + self.writer.write(&bytes).map_err(|e| error!("{e}"))?; + Ok(()) + } +} + +impl<'w, W: Write> Serializer for ProgramSerializer<'w, W> { + fn write<P: Primitive>(&mut self, val: P) -> Result<()> { + val.write(self).map_err(|e| error!("{e}")) + } +} + +impl<'w, W: Write> Write for ProgramSerializer<'w, W> { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + for b in buf { + self.checksum %= 0xf1e3beef; + self.checksum += *b as u64; + } + self.writer.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.writer.flush() + } +} + +impl<'w, W: Write> From<&'w mut W> for ProgramSerializer<'w, W> { + fn from(writer: &'w mut W) -> Self { + Self { writer, checksum: 0xfe } + } +} + +pub struct ProgramDeserializer<'r, R: Read> { + reader: &'r mut R, + checksum: u64, +} + +impl<'r, R: Read> ProgramDeserializer<'r, R> { + fn finish(self) -> Result<()> { + let mut bytes = [0u8; 8]; + self.reader.read_exact(&mut bytes).map_err(|e| error!("{e}"))?; + let checksum = u64::from_le_bytes(bytes); + if self.checksum != checksum { + return Err(error!("checksum doesnt match")) + } + Ok(()) + } +} + +impl<'r, R: Read> Deserializer for ProgramDeserializer<'r, R> { + fn read<P: Primitive>(&mut self) -> Result<P> { + P::read(self).map_err(|e| error!("{e}")) + } +} + +impl<'r, R: Read> Read for ProgramDeserializer<'r, R> { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + let c = self.reader.read(buf)?; + for i in 0..c { + let b = buf[i]; + self.checksum %= 0xf1e3beef; + self.checksum += b as u64; + } + Ok(c) + } +} + +impl<'r, R: Read> From<&'r mut R> for ProgramDeserializer<'r, R> { + fn from(reader: &'r mut R) -> Self { + Self { reader, checksum: 0xfe } + } +} |