1use core::fmt;
2
3use crate::phy::{self, Device, DeviceCapabilities, Medium};
4use crate::time::Instant;
5use crate::wire::pretty_print::{PrettyIndent, PrettyPrint};
6
7pub struct Tracer<D: Device> {
13 inner: D,
14 writer: fn(Instant, Packet),
15}
16
17impl<D: Device> Tracer<D> {
18 pub fn new(inner: D, writer: fn(timestamp: Instant, packet: Packet)) -> Tracer<D> {
20 Tracer { inner, writer }
21 }
22
23 pub fn get_ref(&self) -> &D {
28 &self.inner
29 }
30
31 pub fn get_mut(&mut self) -> &mut D {
35 &mut self.inner
36 }
37
38 pub fn into_inner(self) -> D {
40 self.inner
41 }
42}
43
44impl<D: Device> Device for Tracer<D> {
45 type RxToken<'a> = RxToken<D::RxToken<'a>>
46 where
47 Self: 'a;
48 type TxToken<'a> = TxToken<D::TxToken<'a>>
49 where
50 Self: 'a;
51
52 fn capabilities(&self) -> DeviceCapabilities {
53 self.inner.capabilities()
54 }
55
56 fn receive(&mut self, timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> {
57 let medium = self.inner.capabilities().medium;
58 self.inner.receive(timestamp).map(|(rx_token, tx_token)| {
59 let rx = RxToken {
60 token: rx_token,
61 writer: self.writer,
62 medium,
63 timestamp,
64 };
65 let tx = TxToken {
66 token: tx_token,
67 writer: self.writer,
68 medium,
69 timestamp,
70 };
71 (rx, tx)
72 })
73 }
74
75 fn transmit(&mut self, timestamp: Instant) -> Option<Self::TxToken<'_>> {
76 let medium = self.inner.capabilities().medium;
77 self.inner.transmit(timestamp).map(|tx_token| TxToken {
78 token: tx_token,
79 medium,
80 writer: self.writer,
81 timestamp,
82 })
83 }
84}
85
86#[doc(hidden)]
87pub struct RxToken<Rx: phy::RxToken> {
88 token: Rx,
89 writer: fn(Instant, Packet),
90 medium: Medium,
91 timestamp: Instant,
92}
93
94impl<Rx: phy::RxToken> phy::RxToken for RxToken<Rx> {
95 fn consume<R, F>(self, f: F) -> R
96 where
97 F: FnOnce(&[u8]) -> R,
98 {
99 self.token.consume(|buffer| {
100 (self.writer)(
101 self.timestamp,
102 Packet {
103 buffer,
104 medium: self.medium,
105 prefix: "<- ",
106 },
107 );
108 f(buffer)
109 })
110 }
111
112 fn meta(&self) -> phy::PacketMeta {
113 self.token.meta()
114 }
115}
116
117#[doc(hidden)]
118pub struct TxToken<Tx: phy::TxToken> {
119 token: Tx,
120 writer: fn(Instant, Packet),
121 medium: Medium,
122 timestamp: Instant,
123}
124
125impl<Tx: phy::TxToken> phy::TxToken for TxToken<Tx> {
126 fn consume<R, F>(self, len: usize, f: F) -> R
127 where
128 F: FnOnce(&mut [u8]) -> R,
129 {
130 self.token.consume(len, |buffer| {
131 let result = f(buffer);
132 (self.writer)(
133 self.timestamp,
134 Packet {
135 buffer,
136 medium: self.medium,
137 prefix: "-> ",
138 },
139 );
140 result
141 })
142 }
143
144 fn set_meta(&mut self, meta: phy::PacketMeta) {
145 self.token.set_meta(meta)
146 }
147}
148
149pub struct Packet<'a> {
150 buffer: &'a [u8],
151 medium: Medium,
152 prefix: &'static str,
153}
154
155impl<'a> fmt::Display for Packet<'a> {
156 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
157 let mut indent = PrettyIndent::new(self.prefix);
158 match self.medium {
159 #[cfg(feature = "medium-ethernet")]
160 Medium::Ethernet => crate::wire::EthernetFrame::<&'static [u8]>::pretty_print(
161 &self.buffer,
162 f,
163 &mut indent,
164 ),
165 #[cfg(feature = "medium-ip")]
166 Medium::Ip => match crate::wire::IpVersion::of_packet(self.buffer) {
167 #[cfg(feature = "proto-ipv4")]
168 Ok(crate::wire::IpVersion::Ipv4) => {
169 crate::wire::Ipv4Packet::<&'static [u8]>::pretty_print(
170 &self.buffer,
171 f,
172 &mut indent,
173 )
174 }
175 #[cfg(feature = "proto-ipv6")]
176 Ok(crate::wire::IpVersion::Ipv6) => {
177 crate::wire::Ipv6Packet::<&'static [u8]>::pretty_print(
178 &self.buffer,
179 f,
180 &mut indent,
181 )
182 }
183 _ => f.write_str("unrecognized IP version"),
184 },
185 #[cfg(feature = "medium-ieee802154")]
186 Medium::Ieee802154 => Ok(()), }
188 }
189}