dope-net 0.9.0

The manifold runtime
Documentation
use std::cell::Cell;
use std::mem;

use o3::cell::RawCell;

use super::super::super::NONE;
use super::super::super::config::Config;
use super::super::super::credits::Credits;

struct Node<T> {
    value: Option<T>,
    next: u32,
    bytes: usize,
    resident: usize,
}

pub(crate) struct MetadataPool<T> {
    nodes: Box<[RawCell<Node<T>>]>,
    free: Cell<u32>,
    node_available: Cell<usize>,
    credits: RawCell<Credits>,
}

struct ReservedNode<'a, T> {
    pool: &'a MetadataPool<T>,
    index: u32,
    armed: bool,
}

impl<T> ReservedNode<'_, T> {
    fn commit(mut self) {
        self.armed = false;
    }
}

impl<T> Drop for ReservedNode<'_, T> {
    fn drop(&mut self) {
        if !self.armed {
            return;
        }
        if let Some(node) = self.pool.take_node(self.index) {
            drop(node);
        } else {
            self.pool.release_empty_node(self.index);
        }
    }
}

impl<T> MetadataPool<T> {
    pub(crate) fn with_config(config: Config, lanes: usize) -> Self {
        let capacity = config.entries();
        Self {
            nodes: (0..capacity)
                .map(|index| {
                    RawCell::new(Node {
                        value: None,
                        next: if index + 1 == capacity {
                            NONE
                        } else {
                            (index + 1) as u32
                        },
                        bytes: 0,
                        resident: 0,
                    })
                })
                .collect(),
            free: Cell::new(if capacity == 0 { NONE } else { 0 }),
            node_available: Cell::new(capacity),
            credits: RawCell::new(Credits::with_config(config, lanes)),
        }
    }

    pub(crate) fn reserve_from<V, R>(
        &self,
        value: V,
        wrap: impl FnOnce(V) -> T,
        inspect: impl FnOnce(&mut T) -> R,
    ) -> Result<(u32, R), V> {
        let index = self.free.get();
        if index == NONE {
            return Err(value);
        }
        unsafe {
            self.nodes[index as usize].with_mut(|node| {
                self.free.set(node.next);
                self.node_available.set(self.node_available.get() - 1);
                node.next = NONE;
                node.bytes = 0;
                node.resident = 0;
                let reservation = ReservedNode {
                    pool: self,
                    index,
                    armed: true,
                };
                let result = inspect(node.value.insert(wrap(value)));
                reservation.commit();
                Ok((index, result))
            })
        }
    }

    pub(crate) fn with_value<R>(&self, index: u32, inspect: impl FnOnce(&T) -> R) -> Option<R> {
        unsafe { self.nodes[index as usize].with(|node| node.value.as_ref().map(inspect)) }
    }

    pub(crate) fn set_sizes(&self, index: u32, bytes: usize, resident: usize) {
        unsafe {
            self.nodes[index as usize].with_mut(|node| {
                node.bytes = bytes;
                node.resident = resident;
            })
        };
    }

    pub(crate) fn set_next(&self, index: u32, next: u32) {
        unsafe { self.nodes[index as usize].with_mut(|node| node.next = next) };
    }

    pub(crate) fn next(&self, index: u32) -> u32 {
        unsafe { self.nodes[index as usize].with(|node| node.next) }
    }

    pub(crate) fn take_node(&self, index: u32) -> Option<(u32, T, usize, usize)> {
        unsafe {
            self.nodes[index as usize].with_mut(|node| {
                let value = node.value.take()?;
                let next = node.next;
                let bytes = node.bytes;
                let resident = node.resident;
                node.bytes = 0;
                node.resident = 0;
                node.next = self.free.replace(index);
                self.node_available.set(self.node_available.get() + 1);
                Some((next, value, bytes, resident))
            })
        }
    }

    pub(crate) fn detach_value(&self, index: u32) -> Option<(u32, T, usize, usize)> {
        unsafe {
            self.nodes[index as usize].with_mut(|node| {
                let value = node.value.take()?;
                let next = node.next;
                let bytes = node.bytes;
                let resident = node.resident;
                node.next = NONE;
                Some((next, value, bytes, resident))
            })
        }
    }

    pub(crate) fn restore_value(&self, index: u32, value: T, next: u32) {
        unsafe {
            self.nodes[index as usize].with_mut(|node| {
                debug_assert!(node.value.is_none());
                node.value = Some(value);
                node.next = next;
            })
        };
    }

    pub(crate) fn release_empty_node(&self, index: u32) {
        unsafe {
            self.nodes[index as usize].with_mut(|node| {
                debug_assert!(node.value.is_none());
                node.bytes = 0;
                node.resident = 0;
                node.next = self.free.replace(index);
                self.node_available.set(self.node_available.get() + 1);
            })
        };
    }

    pub(crate) fn drain_nodes(&self, head: &mut u32) {
        let mut drain = NodeDrain {
            pool: self,
            head: mem::replace(head, NONE),
        };
        while let Some(value) = drain.take() {
            drop(value);
        }
    }

    pub(crate) fn front_consume(&self, index: u32, bytes: usize) {
        unsafe {
            self.nodes[index as usize].with_mut(|node| {
                debug_assert!(node.bytes >= bytes);
                node.bytes -= bytes;
            })
        };
    }

    pub(crate) fn lanes(&self) -> usize {
        unsafe { self.credits.with(Credits::lanes) }
    }

    pub(crate) fn has_available(&self) -> bool {
        self.node_available.get() != 0
    }

    pub(crate) fn acquire(&self, lane: usize, entries: usize, bytes: usize) -> bool {
        unsafe {
            self.credits
                .with_mut(|credits| credits.acquire(lane, entries, bytes))
        }
    }

    pub(crate) fn release(&self, lane: usize, entries: usize, bytes: usize) {
        unsafe {
            self.credits
                .with_mut(|credits| credits.release(lane, entries, bytes))
        };
    }
}

struct NodeDrain<'a, T> {
    pool: &'a MetadataPool<T>,
    head: u32,
}

impl<T> NodeDrain<'_, T> {
    fn take(&mut self) -> Option<T> {
        if self.head == NONE {
            return None;
        }
        let (next, value, _, _) = self.pool.take_node(self.head)?;
        self.head = next;
        Some(value)
    }
}

impl<T> Drop for NodeDrain<'_, T> {
    fn drop(&mut self) {
        while let Some(value) = self.take() {
            drop(value);
        }
    }
}