1
Fork 0
turbonss/lib/Group.zig

92 lines
2.5 KiB
Zig

const std = @import("std");
const mem = std.mem;
const Allocator = mem.Allocator;
const Group = @This();
gid: u32,
name: [:0]const u8,
// should be [:null]const ?[:0]const u8, but it crashes the compiler. See
// https://github.com/ziglang/zig/issues/7517.
// members[members.len] is always null for cloned groups. Once the bug
// in the compiler is fixed, we should update the return type here.
members: [:null]const ?[*:0]const u8,
// storage of name + members
_buf: []const u8,
pub fn new(
allocator: Allocator,
gid: u32,
name: []const u8,
members: []const []const u8,
) error{OutOfMemory}!Group {
const buf_len = blk: {
var sum: usize = 0;
for (members) |member| sum += member.len;
break :blk @intCast(u32, sum);
};
_ = buf_len;
_ = allocator;
_ = gid;
_ = name;
_ = members;
return error.OutOfMemory;
}
pub fn clone(self: *const Group, allocator: Allocator) error{OutOfMemory}!Group {
var members = try allocator.allocSentinel(?[*:0]const u8, self.members.len, null);
errdefer allocator.free(members);
var buf = try allocator.alloc(u8, self._buf.len);
errdefer allocator.free(buf);
mem.copy(u8, buf, self._buf);
const our_begin = @ptrToInt(members.ptr);
const their_begin = @ptrToInt(self.members.ptr);
for (self.members) |*name_ptr, i| {
const offset = @ptrToInt(name_ptr) - their_begin;
members[i] = @intToPtr([*:0]const u8, our_begin + offset);
}
return Group{
.gid = self.gid,
.name = buf[0..self.name.len],
.members = members[0.. :null],
._buf = buf,
};
}
pub fn deinit(self: *Group, allocator: Allocator) void {
allocator.free(self.name);
if (self.members[0]) |firstmember|
allocator.free(firstmember);
allocator.free(self.members);
self.* = undefined;
}
const testing = std.testing;
test "Group.clone" {
// TODO: how to do this on stack?
var member1 = mem.sliceTo(try testing.allocator.dupeZ(u8, "member1"), 0);
defer testing.allocator.free(member1);
var group = Group{
.gid = 1,
.name = "foo",
.members = &[_:null]?[*:0]const u8{ member1, "member2" },
};
var cloned = try group.clone(testing.allocator);
defer cloned.deinit(testing.allocator);
group.gid = 2;
group.name = "bar";
member1[0] = 'x';
try testing.expectEqual(cloned.gid, 1);
try testing.expectEqualSlices(u8, cloned.name, "foo");
//try testing.expectEqualSlices(u8, @as([*:0]const u8, cloned.members[0].?), "member1");
}