use crate::envelope::metadata::MetaData;
use crate::envelope::{Correlation, ReceivedAt};
use crate::id::IdGenerator;
use crate::{Entity, Id, Label, Labeling};
#[cfg(feature = "functional")]
use frunk::{Monoid, Semigroup};
use iso8601_timestamp::Timestamp;
use pretty_type_name::pretty_type_name;
use serde::{Deserialize, Serialize, Serializer, de, ser::SerializeStruct};
use std::fmt;
use std::future::Future;
use std::marker::PhantomData;
pub trait IntoEnvelope {
type Content: Label;
type IdGen: IdGenerator;
fn into_envelope(self) -> Envelope<Self::Content, <Self::IdGen as IdGenerator>::IdType>;
fn metadata(&self) -> &MetaData<Self::Content, <Self::IdGen as IdGenerator>::IdType>;
}
#[derive(Clone)]
pub struct Envelope<T, ID>
where
T: ?Sized,
{
metadata: MetaData<T, ID>,
content: T,
}
impl<T, ID> fmt::Debug for Envelope<T, ID>
where
T: fmt::Debug,
ID: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&format!("[{}]{{ {:?} }}", self.metadata, self.content))
}
}
impl<T, ID> fmt::Display for Envelope<T, ID>
where
T: fmt::Display,
ID: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[{}]({})", self.metadata, self.content)
}
}
impl<E> Envelope<E, <<E as Entity>::IdGen as IdGenerator>::IdType>
where
E: Entity,
{
pub fn from_entity(content: E) -> Self {
Self {
metadata: MetaData::default(),
content,
}
}
}
impl<T, ID> Envelope<T, ID>
where
T: Label,
{
pub fn new<G>(content: T) -> Self
where
G: IdGenerator<IdType = ID>,
{
let correlation_id = Id::direct(T::labeler().label(), G::next_id_rep());
Self {
metadata: MetaData::from_parts(correlation_id, Timestamp::now_utc(), None),
content,
}
}
}
impl<T, ID> Envelope<T, ID> {
pub const fn direct(content: T, metadata: MetaData<T, ID>) -> Self {
Self { metadata, content }
}
pub const fn metadata(&self) -> &MetaData<T, ID> {
&self.metadata
}
#[allow(clippy::missing_const_for_fn)]
#[inline]
pub fn into_inner(self) -> T {
self.content
}
#[allow(clippy::missing_const_for_fn)]
#[inline]
pub fn into_parts(self) -> (MetaData<T, ID>, T) {
(self.metadata, self.content)
}
#[inline]
pub const fn from_parts(metadata: MetaData<T, ID>, content: T) -> Self {
Self { metadata, content }
}
}
impl<T, ID> Envelope<T, ID>
where
T: Label,
ID: Clone,
{
pub fn adopt_metadata<U>(&mut self, new_metadata: MetaData<U, ID>) -> MetaData<T, ID>
where
U: Label,
{
let old_metadata = self.metadata.clone();
self.metadata = new_metadata.relabel();
old_metadata
}
pub fn map<F, U>(self, f: F) -> Envelope<U, ID>
where
U: Label,
F: FnOnce(T) -> U,
{
let metadata = self.metadata.clone().relabel();
Envelope {
metadata,
content: f(self.content),
}
}
pub fn flat_map<F, U>(self, f: F) -> Envelope<U, ID>
where
U: Label,
F: FnOnce(Self) -> U,
{
let metadata = self.metadata.clone().relabel();
Envelope {
metadata,
content: f(self),
}
}
}
impl<T, ID> Envelope<T, ID>
where
T: Label + Send,
ID: Clone + Send,
{
pub async fn and_then<Op, Fut, U>(self, f: Op) -> Envelope<U, ID>
where
U: Label + Send,
Fut: Future<Output = U> + Send,
Op: FnOnce(T) -> Fut + Send,
{
let metadata = self.metadata.clone().relabel();
Envelope {
metadata,
content: f(self.content).await,
}
}
}
impl<E> Correlation for Envelope<E, <<E as Entity>::IdGen as IdGenerator>::IdType>
where
E: Entity + Sync,
{
type Correlated = E;
type IdType = <<E as Entity>::IdGen as IdGenerator>::IdType;
fn correlation(&self) -> &Id<Self::Correlated, Self::IdType> {
self.metadata.correlation()
}
}
impl<T, ID> ReceivedAt for Envelope<T, ID> {
fn recv_timestamp(&self) -> Timestamp {
self.metadata.recv_timestamp()
}
}
impl<T, ID> Label for Envelope<T, ID>
where
T: Label,
{
type Labeler = <T as Label>::Labeler;
fn labeler() -> Self::Labeler {
<T as Label>::labeler()
}
}
impl<T, ID> std::ops::Add for Envelope<T, ID>
where
T: std::ops::Add<Output = T>,
ID: PartialOrd,
{
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self::from_parts(self.metadata + rhs.metadata, self.content + rhs.content)
}
}
#[cfg(feature = "functional")]
impl<E> Monoid for Envelope<E, <<E as Entity>::IdGen as IdGenerator>::IdType>
where
E: Entity + Monoid,
<<E as Entity>::IdGen as IdGenerator>::IdType: PartialOrd + Clone,
{
fn empty() -> Self {
Self::from_parts(
<MetaData<E, <<E as Entity>::IdGen as IdGenerator>::IdType> as Monoid>::empty(),
<E as Monoid>::empty(),
)
}
}
#[cfg(feature = "functional")]
impl<E> Semigroup for Envelope<E, <<E as Entity>::IdGen as IdGenerator>::IdType>
where
E: Entity + Semigroup,
<<E as Entity>::IdGen as IdGenerator>::IdType: PartialOrd + Clone,
{
fn combine(&self, other: &Self) -> Self {
Self::from_parts(
self.metadata().combine(other.metadata()),
self.content.combine(&other.content),
)
}
}
impl<E> IntoEnvelope for Envelope<E, <<E as Entity>::IdGen as IdGenerator>::IdType>
where
E: Entity,
{
type Content = E;
type IdGen = <E as Entity>::IdGen;
fn into_envelope(self) -> Envelope<Self::Content, <Self::IdGen as IdGenerator>::IdType> {
self
}
fn metadata(&self) -> &MetaData<Self::Content, <Self::IdGen as IdGenerator>::IdType> {
&self.metadata
}
}
impl<T, ID> std::ops::Deref for Envelope<T, ID> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.content
}
}
impl<T, ID> std::ops::DerefMut for Envelope<T, ID> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.content
}
}
impl<T, ID> AsRef<T> for Envelope<T, ID> {
fn as_ref(&self) -> &T {
&self.content
}
}
impl<T, ID> AsMut<T> for Envelope<T, ID> {
fn as_mut(&mut self) -> &mut T {
&mut self.content
}
}
impl<T, ID> PartialEq for Envelope<T, ID>
where
T: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.content == other.content
}
}
impl<T, ID> PartialEq<T> for Envelope<T, ID>
where
T: PartialEq,
{
fn eq(&self, other: &T) -> bool {
&self.content == other
}
}
impl<T, ID> Envelope<Option<T>, ID>
where
T: Label,
ID: Clone,
{
#[inline]
pub fn transpose(self) -> Option<Envelope<T, ID>> {
match self.content {
Some(d) => Some(Envelope {
content: d,
metadata: self.metadata.relabel(),
}),
None => None,
}
}
}
impl<T, E, ID> Envelope<Result<T, E>, ID>
where
T: Label,
ID: Clone,
{
#[inline]
pub fn transpose(self) -> Result<Envelope<T, ID>, E> {
match self.content {
Ok(content) => Ok(Envelope {
content,
metadata: self.metadata.relabel(),
}),
Err(e) => Err(e),
}
}
}
const ENV_METADATA: &str = "metadata";
const ENV_CONTENT: &str = "content";
const FIELDS: [&str; 2] = [ENV_METADATA, ENV_CONTENT];
impl<T, ID> Serialize for Envelope<T, ID>
where
T: Serialize,
ID: Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_struct("Envelope", 2)?;
state.serialize_field(ENV_METADATA, &self.metadata)?;
state.serialize_field(ENV_CONTENT, &self.content)?;
state.end()
}
}
impl<'de, T, ID> Deserialize<'de> for Envelope<T, ID>
where
T: Label + de::DeserializeOwned,
ID: de::DeserializeOwned,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
enum Field {
MetaData,
Content,
}
impl<'de> Deserialize<'de> for Field {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct FieldVisitor;
impl de::Visitor<'_> for FieldVisitor {
type Value = Field;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("`metadata` or `content`")
}
fn visit_str<E>(self, value: &str) -> Result<Field, E>
where
E: de::Error,
{
match value {
ENV_METADATA => Ok(Field::MetaData),
ENV_CONTENT => Ok(Field::Content),
_ => Err(de::Error::unknown_field(value, &FIELDS)),
}
}
}
deserializer.deserialize_identifier(FieldVisitor)
}
}
struct EnvelopeVisitor<T0, ID0> {
marker: PhantomData<(T0, ID0)>,
}
impl<T0, ID0> EnvelopeVisitor<T0, ID0> {
pub const fn new() -> Self {
Self {
marker: PhantomData,
}
}
}
impl<'de, T0, ID0> de::Visitor<'de> for EnvelopeVisitor<T0, ID0>
where
T0: Label + de::DeserializeOwned,
ID0: de::DeserializeOwned,
{
type Value = Envelope<T0, ID0>;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(
format!(
"struct Envelope<{}, {}>",
pretty_type_name::<T0>(),
pretty_type_name::<ID0>(),
)
.as_str(),
)
}
fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
where
V: de::SeqAccess<'de>,
{
let metadata: MetaData<T0, ID0> = seq
.next_element()?
.ok_or_else(|| de::Error::invalid_length(0, &self))?;
let content: T0 = seq
.next_element()?
.ok_or_else(|| de::Error::invalid_length(1, &self))?;
Ok(Envelope::from_parts(metadata, content))
}
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
where
V: de::MapAccess<'de>,
{
let mut metadata = None;
let mut content = None;
while let Some(key) = map.next_key()? {
match key {
Field::MetaData => {
if metadata.is_some() {
return Err(de::Error::duplicate_field(ENV_METADATA));
}
metadata = Some(map.next_value()?);
}
Field::Content => {
if content.is_some() {
return Err(de::Error::duplicate_field(ENV_CONTENT));
}
content = Some(map.next_value()?);
}
}
}
let metadata: MetaData<T0, ID0> =
metadata.ok_or_else(|| de::Error::missing_field(ENV_METADATA))?;
let content: T0 = content.ok_or_else(|| de::Error::missing_field(ENV_CONTENT))?;
Ok(Envelope::from_parts(metadata, content))
}
}
deserializer.deserialize_struct("Envelope", &FIELDS, EnvelopeVisitor::<T, ID>::new())
}
}