Moving decompression to a vtable interface

This commit is contained in:
Caleb J. Gardner
2026-03-22 06:35:25 -05:00
parent 54aaf30ea5
commit 8e4661c4c6
6 changed files with 311 additions and 79 deletions
+139 -42
View File
@@ -1,13 +1,20 @@
const std = @import("std");
const builtin = @import("builtin");
const Decompressor = @import("../decomp.zig");
const c = @import("c.zig").c;
const DCtx = c.ZSTD_DCtx;
const Self = @This();
alloc: std.mem.Allocator,
ctx: std.AutoHashMap(std.Thread.Id, DCtx),
ctx: std.AutoHashMap(std.Thread.Id, *DCtx),
interface: Decompressor = .{ .vtable = &.{
.decompress = decompress,
.stateless = stateless,
} },
err: ?ZstdError = null,
pub fn init(alloc: std.mem.Allocator) !Self {
return .{
@@ -23,61 +30,151 @@ pub fn deinit(self: Self) void {
self.ctx.deinit(self.alloc);
}
pub fn decompress(self: *Self, in: []u8, out: []u8) ZstdError!usize {
pub fn decompress(decomp: *Decompressor, in: []u8, out: []u8) Decompressor.Error!usize {
var self: *Self = @fieldParentPtr("interface", decomp);
const ctx = try self.getOrCreate();
const res = c.ZSTD_decompressDCtx(ctx, out.ptr, out.len, in.ptr, in.len);
try checkError(res);
try self.checkError(res);
return res;
}
inline fn getOrCreate(self: *Self) ZstdError!*DCtx {
inline fn getOrCreate(self: *Self) Decompressor.Error!*DCtx {
const res = try self.ctx.getOrPut(std.Thread.getCurrentId());
if (res.found_existing) {
try checkError(c.ZSTD_DCtx_reset(res.value_ptr, c.ZSTD_reset_session_only));
return res.value_ptr;
try self.checkError(c.ZSTD_DCtx_reset(res.value_ptr.*, c.ZSTD_reset_session_only));
return res.value_ptr.*;
}
res.value_ptr.* = c.ZSTD_createDCtx() orelse return ZstdError.OutOfMemory;
return res.value_ptr;
res.value_ptr.* = c.ZSTD_createDCtx() orelse return Decompressor.Error.OutOfMemory;
return res.value_ptr.*;
}
fn stateless(alloc: std.mem.Allocator, in: []u8, out: []u8) anyerror!usize {
_ = alloc;
fn stateless(_: std.mem.Allocator, in: []u8, out: []u8) Decompressor.Error!usize {
const res = c.ZSTD_decompress(out.ptr, out.len, in.ptr, in.len);
try checkError(res);
return res;
if (c.ZSTD_isError(res) == 0) return res;
return switch (c.ZSTD_getErrorCode(res)) {
c.ZSTD_error_memory_allocation => Decompressor.Error.OutOfMemory,
c.ZSTD_error_workSpace_tooSmall,
c.ZSTD_error_dstSize_tooSmall,
c.ZSTD_error_dstBuffer_null,
c.ZSTD_error_noForwardProgress_destFull,
=> Decompressor.Error.OutputTooSmall,
else => Decompressor.Error.BadInput,
};
}
inline fn checkError(res: usize) !void {
inline fn checkError(self: *Self, res: usize) Decompressor.Error!void {
if (res == 0) return;
if (c.ZSTD_isError(res) == 0) return;
return switch (c.ZSTD_getErrorCode(res)) {
c.ZSTD_error_prefix_unknown => ZstdError.PrefixUnknown,
c.ZSTD_error_version_unsupported => ZstdError.VersionUnsupported,
c.ZSTD_error_frameParameter_unsupported => ZstdError.FrameParameterUnsupported,
c.ZSTD_error_frameParameter_windowTooLarge => ZstdError.FrameParameterWindowTooLarge,
c.ZSTD_error_corruption_detected => ZstdError.CorruptionDetected,
c.ZSTD_error_checksum_wrong => ZstdError.ChecksumWrong,
c.ZSTD_error_literals_headerWrong => ZstdError.LiteralsHeaderWrong,
c.ZSTD_error_dictionary_corrupted => ZstdError.DictionaryCorrupted,
c.ZSTD_error_dictionary_wrong => ZstdError.DictionaryWrong,
c.ZSTD_error_dictionaryCreation_failed => ZstdError.DictionaryCreationFailed,
c.ZSTD_error_parameter_unsupported => ZstdError.ParameterUnsupported,
c.ZSTD_error_parameter_combination_unsupported => ZstdError.ParameterCombinationUnsupported,
c.ZSTD_error_parameter_outOfBound => ZstdError.ParameterOutOfBound,
c.ZSTD_error_tableLog_tooLarge => ZstdError.TableLogTooLarge,
c.ZSTD_error_maxSymbolValue_tooLarge => ZstdError.MaxSymbolValueTooLarge,
c.ZSTD_error_maxSymbolValue_tooSmall => ZstdError.MaxSymbolValueTooSmall,
c.ZSTD_error_stabilityCondition_notRespected => ZstdError.StabilityConditionNotRespected,
c.ZSTD_error_stage_wrong => ZstdError.StageWrong,
c.ZSTD_error_init_missing => ZstdError.InitMissing,
c.ZSTD_error_memory_allocation => ZstdError.MemoryAllocation,
c.ZSTD_error_workSpace_tooSmall => ZstdError.WorkSpaceTooSmall,
c.ZSTD_error_dstSize_tooSmall => ZstdError.DstSizeTooSmall,
c.ZSTD_error_srcSize_wrong => ZstdError.SrcSizeWrong,
c.ZSTD_error_dstBuffer_null => ZstdError.DstBufferNull,
c.ZSTD_error_noForwardProgress_destFull => ZstdError.NoForwardProgressDestFull,
c.ZSTD_error_noForwardProgress_inputEmpty => ZstdError.NoForwardProgressInputEmpty,
else => ZstdError.Generic,
};
switch (c.ZSTD_getErrorCode(res)) {
c.ZSTD_error_prefix_unknown => {
self.err = ZstdError.PrefixUnknown;
return Decompressor.Error.BadInput;
},
c.ZSTD_error_version_unsupported => {
self.err = ZstdError.VersionUnsupported;
return Decompressor.Error.BadInput;
},
c.ZSTD_error_frameParameter_unsupported => {
self.err = ZstdError.FrameParameterUnsupported;
return Decompressor.Error.BadInput;
},
c.ZSTD_error_frameParameter_windowTooLarge => {
self.err = ZstdError.FrameParameterWindowTooLarge;
return Decompressor.Error.BadInput;
},
c.ZSTD_error_corruption_detected => {
self.err = ZstdError.CorruptionDetected;
return Decompressor.Error.BadInput;
},
c.ZSTD_error_checksum_wrong => {
self.err = ZstdError.ChecksumWrong;
return Decompressor.Error.BadInput;
},
c.ZSTD_error_literals_headerWrong => {
self.err = ZstdError.LiteralsHeaderWrong;
return Decompressor.Error.BadInput;
},
c.ZSTD_error_dictionary_corrupted => {
self.err = ZstdError.DictionaryCorrupted;
return Decompressor.Error.BadInput;
},
c.ZSTD_error_dictionary_wrong => {
self.err = ZstdError.DictionaryWrong;
return Decompressor.Error.BadInput;
},
c.ZSTD_error_dictionaryCreation_failed => {
self.err = ZstdError.DictionaryCreationFailed;
return Decompressor.Error.BadInput;
},
c.ZSTD_error_parameter_unsupported => {
self.err = ZstdError.ParameterUnsupported;
return Decompressor.Error.BadInput;
},
c.ZSTD_error_parameter_combination_unsupported => {
self.err = ZstdError.ParameterCombinationUnsupported;
return Decompressor.Error.BadInput;
},
c.ZSTD_error_parameter_outOfBound => {
self.err = ZstdError.ParameterOutOfBound;
return Decompressor.Error.BadInput;
},
c.ZSTD_error_tableLog_tooLarge => {
self.err = ZstdError.TableLogTooLarge;
return Decompressor.Error.BadInput;
},
c.ZSTD_error_maxSymbolValue_tooLarge => {
self.err = ZstdError.MaxSymbolValueTooLarge;
return Decompressor.Error.BadInput;
},
c.ZSTD_error_maxSymbolValue_tooSmall => {
self.err = ZstdError.MaxSymbolValueTooSmall;
return Decompressor.Error.BadInput;
},
c.ZSTD_error_stabilityCondition_notRespected => {
self.err = ZstdError.StabilityConditionNotRespected;
return Decompressor.Error.BadInput;
},
c.ZSTD_error_stage_wrong => {
self.err = ZstdError.StageWrong;
return Decompressor.Error.BadInput;
},
c.ZSTD_error_init_missing => {
self.err = ZstdError.InitMissing;
return Decompressor.Error.BadInput;
},
c.ZSTD_error_memory_allocation => {
self.err = ZstdError.MemoryAllocation;
return Decompressor.Error.OutOfMemory;
},
c.ZSTD_error_workSpace_tooSmall => {
self.err = ZstdError.WorkSpaceTooSmall;
return Decompressor.Error.OutputTooSmall;
},
c.ZSTD_error_dstSize_tooSmall => {
self.err = ZstdError.DstSizeTooSmall;
return Decompressor.Error.OutputTooSmall;
},
c.ZSTD_error_srcSize_wrong => {
self.err = ZstdError.SrcSizeWrong;
return Decompressor.Error.BadInput;
},
c.ZSTD_error_dstBuffer_null => {
self.err = ZstdError.DstBufferNull;
return Decompressor.Error.OutputTooSmall;
},
c.ZSTD_error_noForwardProgress_destFull => {
self.err = ZstdError.NoForwardProgressDestFull;
return Decompressor.Error.OutputTooSmall;
},
c.ZSTD_error_noForwardProgress_inputEmpty => {
self.err = ZstdError.NoForwardProgressInputEmpty;
return Decompressor.Error.BadInput;
},
else => {
self.err = ZstdError.Generic;
return Decompressor.Error.BadInput;
},
}
}
pub const ZstdError = error{
OutOfMemory,