Skip to content

feat!: C++ callback wrapper + v8.0.30 release (closes #482)#494

Merged
userFRM merged 2 commits into
mainfrom
feat/482e-cpp-callback
May 6, 2026
Merged

feat!: C++ callback wrapper + v8.0.30 release (closes #482)#494
userFRM merged 2 commits into
mainfrom
feat/482e-cpp-callback

Conversation

@userFRM
Copy link
Copy Markdown
Owner

@userFRM userFRM commented May 6, 2026

Summary

Final binding migration for #482. The C++ wrapper moves to the callback C ABI shipped in #490, the fpss_smoke example is restored on the callback path, and the [Unreleased] CHANGELOG block becomes the v8.0.30 release that bundles the entire #482 stack.

New C++ surface

sdks/cpp/include/thetadx.hpp, header-only on tdx::FpssClient:

void set_callback(std::function<void(const FpssEvent&)> fn);
void set_inline_callback(std::function<void(const FpssEvent&)> fn);
uint64_t dropped_events() const;  // already shipped in #490

set_callback wires tdx_fpss_set_callback (queued: dispatcher drain thread invokes fn, reader never blocks). set_inline_callback wires tdx_fpss_set_inline_callback (inline: fn fires on the FPSS reader thread, microsecond-budget contract). The client owns a unique_ptr<std::function<...>> so the address handed to the C ABI as ctx is stable across moves; a free extern "C" shim recovers the function from ctx and swallows any propagating exception so unwinding cannot cross the Rust/C boundary.

Release-note table — what v8.0.30 bundles

PR Layer What ships
#489 Rust core StreamingDispatcher + bounded crossbeam queue + start_streaming_inline
#490 C ABI tdx_*_set_callback / tdx_*_set_inline_callback; next_event / start_streaming removed
#492 Python (in flight) PyO3 callback API; next_event / next_event_typed removed
#493 TypeScript (in flight) NAPI callback API; nextEvent removed
this PR C++ wrapper tdx::FpssClient::set_callback / set_inline_callback; fpss_smoke example restored

Version bump

$ python3 scripts/check_version_sync.py
canonical version (Cargo.toml): 8.0.30
version sync: ok

scripts/bump_version.py 8.0.30 updated every Cargo.toml, every package.json, every optionalDependencies entry, and every Cargo.lock in lockstep.

Heads-up

[Unreleased] was promoted to ## [8.0.30] - 2026-05-06 on a state that includes only PR #489 + #490 in-tree. PR #492 (Python) and PR #493 (TypeScript) currently target the same [Unreleased] block; once they merge they will conflict on this CHANGELOG section. Per the staged plan they fold into the same v8.0.30 release notes — the merge order needs to be resolved by the maintainer.

Test plan

  • cargo fmt --all -- --check
  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo test --workspace
  • cargo deny check
  • cargo run -p thetadatadx --bin generate_sdk_surfaces --features config-file -- --check
  • cargo check / clippy / test --no-run on tools/mcp
  • cargo check --locked on tools/server, sdks/python, sdks/typescript
  • python3 scripts/check_version_sync.pyversion sync: ok
  • cmake -S sdks/cpp -B build/cpp && cmake --build build/cpp — every target (thetadatadx_cpp, thetadatadx_example, thetadatadx_validate, thetadatadx_fpss_smoke) builds clean
  • Live FPSS smoke run (requires creds; ./build/cpp/thetadatadx_fpss_smoke creds.txt)

Closes #482.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR completes the C++ binding migration for FPSS streaming onto the callback-based C ABI and cuts the v8.0.30 release by updating versions, changelogs, and the restored C++ fpss_smoke example.

Changes:

  • Adds C++ tdx::FpssClient callback registration (set_callback, set_inline_callback) and restores sdks/cpp/examples/fpss_smoke.cpp on the callback path.
  • Promotes [Unreleased] to the 8.0.30 release entry in both changelogs and updates C++ SDK docs accordingly.
  • Bumps versions to 8.0.30 across Rust crates/tools and Node packages (plus lockfiles) to keep the repo version-synchronized.

Reviewed changes

Copilot reviewed 16 out of 21 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tools/server/Cargo.toml Bump tool version to 8.0.30.
tools/server/Cargo.lock Lockfile updates reflecting 8.0.30 dependencies.
tools/mcp/Cargo.toml Bump tool version to 8.0.30.
tools/mcp/Cargo.lock Lockfile updates reflecting 8.0.30 dependencies.
tools/cli/Cargo.toml Bump CLI version to 8.0.30.
sdks/typescript/package.json Bump npm package + optionalDependencies versions to 8.0.30.
sdks/typescript/npm/win32-x64-msvc/package.json Bump platform package version to 8.0.30.
sdks/typescript/npm/linux-x64-gnu/package.json Bump platform package version to 8.0.30.
sdks/typescript/npm/darwin-arm64/package.json Bump platform package version to 8.0.30.
sdks/typescript/Cargo.toml Bump napi crate version to 8.0.30.
sdks/typescript/Cargo.lock Lockfile updates reflecting 8.0.30 dependencies.
sdks/python/Cargo.toml Bump PyO3 crate version to 8.0.30.
sdks/python/Cargo.lock Lockfile updates reflecting 8.0.30 dependencies.
sdks/cpp/README.md Update C++ streaming docs to callback-driven API + inline callback notes.
sdks/cpp/include/thetadx.hpp Implement callback registration wrappers and stable callback storage for C++ FPSS client.
sdks/cpp/examples/fpss_smoke.cpp Restore FPSS smoke example using queued callback API.
ffi/Cargo.toml Bump FFI crate version to 8.0.30.
docs-site/docs/changelog.md Promote Unreleased to 8.0.30 release entry on docs site.
crates/thetadatadx/Cargo.toml Bump core Rust crate version to 8.0.30.
CHANGELOG.md Promote Unreleased to 8.0.30 release entry in root changelog.
Cargo.lock Workspace lockfile updates reflecting 8.0.30 versions.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +368 to +374
void set_callback(std::function<void(const FpssEvent&)> fn) {
callback_ = std::make_unique<std::function<void(const FpssEvent&)>>(std::move(fn));
int rc = tdx_fpss_set_callback(handle_.get(), &FpssClient::callback_shim, callback_.get());
if (rc < 0) {
callback_.reset();
throw std::runtime_error("thetadatadx: " + detail::last_ffi_error());
}
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in a886f3a

Comment on lines +382 to +388
void set_inline_callback(std::function<void(const FpssEvent&)> fn) {
callback_ = std::make_unique<std::function<void(const FpssEvent&)>>(std::move(fn));
int rc = tdx_fpss_set_inline_callback(handle_.get(), &FpssClient::callback_shim, callback_.get());
if (rc < 0) {
callback_.reset();
throw std::runtime_error("thetadatadx: " + detail::last_ffi_error());
}
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in a886f3a

Comment thread sdks/cpp/include/thetadx.hpp Outdated
Comment on lines 358 to 362
handle_ = std::move(other.handle_);
callback_ = std::move(other.callback_);
return *this;
}

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in a886f3a

Comment thread CHANGELOG.md
Comment on lines +10 to +14
This release closes #482: the entire FPSS streaming stack — Rust core,
C ABI, Python, TypeScript, and C++ — moves to a callback-driven
delivery model backed by a single `StreamingDispatcher` SSOT. Bundles
PR #489 (dispatcher core), #490 (C ABI), #492 (Python), #493
(TypeScript), and #494 (C++ wrapper).
Comment on lines +10 to +14
This release closes #482: the entire FPSS streaming stack — Rust core,
C ABI, Python, TypeScript, and C++ — moves to a callback-driven
delivery model backed by a single `StreamingDispatcher` SSOT. Bundles
PR #489 (dispatcher core), #490 (C ABI), #492 (Python), #493
(TypeScript), and #494 (C++ wrapper).
userFRM added a commit that referenced this pull request May 6, 2026
…/ move-assign

set_callback / set_inline_callback now stage the new std::function into a
local unique_ptr and only adopt it into callback_ after tdx_fpss_set_callback
returns 0. The C ABI rejects subsequent registrations with -1 while keeping
the previously installed (callback, ctx) live, so overwriting callback_
before checking the return code dangled the Rust-side ctx into freed
storage.

operator=(FpssClient&&) now drains the existing handle via tdx_fpss_shutdown
before dropping the old callback_. tdx_fpss_shutdown stops the FPSS reader
and joins the dispatcher drain thread before returning, so once it
completes no thread can still observe the old ctx pointer.
userFRM added 2 commits May 6, 2026 15:56
Migrate the C++ wrapper to the callback C ABI shipped in PR #490.
`tdx::FpssClient` gains two header-only methods that wrap
`tdx_fpss_set_callback` / `tdx_fpss_set_inline_callback`:

    void set_callback(std::function<void(const FpssEvent&)> fn);
    void set_inline_callback(std::function<void(const FpssEvent&)> fn);

The Client owns a `unique_ptr<std::function<...>>` -- a stable
address survives moves of the owning client and is handed to the C
ABI as the `void* ctx`. A free `extern "C"` shim recovers the
function from `ctx` and invokes it with `const FpssEvent&`,
swallowing any propagating exception so unwinding cannot cross the
Rust/C boundary. The destructor's call to `tdx_fpss_shutdown` runs
before the function storage is freed, so the dispatcher / reader
threads cannot dereference stale state.

`fpss_smoke.cpp` is restored on the callback path -- `#error`
directive deleted, example rewritten to subscribe, register a
queued callback, print events for five seconds, and exit cleanly.
The CMake target builds clean.

`sdks/cpp/README.md` streaming section now documents callback
registration as the only entry point with a dedicated note on the
inline opt-in's microsecond-budget contract.

Version bump 8.0.29 -> 8.0.30 via `scripts/bump_version.py`. The
[Unreleased] CHANGELOG block becomes `## [8.0.30] - 2026-05-06` --
the single coherent #482 release that bundles the dispatcher core
(#489), C ABI callback (#490), and C++ wrapper migration. Python
(#492) and TypeScript (#493) entries land when those PRs merge.

Closes #482.
…/ move-assign

set_callback / set_inline_callback now stage the new std::function into a
local unique_ptr and only adopt it into callback_ after tdx_fpss_set_callback
returns 0. The C ABI rejects subsequent registrations with -1 while keeping
the previously installed (callback, ctx) live, so overwriting callback_
before checking the return code dangled the Rust-side ctx into freed
storage.

operator=(FpssClient&&) now drains the existing handle via tdx_fpss_shutdown
before dropping the old callback_. tdx_fpss_shutdown stops the FPSS reader
and joins the dispatcher drain thread before returning, so once it
completes no thread can still observe the old ctx pointer.
@userFRM userFRM force-pushed the feat/482e-cpp-callback branch from a886f3a to 74706c4 Compare May 6, 2026 13:57
@userFRM userFRM merged commit 8e2bc3e into main May 6, 2026
32 checks passed
@userFRM userFRM deleted the feat/482e-cpp-callback branch May 6, 2026 14:15
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.

Audit std::sync::mpsc on FFI streaming hot path

2 participants