#[cfg(not(target_arch = "wasm32"))]
use alloc::string::ToString;
#[cfg(all(target_arch = "wasm32", feature = "json"))]
use wasm_bindgen::prelude::*;
#[cfg(all(target_arch = "wasm32", feature = "json"))]
pub type Encoded = js_sys::Uint8Array;
#[cfg(not(target_arch = "wasm32"))]
pub type Encoded = alloc::vec::Vec<u8>;
#[cfg(not(target_arch = "wasm32"))]
impl crate::ItsMessage<'_> {
#[allow(clippy::too_many_lines)]
pub fn encode(
self,
encoding_rules: crate::EncodingRules,
) -> Result<Encoded, alloc::string::String> {
use crate::ItsMessage;
let (geo, tp, mut etsi_uper) = match self {
#[cfg(feature = "denm_1_3_1")]
ItsMessage::DenmV1 {
geonetworking,
transport,
etsi,
} => encoding_rules
.codec()
.encode_to_binary(&etsi)
.map(|enc| (geonetworking, transport, enc)),
#[cfg(feature = "denm_2_2_1")]
ItsMessage::DenmV2 {
geonetworking,
transport,
etsi,
} => encoding_rules
.codec()
.encode_to_binary(&etsi)
.map(|enc| (geonetworking, transport, enc)),
#[cfg(feature = "cam_1_4_1")]
ItsMessage::Cam {
geonetworking,
transport,
etsi,
} => encoding_rules
.codec()
.encode_to_binary(&etsi)
.map(|enc| (geonetworking, transport, enc)),
#[cfg(feature = "spatem_2_2_1")]
ItsMessage::Spatem {
geonetworking,
transport,
etsi,
} => encoding_rules
.codec()
.encode_to_binary(&etsi)
.map(|enc| (geonetworking, transport, enc)),
#[cfg(feature = "mapem_2_2_1")]
ItsMessage::Mapem {
geonetworking,
transport,
etsi,
} => encoding_rules
.codec()
.encode_to_binary(&etsi)
.map(|enc| (geonetworking, transport, enc)),
#[cfg(feature = "ivim_2_1_1")]
ItsMessage::IvimV1 {
geonetworking,
transport,
etsi,
} => encoding_rules
.codec()
.encode_to_binary(&etsi)
.map(|enc| (geonetworking, transport, enc)),
#[cfg(feature = "ivim_2_2_1")]
ItsMessage::IvimV2 {
geonetworking,
transport,
etsi,
} => encoding_rules
.codec()
.encode_to_binary(&etsi)
.map(|enc| (geonetworking, transport, enc)),
#[cfg(feature = "srem_2_2_1")]
ItsMessage::Srem {
geonetworking,
transport,
etsi,
} => encoding_rules
.codec()
.encode_to_binary(&etsi)
.map(|enc| (geonetworking, transport, enc)),
#[cfg(feature = "ssem_2_2_1")]
ItsMessage::Ssem {
geonetworking,
transport,
etsi,
} => encoding_rules
.codec()
.encode_to_binary(&etsi)
.map(|enc| (geonetworking, transport, enc)),
#[cfg(feature = "cpm_1")]
ItsMessage::CpmV1 {
geonetworking,
transport,
etsi,
} => encoding_rules
.codec()
.encode_to_binary(&etsi)
.map(|enc| (geonetworking, transport, enc)),
#[cfg(feature = "cpm_2_1_1")]
ItsMessage::CpmV2 {
geonetworking,
transport,
etsi,
} => encoding_rules
.codec()
.encode_to_binary(&etsi)
.map(|enc| (geonetworking, transport, enc)),
}
.map_err(crate::map_err_to_string)?;
if encoding_rules == crate::EncodingRules::UPER {
match (tp, geo) {
(None, None) => Ok(etsi_uper),
(
Some(tp),
Some(geonetworking::Packet::Unsecured {
basic,
common,
extended,
..
} | geonetworking::Packet::Secured {
basic,
common,
extended,
..
}),
) => {
let mut encoded = tp.encode()?;
encoded.append(&mut etsi_uper);
fill_gn_and_encode(geonetworking::UnsecuredHeader { basic, common, extended }, &encoded)
}
_ => Err(
"Expecting either both or neither GeoNetworking and Transport headers to be present!"
.to_string(),
),
}
} else {
Ok(etsi_uper)
}
}
}
#[cfg(all(not(target_arch = "wasm32"), feature = "_etsi"))]
pub fn encode_to_uper<T: rasn::Encode>(input: &T) -> Result<Encoded, alloc::string::String> {
rasn::Codec::Uper
.encode_to_binary(input)
.map_err(crate::map_err_to_string)
}
#[cfg(all(not(target_arch = "wasm32"), feature = "_etsi"))]
pub fn encode_to_xer_buf<T: rasn::Encode>(input: &T) -> Result<Encoded, alloc::string::String> {
rasn::Codec::Xer
.encode_to_binary(input)
.map_err(crate::map_err_to_string)
}
#[cfg(all(not(target_arch = "wasm32"), feature = "_etsi"))]
pub fn encode_to_xer_str<T: rasn::Encode>(
input: &T,
) -> Result<alloc::string::String, alloc::string::String> {
rasn::Codec::Xer
.encode_to_string(input)
.map_err(crate::map_err_to_string)
}
#[cfg(all(not(target_arch = "wasm32"), feature = "_etsi"))]
pub fn encode_to_jer_buf<T: rasn::Encode>(input: &T) -> Result<Encoded, alloc::string::String> {
rasn::Codec::Jer
.encode_to_binary(input)
.map_err(crate::map_err_to_string)
}
#[cfg(all(not(target_arch = "wasm32"), feature = "_etsi"))]
pub fn encode_to_jer_str<T: rasn::Encode>(
input: &T,
) -> Result<alloc::string::String, alloc::string::String> {
rasn::Codec::Jer
.encode_to_string(input)
.map_err(crate::map_err_to_string)
}
#[cfg(all(not(target_arch = "wasm32"), feature = "_etsi"))]
macro_rules! encode_some_type {
($t:ty) => {
impl $t {
pub fn encode_to_uper(&self) -> Result<Encoded, alloc::string::String> {
crate::en::encode_to_uper(&self)
}
pub fn encode_to_xer_buf(&self) -> Result<Encoded, alloc::string::String> {
crate::en::encode_to_xer_buf(&self)
}
pub fn encode_to_xer_str(
&self,
) -> Result<alloc::string::String, alloc::string::String> {
crate::en::encode_to_xer_str(&self)
}
pub fn encode_to_jer_buf(&self) -> Result<Encoded, alloc::string::String> {
crate::en::encode_to_jer_buf(&self)
}
pub fn encode_to_jer_str(
&self,
) -> Result<alloc::string::String, alloc::string::String> {
crate::en::encode_to_jer_str(&self)
}
}
};
}
#[cfg(all(not(target_arch = "wasm32"), feature = "_cdd_1_3_1_1"))]
encode_some_type!(crate::standards::cdd_1_3_1_1::its_container::ItsPduHeader);
#[cfg(all(not(target_arch = "wasm32"), feature = "_cdd_2_2_1"))]
encode_some_type!(crate::standards::cdd_2_2_1::etsi_its_cdd::ItsPduHeader);
#[cfg(all(not(target_arch = "wasm32"), feature = "denm_2_2_1"))]
encode_some_type!(crate::standards::denm_2_2_1::denm_pdu_description::DENM);
#[cfg(all(not(target_arch = "wasm32"), feature = "denm_2_2_1"))]
encode_some_type!(crate::standards::denm_2_2_1::denm_pdu_description::DenmPayload);
#[cfg(all(not(target_arch = "wasm32"), feature = "denm_1_3_1"))]
encode_some_type!(crate::standards::denm_1_3_1::denm_pdu_descriptions::DENM);
#[cfg(all(not(target_arch = "wasm32"), feature = "denm_1_3_1"))]
encode_some_type!(
crate::standards::denm_1_3_1::denm_pdu_descriptions::DecentralizedEnvironmentalNotificationMessage
);
#[cfg(all(not(target_arch = "wasm32"), feature = "cam_1_4_1"))]
encode_some_type!(crate::standards::cam_1_4_1::cam_pdu_descriptions::CAM);
#[cfg(all(not(target_arch = "wasm32"), feature = "cam_1_4_1"))]
encode_some_type!(crate::standards::cam_1_4_1::cam_pdu_descriptions::CoopAwareness);
#[cfg(all(not(target_arch = "wasm32"), feature = "spatem_2_2_1"))]
encode_some_type!(crate::standards::spatem_2_2_1::spatem_pdu_descriptions::SPATEM);
#[cfg(all(not(target_arch = "wasm32"), feature = "_dsrc_2_2_1"))]
encode_some_type!(crate::standards::dsrc_2_2_1::etsi_its_dsrc::SPAT);
#[cfg(all(not(target_arch = "wasm32"), feature = "mapem_2_2_1"))]
encode_some_type!(crate::standards::mapem_2_2_1::mapem_pdu_descriptions::MAPEM);
#[cfg(all(not(target_arch = "wasm32"), feature = "_dsrc_2_2_1"))]
encode_some_type!(crate::standards::dsrc_2_2_1::etsi_its_dsrc::MapData);
#[cfg(all(not(target_arch = "wasm32"), feature = "ivim_2_2_1"))]
encode_some_type!(crate::standards::ivim_2_2_1::ivim_pdu_descriptions::IVIM);
#[cfg(all(not(target_arch = "wasm32"), feature = "ivim_2_2_1"))]
encode_some_type!(crate::standards::ivim_2_2_1::ivi::IviStructure);
#[cfg(all(not(target_arch = "wasm32"), feature = "ivim_2_1_1"))]
encode_some_type!(crate::standards::ivim_2_1_1::ivim_pdu_descriptions::IVIM);
#[cfg(all(not(target_arch = "wasm32"), feature = "ivim_2_1_1"))]
encode_some_type!(crate::standards::ivim_2_1_1::ivi::IviStructure);
#[cfg(all(not(target_arch = "wasm32"), feature = "srem_2_2_1"))]
encode_some_type!(crate::standards::srem_2_2_1::srem_pdu_descriptions::SREM);
#[cfg(all(not(target_arch = "wasm32"), feature = "_dsrc_2_2_1"))]
encode_some_type!(crate::standards::dsrc_2_2_1::etsi_its_dsrc::SignalRequestMessage);
#[cfg(all(not(target_arch = "wasm32"), feature = "ssem_2_2_1"))]
encode_some_type!(crate::standards::ssem_2_2_1::ssem_pdu_descriptions::SSEM);
#[cfg(all(not(target_arch = "wasm32"), feature = "_dsrc_2_2_1"))]
encode_some_type!(crate::standards::dsrc_2_2_1::etsi_its_dsrc::SignalStatusMessage);
#[cfg(all(not(target_arch = "wasm32"), feature = "cpm_2_1_1"))]
encode_some_type!(crate::standards::cpm_2_1_1::cpm_pdu_descriptions::CollectivePerceptionMessage);
#[cfg(all(not(target_arch = "wasm32"), feature = "cpm_2_1_1"))]
encode_some_type!(crate::standards::cpm_2_1_1::cpm_pdu_descriptions::CpmPayload);
#[cfg(all(not(target_arch = "wasm32"), feature = "cpm_1"))]
encode_some_type!(crate::standards::cpm_1::cpm_pdu_descriptions::CPM);
#[cfg(all(not(target_arch = "wasm32"), feature = "cpm_1"))]
encode_some_type!(crate::standards::cpm_1::cpm_pdu_descriptions::CollectivePerceptionMessage);
#[cfg(all(target_arch = "wasm32", feature = "json"))]
#[wasm_bindgen(js_name = encodeDenm)]
pub fn encode_denm(denm: &crate::JsonItsMessage, version: u32) -> Result<Encoded, String> {
let mut payload = vec![];
match (&denm.its, version) {
(None, 131) | (None, 221) => return Err("No DENM JSON provided.".to_string()),
(Some(denm_json), 131) => {
payload.append(&mut transcode_jer_to_uper::<
crate::standards::denm_1_3_1::denm_pdu_descriptions::DENM,
>(denm_json)?);
}
(Some(denm_json), 221) => {
payload.append(&mut transcode_jer_to_uper::<
crate::standards::denm_2_2_1::denm_pdu_description::DENM,
>(denm_json)?);
}
_ => {
return Err(
"Unsupported DENM version: Supported DENM versions are 131 and 221.".to_string(),
);
}
};
let encoded = optionally_encode_headers(&denm.geonetworking, &denm.transport, payload)?;
Ok(Encoded::from(encoded.as_slice()))
}
#[cfg(all(target_arch = "wasm32", feature = "json"))]
#[wasm_bindgen(js_name = encodeCam)]
pub fn encode_cam(cam: &crate::JsonItsMessage, version: u32) -> Result<Encoded, String> {
let mut payload = vec![];
match (&cam.its, version) {
(None, 141) => return Err("No CAM JSON provided.".to_string()),
(Some(json), 141) => {
payload.append(&mut transcode_jer_to_uper::<
crate::standards::cam_1_4_1::cam_pdu_descriptions::CAM,
>(json)?);
}
_ => return Err("Unsupported CAM version: Supported CAM version is 141.".to_string()),
};
let encoded = optionally_encode_headers(&cam.geonetworking, &cam.transport, payload)?;
Ok(Encoded::from(encoded.as_slice()))
}
#[cfg(all(target_arch = "wasm32", feature = "json"))]
#[wasm_bindgen(js_name = encodeMapem)]
pub fn encode_mapem(mapem: &crate::JsonItsMessage, version: u32) -> Result<Encoded, String> {
let mut payload = vec![];
match (&mapem.its, version) {
(None, 221) => return Err("No MAPEM JSON provided.".to_string()),
(Some(json), 221) => {
payload.append(&mut transcode_jer_to_uper::<
crate::standards::mapem_2_2_1::mapem_pdu_descriptions::MAPEM,
>(json)?);
}
_ => return Err("Unsupported MAPEM version: Supported MAPEM version is 221.".to_string()),
};
let encoded = optionally_encode_headers(&mapem.geonetworking, &mapem.transport, payload)?;
Ok(Encoded::from(encoded.as_slice()))
}
#[cfg(all(target_arch = "wasm32", feature = "json"))]
#[wasm_bindgen(js_name = encodeSpatem)]
pub fn encode_spatem(spatem: &crate::JsonItsMessage, version: u32) -> Result<Encoded, String> {
let mut payload = vec![];
match (&spatem.its, version) {
(None, 221) => return Err("No SPATEM JSON provided.".to_string()),
(Some(json), 221) => {
payload.append(&mut transcode_jer_to_uper::<
crate::standards::spatem_2_2_1::spatem_pdu_descriptions::SPATEM,
>(json)?);
}
_ => {
return Err("Unsupported SPATEM version: Supported SPATEM version is 221.".to_string());
}
};
let encoded = optionally_encode_headers(&spatem.geonetworking, &spatem.transport, payload)?;
Ok(Encoded::from(encoded.as_slice()))
}
#[cfg(all(target_arch = "wasm32", feature = "json"))]
#[wasm_bindgen(js_name = encodeIvim)]
pub fn encode_ivim(ivim: &crate::JsonItsMessage, version: u32) -> Result<Encoded, String> {
let mut payload = vec![];
match (&ivim.its, version) {
(None, 131) | (None, 211) | (None, 221) => return Err("No IVIM JSON provided.".to_string()),
(Some(json), 211) | (Some(json), 131) => {
payload.append(&mut transcode_jer_to_uper::<
crate::standards::ivim_2_1_1::ivim_pdu_descriptions::IVIM,
>(json)?);
}
(Some(json), 221) => {
payload.append(&mut transcode_jer_to_uper::<
crate::standards::ivim_2_2_1::ivim_pdu_descriptions::IVIM,
>(json)?);
}
_ => {
return Err(
"Unsupported IVIM version: Supported IVIM versions are 131, 211 and 221."
.to_string(),
);
}
};
let encoded = optionally_encode_headers(&ivim.geonetworking, &ivim.transport, payload)?;
Ok(Encoded::from(encoded.as_slice()))
}
#[cfg(all(target_arch = "wasm32", feature = "json"))]
#[wasm_bindgen(js_name = encodeSrem)]
pub fn encode_srem(srem: &crate::JsonItsMessage, version: u32) -> Result<Encoded, String> {
let mut payload = vec![];
match (&srem.its, version) {
(None, 221) => return Err("No SREM JSON provided.".to_string()),
(Some(json), 221) => {
payload.append(&mut transcode_jer_to_uper::<
crate::standards::srem_2_2_1::srem_pdu_descriptions::SREM,
>(json)?);
}
_ => return Err("Unsupported SREM version: Supported SREM version is 221.".to_string()),
};
let encoded = optionally_encode_headers(&srem.geonetworking, &srem.transport, payload)?;
Ok(Encoded::from(encoded.as_slice()))
}
#[cfg(all(target_arch = "wasm32", feature = "json"))]
#[wasm_bindgen(js_name = encodeCpm)]
pub fn encode_cpm(cpm: &crate::JsonItsMessage, version: u32) -> Result<Encoded, String> {
let mut payload = vec![];
match (&cpm.its, version) {
(None, 131) | (None, 211) => return Err("No CPM JSON provided.".to_string()),
(Some(json), 131) => {
payload.append(&mut transcode_jer_to_uper::<
crate::standards::cpm_1::cpm_pdu_descriptions::CPM,
>(json)?);
}
(Some(json), 211) => {
payload.append(&mut transcode_jer_to_uper::<
crate::standards::cpm_2_1_1::cpm_pdu_descriptions::CollectivePerceptionMessage,
>(json)?);
}
_ => {
return Err(
"Unsupported CPM version: Supported CPM versions are 131 and 211.".to_string(),
);
}
};
let encoded = optionally_encode_headers(&cpm.geonetworking, &cpm.transport, payload)?;
Ok(Encoded::from(encoded.as_slice()))
}
#[cfg(all(target_arch = "wasm32", feature = "json"))]
#[wasm_bindgen(js_name = encodeSsem)]
pub fn encode_ssem(ssem: &crate::JsonItsMessage, version: u32) -> Result<Encoded, String> {
let mut payload = vec![];
match (&ssem.its, version) {
(None, 221) => return Err("No SSEM JSON provided.".to_string()),
(Some(json), 221) => {
payload.append(&mut transcode_jer_to_uper::<
crate::standards::ssem_2_2_1::ssem_pdu_descriptions::SSEM,
>(json)?);
}
_ => return Err("Unsupported SSEM version: Supported SSEM version is 221.".to_string()),
};
let encoded = optionally_encode_headers(&ssem.geonetworking, &ssem.transport, payload)?;
Ok(Encoded::from(encoded.as_slice()))
}
#[cfg(all(target_arch = "wasm32", feature = "json"))]
fn optionally_encode_headers(
gn_json: &Option<String>,
tp_json: &Option<String>,
mut its: alloc::vec::Vec<u8>,
) -> Result<alloc::vec::Vec<u8>, String> {
use crate::transport::encode::Encode as _;
match (gn_json, tp_json) {
(Some(_), None) | (None, Some(_)) => Err(
"Expecting either both or neither GeoNetworking and Transport headers to be present!"
.to_string(),
),
(Some(gn), Some(tp)) => {
let geonetworking =
geonetworking::UnsecuredHeader::from_json(gn).map_err(crate::map_err_to_string)?;
let mut transport = match geonetworking.common.next_header {
geonetworking::en302636_4_1::NextAfterCommon::BTPA => {
crate::transport::BasicTransportAHeader::decode_from_json(tp)
.map_err(crate::map_err_to_string)?
.encode()
.map_err(crate::map_err_to_string)?
}
geonetworking::en302636_4_1::NextAfterCommon::BTPB => {
crate::transport::BasicTransportBHeader::decode_from_json(tp)
.map_err(crate::map_err_to_string)?
.encode()
.map_err(crate::map_err_to_string)?
}
h => {
return Err(alloc::format!(
"Currently only BTP-A and BTP-B headers can be encoded: Encountered {h:?}"
));
}
};
transport.append(&mut its);
fill_gn_and_encode(geonetworking, &transport)
}
_ => Ok(its),
}
}
#[cfg(any(
all(target_arch = "wasm32", feature = "json"),
not(target_arch = "wasm32")
))]
fn fill_gn_and_encode(
mut geonetworking: geonetworking::UnsecuredHeader,
payload: &[u8],
) -> Result<alloc::vec::Vec<u8>, alloc::string::String> {
use geonetworking::Encode as _;
#[allow(clippy::cast_possible_truncation)]
let gn_payload_length = payload.len() as u16;
geonetworking.common.payload_length = gn_payload_length;
geonetworking.basic.remaining_hop_limit = geonetworking.common.maximum_hop_limit;
geonetworking
.with_payload(payload)
.map_err(crate::map_err_to_string)?
.encode_to_vec()
.map_err(crate::map_err_to_string)
}
#[cfg(all(target_arch = "wasm32", feature = "json"))]
fn transcode_jer_to_uper<T: rasn::Decode + rasn::Encode>(
input: &String,
) -> Result<alloc::vec::Vec<u8>, String> {
rasn::uper::encode(&rasn::jer::decode::<T>(input).map_err(crate::map_err_to_string)?)
.map_err(crate::map_err_to_string)
}