1#[cfg(not(target_arch = "wasm32"))]
7use alloc::string::ToString;
8
9#[cfg(all(target_arch = "wasm32", feature = "json"))]
10use wasm_bindgen::prelude::*;
11
12#[cfg(all(target_arch = "wasm32", feature = "json"))]
13pub type Encoded = js_sys::Uint8Array;
15#[cfg(not(target_arch = "wasm32"))]
16pub type Encoded = alloc::vec::Vec<u8>;
18
19#[cfg(not(target_arch = "wasm32"))]
20impl crate::ItsMessage<'_> {
21 #[allow(clippy::too_many_lines)]
22 pub fn encode(
41 self,
42 encoding_rules: crate::EncodingRules,
43 ) -> Result<Encoded, alloc::string::String> {
44 use crate::ItsMessage;
45
46 let (geo, tp, mut etsi_uper) = match self {
47 #[cfg(feature = "denm_1_3_1")]
48 ItsMessage::DenmV1 {
49 geonetworking,
50 transport,
51 etsi,
52 } => encoding_rules
53 .codec()
54 .encode_to_binary(&etsi)
55 .map(|enc| (geonetworking, transport, enc)),
56 #[cfg(feature = "denm_2_2_1")]
57 ItsMessage::DenmV2 {
58 geonetworking,
59 transport,
60 etsi,
61 } => encoding_rules
62 .codec()
63 .encode_to_binary(&etsi)
64 .map(|enc| (geonetworking, transport, enc)),
65 #[cfg(feature = "cam_1_4_1")]
66 ItsMessage::Cam {
67 geonetworking,
68 transport,
69 etsi,
70 } => encoding_rules
71 .codec()
72 .encode_to_binary(&etsi)
73 .map(|enc| (geonetworking, transport, enc)),
74 #[cfg(feature = "spatem_2_2_1")]
75 ItsMessage::Spatem {
76 geonetworking,
77 transport,
78 etsi,
79 } => encoding_rules
80 .codec()
81 .encode_to_binary(&etsi)
82 .map(|enc| (geonetworking, transport, enc)),
83 #[cfg(feature = "mapem_2_2_1")]
84 ItsMessage::Mapem {
85 geonetworking,
86 transport,
87 etsi,
88 } => encoding_rules
89 .codec()
90 .encode_to_binary(&etsi)
91 .map(|enc| (geonetworking, transport, enc)),
92 #[cfg(feature = "ivim_2_1_1")]
93 ItsMessage::IvimV1 {
94 geonetworking,
95 transport,
96 etsi,
97 } => encoding_rules
98 .codec()
99 .encode_to_binary(&etsi)
100 .map(|enc| (geonetworking, transport, enc)),
101 #[cfg(feature = "ivim_2_2_1")]
102 ItsMessage::IvimV2 {
103 geonetworking,
104 transport,
105 etsi,
106 } => encoding_rules
107 .codec()
108 .encode_to_binary(&etsi)
109 .map(|enc| (geonetworking, transport, enc)),
110 #[cfg(feature = "srem_2_2_1")]
111 ItsMessage::Srem {
112 geonetworking,
113 transport,
114 etsi,
115 } => encoding_rules
116 .codec()
117 .encode_to_binary(&etsi)
118 .map(|enc| (geonetworking, transport, enc)),
119 #[cfg(feature = "ssem_2_2_1")]
120 ItsMessage::Ssem {
121 geonetworking,
122 transport,
123 etsi,
124 } => encoding_rules
125 .codec()
126 .encode_to_binary(&etsi)
127 .map(|enc| (geonetworking, transport, enc)),
128 #[cfg(feature = "cpm_1")]
129 ItsMessage::CpmV1 {
130 geonetworking,
131 transport,
132 etsi,
133 } => encoding_rules
134 .codec()
135 .encode_to_binary(&etsi)
136 .map(|enc| (geonetworking, transport, enc)),
137 #[cfg(feature = "cpm_2_1_1")]
138 ItsMessage::CpmV2 {
139 geonetworking,
140 transport,
141 etsi,
142 } => encoding_rules
143 .codec()
144 .encode_to_binary(&etsi)
145 .map(|enc| (geonetworking, transport, enc)),
146 }
147 .map_err(crate::map_err_to_string)?;
148
149 if encoding_rules == crate::EncodingRules::UPER {
150 match (tp, geo) {
151 (None, None) => Ok(etsi_uper),
152 (
153 Some(tp),
154 Some(geonetworking::Packet::Unsecured {
155 basic,
156 common,
157 extended,
158 ..
159 } | geonetworking::Packet::Secured {
160 basic,
161 common,
162 extended,
163 ..
164 }),
165 ) => {
166 let mut encoded = tp.encode()?;
167 encoded.append(&mut etsi_uper);
168 fill_gn_and_encode(geonetworking::UnsecuredHeader { basic, common, extended }, &encoded)
169 }
170 _ => Err(
171 "Expecting either both or neither GeoNetworking and Transport headers to be present!"
172 .to_string(),
173 ),
174 }
175 } else {
176 Ok(etsi_uper)
177 }
178 }
179}
180
181#[cfg(all(not(target_arch = "wasm32"), feature = "_etsi"))]
182pub fn encode_to_uper<T: rasn::Encode>(input: &T) -> Result<Encoded, alloc::string::String> {
187 rasn::Codec::Uper
188 .encode_to_binary(input)
189 .map_err(crate::map_err_to_string)
190}
191
192#[cfg(all(not(target_arch = "wasm32"), feature = "_etsi"))]
193pub fn encode_to_xer_buf<T: rasn::Encode>(input: &T) -> Result<Encoded, alloc::string::String> {
198 rasn::Codec::Xer
199 .encode_to_binary(input)
200 .map_err(crate::map_err_to_string)
201}
202
203#[cfg(all(not(target_arch = "wasm32"), feature = "_etsi"))]
204pub fn encode_to_xer_str<T: rasn::Encode>(
209 input: &T,
210) -> Result<alloc::string::String, alloc::string::String> {
211 rasn::Codec::Xer
212 .encode_to_string(input)
213 .map_err(crate::map_err_to_string)
214}
215
216#[cfg(all(not(target_arch = "wasm32"), feature = "_etsi"))]
217pub fn encode_to_jer_buf<T: rasn::Encode>(input: &T) -> Result<Encoded, alloc::string::String> {
222 rasn::Codec::Jer
223 .encode_to_binary(input)
224 .map_err(crate::map_err_to_string)
225}
226
227#[cfg(all(not(target_arch = "wasm32"), feature = "_etsi"))]
228pub fn encode_to_jer_str<T: rasn::Encode>(
233 input: &T,
234) -> Result<alloc::string::String, alloc::string::String> {
235 rasn::Codec::Jer
236 .encode_to_string(input)
237 .map_err(crate::map_err_to_string)
238}
239
240#[cfg(all(not(target_arch = "wasm32"), feature = "_etsi"))]
241macro_rules! encode_some_type {
245 ($t:ty) => {
246 impl $t {
247 pub fn encode_to_uper(&self) -> Result<Encoded, alloc::string::String> {
252 crate::en::encode_to_uper(&self)
253 }
254
255 pub fn encode_to_xer_buf(&self) -> Result<Encoded, alloc::string::String> {
260 crate::en::encode_to_xer_buf(&self)
261 }
262
263 pub fn encode_to_xer_str(
268 &self,
269 ) -> Result<alloc::string::String, alloc::string::String> {
270 crate::en::encode_to_xer_str(&self)
271 }
272
273 pub fn encode_to_jer_buf(&self) -> Result<Encoded, alloc::string::String> {
278 crate::en::encode_to_jer_buf(&self)
279 }
280
281 pub fn encode_to_jer_str(
286 &self,
287 ) -> Result<alloc::string::String, alloc::string::String> {
288 crate::en::encode_to_jer_str(&self)
289 }
290 }
291 };
292}
293
294#[cfg(all(not(target_arch = "wasm32"), feature = "_cdd_1_3_1_1"))]
295encode_some_type!(crate::standards::cdd_1_3_1_1::its_container::ItsPduHeader);
296#[cfg(all(not(target_arch = "wasm32"), feature = "_cdd_2_2_1"))]
297encode_some_type!(crate::standards::cdd_2_2_1::etsi_its_cdd::ItsPduHeader);
298
299#[cfg(all(not(target_arch = "wasm32"), feature = "denm_2_2_1"))]
300encode_some_type!(crate::standards::denm_2_2_1::denm_pdu_description::DENM);
301#[cfg(all(not(target_arch = "wasm32"), feature = "denm_2_2_1"))]
302encode_some_type!(crate::standards::denm_2_2_1::denm_pdu_description::DenmPayload);
303
304#[cfg(all(not(target_arch = "wasm32"), feature = "denm_1_3_1"))]
305encode_some_type!(crate::standards::denm_1_3_1::denm_pdu_descriptions::DENM);
306#[cfg(all(not(target_arch = "wasm32"), feature = "denm_1_3_1"))]
307encode_some_type!(
308 crate::standards::denm_1_3_1::denm_pdu_descriptions::DecentralizedEnvironmentalNotificationMessage
309);
310
311#[cfg(all(not(target_arch = "wasm32"), feature = "cam_1_4_1"))]
312encode_some_type!(crate::standards::cam_1_4_1::cam_pdu_descriptions::CAM);
313#[cfg(all(not(target_arch = "wasm32"), feature = "cam_1_4_1"))]
314encode_some_type!(crate::standards::cam_1_4_1::cam_pdu_descriptions::CoopAwareness);
315
316#[cfg(all(not(target_arch = "wasm32"), feature = "spatem_2_2_1"))]
317encode_some_type!(crate::standards::spatem_2_2_1::spatem_pdu_descriptions::SPATEM);
318#[cfg(all(not(target_arch = "wasm32"), feature = "_dsrc_2_2_1"))]
319encode_some_type!(crate::standards::dsrc_2_2_1::etsi_its_dsrc::SPAT);
320
321#[cfg(all(not(target_arch = "wasm32"), feature = "mapem_2_2_1"))]
322encode_some_type!(crate::standards::mapem_2_2_1::mapem_pdu_descriptions::MAPEM);
323#[cfg(all(not(target_arch = "wasm32"), feature = "_dsrc_2_2_1"))]
324encode_some_type!(crate::standards::dsrc_2_2_1::etsi_its_dsrc::MapData);
325
326#[cfg(all(not(target_arch = "wasm32"), feature = "ivim_2_2_1"))]
327encode_some_type!(crate::standards::ivim_2_2_1::ivim_pdu_descriptions::IVIM);
328#[cfg(all(not(target_arch = "wasm32"), feature = "ivim_2_2_1"))]
329encode_some_type!(crate::standards::ivim_2_2_1::ivi::IviStructure);
330
331#[cfg(all(not(target_arch = "wasm32"), feature = "ivim_2_1_1"))]
332encode_some_type!(crate::standards::ivim_2_1_1::ivim_pdu_descriptions::IVIM);
333#[cfg(all(not(target_arch = "wasm32"), feature = "ivim_2_1_1"))]
334encode_some_type!(crate::standards::ivim_2_1_1::ivi::IviStructure);
335
336#[cfg(all(not(target_arch = "wasm32"), feature = "srem_2_2_1"))]
337encode_some_type!(crate::standards::srem_2_2_1::srem_pdu_descriptions::SREM);
338#[cfg(all(not(target_arch = "wasm32"), feature = "_dsrc_2_2_1"))]
339encode_some_type!(crate::standards::dsrc_2_2_1::etsi_its_dsrc::SignalRequestMessage);
340
341#[cfg(all(not(target_arch = "wasm32"), feature = "ssem_2_2_1"))]
342encode_some_type!(crate::standards::ssem_2_2_1::ssem_pdu_descriptions::SSEM);
343#[cfg(all(not(target_arch = "wasm32"), feature = "_dsrc_2_2_1"))]
344encode_some_type!(crate::standards::dsrc_2_2_1::etsi_its_dsrc::SignalStatusMessage);
345
346#[cfg(all(not(target_arch = "wasm32"), feature = "cpm_2_1_1"))]
347encode_some_type!(crate::standards::cpm_2_1_1::cpm_pdu_descriptions::CollectivePerceptionMessage);
348#[cfg(all(not(target_arch = "wasm32"), feature = "cpm_2_1_1"))]
349encode_some_type!(crate::standards::cpm_2_1_1::cpm_pdu_descriptions::CpmPayload);
350
351#[cfg(all(not(target_arch = "wasm32"), feature = "cpm_1"))]
352encode_some_type!(crate::standards::cpm_1::cpm_pdu_descriptions::CPM);
353#[cfg(all(not(target_arch = "wasm32"), feature = "cpm_1"))]
354encode_some_type!(crate::standards::cpm_1::cpm_pdu_descriptions::CollectivePerceptionMessage);
355
356#[cfg(all(target_arch = "wasm32", feature = "json"))]
357#[wasm_bindgen(js_name = encodeDenm)]
358pub fn encode_denm(denm: &crate::JsonItsMessage, version: u32) -> Result<Encoded, String> {
363 let mut payload = vec![];
364 match (&denm.its, version) {
365 (None, 131) | (None, 221) => return Err("No DENM JSON provided.".to_string()),
366 (Some(denm_json), 131) => {
367 payload.append(&mut transcode_jer_to_uper::<
368 crate::standards::denm_1_3_1::denm_pdu_descriptions::DENM,
369 >(denm_json)?);
370 }
371 (Some(denm_json), 221) => {
372 payload.append(&mut transcode_jer_to_uper::<
373 crate::standards::denm_2_2_1::denm_pdu_description::DENM,
374 >(denm_json)?);
375 }
376 _ => {
377 return Err(
378 "Unsupported DENM version: Supported DENM versions are 131 and 221.".to_string(),
379 );
380 }
381 };
382 let encoded = optionally_encode_headers(&denm.geonetworking, &denm.transport, payload)?;
383 Ok(Encoded::from(encoded.as_slice()))
384}
385
386#[cfg(all(target_arch = "wasm32", feature = "json"))]
387#[wasm_bindgen(js_name = encodeCam)]
388pub fn encode_cam(cam: &crate::JsonItsMessage, version: u32) -> Result<Encoded, String> {
393 let mut payload = vec![];
394 match (&cam.its, version) {
395 (None, 141) => return Err("No CAM JSON provided.".to_string()),
396 (Some(json), 141) => {
397 payload.append(&mut transcode_jer_to_uper::<
398 crate::standards::cam_1_4_1::cam_pdu_descriptions::CAM,
399 >(json)?);
400 }
401 _ => return Err("Unsupported CAM version: Supported CAM version is 141.".to_string()),
402 };
403 let encoded = optionally_encode_headers(&cam.geonetworking, &cam.transport, payload)?;
404 Ok(Encoded::from(encoded.as_slice()))
405}
406
407#[cfg(all(target_arch = "wasm32", feature = "json"))]
408#[wasm_bindgen(js_name = encodeMapem)]
409pub fn encode_mapem(mapem: &crate::JsonItsMessage, version: u32) -> Result<Encoded, String> {
414 let mut payload = vec![];
415 match (&mapem.its, version) {
416 (None, 221) => return Err("No MAPEM JSON provided.".to_string()),
417 (Some(json), 221) => {
418 payload.append(&mut transcode_jer_to_uper::<
419 crate::standards::mapem_2_2_1::mapem_pdu_descriptions::MAPEM,
420 >(json)?);
421 }
422 _ => return Err("Unsupported MAPEM version: Supported MAPEM version is 221.".to_string()),
423 };
424 let encoded = optionally_encode_headers(&mapem.geonetworking, &mapem.transport, payload)?;
425 Ok(Encoded::from(encoded.as_slice()))
426}
427
428#[cfg(all(target_arch = "wasm32", feature = "json"))]
429#[wasm_bindgen(js_name = encodeSpatem)]
430pub fn encode_spatem(spatem: &crate::JsonItsMessage, version: u32) -> Result<Encoded, String> {
435 let mut payload = vec![];
436 match (&spatem.its, version) {
437 (None, 221) => return Err("No SPATEM JSON provided.".to_string()),
438 (Some(json), 221) => {
439 payload.append(&mut transcode_jer_to_uper::<
440 crate::standards::spatem_2_2_1::spatem_pdu_descriptions::SPATEM,
441 >(json)?);
442 }
443 _ => {
444 return Err("Unsupported SPATEM version: Supported SPATEM version is 221.".to_string());
445 }
446 };
447 let encoded = optionally_encode_headers(&spatem.geonetworking, &spatem.transport, payload)?;
448 Ok(Encoded::from(encoded.as_slice()))
449}
450
451#[cfg(all(target_arch = "wasm32", feature = "json"))]
452#[wasm_bindgen(js_name = encodeIvim)]
453pub fn encode_ivim(ivim: &crate::JsonItsMessage, version: u32) -> Result<Encoded, String> {
458 let mut payload = vec![];
459 match (&ivim.its, version) {
460 (None, 131) | (None, 211) | (None, 221) => return Err("No IVIM JSON provided.".to_string()),
461 (Some(json), 211) | (Some(json), 131) => {
462 payload.append(&mut transcode_jer_to_uper::<
463 crate::standards::ivim_2_1_1::ivim_pdu_descriptions::IVIM,
464 >(json)?);
465 }
466 (Some(json), 221) => {
467 payload.append(&mut transcode_jer_to_uper::<
468 crate::standards::ivim_2_2_1::ivim_pdu_descriptions::IVIM,
469 >(json)?);
470 }
471 _ => {
472 return Err(
473 "Unsupported IVIM version: Supported IVIM versions are 131, 211 and 221."
474 .to_string(),
475 );
476 }
477 };
478 let encoded = optionally_encode_headers(&ivim.geonetworking, &ivim.transport, payload)?;
479 Ok(Encoded::from(encoded.as_slice()))
480}
481
482#[cfg(all(target_arch = "wasm32", feature = "json"))]
483#[wasm_bindgen(js_name = encodeSrem)]
484pub fn encode_srem(srem: &crate::JsonItsMessage, version: u32) -> Result<Encoded, String> {
489 let mut payload = vec![];
490 match (&srem.its, version) {
491 (None, 221) => return Err("No SREM JSON provided.".to_string()),
492 (Some(json), 221) => {
493 payload.append(&mut transcode_jer_to_uper::<
494 crate::standards::srem_2_2_1::srem_pdu_descriptions::SREM,
495 >(json)?);
496 }
497 _ => return Err("Unsupported SREM version: Supported SREM version is 221.".to_string()),
498 };
499 let encoded = optionally_encode_headers(&srem.geonetworking, &srem.transport, payload)?;
500 Ok(Encoded::from(encoded.as_slice()))
501}
502
503#[cfg(all(target_arch = "wasm32", feature = "json"))]
504#[wasm_bindgen(js_name = encodeCpm)]
505pub fn encode_cpm(cpm: &crate::JsonItsMessage, version: u32) -> Result<Encoded, String> {
510 let mut payload = vec![];
511 match (&cpm.its, version) {
512 (None, 131) | (None, 211) => return Err("No CPM JSON provided.".to_string()),
513 (Some(json), 131) => {
514 payload.append(&mut transcode_jer_to_uper::<
515 crate::standards::cpm_1::cpm_pdu_descriptions::CPM,
516 >(json)?);
517 }
518 (Some(json), 211) => {
519 payload.append(&mut transcode_jer_to_uper::<
520 crate::standards::cpm_2_1_1::cpm_pdu_descriptions::CollectivePerceptionMessage,
521 >(json)?);
522 }
523 _ => {
524 return Err(
525 "Unsupported CPM version: Supported CPM versions are 131 and 211.".to_string(),
526 );
527 }
528 };
529 let encoded = optionally_encode_headers(&cpm.geonetworking, &cpm.transport, payload)?;
530 Ok(Encoded::from(encoded.as_slice()))
531}
532
533#[cfg(all(target_arch = "wasm32", feature = "json"))]
534#[wasm_bindgen(js_name = encodeSsem)]
535pub fn encode_ssem(ssem: &crate::JsonItsMessage, version: u32) -> Result<Encoded, String> {
540 let mut payload = vec![];
541 match (&ssem.its, version) {
542 (None, 221) => return Err("No SSEM JSON provided.".to_string()),
543 (Some(json), 221) => {
544 payload.append(&mut transcode_jer_to_uper::<
545 crate::standards::ssem_2_2_1::ssem_pdu_descriptions::SSEM,
546 >(json)?);
547 }
548 _ => return Err("Unsupported SSEM version: Supported SSEM version is 221.".to_string()),
549 };
550 let encoded = optionally_encode_headers(&ssem.geonetworking, &ssem.transport, payload)?;
551 Ok(Encoded::from(encoded.as_slice()))
552}
553
554#[cfg(all(target_arch = "wasm32", feature = "json"))]
555fn optionally_encode_headers(
556 gn_json: &Option<String>,
557 tp_json: &Option<String>,
558 mut its: alloc::vec::Vec<u8>,
559) -> Result<alloc::vec::Vec<u8>, String> {
560 use crate::transport::encode::Encode as _;
561
562 match (gn_json, tp_json) {
563 (Some(_), None) | (None, Some(_)) => Err(
564 "Expecting either both or neither GeoNetworking and Transport headers to be present!"
565 .to_string(),
566 ),
567 (Some(gn), Some(tp)) => {
568 let geonetworking =
569 geonetworking::UnsecuredHeader::from_json(gn).map_err(crate::map_err_to_string)?;
570 let mut transport = match geonetworking.common.next_header {
571 geonetworking::en302636_4_1::NextAfterCommon::BTPA => {
572 crate::transport::BasicTransportAHeader::decode_from_json(tp)
573 .map_err(crate::map_err_to_string)?
574 .encode()
575 .map_err(crate::map_err_to_string)?
576 }
577 geonetworking::en302636_4_1::NextAfterCommon::BTPB => {
578 crate::transport::BasicTransportBHeader::decode_from_json(tp)
579 .map_err(crate::map_err_to_string)?
580 .encode()
581 .map_err(crate::map_err_to_string)?
582 }
583 h => {
584 return Err(alloc::format!(
585 "Currently only BTP-A and BTP-B headers can be encoded: Encountered {h:?}"
586 ));
587 }
588 };
589 transport.append(&mut its);
590 fill_gn_and_encode(geonetworking, &transport)
591 }
592 _ => Ok(its),
593 }
594}
595
596#[cfg(any(
597 all(target_arch = "wasm32", feature = "json"),
598 not(target_arch = "wasm32")
599))]
600fn fill_gn_and_encode(
601 mut geonetworking: geonetworking::UnsecuredHeader,
602 payload: &[u8],
603) -> Result<alloc::vec::Vec<u8>, alloc::string::String> {
604 use geonetworking::Encode as _;
605
606 #[allow(clippy::cast_possible_truncation)]
607 let gn_payload_length = payload.len() as u16;
608
609 geonetworking.common.payload_length = gn_payload_length;
610 geonetworking.basic.remaining_hop_limit = geonetworking.common.maximum_hop_limit;
611 geonetworking
612 .with_payload(payload)
613 .map_err(crate::map_err_to_string)?
614 .encode_to_vec()
615 .map_err(crate::map_err_to_string)
616}
617
618#[cfg(all(target_arch = "wasm32", feature = "json"))]
619fn transcode_jer_to_uper<T: rasn::Decode + rasn::Encode>(
620 input: &String,
621) -> Result<alloc::vec::Vec<u8>, String> {
622 rasn::uper::encode(&rasn::jer::decode::<T>(input).map_err(crate::map_err_to_string)?)
623 .map_err(crate::map_err_to_string)
624}