podo_core_driver/
driver.rs

1use std::any::Any;
2use std::cmp::Ordering;
3use std::sync::Arc;
4
5use crate::error::RuntimeError;
6use crate::resource::Resource;
7use crate::symbol::SymbolRef;
8
9use downcast_rs::{impl_downcast, Downcast, DowncastSync};
10pub use serde_yaml::Value as DriverParams;
11
12pub trait DriverRoot: Send + Sync {
13    fn get(&self, symbol: SymbolRef<'_>) -> Result<ArcDriver, RuntimeError>;
14}
15
16pub fn get_driver_unchecked<T>(root: &dyn DriverRoot, symbol: &str) -> Result<Arc<T>, RuntimeError>
17where
18    T: Driver,
19{
20    let symbol = symbol.split(' ').map(|s| s.to_string()).collect::<Vec<_>>();
21    let driver = root.get(&symbol)?;
22    let driver = downcast_rs::DowncastSync::into_any_arc(driver);
23    let driver = unsafe { Arc::from_raw(Arc::into_raw(driver) as *const T) };
24    Ok(driver)
25}
26
27pub type ArcDriver = Arc<dyn Driver>;
28
29#[test]
30fn test_down() {
31    struct ABC;
32
33    impl Driver for ABC {}
34
35    impl ABC {
36        fn print_msg(&self) -> &'static str {
37            MSG
38        }
39    }
40
41    const MSG: &str = "hello world";
42
43    let abc = Arc::new(ABC) as ArcDriver;
44    assert_eq!(abc.downcast_arc::<ABC>().ok().unwrap().print_msg(), MSG);
45}
46
47impl_downcast!(sync Driver);
48pub trait Driver
49where
50    Self: 'static + Any + Downcast + DowncastSync + Send + Sync,
51{
52    #[allow(unused_variables)]
53    fn call(&self, func: &str, value: &Resource) -> Result<(), RuntimeError> {
54        RuntimeError::unimplemented()
55    }
56
57    #[allow(unused_variables)]
58    fn with(&self, value: &Resource) -> Result<Option<ArcDriver>, RuntimeError> {
59        Ok(None)
60    }
61
62    /// Load the driver's current state.
63    ///
64    /// If there is a shortage of physical resources, hibernate drivers that are not needed.
65    fn status(&self) -> Result<DriverState, RuntimeError> {
66        Ok(DriverState::Running(DriverRunningState::default()))
67    }
68
69    /// Hibernate the driver.
70    ///
71    /// The hibernating driver must unload the heavy data from memory and be able to reload it in the wake.
72    fn hibernate(&self) -> Result<(), RuntimeError> {
73        Ok(())
74    }
75
76    /// Wake the hibernating driver.
77    ///
78    /// note: This function will **never** be called if it is already awake.
79    fn wake_up(&self) -> Result<(), RuntimeError> {
80        Ok(())
81    }
82
83    /// Inform the driver that a work will use it.
84    fn enter(&self) -> Result<(), RuntimeError> {
85        Ok(())
86    }
87
88    /// Inform the driver that the work is completed.
89    fn exit(&self) -> Result<(), RuntimeError> {
90        Ok(())
91    }
92}
93
94#[derive(Copy, Clone, Debug, PartialEq, Eq)]
95pub enum DriverState {
96    /// Doing nothing
97    Idle,
98    /// Doing something
99    Running(DriverRunningState),
100    /// Doing nothing but not available immediately
101    Hibernated,
102}
103
104#[derive(Copy, Clone, Debug, PartialEq, Eq)]
105pub enum DriverRunningState {
106    /// Doing something, but not critical
107    Lazy,
108    /// Doing something, OS interference is not a burden.
109    Normal,
110    /// Doing something, OS interference is burdensome
111    Busy,
112}
113
114impl Default for DriverRunningState {
115    fn default() -> Self {
116        Self::Normal
117    }
118}
119
120impl PartialOrd for DriverState {
121    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
122        self.to_u8().partial_cmp(&other.to_u8())
123    }
124}
125
126impl Ord for DriverState {
127    fn cmp(&self, other: &Self) -> Ordering {
128        self.to_u8().cmp(&other.to_u8())
129    }
130}
131
132impl DriverState {
133    fn to_u8(&self) -> u8 {
134        match self {
135            Self::Idle => 0,
136            Self::Running(DriverRunningState::Lazy) => 1,
137            Self::Running(DriverRunningState::Normal) => 2,
138            Self::Running(DriverRunningState::Busy) => 3,
139            Self::Hibernated => 4,
140        }
141    }
142}