Skip to main content

autapi/
adapters.rs

1use std::pin::Pin;
2
3use serde::{Deserialize, Serialize, Serializer, ser::Error};
4
5use crate::{
6    endpoint::Endpoint,
7    request::Request,
8    response::Response,
9    schema::{SchemaDeserialize, SchemaSerialize},
10};
11
12/// Allows (de-)serializing a [`SchemaDeserialize`] or [`SchemaSerialize`] using standard serde
13/// (de-)serializers.
14#[derive(Debug)]
15pub struct SerdeAdapter<T>(pub T);
16
17impl<T> SerdeAdapter<T>
18where
19    T: SchemaSerialize,
20{
21    pub fn skip_serializing(&self) -> bool {
22        !self.0.is_present()
23    }
24}
25
26impl<T> Serialize for SerdeAdapter<T>
27where
28    T: SchemaSerialize,
29{
30    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
31    where
32        S: Serializer,
33    {
34        if !self.0.is_present() {
35            return Err(S::Error::custom("cannot serialize an absent value"));
36        }
37        self.0.schema_serialize(serializer)
38    }
39}
40
41impl<'de, T> Deserialize<'de> for SerdeAdapter<T>
42where
43    T: SchemaDeserialize,
44{
45    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
46    where
47        D: serde::Deserializer<'de>,
48    {
49        Ok(Self(T::schema_deserialize(deserializer)?))
50    }
51}
52
53/// Wraps an [`Endpoint`] and implements axum's [`Handler`](axum::handler::Handler) trait.
54#[derive(Clone)]
55pub struct AxumHandlerAdapter<E>(pub E);
56
57impl<V: 'static, S: 'static, E: Endpoint<S, V>> axum::handler::Handler<V, S>
58    for AxumHandlerAdapter<E>
59{
60    type Future = Pin<Box<dyn Future<Output = Response> + Send + 'static>>;
61
62    fn call(self, req: Request, state: S) -> Self::Future {
63        Box::pin(self.0.call(req, state))
64    }
65}
66
67impl<E, V> Endpoint<E, V> for AxumHandlerAdapter<E>
68where
69    E: Endpoint<E, V>,
70{
71    fn path(&self) -> std::borrow::Cow<'static, str> {
72        self.0.path()
73    }
74
75    fn method(&self) -> http::Method {
76        self.0.method()
77    }
78
79    fn openapi(&self, registry: &mut crate::Registry) -> crate::openapi::Operation {
80        self.0.openapi(registry)
81    }
82
83    fn call(self, req: Request, state: E) -> impl Future<Output = Response> + Send {
84        self.0.call(req, state)
85    }
86}