How to combine two packed structs into one?

I have two packed structs, how can I combine them, similar to the | syntax of integer?

    const Some = packed struct(u8) {
        a: u1 = 0,
        b: u1 = 0,
        c: u1 = 0,
        d: u1 = 0,
        e: u1 = 0,
        f: u1 = 0,
        g: u1 = 0,
        h: u1 = 0,
    };

    const s1: Some = .{ .a = 1, .b = 1, .c = 1, .d = 1 };
    const s2: Some = .{ .e = 1, .f = 1, .g = 1, .h = 1 };

    // const s3 = s1 + s2; // ???
    // std.debug.print("{b}\n", .{s3});

If you want to treat the underlying structure like it’s an integer, I’d say you can @bitCast it to that integer:

// initialize from integers
const a: Some = @bitCast(@as(u8, 1));
const b: Some = @bitCast(@as(u8, 1));

// cast to integers
const x: u8 = @bitCast(a); 
const y: u8 = @bitCast(b);

// build from integer operations
const z: Some = @bitCast(x + y);

Of course think about endian-ness. On release fast, that whole sequence even after casting z back to an integer being returned from a function results in the following assembly:

mov     al, 2
ret

So the compiler sees right through what’s happening here.

3 Likes

You can add member functions in packed structs.

const s2 = s1.bitOr(s2);

Using the @bitCast mentioned by @AndrewCodeDev

pub fn bitOr(s1: Some, s2: Some) Some {
    const s1u: u8 = @bitCast(s1);
    const s2u: u8 = @bitCast(s2);
    return @bitCast(s1u | s2u);
}

Binary or | is different than addition + when both values are 1.

4 Likes

Worth observing that Zig defines packed structs from least to most significant bit, regardless of the native endianness of the system. So casting back and forth from the backing integer type will give consistent results on all architectures.

2 Likes

True, but I will point out that you may get weird results when you go to an int and then do arithmetic with them. If you set the “leading” field to 1 on the packed struct and add it to another where you did the same, I think you could run into overflow problems if that gets interpreted as the most significant power of 2. We should probably move this to a different thread if we want to continue. That’s a very important piece of information though.

Edit - @mnemnion gave me some resources to look at. The value casted back from the @bitCast will be consistent regardless of endianess. Cool stuff.

1 Like