Skip to main content

harmos_runtime/operations/
lane.rs

1/* ***
2 *
3 * Harmos
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * ***
8 */
9
10/* === Modules === */
11
12/* === Re-Exports === */
13
14/* === Imports === */
15
16// Standard Library Imports
17use std::collections::BTreeMap;
18use std::sync::Arc;
19// Third Party Imports
20use tokio::sync::Semaphore;
21// Local Imports
22
23/* === Constants === */
24
25// The lane resident controls run in: unbounded, so a control that runs until
26// cancelled never holds a slot another call is waiting for.
27pub(crate) const RESIDENT: &str = "harmos.resident";
28
29/* === Macros === */
30
31/* === Type Aliases === */
32
33/* === Structs === */
34
35#[derive(Clone, Copy, Debug, PartialEq, Eq)]
36pub struct Capacity {
37    width: usize,
38}
39
40#[derive(Clone, Debug, Default)]
41pub struct LaneSet {
42    entries: Vec<(&'static str, Capacity)>,
43}
44
45#[derive(Clone)]
46pub(crate) struct Admission {
47    name: &'static str,
48    width: usize,
49    semaphore: Arc<Semaphore>,
50}
51
52pub(crate) struct Lanes {
53    lanes: BTreeMap<&'static str, Admission>,
54}
55
56/* === Enums === */
57
58/* === Traits === */
59
60pub trait Lane: Copy + Eq + Send + Sync + 'static {
61    fn default_lane() -> Self;
62    fn name(&self) -> &'static str;
63    fn capacity(&self) -> Capacity;
64}
65
66/* === Implementations === */
67
68impl Capacity {
69    pub const fn serial() -> Self {
70        Self { width: 1 }
71    }
72
73    pub const fn concurrent(width: usize) -> Self {
74        Self { width }
75    }
76
77    pub const fn unbounded() -> Self {
78        Self { width: usize::MAX }
79    }
80
81    pub(crate) const fn width(self) -> usize {
82        self.width
83    }
84}
85
86impl LaneSet {
87    pub fn declared(entries: impl IntoIterator<Item = (&'static str, Capacity)>) -> Self {
88        Self { entries: entries.into_iter().collect() }
89    }
90
91    pub(crate) fn entries(self) -> Vec<(&'static str, Capacity)> {
92        self.entries
93    }
94
95    pub(crate) fn extend(&mut self, other: Self) {
96        self.entries.extend(other.entries);
97    }
98}
99
100impl Admission {
101    pub(crate) fn name(&self) -> &'static str {
102        self.name
103    }
104
105    pub(crate) fn bounded(&self) -> bool {
106        self.width != usize::MAX
107    }
108
109    pub(crate) fn semaphore(&self) -> Arc<Semaphore> {
110        Arc::clone(&self.semaphore)
111    }
112}
113
114impl Lanes {
115    pub(crate) fn freeze(declared: LaneSet) -> Result<Self, String> {
116        let mut lanes = BTreeMap::from([(
117            RESIDENT,
118            Admission {
119                name: RESIDENT,
120                width: usize::MAX,
121                semaphore: Arc::new(Semaphore::new(Semaphore::MAX_PERMITS)),
122            },
123        )]);
124
125        for (name, capacity) in declared.entries() {
126            if name.is_empty() {
127                return Err("a lane name must not be empty".to_owned());
128            }
129            if capacity.width() == 0 {
130                return Err(format!("lane `{name}` must admit at least one job"));
131            }
132            let admission = Admission {
133                name,
134                width: capacity.width(),
135                semaphore: Arc::new(Semaphore::new(capacity.width().min(Semaphore::MAX_PERMITS))),
136            };
137            if lanes.insert(name, admission).is_some() {
138                return Err(format!("lane `{name}` is declared more than once"));
139            }
140        }
141
142        Ok(Self { lanes })
143    }
144
145    pub(crate) fn get(&self, name: &str) -> Option<Admission> {
146        self.lanes.get(name).cloned()
147    }
148}
149
150/* === Public Functions === */
151
152/* === Private Functions === */
153
154/* === Tests === */