Skip to content

Commit 81886a1

Browse files
add more code
1 parent b1b8fd0 commit 81886a1

File tree

7 files changed

+74
-61
lines changed

7 files changed

+74
-61
lines changed

index.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,25 @@ const { compress: _compress, decompress: _decompress } = require('bindings')('zs
33
// Error objects created via napi don't have JS stacks; wrap them so .stack is present
44
// https://github.com/nodejs/node/issues/25318#issuecomment-451068073
55

6-
exports.compress = async function compress(data) {
6+
exports.compress = async function compress(data, compressionLevel) {
7+
if (!Buffer.isBuffer(data)) {
8+
throw new TypeError(`parameter 'data' must be a Buffer.`);
9+
}
10+
11+
if (compressionLevel != null && typeof compressionLevel !== 'number') {
12+
throw new TypeError(`parameter 'compressionLevel' must be a number.`);
13+
}
14+
715
try {
8-
return await _compress(data);
16+
return await _compress(data, compressionLevel ?? 3);
917
} catch (e) {
1018
throw new Error(`zstd: ${e.message}`);
1119
}
1220
};
1321
exports.decompress = async function decompress(data) {
22+
if (!Buffer.isBuffer(data)) {
23+
throw new TypeError(`parameter 'data' must be a Buffer.`);
24+
}
1425
try {
1526
return await _decompress(data);
1627
} catch (e) {

src/addon.cpp

Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,39 +4,23 @@
44
#include <vector>
55

66
#include "compression_worker.h"
7-
#include "napi_utils.h"
87
#include "compressor.h"
98
#include "decompressor.h"
10-
9+
#include "napi_utils.h"
1110
#include "zstd.h"
1211

1312
using namespace Napi;
1413

1514
Napi::Promise Compress(const Napi::CallbackInfo& info) {
16-
auto number_of_args = info.Length();
17-
size_t compression_level;
18-
Napi::Uint8Array to_compress;
19-
20-
if (number_of_args == 0) {
21-
std::string error_message =
22-
"compress(uint8array) or compress(uint8array, compression level)";
23-
throw TypeError::New(info.Env(), error_message);
24-
} else if (number_of_args == 1) {
25-
to_compress = Uint8ArrayFromValue(info[0], "buffer");
26-
compression_level = 3;
27-
} else if (number_of_args == 2) {
28-
to_compress = Uint8ArrayFromValue(info[0], "buffer");
29-
if (!info[1].IsNumber()) {
30-
throw TypeError::New(info.Env(),
31-
std::string("if provided, compression_level must be a number."));
32-
}
33-
compression_level = (size_t)info[1].ToNumber().Int32Value();
34-
} else {
35-
std::string error_message =
36-
"compress(uint8array) or compress(uint8array, compression level)";
15+
// Argument handling happens in JS
16+
if (info.Length() != 2) {
17+
std::string error_message = "Expected two arguments.";
3718
throw TypeError::New(info.Env(), error_message);
3819
}
3920

21+
Uint8Array to_compress = Uint8ArrayFromValue(info[0], "buffer");
22+
size_t compression_level = (size_t)info[1].ToNumber().Int32Value();
23+
4024
Compressor compressor = Compressor::fromUint8Array(to_compress, compression_level);
4125
Worker<Compressor>* worker = new Worker<Compressor>(info.Env(), std::move(compressor));
4226

@@ -46,19 +30,13 @@ Napi::Promise Compress(const Napi::CallbackInfo& info) {
4630
}
4731

4832
Napi::Promise Decompress(const CallbackInfo& info) {
49-
auto number_of_args = info.Length();
50-
Napi::Uint8Array compressed_data;
51-
52-
if (number_of_args == 0) {
53-
std::string error_message = "decompress(uint8array)";
54-
throw TypeError::New(info.Env(), error_message);
55-
} else if (number_of_args == 1) {
56-
compressed_data = Uint8ArrayFromValue(info[0], "buffer");
57-
} else {
58-
std::string error_message = "decompress(uint8array)";
33+
// Argument handling happens in JS
34+
if (info.Length() != 1) {
35+
std::string error_message = "Expected one argument.";
5936
throw TypeError::New(info.Env(), error_message);
6037
}
6138

39+
Napi::Uint8Array compressed_data = Uint8ArrayFromValue(info[0], "buffer");
6240
Decompressor decompressor = Decompressor::fromUint8Array(compressed_data);
6341
Worker<Decompressor>* worker = new Worker<Decompressor>(info.Env(), decompressor);
6442

src/compression_worker.h

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
using namespace Napi;
66

77
/**
8-
* @brief A class that represents the result of a compression operation. Once the MACOS_DEPLOYMENT_TARGET can be raised to 10.13 and use
9-
* a c++17, we can remove this class and use a std::optional<std::variant<std::vector<uint8_t>, std::string>>> instead.
8+
* @brief A class that represents the result of a compression operation. Once the
9+
* MACOS_DEPLOYMENT_TARGET can be raised to 10.13 and use a c++17, we can remove this class and use
10+
* a std::optional<std::variant<std::vector<uint8_t>, std::string>>> instead.
1011
*/
1112
struct CompressionResult {
1213
CompressionResult(std::string error,
@@ -42,8 +43,9 @@ struct CompressionResult {
4243
};
4344

4445
/**
45-
* @brief An asynchronous Napi::Worker that can be with any functor that produces CompressionResults.
46-
*
46+
* @brief An asynchronous Napi::Worker that can be with any functor that produces
47+
* CompressionResults.
48+
*
4749
* @tparam TWorker - The functor to call asynchronously.
4850
*/
4951
template <typename TWorker>
@@ -66,22 +68,22 @@ class Worker : public Napi::AsyncWorker {
6668

6769
void OnOK() {
6870
if (!result.initialized) {
69-
m_deferred.Reject(
70-
Napi::Error::New(
71-
Env(), "zstd runtime error - async worker finished without a compression or decompression result.")
72-
.Value());
71+
m_deferred.Reject(Napi::Error::New(Env(),
72+
"zstd runtime error - async worker finished without "
73+
"a compression or decompression result.")
74+
.Value());
7375
} else if (result.hasError) {
7476
m_deferred.Reject(Napi::Error::New(Env(), result.error).Value());
7577
} else if (result.hasResult) {
76-
Uint8Array output = Uint8Array::New(m_deferred.Env(), result.result.size());
77-
std::copy(result.result.begin(), result.result.end(), output.Data());
78+
Buffer<uint8_t> output =
79+
Buffer<uint8_t>::Copy(m_deferred.Env(), result.result.data(), result.result.size());
7880

7981
m_deferred.Resolve(output);
8082
} else {
81-
m_deferred.Reject(
82-
Napi::Error::New(
83-
Env(), "zstd runtime error - async worker finished without a compression or decompression result.")
84-
.Value());
83+
m_deferred.Reject(Napi::Error::New(Env(),
84+
"zstd runtime error - async worker finished without "
85+
"a compression or decompression result.")
86+
.Value());
8587
}
8688
}
8789

src/compressor.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11

2-
#include <vector>
32
#include <napi.h>
43

4+
#include <vector>
5+
56
#include "zstd.h"
67

78
using namespace Napi;

src/decompressor.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
#include <vector>
44

5-
6-
75
#include "zstd.h"
86

97
using namespace Napi;

src/napi_utils.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
using namespace Napi;
44

55
/**
6-
* @brief Given a T* source and a T* destination, copies count
6+
* @brief Given a T* source and a T* destination, copies count
77
* elements from source into destination.
88
*/
99
template <typename T>
@@ -14,12 +14,12 @@ void copy_buffer_data(T* source, T* dest, size_t count) {
1414
}
1515

1616
/**
17-
* @brief Given an Napi;:Value, this function returns the value as a Uint8Array, if the
17+
* @brief Given an Napi;:Value, this function returns the value as a Uint8Array, if the
1818
* Value is a Uint8Array. Otherwise, this function throws.
19-
*
19+
*
2020
* @param v - An Napi::Value
2121
* @param argument_name - the name of the value, to use when constructing an error message.
22-
* @return Napi::Uint8Array
22+
* @return Napi::Uint8Array
2323
*/
2424
Uint8Array Uint8ArrayFromValue(Value v, std::string argument_name) {
2525
if (!v.IsTypedArray() || v.As<TypedArray>().TypedArrayType() != napi_uint8_array) {

test/index.test.js

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,37 @@
11
const { describe, test } = require('mocha');
2-
const { compress, decompress } = require('bindings')('zstd');
2+
const { compress, decompress } = require('../index');
33

44
const zstdLegacy = require('@mongodb-js/zstd');
55
const { expect } = require('chai');
66

7+
describe('compat tests', function () {
8+
describe('old compress, new decompress', testSuite(zstdLegacy.decompress, compress));
9+
describe('new compress, decompress', testSuite(decompress, zstdLegacy.compress));
10+
describe('new compress, new decompress', testSuite(decompress, compress));
11+
});
12+
13+
describe('decompress', function () {
14+
test('decompress() throws a TypeError', async function () {
15+
expect(await decompress().catch(e => e))
16+
.to.be.instanceOf(TypeError)
17+
.to.match(/must be a buffer/i);
18+
});
19+
20+
test('decompress() returns a Nodejs buffer', async function () {
21+
const compressed = await zstdLegacy.compress(Buffer.from([1, 2, 3]));
22+
expect(await decompress(compressed)).to.be.instanceOf(Buffer);
23+
});
24+
});
25+
726
describe('compress', function () {
8-
describe('compat tests', function () {
9-
describe('old compress, new decompress', testSuite(zstdLegacy.decompress, compress));
10-
describe('new compress, decompress', testSuite(decompress, zstdLegacy.compress));
11-
describe('new compress, new decompress', testSuite(decompress, compress));
27+
test('compress() throws a TypeError', async function () {
28+
expect(await compress().catch(e => e))
29+
.to.be.instanceOf(TypeError)
30+
.to.match(/must be a buffer/i);
31+
});
32+
33+
test('compress() returns a Nodejs buffer', async function () {
34+
expect(await compress(Buffer.from([1, 2, 3]))).to.be.instanceOf(Buffer);
1235
});
1336
});
1437

0 commit comments

Comments
 (0)