pub struct BasicHeader {
pub version: u8,
pub nh: BasicNH,
pub reserved: u8,
pub lt: LT,
pub rhl: u8,
}Fields§
§version: u8§nh: BasicNH§reserved: u8§lt: LT§rhl: u8Implementations§
Source§impl BasicHeader
impl BasicHeader
Sourcepub fn decode(bytes: [u8; 4]) -> Self
pub fn decode(bytes: [u8; 4]) -> Self
Examples found in repository?
examples/secured_vam_sender_receiver.rs (line 216)
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}More examples
examples/secured_cam_sender_receiver.rs (line 224)
125fn main() {
126 // ── Parse arguments ──────────────────────────────────────────────────
127 let args: Vec<String> = env::args().collect();
128 let mut at_index: usize = 1;
129 let mut iface = "lo".to_string();
130
131 let mut i = 1;
132 while i < args.len() {
133 match args[i].as_str() {
134 "--at" => {
135 i += 1;
136 at_index = args[i].parse::<usize>().expect("--at must be 1 or 2");
137 assert!(at_index == 1 || at_index == 2, "--at must be 1 or 2");
138 }
139 "--iface" | "-i" => {
140 i += 1;
141 iface = args[i].clone();
142 }
143 other => {
144 // Positional argument: interface name
145 iface = other.to_string();
146 }
147 }
148 i += 1;
149 }
150
151 println!("=== Secured CAM Sender/Receiver ===");
152 println!("AT index: {}", at_index);
153 println!("Interface: {}", iface);
154
155 // ── Build security stack ─────────────────────────────────────────────
156 let sign_service = build_security_stack(at_index);
157 println!(
158 "Security stack loaded. Own AT HashedId8: {:02x?}",
159 sign_service
160 .cert_library
161 .own_certificates
162 .keys()
163 .next()
164 .unwrap()
165 );
166
167 // Wrap in Arc<Mutex> so it can be shared between threads
168 let sign_service = Arc::new(Mutex::new(sign_service));
169
170 // ── Generate a random locally-administered MAC ───────────────────────
171 let mac = {
172 use std::time::{SystemTime, UNIX_EPOCH};
173 let seed = SystemTime::now()
174 .duration_since(UNIX_EPOCH)
175 .unwrap()
176 .subsec_nanos()
177 ^ (at_index as u32 * 0x1234_5678); // different seed per AT
178 [
179 0x02u8,
180 (seed >> 24) as u8,
181 (seed >> 16) as u8,
182 (seed >> 8) as u8,
183 seed as u8,
184 at_index as u8,
185 ]
186 };
187 println!(
188 "MAC: {:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
189 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]
190 );
191
192 // ── MIB ──────────────────────────────────────────────────────────────
193 let mut mib: Mib = Mib::new();
194 mib.itsGnLocalGnAddr = GNAddress::new(M::GnMulticast, ST::PassengerCar, MID::new(mac));
195 mib.itsGnBeaconServiceRetransmitTimer = 0;
196
197 // ── Location Service ─────────────────────────────────────────────────
198 let mut loc_svc = LocationService::new();
199 let gn_gps_rx = loc_svc.subscribe();
200 let ca_gps_rx = loc_svc.subscribe();
201
202 // ── Spawn GN router and BTP router ───────────────────────────────────
203 let (gn_handle, gn_to_ll_rx, gn_to_btp_rx) = GNRouter::spawn(mib, None, None, None);
204 let (btp_handle, btp_to_gn_rx) = BTPRouter::spawn(mib);
205
206 // ── Wire RawLinkLayer ────────────────────────────────────────────────
207 let (ll_to_gn_tx, ll_to_gn_rx) = mpsc::channel::<Vec<u8>>();
208
209 // ── Security middleware: TX path ─────────────────────────────────────
210 //
211 // Intercept packets from GN router → link layer.
212 // Sign the payload (CommonHeader + extended header + data) and wrap
213 // in a secured GN packet with BasicNH::SecuredPacket.
214 let (secured_ll_tx, secured_ll_rx) = mpsc::channel::<Vec<u8>>();
215 let sign_svc_tx = Arc::clone(&sign_service);
216 thread::spawn(move || {
217 while let Ok(packet) = gn_to_ll_rx.recv() {
218 if packet.len() < 4 {
219 let _ = secured_ll_tx.send(packet);
220 continue;
221 }
222 // Parse BasicHeader to check if it's a CommonHeader packet
223 let bh_bytes: [u8; 4] = packet[0..4].try_into().unwrap();
224 let bh = BasicHeader::decode(bh_bytes);
225
226 match bh.nh {
227 BasicNH::CommonHeader if packet.len() > 4 => {
228 // The payload to sign = everything after BasicHeader
229 let inner_payload = &packet[4..];
230
231 let request = SNSignRequest {
232 tbs_message: inner_payload.to_vec(),
233 its_aid: ITS_AID_CAM_VAL,
234 permissions: vec![],
235 generation_location: None,
236 };
237
238 let sec_message = {
239 let mut svc = sign_svc_tx.lock().unwrap();
240 svc.sign_request(&request).sec_message
241 };
242
243 // Build new packet: BasicHeader(nh=SecuredPacket) + sec_message
244 let mut new_bh = bh;
245 new_bh.nh = BasicNH::SecuredPacket;
246 let secured_packet: Vec<u8> = new_bh
247 .encode()
248 .iter()
249 .copied()
250 .chain(sec_message.iter().copied())
251 .collect();
252 let _ = secured_ll_tx.send(secured_packet);
253 }
254 _ => {
255 // Pass through (e.g. beacons)
256 let _ = secured_ll_tx.send(packet);
257 }
258 }
259 }
260 });
261
262 // The link layer reads from secured_ll_rx (post-signing)
263 let raw_ll = RawLinkLayer::new(ll_to_gn_tx, secured_ll_rx, &iface, mac);
264 raw_ll.start();
265
266 // ── Security middleware: RX path ─────────────────────────────────────
267 //
268 // Intercept packets from link layer → GN router.
269 // If BasicNH::SecuredPacket, verify and extract, then forward
270 // with BasicNH::CommonHeader.
271 let gn_h_rx = gn_handle.clone();
272 let sign_svc_rx = Arc::clone(&sign_service);
273 thread::spawn(move || {
274 while let Ok(packet) = ll_to_gn_rx.recv() {
275 if packet.len() < 4 {
276 gn_h_rx.send_incoming_packet(packet);
277 continue;
278 }
279 let bh_bytes: [u8; 4] = packet[0..4].try_into().unwrap();
280 let bh = BasicHeader::decode(bh_bytes);
281
282 match bh.nh {
283 BasicNH::SecuredPacket if packet.len() > 4 => {
284 let sec_message = &packet[4..];
285 let request = SNVerifyRequest {
286 message: sec_message.to_vec(),
287 };
288
289 let (confirm, _events) = {
290 let mut svc = sign_svc_rx.lock().unwrap();
291 let svc = &mut *svc;
292 let result = verify_message(&request, &svc.backend, &mut svc.cert_library);
293 // Process VerifyEvents for P2PCD
294 for event in &result.1 {
295 match event {
296 VerifyEvent::UnknownAt(h8) => {
297 svc.notify_unknown_at(h8);
298 }
299 VerifyEvent::InlineP2pcdRequest(h3s) => {
300 svc.notify_inline_p2pcd_request(h3s);
301 }
302 VerifyEvent::ReceivedCaCertificate(cert) => {
303 svc.notify_received_ca_certificate(cert.as_ref().clone());
304 }
305 }
306 }
307 result
308 };
309
310 if confirm.report == ReportVerify::Success {
311 println!(
312 "[SEC RX] Verified OK — ITS-AID={}, cert={:02x?}",
313 confirm.its_aid,
314 &confirm.certificate_id[..],
315 );
316 // Rebuild the packet: BasicHeader(nh=CommonHeader) + plain_message
317 let mut new_bh = bh;
318 new_bh.nh = BasicNH::CommonHeader;
319 let plain_packet: Vec<u8> = new_bh
320 .encode()
321 .iter()
322 .copied()
323 .chain(confirm.plain_message.iter().copied())
324 .collect();
325 gn_h_rx.send_incoming_packet(plain_packet);
326 } else {
327 eprintln!("[SEC RX] Verification failed: {:?}", confirm.report);
328 }
329 }
330 _ => {
331 // Non-secured packet — forward directly
332 gn_h_rx.send_incoming_packet(packet);
333 }
334 }
335 }
336 });
337
338 // ── GN → BTP ─────────────────────────────────────────────────────────
339 let btp_h1 = btp_handle.clone();
340 thread::spawn(move || {
341 while let Ok(ind) = gn_to_btp_rx.recv() {
342 btp_h1.send_gn_data_indication(ind);
343 }
344 });
345
346 // ── BTP → GN ─────────────────────────────────────────────────────────
347 let gn_h2 = gn_handle.clone();
348 thread::spawn(move || {
349 while let Ok(req) = btp_to_gn_rx.recv() {
350 gn_h2.send_gn_data_request(req);
351 }
352 });
353
354 // ── LocationService → GN position vector ─────────────────────────────
355 let gn_h3 = gn_handle.clone();
356 thread::spawn(move || {
357 while let Ok(fix) = gn_gps_rx.recv() {
358 let mut epv = LongPositionVector::decode([0u8; 24]);
359 epv.update_from_gps(
360 fix.latitude,
361 fix.longitude,
362 fix.speed_mps,
363 fix.heading_deg,
364 fix.pai,
365 );
366 gn_h3.update_position_vector(epv);
367 }
368 });
369
370 // ── Local Dynamic Map ────────────────────────────────────────────────
371 let ldm = LdmFacility::new(415_520_000, 21_340_000, 5_000.0);
372 ldm.if_ldm_3
373 .register_data_provider(RegisterDataProviderReq {
374 application_id: ITS_AID_CAM,
375 });
376 ldm.if_ldm_4
377 .register_data_consumer(RegisterDataConsumerReq {
378 application_id: ITS_AID_CAM,
379 });
380
381 // ── CA Basic Service ─────────────────────────────────────────────────
382 let station_id = u32::from_be_bytes([mac[2], mac[3], mac[4], mac[5]]);
383 let vehicle_data = VehicleData {
384 station_id,
385 ..VehicleData::default()
386 };
387 let (ca_svc, _cam_rx) =
388 CooperativeAwarenessBasicService::new(btp_handle.clone(), vehicle_data, Some(ldm.clone()));
389 ca_svc.start(ca_gps_rx);
390
391 // ── LDM query printer ────────────────────────────────────────────────
392 let ldm_reader = ldm.clone();
393 thread::spawn(move || loop {
394 thread::sleep(Duration::from_secs(1));
395 let resp = ldm_reader
396 .if_ldm_4
397 .request_data_objects(RequestDataObjectsReq {
398 application_id: ITS_AID_CAM,
399 data_object_types: vec![ITS_AID_CAM],
400 filter: None,
401 order: None,
402 max_results: None,
403 });
404 if resp.data_objects.is_empty() {
405 println!("[LDM] No CAM records in store");
406 } else {
407 println!("[LDM] {} CAM record(s):", resp.data_objects.len());
408 for entry in &resp.data_objects {
409 if let ItsDataObject::Cam(cam) = &entry.data_object {
410 let lat = cam
411 .cam
412 .cam_parameters
413 .basic_container
414 .reference_position
415 .latitude
416 .0 as f64
417 / 1e7;
418 let lon = cam
419 .cam
420 .cam_parameters
421 .basic_container
422 .reference_position
423 .longitude
424 .0 as f64
425 / 1e7;
426 println!(
427 " [LDM CAM] record={:>5} station={:>10} lat={:.5} lon={:.5}",
428 entry.record_id, cam.header.station_id.0, lat, lon,
429 );
430 }
431 }
432 }
433 });
434
435 // ── GPS publisher (random trajectory — mirrors Python _RandomTrajectoryLocationService) ──
436 //
437 // Updates every 80 ms (below T_CheckCamGen = 100 ms) with a randomly
438 // changing heading (±5–15° per step, always exceeding the 4° condition-1
439 // threshold) and speed random-walking within [5, 20] m/s. This sustains
440 // 10 Hz CAM generation via the dynamics triggering conditions.
441 thread::sleep(Duration::from_millis(100));
442 println!("Publishing GPS fixes @ 12.5 Hz (80 ms) with random trajectory — Ctrl+C to stop\n");
443
444 use rand::Rng;
445 let mut rng = rand::thread_rng();
446
447 const PERIOD_S: f64 = 0.08; // 80 ms — below T_CheckCamGen
448 const EARTH_R: f64 = 6_371_000.0;
449
450 let mut lat: f64 = 41.386931;
451 let mut lon: f64 = 2.112104;
452 let mut heading: f64 = rng.gen_range(0.0..360.0);
453 let mut speed: f64 = 10.0; // ~36 km/h
454
455 loop {
456 thread::sleep(Duration::from_millis(80));
457
458 // Heading: random signed change guaranteed to exceed the 4° threshold
459 let delta: f64 = rng.gen_range(5.0..15.0) * if rng.gen_bool(0.5) { 1.0 } else { -1.0 };
460 heading = (heading + delta).rem_euclid(360.0);
461
462 // Speed: small random walk within [5, 20] m/s
463 speed = (speed + rng.gen_range(-0.5..0.5)).clamp(5.0, 20.0);
464
465 // Position update (flat-Earth approximation; step sizes < 2 m)
466 let d = speed * PERIOD_S;
467 let heading_r = heading * PI / 180.0;
468 let lat_r = lat * PI / 180.0;
469 lat += (d * heading_r.cos() / EARTH_R) * (180.0 / PI);
470 lon += (d * heading_r.sin() / (EARTH_R * lat_r.cos())) * (180.0 / PI);
471
472 loc_svc.publish(GpsFix {
473 latitude: lat,
474 longitude: lon,
475 altitude_m: 120.0,
476 speed_mps: speed,
477 heading_deg: heading,
478 pai: true,
479 });
480 }
481}pub fn initialize_with_mib(mib: &Mib) -> Self
Sourcepub fn initialize_with_mib_request_and_rhl(
mib: &Mib,
max_packet_lifetime: Option<f64>,
rhl: u8,
) -> Self
pub fn initialize_with_mib_request_and_rhl( mib: &Mib, max_packet_lifetime: Option<f64>, rhl: u8, ) -> Self
Initialize from MIB with optional max_packet_lifetime and explicit RHL.
Sourcepub fn encode(&self) -> [u8; 4]
pub fn encode(&self) -> [u8; 4]
Examples found in repository?
examples/secured_vam_sender_receiver.rs (line 238)
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}More examples
examples/secured_cam_sender_receiver.rs (line 247)
125fn main() {
126 // ── Parse arguments ──────────────────────────────────────────────────
127 let args: Vec<String> = env::args().collect();
128 let mut at_index: usize = 1;
129 let mut iface = "lo".to_string();
130
131 let mut i = 1;
132 while i < args.len() {
133 match args[i].as_str() {
134 "--at" => {
135 i += 1;
136 at_index = args[i].parse::<usize>().expect("--at must be 1 or 2");
137 assert!(at_index == 1 || at_index == 2, "--at must be 1 or 2");
138 }
139 "--iface" | "-i" => {
140 i += 1;
141 iface = args[i].clone();
142 }
143 other => {
144 // Positional argument: interface name
145 iface = other.to_string();
146 }
147 }
148 i += 1;
149 }
150
151 println!("=== Secured CAM Sender/Receiver ===");
152 println!("AT index: {}", at_index);
153 println!("Interface: {}", iface);
154
155 // ── Build security stack ─────────────────────────────────────────────
156 let sign_service = build_security_stack(at_index);
157 println!(
158 "Security stack loaded. Own AT HashedId8: {:02x?}",
159 sign_service
160 .cert_library
161 .own_certificates
162 .keys()
163 .next()
164 .unwrap()
165 );
166
167 // Wrap in Arc<Mutex> so it can be shared between threads
168 let sign_service = Arc::new(Mutex::new(sign_service));
169
170 // ── Generate a random locally-administered MAC ───────────────────────
171 let mac = {
172 use std::time::{SystemTime, UNIX_EPOCH};
173 let seed = SystemTime::now()
174 .duration_since(UNIX_EPOCH)
175 .unwrap()
176 .subsec_nanos()
177 ^ (at_index as u32 * 0x1234_5678); // different seed per AT
178 [
179 0x02u8,
180 (seed >> 24) as u8,
181 (seed >> 16) as u8,
182 (seed >> 8) as u8,
183 seed as u8,
184 at_index as u8,
185 ]
186 };
187 println!(
188 "MAC: {:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
189 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]
190 );
191
192 // ── MIB ──────────────────────────────────────────────────────────────
193 let mut mib: Mib = Mib::new();
194 mib.itsGnLocalGnAddr = GNAddress::new(M::GnMulticast, ST::PassengerCar, MID::new(mac));
195 mib.itsGnBeaconServiceRetransmitTimer = 0;
196
197 // ── Location Service ─────────────────────────────────────────────────
198 let mut loc_svc = LocationService::new();
199 let gn_gps_rx = loc_svc.subscribe();
200 let ca_gps_rx = loc_svc.subscribe();
201
202 // ── Spawn GN router and BTP router ───────────────────────────────────
203 let (gn_handle, gn_to_ll_rx, gn_to_btp_rx) = GNRouter::spawn(mib, None, None, None);
204 let (btp_handle, btp_to_gn_rx) = BTPRouter::spawn(mib);
205
206 // ── Wire RawLinkLayer ────────────────────────────────────────────────
207 let (ll_to_gn_tx, ll_to_gn_rx) = mpsc::channel::<Vec<u8>>();
208
209 // ── Security middleware: TX path ─────────────────────────────────────
210 //
211 // Intercept packets from GN router → link layer.
212 // Sign the payload (CommonHeader + extended header + data) and wrap
213 // in a secured GN packet with BasicNH::SecuredPacket.
214 let (secured_ll_tx, secured_ll_rx) = mpsc::channel::<Vec<u8>>();
215 let sign_svc_tx = Arc::clone(&sign_service);
216 thread::spawn(move || {
217 while let Ok(packet) = gn_to_ll_rx.recv() {
218 if packet.len() < 4 {
219 let _ = secured_ll_tx.send(packet);
220 continue;
221 }
222 // Parse BasicHeader to check if it's a CommonHeader packet
223 let bh_bytes: [u8; 4] = packet[0..4].try_into().unwrap();
224 let bh = BasicHeader::decode(bh_bytes);
225
226 match bh.nh {
227 BasicNH::CommonHeader if packet.len() > 4 => {
228 // The payload to sign = everything after BasicHeader
229 let inner_payload = &packet[4..];
230
231 let request = SNSignRequest {
232 tbs_message: inner_payload.to_vec(),
233 its_aid: ITS_AID_CAM_VAL,
234 permissions: vec![],
235 generation_location: None,
236 };
237
238 let sec_message = {
239 let mut svc = sign_svc_tx.lock().unwrap();
240 svc.sign_request(&request).sec_message
241 };
242
243 // Build new packet: BasicHeader(nh=SecuredPacket) + sec_message
244 let mut new_bh = bh;
245 new_bh.nh = BasicNH::SecuredPacket;
246 let secured_packet: Vec<u8> = new_bh
247 .encode()
248 .iter()
249 .copied()
250 .chain(sec_message.iter().copied())
251 .collect();
252 let _ = secured_ll_tx.send(secured_packet);
253 }
254 _ => {
255 // Pass through (e.g. beacons)
256 let _ = secured_ll_tx.send(packet);
257 }
258 }
259 }
260 });
261
262 // The link layer reads from secured_ll_rx (post-signing)
263 let raw_ll = RawLinkLayer::new(ll_to_gn_tx, secured_ll_rx, &iface, mac);
264 raw_ll.start();
265
266 // ── Security middleware: RX path ─────────────────────────────────────
267 //
268 // Intercept packets from link layer → GN router.
269 // If BasicNH::SecuredPacket, verify and extract, then forward
270 // with BasicNH::CommonHeader.
271 let gn_h_rx = gn_handle.clone();
272 let sign_svc_rx = Arc::clone(&sign_service);
273 thread::spawn(move || {
274 while let Ok(packet) = ll_to_gn_rx.recv() {
275 if packet.len() < 4 {
276 gn_h_rx.send_incoming_packet(packet);
277 continue;
278 }
279 let bh_bytes: [u8; 4] = packet[0..4].try_into().unwrap();
280 let bh = BasicHeader::decode(bh_bytes);
281
282 match bh.nh {
283 BasicNH::SecuredPacket if packet.len() > 4 => {
284 let sec_message = &packet[4..];
285 let request = SNVerifyRequest {
286 message: sec_message.to_vec(),
287 };
288
289 let (confirm, _events) = {
290 let mut svc = sign_svc_rx.lock().unwrap();
291 let svc = &mut *svc;
292 let result = verify_message(&request, &svc.backend, &mut svc.cert_library);
293 // Process VerifyEvents for P2PCD
294 for event in &result.1 {
295 match event {
296 VerifyEvent::UnknownAt(h8) => {
297 svc.notify_unknown_at(h8);
298 }
299 VerifyEvent::InlineP2pcdRequest(h3s) => {
300 svc.notify_inline_p2pcd_request(h3s);
301 }
302 VerifyEvent::ReceivedCaCertificate(cert) => {
303 svc.notify_received_ca_certificate(cert.as_ref().clone());
304 }
305 }
306 }
307 result
308 };
309
310 if confirm.report == ReportVerify::Success {
311 println!(
312 "[SEC RX] Verified OK — ITS-AID={}, cert={:02x?}",
313 confirm.its_aid,
314 &confirm.certificate_id[..],
315 );
316 // Rebuild the packet: BasicHeader(nh=CommonHeader) + plain_message
317 let mut new_bh = bh;
318 new_bh.nh = BasicNH::CommonHeader;
319 let plain_packet: Vec<u8> = new_bh
320 .encode()
321 .iter()
322 .copied()
323 .chain(confirm.plain_message.iter().copied())
324 .collect();
325 gn_h_rx.send_incoming_packet(plain_packet);
326 } else {
327 eprintln!("[SEC RX] Verification failed: {:?}", confirm.report);
328 }
329 }
330 _ => {
331 // Non-secured packet — forward directly
332 gn_h_rx.send_incoming_packet(packet);
333 }
334 }
335 }
336 });
337
338 // ── GN → BTP ─────────────────────────────────────────────────────────
339 let btp_h1 = btp_handle.clone();
340 thread::spawn(move || {
341 while let Ok(ind) = gn_to_btp_rx.recv() {
342 btp_h1.send_gn_data_indication(ind);
343 }
344 });
345
346 // ── BTP → GN ─────────────────────────────────────────────────────────
347 let gn_h2 = gn_handle.clone();
348 thread::spawn(move || {
349 while let Ok(req) = btp_to_gn_rx.recv() {
350 gn_h2.send_gn_data_request(req);
351 }
352 });
353
354 // ── LocationService → GN position vector ─────────────────────────────
355 let gn_h3 = gn_handle.clone();
356 thread::spawn(move || {
357 while let Ok(fix) = gn_gps_rx.recv() {
358 let mut epv = LongPositionVector::decode([0u8; 24]);
359 epv.update_from_gps(
360 fix.latitude,
361 fix.longitude,
362 fix.speed_mps,
363 fix.heading_deg,
364 fix.pai,
365 );
366 gn_h3.update_position_vector(epv);
367 }
368 });
369
370 // ── Local Dynamic Map ────────────────────────────────────────────────
371 let ldm = LdmFacility::new(415_520_000, 21_340_000, 5_000.0);
372 ldm.if_ldm_3
373 .register_data_provider(RegisterDataProviderReq {
374 application_id: ITS_AID_CAM,
375 });
376 ldm.if_ldm_4
377 .register_data_consumer(RegisterDataConsumerReq {
378 application_id: ITS_AID_CAM,
379 });
380
381 // ── CA Basic Service ─────────────────────────────────────────────────
382 let station_id = u32::from_be_bytes([mac[2], mac[3], mac[4], mac[5]]);
383 let vehicle_data = VehicleData {
384 station_id,
385 ..VehicleData::default()
386 };
387 let (ca_svc, _cam_rx) =
388 CooperativeAwarenessBasicService::new(btp_handle.clone(), vehicle_data, Some(ldm.clone()));
389 ca_svc.start(ca_gps_rx);
390
391 // ── LDM query printer ────────────────────────────────────────────────
392 let ldm_reader = ldm.clone();
393 thread::spawn(move || loop {
394 thread::sleep(Duration::from_secs(1));
395 let resp = ldm_reader
396 .if_ldm_4
397 .request_data_objects(RequestDataObjectsReq {
398 application_id: ITS_AID_CAM,
399 data_object_types: vec![ITS_AID_CAM],
400 filter: None,
401 order: None,
402 max_results: None,
403 });
404 if resp.data_objects.is_empty() {
405 println!("[LDM] No CAM records in store");
406 } else {
407 println!("[LDM] {} CAM record(s):", resp.data_objects.len());
408 for entry in &resp.data_objects {
409 if let ItsDataObject::Cam(cam) = &entry.data_object {
410 let lat = cam
411 .cam
412 .cam_parameters
413 .basic_container
414 .reference_position
415 .latitude
416 .0 as f64
417 / 1e7;
418 let lon = cam
419 .cam
420 .cam_parameters
421 .basic_container
422 .reference_position
423 .longitude
424 .0 as f64
425 / 1e7;
426 println!(
427 " [LDM CAM] record={:>5} station={:>10} lat={:.5} lon={:.5}",
428 entry.record_id, cam.header.station_id.0, lat, lon,
429 );
430 }
431 }
432 }
433 });
434
435 // ── GPS publisher (random trajectory — mirrors Python _RandomTrajectoryLocationService) ──
436 //
437 // Updates every 80 ms (below T_CheckCamGen = 100 ms) with a randomly
438 // changing heading (±5–15° per step, always exceeding the 4° condition-1
439 // threshold) and speed random-walking within [5, 20] m/s. This sustains
440 // 10 Hz CAM generation via the dynamics triggering conditions.
441 thread::sleep(Duration::from_millis(100));
442 println!("Publishing GPS fixes @ 12.5 Hz (80 ms) with random trajectory — Ctrl+C to stop\n");
443
444 use rand::Rng;
445 let mut rng = rand::thread_rng();
446
447 const PERIOD_S: f64 = 0.08; // 80 ms — below T_CheckCamGen
448 const EARTH_R: f64 = 6_371_000.0;
449
450 let mut lat: f64 = 41.386931;
451 let mut lon: f64 = 2.112104;
452 let mut heading: f64 = rng.gen_range(0.0..360.0);
453 let mut speed: f64 = 10.0; // ~36 km/h
454
455 loop {
456 thread::sleep(Duration::from_millis(80));
457
458 // Heading: random signed change guaranteed to exceed the 4° threshold
459 let delta: f64 = rng.gen_range(5.0..15.0) * if rng.gen_bool(0.5) { 1.0 } else { -1.0 };
460 heading = (heading + delta).rem_euclid(360.0);
461
462 // Speed: small random walk within [5, 20] m/s
463 speed = (speed + rng.gen_range(-0.5..0.5)).clamp(5.0, 20.0);
464
465 // Position update (flat-Earth approximation; step sizes < 2 m)
466 let d = speed * PERIOD_S;
467 let heading_r = heading * PI / 180.0;
468 let lat_r = lat * PI / 180.0;
469 lat += (d * heading_r.cos() / EARTH_R) * (180.0 / PI);
470 lon += (d * heading_r.sin() / (EARTH_R * lat_r.cos())) * (180.0 / PI);
471
472 loc_svc.publish(GpsFix {
473 latitude: lat,
474 longitude: lon,
475 altitude_m: 120.0,
476 speed_mps: speed,
477 heading_deg: heading,
478 pai: true,
479 });
480 }
481}Trait Implementations§
Source§impl Clone for BasicHeader
impl Clone for BasicHeader
Source§fn clone(&self) -> BasicHeader
fn clone(&self) -> BasicHeader
Returns a duplicate of the value. Read more
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
Performs copy-assignment from
source. Read moreSource§impl Debug for BasicHeader
impl Debug for BasicHeader
impl Copy for BasicHeader
Auto Trait Implementations§
impl Freeze for BasicHeader
impl RefUnwindSafe for BasicHeader
impl Send for BasicHeader
impl Sync for BasicHeader
impl Unpin for BasicHeader
impl UnsafeUnpin for BasicHeader
impl UnwindSafe for BasicHeader
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.