diff --git a/src/padding.zig b/src/padding.zig index ee9671d..73308a8 100644 --- a/src/padding.zig +++ b/src/padding.zig @@ -1,5 +1,7 @@ const std = @import("std"); const assert = std.debug.assert; +const Allocator = std.mem.Allocator; +const ArrayList = std.ArrayList; // rounds up an int to the nearest factor of nbits. pub fn roundUp(comptime T: type, comptime nbits: u8, n: T) T { @@ -14,6 +16,12 @@ pub fn roundUpPadding(comptime T: type, comptime nbits: u8, n: T) T { return roundUp(T, nbits, n) - n; } +// arrayList adds padding to an ArrayList(u8) for a given number of nbits +pub fn arrayList(arr: *ArrayList(u8), comptime nbits: u8) Allocator.Error!void { + const padding = roundUpPadding(u64, nbits, arr.items.len); + try arr.*.appendNTimes(0, padding); +} + const testing = std.testing; test "padding" { @@ -30,3 +38,16 @@ test "padding" { try testing.expectEqual(roundUpPadding(u12, 2, 4091), 1); try testing.expectEqual(roundUpPadding(u12, 2, 4092), 0); } + +test "arrayList" { + var buf = try ArrayList(u8).initCapacity(testing.allocator, 16); + defer buf.deinit(); + + buf.appendAssumeCapacity(1); + try arrayList(&buf, 3); + try testing.expectEqual(buf.items.len, 8); + + buf.appendAssumeCapacity(2); + try arrayList(&buf, 10); + try testing.expectEqual(buf.items.len, 1024); +} diff --git a/src/user.zig b/src/user.zig index ca9dd60..a98c875 100644 --- a/src/user.zig +++ b/src/user.zig @@ -141,7 +141,12 @@ pub const PackedUser = struct { // packTo packs the User record and copies it to the given byte slice. The // slice must have at least maxRecordSize() bytes available. // The slice is passed as a pointer, so it can be mutated. - pub fn packTo(buf: *[]u8, user: User, idxFn: shellIndexFn) errInvalid!void { + const packErr = errInvalid || Allocator.Error; + pub fn packTo( + arr: *ArrayList(u8), + user: User, + idxFn: shellIndexFn, + ) packErr!void { // function arguments are consts. We need to mutate the underlying // slice, so passing it via pointer instead. const home_len = try downCast(u6, user.home.len - 1); @@ -167,35 +172,21 @@ pub const PackedUser = struct { }; const innerBytes = mem.asBytes(&inner); - var pos: usize = buf.*.len; - buf.*.len += InnerSize + - user.home.len + - user.gecos.len; - // innerBytes.len is longer than InnerSize. We want to copy // only the InnerSize-number of bytes. - mem.copy(u8, buf.*[pos .. pos + InnerSize], innerBytes[0..InnerSize]); - pos += InnerSize; - mem.copy(u8, buf.*[pos .. pos + user.home.len], user.home); - pos += user.home.len; + try arr.*.appendSlice(innerBytes[0..InnerSize]); + try arr.*.appendSlice(user.home); if (!inner.name_is_a_suffix) { - buf.*.len += user.name.len; - mem.copy(u8, buf.*[pos .. pos + user.name.len], user.name); - pos += user.name.len; + try arr.*.appendSlice(user.name); } - mem.copy(u8, buf.*[pos .. pos + user.gecos.len], user.gecos); - pos += user.gecos.len; + try arr.*.appendSlice(user.gecos); if (inner.shell_here) { - buf.*.len += user.shell.len; - mem.copy(u8, buf.*[pos .. pos + user.shell.len], user.shell); - pos += user.shell.len; + try arr.*.appendSlice(user.shell); } - const padding = pad.roundUpPadding(u64, AlignmentBits, pos); - buf.*.len += padding; - mem.set(u8, buf.*[pos .. pos + padding], 0); + try pad.arrayList(arr, AlignmentBits); } // maxSize is the maximum number of records a PackedUser can take @@ -331,7 +322,7 @@ test "construct PackedUser section" { } }; for (users) |user| { try buf.ensureUnusedCapacity(PackedUser.maxSize()); - try PackedUser.packTo(&buf.items, user, testShellIndex); + try PackedUser.packTo(&buf, user, testShellIndex); } var it = userIterator(buf.items, testShell); @@ -361,6 +352,6 @@ test "PackedUser.maxSize()" { .home = "Home" ** 16, // 64 .shell = "She.LllL" ** 8, // 64 }; - try PackedUser.packTo(&buf.items, largeUser, testShellIndex); + try PackedUser.packTo(&buf, largeUser, testShellIndex); try testing.expectEqual(PackedUser.maxSize(), buf.items.len); }