Files @ ed4fe8216eb0
Branch filter:

Location: CSY/reowolf/src/protocol/arena.rs - annotation

ed4fe8216eb0 2.5 KiB application/rls-services+xml Show Source Show as Raw Download as Raw
MH
Fix binding- and assignment-expression related typing issues.

Simpler solutions are better, so the typechecker is back to normal.
Instead we simply make sure that assignment expression is never
nested under another expression, and binding expressions may only
be nested under LogicalAnd-expressions. If only I knew why I thought
type shenanigans were a good idea in the first place...
use crate::common::*;
use core::hash::Hash;
use core::marker::PhantomData;

pub struct Id<T> {
    // Not actually a signed index into the heap. But the index is set to -1 if
    // we don't know an ID yet. This is checked during debug mode.
    pub(crate) index: i32,
    _phantom: PhantomData<T>,
}

impl<T> Id<T> {
    pub(crate) fn new_invalid() -> Self     { Self{ index: -1, _phantom: Default::default() } }
    pub(crate) fn new(index: i32) -> Self   { Self{ index, _phantom: Default::default() } }
    pub(crate) fn is_invalid(&self) -> bool { self.index < 0 }
}

#[derive(Debug)]
pub(crate) struct Arena<T> {
    store: Vec<T>,
}
//////////////////////////////////

impl<T> Debug for Id<T> {
    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
        f.debug_struct("Id").field("index", &self.index).finish()
    }
}
impl<T> Clone for Id<T> {
    fn clone(&self) -> Self {
        *self
    }
}
impl<T> Copy for Id<T> {}
impl<T> PartialEq for Id<T> {
    fn eq(&self, other: &Self) -> bool {
        self.index.eq(&other.index)
    }
}
impl<T> Eq for Id<T> {}
impl<T> Hash for Id<T> {
    fn hash<H: std::hash::Hasher>(&self, h: &mut H) {
        self.index.hash(h);
    }
}

impl<T> Arena<T> {
    pub fn new() -> Self {
        Self { store: vec![] }
    }

    pub fn alloc_with_id(&mut self, f: impl FnOnce(Id<T>) -> T) -> Id<T> {
        // Lets keep this a runtime assert.
        assert!(self.store.len() < i32::max_value() as usize, "Arena out of capacity");
        let id = Id::new(self.store.len() as i32);
        self.store.push(f(id));
        id
    }

    // Compiler-internal direct retrieval
    pub(crate) fn get(&self, idx: usize) -> &T {
        return &self.store[idx]
    }
    pub(crate) fn get_id(&self, idx: usize) -> Id<T> {
        debug_assert!(idx < self.store.len());
        return Id::new(idx as i32);
    }

    pub fn iter(&self) -> impl Iterator<Item = &T> {
        self.store.iter()
    }

    pub fn len(&self) -> usize {
        self.store.len()
    }
}
impl<T> core::ops::Index<Id<T>> for Arena<T> {
    type Output = T;
    fn index(&self, id: Id<T>) -> &Self::Output {
        debug_assert!(!id.is_invalid(), "attempted to index into Arena with an invalid id (index < 0)");
        self.store.index(id.index as usize)
    }
}
impl<T> core::ops::IndexMut<Id<T>> for Arena<T> {
    fn index_mut(&mut self, id: Id<T>) -> &mut Self::Output {
        debug_assert!(!id.is_invalid(), "attempted to index_mut into Arena with an invalid id (index < 0)");
        self.store.index_mut(id.index as usize)
    }
}