mirror of
https://github.com/clockworklabs/SpacetimeDB.git
synced 2026-07-08 01:18:08 -04:00
1c1aea4abd
# Description of Changes
Adds a lifetime-aware `TableAccessor` trait to the Rust SDK and updates
Rust codegen to emit a generated accessor marker type for each table.
Generated bindings now include a marker type like:
```rust
pub struct PlayerPositionTableAccessor;
impl __sdk::TableAccessor<super::RemoteTables> for PlayerPositionTableAccessor {
type Row = PlayerPositionRow;
type Handle<'db> = PlayerPositionTableHandle<'db>;
fn get<'db>(db: &'db super::RemoteTables) -> Self::Handle<'db> {
db.player_position()
}
}
```
The existing generated table access methods remain unchanged:
```rust
fn player_position(&self) -> PlayerPositionTableHandle<'_>;
```
## Motivation
Generated table handles are lifetime-scoped to `RemoteTables`, which
makes it difficult for downstream crates to expose ergonomic generic
APIs over generated table accessors. In particular, a method like
`RemoteTables::player_position` returns a handle whose type depends on
the borrow lifetime of `RemoteTables`, which is hard to represent in
higher-order APIs.
The existing lifetime is not mechanically required by the current handle
storage model: generated table handles own an SDK `TableHandle<Row>`,
which holds shared connection/cache state rather than borrowing from
`RemoteTables`. However, the lifetime does express the conceptual scope
of a handle relative to the database view that produced it.
This PR preserves that scoped API contract instead of removing the
lifetime, and adds a generated marker type so generic downstream APIs
can name table accessors without erasing or weakening the lifetime
relationship.
This enables APIs such as the below instead of requiring closure-based
registration everywhere which greatly simplifies downstream crate code
and consumer code.
```diff
- .add_table::<PlayerPosition>(|reg, db| reg.bind(db.player_position()))
+ .add_table::<PlayerPositionTableAccessor>()
```
# API and ABI breaking changes
None.
This is additive and should not break existing generated bindings usage.
Existing code such as the below continues to work unchanged:
```rust
ctx.db.player_position().on_insert(...)
```
The new `TableAccessor` trait is exported from both the SDK root and
`__codegen`, and generated marker types are added alongside existing
generated table handles and access traits.
# Expected complexity level and risk
Complexity: **2/5**
The change is small and additive, but it touches Rust SDK codegen and
generated binding shape. The main risk is introducing generated code
that depends on the new SDK trait, so generated bindings and the SDK
version must match.
This does not alter table handle ownership, callback behavior, or
existing access methods.
# Testing
- [x] Ran `cargo check -p spacetimedb-sdk`.
- [x] Regenerated Rust bindings for my game.
- [x] Verified generated bindings include `*TableAccessor` marker types.
- [x] Used generated accessors from downstream local `bevy_stdb`.
- [x] Ran `cargo check -p bevy_stdb` against the local SDK.
---------
Signed-off-by: Jeff Rooks <onx2rj@gmail.com>
Co-authored-by: Phoebe Goldman <phoebe@goldman-tribe.org>
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>