ngen 0.1.4

A very simple game engine using OpenGL
Documentation
use std::alloc::Layout;

use super::{align_to, TempArena};

/// A growable array of elements for a temporary memory arena.
pub struct Array<'t, T> {
    arena: &'t mut TempArena,
    count: usize,
    start: usize,
    phantom: std::marker::PhantomData<T>,
}

impl<'t, T> Array<'t, T> {
    /// Creates a new array, using the supplied temporary arena allocator as its backing store.
    ///
    /// # Example
    /// ```
    ///# use ngen::arena::{Array, TempArena};
    /// let mut arena = TempArena::with_capacity(1024).unwrap();
    /// let array = Array::<u32>::new(&mut arena);
    /// ```
    /// # Note
    /// Instead of creating the array manually, it is easier to use the `array` method of the
    /// `TempArena`.
    /// ```
    ///# use ngen::arena::TempArena;
    /// let mut arena = TempArena::with_capacity(1024).unwrap();
    /// let array = arena.array::<u32>();
    /// ```
    /// # Note
    /// Arrays can be indexed, just like other collections in Rust.
    /// ```
    ///# use ngen::arena::TempArena;
    /// let mut arena = TempArena::with_capacity(1024).unwrap();
    /// let mut array = arena.array();
    ///
    /// array.push(0);
    /// array.push(1);
    /// array.push(2);
    ///
    /// assert_eq!(array[1], 1);
    ///
    /// array[0] = 42;
    /// assert_eq!(array[0], 42);
    /// ```
    pub fn new(arena: &'t mut TempArena) -> Self {
        let start = {
            let memory = arena.memory.borrow();
            let layout = Layout::new::<T>();
            align_to(memory.next, layout.align())
        };

        Self {
            arena,
            start,
            count: 0,
            phantom: std::marker::PhantomData,
        }
    }

    /// Pushes a new element onto the end of the array.
    ///
    /// # Example
    /// ```
    ///# use ngen::arena::TempArena;
    /// let mut arena = TempArena::with_capacity(1024).unwrap();
    /// let mut array = arena.array();
    ///
    /// array.push(7);
    /// array.push(42);
    /// ```
    pub fn push(&mut self, value: T) {
        self.arena.push(value);
        self.count += 1;
    }

    /// Returns the current length of the array.
    ///
    /// # Example
    /// ```
    ///# use ngen::arena::TempArena;
    /// let mut arena = TempArena::with_capacity(1024).unwrap();
    /// let mut array = arena.array();
    ///
    /// array.push(7);
    /// array.push(42);
    ///
    /// assert_eq!(array.len(), 2);
    /// ```
    pub const fn len(&self) -> usize {
        self.count
    }

    /// Ends the array, returning a slice that points to the array's elements. This is important
    /// because it returns access to the temp arena to the rest of the application.
    ///
    /// # Example
    /// ```
    ///# use ngen::arena::{Array, TempArena};
    /// let mut arena = TempArena::with_capacity(1024).unwrap();
    /// let mut array = arena.array();
    ///
    /// for i in 0..42 {
    ///     array.push(i);
    /// }
    ///
    /// for (c, i) in array.end().iter().enumerate() {
    ///     assert_eq!(*i, c as i32);
    /// }
    /// ```
    pub fn end(self) -> &'t mut [T] {
        unsafe { std::slice::from_raw_parts_mut(self.start as *mut T, self.count) }
    }
}

impl<'t, T> std::ops::Index<usize> for Array<'t, T> {
    type Output = T;

    fn index(&self, index: usize) -> &Self::Output {
        assert!(
            index < self.count,
            "Invalid index({}). Array has {} item(s).",
            index,
            self.count
        );

        unsafe {
            let ptr = self.start as *const T;
            &*ptr.add(index)
        }
    }
}

impl<'t, T> std::ops::IndexMut<usize> for Array<'t, T> {
    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
        assert!(
            index < self.count,
            "Invalid index({}). Array has {} item(s).",
            index,
            self.count
        );

        unsafe {
            let ptr = self.start as *mut T;
            &mut *ptr.add(index)
        }
    }
}