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