|
|
|
|
|
by atmikemikeb
327 days ago
|
|
I thought about dynamically sized types (DSTs) in zig recently. Was considering writing about it. I came to a different conclusion. Why not use zig's opaque? 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. |
|
Because the solution outlined in the article stores the lengths alongside the pointer, instead of behind it, there is room for it to work across an ABI (though it currently does not). It's more like a slice in this way.
You could in theory implement your opaque approach using this as a utility to avoid the headache of alignment calculations. For this reason, I think that makes the approach outlined in the article more suitable as a candidate for inclusion in the standard library.