mirror of
https://github.com/clockworklabs/SpacetimeDB.git
synced 2026-05-11 02:00:04 -04:00
52b6c66fa1
# 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>
164 lines
4.6 KiB
C++
164 lines
4.6 KiB
C++
#ifndef SPACETIMEDB_REDUCER_ERROR_H
|
|
#define SPACETIMEDB_REDUCER_ERROR_H
|
|
|
|
#include "spacetimedb/outcome.h"
|
|
#include <string>
|
|
#include <optional>
|
|
|
|
/**
|
|
* @file reducer_error.h
|
|
* @brief Graceful error handling for reducers using Outcome<T> pattern
|
|
*
|
|
* This module provides reducer-specific error handling utilities using the Outcome type.
|
|
* For the general Outcome<T> type definition, see outcome.h.
|
|
*
|
|
* Modern usage (recommended):
|
|
* @code
|
|
* SPACETIMEDB_REDUCER(my_reducer, ReducerContext ctx, uint32_t id) {
|
|
* if (id == 0) {
|
|
* return Err("ID must be non-zero");
|
|
* }
|
|
* // ... rest of logic
|
|
* return Ok();
|
|
* }
|
|
* @endcode
|
|
*
|
|
* Legacy usage (still supported):
|
|
* @code
|
|
* SPACETIMEDB_REDUCER(my_reducer, ReducerContext ctx, uint32_t id) {
|
|
* if (id == 0) {
|
|
* fail_reducer("ID must be non-zero");
|
|
* return Ok(); // Or just return;
|
|
* }
|
|
* // ... rest of logic
|
|
* return Ok();
|
|
* }
|
|
* @endcode
|
|
*
|
|
* When a reducer returns Err():
|
|
* - The transaction is rolled back (not committed to the log)
|
|
* - The error message is captured and returned to the caller
|
|
* - No database changes are persisted
|
|
* - No WASM crash or panic occurs
|
|
*
|
|
* @ingroup sdk_runtime
|
|
*/
|
|
|
|
namespace SpacetimeDB {
|
|
|
|
/**
|
|
* @brief Type alias for reducer return type, matching Rust's ReducerResult
|
|
*
|
|
* Reducers use Outcome<void> for their return type. The Ok() and Err() helper
|
|
* functions from outcome.h can be used directly:
|
|
*
|
|
* @code
|
|
* SPACETIMEDB_REDUCER(my_reducer, ReducerContext ctx, uint32_t id) {
|
|
* if (id == 0) {
|
|
* return Err("ID must be non-zero");
|
|
* }
|
|
* // ... rest of logic
|
|
* return Ok();
|
|
* }
|
|
* @endcode
|
|
*/
|
|
using ReducerResult = Outcome<void>;
|
|
|
|
namespace Internal {
|
|
/**
|
|
* Thread-local error state for the current reducer invocation.
|
|
* This is cleared at the start of each reducer call and checked at the end.
|
|
*/
|
|
extern thread_local std::optional<std::string> g_reducer_error_message;
|
|
|
|
/**
|
|
* Clear the error state. Called automatically at the start of each reducer.
|
|
* @internal
|
|
*/
|
|
inline void clear_reducer_error() {
|
|
g_reducer_error_message = std::nullopt;
|
|
}
|
|
|
|
/**
|
|
* Check if the current reducer has failed.
|
|
* @internal
|
|
*/
|
|
inline bool has_reducer_error() {
|
|
return g_reducer_error_message.has_value();
|
|
}
|
|
|
|
/**
|
|
* Get the error message if one exists.
|
|
* @internal
|
|
*/
|
|
inline std::string get_reducer_error() {
|
|
return g_reducer_error_message.value_or(std::string());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Fail the current reducer with an error message.
|
|
*
|
|
* This function marks the current reducer invocation as failed.
|
|
* The transaction will be rolled back and the error message will be
|
|
* returned to the caller. Failed transactions are NOT committed to the
|
|
* log and will not appear in temporal queries or transaction history.
|
|
*
|
|
* After calling this function, the reducer should return immediately
|
|
* to avoid executing additional logic on inconsistent state.
|
|
*
|
|
* @param message A descriptive error message explaining why the reducer failed
|
|
*
|
|
* @code
|
|
* if (amount <= 0) {
|
|
* SpacetimeDB::fail_reducer("Amount must be positive");
|
|
* return Ok(); // Or just return;
|
|
* }
|
|
*
|
|
* // Alternative using Outcome pattern:
|
|
* if (amount <= 0) {
|
|
* return Err("Amount must be positive");
|
|
* }
|
|
* @endcode
|
|
*
|
|
* @note This is thread-safe and works in WASM single-threaded environments.
|
|
* @note This does NOT throw exceptions or cause panics.
|
|
*/
|
|
inline void fail_reducer(std::string message) {
|
|
Internal::g_reducer_error_message = std::move(message);
|
|
}
|
|
|
|
/**
|
|
* @brief Fail the current reducer with a formatted error message.
|
|
*
|
|
* Convenience function for creating formatted error messages.
|
|
*
|
|
* @tparam Args Variadic template arguments for formatting
|
|
* @param format Printf-style format string
|
|
* @param args Arguments to format into the message
|
|
*
|
|
* @code
|
|
* fail_reducer_fmt("Tracker %u not found", tracker_id);
|
|
* fail_reducer_fmt("Invalid coordinates (%.2f, %.2f)", lat, lon);
|
|
* @endcode
|
|
*/
|
|
template<typename... Args>
|
|
inline void fail_reducer_fmt(const char* format, Args... args) {
|
|
// Get required size
|
|
int size = std::snprintf(nullptr, 0, format, args...);
|
|
if (size <= 0) {
|
|
fail_reducer("Error formatting failure message");
|
|
return;
|
|
}
|
|
|
|
// Format string
|
|
std::string result(size + 1, '\0');
|
|
std::snprintf(result.data(), result.size(), format, args...);
|
|
result.resize(size); // Remove null terminator
|
|
|
|
fail_reducer(std::move(result));
|
|
}
|
|
|
|
} // namespace SpacetimeDB
|
|
|
|
#endif // SPACETIMEDB_REDUCER_ERROR_H
|