#![allow(unused)]
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use openapiv3::{MediaType, Operation, ReferenceOr, RequestBody, Response, Responses, StatusCode};
use pin_project_lite::pin_project;
use openapiv3 as oa;
use crate::OaSchema;
fn type_name_to_operation_id(type_name: &str) -> Option<String> {
Some(type_name.split("::").skip(1).collect::<Vec<_>>().join("_"))
}
pub trait OaOperation<Signature> {
fn referenced_schema(schema: &str) -> oa::Schema;
fn references() -> Vec<&'static str>;
fn operation() -> Operation;
}
pub trait FunctionMetadata {
fn operation_id() -> Option<&'static str>;
fn summary() -> Option<&'static str>;
fn description() -> Option<&'static str>;
}
pin_project! {
#[repr(transparent)]
pub struct TypedResponseFuture<F, Signature> {
#[pin]
inner: F,
_marker: std::marker::PhantomData<Signature>,
}
}
impl<F, Signature> TypedResponseFuture<F, Signature>
{
pub fn new(inner: F) -> Self {
Self { inner, _marker: Default::default() }
}
pub fn into_inner(self) -> F {
self.inner
}
}
impl<F, Signature> Future for TypedResponseFuture<F, Signature>
where
F: Future,
{
type Output = F::Output;
#[inline]
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.as_mut().project();
this.inner.poll(cx)
}
}
macro_rules! construct_operation {
($($arg:ident),+) => {
impl<F, $($arg),+ , Fut, FuncMetadata> OaOperation<( $($arg),+ , Fut, FuncMetadata)> for F
where
F: Fn($($arg),+) -> TypedResponseFuture<Fut, FuncMetadata>,
Fut: Future,
$($arg: OaSchema),+,
Fut::Output: OaSchema,
FuncMetadata: FunctionMetadata,
{
fn referenced_schema(schema: &str) -> oa::Schema {
$(
if $arg::schema_name().map(|s| s == schema).unwrap_or(false) {
return $arg::schema().expect(&format!("Schema not found: {}", schema));
}
)+
if Fut::Output::schema_name().map(|s| s == schema).unwrap_or(false) {
Fut::Output::schema().expect(&format!("Schema not found: {}", schema))
} else {
panic!("Unknown schema: {}", schema)
}
}
fn references() -> Vec<&'static str> {
vec![$($arg::schema_name()),+, Fut::Output::schema_name()].into_iter().flatten().collect()
}
fn operation() -> Operation {
let parameters = vec![
$( $arg::parameters(), )+
]
.into_iter()
.flatten()
.flatten()
.collect::<Vec<_>>();
let body = vec![
$( $arg::schema_ref(), )+
].into_iter().flatten().next();
let mut operation = Operation {
operation_id: type_name_to_operation_id(std::any::type_name::<F>()),
summary: FuncMetadata::summary().map(str::to_string),
parameters,
..Operation::default()
};
operation.add_request_body_json(body);
operation.add_response_success_json(Fut::Output::schema_ref());
operation
}
}
}
}
construct_operation!(A1);
construct_operation!(A1, A2);
construct_operation!(A1, A2, A3);
construct_operation!(A1, A2, A3, A4);
construct_operation!(A1, A2, A3, A4, A5);
construct_operation!(A1, A2, A3, A4, A5, A6);
construct_operation!(A1, A2, A3, A4, A5, A6, A7);
construct_operation!(A1, A2, A3, A4, A5, A6, A7, A8);