mirror of
https://github.com/clockworklabs/SpacetimeDB.git
synced 2026-07-25 11:32:30 -04:00
14f79910ee
# Description of Changes
- Migrated the C++ module-definition assembly path to V10-first
internals:
- Added v10_builder and module_type_registration systems.
- Switched Module::__describe_module__ to serialize RawModuleDef with
V10 payload.
- Updated macro registration pipeline to register through V10
- Added explicit naming support across macro surface (*_NAMED variants
for reducer/procedure/
view and field/index macros).
- Reworked multi-column index macros (FIELD_MultiColumnIndex,
FIELD_MultiColumnIndex_NAMED) with
migration alias.
- Added SPACETIMEDB_SETTING_CASE_CONVERSION(...) to support case
conversion policy
- Error-path hardening by adding explicit constraint-registration error
tracking and preinit validation
- Codegen updates:
- Updated C++ moduledef regen to V10 builder types.
- Adjusted C++ codegen duplicate-variant wrapper generation to emit
proper product-type
wrappers.
- Test/harness updates:
- type-isolation-test runner now defaults to focused V10 regression
checks; --v9 runs broader
legacy/full suite.
- Added focused modules for positive/negative V10 checks:
- test_multicolumn_index_valid
- error_multicolumn_missing_field
- error_default_missing_field
- Re-enabled C++ paths in sdks/rust/tests/test.rs procedure/view/test
suites.
# API and ABI breaking changes
- Refactor of the underlying module definition
- New *_NAMED variant macros for explicit canonical naming
- FIELD_NamedMultiColumnIndex renamed to FIELD_MultiColumnIndex
# Expected complexity level and risk
3 - Large set of changes moving over to V10 with underlying changes to
make future updates a little easier
# Testing
- [x] Ran the type isolation test and expanded it
- [x] Ran the spacetimedb-sdk test framework to confirm no more drift
between C++ and other module languages
- [x] Ran Unreal test suite though not really applicable
- [x] New app creation with `spacetime init --template basic-cpp`
- [x] Ran describe module tests against Rust + C# matching with C++ on
the /modules/sdk-test* modules to find any possible mis-alignment
# Review
- [x] Another look at the new features with C++
- [x] Thoughts on *_NAMED macros, I couldn't come up with a better
solution with C++20
124 lines
4.9 KiB
C++
124 lines
4.9 KiB
C++
#pragma once
|
|
|
|
#include "spacetimedb/procedure_context.h"
|
|
#include "spacetimedb/internal/Module.h"
|
|
#include "spacetimedb/internal/v10_builder.h"
|
|
#include "spacetimedb/macros.h" // For CONCAT
|
|
#include "spacetimedb/error_handling.h"
|
|
#include <string>
|
|
#include <vector>
|
|
#include <type_traits>
|
|
|
|
namespace SpacetimeDB {
|
|
namespace Internal {
|
|
|
|
/**
|
|
* @brief Type trait to validate procedure return types
|
|
*
|
|
* Procedures can return any SpacetimeType, unlike views which are restricted
|
|
* to std::vector<T> or std::optional<T>. This includes primitives, structs,
|
|
* enums, or any custom type that implements the SpacetimeType concept.
|
|
*
|
|
*/
|
|
template<typename T>
|
|
struct is_valid_procedure_return_type : std::integral_constant<bool, bsatn::Serializable<T>> {};
|
|
|
|
} // namespace Internal
|
|
} // namespace SpacetimeDB
|
|
|
|
/**
|
|
* @brief Macro for defining SpacetimeDB procedures
|
|
*
|
|
* Procedures are functions that can return arbitrary values (unlike reducers which return void).
|
|
* They are always public (no access control like reducers).
|
|
*
|
|
* Features:
|
|
* - Pure computations with return values
|
|
* - Database access via explicit transactions (ctx.WithTx() or ctx.TryWithTx())
|
|
* - HTTP requests via ctx.http (when SPACETIMEDB_UNSTABLE_FEATURES enabled)
|
|
* - UUID generation (ctx.new_uuid_v4(), ctx.new_uuid_v7())
|
|
* - Return type directly
|
|
*
|
|
* Key differences from reducers:
|
|
* - NO direct db field (must use ctx.WithTx() for database operations)
|
|
* - Has connection_id (procedures track which connection called them)
|
|
* - Can return any SpacetimeType
|
|
*
|
|
* @param return_type The return type - can be any SpacetimeType (primitive, struct, enum, etc.)
|
|
* @param procedure_name The name of the procedure function
|
|
* @param ctx_param Must be ProcedureContext ctx
|
|
* @param ... Additional parameters (optional) - any SpacetimeType
|
|
*
|
|
* Examples:
|
|
* @code
|
|
* // Pure computation
|
|
* SPACETIMEDB_PROCEDURE(uint32_t, add_numbers, ProcedureContext ctx, uint32_t a, uint32_t b) {
|
|
* return a + b;
|
|
* }
|
|
*
|
|
* // With database transaction
|
|
* SPACETIMEDB_PROCEDURE(Unit, insert_item, ProcedureContext ctx, Item item) {
|
|
* ctx.WithTx([&item](TxContext& tx) {
|
|
* tx.db[items].insert(item);
|
|
* });
|
|
* return Unit{};
|
|
* }
|
|
*
|
|
* // Return struct
|
|
* struct ReturnStruct {
|
|
* uint32_t a;
|
|
* std::string b;
|
|
* };
|
|
* SPACETIMEDB_STRUCT(ReturnStruct, a, b)
|
|
*
|
|
* SPACETIMEDB_PROCEDURE(ReturnStruct, make_struct, ProcedureContext ctx, uint32_t a, std::string b) {
|
|
* return ReturnStruct{a, b};
|
|
* }
|
|
*
|
|
* // UUID generation
|
|
* SPACETIMEDB_PROCEDURE(Uuid, generate_uuid, ProcedureContext ctx) {
|
|
* return ctx.new_uuid_v7();
|
|
* }
|
|
* @endcode
|
|
*/
|
|
#define SPACETIMEDB_PROCEDURE(return_type, procedure_name, ctx_param, ...) \
|
|
/* Validate return type at compile-time */ \
|
|
static_assert(::SpacetimeDB::Internal::is_valid_procedure_return_type<return_type>::value, \
|
|
"Procedure return type must be a SpacetimeType (implement Serializable trait)"); \
|
|
\
|
|
/* Forward declaration with optional parameters */ \
|
|
return_type procedure_name(ctx_param __VA_OPT__(,) __VA_ARGS__); \
|
|
\
|
|
/* Preinit registration function */ \
|
|
/* Procedures run at priority 50 to ensure views are registered first */ \
|
|
__attribute__((export_name("__preinit__50_proc_" #procedure_name))) \
|
|
extern "C" void CONCAT(_spacetimedb_preinit_register_proc_, procedure_name)() { \
|
|
/* Parse parameter names from the stringified parameter list */ \
|
|
std::string param_list = #__VA_ARGS__; \
|
|
std::vector<std::string> param_names = \
|
|
SpacetimeDB::Internal::parseParameterNames(param_list); \
|
|
\
|
|
/* Register the procedure with the V10Builder system */ \
|
|
/* Note: Procedures are always public (no is_public parameter) */ \
|
|
::SpacetimeDB::Internal::getV10Builder().RegisterProcedure( \
|
|
#procedure_name, procedure_name, param_names); \
|
|
} \
|
|
\
|
|
/* The actual procedure function definition */ \
|
|
return_type procedure_name(ctx_param __VA_OPT__(,) __VA_ARGS__)
|
|
|
|
#define SPACETIMEDB_PROCEDURE_NAMED(return_type, procedure_name, canonical_name, ctx_param, ...) \
|
|
static_assert(::SpacetimeDB::Internal::is_valid_procedure_return_type<return_type>::value, \
|
|
"Procedure return type must be a SpacetimeType (implement Serializable trait)"); \
|
|
return_type procedure_name(ctx_param __VA_OPT__(,) __VA_ARGS__); \
|
|
__attribute__((export_name("__preinit__50_proc_" #procedure_name))) \
|
|
extern "C" void CONCAT(_spacetimedb_preinit_register_proc_, procedure_name)() { \
|
|
std::string param_list = #__VA_ARGS__; \
|
|
std::vector<std::string> param_names = \
|
|
SpacetimeDB::Internal::parseParameterNames(param_list); \
|
|
::SpacetimeDB::Internal::getV10Builder().RegisterProcedure( \
|
|
#procedure_name, procedure_name, param_names); \
|
|
SpacetimeDB::Module::RegisterExplicitFunctionName(#procedure_name, canonical_name); \
|
|
} \
|
|
return_type procedure_name(ctx_param __VA_OPT__(,) __VA_ARGS__)
|