use std::future::Future; use giterated_models::{ error::OperationError, object::GiteratedObject, value::GiteratedObjectValue, }; use crate::{ future::{RuntimeFuture, RuntimeFuturesExt}, new_stack::PluginState, vtable::{AnyObject, NewAnyValue}, }; use super::{CallbackPtr, RuntimeState}; #[derive(Copy, Clone)] pub struct ValueGetterCallback { pub callback_ptr: CallbackPtr, pub func: unsafe extern "C" fn( CallbackPtr, runtime_state: &RuntimeState, &PluginState, object: AnyObject, ) -> RuntimeFuture>, } impl ValueGetterCallback { pub fn new>(handler: T) -> Self { Self { func: T::get_value, callback_ptr: handler.callback_ptr(), } } } pub trait IntoPluginValueGetter { unsafe extern "C" fn get_value( callback: CallbackPtr, runtime_state: &RuntimeState, state: &PluginState, object: AnyObject, ) -> RuntimeFuture>; fn callback_ptr(&self) -> CallbackPtr; } impl IntoPluginValueGetter for F where Fut: Future>> + Send + Sync, S: Clone + Send + Sync + 'static, O: GiteratedObject + 'static, V: GiteratedObjectValue + Send + Sync + 'static, F: Fn(S, O) -> Fut + Send + Sync + 'static, { unsafe extern "C" fn get_value( callback: CallbackPtr, runtime_state: &RuntimeState, state: &PluginState, mut object: AnyObject, ) -> RuntimeFuture> { let _guard = trace_span!( "get_value handler", object = O::object_name(), value = V::value_name() ) .entered(); let state = unsafe { state.transmute_ref::() }; let object = unsafe { object.transmute_owned::() }; // Cast the callback ptr to ourselves let callback: *const F = std::mem::transmute(callback.0); let callback = callback.as_ref().unwrap(); let state = state.clone(); runtime_state.spawn_future(async move { let result = callback(state, *object).await; match result { Ok(success) => unsafe { Ok(NewAnyValue::new(success)) }, Err(err) => match err { OperationError::Operation(_) => todo!(), OperationError::Internal(_) => todo!(), OperationError::Unhandled => todo!(), }, } }) } fn callback_ptr(&self) -> CallbackPtr { unsafe { CallbackPtr::from_raw(self as *const _ as *const ()) } } } pub struct ValueChangeCallback { func: unsafe extern "C" fn( &PluginState, object: AnyObject, value_name: &str, new_value: NewAnyValue, ) -> RuntimeFuture<()>, } pub trait IntoValueChangeCallback { unsafe extern "C" fn value_changed( state: &PluginState, object: AnyObject, value_name: &str, new_value: NewAnyValue, ) -> RuntimeFuture<()>; } impl IntoValueChangeCallback for F { unsafe extern "C" fn value_changed( _state: &PluginState, _object: AnyObject, _value_name: &str, _new_value: NewAnyValue, ) -> RuntimeFuture<()> { todo!() } } impl ValueChangeCallback { pub fn new>() -> Self { Self { func: T::value_changed, } } }