dope-net 0.39.0

Owned network transports for dope
use std::mem;

use dope_core::driver::schedule::ready;

use crate::link::egress::{
    self, create,
    load::credit::{
        self,
        wait::{
            store::{Core, Idle, Nodes, Queued, Ready, Records, Selected, State, Waiting},
            tree,
        },
    },
    metadata,
};

pub(in crate::link::egress::load::credit) enum Resume<'p> {
    Waiting,
    Queued,
    Granted(credit::Grant<'p>),
}

pub(in crate::link::egress::load::credit) enum Cancelled {
    Idle,
    Busy,
}

struct Vacant<'a, 'b, 'p, 'd> {
    record: Idle<'a, 'p, 'd>,
    tree: &'a mut tree::State,
    nodes: &'a mut Nodes<'b>,
    ticket: &'a mut tree::Ticket,
    index: tree::Index,
}

impl<'p, 'd> Vacant<'_, '_, 'p, 'd> {
    fn poll(
        self,
        lane: credit::Lane<'_, 'p, 'd, credit::Ready<'p, 'd>>,
        key: ready::Retained<'d>,
        amount: credit::Queued,
    ) -> Result<Resume<'p>, egress::Tickets> {
        let charge = amount.amount();
        let account = lane.account();
        let demand = credit::Demand::queued(account, amount);
        if demand == credit::Demand::<2>::ZERO || (self.tree.is_empty() && lane.is_covered(demand))
        {
            return Ok(Resume::Granted(account.acquire(charge)));
        }
        if self.tree.is_empty() {
            *self.ticket = tree::Ticket::FIRST;
        }
        let ticket = self.ticket.issue()?;
        let record = self.record.wait(
            self.index,
            Waiting {
                key,
                amount,
                bypasses: 0,
            },
        );
        let proof = record.proof();
        self.tree.insert(self.nodes, proof, demand, ticket);
        Ok(Resume::Queued)
    }
}

pub(in crate::link::egress::load::credit) struct Queue<'p, 'd> {
    store: Core<'p, 'd>,
    tree: tree::State,
    ticket: tree::Ticket,
}

impl<'p, 'd> Queue<'p, 'd> {
    pub(in crate::link::egress::load::credit) fn try_new(
        lanes: metadata::LaneCount,
    ) -> Result<Self, create::Error> {
        const {
            let store = mem::size_of::<Core<'p, 'd>>();
            let roots = mem::size_of::<tree::State>();
            let ticket = mem::size_of::<tree::Ticket>();
            assert!(store == 3 * mem::size_of::<usize>());
            assert!(roots == 3 * mem::size_of::<u32>());
            assert!(ticket == mem::size_of::<u32>());
            assert!(mem::align_of::<Core<'p, 'd>>() == mem::align_of::<usize>());
            assert!(mem::align_of::<tree::State>() == mem::align_of::<u32>());
            assert!(mem::align_of::<tree::Ticket>() == mem::align_of::<u32>());
            assert!(mem::align_of::<Self>() == mem::align_of::<usize>());
            assert!(mem::size_of::<Self>() == store + roots + ticket);
            assert!(mem::size_of::<Self>() == 5 * mem::size_of::<usize>());
        };
        Ok(Self {
            store: Core::try_new(lanes)?,
            tree: tree::State::new(),
            ticket: tree::Ticket::FIRST,
        })
    }

    pub(in crate::link::egress::load::credit) fn is_busy(
        &self,
        lane: credit::Lane<'_, 'p, 'd, credit::Ready<'p, 'd>>,
    ) -> bool {
        self.store.is_busy(lane)
    }

    pub(in crate::link::egress::load::credit) fn has_waiting(&self) -> bool {
        !self.tree.is_empty()
    }

    pub(in crate::link::egress::load::credit) fn refresh(
        &mut self,
        lane: credit::Lane<'_, 'p, 'd, credit::Ready<'p, 'd>>,
    ) {
        let index = tree::Index::from(lane);
        let (mut records, mut nodes) = self.store.parts();
        let State::Waiting(record) = Records::state(&mut records, index) else {
            return;
        };
        let waiting = Queued::value(&record);
        let demand = credit::Demand::queued(lane.account(), waiting.amount);
        let proof = record.proof();
        self.tree.refresh(&mut nodes, proof, demand);
    }

    pub(in crate::link::egress::load::credit) fn select<'pool>(
        &mut self,
        scope: &'pool credit::Pool<'p, 'd, credit::Ready<'p, 'd>>,
        shared: credit::Amount,
    ) -> Option<Selected<'_, 'pool, 'p, 'd>> {
        let nodes = self.store.nodes();
        let oldest = self.tree.oldest(&nodes)?;
        let selected = self.tree.eligible(&nodes, shared)?;
        if selected != oldest && !self.store.try_bypass(oldest) {
            return None;
        }
        let (records, mut nodes) = self.store.parts();
        let (selected, proof) = Records::selected(records, selected, scope);
        self.tree.remove(&mut nodes, proof);
        Some(selected)
    }

    pub(in crate::link::egress::load::credit) fn resume(
        &mut self,
        lane: credit::Lane<'_, 'p, 'd, credit::Ready<'p, 'd>>,
        key: ready::Retained<'d>,
        amount: credit::Queued,
    ) -> Result<Resume<'p>, egress::Tickets> {
        let index = tree::Index::from(lane);
        let (mut records, mut nodes) = self.store.parts();
        let record = match Records::state(&mut records, index) {
            State::Idle(record) => record,
            State::Waiting(record) => {
                let waiting = Queued::value(&record);
                if waiting.key == key && waiting.amount == amount {
                    return Ok(Resume::Waiting);
                }
                let demand = credit::Demand::queued(lane.account(), amount);
                let change = record.replace(Waiting {
                    key,
                    amount,
                    bypasses: waiting.bypasses,
                });
                self.tree.refresh(&mut nodes, change, demand);
                return Ok(Resume::Queued);
            }
            State::Granted(record) if Ready::matches(&record, key, amount) => {
                return Ok(Resume::Granted(Ready::take(record)));
            }
            State::Granted(record) => {
                let (idle, grant) = Ready::vacate(record);
                grant.release();
                idle
            }
        };
        Vacant {
            record,
            tree: &mut self.tree,
            nodes: &mut nodes,
            ticket: &mut self.ticket,
            index,
        }
        .poll(lane, key, amount)
    }

    pub(in crate::link::egress::load::credit) fn cancel(
        &mut self,
        lane: credit::Lane<'_, 'p, 'd, credit::Ready<'p, 'd>>,
    ) -> Cancelled {
        let index = tree::Index::from(lane);
        let (mut records, mut nodes) = self.store.parts();
        match Records::state(&mut records, index) {
            State::Idle(_) => Cancelled::Idle,
            State::Waiting(record) => {
                let proof = Queued::clear(record);
                self.tree.remove(&mut nodes, proof);
                Cancelled::Busy
            }
            State::Granted(record) => {
                Ready::take(record).release();
                Cancelled::Busy
            }
        }
    }
}