use crate::ack::AckType;
use crate::error::{AckIdError, AttachmentsError};
use bytes::Bytes;
use std::fmt::DebugMap;
use std::marker::PhantomData;
pub trait AckMarker {
type Id: Sized;
fn parse(id: Option<u64>) -> Result<Self::Id, AckIdError>;
fn format(id: &Self::Id, map: &mut DebugMap<'_, '_>);
}
#[derive(Debug)]
pub struct NoAck;
impl AckMarker for NoAck {
type Id = ();
fn parse(id: Option<u64>) -> Result<Self::Id, AckIdError> {
match id {
Some(_) => Err(AckIdError::Unexpected),
None => Ok(()),
}
}
fn format(_id: &Self::Id, _map: &mut DebugMap<'_, '_>) {}
}
#[derive(Debug)]
pub struct HasAck<A>(PhantomData<A>);
impl<A> AckMarker for HasAck<A>
where
A: AckType,
{
type Id = AckId<A>;
fn parse(id: Option<u64>) -> Result<Self::Id, AckIdError> {
id.map(AckId::new).ok_or(AckIdError::Missing)
}
fn format(id: &Self::Id, map: &mut DebugMap<'_, '_>) {
map.entry(&"id", &id.0);
}
}
#[must_use = "AckId must be used to acknowledge the event"]
pub struct AckId<A>(u64, PhantomData<A>);
impl<A> std::fmt::Debug for AckId<A> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("AckId").field(&self.0).finish()
}
}
impl<A> AckId<A> {
fn new(id: u64) -> Self {
Self(id, PhantomData)
}
pub fn get(self) -> u64 {
self.0
}
}
pub trait BinaryMarker {
type Attachments: Sized;
fn parse(attachment: Option<Vec<Bytes>>) -> Result<Self::Attachments, AttachmentsError>;
fn get(attachments: Self::Attachments) -> Option<Vec<Bytes>>;
fn format(attachments: &Self::Attachments, map: &mut DebugMap<'_, '_>);
}
#[derive(Debug)]
pub struct HasBinary;
#[derive(Debug)]
pub struct NoBinary;
impl BinaryMarker for NoBinary {
type Attachments = ();
fn parse(attachment: Option<Vec<Bytes>>) -> Result<Self::Attachments, AttachmentsError> {
match attachment {
Some(_) => Err(AttachmentsError::Unexpected),
None => Ok(()),
}
}
fn get(_attachments: Self::Attachments) -> Option<Vec<Bytes>> {
None
}
fn format(_attachments: &Self::Attachments, _map: &mut DebugMap<'_, '_>) {}
}
impl BinaryMarker for HasBinary {
type Attachments = Vec<Bytes>;
fn parse(attachment: Option<Vec<Bytes>>) -> Result<Self::Attachments, AttachmentsError> {
attachment.ok_or(AttachmentsError::Missing)
}
fn get(attachments: Self::Attachments) -> Option<Vec<Bytes>> {
Some(attachments)
}
fn format(attachments: &Self::Attachments, map: &mut DebugMap<'_, '_>) {
map.entry(&"count", &attachments.len());
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn no_binary_parse_none_succeeds() {
assert!(NoBinary::parse(None).is_ok());
}
#[test]
fn no_binary_parse_some_fails() {
let attachments = Some(vec![Bytes::from_static(b"data")]);
assert!(NoBinary::parse(attachments).is_err());
}
#[test]
fn no_binary_get_returns_none() {
assert!(NoBinary::get(()).is_none());
}
#[test]
fn has_binary_parse_some_succeeds() {
let input = vec![Bytes::from_static(b"a"), Bytes::from_static(b"b")];
let parsed = HasBinary::parse(Some(input.clone())).unwrap();
assert_eq!(parsed.len(), 2);
assert_eq!(parsed[0], input[0]);
}
#[test]
fn has_binary_parse_none_fails() {
assert!(HasBinary::parse(None).is_err());
}
#[test]
fn has_binary_get_returns_some() {
let input = vec![Bytes::from_static(b"x")];
let result = HasBinary::get(input.clone());
assert_eq!(result.unwrap(), input);
}
#[test]
fn no_ack_parse_none_succeeds() {
assert!(NoAck::parse(None).is_ok());
}
#[test]
fn no_ack_parse_some_fails() {
assert!(NoAck::parse(Some(42)).is_err());
}
#[test]
fn has_ack_parse_some_succeeds() {
let id = <HasAck<()>>::parse(Some(7)).unwrap();
assert_eq!(id.get(), 7);
}
#[test]
fn has_ack_parse_none_fails() {
assert!(<HasAck<()>>::parse(None).is_err());
}
}