ergot_base/interface_manager/
std_utils.rs

1use crate::{Address, FrameKind, HeaderSeq, Key};
2
3pub(crate) struct OwnedFrame {
4    pub(crate) hdr: HeaderSeq,
5    pub(crate) body: Vec<u8>,
6}
7
8#[derive(Debug, PartialEq)]
9pub enum ReceiverError {
10    SocketClosed,
11}
12
13pub(crate) fn ser_frame(frame: OwnedFrame) -> Vec<u8> {
14    let dst_any = frame.hdr.dst.port_id == 0;
15    let src = frame.hdr.src.as_u32();
16    let dst = frame.hdr.dst.as_u32();
17    let seq = frame.hdr.seq_no;
18
19    let mut out = vec![];
20    // TODO: This is bad and does a ton of allocs. yolo
21    //
22    out.extend_from_slice(&postcard::to_stdvec(&src).unwrap());
23    out.extend_from_slice(&postcard::to_stdvec(&dst).unwrap());
24    out.push(frame.hdr.kind.0);
25    if dst_any {
26        let key = frame.hdr.key.unwrap();
27        out.extend_from_slice(&key.0);
28    }
29
30    out.extend_from_slice(&postcard::to_stdvec(&seq).unwrap());
31    out.extend_from_slice(&frame.body);
32    let mut out = cobs::encode_vec(&out);
33    out.push(0);
34    out
35}
36
37pub(crate) fn de_frame(remain: &[u8]) -> Option<OwnedFrame> {
38    let (src_word, remain) = postcard::take_from_bytes::<u32>(remain).ok()?;
39    let src = Address::from_word(src_word);
40    let (dst_word, remain) = postcard::take_from_bytes::<u32>(remain).ok()?;
41    let dst = Address::from_word(dst_word);
42    let (kind, remain) = remain.split_first()?;
43    let kind = FrameKind(*kind);
44    let (key, remain) = if dst.port_id == 0 {
45        if remain.len() < 8 {
46            return None;
47        }
48        let (keyb, remain) = remain.split_at(8);
49        let mut buf = [0u8; 8];
50        buf.copy_from_slice(keyb);
51        (Some(Key(buf)), remain)
52    } else {
53        (None, remain)
54    };
55
56    let (seq, remain) = postcard::take_from_bytes::<u16>(remain).ok()?;
57    let body = remain.to_vec();
58
59    Some(OwnedFrame {
60        hdr: HeaderSeq {
61            src,
62            dst,
63            seq_no: seq,
64            key,
65            kind,
66        },
67        body,
68    })
69}
70
71pub(crate) mod acc {
72    //! Basically postcard's cobs accumulator, but without the deser part
73
74    pub struct CobsAccumulator {
75        buf: Box<[u8]>,
76        idx: usize,
77    }
78
79    /// The result of feeding the accumulator.
80    pub enum FeedResult<'input, 'buf> {
81        /// Consumed all data, still pending.
82        Consumed,
83
84        /// Buffer was filled. Contains remaining section of input, if any.
85        OverFull(&'input [u8]),
86
87        /// Reached end of chunk, but deserialization failed. Contains remaining section of input, if.
88        /// any
89        DeserError(&'input [u8]),
90
91        Success {
92            /// Decoded data.
93            data: &'buf [u8],
94
95            /// Remaining data left in the buffer after deserializing.
96            remaining: &'input [u8],
97        },
98    }
99
100    impl CobsAccumulator {
101        /// Create a new accumulator.
102        pub fn new(sz: usize) -> Self {
103            CobsAccumulator {
104                buf: vec![0u8; sz].into_boxed_slice(),
105                idx: 0,
106            }
107        }
108
109        /// Appends data to the internal buffer and attempts to deserialize the accumulated data into
110        /// `T`.
111        ///
112        /// This differs from feed, as it allows the `T` to reference data within the internal buffer, but
113        /// mutably borrows the accumulator for the lifetime of the deserialization.
114        /// If `T` does not require the reference, the borrow of `self` ends at the end of the function.
115        pub fn feed_raw<'me, 'input>(
116            &'me mut self,
117            input: &'input [u8],
118        ) -> FeedResult<'input, 'me> {
119            if input.is_empty() {
120                return FeedResult::Consumed;
121            }
122
123            let zero_pos = input.iter().position(|&i| i == 0);
124            let max_len = self.buf.len();
125
126            if let Some(n) = zero_pos {
127                // Yes! We have an end of message here.
128                // Add one to include the zero in the "take" portion
129                // of the buffer, rather than in "release".
130                let (take, release) = input.split_at(n + 1);
131
132                // TODO(AJM): We could special case when idx == 0 to avoid copying
133                // into the dest buffer if there's a whole packet in the input
134
135                // Does it fit?
136                if (self.idx + take.len()) <= max_len {
137                    // Aw yiss - add to array
138                    self.extend_unchecked(take);
139
140                    let retval = match cobs::decode_in_place(&mut self.buf[..self.idx]) {
141                        Ok(ct) => FeedResult::Success {
142                            data: &self.buf[..ct],
143                            remaining: release,
144                        },
145                        Err(_) => FeedResult::DeserError(release),
146                    };
147                    self.idx = 0;
148                    retval
149                } else {
150                    self.idx = 0;
151                    FeedResult::OverFull(release)
152                }
153            } else {
154                // Does it fit?
155                if (self.idx + input.len()) > max_len {
156                    // nope
157                    let new_start = max_len - self.idx;
158                    self.idx = 0;
159                    FeedResult::OverFull(&input[new_start..])
160                } else {
161                    // yup!
162                    self.extend_unchecked(input);
163                    FeedResult::Consumed
164                }
165            }
166        }
167
168        /// Extend the internal buffer with the given input.
169        ///
170        /// # Panics
171        ///
172        /// Will panic if the input does not fit in the internal buffer.
173        fn extend_unchecked(&mut self, input: &[u8]) {
174            let new_end = self.idx + input.len();
175            self.buf[self.idx..new_end].copy_from_slice(input);
176            self.idx = new_end;
177        }
178    }
179}