diff --git a/README.md b/README.md index 1060108..ad0a214 100644 --- a/README.md +++ b/README.md @@ -81,16 +81,18 @@ release(refer); > Warning: To avoid access violations, `release()` should not be used with interface objects, such as Boolean. --- -`encode(refer:Reference) -> Vec` +`encode(refer:Reference) -> Vec` `encode_raw(refer:Reference) -> Vec` + Serializes an object into binary encoding. The raw variant does not produce a tag prefix for the root object. > Not implemented --- -`decode(data:Vec) -> Result` +`decode(data:Vec) -> Result` `decode_raw(data:Vec, type_id:usize) -> Result` + Parses a valid binary encoding and produces the represented object. The raw variant does not decode a tag prefix on the root object. @@ -139,10 +141,14 @@ Stores a value of any other type. `is_null() -> bool` +Specifies whether or not the variable contains a object. + --- `get() -> Reference` +Returns a reference to the contained object. + ``` let var = Varying::with(*Boolean::with(true)); let value = Boolean::from(var.get()).unwrap(); @@ -151,6 +157,8 @@ let value = Boolean::from(var.get()).unwrap(); `set(refer:Reference)` +Replaces the contained object. + ``` let var = Varying::new(); var.set(*Sequence::with("Hello!")); @@ -163,6 +171,8 @@ Stores the value true or false. `get() -> bool` +Returns the contained value. + ``` let value = Boolean::with(true); if value.get() { @@ -173,6 +183,8 @@ if value.get() { `set(value:bool)` +Replaces the contained value. + ``` let mut value = Boolean::new(); value.set(true); @@ -184,6 +196,9 @@ value.set(true); Stores a non-negative integer value. `get() -> u64` + +Returns the contained value. + ``` let value = Integer::with(-1); println!("{}", value.get()); @@ -191,6 +206,9 @@ println!("{}", value.get()); --- `set(value:u64)` + +Replaces the contained value. + ``` let mut value = Integer::new(); value.set(-273); @@ -202,6 +220,9 @@ value.set(-273); Stores a signed integer value. `get() -> i64` + +Returns the contained value. + ``` let value = Integer::with(-1); println!("{}", value.get()); @@ -209,6 +230,9 @@ println!("{}", value.get()); --- `set(value:i64)` + +Replaces the contained value. + ``` let mut value = Integer::new(); value.set(-273); @@ -216,6 +240,10 @@ value.set(-273); --- +## Significant +Stores a fixed-precision, variable-magnitude + + ## Block Constant-sized series of bytes. diff --git a/src/interface/list.rs b/src/interface/list.rs index dd1a8e2..fa54c46 100644 --- a/src/interface/list.rs +++ b/src/interface/list.rs @@ -10,7 +10,7 @@ use crate::runtime::{ list_reserve, }; use crate::tag; -use super::{varying, list}; +use super::list; pub struct List { managed:bool, @@ -35,9 +35,9 @@ impl List { } } - pub fn with(data:Vec) -> Self + pub fn with(class:usize, data:Vec) -> Self { - let mut obj = Self::new(varying()); + let mut obj = Self::new(class); for item in data { obj.insert(obj.length(), item); } diff --git a/src/interface/schema.rs b/src/interface/schema.rs index e3df430..483fe73 100644 --- a/src/interface/schema.rs +++ b/src/interface/schema.rs @@ -12,15 +12,6 @@ use crate::runtime::{ use crate::tag; use super::schema; -//pub struct Builder { -// data:Schema, -//} -//impl Builder { -// pub fn add() { } -// pub fn map() { } -// pub fn bind() { } -//} - pub struct Schema { managed:bool, addr:Reference, @@ -53,11 +44,6 @@ impl Schema { } return obj; } - - //pub fn build() -> Builder - //{ - // Builder { } - //} pub fn length(&self) -> usize { diff --git a/src/interface/varying.rs b/src/interface/varying.rs index c538c40..4422ca3 100644 --- a/src/interface/varying.rs +++ b/src/interface/varying.rs @@ -2,6 +2,7 @@ use crate::runtime::{ Reference, acquire, release, type_key, + varying_get, varying_set, }; use crate::tag; use super::varying; @@ -29,14 +30,19 @@ impl Varying { } } - pub fn set(&mut self, _addr:Reference) + pub fn is_null(&self) -> bool { - + (unsafe {varying_get(self.addr)}).address == 0 + } + + pub fn set(&mut self, source:Reference) + { + unsafe { varying_set(self.addr, source); } } pub fn get(&self) -> Reference { - self.addr + unsafe { varying_get(self.addr) } } } impl std::ops::Deref for Varying { diff --git a/src/lib.rs b/src/lib.rs index 0d61080..67649fe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,7 +31,6 @@ pub fn test() { *Natural::with(25), ]).unwrap()); - { // get and remove bullet let mut list = List::from(mag.at(1)).unwrap(); @@ -60,103 +59,4 @@ pub fn test() { } #[cfg(test)] -mod tests { - #[test] - fn boolean_initialize() - { - let value = crate::Boolean::new(); - assert_eq!(false, value.get(), "Boolean::new() produces value of false."); - } - - #[test] - fn boolean_with() - { - assert_eq!(false, crate::Boolean::with(false).get(), "Boolean::with(false) produces value of false."); - assert_eq!(true, crate::Boolean::with(true).get(), "Boolean::with(true) produces value of true."); - } - - #[test] - fn boolean_set_get() - { - let mut value = crate::Boolean::new(); - value.set(true); - assert_eq!(true, value.get(), "Boolean.set(true) produces value of true."); - value.set(false); - assert_eq!(false, value.get(), "Boolean.set(false) produces value of false."); - } - - #[test] - fn natural_initialize() - { - let value = crate::Natural::new(); - assert_eq!(0, value.get(), "Natural::new() produces value of 0."); - } - - #[test] - fn natural_set_get() - { - let mut value = crate::Natural::new(); - value.set(12); - assert_eq!(12, value.get(), "Natural.set(12) produces value of 12."); - value.set(38695); - assert_eq!(38695, value.get(), "Natural.set(38695) produces value of 38695."); - } - - #[test] - fn integer_initialize() - { - let value = crate::Integer::new(); - assert_eq!(0, value.get(), "Integer::new() produces value of 0."); - } - - #[test] - fn integer_set_get() - { - let mut value = crate::Integer::new(); - value.set(-273); - assert_eq!(-273, value.get(), "Integer.set(-273) produces value of -273."); - value.set(100); - assert_eq!(100, value.get(), "Integer.set(100) produces value of 100."); - } - - #[test] - fn block_initialize() - { - let value = crate::Block::new(8); - assert_eq!(8, value.length(), "Block::new(8) has length of 8."); - assert_eq!(vec![0;8], value.get(), "Block::new(8) has value of 0."); - } - - #[test] - fn block_set_get() - { - let mut value = crate::Block::new(4); - value.set(vec![1, 2, 3, 4]); - assert_eq!(vec![1, 2, 3, 4], value.get(), "Block::set([1,2,3,4]) has value of [1,2,3,4]."); - } - - #[test] - fn sequence_initialize() - { - let value = crate::Sequence::new(); - assert_eq!(0, value.length(), "Sequence::new() has length 0."); - } - - #[test] - fn sequence_set_get_raw() - { - let mut value = crate::Sequence::new(); - value.set_raw(vec![0, 1, 2, 3, 2, 1]); - assert_eq!(6, value.length(), "Sequence.set_raw([0,1,2,3,2,1]) has length 6."); - assert_eq!(vec![0,1,2,3,2,1], value.get_raw(), "Sequence.set_raw([0,1,2,3,2,1]) produces value [0,1,2,3,2,1]."); - } - - #[test] - fn sequence_set_get_str() - { - let mut value = crate::Sequence::new(); - value.set("hello"); - assert_eq!(5, value.length(), "Sequence.set(hello) has length 5."); - assert_eq!(String::from("hello"), value.get(), "Sequence.set(hello) produces value hello."); - } -} +mod tests; diff --git a/src/runtime/lib.cc b/src/runtime/lib.cc index ede16ee..a0c0472 100644 --- a/src/runtime/lib.cc +++ b/src/runtime/lib.cc @@ -207,93 +207,95 @@ extern "C" void release(Reference addr) bool copy(Reference src, Reference dst) { - Reference source = src; - Reference destination = dst; - - // dereference varying data - if(type_key(src.type) == Type::Tag::Varying) { - source = *reinterpret_cast(src.address); - } - - // prepare destination for varying data - if(type_key(dst.type) == Type::Tag::Varying) { - auto& dest_ref = *reinterpret_cast(dst.address); + if(src.address != dst.address) { + Reference source = src; + Reference destination = dst; - // determine if memory can be reused, otherwise free and reallocate - if(source.type != dest_ref.type) { - if(dest_ref.address != nullptr) { - free(dest_ref.address); - dest_ref.type = Type::Tag::Null; - dest_ref.address = nullptr; - } - dest_ref = acquire(source.type); + // dereference varying data + if(type_key(src.type) == Type::Tag::Varying) { + source = *reinterpret_cast(src.address); } - } - // copy data into destination - if(source.type == destination.type) { - switch(type_key(destination.type)) { - case Type::Tag::Null: { } break; - - case Type::Tag::Boolean: - case Type::Tag::Natural: - case Type::Tag::Integer: - case Type::Tag::Block: - { - memcpy(destination.address, source.address, type_size(source.type)); - } break; + // prepare destination for varying data + if(type_key(dst.type) == Type::Tag::Varying) { + auto& dest_ref = *reinterpret_cast(dst.address); - case Type::Tag::List: { - auto& src_list = *reinterpret_cast(source.address); - auto& dst_list = *reinterpret_cast(destination.address); - - rawlist_reserve(dst_list.data, type_size(type_inner(source.type)), src_list.data.capacity); - dst_list.data.length = src_list.data.length; - //dst_list.data = allocate(type_inner(source.type), src_list.capacity); - - for(size_t i = 0; i < src_list.data.length; ++i) { - copy(list_at(source, i), list_at(destination, i)); + // determine if memory can be reused, otherwise free and reallocate + if(source.type != dest_ref.type) { + if(dest_ref.address != nullptr) { + free(dest_ref.address); + dest_ref.type = Type::Tag::Null; + dest_ref.address = nullptr; } - } break; - - case Type::Tag::Record: { - size_t schema_id = type_innerkey(source.type); - auto binding = DB_SCHEMA.get(schema_id); - if(binding != nullptr) { - for(size_t i = 0; i < binding->data.size(); ++i) { - auto src_cell = record_cell(source, i); - auto dst_cell = record_cell(destination, i); - copy(src_cell, dst_cell); - } - } - } break; - - case Type::Tag::Schema: { - auto& src_schema = *reinterpret_cast(source.address); - auto& dst_schema = *reinterpret_cast(destination.address); - - rawlist_reserve(dst_schema.data, sizeof(size_t), src_schema.data.length); - rawlist_reserve(dst_schema.map, sizeof(size_t), src_schema.map.length); - - for(size_t i = 0; i < src_schema.data.length; ++i) { - auto src_cell = reinterpret_cast(rawlist_cell(src_schema.data, sizeof(size_t), i)); - auto dst_cell = reinterpret_cast(rawlist_cell(dst_schema.data, sizeof(size_t), i)); - if(src_cell != nullptr && dst_cell != nullptr) { - *dst_cell = *src_cell; - } - } - - for(size_t i = 0; i < src_schema.map.length; ++i) { - auto src_cell = reinterpret_cast(rawlist_cell(src_schema.map, sizeof(size_t), i)); - auto dst_cell = reinterpret_cast(rawlist_cell(dst_schema.map, sizeof(size_t), i)); - if(src_cell != nullptr && dst_cell != nullptr) { - *dst_cell = *src_cell; - } - } - } break; + dest_ref = acquire(source.type); + } } - return true; + // copy data into destination + if(source.type == destination.type) { + switch(type_key(destination.type)) { + case Type::Tag::Null: { } break; + + case Type::Tag::Boolean: + case Type::Tag::Natural: + case Type::Tag::Integer: + case Type::Tag::Block: + { + memcpy(destination.address, source.address, type_size(source.type)); + } break; + + case Type::Tag::List: { + auto& src_list = *reinterpret_cast(source.address); + auto& dst_list = *reinterpret_cast(destination.address); + + rawlist_reserve(dst_list.data, type_size(type_inner(source.type)), src_list.data.capacity); + dst_list.data.length = src_list.data.length; + //dst_list.data = allocate(type_inner(source.type), src_list.capacity); + + for(size_t i = 0; i < src_list.data.length; ++i) { + copy(list_at(source, i), list_at(destination, i)); + } + } break; + + case Type::Tag::Record: { + size_t schema_id = type_innerkey(source.type); + auto binding = DB_SCHEMA.get(schema_id); + if(binding != nullptr) { + for(size_t i = 0; i < binding->data.size(); ++i) { + auto src_cell = record_cell(source, i); + auto dst_cell = record_cell(destination, i); + copy(src_cell, dst_cell); + } + } + } break; + + case Type::Tag::Schema: { + auto& src_schema = *reinterpret_cast(source.address); + auto& dst_schema = *reinterpret_cast(destination.address); + + rawlist_reserve(dst_schema.data, sizeof(size_t), src_schema.data.length); + rawlist_reserve(dst_schema.map, sizeof(size_t), src_schema.map.length); + + for(size_t i = 0; i < src_schema.data.length; ++i) { + auto src_cell = reinterpret_cast(rawlist_cell(src_schema.data, sizeof(size_t), i)); + auto dst_cell = reinterpret_cast(rawlist_cell(dst_schema.data, sizeof(size_t), i)); + if(src_cell != nullptr && dst_cell != nullptr) { + *dst_cell = *src_cell; + } + } + + for(size_t i = 0; i < src_schema.map.length; ++i) { + auto src_cell = reinterpret_cast(rawlist_cell(src_schema.map, sizeof(size_t), i)); + auto dst_cell = reinterpret_cast(rawlist_cell(dst_schema.map, sizeof(size_t), i)); + if(src_cell != nullptr && dst_cell != nullptr) { + *dst_cell = *src_cell; + } + } + } break; + } + + return true; + } } return false; } diff --git a/src/runtime/mod.rs b/src/runtime/mod.rs index d14a805..68ba17a 100644 --- a/src/runtime/mod.rs +++ b/src/runtime/mod.rs @@ -44,6 +44,10 @@ extern "C" { pub fn name_keyof(index:usize) -> Str; pub fn name_release(data:Str); + pub fn varying_get(addr:Reference) -> Reference; + pub fn varying_set(addr:Reference, source:Reference); + pub fn varying_clear(addr:Reference); + pub fn bool_set(addr:Reference, data:bool); pub fn bool_get(addr:Reference) -> bool; diff --git a/src/tests.rs b/src/tests.rs new file mode 100644 index 0000000..e963c94 --- /dev/null +++ b/src/tests.rs @@ -0,0 +1,224 @@ +use crate::*; + +#[test] +fn boolean_initialize() +{ + let value = Boolean::new(); + assert_eq!(false, value.get(), "Boolean::new() produces value of false."); +} + +#[test] +fn boolean_with() +{ + assert_eq!(false, Boolean::with(false).get(), "Boolean::with(false) produces value of false."); + assert_eq!(true, Boolean::with(true).get(), "Boolean::with(true) produces value of true."); +} + +#[test] +fn boolean_set_get() +{ + let mut value = Boolean::new(); + value.set(true); + assert_eq!(true, value.get(), "Boolean.set(true) produces value of true."); + value.set(false); + assert_eq!(false, value.get(), "Boolean.set(false) produces value of false."); +} + +#[test] +fn natural_initialize() +{ + let value = Natural::new(); + assert_eq!(0, value.get(), "Natural::new() produces value of 0."); +} + +#[test] +fn natural_set_get() +{ + let mut value = Natural::new(); + value.set(12); + assert_eq!(12, value.get(), "Natural.set(12) produces value of 12."); + value.set(38695); + assert_eq!(38695, value.get(), "Natural.set(38695) produces value of 38695."); +} + +#[test] +fn integer_initialize() +{ + let value = Integer::new(); + assert_eq!(0, value.get(), "Integer::new() produces value of 0."); +} + +#[test] +fn integer_set_get() +{ + let mut value = Integer::new(); + value.set(-273); + assert_eq!(-273, value.get(), "Integer.set(-273) produces value of -273."); + value.set(100); + assert_eq!(100, value.get(), "Integer.set(100) produces value of 100."); +} + +#[test] +fn block_initialize() +{ + let value = Block::new(8); + assert_eq!(8, value.length(), "Block::new(8) has length of 8."); + assert_eq!(vec![0;8], value.get(), "Block::new(8) has value of 0."); +} + +#[test] +fn block_set_get() +{ + let mut value = Block::new(4); + value.set(vec![1, 2, 3, 4]); + assert_eq!(vec![1, 2, 3, 4], value.get(), "Block::set([1,2,3,4]) has value of [1,2,3,4]."); +} + +#[test] +fn sequence_initialize() +{ + let value = Sequence::new(); + assert_eq!(0, value.length(), "Sequence::new() has length 0."); +} + +#[test] +fn sequence_set_get_raw() +{ + let mut value = Sequence::new(); + value.set_raw(vec![0, 1, 2, 3, 2, 1]); + assert_eq!(6, value.length(), "Sequence.set_raw([0,1,2,3,2,1]) has length 6."); + assert_eq!(vec![0,1,2,3,2,1], value.get_raw(), "Sequence.set_raw([0,1,2,3,2,1]) produces value [0,1,2,3,2,1]."); +} + +#[test] +fn sequence_set_get_str() +{ + let mut value = Sequence::new(); + value.set("hello"); + assert_eq!(5, value.length(), "Sequence.set(hello) has length 5."); + assert_eq!(String::from("hello"), value.get(), "Sequence.set(hello) produces value hello."); +} + +#[test] +fn list_initialize() +{ + let list = List::new(natural()); + assert_eq!(0, list.capacity(), "New list has capacity of 0."); + assert_eq!(0, list.length(), "New list has length of 0."); +} + +#[test] +fn list_from() +{ + let list = List::new(natural()); + let mut list_ref = List::from(*list).unwrap(); + list_ref.append(*Natural::with(10)); + + assert_eq!(1, list.length(), "List has length 1 after append to reference."); + assert_eq!(10, Natural::from(list.at(0)).unwrap().get()); +} + +#[test] +fn list_with() +{ + let list = List::with(natural(), vec![ + *Natural::with(5), + *Natural::with(10), + *Natural::with(15), + *Natural::with(20), + ]); + assert_eq!(4, list.length()); + assert_eq!(15, Natural::from(list.at(2)).unwrap().get()); +} + +#[test] +fn list_clear() +{ + let mut list = List::with(natural(), vec![ + *Natural::with(33), + *Natural::with(66), + *Natural::with(99), + ]); + assert_eq!(3, list.length(), "List initialized with 3 elements has length of 3."); + list.clear(); + assert_eq!(0, list.length(), "Cleared list has length of 0."); +} + +#[test] +fn list_insert() +{ + +} + +#[test] +fn list_prepend() +{ + let mut list = List::with(natural(), vec![ + *Natural::with(1000), + *Natural::with(2000), + *Natural::with(3000), + ]); + assert_eq!(3, list.length(), "List initialized with 3 elements has length of 3."); + list.prepend(*Natural::with(0)); + assert_eq!(4, list.length(), "List of 3 elements has length of 4 after prepend."); + assert_eq!(0, Natural::from(list.at(0)).unwrap().get(), "First element in list has value 0."); + assert_eq!(1000, Natural::from(list.at(1)).unwrap().get(), "Second element in list has value 1000."); +} + +#[test] +fn list_append() +{ + let mut list = List::with(natural(), vec![ + *Natural::with(1000), + *Natural::with(2000), + *Natural::with(3000), + ]); + assert_eq!(3, list.length(), "List initialized with 3 elements has length of 3."); + list.append(*Natural::with(4000)); + assert_eq!(4, list.length(), "List of 3 elements has length of 4 after prepend."); + assert_eq!(3000, Natural::from(list.at(2)).unwrap().get(), "Third element in list has value 3000."); + assert_eq!(4000, Natural::from(list.at(3)).unwrap().get(), "Last element in list has value 4000.");} + +#[test] +fn list_set() +{ + let mut list = List::with(natural(), vec![ + *Natural::with(1), + *Natural::with(1), + *Natural::with(3), + ]); + assert_eq!(3, list.length(), "List initialized with 3 elements has length of 3."); + list.set(1, *Natural::with(2)); + assert_eq!(2, Natural::from(list.at(1)).unwrap().get(), "Second element in list has value 2."); +} + +#[test] +fn list_remove() +{ + let mut list = List::with(natural(), vec![ + *Natural::with(0), + *Natural::with(1), + *Natural::with(2), + *Natural::with(3), + *Natural::with(4), + *Natural::with(5), + ]); + assert_eq!(6, list.length(), "List initialized with 6 elements has length of 6."); + list.remove(5); + list.remove(0); + list.remove(2); + assert_eq!(3, list.length(), "List with 3/6 elements removed has length of 3."); + assert_eq!(1, Natural::from(list.at(0)).unwrap().get(), "First element in list is 1."); + assert_eq!(2, Natural::from(list.at(1)).unwrap().get(), "Second element in list is 2."); + assert_eq!(4, Natural::from(list.at(2)).unwrap().get(), "Last element in list is 4."); +} + +#[test] +fn list_reserve() +{ + let capacity :usize = 10; + let mut list = List::new(natural()); + assert_eq!(0, list.capacity(), "List has initial capacity of 0."); + list.reserve(capacity); + assert_eq!(capacity, list.capacity(), "List has updated capacity."); +}