dope-net 0.8.1

The manifold runtime
Documentation
use super::config::Config;

pub(super) struct Credits {
    entries: Balance,
    bytes: Balance,
    held: Box<[Held]>,
}

#[derive(Clone, Copy, Default)]
struct Held {
    entries: usize,
    bytes: usize,
}

struct Debit {
    entries: usize,
    bytes: usize,
}

struct Reserve {
    base: usize,
    remainder: usize,
}

impl Reserve {
    fn new(total: usize, lanes: usize) -> Self {
        Self {
            base: total / lanes,
            remainder: total % lanes,
        }
    }

    fn get(&self, lane: usize) -> usize {
        self.base + usize::from(lane < self.remainder)
    }
}

struct Balance {
    available: usize,
    protected: usize,
    reserve: Reserve,
}

impl Balance {
    fn new(total: usize, reserved: usize, lanes: usize) -> Self {
        Self {
            available: total,
            protected: reserved,
            reserve: Reserve::new(reserved, lanes),
        }
    }

    fn debit(&self, lane: usize, held: usize, amount: usize) -> Option<usize> {
        if amount > self.available {
            return None;
        }
        let own = self.reserve.get(lane).saturating_sub(held).min(amount);
        (amount - own <= self.available - self.protected).then_some(own)
    }

    fn acquire(&mut self, amount: usize, own: usize) {
        self.available -= amount;
        self.protected -= own;
    }

    fn release(&mut self, lane: usize, held: usize, amount: usize) {
        let reserve = self.reserve.get(lane);
        let before = reserve.saturating_sub(held);
        let after = reserve.saturating_sub(held - amount);
        self.available += amount;
        self.protected += after - before;
    }
}

impl Credits {
    pub(super) fn with_config(config: Config, lanes: usize) -> Self {
        assert!(lanes > 0, "egress credit lanes must be positive");
        Self {
            entries: Balance::new(config.entries(), config.reserved_entries as usize, lanes),
            bytes: Balance::new(config.bytes(), config.reserved_bytes as usize, lanes),
            held: vec![Held::default(); lanes].into_boxed_slice(),
        }
    }

    pub(super) fn lanes(&self) -> usize {
        self.held.len()
    }

    fn debit(&self, lane: usize, held: Held, entries: usize, bytes: usize) -> Option<Debit> {
        Some(Debit {
            entries: self.entries.debit(lane, held.entries, entries)?,
            bytes: self.bytes.debit(lane, held.bytes, bytes)?,
        })
    }

    pub(super) fn acquire(&mut self, lane: usize, entries: usize, bytes: usize) -> bool {
        let Some(&held) = self.held.get(lane) else {
            return false;
        };
        let Some(debit) = self.debit(lane, held, entries, bytes) else {
            return false;
        };
        self.entries.acquire(entries, debit.entries);
        self.bytes.acquire(bytes, debit.bytes);
        let held = &mut self.held[lane];
        held.entries += entries;
        held.bytes += bytes;
        true
    }

    pub(super) fn release(&mut self, lane: usize, entries: usize, bytes: usize) {
        let held = &mut self.held[lane];
        debug_assert!(held.entries >= entries);
        debug_assert!(held.bytes >= bytes);
        self.entries.release(lane, held.entries, entries);
        self.bytes.release(lane, held.bytes, bytes);
        held.entries -= entries;
        held.bytes -= bytes;
    }
}