Files
Jason Larabie 52b6c66fa1 Add C++ Bindings (#3544)
# Description of Changes

This adds C++ server bindings (/crate/bindings-cpp) to allow writing C++
20 modules.

- Emscripten WASM build system integration with CMake
- Macro-based code generation (SPACETIMEDB_TABLE, SPACETIMEDB_REDUCER,
etc)
- All SpacetimeDB types supported (primitives, Timestamp, Identity,
Uuid, etc)
- Product types via SPACETIMEDB_STRUCT
- Sum types via SPACETIMEDB_ENUM
- Constraints marked with FIELD* macros

# API and ABI breaking changes

None

# Expected complexity level and risk

2 - Doesn't heavily impact any other areas but is complex macro C++
structure to support a similar developer experience, did have a small
impact on init command

# Testing

- [x] modules/module-test-cpp - heavily tested every reducer
- [x] modules/benchmarks-cpp - tested through the standalone (~6x faster
than C#, ~6x slower than Rust)
- [x] modules/sdk-test-cpp
- [x] modules/sdk-test-procedure-cpp
- [x] modules/sdk-test-view-cpp  
- [x] Wrote several test modules myself
- [x] Quickstart smoketest [Currently in progress]
- [ ] Write Blackholio C++ server module

---------

Signed-off-by: Jason Larabie <jason@clockworklabs.io>
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
Co-authored-by: Ryan <r.ekhoff@clockworklabs.io>
Co-authored-by: John Detter <4099508+jdetter@users.noreply.github.com>
2026-02-07 04:26:45 +00:00

120 lines
3.6 KiB
C++

#ifndef REDUCER_CONTEXT_H
#define REDUCER_CONTEXT_H
#include <spacetimedb/bsatn/types.h> // For Identity, ConnectionId
#include <spacetimedb/bsatn/timestamp.h> // For Timestamp
#include <spacetimedb/bsatn/uuid.h> // For Uuid
#include <spacetimedb/random.h> // For StdbRng
#include <spacetimedb/auth_ctx.h> // For AuthCtx
#include <optional>
#include <array>
#include <memory>
// Include database for DatabaseContext
#include <spacetimedb/database.h>
namespace SpacetimeDB {
// Enhanced ReducerContext with database access - matches Rust pattern
struct ReducerContext {
// Core fields - directly accessible like in Rust
Identity sender;
std::optional<ConnectionId> connection_id;
Timestamp timestamp;
// Database context with name-based access
DatabaseContext db;
private:
// Authentication context with lazy JWT loading (private like in Rust)
AuthCtx sender_auth_;
// Lazily initialized RNG (similar to Rust's OnceCell pattern)
// Using shared_ptr to make ReducerContext copyable
mutable std::shared_ptr<StdbRng> rng_instance;
// Monotonic counter for UUID v7 generation (31 bits, wraps around)
mutable uint32_t counter_uuid_ = 0;
public:
// Returns the authorization information for the caller of this reducer
const AuthCtx& sender_auth() const {
return sender_auth_;
}
// Get the random number generator for this reducer call
// Lazily initialized and seeded with the timestamp
StdbRng& rng() const {
if (!rng_instance) {
rng_instance = std::make_unique<StdbRng>(timestamp);
}
return *rng_instance;
}
Identity identity() const {
std::array<uint8_t, 32> buffer;
::identity(buffer.data());
return Identity(buffer);
}
/**
* Generate a new random UUID v4.
*
* Creates a random UUID using the reducer's deterministic RNG.
*
* Example:
* @code
* SPACETIMEDB_REDUCER(void, create_session, ReducerContext ctx) {
* Uuid session_id = ctx.new_uuid_v4();
* ctx.db[sessions].insert(Session{session_id});
* }
* @endcode
*
* @return A new UUID v4
*/
Uuid new_uuid_v4() const {
// Get 16 random bytes from the context RNG
std::array<uint8_t, 16> random_bytes;
rng().fill_bytes(random_bytes.data(), 16);
// Generate UUID v4
return Uuid::from_random_bytes_v4(random_bytes);
}
/**
* Generate a new UUID v7.
*
* Creates a time-ordered UUID with the reducer's timestamp, a monotonic counter,
* and random bytes from the reducer's deterministic RNG.
*
* Example:
* @code
* SPACETIMEDB_REDUCER(void, create_user, ReducerContext ctx, std::string name) {
* Uuid user_id = ctx.new_uuid_v7();
* ctx.db[users].insert(User{user_id, name});
* }
* @endcode
*
* @return A new UUID v7
*/
Uuid new_uuid_v7() const {
// Get 4 random bytes from the context RNG
std::array<uint8_t, 4> random_bytes;
rng().fill_bytes(random_bytes.data(), 4);
// Generate UUID v7 with timestamp and counter
return Uuid::from_counter_v7(counter_uuid_, timestamp, random_bytes);
}
// Constructors
ReducerContext() : sender_auth_(AuthCtx::internal()) {}
ReducerContext(Identity s, std::optional<ConnectionId> cid, Timestamp ts)
: sender(s), connection_id(cid), timestamp(ts),
sender_auth_(AuthCtx::from_connection_id_opt(cid, s)) {}
};
} // namespace SpacetimeDB
#endif // REDUCER_CONTEXT_H