From b3b41faf332034e2d310df09817f40bc51fec327 Mon Sep 17 00:00:00 2001 From: sergeych Date: Sat, 7 Oct 2023 01:44:29 +0100 Subject: [PATCH] Initial commit --- .gitignore | 2 ++ Cargo.toml | 14 ++++++++ src/bipack_sink.rs | 64 ++++++++++++++++++++++++++++++++++++ src/bipack_source.rs | 77 ++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 55 +++++++++++++++++++++++++++++++ 5 files changed, 212 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 src/bipack_sink.rs create mode 100644 src/bipack_source.rs create mode 100644 src/lib.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4fffb2f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +/Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..3b3e004 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "bipack_ru" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0" +lazy_static = "1.4.0" + +[dev-dependencies] +base64 = "0.21.4" +hex = "0.4.3" diff --git a/src/bipack_sink.rs b/src/bipack_sink.rs new file mode 100644 index 0000000..bf10b81 --- /dev/null +++ b/src/bipack_sink.rs @@ -0,0 +1,64 @@ +use std::iter::Iterator; + +pub trait DataSink { + fn put_u8(self: &mut Self, data: u8) -> &Self; + + fn put_fixed_bytes(self: &mut Self, data: &[u8]) -> &Self { + for b in data { self.put_u8(*b); } + return self + } + + fn put_u16(self: &mut Self, mut value: u16) -> &Self { + let mut result = [0u8; 2]; + for i in (0..result.len()).rev() { + result[i] = value as u8; + println!(":: {} / {}", value, value as u8); + value = value >> 8; + } + self.put_fixed_bytes(&result) + } + + fn put_u32(self: &mut Self, mut value: u32) -> &Self { + let mut result = [0u8; 4]; + for i in (0..result.len()).rev() { + result[i] = value as u8; + println!(":: {} / {}", value, value as u8); + value = value >> 8; + } + self.put_fixed_bytes(&result) + } + fn put_u64(self: &mut Self, mut value: u64) -> &Self { + let mut result = [0u8; 8]; + for i in (0..result.len()).rev() { + result[i] = value as u8; + println!(":: {} / {}", value, value as u8); + value = value >> 8; + } + self.put_fixed_bytes(&result) + } +} + +const V0LIMIT: u64 = 1u64 << 6; +const V1LIMIT: u64 = 1u64 << 14; +const V2LIMIT: u64 = 1u64 << 22; + +impl DataSink for Vec { + fn put_u8(self: &mut Self, data: u8) -> &Self { + self.push(data); + self + } +} + +const HEX_DIGS: [char; 16] = [ + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +]; +pub fn to_hex(src: &[u8]) -> Box { + let mut result = Vec::new(); + for i in src { + result.push( HEX_DIGS[(i>>4) as usize]); + result.push( HEX_DIGS[(i&15) as usize]); + } + Box::new(String::from_iter(result)) +} + diff --git a/src/bipack_source.rs b/src/bipack_source.rs new file mode 100644 index 0000000..ad2d431 --- /dev/null +++ b/src/bipack_source.rs @@ -0,0 +1,77 @@ +/// Data source compatible with mp_bintools serialization. It supports +/// fixed-size integers in rihgt order and varint ans smartint encodings +/// separately. +pub trait BipackSource { + fn u8(self: &mut Self) -> u8; + + fn u16(self: &mut Self) -> u16 { + ((self.u8() as u16) << 8) + (self.u8() as u16) + } + fn u32(self: &mut Self) -> u32 { + ((self.u16() as u32) << 16) + (self.u16() as u32) + } + + fn u64(self: &mut Self) -> u64 { + ((self.u32() as u64) << 32) | (self.u32() as u64) + } + + fn smart_u64(self: &mut Self) -> u64 { + let mut get = || -> u64 { self.u8() as u64 }; + let first = get(); + let mut ty = first & 3; + + + let mut result = first >> 2; + if ty == 0 { return result; } + ty -= 1; + + result = result + (get() << 6); + if ty == 0 { return result; } + ty -= 1; + + result = result + (get() << 14); + if ty == 0 { return result; } + + result | (self.var_u64() << 22) + } + + fn var_u64(self: &mut Self) -> u64 { + let mut result = 0u64; + let mut count = 0; + loop { + let x = self.u8() as u64; + result = result | ((x & 0x7F) << count); + if (x & 0x80) == 0 { return result; } + count += 7 + } + } + + fn smart_u16(self: &mut Self) -> u16 { + self.smart_u64() as u16 + } + fn smart_u32(self: &mut Self) -> u32 { self.smart_u64() as u32 } +} + +pub struct SliceSource<'a> { + data: &'a [u8], + position: usize, +} + +impl<'a> SliceSource<'a> { + pub fn new(src: &'a [u8]) -> SliceSource { + SliceSource { data: src, position: 0 } + } +} + +impl<'x> BipackSource for SliceSource<'x> { + fn u8(self: &mut Self) -> u8 { + let result = self.data[self.position]; + self.position += 1; + result + } +} + +pub fn bipack_source<'b>(v: &'b [u8]) -> SliceSource<'b> { + SliceSource::new(v) +} + diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..2f29f16 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,55 @@ +#![allow(dead_code)] +#![allow(unused_variables)] + +mod bipack_source; +mod bipack_sink; + +pub fn add(left: usize, right: usize) -> usize { + left + right +} + +#[cfg(test)] +mod tests { + use base64::Engine; + use crate::bipack_sink::{BipackSink}; + use crate::bipack_source::{bipack_source, BipackSource, SliceSource}; + + #[test] + fn fixed_unpack() { + let mut src = Vec::new(); + base64::engine::general_purpose::STANDARD_NO_PAD + .decode_vec("B/oAAAEB0AAAANjLgKAv", &mut src) + .expect("decoded vector"); + println!(": {}", hex::encode(&src)); + let mut ss = SliceSource::new(&src); + assert_eq!(7, ss.u8()); + assert_eq!(64000, ss.u16()); + assert_eq!(66000, ss.u32()); + assert_eq!(931127140399, ss.u64()); + } + + #[test] + fn smartint_unpack() { + let mut src = Vec::new(); + base64::engine::general_purpose::STANDARD_NO_PAD + .decode_vec("BwLoA0IHBL+AAq7GDQ", &mut src) + .expect("decoded vector"); + let mut ss = bipack_source(&src); + assert_eq!(7, ss.u8()); + assert_eq!(64000, ss.smart_u16()); + assert_eq!(66000, ss.smart_u32()); + assert_eq!(931127140399, ss.smart_u64()); + } + + #[test] + fn fixed_pack() { + let mut data: Vec = Vec::new(); + data.put_u8(7); + data.put_u16(64000); + data.put_u32(66000); + data.put_u64(931127140399); + // println!("-- {:?}", data.iter().map(|x| format!("{:0x}", x)).collect::>()); + assert_eq!("07fa00000101d0000000d8cb80a02f", hex::encode(&data).as_str()); + // println!("data = {}", to_hex(&data)); + } +} \ No newline at end of file