Skip to content

Commit

Permalink
implement buffer interface; tag 0.1.0-a3
Browse files Browse the repository at this point in the history
  • Loading branch information
tiye committed Oct 12, 2021
1 parent 8b5deef commit aa2e904
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "dual_balanced_ternary"
version = "0.1.0-a2"
version = "0.1.0-a3"
edition = "2018"
license = "MIT"
description = "Dual Balanced Ternary Arithmetic"
Expand Down
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,21 @@ use dual_balanced_ternary::{ternary};
ternary("&1.1")
```

### Development

```bash
cargo test
cargo run --example buffer
```

Notice, current buffer format is not compact, but conceptually:

```text
[magic 3]+[integral length]+[integral pairs]+[fractional pairs]
```

since a dbt digits pair takes `81` and `u8` takes `256`, `2/3` of spaces are wasted.

### License

MIT
13 changes: 13 additions & 0 deletions examples/buffer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use dual_balanced_ternary::{ternary, DualBalancedTernary};

pub fn main() -> Result<(), String> {
println!("{:?}", ternary("&1.1").to_buffer());
println!("{:?}", ternary("&14.14").to_buffer());

println!("{:?}", DualBalancedTernary::from_buffer(vec![3, 1, 21, 21]));
println!("{:?}", DualBalancedTernary::from_buffer(vec![3, 1, 65, 20]));

println!("TODO {:?}", ternary("&12.12").to_buffer()?);

Ok(())
}
29 changes: 29 additions & 0 deletions src/digit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,35 @@ use DualBalancedTernaryDigit::*;
pub type DigitsPair = (DualBalancedTernaryDigit, DualBalancedTernaryDigit);

impl DualBalancedTernaryDigit {
pub fn to_u8(&self) -> u8 {
match self {
Dbt1 => 1,
Dbt2 => 2,
Dbt3 => 3,
Dbt4 => 4,
Dbt5 => 5,
Dbt6 => 6,
Dbt7 => 7,
Dbt8 => 8,
Dbt9 => 9,
}
}

pub fn from_u8(x: u8) -> Result<Self, String> {
match x {
1 => Ok(Dbt1),
2 => Ok(Dbt2),
3 => Ok(Dbt3),
4 => Ok(Dbt4),
5 => Ok(Dbt5),
6 => Ok(Dbt6),
7 => Ok(Dbt7),
8 => Ok(Dbt8),
9 => Ok(Dbt9),
_ => Err(format!("unknown digit for dbt: {}", x)),
}
}

pub fn negate(&self) -> DualBalancedTernaryDigit {
match self {
Dbt1 => Dbt9,
Expand Down
92 changes: 92 additions & 0 deletions src/primes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,98 @@ impl DualBalancedTernary {
}
result
}

/// buffer format
/// [magic 3]+[integral length]+[integral pairs]+[fractional pairs]
pub fn to_buffer(&self) -> Result<Vec<u8>, String> {
let int_len = self.integral.len();
if int_len < 256 {
let mut buf: Vec<u8> = vec![3, int_len as u8];
// for integral part, put space 5 at head
let mut halfed = false;
let mut prev: u8 = 0;
for x in &self.integral {
if halfed {
prev += x.to_u8();
buf.push(prev.to_owned());
halfed = false;
} else {
prev = x.to_u8() << 4;
halfed = true;
}
}
if halfed {
prev += 5;
buf.push(prev.to_owned());
halfed = false;
}

// expected handled by pair
assert_eq!(buf.len(), ((int_len + 1) >> 1) + 2);

// for integral part, put space 5 at tail
for x in &self.fractional {
if halfed {
prev += x.to_u8();
buf.push(prev.to_owned());
halfed = false;
} else {
prev = x.to_u8() << 4;
halfed = true;
}
}
if halfed {
prev += 5;
buf.push(prev.to_owned());
}

Ok(buf)
} else {
Err(format!("integral part too long: {}", int_len))
}
}

/// buffer format
/// [magic 3]+[integral length]+[integral pairs]+[fractional pairs]
pub fn from_buffer(buf: Vec<u8>) -> Result<Self, String> {
if buf.len() < 2 {
return Err(String::from("dbt buffer expected >=2 u8 numbers"));
}
if buf[0] != 3 {
return Err(String::from("dbt magic number should be 3"));
}

let int_range = (buf[1] + 1) as usize >> 1;

if buf.len() < (int_range + 2) {
return Err(String::from("dbt buffer length smaller than integral size"));
}
let mut integral: Vec<DualBalancedTernaryDigit> = vec![];
let mut fractional: Vec<DualBalancedTernaryDigit> = vec![];

// println!("buffer: {:?}", buf);
for (idx, x) in buf.iter().enumerate() {
if idx < 2 {
continue;
}
// println!("reading: {} {}", idx, x);
if idx < (int_range + 2) as usize {
integral.push(DualBalancedTernaryDigit::from_u8((x & 0b11110000) >> 4)?);
integral.push(DualBalancedTernaryDigit::from_u8(x & 0b00001111)?);
} else {
fractional.push(DualBalancedTernaryDigit::from_u8((x & 0b11110000) >> 4)?);
fractional.push(DualBalancedTernaryDigit::from_u8(x & 0b00001111)?);
}
}

Ok(
Self {
integral,
fractional,
}
.strip_empty_tails(),
)
}
}

pub fn parse_ternary_digit(s: char) -> Result<DualBalancedTernaryDigit, String> {
Expand Down
32 changes: 32 additions & 0 deletions tests/buffer_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use dual_balanced_ternary::complex::ComplextXy;
use dual_balanced_ternary::{
create_dual_balanced_ternary_from_pair, ternary, DualBalancedTernary, DualBalancedTernaryDigit::*,
};

#[test]
fn to_buffer() -> Result<(), String> {
assert_eq!(
DualBalancedTernary::from_buffer(ternary("&.").to_buffer()?),
Ok(ternary("&."))
);
assert_eq!(
DualBalancedTernary::from_buffer(ternary("&1.").to_buffer()?),
Ok(ternary("&1."))
);
assert_eq!(
DualBalancedTernary::from_buffer(ternary("&.1").to_buffer()?),
Ok(ternary("&.1"))
);

assert_eq!(
DualBalancedTernary::from_buffer(ternary("&12.12").to_buffer()?),
Ok(ternary("&12.12"))
);

assert_eq!(
DualBalancedTernary::from_buffer(ternary("&3445647.674").to_buffer()?),
Ok(ternary("&3445647.674"))
);

Ok(())
}

0 comments on commit aa2e904

Please sign in to comment.