conjure_http/client/
mod.rs

1// Copyright 2019 Palantir Technologies, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! The Conjure HTTP client API.
16use bytes::Bytes;
17use conjure_error::Error;
18use futures_core::Stream;
19use http::{HeaderValue, Request, Response};
20use serde::de::DeserializeOwned;
21use serde::Serialize;
22use std::convert::TryFrom;
23use std::fmt::Display;
24use std::future::Future;
25use std::io::Write;
26use std::marker::PhantomData;
27use std::pin::Pin;
28use std::sync::Arc;
29
30pub use crate::client::encoding::*;
31#[doc(inline)]
32pub use crate::client::runtime::ConjureRuntime;
33use crate::private;
34
35pub mod conjure;
36mod encoding;
37pub mod runtime;
38
39/// A trait implemented by generated blocking client interfaces for a Conjure service.
40pub trait Service<C> {
41    /// Creates a new service wrapping an HTTP client.
42    fn new(client: C, runtime: &Arc<ConjureRuntime>) -> Self;
43}
44
45/// A trait implemented by generated async client interfaces for a Conjure service.
46pub trait AsyncService<C> {
47    /// Creates a new service wrapping an async HTTP client.
48    fn new(client: C, runtime: &Arc<ConjureRuntime>) -> Self;
49}
50
51/// Conjure-specific metadata about an endpoint.
52///
53/// This is included as an extension in all `Request`s passed to blocking and async Conjure clients.
54#[derive(Debug, Clone, PartialEq, Eq)]
55pub struct Endpoint {
56    service: &'static str,
57    version: Option<&'static str>,
58    name: &'static str,
59    path: &'static str,
60}
61
62impl Endpoint {
63    /// Creates a new `Endpoint`.
64    #[inline]
65    pub fn new(
66        service: &'static str,
67        version: Option<&'static str>,
68        name: &'static str,
69        path: &'static str,
70    ) -> Self {
71        Endpoint {
72            service,
73            version,
74            name,
75            path,
76        }
77    }
78
79    /// Returns the name of the service the endpoint is part of.
80    #[inline]
81    pub fn service(&self) -> &'static str {
82        self.service
83    }
84
85    /// Returns the version of the Conjure definition defining the service, if known.
86    #[inline]
87    pub fn version(&self) -> Option<&'static str> {
88        self.version
89    }
90
91    /// Returns the name of the endpoint.
92    #[inline]
93    pub fn name(&self) -> &'static str {
94        self.name
95    }
96
97    /// Returns the templated URI path of the endpoint.
98    #[inline]
99    pub fn path(&self) -> &'static str {
100        self.path
101    }
102}
103
104/// The body of a blocking Conjure request.
105pub enum RequestBody<'a, W> {
106    /// No body.
107    Empty,
108    /// A body already buffered in memory.
109    Fixed(Bytes),
110    /// A streaming body.
111    Streaming(Box<dyn WriteBody<W> + 'a>),
112}
113
114/// The body of an async Conjure request.
115pub enum AsyncRequestBody<'a, W> {
116    /// No body.
117    Empty,
118    /// A body already buffered in memory.
119    Fixed(Bytes),
120    /// A streaming body.
121    Streaming(BoxAsyncWriteBody<'a, W>),
122}
123
124/// The body of a local async Conjure request.
125pub enum LocalAsyncRequestBody<'a, W> {
126    /// No body.
127    Empty,
128    /// A body already buffered in memory.
129    Fixed(Bytes),
130    /// A streaming body.
131    Streaming(BoxLocalAsyncWriteBody<'a, W>),
132}
133
134/// A trait implemented by HTTP client implementations.
135pub trait Client {
136    /// The client's binary request write type.
137    type BodyWriter;
138    /// The client's binary response body type.
139    type ResponseBody: Iterator<Item = Result<Bytes, Error>>;
140
141    /// Makes an HTTP request.
142    ///
143    /// The request's URI will be in absolute-form and it will always contain an `Endpoint` object in its extensions.
144    ///
145    /// A response must only be returned if it has a 2xx status code. The client is responsible for handling all other
146    /// status codes (for example, converting a 5xx response into a service error). The client is also responsible for
147    /// decoding the response body if necessary.
148    fn send(
149        &self,
150        req: Request<RequestBody<'_, Self::BodyWriter>>,
151    ) -> Result<Response<Self::ResponseBody>, Error>;
152}
153
154/// A trait implemented by async HTTP client implementations.
155pub trait AsyncClient {
156    /// The client's binary request body write type.
157    type BodyWriter;
158    /// The client's binary response body type.
159    type ResponseBody: Stream<Item = Result<Bytes, Error>>;
160
161    /// Makes an HTTP request.
162    ///
163    /// The client is responsible for assembling the request URI. It is provided with the path template, unencoded path
164    /// parameters, unencoded query parameters, header parameters, and request body.
165    ///
166    /// A response must only be returned if it has a 2xx status code. The client is responsible for handling all other
167    /// status codes (for example, converting a 5xx response into a service error). The client is also responsible for
168    /// decoding the response body if necessary.
169    fn send(
170        &self,
171        req: Request<AsyncRequestBody<'_, Self::BodyWriter>>,
172    ) -> impl Future<Output = Result<Response<Self::ResponseBody>, Error>> + Send;
173}
174
175/// A trait implemented by local async HTTP client implementations.
176pub trait LocalAsyncClient {
177    /// The client's binary request body write type.
178    type BodyWriter;
179    /// The client's binary response body type.
180    type ResponseBody: Stream<Item = Result<Bytes, Error>>;
181
182    /// Makes an HTTP request.
183    ///
184    /// The client is responsible for assembling the request URI. It is provided with the path template, unencoded path
185    /// parameters, unencoded query parameters, header parameters, and request body.
186    ///
187    /// A response must only be returned if it has a 2xx status code. The client is responsible for handling all other
188    /// status codes (for example, converting a 5xx response into a service error). The client is also responsible for
189    /// decoding the response body if necessary.
190    fn send(
191        &self,
192        req: Request<LocalAsyncRequestBody<'_, Self::BodyWriter>>,
193    ) -> impl Future<Output = Result<Response<Self::ResponseBody>, Error>>;
194}
195
196/// A trait implemented by streaming bodies.
197pub trait WriteBody<W> {
198    /// Writes the body out, in its entirety.
199    ///
200    /// Behavior is unspecified if this method is called twice without a successful call to `reset` in between.
201    fn write_body(&mut self, w: &mut W) -> Result<(), Error>;
202
203    /// Attempts to reset the body so that it can be written out again.
204    ///
205    /// Returns `true` if successful. Behavior is unspecified if this is not called after a call to `write_body`.
206    fn reset(&mut self) -> bool;
207}
208
209impl<W> WriteBody<W> for &[u8]
210where
211    W: Write,
212{
213    fn write_body(&mut self, w: &mut W) -> Result<(), Error> {
214        w.write_all(self).map_err(Error::internal_safe)
215    }
216
217    fn reset(&mut self) -> bool {
218        true
219    }
220}
221
222/// A trait implemented by async streaming bodies.
223///
224/// # Examples
225///
226/// ```ignore
227/// use conjure_error::Error;
228/// use conjure_http::client::AsyncWriteBody;
229/// use std::pin::Pin;
230/// use tokio_io::{AsyncWrite, AsyncWriteExt};
231///
232/// pub struct SimpleBodyWriter;
233///
234/// impl<W> AsyncWriteBody<W> for SimpleBodyWriter
235/// where
236///     W: AsyncWrite + Send,
237/// {
238///     async fn write_body(self: Pin<&mut Self>, mut w: Pin<&mut W>) -> Result<(), Error> {
239///         w.write_all(b"hello world").await.map_err(Error::internal_safe)
240///     }
241///
242///     async fn reset(self: Pin<&mut Self>) -> bool {
243///         true
244///     }
245/// }
246/// ```
247pub trait AsyncWriteBody<W> {
248    /// Writes the body out, in its entirety.
249    ///
250    /// Behavior is unspecified if this method is called twice without a successful call to `reset` in between.
251    fn write_body(
252        self: Pin<&mut Self>,
253        w: Pin<&mut W>,
254    ) -> impl Future<Output = Result<(), Error>> + Send;
255
256    /// Attempts to reset the body so that it can be written out again.
257    ///
258    /// Returns `true` if successful. Behavior is unspecified if this is not called after a call to `write_body`.
259    fn reset(self: Pin<&mut Self>) -> impl Future<Output = bool> + Send;
260}
261
262// An internal object-safe version of AsyncWriteBody used to implement BoxAsyncWriteBody.
263trait AsyncWriteBodyEraser<W> {
264    fn write_body<'a>(
265        self: Pin<&'a mut Self>,
266        w: Pin<&'a mut W>,
267    ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'a>>;
268
269    fn reset<'a>(self: Pin<&'a mut Self>) -> Pin<Box<dyn Future<Output = bool> + Send + 'a>>
270    where
271        W: 'a;
272}
273
274impl<T, W> AsyncWriteBodyEraser<W> for T
275where
276    T: AsyncWriteBody<W> + ?Sized,
277{
278    fn write_body<'a>(
279        self: Pin<&'a mut Self>,
280        w: Pin<&'a mut W>,
281    ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'a>> {
282        Box::pin(self.write_body(w))
283    }
284
285    fn reset<'a>(self: Pin<&'a mut Self>) -> Pin<Box<dyn Future<Output = bool> + Send + 'a>>
286    where
287        W: 'a,
288    {
289        Box::pin(self.reset())
290    }
291}
292
293/// A boxed [`AsyncWriteBody`] trait object.
294pub struct BoxAsyncWriteBody<'a, W> {
295    inner: Pin<Box<dyn AsyncWriteBodyEraser<W> + Send + 'a>>,
296}
297
298impl<'a, W> BoxAsyncWriteBody<'a, W> {
299    /// Creates a new `BoxAsyncWriteBody`.
300    pub fn new<T>(v: T) -> Self
301    where
302        T: AsyncWriteBody<W> + Send + 'a,
303    {
304        BoxAsyncWriteBody { inner: Box::pin(v) }
305    }
306}
307
308impl<W> AsyncWriteBody<W> for BoxAsyncWriteBody<'_, W>
309where
310    W: Send,
311{
312    async fn write_body(mut self: Pin<&mut Self>, w: Pin<&mut W>) -> Result<(), Error> {
313        self.inner.as_mut().write_body(w).await
314    }
315
316    async fn reset(mut self: Pin<&mut Self>) -> bool {
317        self.inner.as_mut().reset().await
318    }
319}
320
321/// A trait implemented by local async streaming bodies.
322///
323/// # Examples
324///
325/// ```ignore
326/// use conjure_error::Error;
327/// use conjure_http::client::LocalAsyncWriteBody;
328/// use std::pin::Pin;
329/// use tokio_io::{AsyncWrite, AsyncWriteExt};
330///
331/// pub struct SimpleBodyWriter;
332///
333/// impl<W> LocalAsyncWriteBody<W> for SimpleBodyWriter
334/// where
335///     W: AsyncWrite,
336/// {
337///     async fn write_body(self: Pin<&mut Self>, mut w: Pin<&mut W>) -> Result<(), Error> {
338///         w.write_all(b"hello world").await.map_err(Error::internal_safe)
339///     }
340///
341///     async fn reset(self: Pin<&mut Self>) -> bool {
342///         true
343///     }
344/// }
345/// ```
346pub trait LocalAsyncWriteBody<W> {
347    /// Writes the body out, in its entirety.
348    ///
349    /// Behavior is unspecified if this method is called twice without a successful call to `reset` in between.
350    fn write_body(self: Pin<&mut Self>, w: Pin<&mut W>) -> impl Future<Output = Result<(), Error>>;
351
352    /// Attempts to reset the body so that it can be written out again.
353    ///
354    /// Returns `true` if successful. Behavior is unspecified if this is not called after a call to `write_body`.
355    fn reset(self: Pin<&mut Self>) -> impl Future<Output = bool>;
356}
357
358// An internal object-safe version of LocalAsyncWriteBody used to implement BoxLocalAsyncWriteBody.
359trait LocalAsyncWriteBodyEraser<W> {
360    fn write_body<'a>(
361        self: Pin<&'a mut Self>,
362        w: Pin<&'a mut W>,
363    ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + 'a>>;
364
365    fn reset<'a>(self: Pin<&'a mut Self>) -> Pin<Box<dyn Future<Output = bool> + 'a>>
366    where
367        W: 'a;
368}
369
370impl<T, W> LocalAsyncWriteBodyEraser<W> for T
371where
372    T: LocalAsyncWriteBody<W> + ?Sized,
373{
374    fn write_body<'a>(
375        self: Pin<&'a mut Self>,
376        w: Pin<&'a mut W>,
377    ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + 'a>> {
378        Box::pin(self.write_body(w))
379    }
380
381    fn reset<'a>(self: Pin<&'a mut Self>) -> Pin<Box<dyn Future<Output = bool> + 'a>>
382    where
383        W: 'a,
384    {
385        Box::pin(self.reset())
386    }
387}
388
389/// A boxed [`LocalAsyncWriteBody`] trait object.
390pub struct BoxLocalAsyncWriteBody<'a, W> {
391    inner: Pin<Box<dyn LocalAsyncWriteBodyEraser<W> + 'a>>,
392}
393
394impl<'a, W> BoxLocalAsyncWriteBody<'a, W> {
395    /// Creates a new `BoxLocalAsyncWriteBody`.
396    pub fn new<T>(v: T) -> Self
397    where
398        T: LocalAsyncWriteBody<W> + 'a,
399    {
400        BoxLocalAsyncWriteBody { inner: Box::pin(v) }
401    }
402}
403
404impl<W> LocalAsyncWriteBody<W> for BoxLocalAsyncWriteBody<'_, W> {
405    async fn write_body(mut self: Pin<&mut Self>, w: Pin<&mut W>) -> Result<(), Error> {
406        self.inner.as_mut().write_body(w).await
407    }
408
409    async fn reset(mut self: Pin<&mut Self>) -> bool {
410        self.inner.as_mut().reset().await
411    }
412}
413
414/// A trait implemented by request body serializers used by custom Conjure client trait
415/// implementations.
416pub trait SerializeRequest<'a, T, W> {
417    /// Returns the body's content type.
418    fn content_type(runtime: &ConjureRuntime, value: &T) -> HeaderValue;
419
420    /// Returns the body's length, if known.
421    ///
422    /// Empty and fixed size bodies will have their content length filled in automatically.
423    ///
424    /// The default implementation returns `None`.
425    fn content_length(runtime: &ConjureRuntime, value: &T) -> Option<u64> {
426        let _runtime = runtime;
427        let _value = value;
428        None
429    }
430
431    /// Serializes the body.
432    fn serialize(runtime: &ConjureRuntime, value: T) -> Result<RequestBody<'a, W>, Error>;
433}
434
435/// A trait implemented by request body serializers used by custom async Conjure client trait
436/// implementations.
437pub trait AsyncSerializeRequest<'a, T, W> {
438    /// Returns the body's content type.
439    fn content_type(runtime: &ConjureRuntime, value: &T) -> HeaderValue;
440
441    /// Returns the body's length, if known.
442    ///
443    /// Empty and fixed size bodies will have their content length filled in automatically.
444    ///
445    /// The default implementation returns `None`.
446    fn content_length(runtime: &ConjureRuntime, value: &T) -> Option<u64> {
447        let _runtime = runtime;
448        let _value = value;
449        None
450    }
451
452    /// Serializes the body.
453    fn serialize(runtime: &ConjureRuntime, value: T) -> Result<AsyncRequestBody<'a, W>, Error>;
454}
455
456/// A trait implemented by request body serializers used by custom local async Conjure client trait
457/// implementations.
458pub trait LocalAsyncSerializeRequest<'a, T, W> {
459    /// Returns the body's content type.
460    fn content_type(runtime: &ConjureRuntime, value: &T) -> HeaderValue;
461
462    /// Returns the body's length, if known.
463    ///
464    /// Empty and fixed size bodies will have their content length filled in automatically.
465    ///
466    /// The default implementation returns `None`.
467    fn content_length(runtime: &ConjureRuntime, value: &T) -> Option<u64> {
468        let _runtime = runtime;
469        let _value = value;
470        None
471    }
472
473    /// Serializes the body.
474    fn serialize(runtime: &ConjureRuntime, value: T)
475        -> Result<LocalAsyncRequestBody<'a, W>, Error>;
476}
477
478/// A body serializer for standard request types.
479pub enum StdRequestSerializer {}
480
481impl StdRequestSerializer {
482    fn serialize_inner<B>(
483        runtime: &ConjureRuntime,
484        value: &dyn erased_serde::Serialize,
485        make_body: impl FnOnce(Bytes) -> B,
486    ) -> Result<B, Error> {
487        let mut body = vec![];
488        value
489            .erased_serialize(
490                &mut *runtime
491                    .request_body_encoding()
492                    .serializer(&mut body)
493                    .serializer(),
494            )
495            .map_err(Error::internal)?;
496
497        Ok(make_body(body.into()))
498    }
499}
500
501impl<'a, T, W> SerializeRequest<'a, T, W> for StdRequestSerializer
502where
503    T: Serialize,
504{
505    fn content_type(runtime: &ConjureRuntime, _: &T) -> HeaderValue {
506        runtime.request_body_encoding().content_type()
507    }
508
509    fn serialize(runtime: &ConjureRuntime, value: T) -> Result<RequestBody<'a, W>, Error> {
510        Self::serialize_inner(runtime, &value, RequestBody::Fixed)
511    }
512}
513
514impl<'a, T, W> AsyncSerializeRequest<'a, T, W> for StdRequestSerializer
515where
516    T: Serialize,
517{
518    fn content_type(runtime: &ConjureRuntime, _: &T) -> HeaderValue {
519        runtime.request_body_encoding().content_type()
520    }
521
522    fn serialize(runtime: &ConjureRuntime, value: T) -> Result<AsyncRequestBody<'a, W>, Error> {
523        Self::serialize_inner(runtime, &value, AsyncRequestBody::Fixed)
524    }
525}
526
527impl<'a, T, W> LocalAsyncSerializeRequest<'a, T, W> for StdRequestSerializer
528where
529    T: Serialize,
530{
531    fn content_type(runtime: &ConjureRuntime, _: &T) -> HeaderValue {
532        runtime.request_body_encoding().content_type()
533    }
534
535    fn serialize(
536        runtime: &ConjureRuntime,
537        value: T,
538    ) -> Result<LocalAsyncRequestBody<'a, W>, Error> {
539        Self::serialize_inner(runtime, &value, LocalAsyncRequestBody::Fixed)
540    }
541}
542
543/// A trait implemented by response deserializers used by custom Conjure client trait
544/// implementations.
545pub trait DeserializeResponse<T, R> {
546    /// Returns the value of the `Accept` header to be included in the request.
547    fn accept(runtime: &ConjureRuntime) -> Option<HeaderValue>;
548
549    /// Deserializes the response.
550    fn deserialize(runtime: &ConjureRuntime, response: Response<R>) -> Result<T, Error>;
551}
552
553/// A trait implemented by response deserializers used by custom async Conjure client trait
554/// implementations.
555pub trait AsyncDeserializeResponse<T, R> {
556    /// Returns the value of the `Accept` header to be included in the request.
557    fn accept(runtime: &ConjureRuntime) -> Option<HeaderValue>;
558
559    /// Deserializes the response.
560    fn deserialize(
561        runtime: &ConjureRuntime,
562        response: Response<R>,
563    ) -> impl Future<Output = Result<T, Error>> + Send;
564}
565
566/// A trait implemented by response deserializers used by custom local async Conjure client trait
567/// implementations.
568pub trait LocalAsyncDeserializeResponse<T, R> {
569    /// Returns the value of the `Accept` header to be included in the request.
570    fn accept(runtime: &ConjureRuntime) -> Option<HeaderValue>;
571
572    /// Deserializes the response.
573    fn deserialize(
574        runtime: &ConjureRuntime,
575        response: Response<R>,
576    ) -> impl Future<Output = Result<T, Error>>;
577}
578
579/// A response deserializer which ignores the response and returns `()`.
580pub enum UnitResponseDeserializer {}
581
582impl<R> DeserializeResponse<(), R> for UnitResponseDeserializer {
583    fn accept(_: &ConjureRuntime) -> Option<HeaderValue> {
584        None
585    }
586
587    fn deserialize(_: &ConjureRuntime, _: Response<R>) -> Result<(), Error> {
588        Ok(())
589    }
590}
591
592impl<R> AsyncDeserializeResponse<(), R> for UnitResponseDeserializer
593where
594    R: Send,
595{
596    fn accept(_: &ConjureRuntime) -> Option<HeaderValue> {
597        None
598    }
599
600    async fn deserialize(_: &ConjureRuntime, _: Response<R>) -> Result<(), Error> {
601        Ok(())
602    }
603}
604
605impl<R> LocalAsyncDeserializeResponse<(), R> for UnitResponseDeserializer {
606    fn accept(_: &ConjureRuntime) -> Option<HeaderValue> {
607        None
608    }
609
610    async fn deserialize(_: &ConjureRuntime, _: Response<R>) -> Result<(), Error> {
611        Ok(())
612    }
613}
614
615/// A response deserializer for standard body types.
616pub enum StdResponseDeserializer {}
617
618impl<T, R> DeserializeResponse<T, R> for StdResponseDeserializer
619where
620    T: DeserializeOwned,
621    R: Iterator<Item = Result<Bytes, Error>>,
622{
623    fn accept(runtime: &ConjureRuntime) -> Option<HeaderValue> {
624        Some(runtime.accept())
625    }
626
627    fn deserialize(runtime: &ConjureRuntime, response: Response<R>) -> Result<T, Error> {
628        let encoding = runtime.response_body_encoding(response.headers())?;
629        let buf = private::read_body(response.into_body(), None)?;
630        let v =
631            T::deserialize(encoding.deserializer(&buf).deserializer()).map_err(Error::internal)?;
632        Ok(v)
633    }
634}
635
636impl<T, R> AsyncDeserializeResponse<T, R> for StdResponseDeserializer
637where
638    T: DeserializeOwned,
639    R: Stream<Item = Result<Bytes, Error>> + Send,
640{
641    fn accept(runtime: &ConjureRuntime) -> Option<HeaderValue> {
642        Some(runtime.accept())
643    }
644
645    async fn deserialize(runtime: &ConjureRuntime, response: Response<R>) -> Result<T, Error> {
646        let encoding = runtime.response_body_encoding(response.headers())?;
647        let buf = private::async_read_body(response.into_body(), None).await?;
648        let v =
649            T::deserialize(encoding.deserializer(&buf).deserializer()).map_err(Error::internal)?;
650        Ok(v)
651    }
652}
653
654impl<T, R> LocalAsyncDeserializeResponse<T, R> for StdResponseDeserializer
655where
656    T: DeserializeOwned,
657    R: Stream<Item = Result<Bytes, Error>>,
658{
659    fn accept(runtime: &ConjureRuntime) -> Option<HeaderValue> {
660        Some(runtime.accept())
661    }
662
663    async fn deserialize(runtime: &ConjureRuntime, response: Response<R>) -> Result<T, Error> {
664        let encoding = runtime.response_body_encoding(response.headers())?;
665        let buf = private::async_read_body(response.into_body(), None).await?;
666        let v =
667            T::deserialize(encoding.deserializer(&buf).deserializer()).map_err(Error::internal)?;
668        Ok(v)
669    }
670}
671
672/// A trait implemented by header encoders used by custom Conjure client trait implementations.
673pub trait EncodeHeader<T> {
674    /// Encodes the value into headers.
675    ///
676    /// In almost all cases a single `HeaderValue` should be returned.
677    fn encode(runtime: &ConjureRuntime, value: T) -> Result<Vec<HeaderValue>, Error>;
678}
679
680/// A trait implemented by URL parameter encoders used by custom Conjure client trait
681/// implementations.
682pub trait EncodeParam<T> {
683    /// Encodes the value into a sequence of parameters.
684    ///
685    /// When used with a path parameter, each returned string will be a separate path component.
686    /// When used with a query parameter, each returned string will be the value of a separate query
687    /// entry.
688    fn encode(runtime: &ConjureRuntime, value: T) -> Result<Vec<String>, Error>;
689}
690
691/// An encoder which converts values via their `Display` implementation.
692pub enum DisplayEncoder {}
693
694impl<T> EncodeHeader<T> for DisplayEncoder
695where
696    T: Display,
697{
698    fn encode(_: &ConjureRuntime, value: T) -> Result<Vec<HeaderValue>, Error> {
699        HeaderValue::try_from(value.to_string())
700            .map_err(Error::internal_safe)
701            .map(|v| vec![v])
702    }
703}
704
705impl<T> EncodeParam<T> for DisplayEncoder
706where
707    T: Display,
708{
709    fn encode(_: &ConjureRuntime, value: T) -> Result<Vec<String>, Error> {
710        Ok(vec![value.to_string()])
711    }
712}
713
714/// An encoder which converts a sequence of values via their individual `Display`
715/// implementations.
716pub enum DisplaySeqEncoder {}
717
718impl<T, U> EncodeHeader<T> for DisplaySeqEncoder
719where
720    T: IntoIterator<Item = U>,
721    U: Display,
722{
723    fn encode(_: &ConjureRuntime, value: T) -> Result<Vec<HeaderValue>, Error> {
724        value
725            .into_iter()
726            .map(|v| HeaderValue::try_from(v.to_string()).map_err(Error::internal_safe))
727            .collect()
728    }
729}
730
731impl<T, U> EncodeParam<T> for DisplaySeqEncoder
732where
733    T: IntoIterator<Item = U>,
734    U: Display,
735{
736    fn encode(_: &ConjureRuntime, value: T) -> Result<Vec<String>, Error> {
737        Ok(value.into_iter().map(|v| v.to_string()).collect())
738    }
739}
740
741/// An encoder which delegates to another with [`AsRef::as_ref`].
742pub struct AsRefEncoder<D, U> {
743    _p: PhantomData<(D, U)>,
744}
745
746impl<T, D, U> EncodeHeader<T> for AsRefEncoder<D, U>
747where
748    T: AsRef<U>,
749    for<'a> D: EncodeHeader<&'a U>,
750{
751    fn encode(runtime: &ConjureRuntime, value: T) -> Result<Vec<HeaderValue>, Error> {
752        D::encode(runtime, value.as_ref())
753    }
754}
755
756impl<T, D, U> EncodeParam<T> for AsRefEncoder<D, U>
757where
758    T: AsRef<U>,
759    for<'a> D: EncodeParam<&'a U>,
760{
761    fn encode(runtime: &ConjureRuntime, value: T) -> Result<Vec<String>, Error> {
762        D::encode(runtime, value.as_ref())
763    }
764}