diff --git a/.cargo/config.toml b/.cargo/config.toml index 8b5b5992..d5de7aa5 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,6 +1,3 @@ -[target.x86_64-pc-windows-msvc] -rustflags = ["-C", "target-cpu=skylake"] - [target.aarch64-unknown-linux-gnu] linker = "aarch64-linux-gnu-gcc" diff --git a/README.md b/README.md index da2dc972..227b2581 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # node-rs +![](https://github.com/napi-rs/node-rs/workflows/CI/badge.svg) + When `Node.js` meet `Rust` = 🚀 # napi-rs @@ -8,26 +10,27 @@ Make rust crates binding to Node.js use [napi-rs](https://github.com/napi-rs/nap # Support matrix -| | node12 | node14 | node16 | -| ---------------- | ------ | ------ | ------ | -| Windows x64 | ✓ | ✓ | ✓ | -| Windows x32 | ✓ | ✓ | ✓ | -| Windows arm64 | ✓ | ✓ | ✓ | -| macOS x64 | ✓ | ✓ | ✓ | -| macOS arm64 | ✓ | ✓ | ✓ | -| Linux x64 gnu | ✓ | ✓ | ✓ | -| Linux x64 musl | ✓ | ✓ | ✓ | -| Linux arm gnu | ✓ | ✓ | ✓ | -| Linux arm64 gnu | ✓ | ✓ | ✓ | -| Linux arm64 musl | ✓ | ✓ | ✓ | -| Android arm64 | ✓ | ✓ | ✓ | -| FreeBSD x64 | ✓ | ✓ | ✓ | +| | node12 | node14 | node16 | +| --------------------- | ------ | ------ | ------ | +| Windows x64 | ✓ | ✓ | ✓ | +| Windows x32 | ✓ | ✓ | ✓ | +| Windows arm64 | ✓ | ✓ | ✓ | +| macOS x64 | ✓ | ✓ | ✓ | +| macOS arm64 (m chips) | ✓ | ✓ | ✓ | +| Linux x64 gnu | ✓ | ✓ | ✓ | +| Linux x64 musl | ✓ | ✓ | ✓ | +| Linux arm gnu | ✓ | ✓ | ✓ | +| Linux arm64 gnu | ✓ | ✓ | ✓ | +| Linux arm64 musl | ✓ | ✓ | ✓ | +| Android arm64 | ✓ | ✓ | ✓ | +| FreeBSD x64 | ✓ | ✓ | ✓ | # Packages -| Package | Status | Downloads | Description | -| -------------------------------------------- | -------------------------------------------------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------ | -| [`@node-rs/crc32`](./packages/crc32) | ![](https://github.com/napi-rs/node-rs/workflows/CI/badge.svg) | ![](https://img.shields.io/npm/dm/@node-rs/crc32.svg?sanitize=true) | Fastest `CRC32` implementation using `SIMD` | -| [`@node-rs/jieba`](./packages/jieba) | ![](https://github.com/napi-rs/node-rs/workflows/CI/badge.svg) | ![](https://img.shields.io/npm/dm/@node-rs/jieba.svg?sanitize=true) | [`jieba-rs`](https://github.com/messense/jieba-rs) binding | -| [`@node-rs/bcrypt`](./packages/bcrypt) | ![](https://github.com/napi-rs/node-rs/workflows/CI/badge.svg) | ![](https://img.shields.io/npm/dm/@node-rs/bcrypt.svg?sanitize=true) | Fastest bcrypt implementation | -| [`@node-rs/deno-lint`](./packages/deno-lint) | ![](https://github.com/napi-rs/node-rs/workflows/CI/badge.svg) | ![](https://img.shields.io/npm/dm/@node-rs/deno-lint.svg?sanitize=true) | [deno_lint](https://github.com/denoland/deno_lint) Node.js binding | +| Package | Version | Downloads | Description | +| -------------------------------------------- | -------------------------------------------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------- | +| [`@node-rs/crc32`](./packages/crc32) | ![](https://img.shields.io/npm/v/@node-rs/crc32.svg) | ![](https://img.shields.io/npm/dm/@node-rs/crc32.svg?sanitize=true) | Fastest `CRC32` implementation using `SIMD` | +| [`@node-rs/jieba`](./packages/jieba) | ![](https://img.shields.io/npm/v/@node-rs/jieba.svg) | ![](https://img.shields.io/npm/dm/@node-rs/jieba.svg?sanitize=true) | [`jieba-rs`](https://github.com/messense/jieba-rs) binding | +| [`@node-rs/bcrypt`](./packages/bcrypt) | ![](https://img.shields.io/npm/v/@node-rs/bcrypt.svg) | ![](https://img.shields.io/npm/dm/@node-rs/bcrypt.svg?sanitize=true) | Fastest bcrypt implementation | +| [`@node-rs/deno-lint`](./packages/deno-lint) | ![](https://img.shields.io/npm/v/@node-rs/deno-lint.svg) | ![](https://img.shields.io/npm/dm/@node-rs/deno-lint.svg?sanitize=true) | [deno_lint](https://github.com/denoland/deno_lint) Node.js binding | +| [`@node-rs/xxhash`](./packages/xxhash) | ![](https://img.shields.io/npm/v/@node-rs/xxhash.svg) | ![](https://img.shields.io/npm/dm/@node-rs/xxhash.svg?sanitize=true) | [`xxhash-rust`](https://github.com/DoumanAsh/xxhash-rust) Node.js binding | diff --git a/packages/xxhash/README.md b/packages/xxhash/README.md index 8daa018e..e2da14da 100644 --- a/packages/xxhash/README.md +++ b/packages/xxhash/README.md @@ -6,7 +6,7 @@ > 🚀 Help me to become a full-time open-source developer by [sponsoring me on Github](https://github.com/sponsors/Brooooooklyn) -Fastest `xxhash` implementation in Node.js. +[`xxhash-rust`](https://github.com/DoumanAsh/xxhash-rust) binding for Node.js. ## Install this package @@ -52,12 +52,31 @@ export class Xxh32 { constructor(seed?: number) update(input: BufferLike): this digest(): number + reset(): void } export class Xxh64 { constructor(seed?: BigInt) update(input: BufferLike): this digest(): BigInt + reset(): void +} + +export class Xxh3 { + static withSeed(seed?: BigInt): Xxh3 + static withSecret(secret: BufferLike): Xxh3 + private constructor() {} + update(input: BufferLike): this + digest(): BigInt + reset(): void +} + +export const xxh3: { + xxh64: (input: BufferLike, seed?: BigInt) => BigInt + xxh64WithSecret: (input: BufferLike, secret: BufferLike) => BigInt + xxh128: (input: BufferLike, seed?: BigInt) => BigInt + xxh128WithSecret: (input: BufferLike, secret: BufferLike) => BigInt + Xxh3: typeof Xxh3 } ``` diff --git a/packages/xxhash/__test__/xxh3.spec.ts b/packages/xxhash/__test__/xxh3.spec.ts new file mode 100644 index 00000000..137ed370 --- /dev/null +++ b/packages/xxhash/__test__/xxh3.spec.ts @@ -0,0 +1,58 @@ +import test from 'ava' + +import { xxh3 } from '../index' + +const SEC_WITH_192_LENGTH = Buffer.from( + '515293b422141cabb24c131a914d54d767738ce3f46141d91dfdfffa8b2e7ada507318f242dd112f28f213cfc1c4aba1e641e8a7f103746cc542d66668607e2ea4fce4f08640780d0bcd9f171a31f8932ae617033afd5e100c3fb6f0b5b9be611419d79c2bf2358ba1c8562ae24dd1aa2619ab30dcfaa9b8f3363b2a350e750a6aae7e307d16b1d3250f7ed6315ec127fac8643dfcb733ffe622bbc97a3097c6eabd24dee519bc7817e0e8195a426b07ad7452f6ee72465e065afe56e498a450', + 'hex', +) + +test('xxh64 string', (t) => { + t.is(xxh3.xxh64('hello world'), BigInt('15296390279056496779')) +}) + +test('xxh64 Buffer', (t) => { + t.is(xxh3.xxh64(Buffer.from('hello world')), BigInt('15296390279056496779')) +}) + +test('xxh64 with seed', (t) => { + t.is(xxh3.xxh64(Buffer.from('hello world'), BigInt(128)), BigInt('18072542215751182891')) +}) + +test('xxh64 with secret', (t) => { + t.is(xxh3.xxh64WithSecret('hello world', SEC_WITH_192_LENGTH), BigInt('8365614992180151249')) +}) + +test('xxh128 string', (t) => { + t.is(xxh3.xxh128('hello world'), BigInt('297150157938599054391163723952090887879')) +}) + +test('xxh128 buffer', (t) => { + t.is(xxh3.xxh128(Buffer.from('hello world')), BigInt('297150157938599054391163723952090887879')) +}) + +test('xxh128 with seed', (t) => { + t.is(xxh3.xxh128(Buffer.from('hello world'), BigInt(128)), BigInt('248039115514001876413444952452915338056')) +}) + +test('xxh128 with secret', (t) => { + t.is(xxh3.xxh128WithSecret('hello world', SEC_WITH_192_LENGTH), BigInt('169165111715981571090973585540606896681')) +}) + +test('Xxh3 withSeed', (t) => { + const instance = xxh3.Xxh3.withSeed() + t.true(instance instanceof xxh3.Xxh3) + t.is(instance.update('hello world').digest(), BigInt('15296390279056496779')) + t.is(instance.update(Buffer.from('hello world')).digest(), BigInt('16495854690286049632')) + instance.reset() + t.is(instance.update('hello world').digest(), BigInt('15296390279056496779')) +}) + +test('Xxh3 withSecret', (t) => { + const instance = xxh3.Xxh3.withSecret(SEC_WITH_192_LENGTH) + t.true(instance instanceof xxh3.Xxh3) + t.is(instance.update('hello world').digest(), BigInt('8365614992180151249')) + t.is(instance.update(Buffer.from('hello world')).digest(), BigInt('14168446104542996972')) + instance.reset() + t.is(instance.update('hello world').digest(), BigInt('8365614992180151249')) +}) diff --git a/packages/xxhash/index.d.ts b/packages/xxhash/index.d.ts index 77b6947b..589955f3 100644 --- a/packages/xxhash/index.d.ts +++ b/packages/xxhash/index.d.ts @@ -14,10 +14,29 @@ export class Xxh32 { constructor(seed?: number) update(input: BufferLike): this digest(): number + reset(): void } export class Xxh64 { constructor(seed?: BigInt) update(input: BufferLike): this digest(): BigInt + reset(): void +} + +export class Xxh3 { + static withSeed(seed?: BigInt): Xxh3 + static withSecret(secret: BufferLike): Xxh3 + private constructor() {} + update(input: BufferLike): this + digest(): BigInt + reset(): void +} + +export const xxh3: { + xxh64: (input: BufferLike, seed?: BigInt) => BigInt + xxh64WithSecret: (input: BufferLike, secret: BufferLike) => BigInt + xxh128: (input: BufferLike, seed?: BigInt) => BigInt + xxh128WithSecret: (input: BufferLike, secret: BufferLike) => BigInt + Xxh3: typeof Xxh3 } diff --git a/packages/xxhash/index.js b/packages/xxhash/index.js index 2bfd9534..0a4e8e45 100644 --- a/packages/xxhash/index.js +++ b/packages/xxhash/index.js @@ -5,8 +5,30 @@ const { xxh64: _xxh64, Xxh32: _Xxh32, Xxh64: _Xxh64, + xxh3, } = loadBinding(__dirname, 'xxhash', '@node-rs/xxhash') +class Xxh3 { + update(data) { + return xxh3.update.call(this, Buffer.from(data)) + } +} + +Xxh3.withSecret = function withSecret(secret) { + const instance = new Xxh3() + xxh3.createXxh3WithSecret(instance, Buffer.from(secret)) + return instance +} + +Xxh3.withSeed = function withSeed(seed = BigInt(0)) { + const instance = new Xxh3() + xxh3.createXxh3WithSeed(instance, seed) + return instance +} + +Xxh3.prototype.digest = xxh3.digest +Xxh3.prototype.reset = xxh3.reset + module.exports = { xxh32: function xxh32(input, seed) { return _xxh32(Buffer.from(input), seed == null ? 0 : seed) @@ -24,4 +46,19 @@ module.exports = { return super.update(Buffer.from(input)) } }, + xxh3: { + xxh64: function xxh64(input, seed) { + return xxh3.xxh64(Buffer.from(input), seed == null ? BigInt(0) : seed) + }, + xxh64WithSecret(input, secret) { + return xxh3.xxh64WithSecret(Buffer.from(input), Buffer.from(secret)) + }, + xxh128: function xxh128(input, seed) { + return xxh3.xxh128(Buffer.from(input), seed == null ? BigInt(0) : seed) + }, + xxh128WithSecret(input, secret) { + return xxh3.xxh128WithSecret(Buffer.from(input), Buffer.from(secret)) + }, + Xxh3, + }, } diff --git a/packages/xxhash/src/lib.rs b/packages/xxhash/src/lib.rs index 24c4dbca..412fddc6 100644 --- a/packages/xxhash/src/lib.rs +++ b/packages/xxhash/src/lib.rs @@ -3,7 +3,7 @@ extern crate global_alloc; use napi::*; use napi_derive::*; -use xxhash_rust::{xxh32, xxh64}; +use xxhash_rust::{xxh3, xxh32, xxh64}; #[module_exports] fn init(mut exports: JsObject, env: Env) -> Result<()> { @@ -16,6 +16,7 @@ fn init(mut exports: JsObject, env: Env) -> Result<()> { &[ Property::new(&env, "update")?.with_method(update_xxh32), Property::new(&env, "digest")?.with_method(digest_xxh32), + Property::new(&env, "reset")?.with_method(reset_xxh32), ], )?; let xxh64_class = env.define_class( @@ -24,10 +25,23 @@ fn init(mut exports: JsObject, env: Env) -> Result<()> { &[ Property::new(&env, "update")?.with_method(update_xxh64), Property::new(&env, "digest")?.with_method(digest_xxh64), + Property::new(&env, "reset")?.with_method(reset_xxh64), ], )?; exports.set_named_property("Xxh32", xxh32_class)?; exports.set_named_property("Xxh64", xxh64_class)?; + + let mut xxh3 = env.create_object()?; + xxh3.create_named_method("xxh64", xxh3_xxh64)?; + xxh3.create_named_method("xxh64WithSecret", xxh3_xxh64_with_secret)?; + xxh3.create_named_method("xxh128", xxh3_xxh128)?; + xxh3.create_named_method("xxh128WithSecret", xxh3_xxh128_with_secret)?; + xxh3.create_named_method("createXxh3WithSeed", create_xxh3_with_seed)?; + xxh3.create_named_method("createXxh3WithSecret", create_xxh3_with_secret)?; + xxh3.create_named_method("update", update_xxh3)?; + xxh3.create_named_method("digest", digest_xxh3)?; + xxh3.create_named_method("reset", reset_xxh3)?; + exports.set_named_property("xxh3", xxh3)?; Ok(()) } @@ -69,6 +83,19 @@ fn digest_xxh32(ctx: CallContext) -> Result { ctx.env.create_uint32(native.digest()) } +#[js_function(1)] +fn reset_xxh32(ctx: CallContext) -> Result { + let this = ctx.this_unchecked::(); + let native = ctx.env.unwrap::(&this)?; + let seed = if ctx.length == 1 { + ctx.get::(0)?.get_uint32()? + } else { + 0 + }; + native.reset(seed); + ctx.env.get_undefined() +} + #[js_function(2)] fn xxh64(ctx: CallContext) -> Result { let input = ctx.get::(0)?.into_value()?; @@ -106,3 +133,108 @@ fn digest_xxh64(ctx: CallContext) -> Result { let native = ctx.env.unwrap::(&this)?; ctx.env.create_bigint_from_u64(native.digest()) } + +#[js_function(1)] +fn reset_xxh64(ctx: CallContext) -> Result { + let this = ctx.this_unchecked::(); + let native = ctx.env.unwrap::(&this)?; + let seed = if ctx.length == 1 { + ctx.get::(0)?.get_u64()?.0 + } else { + 0 + }; + native.reset(seed); + ctx.env.get_undefined() +} + +#[js_function(2)] +fn xxh3_xxh64(ctx: CallContext) -> Result { + let input = ctx.get::(0)?.into_value()?; + let seed = if ctx.length == 2 { + ctx.get::(1)?.get_u64()?.0 + } else { + 0 + }; + ctx + .env + .create_bigint_from_u64(xxh3::xxh3_64_with_seed(input.as_ref(), seed)) +} + +#[js_function(2)] +fn xxh3_xxh64_with_secret(ctx: CallContext) -> Result { + let input = ctx.get::(0)?.into_value()?; + let secret = ctx.get::(1)?.into_value()?; + ctx + .env + .create_bigint_from_u64(xxh3::xxh3_64_with_secret(input.as_ref(), secret.as_ref())) +} + +#[js_function(2)] +fn xxh3_xxh128(ctx: CallContext) -> Result { + let input = ctx.get::(0)?.into_value()?; + let seed = if ctx.length == 2 { + ctx.get::(1)?.get_u64()?.0 + } else { + 0 + }; + ctx + .env + .create_bigint_from_u128(xxh3::xxh3_128_with_seed(input.as_ref(), seed)) +} + +#[js_function(2)] +fn xxh3_xxh128_with_secret(ctx: CallContext) -> Result { + let input = ctx.get::(0)?.into_value()?; + let secret = ctx.get::(1)?.into_value()?; + ctx + .env + .create_bigint_from_u128(xxh3::xxh3_128_with_secret(input.as_ref(), secret.as_ref())) +} + +#[js_function(2)] +fn create_xxh3_with_seed(ctx: CallContext) -> Result { + let mut js_this = ctx.get::(0)?; + let seed = if ctx.length == 2 { + ctx.get::(1)?.get_u64()?.0 + } else { + 0 + }; + let xxh3_instance = xxh3::Xxh3::with_seed(seed); + ctx.env.wrap(&mut js_this, xxh3_instance)?; + ctx.env.get_undefined() +} + +#[js_function(2)] +fn create_xxh3_with_secret(ctx: CallContext) -> Result { + let mut js_this = ctx.get::(0)?; + let secret = ctx.get::(1)?.into_value()?; + let mut sec = [0u8; 192]; + sec.copy_from_slice(secret.as_ref()); + let xxh3_instance = xxh3::Xxh3::with_secret(sec); + ctx.env.wrap(&mut js_this, xxh3_instance)?; + ctx.env.get_undefined() +} + +#[js_function(2)] +fn update_xxh3(ctx: CallContext) -> Result { + let this = ctx.this_unchecked::(); + let native = ctx.env.unwrap::(&this)?; + let input = ctx.get::(0)?.into_value()?; + native.update(input.as_ref()); + Ok(this) +} + +#[js_function] +fn digest_xxh3(ctx: CallContext) -> Result { + let this = ctx.this_unchecked::(); + let native = ctx.env.unwrap::(&this)?; + ctx.env.create_bigint_from_u64(native.digest()) +} + +#[js_function] +fn reset_xxh3(ctx: CallContext) -> Result { + let this = ctx.this_unchecked::(); + let native = ctx.env.unwrap::(&this)?; + native.reset(); + ctx.env.get_undefined() +}