mod convert;
mod encoder;
mod extras;
mod streaming;
use convert::*;
use tensogram::{self as core, DecodeOptions};
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn decode(buf: &[u8], verify_hash: Option<bool>) -> Result<DecodedMessage, JsError> {
let options = DecodeOptions {
verify_hash: verify_hash.unwrap_or(false),
..Default::default()
};
let (metadata, objects) = core::decode(buf, &options).map_err(js_err)?;
Ok(DecodedMessage { metadata, objects })
}
#[wasm_bindgen]
pub fn decode_metadata(buf: &[u8]) -> Result<JsValue, JsError> {
let meta = core::decode_metadata(buf).map_err(js_err)?;
to_js(&meta)
}
#[wasm_bindgen]
pub fn decode_object(
buf: &[u8],
index: usize,
verify_hash: Option<bool>,
) -> Result<DecodedMessage, JsError> {
let options = DecodeOptions {
verify_hash: verify_hash.unwrap_or(false),
..Default::default()
};
let (metadata, descriptor, data) = core::decode_object(buf, index, &options).map_err(js_err)?;
Ok(DecodedMessage {
metadata,
objects: vec![(descriptor, data)],
})
}
#[wasm_bindgen]
pub fn scan(buf: &[u8]) -> Result<JsValue, JsError> {
let positions = core::scan(buf);
to_js(&positions)
}
#[wasm_bindgen]
pub fn encode(
metadata_js: JsValue,
objects_js: js_sys::Array,
hash: Option<bool>,
reject_nan: Option<bool>,
reject_inf: Option<bool>,
) -> Result<js_sys::Uint8Array, JsError> {
let metadata: core::GlobalMetadata =
serde_wasm_bindgen::from_value(metadata_js).map_err(js_err)?;
let (descriptors, data_vec) = extract_descriptor_data_pairs(&objects_js)?;
let pairs: Vec<(&core::DataObjectDescriptor, &[u8])> = descriptors
.iter()
.zip(data_vec.iter())
.map(|(d, v)| (d, v.as_slice()))
.collect();
let encoded = core::encode(
&metadata,
&pairs,
&build_encode_options(hash, reject_nan, reject_inf),
)
.map_err(js_err)?;
Ok(js_sys::Uint8Array::from(encoded.as_slice()))
}
#[wasm_bindgen]
pub struct DecodedMessage {
metadata: core::GlobalMetadata,
objects: Vec<core::DecodedObject>,
}
#[wasm_bindgen]
impl DecodedMessage {
pub fn metadata(&self) -> Result<JsValue, JsError> {
to_js(&self.metadata)
}
pub fn object_count(&self) -> usize {
self.objects.len()
}
pub fn object_descriptor(&self, index: usize) -> Result<JsValue, JsError> {
let _ = self.payload(index)?;
to_js(&self.objects[index].0)
}
pub fn object_data_f32(&self, index: usize) -> Result<js_sys::Float32Array, JsError> {
let data = self.payload(index)?;
view_as_f32(data)
}
pub fn object_data_f64(&self, index: usize) -> Result<js_sys::Float64Array, JsError> {
let data = self.payload(index)?;
view_as_f64(data)
}
pub fn object_data_i32(&self, index: usize) -> Result<js_sys::Int32Array, JsError> {
let data = self.payload(index)?;
view_as_i32(data)
}
pub fn object_data_u8(&self, index: usize) -> Result<js_sys::Uint8Array, JsError> {
let data = self.payload(index)?;
Ok(view_as_u8(data))
}
pub fn object_data_copy_f32(&self, index: usize) -> Result<js_sys::Float32Array, JsError> {
let data = self.payload(index)?;
copy_as_f32(data)
}
pub fn object_byte_length(&self, index: usize) -> Result<usize, JsError> {
Ok(self.payload(index)?.len())
}
}
impl DecodedMessage {
fn payload(&self, index: usize) -> Result<&[u8], JsError> {
if index >= self.objects.len() {
return Err(JsError::new(&format!(
"object index {index} out of range (have {})",
self.objects.len()
)));
}
Ok(&self.objects[index].1)
}
}
pub use streaming::StreamingDecoder;
pub use encoder::StreamingEncoder;
pub use extras::{
compute_hash, decode_range, encode_pre_encoded, simple_packing_compute_params, validate_buffer,
};