mahler-core 0.22.0

An automated job orchestration library that builds and executes dynamic workflows
Documentation
use json_patch::{patch, Patch};
use serde::{de::DeserializeOwned, Serialize};
use serde_json::Value;
use std::{
    any::{Any, TypeId},
    collections::HashMap,
    fmt::Display,
    ops::Deref,
    sync::Arc,
};

#[derive(Clone)]
pub struct Resources(HashMap<TypeId, Arc<dyn Any + Send + Sync>>);

impl Default for Resources {
    fn default() -> Self {
        Self::new()
    }
}

impl Resources {
    pub fn new() -> Self {
        Self(HashMap::new())
    }

    pub fn insert<R>(&mut self, res: R)
    where
        R: Send + Sync + 'static,
    {
        let type_id = TypeId::of::<R>();
        self.0.insert(type_id, Arc::new(res));
    }

    pub fn get<R>(&self) -> Option<Arc<R>>
    where
        R: Send + Sync + 'static,
    {
        let type_id = TypeId::of::<R>();
        self.0.get(&type_id).and_then(|res| {
            // Clone the Arc<dyn Any + Send + Sync> first
            let arc = Arc::clone(res);

            // Then downcast it into Arc<E>
            arc.downcast::<R>().ok()
        })
    }
}

#[derive(Clone)]
pub struct System {
    state: Value,
    resources: Resources,
}

impl std::fmt::Debug for System {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("System")
            .field("state", &self.state)
            .field("resources", &"Resources { ... }")
            .finish()
    }
}

impl Display for System {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        self.state.fmt(f)
    }
}

impl System {
    pub fn try_from<S: Serialize>(state: S) -> Result<Self, serde_json::Error> {
        let state = serde_json::to_value(state)?;
        Ok(Self {
            state,
            resources: Resources::new(),
        })
    }

    pub fn root(&self) -> &Value {
        &self.state
    }

    pub(crate) fn patch(&mut self, changes: Patch) -> Result<(), json_patch::PatchError> {
        patch(&mut self.state, &changes)?;
        Ok(())
    }

    pub fn state<S: DeserializeOwned>(&self) -> Result<S, serde_json::Error> {
        let s = serde_json::from_value(self.state.clone())?;
        Ok(s)
    }

    pub(crate) fn set_resources(&mut self, resources: Resources) {
        self.resources = resources;
    }

    pub(crate) fn resource<R>(&self) -> Option<Arc<R>>
    where
        R: Send + Sync + 'static,
    {
        self.resources.get::<R>()
    }
}

impl Deref for System {
    type Target = Value;

    fn deref(&self) -> &Self::Target {
        &self.state
    }
}