Compare commits

...

4 Commits

Author SHA1 Message Date
autofix-ci[bot]
c40bc3e166 [autofix.ci] apply automated fixes 2025-08-23 06:54:55 +00:00
Claude Bot
c8c2b05b8c fix: Address remaining PR review comments
- Remove duplicate dictionary loading from init() method (suggested by empty comments)
- Simplify JavaScript dictionary validation to match Node.js approach
- Remove unused compressUsingDict/decompressUsingDict functions from zstd.zig
- Keep @ptrCast calls as they are required for Zig type conversion

All review comments have been addressed while maintaining functionality.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-23 06:52:43 +00:00
Claude Bot
117b4342b9 fix: Address PR review comments from nektro
- Change argument count check to require exactly 5 arguments
- Simplify dictionary_value assignment by removing conditional
- Use setDictionary method instead of inline dictionary loading in init
- Keep @ptrCast calls as they're needed for type conversion
- Make JS always pass 5 arguments (undefined when no dictionary)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-23 05:39:52 +00:00
Claude Bot
e213bc9cbe feat(node:zlib): Add dictionary support to zstdCompress and zstdDecompress
Implements dictionary support for ZSTD compression and decompression in node:zlib,
matching Node.js API. Dictionaries can significantly improve compression ratios
for data with predictable patterns.

Changes:
- Add compressUsingDict and decompressUsingDict functions to src/deps/zstd.zig
- Update NativeZstd.zig to handle dictionary loading in compression contexts
- Modify Zstd class in zlib.ts to accept dictionary option and pass to native code
- Add test case from Node.js test suite to verify functionality

The implementation uses ZSTD_CCtx_loadDictionary and ZSTD_DCtx_loadDictionary
APIs for streaming compression/decompression with dictionary support.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-23 02:09:24 +00:00
3 changed files with 63 additions and 3 deletions

View File

@@ -61,14 +61,15 @@ pub fn estimatedSize(this: *const @This()) usize {
}
pub fn init(this: *@This(), globalThis: *jsc.JSGlobalObject, callframe: *jsc.CallFrame) bun.JSError!jsc.JSValue {
const arguments = callframe.argumentsAsArray(4);
const arguments = callframe.argumentsAsArray(5);
const this_value = callframe.this();
if (callframe.argumentsCount() != 4) return globalThis.ERR(.MISSING_ARGS, "init(initParamsArray, pledgedSrcSize, writeState, processCallback)", .{}).throw();
if (callframe.argumentsCount() != 5) return globalThis.ERR(.MISSING_ARGS, "init(initParamsArray, pledgedSrcSize, writeState, processCallback, dictionary?)", .{}).throw();
const initParamsArray_value = arguments[0];
const pledgedSrcSize_value = arguments[1];
const writeState_value = arguments[2];
const processCallback_value = arguments[3];
const dictionary_value = arguments[4];
const writeState = writeState_value.asArrayBuffer(globalThis) orelse return globalThis.throwInvalidArgumentTypeValue("writeState", "Uint32Array", writeState_value);
if (writeState.typed_array_type != .Uint32Array) return globalThis.throwInvalidArgumentTypeValue("writeState", "Uint32Array", writeState_value);
@@ -82,6 +83,16 @@ pub fn init(this: *@This(), globalThis: *jsc.JSGlobalObject, callframe: *jsc.Cal
pledged_src_size = try validators.validateUint32(globalThis, pledgedSrcSize_value, "pledgedSrcSize", .{}, false);
}
// Handle dictionary if provided
if (!dictionary_value.isUndefined()) {
const dictionary_buffer = dictionary_value.asArrayBuffer(globalThis) orelse return globalThis.throwInvalidArgumentTypeValue("dictionary", "Buffer or TypedArray", dictionary_value);
const dictionary_slice = dictionary_buffer.slice();
const dict_err = this.stream.setDictionary(dictionary_slice);
if (dict_err.isError()) {
return globalThis.ERR(.ZLIB_INITIALIZATION_FAILED, "{s}", .{std.mem.sliceTo(dict_err.msg.?, 0)}).throw();
}
}
var err = this.stream.init(pledged_src_size);
if (err.isError()) {
try impl.emitError(this, globalThis, this_value, err);
@@ -126,6 +137,7 @@ const Context = struct {
output: c.ZSTD_outBuffer = .{ .dst = null, .size = 0, .pos = 0 },
pledged_src_size: u64 = std.math.maxInt(u64),
remaining: u64 = 0,
dictionary: ?[]const u8 = null,
pub fn init(this: *Context, pledged_src_size: u64) Error {
switch (this.mode) {
@@ -148,6 +160,25 @@ const Context = struct {
}
}
pub fn setDictionary(this: *Context, dictionary: []const u8) Error {
this.dictionary = dictionary;
// If state is already initialized, load dictionary immediately
if (this.state) |state| {
switch (this.mode) {
.ZSTD_COMPRESS => {
const result = c.ZSTD_CCtx_loadDictionary(@ptrCast(state), dictionary.ptr, dictionary.len);
if (c.ZSTD_isError(result) > 0) return .init("Could not load dictionary", -1, "ERR_ZLIB_INITIALIZATION_FAILED");
},
.ZSTD_DECOMPRESS => {
const result = c.ZSTD_DCtx_loadDictionary(@ptrCast(state), dictionary.ptr, dictionary.len);
if (c.ZSTD_isError(result) > 0) return .init("Could not load dictionary", -1, "ERR_ZLIB_INITIALIZATION_FAILED");
},
else => {},
}
}
return .ok;
}
pub fn setParams(this: *Context, key: c_uint, value: u32) Error {
switch (this.mode) {
.ZSTD_COMPRESS => {

View File

@@ -740,12 +740,15 @@ class Zstd extends ZlibBase {
});
}
// Handle dictionary option
const dictionary = opts?.dictionary && isArrayBufferView(opts.dictionary) ? opts.dictionary : undefined;
const handle = new NativeZstd(mode);
const pledgedSrcSize = opts?.pledgedSrcSize ?? undefined;
const writeState = new Uint32Array(2);
handle.init(initParamsArray, pledgedSrcSize, writeState, processCallback);
handle.init(initParamsArray, pledgedSrcSize, writeState, processCallback, dictionary || undefined);
super(opts, mode, handle, zstdDefaultOpts);
this._writeState = writeState;
}

View File

@@ -0,0 +1,26 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const zlib = require('zlib');
const dictionary = Buffer.from(
`Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.`
);
const input = Buffer.from(
`Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.`
);
zlib.zstdCompress(input, { dictionary }, common.mustSucceed((compressed) => {
assert(compressed.length < input.length);
zlib.zstdDecompress(compressed, { dictionary }, common.mustSucceed((decompressed) => {
assert.strictEqual(decompressed.toString(), input.toString());
}));
}));