Extremely barebones IRC server project for learning Rust.
use futures::prelude::*;
use futures::stream::FuturesUnordered;
use log::info;
use std::collections::HashMap;
use tokio::signal::unix::{signal, SignalKind};
use tokio::sync::broadcast::Sender;

pub struct SignalGuard {}

impl SignalGuard {
    pub async fn wait_for_stop(signal_forwarder: &Sender<i32>) -> Option<()> {
        // Default behavior in UNIX is to terminate process when any of the
        // following signals are received. In each of these case we initiate
        // the controlled shutdown.
        let mut interrupt_stream = signal(SignalKind::interrupt()).ok()?;
        let mut terminate_stream = signal(SignalKind::terminate()).ok()?;
        let mut alarm_stream = signal(SignalKind::alarm()).ok()?;
        let mut hangup_stream = signal(SignalKind::hangup()).ok()?;
        let mut quit_stream = signal(SignalKind::quit()).ok()?;
        let mut user_defined1_stream = signal(SignalKind::user_defined1()).ok()?;
        let mut user_defined2_stream = signal(SignalKind::user_defined2()).ok()?;

        let interrupt_future = interrupt_stream.recv();
        let terminate_future = terminate_stream.recv();
        let alarm_future = alarm_stream.recv();
        let hangup_future = hangup_stream.recv();
        let quit_future = quit_stream.recv();
        let user_defined1_future = user_defined1_stream.recv();
        let user_defined2_future = user_defined2_stream.recv();

        let all_futures = vec![
            interrupt_future,
            terminate_future,
            alarm_future,
            hangup_future,
            quit_future,
            user_defined1_future,
            user_defined2_future,
        ];

        let mut signal_map = HashMap::with_capacity(all_futures.len());

        signal_map.insert(0, SignalKind::interrupt().as_raw_value());
        signal_map.insert(1, SignalKind::terminate().as_raw_value());
        signal_map.insert(2, SignalKind::alarm().as_raw_value());
        signal_map.insert(3, SignalKind::hangup().as_raw_value());
        signal_map.insert(4, SignalKind::quit().as_raw_value());
        signal_map.insert(5, SignalKind::user_defined1().as_raw_value());
        signal_map.insert(6, SignalKind::user_defined2().as_raw_value());

        let all_futures = all_futures
            .into_iter()
            .enumerate()
            .map(|(i, fut)| fut.map(move |res| (i, res)))
            .collect::<FuturesUnordered<_>>();

        // use collection as a stream, await only first 1 future to complete
        let first_one = all_futures.take(1).collect::<Vec<_>>().await;
        let signal_index = first_one[0].0;

        // Currently we mask all signals to SIGTERM.
        let received = signal_map[&signal_index];

        info!("SIGNAL_GUARD: RECEIVED CODE {} FROM OS", received);

        signal_forwarder.send(received).unwrap();

        Option::Some(())
    }
}