harmos_runtime/operations/
lane.rs1use std::collections::BTreeMap;
18use std::sync::Arc;
19use tokio::sync::Semaphore;
21pub(crate) const RESIDENT: &str = "harmos.resident";
28
29#[derive(Clone, Copy, Debug, PartialEq, Eq)]
36pub struct Capacity {
37 width: usize,
38}
39
40#[derive(Clone, Copy, Debug, PartialEq, Eq)]
41pub struct LaneSettings {
42 pub capacity: Capacity,
43}
44
45#[derive(Clone, Debug, Default)]
46pub struct LaneSet {
47 entries: Vec<(&'static str, Capacity)>,
48}
49
50#[derive(Clone)]
51pub(crate) struct Admission {
52 name: &'static str,
53 width: usize,
54 semaphore: Arc<Semaphore>,
55}
56
57pub(crate) struct Lanes {
58 lanes: BTreeMap<&'static str, Admission>,
59}
60
61pub trait Lane: Copy + Eq + Send + Sync + 'static {
66 fn catalog() -> LaneSet;
67 fn default_lane() -> Self;
68 fn name(&self) -> &'static str;
69 fn capacity(&self) -> Capacity;
70}
71
72impl Capacity {
75 pub const fn serial() -> Self {
76 Self { width: 1 }
77 }
78
79 pub const fn concurrent(width: usize) -> Self {
80 Self { width }
81 }
82
83 pub const fn unbounded() -> Self {
84 Self { width: usize::MAX }
85 }
86
87 pub(crate) const fn width(self) -> usize {
88 self.width
89 }
90}
91
92impl LaneSet {
93 pub fn declared(entries: impl IntoIterator<Item = (&'static str, Capacity)>) -> Self {
94 Self { entries: entries.into_iter().collect() }
95 }
96
97 pub(crate) fn entries(self) -> Vec<(&'static str, Capacity)> {
98 self.entries
99 }
100
101 pub(crate) fn contains(&self, lane: &str) -> bool {
102 self.entries.iter().any(|(name, _)| *name == lane)
103 }
104
105 pub(crate) fn configure(&mut self, lane: &str, capacity: Capacity) -> bool {
106 let Some((_, configured)) = self.entries.iter_mut().find(|(name, _)| *name == lane) else {
107 return false;
108 };
109 *configured = capacity;
110 true
111 }
112}
113
114impl Admission {
115 pub(crate) fn name(&self) -> &'static str {
116 self.name
117 }
118
119 pub(crate) fn bounded(&self) -> bool {
120 self.width != usize::MAX
121 }
122
123 pub(crate) fn semaphore(&self) -> Arc<Semaphore> {
124 Arc::clone(&self.semaphore)
125 }
126}
127
128impl Lanes {
129 pub(crate) fn freeze(declared: LaneSet) -> Result<Self, String> {
130 let mut lanes = BTreeMap::from([(
131 RESIDENT,
132 Admission {
133 name: RESIDENT,
134 width: usize::MAX,
135 semaphore: Arc::new(Semaphore::new(Semaphore::MAX_PERMITS)),
136 },
137 )]);
138
139 for (name, capacity) in declared.entries() {
140 if name.is_empty() {
141 return Err("a lane name must not be empty".to_owned());
142 }
143 if capacity.width() == 0 {
144 return Err(format!("lane `{name}` must admit at least one job"));
145 }
146 let admission = Admission {
147 name,
148 width: capacity.width(),
149 semaphore: Arc::new(Semaphore::new(capacity.width().min(Semaphore::MAX_PERMITS))),
150 };
151 if lanes.insert(name, admission).is_some() {
152 return Err(format!("lane `{name}` is declared more than once"));
153 }
154 }
155
156 Ok(Self { lanes })
157 }
158
159 pub(crate) fn get(&self, name: &str) -> Option<Admission> {
160 self.lanes.get(name).cloned()
161 }
162}
163
164