use std::boxed::Box as StdBox;
use std::vec::Vec as StdVec;
pub trait Emitter<Message>: Send + Sync {
type Output;
fn emit(&self, message: &Message) -> Self::Output;
fn emit_all(&self, messages: &[Message]) -> Self::Output;
fn name(&self) -> &'static str;
}
impl<Message, Output, T> Emitter<Message> for StdBox<T>
where
T: Emitter<Message, Output = Output> + ?Sized,
{
type Output = Output;
fn emit(&self, message: &Message) -> Self::Output {
self.as_ref().emit(message)
}
fn emit_all(&self, messages: &[Message]) -> Self::Output {
self.as_ref().emit_all(messages)
}
fn name(&self) -> &'static str {
self.as_ref().name()
}
}
pub struct Telegraph<Message, Output> {
emitters: StdVec<StdBox<dyn Emitter<Message, Output = Output>>>,
}
impl<Message, Output> Telegraph<Message, Output> {
pub fn new() -> Self {
Self {
emitters: StdVec::new(),
}
}
pub fn add_emitter<E>(&mut self, emitter: E)
where
E: Emitter<Message, Output = Output> + 'static,
{
self.emitters.push(StdBox::new(emitter));
}
pub fn add_boxed_emitter(&mut self, emitter: StdBox<dyn Emitter<Message, Output = Output>>) {
self.emitters.push(emitter);
}
pub fn len(&self) -> usize {
self.emitters.len()
}
pub fn is_empty(&self) -> bool {
self.emitters.is_empty()
}
pub fn transmit(&self, message: &Message) -> StdVec<Output> {
self.emitters
.iter()
.map(|emitter| emitter.emit(message))
.collect()
}
pub fn transmit_all(&self, messages: &[Message]) -> StdVec<Output> {
self.emitters
.iter()
.map(|emitter| emitter.emit_all(messages))
.collect()
}
}
impl<Message, Output> Default for Telegraph<Message, Output> {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::{Emitter, Telegraph};
use std::string::String;
#[derive(Debug, Clone)]
struct Message(&'static str);
struct PrefixEmitter(&'static str);
impl Emitter<Message> for PrefixEmitter {
type Output = String;
fn emit(&self, message: &Message) -> Self::Output {
let mut output = String::from(self.0);
output.push_str(message.0);
output
}
fn emit_all(&self, messages: &[Message]) -> Self::Output {
let mut output = String::from(self.0);
for message in messages {
if !output.ends_with(':') {
output.push(',');
}
output.push_str(message.0);
}
output
}
fn name(&self) -> &'static str {
self.0
}
}
#[test]
fn transmits_one_message_to_all_emitters() {
let mut telegraph = Telegraph::new();
telegraph.add_emitter(PrefixEmitter("a:"));
telegraph.add_emitter(PrefixEmitter("b:"));
let outputs = telegraph.transmit(&Message("ping"));
assert_eq!(outputs, ["a:ping", "b:ping"]);
}
#[test]
fn transmits_batches_to_all_emitters() {
let mut telegraph = Telegraph::new();
telegraph.add_emitter(PrefixEmitter("batch:"));
let outputs = telegraph.transmit_all(&[Message("one"), Message("two")]);
assert_eq!(outputs, ["batch:one,two"]);
}
}