Skip to content

flags: support flags that are just combinations of other flags, not taking a new bit. #660

Open

Description

@programmerjake

This came up in WebAssembly/wasi-webgpu#71 (comment)

where WebGpu has a C definition:
https://github.com/webgpu-native/webgpu-headers/blob/bf8ddb91dc38ea11ec1b727dae1fa965c4207d22/webgpu.h#L1334

/**
 * `Red | Green | Blue | Alpha`.
 */
static const WGPUColorWriteMask WGPUColorWriteMask_All = 0x000000000000000F;

the generated WIT in WebAssembly/wasi-webgpu#71 as of writing is:

flags gpu-color-write {
    red,
    green,
    blue,
    alpha,
    all,
}

which is incorrect in that all shouldn't be a new flag, just a shorthand for a combination of all the other flags.

I think WIT should be changed to allow expressing named flag values that are just combinations of zero or more existing flags by allowing assigning flag values to either 0 or the bitwise or of one or more other named flags:

flags colors {
    black = 0,
    red,
    green,
    yellow = red | green,
    blue,
    magenta = red | blue,
    purple = magenta,
    cyan = green | blue,
    white = red | green | blue,
}

note: I'm not planning on implementing this myself, so whoever's interested feel free to implement it whenever ready.

Activity

  1. lukewagner commented on Jun 15, 2026

    @lukewagner
    Member

    Thanks for filing; this seems like an interesting addition worth exploring!

    So currently, flags is defined as a specialization of records (as a record-of-bool-valued fields). If we added just the | extension (the ability to define a flag as the combination of other preceding flags), I think that framing still makes sense. If we also add the ability to define flag values as integer constants, then we probably need to switch to thinking of flags more like integers. That's not necessarily a problem, and is quite natural for C and other low-level languages, but probably requires some extra discussion since it might change whether the bindings generators for non-low-level-languages spit out a number vs. a record with boolean fields. Actually, I don't know what, e.g., componentize-{js,py} already do for flags; maybe they already use numbers? Anyone know?

    If we allow integer constants, there's also some questions of what the rules are for constants. E.g., can I have:

    flags f {
      a = 0x1,
      b = 0x2,
      c = 0x3
    }

    since c = a | b (and then would this be invalid if b was removed so that c was no longer the conjunction of multiple fields?) or do we only allow integer constants that are powers of 2 and non-powers-of-2 have to be expressed as conjunctions? I expect there are good answers, but it'll require some discussion of how much we want to lean into "they're just integers".

    To wit, looking at the current lifting rules (in lift_flat_flags in CanonicalABI.md), there is not a trap on stray bits (i.e., invalid flags values), but stray bits also don't propagate across component boundaries (so on the receiving end, you can assume a valid flags value) which implies a masking operation. Masking would continue to work with only-powers-of-2-integer-constants, but wouldn't in the general case for arbitrary constants, so that's another consideration.

    That's just some initial thoughts; happy to discuss more.

  2. programmerjake commented on Jun 15, 2026

    @programmerjake
    Author

    ah, i was proposing that only literally 0 would be accepted, not arbitrary integer constants. so in terms of a record of bools, it would just be the record value where all fields are false.

    that said, I'm not against supporting integer constants if it makes sense.

  3. dicej commented on Jun 15, 2026

    @dicej
    Collaborator

    For reference, componentize-py uses enum.Flag when generating code for WIT flags, which appears to be compatible with integer constants. ComponentizeJS generates an object with a bunch of boolean fields: https://github.com/bytecodealliance/jco/blob/2fd05be4b34137e720fe91043d2ce1232f66ac4d/crates/js-component-bindgen/src/ts_bindgen.rs#L1222-L1234

  4. lukewagner commented on Jun 15, 2026

    @lukewagner
    Member

    @programmerjake Ahh, I see; just to indicate "no flags set". That nicely avoids a number of the trickier questions I listed.

    @dicej Thanks!

    So if we added |, I guess there's still a question of what JS bindings would do for combo values. Since there's also plenty of cases of Web APIs using JS numbers as bitfields (NodeFilter, compareDocumentPosition and, in WebGPU, GPUBufferUsage, GPUTextureUsage, etc), I wonder if the JS bindings should do that, and then each flags value can just be a Number-valued property. Probably also good for bindings performance. (cc @vados-cosmonic)

  5. lukewagner commented on Jun 15, 2026

    @lukewagner
    Member

    Oh, hah, I just got to #662 in my inbox queue, which does seem to want integer constants other than 0.

  6. programmerjake commented on Jun 15, 2026

    @programmerjake
    Author

    for integer values, we could continue to do masking and the mask would just be the bitwise or of all possible flags, so:

    flags f {
        a = 0b1,
        b = 0b1100,
        c = 0b1001,
    }
    

    would mask by 0b1101.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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