use std::{collections::HashMap, sync::Arc}; use futures_util::FutureExt; use giterated_models::{ error::OperationError, instance::Instance, object::{GiteratedObject, ObjectRequest, ObjectResponse}, operation::GiteratedOperation, settings::Setting, value::GiteratedObjectValue, }; use tracing::{info, trace}; use crate::{ handler::HandlerWrapper, provider::MetadataProvider, AnyFailure, AnyObject, AnyOperation, AnySetting, AnySuccess, AnyValue, GiteratedStack, GiteratedStackState, IntoGiteratedHandler, ObjectOperationPair, ObjectSettingPair, ObjectValuePair, OperationHandler, RuntimeMetadata, SettingChange, SettingGetter, StackOperationState, ValueChange, ValueGetter, }; pub struct SubstackBuilder { pub(crate) operation_handlers: HashMap, OperationHandler>, pub(crate) value_getters: HashMap, ValueGetter>, pub(crate) setting_getters: HashMap<&'static str, SettingGetter>, pub(crate) metadata: RuntimeMetadata, pub(crate) value_change: HashMap, ValueChange>, pub(crate) metadata_providers: Vec>, pub(crate) setting_change: HashMap, SettingChange>, pub(crate) state: S, } impl SubstackBuilder { pub fn new(state: S) -> Self { Self { operation_handlers: Default::default(), value_getters: Default::default(), setting_getters: Default::default(), metadata: Default::default(), value_change: Default::default(), metadata_providers: Default::default(), setting_change: Default::default(), state, } } } impl SubstackBuilder { /// Insert an operation handler into the runtime builder. /// /// # Type Registration /// Inserting the handler will automatically, if required, register the operation type of the /// handler. It will **not** register the object type automatically. pub fn operation(&mut self, handler: H) -> &mut Self where O: GiteratedObject + Clone, D: GiteratedOperation + Clone, H: IntoGiteratedHandler< (O, D), A, S, StackOperationState, Result>, > + Send + Sync + 'static, O: 'static, D: 'static, D::Failure: std::fmt::Debug + 'static, D::Success: 'static, { let wrapped = HandlerWrapper::new(self.state.clone(), handler); let wrapped = wrapped.map( |(any_object, any_operation): &(AnyObject, AnyOperation), _state: &StackOperationState| { Ok(( any_object.0.downcast_ref::().unwrap().clone(), any_operation.0.downcast_ref::().unwrap().clone(), )) }, ); let wrapped = wrapped.map_return(|ret_val, _state| match ret_val { Ok(success) => Ok(AnySuccess(Arc::new(success))), Err(err) => Err(match err { OperationError::Operation(failure) => { OperationError::Operation(AnyFailure(Arc::new(failure))) } OperationError::Internal(err) => OperationError::Internal(err), OperationError::Unhandled => OperationError::Unhandled, }), }); let pair = ObjectOperationPair::from_types::(); self.operation_handlers.insert(pair, wrapped); self.metadata.register_operation::(); self } /// Register a [`GiteratedObject`] type with the runtime. /// /// # Type Registration /// This will register the provided object type. pub fn object(&mut self) -> &mut Self { self.metadata.register_object::(); // Insert handler so ObjectRequest is handled properly self.operation( move |_object: Instance, operation: ObjectRequest, _state: S, _operation_state: StackOperationState, stack: Arc| { let operation = operation.clone(); async move { for (_object_name, object_meta) in stack.metadata.objects.iter() { if (object_meta.from_str)(&operation.0).is_ok() { return Ok(ObjectResponse(operation.0.clone())); } } Err(OperationError::Unhandled) } .boxed_local() }, ); self } /// Register a [`Setting`] type with the runtime. /// /// # Type Registration /// This will register the provided setting type. pub fn setting( &mut self, ) -> &mut Self { self.metadata.register_setting::(); self } /// Register a [`GiteratedObjectValue`] that is also a [`Setting`], which /// allows for automatic value updates. pub fn value_setting< O: GiteratedObject + 'static + Clone, T: GiteratedObjectValue + Setting + 'static + Clone, >( &mut self, ) -> &mut Self { self.metadata.register_setting::(); self.metadata.register_value::(); self.setting_change.insert( ObjectSettingPair::from_types::(), HandlerWrapper::new( (), move |object: AnyObject, setting: AnySetting, _state: (), operation_state: StackOperationState, stack: Arc| { trace!( "value setting updated {}::{}", O::object_name(), T::value_name() ); let object = object.clone(); async move { let object = object.0.downcast_ref::().unwrap(); let setting = setting.0.downcast_ref::().unwrap(); stack .value_update(object.clone(), setting.clone(), &operation_state) .await; Ok(()) } .boxed_local() }, ), ); let wrapped = HandlerWrapper::new( self.state.clone(), |object: AnyObject, _state: _, _operation_state: StackOperationState, stack: Arc| { info!("a setting handler called"); let object = object.clone(); async move { match stack .new_get_setting::(object.0.downcast_ref().unwrap()) .await { Ok(setting) => Ok(AnyValue(Arc::new(setting))), Err(err) => { panic!("Error: {:?}", err); } } } .boxed_local() }, ); self.value_getters .insert(ObjectValuePair::from_types::(), wrapped); self } /// Register a [`GiteratedObjectValue`] type with the runtime, providing /// its associated handler for [`GetValue`]. /// /// # Type Registration /// This will register the provided [`GiteratedObjectValue`] type for its matching / specified /// object type. It will **not** register the object type automatically. pub fn value(&mut self, handler: F) -> &mut Self where O: GiteratedObject + 'static, V: GiteratedObjectValue + 'static + Clone, F: IntoGiteratedHandler<(O,), A, S, StackOperationState, Result>> + Send + Sync, E: Into + 'static + std::fmt::Debug + Clone, F: 'static, { let wrapped = HandlerWrapper::new(self.state.clone(), handler); let wrapped = wrapped.map( |(any_object,): &(AnyObject,), _state: &StackOperationState| { Ok((any_object .0 .downcast_ref::() .ok_or_else(|| OperationError::Internal(DowncastError.into()))? .clone(),)) }, ); let wrapped = wrapped.map_return(|ret_val, _state| match ret_val { Ok(success) => Ok(AnyValue(Arc::new(success))), Err(err) => Err(match err { OperationError::Operation(failure) => OperationError::Internal(failure.into()), OperationError::Internal(err) => OperationError::Internal(err), OperationError::Unhandled => OperationError::Unhandled, }), }); assert!(self .value_getters .insert(ObjectValuePair::from_types::(), wrapped) .is_none()); self.metadata.register_value::(); self } pub fn value_change(&mut self, handler: F) -> &mut Self where O: GiteratedObject + 'static, F: IntoGiteratedHandler< (O, V), A, S, StackOperationState, Result<(), OperationError>, > + Send + Sync, V: GiteratedObjectValue + Clone + 'static, O: 'static, V: 'static, F: 'static, { let wrapped = HandlerWrapper::new(self.state.clone(), handler); let wrapped = wrapped.map( |(any_object, any_value): &(AnyObject, AnyValue), _state: &StackOperationState| { Ok(( any_object .0 .downcast_ref::() .ok_or_else(|| OperationError::Internal(DowncastError.into()))? .clone(), any_value .0 .downcast_ref::() .ok_or_else(|| OperationError::Internal(DowncastError.into()))? .clone(), )) }, ); assert!(self .value_change .insert(ObjectValuePair::from_types::(), wrapped) .is_none()); self } pub fn object_metadata_provider(&mut self, provider: Box) -> &mut Self { self.metadata_providers.push(provider); self } } #[derive(Debug, Clone, thiserror::Error)] #[error("downcast error")] pub struct DowncastError;