nuts 0.2.1

Nuts is a library that offers a simple publish-subscribe API, featuring decoupled creation of the publisher and the subscriber.
Documentation
use std::{future::Future, task::Poll};

use crate::nut::Nut;

#[derive(Default)]
pub(crate) struct ResponseTracker {
    slots: Vec<SlotState>,
}

enum SlotState {
    Available,
    Occupied,
    Done,
}

pub(crate) struct Slot(usize);

#[allow(clippy::single_match)]
impl ResponseTracker {
    pub fn allocate(&mut self) -> Slot {
        for (i, slot) in self.slots.iter_mut().enumerate() {
            match slot {
                SlotState::Available => {
                    *slot = SlotState::Occupied;
                    return Slot(i);
                }
                _ => {}
            }
        }
        let i = self.slots.len();
        self.slots.push(SlotState::Occupied);
        Slot(i)
    }
    pub fn done(&mut self, slot: &Slot) {
        self.slots[slot.0] = SlotState::Done;
    }
    fn free(&mut self, index: usize) {
        self.slots[index] = SlotState::Available;
    }
}

pub struct NutsResponse {
    index: usize,
}

impl NutsResponse {
    pub(crate) fn new(slot: &Slot) -> Self {
        Self { index: slot.0 }
    }
}

impl Future for NutsResponse {
    type Output = ();

    fn poll(
        self: std::pin::Pin<&mut Self>,
        _cx: &mut std::task::Context<'_>,
    ) -> Poll<Self::Output> {
        Nut::with_response_tracker_mut(|response_tracker| {
            match response_tracker.slots[self.index] {
                SlotState::Available => panic!("Corrupted futures State"),
                SlotState::Occupied => Poll::Pending,
                SlotState::Done => {
                    response_tracker.free(self.index);
                    Poll::Ready(())
                }
            }
        })
    }
}