1use std::any::TypeId;
2
3use salvo_core::http::StatusCode;
4use salvo_core::{prelude::StatusError, writing};
5
6use crate::{Components, Operation, Response, ToResponse, ToResponses, ToSchema};
7
8pub struct Endpoint {
12 pub operation: Operation,
14 pub components: Components,
16}
17
18impl Endpoint {
19 pub fn new(operation: Operation, components: Components) -> Self {
21 Self {
22 operation,
23 components,
24 }
25 }
26}
27
28pub trait EndpointArgRegister {
30 fn register(components: &mut Components, operation: &mut Operation, arg: &str);
32}
33pub trait EndpointOutRegister {
35 fn register(components: &mut Components, operation: &mut Operation);
37}
38
39impl<C> EndpointOutRegister for writing::Json<C>
40where
41 C: ToSchema,
42{
43 #[inline]
44 fn register(components: &mut Components, operation: &mut Operation) {
45 operation
46 .responses
47 .insert("200", Self::to_response(components));
48 }
49}
50impl<T, E> EndpointOutRegister for Result<T, E>
51where
52 T: EndpointOutRegister + Send,
53 E: EndpointOutRegister + Send,
54{
55 #[inline]
56 fn register(components: &mut Components, operation: &mut Operation) {
57 T::register(components, operation);
58 E::register(components, operation);
59 }
60}
61impl<E> EndpointOutRegister for Result<(), E>
62where
63 E: EndpointOutRegister + Send,
64{
65 #[inline]
66 fn register(components: &mut Components, operation: &mut Operation) {
67 operation.responses.insert("200", Response::new("Ok"));
68 E::register(components, operation);
69 }
70}
71
72impl EndpointOutRegister for StatusError {
73 #[inline]
74 fn register(components: &mut Components, operation: &mut Operation) {
75 operation
76 .responses
77 .append(&mut Self::to_responses(components));
78 }
79}
80impl EndpointOutRegister for StatusCode {
81 fn register(components: &mut Components, operation: &mut Operation) {
82 for code in [
83 StatusCode::CONTINUE,
84 StatusCode::SWITCHING_PROTOCOLS,
85 StatusCode::PROCESSING,
86 StatusCode::OK,
87 StatusCode::CREATED,
88 StatusCode::ACCEPTED,
89 StatusCode::NON_AUTHORITATIVE_INFORMATION,
90 StatusCode::NO_CONTENT,
91 StatusCode::RESET_CONTENT,
92 StatusCode::PARTIAL_CONTENT,
93 StatusCode::MULTI_STATUS,
94 StatusCode::ALREADY_REPORTED,
95 StatusCode::IM_USED,
96 StatusCode::MULTIPLE_CHOICES,
97 StatusCode::MOVED_PERMANENTLY,
98 StatusCode::FOUND,
99 StatusCode::SEE_OTHER,
100 StatusCode::NOT_MODIFIED,
101 StatusCode::USE_PROXY,
102 StatusCode::TEMPORARY_REDIRECT,
103 StatusCode::PERMANENT_REDIRECT,
104 ] {
105 operation.responses.insert(
106 code.as_str(),
107 Response::new(
108 code.canonical_reason()
109 .unwrap_or("No further explanation is available."),
110 ),
111 )
112 }
113 operation
114 .responses
115 .append(&mut StatusError::to_responses(components));
116 }
117}
118impl EndpointOutRegister for salvo_core::Error {
119 #[inline]
120 fn register(components: &mut Components, operation: &mut Operation) {
121 operation
122 .responses
123 .append(&mut Self::to_responses(components));
124 }
125}
126
127impl EndpointOutRegister for &str {
128 #[inline]
129 fn register(components: &mut Components, operation: &mut Operation) {
130 operation.responses.insert(
131 "200",
132 Response::new("Ok").add_content("text/plain", String::to_schema(components)),
133 );
134 }
135}
136impl EndpointOutRegister for String {
137 #[inline]
138 fn register(components: &mut Components, operation: &mut Operation) {
139 operation.responses.insert(
140 "200",
141 Response::new("Ok").add_content("text/plain", String::to_schema(components)),
142 );
143 }
144}
145impl EndpointOutRegister for &String {
146 #[inline]
147 fn register(components: &mut Components, operation: &mut Operation) {
148 operation.responses.insert(
149 "200",
150 Response::new("Ok").add_content("text/plain", String::to_schema(components)),
151 );
152 }
153}
154
155#[doc(hidden)]
157#[non_exhaustive]
158pub struct EndpointRegistry {
159 pub type_id: fn() -> TypeId,
161 pub creator: fn() -> Endpoint,
163}
164
165impl EndpointRegistry {
166 pub const fn save(type_id: fn() -> TypeId, creator: fn() -> Endpoint) -> Self {
168 Self { type_id, creator }
169 }
170 pub fn find(type_id: &TypeId) -> Option<fn() -> Endpoint> {
172 for record in inventory::iter::<EndpointRegistry> {
173 if (record.type_id)() == *type_id {
174 return Some(record.creator);
175 }
176 }
177 None
178 }
179}
180inventory::collect!(EndpointRegistry);