dtp/lib.rs
1// dtp/src/lib.rs
2
3// The core of your library depends on the `bytes` crate for efficient payload handling
4// and `dev_utils` for formatting in the Display implementation.
5use bytes::Bytes;
6use dev_utils::format::*;
7use std::fmt::{self, Display, Formatter};
8
9
10// Main layers (modules)
11pub mod datalink;
12pub mod network;
13pub mod transport;
14
15
16// --- GENERIC BUILDING BLOCKS ---
17
18/// A generic container for a source and destination address pair.
19pub type AddressPair<A> = (A, A);
20
21/// A generic header containing a pair of addresses.
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23pub struct Header<A> {
24 pub addresses: AddressPair<A>,
25}
26
27impl<A> Header<A> {
28 /// Creates a new header with source and destination addresses.
29 pub fn new(src: A, dst: A) -> Self {
30 Self {
31 addresses: (src, dst),
32 }
33 }
34 /// Returns a reference to the source address.
35 pub fn src(&self) -> &A {
36 &self.addresses.0
37 }
38 /// Returns a reference to the destination address.
39 pub fn dst(&self) -> &A {
40 &self.addresses.1
41 }
42}
43
44/// A macro to quickly define address types and their default `Header` implementations.
45macro_rules! define_addresses {
46 ($($(#[$meta_d:meta])* $name:ident: $inner:ty, $default:expr),* $(,)?) => {
47 $(
48 $(#[$meta_d])*
49 pub type $name = $inner;
50
51 impl Default for Header<$name> {
52 fn default() -> Self {
53 let default_addr: $name = $default;
54 Self {addresses: (default_addr, default_addr),}
55 }
56 }
57 )*
58 };
59}
60
61// Define the concrete address types used in the protocol stack.
62define_addresses! {
63 /// Represents a Data Link Layer MAC address ([u8; 6]).
64 MacAddress: [u8; 6], [0, 0, 0, 0, 0, 0],
65 /// Represents a Network Layer IPv4 address (u32).
66 Ipv4Address: u32, 0x7F000001, // 127.0.0.1
67 /// Represents a Transport Layer Port address (u16).
68 PortAddress: u16, 80,
69}
70
71/// A macro to implement the `IntoIterator` trait for the layered structs,
72/// allowing easy iteration over their payloads.
73macro_rules! impl_iterator_trait {
74 ($name:ident, $payload_field:ident, $payload_ty:ty) => {
75 // Implementation for consuming iteration: `for item in layer_struct { ... }`
76 impl IntoIterator for $name {
77 type Item = <$payload_ty as IntoIterator>::Item;
78 type IntoIter = <$payload_ty as IntoIterator>::IntoIter;
79
80 fn into_iter(self) -> Self::IntoIter {
81 self.$payload_field.into_iter()
82 }
83 }
84
85 // Implementation for borrowing iteration: `for item in &layer_struct { ... }`
86 impl<'a> IntoIterator for &'a $name {
87 type Item = &'a <$payload_ty as IntoIterator>::Item;
88 type IntoIter = std::slice::Iter<'a, <$payload_ty as IntoIterator>::Item>;
89
90 fn into_iter(self) -> Self::IntoIter {
91 self.$payload_field.iter()
92 }
93 }
94 };
95}
96
97/// A macro to define a protocol layer struct (`Frame`, `Packet`, `Segment`).
98/// This reduces boilerplate by creating the struct definition, `new` and `Default`
99/// implementations, a rich `Display` implementation, and iterator support.
100macro_rules! define_layer_struct {
101 (
102 $(
103 $(#[$meta:meta])*
104 $name:ident { header: $header_ty:ty, $payload_field:ident: $payload_ty:ty $(,)? }
105 ),* $(,)?
106 ) => {
107 $(
108 $(#[$meta])*
109 #[derive(Clone, PartialEq, Debug)]
110 pub struct $name {
111 pub header: Header<$header_ty>,
112 pub $payload_field: $payload_ty,
113 }
114
115 impl $name {
116 /// Constructs a new instance of the layer.
117 pub fn new(header: Header<$header_ty>, $payload_field: $payload_ty) -> Self {
118 Self {
119 header,
120 $payload_field,
121 }
122 }
123 }
124
125 impl Default for $name {
126 fn default() -> Self {
127 Self {
128 header: Header::<$header_ty>::default(),
129 $payload_field: Default::default(),
130 }
131 }
132 }
133
134 impl Display for $name {
135 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
136 writeln!( f, "{}", format!(
137 "src: {:X?} -> dst: {:X?} | {:>4} {} |",
138 self.header.addresses.0,
139 self.header.addresses.1,
140 self.$payload_field.len(),
141 // A bit of a trick to get a plural 's' correctly
142 if self.$payload_field.len() == 1 { stringify!($payload_field).trim_end_matches('s') } else { stringify!($payload_field) }
143 ).style(Style::Italic)
144 )?;
145 for (idx, item) in self.$payload_field.iter().enumerate() {
146 // Recursively print the nested layers with indentation
147 let item_str = format!("{}", item);
148 for line in item_str.lines() {
149 writeln!(f, "\t{}", line)?;
150 }
151 }
152 Ok(())
153 }
154 }
155
156 // Implement iteration for the struct
157 impl_iterator_trait!($name, $payload_field, $payload_ty);
158 )*
159 }
160}
161
162
163// --- PROTOCOL STACK DEFINITIONS ---
164
165define_layer_struct! {
166 /// Represents a Transport Layer Segment. It carries the raw application data payload.
167 Segment { header: PortAddress, payload: Bytes },
168
169 /// Represents a Network Layer Packet. It contains one or more `Segment`s.
170 Packet { header: Ipv4Address, pdu: Vec<Segment> },
171
172 /// Represents a Data Link Layer Frame. This is the final container, holding one or more `Packet`s.
173 Frame { header: MacAddress, network_pdu: Vec<Packet> },
174}
175
176
177// --- CORE TRAITS ---
178
179/// A trait for types that can be serialized into a byte vector.
180pub trait ToBytes {
181 /// Converts the structure to a byte representation.
182 fn to_bytes(&self) -> Vec<u8>;
183}
184
185/// A trait for getting size information about a network layer.
186pub trait LayerSize {
187 /// Returns the size of the payload in bytes.
188 fn payload_size(&self) -> usize;
189 /// Returns the total size of the layer, including headers.
190 fn total_size(&self) -> usize;
191}
192
193/// A generic builder trait.
194pub trait LayerBuilder {
195 type Output;
196 /// Builds the final output from the builder's configuration.
197 fn build(&self) -> Self::Output;
198}