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::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};

#[derive(Debug)]
pub(super) struct Limit {
    capacity: usize,
    held: AtomicUsize,
}

impl Limit {
    pub(super) const fn new(capacity: usize) -> Self {
        Self {
            capacity,
            held: AtomicUsize::new(0),
        }
    }

    pub(super) fn enter(self: &Arc<Self>) -> Option<Permit> {
        let mut held = self.held.load(Ordering::Acquire);
        loop {
            if held >= self.capacity {
                return None;
            }
            match self.held.compare_exchange_weak(
                held,
                held + 1,
                Ordering::AcqRel,
                Ordering::Acquire,
            ) {
                Ok(_) => return Some(Permit(Arc::clone(self))),
                Err(current) => held = current,
            }
        }
    }
}

pub(super) struct Permit(Arc<Limit>);

impl Drop for Permit {
    fn drop(&mut self) {
        self.0.held.fetch_sub(1, Ordering::Release);
    }
}