use super::any_chunk::AnyChunk;
use super::content::ContentChunk;
use super::traits::{BmtChunk, Chunk};
use crate::bmt::{BRANCHES, DEFAULT_BODY_SIZE, HASH_SIZE, SPAN_SIZE};
use js_sys::{Array, Uint8Array};
use wasm_bindgen::prelude::*;
#[wasm_bindgen(js_name = ContentChunk)]
pub struct WasmContentChunk(ContentChunk<DEFAULT_BODY_SIZE>);
#[wasm_bindgen(js_class = ContentChunk)]
impl WasmContentChunk {
#[wasm_bindgen(constructor)]
pub fn new(data: &Uint8Array) -> Result<WasmContentChunk, JsValue> {
ContentChunk::<DEFAULT_BODY_SIZE>::new(data.to_vec())
.map(WasmContentChunk)
.map_err(|e| JsValue::from_str(&e.to_string()))
}
#[wasm_bindgen]
pub fn address(&self) -> Uint8Array {
let result = Uint8Array::new_with_length(32);
result.copy_from(self.0.address().as_slice());
result
}
#[wasm_bindgen]
pub fn data(&self) -> Uint8Array {
let data = self.0.data();
let result = Uint8Array::new_with_length(data.len() as u32);
result.copy_from(data);
result
}
#[wasm_bindgen]
pub fn span(&self) -> u64 {
self.0.span()
}
#[wasm_bindgen]
pub fn serialize(&self) -> Uint8Array {
let bytes: bytes::Bytes = self.0.clone().into();
let result = Uint8Array::new_with_length(bytes.len() as u32);
result.copy_from(&bytes);
result
}
}
#[wasm_bindgen(js_name = SplitResult)]
pub struct WasmSplitResult {
root: [u8; 32],
chunks: Vec<AnyChunk<DEFAULT_BODY_SIZE>>,
}
#[wasm_bindgen(js_class = SplitResult)]
impl WasmSplitResult {
#[wasm_bindgen(getter, js_name = rootAddress)]
pub fn root_address(&self) -> Uint8Array {
let result = Uint8Array::new_with_length(32);
result.copy_from(&self.root);
result
}
#[wasm_bindgen(getter, js_name = chunkCount)]
pub fn chunk_count(&self) -> usize {
self.chunks.len()
}
#[wasm_bindgen]
pub fn chunks(&self) -> Array {
let arr = Array::new();
for chunk in &self.chunks {
if let Some(content) = chunk.as_content() {
arr.push(&WasmContentChunk(content.clone()).into());
}
}
arr
}
#[wasm_bindgen(js_name = getChunk)]
pub fn get_chunk(&self, index: usize) -> Option<WasmContentChunk> {
self.chunks
.get(index)
.and_then(|c| c.as_content())
.cloned()
.map(WasmContentChunk)
}
#[wasm_bindgen]
pub fn addresses(&self) -> Array {
let arr = Array::new();
for chunk in &self.chunks {
let addr = Uint8Array::new_with_length(32);
addr.copy_from(chunk.address().as_slice());
arr.push(&addr);
}
arr
}
}
#[wasm_bindgen(js_name = splitFile)]
pub fn split_file(data: &Uint8Array) -> Result<WasmSplitResult, JsValue> {
let bytes = data.to_vec();
let (root, store) = crate::file::sync_split::<DEFAULT_BODY_SIZE>(&bytes)
.map_err(|e| JsValue::from_str(&e.to_string()))?;
Ok(WasmSplitResult {
root: root.into(),
chunks: store.into_chunks().into_values().collect(),
})
}
#[wasm_bindgen(js_name = hashChunkData)]
pub fn hash_chunk_data(data: &Uint8Array, span: u64) -> Result<Uint8Array, JsValue> {
use crate::bmt::Hasher;
let data_vec = data.to_vec();
if data_vec.len() > DEFAULT_BODY_SIZE {
return Err(JsValue::from_str(&format!(
"Data too large: {} bytes (max {})",
data_vec.len(),
DEFAULT_BODY_SIZE
)));
}
let mut hasher = Hasher::<DEFAULT_BODY_SIZE>::new();
hasher.set_span(span);
hasher.update(&data_vec);
let hash = hasher.sum();
let result = Uint8Array::new_with_length(32);
result.copy_from(hash.as_slice());
Ok(result)
}
#[wasm_bindgen(js_name = chunkFromBytes)]
pub fn chunk_from_bytes(bytes: &Uint8Array) -> Result<WasmContentChunk, JsValue> {
let bytes_vec = bytes.to_vec();
ContentChunk::<DEFAULT_BODY_SIZE>::try_from(bytes::Bytes::from(bytes_vec))
.map(WasmContentChunk)
.map_err(|e| JsValue::from_str(&e.to_string()))
}
#[wasm_bindgen(js_name = getConstants)]
pub fn get_constants() -> Result<JsValue, JsValue> {
use js_sys::Object;
let obj = Object::new();
js_sys::Reflect::set(&obj, &"BODY_SIZE".into(), &JsValue::from(DEFAULT_BODY_SIZE))?;
js_sys::Reflect::set(&obj, &"SPAN_SIZE".into(), &JsValue::from(SPAN_SIZE))?;
js_sys::Reflect::set(&obj, &"HASH_SIZE".into(), &JsValue::from(HASH_SIZE))?;
js_sys::Reflect::set(&obj, &"BRANCHES".into(), &JsValue::from(BRANCHES))?;
Ok(obj.into())
}