@ -7,6 +7,18 @@ use crate::{Context, JsBigInt, JsObject, JsString, JsSymbol};
use indexmap ::{ IndexMap , IndexSet } ;
use std ::fmt ::{ Debug , Display } ;
/// TODO: doc
pub trait Serialize {
/// Serialize type
fn serialize ( & self , s : & mut SnapshotSerializer ) -> Result < ( ) , SnapshotError > ;
}
/// TODO: doc
pub trait Deserialize : Sized {
/// TODO: doc
fn deserialize ( d : & mut SnapshotDeserializer < ' _ > ) -> Result < Self , SnapshotError > ;
}
/// TODO: doc
#[ derive(Debug, Clone, Copy) ]
pub struct Header {
@ -15,12 +27,6 @@ pub struct Header {
// checksum: u64,
}
/// TODO: doc
pub trait Serialize {
/// Serialize type
fn serialize ( & self , s : & mut SnapshotSerializer ) -> Result < ( ) , SnapshotError > ;
}
impl Serialize for Header {
fn serialize ( & self , s : & mut SnapshotSerializer ) -> Result < ( ) , SnapshotError > {
s . write_bytes ( & self . signature ) ? ;
@ -29,6 +35,17 @@ impl Serialize for Header {
}
}
impl Deserialize for Header {
fn deserialize ( d : & mut SnapshotDeserializer < ' _ > ) -> Result < Self , SnapshotError > {
let signature = d . read_bytes ( 4 ) ? ;
let signature = [ signature [ 0 ] , signature [ 1 ] , signature [ 2 ] , signature [ 3 ] ] ;
let version = d . read_u32 ( ) ? ;
Ok ( Self { signature , version } )
}
}
impl Serialize for JsObject {
fn serialize ( & self , s : & mut SnapshotSerializer ) -> Result < ( ) , SnapshotError > {
let value = s . objects . insert_full ( self . clone ( ) ) . 0 ;
@ -40,8 +57,149 @@ impl Serialize for JsObject {
/// TODO: doc
pub struct Snapshot {
header : Header ,
bytes : Vec < u8 > ,
external_references : IndexSet < usize > ,
}
impl Snapshot {
/// TODO: doc
pub fn new ( bytes : Vec < u8 > ) -> Self {
Self {
bytes ,
external_references : IndexSet ::default ( ) ,
}
}
/// TODO: doc
pub fn bytes ( & self ) -> & [ u8 ] {
& self . bytes
}
/// TODO: doc
pub fn deserialize < ' a > ( & self ) -> Result < Context < ' a > , SnapshotError > {
let mut deserializer = SnapshotDeserializer {
index : 0 ,
bytes : & self . bytes ,
external_references : & self . external_references ,
} ;
let header = Header ::deserialize ( & mut deserializer ) ? ;
// TODO: Do error handling and snapshot integrity checks.
assert_eq! ( & header . signature , b" .boa " ) ;
assert_eq! ( header . version , 42 ) ;
let context = Context ::deserialize ( & mut deserializer ) ? ;
// Assert that all bytes are consumed.
// assert_eq!(deserializer.index, deserializer.bytes.len());
Ok ( context )
}
}
/// TODO: doc
pub struct SnapshotDeserializer < ' snapshot > {
bytes : & ' snapshot [ u8 ] ,
index : usize ,
external_references : & ' snapshot IndexSet < usize > ,
}
impl SnapshotDeserializer < ' _ > {
/// TODO: doc
pub fn read_bool ( & mut self ) -> Result < bool , SnapshotError > {
let byte = self . read_u8 ( ) ? ;
assert! ( byte = = 0 | | byte = = 1 ) ;
Ok ( byte = = 1 )
}
/// TODO: doc
pub fn read_u8 ( & mut self ) -> Result < u8 , SnapshotError > {
let byte = self . bytes [ self . index ] ;
self . index + = 1 ;
Ok ( byte )
}
/// TODO: doc
pub fn read_i8 ( & mut self ) -> Result < i8 , SnapshotError > {
let byte = self . bytes [ self . index ] ;
self . index + = 1 ;
Ok ( byte as i8 )
}
/// TODO: doc
pub fn read_u16 ( & mut self ) -> Result < u16 , SnapshotError > {
let bytes = self . read_bytes ( std ::mem ::size_of ::< u16 > ( ) ) ? ;
let value = u16 ::from_le_bytes ( [ bytes [ 0 ] , bytes [ 1 ] ] ) ;
Ok ( value )
}
/// TODO: doc
pub fn read_i16 ( & mut self ) -> Result < i16 , SnapshotError > {
let value = self . read_u16 ( ) ? ;
Ok ( value as i16 )
}
/// TODO: doc
pub fn read_u32 ( & mut self ) -> Result < u32 , SnapshotError > {
let bytes = self . read_bytes ( 4 ) ? ;
let value = u32 ::from_le_bytes ( [ bytes [ 0 ] , bytes [ 1 ] , bytes [ 2 ] , bytes [ 3 ] ] ) ;
Ok ( value )
}
/// TODO: doc
pub fn read_i32 ( & mut self ) -> Result < i32 , SnapshotError > {
let value = self . read_u32 ( ) ? ;
Ok ( value as i32 )
}
/// TODO: doc
pub fn read_f32 ( & mut self ) -> Result < f32 , SnapshotError > {
let value = self . read_u32 ( ) ? ;
Ok ( f32 ::from_bits ( value ) )
}
/// TODO: doc
pub fn read_f64 ( & mut self ) -> Result < f64 , SnapshotError > {
let value = self . read_u64 ( ) ? ;
Ok ( f64 ::from_bits ( value ) )
}
/// TODO: doc
pub fn read_u64 ( & mut self ) -> Result < u64 , SnapshotError > {
let bytes = self . read_bytes ( std ::mem ::size_of ::< u64 > ( ) ) ? ;
let value = u64 ::from_le_bytes ( [
bytes [ 0 ] , bytes [ 1 ] , bytes [ 2 ] , bytes [ 3 ] , bytes [ 4 ] , bytes [ 5 ] , bytes [ 6 ] , bytes [ 7 ] ,
] ) ;
Ok ( value )
}
/// TODO: doc
pub fn read_i64 ( & mut self ) -> Result < i64 , SnapshotError > {
let value = self . read_u64 ( ) ? ;
Ok ( value as i64 )
}
/// TODO: doc
pub fn read_usize ( & mut self ) -> Result < usize , SnapshotError > {
let value = self . read_u64 ( ) ? ;
// TODO: handle error.
Ok ( usize ::try_from ( value ) . unwrap ( ) )
}
/// TODO: doc
pub fn read_isize ( & mut self ) -> Result < isize , SnapshotError > {
let value = self . read_usize ( ) ? ;
Ok ( value as isize )
}
/// TODO: doc
pub fn read_string ( & mut self ) -> Result < & str , SnapshotError > {
let len = self . read_usize ( ) ? ;
let bytes = self . read_bytes ( len ) ? ;
// TODO: handle error
Ok ( std ::str ::from_utf8 ( bytes ) . unwrap ( ) )
}
/// TODO: doc
pub fn read_bytes ( & mut self , count : usize ) -> Result < & [ u8 ] , SnapshotError > {
let index = self . index ;
self . index + = count ;
// TODO: use .get() so we can handle the error.
let bytes = & self . bytes [ index .. ( index + count ) ] ;
Ok ( bytes )
}
}
/// TODO: doc
@ -91,18 +249,12 @@ impl SnapshotSerializer {
}
}
/// TODO: doc
pub fn bytes ( & self ) -> & [ u8 ] {
& self . bytes
}
/// Serialize the given [`Context`].
pub fn serialize ( & mut self , context : & mut Context < ' _ > ) -> Result < ( ) , SnapshotError > {
pub fn serialize ( mut self , context : & mut Context < ' _ > ) -> Result < Snapshot , SnapshotError > {
// Remove any garbage objects before serialization.
boa_gc ::force_collect ( ) ;
// boa_gc::walk_gc_alloc_pointers(|address| {
// });
let header = Header {
@ -110,8 +262,8 @@ impl SnapshotSerializer {
version : 42 ,
} ;
header . serialize ( self ) ? ;
context . serialize ( self ) ? ;
header . serialize ( & mut self ) ? ;
context . serialize ( & mut self ) ? ;
for i in 0 .. self . objects . len ( ) {
let object = self
@ -119,7 +271,7 @@ impl SnapshotSerializer {
. get_index ( i )
. expect ( "There should be an object" )
. clone ( ) ;
object . inner ( ) . serialize ( self ) ? ;
object . inner ( ) . serialize ( & mut self ) ? ;
}
for i in 0 .. self . symbols . len ( ) {
@ -132,7 +284,7 @@ impl SnapshotSerializer {
self . write_u64 ( hash ) ? ;
if let Some ( desc ) = symbol . description ( ) {
self . write_bool ( true ) ? ;
desc . serialize ( self ) ? ;
desc . serialize ( & mut self ) ? ;
} else {
self . write_bool ( false ) ? ;
}
@ -146,7 +298,7 @@ impl SnapshotSerializer {
. 1
. clone ( ) ;
// string.
string . serialize ( self ) ? ;
string . serialize ( & mut self ) ? ;
self . write_bool ( string . is_static ( ) ) ? ;
self . write_usize ( string . len ( ) ) ? ;
@ -155,7 +307,10 @@ impl SnapshotSerializer {
}
}
Ok ( ( ) )
Ok ( Snapshot {
bytes : self . bytes ,
external_references : self . external_references ,
} )
}
/// TODO: doc