-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Generalization of a struct/union that allows for explicitly defined memory layout #6478
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I think this should be done by re-introducing the e.g. const MMIOControlRegisterStruct = @Type(.{
.Struct = .{
// .layout =
.fields = &[_]std.builtin.TypeInfo.StructField{
.{
.name = "enable_interrupt",
.field_type = u8,
.offset = 0x00000100,
},
.{
.name = "dma_dest_physaddr",
.field_type = u48,
.offset = 0x00000320,
},
.{
.name = "desc_select",
.field_type = u16,
.offset = 0x00000005e,
},
},
// .decls = .{},
},
}); |
(but use Technically we can parse string in comptime and generate struct, but it is still inconvenient... proposal: const MMIOControlRegisterStruct = transform(struct {
enable_interrupt: u8 "offset: 0x00000100",
});
fn transform(comptime Original: type) type {
var orig = @TypeInfo(Original);
inline for (orig.fields) |*field| {
field.offset = parseTag(field.tag, usize, "offset");
}
return @Type(orig);
} Oh, there is already Tags proposal: #1099 |
@codehz name of the field can be a tag const MMIOControlRegisterStruct = Transform(struct {
enable_interrupt_OFFSET_0x00000100: u8,
// or
@"enable_interrupt$0x00000100": u8,
});
fn Transform(comptime Original: type) type {
var orig = @TypeInfo(Original);
inline for (orig.fields) |*field| {
if (mem.indexOf(u8, field.name, "OFFSET_") != 0)
field.offset = parseTag(mem.substring(u8, 0, mem.indexOf(u8, field.name, "OFFSET_")), usize);
}
return @Type(orig);
} |
I have another use case for opting into more well-defined layout: fn Rc(comptime T: type) type {
return struct {
strong_count: usize,
weak_count: usize,
value: T,
fn weak(self: *@This()) *Weak(T) {
self.weak_count += 1;
return @ptrCast(*Weak(T), self);
}
};
}
fn Weak(comptime T: type) type {
return struct {
strong_count: usize,
weak_count: usize,
value: T,
fn upgrade(self: *@This()) ?*Rc(T) {
if (self.strong_count == 0) return null;
self.strong_count += 1;
return @ptrCast(*Rc(T), self);
}
};
} Currently, this wouldn't work, since I don't think there's a good way to do this is Zig right now, but I'd love to be corrected. |
|
I agree that const T = struct { x: i32 };
const P = packed struct { t: T align(@alignOf(T)) }; Produces the message
|
Just to add that I believe that this proposal would be the best way to address the issues presented in #6349, #985 and #1214 - any construction of nested anonymous structures could be easily converted to a |
Having a simple solution to this would be really great. C# has explicit struct layouts
It makes C# really attractive for use cases such as Reverse Engineering, MMIO, easily reading binary files etc as it makes matching layouts super simple. Zig feels like it should be an even more natural fit for those use cases in general, but without explicit struct layouts it falls a little short currently. No language really fills this niche fully at the moment, but this feature would go a long way to making Zig the standout in that category. |
Uh oh!
There was an error while loading. Please reload this page.
When dealing with data that depends on fixed memory offsets, such as in MMIO or serialization routines, it's sometimes convenient to be able to explicitly specify field offsets, especially when they are non-contiguous or have unaligned overlap. Of course, any such composite type can be emulated with nested structs/unions and dummy padding fields. Or you could also use other workarounds, like indexing into arrays with descriptively named const variables, or hiding the logic behind getter and setter functions. However, such techniques are typically hard to read, repetitive to write, and/or error-prone, making them ill-suited for the aforementioned use case.
I believe it would be nice to have a generalized composite primitive that allows for a user-defined memory layout, where each field would be qualified with a type and an offset. This would make certain patterns easier to express: (making up possible syntax)
Or perhaps the offset values could be made bit-addressable:
The text was updated successfully, but these errors were encountered: