use pinned_vec::PinnedVec;
use std::cell::RefCell;
use std::sync::atomic::AtomicU32;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use fnv::FnvHashMap;
use crate::ast::Designator;
use crate::SrcPos;
use super::AnyEnt;
use super::AnyEntKind;
use super::EntRef;
use super::Related;
use super::TypeEnt;
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct ArenaId(u32);
static ACOUNTER: AtomicU32 = AtomicU32::new(1);
impl Default for ArenaId {
fn default() -> Self {
ArenaId(ACOUNTER.fetch_add(1, Ordering::Relaxed))
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct LocalId(u32);
struct LocalArena {
pub id: ArenaId,
items: PinnedVec<AnyEnt<'static>>,
}
impl LocalArena {
pub fn new(id: ArenaId) -> Self {
Self {
id,
items: PinnedVec::new(),
}
}
unsafe fn alloc(&mut self, mut ent: AnyEnt) -> *const AnyEnt<'static> {
let idx = self.items.len();
if idx > u32::MAX as usize {
panic!("Entity index overflow");
}
let ent_id = EntityId::new_arena(self.id, LocalId(idx as u32));
ent.id = ent_id;
self.items.push(std::mem::transmute(ent));
self.get(ent_id.local_id())
}
unsafe fn get(&self, id: LocalId) -> *const AnyEnt<'static> {
self.panic_on_missing(id);
let item = self.items.get(id.0 as usize).unwrap();
std::pin::Pin::into_inner(item) as *const AnyEnt
}
unsafe fn get_mut(&mut self, id: LocalId) -> *mut AnyEnt {
self.panic_on_missing(id);
let item = self.items.get_mut(id.0 as usize).unwrap();
std::mem::transmute(std::pin::Pin::into_inner(item) as *mut AnyEnt)
}
fn panic_on_missing(&self, id: LocalId) {
if (id.0 as usize) < self.items.len() {
return;
}
eprintln!("Could not find {:?} within arena {:?}", id, self.id);
eprintln!("Found these entities:");
for i in 0..self.items.len() {
let ent = self.items.get(i).unwrap();
eprintln!(
"{:?} {:?} {}",
ent.id().arena_id(),
ent.id().local_id(),
ent.describe()
);
}
panic!("Panic on missing id in arena");
}
}
#[derive(Clone, Default)]
pub struct FinalArena {
refs: FnvHashMap<u32, Arc<LocalArena>>,
}
impl<'a> FinalArena {
pub fn get(&'a self, id: EntityId) -> EntRef<'a> {
unsafe {
let ent = self.refs[&id.arena_id().0].get(id.local_id());
&*ent as &'a AnyEnt
}
}
pub fn link(&mut self, referenced: &FinalArena) {
for (id, arena) in referenced.refs.iter() {
self.refs.entry(*id).or_insert_with(|| arena.clone());
}
}
pub fn clear(&mut self) {
self.refs.clear();
}
}
pub struct Arena {
local: RefCell<LocalArena>,
refs: RefCell<FinalArena>,
}
impl Arena {
pub fn new(id: ArenaId) -> Self {
Self {
local: RefCell::new(LocalArena::new(id)),
refs: Default::default(),
}
}
pub fn new_std() -> Self {
Self {
local: RefCell::new(LocalArena::new(ArenaId(0))),
refs: Default::default(),
}
}
pub fn link(&self, referenced: &FinalArena) {
self.refs.borrow_mut().link(referenced)
}
pub fn alloc<'a>(
&'a self,
designator: Designator,
parent: Option<EntRef<'a>>,
related: Related<'a>,
kind: AnyEntKind<'a>,
decl_pos: Option<SrcPos>,
) -> EntRef<'a> {
let ent = AnyEnt {
id: EntityId::undefined(),
parent,
related,
implicits: Vec::new(),
designator,
kind,
decl_pos,
};
unsafe {
let ent = self.local.borrow_mut().alloc(ent);
&*ent as EntRef<'a>
}
}
pub(crate) unsafe fn update<'a>(
&'a self,
id: EntityId,
designator: Designator,
parent: Option<EntRef<'a>>,
related: Related<'a>,
kind: AnyEntKind<'a>,
decl_pos: Option<SrcPos>,
) -> EntRef<'a> {
unsafe {
let local = self.local.borrow_mut();
assert_eq!(id.arena_id(), local.id);
let p = &mut *self.local.as_ptr() as &mut LocalArena;
let eref = p.get_mut(id.local_id());
*eref = AnyEnt {
id,
parent,
related,
implicits: Vec::new(),
designator,
kind,
decl_pos,
};
&*eref as EntRef<'a>
}
}
pub(crate) unsafe fn add_implicit<'a>(&'a self, id: EntityId, ent: EntRef<'a>) {
let local = self.local.borrow_mut();
assert_eq!(id.arena_id(), local.id);
let p = &mut *self.local.as_ptr() as &mut LocalArena;
let eref = p.get_mut(id.local_id());
unsafe {
let eref: &mut AnyEnt = &mut *eref as &mut AnyEnt;
eref.add_implicit(ent);
}
}
pub fn get<'a>(&'a self, id: EntityId) -> EntRef<'a> {
unsafe {
let p = &*self.local.as_ptr() as &LocalArena;
if p.id == id.arena_id() {
let ent = p.get(id.local_id());
return &*ent as &'a AnyEnt;
}
}
unsafe {
let p = &*self.refs.as_ptr() as &FinalArena;
let ent = p.get(id);
ent as &'a AnyEnt
}
}
pub fn get_type(&self, id: EntityId) -> TypeEnt {
TypeEnt::from_any(self.get(id)).unwrap()
}
pub fn finalize(self) -> FinalArena {
let Arena { local, refs } = self;
let local = local.into_inner();
let mut refs = refs.into_inner();
refs.refs.insert(local.id.0, Arc::new(local));
refs
}
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct EntityId {
id: usize,
}
impl EntityId {
#[allow(clippy::new_without_default)]
pub fn undefined() -> Self {
EntityId { id: usize::MAX }
}
pub(crate) fn new_arena(arena_id: ArenaId, id: LocalId) -> Self {
EntityId {
id: ((arena_id.0 as usize) << u32::BITS) | (id.0 as usize),
}
}
pub fn arena_id(&self) -> ArenaId {
ArenaId((self.id >> u32::BITS) as u32)
}
fn local_id(&self) -> LocalId {
LocalId((self.id & (u32::MAX as usize)) as u32)
}
}