use std::any::TypeId;
use salvo_core::http::StatusCode;
use salvo_core::{prelude::StatusError, writing};
use crate::{Components, Operation, Response, ToResponse, ToResponses, ToSchema};
pub struct Endpoint {
pub operation: Operation,
pub components: Components,
}
impl Endpoint {
pub fn new(operation: Operation, components: Components) -> Self {
Self { operation, components }
}
}
pub trait EndpointArgRegister {
fn register(components: &mut Components, operation: &mut Operation, arg: &str);
}
pub trait EndpointOutRegister {
fn register(components: &mut Components, operation: &mut Operation);
}
impl<C> EndpointOutRegister for writing::Json<C>
where
C: ToSchema,
{
#[inline]
fn register(components: &mut Components, operation: &mut Operation) {
operation.responses.insert("200", Self::to_response(components));
}
}
impl<T, E> EndpointOutRegister for Result<T, E>
where
T: EndpointOutRegister + Send,
E: EndpointOutRegister + Send,
{
#[inline]
fn register(components: &mut Components, operation: &mut Operation) {
T::register(components, operation);
E::register(components, operation);
}
}
impl<E> EndpointOutRegister for Result<(), E>
where
E: EndpointOutRegister + Send,
{
#[inline]
fn register(components: &mut Components, operation: &mut Operation) {
operation.responses.insert("200", Response::new("Ok"));
E::register(components, operation);
}
}
impl EndpointOutRegister for StatusError {
#[inline]
fn register(components: &mut Components, operation: &mut Operation) {
operation.responses.append(&mut Self::to_responses(components));
}
}
impl EndpointOutRegister for StatusCode {
#[inline]
fn register(components: &mut Components, operation: &mut Operation) {
for code in [
StatusCode::CONTINUE,
StatusCode::SWITCHING_PROTOCOLS,
StatusCode::PROCESSING,
StatusCode::OK,
StatusCode::CREATED,
StatusCode::ACCEPTED,
StatusCode::NON_AUTHORITATIVE_INFORMATION,
StatusCode::NO_CONTENT,
StatusCode::RESET_CONTENT,
StatusCode::PARTIAL_CONTENT,
StatusCode::MULTI_STATUS,
StatusCode::ALREADY_REPORTED,
StatusCode::IM_USED,
StatusCode::MULTIPLE_CHOICES,
StatusCode::MOVED_PERMANENTLY,
StatusCode::FOUND,
StatusCode::SEE_OTHER,
StatusCode::NOT_MODIFIED,
StatusCode::USE_PROXY,
StatusCode::TEMPORARY_REDIRECT,
StatusCode::PERMANENT_REDIRECT,
] {
operation.responses.insert(
code.as_str(),
Response::new(
code.canonical_reason()
.unwrap_or("No further explanation is available."),
),
)
}
operation.responses.append(&mut StatusError::to_responses(components));
}
}
impl EndpointOutRegister for salvo_core::Error {
#[inline]
fn register(components: &mut Components, operation: &mut Operation) {
operation.responses.append(&mut Self::to_responses(components));
}
}
impl EndpointOutRegister for &'static str {
#[inline]
fn register(components: &mut Components, operation: &mut Operation) {
operation.responses.insert(
"200",
Response::new("Ok").add_content("text/plain", String::to_schema(components)),
);
}
}
impl EndpointOutRegister for String {
#[inline]
fn register(components: &mut Components, operation: &mut Operation) {
operation.responses.insert(
"200",
Response::new("Ok").add_content("text/plain", String::to_schema(components)),
);
}
}
impl<'a> EndpointOutRegister for &'a String {
#[inline]
fn register(components: &mut Components, operation: &mut Operation) {
operation.responses.insert(
"200",
Response::new("Ok").add_content("text/plain", String::to_schema(components)),
);
}
}
#[non_exhaustive]
pub struct EndpointRegistry {
pub type_id: fn() -> TypeId,
pub creator: fn() -> Endpoint,
}
impl EndpointRegistry {
pub const fn save(type_id: fn() -> TypeId, creator: fn() -> Endpoint) -> Self {
Self { type_id, creator }
}
pub fn find(type_id: &TypeId) -> Option<fn() -> Endpoint> {
for record in inventory::iter::<EndpointRegistry> {
if (record.type_id)() == *type_id {
return Some(record.creator);
}
}
None
}
}
inventory::collect!(EndpointRegistry);