154 lines
3.8 KiB
Rust
154 lines
3.8 KiB
Rust
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 }
|
|
}
|
|
}
|