1use crate::body::Body;
2use crate::error::CamelError;
3use bytes::Bytes;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum BodyType {
8 Text,
9 Json,
10 Bytes,
11 Empty,
12}
13
14pub fn convert(body: Body, target: BodyType) -> Result<Body, CamelError> {
19 match (body, target) {
20 (b @ Body::Text(_), BodyType::Text) => Ok(b),
22 (b @ Body::Json(_), BodyType::Json) => Ok(b),
23 (b @ Body::Bytes(_), BodyType::Bytes) => Ok(b),
24 (Body::Empty, BodyType::Empty) => Ok(Body::Empty),
25
26 (Body::Text(s), BodyType::Json) => {
28 let v = serde_json::from_str(&s).map_err(|e| {
29 CamelError::TypeConversionFailed(format!("cannot convert Body::Text to Json: {e}"))
30 })?;
31 Ok(Body::Json(v))
32 }
33 (Body::Text(s), BodyType::Bytes) => Ok(Body::Bytes(Bytes::from(s.into_bytes()))),
34 (Body::Text(_), BodyType::Empty) => Err(CamelError::TypeConversionFailed(
35 "cannot convert Body::Text to Empty".to_string(),
36 )),
37
38 (Body::Json(v), BodyType::Text) => Ok(Body::Text(v.to_string())),
40 (Body::Json(v), BodyType::Bytes) => {
41 let b = serde_json::to_vec(&v).map_err(|e| {
42 CamelError::TypeConversionFailed(format!("cannot convert Body::Json to Bytes: {e}"))
43 })?;
44 Ok(Body::Bytes(Bytes::from(b)))
45 }
46 (Body::Json(_), BodyType::Empty) => Err(CamelError::TypeConversionFailed(
47 "cannot convert Body::Json to Empty".to_string(),
48 )),
49
50 (Body::Bytes(b), BodyType::Text) => {
52 let s = String::from_utf8(b.to_vec()).map_err(|e| {
53 CamelError::TypeConversionFailed(format!(
54 "cannot convert Body::Bytes to Text: invalid UTF-8 sequence: {e}"
55 ))
56 })?;
57 Ok(Body::Text(s))
58 }
59 (Body::Bytes(b), BodyType::Json) => {
60 let s = String::from_utf8(b.to_vec()).map_err(|e| {
61 CamelError::TypeConversionFailed(format!(
62 "cannot convert Body::Bytes to Json (UTF-8 error): {e}"
63 ))
64 })?;
65 let v = serde_json::from_str(&s).map_err(|e| {
66 CamelError::TypeConversionFailed(format!("cannot convert Body::Bytes to Json: {e}"))
67 })?;
68 Ok(Body::Json(v))
69 }
70 (Body::Bytes(_), BodyType::Empty) => Err(CamelError::TypeConversionFailed(
71 "cannot convert Body::Bytes to Empty".to_string(),
72 )),
73
74 (Body::Empty, BodyType::Text) => Err(CamelError::TypeConversionFailed(
76 "cannot convert Empty body to Text".to_string(),
77 )),
78 (Body::Empty, BodyType::Json) => Err(CamelError::TypeConversionFailed(
79 "cannot convert Empty body to Json".to_string(),
80 )),
81 (Body::Empty, BodyType::Bytes) => Err(CamelError::TypeConversionFailed(
82 "cannot convert Empty body to Bytes".to_string(),
83 )),
84
85 (Body::Stream(_), _) => Err(CamelError::TypeConversionFailed(
87 "cannot convert Body::Stream: materialize first with into_bytes()".to_string(),
88 )),
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95 use serde_json::json;
96
97 #[test]
98 fn text_to_json_valid() {
99 let body = Body::Text(r#"{"a":1}"#.to_string());
100 let result = convert(body, BodyType::Json).unwrap();
101 assert_eq!(result, Body::Json(json!({"a": 1})));
102 }
103
104 #[test]
105 fn text_to_json_invalid() {
106 let body = Body::Text("not json".to_string());
107 let result = convert(body, BodyType::Json);
108 assert!(matches!(result, Err(CamelError::TypeConversionFailed(_))));
109 }
110
111 #[test]
112 fn json_to_text() {
113 let body = Body::Json(json!({"a": 1}));
114 let result = convert(body, BodyType::Text).unwrap();
115 match result {
116 Body::Text(s) => assert!(s.contains("\"a\"")),
117 _ => panic!("expected Body::Text"),
118 }
119 }
120
121 #[test]
122 fn json_to_bytes() {
123 let body = Body::Json(json!({"x": 2}));
124 let result = convert(body, BodyType::Bytes).unwrap();
125 assert!(matches!(result, Body::Bytes(_)));
126 }
127
128 #[test]
129 fn bytes_to_text_valid() {
130 let body = Body::Bytes(Bytes::from_static(b"hello"));
131 let result = convert(body, BodyType::Text).unwrap();
132 assert_eq!(result, Body::Text("hello".to_string()));
133 }
134
135 #[test]
136 fn bytes_to_text_invalid_utf8() {
137 let body = Body::Bytes(Bytes::from_static(&[0xFF, 0xFE]));
138 let result = convert(body, BodyType::Text);
139 assert!(matches!(result, Err(CamelError::TypeConversionFailed(_))));
140 }
141
142 #[test]
143 fn text_to_bytes() {
144 let body = Body::Text("hi".to_string());
145 let result = convert(body, BodyType::Bytes).unwrap();
146 assert_eq!(result, Body::Bytes(Bytes::from_static(b"hi")));
147 }
148
149 #[test]
150 fn empty_to_text_fails() {
151 let result = convert(Body::Empty, BodyType::Text);
152 assert!(matches!(result, Err(CamelError::TypeConversionFailed(_))));
153 }
154
155 #[test]
156 fn empty_to_empty_noop() {
157 let result = convert(Body::Empty, BodyType::Empty).unwrap();
158 assert!(matches!(result, Body::Empty));
159 }
160
161 #[test]
162 fn noop_same_type_text() {
163 let body = Body::Text("x".to_string());
164 let result = convert(body, BodyType::Text).unwrap();
165 assert!(matches!(result, Body::Text(_)));
166 }
167
168 #[test]
169 fn noop_same_type_json() {
170 let body = Body::Json(json!(1));
171 let result = convert(body, BodyType::Json).unwrap();
172 assert!(matches!(result, Body::Json(_)));
173 }
174
175 #[test]
176 fn noop_same_type_bytes() {
177 let body = Body::Bytes(Bytes::from_static(b"x"));
178 let result = convert(body, BodyType::Bytes).unwrap();
179 assert!(matches!(result, Body::Bytes(_)));
180 }
181
182 #[test]
183 fn stream_to_any_fails() {
184 use crate::body::{StreamBody, StreamMetadata};
185 use futures::stream;
186 use std::sync::Arc;
187 use tokio::sync::Mutex;
188
189 let stream = stream::iter(vec![Ok(Bytes::from_static(b"data"))]);
190 let body = Body::Stream(StreamBody {
191 stream: Arc::new(Mutex::new(Some(Box::pin(stream)))),
192 metadata: StreamMetadata::default(),
193 });
194 let result = convert(body, BodyType::Text);
195 assert!(matches!(result, Err(CamelError::TypeConversionFailed(_))));
196 }
197
198 #[test]
199 fn bytes_to_json_valid() {
200 let body = Body::Bytes(Bytes::from_static(b"{\"k\":1}"));
201 let result = convert(body, BodyType::Json).unwrap();
202 assert!(matches!(result, Body::Json(_)));
203 }
204
205 #[test]
206 fn bytes_to_json_invalid_utf8() {
207 let body = Body::Bytes(Bytes::from_static(&[0xFF, 0xFE]));
208 let result = convert(body, BodyType::Json);
209 assert!(matches!(result, Err(CamelError::TypeConversionFailed(_))));
210 }
211
212 #[test]
213 fn to_empty_always_fails() {
214 assert!(matches!(
215 convert(Body::Text("x".into()), BodyType::Empty),
216 Err(CamelError::TypeConversionFailed(_))
217 ));
218 assert!(matches!(
219 convert(Body::Json(serde_json::json!(1)), BodyType::Empty),
220 Err(CamelError::TypeConversionFailed(_))
221 ));
222 assert!(matches!(
223 convert(Body::Bytes(Bytes::from_static(b"x")), BodyType::Empty),
224 Err(CamelError::TypeConversionFailed(_))
225 ));
226 }
227}