Skip to content

feat(truapi-codegen): emit Rust dispatcher, wire table, and host callbacks#254

Open
pgherveou wants to merge 1 commit into
rust-core/02-platform-traitsfrom
rust-core/04-codegen
Open

feat(truapi-codegen): emit Rust dispatcher, wire table, and host callbacks#254
pgherveou wants to merge 1 commit into
rust-core/02-platform-traitsfrom
rust-core/04-codegen

Conversation

@pgherveou

@pgherveou pgherveou commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

Extends the rustdoc-JSON code generator to emit the Rust dispatcher and wire table consumed by truapi-server, plus the TS host-callbacks adapter. Golden tests pin the emitted shapes.

This replaces #251 after reordering the stack so the codegen layer can be reviewed and merged before the server runtime layer.


Stack

Part of the Rust core runtime port (umbrella: #104), split into a reviewable stack. Merge bottom-up.

  1. feat(truapi): add testing API and versioned wiring #248 — truapi: testing API + versioned wiring
  2. feat(truapi-platform): add host capability traits #249 — truapi-platform: host capability traits
  3. feat(truapi-codegen): emit Rust dispatcher, wire table, and host callbacks #254 — truapi-codegen: Rust dispatcher + wire table 👈
  4. feat(truapi-server): add host logic primitives #255 — truapi-server: host logic primitives
  5. feat(truapi-server): add wire and chain infrastructure #256 — truapi-server: wire and chain infrastructure
  6. feat(truapi-server): add platform runtime and host bridge #250 — truapi-server: platform runtime and host bridge
  7. feat(host-wasm): add @parity/truapi-host-wasm runtime #252 — host-wasm: @parity/truapi-host-wasm runtime
  8. chore: docs, CI, tooling, and dotli integration for the Rust core #253 — docs, CI, tooling, dotli integration

@socket-security

socket-security Bot commented Jul 1, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedcargo/​tempfile@​3.27.09810093100100

View full report

…backs

Extends the rustdoc-JSON code generator to emit the Rust dispatcher and wire
table consumed by truapi-server, plus the TS host-callbacks adapter. Golden
tests pin the emitted shapes.
@pgherveou pgherveou force-pushed the rust-core/04-codegen branch from 8ad3cf9 to 8ddbe78 Compare July 1, 2026 21:23
@pgherveou pgherveou force-pushed the rust-core/02-platform-traits branch from 0a7b831 to d2454f8 Compare July 1, 2026 21:23
method.params.len()
),
};

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.

Suggested change
if matches!(method.kind, MethodKind::Subscription | MethodKind::ResultSubscription)
&& matches!(request_payload, Some(WirePayload::Raw(_)))
{
bail!(
"Method `{}`: subscription request parameters must be versioned wrappers \
(got a non-versioned type); the dispatcher cannot decode a raw subscription request",
method.name
);
}

Might be worth having this kind of guard.

let fn_name = format!("register_{module}");
let trait_name = &trait_def.name;
let mut code = String::new();
if trait_name == "Testing" {

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.

I am seeing a lot of checks for trait_name == "Testing", it might be worth having a single helper for this to make sure it never drifts etc.

/// Walk the platform crate and extract every public trait + its methods.
pub fn extract(krate: &Crate) -> Result<PlatformDefinition> {
let trait_ids = collect_local_trait_ids(krate);
let names = NameContext::default();

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.

Is an empty NameContext here intentional?

let Some(name) = item_path.path.last() else {
continue;
};
if !referenced.contains(name) || extracted.contains(name) {

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.

Suggested change
if !referenced.contains(name) || extracted.contains(name) {
if !referenced.contains(name) {
continue;
}
if let Some(existing_module) = extracted.get(name) {
if existing_module != &item_path.path[..item_path.path.len() - 1] {
bail!(
"platform type name `{name}` is ambiguous: defined in both \
`{}` and `{}`",
existing_module.join("::"),
item_path.path[..item_path.path.len() - 1].join("::"),
);
}
continue; // same type already extracted — normal dedup
}

Could be a better guard as well.

Some(response) => {
let target_version_expr = target_version_expr
.as_deref()
.expect("versioned responses require a target version");

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.

Suggested change
.expect("versioned responses require a target version");
.ok_or_else(|| anyhow::anyhow!(
"Method `{}`: versioned response with a non-versioned (raw) request \
has no target version to encode against", self.name))?

Might be better swapping the panics with a bail!

)
.unwrap();
if is_result_sub {
let _ = error.expect("result subscription methods must have an error wrapper");

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.

Suggested change
let _ = error.expect("result subscription methods must have an error wrapper");
let error = error.ok_or_else(|| anyhow::anyhow!(
"Method `{}`: result-subscription error type must be a versioned wrapper", self.name))?;

Same panic vs bail here.

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.

2 participants