azure_functions/bindings/
service_bus_message.rs1use crate::{
2 http::Body,
3 rpc::{typed_data::Data, TypedData},
4 FromVec,
5};
6use serde::de::Error;
7use serde::Deserialize;
8use serde_json::{from_str, Result, Value};
9use std::borrow::Cow;
10use std::fmt;
11use std::str::from_utf8;
12
13#[derive(Debug, Clone)]
70pub struct ServiceBusMessage(TypedData);
71
72impl ServiceBusMessage {
73 pub fn as_str(&self) -> Option<&str> {
77 match &self.0.data {
78 Some(Data::String(s)) => Some(s),
79 Some(Data::Json(s)) => Some(s),
80 Some(Data::Bytes(b)) => from_utf8(b).ok(),
81 Some(Data::Stream(s)) => from_utf8(s).ok(),
82 _ => None,
83 }
84 }
85
86 pub fn as_bytes(&self) -> &[u8] {
88 match &self.0.data {
89 Some(Data::String(s)) => s.as_bytes(),
90 Some(Data::Json(s)) => s.as_bytes(),
91 Some(Data::Bytes(b)) => b,
92 Some(Data::Stream(s)) => s,
93 _ => panic!("unexpected data for service bus message content"),
94 }
95 }
96
97 pub fn as_json<'b, T>(&'b self) -> Result<T>
99 where
100 T: Deserialize<'b>,
101 {
102 from_str(
103 self.as_str().ok_or_else(|| {
104 ::serde_json::Error::custom("service bus message is not valid UTF-8")
105 })?,
106 )
107 }
108}
109
110impl fmt::Display for ServiceBusMessage {
111 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
112 write!(f, "{}", self.as_str().unwrap_or(""))
113 }
114}
115
116impl<'a> From<&'a str> for ServiceBusMessage {
117 fn from(content: &'a str) -> Self {
118 ServiceBusMessage(TypedData {
119 data: Some(Data::String(content.to_owned())),
120 })
121 }
122}
123
124impl From<String> for ServiceBusMessage {
125 fn from(content: String) -> Self {
126 ServiceBusMessage(TypedData {
127 data: Some(Data::String(content)),
128 })
129 }
130}
131
132impl From<&Value> for ServiceBusMessage {
133 fn from(content: &Value) -> Self {
134 ServiceBusMessage(TypedData {
135 data: Some(Data::Json(content.to_string())),
136 })
137 }
138}
139
140impl From<Value> for ServiceBusMessage {
141 fn from(content: Value) -> Self {
142 ServiceBusMessage(TypedData {
143 data: Some(Data::Json(content.to_string())),
144 })
145 }
146}
147
148impl<'a> From<&'a [u8]> for ServiceBusMessage {
149 fn from(content: &'a [u8]) -> Self {
150 ServiceBusMessage(TypedData {
151 data: Some(Data::Bytes(content.to_owned())),
152 })
153 }
154}
155
156impl From<Vec<u8>> for ServiceBusMessage {
157 fn from(content: Vec<u8>) -> Self {
158 ServiceBusMessage(TypedData {
159 data: Some(Data::Bytes(content)),
160 })
161 }
162}
163
164#[doc(hidden)]
165impl From<TypedData> for ServiceBusMessage {
166 fn from(data: TypedData) -> Self {
167 ServiceBusMessage(data)
168 }
169}
170
171#[doc(hidden)]
172impl FromVec<ServiceBusMessage> for TypedData {
173 fn from_vec(vec: Vec<ServiceBusMessage>) -> Self {
174 TypedData {
175 data: Some(Data::Json(
176 Value::Array(vec.into_iter().map(Into::into).collect()).to_string(),
177 )),
178 }
179 }
180}
181
182impl Into<String> for ServiceBusMessage {
183 fn into(self) -> String {
184 match self.0.data {
185 Some(Data::String(s)) => s,
186 Some(Data::Json(s)) => s,
187 Some(Data::Bytes(b)) => String::from_utf8(b)
188 .expect("service bus message does not contain valid UTF-8 bytes"),
189 Some(Data::Stream(s)) => String::from_utf8(s)
190 .expect("service bus message does not contain valid UTF-8 bytes"),
191 _ => panic!("unexpected data for service bus message content"),
192 }
193 }
194}
195
196impl Into<Value> for ServiceBusMessage {
197 fn into(self) -> Value {
198 match self.0.data {
200 Some(Data::String(s)) => Value::String(s),
201 Some(Data::Json(s)) => {
202 from_str(&s).expect("service bus message does not contain valid JSON data")
203 }
204 Some(Data::Bytes(b)) => Value::Array(
205 b.iter()
206 .map(|n| Value::Number(u64::from(*n).into()))
207 .collect(),
208 ),
209 Some(Data::Stream(s)) => Value::Array(
210 s.iter()
211 .map(|n| Value::Number(u64::from(*n).into()))
212 .collect(),
213 ),
214 _ => panic!("unexpected data for service bus message content"),
215 }
216 }
217}
218
219impl Into<Vec<u8>> for ServiceBusMessage {
220 fn into(self) -> Vec<u8> {
221 match self.0.data {
222 Some(Data::String(s)) => s.into_bytes(),
223 Some(Data::Json(s)) => s.into_bytes(),
224 Some(Data::Bytes(b)) => b,
225 Some(Data::Stream(s)) => s,
226 _ => panic!("unexpected data for service bus message content"),
227 }
228 }
229}
230
231impl<'a> Into<Body<'a>> for ServiceBusMessage {
232 fn into(self) -> Body<'a> {
233 match self.0.data {
234 Some(Data::String(s)) => s.into(),
235 Some(Data::Json(s)) => Body::Json(Cow::from(s)),
236 Some(Data::Bytes(b)) => b.into(),
237 Some(Data::Stream(s)) => s.into(),
238 _ => panic!("unexpected data for service bus message content"),
239 }
240 }
241}
242
243#[doc(hidden)]
244impl Into<TypedData> for ServiceBusMessage {
245 fn into(self) -> TypedData {
246 self.0
247 }
248}
249
250#[cfg(test)]
251mod tests {
252 use super::*;
253 use serde::{Deserialize, Serialize};
254 use serde_json::{json, to_value};
255 use std::fmt::Write;
256
257 #[test]
258 fn it_has_string_content() {
259 const MESSAGE: &'static str = "test message";
260
261 let message: ServiceBusMessage = MESSAGE.into();
262 assert_eq!(message.as_str().unwrap(), MESSAGE);
263
264 let data: TypedData = message.into();
265 assert_eq!(data.data, Some(Data::String(MESSAGE.to_string())));
266 }
267
268 #[test]
269 fn it_has_json_content() {
270 #[derive(Serialize, Deserialize)]
271 struct SerializedData {
272 message: String,
273 };
274
275 const MESSAGE: &'static str = "test";
276
277 let data = SerializedData {
278 message: MESSAGE.to_string(),
279 };
280
281 let message: ServiceBusMessage = ::serde_json::to_value(data).unwrap().into();
282 assert_eq!(
283 message.as_json::<SerializedData>().unwrap().message,
284 MESSAGE
285 );
286
287 let data: TypedData = message.into();
288 assert_eq!(
289 data.data,
290 Some(Data::Json(r#"{"message":"test"}"#.to_string()))
291 );
292 }
293
294 #[test]
295 fn it_has_bytes_content() {
296 const MESSAGE: &'static [u8] = &[1, 2, 3];
297
298 let message: ServiceBusMessage = MESSAGE.into();
299 assert_eq!(message.as_bytes(), MESSAGE);
300
301 let data: TypedData = message.into();
302 assert_eq!(data.data, Some(Data::Bytes(MESSAGE.to_vec())));
303 }
304
305 #[test]
306 fn it_displays_as_a_string() {
307 const MESSAGE: &'static str = "test";
308
309 let message: ServiceBusMessage = MESSAGE.into();
310
311 let mut s = String::new();
312 write!(s, "{}", message).unwrap();
313
314 assert_eq!(s, MESSAGE);
315 }
316
317 #[test]
318 fn it_converts_from_str() {
319 let message: ServiceBusMessage = "test".into();
320 assert_eq!(message.as_str().unwrap(), "test");
321 }
322
323 #[test]
324 fn it_converts_from_string() {
325 let message: ServiceBusMessage = "test".to_string().into();
326 assert_eq!(message.as_str().unwrap(), "test");
327 }
328
329 #[test]
330 fn it_converts_from_json() {
331 let message: ServiceBusMessage = to_value("hello world").unwrap().into();
332 assert_eq!(message.as_str().unwrap(), r#""hello world""#);
333 }
334
335 #[test]
336 fn it_converts_from_u8_slice() {
337 let message: ServiceBusMessage = [0, 1, 2][..].into();
338 assert_eq!(message.as_bytes(), [0, 1, 2]);
339 }
340
341 #[test]
342 fn it_converts_from_u8_vec() {
343 let message: ServiceBusMessage = vec![0, 1, 2].into();
344 assert_eq!(message.as_bytes(), [0, 1, 2]);
345 }
346
347 #[test]
348 fn it_converts_to_string() {
349 let message: ServiceBusMessage = "hello world!".into();
350 let s: String = message.into();
351 assert_eq!(s, "hello world!");
352 }
353
354 #[test]
355 fn it_converts_to_json() {
356 let message: ServiceBusMessage = json!({"hello": "world"}).into();
357 let value: Value = message.into();
358 assert_eq!(value.to_string(), r#"{"hello":"world"}"#);
359 }
360
361 #[test]
362 fn it_converts_to_bytes() {
363 let message: ServiceBusMessage = vec![1, 2, 3].into();
364 let bytes: Vec<u8> = message.into();
365 assert_eq!(bytes, [1, 2, 3]);
366 }
367
368 #[test]
369 fn it_converts_to_body() {
370 let message: ServiceBusMessage = "hello world!".into();
371 let body: Body = message.into();
372 assert_eq!(body.as_str().unwrap(), "hello world!");
373
374 let message: ServiceBusMessage = json!({"hello": "world"}).into();
375 let body: Body = message.into();
376 assert_eq!(body.as_str().unwrap(), r#"{"hello":"world"}"#);
377
378 let message: ServiceBusMessage = vec![1, 2, 3].into();
379 let body: Body = message.into();
380 assert_eq!(body.as_bytes(), [1, 2, 3]);
381 }
382
383 #[test]
384 fn it_converts_to_typed_data() {
385 let message: ServiceBusMessage = "test".into();
386 let data: TypedData = message.into();
387 assert_eq!(data.data, Some(Data::String("test".to_string())));
388
389 let message: ServiceBusMessage = to_value("test").unwrap().into();
390 let data: TypedData = message.into();
391 assert_eq!(data.data, Some(Data::Json(r#""test""#.to_string())));
392
393 let message: ServiceBusMessage = vec![1, 2, 3].into();
394 let data: TypedData = message.into();
395 assert_eq!(data.data, Some(Data::Bytes([1, 2, 3].to_vec())));
396 }
397}