summaryrefslogtreecommitdiff
path: root/matrix-lang/src/binary/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'matrix-lang/src/binary/mod.rs')
-rw-r--r--matrix-lang/src/binary/mod.rs154
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 }
+ }
+}