nitinol-resolver 0.1.0

Library for Nitinol to abstract how to process Events to Entity
Documentation
use std::fmt::{Debug, Display};
use std::marker::PhantomData;

use async_trait::async_trait;
use nitinol_core::event::Event;

use crate::errors::ResolveError;

#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub struct ResolveType {
    event: &'static str,
    handler: &'static str,
}

impl ResolveType {
    pub const fn new(event: &'static str, handler: &'static str) -> Self {
        Self { event, handler }
    }

    pub fn event(&self) -> &'static str {
        self.event
    }

    pub fn handler(&self) -> &'static str {
        self.handler
    }
}

impl Display for ResolveType {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}-{}", self.event, self.handler)
    }
}

#[async_trait]
pub trait ResolveHandler<E: Event, T>: 'static + Sync + Send {
    const HANDLER_TYPE: &'static str;
    type Error: Debug + Sync + Send + 'static;
    async fn apply(entity: &mut Option<T>, event: E) -> Result<(), Self::Error>;
}

pub trait ResolverType<T> 
where 
    Self: Resolver<T>
{
    const RESOLVE_TYPE: &'static str;
}

#[async_trait]
pub trait Resolver<T>: 'static + Sync + Send {
    async fn resolve(&self, entity: &mut Option<T>, payload: &[u8]) -> Result<(), ResolveError>;
}

pub(crate) struct TypedResolver<E: Event, T, H> {
    _event: PhantomData<E>,
    _resolve: PhantomData<T>,
    _handler: PhantomData<H>,
}

impl<E: Event, T, H: ResolveHandler<E, T>> Default for TypedResolver<E, T, H> {
    fn default() -> Self {
        Self {
            _event: Default::default(),
            _resolve: Default::default(),
            _handler: Default::default(),
        }
    }
}

#[async_trait]
impl<E: Event, T, H> Resolver<T> for TypedResolver<E, T, H>
where
    T: 'static + Sync + Send,
    H: ResolveHandler<E, T>,
{
    async fn resolve(&self, entity: &mut Option<T>, payload: &[u8]) -> Result<(), ResolveError> {
        let event = E::from_bytes(payload)?;
        if let Err(reason) = H::apply(entity, event).await {
            tracing::error!("{:?}", reason);
            return Err(ResolveError::InProcess {
                trace: format!("{:?}", reason),
            });
        }
        Ok(())
    }
}