1use bytes::Bytes;
8use serde_json::Value;
9
10use crate::body::Body;
11use crate::error::CamelError;
12
13pub trait FromBody: Sized {
21 fn from_body(body: &Body) -> Result<Self, CamelError>;
22}
23
24impl FromBody for String {
29 fn from_body(body: &Body) -> Result<Self, CamelError> {
30 match body {
31 Body::Text(s) => Ok(s.clone()),
32 Body::Json(Value::String(s)) => Ok(s.clone()),
34 Body::Json(v) => Ok(v.to_string()),
36 Body::Bytes(b) => String::from_utf8(b.to_vec()).map_err(|e| {
37 CamelError::TypeConversionFailed(format!(
38 "cannot convert Body::Bytes to String: invalid UTF-8: {e}"
39 ))
40 }),
41 Body::Xml(s) => Ok(s.clone()),
42 Body::Empty | Body::Stream(_) => Err(CamelError::TypeConversionFailed(
43 "cannot convert empty or stream body to String".into(),
44 )),
45 }
46 }
47}
48
49impl FromBody for Vec<u8> {
54 fn from_body(body: &Body) -> Result<Self, CamelError> {
55 match body {
56 Body::Text(s) => Ok(s.clone().into_bytes()),
57 Body::Json(v) => serde_json::to_vec(v).map_err(|e| {
58 CamelError::TypeConversionFailed(format!(
59 "cannot serialize Body::Json to Vec<u8>: {e}"
60 ))
61 }),
62 Body::Bytes(b) => Ok(b.to_vec()),
63 Body::Xml(s) => Ok(s.clone().into_bytes()),
64 Body::Empty | Body::Stream(_) => Err(CamelError::TypeConversionFailed(
65 "cannot convert empty or stream body to Vec<u8>".into(),
66 )),
67 }
68 }
69}
70
71impl FromBody for Bytes {
76 fn from_body(body: &Body) -> Result<Self, CamelError> {
77 match body {
78 Body::Text(s) => Ok(Bytes::from(s.clone().into_bytes())),
79 Body::Json(v) => {
80 let b = serde_json::to_vec(v).map_err(|e| {
81 CamelError::TypeConversionFailed(format!(
82 "cannot serialize Body::Json to Bytes: {e}"
83 ))
84 })?;
85 Ok(Bytes::from(b))
86 }
87 Body::Bytes(b) => Ok(b.clone()),
88 Body::Xml(s) => Ok(Bytes::from(s.clone().into_bytes())),
89 Body::Empty | Body::Stream(_) => Err(CamelError::TypeConversionFailed(
90 "cannot convert empty or stream body to Bytes".into(),
91 )),
92 }
93 }
94}
95
96impl FromBody for Value {
101 fn from_body(body: &Body) -> Result<Self, CamelError> {
102 match body {
103 Body::Json(v) => Ok(v.clone()),
104 Body::Text(s) => serde_json::from_str(s).map_err(|e| {
105 CamelError::TypeConversionFailed(format!("cannot parse Body::Text as JSON: {e}"))
106 }),
107 Body::Bytes(b) => serde_json::from_slice(b).map_err(|e| {
108 CamelError::TypeConversionFailed(format!("cannot parse Body::Bytes as JSON: {e}"))
109 }),
110 Body::Xml(_) | Body::Empty | Body::Stream(_) => Err(CamelError::TypeConversionFailed(
111 "cannot convert Xml, Empty or Stream body to serde_json::Value".into(),
112 )),
113 }
114 }
115}
116
117#[macro_export]
134macro_rules! impl_from_body_via_serde {
135 ($t:ty) => {
136 impl $crate::FromBody for $t {
137 fn from_body(body: &$crate::body::Body) -> Result<Self, $crate::error::CamelError> {
138 match body {
139 $crate::body::Body::Json(v) => serde_json::from_value(v.clone()).map_err(|e| {
140 $crate::error::CamelError::TypeConversionFailed(e.to_string())
141 }),
142 $crate::body::Body::Text(s) => serde_json::from_str(s).map_err(|e| {
143 $crate::error::CamelError::TypeConversionFailed(e.to_string())
144 }),
145 $crate::body::Body::Bytes(b) => serde_json::from_slice(b).map_err(|e| {
146 $crate::error::CamelError::TypeConversionFailed(e.to_string())
147 }),
148 _ => Err($crate::error::CamelError::TypeConversionFailed(format!(
149 "impl_from_body_via_serde: unsupported body variant for {}",
150 std::any::type_name::<$t>()
151 ))),
152 }
153 }
154 }
155 };
156}
157
158#[cfg(test)]
163mod tests {
164 use super::*;
165 use bytes::Bytes;
166 use serde::Deserialize;
167 use serde_json::json;
168
169 #[test]
172 fn string_from_text() {
173 let body = Body::Text("hello".into());
174 assert_eq!(String::from_body(&body).unwrap(), "hello");
175 }
176
177 #[test]
178 fn string_from_json_string_literal() {
179 let body = Body::Json(json!("hello"));
181 assert_eq!(String::from_body(&body).unwrap(), "hello");
182 }
183
184 #[test]
185 fn string_from_json_number() {
186 let body = Body::Json(json!(42));
187 assert_eq!(String::from_body(&body).unwrap(), "42");
188 }
189
190 #[test]
191 fn string_from_json_object() {
192 let body = Body::Json(json!({"a": 1}));
193 let s = String::from_body(&body).unwrap();
194 assert!(s.contains("\"a\""));
195 }
196
197 #[test]
198 fn string_from_bytes_valid_utf8() {
199 let body = Body::Bytes(Bytes::from_static(b"world"));
200 assert_eq!(String::from_body(&body).unwrap(), "world");
201 }
202
203 #[test]
204 fn string_from_bytes_invalid_utf8() {
205 let body = Body::Bytes(Bytes::from_static(&[0xFF, 0xFE]));
206 assert!(matches!(
207 String::from_body(&body),
208 Err(CamelError::TypeConversionFailed(_))
209 ));
210 }
211
212 #[test]
213 fn string_from_xml() {
214 let body = Body::Xml("<root/>".into());
215 assert_eq!(String::from_body(&body).unwrap(), "<root/>");
216 }
217
218 #[test]
219 fn string_from_empty_fails() {
220 assert!(matches!(
221 String::from_body(&Body::Empty),
222 Err(CamelError::TypeConversionFailed(_))
223 ));
224 }
225
226 #[test]
229 fn vec_u8_from_text() {
230 let body = Body::Text("hi".into());
231 assert_eq!(Vec::<u8>::from_body(&body).unwrap(), b"hi");
232 }
233
234 #[test]
235 fn vec_u8_from_json() {
236 let body = Body::Json(json!({"k": 1}));
237 let v = Vec::<u8>::from_body(&body).unwrap();
238 let s = String::from_utf8(v).unwrap();
239 assert!(s.contains("\"k\""));
240 }
241
242 #[test]
243 fn vec_u8_from_bytes() {
244 let body = Body::Bytes(Bytes::from_static(b"data"));
245 assert_eq!(Vec::<u8>::from_body(&body).unwrap(), b"data");
246 }
247
248 #[test]
249 fn vec_u8_from_xml() {
250 let body = Body::Xml("<r/>".into());
251 assert_eq!(Vec::<u8>::from_body(&body).unwrap(), b"<r/>");
252 }
253
254 #[test]
255 fn vec_u8_from_empty_fails() {
256 assert!(matches!(
257 Vec::<u8>::from_body(&Body::Empty),
258 Err(CamelError::TypeConversionFailed(_))
259 ));
260 }
261
262 #[test]
265 fn bytes_from_text() {
266 let body = Body::Text("hi".into());
267 assert_eq!(Bytes::from_body(&body).unwrap(), Bytes::from_static(b"hi"));
268 }
269
270 #[test]
271 fn bytes_from_json() {
272 let body = Body::Json(json!(1));
273 let b = Bytes::from_body(&body).unwrap();
274 assert_eq!(&b[..], b"1");
275 }
276
277 #[test]
278 fn bytes_from_bytes() {
279 let body = Body::Bytes(Bytes::from_static(b"raw"));
280 assert_eq!(Bytes::from_body(&body).unwrap(), Bytes::from_static(b"raw"));
281 }
282
283 #[test]
284 fn bytes_from_xml() {
285 let body = Body::Xml("<x/>".into());
286 assert_eq!(
287 Bytes::from_body(&body).unwrap(),
288 Bytes::from_static(b"<x/>")
289 );
290 }
291
292 #[test]
293 fn bytes_from_empty_fails() {
294 assert!(matches!(
295 Bytes::from_body(&Body::Empty),
296 Err(CamelError::TypeConversionFailed(_))
297 ));
298 }
299
300 #[test]
303 fn value_from_json() {
304 let body = Body::Json(json!({"x": 2}));
305 assert_eq!(Value::from_body(&body).unwrap(), json!({"x": 2}));
306 }
307
308 #[test]
309 fn value_from_text_valid_json() {
310 let body = Body::Text(r#"{"a":1}"#.into());
311 let v = Value::from_body(&body).unwrap();
312 assert_eq!(v["a"], 1);
313 }
314
315 #[test]
316 fn value_from_text_invalid_json() {
317 let body = Body::Text("not json".into());
318 assert!(matches!(
319 Value::from_body(&body),
320 Err(CamelError::TypeConversionFailed(_))
321 ));
322 }
323
324 #[test]
325 fn value_from_bytes_valid_json() {
326 let body = Body::Bytes(Bytes::from_static(b"{\"z\":3}"));
327 let v = Value::from_body(&body).unwrap();
328 assert_eq!(v["z"], 3);
329 }
330
331 #[test]
332 fn value_from_xml_fails() {
333 let body = Body::Xml("<root/>".into());
334 assert!(matches!(
335 Value::from_body(&body),
336 Err(CamelError::TypeConversionFailed(_))
337 ));
338 }
339
340 #[test]
341 fn value_from_empty_fails() {
342 assert!(matches!(
343 Value::from_body(&Body::Empty),
344 Err(CamelError::TypeConversionFailed(_))
345 ));
346 }
347
348 #[derive(Debug, PartialEq, Deserialize)]
351 struct Order {
352 id: u64,
353 amount: f64,
354 }
355
356 crate::impl_from_body_via_serde!(Order);
357
358 #[test]
359 fn serde_macro_from_json() {
360 let body = Body::Json(json!({"id": 1, "amount": 9.99}));
361 let order = Order::from_body(&body).unwrap();
362 assert_eq!(
363 order,
364 Order {
365 id: 1,
366 amount: 9.99
367 }
368 );
369 }
370
371 #[test]
372 fn serde_macro_from_text() {
373 let body = Body::Text(r#"{"id": 2, "amount": 5.0}"#.into());
374 let order = Order::from_body(&body).unwrap();
375 assert_eq!(order, Order { id: 2, amount: 5.0 });
376 }
377
378 #[test]
379 fn serde_macro_from_bytes() {
380 let body = Body::Bytes(Bytes::from_static(br#"{"id": 3, "amount": 1.0}"#));
381 let order = Order::from_body(&body).unwrap();
382 assert_eq!(order, Order { id: 3, amount: 1.0 });
383 }
384
385 #[test]
386 fn serde_macro_from_xml_fails() {
387 let body = Body::Xml("<root/>".into());
388 assert!(matches!(
389 Order::from_body(&body),
390 Err(CamelError::TypeConversionFailed(_))
391 ));
392 }
393
394 #[test]
395 fn serde_macro_invalid_json_fails() {
396 let body = Body::Json(json!({"wrong_field": "x"}));
397 assert!(matches!(
398 Order::from_body(&body),
399 Err(CamelError::TypeConversionFailed(_))
400 ));
401 }
402}