use std::{
error::Error,
fmt::Debug,
hash::Hash,
marker::PhantomData,
sync::{
Arc,
atomic::{AtomicU64, Ordering},
},
};
use async_trait::async_trait;
use once_cell::sync::Lazy;
use super::traits::{Event, EventConsumer};
mod waiter;
pub use waiter::{Trigger, Waiter};
pub enum Either<A, B> {
Happy(A),
Sad(B),
}
#[derive(PartialEq, Eq, Ord, PartialOrd, Debug, Hash)]
pub struct CompletionToken(Arc<u64>);
impl CompletionToken {
pub fn new() -> (CompletionToken, CompletionToken) {
static COUNTER: Lazy<AtomicU64> = Lazy::new(|| AtomicU64::new(0));
let value = Arc::new(COUNTER.fetch_add(1, Ordering::SeqCst));
(CompletionToken(value.clone()), CompletionToken(value))
}
pub fn count(&self) -> usize {
let count = Arc::strong_count(&self.0);
debug_assert!(
count <= 2,
"A CompletionToken has been illegally duplicated, copies: {} maximum: 2. \
This is a bug, please file a bug report.",
count
);
count
}
}
pub struct DynamicError(Box<dyn Error + Send + Sync>);
impl std::fmt::Display for DynamicError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(&self.0, f)
}
}
impl std::fmt::Debug for DynamicError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
#[allow(deprecated)]
impl Error for DynamicError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
self.0.source()
}
fn description(&self) -> &str {
self.0.description()
}
fn cause(&self) -> Option<&dyn Error> {
self.0.cause()
}
}
pub struct DynamicConsumer<E: Event, C: EventConsumer<E>> {
inner: C,
_event: PhantomData<E>,
}
impl<E: Event, C: EventConsumer<E>> From<C> for DynamicConsumer<E, C> {
fn from(inner: C) -> Self {
Self {
inner,
_event: PhantomData,
}
}
}
#[async_trait]
impl<E: Event, C: EventConsumer<E>> EventConsumer<E> for DynamicConsumer<E, C> {
type Error = DynamicError;
async fn accept(&self, event: E) -> Result<(), Self::Error> {
match self.inner.accept(event).await {
Ok(_) => Ok(()),
Err(e) => Err(DynamicError(Box::new(e))),
}
}
fn accept_sync(&self, event: E) -> Result<(), Self::Error> {
match self.inner.accept_sync(event) {
Ok(_) => Ok(()),
Err(e) => Err(DynamicError(Box::new(e))),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn completion_token_ref_counting() {
let (token_1, token_2) = CompletionToken::new();
assert_eq!(token_1.count(), 2);
assert_eq!(token_2.count(), 2);
std::mem::drop(token_2);
assert_eq!(token_1.count(), 1);
}
#[test]
fn token_self_equality() {
let (token_a, token_b) = CompletionToken::new();
assert_eq!(token_a, token_b);
}
#[test]
fn token_non_equal() {
let (token_a, _) = CompletionToken::new();
let (token_b, _) = CompletionToken::new();
assert_ne!(token_a, token_b);
}
}