podo-core-driver 0.4.4

Podo Driver FFI
Documentation
use std::any::Any;
use std::cmp::Ordering;
use std::sync::Arc;

use crate::error::RuntimeError;
use crate::resource::Resource;
use crate::symbol::SymbolRef;

use downcast_rs::{impl_downcast, Downcast, DowncastSync};
pub use serde_yaml::Value as DriverParams;

pub trait DriverRoot: Send + Sync {
    fn get(&self, symbol: SymbolRef<'_>) -> Result<ArcDriver, RuntimeError>;
}

pub fn get_driver_unchecked<T>(root: &dyn DriverRoot, symbol: &str) -> Result<Arc<T>, RuntimeError>
where
    T: Driver,
{
    let symbol = symbol.split(' ').map(|s| s.to_string()).collect::<Vec<_>>();
    let driver = root.get(&symbol)?;
    let driver = downcast_rs::DowncastSync::into_any_arc(driver);
    let driver = unsafe { Arc::from_raw(Arc::into_raw(driver) as *const T) };
    Ok(driver)
}

pub type ArcDriver = Arc<dyn Driver>;

#[test]
fn test_down() {
    struct ABC;

    impl Driver for ABC {}

    impl ABC {
        fn print_msg(&self) -> &'static str {
            MSG
        }
    }

    const MSG: &str = "hello world";

    let abc = Arc::new(ABC) as ArcDriver;
    assert_eq!(abc.downcast_arc::<ABC>().ok().unwrap().print_msg(), MSG);
}

impl_downcast!(sync Driver);
pub trait Driver
where
    Self: 'static + Any + Downcast + DowncastSync + Send + Sync,
{
    #[allow(unused_variables)]
    fn call(&self, func: &str, value: &Resource) -> Result<(), RuntimeError> {
        RuntimeError::unimplemented()
    }

    #[allow(unused_variables)]
    fn with(&self, value: &Resource) -> Result<Option<ArcDriver>, RuntimeError> {
        Ok(None)
    }

    /// Load the driver's current state.
    ///
    /// If there is a shortage of physical resources, hibernate drivers that are not needed.
    fn status(&self) -> Result<DriverState, RuntimeError> {
        Ok(DriverState::Running(DriverRunningState::default()))
    }

    /// Hibernate the driver.
    ///
    /// The hibernating driver must unload the heavy data from memory and be able to reload it in the wake.
    fn hibernate(&self) -> Result<(), RuntimeError> {
        Ok(())
    }

    /// Wake the hibernating driver.
    ///
    /// note: This function will **never** be called if it is already awake.
    fn wake_up(&self) -> Result<(), RuntimeError> {
        Ok(())
    }

    /// Inform the driver that a work will use it.
    fn enter(&self) -> Result<(), RuntimeError> {
        Ok(())
    }

    /// Inform the driver that the work is completed.
    fn exit(&self) -> Result<(), RuntimeError> {
        Ok(())
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum DriverState {
    /// Doing nothing
    Idle,
    /// Doing something
    Running(DriverRunningState),
    /// Doing nothing but not available immediately
    Hibernated,
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum DriverRunningState {
    /// Doing something, but not critical
    Lazy,
    /// Doing something, OS interference is not a burden.
    Normal,
    /// Doing something, OS interference is burdensome
    Busy,
}

impl Default for DriverRunningState {
    fn default() -> Self {
        Self::Normal
    }
}

impl PartialOrd for DriverState {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.to_u8().partial_cmp(&other.to_u8())
    }
}

impl Ord for DriverState {
    fn cmp(&self, other: &Self) -> Ordering {
        self.to_u8().cmp(&other.to_u8())
    }
}

impl DriverState {
    fn to_u8(&self) -> u8 {
        match self {
            Self::Idle => 0,
            Self::Running(DriverRunningState::Lazy) => 1,
            Self::Running(DriverRunningState::Normal) => 2,
            Self::Running(DriverRunningState::Busy) => 3,
            Self::Hibernated => 4,
        }
    }
}