httpclient/body/
memory.rs1use crate::sanitize::sanitize_value;
2use crate::InMemoryResult;
3use hyper::body::Bytes;
4use serde::de::{DeserializeOwned, Error};
5use serde::{Deserialize, Serialize};
6use serde_json::Value;
7use std::borrow::Cow;
8use std::hash::Hasher;
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
11#[serde(untagged)]
12#[derive(Default)]
13pub enum InMemoryBody {
14 #[default]
15 Empty,
16 Json(Value),
19 Bytes(Vec<u8>),
20 Text(String),
21}
22
23impl TryInto<String> for InMemoryBody {
24 type Error = crate::InMemoryError;
25
26 fn try_into(self) -> InMemoryResult<String> {
27 match self {
28 InMemoryBody::Empty => Ok(String::new()),
29 InMemoryBody::Bytes(b) => String::from_utf8(b).map_err(std::convert::Into::into),
30 InMemoryBody::Text(s) => Ok(s),
31 InMemoryBody::Json(val) => match val {
32 Value::String(s) => Ok(s),
33 _ => serde_json::to_string(&val).map_err(std::convert::Into::into),
34 },
35 }
36 }
37}
38
39impl TryInto<Bytes> for InMemoryBody {
40 type Error = crate::InMemoryError;
41
42 fn try_into(self) -> InMemoryResult<Bytes> {
43 match self {
44 InMemoryBody::Empty => Ok(Bytes::new()),
45 InMemoryBody::Bytes(b) => Ok(Bytes::from(b)),
46 InMemoryBody::Text(s) => Ok(Bytes::from(s)),
47 InMemoryBody::Json(val) => {
48 if let Value::Array(a) = &val {
49 if a.iter().all(|v| v.is_number()) {
50 let mut bytes = Vec::with_capacity(a.len());
51 for v in a {
52 bytes.push(v.as_u64().unwrap() as u8);
53 }
54 return Ok(Bytes::from(bytes));
55 }
56 }
57 Ok(Bytes::from(serde_json::to_string(&val)?))
58 }
59 }
60 }
61}
62
63impl InMemoryBody {
64 pub fn is_empty(&self) -> bool {
65 match self {
66 InMemoryBody::Empty => true,
67 InMemoryBody::Bytes(b) => b.is_empty(),
68 InMemoryBody::Text(s) => s.is_empty(),
69 InMemoryBody::Json(_) => false,
70 }
71 }
72
73 pub fn text(&self) -> InMemoryResult<Cow<str>> {
74 match self {
75 InMemoryBody::Empty => Ok(Cow::Borrowed("")),
76 InMemoryBody::Json(value) => serde_json::to_string(&value).map(Cow::Owned).map_err(Into::into),
77 InMemoryBody::Bytes(items) => std::str::from_utf8(items).map(Cow::Borrowed).map_err(Into::into),
78 InMemoryBody::Text(s) => Ok(Cow::Borrowed(s.as_str())),
79 }
80 }
81
82 pub fn into_text(self) -> InMemoryResult<String> {
83 self.try_into()
84 }
85
86 pub fn json<T: DeserializeOwned>(self) -> serde_json::Result<T> {
87 match self {
88 InMemoryBody::Empty => Err(serde_json::Error::custom("Empty body")),
89 InMemoryBody::Bytes(b) => serde_json::from_slice(&b),
90 InMemoryBody::Text(t) => serde_json::from_str(&t),
91 InMemoryBody::Json(v) => serde_json::from_value(v),
92 }
93 }
94
95 pub fn bytes(self) -> InMemoryResult<Bytes> {
96 self.try_into()
97 }
98
99 pub fn sanitize(&mut self) {
100 if let InMemoryBody::Json(value) = self {
101 sanitize_value(value);
102 }
103 }
104}
105
106impl std::hash::Hash for InMemoryBody {
107 fn hash<H: Hasher>(&self, state: &mut H) {
108 match self {
109 InMemoryBody::Empty => {}
110 InMemoryBody::Bytes(b) => {
112 state.write(b.as_slice());
114 }
115 InMemoryBody::Text(s) => {
116 state.write(s.as_bytes());
118 }
119 InMemoryBody::Json(serde_json::Value::String(s)) => {
120 state.write(s.as_bytes());
121 }
124 InMemoryBody::Json(v) => {
125 state.write(v.to_string().as_bytes());
126 }
127 }
128 }
129}
130
131impl Into<InMemoryBody> for String {
132 fn into(self) -> InMemoryBody {
133 InMemoryBody::Text(self)
134 }
135}
136
137impl Into<InMemoryBody> for Vec<u8> {
138 fn into(self) -> InMemoryBody {
139 InMemoryBody::Bytes(self)
140 }
141}