Repository navigation
feat!: ship C ABI 5, model v2, and a producer API without boilerplate - #57
Open
owenthcarey wants to merge 2 commits into
Open
owenthcarey wants to merge 2 commits into
owenthcarey wants to merge 2 commits into
Conversation
Settle the foundations so later work only adds things: an ABI designed to
be extended additively, a model generators can't second-guess, and a
producer macro that needs no hand-written glue.
C ABI revision 5:
- C-style enums, rich-enum tags, and error-code types are `int32_t`
typedefs, never `typedef enum`.
- The error struct carries the message as `(message_ptr, message_len)`;
`{p}_error_set` takes a pointer and length.
- New OptDirect family: scalar optionals (`i32?`, `bool?`, `Color?`) cross
as a flag plus a value in every position instead of a value buffer.
- New Slice family: numeric lists (`[i32]`, `[f64]`, ...) cross as typed
arrays in every position.
- Every byte run is 8-aligned.
- Contract hashes exclude parameter and field names; every error code and
every callback method gets its own entry, so adding either never breaks
a deployed binding. Error domains are open: an unknown code maps to the
domain's base error.
- Vtable flag `THREAD_AFFINE`: a value-returning callback called off its
thread fails with -4 instead of aborting (Dart sets it).
Schema 0.12.0: `throws: <Domain>` or `throws: any` replaces `throws:
true`; a module may declare several error domains (`errors:` is a list);
YAML and JSON only (TOML IDL removed); serde_yaml_ng replaces serde_yaml.
Model v2: `Ty`, `ParamTy`, and `RetTy` split by position; owned
`ArgPass`, `RetPass`, `ResultPass`, `ItemPass`, `CallbackRetPass`, and
`ErrorStrategy` stored on every binding with release symbols and domains
resolved; callback methods carry an `AbiFn`; a typed symbol table; a
`SlotCollision` rule; no unknown-name fallback or public escape hatches.
Error type names are no longer doubled (`KitchenErrors` -> `KitchenError`).
The macro's extractor moved into weaveffi-macros, so the model no longer
depends on syn.
Producer API: `#[weaveffi::error]` generates `Display` and `Error` from doc
comments or `#[weaveffi(message = "...")]` (opt out with `no_display`);
per-function error types, with any `Display` error becoming `throws any`;
callback methods return `Result<T, E>` with `E: From<ForeignError>`;
`usize`, `isize`, and `char` cross; custom types via
`#[weaveffi::custom]`; `#[weaveffi::skip]`; hygienic thunks; stray
markers and a missing `export_runtime!` fail to compile. Tokio is the
default executor and the hand-rolled worker pool is gone.
Generators: one `Target` trait and one registry; shared emitters for
composite codecs, contract tables, error tables, and doc rewriting; every
target ported, with catchable load checks everywhere and per-target fixes
(Node.js 64-bit UB and integer range checks, wasm instance poisoning,
Emscripten mode removed, Dart per-call out slots and `Uint8List`, Kotlin
content equality and `@JvmStatic`/`@Throws`, Go `Check() error` and a
configurable package, Swift `check()` and identity equality, C++ `Error`
root and generic templates, Python 3.10 frozen dataclasses, Ruby 3.2
`Data.define` records, .NET records and re-enumerable iterators).
CLI: `diff` folds into `generate --check`/`--diff`, `schema --version`
replaces `schema-version`, one `--profile` flag, producers build with
`cargo rustc --crate-type cdylib` (no `crate-type` needed), `--strict`
for build and package, manylinux tags read from ELF symbol versions.
Tests and docs: full snapshots for kitchen_sink only, conformance
consumers in all 11 languages cover every new shape, and the docs
describe ABI 5, schema 0.12, target tiers, and migration notes.
BREAKING CHANGE: C ABI revision 5 and IDL schema 0.12.0. Regenerate every
binding and rebuild every producer. See docs/src/stability.md for the
migration notes.
- Dart: build `part` paths with `/` instead of platform joins, so Windows emits `src/runtime/loader.dart`, not `src/runtime\loader.dart`. - CLI test: compare the TOML-rejection message without spaces, since miette wraps it at the terminal width. - Conformance: the missing-library checks (Python, Kotlin, .NET) use a leaf name the real library doesn't have. dyld searches DYLD_LIBRARY_PATH by leaf name even for an absolute path, which found the real library on CI runners, where DYLD_* reaches the process.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This is the foundations overhaul: a pre-1.0 rewrite with no compatibility shims. The goal is that later work only adds things. That means an ABI designed to be extended additively, a model that generators can't second-guess, and a producer macro that needs no hand-written glue.
int32_ttypedefs, nevertypedef enum. The size of a C enum is implementation-defined, for example under-fshort-enums.(message_ptr, message_len)instead of a NUL-terminated string, and{p}_error_settakes a pointer and a length.i32?,bool?,Color?) cross as a flag plus a value in every position, with no value buffer.[i32],[f64], …) cross as typed arrays in every position.THREAD_AFFINEvtable flag: a value-returning callback called off its thread fails with -4 instead of aborting the process. Dart sets it.throws: <Domain>orthrows: anyreplacesthrows: true.serde_yaml_ngreplaces the archivedserde_yaml.Ty,ParamTyandRetTyare split by position.ArgPass,RetPass,ResultPass,ItemPass,CallbackRetPassandErrorStrategy. No generator matches onFamily::anymore.SlotCollisionrule, and the unknown-name fallback is gone.KitchenErrorsbecomesKitchenError.weaveffi-macros, soweaveffi-modelno longer depends onsyn.#[weaveffi::error]generatesDisplayandErrorfrom doc comments or from#[weaveffi(message = "... {field} ...")].String,io::Error,anyhow::Error) becomesthrows any.Result<T, E>withE: From<ForeignError>.usize,isize,char, custom types via#[weaveffi::custom], and#[weaveffi::skip].export_runtime!is now a compile error.Targettrait and one registry, which drives config,--target, snapshots and a CI-matrix check.Uint8List.@JvmStaticand@Throws.Check() errorand a configurable package name.check()and identityHashable.Errorroot for every exception and generic templates.Data.definerecords.sealed recordtypes and re-enumerable iterators.difffolds intogenerate --checkandgenerate --diff;schema --versionreplacesschema-version.--profileflag replaces--releaseand--debug.cargo rustc --crate-type cdylib, so crates no longer needcrate-type.buildandpackagegain--strict.deps/.kitchen_sinkonly; the other fixtures are covered by compile checks.docs/src/stability.md.Test plan
cargo test --workspace(cargo insta test --workspace --checkpasses),cargo clippy --workspace --all-targets -- -D warnings(also-p weaveffi --no-default-features), the strict rustdoc build,mdbook build docs, andcargo check -p weaveffi-fuzzNotes for reviewers
Result, so callback methods extracted from Rust arethrows any.{Code}Error.weaveffi devprints the library path undertarget/<profile>/deps/.check()throws, but a call made despite a mismatch still traps; the alternative would make every Swift callthrows.