ergot_base/interface_manager/mod.rs
1//! The Interface Manager
2//!
3//! The [`NetStack`] is generic over an "Interface Manager", which is
4//! responsible for handling any external interfaces of the current program
5//! or device.
6//!
7//! Different interface managers may support a various number of external
8//! interfaces. The simplest interface manager is a "Null Interface Manager",
9//! Which supports no external interfaces, meaning that messages may only be
10//! routed locally.
11//!
12//! The next simplest interface manager is one that only supports zero or one
13//! active interfaces, for example if a device is directly connected to a PC
14//! using USB. In this case, routing is again simple: if messages are not
15//! intended for the local device, they should be routed out of the one external
16//! interface. Similarly, if we support an interface, but it is not connected
17//! (e.g. the USB cable is unplugged), all packets with external destinations
18//! will fail to send.
19//!
20//! For more complex devices, an interface manager with multiple (bounded or
21//! unbounded) interfaces, and more complex routing capabilities, may be
22//! selected.
23//!
24//! Unlike Sockets, which might be various and diverse on all systems, a system
25//! is expected to have one statically-known interface manager, which may
26//! manage various and diverse interfaces. Therefore, the interface manager is
27//! a generic type (unlike sockets), while the interfaces owned by an interface
28//! manager use similar "trick"s like the socket list to handle different
29//! kinds of interfaces (for example, USB on one interface, and RS-485 on
30//! another).
31//!
32//! In general when sending a message, the [`NetStack`] will check if the
33//! message is definitively for the local device (e.g. Net ID = 0, Node ID = 0),
34//! and if not the NetStack will pass the message to the Interface Manager. If
35//! the interface manager can route this packet, it informs the NetStack it has
36//! done so. If the Interface Manager realizes that the packet is still for us
37//! (e.g. matching a Net ID and Node ID of the local device), it may bounce the
38//! message back to the NetStack to locally route.
39//!
40//! [`NetStack`]: crate::NetStack
41
42use crate::{Header, ProtocolError};
43use serde::Serialize;
44
45pub mod null;
46pub mod std_tcp_client;
47pub mod std_tcp_router;
48pub mod std_utils;
49
50#[derive(Debug, PartialEq, Eq)]
51#[non_exhaustive]
52pub enum InterfaceSendError {
53 /// Refusing to send local destination remotely
54 DestinationLocal,
55 /// Interface Manager does not know how to route to requested destination
56 NoRouteToDest,
57 /// Interface Manager found a destination interface, but that interface
58 /// was full in space/slots
59 InterfaceFull,
60 /// TODO: Remove
61 PlaceholderOhNo,
62 /// Destination was an "any" port, but a key was not provided
63 AnyPortMissingKey,
64 /// TTL has reached the terminal value
65 TtlExpired,
66}
67
68pub trait ConstInit {
69 const INIT: Self;
70}
71
72// An interface send is very similar to a socket send, with the exception
73// that interface sends are ALWAYS a serializing operation (or requires
74// serialization has already been done), which means we don't need to
75// differentiate between "send owned" and "send borrowed". The exception
76// to this is "send raw", where serialization has already been done, e.g.
77// if we are routing a packet.
78pub trait InterfaceManager {
79 fn send<T: Serialize>(&mut self, hdr: &Header, data: &T) -> Result<(), InterfaceSendError>;
80 fn send_err(&mut self, hdr: &Header, err: ProtocolError) -> Result<(), InterfaceSendError>;
81 fn send_raw(&mut self, hdr: &Header, data: &[u8]) -> Result<(), InterfaceSendError>;
82}
83
84impl InterfaceSendError {
85 pub fn to_error(&self) -> ProtocolError {
86 match self {
87 InterfaceSendError::DestinationLocal => ProtocolError::ISE_DESTINATION_LOCAL,
88 InterfaceSendError::NoRouteToDest => ProtocolError::ISE_NO_ROUTE_TO_DEST,
89 InterfaceSendError::InterfaceFull => ProtocolError::ISE_INTERFACE_FULL,
90 InterfaceSendError::PlaceholderOhNo => ProtocolError::ISE_PLACEHOLDER_OH_NO,
91 InterfaceSendError::AnyPortMissingKey => ProtocolError::ISE_ANY_PORT_MISSING_KEY,
92 InterfaceSendError::TtlExpired => ProtocolError::ISE_TTL_EXPIRED,
93 }
94 }
95}