use crate::observe::{Event, Interest, Observer};
pub(crate) struct Observers<'r> {
slots: [Option<(&'r dyn Observer, Interest)>; 2],
union: Interest,
timed_tasks: bool,
timed_workflows: bool,
}
impl<'r> Observers<'r> {
pub(crate) fn attach(engine: Option<&'r dyn Observer>, run: Option<&'r dyn Observer>) -> Self {
let slots = [engine, run].map(|o| o.map(|o| (o, o.interest())));
let union = slots
.iter()
.flatten()
.fold(Interest::NONE, |union, &(_, interest)| union | interest);
let timed = |kind: Interest| {
let both = kind | Interest::TIMINGS;
slots.iter().flatten().any(|&(_, i)| i.contains(both))
};
Self {
timed_tasks: timed(Interest::TASKS),
timed_workflows: timed(Interest::WORKFLOWS),
slots,
union,
}
}
pub(crate) fn timed(&self) -> bool {
self.union.contains(Interest::TIMINGS)
}
pub(crate) fn timed_tasks(&self) -> bool {
self.timed_tasks
}
pub(crate) fn timed_workflows(&self) -> bool {
self.timed_workflows
}
pub(crate) fn workflows(&self) -> bool {
self.union.contains(Interest::WORKFLOWS)
}
pub(crate) fn tasks(&self) -> bool {
self.union.contains(Interest::TASKS)
}
#[inline]
pub(crate) fn emit(&self, event: Event<'_>) {
if self.slots.iter().any(Option::is_some) {
self.deliver(event);
}
}
fn deliver(&self, event: Event<'_>) {
let wants = match event {
Event::RunStarted { .. } | Event::RunFinished { .. } => Interest::NONE,
Event::WorkflowStarted { .. } | Event::WorkflowFinished { .. } => Interest::WORKFLOWS,
Event::TaskFinished { .. } => Interest::TASKS,
};
for &(observer, interest) in self.slots.iter().flatten() {
if !interest.contains(wants) {
continue;
}
if interest.contains(Interest::TIMINGS) {
observer.on(&event);
} else {
observer.on(&untimed(&event));
}
}
}
}
fn untimed<'a>(event: &Event<'a>) -> Event<'a> {
match *event {
Event::RunStarted {
program,
message_id,
channel,
considered,
} => Event::RunStarted {
program,
message_id,
channel,
considered,
},
Event::WorkflowStarted { workflow, id } => Event::WorkflowStarted { workflow, id },
Event::TaskFinished { info, status, .. } => Event::TaskFinished {
info,
status,
elapsed: None,
},
Event::WorkflowFinished { record, .. } => Event::WorkflowFinished {
record,
elapsed: None,
},
Event::RunFinished {
message_id,
status,
errors,
..
} => Event::RunFinished {
message_id,
status,
errors,
elapsed: None,
},
}
}