diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bun.js/base.zig | 10 | ||||
-rw-r--r-- | src/compress.zig | 103 | ||||
-rw-r--r-- | src/deps/brotli.zig | 45 | ||||
-rw-r--r-- | src/stream_tester.zig | 59 |
4 files changed, 139 insertions, 78 deletions
diff --git a/src/bun.js/base.zig b/src/bun.js/base.zig index 535c08395..b9dba8b37 100644 --- a/src/bun.js/base.zig +++ b/src/bun.js/base.zig @@ -1784,6 +1784,16 @@ pub const ArrayBuffer = extern struct { }; } + pub fn createFromLength(globalThis: *JSC.JSGlobalObject, len: usize, comptime kind: BinaryType) JSValue { + JSC.markBinding(@src()); + return switch (comptime kind) { + .Uint8Array => Bun__createUint8ArrayForCopy(globalThis, null, len, false), + .Buffer => Bun__createUint8ArrayForCopy(globalThis, null, len, true), + .ArrayBuffer => Bun__createArrayBufferForCopy(globalThis, null, len), + else => @compileError("Not implemented yet"), + }; + } + pub fn createEmpty(globalThis: *JSC.JSGlobalObject, comptime kind: JSC.JSValue.JSType) JSValue { JSC.markBinding(@src()); diff --git a/src/compress.zig b/src/compress.zig index dd882849e..c2470dfa4 100644 --- a/src/compress.zig +++ b/src/compress.zig @@ -3,9 +3,12 @@ const std = @import("std"); const zlib = @import("./zlib.zig"); const brotli = bun.brotli; +const String = bun.String; + pub const Error = struct { - code: bun.String = bun.String.empty, - message: bun.String = bun.String.empty, + // To workaround a zig compiler bug, we avoid using String here. + code: []const u8, + message: []const u8, }; pub const Ownership = enum { transfer, must_copy }; @@ -31,84 +34,42 @@ pub const Controller = struct { this.pull_fn(this.ctx); } - pub fn init(comptime Context: type, context: Context) Controller { + pub fn init(comptime ContextType: type, context: ContextType) Controller { + const Context = std.meta.Child(ContextType); return Controller{ .ctx = @ptrCast(*anyopaque, context), .closed = @ptrCast(*bool, &context.closed), - .receive_data_fn = @ptrCast(*const fn (*anyopaque, []const u8, Ownership, Completion) void, Context.onData), - .receive_error_fn = @ptrCast(*const fn (*anyopaque, Error) void, Context.onError), - .pull_fn = @ptrCast(*const fn (*anyopaque) void, Context.onPull), + .receive_data_fn = @ptrCast(*const fn (*anyopaque, []const u8, Ownership, Completion) void, &Context.onData), + .receive_error_fn = @ptrCast(*const fn (*anyopaque, Error) void, &Context.onError), + .pull_fn = @ptrCast(*const fn (*anyopaque) void, &Context.onPull), }; } }; -pub const CLIFileStreamCompressor = struct { - input: std.fs.File, - output: std.fs.File, - closed: bool = false, - - ready_for_more: bool = false, - has_more_output: bool = true, - - pub fn controller(this: *CLIFileStreamCompressor) Controller { - return Controller.init(*CLIFileStreamCompressor, this); - } - - pub fn onData(this: *CLIFileStreamCompressor, bytes: []const u8, _: Ownership, completion: Completion) void { - std.debug.assert(!this.closed); - this.output.writeAll(bytes) catch @panic("failed to write to file"); - if (completion == Completion.last) { - this.ready_for_more = false; - } - } - - pub fn onError(this: *CLIFileStreamCompressor, err: Error) void { - std.debug.assert(!this.closed); - std.debug.panic("Error: {}\n{}", .{ err.code, err.message }); - } - - pub fn onPull(this: *CLIFileStreamCompressor) void { - this.ready_for_more = true; - } - - pub fn init(path: []const u8) !CLIFileStreamCompressor { - var file = try std.fs.cwd().openFile(path, .{ .mode = .read_write }); - return CLIFileStreamCompressor{ .input = file, .output = std.io.getStdOut() }; - } - - pub fn run(this: *CLIFileStreamCompressor, stream: *Compressor) !void { - this.ready_for_more = true; - const ctrl = this.controller(); - - while (this.has_more_output) { - var buffer: [64 * 1024]u8 = undefined; - var to_read: []u8 = buffer[0..try this.input.readAll(&buffer)]; - this.has_more_output = to_read.len != 0; - if (this.has_more_output) { - stream.write(to_read, ctrl); - } - } - - stream.end(ctrl); - } -}; - pub const Compressor = union(enum) { BrotliEncoder: Brotli.Encoder, BrotliDecoder: Brotli.Decoder, pub fn write(this: *Compressor, data: []const u8, controller: Controller) void { - return switch (this) { - .BrotliEncoder => this.BrotliEncoder.write(data, controller), - .BrotliDecoder => this.BrotliDecoder.write(data, controller), - }; + switch (this.*) { + .BrotliEncoder => { + this.BrotliEncoder.write(data, controller); + }, + .BrotliDecoder => { + this.BrotliDecoder.write(data, controller); + }, + } } - pub fn end(this: *Compressor) void { - return switch (this) { - .BrotliEncoder => this.BrotliEncoder.end(), - .BrotliDecoder => this.BrotliDecoder.end(), - }; + pub fn end(this: *Compressor, controller: Controller) void { + switch (this.*) { + .BrotliEncoder => { + this.BrotliEncoder.end(controller); + }, + .BrotliDecoder => { + this.BrotliDecoder.end(controller); + }, + } } pub fn initWithType(comptime Type: type, value: Type) !*Compressor { @@ -157,7 +118,7 @@ pub const Brotli = struct { controller.enqueue( taken, .must_copy, - false, + .not_last, ); if (!state.hasMoreOutput()) @@ -195,8 +156,8 @@ pub const Brotli = struct { .@"error" => { const code = state.getErrorCode(); controller.fail(Error{ - .code = bun.String.static(code.code()), - .message = bun.String.static(code.message()), + .code = code.code(), + .message = code.message(), }); return; }, @@ -233,9 +194,7 @@ pub const Brotli = struct { pub fn end(this: *Decoder, controller: Controller) void { var state = this.state orelse return; this.state = null; - consume(state, controller); - std.debug.assert(state.finish(null, null, null)); - consume(state, controller); + consume(state, controller, true); state.deinit(); } }; diff --git a/src/deps/brotli.zig b/src/deps/brotli.zig index f6bcfe310..141e221f8 100644 --- a/src/deps/brotli.zig +++ b/src/deps/brotli.zig @@ -42,16 +42,51 @@ pub const BrotliDecoderState = opaque { return BrotliDecoderSetParameter(self, param, value) == BROTLI_TRUE; } - pub fn write(self: *BrotliDecoderState, input: *[]const u8, output: *[]u8, total_size: ?*usize) BrotliDecoderResult { - return BrotliDecoderDecompressStream(self, &input.len, &input.ptr, &output.len, &output.ptr, total_size); + pub fn write(self: *BrotliDecoderState, input: ?*[]const u8, output: ?*[]u8, total_size: ?*usize) BrotliDecoderResult { + var input_len: usize = 0; + var input_ptr: ?[*]const u8 = null; + + var output_len: usize = 0; + var output_ptr: ?[*]u8 = null; + + if (input) |in| { + input_len = in.len; + input_ptr = in.ptr; + } + + if (output) |out| { + output_len = out.len; + output_ptr = out.ptr; + } + + defer { + if (input) |in| { + in.len = input_len; + if (input_ptr != null) + in.ptr = input_ptr.?; + } + + if (output) |out| { + out.len = output_len; + if (output_ptr != null) + out.ptr = output_ptr.?; + } + } + return BrotliDecoderDecompressStream(self, &input_len, &input_ptr, &output_len, &output_ptr, total_size); } pub fn getErrorCode(self: *const BrotliDecoderState) BrotliDecoderErrorCode { return BrotliDecoderGetErrorCode(self); } - pub fn hasMoreOutput(self: *BrotliEncoderState) bool { - return BrotliEncoderHasMoreOutput(self) == BROTLI_TRUE; + pub fn hasMoreOutput(self: *const BrotliDecoderState) bool { + return BrotliDecoderHasMoreOutput(self) == BROTLI_TRUE; + } + + pub fn take(self: *BrotliDecoderState, requested: usize) []const u8 { + var size: usize = requested; + var ptr = BrotliDecoderTakeOutput(self, &size) orelse return ""; + return ptr[0..size]; } }; @@ -291,7 +326,7 @@ pub extern fn BrotliDecoderAttachDictionary(state: ?*BrotliDecoderState, @"type" pub extern fn BrotliDecoderCreateInstance(alloc_func: brotli_alloc_func, free_func: brotli_free_func, @"opaque": ?*anyopaque) *BrotliDecoderState; pub extern fn BrotliDecoderDestroyInstance(state: ?*BrotliDecoderState) void; pub extern fn BrotliDecoderDecompress(encoded_size: usize, encoded_buffer: [*]const u8, decoded_size: *usize, decoded_buffer: [*]u8) BrotliDecoderResult; -pub extern fn BrotliDecoderDecompressStream(state: *BrotliDecoderState, available_in: *usize, next_in: *[*]const u8, available_out: *usize, next_out: *[*]u8, total_out: ?*usize) BrotliDecoderResult; +pub extern fn BrotliDecoderDecompressStream(state: *BrotliDecoderState, available_in: *usize, next_in: *?[*]const u8, available_out: *usize, next_out: *?[*]u8, total_out: ?*usize) BrotliDecoderResult; pub extern fn BrotliDecoderHasMoreOutput(state: *const BrotliDecoderState) c_int; pub extern fn BrotliDecoderTakeOutput(state: *BrotliDecoderState, size: *usize) ?[*]const u8; pub extern fn BrotliDecoderIsUsed(state: ?*const BrotliDecoderState) c_int; diff --git a/src/stream_tester.zig b/src/stream_tester.zig index a6912bd27..4ad4753cc 100644 --- a/src/stream_tester.zig +++ b/src/stream_tester.zig @@ -2,9 +2,66 @@ const compress = @import("./compress.zig"); pub const bun = @import("./bun.zig"); const std = @import("std"); +const Controller = compress.Controller; +const Completion = compress.Completion; +const Ownership = compress.Ownership; +const Error = compress.Error; + +pub const CLIFileStreamCompressor = struct { + input: std.fs.File, + output: std.fs.File, + closed: bool = false, + + ready_for_more: bool = false, + has_more_output: bool = true, + + pub fn controller(this: *CLIFileStreamCompressor) Controller { + return Controller.init(*CLIFileStreamCompressor, this); + } + + pub fn onData(this: *CLIFileStreamCompressor, bytes: []const u8, _: Ownership, completion: Completion) void { + std.debug.assert(!this.closed); + this.output.writeAll(bytes) catch @panic("failed to write to file"); + if (completion == Completion.last) { + this.ready_for_more = false; + } + } + + pub fn onError(this: *CLIFileStreamCompressor, err: Error) void { + _ = err; + std.debug.assert(!this.closed); + // std.debug.panic("Error: {}\n{}", .{ err.code, err.message }); + } + + pub fn onPull(this: *CLIFileStreamCompressor) void { + this.ready_for_more = true; + } + + pub fn init(path: []const u8) !CLIFileStreamCompressor { + var file = try std.fs.cwd().openFile(path, .{ .mode = .read_write }); + return CLIFileStreamCompressor{ .input = file, .output = std.io.getStdOut() }; + } + + pub fn run(this: *CLIFileStreamCompressor, stream: *compress.Compressor) !void { + this.ready_for_more = true; + const ctrl = this.controller(); + + while (this.has_more_output) { + var buffer: [64 * 1024]u8 = undefined; + var to_read: []const u8 = buffer[0..try this.input.readAll(&buffer)]; + this.has_more_output = to_read.len != 0; + if (this.has_more_output) { + stream.write(to_read, ctrl); + } + } + + stream.end(ctrl); + } +}; + pub fn main() anyerror!void { const path: []const u8 = std.mem.span(std.os.argv[std.os.argv.len - 1]); - var file_stream = try compress.CLIFileStreamCompressor.init(path); + var file_stream = try CLIFileStreamCompressor.init(path); var stream: *compress.Compressor = if (bun.strings.endsWith(path, ".br")) try compress.Compressor.init(compress.Brotli.Decoder.initWithoutOptions()) else |