diff --git a/crates/cli/src/subcommands/generate/rust.rs b/crates/cli/src/subcommands/generate/rust.rs index 4a8bfb5c8b..158a5bfce6 100644 --- a/crates/cli/src/subcommands/generate/rust.rs +++ b/crates/cli/src/subcommands/generate/rust.rs @@ -636,7 +636,7 @@ pub fn autogen_rust_reducer(ctx: &GenCtx, reducer: &ReducerDef) -> String { writeln!(out, "{}", ALLOW_UNUSED).unwrap(); write!( out, - "pub fn on_{}(mut __callback: impl FnMut(&Identity, Status", + "pub fn on_{}(mut __callback: impl FnMut(&Identity, &Status", func_name ) .unwrap(); @@ -679,7 +679,7 @@ pub fn autogen_rust_reducer(ctx: &GenCtx, reducer: &ReducerDef) -> String { writeln!(out, "{}", ALLOW_UNUSED).unwrap(); write!( out, - "pub fn once_on_{}(__callback: impl FnOnce(&Identity, Status", + "pub fn once_on_{}(__callback: impl FnOnce(&Identity, &Status", func_name ) .unwrap(); diff --git a/crates/sdk/src/callbacks.rs b/crates/sdk/src/callbacks.rs index 31a44c3693..d0ca57089a 100644 --- a/crates/sdk/src/callbacks.rs +++ b/crates/sdk/src/callbacks.rs @@ -136,8 +136,7 @@ impl std::fmt::Debug for CallbackId { // - `Credentials` -> `&Credentials`, for `on_connect`. // - `()` -> `()`, for `on_subscription_applied`. // - `(T, T, U)` -> `(&T, &T, U)`, for `TableWithPrimaryKey::on_update`. -// - `(Identity, Status, R)` -> `(&Identity, Status, &R)`, for `Reducer::on_reducer`. -// Note that `Status` is `Copy`. +// - `(Identity, Status, R)` -> `(&Identity, &Status, &R)`, for `Reducer::on_reducer`. impl OwnedArgs for Credentials { type Borrowed<'a> = &'a Credentials; @@ -182,9 +181,9 @@ impl OwnedArgs for (Identity, Status, R) where R: Send + 'static, { - type Borrowed<'a> = (&'a Identity, Status, &'a R); - fn borrow(&self) -> (&Identity, Status, &R) { - (&self.0, self.1, &self.2) + type Borrowed<'a> = (&'a Identity, &'a Status, &'a R); + fn borrow(&self) -> (&Identity, &Status, &R) { + (&self.0, &self.1, &self.2) } } @@ -450,8 +449,8 @@ fn uncurry_update_callback( /// /// This function is intended specifically for `Reducer::on_reducer` callbacks. fn uncurry_reducer_callback( - mut f: impl for<'a> FnMut(&'a Identity, Status, &'a R) + Send + 'static, -) -> impl for<'a> FnMut((&'a Identity, Status, &'a R)) + Send + 'static { + mut f: impl for<'a> FnMut(&'a Identity, &'a Status, &'a R) + Send + 'static, +) -> impl for<'a> FnMut((&'a Identity, &'a Status, &'a R)) + Send + 'static { move |(identity, status, reducer)| f(identity, status, reducer) } @@ -659,12 +658,14 @@ pub struct ReducerCallbacks { // which we must then compare against the enum variants. // This helper function does that comparison. -fn parse_status(status: i32) -> Option { +fn parse_status(status: i32, message: String) -> Option { if status == client_api_messages::event::Status::Committed as i32 { + debug_assert!(message.is_empty()); Some(Status::Committed) } else if status == client_api_messages::event::Status::Failed as i32 { - Some(Status::Failed) + Some(Status::Failed(message)) } else if status == client_api_messages::event::Status::OutOfEnergy as i32 { + debug_assert!(message.is_empty()); Some(Status::OutOfEnergy) } else { None @@ -707,13 +708,14 @@ impl ReducerCallbacks { caller_identity, function_call: Some(function_call), status, + message, .. } = event else { log::warn!("Received Event with function_call of None"); return None; }; let identity = Identity { bytes: caller_identity }; - let Some(status) = parse_status(status) else { + let Some(status) = parse_status(status, message) else { log::warn!("Received Event with unknown status {:?}", status); return None; }; @@ -736,7 +738,7 @@ impl ReducerCallbacks { // TODO: reduce monomorphization by accepting `Box` instead of `impl Callback` pub(crate) fn register_on_reducer( &mut self, - callback: impl FnMut(&Identity, Status, &R) + Send + 'static, + callback: impl FnMut(&Identity, &Status, &R) + Send + 'static, ) -> CallbackId<(Identity, Status, R)> { self.find_callbacks::() .insert(Box::new(uncurry_reducer_callback(callback))) @@ -750,7 +752,7 @@ impl ReducerCallbacks { // since [`CallbackMap::insert_oneshot`] boxes its wrapper callback. pub(crate) fn register_on_reducer_oneshot( &mut self, - callback: impl FnOnce(&Identity, Status, &R) + Send + 'static, + callback: impl FnOnce(&Identity, &Status, &R) + Send + 'static, ) -> CallbackId<(Identity, Status, R)> { self.find_callbacks::() .insert_oneshot(move |(identity, status, args)| callback(identity, status, args)) diff --git a/crates/sdk/src/reducer.rs b/crates/sdk/src/reducer.rs index 62f374052e..4457cc34d3 100644 --- a/crates/sdk/src/reducer.rs +++ b/crates/sdk/src/reducer.rs @@ -5,10 +5,10 @@ use anyhow::Result; use spacetimedb_sats::{de::DeserializeOwned, ser::Serialize}; use std::any::Any; -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, PartialEq, Eq, Hash, Debug)] pub enum Status { Committed, - Failed, + Failed(String), OutOfEnergy, } @@ -39,7 +39,7 @@ pub trait Reducer: DeserializeOwned + Serialize + Any + Send + Sync + Clone { // /// The returned `ReducerCallbackId` can be passed to `remove_on_reducer` to /// unregister the callback. - fn on_reducer(callback: impl FnMut(&Identity, Status, &Self) + Send + 'static) -> ReducerCallbackId { + fn on_reducer(callback: impl FnMut(&Identity, &Status, &Self) + Send + 'static) -> ReducerCallbackId { let id = with_reducer_callbacks(|callbacks| callbacks.register_on_reducer::(callback)); ReducerCallbackId { id } } @@ -49,7 +49,7 @@ pub trait Reducer: DeserializeOwned + Serialize + Any + Send + Sync + Clone { /// The `callback` will run at most once, then unregister itself. /// It can also be unregistered by passing the returned `ReducerCallbackId` /// to `remove_on_reducer`. - fn once_on_reducer(callback: impl FnOnce(&Identity, Status, &Self) + Send + 'static) -> ReducerCallbackId { + fn once_on_reducer(callback: impl FnOnce(&Identity, &Status, &Self) + Send + 'static) -> ReducerCallbackId { let id = with_reducer_callbacks(|callbacks| callbacks.register_on_reducer_oneshot::(callback)); ReducerCallbackId { id } }