Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

Oid

The ID of a Git object.

git.Oid
pub const Oid = union(Format)

File

Code

pub const Oid = union(Format) {
    sha1: [Sha1.digest_length]u8,
    sha256: [Sha256.digest_length]u8,

    pub const max_formatted_length = len: {
        var max: usize = 0;
        for (std.enums.values(Format)) |f| {
            max = @max(max, f.formattedLength());
        }
        break :len max;
    };

    pub const Format = enum {
        sha1,
        sha256,

        pub fn byteLength(f: Format) usize {
            return switch (f) {
                .sha1 => Sha1.digest_length,
                .sha256 => Sha256.digest_length,
            };
        }

        pub fn formattedLength(f: Format) usize {
            return 2 * f.byteLength();
        }
    };

    const Hasher = union(Format) {
        sha1: Sha1,
        sha256: Sha256,

        fn init(oid_format: Format) Hasher {
            return switch (oid_format) {
                .sha1 => .{ .sha1 = Sha1.init(.{}) },
                .sha256 => .{ .sha256 = Sha256.init(.{}) },
            };
        }

        // Must be public for use from HashedReader and HashedWriter.
        pub fn update(hasher: *Hasher, b: []const u8) void {
            switch (hasher.*) {
                inline else => |*inner| inner.update(b),
            }
        }

        fn finalResult(hasher: *Hasher) Oid {
            return switch (hasher.*) {
                inline else => |*inner, tag| @unionInit(Oid, @tagName(tag), inner.finalResult()),
            };
        }
    };

    const Hashing = union(Format) {
        sha1: Io.Writer.Hashing(Sha1),
        sha256: Io.Writer.Hashing(Sha256),

        fn init(oid_format: Format, buffer: []u8) Hashing {
            return switch (oid_format) {
                .sha1 => .{ .sha1 = .init(buffer) },
                .sha256 => .{ .sha256 = .init(buffer) },
            };
        }

        fn writer(h: *@This()) *Io.Writer {
            return switch (h.*) {
                inline else => |*inner| &inner.writer,
            };
        }

        fn final(h: *@This()) Oid {
            switch (h.*) {
                inline else => |*inner, tag| {
                    inner.writer.flush() catch unreachable; // hashers cannot fail
                    return @unionInit(Oid, @tagName(tag), inner.hasher.finalResult());
                },
            }
        }
    };

    pub fn fromBytes(oid_format: Format, bytes: []const u8) Oid {
        assert(bytes.len == oid_format.byteLength());
        return switch (oid_format) {
            inline else => |tag| @unionInit(Oid, @tagName(tag), bytes[0..comptime tag.byteLength()].*),
        };
    }

    pub fn readBytes(oid_format: Format, reader: *Io.Reader) !Oid {
        return switch (oid_format) {
            inline else => |tag| @unionInit(Oid, @tagName(tag), (try reader.takeArray(tag.byteLength())).*),
        };
    }

    pub fn parse(oid_format: Format, s: []const u8) error{InvalidOid}!Oid {
        switch (oid_format) {
            inline else => |tag| {
                if (s.len != tag.formattedLength()) return error.InvalidOid;
                var bytes: [tag.byteLength()]u8 = undefined;
                for (&bytes, 0..) |*b, i| {
                    b.* = std.fmt.parseUnsigned(u8, s[2 * i ..][0..2], 16) catch return error.InvalidOid;
                }
                return @unionInit(Oid, @tagName(tag), bytes);
            },
        }
    }

    test parse {
        try testing.expectEqualSlices(
            u8,
            &.{ 0xCE, 0x91, 0x9C, 0xCF, 0x45, 0x95, 0x18, 0x56, 0xA7, 0x62, 0xFF, 0xDB, 0x8E, 0xF8, 0x50, 0x30, 0x1C, 0xD8, 0xC5, 0x88 },
            &(try parse(.sha1, "ce919ccf45951856a762ffdb8ef850301cd8c588")).sha1,
        );
        try testing.expectError(error.InvalidOid, parse(.sha256, "ce919ccf45951856a762ffdb8ef850301cd8c588"));
        try testing.expectError(error.InvalidOid, parse(.sha1, "7f444a92bd4572ee4a28b2c63059924a9ca1829138553ef3e7c41ee159afae7a"));
        try testing.expectEqualSlices(
            u8,
            &.{ 0x7F, 0x44, 0x4A, 0x92, 0xBD, 0x45, 0x72, 0xEE, 0x4A, 0x28, 0xB2, 0xC6, 0x30, 0x59, 0x92, 0x4A, 0x9C, 0xA1, 0x82, 0x91, 0x38, 0x55, 0x3E, 0xF3, 0xE7, 0xC4, 0x1E, 0xE1, 0x59, 0xAF, 0xAE, 0x7A },
            &(try parse(.sha256, "7f444a92bd4572ee4a28b2c63059924a9ca1829138553ef3e7c41ee159afae7a")).sha256,
        );
        try testing.expectError(error.InvalidOid, parse(.sha1, "ce919ccf"));
        try testing.expectError(error.InvalidOid, parse(.sha256, "ce919ccf"));
        try testing.expectError(error.InvalidOid, parse(.sha1, "master"));
        try testing.expectError(error.InvalidOid, parse(.sha256, "master"));
        try testing.expectError(error.InvalidOid, parse(.sha1, "HEAD"));
        try testing.expectError(error.InvalidOid, parse(.sha256, "HEAD"));
    }

    pub fn parseAny(s: []const u8) error{InvalidOid}!Oid {
        return for (std.enums.values(Format)) |f| {
            if (s.len == f.formattedLength()) break parse(f, s);
        } else error.InvalidOid;
    }

    pub fn format(oid: Oid, writer: *Io.Writer) Io.Writer.Error!void {
        try writer.print("{x}", .{oid.slice()});
    }

    pub fn slice(oid: *const Oid) []const u8 {
        return switch (oid.*) {
            inline else => |*bytes| bytes,
        };
    }
}