Reflection on packed struct

I am using 'packed struct(u32) ’ to represent the registers on the A64 SoC. I got some debug output working at last over serial cable :slight_smile: and now I want to use reflection to debug the register values.

I can treat them as u32 and can already dump the hex values :slight_smile: but I was trying to be clever with the bit fields, and my packed structs are broken down into a series of u1, bool, u3, enum(u3), u8, u24 etc etc.

So I can check for ‘bool’ field type, use @field to access the value, and output “true” or “false” per bit flag next to the field name, nice! thank-you Zig :slight_smile:

For the rest it is a bit messy, I have a huge if(typ == u1 or typ == u2 … or typ == u32).

Is there a way to simplify the if clause to something like @isNumeric(typ)?

Similarly, is there a way to ask @isEnum(typ) (I dont want to add if clauses for every enum I defined, I will just @intFromEnum them all, or maybe I will at a later date assuming I can get back to the Enum field name)

I tried to see how println format is working, but I am so lost browsing the code & docs that I couldnt even locate the format specifiers. Although maybe I imagined a struct formatter, or possibly it is from Go.

I only got this far because I found a Test Case for packed struct. I have no idea if accessing the fields via typInfo.@“struct”.fields is even correct? Having a string involved feels a bit hacky, but it works :slight_smile:

from what I understand, you just want to print out the struct, right? If that’s the case, you can just use “{?}” in the print statement, so something like

std.debug.print("{?}\n", .{object});

Switching on the result of @typeInfo will allow you to do what you want. However, out of curiosity, have you tried:

std.debug.print("{any}\n", .{your_packed_struct});

?

Here’s some test code:

const std = @import("std");

const Foo = packed struct(u32) {
    a: u1,
    b: bool,
    c: u3,
    d: enum(u3) {
        foo,
        bar,
        baz,
        _,
    },
    e: u8,
    f: u16,
};

pub fn main() !void {
    const foo: Foo = .{
        .a = 1,
        .b = true,
        .c = 5,
        .d = .baz,
        .e = 255,
        .f = 12345,
    };
    std.debug.print("{any}\n", .{foo});
}

On the master branch, that will print:

.{ .a = 1, .b = true, .c = 5, .d = .baz, .e = 255, .f = 12345 }

With 0.14.1, that will print:

fmtpacked.Foo{ .a = 1, .b = true, .c = 5, .d = fmtpacked.Foo__enum_23882.baz, .e = 255, .f = 12345 }

The code that does this is pretty straightforward and switches on the @typeInfo:

1 Like

Thanks, to both replies. I should have been more clear that I try to implement it myself. I am trying to avoid std, allocators, and all the other nice toys that Zig offers which arent really needed for the simple SoC stuff I am doing. Maybe when I get to OS level dev work that will change :slight_smile: But for now I am able to pump single bytes to my serial debugger, and I only need very simple atoi, hex, string and now struct.

OK, and now I see where I was going wrong, I was using typeInfo on the struct, iterating the fields, and then only looking at field.type not realising I could use the typeInfo again on the field types and check for .int etc, Nice thanks!

And is the @“struct”.fields the correct accessor?

1 Like

Yes @"something" is syntax for arbitrary identifiers and it is required to be used if the something identifier would be an invalid identifier without it (in this case a keyword).

1 Like

ah ha! more enlightenment :slight_smile: hence why I could use .int, but needed .@“enum”, thanks.

1 Like