luau-syntax 0.732.0

Luau lexer, parser, AST, CST, and source utilities
Documentation
use std::cell::UnsafeCell;
use std::marker::PhantomData;
use std::ops::Index;
use std::slice;

pub(super) struct ScratchVec<T> {
    storage: Box<UnsafeCell<Vec<T>>>,
}

impl<T> Default for ScratchVec<T> {
    fn default() -> Self {
        Self {
            storage: Box::new(UnsafeCell::new(Vec::new())),
        }
    }
}

impl<T> ScratchVec<T> {
    pub(super) fn reserve(&mut self, additional: usize) {
        unsafe {
            (*self.storage.get()).reserve(additional);
        }
    }

    fn as_ptr(&self) -> *mut Vec<T> {
        self.storage.get()
    }
}

pub(super) struct TempVector<T> {
    storage: *mut Vec<T>,
    offset: usize,
    size: usize,
    _marker: PhantomData<*mut Vec<T>>,
}

impl<T> TempVector<T> {
    pub(super) fn new(storage: &ScratchVec<T>) -> Self {
        let storage = storage.as_ptr();
        Self {
            storage,
            offset: unsafe { (*storage).len() },
            size: 0,
            _marker: PhantomData,
        }
    }

    pub(super) fn nested(&mut self) -> Self {
        // TempVector mirrors Luau's parser scratch arrays: nested users may append
        // only at the current end, and drops must unwind in stack order.  UnsafeCell
        // keeps that source-shaped storage model without creating overlapping Rust
        // `&mut Vec<T>` borrows while a parent TempVector is still alive.
        let storage = self.storage;
        let offset = self.storage().len();
        Self {
            storage,
            offset,
            size: 0,
            _marker: PhantomData,
        }
    }

    pub(super) fn push_back(&mut self, item: T) {
        debug_assert!(self.storage().len() == self.offset + self.size);
        self.storage_mut().push(item);
        self.size += 1;
    }

    pub(super) fn len(&self) -> usize {
        self.size
    }

    pub(super) fn as_slice(&self) -> &[T] {
        let storage = self.storage();
        &storage[self.offset..self.offset + self.size]
    }

    pub(super) fn as_mut_slice(&mut self) -> &mut [T] {
        let offset = self.offset;
        let size = self.size;
        &mut self.storage_mut()[offset..offset + size]
    }

    pub(super) fn iter(&self) -> slice::Iter<'_, T> {
        self.as_slice().iter()
    }

    fn storage(&self) -> &Vec<T> {
        unsafe { &*self.storage }
    }

    fn storage_mut(&mut self) -> &mut Vec<T> {
        unsafe { &mut *self.storage }
    }
}

impl<T> Drop for TempVector<T> {
    fn drop(&mut self) {
        let offset = self.offset;
        let size = self.size;
        let storage = self.storage_mut();
        debug_assert!(storage.len() == offset + size);
        storage.truncate(offset);
    }
}

impl<T> Index<usize> for TempVector<T> {
    type Output = T;

    fn index(&self, index: usize) -> &Self::Output {
        &self.as_slice()[index]
    }
}