use std::future::Future;
use super::{Message, TransportError};
pub trait AsyncMessagePublisher: Send + Sync {
fn publish(
&self,
message: Message,
) -> impl Future<Output = Result<(), TransportError>> + Send + '_;
#[allow(clippy::manual_async_fn)]
fn publish_batch(
&self,
messages: Vec<Message>,
) -> impl Future<Output = Result<(), TransportError>> + Send + '_ {
async move {
for message in messages {
self.publish(message).await?;
}
Ok(())
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::bus::MessageKind;
use std::future::Future;
use std::sync::Mutex;
fn block_on<F: Future>(future: F) -> F::Output {
use std::ptr;
use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
const VTABLE: RawWakerVTable = RawWakerVTable::new(
|_| RawWaker::new(ptr::null(), &VTABLE),
|_| {},
|_| {},
|_| {},
);
let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &VTABLE)) };
let mut cx = Context::from_waker(&waker);
let mut future = std::pin::pin!(future);
loop {
if let Poll::Ready(output) = future.as_mut().poll(&mut cx) {
return output;
}
}
}
struct CountingPublisher {
published: Mutex<Vec<String>>,
fail_at: Option<usize>,
}
impl AsyncMessagePublisher for CountingPublisher {
async fn publish(&self, message: Message) -> Result<(), TransportError> {
let mut published = self.published.lock().unwrap();
if self.fail_at == Some(published.len()) {
return Err(TransportError::retryable("publish failed"));
}
published.push(message.name().to_string());
Ok(())
}
}
fn msg(name: &str) -> Message {
Message::new(name, MessageKind::Event, b"{}".to_vec())
}
#[test]
fn publish_batch_publishes_all_on_success() {
let publisher = CountingPublisher {
published: Mutex::new(Vec::new()),
fail_at: None,
};
block_on(publisher.publish_batch(vec![msg("a"), msg("b"), msg("c")])).unwrap();
assert_eq!(*publisher.published.lock().unwrap(), vec!["a", "b", "c"]);
}
#[test]
fn publish_batch_stops_at_first_error_with_partial_progress() {
let publisher = CountingPublisher {
published: Mutex::new(Vec::new()),
fail_at: Some(1), };
let result = block_on(publisher.publish_batch(vec![msg("a"), msg("b"), msg("c")]));
assert!(result.is_err());
assert_eq!(*publisher.published.lock().unwrap(), vec!["a"]);
}
}