1use std::{error, iter::FromIterator, marker::PhantomData};
18
19use bytes::Bytes;
20use conjure_error::{Error, InvalidArgument};
21use conjure_object::FromPlain;
22use futures_core::Stream;
23use http::{header::CONTENT_TYPE, HeaderMap, HeaderValue, Response};
24use serde::{de::DeserializeOwned, Serialize};
25
26use crate::private::APPLICATION_OCTET_STREAM;
27
28use super::{
29 AsyncDeserializeRequest, AsyncResponseBody, AsyncSerializeResponse, AsyncWriteBody,
30 ConjureRuntime, DecodeHeader, DecodeParam, DeserializeRequest, EmptyResponseSerializer,
31 LocalAsyncDeserializeRequest, LocalAsyncResponseBody, LocalAsyncSerializeResponse,
32 LocalAsyncWriteBody, ResponseBody, SerializeResponse, StdRequestDeserializer,
33 StdResponseSerializer, WriteBody,
34};
35
36pub enum OptionalRequestDeserializer {}
38
39impl<T, R> DeserializeRequest<Option<T>, R> for OptionalRequestDeserializer
40where
41 T: DeserializeOwned,
42 R: Iterator<Item = Result<Bytes, Error>>,
43{
44 fn deserialize(
45 runtime: &ConjureRuntime,
46 headers: &HeaderMap,
47 body: R,
48 ) -> Result<Option<T>, Error> {
49 if !headers.contains_key(CONTENT_TYPE) {
50 return Ok(None);
51 }
52
53 <StdRequestDeserializer as DeserializeRequest<_, _>>::deserialize(runtime, headers, body)
54 }
55}
56
57impl<T, R> AsyncDeserializeRequest<Option<T>, R> for OptionalRequestDeserializer
58where
59 T: DeserializeOwned,
60 R: Stream<Item = Result<Bytes, Error>> + Send,
61{
62 async fn deserialize(
63 runtime: &ConjureRuntime,
64 headers: &HeaderMap,
65 body: R,
66 ) -> Result<Option<T>, Error> {
67 if !headers.contains_key(CONTENT_TYPE) {
68 return Ok(None);
69 }
70
71 <StdRequestDeserializer as AsyncDeserializeRequest<_, _>>::deserialize(
72 runtime, headers, body,
73 )
74 .await
75 }
76}
77
78impl<T, R> LocalAsyncDeserializeRequest<Option<T>, R> for OptionalRequestDeserializer
79where
80 T: DeserializeOwned,
81 R: Stream<Item = Result<Bytes, Error>>,
82{
83 async fn deserialize(
84 runtime: &ConjureRuntime,
85 headers: &HeaderMap,
86 body: R,
87 ) -> Result<Option<T>, Error> {
88 if !headers.contains_key(CONTENT_TYPE) {
89 return Ok(None);
90 }
91
92 <StdRequestDeserializer as LocalAsyncDeserializeRequest<_, _>>::deserialize(
93 runtime, headers, body,
94 )
95 .await
96 }
97}
98
99pub enum BinaryRequestDeserializer {}
101
102impl BinaryRequestDeserializer {
103 fn deserialize_inner<R>(headers: &HeaderMap, body: R) -> Result<R, Error> {
104 if headers.get(CONTENT_TYPE) != Some(&APPLICATION_OCTET_STREAM) {
105 return Err(Error::service_safe(
106 "unexpected Content-Type",
107 InvalidArgument::new(),
108 ));
109 }
110
111 Ok(body)
112 }
113}
114
115impl<R> DeserializeRequest<R, R> for BinaryRequestDeserializer {
116 fn deserialize(_runtime: &ConjureRuntime, headers: &HeaderMap, body: R) -> Result<R, Error> {
117 Self::deserialize_inner(headers, body)
118 }
119}
120
121impl<R> AsyncDeserializeRequest<R, R> for BinaryRequestDeserializer
122where
123 R: Send,
124{
125 async fn deserialize(
126 _runtime: &ConjureRuntime,
127 headers: &HeaderMap,
128 body: R,
129 ) -> Result<R, Error> {
130 Self::deserialize_inner(headers, body)
131 }
132}
133
134impl<R> LocalAsyncDeserializeRequest<R, R> for BinaryRequestDeserializer {
135 async fn deserialize(
136 _runtime: &ConjureRuntime,
137 headers: &HeaderMap,
138 body: R,
139 ) -> Result<R, Error> {
140 Self::deserialize_inner(headers, body)
141 }
142}
143
144pub enum CollectionResponseSerializer {}
146
147impl<T, W> SerializeResponse<T, W> for CollectionResponseSerializer
148where
149 T: Serialize + PartialEq + Default,
150{
151 fn serialize(
152 runtime: &ConjureRuntime,
153 request_headers: &HeaderMap,
154 value: T,
155 ) -> Result<Response<ResponseBody<W>>, Error> {
156 if value == T::default() {
157 <EmptyResponseSerializer as SerializeResponse<_, _>>::serialize(
158 runtime,
159 request_headers,
160 (),
161 )
162 } else {
163 <StdResponseSerializer as SerializeResponse<_, _>>::serialize(
164 runtime,
165 request_headers,
166 value,
167 )
168 }
169 }
170}
171
172impl<T, W> AsyncSerializeResponse<T, W> for CollectionResponseSerializer
173where
174 T: Serialize + PartialEq + Default,
175{
176 fn serialize(
177 runtime: &ConjureRuntime,
178 request_headers: &HeaderMap,
179 value: T,
180 ) -> Result<Response<AsyncResponseBody<W>>, Error> {
181 if value == T::default() {
182 <EmptyResponseSerializer as AsyncSerializeResponse<_, _>>::serialize(
183 runtime,
184 request_headers,
185 (),
186 )
187 } else {
188 <StdResponseSerializer as AsyncSerializeResponse<_, _>>::serialize(
189 runtime,
190 request_headers,
191 value,
192 )
193 }
194 }
195}
196
197impl<T, W> LocalAsyncSerializeResponse<T, W> for CollectionResponseSerializer
198where
199 T: Serialize + PartialEq + Default,
200{
201 fn serialize(
202 runtime: &ConjureRuntime,
203 request_headers: &HeaderMap,
204 value: T,
205 ) -> Result<Response<LocalAsyncResponseBody<W>>, Error> {
206 if value == T::default() {
207 <EmptyResponseSerializer as LocalAsyncSerializeResponse<_, _>>::serialize(
208 runtime,
209 request_headers,
210 (),
211 )
212 } else {
213 <StdResponseSerializer as LocalAsyncSerializeResponse<_, _>>::serialize(
214 runtime,
215 request_headers,
216 value,
217 )
218 }
219 }
220}
221
222pub enum BinaryResponseSerializer {}
224
225impl BinaryResponseSerializer {
226 fn serialize_inner<B>(body: B) -> Result<Response<B>, Error> {
227 let mut response = Response::new(body);
228
229 response
230 .headers_mut()
231 .insert(CONTENT_TYPE, APPLICATION_OCTET_STREAM);
232 Ok(response)
233 }
234}
235
236impl<T, W> SerializeResponse<T, W> for BinaryResponseSerializer
237where
238 T: WriteBody<W> + 'static,
239{
240 fn serialize(
241 _runtime: &ConjureRuntime,
242 _request_headers: &HeaderMap,
243 value: T,
244 ) -> Result<Response<ResponseBody<W>>, Error> {
245 Self::serialize_inner(ResponseBody::Streaming(Box::new(value)))
246 }
247}
248
249impl<T, W> AsyncSerializeResponse<T, W> for BinaryResponseSerializer
250where
251 T: AsyncWriteBody<W> + 'static + Send,
252{
253 fn serialize(
254 _runtime: &ConjureRuntime,
255 _request_headers: &HeaderMap,
256 value: T,
257 ) -> Result<Response<AsyncResponseBody<W>>, Error> {
258 Self::serialize_inner(AsyncResponseBody::Streaming(super::BoxAsyncWriteBody::new(
259 value,
260 )))
261 }
262}
263
264impl<T, W> LocalAsyncSerializeResponse<T, W> for BinaryResponseSerializer
265where
266 T: LocalAsyncWriteBody<W> + 'static,
267{
268 fn serialize(
269 _runtime: &ConjureRuntime,
270 _request_headers: &HeaderMap,
271 value: T,
272 ) -> Result<Response<LocalAsyncResponseBody<W>>, Error> {
273 Self::serialize_inner(LocalAsyncResponseBody::Streaming(
274 super::BoxLocalAsyncWriteBody::new(value),
275 ))
276 }
277}
278
279pub enum OptionalBinaryResponseSerializer {}
281
282impl<T, W> SerializeResponse<Option<T>, W> for OptionalBinaryResponseSerializer
283where
284 T: WriteBody<W> + 'static,
285{
286 fn serialize(
287 runtime: &ConjureRuntime,
288 request_headers: &HeaderMap,
289 value: Option<T>,
290 ) -> Result<Response<ResponseBody<W>>, Error> {
291 match value {
292 Some(value) => <BinaryResponseSerializer as SerializeResponse<_, _>>::serialize(
293 runtime,
294 request_headers,
295 value,
296 ),
297 None => <EmptyResponseSerializer as SerializeResponse<_, _>>::serialize(
298 runtime,
299 request_headers,
300 (),
301 ),
302 }
303 }
304}
305
306impl<T, W> AsyncSerializeResponse<Option<T>, W> for OptionalBinaryResponseSerializer
307where
308 T: AsyncWriteBody<W> + 'static + Send,
309{
310 fn serialize(
311 runtime: &ConjureRuntime,
312 request_headers: &HeaderMap,
313 value: Option<T>,
314 ) -> Result<Response<AsyncResponseBody<W>>, Error> {
315 match value {
316 Some(value) => <BinaryResponseSerializer as AsyncSerializeResponse<_, _>>::serialize(
317 runtime,
318 request_headers,
319 value,
320 ),
321 None => <EmptyResponseSerializer as AsyncSerializeResponse<_, _>>::serialize(
322 runtime,
323 request_headers,
324 (),
325 ),
326 }
327 }
328}
329
330impl<T, W> LocalAsyncSerializeResponse<Option<T>, W> for OptionalBinaryResponseSerializer
331where
332 T: LocalAsyncWriteBody<W> + 'static,
333{
334 fn serialize(
335 runtime: &ConjureRuntime,
336 request_headers: &HeaderMap,
337 value: Option<T>,
338 ) -> Result<Response<LocalAsyncResponseBody<W>>, Error> {
339 match value {
340 Some(value) => {
341 <BinaryResponseSerializer as LocalAsyncSerializeResponse<_, _>>::serialize(
342 runtime,
343 request_headers,
344 value,
345 )
346 }
347 None => <EmptyResponseSerializer as LocalAsyncSerializeResponse<_, _>>::serialize(
348 runtime,
349 request_headers,
350 (),
351 ),
352 }
353 }
354}
355
356pub enum FromPlainDecoder {}
358
359impl<T> DecodeHeader<T> for FromPlainDecoder
360where
361 T: FromPlain,
362 T::Err: Into<Box<dyn error::Error + Sync + Send>>,
363{
364 fn decode<'a, I>(_: &ConjureRuntime, headers: I) -> Result<T, Error>
365 where
366 I: IntoIterator<Item = &'a HeaderValue>,
367 {
368 T::from_plain(
369 super::only_item(headers)?
370 .to_str()
371 .map_err(|e| Error::service(e, InvalidArgument::new()))?,
372 )
373 .map_err(|e| Error::service(e, InvalidArgument::new()))
374 }
375}
376
377impl<T> DecodeParam<T> for FromPlainDecoder
378where
379 T: FromPlain,
380 T::Err: Into<Box<dyn error::Error + Sync + Send>>,
381{
382 fn decode<I>(_: &ConjureRuntime, params: I) -> Result<T, Error>
383 where
384 I: IntoIterator,
385 I::Item: AsRef<str>,
386 {
387 T::from_plain(super::only_item(params)?.as_ref())
388 .map_err(|e| Error::service(e, InvalidArgument::new()))
389 }
390}
391
392pub enum FromPlainOptionDecoder {}
394
395impl<T> DecodeHeader<Option<T>> for FromPlainOptionDecoder
396where
397 T: FromPlain,
398 T::Err: Into<Box<dyn error::Error + Sync + Send>>,
399{
400 fn decode<'a, I>(_: &ConjureRuntime, headers: I) -> Result<Option<T>, Error>
401 where
402 I: IntoIterator<Item = &'a HeaderValue>,
403 {
404 let Some(header) = super::optional_item(headers)? else {
405 return Ok(None);
406 };
407 let value = T::from_plain(
408 header
409 .to_str()
410 .map_err(|e| Error::service(e, InvalidArgument::new()))?,
411 )
412 .map_err(|e| Error::service(e, InvalidArgument::new()))?;
413 Ok(Some(value))
414 }
415}
416
417impl<T> DecodeParam<Option<T>> for FromPlainOptionDecoder
418where
419 T: FromPlain,
420 T::Err: Into<Box<dyn error::Error + Sync + Send>>,
421{
422 fn decode<I>(_: &ConjureRuntime, params: I) -> Result<Option<T>, Error>
423 where
424 I: IntoIterator,
425 I::Item: AsRef<str>,
426 {
427 let Some(param) = super::optional_item(params)? else {
428 return Ok(None);
429 };
430 let value =
431 T::from_plain(param.as_ref()).map_err(|e| Error::service(e, InvalidArgument::new()))?;
432 Ok(Some(value))
433 }
434}
435
436pub struct FromPlainSeqDecoder<U> {
439 _p: PhantomData<U>,
440}
441
442impl<T, U> DecodeParam<T> for FromPlainSeqDecoder<U>
443where
444 T: FromIterator<U>,
445 U: FromPlain,
446 U::Err: Into<Box<dyn error::Error + Sync + Send>>,
447{
448 fn decode<I>(_: &ConjureRuntime, params: I) -> Result<T, Error>
449 where
450 I: IntoIterator,
451 I::Item: AsRef<str>,
452 {
453 params
454 .into_iter()
455 .map(|s| {
456 U::from_plain(s.as_ref()).map_err(|e| Error::service(e, InvalidArgument::new()))
457 })
458 .collect()
459 }
460}