diff --git a/Cargo.toml b/Cargo.toml index f82e7665..7ee3f919 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,4 +13,5 @@ repository = "https://github.com/datablockset/blockset" io-trait = "0.8.0" io-impl = "0.8.1" io-test = "0.8.1" -wasm-bindgen-test = "0.3.39" +wasm-bindgen-test = "0.3.41" +nanvm-lib = "0.0.1" diff --git a/blockset-lib/Cargo.toml b/blockset-lib/Cargo.toml index 299483dc..91446744 100644 --- a/blockset-lib/Cargo.toml +++ b/blockset-lib/Cargo.toml @@ -11,6 +11,7 @@ repository.workspace = true [dependencies] io-trait.workspace = true +nanvm-lib.workspace = true [dev-dependencies] io-test.workspace = true diff --git a/blockset-lib/src/app.rs b/blockset-lib/src/app.rs index 53b54abf..6a8a50c2 100644 --- a/blockset-lib/src/app.rs +++ b/blockset-lib/src/app.rs @@ -15,6 +15,43 @@ use crate::{ uint::u224::U224, }; +fn set_progress( + state: &mut StatusLine<'_, impl Io>, + display_new: bool, + new: u64, + progress::State { current, total }: progress::State, +) -> io::Result<()> { + let p = if total == 0 { + 1.0 + } else { + (current as f64) / (total as f64) + }; + let s = if display_new { + "New data: ".to_owned() + &mb(new) + ". " + } else { + String::new() + } + "Processed: " + + &mb(current) + + ", "; + state.set_progress(&s, p) +} + +fn file_read( + file: &mut (impl Read + Progress), + tree: &mut MainTreeAdd, + new: &mut u64, +) -> io::Result { + let mut buf = [0; 1024]; + let size = file.read(buf.as_mut())?; + if size == 0 { + return Ok(true); + } + for c in buf[0..size].iter() { + *new += tree.push(*c)?; + } + Ok(false) +} + fn read_to_tree( s: T, mut file: impl Read + Progress, @@ -26,28 +63,10 @@ fn read_to_tree( let mut new = 0; loop { let pr = file.progress(); - let progress::State { current, total } = pr?; - let mut buf = [0; 1024]; - let p = if total == 0 { - 1.0 - } else { - (current as f64) / (total as f64) - }; - let s = if display_new { - "New data: ".to_owned() + &mb(new) + ". " - } else { - String::new() - } + "Processed: " - + &mb(current) - + ", "; - state.set_progress(&s, p)?; - let size = file.read(buf.as_mut())?; - if size == 0 { + set_progress(&mut state, display_new, new, pr?)?; + if file_read(&mut file, &mut tree, &mut new)? { break; } - for c in buf[0..size].iter() { - new += tree.push(*c)?; - } } Ok(tree.end()?.0.to_base32()) } @@ -65,35 +84,58 @@ fn invalid_input(s: &str) -> io::Error { io::Error::new(ErrorKind::InvalidInput, s) } -fn add<'a, T: Io, S: 'a + TreeAdd>( - io: &'a T, - a: &mut T::Args, - storage: impl Fn(&'a T) -> S, - display_new: bool, -) -> io::Result<()> { - let stdout = &mut io.stdout(); - let path = a.next().ok_or(invalid_input("missing file name"))?; - let to_posix_eol = if let Some(option) = a.next() { +fn is_to_posix_eol(a: &mut impl Iterator) -> io::Result { + Ok(if let Some(option) = a.next() { if option != "--to-posix-eol" { return Err(invalid_input("unknown option")); } true } else { false - }; - // let len = io.metadata(&path)?.len(); - let f = io.open(&path)?; - let s = storage(io); - let k = if to_posix_eol { + }) +} + +fn read_to_tree_file( + to_posix_eol: bool, + s: impl TreeAdd, + f: impl Read + Progress, + io: &impl Io, + display_new: bool, +) -> io::Result { + if to_posix_eol { // this may lead to incorrect progress bar because, a size of a file with replaced CRLF // is smaller than `len`. Proposed solution: // a Read implementation which can also report a progress. - read_to_tree(s, ToPosixEol::new(f), io, display_new)? + read_to_tree(s, ToPosixEol::new(f), io, display_new) } else { - read_to_tree(s, f, io, display_new)? - }; - println(stdout, &k)?; - Ok(()) + read_to_tree(s, f, io, display_new) + } +} + +fn add<'a, T: Io, S: 'a + TreeAdd>( + io: &'a T, + a: &mut T::Args, + storage: impl Fn(&'a T) -> S, + display_new: bool, +) -> io::Result<()> { + let stdout = &mut io.stdout(); + let path = a.next().ok_or(invalid_input("missing file name"))?; + let to_posix_eol = is_to_posix_eol(a)?; + // let len = io.metadata(&path)?.len(); + let f = io.open(&path)?; + let k = read_to_tree_file(to_posix_eol, storage(io), f, io, display_new)?; + println(stdout, &k) +} + +fn get_hash(a: &mut impl Iterator) -> io::Result { + let b32 = a.next().ok_or(invalid_input("missing hash"))?; + b32.from_base32::() + .ok_or(invalid_input("invalid hash")) +} + +fn validate(a: &mut impl Iterator, stdout: &mut impl Write) -> io::Result<()> { + let d = get_hash(a)?.to_base32(); + println(stdout, &("valid: ".to_owned() + &d)) } pub fn run(io: &impl Io) -> io::Result<()> { @@ -102,34 +144,19 @@ pub fn run(io: &impl Io) -> io::Result<()> { a.next().unwrap(); let command = a.next().ok_or(invalid_input("missing command"))?; match command.as_str() { - "validate" => { - let b32 = a.next().ok_or(invalid_input("missing hash"))?; - let d = b32 - .from_base32::() - .ok_or(invalid_input("invalid hash"))?; - print(stdout, "valid: ")?; - println(stdout, &d.to_base32())?; - Ok(()) - } + "validate" => validate(&mut a, stdout), "hash" => add(io, &mut a, |_| (), false), "add" => add(io, &mut a, |io| ForestTreeAdd::new(FileForest(io)), true), "get" => { - let b32 = a.next().ok_or(invalid_input("missing hash"))?; - let d = b32 - .from_base32::() - .ok_or(invalid_input("invalid hash"))?; + let d = get_hash(&mut a)?; let path = a.next().ok_or(invalid_input("missing file name"))?; - let mut f = io.create(&path)?; - let table = FileForest(io); - table.restore(&ForestNodeId::new(NodeType::Root, &d), &mut f, io)?; - Ok(()) - } - "info" => { - let total = calculate_total(io)?; - let s = "size: ".to_owned() + &total.to_string() + " B."; - println(stdout, &s)?; - Ok(()) + let w = &mut io.create(&path)?; + FileForest(io).restore(&ForestNodeId::new(NodeType::Root, &d), w, io) } + "info" => println( + stdout, + &("size: ".to_owned() + &calculate_total(io)?.to_string() + " B."), + ), _ => Err(invalid_input("unknown command")), } } diff --git a/blockset-lib/src/cdt/main_tree.rs b/blockset-lib/src/cdt/main_tree.rs index 3bf499aa..ba1b5f61 100644 --- a/blockset-lib/src/cdt/main_tree.rs +++ b/blockset-lib/src/cdt/main_tree.rs @@ -1,5 +1,7 @@ use std::io; +use nanvm_lib::common::default::default; + use crate::uint::u224::U224; use super::{ @@ -17,7 +19,7 @@ impl MainTreeAdd { pub fn new(tree_add: T) -> Self { Self { tree_add, - state: Vec::default(), + state: default(), } } pub fn push(&mut self, c: u8) -> io::Result { diff --git a/blockset-lib/src/cdt/node_id.rs b/blockset-lib/src/cdt/node_id.rs index 0fe9e802..5bbefa44 100644 --- a/blockset-lib/src/cdt/node_id.rs +++ b/blockset-lib/src/cdt/node_id.rs @@ -60,6 +60,7 @@ pub const fn root(hash: &U256) -> U224 { #[cfg(test)] mod test { + use nanvm_lib::common::default::default; use wasm_bindgen_test::wasm_bindgen_test; use crate::{ @@ -87,8 +88,8 @@ mod test { #[wasm_bindgen_test] #[test] fn merge_empty_test() { - assert_eq!(merge(&to_node_id(0x12), &U256::default()), to_node_id(0x12)); - assert_eq!(merge(&U256::default(), &to_node_id(0x34)), to_node_id(0x34)); + assert_eq!(merge(&to_node_id(0x12), &default()), to_node_id(0x12)); + assert_eq!(merge(&default(), &to_node_id(0x34)), to_node_id(0x34)); } #[wasm_bindgen_test] diff --git a/blockset-lib/src/cdt/node_type.rs b/blockset-lib/src/cdt/node_type.rs index 994ef55f..73c4cd0f 100644 --- a/blockset-lib/src/cdt/node_type.rs +++ b/blockset-lib/src/cdt/node_type.rs @@ -1,5 +1,5 @@ #[repr(u8)] -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum NodeType { Root = 0, Child = 1, diff --git a/blockset-lib/src/cdt/subtree.rs b/blockset-lib/src/cdt/subtree.rs index a30ca01d..449219ce 100644 --- a/blockset-lib/src/cdt/subtree.rs +++ b/blockset-lib/src/cdt/subtree.rs @@ -1,6 +1,7 @@ +use nanvm_lib::common::cast::Cast; + use crate::{ cdt::node_id::merge, - common::array::ArrayEx, uint::u256::{great, U256}, }; @@ -42,7 +43,7 @@ pub struct SubTree(Vec); impl SubTree { pub fn new(last: &U256) -> Self { - Self([Node::new2(last, 0)].move_to_vec()) + Self([Node::new2(last, 0)].cast()) } pub fn push(&mut self, last0: &U256) -> Option { let mut height10 = 0; @@ -79,6 +80,7 @@ impl SubTree { #[cfg(test)] mod test { + use nanvm_lib::common::default::default; use wasm_bindgen_test::wasm_bindgen_test; use crate::{ @@ -122,7 +124,7 @@ mod test { assert!(t.0.is_empty()); } { - let mut t = SubTree(Vec::default()); + let mut t = SubTree(default()); assert_eq!(t.push(&c), None); assert_eq!( t.0, @@ -244,7 +246,7 @@ mod test { let a = to_node_id(b'a'); let b = to_node_id(b'b'); let ab = { - let mut t = SubTree(Vec::default()); + let mut t = SubTree(default()); assert_eq!(t.push(&a), None); assert_eq!(t.0, [Node::new2(&a, 0)]); let ab = t.push(&b); @@ -254,7 +256,7 @@ mod test { } .unwrap(); let baa = { - let mut t = SubTree(Vec::default()); + let mut t = SubTree(default()); assert_eq!(t.push(&b), None); assert_eq!(t.0, [Node::new2(&b, 0)]); assert_eq!(t.push(&a), None); @@ -266,7 +268,7 @@ mod test { } .unwrap(); { - let mut t = SubTree(Vec::default()); + let mut t = SubTree(default()); assert_eq!(t.push(&ab), None); assert_eq!(t.0, [Node::new2(&ab, 0)]); let r = t.push(&baa); diff --git a/blockset-lib/src/common/array.rs b/blockset-lib/src/common/array.rs deleted file mode 100644 index def286a1..00000000 --- a/blockset-lib/src/common/array.rs +++ /dev/null @@ -1,17 +0,0 @@ -pub trait ArrayEx { - type Item; - /// Move the array into a vector. - /// Compare to `.to_vec()`, the function doesn't require `Clone` trait. - fn move_to_vec(self) -> Vec; -} - -impl ArrayEx for [T; N] { - type Item = T; - fn move_to_vec(self) -> Vec { - let mut result = Vec::with_capacity(N); - for i in self { - result.push(i); - } - result - } -} diff --git a/blockset-lib/src/common/ascii.rs b/blockset-lib/src/common/ascii.rs index 7aab1bac..008ef7c3 100644 --- a/blockset-lib/src/common/ascii.rs +++ b/blockset-lib/src/common/ascii.rs @@ -5,3 +5,27 @@ pub const fn to_ascii(x: char) -> Option { None } } + +#[cfg(test)] +mod test { + use wasm_bindgen_test::wasm_bindgen_test; + + use super::to_ascii; + + #[inline(never)] + fn x(x: char, y: Option) { + assert_eq!(to_ascii(x), y); + if let Some(y) = y { + assert_eq!(to_ascii(char::from_u32(x as u32 / 2).unwrap()), Some(y / 2)); + } else { + assert_eq!(to_ascii(char::from_u32(x as u32 / 2).unwrap()), None); + } + } + + #[test] + #[wasm_bindgen_test] + fn test() { + x('a', Some(97)); + x('🦀', None); + } +} diff --git a/blockset-lib/src/common/bit_vec.rs b/blockset-lib/src/common/bit_vec.rs index 4b6493d1..c77d443f 100644 --- a/blockset-lib/src/common/bit_vec.rs +++ b/blockset-lib/src/common/bit_vec.rs @@ -22,3 +22,18 @@ impl BitVec { } } } + +#[cfg(test)] +mod test { + use wasm_bindgen_test::wasm_bindgen_test; + + use super::BitVec; + + #[test] + #[wasm_bindgen_test] + fn test() { + let x = BitVec::new(0b1010, 4); + assert_eq!(x.value, 0b1010); + assert_eq!(x.len, 4); + } +} diff --git a/blockset-lib/src/common/eol.rs b/blockset-lib/src/common/eol.rs index 4c92f305..cfb13a3c 100644 --- a/blockset-lib/src/common/eol.rs +++ b/blockset-lib/src/common/eol.rs @@ -24,11 +24,14 @@ impl ToPosixEol { pub fn new(read: R) -> Self { Self { read, last: None } } + fn get_one(&mut self) -> io::Result> { + self.last + .take() + .map_or_else(|| self.read.read_byte(), |x| Ok(Some(x))) + } fn next(&mut self) -> io::Result> { // read the last item - let mut last = if let Some(last) = self.last.take() { - last - } else if let Some(last) = self.read.read_byte()? { + let mut last = if let Some(last) = self.get_one()? { last } else { return Ok(None); @@ -72,23 +75,42 @@ impl Progress for ToPosixEol { mod test { use std::io::{Cursor, Read}; + use nanvm_lib::common::default::default; + use wasm_bindgen_test::wasm_bindgen_test; + use super::ToPosixEol; #[test] + #[wasm_bindgen_test] fn test() { let cursor = Cursor::new(b"abc\r\ndef\r\n\r\nghi\r\n\re"); let mut x = ToPosixEol::new(cursor); - let mut b = Default::default(); + let mut b = default(); x.read_to_end(&mut b).unwrap(); assert_eq!(b, b"abc\ndef\n\nghi\n\re"); } #[test] + #[wasm_bindgen_test] fn test_overflow() { let c = b"\r\r"; let cursor = Cursor::new(c); let mut x = ToPosixEol::new(cursor); - let mut b = Default::default(); + let mut b = default(); x.read_to_end(&mut b).unwrap(); assert_eq!(b, c); } + + #[test] + #[wasm_bindgen_test] + fn test_error() { + struct ReadError(); + impl Read for ReadError { + fn read(&mut self, _: &mut [u8]) -> std::io::Result { + Err(std::io::Error::new(std::io::ErrorKind::Other, "read error")) + } + } + let mut x = ToPosixEol::new(ReadError()); + let mut b = default(); + x.read_to_end(&mut b).unwrap_err(); + } } diff --git a/blockset-lib/src/common/mod.rs b/blockset-lib/src/common/mod.rs index 6109b53f..3d899b46 100644 --- a/blockset-lib/src/common/mod.rs +++ b/blockset-lib/src/common/mod.rs @@ -1,4 +1,3 @@ -pub mod array; pub mod ascii; pub mod base32; pub mod bit_vec; diff --git a/blockset-lib/src/forest/mod.rs b/blockset-lib/src/forest/mod.rs index 42a39361..3de39cf8 100644 --- a/blockset-lib/src/forest/mod.rs +++ b/blockset-lib/src/forest/mod.rs @@ -17,6 +17,15 @@ pub mod tree_add; const EMPTY: U224 = root(&[0, 0]); +fn get_len(v: &[u8]) -> Option { + let len = *v.first().unwrap(); + if len == 0x20 { + None + } else { + Some(len as usize + 1) + } +} + pub trait Forest { fn has_block(&self, id: &ForestNodeId) -> bool; fn get_block(&self, id: &ForestNodeId) -> io::Result>; @@ -46,17 +55,9 @@ pub trait Forest { state.set_progress("", 0.0)?; while let Some((key, size)) = keys.pop() { let v = self.get_block(&ForestNodeId::new(t, &key))?; - let mut len = *v.first().unwrap() as usize; - if len == 0x20 { - let buf = &v[1..]; - w.write_all(buf)?; - progress_p += size; - progress_b += buf.len() as u64; - state.set_progress(&(mb(progress_b) + ", "), progress_p)?; - } else { - len += 1; + if let Some(len) = get_len(&v) { if len > 1 { - assert!(tail.is_empty()); + //assert!(tail.is_empty()); tail = v[1..len].to_vec(); } let mut i = v.len(); @@ -74,6 +75,12 @@ pub trait Forest { } keys.push((kn, size)); } + } else { + let buf = &v[1..]; + w.write_all(buf)?; + progress_p += size; + progress_b += buf.len() as u64; + state.set_progress(&(mb(progress_b) + ", "), progress_p)?; } t = NodeType::Child; } diff --git a/blockset-lib/src/forest/node_id.rs b/blockset-lib/src/forest/node_id.rs index 0b88f6e6..e3e0bdb7 100644 --- a/blockset-lib/src/forest/node_id.rs +++ b/blockset-lib/src/forest/node_id.rs @@ -6,10 +6,26 @@ pub struct ForestNodeId { } impl ForestNodeId { - pub fn new(node_type: NodeType, hash: &U224) -> Self { + pub const fn new(node_type: NodeType, hash: &U224) -> Self { Self { node_type, hash: *hash, } } } + +#[cfg(test)] +mod test { + use wasm_bindgen_test::wasm_bindgen_test; + + use super::ForestNodeId; + use crate::cdt::node_type::NodeType; + + #[test] + #[wasm_bindgen_test] + fn test() { + let x = ForestNodeId::new(NodeType::Root, &[0, 0, 0, 0, 0, 0, 0]); + assert_eq!(x.node_type, NodeType::Root); + assert_eq!(x.hash, [0, 0, 0, 0, 0, 0, 0]); + } +} diff --git a/blockset-lib/src/forest/tree_add.rs b/blockset-lib/src/forest/tree_add.rs index 2473f5b8..0f29cfd8 100644 --- a/blockset-lib/src/forest/tree_add.rs +++ b/blockset-lib/src/forest/tree_add.rs @@ -1,5 +1,7 @@ use std::{io, iter::once, mem::take}; +use nanvm_lib::common::default::default; + use super::{node_id::ForestNodeId, Forest}; use crate::{ @@ -76,7 +78,7 @@ impl ForestTreeAdd { pub fn new(forest: T) -> Self { Self { forest, - levels: Default::default(), + levels: default(), } } } @@ -96,7 +98,7 @@ impl TreeAdd for ForestTreeAdd { } i /= SKIP_LEVEL; if i >= self.levels.nodes.len() { - self.levels.nodes.push(Nodes::default()); + self.levels.nodes.push(default()); } let level = &mut self.levels.nodes[i]; if let Some(k) = to_u224(digest) { @@ -134,6 +136,7 @@ mod test { use std::io::Cursor; use io_test::VirtualIo; + use nanvm_lib::common::default::default; use wasm_bindgen_test::wasm_bindgen_test; use crate::{ @@ -157,7 +160,7 @@ mod test { } fn small(c: &str) { - let mut table = MemForest::default(); + let mut table = default(); let k = add(&mut table, c); let v = (&mut table) .get_block(&ForestNodeId::new(NodeType::Root, &k)) @@ -166,7 +169,7 @@ mod test { } fn big(c: &str) { - let table = &mut MemForest::default(); + let table = &mut default(); let k = add(table, c); let mut v = Vec::default(); let mut cursor = Cursor::new(&mut v); diff --git a/blockset-lib/src/info/mod.rs b/blockset-lib/src/info/mod.rs index c533441a..7fd78c49 100644 --- a/blockset-lib/src/info/mod.rs +++ b/blockset-lib/src/info/mod.rs @@ -4,6 +4,7 @@ mod node_type_set; use std::io; use io_trait::{DirEntry, Io, Metadata}; +use nanvm_lib::common::default::default; use crate::{ cdt::node_type::NodeType, @@ -41,7 +42,7 @@ fn get_all_dir( is_dir: bool, entry: NodeTypeSet, ) -> Vec<(T::DirEntry, NodeType)> { - let mut result = Vec::default(); + let mut result = default(); get_dir(io, path, is_dir, NodeType::Root, entry, &mut result); get_dir(io, path, is_dir, NodeType::Child, entry, &mut result); result diff --git a/blockset-lib/src/info/node_type_set.rs b/blockset-lib/src/info/node_type_set.rs index 4daa8056..491be11d 100644 --- a/blockset-lib/src/info/node_type_set.rs +++ b/blockset-lib/src/info/node_type_set.rs @@ -24,3 +24,38 @@ impl NodeTypeSet { !self.intersection(NodeTypeSet::new(b)).eq(Self::EMPTY) } } + +#[cfg(test)] +mod test { + use wasm_bindgen_test::wasm_bindgen_test; + + use super::NodeTypeSet; + use crate::cdt::node_type::NodeType; + + #[inline(never)] + fn check(x: NodeType, y: NodeType, union: fn(NodeTypeSet, NodeTypeSet) -> NodeTypeSet) { + let xi = 1 << x as u8; + let yi = 1 << y as u8; + let xs = NodeTypeSet::new(x); + let ys = NodeTypeSet::new(y); + assert_eq!(union(xs, ys).0, xi | yi); + assert_eq!(xs.intersection(ys).0, xi & yi); + } + + #[test] + #[wasm_bindgen_test] + fn test() { + check(NodeType::Child, NodeType::Child, NodeTypeSet::union); + check(NodeType::Child, NodeType::Root, NodeTypeSet::union); + let x = NodeTypeSet::new(NodeType::Root); + assert_eq!(x.0, 1); + let y = NodeTypeSet::new(NodeType::Child); + assert_eq!(y.0, 2); + let z = x.union(y); + assert_eq!(z.0, 3); + assert_eq!(z.has(NodeType::Root), true); + assert_eq!(z.has(NodeType::Child), true); + assert_eq!(z.has(NodeType::Root), true); + assert_eq!(z.has(NodeType::Child), true); + } +} diff --git a/blockset-lib/src/uint/u128.rs b/blockset-lib/src/uint/u128.rs index c85b99de..b4724fc9 100644 --- a/blockset-lib/src/uint/u128.rs +++ b/blockset-lib/src/uint/u128.rs @@ -35,3 +35,25 @@ pub const fn u32x4_add(a: u128, b: u128) -> u128 { let [b0, b1, b2, b3] = to_u32x4(b); from_u32x4([add(a0, b0), add(a1, b1), add(a2, b2), add(a3, b3)]) } + +#[inline(always)] +pub const fn shl(u: u128, i: i32) -> u128 { + match i { + -127..=-1 => u >> -i, + 0..=127 => u << i, + _ => 0, + } +} + +#[cfg(test)] +mod test { + use wasm_bindgen_test::wasm_bindgen_test; + + use crate::uint::u128::shl; + + #[wasm_bindgen_test] + #[test] + fn shl_test() { + assert_eq!(shl(1, -130), 0); + } +} diff --git a/blockset-lib/src/uint/u256.rs b/blockset-lib/src/uint/u256.rs index 2d705071..de0dc1c8 100644 --- a/blockset-lib/src/uint/u256.rs +++ b/blockset-lib/src/uint/u256.rs @@ -1,4 +1,4 @@ -use crate::uint::u128::{to_u32x4, u32x4_add}; +use crate::uint::u128::{shl as shl128, to_u32x4, u32x4_add}; pub type U256 = [u128; 2]; @@ -7,18 +7,12 @@ pub const fn u32x8_add(&[a0, a1]: &U256, &[b0, b1]: &U256) -> U256 { [u32x4_add(a0, b0), u32x4_add(a1, b1)] } +#[inline(always)] pub const fn shl(&[lo, hi]: &U256, i: usize) -> U256 { - if i < 128 { - if i == 0 { - [lo, hi] - } else { - [lo << i, (hi << i) | ((lo >> (128 - i)) & ((1 << i) - 1))] - } - } else { - // If i >= 256, a standard `<<` function should panic in debug mode and return the original - // value in release mode. The `shl` function returns 0 in both modes. - [0, if i >= 256 { 0 } else { lo << (i - 128) }] - } + [ + shl128(lo, i as i32), + shl128(hi, i as i32) | shl128(lo, i as i32 - 128), + ] } #[inline(always)] @@ -56,13 +50,14 @@ mod test { use super::{shl, U256}; + const X: U256 = [ + 0x100F_0E0D_0C0B_0A09_0807_0605_0403_0201, + 0x201F_1E1D_1C1B_1A19_1817_1615_1413_1211, + ]; + #[wasm_bindgen_test] #[test] fn shl_test() { - const X: U256 = [ - 0x100F_0E0D_0C0B_0A09_0807_0605_0403_0201, - 0x201F_1E1D_1C1B_1A19_1817_1615_1413_1211, - ]; assert_eq!(shl(&X, 0), X); assert_eq!( shl(&X, 1), @@ -95,6 +90,11 @@ mod test { 0x8807_8706_8605_8504_8403_8302_8201_8100, ] ); + } + + #[wasm_bindgen_test] + #[test] + fn shl_test2() { assert_eq!(shl(&X, 128), [0, 0x100F_0E0D_0C0B_0A09_0807_0605_0403_0201]); assert_eq!(shl(&X, 129), [0, 0x201E_1C1A_1816_1412_100E_0C0A_0806_0402]); assert_eq!(shl(&X, 136), [0, 0x0F_0E0D_0C0B_0A09_0807_0605_0403_020100]); diff --git a/blockset-lib/src/uint/u512.rs b/blockset-lib/src/uint/u512.rs index 249976ff..2cb83d69 100644 --- a/blockset-lib/src/uint/u512.rs +++ b/blockset-lib/src/uint/u512.rs @@ -14,15 +14,39 @@ pub const fn get_u128(a: &U512, i: usize) -> u128 { mod test { use wasm_bindgen_test::wasm_bindgen_test; - use super::new; + use super::{new, U512}; + + //#[inline(never)] + fn create2( + a: u128, + b: u128, + c: u128, + d: u128, + i: u128, + f: fn(u128, u128, u128, u128) -> U512, + ) -> U512 { + f(a * i, b + i, c / (i + 1), d - 1) + } + + //#[inline(never)] + fn create(a: u128, b: u128, c: u128, d: u128) { + for i in 0..10 { + let x = create2(a, b, c, d, i, new); + assert_eq!(x[0][0], a * i); + assert_eq!(x[0][1], b + i); + assert_eq!(x[1][0], c / (i + 1)); + assert_eq!(x[1][1], d - 1); + let xa = new(a, b + i, c / (i + 1), d - 1); + assert_eq!(xa[0][0], a); + assert_eq!(xa[0][1], b + i); + assert_eq!(xa[1][0], c / (i + 1)); + assert_eq!(xa[1][1], d - 1); + } + } #[wasm_bindgen_test] #[test] fn test() { - let a = new(1, 2, 3, 4); - assert_eq!(a[0][0], 1); - assert_eq!(a[0][1], 2); - assert_eq!(a[1][0], 3); - assert_eq!(a[1][1], 4); + create(1, 2, 3, 4); } }