o3 0.11.0

shared-nothing primitives
Documentation
use crate::collections::slab::{
    GenerationState,
    core::{Mode, NONE, SlabCore, SlotIndex, State, guards::Busy},
};

pub(in crate::collections::slab) trait Entries<T, G: GenerationState, M: Mode> {
    fn get(&self, index: u32, generation: G) -> Option<&T>;
    fn get_mut(&mut self, index: u32, generation: G) -> Option<&mut T>;
    fn remove(&self, index: u32, generation: G) -> Option<(T, SlotIndex)>;
    fn remove_with<R>(
        &self,
        index: u32,
        generation: G,
        f: impl FnOnce(&mut T) -> Option<R>,
    ) -> Option<(T, R)>;
    fn remove_index(&self, index: u32) -> Option<(T, SlotIndex)>;
    fn remove_index_with<R>(
        &self,
        index: u32,
        f: impl FnOnce(&mut T, G) -> Option<R>,
    ) -> Option<(T, R, SlotIndex)>;
    fn index(&self, index: u32) -> Option<(&T, G)>;
    fn index_mut(&mut self, index: u32) -> Option<(&mut T, G)>;
    fn generation(&self, index: u32) -> Option<G>;
    fn occupied_at(&self, position: usize) -> Option<(u32, G)>;
    fn values<'a>(&'a self) -> impl Iterator<Item = &'a T>
    where
        T: 'a;
    fn values_mut<'a>(&'a mut self) -> impl Iterator<Item = &'a mut T>
    where
        T: 'a;
    fn clear(&mut self);
    fn update<R>(&self, index: u32, generation: G, f: impl FnOnce(&mut T) -> R) -> Option<R>;
    fn remove_occupied(&self, index: SlotIndex);
}

impl<T, G: GenerationState, M: Mode> Entries<T, G, M> for SlabCore<T, G, M> {
    fn get(&self, index: u32, generation: G) -> Option<&T> {
        let slot = self.slots.get(index as usize)?;
        if slot.state.get() == State::Occupied && slot.generation.get() == generation {
            Some(unsafe { slot.value() })
        } else {
            None
        }
    }

    fn get_mut(&mut self, index: u32, generation: G) -> Option<&mut T> {
        let slot = self.slots.get_mut(index as usize)?;
        if slot.state.get() == State::Occupied && slot.generation.get() == generation {
            Some(unsafe { &mut *slot.value_ptr() })
        } else {
            None
        }
    }

    fn remove(&self, index: u32, generation: G) -> Option<(T, SlotIndex)> {
        Some(Busy::take_key(self, index, generation)?.commit_removal())
    }

    fn remove_with<R>(
        &self,
        index: u32,
        generation: G,
        f: impl FnOnce(&mut T) -> Option<R>,
    ) -> Option<(T, R)> {
        let mut busy = Busy::take_key(self, index, generation)?;
        let result = f(busy.value_mut())?;
        let (value, _) = busy.commit_removal();
        Some((value, result))
    }

    fn remove_index(&self, index: u32) -> Option<(T, SlotIndex)> {
        Some(Busy::take(self, index)?.commit_removal())
    }

    fn remove_index_with<R>(
        &self,
        index: u32,
        f: impl FnOnce(&mut T, G) -> Option<R>,
    ) -> Option<(T, R, SlotIndex)> {
        let mut busy = Busy::take(self, index)?;
        let generation = busy.generation();
        let result = f(busy.value_mut(), generation)?;
        let (value, index) = busy.commit_removal();
        Some((value, result, index))
    }

    fn index(&self, index: u32) -> Option<(&T, G)> {
        let slot = self.slots.get(index as usize)?;
        if slot.state.get() == State::Occupied {
            Some((unsafe { slot.value() }, slot.generation.get()))
        } else {
            None
        }
    }

    fn index_mut(&mut self, index: u32) -> Option<(&mut T, G)> {
        let slot = self.slots.get_mut(index as usize)?;
        if slot.state.get() == State::Occupied {
            let generation = slot.generation.get();
            Some((unsafe { &mut *slot.value_ptr() }, generation))
        } else {
            None
        }
    }

    fn generation(&self, index: u32) -> Option<G> {
        let slot = self.slots.get(index as usize)?;
        (slot.state.get() == State::Occupied).then(|| slot.generation.get())
    }

    fn occupied_at(&self, position: usize) -> Option<(u32, G)> {
        if position >= self.len() {
            return None;
        }
        let index = self.occupied.get(position)?.get();
        let slot = self.slots.get(index as usize)?;
        (slot.state.get() == State::Occupied && slot.position.get() as usize == position)
            .then(|| (index, slot.generation.get()))
    }

    fn values<'a>(&'a self) -> impl Iterator<Item = &'a T>
    where
        T: 'a,
    {
        (0..self.len()).map(|position| {
            let index = unsafe { self.occupied.get_unchecked(position) }.get();
            let slot = unsafe { self.slots.get_unchecked(index as usize) };
            debug_assert!(slot.state.get() == State::Occupied);
            unsafe { slot.value() }
        })
    }

    fn values_mut<'a>(&'a mut self) -> impl Iterator<Item = &'a mut T>
    where
        T: 'a,
    {
        let len = self.len();
        let slots = self.slots.as_mut_ptr();
        let occupied = &self.occupied;
        (0..len).map(move |position| {
            let index = unsafe { occupied.get_unchecked(position) }.get();
            let slot = unsafe { &mut *slots.add(index as usize) };
            debug_assert!(slot.state.get() == State::Occupied);
            unsafe { &mut *slot.value_ptr() }
        })
    }

    fn clear(&mut self) {
        while self.len.get() != 0 {
            let position = self.len.get() - 1;
            let index = unsafe { self.occupied.get_unchecked(position as usize) }.get();
            drop(self.remove_index(index).map(|(value, _)| value));
        }
    }

    fn update<R>(&self, index: u32, generation: G, f: impl FnOnce(&mut T) -> R) -> Option<R> {
        let mut busy = Busy::take_key(self, index, generation)?;
        Some(f(busy.value_mut()))
    }

    fn remove_occupied(&self, index: SlotIndex) {
        let slot = unsafe { self.slots.get_unchecked(index.get() as usize) };
        let position = slot.position.replace(NONE);
        let last_position = self.len.get() - 1;
        let last_index = unsafe { self.occupied.get_unchecked(last_position as usize) }.get();
        unsafe { self.occupied.get_unchecked(position as usize) }.set(last_index);
        unsafe { self.occupied.get_unchecked(last_position as usize) }.set(NONE);
        if last_index != index.get() {
            unsafe { self.slots.get_unchecked(last_index as usize) }
                .position
                .set(position);
        }
        self.len.set(last_position);
    }
}