Skip to content

Introduce a new type opaquebits(N) #25413

@ikskuh

Description

@ikskuh

Proposal extracted from #19660:

Proposal

Introduce a new type opaquebits(N) that is an opaque bag of bits that has no semantics defined except for "it takes N bits of space".

This type can be used for storing fully opaque data and the only way to interpret its content is by using @bitCast from and to it.

Use Cases

Some microcontrollers enforce that you do not change the values of certain bits in registers, but also don't define these values. This means that you always have to read them, never interpret them, and if you want to change some others, write them back as is. This could be implemented as such:

const Register = bitpacked struct(u32) {
  data: u8,
  reserved: opaquebits(u24),
};

Another use case is the safe implementation of bitpacked union(T), where some bits determine the meaning of the others:

const VideoInputDefinition = bitpacked(u8) struct
{
    const Analog = bitpacked struct(u7) {
        serrations: Support,
        composite_sync_on_green: Support,
        composite_sync_on_horiz: Support,
        separate_sync: Support,
        setup: enum(u1) { … },
        signal_level: enum(u2) { … },
    };
    const Digital = bitpacked struct(u7) {
        standard: enum(u4) { … },
        color_depth: enum(u3) { … },
    };

    config: opaquebits(u7),
    type: enum(u1) { analog=0, digital=1 };

    fn as_analog(vdi: VideoInputDefinition) ?Analog {
        return switch(vdi.type) {
            .analog => @as(Analog, @bitCast(vdi.config)),
            .digital => null,
        };
    }

    fn as_digital(vdi: VideoInputDefinition) ?Digital {
        return switch(vdi.type) {
            .analog => @as(Digital, @bitCast(vdi.config)),
            .digital => null,
        };
    }
};

Behaviour Tests

test "opaquebits: basic operations" {
    const T = opaquebits(u8);

    // Same size and alignment as backing integer:
    comptime assert(@sizeOf(T) == @sizeOf(u8));
    comptime assert(@alignOf(T) == @alignOf(u8));

    // Exactly 8 bits:
    comptime assert(@bitSizeOf(T) == 8);

    const input: u8 = 10;
    const value: T = @bitCast(input);
    const output: u8 = @bitCast(value);

    try std.testing.expectEqual(input, output);
}

test "opaquebits: assign undefined" {
    const T = opaquebits(u32);

    const value: T = undefined; // only possible coercion

    _ = value;
}

test "opaquebits: embedding into bitpacked union" {
    const U = bitpacked union(u8) {
        bits: opaquebits(u8),
        int: u8,
    };

    const bundle: U = .{ .int = 0x13 };

    try std.testing.expectEqual(0x13, bundle.int);

    const bits: opaquebits(u8) = bundle.bits;

    const int: u8 = @bitCast(bits);

    try std.testing.expectEqual(0x13, int);
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions