Implement varying, add tests for list.

This commit is contained in:
yukirij 2023-08-15 12:27:35 -07:00
parent 5d4e6db64b
commit c5d551bde2
8 changed files with 353 additions and 203 deletions

View File

@ -81,16 +81,18 @@ release(refer);
> Warning: To avoid access violations, `release()` should not be used with interface objects, such as Boolean. > Warning: To avoid access violations, `release()` should not be used with interface objects, such as Boolean.
--- ---
`encode(refer:Reference) -> Vec<u8>` `encode(refer:Reference) -> Vec<u8>`
`encode_raw(refer:Reference) -> Vec<u8>` `encode_raw(refer:Reference) -> Vec<u8>`
Serializes an object into binary encoding. Serializes an object into binary encoding.
The raw variant does not produce a tag prefix for the root object. The raw variant does not produce a tag prefix for the root object.
> Not implemented > Not implemented
--- ---
`decode(data:Vec<u8>) -> Result<Reference,()>` `decode(data:Vec<u8>) -> Result<Reference,()>`
`decode_raw(data:Vec<u8>, type_id:usize) -> Result<Reference,()>` `decode_raw(data:Vec<u8>, type_id:usize) -> Result<Reference,()>`
Parses a valid binary encoding and produces the represented object. Parses a valid binary encoding and produces the represented object.
The raw variant does not decode a tag prefix on the root 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` `is_null() -> bool`
Specifies whether or not the variable contains a object.
--- ---
`get() -> Reference` `get() -> Reference`
Returns a reference to the contained object.
``` ```
let var = Varying::with(*Boolean::with(true)); let var = Varying::with(*Boolean::with(true));
let value = Boolean::from(var.get()).unwrap(); let value = Boolean::from(var.get()).unwrap();
@ -151,6 +157,8 @@ let value = Boolean::from(var.get()).unwrap();
`set(refer:Reference)` `set(refer:Reference)`
Replaces the contained object.
``` ```
let var = Varying::new(); let var = Varying::new();
var.set(*Sequence::with("Hello!")); var.set(*Sequence::with("Hello!"));
@ -163,6 +171,8 @@ Stores the value true or false.
`get() -> bool` `get() -> bool`
Returns the contained value.
``` ```
let value = Boolean::with(true); let value = Boolean::with(true);
if value.get() { if value.get() {
@ -173,6 +183,8 @@ if value.get() {
`set(value:bool)` `set(value:bool)`
Replaces the contained value.
``` ```
let mut value = Boolean::new(); let mut value = Boolean::new();
value.set(true); value.set(true);
@ -184,6 +196,9 @@ value.set(true);
Stores a non-negative integer value. Stores a non-negative integer value.
`get() -> u64` `get() -> u64`
Returns the contained value.
``` ```
let value = Integer::with(-1); let value = Integer::with(-1);
println!("{}", value.get()); println!("{}", value.get());
@ -191,6 +206,9 @@ println!("{}", value.get());
--- ---
`set(value:u64)` `set(value:u64)`
Replaces the contained value.
``` ```
let mut value = Integer::new(); let mut value = Integer::new();
value.set(-273); value.set(-273);
@ -202,6 +220,9 @@ value.set(-273);
Stores a signed integer value. Stores a signed integer value.
`get() -> i64` `get() -> i64`
Returns the contained value.
``` ```
let value = Integer::with(-1); let value = Integer::with(-1);
println!("{}", value.get()); println!("{}", value.get());
@ -209,6 +230,9 @@ println!("{}", value.get());
--- ---
`set(value:i64)` `set(value:i64)`
Replaces the contained value.
``` ```
let mut value = Integer::new(); let mut value = Integer::new();
value.set(-273); value.set(-273);
@ -216,6 +240,10 @@ value.set(-273);
--- ---
## Significant
Stores a fixed-precision, variable-magnitude
## Block ## Block
Constant-sized series of bytes. Constant-sized series of bytes.

View File

@ -10,7 +10,7 @@ use crate::runtime::{
list_reserve, list_reserve,
}; };
use crate::tag; use crate::tag;
use super::{varying, list}; use super::list;
pub struct List { pub struct List {
managed:bool, managed:bool,
@ -35,9 +35,9 @@ impl List {
} }
} }
pub fn with(data:Vec<Reference>) -> Self pub fn with(class:usize, data:Vec<Reference>) -> Self
{ {
let mut obj = Self::new(varying()); let mut obj = Self::new(class);
for item in data { for item in data {
obj.insert(obj.length(), item); obj.insert(obj.length(), item);
} }

View File

@ -12,15 +12,6 @@ use crate::runtime::{
use crate::tag; use crate::tag;
use super::schema; use super::schema;
//pub struct Builder {
// data:Schema,
//}
//impl Builder {
// pub fn add() { }
// pub fn map() { }
// pub fn bind() { }
//}
pub struct Schema { pub struct Schema {
managed:bool, managed:bool,
addr:Reference, addr:Reference,
@ -53,11 +44,6 @@ impl Schema {
} }
return obj; return obj;
} }
//pub fn build() -> Builder
//{
// Builder { }
//}
pub fn length(&self) -> usize pub fn length(&self) -> usize
{ {

View File

@ -2,6 +2,7 @@ use crate::runtime::{
Reference, Reference,
acquire, release, acquire, release,
type_key, type_key,
varying_get, varying_set,
}; };
use crate::tag; use crate::tag;
use super::varying; 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 pub fn get(&self) -> Reference
{ {
self.addr unsafe { varying_get(self.addr) }
} }
} }
impl std::ops::Deref for Varying { impl std::ops::Deref for Varying {

View File

@ -31,7 +31,6 @@ pub fn test() {
*Natural::with(25), *Natural::with(25),
]).unwrap()); ]).unwrap());
{ {
// get and remove bullet // get and remove bullet
let mut list = List::from(mag.at(1)).unwrap(); let mut list = List::from(mag.at(1)).unwrap();
@ -60,103 +59,4 @@ pub fn test() {
} }
#[cfg(test)] #[cfg(test)]
mod tests { 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.");
}
}

View File

@ -207,93 +207,95 @@ extern "C" void release(Reference addr)
bool copy(Reference src, Reference dst) bool copy(Reference src, Reference dst)
{ {
Reference source = src; if(src.address != dst.address) {
Reference destination = dst; Reference source = src;
Reference destination = dst;
// dereference varying data
if(type_key(src.type) == Type::Tag::Varying) {
source = *reinterpret_cast<Reference*>(src.address);
}
// prepare destination for varying data
if(type_key(dst.type) == Type::Tag::Varying) {
auto& dest_ref = *reinterpret_cast<Reference*>(dst.address);
// determine if memory can be reused, otherwise free and reallocate // dereference varying data
if(source.type != dest_ref.type) { if(type_key(src.type) == Type::Tag::Varying) {
if(dest_ref.address != nullptr) { source = *reinterpret_cast<Reference*>(src.address);
free(dest_ref.address);
dest_ref.type = Type::Tag::Null;
dest_ref.address = nullptr;
}
dest_ref = acquire(source.type);
} }
}
// copy data into destination // prepare destination for varying data
if(source.type == destination.type) { if(type_key(dst.type) == Type::Tag::Varying) {
switch(type_key(destination.type)) { auto& dest_ref = *reinterpret_cast<Reference*>(dst.address);
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: { // determine if memory can be reused, otherwise free and reallocate
auto& src_list = *reinterpret_cast<Type::List*>(source.address); if(source.type != dest_ref.type) {
auto& dst_list = *reinterpret_cast<Type::List*>(destination.address); if(dest_ref.address != nullptr) {
free(dest_ref.address);
rawlist_reserve(dst_list.data, type_size(type_inner(source.type)), src_list.data.capacity); dest_ref.type = Type::Tag::Null;
dst_list.data.length = src_list.data.length; dest_ref.address = nullptr;
//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; dest_ref = acquire(source.type);
}
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<Type::Schema*>(source.address);
auto& dst_schema = *reinterpret_cast<Type::Schema*>(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<size_t*>(rawlist_cell(src_schema.data, sizeof(size_t), i));
auto dst_cell = reinterpret_cast<size_t*>(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<size_t*>(rawlist_cell(src_schema.map, sizeof(size_t), i));
auto dst_cell = reinterpret_cast<size_t*>(rawlist_cell(dst_schema.map, sizeof(size_t), i));
if(src_cell != nullptr && dst_cell != nullptr) {
*dst_cell = *src_cell;
}
}
} break;
} }
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<Type::List*>(source.address);
auto& dst_list = *reinterpret_cast<Type::List*>(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<Type::Schema*>(source.address);
auto& dst_schema = *reinterpret_cast<Type::Schema*>(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<size_t*>(rawlist_cell(src_schema.data, sizeof(size_t), i));
auto dst_cell = reinterpret_cast<size_t*>(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<size_t*>(rawlist_cell(src_schema.map, sizeof(size_t), i));
auto dst_cell = reinterpret_cast<size_t*>(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; return false;
} }

View File

@ -44,6 +44,10 @@ extern "C" {
pub fn name_keyof(index:usize) -> Str; pub fn name_keyof(index:usize) -> Str;
pub fn name_release(data: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_set(addr:Reference, data:bool);
pub fn bool_get(addr:Reference) -> bool; pub fn bool_get(addr:Reference) -> bool;

224
src/tests.rs Normal file
View File

@ -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.");
}