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)
}
fn status(&self) -> Result<DriverState, RuntimeError> {
Ok(DriverState::Running(DriverRunningState::default()))
}
fn hibernate(&self) -> Result<(), RuntimeError> {
Ok(())
}
fn wake_up(&self) -> Result<(), RuntimeError> {
Ok(())
}
fn enter(&self) -> Result<(), RuntimeError> {
Ok(())
}
fn exit(&self) -> Result<(), RuntimeError> {
Ok(())
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum DriverState {
Idle,
Running(DriverRunningState),
Hibernated,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum DriverRunningState {
Lazy,
Normal,
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,
}
}
}