working on iterator

This commit is contained in:
Motiejus Jakštys 2022-02-20 13:17:05 +02:00 committed by Motiejus Jakštys
parent 54ec710f10
commit f2434e3d3c
3 changed files with 89 additions and 39 deletions

View File

@ -1,19 +1,19 @@
const std = @import("std");
const assert = std.debug.assert;
// rounds up a u12 to the nearest factor of 4 and returns the difference
// (padding)
pub fn roundUpPadding(comptime T: type, comptime nbits: u8, n: T) T {
return roundUp(T, nbits, n) - n;
}
// rounds up a u12 to the nearest factor of 4.
// rounds up an int to the nearest factor of nbits.
pub fn roundUp(comptime T: type, comptime nbits: u8, n: T) T {
comptime assert(nbits < @bitSizeOf(T));
const factor = comptime (1 << nbits) - 1;
return ((n + factor) & ~@as(T, factor));
}
// rounds up an integer to the nearest factor of nbits and returns the
// difference (padding)
pub fn roundUpPadding(comptime T: type, comptime nbits: u8, n: T) T {
return roundUp(T, nbits, n) - n;
}
const testing = std.testing;
test "padding" {

View File

@ -25,7 +25,7 @@ pub const ShellReader = struct {
}
// get returns a shell at the given index.
pub fn get(self: *const ShellReader, idx: u10) []const u8 {
pub fn get(self: *const ShellReader, idx: u6) []const u8 {
const shellIndex = self.sectionIndex[idx];
const start = shellIndex.offset << 2;
const end = start + shellIndex.len + 1;

View File

@ -17,6 +17,21 @@ pub const PackedUser = packed struct {
name_is_a_suffix: bool,
name_len: u5,
gecos_len: u8,
wip_padding: u8, // https://github.com/ziglang/zig/pull/10941
// blobSize returns the length of the blob storing string values.
pub fn blobLength(self: *const PackedUser) usize {
var result: usize = self.home_len;
if (!self.name_is_a_suffix) {
result += self.name_len;
}
result += self.gecos_len;
if (self.shell_here) {
result += self.shell_len_or_idx;
}
return result;
}
};
const PackedUserAlignmentBits = 3;
@ -71,6 +86,7 @@ pub const UserWriter = struct {
.name_is_a_suffix = std.mem.endsWith(u8, user.home, user.name),
.name_len = name_len,
.gecos_len = gecos_len,
.wip_padding = 0,
};
try self.appendTo.appendSlice(std.mem.asBytes(&puser));
@ -92,37 +108,52 @@ pub const UserWriter = struct {
};
pub const UserReader = struct {
const shellIndexProto = fn (u10) []const u8;
const shellIndexProto = fn (u6) []const u8;
blob: []u8,
shellIndex: shellIndexProto,
blob: []const u8,
pub const PackedUserEntry = struct {
const PackedEntry = struct {
packed_user: *PackedUser,
blob: []const u8,
};
pub fn init(shellIndex: shellIndexProto, blob: []const u8) UserReader {
pub fn init(blob: []u8, shellIndex: shellIndexProto) UserReader {
return UserReader{
.shellIndex = shellIndex,
.blob = blob,
.shellIndex = shellIndex,
};
}
pub const PackedUserIterator = struct {
ur: *const UserReader,
index: u32 = 0,
pub const PackedIterator = struct {
ur: *UserReader,
index: usize = 0,
pub fn next(it: *PackedUserIterator) ?PackedUserEntry {
pub fn next(it: *PackedIterator) ?PackedEntry {
if (it.index == it.ur.blob.len) return null;
assert(it.index < it.blob.len);
assert(it.index < it.ur.blob.len);
const start = it.index;
const end = it.index + it.index + @sizeOf(PackedUser);
var pu = std.mem.bytesAsValue(it.ur.blob[start..end]);
_ = pu;
const endUser = it.index + PackedUserSize;
var packedUser = std.mem.bytesAsValue(
PackedUser,
it.ur.blob[it.index..endUser][0..PackedUserSize],
);
const startBlob = endUser + 1;
const endBlob = startBlob + packedUser.blobLength();
it.index = pad.roundUp(usize, PackedUserAlignmentBits, endBlob + 1);
return PackedEntry{
.packed_user = packedUser,
.blob = it.ur.blob[startBlob..endBlob],
};
}
};
pub fn packedIterator(self: *UserReader) PackedIterator {
return .{ .ur = self };
}
};
const testing = std.testing;
@ -140,27 +171,46 @@ fn testShellIndex(shell: []const u8) ?u6 {
return null;
}
fn testShell(index: u6) []const u8 {
return switch (index) {
0 => "/bin/bash",
1 => "/bin/zsh",
else => unreachable,
};
}
test "construct PackedUser blob" {
var buf = ArrayList(u8).init(testing.allocator);
defer buf.deinit();
var writer = UserWriter.init(&buf, testShellIndex);
const user1 = User{
.uid = 1000,
.gid = 1000,
.name = "vidmantas",
.gecos = "Vidmantas Kaminskas",
.home = "/home/vidmantas",
.shell = "/bin/bash",
const users = [_]User{
User{
.uid = 1000,
.gid = 1000,
.name = "vidmantas",
.gecos = "Vidmantas Kaminskas",
.home = "/home/vidmantas",
.shell = "/bin/bash",
},
User{
.uid = 1001,
.gid = 1001,
.name = "svc-foo",
.gecos = "Service Account",
.home = "/home/service1",
.shell = "/usr/bin/nologin",
},
};
const user2 = User{
.uid = 1001,
.gid = 1001,
.name = "svc-foo",
.gecos = "Service Account",
.home = "/home/service1",
.shell = "/usr/bin/nologin",
};
try writer.appendUser(user1);
try writer.appendUser(user2);
for (users) |user| {
try writer.appendUser(user);
}
var rd = UserReader.init(buf.items, testShell);
var it = rd.packedIterator();
var i: u32 = 0;
while (it.next()) |entry| : (i += 1) {
try testing.expectEqual(users[i].uid, entry.packed_user.uid);
try testing.expectEqual(users[i].gid, entry.packed_user.gid);
}
}