diff --git a/src/BufIndexer.zig b/src/BufIndexer.zig index 3c87d1a7249da5ed2cf3c0cd685b6cde7cdc73d9..a73dbf487e4fa927bfc845beb4b0fd7221e52f17 100644 --- a/src/BufIndexer.zig +++ b/src/BufIndexer.zig @@ -1,6 +1,8 @@ const std = @import("std"); const string = []const u8; const extras = @import("./lib.zig"); +const indexBufferT = extras.indexBufferT; +const rawInt = extras.rawInt; pub fn BufIndexer(comptime T: type, comptime endian: std.builtin.Endian) type { return struct { @@ -16,8 +18,44 @@ pub fn BufIndexer(comptime T: type, comptime endian: std.builtin.Endian) type { }; } + /// asserts 'idx' to be in bounds pub fn at(self: *const Self, idx: usize) T { - return extras.indexBufferT(self.bytes, T, endian, idx, self.max_len); + return indexBufferT(self.bytes, T, endian, idx, self.max_len); } }; } + +test { + const bytes = std.mem.toBytes(rawInt(u64, 0x4e5a7da9f3f1d132)); + const bindex = BufIndexer(u64, .Big).init(&bytes, 1); + try std.testing.expect(bindex.at(0) == 0x4e5a7da9f3f1d132); +} + +test { + const bytes = std.mem.toBytes(rawInt(u64, 0x4e5a7da9f3f1d132)); + const bindex = BufIndexer(u32, .Big).init(&bytes, 2); + try std.testing.expect(bindex.at(0) == 0x4e5a7da9); + try std.testing.expect(bindex.at(1) == 0xf3f1d132); +} + +test { + const bytes = std.mem.toBytes(rawInt(u64, 0x4e5a7da9f3f1d132)); + const bindex = BufIndexer(u16, .Big).init(&bytes, 4); + try std.testing.expect(bindex.at(0) == 0x4e5a); + try std.testing.expect(bindex.at(1) == 0x7da9); + try std.testing.expect(bindex.at(2) == 0xf3f1); + try std.testing.expect(bindex.at(3) == 0xd132); +} + +test { + const bytes = std.mem.toBytes(rawInt(u64, 0x4e5a7da9f3f1d132)); + const bindex = BufIndexer(u8, .Big).init(&bytes, 8); + try std.testing.expect(bindex.at(0) == 0x4e); + try std.testing.expect(bindex.at(1) == 0x5a); + try std.testing.expect(bindex.at(2) == 0x7d); + try std.testing.expect(bindex.at(3) == 0xa9); + try std.testing.expect(bindex.at(4) == 0xf3); + try std.testing.expect(bindex.at(5) == 0xf1); + try std.testing.expect(bindex.at(6) == 0xd1); + try std.testing.expect(bindex.at(7) == 0x32); +} diff --git a/src/FixedMaxBuffer.zig b/src/FixedMaxBuffer.zig index 92cbe6c233fea1af7f75acc3695ca220f43e7f7a..7fe9f4878f09438c015a130fd77bc5a0007e2913 100644 --- a/src/FixedMaxBuffer.zig +++ b/src/FixedMaxBuffer.zig @@ -46,3 +46,7 @@ pub fn FixedMaxBuffer(comptime max_len: usize) type { } }; } + +test { + std.testing.refAllDecls(FixedMaxBuffer(16)); +} diff --git a/src/TagNameJsonStringifyMixin.zig b/src/TagNameJsonStringifyMixin.zig index 6903a7a73c0de6c4b62c2df70e19c3ba2b8b3f90..bdcdcd835be56214eb16a3bdc572dbcd504d668f 100644 --- a/src/TagNameJsonStringifyMixin.zig +++ b/src/TagNameJsonStringifyMixin.zig @@ -4,8 +4,24 @@ const extras = @import("./lib.zig"); pub fn TagNameJsonStringifyMixin(comptime S: type) type { return struct { - pub fn jsonStringify(self: S, options: std.json.StringifyOptions, out_stream: anytype) !void { - try std.json.stringify(@tagName(self), options, out_stream); + pub fn jsonStringify(self: S, json_stream: anytype) !void { + try json_stream.write(@tagName(self)); } }; } + +test { + const E = enum { + windows, + linux, + macos, + freebsd, + + pub usingnamespace TagNameJsonStringifyMixin(@This()); + }; + const allocator = std.testing.allocator; + var str = std.ArrayList(u8).init(allocator); + defer str.deinit(); + try std.json.stringify(@as(E, .linux), .{}, str.writer()); + try std.testing.expect(std.mem.eql(u8, str.items, "\"linux\"")); +} diff --git a/src/containsString.zig b/src/containsString.zig index b468d9001943e3b704a7bc8b2ae5fb63a0b3494f..7a10ac250780687d381e95c2bb7856886c801619 100644 --- a/src/containsString.zig +++ b/src/containsString.zig @@ -10,3 +10,10 @@ pub fn containsString(haystack: []const string, needle: string) bool { } return false; } + +test { + try std.testing.expect(containsString(&.{ "a", "b", "c", "d" }, "b")); +} +test { + try std.testing.expect(!containsString(&.{}, "b")); +} diff --git a/src/countScalar.zig b/src/countScalar.zig index 28087c62fb43990c554366c9b6c160ca2272744f..995167b3f1a1de5fec5dab983ce4d71f214cb116 100644 --- a/src/countScalar.zig +++ b/src/countScalar.zig @@ -12,3 +12,10 @@ pub fn countScalar(comptime T: type, haystack: []const T, needle: T) usize { } return found; } + +test { + try std.testing.expect(countScalar(u8, "The lazy brown fox jumped over the lazy dog.", ' ') == 8); +} +test { + try std.testing.expect(countScalar(u8, "kljsklksldajvaskidjklvadv", 'z') == 0); +} diff --git a/src/ensureFieldSubset.zig b/src/ensureFieldSubset.zig index b27ba8c12cd1a928f041cbec8a6b4af03424b3a7..c3e5406a7c26cbda9f0fd01f0741b424f21ac680 100644 --- a/src/ensureFieldSubset.zig +++ b/src/ensureFieldSubset.zig @@ -2,8 +2,22 @@ const std = @import("std"); const string = []const u8; const extras = @import("./lib.zig"); +/// Asserts at comptime that L ⊆ R. pub fn ensureFieldSubset(comptime L: type, comptime R: type) void { for (std.meta.fields(L)) |item| { - if (!@hasField(R, item.name)) @compileError(std.fmt.comptimePrint("{s} is missing the {s} field from {s}", .{ R, item.name, L })); + if (!@hasField(R, item.name)) { + @compileError(std.fmt.comptimePrint("'{s}' field in {s} is not present in {s}", .{ item.name, @typeName(L), @typeName(R) })); + } + } +} + +test { + comptime { + ensureFieldSubset(enum { + linux, + macos, + windows, + freebsd, + }, std.Target.Os.Tag); } } diff --git a/src/fmtReplacer.zig b/src/fmtReplacer.zig index 76b074affe55eabc33fe726e8a2eb3da5cffdb82..94185122fc9b8673b46b6b35cbfc79297ca6359d 100644 --- a/src/fmtReplacer.zig +++ b/src/fmtReplacer.zig @@ -10,12 +10,14 @@ pub fn fmtReplacer(bytes: string, from: u8, to: u8) std.fmt.Formatter(formatRepl } }; } +const FormatData = struct { + bytes: string, + from: u8, + to: u8, +}; + fn formatReplacer( - self: struct { - bytes: string, - from: u8, - to: u8, - }, + self: FormatData, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype, @@ -26,3 +28,9 @@ fn formatReplacer( try writer.writeByte(if (c == self.from) self.to else @intCast(c)); } } + +test { + const in = "C:\\Program Files\\Custom Utilities\\StringFinder.exe"; + const out = "C:/Program Files/Custom Utilities/StringFinder.exe"; + try std.testing.expectFmt(out, "{}", .{fmtReplacer(in, '\\', '/')}); +} diff --git a/src/hashBytes.zig b/src/hashBytes.zig index 7780110bf76bf333554bc742eef87de5d7a3b007..0f9d7f5a11f32860901856c8992c801898687eba 100644 --- a/src/hashBytes.zig +++ b/src/hashBytes.zig @@ -1,6 +1,7 @@ const std = @import("std"); const string = []const u8; const extras = @import("./lib.zig"); +const rawInt = extras.rawInt; pub fn hashBytes(comptime Algo: type, bytes: []const u8) [Algo.digest_length]u8 { var h = Algo.init(.{}); @@ -9,3 +10,19 @@ pub fn hashBytes(comptime Algo: type, bytes: []const u8) [Algo.digest_length]u8 h.final(&out); return out; } + +test { + const A = std.crypto.hash.Md5; + try std.testing.expect(std.mem.eql(u8, &hashBytes(A, "hello"), &std.mem.toBytes(rawInt(u128, 0x5d41402abc4b2a76b9719d911017c592)))); +} + +test { + const A = std.crypto.hash.Sha1; + // by default the array len is 24 for u160 + try std.testing.expect(std.mem.eql(u8, &hashBytes(A, "hello"), std.mem.toBytes(rawInt(u160, 0xaaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d))[0..20])); +} + +test { + const A = std.crypto.hash.sha2.Sha256; + try std.testing.expect(std.mem.eql(u8, &hashBytes(A, "hello"), &std.mem.toBytes(rawInt(u256, 0x2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824)))); +} diff --git a/src/indexBufferT.zig b/src/indexBufferT.zig index 0cde81f51f69340ee0b295792428502ff1f1dab9..9b0c249023fb773ce8c7741a314631a2d8561b67 100644 --- a/src/indexBufferT.zig +++ b/src/indexBufferT.zig @@ -1,11 +1,24 @@ const std = @import("std"); const string = []const u8; const extras = @import("./lib.zig"); +const readType = extras.readType; +const rawInt = extras.rawInt; pub fn indexBufferT(bytes: [*]const u8, comptime T: type, endian: std.builtin.Endian, idx: usize, max_len: usize) T { std.debug.assert(idx < max_len); var fbs = std.io.fixedBufferStream((bytes + (idx * @sizeOf(T)))[0..@sizeOf(T)]); - return extras.readType(fbs.reader(), T, endian) catch |err| switch (err) { + return readType(fbs.reader(), T, endian) catch |err| switch (err) { error.EndOfStream => unreachable, // assert above has been violated }; } + +test { + const bytes = std.mem.toBytes(rawInt(u32, 0x4e5a7da9)); + try std.testing.expect(indexBufferT(&bytes, u16, .Big, 0, 2) == 0x4e5a); + try std.testing.expect(indexBufferT(&bytes, u16, .Big, 1, 2) == 0x7da9); +} +test { + const bytes = std.mem.toBytes(rawInt(u32, 0x4e5a7da9)); + try std.testing.expect(indexBufferT(&bytes, u16, .Little, 0, 2) == 0x5a4e); + try std.testing.expect(indexBufferT(&bytes, u16, .Little, 1, 2) == 0xa97d); +} diff --git a/src/is.zig b/src/is.zig index e930efb0e403a0ae7cb7176c5d2dfbab122f34c4..f390f60f73275cbf5712559eef2bb2b768d141bc 100644 --- a/src/is.zig +++ b/src/is.zig @@ -4,6 +4,20 @@ const extras = @import("./lib.zig"); /// ?A == A fails /// ?A == @as(?A, b) works +/// Sourced from https://github.com/ziglang/zig/issues/12609 pub fn is(a: anytype, b: @TypeOf(a)) bool { return a == b; } + +test { + try std.testing.expect(is(@as(u8, 5), 5)); +} +test { + try std.testing.expect(is(@as(?u8, 5), 5)); +} +test { + try std.testing.expect(!is(@as(u8, 5), 8)); +} +test { + try std.testing.expect(!is(@as(?u8, 5), 8)); +} diff --git a/src/lessThanSlice.zig b/src/lessThanSlice.zig index 04eaf6594eac2dace72ea3433dda419418c9aab1..f5c65af0db094f96a3c9b0df03d8e0279ef364a0 100644 --- a/src/lessThanSlice.zig +++ b/src/lessThanSlice.zig @@ -3,6 +3,7 @@ const string = []const u8; const extras = @import("./lib.zig"); pub fn lessThanSlice(comptime T: type) fn (void, T, T) bool { + comptime std.debug.assert(std.meta.trait.isSlice(T)); return struct { fn f(_: void, lhs: T, rhs: T) bool { const result = for (0..@min(lhs.len, rhs.len)) |i| { @@ -13,3 +14,13 @@ pub fn lessThanSlice(comptime T: type) fn (void, T, T) bool { } }.f; } + +test { + try std.testing.expect(lessThanSlice(string)({}, "mouse", "possum")); +} +test { + try std.testing.expect(!lessThanSlice(string)({}, "mouse", "kangaroo")); +} +test { + try std.testing.expect(!lessThanSlice(string)({}, "mouse", "mouse")); +} diff --git a/src/ptrCast.zig b/src/ptrCast.zig index 9437ced539e489aceead12c3be6bb6d3eaeb8021..dbb99f1b69f74e70575fb952e52df259bee0d1bc 100644 --- a/src/ptrCast.zig +++ b/src/ptrCast.zig @@ -6,3 +6,10 @@ pub fn ptrCast(comptime T: type, ptr: *anyopaque) *T { if (@alignOf(T) == 0) @compileError(@typeName(T)); return @ptrCast(@alignCast(ptr)); } + +test { + var a: u16 = 42; + const b: *anyopaque = &a; + const c: *u16 = ptrCast(u16, b); + try std.testing.expect(a == c.*); +} diff --git a/src/ptrCastConst.zig b/src/ptrCastConst.zig index 4c5c207b027794e8387b2df695ecabcfebc0b675..550260ac9ec8065eab0faf92cdee3cfcd0bce355 100644 --- a/src/ptrCastConst.zig +++ b/src/ptrCastConst.zig @@ -6,3 +6,10 @@ pub fn ptrCastConst(comptime T: type, ptr: *const anyopaque) *const T { if (@alignOf(T) == 0) @compileError(@typeName(T)); return @ptrCast(@alignCast(ptr)); } + +test { + const a: u16 = 42; + const b: *const anyopaque = &a; + const c: *const u16 = ptrCastConst(u16, b); + try std.testing.expect(a == c.*); +} diff --git a/src/randomBytes.zig b/src/randomBytes.zig index 5950467b3f18f0078389d9ea5b5be63576dd7857..98853132c30ec9bbe40c198c5a35ceeffa78d6b5 100644 --- a/src/randomBytes.zig +++ b/src/randomBytes.zig @@ -7,3 +7,7 @@ pub fn randomBytes(comptime len: usize) [len]u8 { std.crypto.random.bytes(&bytes); return bytes; } + +test { + std.testing.refAllDecls(@This()); +} diff --git a/src/readBytes.zig b/src/readBytes.zig index b9b47923d6ac436b37689dd5304071a09f8e4eab..ac6d3f5c4f597fe5e4488311c868228bb1c114e5 100644 --- a/src/readBytes.zig +++ b/src/readBytes.zig @@ -8,3 +8,7 @@ pub fn readBytes(reader: anytype, comptime len: usize) ![len]u8 { assert(try reader.readAll(&bytes) == len); return bytes; } + +test { + std.testing.refAllDecls(@This()); +} diff --git a/src/readBytesAlloc.zig b/src/readBytesAlloc.zig index 55510b48fdca5d87f1e554c3c66a76ccdc3062b6..65b903f1240a2cf8cfcb8345b35cf62733583c8c 100644 --- a/src/readBytesAlloc.zig +++ b/src/readBytesAlloc.zig @@ -3,10 +3,29 @@ const string = []const u8; const extras = @import("./lib.zig"); pub fn readBytesAlloc(reader: anytype, alloc: std.mem.Allocator, len: usize) ![]u8 { - var list = std.ArrayListUnmanaged(u8){}; + var list = try std.ArrayListUnmanaged(u8).initCapacity(alloc, len); try list.ensureTotalCapacityPrecise(alloc, len); errdefer list.deinit(alloc); list.appendNTimesAssumeCapacity(0, len); try reader.readNoEof(list.items[0..len]); return list.items; } + +test { + const array = [_]u8{ 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; + var fba = std.io.fixedBufferStream(&array); + const reader = fba.reader(); + const alloc = std.testing.allocator; + const res = try readBytesAlloc(reader, alloc, 2); + defer alloc.free(res); + try std.testing.expect(res.len == 2); + try std.testing.expect(std.mem.eql(u8, res, &.{ 9, 8 })); +} + +test { + const array = [_]u8{ 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; + var fba = std.io.fixedBufferStream(&array); + const reader = fba.reader(); + const alloc = std.testing.allocator; + try std.testing.expect(readBytesAlloc(reader, alloc, 11) == error.EndOfStream); +} diff --git a/src/readExpected.zig b/src/readExpected.zig index 422d81cf47f6a993bdd11b4a6c26ba45a49fc62e..959a106ea5c6487c1d7fadd23d1b9597455bfc4a 100644 --- a/src/readExpected.zig +++ b/src/readExpected.zig @@ -11,3 +11,7 @@ pub fn readExpected(reader: anytype, expected: []const u8) !bool { } return true; } + +test { + std.testing.refAllDecls(@This()); +} diff --git a/src/readType.zig b/src/readType.zig index e728c8225d3bf5536de5206e1fa0e3382062977a..16f754866a4f7d47be84e24b4e8238f9cefcbe8e 100644 --- a/src/readType.zig +++ b/src/readType.zig @@ -1,6 +1,9 @@ const std = @import("std"); const string = []const u8; const extras = @import("./lib.zig"); +const builtin = @import("builtin"); +const native_endian = builtin.target.cpu.arch.endian(); +const rawInt = extras.rawInt; pub fn readType(reader: anytype, comptime T: type, endian: std.builtin.Endian) !T { if (T == u8) return reader.readByte(); // single bytes dont have an endianness @@ -29,3 +32,64 @@ pub fn readType(reader: anytype, comptime T: type, endian: std.builtin.Endian) ! else => |e| @compileError(@tagName(e)), }; } + +test { + const bytes = std.mem.toBytes(@as(u32, 0x4e5a7da9)); + var fba = std.io.fixedBufferStream(&bytes); + const I = u32; + const i = try readType(fba.reader(), I, native_endian); + try std.testing.expect(i == 1314553257); +} + +test { + const bytes = std.mem.toBytes(@as(u32, 0x4e5a7da9)); + var fba = std.io.fixedBufferStream(&bytes); + const E = enum(u32) { + a, + b, + c, + d = 0x4e5a7da9, + e, + }; + const e = try readType(fba.reader(), E, native_endian); + try std.testing.expect(e == .d); +} + +test { + const bytes = std.mem.toBytes(rawInt(u32, 0x4e5a7da9)); + var fba = std.io.fixedBufferStream(&bytes); + const S = struct { + a: u16, + b: u8, + c: u8, + }; + const s = try readType(fba.reader(), S, .Big); + try std.testing.expect(s.a == 0x4e5a); + try std.testing.expect(s.b == 0x7d); + try std.testing.expect(s.c == 0xa9); +} + +test { + const bytes = std.mem.toBytes(rawInt(u32, 0x4e5a7da9)); + var fba = std.io.fixedBufferStream(&bytes); + const A = [2]u16; + const a = try readType(fba.reader(), A, .Big); + try std.testing.expect(a[0] == 0x4e5a); + try std.testing.expect(a[1] == 0x7da9); +} + +test { + const bytes = std.mem.toBytes(rawInt(u32, 0x4e5a7da9)); + var fba = std.io.fixedBufferStream(&bytes); + const S = packed struct { + a: u16, + b: u4, + c: u4, + d: u8, + }; + const s = try readType(fba.reader(), S, .Big); + try std.testing.expect(s.a == 0x7da9); + try std.testing.expect(s.b == 0xa); + try std.testing.expect(s.c == 0x5); + try std.testing.expect(s.d == 0x4e); +} diff --git a/src/safeAdd.zig b/src/safeAdd.zig index 0011e90b45f6aaa12f69dbcbc00a47e603023770..79a13edfd13bf7280b3678b17db503f1a7420b94 100644 --- a/src/safeAdd.zig +++ b/src/safeAdd.zig @@ -1,11 +1,19 @@ const std = @import("std"); const string = []const u8; const extras = @import("./lib.zig"); +const OneBiggerInt = extras.OneBiggerInt; /// Allows u32 + i16 to work pub fn safeAdd(a: anytype, b: anytype) @TypeOf(a) { if (b >= 0) { return a + @as(@TypeOf(a), @intCast(b)); } - return a - @as(@TypeOf(a), @intCast(-@as(extras.OneBiggerInt(@TypeOf(b)), b))); + return a - @as(@TypeOf(a), @intCast(-@as(OneBiggerInt(@TypeOf(b)), b))); +} + +test { + try std.testing.expect(safeAdd(@as(u16, 10), @as(i8, -2)) == 8); +} +test { + try std.testing.expect(safeAdd(@as(u16, 256), @as(i8, -128)) == 128); } diff --git a/src/safeAddWrap.zig b/src/safeAddWrap.zig index 6fb1a11b21145bf07aa7e830903de9a9d4ee839c..b29720bdb1c203801cdd1d82cb597004e7a3383a 100644 --- a/src/safeAddWrap.zig +++ b/src/safeAddWrap.zig @@ -1,11 +1,25 @@ const std = @import("std"); const string = []const u8; const extras = @import("./lib.zig"); +const OneBiggerInt = extras.OneBiggerInt; /// Allows u32 +% i16 to work pub fn safeAddWrap(a: anytype, b: anytype) @TypeOf(a) { if (b >= 0) { return a +% @as(@TypeOf(a), @intCast(b)); } - return a -% @as(@TypeOf(a), @intCast(-@as(extras.OneBiggerInt(@TypeOf(b)), b))); + return a -% @as(@TypeOf(a), @intCast(-@as(OneBiggerInt(@TypeOf(b)), b))); +} + +test { + try std.testing.expect(safeAddWrap(@as(u16, 0), @as(i8, -2)) == 65534); +} +test { + try std.testing.expect(safeAddWrap(@as(u16, 10), @as(i8, -2)) == 8); +} +test { + try std.testing.expect(safeAddWrap(@as(u16, 65535), @as(i8, 1)) == 0); +} +test { + try std.testing.expect(safeAddWrap(@as(u16, 256), @as(i8, -128)) == 128); } diff --git a/src/skipToBoundary.zig b/src/skipToBoundary.zig index 7408b0a8df89632864bc5e08edcbcab19f15b85a..639957c027dc673069d38de5c0953960d06b9d58 100644 --- a/src/skipToBoundary.zig +++ b/src/skipToBoundary.zig @@ -9,3 +9,53 @@ pub fn skipToBoundary(pos: u64, boundary: u64, reader: anytype) !void { const b = boundary; try reader.skipBytes(((a + (b - 1)) & ~(b - 1)) - a, .{}); } + +test { + const array = [_]u8{ 5, 4, 3, 2, 1, 0 }; + var fba = std.io.fixedBufferStream(&array); + var counter = std.io.countingReader(fba.reader()); + const reader = counter.reader(); + try reader.skipBytes(0, .{}); + try skipToBoundary(counter.bytes_read, 4, reader); + try std.testing.expect(counter.bytes_read == 0); +} + +test { + const array = [_]u8{ 5, 4, 3, 2, 1, 0 }; + var fba = std.io.fixedBufferStream(&array); + var counter = std.io.countingReader(fba.reader()); + const reader = counter.reader(); + try reader.skipBytes(1, .{}); + try skipToBoundary(counter.bytes_read, 4, reader); + try std.testing.expect(counter.bytes_read == 4); +} + +test { + const array = [_]u8{ 5, 4, 3, 2, 1, 0 }; + var fba = std.io.fixedBufferStream(&array); + var counter = std.io.countingReader(fba.reader()); + const reader = counter.reader(); + try reader.skipBytes(2, .{}); + try skipToBoundary(counter.bytes_read, 4, reader); + try std.testing.expect(counter.bytes_read == 4); +} + +test { + const array = [_]u8{ 5, 4, 3, 2, 1, 0 }; + var fba = std.io.fixedBufferStream(&array); + var counter = std.io.countingReader(fba.reader()); + const reader = counter.reader(); + try reader.skipBytes(3, .{}); + try skipToBoundary(counter.bytes_read, 4, reader); + try std.testing.expect(counter.bytes_read == 4); +} + +test { + const array = [_]u8{ 5, 4, 3, 2, 1, 0 }; + var fba = std.io.fixedBufferStream(&array); + var counter = std.io.countingReader(fba.reader()); + const reader = counter.reader(); + try reader.skipBytes(4, .{}); + try skipToBoundary(counter.bytes_read, 4, reader); + try std.testing.expect(counter.bytes_read == 4); +} diff --git a/src/sortBy.zig b/src/sortBy.zig index a838bd7f50bdbc078fccaad2c890aa4fdcf6c0f4..91c8c91d6240521987d42a31ad590eb61570d96d 100644 --- a/src/sortBy.zig +++ b/src/sortBy.zig @@ -9,3 +9,24 @@ pub fn sortBy(comptime T: type, items: []T, comptime field: std.meta.FieldEnum(T } }.f); } + +test { + const Block = struct { + from: u21, + to: u21, + name: []const u8, + }; + var data = [_]Block{ + .{ .from = 0x0000, .to = 0x007F, .name = "Basic Latin" }, + .{ .from = 0x0250, .to = 0x02AF, .name = "IPA Extensions" }, + .{ .from = 0x0100, .to = 0x017F, .name = "Latin Extended-A" }, + .{ .from = 0x0180, .to = 0x024F, .name = "Latin Extended-B" }, + .{ .from = 0x0080, .to = 0x00FF, .name = "Latin-1 Supplement" }, + }; + sortBy(Block, &data, .from); + try std.testing.expect(std.mem.eql(u8, data[0].name, "Basic Latin")); + try std.testing.expect(std.mem.eql(u8, data[1].name, "Latin-1 Supplement")); + try std.testing.expect(std.mem.eql(u8, data[2].name, "Latin Extended-A")); + try std.testing.expect(std.mem.eql(u8, data[3].name, "Latin Extended-B")); + try std.testing.expect(std.mem.eql(u8, data[4].name, "IPA Extensions")); +} diff --git a/src/sortBySlice.zig b/src/sortBySlice.zig index 79e8fece047dcddc12017071ecae9ed3a7a26b0b..1f4bb5f33677a0e5f94e2d29ce7c5911083092b7 100644 --- a/src/sortBySlice.zig +++ b/src/sortBySlice.zig @@ -1,11 +1,33 @@ const std = @import("std"); const string = []const u8; const extras = @import("./lib.zig"); +const lessThanSlice = extras.lessThanSlice; pub fn sortBySlice(comptime T: type, items: []T, comptime field: std.meta.FieldEnum(T)) void { std.mem.sort(T, items, {}, struct { fn f(_: void, lhs: T, rhs: T) bool { - return extras.lessThanSlice(std.meta.FieldType(T, field))({}, @field(lhs, @tagName(field)), @field(rhs, @tagName(field))); + return lessThanSlice(std.meta.FieldType(T, field))({}, @field(lhs, @tagName(field)), @field(rhs, @tagName(field))); } }.f); } + +test { + const Block = struct { + from: u21, + to: u21, + name: []const u8, + }; + var data = [_]Block{ + .{ .from = 0x0000, .to = 0x007F, .name = "Basic Latin" }, + .{ .from = 0x0080, .to = 0x00FF, .name = "Latin-1 Supplement" }, + .{ .from = 0x0180, .to = 0x024F, .name = "Latin Extended-B" }, + .{ .from = 0x0100, .to = 0x017F, .name = "Latin Extended-A" }, + .{ .from = 0x0250, .to = 0x02AF, .name = "IPA Extensions" }, + }; + sortBySlice(Block, &data, .name); + try std.testing.expect(std.mem.eql(u8, data[0].name, "Basic Latin")); + try std.testing.expect(std.mem.eql(u8, data[1].name, "IPA Extensions")); + try std.testing.expect(std.mem.eql(u8, data[2].name, "Latin Extended-A")); + try std.testing.expect(std.mem.eql(u8, data[3].name, "Latin Extended-B")); + try std.testing.expect(std.mem.eql(u8, data[4].name, "Latin-1 Supplement")); +}