nodo/codelet/
mod.rs

1// Copyright 2023 David Weikersdorfer
2
3mod codelet_instance;
4mod lifecycle;
5mod schedule;
6mod sequence;
7mod statistics;
8mod task_clock;
9mod transition;
10mod vise;
11
12#[cfg(feature = "instantiate_from_json")]
13mod instantiate_from_json;
14
15pub use codelet_instance::*;
16pub use lifecycle::*;
17pub use schedule::*;
18pub use sequence::*;
19pub use statistics::*;
20pub use task_clock::*;
21pub use transition::*;
22pub use vise::*;
23
24#[cfg(feature = "instantiate_from_json")]
25pub use instantiate_from_json::*;
26
27use crate::{
28    channels::{RxBundle, TxBundle},
29    config::Config,
30    core::DefaultStatus,
31    prelude::Signals,
32};
33use eyre::Result;
34
35/// Codelets can be implemented by the user to execute work.
36pub trait Codelet: Send {
37    /// Status code used to indicate health of codelet
38    type Status: CodeletStatus;
39
40    /// Type used for configuration
41    type Config: Config + Send;
42
43    /// Type holding all receiving (RX) endpoints
44    type Rx: RxBundle;
45
46    /// Type holding all transmitting (TX) endpoints
47    type Tx: TxBundle;
48
49    /// Type storing the codelet's signals
50    type Signals: Signals;
51
52    /// Constructs channel bundles
53    fn build_bundles(cfg: &Self::Config) -> (Self::Rx, Self::Tx);
54
55    /// Start is guaranteed to be called first. Start may be called again after stop was called.
56    fn start(
57        &mut self,
58        _cx: Context<Self>,
59        _rx: &mut Self::Rx,
60        _tx: &mut Self::Tx,
61    ) -> Result<Self::Status> {
62        Ok(Self::Status::default_implementation_status())
63    }
64
65    /// Stop is guaranteed to be called at the end if start was called.
66    fn stop(
67        &mut self,
68        _cx: Context<Self>,
69        _rx: &mut Self::Rx,
70        _tx: &mut Self::Tx,
71    ) -> Result<Self::Status> {
72        Ok(Self::Status::default_implementation_status())
73    }
74
75    /// Step is executed periodically after the codelet is started and while it is not paused.
76    fn step(
77        &mut self,
78        _cx: Context<Self>,
79        _rx: &mut Self::Rx,
80        _tx: &mut Self::Tx,
81    ) -> Result<Self::Status> {
82        Ok(Self::Status::default_implementation_status())
83    }
84
85    /// Pause may be called to suspend stepping.
86    fn pause(&mut self) -> Result<Self::Status> {
87        Ok(Self::Status::default_implementation_status())
88    }
89
90    /// Resume is called to resume stepping. Note that stop may also be called while the codelet
91    /// is paused to stop the codelet completely instead of resuming stepping.
92    fn resume(&mut self) -> Result<Self::Status> {
93        Ok(Self::Status::default_implementation_status())
94    }
95}
96
97pub trait CodeletStatus: 'static + Send + Sync {
98    /// The status used for codelet functions which have not been implemented by the user
99    fn default_implementation_status() -> Self
100    where
101        Self: Sized;
102
103    /// Converts the status to a default status used internally by the framework
104    fn as_default_status(&self) -> DefaultStatus;
105
106    /// A textual rendering of the status code
107    fn label(&self) -> &str;
108}
109
110impl CodeletStatus for DefaultStatus {
111    fn default_implementation_status() -> Self {
112        DefaultStatus::Skipped
113    }
114
115    fn as_default_status(&self) -> DefaultStatus {
116        *self
117    }
118
119    fn label(&self) -> &str {
120        match self {
121            DefaultStatus::Skipped => "skipped",
122            DefaultStatus::Running => "running",
123        }
124    }
125}
126
127/// Context argument used for `Codelet` start, step and stop functions
128pub struct Context<'a, C>
129where
130    C: Codelet + ?Sized,
131{
132    /// Access to various clocks
133    pub clocks: &'a TaskClocks,
134
135    /// The configuration used for this instance
136    pub config: &'a C::Config,
137
138    /// Additional information about configuration
139    pub config_aux: &'a <C::Config as Config>::Aux,
140
141    /// Statistics about codelet execution
142    pub pulse: &'a CodeletPulse,
143
144    /// Signals
145    pub signals: &'a mut C::Signals,
146}
147
148pub struct CodeletPulse {
149    /// Total number of steps executed. This will be 0 for the first step.
150    pub step_count: usize,
151}
152
153impl CodeletPulse {
154    pub(crate) fn new() -> Self {
155        Self { step_count: 0 }
156    }
157
158    pub(crate) fn on_step_post(&mut self) {
159        self.step_count += 1;
160    }
161}
162
163/// All instances of codelets can be converted into a CodeletInstance with into_instance
164///
165/// ```
166/// use nodo::prelude::*;
167///
168/// struct MyCodelet { num: u32 };
169///
170/// impl Codelet for MyCodelet {
171///   type Status = DefaultStatus;
172///   type Config = ();
173///   type Rx = ();
174///   type Tx = ();
175///   type Signals = ();
176///   fn build_bundles(_: &Self::Config) -> (Self::Rx, Self::Tx) { ((),()) }
177/// }
178///
179/// let c = MyCodelet{ num: 42 }.into_instance("my_name", ());
180/// ```
181pub trait IntoInstance: Codelet + Sized {
182    fn into_instance<S: Into<String>>(self, name: S, config: Self::Config)
183        -> CodeletInstance<Self>;
184}
185
186impl<C> IntoInstance for C
187where
188    C: Codelet,
189{
190    fn into_instance<S: Into<String>>(
191        self,
192        name: S,
193        config: Self::Config,
194    ) -> CodeletInstance<Self> {
195        CodeletInstance::new(name, self, config)
196    }
197}
198
199/// Default-constructible codelets can be instantiated directly
200///
201/// ```
202/// use nodo::prelude::*;
203///
204/// #[derive(Default)]
205/// struct MyCodelet { text: String };
206///
207/// impl Codelet for MyCodelet {
208///   type Status = DefaultStatus;
209///   type Config = ();
210///   type Rx = ();
211///   type Tx = ();
212///   type Signals = ();
213///   fn build_bundles(_: &Self::Config) -> (Self::Rx, Self::Tx) { ((),()) }
214/// }
215///
216/// let c = MyCodelet::instantiate("my_name", ());
217/// ```
218pub trait Instantiate: Codelet + Sized {
219    fn instantiate<S: Into<String>>(name: S, config: Self::Config) -> CodeletInstance<Self>;
220}
221
222impl<C> Instantiate for C
223where
224    C: Codelet + Default,
225{
226    fn instantiate<S: Into<String>>(name: S, config: Self::Config) -> CodeletInstance<Self> {
227        CodeletInstance::new(name, C::default(), config)
228    }
229}