const std = @import("std"); const HeaderSize = @bitSizeOf(Header) / 8; const Magic = [4]u8{ 0xf0, 0x9f, 0xa4, 0xb7 }; const Version = 0; const Bom = 0x1234; const Header = packed struct { magic: [4]u8, version: u8, bom: u16, num_shells: u8, num_users: u32, num_groups: u32, offset_cmph_uid2user: u32, offset_cmph_groupname2group: u32, offset_cmph_username2user: u32, offset_idx: u32, offset_groups: u32, offset_users: u32, offset_groupmembers: u32, offset_additional_gids: u32, // TODO(motiejus) should we be returning *Header instead? That way all // stacks could be smaller by 48 bytes, and we would be referring to // it's fields in the mmap'ed region. pub fn init(blob: [HeaderSize]u8) Header { return @bitCast(Header, blob); } pub fn asArray(self: *const Header) [HeaderSize]u8 { return @bitCast([HeaderSize]u8, self.*); } }; const testing = std.testing; test "header size is byte-aligned" { try testing.expectEqual(HeaderSize * 8, @bitSizeOf(Header)); } test "header pack and unpack" { const header = Header{ .magic = Magic, .version = Version, .bom = Bom, .num_shells = 0, .num_users = 0, .num_groups = 0, .offset_cmph_uid2user = 0, .offset_cmph_groupname2group = 0, .offset_cmph_username2user = 0, .offset_idx = 0, .offset_groups = 0, .offset_users = 0, .offset_groupmembers = 0, .offset_additional_gids = 0, }; const blob = header.asArray(); const header2 = Header.init(blob); try testing.expectEqual(header, header2); }