+variable-length signed support
This commit is contained in:
parent
588446cd42
commit
e0ac1b1094
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "bipack_ru"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
edition = "2021"
|
||||
license = "Apache-2.0"
|
||||
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
|
||||
|
||||
> This is yet an alpha. We are still experimenting with the interface. 0.1.* could
|
||||
> be backward incompatible!
|
||||
This is Bipack format implementation, minimalistic by purpose.
|
||||
|
||||
> 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
|
||||
it will increase .wasm size. Could be added later.
|
||||
|
||||
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
|
||||
|
||||
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); }
|
||||
}
|
||||
|
||||
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_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());
|
||||
}
|
||||
|
||||
@ -118,20 +118,30 @@ pub trait BipackSink {
|
||||
};
|
||||
|
||||
if value < V0LIMIT {
|
||||
encode_seq(0, &[value]);
|
||||
}
|
||||
else if value < V1LIMIT {
|
||||
encode_seq( 1, &[value & 0x3F, value >> 6]);
|
||||
}
|
||||
else if value < V2LIMIT {
|
||||
encode_seq( 2, &[value & 0x3f, value >> 6, value >> 14]);
|
||||
}
|
||||
else {
|
||||
encode_seq(0, &[value]);
|
||||
} else if value < V1LIMIT {
|
||||
encode_seq(1, &[value & 0x3F, value >> 6]);
|
||||
} else if value < V2LIMIT {
|
||||
encode_seq(2, &[value & 0x3f, value >> 6, value >> 14]);
|
||||
} else {
|
||||
encode_seq(3, &[value & 0x3f, value >> 6, value >> 14]);
|
||||
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) {
|
||||
let mut rest = value;
|
||||
loop {
|
||||
|
@ -97,6 +97,14 @@ pub trait BipackSource {
|
||||
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
|
||||
/// using it directly; use [BipackSource::get_unsigned] instead.
|
||||
fn get_varint_unsigned(self: &mut Self) -> Result<u64> {
|
||||
|
27
src/lib.rs
27
src/lib.rs
@ -245,6 +245,33 @@ mod tests {
|
||||
}
|
||||
|
||||
#[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<()>{
|
||||
let a = 177u32;
|
||||
let b = "hello!";
|
||||
|
Loading…
Reference in New Issue
Block a user