This commit is contained in:
Ben Burkert 2025-11-23 22:57:18 +00:00 committed by GitHub
commit 4bc2c55a1a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 84 additions and 8 deletions

View file

@ -1,3 +1,8 @@
pub const asn1 = @import("codecs/asn1.zig");
pub const base64 = @import("codecs/base64_hex_ct.zig").base64;
pub const hex = @import("codecs/base64_hex_ct.zig").hex;
test {
_ = @import("codecs/asn1.zig");
_ = @import("codecs/base64_hex_ct.zig");
}

View file

@ -90,7 +90,7 @@ pub const Tag = struct {
};
}
pub fn encode(self: Tag, writer: *std.Io.Writer) @TypeOf(writer).Error!void {
pub fn encode(self: Tag, writer: *std.Io.Writer) std.Io.Writer.Error!void {
var tag1 = FirstTag{
.number = undefined,
.constructed = self.constructed,
@ -98,7 +98,7 @@ pub const Tag = struct {
};
var buffer: [3]u8 = undefined;
var writer2: std.Io.Writer = .init(&buffer);
var writer2: std.Io.Writer = .fixed(&buffer);
switch (@intFromEnum(self.number)) {
0...std.math.maxInt(u5) => |n| {
@ -183,7 +183,7 @@ pub const Element = struct {
}
};
pub const DecodeError = error{ InvalidLength, EndOfStream };
pub const DecodeError = error{ InvalidLength, EndOfStream, ReadFailed };
/// Safely decode a DER/BER/CER element at `index`:
/// - Ensures length uses shortest form

View file

@ -47,7 +47,7 @@ test fromDot {
}
}
pub fn toDot(self: Oid, writer: anytype) @TypeOf(writer).Error!void {
pub fn toDot(self: Oid, writer: anytype) std.Io.Writer.Error!void {
const encoded = self.encoded;
const first = @divTrunc(encoded[0], 40);
const second = encoded[0] - first * 40;
@ -81,7 +81,7 @@ test toDot {
for (test_cases) |t| {
var stream: std.Io.Writer = .fixed(&buf);
try toDot(Oid{ .encoded = t.encoded }, &stream);
try std.testing.expectEqualStrings(t.dot_notation, stream.written());
try std.testing.expectEqualStrings(t.dot_notation, stream.buffered());
}
}

View file

@ -7,18 +7,28 @@
const std = @import("std");
const Allocator = std.mem.Allocator;
const Io = std.Io;
const assert = std.debug.assert;
const testing = std.testing;
data: []u8,
capacity: usize,
allocator: Allocator,
writer: Io.Writer,
const ArrayListReverse = @This();
const Error = Allocator.Error;
pub fn init(allocator: Allocator) ArrayListReverse {
return .{ .data = &.{}, .capacity = 0, .allocator = allocator };
return .{
.data = &.{},
.capacity = 0,
.allocator = allocator,
.writer = .{
.buffer = &.{},
.vtable = &vtable,
},
};
}
pub fn deinit(self: *ArrayListReverse) void {
@ -67,6 +77,67 @@ pub fn clearAndFree(self: *ArrayListReverse) void {
self.capacity = 0;
}
const vtable: Io.Writer.VTable = .{
.drain = &drain,
};
fn drain(w: *Io.Writer, data: []const []const u8, splat: usize) Io.Writer.Error!usize {
const self: *ArrayListReverse = @fieldParentPtr("writer", w);
assert(w.buffered().len == 0);
if (data.len == 1 and splat == 1) {
@branchHint(.likely);
self.prependSlice(data[0]) catch return error.WriteFailed;
return data[0].len;
}
const count = Io.Writer.countSplat(data, splat);
self.ensureCapacity(self.data.len + count) catch return error.WriteFailed;
const end = self.data.ptr;
const begin = end - count;
var slice = begin[0..count];
for (data[0 .. data.len - 1]) |bytes| {
@memcpy(slice[0..bytes.len], bytes);
slice = slice[bytes.len..];
}
for (0..splat) |_| {
const bytes = data[data.len - 1];
@memcpy(slice[0..bytes.len], bytes);
slice = slice[bytes.len..];
}
self.data.ptr = begin;
self.data.len += count;
return count;
}
test drain {
var b: ArrayListReverse = .init(std.testing.allocator);
defer b.deinit();
var n = try b.writer.write(&.{ 1, 2, 3 });
try std.testing.expectEqual(3, n);
try std.testing.expectEqualSlices(u8, &.{ 1, 2, 3 }, b.data);
n = try b.writer.writeSplat(&.{
&.{ 4, 5, 6 },
&.{ 7, 8, 9 },
}, 2);
try std.testing.expectEqual(9, n);
try std.testing.expectEqualSlices(
u8,
&.{
4, 5, 6,
7, 8, 9,
7, 8, 9,
1, 2, 3,
},
b.data,
);
}
/// The caller owns the returned memory.
/// Capacity is cleared, making deinit() safe but unnecessary to call.
pub fn toOwnedSlice(self: *ArrayListReverse) Error![]u8 {

View file

@ -117,8 +117,8 @@ pub fn tagBytes(self: *Encoder, tag_: Tag, bytes: []const u8) !void {
}
/// Warning: This writer writes backwards. `fn print` will NOT work as expected.
pub fn writer(self: *Encoder) ArrayListReverse.Writer {
return self.buffer.writer();
pub fn writer(self: *Encoder) *std.Io.Writer {
return &self.buffer.writer;
}
fn int(self: *Encoder, comptime T: type, value: T) !void {