diff --git a/__test__/index.spec.ts b/__test__/index.spec.ts index a052faa..4832f6e 100644 --- a/__test__/index.spec.ts +++ b/__test__/index.spec.ts @@ -12,12 +12,22 @@ test('compress should be async version of compressSync', async (t) => { t.deepEqual(await compress(fixture), compressSync(fixture)) }) -test('should be able to decompress sync', (t) => { +test('should be able to uncompress sync', (t) => { const fixture = 'hello world 😂 🎧 🚀' t.deepEqual(uncompressSync(compressSync(fixture)), Buffer.from(fixture)) }) -test('should be able to decompress', async (t) => { +test('should be able to uncompress sync into string', (t) => { + const fixture = 'hello world 😂 🎧 🚀' + t.deepEqual(uncompressSync(compressSync(fixture), { asBuffer: false }), fixture) +}) + +test('should be able to uncompress', async (t) => { const fixture = 'hello world 😂 🎧 🚀' t.deepEqual(await uncompress(await compress(fixture)), Buffer.from(fixture)) }) + +test('should be able to uncompress into string', async (t) => { + const fixture = 'hello world 😂 🎧 🚀' + t.deepEqual(await uncompress(await compress(fixture), { asBuffer: false }), fixture) +}) diff --git a/index.d.ts b/index.d.ts index 293731d..6c541b6 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,4 +1,10 @@ export function compressSync(input: Buffer | string | ArrayBuffer | Uint8Array): Buffer export function compress(input: Buffer | string | ArrayBuffer | Uint8Array): Promise export function uncompressSync(compressed: Buffer): Buffer +export function uncompressSync(compressed: Buffer, opt: { asBuffer: true }): Buffer +export function uncompressSync(compressed: Buffer, opt: { asBuffer: false }): string +export function uncompressSync(compressed: Buffer, opt?: { asBuffer: boolean }): string | Buffer export function uncompress(compressed: Buffer): Promise +export function uncompress(compressed: Buffer, opt: { asBuffer: true }): Promise +export function uncompress(compressed: Buffer, opt: { asBuffer: false }): Promise +export function uncompress(compressed: Buffer, opt?: { asBuffer: boolean }): Promise diff --git a/index.js b/index.js index 1bcb543..fdeda4f 100644 --- a/index.js +++ b/index.js @@ -3,8 +3,8 @@ const { loadBinding } = require('@node-rs/helper') const { compressSync: _compressSync, compress: _compress, - uncompress, - uncompressSync, + uncompress: _uncompress, + uncompressSync: _uncompressSync, } = loadBinding(__dirname, 'snappy', '@napi-rs/snappy') module.exports = { @@ -14,6 +14,10 @@ module.exports = { compress: function compress(input) { return _compress(Buffer.from(input)) }, - uncompress, - uncompressSync, + uncompress: function uncompress(input, opt = { asBuffer: true }) { + return _uncompress(input, Boolean(opt.asBuffer)) + }, + uncompressSync: function uncompressSync(input, opt = { asBuffer: true }) { + return _uncompressSync(input, Boolean(opt.asBuffer)) + }, } diff --git a/src/lib.rs b/src/lib.rs index 60b6686..6a3c201 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,12 @@ #[macro_use] extern crate napi_derive; -use napi::{CallContext, Env, Error, JsBuffer, JsBufferValue, JsObject, Ref, Result, Status, Task}; +use std::ffi::CString; + +use napi::{ + CallContext, Env, Error, JsBoolean, JsBuffer, JsBufferValue, JsObject, JsUnknown, Ref, Result, + Status, Task, +}; use snap::raw::{Decoder, Encoder}; #[cfg(all( @@ -48,11 +53,12 @@ impl Task for Enc { struct Dec { inner: Decoder, data: Ref, + as_buffer: bool, } impl Task for Dec { type Output = Vec; - type JsValue = JsBuffer; + type JsValue = JsUnknown; fn compute(&mut self) -> Result { let data_ref: &[u8] = &self.data; @@ -63,7 +69,15 @@ impl Task for Dec { } fn resolve(self, env: Env, output: Self::Output) -> Result { - env.create_buffer_with_data(output).map(|b| b.into_raw()) + if self.as_buffer { + env + .create_buffer_with_data(output) + .map(|b| b.into_raw().into_unknown()) + } else { + let len = output.len(); + let c_string = CString::new(output)?; + unsafe { env.create_string_from_c_char(c_string.as_ptr(), len) }.map(|v| v.into_unknown()) + } } } @@ -89,24 +103,38 @@ fn compress(ctx: CallContext) -> Result { ctx.env.spawn(encoder).map(|v| v.promise_object()) } -#[js_function(1)] -fn uncompress_sync(ctx: CallContext) -> Result { +#[js_function(2)] +fn uncompress_sync(ctx: CallContext) -> Result { let data = ctx.get::(0)?; + let as_buffer = ctx.get::(1)?.get_value()?; let mut dec = Decoder::new(); dec .decompress_vec(&data.into_value()?) .map_err(|e| Error::new(napi::Status::GenericFailure, format!("{}", e))) - .and_then(|d| ctx.env.create_buffer_with_data(d)) - .map(|b| b.into_raw()) + .and_then(|d| { + if as_buffer { + ctx + .env + .create_buffer_with_data(d) + .map(|b| b.into_raw().into_unknown()) + } else { + let len = d.len(); + let c_string = CString::new(d)?; + unsafe { ctx.env.create_string_from_c_char(c_string.as_ptr(), len) } + .map(|v| v.into_unknown()) + } + }) } -#[js_function(1)] +#[js_function(2)] fn uncompress(ctx: CallContext) -> Result { let data = ctx.get::(0)?; + let as_buffer = ctx.get::(1)?.get_value()?; let dec = Decoder::new(); let decoder = Dec { inner: dec, data: data.into_ref()?, + as_buffer, }; ctx.env.spawn(decoder).map(|v| v.promise_object()) }