1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
use std::{borrow::Cow, collections::BTreeMap};

use bytes::{Bytes, BytesMut};
use http::StatusCode;

use crate::{
    body::ResponseBody,
    media_type::MultiResponseMediaType,
    openapi::{self, Components},
};

pub type Response<T = ResponseBody> = http::Response<T>;

pub trait SingleResponse {
    const STATUS_CODE: u16 = 200;

    fn response(components: &mut Components) -> openapi::Response;
}

pub trait MultiResponse {
    fn responses(components: &mut Components) -> BTreeMap<StatusCode, openapi::Response>;
}

impl<T: SingleResponse> MultiResponse for T {
    fn responses(components: &mut Components) -> BTreeMap<StatusCode, openapi::Response> {
        let mut map = BTreeMap::new();

        map.insert(
            StatusCode::from_u16(T::STATUS_CODE).unwrap_or_else(|_| {
                panic!(
                    "`<{} as SingleResponse>::STATUS_CODE` is {}, which is not a valid status code",
                    std::any::type_name::<T>(),
                    T::STATUS_CODE
                )
            }),
            T::response(components),
        );

        map
    }
}

impl SingleResponse for () {
    fn response(_: &mut Components) -> openapi::Response {
        openapi::Response::default()
    }
}

macro_rules! some_impl {
    ($ty:ty; $($desc:tt)+) => {
        impl $($desc)+
        {
            fn response(components: &mut Components) -> openapi::Response {
                openapi::Response {
                    content: <$ty as MultiResponseMediaType>::content(components),
                    ..Default::default()
                }
            }
        }
    };
}

some_impl!(String; SingleResponse for &'static str);
some_impl!(String; SingleResponse for Cow<'static, str>);
some_impl!(String; SingleResponse for String);
some_impl!(String; SingleResponse for Box<str>);

some_impl!(Vec<u8>; SingleResponse for &'static [u8]);
some_impl!(Vec<u8>; SingleResponse for Cow<'static, [u8]>);
some_impl!(Vec<u8>; SingleResponse for Vec<u8>);
some_impl!(Vec<u8>; SingleResponse for Bytes);
some_impl!(Vec<u8>; SingleResponse for BytesMut);
some_impl!(Vec<u8>; SingleResponse for Box<[u8]>);

some_impl!([u8; N]; <const N: usize> SingleResponse for [u8; N]);
some_impl!([u8; N]; <const N: usize> SingleResponse for &'static [u8; N]);