use std::borrow::Cow;
use std::fmt;
use serde::{Deserialize, Serialize};
use super::{DOMAIN_EVENT_BODY_CODEC, DOMAIN_EVENT_BODY_CODEC_VERSION};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum DomainEventBodyKind {
State,
Event,
Deletion,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct DomainEventBodyDescriptor {
pub kind: DomainEventBodyKind,
pub type_name: Cow<'static, str>,
pub version: u64,
pub schema: Cow<'static, str>,
pub fingerprint: Cow<'static, str>,
pub codec: Cow<'static, str>,
pub codec_version: u16,
}
impl DomainEventBodyDescriptor {
pub const fn distributed_json(
kind: DomainEventBodyKind,
type_name: &'static str,
version: u64,
schema: &'static str,
fingerprint: &'static str,
) -> Self {
Self {
kind,
type_name: Cow::Borrowed(type_name),
version,
schema: Cow::Borrowed(schema),
fingerprint: Cow::Borrowed(fingerprint),
codec: Cow::Borrowed(DOMAIN_EVENT_BODY_CODEC),
codec_version: DOMAIN_EVENT_BODY_CODEC_VERSION,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct DomainStateDescriptor {
pub type_name: Cow<'static, str>,
pub version: u64,
pub schema: Cow<'static, str>,
pub fingerprint: Cow<'static, str>,
pub codec: Cow<'static, str>,
pub codec_version: u16,
}
impl DomainStateDescriptor {
pub const fn distributed_json(
type_name: &'static str,
version: u64,
schema: &'static str,
fingerprint: &'static str,
) -> Self {
Self {
type_name: Cow::Borrowed(type_name),
version,
schema: Cow::Borrowed(schema),
fingerprint: Cow::Borrowed(fingerprint),
codec: Cow::Borrowed(DOMAIN_EVENT_BODY_CODEC),
codec_version: DOMAIN_EVENT_BODY_CODEC_VERSION,
}
}
pub fn event(self, name: impl Into<Cow<'static, str>>, version: u64) -> DomainEventDescriptor {
DomainEventDescriptor {
name: name.into(),
version,
body: self.into(),
}
}
}
impl From<DomainStateDescriptor> for DomainEventBodyDescriptor {
fn from(state: DomainStateDescriptor) -> Self {
Self {
kind: DomainEventBodyKind::State,
type_name: state.type_name,
version: state.version,
schema: state.schema,
fingerprint: state.fingerprint,
codec: state.codec,
codec_version: state.codec_version,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct DomainEventDescriptor {
pub name: Cow<'static, str>,
pub version: u64,
pub body: DomainEventBodyDescriptor,
}
impl DomainEventDescriptor {
pub fn state<S: DomainState>(name: impl Into<Cow<'static, str>>, version: u64) -> Self {
S::DESCRIPTOR.clone().event(name, version)
}
}
pub trait DomainState: Serialize {
const DESCRIPTOR: DomainStateDescriptor;
}
pub trait DomainEvent: Serialize {
const DESCRIPTOR: DomainEventDescriptor;
}
#[doc(hidden)]
pub trait DomainEventContract {
const EVENT_NAME: &'static str;
const EVENT_VERSION: u64;
fn descriptor() -> DomainEventDescriptor;
}
#[doc(hidden)]
pub trait DomainEventBodyContract<B: Serialize>: DomainEventContract {}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct DomainDeletion<K> {
pub key: K,
pub incarnation: u64,
}
impl<K> DomainDeletion<K> {
pub fn new(key: K, incarnation: u64) -> Result<Self, DomainDeletionError> {
if incarnation == 0 {
return Err(DomainDeletionError);
}
Ok(Self { key, incarnation })
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct DomainDeletionError;
impl fmt::Display for DomainDeletionError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("domain deletion incarnation must be non-zero")
}
}
impl std::error::Error for DomainDeletionError {}