use std::collections::BTreeMap;
use crate::value::{Cell, CellId, FunctionDef, FunctionId, Object, ObjectId, Value};
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct Heap {
objects: BTreeMap<ObjectId, Object>,
functions: BTreeMap<FunctionId, FunctionDef>,
cells: BTreeMap<CellId, Cell>,
next_object: u64,
next_function: u64,
next_cell: u64,
}
impl Heap {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn alloc_object(self, object: Object) -> (ObjectId, Self) {
let id = ObjectId::new(self.next_object);
let mut next_objects = self.objects;
let _ = next_objects.insert(id, object);
let next = Self {
objects: next_objects,
functions: self.functions,
cells: self.cells,
next_object: self.next_object + 1,
next_function: self.next_function,
next_cell: self.next_cell,
};
(id, next)
}
#[must_use]
pub fn alloc_function(self, function: FunctionDef) -> (FunctionId, Self) {
let id = FunctionId::new(self.next_function);
let mut next_functions = self.functions;
let _ = next_functions.insert(id, function);
let next = Self {
objects: self.objects,
functions: next_functions,
cells: self.cells,
next_object: self.next_object,
next_function: self.next_function + 1,
next_cell: self.next_cell,
};
(id, next)
}
#[must_use]
pub fn alloc_cell(self, cell: Cell) -> (CellId, Self) {
let id = CellId::new(self.next_cell);
let mut next_cells = self.cells;
let _ = next_cells.insert(id, cell);
let next = Self {
objects: self.objects,
functions: self.functions,
cells: next_cells,
next_object: self.next_object,
next_function: self.next_function,
next_cell: self.next_cell + 1,
};
(id, next)
}
pub fn store_object(self, id: ObjectId, object: Object) -> Result<Self, Self> {
if self.objects.contains_key(&id) {
let mut next_objects = self.objects;
let _ = next_objects.insert(id, object);
Ok(Self {
objects: next_objects,
functions: self.functions,
cells: self.cells,
next_object: self.next_object,
next_function: self.next_function,
next_cell: self.next_cell,
})
} else {
Err(self)
}
}
pub fn store_cell(self, id: CellId, value: Value) -> Result<Self, Self> {
let cloned = self.cells.get(&id).cloned();
if let Some(existing) = cloned {
if existing.is_mutable() {
let mut next_cells = self.cells;
let _ = next_cells.insert(id, existing.with_value(value));
Ok(Self {
objects: self.objects,
functions: self.functions,
cells: next_cells,
next_object: self.next_object,
next_function: self.next_function,
next_cell: self.next_cell,
})
} else {
Err(self)
}
} else {
Err(self)
}
}
#[must_use]
pub fn object(&self, id: ObjectId) -> Option<&Object> {
self.objects.get(&id)
}
#[must_use]
pub fn function(&self, id: FunctionId) -> Option<&FunctionDef> {
self.functions.get(&id)
}
#[must_use]
pub fn cell(&self, id: CellId) -> Option<&Cell> {
self.cells.get(&id)
}
#[must_use]
pub fn object_count(&self) -> usize {
self.objects.len()
}
#[must_use]
pub fn function_count(&self) -> usize {
self.functions.len()
}
#[must_use]
pub fn cell_count(&self) -> usize {
self.cells.len()
}
}