use serde::de::DeserializeOwned;
use crate::runtime::input::{Decoded, DecodedPair, InputKind, Provided};
use super::docs::DocState;
use super::verdict::{Batched, OneByOne, VerdictFamily};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Message<H, P> {
pub headers: H,
pub body: P,
}
impl<H, P> Message<H, P> {
#[must_use]
pub const fn new(headers: H, body: P) -> Self {
Self { headers, body }
}
}
pub trait Deserialized: Sized {
type Output<'a>: Send + Sync;
type Error: std::fmt::Display;
fn from_payload(payload: &[u8]) -> Result<Self::Output<'_>, Self::Error>;
}
#[doc(hidden)]
pub trait DecodeOutcome<T> {
fn finish(self) -> Result<T, Box<dyn std::error::Error + Send + Sync>>;
}
impl<T, E: std::error::Error + Send + Sync + 'static> DecodeOutcome<T> for Result<T, E> {
fn finish(self) -> Result<T, Box<dyn std::error::Error + Send + Sync>> {
self.map_err(|err| Box::new(err) as Box<dyn std::error::Error + Send + Sync>)
}
}
#[diagnostic::on_unimplemented(
message = "`{Self}` is not a handler input",
note = "a body's input is `&T` (T: DeserializeOwned), `&F<'_>` (F: Deserialized - derive it \
for a raw-payload type), `&Message<H, P>`, or a batch: `&[T]`, `&[F<'_>]`, \
`&[Message<H, P>]`"
)]
pub trait Input {
type Axis: Axis;
}
#[doc(hidden)]
pub trait Axis: Send + Sync + 'static {
type Family: VerdictFamily;
type Kind: InputKind;
type EagerForm;
type SlotForm;
#[must_use]
fn payload_schema<Doc: AxisDocs<Self>>() -> Option<String> {
Doc::payload_schema()
}
}
#[doc(hidden)]
pub trait AxisDocs<A: Axis + ?Sized> {
fn payload_schema() -> Option<String>;
#[must_use]
fn headers_schema() -> Option<String> {
None
}
}
#[derive(Debug)]
pub struct Solo<T>(core::marker::PhantomData<T>);
#[derive(Debug)]
pub struct SoloDeserialized<F>(core::marker::PhantomData<F>);
#[derive(Debug)]
pub struct SoloPair<H, P>(core::marker::PhantomData<(H, P)>);
#[derive(Debug)]
pub struct Batch<T>(core::marker::PhantomData<T>);
#[derive(Debug)]
pub struct BatchDeserialized<F>(core::marker::PhantomData<F>);
#[derive(Debug)]
pub struct BatchPair<H, P>(core::marker::PhantomData<(H, P)>);
impl<T: DeserializeOwned + Send + Sync + 'static> Input for T {
type Axis = Solo<T>;
}
impl<H, P> Input for Message<H, P>
where
H: DeserializeOwned + Send + Sync + 'static,
P: DeserializeOwned + Send + Sync + 'static,
{
type Axis = SoloPair<H, P>;
}
#[doc(hidden)]
pub trait BatchedFrom {
type Batch: Axis;
}
impl<T: Send + Sync + 'static> BatchedFrom for Solo<T> {
type Batch = Batch<T>;
}
impl<F: Send + Sync + 'static> BatchedFrom for SoloDeserialized<F> {
type Batch = BatchDeserialized<F>;
}
impl<H: Send + Sync + 'static, P: Send + Sync + 'static> BatchedFrom for SoloPair<H, P> {
type Batch = BatchPair<H, P>;
}
impl<E> Input for [E]
where
E: Input,
E::Axis: BatchedFrom,
{
type Axis = <E::Axis as BatchedFrom>::Batch;
}
impl<T: Send + Sync + 'static> Axis for Solo<T> {
type Family = OneByOne;
type Kind = Decoded<T>;
type EagerForm = crate::runtime::router::forms::Subscribing;
type SlotForm = crate::runtime::router::forms::Out;
}
impl<F: Send + Sync + 'static> Axis for SoloDeserialized<F> {
type Family = OneByOne;
type Kind = Provided<F>;
type EagerForm = crate::runtime::router::forms::RawSubscribing;
type SlotForm = crate::runtime::router::forms::Out;
}
impl<H: Send + Sync + 'static, P: Send + Sync + 'static> Axis for SoloPair<H, P> {
type Family = OneByOne;
type Kind = DecodedPair<H, P>;
type EagerForm = crate::runtime::router::forms::Subscribing;
type SlotForm = crate::runtime::router::forms::Out;
}
impl<T: Send + Sync + 'static> Axis for Batch<T> {
type Family = Batched;
type Kind = Decoded<T>;
type EagerForm = crate::runtime::router::forms::Batch;
type SlotForm = crate::runtime::router::forms::BatchOut;
}
impl<F: Send + Sync + 'static> Axis for BatchDeserialized<F> {
type Family = Batched;
type Kind = Provided<F>;
type EagerForm = crate::runtime::router::forms::RawBatch;
type SlotForm = crate::runtime::router::forms::BatchOut;
}
impl<H: Send + Sync + 'static, P: Send + Sync + 'static> Axis for BatchPair<H, P> {
type Family = Batched;
type Kind = DecodedPair<H, P>;
type EagerForm = crate::runtime::router::forms::Batch;
type SlotForm = crate::runtime::router::forms::BatchOut;
}
impl<T: Send + Sync + 'static, Doc: DocState<T>> AxisDocs<Solo<T>> for Doc {
fn payload_schema() -> Option<String> {
Doc::schema()
}
}
impl<F, Doc> AxisDocs<SoloDeserialized<F>> for Doc
where
F: Send + Sync + 'static,
{
fn payload_schema() -> Option<String> {
None
}
}
impl<H, P, Doc> AxisDocs<SoloPair<H, P>> for Doc
where
H: Send + Sync + 'static,
P: Send + Sync + 'static,
Doc: DocState<P> + DocState<H>,
{
fn payload_schema() -> Option<String> {
<Doc as DocState<P>>::schema()
}
fn headers_schema() -> Option<String> {
<Doc as DocState<H>>::schema()
}
}
impl<T: Send + Sync + 'static, Doc: DocState<T>> AxisDocs<Batch<T>> for Doc {
fn payload_schema() -> Option<String> {
Doc::schema()
}
}
impl<F, Doc> AxisDocs<BatchDeserialized<F>> for Doc
where
F: Send + Sync + 'static,
{
fn payload_schema() -> Option<String> {
None
}
}
impl<H, P, Doc> AxisDocs<BatchPair<H, P>> for Doc
where
H: Send + Sync + 'static,
P: Send + Sync + 'static,
Doc: DocState<P> + DocState<H>,
{
fn payload_schema() -> Option<String> {
<Doc as DocState<P>>::schema()
}
fn headers_schema() -> Option<String> {
<Doc as DocState<H>>::schema()
}
}
#[doc(hidden)]
pub trait SoloAxis: Axis<Family = OneByOne> {}
impl<T: Send + Sync + 'static> SoloAxis for Solo<T> {}
impl<F: Send + Sync + 'static> SoloAxis for SoloDeserialized<F> {}
impl<H: Send + Sync + 'static, P: Send + Sync + 'static> SoloAxis for SoloPair<H, P> {}
#[doc(hidden)]
pub trait BatchedAxis: Axis<Family = Batched> {}
impl<T: Send + Sync + 'static> BatchedAxis for Batch<T> {}
impl<F: Send + Sync + 'static> BatchedAxis for BatchDeserialized<F> {}
impl<H: Send + Sync + 'static, P: Send + Sync + 'static> BatchedAxis for BatchPair<H, P> {}