pub struct Mib {Show 35 fields
pub itsGnLocalGnAddr: GNAddress,
pub itsGnLocalGnAddrConfMethod: LocalGnAddrConfMethod,
pub itsGnProtocolVersion: u8,
pub itsGnIsMobile: GnIsMobile,
pub itsGnIfType: GnIfType,
pub itsGnMinUpdateFrequencyEPV: u16,
pub itsGnPaiInterval: u8,
pub itsGnMaxSduSize: u16,
pub itsGnMaxGeoNetworkingHeaderSize: u16,
pub itsGnLifetimeLocTE: u16,
pub itsGnSecurity: GnSecurity,
pub itsGnSnDecapResultHandling: SnDecapResultHandling,
pub itsGnLocationServiceMaxRetrans: u8,
pub itsGnLocationServiceRetransmitTimer: u16,
pub itsGnLocationServicePacketBufferSize: u16,
pub itsGnBeaconServiceRetransmitTimer: u16,
pub itsGnBeaconServiceMaxJitter: u16,
pub itsGnDefaultHopLimit: u8,
pub itsGnDPLLength: u8,
pub itsGnMaxPacketLifetime: u16,
pub itsGnDefaultPacketLifetime: u8,
pub itsGnMaxPacketDataRate: u32,
pub itsGnMaxPacketDataRateEmaBeta: u8,
pub itsGnMaxGeoAreaSize: u16,
pub itsGnMinPacketRepetitionInterval: u16,
pub itsGnNonAreaForwardingAlgorithm: NonAreaForwardingAlgorithm,
pub itsGnAreaForwardingAlgorithm: AreaForwardingAlgorithm,
pub itsGnCbfMinTime: u16,
pub itsGnCbfMaxTime: u16,
pub itsGnDefaultMaxCommunicationRange: u16,
pub itsGnBroadcastCBFDefSectorAngle: u8,
pub itsGnUcForwardingPacketBufferSize: u16,
pub itsGnBcForwardingPacketBufferSize: u16,
pub itsGnCbfPacketBufferSize: u16,
pub itsGnDefaultTrafficClass: u8,
}Fields§
§itsGnLocalGnAddr: GNAddress§itsGnLocalGnAddrConfMethod: LocalGnAddrConfMethod§itsGnProtocolVersion: u8§itsGnIsMobile: GnIsMobile§itsGnIfType: GnIfType§itsGnMinUpdateFrequencyEPV: u16§itsGnPaiInterval: u8§itsGnMaxSduSize: u16§itsGnMaxGeoNetworkingHeaderSize: u16§itsGnLifetimeLocTE: u16§itsGnSecurity: GnSecurity§itsGnSnDecapResultHandling: SnDecapResultHandling§itsGnLocationServiceMaxRetrans: u8§itsGnLocationServiceRetransmitTimer: u16§itsGnLocationServicePacketBufferSize: u16§itsGnBeaconServiceRetransmitTimer: u16§itsGnBeaconServiceMaxJitter: u16§itsGnDefaultHopLimit: u8§itsGnDPLLength: u8§itsGnMaxPacketLifetime: u16§itsGnDefaultPacketLifetime: u8§itsGnMaxPacketDataRate: u32§itsGnMaxPacketDataRateEmaBeta: u8§itsGnMaxGeoAreaSize: u16§itsGnMinPacketRepetitionInterval: u16§itsGnNonAreaForwardingAlgorithm: NonAreaForwardingAlgorithm§itsGnAreaForwardingAlgorithm: AreaForwardingAlgorithm§itsGnCbfMinTime: u16§itsGnCbfMaxTime: u16§itsGnDefaultMaxCommunicationRange: u16§itsGnBroadcastCBFDefSectorAngle: u8§itsGnUcForwardingPacketBufferSize: u16§itsGnBcForwardingPacketBufferSize: u16§itsGnCbfPacketBufferSize: u16§itsGnDefaultTrafficClass: u8Implementations§
Source§impl Mib
impl Mib
Sourcepub fn new() -> Self
pub fn new() -> Self
Examples found in repository?
examples/bench_cam_tx.rs (line 57)
44fn main() {
45 let iface = env::args().nth(1).unwrap_or_else(|| "lo".to_string());
46 let duration_s = env::args()
47 .nth(2)
48 .and_then(|s| s.parse::<u64>().ok())
49 .unwrap_or(10);
50
51 println!("=== Benchmark: Maximum CAM TX throughput ===");
52 println!("Interface : {iface}");
53 println!("Duration : {duration_s} s\n");
54
55 // ── MAC / MIB ─────────────────────────────────────────────────────────────
56 let mac = random_mac();
57 let mut mib = Mib::new();
58 mib.itsGnLocalGnAddr = GNAddress::new(M::GnMulticast, ST::PassengerCar, MID::new(mac));
59 mib.itsGnBeaconServiceRetransmitTimer = 0;
60
61 // ── Routers + link layer ──────────────────────────────────────────────────
62 let (gn_handle, gn_to_ll_rx, gn_to_btp_rx) = GNRouter::spawn(mib, None, None, None);
63 let (btp_handle, btp_to_gn_rx) = BTPRouter::spawn(mib);
64
65 let (ll_to_gn_tx, ll_to_gn_rx) = mpsc::channel::<Vec<u8>>();
66 RawLinkLayer::new(ll_to_gn_tx, gn_to_ll_rx, &iface, mac).start();
67 wire_routers(
68 &gn_handle,
69 &btp_handle,
70 ll_to_gn_rx,
71 gn_to_btp_rx,
72 btp_to_gn_rx,
73 );
74
75 // Seed GN position vector so packets are accepted downstream.
76 let mut epv = LongPositionVector::decode([0u8; 24]);
77 epv.update_from_gps(41.552, 2.134, 0.0, 0.0, true);
78 gn_handle.update_position_vector(epv);
79 thread::sleep(Duration::from_millis(50));
80
81 // ── Coder + template CAM ──────────────────────────────────────────────────
82 let station_id = u32::from_be_bytes([mac[2], mac[3], mac[4], mac[5]]);
83 let coder = CamCoder::new();
84 let template = make_cam(station_id);
85
86 // ── Benchmark loop ────────────────────────────────────────────────────────
87 println!("Sending CAMs as fast as possible…\n");
88 println!(
89 "{:>7} {:>10} {:>12} {:>12}",
90 "time(s)", "total_sent", "rate(pkt/s)", "avg_enc(µs)"
91 );
92
93 let mut total_sent: u64 = 0;
94 let mut total_enc_us: u128 = 0;
95 let bench_start = Instant::now();
96 let bench_end = bench_start + Duration::from_secs(duration_s);
97 let mut win_start = Instant::now();
98 let mut win_sent: u64 = 0;
99
100 while Instant::now() < bench_end {
101 let t0 = Instant::now();
102 let data = match coder.encode(&template) {
103 Ok(d) => d,
104 Err(e) => {
105 eprintln!("[TX] Encode error: {e}");
106 continue;
107 }
108 };
109 let enc_us = t0.elapsed().as_micros();
110
111 btp_handle.send_btp_data_request(cam_btp_request(data));
112
113 total_sent += 1;
114 total_enc_us += enc_us;
115 win_sent += 1;
116
117 let win_elapsed = win_start.elapsed();
118 if win_elapsed >= Duration::from_secs(1) {
119 let pps = win_sent as f64 / win_elapsed.as_secs_f64();
120 let avg_enc = total_enc_us / total_sent.max(1) as u128;
121 println!(
122 "{:>7.1} {:>10} {:>12.1} {:>12}",
123 bench_start.elapsed().as_secs_f64(),
124 total_sent,
125 pps,
126 avg_enc
127 );
128 win_start = Instant::now();
129 win_sent = 0;
130 }
131 }
132
133 // ── Summary ───────────────────────────────────────────────────────────────
134 let elapsed = bench_start.elapsed().as_secs_f64();
135 let avg_rate = total_sent as f64 / elapsed;
136 let avg_encode = total_enc_us / total_sent.max(1) as u128;
137
138 println!();
139 println!("=== CAM TX Results ===");
140 println!(" Total sent : {total_sent}");
141 println!(" Elapsed : {elapsed:.3} s");
142 println!(" Average rate : {avg_rate:.1} pkt/s");
143 println!(" Avg encode time : {avg_encode} µs");
144}More examples
examples/bench_cam_rx.rs (line 46)
33fn main() {
34 let iface = env::args().nth(1).unwrap_or_else(|| "lo".to_string());
35 let duration_s = env::args()
36 .nth(2)
37 .and_then(|s| s.parse::<u64>().ok())
38 .unwrap_or(30);
39
40 println!("=== Benchmark: Maximum CAM RX throughput ===");
41 println!("Interface : {iface}");
42 println!("Duration : {duration_s} s\n");
43
44 // ── MAC / MIB ─────────────────────────────────────────────────────────────
45 let mac = random_mac();
46 let mut mib = Mib::new();
47 mib.itsGnLocalGnAddr = GNAddress::new(M::GnMulticast, ST::PassengerCar, MID::new(mac));
48 mib.itsGnBeaconServiceRetransmitTimer = 0;
49
50 // ── Routers + link layer ──────────────────────────────────────────────────
51 let (gn_handle, gn_to_ll_rx, gn_to_btp_rx) = GNRouter::spawn(mib, None, None, None);
52 let (btp_handle, btp_to_gn_rx) = BTPRouter::spawn(mib);
53
54 let (ll_to_gn_tx, ll_to_gn_rx) = mpsc::channel::<Vec<u8>>();
55 RawLinkLayer::new(ll_to_gn_tx, gn_to_ll_rx, &iface, mac).start();
56 wire_routers(
57 &gn_handle,
58 &btp_handle,
59 ll_to_gn_rx,
60 gn_to_btp_rx,
61 btp_to_gn_rx,
62 );
63
64 // Seed position vector.
65 let mut epv = LongPositionVector::decode([0u8; 24]);
66 epv.update_from_gps(41.552, 2.134, 0.0, 0.0, true);
67 gn_handle.update_position_vector(epv);
68 thread::sleep(Duration::from_millis(50));
69
70 // ── Register on BTP port 2001 ─────────────────────────────────────────────
71 let (ind_tx, ind_rx) = mpsc::channel::<BTPDataIndication>();
72 btp_handle.register_port(2001, ind_tx);
73
74 // ── Benchmark loop ────────────────────────────────────────────────────────
75 println!("Waiting for CAMs on port 2001…\n");
76 println!(
77 "{:>7} {:>10} {:>12} {:>12} {:>10}",
78 "time(s)", "total_recv", "rate(pkt/s)", "avg_dec(µs)", "errors"
79 );
80
81 let coder = CamCoder::new();
82 let mut total_recv: u64 = 0;
83 let mut total_errors: u64 = 0;
84 let mut total_dec_us: u128 = 0;
85 let bench_start = Instant::now();
86 let bench_end = bench_start + Duration::from_secs(duration_s);
87 let mut win_start = Instant::now();
88 let mut win_recv: u64 = 0;
89
90 loop {
91 let now = Instant::now();
92 if now >= bench_end {
93 break;
94 }
95
96 let timeout = (bench_end - now).min(Duration::from_millis(500));
97 match ind_rx.recv_timeout(timeout) {
98 Ok(ind) => {
99 let t0 = Instant::now();
100 match coder.decode(&ind.data) {
101 Ok(_) => {}
102 Err(e) => {
103 total_errors += 1;
104 eprintln!("[RX] Decode error: {e}");
105 }
106 }
107 let dec_us = t0.elapsed().as_micros();
108 total_recv += 1;
109 total_dec_us += dec_us;
110 win_recv += 1;
111 }
112 Err(mpsc::RecvTimeoutError::Timeout) => {}
113 Err(mpsc::RecvTimeoutError::Disconnected) => break,
114 }
115
116 let win_elapsed = win_start.elapsed();
117 if win_elapsed >= Duration::from_secs(1) {
118 let pps = win_recv as f64 / win_elapsed.as_secs_f64();
119 let avg_dec = if total_recv > 0 {
120 total_dec_us / total_recv as u128
121 } else {
122 0
123 };
124 println!(
125 "{:>7.1} {:>10} {:>12.1} {:>12} {:>10}",
126 bench_start.elapsed().as_secs_f64(),
127 total_recv,
128 pps,
129 avg_dec,
130 total_errors
131 );
132 win_start = Instant::now();
133 win_recv = 0;
134 }
135 }
136
137 // ── Summary ───────────────────────────────────────────────────────────────
138 let elapsed = bench_start.elapsed().as_secs_f64();
139 let avg_rate = total_recv as f64 / elapsed;
140 let avg_decode = if total_recv > 0 {
141 total_dec_us / total_recv as u128
142 } else {
143 0
144 };
145
146 println!();
147 println!("=== CAM RX Results ===");
148 println!(" Total received : {total_recv}");
149 println!(" Decode errors : {total_errors}");
150 println!(" Elapsed : {elapsed:.3} s");
151 println!(" Average rate : {avg_rate:.1} pkt/s");
152 println!(" Avg decode time : {avg_decode} µs");
153}examples/vam_sender_receiver.rs (line 72)
43fn main() {
44 // ── Parse optional interface argument ─────────────────────────────────────
45 let iface = env::args().nth(1).unwrap_or_else(|| "lo".to_string());
46
47 println!("=== VAM Sender/Receiver Example (VRU Awareness Service) ===");
48 println!("Interface: {}", iface);
49
50 // ── Generate a random locally-administered MAC ────────────────────────────
51 let mac = {
52 use std::time::{SystemTime, UNIX_EPOCH};
53 let seed = SystemTime::now()
54 .duration_since(UNIX_EPOCH)
55 .unwrap()
56 .subsec_nanos();
57 [
58 0x02u8,
59 (seed >> 24) as u8,
60 (seed >> 16) as u8,
61 (seed >> 8) as u8,
62 seed as u8,
63 0xBB,
64 ]
65 };
66 println!(
67 "MAC: {:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
68 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]
69 );
70
71 // ── MIB ───────────────────────────────────────────────────────────────────
72 let mut mib = Mib::new();
73 mib.itsGnLocalGnAddr = GNAddress::new(M::GnMulticast, ST::Cyclist, MID::new(mac));
74 mib.itsGnBeaconServiceRetransmitTimer = 0;
75
76 // ── Location Service ──────────────────────────────────────────────────────
77 //
78 // A single LocationService publishes GPS fixes to multiple subscribers.
79 // We subscribe twice: once for the GN router's position vector, and once
80 // for the VRU Awareness Service VAM generation.
81 let mut loc_svc = LocationService::new();
82 let gn_gps_rx = loc_svc.subscribe(); // → GN position vector updates
83 let vru_gps_rx = loc_svc.subscribe(); // → VAM transmission
84
85 // ── Spawn GeoNetworking router ────────────────────────────────────────────
86 let (gn_handle, gn_to_ll_rx, gn_to_btp_rx) = GNRouter::spawn(mib, None, None, None);
87
88 // ── Spawn BTP router ──────────────────────────────────────────────────────
89 let (btp_handle, btp_to_gn_rx) = BTPRouter::spawn(mib);
90
91 // ── Wire RawLinkLayer ─────────────────────────────────────────────────────
92 let (ll_to_gn_tx, ll_to_gn_rx) = mpsc::channel::<Vec<u8>>();
93 let raw_ll = RawLinkLayer::new(ll_to_gn_tx, gn_to_ll_rx, &iface, mac);
94 raw_ll.start();
95
96 // ── Wire threads ──────────────────────────────────────────────────────────
97
98 // LL → GN
99 let gn_h1 = gn_handle.clone();
100 thread::spawn(move || {
101 while let Ok(pkt) = ll_to_gn_rx.recv() {
102 gn_h1.send_incoming_packet(pkt);
103 }
104 });
105
106 // GN → BTP
107 let btp_h1 = btp_handle.clone();
108 thread::spawn(move || {
109 while let Ok(ind) = gn_to_btp_rx.recv() {
110 btp_h1.send_gn_data_indication(ind);
111 }
112 });
113
114 // BTP → GN
115 let gn_h2 = gn_handle.clone();
116 thread::spawn(move || {
117 while let Ok(req) = btp_to_gn_rx.recv() {
118 gn_h2.send_gn_data_request(req);
119 }
120 });
121
122 // ── Bridge: LocationService → GN router position vector ───────────────────
123 //
124 // Converts each GpsFix into a LongPositionVector and pushes it into the
125 // GeoNetworking router so the EPV in every outgoing GN header is current.
126 let gn_h3 = gn_handle.clone();
127 thread::spawn(move || {
128 while let Ok(fix) = gn_gps_rx.recv() {
129 let mut epv = LongPositionVector::decode([0u8; 24]);
130 epv.update_from_gps(
131 fix.latitude,
132 fix.longitude,
133 fix.speed_mps,
134 fix.heading_deg,
135 fix.pai,
136 );
137 gn_h3.update_position_vector(epv);
138 }
139 });
140
141 // ── VRU Awareness Service ─────────────────────────────────────────────────
142 //
143 // DeviceData carries static VRU metadata that goes into every VAM.
144 // station_id is derived from the MAC bytes; station_type 2 = cyclist.
145 let station_id = u32::from_be_bytes([mac[2], mac[3], mac[4], mac[5]]);
146 let device_data = DeviceData {
147 station_id,
148 station_type: 2, // cyclist
149 };
150
151 // VruAwarenessService::new returns the service handle plus a
152 // Receiver<Vam> on which decoded incoming VAMs arrive.
153 let (vru_svc, vam_rx) = VruAwarenessService::new(btp_handle.clone(), device_data);
154
155 // start() consumes the service handle and spawns the TX + RX threads.
156 vru_svc.start(vru_gps_rx);
157
158 // ── Decoded VAM printer ───────────────────────────────────────────────────
159 thread::spawn(move || {
160 while let Ok(vam) = vam_rx.recv() {
161 let lat = vam
162 .vam
163 .vam_parameters
164 .basic_container
165 .reference_position
166 .latitude
167 .0 as f64
168 / 1e7;
169 let lon = vam
170 .vam
171 .vam_parameters
172 .basic_container
173 .reference_position
174 .longitude
175 .0 as f64
176 / 1e7;
177 println!(
178 "[VAM RX] station={:>10} lat={:.5} lon={:.5}",
179 vam.header.0.station_id.0, lat, lon,
180 );
181 }
182 });
183
184 // ── GPS publisher (simulates a real GNSS sensor at 1 Hz) ──────────────────
185 //
186 // In a real application this thread would read from gpsd or a serial port.
187 // Wait briefly for the routers to finish initialising.
188 thread::sleep(Duration::from_millis(100));
189 println!("Publishing GPS fixes @ 10 Hz — Ctrl+C to stop\n");
190
191 loop {
192 thread::sleep(Duration::from_millis(100));
193 // 41.552°N 2.134°E — Parc Tecnològic del Vallès
194 loc_svc.publish(GpsFix {
195 latitude: 41.552,
196 longitude: 2.134,
197 altitude_m: 120.0,
198 speed_mps: 1.5,
199 heading_deg: 90.0,
200 pai: true,
201 });
202 }
203}examples/denm_sender_receiver.rs (line 77)
48fn main() {
49 // ── Parse optional interface argument ─────────────────────────────────────
50 let iface = env::args().nth(1).unwrap_or_else(|| "lo".to_string());
51
52 println!("=== DENM Sender/Receiver Example (DEN Service) ===");
53 println!("Interface: {}", iface);
54
55 // ── Generate a random locally-administered MAC ────────────────────────────
56 let mac = {
57 use std::time::{SystemTime, UNIX_EPOCH};
58 let seed = SystemTime::now()
59 .duration_since(UNIX_EPOCH)
60 .unwrap()
61 .subsec_nanos();
62 [
63 0x02u8,
64 (seed >> 24) as u8,
65 (seed >> 16) as u8,
66 (seed >> 8) as u8,
67 seed as u8,
68 0xCC,
69 ]
70 };
71 println!(
72 "MAC: {:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
73 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]
74 );
75
76 // ── MIB ───────────────────────────────────────────────────────────────────
77 let mut mib = Mib::new();
78 mib.itsGnLocalGnAddr = GNAddress::new(M::GnMulticast, ST::PassengerCar, MID::new(mac));
79 mib.itsGnBeaconServiceRetransmitTimer = 0;
80
81 // ── Location Service ──────────────────────────────────────────────────────
82 //
83 // A single LocationService publishes GPS fixes. We subscribe once for the
84 // GN router's position vector updates.
85 let mut loc_svc = LocationService::new();
86 let gn_gps_rx = loc_svc.subscribe();
87
88 // ── Spawn GeoNetworking router ────────────────────────────────────────────
89 let (gn_handle, gn_to_ll_rx, gn_to_btp_rx) = GNRouter::spawn(mib, None, None, None);
90
91 // ── Spawn BTP router ──────────────────────────────────────────────────────
92 let (btp_handle, btp_to_gn_rx) = BTPRouter::spawn(mib);
93
94 // ── Wire RawLinkLayer ─────────────────────────────────────────────────────
95 let (ll_to_gn_tx, ll_to_gn_rx) = mpsc::channel::<Vec<u8>>();
96 let raw_ll = RawLinkLayer::new(ll_to_gn_tx, gn_to_ll_rx, &iface, mac);
97 raw_ll.start();
98
99 // ── Wire threads ──────────────────────────────────────────────────────────
100
101 // LL → GN
102 let gn_h1 = gn_handle.clone();
103 thread::spawn(move || {
104 while let Ok(pkt) = ll_to_gn_rx.recv() {
105 gn_h1.send_incoming_packet(pkt);
106 }
107 });
108
109 // GN → BTP
110 let btp_h1 = btp_handle.clone();
111 thread::spawn(move || {
112 while let Ok(ind) = gn_to_btp_rx.recv() {
113 btp_h1.send_gn_data_indication(ind);
114 }
115 });
116
117 // BTP → GN
118 let gn_h2 = gn_handle.clone();
119 thread::spawn(move || {
120 while let Ok(req) = btp_to_gn_rx.recv() {
121 gn_h2.send_gn_data_request(req);
122 }
123 });
124
125 // ── Bridge: LocationService → GN router position vector ───────────────────
126 let gn_h3 = gn_handle.clone();
127 thread::spawn(move || {
128 while let Ok(fix) = gn_gps_rx.recv() {
129 let mut epv = LongPositionVector::decode([0u8; 24]);
130 epv.update_from_gps(
131 fix.latitude,
132 fix.longitude,
133 fix.speed_mps,
134 fix.heading_deg,
135 fix.pai,
136 );
137 gn_h3.update_position_vector(epv);
138 }
139 });
140
141 // ── DEN Service ───────────────────────────────────────────────────────────
142 let station_id = u32::from_be_bytes([mac[2], mac[3], mac[4], mac[5]]);
143 let vehicle_data = VehicleData {
144 station_id,
145 station_type: 5, // passengerCar
146 };
147
148 // DecentralizedEnvironmentalNotificationService::new returns the service
149 // handle plus a Receiver<Denm> on which decoded incoming DENMs arrive.
150 // The reception thread is started immediately (registers BTP port 2002).
151 let (den_svc, denm_rx) =
152 DecentralizedEnvironmentalNotificationService::new(btp_handle.clone(), vehicle_data);
153
154 // ── Decoded DENM printer ──────────────────────────────────────────────────
155 thread::spawn(move || {
156 while let Ok(denm) = denm_rx.recv() {
157 let lat = denm.denm.management.event_position.latitude.0 as f64 / 1e7;
158 let lon = denm.denm.management.event_position.longitude.0 as f64 / 1e7;
159 let seq = denm.denm.management.action_id.sequence_number.0;
160 println!(
161 "[DENM RX] station={:>10} seq={:>5} event_lat={:.5} event_lon={:.5}",
162 denm.header.station_id.0, seq, lat, lon,
163 );
164 }
165 });
166
167 // ── Publish initial GPS fix to initialise the GN router ───────────────────
168 thread::sleep(Duration::from_millis(100));
169
170 // Publish position fixes to keep the GN position vector up to date.
171 let gps_fix = GpsFix {
172 latitude: 41.552,
173 longitude: 2.134,
174 altitude_m: 120.0,
175 speed_mps: 14.0, // ~50 km/h
176 heading_deg: 90.0,
177 pai: true,
178 };
179 loc_svc.publish(gps_fix);
180
181 // ── Trigger DENM: Road Hazard (accident) at current position ──────────────
182 //
183 // Send 1 DENM/s for 30 s, 1 000 m geo-broadcast circle.
184 println!("Triggering road-hazard DENM (accident) for 30 s @ 1 Hz");
185 den_svc.trigger_denm(DENRequest {
186 event_latitude: gps_fix.latitude,
187 event_longitude: gps_fix.longitude,
188 event_altitude_m: gps_fix.altitude_m,
189 cause_code: CauseCodeChoice::accident2(AccidentSubCauseCode(0)),
190 information_quality: 4,
191 event_speed_raw: (gps_fix.speed_mps * 100.0) as u16,
192 event_heading_raw: (gps_fix.heading_deg * 10.0) as u16,
193 denm_interval_ms: 1_000,
194 time_period_ms: 30_000,
195 relevance_radius_m: 1_000,
196 });
197
198 // ── GPS publisher loop ────────────────────────────────────────────────────
199 println!("Publishing GPS fixes @ 1 Hz — Ctrl+C to stop\n");
200 loop {
201 thread::sleep(Duration::from_secs(1));
202 loc_svc.publish(gps_fix);
203 }
204}examples/cam_sender_receiver.rs (line 76)
47fn main() {
48 // ── Parse optional interface argument ────────────────────────────────────
49 let iface = env::args().nth(1).unwrap_or_else(|| "lo".to_string());
50
51 println!("=== CAM Sender/Receiver Example (CA Basic Service) ===");
52 println!("Interface: {}", iface);
53
54 // ── Generate a random locally-administered MAC ────────────────────────
55 let mac = {
56 use std::time::{SystemTime, UNIX_EPOCH};
57 let seed = SystemTime::now()
58 .duration_since(UNIX_EPOCH)
59 .unwrap()
60 .subsec_nanos();
61 [
62 0x02u8,
63 (seed >> 24) as u8,
64 (seed >> 16) as u8,
65 (seed >> 8) as u8,
66 seed as u8,
67 0xAA,
68 ]
69 };
70 println!(
71 "MAC: {:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
72 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]
73 );
74
75 // ── MIB ──────────────────────────────────────────────────────────────────
76 let mut mib = Mib::new();
77 mib.itsGnLocalGnAddr = GNAddress::new(M::GnMulticast, ST::PassengerCar, MID::new(mac));
78 mib.itsGnBeaconServiceRetransmitTimer = 0;
79
80 // ── Location Service ─────────────────────────────────────────────────────
81 //
82 // A single LocationService publishes GPS fixes to multiple subscribers.
83 // We subscribe twice: once for the GN router's position vector, and once
84 // for the CA Basic Service CAM generation.
85 let mut loc_svc = LocationService::new();
86 let gn_gps_rx = loc_svc.subscribe(); // → GN position vector updates
87 let ca_gps_rx = loc_svc.subscribe(); // → CAM transmission
88
89 // ── Spawn GeoNetworking router ────────────────────────────────────────────
90 let (gn_handle, gn_to_ll_rx, gn_to_btp_rx) = GNRouter::spawn(mib, None, None, None);
91
92 // ── Spawn BTP router ─────────────────────────────────────────────────────
93 let (btp_handle, btp_to_gn_rx) = BTPRouter::spawn(mib);
94
95 // ── Wire RawLinkLayer ────────────────────────────────────────────────────
96 let (ll_to_gn_tx, ll_to_gn_rx) = mpsc::channel::<Vec<u8>>();
97 let raw_ll = RawLinkLayer::new(ll_to_gn_tx, gn_to_ll_rx, &iface, mac);
98 raw_ll.start();
99
100 // ── Wire threads ─────────────────────────────────────────────────────────
101
102 // LL → GN
103 let gn_h1 = gn_handle.clone();
104 thread::spawn(move || {
105 while let Ok(pkt) = ll_to_gn_rx.recv() {
106 gn_h1.send_incoming_packet(pkt);
107 }
108 });
109
110 // GN → BTP
111 let btp_h1 = btp_handle.clone();
112 thread::spawn(move || {
113 while let Ok(ind) = gn_to_btp_rx.recv() {
114 btp_h1.send_gn_data_indication(ind);
115 }
116 });
117
118 // BTP → GN
119 let gn_h2 = gn_handle.clone();
120 thread::spawn(move || {
121 while let Ok(req) = btp_to_gn_rx.recv() {
122 gn_h2.send_gn_data_request(req);
123 }
124 });
125
126 // ── Bridge: LocationService → GN router position vector ──────────────────
127 //
128 // Converts each GpsFix into a LongPositionVector and pushes it into the
129 // GeoNetworking router so the EPV in every outgoing GN header is current.
130 let gn_h3 = gn_handle.clone();
131 thread::spawn(move || {
132 while let Ok(fix) = gn_gps_rx.recv() {
133 let mut epv = LongPositionVector::decode([0u8; 24]);
134 epv.update_from_gps(
135 fix.latitude,
136 fix.longitude,
137 fix.speed_mps,
138 fix.heading_deg,
139 fix.pai,
140 );
141 gn_h3.update_position_vector(epv);
142 }
143 });
144
145 // ── Local Dynamic Map ─────────────────────────────────────────────────────
146 //
147 // Create the LDM centred on the simulated GPS position with a 5 km radius.
148 // Parc Tecnològic del Vallès: 41.552°N 2.134°E → ETSI integers × 1e7.
149 let ldm = LdmFacility::new(415_520_000, 21_340_000, 5_000.0);
150
151 // Register this node as a CAM data provider and consumer.
152 ldm.if_ldm_3
153 .register_data_provider(RegisterDataProviderReq {
154 application_id: ITS_AID_CAM,
155 });
156 ldm.if_ldm_4
157 .register_data_consumer(RegisterDataConsumerReq {
158 application_id: ITS_AID_CAM,
159 });
160
161 // ── CA Basic Service ─────────────────────────────────────────────────────
162 //
163 // VehicleData carries static vehicle metadata that goes into every CAM.
164 // station_id should match the GN address mid bytes in a real deployment.
165 let station_id = u32::from_be_bytes([mac[2], mac[3], mac[4], mac[5]]);
166 let vehicle_data = VehicleData {
167 station_id,
168 ..VehicleData::default() // PassengerCar, unavailable lengths
169 };
170
171 // Pass Some(ldm) so every received CAM is stored in the LDM before being
172 // forwarded. The _cam_rx channel is still available for direct consumers
173 // but in this example we read via IF.LDM.4 instead.
174 let (ca_svc, _cam_rx) =
175 CooperativeAwarenessBasicService::new(btp_handle.clone(), vehicle_data, Some(ldm.clone()));
176
177 // start() consumes the service handle and spawns the TX + RX threads.
178 ca_svc.start(ca_gps_rx);
179
180 // ── LDM query printer ─────────────────────────────────────────────────────
181 //
182 // Every second, query the LDM for all CAM records and print them.
183 // This uses the ETSI IF.LDM.4 interface and confirms that received CAMs
184 // are correctly stored and retrievable.
185 let ldm_reader = ldm.clone();
186 thread::spawn(move || loop {
187 thread::sleep(Duration::from_secs(1));
188 let resp = ldm_reader
189 .if_ldm_4
190 .request_data_objects(RequestDataObjectsReq {
191 application_id: ITS_AID_CAM,
192 data_object_types: vec![ITS_AID_CAM],
193 filter: None,
194 order: None,
195 max_results: None,
196 });
197 if resp.data_objects.is_empty() {
198 println!("[LDM] No CAM records in store");
199 } else {
200 println!("[LDM] {} CAM record(s):", resp.data_objects.len());
201 for entry in &resp.data_objects {
202 if let ItsDataObject::Cam(cam) = &entry.data_object {
203 let lat = cam
204 .cam
205 .cam_parameters
206 .basic_container
207 .reference_position
208 .latitude
209 .0 as f64
210 / 1e7;
211 let lon = cam
212 .cam
213 .cam_parameters
214 .basic_container
215 .reference_position
216 .longitude
217 .0 as f64
218 / 1e7;
219 println!(
220 " [LDM CAM] record={:>5} station={:>10} lat={:.5} lon={:.5}",
221 entry.record_id, cam.header.station_id.0, lat, lon,
222 );
223 }
224 }
225 }
226 });
227
228 // ── GPS publisher (simulates a real GNSS sensor at 1 Hz) ─────────────────
229 //
230 // In a real application this thread would read from gpsd or a serial port.
231 // Wait briefly for the routers to finish initialising.
232 thread::sleep(Duration::from_millis(100));
233 println!("Publishing GPS fixes @ 10 Hz — Ctrl+C to stop\n");
234
235 loop {
236 thread::sleep(Duration::from_millis(100));
237 // 41.552°N 2.134°E — Parc Tecnològic del Vallès
238 loc_svc.publish(GpsFix {
239 latitude: 41.552,
240 longitude: 2.134,
241 altitude_m: 120.0,
242 speed_mps: 0.0,
243 heading_deg: 0.0,
244 pai: true,
245 });
246 }
247}examples/secured_vam_sender_receiver.rs (line 186)
118fn main() {
119 // ── Parse arguments ──────────────────────────────────────────────────
120 let args: Vec<String> = env::args().collect();
121 let mut at_index: usize = 1;
122 let mut iface = "lo".to_string();
123
124 let mut i = 1;
125 while i < args.len() {
126 match args[i].as_str() {
127 "--at" => {
128 i += 1;
129 at_index = args[i].parse::<usize>().expect("--at must be 1 or 2");
130 assert!(at_index == 1 || at_index == 2, "--at must be 1 or 2");
131 }
132 "--iface" | "-i" => {
133 i += 1;
134 iface = args[i].clone();
135 }
136 other => {
137 // Positional argument: interface name
138 iface = other.to_string();
139 }
140 }
141 i += 1;
142 }
143
144 println!("=== Secured VAM Sender/Receiver (VRU Awareness Service) ===");
145 println!("AT index: {}", at_index);
146 println!("Interface: {}", iface);
147
148 // ── Build security stack ─────────────────────────────────────────────
149 let sign_service = build_security_stack(at_index);
150 println!(
151 "Security stack loaded. Own AT HashedId8: {:02x?}",
152 sign_service
153 .cert_library
154 .own_certificates
155 .keys()
156 .next()
157 .unwrap()
158 );
159
160 // Wrap in Arc<Mutex> so it can be shared between threads
161 let sign_service = Arc::new(Mutex::new(sign_service));
162
163 // ── Generate a random locally-administered MAC ───────────────────────
164 let mac = {
165 use std::time::{SystemTime, UNIX_EPOCH};
166 let seed = SystemTime::now()
167 .duration_since(UNIX_EPOCH)
168 .unwrap()
169 .subsec_nanos()
170 ^ (at_index as u32 * 0x1234_5678); // different seed per AT
171 [
172 0x02u8,
173 (seed >> 24) as u8,
174 (seed >> 16) as u8,
175 (seed >> 8) as u8,
176 seed as u8,
177 at_index as u8,
178 ]
179 };
180 println!(
181 "MAC: {:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
182 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]
183 );
184
185 // ── MIB ──────────────────────────────────────────────────────────────
186 let mut mib = Mib::new();
187 mib.itsGnLocalGnAddr = GNAddress::new(M::GnMulticast, ST::Cyclist, MID::new(mac));
188 mib.itsGnBeaconServiceRetransmitTimer = 0;
189
190 // ── Location Service ─────────────────────────────────────────────────
191 let mut loc_svc = LocationService::new();
192 let gn_gps_rx = loc_svc.subscribe();
193 let vru_gps_rx = loc_svc.subscribe();
194
195 // ── Spawn GN router and BTP router ───────────────────────────────────
196 let (gn_handle, gn_to_ll_rx, gn_to_btp_rx) = GNRouter::spawn(mib, None, None, None);
197 let (btp_handle, btp_to_gn_rx) = BTPRouter::spawn(mib);
198
199 // ── Wire RawLinkLayer ────────────────────────────────────────────────
200 let (ll_to_gn_tx, ll_to_gn_rx) = mpsc::channel::<Vec<u8>>();
201
202 // ── Security middleware: TX path ─────────────────────────────────────
203 //
204 // Intercept packets from GN router → link layer.
205 // Sign the payload (CommonHeader + extended header + data) and wrap
206 // in a secured GN packet with BasicNH::SecuredPacket.
207 let (secured_ll_tx, secured_ll_rx) = mpsc::channel::<Vec<u8>>();
208 let sign_svc_tx = Arc::clone(&sign_service);
209 thread::spawn(move || {
210 while let Ok(packet) = gn_to_ll_rx.recv() {
211 if packet.len() < 4 {
212 let _ = secured_ll_tx.send(packet);
213 continue;
214 }
215 let bh_bytes: [u8; 4] = packet[0..4].try_into().unwrap();
216 let bh = BasicHeader::decode(bh_bytes);
217
218 match bh.nh {
219 BasicNH::CommonHeader if packet.len() > 4 => {
220 let inner_payload = &packet[4..];
221
222 let request = SNSignRequest {
223 tbs_message: inner_payload.to_vec(),
224 its_aid: ITS_AID_VAM,
225 permissions: vec![],
226 generation_location: None,
227 };
228
229 let sec_message = {
230 let mut svc = sign_svc_tx.lock().unwrap();
231 svc.sign_request(&request).sec_message
232 };
233
234 // Build new packet: BasicHeader(nh=SecuredPacket) + sec_message
235 let mut new_bh = bh;
236 new_bh.nh = BasicNH::SecuredPacket;
237 let secured_packet: Vec<u8> = new_bh
238 .encode()
239 .iter()
240 .copied()
241 .chain(sec_message.iter().copied())
242 .collect();
243 let _ = secured_ll_tx.send(secured_packet);
244 }
245 _ => {
246 // Pass through (e.g. beacons)
247 let _ = secured_ll_tx.send(packet);
248 }
249 }
250 }
251 });
252
253 // The link layer reads from secured_ll_rx (post-signing)
254 let raw_ll = RawLinkLayer::new(ll_to_gn_tx, secured_ll_rx, &iface, mac);
255 raw_ll.start();
256
257 // ── Security middleware: RX path ─────────────────────────────────────
258 //
259 // Intercept packets from link layer → GN router.
260 // If BasicNH::SecuredPacket, verify and extract, then forward
261 // with BasicNH::CommonHeader.
262 let gn_h_rx = gn_handle.clone();
263 let sign_svc_rx = Arc::clone(&sign_service);
264 thread::spawn(move || {
265 while let Ok(packet) = ll_to_gn_rx.recv() {
266 if packet.len() < 4 {
267 gn_h_rx.send_incoming_packet(packet);
268 continue;
269 }
270 let bh_bytes: [u8; 4] = packet[0..4].try_into().unwrap();
271 let bh = BasicHeader::decode(bh_bytes);
272
273 match bh.nh {
274 BasicNH::SecuredPacket if packet.len() > 4 => {
275 let sec_message = &packet[4..];
276 let request = SNVerifyRequest {
277 message: sec_message.to_vec(),
278 };
279
280 let (confirm, _events) = {
281 let mut svc = sign_svc_rx.lock().unwrap();
282 let svc = &mut *svc;
283 let result = verify_message(&request, &svc.backend, &mut svc.cert_library);
284 // Process VerifyEvents for P2PCD
285 for event in &result.1 {
286 match event {
287 VerifyEvent::UnknownAt(h8) => {
288 svc.notify_unknown_at(h8);
289 }
290 VerifyEvent::InlineP2pcdRequest(h3s) => {
291 svc.notify_inline_p2pcd_request(h3s);
292 }
293 VerifyEvent::ReceivedCaCertificate(cert) => {
294 svc.notify_received_ca_certificate(cert.as_ref().clone());
295 }
296 }
297 }
298 result
299 };
300
301 if confirm.report == ReportVerify::Success {
302 println!(
303 "[SEC RX] Verified OK — ITS-AID={}, cert={:02x?}",
304 confirm.its_aid,
305 &confirm.certificate_id[..],
306 );
307 // Rebuild the packet: BasicHeader(nh=CommonHeader) + plain_message
308 let mut new_bh = bh;
309 new_bh.nh = BasicNH::CommonHeader;
310 let plain_packet: Vec<u8> = new_bh
311 .encode()
312 .iter()
313 .copied()
314 .chain(confirm.plain_message.iter().copied())
315 .collect();
316 gn_h_rx.send_incoming_packet(plain_packet);
317 } else {
318 eprintln!("[SEC RX] Verification failed: {:?}", confirm.report);
319 }
320 }
321 _ => {
322 // Non-secured packet — forward directly
323 gn_h_rx.send_incoming_packet(packet);
324 }
325 }
326 }
327 });
328
329 // ── GN → BTP ─────────────────────────────────────────────────────────
330 let btp_h1 = btp_handle.clone();
331 thread::spawn(move || {
332 while let Ok(ind) = gn_to_btp_rx.recv() {
333 btp_h1.send_gn_data_indication(ind);
334 }
335 });
336
337 // ── BTP → GN ─────────────────────────────────────────────────────────
338 let gn_h2 = gn_handle.clone();
339 thread::spawn(move || {
340 while let Ok(req) = btp_to_gn_rx.recv() {
341 gn_h2.send_gn_data_request(req);
342 }
343 });
344
345 // ── LocationService → GN position vector ─────────────────────────────
346 let gn_h3 = gn_handle.clone();
347 thread::spawn(move || {
348 while let Ok(fix) = gn_gps_rx.recv() {
349 let mut epv = LongPositionVector::decode([0u8; 24]);
350 epv.update_from_gps(
351 fix.latitude,
352 fix.longitude,
353 fix.speed_mps,
354 fix.heading_deg,
355 fix.pai,
356 );
357 gn_h3.update_position_vector(epv);
358 }
359 });
360
361 // ── VRU Awareness Service ────────────────────────────────────────────
362 let station_id = u32::from_be_bytes([mac[2], mac[3], mac[4], mac[5]]);
363 let device_data = DeviceData {
364 station_id,
365 station_type: 2, // cyclist
366 };
367
368 let (vru_svc, vam_rx) = VruAwarenessService::new(btp_handle.clone(), device_data);
369 vru_svc.start(vru_gps_rx);
370
371 // ── Decoded VAM printer ──────────────────────────────────────────────
372 thread::spawn(move || {
373 while let Ok(vam) = vam_rx.recv() {
374 let lat = vam
375 .vam
376 .vam_parameters
377 .basic_container
378 .reference_position
379 .latitude
380 .0 as f64
381 / 1e7;
382 let lon = vam
383 .vam
384 .vam_parameters
385 .basic_container
386 .reference_position
387 .longitude
388 .0 as f64
389 / 1e7;
390 println!(
391 "[VAM RX] station={:>10} lat={:.5} lon={:.5}",
392 vam.header.0.station_id.0, lat, lon,
393 );
394 }
395 });
396
397 // ── GPS publisher (simulates a VRU GNSS sensor at 10 Hz) ─────────────
398 thread::sleep(Duration::from_millis(100));
399 println!("Publishing GPS fixes @ 10 Hz — Ctrl+C to stop\n");
400
401 loop {
402 thread::sleep(Duration::from_millis(100));
403 // 41.552°N 2.134°E — Parc Tecnològic del Vallès
404 loc_svc.publish(GpsFix {
405 latitude: 41.552,
406 longitude: 2.134,
407 altitude_m: 120.0,
408 speed_mps: 1.5,
409 heading_deg: 90.0,
410 pai: true,
411 });
412 }
413}Additional examples can be found in:
Trait Implementations§
impl Copy for Mib
impl StructuralPartialEq for Mib
Auto Trait Implementations§
impl Freeze for Mib
impl RefUnwindSafe for Mib
impl Send for Mib
impl Sync for Mib
impl Unpin for Mib
impl UnsafeUnpin for Mib
impl UnwindSafe for Mib
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> FmtForward for T
impl<T> FmtForward for T
Source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
Causes
self to use its Binary implementation when Debug-formatted.Source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
Causes
self to use its Display implementation when
Debug-formatted.Source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
Causes
self to use its LowerExp implementation when
Debug-formatted.Source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
Causes
self to use its LowerHex implementation when
Debug-formatted.Source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
Causes
self to use its Octal implementation when Debug-formatted.Source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
Causes
self to use its Pointer implementation when
Debug-formatted.Source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
Causes
self to use its UpperExp implementation when
Debug-formatted.Source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
Causes
self to use its UpperHex implementation when
Debug-formatted.Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
Converts
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
Converts
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Pipes by value. This is generally the method you want to use. Read more
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
Borrows
self and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
Mutably borrows
self and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
Borrows
self, then passes self.as_ref() into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
Mutably borrows
self, then passes self.as_mut() into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
Borrows
self, then passes self.deref() into the pipe function.Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Immutable access to the
Borrow<B> of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
Mutable access to the
BorrowMut<B> of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
Immutable access to the
AsRef<R> view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
Mutable access to the
AsMut<R> view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Immutable access to the
Deref::Target of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Mutable access to the
Deref::Target of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
Calls
.tap() only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
Calls
.tap_mut() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
Calls
.tap_borrow() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
Calls
.tap_borrow_mut() only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
Calls
.tap_ref() only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
Calls
.tap_ref_mut() only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
Calls
.tap_deref() only in debug builds, and is erased in release
builds.