use std::marker::PhantomData;
use std::sync::Arc;
use crate::context::PluginContext;
use crate::error::PluginError;
use crate::executor::erase_result;
use crate::hooks::payload::{Extensions, PluginPayload};
use crate::hooks::trait_def::{HookHandler, HookTypeDef, PluginResult};
use crate::plugin::Plugin;
use crate::registry::AnyHookHandler;
pub struct TypedHandlerAdapter<H, P>
where
H: HookTypeDef,
H::Result: Into<PluginResult<H::Payload>>,
P: Plugin + HookHandler<H> + 'static,
{
plugin: Arc<P>,
_hook: PhantomData<H>,
}
impl<H, P> TypedHandlerAdapter<H, P>
where
H: HookTypeDef,
H::Result: Into<PluginResult<H::Payload>>,
P: Plugin + HookHandler<H> + 'static,
{
pub fn new(plugin: Arc<P>) -> Self {
Self {
plugin,
_hook: PhantomData,
}
}
}
#[async_trait::async_trait]
impl<H, P> AnyHookHandler for TypedHandlerAdapter<H, P>
where
H: HookTypeDef,
H::Result: Into<PluginResult<H::Payload>>,
P: Plugin + HookHandler<H> + 'static,
{
async fn invoke(
&self,
payload: &dyn PluginPayload,
extensions: &Extensions,
ctx: &mut PluginContext,
) -> Result<Box<dyn std::any::Any + Send + Sync>, Box<PluginError>> {
let typed_ref: &H::Payload =
payload
.as_any()
.downcast_ref::<H::Payload>()
.ok_or_else(|| PluginError::Config {
message: format!(
"payload type mismatch for hook '{}': expected {}",
H::NAME,
std::any::type_name::<H::Payload>()
),
})?;
let result = self.plugin.handle(typed_ref, extensions, ctx).await;
let plugin_result: PluginResult<H::Payload> = result.into();
Ok(erase_result(plugin_result))
}
fn hook_type_name(&self) -> &'static str {
H::NAME
}
}