o3 0.16.3

shared-nothing primitives
Documentation
use std::{hint, ops};

use crate::collections::slab::sealed::{self, core};

pub(in crate::collections::slab::sealed) struct Reservations<
    'a,
    T,
    G: sealed::GenerationState,
    M: core::Mode,
    const PARTITIONS: usize,
> {
    core: &'a core::Core<T, G, M, PARTITIONS>,
}

impl<'a, T, G: sealed::GenerationState, M: core::Mode, const PARTITIONS: usize>
    Reservations<'a, T, G, M, PARTITIONS>
{
    pub(super) fn new(core: &'a core::Core<T, G, M, PARTITIONS>) -> Self {
        Self { core }
    }

    pub(in crate::collections::slab::sealed) fn take_free(&self) -> Option<core::Ticket<G>> {
        if let Some(ticket) = self.take_partition(0) {
            return Some(ticket);
        }
        if PARTITIONS == 2 {
            return self.take_partition(1);
        }
        None
    }

    pub(in crate::collections::slab::sealed) fn take_range(
        &self,
        mut range: ops::Range<u32>,
    ) -> Option<core::Ticket<G>> {
        let capacity = self.core.capacity() as u32;
        if range == (0..capacity) {
            return self.take_free();
        }
        if PARTITIONS == 2 {
            let boundary = capacity.div_ceil(2);
            if range == (0..boundary) {
                return self.take_partition(0);
            }
            if range == (boundary..capacity) {
                return self.take_partition(1);
            }
        }
        range.find_map(|index| self.take_index(index))
    }

    fn take_partition(&self, partition: usize) -> Option<core::Ticket<G>> {
        let raw = self.core.free.get(partition)?.get();
        (raw != core::NONE).then(|| unsafe { self.take_free_raw(raw, partition) })
    }

    unsafe fn take_free_raw(&self, raw: u32, partition: usize) -> core::Ticket<G> {
        let index = core::SlotIndex(raw);
        let slot = unsafe { self.core.slots.get_unchecked(index.get() as usize) };
        if slot.state.get() != core::State::Free {
            unsafe { hint::unreachable_unchecked() }
        }
        let generation = slot.generation.get();
        let core::Links { next, prev } = unsafe { slot.links() };
        debug_assert_eq!(prev, core::NONE);
        if next != core::NONE {
            let next = unsafe { self.core.slots.get_unchecked(next as usize) };
            if next.state.get() != core::State::Free {
                unsafe { hint::unreachable_unchecked() }
            }
            let core::Links { next: link, .. } = unsafe { next.links() };
            unsafe {
                next.set_links(core::Links {
                    next: link,
                    prev: core::NONE,
                })
            };
        }
        unsafe { self.core.free.get_unchecked(partition) }.set(next);
        slot.state.set(core::State::Reserved);
        core::Ticket { index, generation }
    }

    pub(in crate::collections::slab::sealed) fn take_index(
        &self,
        index: u32,
    ) -> Option<core::Ticket<G>> {
        let slot = self.core.slots.get(index as usize)?;
        let index = core::SlotIndex::new(index, self.core.slots.len())?;
        if slot.state.get() != core::State::Free {
            return None;
        }
        let generation = slot.generation.get();
        let core::Links { next, prev } = unsafe { slot.links() };
        self.unlink(index, prev, next);
        slot.state.set(core::State::Reserved);
        Some(core::Ticket { index, generation })
    }

    fn unlink(&self, index: core::SlotIndex, prev: u32, next: u32) {
        if prev == core::NONE {
            let partition = self.core.partition(index);
            let head = unsafe { self.core.free.get_unchecked(partition) };
            debug_assert_eq!(head.get(), index.get());
            head.set(next);
        } else {
            self.set_free_next(prev, next);
        }
        if next != core::NONE {
            self.set_free_prev(next, prev);
        }
    }

    pub(super) fn release(&self, index: core::SlotIndex, generation: G) {
        let partition = self.core.partition(index);
        let head = unsafe { self.core.free.get_unchecked(partition) }.replace(index.get());
        let slot = unsafe { self.core.slots.get_unchecked(index.get() as usize) };
        slot.generation.set(generation);
        unsafe {
            slot.set_links(core::Links {
                next: head,
                prev: core::NONE,
            })
        };
        slot.state.set(core::State::Free);
        if head != core::NONE {
            self.set_free_prev(head, index.get());
        }
    }

    fn set_free_next(&self, index: u32, next: u32) {
        let slot = free_slot(self.core, index);
        let core::Links { prev, .. } = unsafe { slot.links() };
        unsafe { slot.set_links(core::Links { next, prev }) };
    }

    pub(super) fn set_free_prev(&self, index: u32, prev: u32) {
        let slot = free_slot(self.core, index);
        let core::Links { next, .. } = unsafe { slot.links() };
        unsafe { slot.set_links(core::Links { next, prev }) };
    }

    pub(in crate::collections::slab::sealed) fn commit(&self, ticket: core::Ticket<G>, value: T) {
        let slot = reserved_slot(self.core, ticket);
        unsafe { slot.write_value(value) };
        self.commit_initialized(ticket);
    }

    fn commit_initialized(&self, ticket: core::Ticket<G>) {
        let slot = reserved_slot(self.core, ticket);
        let position = self.core.len.get();
        unsafe { self.core.occupied.get_unchecked(position as usize) }.set(ticket.index.get());
        slot.position.set(position);
        slot.state.set(core::State::Occupied);
        self.core.len.set(position + 1);
    }

    pub(in crate::collections::slab::sealed) fn rollback(&self, ticket: core::Ticket<G>) {
        let slot = reserved_slot(self.core, ticket);
        match ticket.generation.next() {
            Some(generation) => self.release(ticket.index, generation),
            None if self.core.recycle_generations() => self.release(ticket.index, G::MIN),
            None => slot.state.set(core::State::Retired),
        }
    }
}

fn free_slot<T, G: sealed::GenerationState, M: core::Mode, const PARTITIONS: usize>(
    core: &core::Core<T, G, M, PARTITIONS>,
    index: u32,
) -> &core::Slot<T, G> {
    let slot = unsafe { core.slots.get_unchecked(index as usize) };
    if slot.state.get() != core::State::Free {
        unsafe { hint::unreachable_unchecked() }
    }
    slot
}

fn reserved_slot<T, G: sealed::GenerationState, M: core::Mode, const PARTITIONS: usize>(
    core: &core::Core<T, G, M, PARTITIONS>,
    ticket: core::Ticket<G>,
) -> &core::Slot<T, G> {
    let slot = unsafe { core.slots.get_unchecked(ticket.index.get() as usize) };
    debug_assert!(
        slot.state.get() == core::State::Reserved && slot.generation.get() == ticket.generation
    );
    slot
}