1use crate::context::RawStreamEvent;
2
3pub trait IntoResponse {
5 fn into_stream_events(self, default_language: &str) -> Vec<RawStreamEvent>;
6}
7
8impl IntoResponse for String {
9 fn into_stream_events(self, _default_language: &str) -> Vec<RawStreamEvent> {
10 vec![RawStreamEvent::Content {
11 data: self.into_bytes(),
12 mime_type: Some(crate::constants::MIME_TEXT.to_string()),
13 metadata: vec![],
14 }]
15 }
16}
17
18impl IntoResponse for &str {
19 fn into_stream_events(self, default_language: &str) -> Vec<RawStreamEvent> {
20 self.to_string().into_stream_events(default_language)
21 }
22}
23
24impl IntoResponse for () {
25 fn into_stream_events(self, _default_language: &str) -> Vec<RawStreamEvent> {
26 vec![]
27 }
28}
29
30impl IntoResponse for Vec<u8> {
31 fn into_stream_events(self, _default_language: &str) -> Vec<RawStreamEvent> {
32 vec![RawStreamEvent::Content {
33 data: self,
34 mime_type: Some(crate::constants::MIME_OCTET_STREAM.to_string()),
35 metadata: vec![],
36 }]
37 }
38}
39
40pub struct Json<T>(pub T);
42
43impl<T: serde::Serialize> IntoResponse for Json<T> {
44 fn into_stream_events(self, _default_language: &str) -> Vec<RawStreamEvent> {
45 vec![RawStreamEvent::Content {
46 data: serde_json::to_vec(&self.0).unwrap_or_default(),
47 mime_type: Some(crate::constants::MIME_JSON.to_string()),
48 metadata: vec![],
49 }]
50 }
51}
52
53pub struct Content(pub &'static str, pub Vec<u8>);
57
58impl IntoResponse for Content {
59 fn into_stream_events(self, _default_language: &str) -> Vec<RawStreamEvent> {
60 vec![RawStreamEvent::Content {
61 data: self.1,
62 mime_type: Some(self.0.to_string()),
63 metadata: vec![],
64 }]
65 }
66}
67
68#[doc(hidden)]
73pub fn cbor_encode_response<T: serde::Serialize>(
74 val: &T,
75 _default_language: &str,
76) -> Vec<RawStreamEvent> {
77 let mut buf = Vec::new();
78 ciborium::into_writer(val, &mut buf).expect("CBOR serialization should not fail");
79 vec![RawStreamEvent::Content {
80 data: buf,
81 mime_type: Some(crate::constants::MIME_CBOR.to_string()),
82 metadata: vec![],
83 }]
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89 use serde_json::json;
90
91 fn extract_content(events: Vec<RawStreamEvent>) -> (Vec<u8>, Option<String>) {
92 match events.into_iter().next().unwrap() {
93 RawStreamEvent::Content {
94 data, mime_type, ..
95 } => (data, mime_type),
96 _ => panic!("expected Content event"),
97 }
98 }
99
100 #[test]
101 fn json_wrapper_produces_json_mime() {
102 let value = json!({"rows": [1, 2, 3]});
103 let events = Json(value.clone()).into_stream_events("en");
104 let (data, mime) = extract_content(events);
105 assert_eq!(mime.as_deref(), Some(crate::constants::MIME_JSON));
106 let parsed: serde_json::Value = serde_json::from_slice(&data).unwrap();
107 assert_eq!(parsed, value);
108 }
109
110 #[test]
111 fn content_wrapper_explicit_mime() {
112 let png_header = vec![0x89, 0x50, 0x4E, 0x47];
113 let events = Content("image/png", png_header.clone()).into_stream_events("en");
114 let (data, mime) = extract_content(events);
115 assert_eq!(mime.as_deref(), Some("image/png"));
116 assert_eq!(data, png_header);
117 }
118
119 #[test]
120 fn cbor_encode_produces_cbor_mime() {
121 let input = vec![1u32, 2, 3];
122 let events = cbor_encode_response(&input, "en");
123 let (data, mime) = extract_content(events);
124 assert_eq!(mime.as_deref(), Some(crate::constants::MIME_CBOR));
125 let decoded: Vec<u32> = ciborium::from_reader(&data[..]).unwrap();
126 assert_eq!(decoded, input);
127 }
128
129 #[test]
130 fn vec_u8_produces_octet_stream() {
131 let events = vec![1u8, 2, 3].into_stream_events("en");
132 let (_data, mime) = extract_content(events);
133 assert_eq!(mime.as_deref(), Some(crate::constants::MIME_OCTET_STREAM));
134 }
135
136 #[test]
137 fn string_still_produces_text_plain() {
138 let events = "hello".to_string().into_stream_events("en");
139 let (data, mime) = extract_content(events);
140 assert_eq!(mime.as_deref(), Some(crate::constants::MIME_TEXT));
141 assert_eq!(data, b"hello");
142 }
143}