~alva/zig-bare

b7a656db5b23a96a18e75f2a6cadd039b9e2ab49 — owl 6 months ago 843a99d
move varint to separate library
5 files changed, 168 insertions(+), 132 deletions(-)

M build.zig
A build.zig.zon
M src/bare.zig
M src/test.zig
A src/varint.zig
M build.zig => build.zig +9 -0
@@ 11,8 11,16 @@ pub fn build(b: *Builder) !void {
    const optimize = b.standardOptimizeOption(.{});
    const target = b.standardTargetOptions(.{});

    const varint_dep = b.dependency("varint", .{});

    const bare_mod = b.addModule("bare", .{
        .source_file = .{ .path = "src" ++ sep ++ "bare.zig" },
        .dependencies = &.{
            .{
                .name = "varint",
                .module = varint_dep.module("varint"),
            },
        },
    });

    const bench = b.addExecutable(.{


@@ 22,6 30,7 @@ pub fn build(b: *Builder) !void {
        .target = target,
    });
    bench.addModule("bare", bare_mod);
    bench.addModule("varint", varint_dep.module("varint"));

    const tests = b.addTest(.{
        .root_source_file = .{ .path = "src" ++ sep ++ "test.zig" },

A build.zig.zon => build.zig.zon +11 -0
@@ 0,0 1,11 @@
.{
    .name = "bare",
    .version = "0.10.0",
    .paths = .{""},
    .dependencies = .{
        .varint = .{
            .url = "https://git.sr.ht/~alva/zig-varint/archive/f72dd5fd.tar.gz",
            .hash = "1220cd18cd3e4f76e09e11e20461ad80dfe6e211996dc4a0afa41b1d9b270732b0d0",
        },
    },
}

M src/bare.zig => src/bare.zig +5 -128
@@ 1,4 1,5 @@
const std = @import("std");
const varint = @import("varint.zig");
const io = std.io;
const math = std.math;
const mem = std.mem;


@@ 58,37 59,11 @@ pub fn Decoder(comptime ReaderType: type) type {
        }

        fn decodeVarInt(self: *Self) !i64 {
            const ux = try self.decodeVarUint();
            const x: i64 = @intCast(ux >> 1);
            const y: i64 = @intCast(ux & 1);
            return x ^ -y;
            return varint.decodeVarInt(self.reader);
        }

        fn decodeVarUint(self: *Self) !u64 {
            var x: u64 = 0;
            var s: u6 = 0;

            for (0..math.maxInt(u4)) |i| {
                const b = try self.reader.readByte();
                const orm: u64 = @intCast(b & 0x7f);
                x |= orm << s;

                if (b < 0x80) {
                    if (9 < i or i == 9 and 1 < b)
                        return DecodeError.Overflow;

                    return x;
                }

                const ov = @addWithOverflow(s, 7);

                if (0 != ov[1])
                    return DecodeError.Overflow;

                s = ov[0];
            }

            return 0;
            return varint.decodeVarUint(self.reader);
        }

        fn decodeInt(self: *Self, comptime T: type) !T {


@@ 255,20 230,11 @@ pub fn Encoder(comptime WriterType: type) type {
        }

        fn encodeVarUint(self: *Self, value: u64) !void {
            var x = value;

            while (0x80 <= x) {
                const b: u8 = @truncate(x);
                try self.writer.writeByte(b | 0x80);
                x >>= 7;
            }

            try self.writer.writeByte(@truncate(x));
            return varint.encodeVarUint(self.writer, value);
        }

        fn encodeVarInt(self: *Self, value: i64) !void {
            const ux: u64 = @bitCast((2 * value) ^ (value >> 63));
            return self.encodeVarUint(ux);
            return varint.encodeVarInt(self.writer, value);
        }

        fn encodeInt(self: *Self, comptime T: type, value: T) !void {


@@ 409,95 375,6 @@ fn isValidHashMapKeyType(comptime T: type) bool {
    };
}

test "read variable uint" {
    var fbs = io.fixedBufferStream("\x2a");
    var reader = fbs.reader();
    var d = decoder(std.testing.allocator, reader);
    const x = try d.decodeVarUint();
    try std.testing.expectEqual(x, 42);
    fbs = io.fixedBufferStream("\x80\x02");
    const y = d.decodeVarUint();
    try std.testing.expectEqual(y, 0x100);
}

test "read variable uint overflow 1" {
    const buf = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\x02";
    var fbs = io.fixedBufferStream(buf);
    var reader = fbs.reader();
    var d = decoder(std.testing.allocator, reader);
    const x = d.decodeVarUint();
    try std.testing.expectError(DecodeError.Overflow, x);
}

test "read variable uint overflow 2" {
    const buf = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00";
    var fbs = io.fixedBufferStream(buf);
    var reader = fbs.reader();
    var d = decoder(std.testing.allocator, reader);
    const x = d.decodeVarUint();
    try std.testing.expectError(DecodeError.Overflow, x);
}

test "write variable uint" {
    var buf: [4]u8 = undefined;
    var fbs = io.fixedBufferStream(&buf);
    var writer = fbs.writer();
    var e = encoder(writer);
    try e.encodeVarUint(42);
    try std.testing.expectEqual(fbs.getWritten()[0], 42);
    try e.encodeVarUint(0x100);
    try std.testing.expectEqual(fbs.getWritten()[1], 128);
    try std.testing.expectEqual(fbs.getWritten()[2], 2);
}

test "write variable int" {
    var buf: [4]u8 = undefined;
    var fbs = io.fixedBufferStream(&buf);
    var writer = fbs.writer();
    var e = encoder(writer);
    try e.encodeVarInt(42);
    try std.testing.expectEqual(fbs.getWritten()[0], 42 << 1);
}

test "round trip variable uint" {
    var buf: [4]u8 = undefined;
    var fbs = io.fixedBufferStream(&buf);
    var reader = fbs.reader();
    var writer = fbs.writer();
    var e = encoder(writer);
    try e.encodeVarUint(0x10000);
    var d = decoder(std.testing.allocator, reader);
    fbs = io.fixedBufferStream(fbs.getWritten());
    const res = try d.decodeVarUint();
    try std.testing.expectEqual(res, 0x10000);
}

test "round trip variable int 1" {
    var buf: [4]u8 = undefined;
    var fbs = io.fixedBufferStream(&buf);
    var reader = fbs.reader();
    var writer = fbs.writer();
    var e = encoder(writer);
    try e.encodeVarInt(-0x10000);
    var d = decoder(std.testing.allocator, reader);
    fbs = io.fixedBufferStream(fbs.getWritten());
    const res = try d.decodeVarInt();
    try std.testing.expectEqual(res, -0x10000);
}

test "round trip variable int 2" {
    var buf: [4]u8 = undefined;
    var fbs = io.fixedBufferStream(&buf);
    var reader = fbs.reader();
    var writer = fbs.writer();
    var e = encoder(writer);
    try e.encodeVarInt(0x10000);
    var d = decoder(std.testing.allocator, reader);
    fbs = io.fixedBufferStream(fbs.getWritten());
    const res = try d.decodeVarInt();
    try std.testing.expectEqual(res, 0x10000);
}

test "round trip union with void member" {
    const U = union(enum) {
        Void: void,

M src/test.zig => src/test.zig +8 -4
@@ 950,13 950,14 @@ fn testCompileError(comptime code: []const u8, comptime expected_error: []const 
    test_file_seq += 1;
    var cwd = fs.cwd();
    try cwd.copyFile("src/bare.zig", cwd, "/tmp/zig-bare.zig", .{});
    try cwd.copyFile("src/varint.zig", cwd, "/tmp/varint.zig", .{});
    var tmpfile = try cwd.createFile(fname, .{ .read = true, .truncate = true });
    defer tmpfile.close();
    _ = try tmpfile.write(boilerplate);
    _ = try tmpfile.write(code);
    const res = try std.ChildProcess.run(.{
        .allocator = testing.allocator,
        .argv = &[_][]const u8{ "zig", "build-exe", fname, "-fno-emit-bin" },
        .argv = &[_][]const u8{ "zig", "build-exe", fname, "-fno-emit-bin", "--color", "off" },
    });
    defer {
        testing.allocator.free(res.stdout);


@@ 972,13 973,14 @@ fn runZigTestOnCodeString(comptime code: []const u8) !void {
    test_file_seq += 1;
    var cwd = fs.cwd();
    try cwd.copyFile("src/bare.zig", cwd, "/tmp/zig-bare.zig", .{});
    try cwd.copyFile("src/varint.zig", cwd, "/tmp/varint.zig", .{});
    var tmpfile = try cwd.createFile(fname, .{ .read = true, .truncate = true });
    defer tmpfile.close();
    _ = try tmpfile.write(boilerplate);
    _ = try tmpfile.write(code);
    const res = try std.ChildProcess.run(.{
        .allocator = testing.allocator,
        .argv = &[_][]const u8{ "zig", "test", fname, "-fno-emit-bin" },
        .argv = &[_][]const u8{ "zig", "test", fname, "-fno-emit-bin", "--color", "off" },
    });
    defer {
        testing.allocator.free(res.stdout);


@@ 990,8 992,10 @@ fn runZigTestOnCodeString(comptime code: []const u8) !void {
fn checkErrorMessage(haystack: []const u8, message: []const u8) !void {
    const errorstart = "error: ";
    const idx = mem.indexOf(u8, haystack, errorstart) orelse unreachable;
    const errorslice = haystack[idx + errorstart.len ..];
    try testing.expect(null != std.mem.indexOf(u8, errorslice, message));
    const errorslice = haystack[idx + errorstart.len .. idx + errorstart.len + message.len];

    if (null != std.mem.indexOf(u8, errorslice, message))
        try expectEqualSlices(u8, message, errorslice);
}

test "README example" {

A src/varint.zig => src/varint.zig +135 -0
@@ 0,0 1,135 @@
const std = @import("std");

pub fn encodeVarUint(writer: anytype, value: u64) !void {
    var x = value;

    while (0x80 <= x) {
        const b: u8 = @truncate(x);
        try writer.writeByte(b | 0x80);
        x >>= 7;
    }

    try writer.writeByte(@truncate(x));
}

pub fn encodeVarInt(writer: anytype, value: i64) !void {
    const ux: u64 = @bitCast((2 * value) ^ (value >> 63));
    return encodeVarUint(writer, ux);
}

pub const DecodeError = error{Overflow};

pub fn decodeVarInt(reader: anytype) !i64 {
    const ux = try decodeVarUint(reader);
    const x: i64 = @intCast(ux >> 1);
    const y: i64 = @intCast(ux & 1);
    return x ^ -y;
}

pub fn decodeVarUint(reader: anytype) !u64 {
    var x: u64 = 0;
    var s: u6 = 0;

    for (0..std.math.maxInt(u4)) |i| {
        const b = try reader.readByte();
        const orm: u64 = @intCast(b & 0x7f);
        x |= orm << s;

        if (b < 0x80) {
            if (9 < i or i == 9 and 1 < b)
                return DecodeError.Overflow;

            return x;
        }

        const ov = @addWithOverflow(s, 7);

        if (0 != ov[1])
            return DecodeError.Overflow;

        s = ov[0];
    }

    return 0;
}

const io = std.io;
const testing = std.testing;

test "read variable uint" {
    var fbs = io.fixedBufferStream("\x2a");
    var reader = fbs.reader();
    const x = try decodeVarUint(&reader);
    try testing.expectEqual(x, 42);
    fbs = io.fixedBufferStream("\x80\x02");
    const y = decodeVarUint(fbs.reader());
    try testing.expectEqual(y, 0x100);
}

test "read variable uint overflow 1" {
    const buf = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\x02";
    var fbs = io.fixedBufferStream(buf);
    var reader = fbs.reader();
    const x = decodeVarUint(reader);
    try testing.expectError(DecodeError.Overflow, x);
}

test "read variable uint overflow 2" {
    const buf = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x00";
    var fbs = io.fixedBufferStream(buf);
    var reader = fbs.reader();
    const x = decodeVarUint(reader);
    try testing.expectError(DecodeError.Overflow, x);
}

test "write variable uint" {
    var buf: [4]u8 = undefined;
    var fbs = io.fixedBufferStream(&buf);
    var writer = fbs.writer();
    try encodeVarUint(writer, 42);
    try testing.expectEqual(fbs.getWritten()[0], 42);
    try encodeVarUint(writer, 0x100);
    try testing.expectEqual(fbs.getWritten()[1], 128);
    try testing.expectEqual(fbs.getWritten()[2], 2);
}

test "write variable int" {
    var buf: [4]u8 = undefined;
    var fbs = io.fixedBufferStream(&buf);
    var writer = fbs.writer();
    try encodeVarInt(writer, 42);
    try testing.expectEqual(fbs.getWritten()[0], 42 << 1);
}

test "round trip variable uint" {
    var buf: [4]u8 = undefined;
    var fbs = io.fixedBufferStream(&buf);
    var reader = fbs.reader();
    var writer = fbs.writer();
    try encodeVarUint(writer, 0x10000);
    fbs = io.fixedBufferStream(fbs.getWritten());
    const res = try decodeVarUint(reader);
    try testing.expectEqual(res, 0x10000);
}

test "round trip variable int 1" {
    var buf: [4]u8 = undefined;
    var fbs = io.fixedBufferStream(&buf);
    var reader = fbs.reader();
    var writer = fbs.writer();
    try encodeVarInt(writer, -0x10000);
    fbs = io.fixedBufferStream(fbs.getWritten());
    const res = try decodeVarInt(reader);
    try testing.expectEqual(res, -0x10000);
}

test "round trip variable int 2" {
    var buf: [4]u8 = undefined;
    var fbs = io.fixedBufferStream(&buf);
    var reader = fbs.reader();
    var writer = fbs.writer();
    try encodeVarInt(writer, 0x10000);
    fbs = io.fixedBufferStream(fbs.getWritten());
    const res = try decodeVarInt(reader);
    try testing.expectEqual(res, 0x10000);
}