const A = extern struct {
foo: u32,
bar: u64,
};
const B = struct {
a: A,
pub fn init(foo: u32, bar: u64) B {
return .{ .a = .{ .foo = foo, .bar = bar };
}
};
Could I @bitCast B to A?
There is a case where I need to keep an external layout, but I’d like to add a helper for constructing it in a cross-platform way. Specifically it’s for iovec vs WSABUF. I’d like to have .fromSlice() method, but internally I need to be able to bitcast it, or rather ptrcast the pointer to an array of such structs.
Maybe adding extern to B too would help because I think it guarantees compatibility with C ABI. I have not used this in C myself but I have heard it being used in this talk so I would assume it works consistently. https://youtu.be/443UNeGrFoM?si=OTZHwVcbu5zLJ7wb&t=4275
If I were you I would mark everything extern, assume @bitCast works and add the following block in the code:
comptime {
if (@sizeOf(A) != @sizeOf(B)) @compileError(“struct A must be the same size as struct B”);
}
This way if your code doesn’t work on a platform you know immediately and can act accordingly. You could also edit this block to add more checks for anything “fishy” you plan to do.
ah, you already have a slice of B. Then I would say, pointer casting is the most ergonomic, assuming B only contains an A. That requirement should be documented in B.
But I do question why you have B at all, why not just use A directly?
I assume, either, A is from some library you are using, or/and, A is a lower level primitive and B is an abstraction over different potential lower level primitives, in which case the only reason to have B is to call the functions on an instance b.foo() as opposed to foo(a), without having to implement almost identical code for each A.
I would prefer foo(a) to avoid pointer casting and keep type safety.