use super::ShutdownSignal;
use futures::future::select_all;
use std::pin::Pin;
pub struct CompositeSignal {
signals: Vec<Box<dyn ShutdownSignal>>,
name: String,
}
impl CompositeSignal {
pub fn new() -> Self {
Self {
signals: Vec::new(),
name: "composite".to_string(),
}
}
pub fn from_signals(signals: Vec<Box<dyn ShutdownSignal>>) -> Self {
Self {
signals,
name: "composite".to_string(),
}
}
#[allow(clippy::should_implement_trait)]
pub fn add(mut self, signal: Box<dyn ShutdownSignal>) -> Self {
self.signals.push(signal);
self
}
pub fn with_name(mut self, name: impl Into<String>) -> Self {
self.name = name.into();
self
}
}
impl Default for CompositeSignal {
fn default() -> Self {
Self::new()
}
}
impl ShutdownSignal for CompositeSignal {
fn wait(&mut self) -> Pin<Box<dyn std::future::Future<Output = ()> + Send + '_>> {
if self.signals.is_empty() {
return Box::pin(std::future::pending::<()>());
}
let futures: Vec<_> = self.signals.iter_mut().map(|s| s.wait()).collect();
if futures.is_empty() {
return Box::pin(std::future::pending::<()>());
}
Box::pin(async move {
let (result, _index, _others) = select_all(futures).await;
result
})
}
fn name(&self) -> &str {
&self.name
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::signal::CtrlCSignal;
#[test]
fn test_composite_signal_new() {
let signal = CompositeSignal::new();
assert_eq!(signal.name(), "composite");
}
#[test]
fn test_composite_signal_add() {
let signal = CompositeSignal::new()
.add(Box::new(CtrlCSignal::new()))
.add(Box::new(CtrlCSignal::new()));
assert_eq!(signal.name(), "composite");
}
#[test]
fn test_composite_signal_from_signals() {
let signal = CompositeSignal::from_signals(vec![
Box::new(CtrlCSignal::new()),
Box::new(CtrlCSignal::new()),
]);
assert_eq!(signal.name(), "composite");
}
}