use std::borrow::Cow;
use std::fmt;
use std::marker::PhantomData;
use crate::runtime::settings::{CapsBatches, SubscriberBuilder};
use super::axis::{Batch, BatchDeserialized, BatchPair, Input};
use super::docs::{Docs, Documented, Probed, ProbedDocs, Undocumented};
use super::{Handle, IntoSource};
type HandleAxes<A, R, O, C, Doc> = PhantomData<fn() -> (A, R, O, C, Doc)>;
type PlainChain<A, R, O, C, H, Doc, Src, State, DC> =
SubscriberBuilder<HandleValue<A, R, O, C, H, Doc>, Src, State, DC>;
type ReplyChain<V, Dest, Src, State, DC> = SubscriberBuilder<ReplyValue<V, Dest>, Src, State, DC>;
type ReplyStart<A, R, O, C, H, Doc, Src, State, DC> =
ReplyChain<HandleValue<A, R, O, C, H, Doc>, DeclaredDest, Src, State, DC>;
type SealedChain<V, Src, State, DC> = SubscriberBuilder<Sealed<V>, Src, State, DC>;
type FreshChain<A, R, O, C, H, Src> = super::ValueBuilder<HandleValue<A, R, O, C, H>, Src>;
type SealedPlainChain<A, R, O, C, H, Doc, Src, State, DC> =
SealedChain<HandleValue<A, R, O, C, H, Doc>, Src, State, DC>;
type UndocumentedReplyChain<A, R, O, C, H, Dest, Src, State, DC> =
ReplyChain<HandleValue<A, R, O, C, H, Undocumented>, Dest, Src, State, DC>;
type SealedReplyChain<A, R, O, C, H, Doc, Dest, Src, State, DC> =
SealedChain<ReplyValue<HandleValue<A, R, O, C, H, Doc>, Dest>, Src, State, DC>;
pub struct HandleValue<A, R, O, C, H, Doc = Documented> {
pub(super) body: H,
pub(super) docs: Docs,
pub(super) _axes: HandleAxes<A, R, O, C, Doc>,
}
impl<A, R, O, C, H, Doc> fmt::Debug for HandleValue<A, R, O, C, H, Doc> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("HandleValue").finish_non_exhaustive()
}
}
impl<A, R, O, C, H, Doc> HandleValue<A, R, O, C, H, Doc> {
fn with_doc<NewDoc>(self) -> HandleValue<A, R, O, C, H, NewDoc> {
HandleValue {
body: self.body,
docs: self.docs,
_axes: PhantomData,
}
}
}
#[must_use]
pub fn subscriber<Src, In, R, O, C, S, H>(
source: Src,
body: H,
) -> FreshChain<In::Axis, R, O, C, H, Src>
where
Src: IntoSource,
In: ?Sized + Input,
H: Handle<In, R, O, C, S>,
{
SubscriberBuilder::new(
HandleValue {
body,
docs: Docs::default(),
_axes: PhantomData,
},
source.into_source(),
)
}
#[doc(hidden)]
#[must_use]
pub fn probed_def<A, R, O, C, H>(
body: H,
docs: ProbedDocs,
) -> Sealed<HandleValue<A, R, O, C, H, Probed>> {
Sealed(HandleValue {
body,
docs: docs.into_docs(),
_axes: PhantomData,
})
}
#[doc(hidden)]
pub type ProbedReplyDef<A, R, O, C, H> =
Sealed<ReplyValue<HandleValue<A, R, O, C, H, Probed>, ResolvedDest>>;
#[doc(hidden)]
pub type ProbedDeclaredReplyDef<A, R, O, C, H> =
Sealed<ReplyValue<HandleValue<A, R, O, C, H, Probed>, DeclaredDest>>;
#[doc(hidden)]
#[must_use]
pub fn probed_reply_def<A, R, O, C, H>(
body: H,
docs: ProbedDocs,
dest: ResolvedDest,
) -> ProbedReplyDef<A, R, O, C, H> {
let Sealed(value) = probed_def(body, docs);
Sealed(ReplyValue { value, dest })
}
#[doc(hidden)]
#[must_use]
pub fn probed_declared_reply_def<A, R, O, C, H>(
body: H,
docs: ProbedDocs,
) -> ProbedDeclaredReplyDef<A, R, O, C, H> {
let Sealed(value) = probed_def(body, docs);
Sealed(ReplyValue {
value,
dest: DeclaredDest,
})
}
#[derive(Debug, Clone, Copy)]
pub struct ResolvedDest {
pub(super) name: &'static str,
pub(super) ignored: Option<&'static str>,
}
impl ResolvedDest {
#[doc(hidden)]
#[must_use]
pub const fn name(self) -> &'static str {
self.name
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct DeclaredDest;
#[derive(Debug, Clone)]
pub struct NamedDest(pub(super) Cow<'static, str>);
#[derive(Debug, Clone, Copy)]
pub struct EncodedReply;
#[derive(Debug, Clone, Copy)]
pub struct SerializedReply;
pub struct ReplyValue<V, Dest> {
pub(super) value: V,
pub(super) dest: Dest,
}
impl<V, Dest> fmt::Debug for ReplyValue<V, Dest> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ReplyValue").finish_non_exhaustive()
}
}
impl<V, Dest> ReplyValue<V, Dest> {
fn map_value<W>(self, f: impl FnOnce(V) -> W) -> ReplyValue<W, Dest> {
ReplyValue {
value: f(self.value),
dest: self.dest,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct UnbuiltDefinition;
impl<A, R, O, C, H, Doc> crate::runtime::router::IncludeDef for HandleValue<A, R, O, C, H, Doc> {
type Form = UnbuiltDefinition;
}
impl<V, Dest> crate::runtime::router::IncludeDef for ReplyValue<V, Dest> {
type Form = UnbuiltDefinition;
}
pub struct Sealed<V>(pub(super) V);
impl<V> fmt::Debug for Sealed<V> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Sealed").finish_non_exhaustive()
}
}
impl<T, R, O, C, H, Doc> CapsBatches for HandleValue<Batch<T>, R, O, C, H, Doc> {}
impl<F, R, O, C, H, Doc> CapsBatches for HandleValue<BatchDeserialized<F>, R, O, C, H, Doc> {}
impl<Hd, P, R, O, C, H, Doc> CapsBatches for HandleValue<BatchPair<Hd, P>, R, O, C, H, Doc> {}
impl<V: CapsBatches, Dest> CapsBatches for ReplyValue<V, Dest> {}
impl<V: CapsBatches> CapsBatches for Sealed<V> {}
impl<A, R, O, C, H, Doc, Src, State, DC>
SubscriberBuilder<HandleValue<A, R, O, C, H, Doc>, Src, State, DC>
{
#[must_use]
pub fn describe(self, text: impl Into<Cow<'static, str>>) -> Self {
self.map_def(|mut def| {
def.docs.description = Some(text.into());
def
})
}
#[must_use]
pub fn undocumented(self) -> PlainChain<A, R, O, C, H, Undocumented, Src, State, DC>
where
Doc: IsDocumented,
{
self.map_def(HandleValue::with_doc)
}
#[must_use]
pub fn reply(self) -> ReplyStart<A, R, O, C, H, Doc, Src, State, DC> {
self.map_def(|value| ReplyValue {
value,
dest: DeclaredDest,
})
}
#[must_use]
pub fn build(self) -> SealedPlainChain<A, R, O, C, H, Doc, Src, State, DC> {
self.map_def(Sealed)
}
}
#[diagnostic::on_unimplemented(
message = "this registration is already undocumented",
label = "`.undocumented()` was already chained"
)]
pub trait IsDocumented {}
impl IsDocumented for Documented {}
impl<V, Src, State, DC> SubscriberBuilder<ReplyValue<V, DeclaredDest>, Src, State, DC> {
#[must_use]
pub fn to(
self,
name: impl Into<Cow<'static, str>>,
) -> SubscriberBuilder<ReplyValue<V, NamedDest>, Src, State, DC> {
self.map_def(|def| ReplyValue {
value: def.value,
dest: NamedDest(name.into()),
})
}
}
impl<A, R, O, C, H, Doc, Dest, Src, State, DC>
SubscriberBuilder<ReplyValue<HandleValue<A, R, O, C, H, Doc>, Dest>, Src, State, DC>
{
#[must_use]
pub fn describe(self, text: impl Into<Cow<'static, str>>) -> Self {
self.map_def(|def| {
def.map_value(|mut value| {
value.docs.description = Some(text.into());
value
})
})
}
#[must_use]
pub fn undocumented(self) -> UndocumentedReplyChain<A, R, O, C, H, Dest, Src, State, DC>
where
Doc: IsDocumented,
{
self.map_def(|def| def.map_value(HandleValue::with_doc))
}
#[must_use]
pub fn build(self) -> SealedReplyChain<A, R, O, C, H, Doc, Dest, Src, State, DC> {
self.map_def(Sealed)
}
}