It's pretty clean at this imo: Less metaprogramming but I think nicer to use in some cases.
const Connection = opaque {
pub const Header = struct {
host_len: usize,
// add more static fields or dynamic field lengths here
//buff_len: usize,
};
pub fn init(a: std.mem.Allocator, args: struct { host: []const u8 }) *@This() {
var this = a.allocWithOptions(u8, @sizeOf(Header) + host.len, @alignOf(Header), null);
@memcpy(this[@sizeOf(Header)..], host);
return this.ptr;
}
pub fn host(self: *const @This()) []const u8 {
const bytes: *u8 = @ptrCast(self);
const header: *Header = @ptrCast(self);
const data = bytes[@sizeOf(Header)..];
const host = data[0..header.host_len];
return host;
}
};
going off memory so I expect it to not actually compile, but I've definitely done something like this before.