use std::borrow::Cow;
use std::fmt::{self, Display, Formatter};
use std::future::Future;
use std::hash::{Hash, Hasher};
use std::mem;
use std::ops::Deref;
use std::pin::Pin;
use bytes::BytesMut;
use bytes_utils::Str;
use crate::HeaderMap;
use crate::runtime::lifecycle::BoxError;
pub(super) type PublishFut<'a> = Pin<Box<dyn Future<Output = Result<(), BoxError>> + Send + 'a>>;
#[derive(Debug, Clone)]
pub struct Outgoing<'a> {
name: OutgoingName<'a>,
payload: Payload<'a>,
headers: HeaderMap,
}
#[derive(Debug, Clone)]
pub enum OutgoingName<'a> {
Borrowed(&'a str),
Owned(String),
Shared(Str),
}
impl OutgoingName<'_> {
#[must_use]
pub fn as_str(&self) -> &str {
match self {
Self::Borrowed(name) => name,
Self::Owned(name) => name,
Self::Shared(name) => name,
}
}
}
impl Deref for OutgoingName<'_> {
type Target = str;
fn deref(&self) -> &str {
self.as_str()
}
}
impl AsRef<str> for OutgoingName<'_> {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl Display for OutgoingName<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl PartialEq for OutgoingName<'_> {
fn eq(&self, other: &Self) -> bool {
self.as_str() == other.as_str()
}
}
impl Eq for OutgoingName<'_> {}
impl Hash for OutgoingName<'_> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.as_str().hash(state);
}
}
impl<'a> From<&'a str> for OutgoingName<'a> {
fn from(name: &'a str) -> Self {
Self::Borrowed(name)
}
}
impl From<String> for OutgoingName<'_> {
fn from(name: String) -> Self {
Self::Owned(name)
}
}
impl From<Str> for OutgoingName<'_> {
fn from(name: Str) -> Self {
Self::Shared(name)
}
}
impl<'a> From<Cow<'a, str>> for OutgoingName<'a> {
fn from(name: Cow<'a, str>) -> Self {
match name {
Cow::Borrowed(name) => Self::Borrowed(name),
Cow::Owned(name) => Self::Owned(name),
}
}
}
#[derive(Debug, Clone)]
pub(crate) enum Payload<'a> {
Lent(&'a [u8]),
Owned(BytesMut),
}
impl Payload<'_> {
#[inline]
pub(crate) fn as_slice(&self) -> &[u8] {
match self {
Self::Lent(bytes) => bytes,
Self::Owned(buf) => buf,
}
}
fn to_mut(&mut self) -> &mut BytesMut {
if let Self::Lent(bytes) = *self {
*self = Self::Owned(BytesMut::from(bytes));
}
match self {
Self::Owned(buf) => buf,
Self::Lent(_) => unreachable!(),
}
}
}
impl<'a> Outgoing<'a> {
#[must_use]
pub fn new(name: impl Into<OutgoingName<'a>>, payload: impl Into<BytesMut>) -> Self {
Self {
name: name.into(),
payload: Payload::Owned(payload.into()),
headers: HeaderMap::new(),
}
}
#[inline]
pub(crate) fn rebuilding(
name: impl Into<OutgoingName<'a>>,
payload: Payload<'a>,
headers: HeaderMap,
) -> Self {
Self {
name: name.into(),
payload,
headers,
}
}
#[must_use]
pub fn name(&self) -> &str {
&self.name
}
pub fn set_name(&mut self, name: impl Into<OutgoingName<'a>>) {
self.name = name.into();
}
#[must_use]
pub fn payload(&self) -> &[u8] {
self.payload.as_slice()
}
pub fn payload_mut(&mut self) -> &mut BytesMut {
self.payload.to_mut()
}
pub fn set_payload(&mut self, payload: impl Into<BytesMut>) {
self.payload = Payload::Owned(payload.into());
}
#[inline]
pub(crate) fn take_payload(&mut self) -> BytesMut {
match mem::replace(&mut self.payload, Payload::Lent(&[])) {
Payload::Lent(bytes) => BytesMut::from(bytes),
Payload::Owned(buf) => buf,
}
}
#[must_use]
pub fn headers(&self) -> &HeaderMap {
&self.headers
}
pub fn headers_mut(&mut self) -> &mut HeaderMap {
&mut self.headers
}
#[inline]
pub(crate) fn into_parts(self) -> (OutgoingName<'a>, Payload<'a>, HeaderMap) {
(self.name, self.payload, self.headers)
}
#[inline]
pub(crate) fn take_headers(&mut self) -> HeaderMap {
mem::take(&mut self.headers)
}
}
mod sealed {
pub trait Sealed {}
impl<P, C, PL, BL> Sealed for super::TypedPublisher<P, C, PL, BL> {}
impl<P, C, PL, BL> Sealed for super::Transactional<P, C, PL, BL> {}
}
mod builder;
mod ext;
mod form;
mod out;
mod pipeline;
mod publisher;
mod reply;
mod sink;
mod transaction;
mod transform;
mod wiring;
pub(crate) use builder::message_of;
#[cfg(test)]
pub(crate) use builder::raw_of;
pub use builder::{
BoundSegment, EncodeOutcome, EncodedWire, HeaderSource, HeadersUnset, MapHeaders, MessageBody,
MessageWire, MissingSegment, PayloadError, PublishAt, PublishBuilder, PublishError,
PublishHeaders, ResolvedName, SatisfiesContract, SerializePayloadError, Serialized,
SerializedWire, SuppliedName, TemplateAddress, TypedHeaders, WireBytes, WirePayload,
};
pub use ext::PublishExt;
pub use out::{
LowerOutTransforms, NamedDestinationSend, NarrowToUse, OutPipeline, PipelinePublishError,
SendOnlyPolicy, SlotStackUse, SlotTransforms,
};
pub use pipeline::{
PublishDynLayer, PublishDynNext, PublishDynStack, PublishIdentity, PublishLayer, PublishNext,
PublishPipeline, PublishStack,
};
pub use publisher::{Transactional, TypedPublisher};
pub use reply::ReplyPublisher;
pub use sink::{CallCodec, PublishCodec, PublishSink, UnnamedCodec};
pub use transaction::{
Admits, AnyDeclared, TransactionPublishError, TransactionScope, TypedTransaction,
};
pub use transform::{
BatchPublishTransform, BatchPublishTransformStack, BatchTransformIdentity, ContextKind,
DestinationSettled, DestinationUse, Either, FitsOffer, FitsTaken, ForBatch, ForReply, ForSlot,
Names, NamesDestination, NamingOffered, NamingUntaken, PublishContext, PublishTransform,
PublishTransformIdentity, PublishTransformStack, Reads, SlotContext, for_batch,
};
pub use wiring::{
AddBatchReplyTransform, AddReplyTransform, CodecSlotOpen, Direct, InTransaction,
MapReplyPolicy, NameReplyCodec, PublishingDirectly, RawReplyWiring, ReplyWiring,
TransactionalReply,
};
#[cfg(test)]
mod tests;