Add wasm bindings for `Hash`
This commit is contained in:
parent
488dc37fec
commit
03a956e8d9
|
@ -1,7 +1,7 @@
|
||||||
//! The `hash` module provides functions for creating SHA-256 hashes.
|
//! The `hash` module provides functions for creating SHA-256 hashes.
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::sanitize::Sanitize,
|
crate::{sanitize::Sanitize, wasm_bindgen},
|
||||||
borsh::{BorshDeserialize, BorshSchema, BorshSerialize},
|
borsh::{BorshDeserialize, BorshSchema, BorshSerialize},
|
||||||
sha2::{Digest, Sha256},
|
sha2::{Digest, Sha256},
|
||||||
std::{convert::TryFrom, fmt, mem, str::FromStr},
|
std::{convert::TryFrom, fmt, mem, str::FromStr},
|
||||||
|
@ -11,6 +11,8 @@ use {
|
||||||
pub const HASH_BYTES: usize = 32;
|
pub const HASH_BYTES: usize = 32;
|
||||||
/// Maximum string length of a base58 encoded hash
|
/// Maximum string length of a base58 encoded hash
|
||||||
const MAX_BASE58_LEN: usize = 44;
|
const MAX_BASE58_LEN: usize = 44;
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
#[derive(
|
#[derive(
|
||||||
Serialize,
|
Serialize,
|
||||||
Deserialize,
|
Deserialize,
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
//! `Hash` Javascript interface
|
||||||
|
#![cfg(target_arch = "wasm32")]
|
||||||
|
#![allow(non_snake_case)]
|
||||||
|
use {
|
||||||
|
crate::{hash::*, wasm::display_to_jsvalue},
|
||||||
|
js_sys::{Array, Uint8Array},
|
||||||
|
wasm_bindgen::{prelude::*, JsCast},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
impl Hash {
|
||||||
|
/// Create a new Hash object
|
||||||
|
///
|
||||||
|
/// * `value` - optional hash as a base58 encoded string, `Uint8Array`, `[number]`
|
||||||
|
#[wasm_bindgen(constructor)]
|
||||||
|
pub fn constructor(value: JsValue) -> Result<Hash, JsValue> {
|
||||||
|
if let Some(base58_str) = value.as_string() {
|
||||||
|
base58_str.parse::<Hash>().map_err(display_to_jsvalue)
|
||||||
|
} else if let Some(uint8_array) = value.dyn_ref::<Uint8Array>() {
|
||||||
|
Ok(Hash::new(&uint8_array.to_vec()))
|
||||||
|
} else if let Some(array) = value.dyn_ref::<Array>() {
|
||||||
|
let mut bytes = vec![];
|
||||||
|
let iterator = js_sys::try_iter(&array.values())?.expect("array to be iterable");
|
||||||
|
for x in iterator {
|
||||||
|
let x = x?;
|
||||||
|
|
||||||
|
if let Some(n) = x.as_f64() {
|
||||||
|
if n >= 0. && n <= 255. {
|
||||||
|
bytes.push(n as u8);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Err(format!("Invalid array argument: {:?}", x).into());
|
||||||
|
}
|
||||||
|
Ok(Hash::new(&bytes))
|
||||||
|
} else if value.is_undefined() {
|
||||||
|
Ok(Hash::default())
|
||||||
|
} else {
|
||||||
|
Err("Unsupported argument".into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the base58 string representation of the hash
|
||||||
|
pub fn toString(&self) -> String {
|
||||||
|
self.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if two `Hash`s are equal
|
||||||
|
pub fn equals(&self, other: &Hash) -> bool {
|
||||||
|
self == other
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the `Uint8Array` representation of the hash
|
||||||
|
pub fn toBytes(&self) -> Box<[u8]> {
|
||||||
|
self.0.clone().into()
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,13 +2,19 @@
|
||||||
#![cfg(target_arch = "wasm32")]
|
#![cfg(target_arch = "wasm32")]
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
|
pub mod hash;
|
||||||
pub mod pubkey;
|
pub mod pubkey;
|
||||||
|
|
||||||
/// Initialize Javascript logging and panic handler
|
/// Initialize Javascript logging and panic handler
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
|
use std::sync::Once;
|
||||||
|
static INIT: Once = Once::new();
|
||||||
|
|
||||||
|
INIT.call_once(|| {
|
||||||
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
|
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
|
||||||
console_log::init_with_level(log::Level::Info).unwrap();
|
console_log::init_with_level(log::Level::Info).unwrap();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn display_to_jsvalue<T: std::fmt::Display>(display: T) -> JsValue {
|
pub fn display_to_jsvalue<T: std::fmt::Display>(display: T) -> JsValue {
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
import { expect } from "chai";
|
||||||
|
import { init, Hash } from "crate";
|
||||||
|
init();
|
||||||
|
|
||||||
|
// TODO: wasm_bindgen doesn't currently support exporting constants
|
||||||
|
const HASH_BYTES = 32;
|
||||||
|
|
||||||
|
describe("Hash", function () {
|
||||||
|
it("invalid", () => {
|
||||||
|
expect(() => {
|
||||||
|
new Hash([
|
||||||
|
3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
]);
|
||||||
|
}).to.throw();
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
new Hash([
|
||||||
|
'invalid', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0,
|
||||||
|
]);
|
||||||
|
}).to.throw();
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
new Hash(
|
||||||
|
"0x300000000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
);
|
||||||
|
}).to.throw();
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
new Hash(
|
||||||
|
"0x300000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
);
|
||||||
|
}).to.throw();
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
new Hash(
|
||||||
|
"135693854574979916511997248057056142015550763280047535983739356259273198796800000"
|
||||||
|
);
|
||||||
|
}).to.throw();
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
new Hash("12345");
|
||||||
|
}).to.throw();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("toString", () => {
|
||||||
|
const key = new Hash("CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3");
|
||||||
|
expect(key.toString()).to.eq("CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3");
|
||||||
|
|
||||||
|
const key2 = new Hash("1111111111111111111111111111BukQL");
|
||||||
|
expect(key2.toString()).to.eq("1111111111111111111111111111BukQL");
|
||||||
|
|
||||||
|
const key3 = new Hash("11111111111111111111111111111111");
|
||||||
|
expect(key3.toString()).to.eq("11111111111111111111111111111111");
|
||||||
|
|
||||||
|
const key4 = new Hash([
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0,
|
||||||
|
]);
|
||||||
|
expect(key4.toString()).to.eq("11111111111111111111111111111111");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("toBytes", () => {
|
||||||
|
const key = new Hash("CiDwVBFgWV9E5MvXWoLgnEgn2hK7rJikbvfWavzAQz3");
|
||||||
|
expect(key.toBytes()).to.deep.equal(
|
||||||
|
new Uint8Array([
|
||||||
|
3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
const key2 = new Hash();
|
||||||
|
expect(key2.toBytes()).to.deep.equal(
|
||||||
|
new Uint8Array([
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
])
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue