haematite-cli 0.21.8

The haematite command: serve a store, its door and Studio, answer MCP, query with jq, and host the store's assistant seat
Documentation
use std::io;
use std::sync::{Arc, Condvar, Mutex};

#[derive(Default)]
pub(super) struct Gate {
    opened: Mutex<bool>,
    signal: Condvar,
}

impl Gate {
    pub(super) fn wait(&self) -> io::Result<()> {
        let mut opened = self
            .opened
            .lock()
            .map_err(|_| io::Error::other("fixture gate poisoned"))?;
        while !*opened {
            opened = self
                .signal
                .wait(opened)
                .map_err(|_| io::Error::other("fixture gate poisoned"))?;
        }
        drop(opened);
        Ok(())
    }

    pub(super) fn open(&self) -> io::Result<()> {
        let mut opened = self
            .opened
            .lock()
            .map_err(|_| io::Error::other("fixture gate poisoned"))?;
        *opened = true;
        drop(opened);
        self.signal.notify_all();
        Ok(())
    }
}

pub(super) struct Release(pub(super) Arc<Gate>);

impl Drop for Release {
    fn drop(&mut self) {
        if let Err(error) = self.0.open() {
            eprintln!("http_fixture_release_failed: {error}");
        }
    }
}