+variable-length signed support
This commit is contained in:
parent
588446cd42
commit
e0ac1b1094
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "bipack_ru"
|
name = "bipack_ru"
|
||||||
version = "0.2.0"
|
version = "0.2.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
description = "binary size-effective format used in Divan smart contracts, wasm bindings, network protocols, etc."
|
description = "binary size-effective format used in Divan smart contracts, wasm bindings, network protocols, etc."
|
||||||
|
36
README.md
36
README.md
@ -1,15 +1,45 @@
|
|||||||
# bipack_ru
|
# bipack_ru
|
||||||
|
|
||||||
> This is yet an alpha. We are still experimenting with the interface. 0.1.* could
|
This is Bipack format implementation, minimalistic by purpose.
|
||||||
> be backward incompatible!
|
|
||||||
|
> work in progress.
|
||||||
|
|
||||||
|
## Already implemented:
|
||||||
|
|
||||||
|
The following parts are already safe to use
|
||||||
|
|
||||||
|
- u8, u16, u32, u64, `smartint` variable-length unsigned
|
||||||
|
- i8, i16, i32, i64, `smartint` variable-length signed
|
||||||
|
- strings (utf8, variable length)
|
||||||
|
- fixed byte arrays
|
||||||
|
- variable length byte arrays
|
||||||
|
|
||||||
|
The sample code (see `src/lib.rs` for more:)
|
||||||
|
```rust
|
||||||
|
fn test() {
|
||||||
|
let mut data = Vec::<u8>::new();
|
||||||
|
data.put_str("Hello, rupack!");
|
||||||
|
println!("size ${}\n{}", data.len(), to_dump(&data));
|
||||||
|
let mut src = SliceSource::from(&data);
|
||||||
|
assert_eq!("Hello, rupack!", src.get_str().unwrap());
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tools and macros
|
||||||
|
|
||||||
|
- `to_dump` to convert binary slice into human-readable dump
|
||||||
|
- 'StringBuilder' super minimalistic string builder (footprint).
|
||||||
|
|
||||||
Bipack format implementation, minimalistic by purpose.
|
|
||||||
|
|
||||||
At the moment it does not include `serde` module as it is yet unclear how much
|
At the moment it does not include `serde` module as it is yet unclear how much
|
||||||
it will increase .wasm size. Could be added later.
|
it will increase .wasm size. Could be added later.
|
||||||
|
|
||||||
The autodoc documentation is good enough already, so we do not repeat it here now.
|
The autodoc documentation is good enough already, so we do not repeat it here now.
|
||||||
|
|
||||||
|
## How to
|
||||||
|
|
||||||
|
- just ad this package to your dependencies, it is on crates.io.
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
|
||||||
For compliance with other modules this work is provided under APACHE 2.0 license a copy of which is included in the file `LICENSE`.
|
For compliance with other modules this work is provided under APACHE 2.0 license a copy of which is included in the file `LICENSE`.
|
@ -54,12 +54,12 @@ pub trait BipackSink {
|
|||||||
for b in data { self.put_u8(*b); }
|
for b in data { self.put_u8(*b); }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn put_var_bytes(self: &mut Self,data: &[u8]) {
|
fn put_var_bytes(self: &mut Self, data: &[u8]) {
|
||||||
self.put_unsigned(data.len());
|
self.put_unsigned(data.len());
|
||||||
self.put_fixed_bytes(data);
|
self.put_fixed_bytes(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn put_str(self: &mut Self,str: &str) {
|
fn put_str(self: &mut Self, str: &str) {
|
||||||
self.put_var_bytes(str.as_bytes());
|
self.put_var_bytes(str.as_bytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,20 +118,30 @@ pub trait BipackSink {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if value < V0LIMIT {
|
if value < V0LIMIT {
|
||||||
encode_seq(0, &[value]);
|
encode_seq(0, &[value]);
|
||||||
}
|
} else if value < V1LIMIT {
|
||||||
else if value < V1LIMIT {
|
encode_seq(1, &[value & 0x3F, value >> 6]);
|
||||||
encode_seq( 1, &[value & 0x3F, value >> 6]);
|
} else if value < V2LIMIT {
|
||||||
}
|
encode_seq(2, &[value & 0x3f, value >> 6, value >> 14]);
|
||||||
else if value < V2LIMIT {
|
} else {
|
||||||
encode_seq( 2, &[value & 0x3f, value >> 6, value >> 14]);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
encode_seq(3, &[value & 0x3f, value >> 6, value >> 14]);
|
encode_seq(3, &[value & 0x3f, value >> 6, value >> 14]);
|
||||||
self.put_var_unsigned(value >> 22);
|
self.put_var_unsigned(value >> 22);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Put variable-length encoded integer value. it is packed just like variable-length
|
||||||
|
/// unsigned value except that LSB (bit 0) is used as negative number flag (when set,
|
||||||
|
/// the encoded number is negative).
|
||||||
|
///
|
||||||
|
/// Note that because of this the range of supported integers is one bit smaller than
|
||||||
|
/// i64, only 30 bits for value and one for a sign. This will probably be fixed later
|
||||||
|
/// but please note that it is impractical to store really big numbers in variable-length
|
||||||
|
/// format, consider using [put_i64] instead which has no such limitation.
|
||||||
|
fn put_signed(self: &mut Self, val: i64) {
|
||||||
|
let (neg, val) = if val < 0 { (1, -val) } else { (0, val) };
|
||||||
|
self.put_unsigned( (neg as u64) | ((val as u64) << 1) );
|
||||||
|
}
|
||||||
|
|
||||||
fn put_var_unsigned(self: &mut Self, value: u64) {
|
fn put_var_unsigned(self: &mut Self, value: u64) {
|
||||||
let mut rest = value;
|
let mut rest = value;
|
||||||
loop {
|
loop {
|
||||||
|
@ -97,6 +97,14 @@ pub trait BipackSource {
|
|||||||
Ok(result | (self.get_varint_unsigned()? << 22))
|
Ok(result | (self.get_varint_unsigned()? << 22))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Unpack variable-length signed value, packed with
|
||||||
|
/// [crate::bipack_sink::BipackSink::put_signed], see it for the packing details.
|
||||||
|
fn get_signed(self: &mut Self) -> Result<i64> {
|
||||||
|
let value = self.get_unsigned()?;
|
||||||
|
let result = (value >> 1) as i64;
|
||||||
|
Ok(if value & 1 != 0 { -result } else { result } )
|
||||||
|
}
|
||||||
|
|
||||||
/// read 8-bytes varint-packed unsigned value from the source. We dont' recommend
|
/// read 8-bytes varint-packed unsigned value from the source. We dont' recommend
|
||||||
/// using it directly; use [BipackSource::get_unsigned] instead.
|
/// using it directly; use [BipackSource::get_unsigned] instead.
|
||||||
fn get_varint_unsigned(self: &mut Self) -> Result<u64> {
|
fn get_varint_unsigned(self: &mut Self) -> Result<u64> {
|
||||||
|
27
src/lib.rs
27
src/lib.rs
@ -245,6 +245,33 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
fn test_varsigned() -> Result<()> {
|
||||||
|
fn test(value: i64) -> Result<()> {
|
||||||
|
let mut x = Vec::new();
|
||||||
|
x.put_signed(value);
|
||||||
|
assert_eq!(value, SliceSource::from(&x).get_signed()?);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
fn test2(value: i64) -> Result<()> {
|
||||||
|
test(value)?;
|
||||||
|
test(-value)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
test(0)?;
|
||||||
|
test2(1)?;
|
||||||
|
test2(2)?;
|
||||||
|
test2(64)?;
|
||||||
|
test2(65)?;
|
||||||
|
test2(127)?;
|
||||||
|
test2(128)?;
|
||||||
|
test2(255)?;
|
||||||
|
test2(256)?;
|
||||||
|
test2(2147483647)?;
|
||||||
|
test2(2222147483647)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
fn test_packer() -> Result<()>{
|
fn test_packer() -> Result<()>{
|
||||||
let a = 177u32;
|
let a = 177u32;
|
||||||
let b = "hello!";
|
let b = "hello!";
|
||||||
|
Loading…
Reference in New Issue
Block a user