commit 9b3f7698b51dd3225f48f8c119cc358f1f2196c0 Author: yukirij Date: Wed Apr 26 22:13:32 2023 -0700 Initialize project. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..a1740ea --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "szun" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..76b4d94 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "szun" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/project.code-workspace b/project.code-workspace new file mode 100644 index 0000000..732b176 --- /dev/null +++ b/project.code-workspace @@ -0,0 +1,12 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": { + "rust-analyzer.linkedProjects": [ + ".\\Cargo.toml" + ] + } +} \ No newline at end of file diff --git a/src/bin/main.rs b/src/bin/main.rs new file mode 100644 index 0000000..778d05a --- /dev/null +++ b/src/bin/main.rs @@ -0,0 +1,7 @@ +fn main() +{ + let d = szun::Integer::from(-1); + let enc = d.encode(); + + for b in enc { print!("{:02x}", b); } print!("\n"); +} diff --git a/src/data/boolean.rs b/src/data/boolean.rs new file mode 100644 index 0000000..8d842d1 --- /dev/null +++ b/src/data/boolean.rs @@ -0,0 +1,19 @@ +use crate::{Szun, Type}; + +pub struct Boolean { + data:bool, +} +impl Boolean { + pub fn new() -> Szun + { + Szun::Boolean(false) + } + + pub fn from(data:bool) -> Szun + { + Szun::Boolean(data) + } +} +impl Type for Boolean { + fn tag() -> u32 { 0x02 } +} diff --git a/src/data/integer.rs b/src/data/integer.rs new file mode 100644 index 0000000..fc4484d --- /dev/null +++ b/src/data/integer.rs @@ -0,0 +1,19 @@ +use crate::{Szun, Type}; + +pub struct Integer { + data:i64, +} +impl Integer { + pub fn new() -> Szun + { + Szun::Integer(0) + } + + pub fn from(data:i64) -> Szun + { + Szun::Integer(data) + } +} +impl Type for Integer { + fn tag() -> u32 { 0x11 } +} diff --git a/src/data/mod.rs b/src/data/mod.rs new file mode 100644 index 0000000..2e054e6 --- /dev/null +++ b/src/data/mod.rs @@ -0,0 +1,4 @@ +mod null; pub use null::Null; +mod boolean; pub use boolean::Boolean; +mod natural; pub use natural::Natural; +mod integer; pub use integer::Integer; diff --git a/src/data/natural.rs b/src/data/natural.rs new file mode 100644 index 0000000..4c7984b --- /dev/null +++ b/src/data/natural.rs @@ -0,0 +1,19 @@ +use crate::{Szun, Type}; + +pub struct Natural { + data:u64, +} +impl Natural { + pub fn new() -> Szun + { + Szun::Natural(0) + } + + pub fn from(data:u64) -> Szun + { + Szun::Natural(data) + } +} +impl Type for Natural { + fn tag() -> u32 { 0x10 } +} diff --git a/src/data/null.rs b/src/data/null.rs new file mode 100644 index 0000000..f020364 --- /dev/null +++ b/src/data/null.rs @@ -0,0 +1,11 @@ +use crate::{Szun, Type}; + +pub struct Null { } +impl Null { + pub fn new() -> Szun { + Szun::Null + } +} +impl Type for Null { + fn tag() -> u32 { 0x00 } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..83fe9e9 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,129 @@ +#![allow(dead_code)] + +mod util; +mod template; use template::Type; +mod data; pub use data::*; + +pub enum Szun { + Null, + Boolean(bool), + Natural(u64), + Integer(i64), + Decimal(f64), + Block(Vec), + String(String), + Set(Vec), + Array(Vec), + List(Vec), + Sparse(Vec), + Map(Vec), + //Tree(Vec), + //Graph(Vec), + Enum(Vec), + Selection(Vec), + Record(Vec), + Schema(Vec), +} +impl Szun { + fn encode_parts(&self) -> (Vec, Vec) + { + let mut tags = Vec::::with_capacity(1); + let mut encoded = Vec::::with_capacity(64); + + match self { + Self::Null => { + tags.push(Null::tag()); + } + + Self::Boolean(_data) => { + tags.push(Boolean::tag()); + } + + Self::Natural(data) => { + tags.push(Natural::tag()); + encoded.append(&mut util::pack_natural(*data)); + } + + Self::Integer(data) => { + tags.push(Integer::tag()); + encoded.append(&mut &mut util::pack_integer(*data)); + } + + _ => { + tags.push(0); + } + + /*Self::Decimal(_data) => { + tag = Decimal::tag(); + } + + Self::Block(_data) => { + tag = Block::tag(); + } + + Self::String(_data) => { + tag = String::tag(); + } + + Self::Set(_data) => { + tag = Set::tag(); + } + + Self::Array(_data) => { + tag = Array::tag(); + } + + Self::List(_data) => { + tag = List::tag(); + } + + Self::Sparse(_data) => { + tag = Sparse::tag(); + } + + Self::Map(_data) => { + tag = Map::tag(); + } + + Self::Enum(_data) => { + tag = Enum::tag(); + } + + Self::Selection(_data) => { + tag = Selection::tag(); + } + + Self::Record(_data) => { + tag = Record::tag(); + } + + Self::Schema(_data) => { + tag = Schema::tag(); + }*/ + } + + return (tags, encoded); + } + + pub fn encode_data(&self) -> Vec + { + let (_, encoded) = self.encode_parts(); + return encoded; + } + + pub fn encode(&self) -> Vec + { + let (tags, data) = self.encode_parts(); + let mut prefix = Vec::::with_capacity(16); + + for tag in tags { + prefix.append(&mut util::pack_natural(tag as u64)); + } + + let mut encoded = Vec::::with_capacity(prefix.len() + data.len()); + for b in prefix { encoded.push(b); } + for b in data { encoded.push(b); } + + return encoded; + } +} diff --git a/src/template/mod.rs b/src/template/mod.rs new file mode 100644 index 0000000..d92275a --- /dev/null +++ b/src/template/mod.rs @@ -0,0 +1,3 @@ +pub trait Type { + fn tag() -> u32; +} diff --git a/src/util/mod.rs b/src/util/mod.rs new file mode 100644 index 0000000..132d82f --- /dev/null +++ b/src/util/mod.rs @@ -0,0 +1,123 @@ +fn pack_count_leading_ones(data:u8) -> usize +{ + (data == 0xff) as usize + + (data >= 0xfe) as usize + + (data >= 0xfc) as usize + + (data >= 0xf8) as usize + + (data >= 0xf0) as usize + + (data >= 0xe0) as usize + + (data >= 0xc0) as usize + + (data >= 0x80) as usize +} + +fn pack_encode_size(data:u64, signed:bool) -> usize +{ + let sign_bit = signed as u32; + 1 + (data >= 1 << (7 - sign_bit)) as usize + + (data >= 1 << (14 - sign_bit)) as usize + + (data >= 1 << (21 - sign_bit)) as usize + + (data >= 1 << (28 - sign_bit)) as usize + + (data >= 1 << (35 - sign_bit)) as usize + + (data >= 1 << (42 - sign_bit)) as usize + + (data >= 1 << (49 - sign_bit)) as usize + + (data >= 1 << (56 - sign_bit)) as usize + + (signed && data >= 1 << 63) as usize +} + +fn pack_data(size:usize, data:u64, sign:bool) -> Vec +{ + let mut data = data; + let mut buffer :Vec = vec![0]; + let mut header_size = size - 1; + let mut buffer_size = size; + + if header_size >= 8 { + buffer.append(&mut pack_natural(header_size as u64)); + buffer_size += buffer.len() - 1; + header_size = 8; + } + buffer.resize(buffer_size, 0); + buffer[0] = ((0xFF00 >> header_size) & 0xFF) as u8; + + for i in 1..buffer_size + 1 { + buffer[buffer_size - i] |= (data & 0xFF) as u8; + data >>= 8; + } + + if sign { + match header_size { + 8 => { buffer[buffer_size - (size - 1)] |= 0x80; } + 7 => { buffer[1] |= 0x80; } + _ => { buffer[0] |= 1 << 6 - header_size; } + } + } + + return buffer; +} + +pub fn pack_natural(data:u64) -> Vec +{ + pack_data(pack_encode_size(data, false), data, false) +} + +pub fn pack_integer(data:i64) -> Vec +{ + let mut udata :u64 = data as u64; + let negative :bool = data < 0; + if negative { udata = !udata; } + + pack_data(pack_encode_size(udata, true), udata, negative) +} + +fn unpack_data(data:&Vec, index:&mut usize, signed:bool) -> u64 +{ + let mut result :u64 = 0; + let mut negative = false; + if *index < data.len() { + let mut pack_size = pack_count_leading_ones(data[*index]); + + if pack_size < 7 { + result = (((data[*index] as u64) << pack_size) & 0xFF) >> pack_size; + if signed { + let sign_mask = 1 << (6 - pack_size); + println!("data: {}, mask: {}", result, sign_mask); + negative = (result & sign_mask) != 0; + result &= !sign_mask; + } + *index += 1; + } + else { + *index += 1; + if pack_size == 8 { + pack_size = unpack_natural(&data, index) as usize; + } + pack_size -= 1; + + result = data[*index] as u64; + if signed { + negative = (result & 0x80) != 0; + result &= 0x7F; + } + *index += 1; + } + + for _ in 1..pack_size + 1 { + result <<= 8; + result += data[*index] as u64; + *index += 1; + } + + if negative { result = !result; } + } + return result; +} + +pub fn unpack_natural(data:&Vec, index:&mut usize) -> u64 +{ + unpack_data(data, index, false) +} + +pub fn unpack_integer(data:&Vec, index:&mut usize) -> i64 +{ + unpack_data(data, index, true) as i64 +}