diff --git a/src/vm/obj/assemble.rs b/src/vm/obj/assemble.rs index 9a16bd5..8e5b84a 100644 --- a/src/vm/obj/assemble.rs +++ b/src/vm/obj/assemble.rs @@ -143,6 +143,7 @@ impl Assemble for DataSection { ); asm.names.pop(); Ok(obj::DataSection { + name: self.name.clone(), start, len: section_len, contents, diff --git a/src/vm/obj/obj.rs b/src/vm/obj/obj.rs index 6f86a33..2547366 100644 --- a/src/vm/obj/obj.rs +++ b/src/vm/obj/obj.rs @@ -1,23 +1,34 @@ use crate::vm::obj::error::{ParseError, Result}; -use byteorder::{ReadBytesExt, LE}; +use byteorder::{ReadBytesExt, WriteBytesExt, LE}; use std::{ collections::HashMap, convert::{TryFrom, TryInto}, fmt::Debug, - io::{Cursor, Read}, + io::{Cursor, Read, Write}, }; pub const MAGIC: u64 = 0xDEAD_BEA7_BA5E_BA11; pub const OBJ_VERSION: u32 = 0; const OBJECT_HEADER_LEN: usize = 16; // 8 + 4 + 4 -#[derive(Debug)] +#[derive(Debug, Clone, PartialEq)] pub struct Object { pub version: u32, pub sections: Vec
, } impl Object { + pub fn to_bytes(&self) -> Vec { + let mut cursor = Cursor::new(Vec::new()); + cursor.write_u64::(MAGIC).unwrap(); + cursor.write_u32::(OBJ_VERSION).unwrap(); + cursor.write_u32::(self.sections.len() as u32).unwrap(); + for section in self.sections.iter() { + cursor.write(§ion.to_bytes()).unwrap(); + } + cursor.into_inner() + } + pub fn from_bytes(bytes: &[u8]) -> Result { let mut cursor = Cursor::new(bytes); let magic = cursor.read_u64::()?; @@ -29,18 +40,23 @@ impl Object { let mut sections = Vec::new(); for _ in 0..section_count { - let section = Section::from_bytes(&mut cursor)?; + let start = cursor.position() as usize; + let section = Section::from_bytes(&bytes[start..])?; + cursor.set_position((start + section.len()) as u64); sections.push(section); } Ok(Object { version, sections }) } pub fn virtual_len(&self) -> usize { - self.sections.iter() + self.sections + .iter() .map(|s| match s { - Section::Data(DataSection { start, len, .. }) => { (start + len) as usize } - Section::Meta { .. } => { 0 } - }).max().unwrap_or(0) + Section::Data(DataSection { start, len, .. }) => (start + len) as usize, + Section::Meta { .. } => 0, + }) + .max() + .unwrap_or(0) } } @@ -69,6 +85,16 @@ macro_rules! section_kind { } } } + + impl From for u8 { + fn from(other: SectionKind) -> Self { + match other { + $( + $enum_name::$name => $value, + )* + } + } + } }; } @@ -79,20 +105,45 @@ section_kind! { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub enum Section { Data(DataSection), Meta(MetaSection), } impl Section { - fn from_bytes(cursor: &mut Cursor<&[u8]>) -> Result { + pub fn len(&self) -> usize { + match self { + Section::Data(s) => { 1 + 8 + s.len() }, + Section::Meta(s) => { 1 + 8 + s.len() }, + } + } + + pub fn to_bytes(&self) -> Vec { + let mut cursor = Cursor::new(Vec::new()); + let bytes = match self { + Section::Data(s) => { + cursor.write_u8(SectionKind::Data.into()).unwrap(); + s.to_bytes() + } + Section::Meta(s) => { + cursor.write_u8(SectionKind::Meta.into()).unwrap(); + s.to_bytes() + }, + }; + cursor.write_u64::(bytes.len() as u64).unwrap(); + cursor.write(&bytes).unwrap(); + cursor.into_inner() + } + + pub fn from_bytes(bytes: &[u8]) -> Result { + let mut cursor = Cursor::new(bytes); + let kind: SectionKind = cursor.read_u8()?.try_into()?; let len = cursor.read_u64::()?; let start = cursor.position() as usize; let end = start + len as usize; let bytes = &cursor.get_ref()[start..end]; - let kind: SectionKind = cursor.read_u8()?.try_into()?; match kind { SectionKind::Data => Ok(Section::Data(DataSection::from_bytes(bytes)?)), SectionKind::Meta => Ok(Section::Meta(MetaSection::from_bytes(bytes)?)), @@ -100,20 +151,46 @@ impl Section { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct DataSection { + pub name: String, pub start: u64, pub len: u64, pub contents: Vec, } impl DataSection { + pub fn len(&self) -> usize { + 2 + self.name.as_bytes().len() + 8 + 8 + self.contents.len() + } + + pub fn to_bytes(&self) -> Vec { + let mut cursor = Cursor::new(Vec::new()); + assert!(self.name.len() < u16::max_value() as usize); + cursor.write_u16::(self.name.len() as u16).unwrap(); + cursor.write(self.name.as_bytes()).unwrap(); + cursor.write_u64::(self.start).unwrap(); + cursor.write_u64::(self.len).unwrap(); + cursor.write(&self.contents).unwrap(); + cursor.into_inner() + } + pub fn from_bytes(bytes: &[u8]) -> Result { let mut cursor = Cursor::new(bytes); + + let name_len = cursor.read_u16::()? as usize; + let name_start = cursor.position() as usize; + let name_end = name_start + name_len; + let name_bytes = &bytes[name_start .. name_end]; + let name_string = String::from_utf8(name_bytes.to_vec())?; + cursor.set_position(name_end as u64); + let start = cursor.read_u64::()?; let len = cursor.read_u64::()?; + let contents = &bytes[cursor.position() as usize..]; Ok(DataSection { + name: name_string, start, len, contents: From::from(contents), @@ -121,12 +198,20 @@ impl DataSection { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct MetaSection { pub entries: HashMap, } impl MetaSection { + pub fn len(&self) -> usize { + todo!() // 8 + ... + } + + pub fn to_bytes(&self) -> Vec { + todo!() + } + pub fn from_bytes(bytes: &[u8]) -> Result { let mut cursor = Cursor::new(bytes); let entry_count = cursor.read_u64::()?; @@ -145,3 +230,27 @@ impl MetaSection { Ok(MetaSection { entries }) } } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_to_from_bytes() { + let obj = Object { + version: OBJ_VERSION, + sections: vec![ + Section::Data(DataSection { + name: "data".to_string(), + start: 0, + len: 16, + contents: vec!(0u8; 16), + }), + ], + }; + + let obj_bytes = obj.to_bytes(); + let converted = Object::from_bytes(&obj_bytes).unwrap(); + assert_eq!(obj, converted); + } +} diff --git a/src/vm/state.rs b/src/vm/state.rs index 18ce74e..89dd06c 100644 --- a/src/vm/state.rs +++ b/src/vm/state.rs @@ -26,6 +26,7 @@ impl State { for section in object.sections { match section { Section::Data(DataSection { + name: _, start, len, contents,