ergot_base/
address.rs

1//! Addressing
2//!
3//! Addresses in Ergot have three main components:
4//!
5//! * A 16-bit **Network ID**
6//! * An 8-bit **Node ID**
7//! * An 8-bit **Socket ID**
8//!
9//! This addressing is similar in form to AppleTalk's addressing. This
10//! addressing is quite different to how TCP/IP IPv4 addressing works.
11//!
12//! ### Network IDs
13//!
14//! Network IDs represent a single "network segment", where all nodes of a
15//! network segment can hear all messages sent on that segment.
16//!
17//! For example, in a point-to-point link (e.g. UART, TCP, USB), that link will
18//! be a single Network ID, containing two nodes. In a bus-style link
19//! (e.g. RS-485, I2C), the bus will be a single Network ID, with one or more
20//! nodes residing on that link.
21//!
22//! The Network ID of "0" is reserved, and is generally used when sending
23//! messages within the local device, or used to mean "the current network
24//! segment" before an interface has discovered the Network ID of the Network
25//! Segment it resides on.
26//!
27//! The Network ID of "65535" is reserved.
28//!
29//! Network IDs are intended to be discovered/negotiated at runtime, and are
30//! not typically hardcoded. The general process of negotiating Network IDs,
31//! particularly across multiple network segment hops, is not yet defined.
32//!
33//! Networks that require more than 65534 network segments are not supported
34//! by Ergot. At that point, you should probably just use IPv4/v6.
35//!
36//! ### Node IDs
37//!
38//! Node IDs represent a single entity on a network segment.
39//!
40//! The Node ID of "0" is reserved, and is generally used when sending messages
41//! within the local device.
42//!
43//! The Node ID of "255" is reserved.
44//!
45//! Network segments that require more than 254 nodes are not supported by
46//! Ergot.
47//!
48//! Network IDs are intended to be discovered/negotiated at runtime, and are
49//! not typically hardcoded. One exception to this is for known point-to-point
50//! network segments that have a defined "controller" and "target" role, such
51//! as USB (where the "host" is the "controller", and the "device" is the
52//! "target"). In these cases, the "controller" typically hardcodes the Node ID
53//! of "1", and the "target" hardcodes the Node ID of "2". This is done to
54//! reduce complexity on these interface implementations.
55//!
56//! ### Socket IDs
57//!
58//! Socket IDs represent a single receiving socket within a [`NetStack`].
59//!
60//! The Socket ID of "0" is reserved, and is generally used as a "wildcard"
61//! when sending messages to a device.
62//!
63//! The Socket ID of "255" is reserved.
64//!
65//! Systems that require more than 254 active sockets are not supported by
66//! Ergot.
67//!
68//! Socket IDs are assigned dynamically by the [`NetStack`], and are never
69//! intended to be hardcoded. Socket IDs may be recycled over time.
70//!
71//! If a device has multiple interfaces, and therefore has multiple (Network ID,
72//! Node ID) tuples that refer to it, the same Socket ID is used on all
73//! interfaces.
74//!
75//! ### Form on the wire
76//!
77//! When serialized into a packet, addresses are encoded with Network ID as the
78//! most significant bytes, and the socket ID as the least significant bytes,
79//! and then varint encoded. This means that in many cases, where "0" is used
80//! for the Network or Node ID, or low numbers are used, Addresses can be
81//! encoded in fewer than 4 bytes on the wire.
82//!
83//! For this reason, when negotiating any ID, lower numbers should be preferred
84//! when possible. Addresses are only encoded as larger than 4 bytes when
85//! addressing a network ID >= 4096.
86//!
87//! [`NetStack`]: crate::NetStack
88
89use serde::{Deserialize, Serialize};
90
91/// The Ergot Address type
92#[derive(Clone, Copy, Debug, PartialEq)]
93pub struct Address {
94    pub network_id: u16,
95    pub node_id: u8,
96    pub port_id: u8,
97}
98
99// ---- impl Address ----
100
101impl Address {
102    pub const fn unknown() -> Self {
103        Self {
104            network_id: 0,
105            node_id: 0,
106            port_id: 0,
107        }
108    }
109
110    #[inline]
111    pub fn net_node_any(&self) -> bool {
112        self.network_id == 0 && self.node_id == 0
113    }
114
115    #[inline]
116    pub fn as_u32(&self) -> u32 {
117        ((self.network_id as u32) << 16) | ((self.node_id as u32) << 8) | (self.port_id as u32)
118    }
119
120    #[inline]
121    pub fn from_word(word: u32) -> Self {
122        Self {
123            network_id: (word >> 16) as u16,
124            node_id: (word >> 8) as u8,
125            port_id: word as u8,
126        }
127    }
128}
129
130impl Serialize for Address {
131    #[inline]
132    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
133    where
134        S: serde::Serializer,
135    {
136        let val = self.as_u32();
137        val.serialize(serializer)
138    }
139}
140
141impl<'de> Deserialize<'de> for Address {
142    #[inline]
143    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
144    where
145        D: serde::Deserializer<'de>,
146    {
147        let val = u32::deserialize(deserializer)?;
148        Ok(Self::from_word(val))
149    }
150}
151
152#[cfg(feature = "postcard-schema-v0_2")]
153impl postcard_schema::Schema for Address {
154    const SCHEMA: &'static postcard_schema::schema::NamedType =
155        &postcard_schema::schema::NamedType {
156            name: "Address",
157            ty: u32::SCHEMA.ty,
158        };
159}