Skip to main content

dope_core/driver/settings/
receive.rs

1use std::num;
2
3use crate::{
4    driver::settings::{Buffers, Ring, demands, errors},
5    io::{datagram::payload, transfer},
6};
7
8#[derive(Clone, Copy, PartialEq, Eq)]
9pub struct Receive {
10    pub(in crate::driver::settings) entries: Buffers,
11    pub(in crate::driver::settings) len: transfer::NonZero,
12}
13
14impl Receive {
15    pub const DEFAULT: Self = Self::fixed::<4096, 4096>();
16    pub const MIN_DATAGRAM_SLOT: transfer::NonZero =
17        transfer::NonZero::from_payload(payload::Len::fixed::<1>());
18
19    pub const fn fixed<const ENTRIES: u16, const LEN: u32>() -> Self {
20        const {
21            assert!(ENTRIES >= 2);
22            assert!(ENTRIES.is_power_of_two());
23            assert!(LEN != 0);
24            assert!(LEN <= transfer::MAX_BYTES as u32);
25            assert!((ENTRIES as usize) <= (isize::MAX as usize) / (LEN as usize));
26            Self {
27                entries: Buffers(num::NonZero::<u16>::MIN.saturating_add(ENTRIES - 1)),
28                len: transfer::NonZero::fixed::<LEN>(),
29            }
30        }
31    }
32
33    pub(super) const fn from_parts(entries: Buffers, len: transfer::NonZero) -> Self {
34        Self { entries, len }
35    }
36
37    pub fn resolve(self, need: demands::Receive) -> Result<Self, errors::Claim> {
38        let base = demands::Receive::from(self);
39        let entries = if base.entries().get() >= need.entries().get() {
40            base.entries()
41        } else {
42            need.entries()
43        };
44        let len = base.buffer_len().max(need.buffer_len());
45        Self::exact(demands::Receive::new(entries, len))
46    }
47
48    pub fn exact(need: demands::Receive) -> Result<Self, errors::Claim> {
49        let entries = Ring::try_round(need.entries().get())?;
50        let len = transfer::NonZero::try_from(need.buffer_len())
51            .map_err(errors::Config::ReceiveBuffer)?;
52        Self::assemble(entries, len).map_err(Into::into)
53    }
54
55    pub(super) const fn assemble(
56        entries: Ring,
57        len: transfer::NonZero,
58    ) -> Result<Self, errors::Config> {
59        let entries = entries.buffers();
60        let raw = len.into_nonzero().get();
61        let bytes = entries.get() as u64 * raw as u64;
62        if bytes > isize::MAX as u64 {
63            return Err(errors::Config::ReceiveAllocationTooLarge {
64                entries: entries.get(),
65                buffer_len: raw,
66                actual: bytes,
67                maximum: isize::MAX as u64,
68            });
69        }
70        Ok(Self { entries, len })
71    }
72
73    pub const fn buffers(self) -> Buffers {
74        self.entries
75    }
76    pub(crate) const fn entries(self) -> u16 {
77        self.entries.get()
78    }
79    pub(crate) const fn count(self) -> num::NonZero<u16> {
80        self.entries.0
81    }
82    /// Keeps one receive slot available while other buffers remain accounted.
83    pub(crate) const fn accounts(self) -> u32 {
84        self.entries.get() as u32 - 1
85    }
86    /// Returns the positive slot length proven representable by every backend.
87    pub const fn buffer_len(self) -> transfer::NonZero {
88        self.len
89    }
90}