mpgen: support primitive std::optional struct fields #243

pull ryanofsky wants to merge 3 commits into bitcoin-core:master from ryanofsky:pr/optint changing 5 files +142 −113
  1. ryanofsky commented at 10:27 pm on February 20, 2026: collaborator

    Currently C++ structs with primitive std::optional members (ints, bools, floats) cannot easily by mapped to Cap’n Proto structs because Cap’n Proto does not provide a way to leave primitive fields unset, so there isn’t a natural way to represent std::nullopt values. This PR makes it possible to map C++ structs with fields like:

    0    std::optional<int> foo;
    

    to Cap’n Proto structs by using extra Bool fields prefixed with “has” for primitive optional members:

    0    foo [@3](/bitcoin-core-multiprocess/contributor/3/) :Int32;
    1    hasFoo [@4](/bitcoin-core-multiprocess/contributor/4/) :Bool;
    

    Boolean “has” fields were already supported by the code generator and used to pass primitive std::optional parameters and return values, so this PR just extends it work with all struct fields, not just fields in params and result structs.

    Note: Motivation for this change is dealing with the CreatedTransactionResult::change_pos field introduced to the wallet interface in bitcoin-core/gui#807. This also could have been useful in https://github.com/bitcoin/bitcoin/pull/33965#issuecomment-3937522269

  2. mpgen refactor: Move field handling code to FieldList class
    This is a move-only change that should be easy to review with --color-moved. No
    behavior is changing.
    5a52ea01a9
  3. DrahtBot commented at 10:27 pm on February 20, 2026: none

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Reviews

    See the guideline for information on the review process. A summary of reviews will appear here.

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #242 (proxy-types: add CustomHasField hook to map Cap’n Proto values to null C++ values by Sjors)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

  4. mpgen refactor: add AccessorType function
    This doesn't change generated code at all, just noves functionality out of
    Generate method into a helper method so it can be reused in the next commit.
    d4ee75d5db
  5. mpgen: support primitive std::optional struct fields
    Currently optional primitive fields like `std::optional<int>` are not well
    supported as struct members.
    
    Non-primitive optional fields like `std::optional<std::string>` and optional
    struct fields are well-supported because Cap'n Proto allows non-primitive
    fields to be unset, but primitive fields are always considered set so there is
    natural way to represent null values.
    
    Libmultiprocess does already support primitive optional method parameters and
    result values, by allowing the .capnp files to declare extra boolean parameters
    prefixed with "has" and treating the extra boolean parameters as indicators of
    whether options are set or unset. This commit just this functionality to work
    for struct members as well.
    
    For example a C++ `std::optional<int> param` parameter can be represented by
    'param :Int32, hasParam :Bool` parameters in a .capnp file and libmultiprocess
    will use both Cap'n Proto fields together to represent the C++ value. Now C++
    struct fields can be represented the same way (see unit changes test for an
    example).
    26fdbad22b
  6. Sjors commented at 12:26 pm on February 24, 2026: member
    It would be useful to demonstrate that other implementations can straightforwardly handle this, e.g. with a functional tests in a Bitcoin Core branch (or PR).
  7. in src/mp/gen.cpp:448 in 9f99c7d8e0
    446                 add_accessor(field_name);
    447                 dec << "    using " << Cap(field_name) << "Accessor = Accessor<" << base_name
    448                     << "_fields::" << Cap(field_name) << ", FIELD_IN | FIELD_OUT";
    449-                if (BoxedType(field.getType())) dec << " | FIELD_BOXED";
    450+                if (field.optional) dec << " | FIELD_OPTIONAL";
    451+                if (field.requested) dec << " | FIELD_REQUESTED";
    


    Sjors commented at 1:29 pm on February 24, 2026:
    In 9f99c7d8e0f5bbdbf5262094b6b9fe515c19bf05 mpgen: support primitive std::optional struct fields: IIUC all changes in this file, except these two lines, could be a separate refactor commit. LLM came up with this: https://github.com/Sjors/libmultiprocess/commit/eced98fb71db1e54a138f02c3843cbe49080f0ce

    ryanofsky commented at 10:47 am on February 25, 2026:

    re: #243 (review)

    In 9f99c7d mpgen: support primitive std::optional struct fields: IIUC all changes in this file, except these two lines, could be a separate refactor commit.

    Thanks, I added a separate refactoring commit similar makes changes in this commit smaller and eliminates the need to add these two lines.

  8. ryanofsky force-pushed on Feb 25, 2026
  9. ryanofsky commented at 11:02 am on February 25, 2026: collaborator

    It would be useful to demonstrate that other implementations can straightforwardly handle this, e.g. with a functional tests in a Bitcoin Core branch (or PR).

    My next rebase of https://github.com/bitcoin/bitcoin/pull/10102 will use this for the change_pos field as mentioned in the PR description, but that’s probably a less obvious application than a mining interface change accepting optional BlockCreateOptions. Technically https://github.com/bitcoin/bitcoin/pull/33966 could do that but I think because of complexity of that PR, it’s best if that PR only updates the C++ mining interface and leaves extending the Cap’n Proto interface as a followup.

    In the meantime I updated the PR description with a more specific example of how this can be used and I think the unit test should provide a good test of functionality.

    Updated 9f99c7d8e0f5bbdbf5262094b6b9fe515c19bf05 -> 4de44299ea6d981f79c41fbbd76b61d902dd3580 (pr/optint.1 -> pr/optint.2, compare) adding a refactoring commit deduplicating more code between parameter & struct field mapping implementations and reducing size of the last commit

    Updated 4de44299ea6d981f79c41fbbd76b61d902dd3580 -> 26fdbad22bacaa28868fa0ad3c7d4de8e058dd16 (pr/optint.2 -> pr/optint.3, compare) tweaking $Proxy.skip implementation to continue defining accessors for skipped struct fields (needed for https://github.com/bitcoin/bitcoin/pull/10102)

  10. ryanofsky force-pushed on Mar 1, 2026

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin-core/libmultiprocess. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-03-09 11:30 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me