ergot/
lib.rs

1#![doc = include_str!("../README.md")]
2#![cfg_attr(not(any(test, feature = "std")), no_std)]
3#![allow(clippy::uninlined_format_args)]
4
5pub mod address;
6pub mod book;
7pub mod interface_manager;
8pub mod logging;
9pub mod nash;
10pub mod net_stack;
11pub mod socket;
12pub mod toolkits;
13pub mod traits;
14pub mod well_known;
15pub mod wire_frames;
16
17#[cfg(any(test, feature = "std"))]
18pub mod conformance;
19
20// Compat hack, remove on next breaking change
21pub use logging::fmtlog;
22
23use crate::logging::warn;
24pub use address::Address;
25use interface_manager::InterfaceSendError;
26use nash::NameHash;
27pub use net_stack::{NetStack, NetStackSendError};
28use serde::{Deserialize, Serialize};
29
30#[cfg_attr(feature = "defmt-v1", derive(defmt::Format))]
31#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Eq)]
32pub struct FrameKind(pub u8);
33
34#[cfg_attr(feature = "defmt-v1", derive(defmt::Format))]
35#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
36pub struct Key(pub [u8; 8]);
37
38#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
39pub struct ProtocolError(pub u16);
40
41#[cfg_attr(feature = "defmt-v1", derive(defmt::Format))]
42#[derive(Debug, Clone, PartialEq)]
43pub struct AnyAllAppendix {
44    pub key: Key,
45    pub nash: Option<NameHash>,
46}
47
48#[cfg_attr(feature = "defmt-v1", derive(defmt::Format))]
49#[derive(Debug, Clone, PartialEq)]
50pub struct Header {
51    pub src: Address,
52    pub dst: Address,
53    pub any_all: Option<AnyAllAppendix>,
54    pub seq_no: Option<u16>,
55    pub kind: FrameKind,
56    pub ttl: u8,
57}
58
59#[cfg_attr(feature = "defmt-v1", derive(defmt::Format))]
60#[derive(Debug, Clone)]
61pub struct HeaderSeq {
62    pub src: Address,
63    pub dst: Address,
64    pub any_all: Option<AnyAllAppendix>,
65    pub seq_no: u16,
66    pub kind: FrameKind,
67    pub ttl: u8,
68}
69
70impl core::fmt::Display for Header {
71    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
72        write!(
73            f,
74            "({} -> {}; FK:{:03}, SQ:",
75            self.src, self.dst, self.kind.0,
76        )?;
77        if let Some(seq) = self.seq_no {
78            write!(f, "{:04X}", seq)?;
79        } else {
80            f.write_str("----")?;
81        }
82        f.write_str(")")?;
83        Ok(())
84    }
85}
86
87impl core::fmt::Display for HeaderSeq {
88    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
89        write!(
90            f,
91            "({} -> {}; FK:{:03}, SQ:{:04X})",
92            self.src, self.dst, self.kind.0, self.seq_no,
93        )?;
94        Ok(())
95    }
96}
97
98impl FrameKind {
99    pub const RESERVED: Self = Self(0);
100    pub const ENDPOINT_REQ: Self = Self(1);
101    pub const ENDPOINT_RESP: Self = Self(2);
102    pub const TOPIC_MSG: Self = Self(3);
103    pub const PROTOCOL_ERROR: Self = Self(u8::MAX);
104}
105
106impl postcard_schema::Schema for FrameKind {
107    const SCHEMA: &'static postcard_schema::schema::NamedType =
108        &postcard_schema::schema::NamedType {
109            name: "FrameKind",
110            ty: u8::SCHEMA.ty,
111        };
112}
113
114impl postcard_schema::Schema for Key {
115    const SCHEMA: &'static postcard_schema::schema::NamedType =
116        &postcard_schema::schema::NamedType {
117            name: "Key",
118            ty: <[u8; 8]>::SCHEMA.ty,
119        };
120}
121
122impl ProtocolError {
123    pub const RESERVED: Self = Self(0);
124    // 1..11: SocketSendError
125    pub const SSE_NO_SPACE: Self = Self(1);
126    pub const SSE_DESER_FAILED: Self = Self(2);
127    pub const SSE_TYPE_MISMATCH: Self = Self(3);
128    pub const SSE_WHAT_THE_HELL: Self = Self(4);
129    // 11..21: InterfaceSendError
130    pub const ISE_DESTINATION_LOCAL: Self = Self(11);
131    pub const ISE_NO_ROUTE_TO_DEST: Self = Self(12);
132    pub const ISE_INTERFACE_FULL: Self = Self(13);
133    pub const ISE_INTERNAL_ERROR: Self = Self(14);
134    pub const ISE_ANY_PORT_MISSING_KEY: Self = Self(15);
135    pub const ISE_TTL_EXPIRED: Self = Self(16);
136    pub const ISE_ROUTING_LOOP: Self = Self(17);
137    // 21..31: NetStackSendError
138    pub const NSSE_NO_ROUTE: Self = Self(21);
139    pub const NSSE_ANY_PORT_MISSING_KEY: Self = Self(22);
140    pub const NSSE_WRONG_PORT_KIND: Self = Self(23);
141    pub const NSSE_ANY_PORT_NOT_UNIQUE: Self = Self(24);
142    pub const NSSE_ALL_PORT_MISSING_KEY: Self = Self(25);
143    pub const NSSE_WOULD_DEADLOCK: Self = Self(26);
144}
145
146impl Header {
147    #[inline]
148    pub fn with_seq(self, seq_no: u16) -> HeaderSeq {
149        let Self {
150            src,
151            dst,
152            any_all,
153            seq_no: _,
154            kind,
155            ttl,
156        } = self;
157        HeaderSeq {
158            src,
159            dst,
160            any_all,
161            seq_no,
162            kind,
163            ttl,
164        }
165    }
166
167    #[inline]
168    pub fn to_headerseq_or_with_seq<F: FnOnce() -> u16>(&self, f: F) -> HeaderSeq {
169        HeaderSeq {
170            src: self.src,
171            dst: self.dst,
172            any_all: self.any_all.clone(),
173            seq_no: self.seq_no.unwrap_or_else(f),
174            kind: self.kind,
175            ttl: self.ttl,
176        }
177    }
178
179    #[inline]
180    pub fn decrement_ttl(&mut self) -> Result<(), InterfaceSendError> {
181        self.ttl = self.ttl.checked_sub(1).ok_or_else(|| {
182            warn!("Header TTL expired: {:?}", self);
183            InterfaceSendError::TtlExpired
184        })?;
185        Ok(())
186    }
187}
188
189impl HeaderSeq {
190    #[inline]
191    pub fn decrement_ttl(&mut self) -> Result<(), InterfaceSendError> {
192        self.ttl = self.ttl.checked_sub(1).ok_or_else(|| {
193            warn!("Header TTL expired: {:?}", self);
194            InterfaceSendError::TtlExpired
195        })?;
196        Ok(())
197    }
198}
199
200impl From<HeaderSeq> for Header {
201    fn from(val: HeaderSeq) -> Self {
202        Self {
203            src: val.src,
204            dst: val.dst,
205            any_all: val.any_all.clone(),
206            seq_no: Some(val.seq_no),
207            kind: val.kind,
208            ttl: val.ttl,
209        }
210    }
211}
212
213pub const DEFAULT_TTL: u8 = 16;
214
215/// Exports of used crate versions
216pub mod exports {
217    pub use bbq2;
218    pub use mutex;
219}