dope_core/driver/settings/
mod.rs1use std::num;
2
3pub use config::Config;
4pub(crate) use config::plan::{Plan, Ready};
5pub use demands::Schedule;
6use o3::{base::num::bounded, depot, depot::capacity};
7pub use receive::Receive;
8pub use resource::Resource;
9pub use routes::Routes;
10
11use crate::{
12 driver::route::{SLOT_MASK, indices::SlotIndex, table},
13 io::{datagram::payload, socket::option, transfer},
14};
15
16pub mod claim;
17mod config;
18pub mod demands;
19pub mod errors;
20mod receive;
21mod resource;
22mod routes;
23
24#[derive(Clone, Copy, Debug, PartialEq, Eq)]
25pub struct DomainSum {
26 current: Domain,
27 added: Domain,
28}
29
30impl DomainSum {
31 pub const fn parts(&self) -> (&Domain, &Domain) {
32 (&self.current, &self.added)
33 }
34}
35
36#[derive(Clone, Copy, PartialEq, Eq)]
38#[repr(transparent)]
39pub struct Ring(Buffers);
40
41impl Ring {
42 pub fn try_round(entries: u32) -> Result<Self, errors::Claim> {
43 if entries < 2 {
44 return Err(errors::Config::ReceiveEntriesOutOfRange {
45 actual: entries,
46 minimum: 2,
47 maximum: u16::MAX as u32,
48 }
49 .into());
50 }
51 let count = entries
52 .checked_next_power_of_two()
53 .ok_or(errors::Claim::ReceiveEntriesPowerOfTwoOverflow { requested: entries })?;
54 if count > u32::from(u16::MAX) {
55 return Err(errors::Claim::ReceiveEntriesTooLarge {
56 actual: count as usize,
57 maximum: u16::MAX as usize,
58 });
59 }
60 Ok(Self(Buffers(
61 num::NonZero::<u16>::MIN.saturating_add(count as u16 - 1),
62 )))
63 }
64
65 pub const fn buffers(self) -> Buffers {
66 self.0
67 }
68}
69
70impl TryFrom<u16> for Ring {
71 type Error = errors::Config;
72
73 fn try_from(entries: u16) -> Result<Self, Self::Error> {
74 if entries < 2 {
75 return Err(errors::Config::ReceiveEntriesOutOfRange {
76 actual: entries as u32,
77 minimum: 2,
78 maximum: u16::MAX as u32,
79 });
80 }
81 if !entries.is_power_of_two() {
82 return Err(errors::Config::ReceiveEntriesNotPowerOfTwo { actual: entries });
83 }
84 Ok(Self(Buffers(
85 num::NonZero::<u16>::MIN.saturating_add(entries - 1),
86 )))
87 }
88}
89
90const _: () = assert!(std::mem::size_of::<Ring>() == std::mem::size_of::<Buffers>());
91
92#[derive(Clone, Copy, PartialEq, Eq)]
93#[repr(transparent)]
94pub struct Datagram(Receive);
95
96impl Datagram {
97 pub const fn fixed<const ENTRIES: u16, const PAYLOAD: u32>() -> Self {
100 const {
101 assert!(ENTRIES >= 2);
102 assert!(ENTRIES.is_power_of_two());
103 let len = transfer::NonZero::from_payload(payload::Len::fixed::<PAYLOAD>());
104 assert!((ENTRIES as u64) * (len.into_nonzero().get() as u64) <= isize::MAX as u64);
105 let entries = Buffers(num::NonZero::<u16>::MIN.saturating_add(ENTRIES - 1));
106 Self(Receive::from_parts(entries, len))
107 }
108 }
109
110 pub const fn new(entries: Ring, payload: payload::Len) -> Self {
111 let len = transfer::NonZero::from_payload(payload);
112 Self(Receive::from_parts(entries.buffers(), len))
113 }
114
115 pub const fn receive(self) -> Receive {
116 self.0
117 }
118}
119
120const _: () = {
121 assert!(std::mem::size_of::<Datagram>() == std::mem::size_of::<Receive>());
122 assert!(std::mem::align_of::<Datagram>() == std::mem::align_of::<Receive>());
123};
124
125const MIN_SUBMISSION_CAPACITY: u32 = (option::MAX_STREAM_OPTIONS + 1) as u32;
126const MAX_SUBMISSION_CAPACITY: u32 = 32_768;
127const MAX_COMPLETION_CAPACITY: u32 = 65_536;
128pub(crate) const MAX_FILE_CAPACITY: u32 = SLOT_MASK as u32 + 1;
129
130#[derive(Clone, Copy, PartialEq, Eq)]
132#[repr(u8)]
133pub enum Progress {
134 Prompt,
136 BatchedWhenSupported,
138}
139
140pub trait Profile {
145 const QUEUES: QueueLayout;
146 const SCHEDULER: Schedule = Schedule::DEFAULT;
147 const COMPLETION_PROGRESS: Progress = Progress::BatchedWhenSupported;
148 const FILES: FileSlots = FileSlots::fixed::<0, 256>();
151 const RECEIVE: Receive = Receive::DEFAULT;
152 const RESIDENT_DOMAINS: Domain = Domain::ZERO;
154}
155
156#[derive(Clone, Copy, PartialEq, Eq, Debug)]
157#[repr(transparent)]
158pub struct Buffers(num::NonZero<u16>);
159
160impl Buffers {
161 pub const fn into_nonzero(self) -> num::NonZero<u16> {
162 self.0
163 }
164
165 pub(crate) const fn get(self) -> u16 {
166 self.0.get()
167 }
168}
169
170#[derive(Clone, Copy, Debug, PartialEq, Eq)]
171pub struct QueueLayout {
172 submissions: Submission,
173 completions: Completion,
174}
175
176impl QueueLayout {
177 pub const fn fixed<const SUBMISSIONS: u32, const COMPLETIONS: u32>() -> Self {
179 const {
180 assert!(SUBMISSIONS >= MIN_SUBMISSION_CAPACITY);
181 assert!(SUBMISSIONS <= MAX_SUBMISSION_CAPACITY);
182 assert!(SUBMISSIONS.is_power_of_two());
183 assert!(COMPLETIONS != 0);
184 assert!(COMPLETIONS <= MAX_COMPLETION_CAPACITY);
185 assert!(COMPLETIONS.is_power_of_two());
186 assert!(COMPLETIONS >= SUBMISSIONS);
187 QueueLayout {
188 submissions: Submission(bounded::U32::clamp(SUBMISSIONS as usize)),
189 completions: Completion(bounded::U32::clamp(COMPLETIONS as usize)),
190 }
191 }
192 }
193
194 pub fn resolve(self, need: demands::Submit) -> Result<Self, errors::Claim> {
196 let wanted = self.submissions().max(need.get());
197 let submit = wanted
198 .checked_next_power_of_two()
199 .ok_or(errors::Claim::QueueSubmissionsPowerOfTwoOverflow { requested: wanted })?;
200 if submit > MAX_SUBMISSION_CAPACITY {
201 return Err(errors::Config::QueueSubmissionsOutOfRange {
202 actual: submit,
203 minimum: MIN_SUBMISSION_CAPACITY,
204 maximum: MAX_SUBMISSION_CAPACITY,
205 }
206 .into());
207 }
208
209 let complete = self.completions().max(submit);
210
211 Ok(Self {
212 submissions: Submission(bounded::U32::clamp(submit as usize)),
213 completions: Completion(bounded::U32::clamp(complete as usize)),
214 })
215 }
216
217 pub const fn submission(self) -> Submission {
218 self.submissions
219 }
220
221 pub(crate) const fn completion(self) -> Completion {
222 self.completions
223 }
224
225 pub(crate) const fn submissions(self) -> u32 {
226 self.submissions.get()
227 }
228
229 pub(crate) const fn completions(self) -> u32 {
230 self.completions.get()
231 }
232}
233
234#[derive(Clone, Copy, PartialEq, Eq)]
236pub struct FileSlots {
237 accept: table::Capacity,
238 table: bounded::U32<1, MAX_FILE_CAPACITY>,
239}
240
241impl FileSlots {
242 pub const fn fixed<const ACCEPT: u32, const OUTBOUND: u32>() -> Self {
246 const {
247 assert!(ACCEPT <= u32::MAX - OUTBOUND);
248 assert!(OUTBOUND != 0);
249 let total = ACCEPT + OUTBOUND;
250 assert!(total <= MAX_FILE_CAPACITY);
251 FileSlots {
252 accept: table::Capacity(capacity::Count::new(ACCEPT)),
253 table: bounded::U32::clamp(total as usize),
254 }
255 }
256 }
257
258 pub fn resolve(self, need: demands::Files) -> Result<Self, errors::Config> {
260 let accept = self.accept().raw().max(need.accepted().get());
261 let outbound = self.outbound().raw().max(need.outbound().get());
262 let total = accept as u64 + outbound as u64;
263 let maximum = MAX_FILE_CAPACITY;
264 if total > maximum as u64 {
265 return Err(errors::Config::DescriptorCapacityOutOfRange {
266 accepted: accept,
267 outbound,
268 actual: total,
269 minimum: 1,
270 maximum,
271 });
272 }
273 Ok(Self {
274 accept: table::Capacity(capacity::Count::new(accept)),
275 table: bounded::U32::clamp(total as usize),
276 })
277 }
278
279 #[must_use]
280 pub const fn capacity(self) -> table::Capacity {
281 table::Capacity(capacity::Count::new(self.table.get()))
282 }
283
284 #[must_use]
285 pub const fn accept(self) -> table::Capacity {
286 self.accept
287 }
288
289 #[must_use]
290 pub const fn outbound(self) -> table::Capacity {
291 table::Capacity(capacity::Count::new(self.table.get() - self.accept.raw()))
292 }
293
294 pub(crate) fn slots(self) -> impl DoubleEndedIterator<Item = SlotIndex> + ExactSizeIterator {
295 self.capacity()
296 .into_iter()
297 .rev()
298 .take(self.outbound().count().get())
299 .rev()
300 }
301
302 pub(crate) fn accept_slot(self) -> Option<SlotIndex> {
303 let span = self.accept.span()?;
304 Some(SlotIndex::from_field(u64::from(span.get())))
305 }
306
307 pub(crate) const fn bound(self) -> bounded::U32<1, MAX_FILE_CAPACITY> {
308 self.table
309 }
310}
311
312#[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
315#[repr(transparent)]
316pub struct Domain(u32);
317
318impl Domain {
319 pub const ZERO: Self = Self(0);
320 pub const ONE: Self = Self(1);
321 pub const MAX: Self = Self(u32::MAX);
322
323 pub const fn fixed<const COUNT: u32>() -> Self {
325 Self(COUNT)
326 }
327
328 #[must_use]
330 pub const fn resolve(self, need: Self) -> Self {
331 if self.0 >= need.0 { self } else { need }
332 }
333
334 pub const fn combine(self, next: Self) -> Result<Self, DomainSum> {
335 match self.0.checked_add(next.0) {
336 Some(total) => Ok(Self(total)),
337 None => Err(DomainSum {
338 current: self,
339 added: next,
340 }),
341 }
342 }
343
344 #[must_use]
345 pub const fn get(self) -> u32 {
346 self.0
347 }
348}
349
350const _: () = {
351 assert!(std::mem::size_of::<Domain>() == std::mem::size_of::<u32>());
352 assert!(std::mem::align_of::<Domain>() == std::mem::align_of::<u32>());
353};
354
355#[derive(Clone, Copy, PartialEq, Eq, Debug)]
356#[repr(transparent)]
357pub struct Submission(bounded::U32<MIN_SUBMISSION_CAPACITY, MAX_SUBMISSION_CAPACITY>);
358
359impl Submission {
360 pub(crate) const fn get(self) -> u32 {
361 self.0.get()
362 }
363}
364
365#[derive(Clone, Copy, PartialEq, Eq, Debug)]
366#[repr(transparent)]
367pub(crate) struct Completion(pub(crate) bounded::U32<1, MAX_COMPLETION_CAPACITY>);
368
369impl Completion {
370 pub(crate) const fn get(self) -> u32 {
371 self.0.get()
372 }
373}
374
375const _: () = {
376 assert!(std::mem::size_of::<Completion>() == std::mem::size_of::<u32>());
377 assert!(std::mem::align_of::<Completion>() == std::mem::align_of::<u32>());
378};
379
380impl From<FileSlots> for (table::Capacity, table::Capacity) {
381 fn from(layout: FileSlots) -> Self {
382 (layout.capacity(), layout.accept)
383 }
384}
385
386unsafe impl depot::raw::Count for Completion {
388 const MAX: u32 = MAX_COMPLETION_CAPACITY;
389
390 fn count(self) -> capacity::Count {
391 capacity::Count::new(self.0.get())
392 }
393}