Skip to content

Add narrow Struct builder C API - #1153

Draft
goblinmode2700 wants to merge 2 commits into
msgspec:mainfrom
goblinmode2700:narrow-struct-builder-capi
Draft

Add narrow Struct builder C API#1153
goblinmode2700 wants to merge 2 commits into
msgspec:mainfrom
goblinmode2700:narrow-struct-builder-capi

Conversation

@goblinmode2700

Copy link
Copy Markdown

What this draft tests

This is a deliberately narrow alternative/complement to #961: one opaque,
versioned C-API capability for constructing an already-validated msgspec.Struct
from declared-order owned references. It does not expose msgspec's private
layouts, offsets, metaclass construction, encoders, or decoders.

The concrete consumer is a native TOON decoder. Its parser already knows the
target schema and has final Python field values, but today it must call the
public Struct constructor, which repeats argument binding. The proposed call
lets msgspec retain ownership of allocation, defaults/factories, GC decisions,
abstract checks, and __post_init__ while removing that duplicate binding work.

Safety and fallback

  • The returned builder is an opaque Python object, not a raw private-layout
    handle.
  • It participates in cyclic GC. The test suite covers the class -> token ->
    class cycle found during external review.
  • The build call has an explicit consume-on-success-and-failure ownership
    contract.
  • Unsupported class/metaclass/interpreter configurations return a normal
    fallback status without an exception.
  • V1 advertises no capability on free-threaded builds.
  • The public header and table are size/capability/version checked.

Evidence

  • CPython 3.13 upstream unit suite: 6,387 passed, 143 skipped.
  • CPython 3.14 free-threaded upstream unit suite: 6,369 passed, 155 skipped.
  • Focused API/lifecycle tests: 7 passed.
  • TOON 4.1.1 corpus through the consumer: 538/538; strict errors 84/84.
  • Matched current-main A/B, same codec wheel and same msgspec base commit:
    S1 about 3% faster (resolved only after doubled sampling), S6 about 3% faster
    but unresolved on confirmation, and S12 about 5% faster and resolved.

This is a draft to discuss whether this small producer-owned capability is a
maintainable first C-API boundary. Production msgspec-toon remains pinned to
stock msgspec==0.21.1; no patched dependency is shipped.

Thank you to @Vizonex and the participants in #958/#961 for establishing the
capsule/test-module prior art and surfacing the broader extension use cases.

@codspeed-hq

codspeed-hq Bot commented Aug 12, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 139 untouched benchmarks
⏩ 135 skipped benchmarks1


Comparing goblinmode2700:narrow-struct-builder-capi (15579c3) with main (f51f378)

Open in CodSpeed

Footnotes

  1. 135 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@ofek ofek left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please provide a concrete example of code that illustrates how you intend for this to be used.

Comment thread src/msgspec/msgspec.h
* This header exposes no msgspec object layouts. The capsule table is an
* opaque, versioned capability boundary implemented by msgspec.
*/
#define MSGSPEC_CAPI_CAPSULE_NAME "msgspec._core._C_API_v1"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really do not believe a _v1 is needed in this naming and it confuses me quite a bit. You have the right approach was we can slowly add more things in when this first PR has been merged but a recommendation I have is to remove this _v1 it isn't needed here.

Comment thread src/msgspec/msgspec.h
* failure. The caller must treat every entry as moved after the call.
* - success returns a new reference; failure returns NULL with an exception.
*/
typedef struct Msgspec_CAPI_v1 {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More or a less a ditto to what I explained a bit earlier.

@Vizonex Vizonex left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@goblinmode2700 while I love your approach to this just know that I stopped working on #958 due to my IRL job taking up more chunks of my time away and wanting to explore and invent new things. I am however willing to take the time to review and help you this this PR.
Be sure to comment that it closes #958 Just know that I am not inline with the whole _v1 thing and believe this suffix needs dropping. As long as you provide some code examples you should be all set to go.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants