Skip to main content

prns_runtime/manifold/
grant.rs

1use crate::engine::FanTarget;
2use crate::interfaces::{FrameSink, FrameSinkError, InterfaceId, PacketPhyStats, INTERFACE_ID_LEN};
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5// repr(C): crosses the dual-core channel inside `FrameSlot`; see the layout note on `PrnsCommand`.
6#[repr(C)]
7pub enum FrameTarget {
8    Direct(InterfaceId),
9    Fan(FanTarget),
10}
11
12pub struct FrameSlot<const FRAME: usize> {
13    pub target: FrameTarget,
14    pub len: usize,
15    pub bytes: [u8; FRAME],
16    pub packet_phy: PacketPhyStats,
17}
18
19impl<const FRAME: usize> FrameSlot<FRAME> {
20    pub const fn empty() -> Self {
21        Self {
22            target: FrameTarget::Direct(InterfaceId::new([0u8; INTERFACE_ID_LEN])),
23            len: 0,
24            bytes: [0u8; FRAME],
25            packet_phy: PacketPhyStats {
26                rssi: None,
27                snr: None,
28                quality: None,
29            },
30        }
31    }
32
33    fn fill(&mut self, frame: &[u8]) {
34        self.packet_phy = PacketPhyStats::default();
35        debug_assert!(
36            frame.len() <= FRAME,
37            "a {}-byte frame cannot fit this {FRAME}-byte slot",
38            frame.len()
39        );
40        let len = frame.len().min(FRAME);
41        self.bytes[..len].copy_from_slice(&frame[..len]);
42        self.len = len;
43    }
44
45    pub fn fill_for(&mut self, interface_id: InterfaceId, frame: &[u8]) {
46        self.target = FrameTarget::Direct(interface_id);
47        self.fill(frame);
48    }
49
50    pub fn fill_for_fan(&mut self, fan: FanTarget, frame: &[u8]) {
51        self.target = FrameTarget::Fan(fan);
52        self.fill(frame);
53    }
54
55    pub fn frame(&self) -> &[u8] {
56        &self.bytes[..self.len]
57    }
58
59    pub fn frame_mut(&mut self) -> &mut [u8] {
60        let len = self.len;
61        &mut self.bytes[..len]
62    }
63}
64
65/// As a [`FrameSink`] the slot is a streaming deframer's destination: `len` is the accumulation cursor, and the committer stamps `target` when the frame is done.
66impl<const FRAME: usize> FrameSink for FrameSlot<FRAME> {
67    fn clear(&mut self) {
68        self.len = 0;
69        self.packet_phy = PacketPhyStats::default();
70    }
71
72    fn frame_len(&self) -> usize {
73        self.len
74    }
75
76    fn free_capacity(&self) -> usize {
77        FRAME.saturating_sub(self.len)
78    }
79
80    fn push(&mut self, byte: u8) -> Result<(), FrameSinkError> {
81        if self.len >= FRAME {
82            return Err(FrameSinkError::Full);
83        }
84        self.bytes[self.len] = byte;
85        self.len += 1;
86        Ok(())
87    }
88
89    fn extend_from_slice(&mut self, run: &[u8]) -> Result<(), FrameSinkError> {
90        if run.len() > FRAME.saturating_sub(self.len) {
91            return Err(FrameSinkError::Full);
92        }
93        self.bytes[self.len..self.len + run.len()].copy_from_slice(run);
94        self.len += run.len();
95        Ok(())
96    }
97}
98
99#[allow(async_fn_in_trait)]
100pub trait GrantProducer<const FRAME: usize> {
101    fn try_grant(&mut self) -> Option<&mut FrameSlot<FRAME>>;
102    async fn grant(&mut self) -> &mut FrameSlot<FRAME>;
103    fn commit(&mut self);
104}
105
106#[allow(async_fn_in_trait)]
107pub trait GrantConsumer<const FRAME: usize> {
108    fn try_peek(&mut self) -> Option<&mut FrameSlot<FRAME>>;
109    async fn peek(&mut self) -> &mut FrameSlot<FRAME>;
110    fn release(&mut self);
111}
112
113pub trait ManifoldLaneReader: Send {
114    fn try_read(&mut self) -> Option<(FrameTarget, PacketPhyStats, &mut [u8])>;
115    fn release(&mut self);
116}
117
118#[derive(Debug, Clone, Copy, PartialEq, Eq)]
119#[must_use]
120pub enum LaneWriteOutcome {
121    Written,
122    Full,
123    FrameTooLarge { frame_len: usize, capacity: usize },
124}
125
126pub trait ManifoldLaneWriter: Send {
127    fn try_write(&mut self, target: FrameTarget, frame: &[u8]) -> LaneWriteOutcome;
128}