1use mediatype::MediaType;
15
16use crate::SerializationError;
17
18#[derive(Debug)]
19pub enum UPayloadError {
20 SerializationError(String),
21 MediatypeProblem,
22}
23
24impl UPayloadError {
25 pub fn serialization_error<T>(message: T) -> UPayloadError
26 where
27 T: Into<String>,
28 {
29 Self::SerializationError(message.into())
30 }
31
32 pub fn mediatype_error() -> UPayloadError {
33 Self::MediatypeProblem
34 }
35}
36
37impl std::fmt::Display for UPayloadError {
38 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39 match self {
40 Self::SerializationError(e) => f.write_fmt(format_args!("Serialization error: {e}")),
41 Self::MediatypeProblem => {
42 f.write_fmt(format_args!("Mediatype problem unsupported or malformed"))
43 }
44 }
45 }
46}
47
48impl std::error::Error for UPayloadError {}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
51#[repr(C)]
52pub enum UPayloadFormat {
54 Unspecified = 0,
56 ProtobufWrappedInAny = 1,
58 Protobuf = 2,
60 Json = 3,
62 Someip = 4,
64 SomeipTlv = 5,
66 Raw = 6,
68 Text = 7,
70 Shm = 8,
72}
73
74impl UPayloadFormat {
75 #[must_use]
77 pub fn as_i32(&self) -> i32 {
78 *self as i32
79 }
80
81 pub fn try_from_i32(value: i32) -> Result<UPayloadFormat, SerializationError> {
87 match value {
88 x if x == UPayloadFormat::Unspecified as i32 => Ok(UPayloadFormat::Unspecified),
89 x if x == UPayloadFormat::ProtobufWrappedInAny as i32 => {
90 Ok(UPayloadFormat::ProtobufWrappedInAny)
91 }
92 x if x == UPayloadFormat::Protobuf as i32 => Ok(UPayloadFormat::Protobuf),
93 x if x == UPayloadFormat::Json as i32 => Ok(UPayloadFormat::Json),
94 x if x == UPayloadFormat::Someip as i32 => Ok(UPayloadFormat::Someip),
95 x if x == UPayloadFormat::SomeipTlv as i32 => Ok(UPayloadFormat::SomeipTlv),
96 x if x == UPayloadFormat::Raw as i32 => Ok(UPayloadFormat::Raw),
97 x if x == UPayloadFormat::Text as i32 => Ok(UPayloadFormat::Text),
98 x if x == UPayloadFormat::Shm as i32 => Ok(UPayloadFormat::Shm),
99 _ => Err(SerializationError::new(format!(
100 "unknown payload format code {value}"
101 ))),
102 }
103 }
104}
105
106impl UPayloadFormat {
107 pub fn from_media_type(media_type_string: &str) -> Result<Self, UPayloadError> {
125 if let Ok(media_type) = MediaType::parse(media_type_string) {
126 match (media_type.ty.as_str(), media_type.subty.as_str()) {
127 ("application", "json") => return Ok(UPayloadFormat::Json),
128 ("application", "protobuf") => return Ok(UPayloadFormat::Protobuf),
129 ("application", "x-protobuf") => return Ok(UPayloadFormat::ProtobufWrappedInAny),
130 ("application", "octet-stream") => return Ok(UPayloadFormat::Raw),
131 ("application", "x-someip") => return Ok(UPayloadFormat::Someip),
132 ("application", "x-someip_tlv") => return Ok(UPayloadFormat::SomeipTlv),
133 ("text", "plain") => return Ok(UPayloadFormat::Text),
134 ("application", "x-shm") => return Ok(UPayloadFormat::Shm),
135 _ => return Err(UPayloadError::mediatype_error()),
136 }
137 }
138 Err(UPayloadError::mediatype_error())
139 }
140
141 #[must_use]
156 pub fn to_media_type(self) -> Option<String> {
157 match self {
158 UPayloadFormat::Unspecified => None,
159 UPayloadFormat::ProtobufWrappedInAny => Some("application/x-protobuf".to_string()),
160 UPayloadFormat::Protobuf => Some("application/protobuf".to_string()),
161 UPayloadFormat::Json => Some("application/json".to_string()),
162 UPayloadFormat::Someip => Some("application/x-someip".to_string()),
163 UPayloadFormat::SomeipTlv => Some("application/x-someip_tlv".to_string()),
164 UPayloadFormat::Raw => Some("application/octet-stream".to_string()),
165 UPayloadFormat::Text => Some("text/plain".to_string()),
166 UPayloadFormat::Shm => Some("application/x-shm".to_string()),
167 }
168 }
169}
170
171#[cfg(feature = "up-core-api")]
172mod core_types_support {
173 use super::*;
174 use crate::up_core_api::uattributes::UPayloadFormat as UPayloadFormatProto;
175
176 impl From<UPayloadFormatProto> for UPayloadFormat {
177 fn from(value: UPayloadFormatProto) -> Self {
178 match value {
179 UPayloadFormatProto::UPAYLOAD_FORMAT_UNSPECIFIED => UPayloadFormat::Unspecified,
180 UPayloadFormatProto::UPAYLOAD_FORMAT_JSON => UPayloadFormat::Json,
181 UPayloadFormatProto::UPAYLOAD_FORMAT_PROTOBUF => UPayloadFormat::Protobuf,
182 UPayloadFormatProto::UPAYLOAD_FORMAT_PROTOBUF_WRAPPED_IN_ANY => {
183 UPayloadFormat::ProtobufWrappedInAny
184 }
185 UPayloadFormatProto::UPAYLOAD_FORMAT_RAW => UPayloadFormat::Raw,
186 UPayloadFormatProto::UPAYLOAD_FORMAT_SHM => UPayloadFormat::Shm,
187 UPayloadFormatProto::UPAYLOAD_FORMAT_SOMEIP => UPayloadFormat::Someip,
188 UPayloadFormatProto::UPAYLOAD_FORMAT_SOMEIP_TLV => UPayloadFormat::SomeipTlv,
189 UPayloadFormatProto::UPAYLOAD_FORMAT_TEXT => UPayloadFormat::Text,
190 }
191 }
192 }
193
194 impl From<&UPayloadFormat> for UPayloadFormatProto {
195 fn from(value: &UPayloadFormat) -> Self {
196 match value {
197 UPayloadFormat::Unspecified => UPayloadFormatProto::UPAYLOAD_FORMAT_UNSPECIFIED,
198 UPayloadFormat::Json => UPayloadFormatProto::UPAYLOAD_FORMAT_JSON,
199 UPayloadFormat::Protobuf => UPayloadFormatProto::UPAYLOAD_FORMAT_PROTOBUF,
200 UPayloadFormat::ProtobufWrappedInAny => {
201 UPayloadFormatProto::UPAYLOAD_FORMAT_PROTOBUF_WRAPPED_IN_ANY
202 }
203 UPayloadFormat::Raw => UPayloadFormatProto::UPAYLOAD_FORMAT_RAW,
204 UPayloadFormat::Shm => UPayloadFormatProto::UPAYLOAD_FORMAT_SHM,
205 UPayloadFormat::Someip => UPayloadFormatProto::UPAYLOAD_FORMAT_SOMEIP,
206 UPayloadFormat::SomeipTlv => UPayloadFormatProto::UPAYLOAD_FORMAT_SOMEIP_TLV,
207 UPayloadFormat::Text => UPayloadFormatProto::UPAYLOAD_FORMAT_TEXT,
208 }
209 }
210 }
211}
212
213#[cfg(test)]
214mod tests {
215 use super::*;
216
217 use test_case::test_case;
218
219 #[test_case("application/json", Ok(UPayloadFormat::Json); "map from JSON")]
220 #[test_case(
221 "application/json; charset=utf-8",
222 Ok(UPayloadFormat::Json);
223 "map from JSON with parameter"
224 )]
225 #[test_case("application/protobuf", Ok(UPayloadFormat::Protobuf); "map from PROTOBUF")]
226 #[test_case(
227 "application/x-protobuf",
228 Ok(UPayloadFormat::ProtobufWrappedInAny); "map from PROTOBUF_WRAPPED"
229 )]
230 #[test_case("application/octet-stream", Ok(UPayloadFormat::Raw); "map from RAW")]
231 #[test_case("application/x-someip", Ok(UPayloadFormat::Someip); "map from SOMEIP")]
232 #[test_case(
233 "application/x-someip_tlv",
234 Ok(UPayloadFormat::SomeipTlv); "map from SOMEIP_TLV"
235 )]
236 #[test_case("text/plain", Ok(UPayloadFormat::Text); "map from TEXT")]
237 #[test_case("application/unsupported; foo=bar", Err(UPayloadError::mediatype_error()); "fail for unsupported media type")]
238 fn test_from_media_type(
239 media_type: &str,
240 expected_format: Result<UPayloadFormat, UPayloadError>,
241 ) {
242 let parsing_result = UPayloadFormat::from_media_type(media_type);
243 assert!(parsing_result.is_ok() == expected_format.is_ok());
244 if let Ok(format) = expected_format {
245 assert_eq!(format, parsing_result.unwrap());
246 }
247 }
248
249 #[test_case(UPayloadFormat::Json, Some("application/json".to_string()); "map JSON format to media type")]
250 #[test_case(UPayloadFormat::Protobuf, Some("application/protobuf".to_string()); "map PROTOBUF format to media type")]
251 #[test_case(UPayloadFormat::ProtobufWrappedInAny, Some("application/x-protobuf".to_string()); "map PROTOBUF_WRAPPED format to media type")]
252 #[test_case(UPayloadFormat::Raw, Some("application/octet-stream".to_string()); "map RAW format to media type")]
253 #[test_case(UPayloadFormat::Shm, Some("application/x-shm".to_string()); "map SHM format to media type")]
254 #[test_case(UPayloadFormat::Someip, Some("application/x-someip".to_string()); "map SOMEIP format to media type")]
255 #[test_case(UPayloadFormat::SomeipTlv, Some("application/x-someip_tlv".to_string()); "map SOMEIP_TLV format to media type")]
256 #[test_case(UPayloadFormat::Text, Some("text/plain".to_string()); "map TEXT format to media type")]
257 #[test_case(UPayloadFormat::Unspecified, None; "map UNSPECIFIED format to None")]
258 fn test_to_media_type(format: UPayloadFormat, expected_media_type: Option<String>) {
259 assert_eq!(format.to_media_type(), expected_media_type);
260 }
261}