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