Commit 33c6a9f
authored
fix(codegen): construct private-field core types via Default-seeded builder (#160)
* fix(codegen): construct private-field core types via Default-seeded builder
Core structs with private (`pub(crate)`) fields cannot be built with struct-literal
syntax from a foreign crate — neither by naming the private field (E0451) nor by
patching it with `..Default::default()`. The generated binding->core `From` impls for
such types failed to compile against cores that moved internal fields behind
`pub(crate)` (e.g. extraction/OCR result types whose `internal_document` fields became
private).
Record a `has_private_fields` flag on struct IR during extraction, and centralize the
construction strategy in a shared helper (`conversions::construction`): seed the core
type's `Default` — built inside the defining crate, so it fills the private fields —
and assign only the public fields onto it. When the core type has private fields but
no `Default`, emit a `compile_error!` guiding the author to derive it. The helper is
used by the shared pyo3/napi/wasm/extendr/rustler/magnus generator and the Dart
mirror-crate generator, so every backend that builds core structs stays in lockstep.
Also repair two pyo3 trait-bridge regressions surfaced by the same core migration:
- Marshal owned (by-value) native-struct callback params into the host's native object
via `From<core::T>`, as borrowed params already were. A trait method taking a serde
struct by value (e.g. a URI-based extraction-input envelope) passed the raw `core::T`
across the Python boundary, which has no `IntoPyObject` and failed to compile.
- When a core `register_*` free function shares its name with a trait bridge's
`register_fn`, emit only the bridge's duck-typed registration. The function loop also
emitted the auto-wrapped core version, which collided (E0428) and no longer
type-checks against a registry that takes `Arc<dyn Trait>`.
Adds extractor and conversion-strategy unit tests; existing snapshots are unchanged
since no neutral fixture has private fields.
* fix(php): construct private-field core types and marshal owned bridge params
Extends the private-field construction fix to PHP's ext-php-rs paths, the last
backend still failing against the migrated core:
- The enum-tainted `From<Binding>` emitter (`gen_enum_tainted_from_binding_to_core`)
collected its conversions into a struct literal, which cannot build a core type with
private fields. It now collects `(field, expr)` pairs and delegates to the shared
`conversions::construction` helper — the same `Default`-seeded builder / `compile_error!`
strategy the other backends use — for private-field types, keeping the struct literal for
fully-public types.
- Owned (by-value) native-struct callback params were dereferenced as if borrowed
(`{Class}::from((*input).clone())`), which does not type-check on an owned `core::T`
(`E0614`). Owned params now construct from the value directly.
- The native-object return fast-path emitted `<Binding as FromZval>::from_zval(&val)`, but a
PHP `#[php_class]` binding struct implements `FromZvalMut` (for `&mut T`), not `FromZval`
(for `T`). The bridge now keeps the JSON/string return path for every type — the
well-defined path for PHP — rather than a native fast-path that cannot compile.
All seven generated binding crates (py/node/wasm/dart/ffi/swift/php) now compile against
xberg 1.0.0-rc.1.
* perf(trait-bridge): move owned native-struct params instead of cloning
The bridge marshalling cloned the owned core value when handing it to the host
(`T::from(owned.clone())`). The param — e.g. a by-value `ExtractInput` envelope carrying
document bytes — is consumed exactly once, so it is moved in instead. Borrowed params still
clone out of the `&`, which is unavoidable. Applies to the pyo3 (sync + async) and PHP
bridge generators.
* fix(pyo3): serialize dict/list JSON config fields in api.py converters
PyO3 cannot expose a settable serde_json::Value field (unlike NAPI's json_as_value), so
JSON config fields are stored as String in the binding while the public dataclass and .pyi
stub type them as dict[str, Any]. The generated api.py converter forwarded the dict straight
to _rust, raising 'TypeError: dict is not str' at runtime. Serialize a dict/list via
json.dumps in the converter; pass str/None through unchanged.
* fix(pyo3): enlarge async-runtime worker stack to prevent deep-future SIGBUS
pyo3-async-runtimes' default multi-thread runtime gives worker threads a small (~2 MB)
stack. A deep consumer future — e.g. a multi-stage PDF/OCR pipeline — overflows it and the
process aborts with SIGBUS (EXC_BAD_ACCESS, KERN_PROTECTION_FAILURE on the worker stack
guard page). The generated #[pymodule] init now installs a tokio runtime with a 16 MB
thread_stack_size via pyo3_async_runtimes::tokio::init before the first future_into_py.
Reproduced and verified fixed against a real consumer: an image-only PDF + tesseract OCR
aborted with exit 138 before, runs to completion after.
* fix(napi): enlarge streaming WORKER_POOL worker stack to prevent deep-future SIGBUS
Mirrors the pyo3 worker-stack fix for node: the generated streaming WORKER_POOL tokio
runtime used the default (~2 MB) worker stack, which a deep consumer future (e.g. an OCR
pipeline) overflows, aborting the process with SIGBUS. Build it with a 16 MB thread_stack_size.1 parent e31b5f1 commit 33c6a9f
87 files changed
Lines changed: 882 additions & 226 deletions
File tree
- src
- backends
- csharp
- gen_bindings/types
- trait_bridge
- dart
- gen_bindings
- service_api
- gen_rust_crate
- trait_bridge
- extendr/gen_bindings
- tests
- ffi
- gen_bindings/tests
- trait_bridge
- tests
- go
- gen_bindings
- methods
- types
- trait_bridge
- java
- gen_bindings
- trait_bridge
- types
- gen_visitor
- kotlin_android
- kotlin/gen_bindings
- magnus/gen_bindings
- classes
- napi
- gen_bindings
- functions
- php
- gen_bindings/helpers
- trait_bridge
- pyo3
- gen_bindings
- functions
- templates/trait_bridge
- trait_bridge
- rustler/gen_bindings
- swift
- gen_bindings
- gen_rust_crate/wrappers
- wasm/gen_bindings/functions
- zig/trait_bridge
- cli/pipeline/extract
- codegen
- config_gen
- tests
- conversions
- binding_to_core
- generators
- trait_bridge
- tests
- templates/conversions
- core/ir
- docs/tests
- e2e/codegen
- csharp
- kotlin
- typescript/test_file
- extract
- extractor
- functions
- tests
- reexports
- scaffold/tests
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
28 | 28 | | |
29 | 29 | | |
30 | 30 | | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
31 | 66 | | |
32 | 67 | | |
33 | 68 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
49 | 49 | | |
50 | 50 | | |
51 | 51 | | |
| 52 | + | |
52 | 53 | | |
53 | 54 | | |
54 | 55 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
662 | 662 | | |
663 | 663 | | |
664 | 664 | | |
| 665 | + | |
665 | 666 | | |
666 | 667 | | |
667 | 668 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
23 | 23 | | |
24 | 24 | | |
25 | 25 | | |
| 26 | + | |
26 | 27 | | |
27 | 28 | | |
28 | 29 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
342 | 342 | | |
343 | 343 | | |
344 | 344 | | |
| 345 | + | |
345 | 346 | | |
346 | 347 | | |
347 | 348 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
276 | 276 | | |
277 | 277 | | |
278 | 278 | | |
| 279 | + | |
279 | 280 | | |
280 | 281 | | |
281 | 282 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
465 | 465 | | |
466 | 466 | | |
467 | 467 | | |
| 468 | + | |
| 469 | + | |
| 470 | + | |
| 471 | + | |
| 472 | + | |
| 473 | + | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
| 478 | + | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
| 494 | + | |
| 495 | + | |
| 496 | + | |
| 497 | + | |
| 498 | + | |
| 499 | + | |
| 500 | + | |
| 501 | + | |
468 | 502 | | |
469 | 503 | | |
470 | 504 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
| 28 | + | |
28 | 29 | | |
29 | 30 | | |
30 | 31 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
75 | 75 | | |
76 | 76 | | |
77 | 77 | | |
| 78 | + | |
78 | 79 | | |
79 | 80 | | |
80 | 81 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
162 | 162 | | |
163 | 163 | | |
164 | 164 | | |
| 165 | + | |
165 | 166 | | |
166 | 167 | | |
167 | 168 | | |
| |||
300 | 301 | | |
301 | 302 | | |
302 | 303 | | |
| 304 | + | |
303 | 305 | | |
304 | 306 | | |
305 | 307 | | |
| |||
389 | 391 | | |
390 | 392 | | |
391 | 393 | | |
| 394 | + | |
392 | 395 | | |
393 | 396 | | |
394 | 397 | | |
| |||
0 commit comments