ncomm_executors/
lib.rs

1//!
2//! NComm-Executors provides a set of executors (kind of like schedulers)
3//! for nodes.
4//!
5//! The main idea with this create is to make executing nodes fit the specific
6//! use case.  Specifically, there may be times when a Threadpooled model works
7//! best or another use case where a Green-threaded Tokio implementation works best.
8//!
9//! Ideally, this crate should contain all of the commonly used executors that
10//! conform to the common ncomm-core traits to make creating robotics systems
11//! as easy and pain-free as possible.
12//!
13
14#![deny(missing_docs)]
15// To test the internal state of nodes, they need to be force
16// downcasted into their respective type.
17#![cfg_attr(test, feature(downcast_unchecked))]
18#![cfg_attr(not(feature = "std"), no_std)]
19#[cfg(feature = "alloc")]
20extern crate alloc;
21
22#[cfg(feature = "std")]
23pub mod simple_executor;
24#[cfg(feature = "std")]
25pub use simple_executor::SimpleExecutor;
26
27#[cfg(feature = "std")]
28pub mod threadpool_executor;
29#[cfg(feature = "std")]
30pub use threadpool_executor::ThreadPoolExecutor;
31
32#[cfg(feature = "std")]
33pub mod threaded_executor;
34#[cfg(feature = "std")]
35pub use threaded_executor::ThreadedExecutor;
36
37use core::cmp::{Ord, Ordering};
38use ncomm_core::node::Node;
39
40#[cfg(feature = "alloc")]
41use alloc::{boxed::Box, vec::Vec};
42#[cfg(feature = "std")]
43use std::{boxed::Box, vec::Vec};
44
45#[cfg(any(feature = "alloc", feature = "std"))]
46/// The NodeWrapper wraps nodes giving them a priority based on the timestamp
47/// of their next update.
48///
49/// This ensures that nodes are updated at the correct time
50pub(crate) struct NodeWrapper<ID: PartialEq> {
51    /// The timestamp of the nodes next update
52    pub priority: u128,
53    /// The nde this NodeWrapper is wrapping around
54    pub node: Box<dyn Node<ID>>,
55}
56
57#[cfg(any(feature = "alloc", feature = "std"))]
58impl<ID: PartialEq> NodeWrapper<ID> {
59    /// Destroy the node wrapper returning the node it was wrapping.
60    pub fn destroy(self) -> Box<dyn Node<ID>> {
61        self.node
62    }
63}
64
65#[cfg(any(feature = "alloc", feature = "std"))]
66impl<ID: PartialEq> Ord for NodeWrapper<ID> {
67    fn cmp(&self, other: &Self) -> Ordering {
68        self.priority.cmp(&other.priority).reverse()
69    }
70}
71
72#[cfg(any(feature = "alloc", feature = "std"))]
73impl<ID: PartialEq> PartialOrd for NodeWrapper<ID> {
74    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
75        Some(self.cmp(other))
76    }
77}
78
79#[cfg(any(feature = "alloc", feature = "std"))]
80impl<ID: PartialEq> PartialEq for NodeWrapper<ID> {
81    fn eq(&self, other: &Self) -> bool {
82        self.priority == other.priority
83    }
84}
85
86#[cfg(any(feature = "alloc", feature = "std"))]
87impl<ID: PartialEq> Eq for NodeWrapper<ID> {}
88
89#[cfg(any(feature = "alloc", feature = "std"))]
90/// This method performs binary search insertion into the sorted vector
91/// `vec` with the node `node`.
92///
93/// This is just a convenience method I found myself using a ton so I decided
94/// to make it its own method.
95#[inline(always)]
96pub(crate) fn insert_into<ID: PartialEq>(vec: &mut Vec<NodeWrapper<ID>>, node: NodeWrapper<ID>) {
97    // If another node is found with the same priority, insert the node after that
98    // node.  Otherwise, insert the node into the position it should be in in the
99    // sorted vector
100    match vec.binary_search(&node) {
101        Ok(idx) => vec.insert(idx + 1, node),
102        Err(idx) => vec.insert(idx, node),
103    }
104}