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