use oxilean_kernel::Name;
use std::collections::HashMap;
use std::hash::{Hash, Hasher};
use super::functions::BoxInto;
use super::rtobject_type::RtObject;
#[derive(Clone, Debug)]
pub struct BigIntData {
pub header: ObjectHeader,
pub negative: bool,
pub digits: Vec<u64>,
}
#[derive(Clone, Debug)]
pub struct StringData {
pub header: ObjectHeader,
pub value: String,
pub cached_hash: Option<u64>,
}
#[derive(Clone, Debug)]
pub struct BigNatData {
pub header: ObjectHeader,
pub digits: Vec<u64>,
}
#[derive(Clone, Debug)]
pub enum ThunkState {
Unevaluated {
closure: RtObject,
},
Evaluating,
Evaluated {
value: RtObject,
},
Excepted {
exception: RtObject,
},
}
#[derive(Clone, Debug)]
pub struct BoxedFloatData {
pub header: ObjectHeader,
pub value: f64,
}
#[derive(Clone, Debug)]
pub struct MutRecData {
pub header: ObjectHeader,
pub closures: Vec<RtObject>,
pub index: u32,
}
pub struct FieldAccess;
impl FieldAccess {
pub fn get_field(obj: &RtObject, field_index: usize) -> Option<RtObject> {
obj.with_heap(|heap| {
if let HeapObject::Constructor(data) = heap {
data.object_fields.get(field_index).cloned()
} else {
None
}
})
.flatten()
}
pub fn set_field(obj: &RtObject, field_index: usize, value: RtObject) -> bool {
obj.with_heap_mut(|heap| {
if let HeapObject::Constructor(data) = heap {
if field_index < data.object_fields.len() {
data.object_fields[field_index] = value;
return true;
}
}
false
})
.unwrap_or(false)
}
pub fn get_ctor_index(obj: &RtObject) -> Option<u32> {
if let Some(idx) = obj.as_small_ctor() {
return Some(idx);
}
obj.with_heap(|heap| {
if let HeapObject::Constructor(data) = heap {
Some(data.ctor_index)
} else {
None
}
})
.flatten()
}
pub fn num_fields(obj: &RtObject) -> Option<usize> {
if obj.is_small_ctor() {
return Some(0);
}
obj.with_heap(|heap| {
if let HeapObject::Constructor(data) = heap {
Some(data.object_fields.len())
} else {
None
}
})
.flatten()
}
pub fn get_scalar_field(obj: &RtObject, field_index: usize) -> Option<u64> {
obj.with_heap(|heap| {
if let HeapObject::Constructor(data) = heap {
data.scalar_fields.get(field_index).copied()
} else {
None
}
})
.flatten()
}
pub fn proj_fst(obj: &RtObject) -> Option<RtObject> {
Self::get_field(obj, 0)
}
pub fn proj_snd(obj: &RtObject) -> Option<RtObject> {
Self::get_field(obj, 1)
}
}
#[derive(Clone, Debug)]
pub enum HeapObject {
Closure(ClosureData),
Constructor(ConstructorData),
Array(ArrayData),
StringObj(StringData),
BigNat(BigNatData),
BigInt(BigIntData),
Thunk(ThunkData),
IoAction(IoActionData),
Task(TaskData),
External(ExternalData),
Pap(PapData),
MutRec(MutRecData),
BoxedFloat(BoxedFloatData),
ByteArray(ByteArrayData),
}
impl HeapObject {
pub fn type_tag(&self) -> TypeTag {
match self {
HeapObject::Closure(_) => TypeTag::Closure,
HeapObject::Constructor(_) => TypeTag::Constructor,
HeapObject::Array(_) => TypeTag::Array,
HeapObject::StringObj(_) => TypeTag::StringObj,
HeapObject::BigNat(_) => TypeTag::BigNat,
HeapObject::BigInt(_) => TypeTag::BigInt,
HeapObject::Thunk(_) => TypeTag::Thunk,
HeapObject::IoAction(_) => TypeTag::IoAction,
HeapObject::Task(_) => TypeTag::Task,
HeapObject::External(_) => TypeTag::External,
HeapObject::Pap(_) => TypeTag::Pap,
HeapObject::MutRec(_) => TypeTag::MutRec,
HeapObject::BoxedFloat(_) => TypeTag::BoxedFloat,
HeapObject::ByteArray(_) => TypeTag::ByteArray,
}
}
pub fn header(&self) -> &ObjectHeader {
match self {
HeapObject::Closure(d) => &d.header,
HeapObject::Constructor(d) => &d.header,
HeapObject::Array(d) => &d.header,
HeapObject::StringObj(d) => &d.header,
HeapObject::BigNat(d) => &d.header,
HeapObject::BigInt(d) => &d.header,
HeapObject::Thunk(d) => &d.header,
HeapObject::IoAction(d) => &d.header,
HeapObject::Task(d) => &d.header,
HeapObject::External(d) => &d.header,
HeapObject::Pap(d) => &d.header,
HeapObject::MutRec(d) => &d.header,
HeapObject::BoxedFloat(d) => &d.header,
HeapObject::ByteArray(d) => &d.header,
}
}
pub fn header_mut(&mut self) -> &mut ObjectHeader {
match self {
HeapObject::Closure(d) => &mut d.header,
HeapObject::Constructor(d) => &mut d.header,
HeapObject::Array(d) => &mut d.header,
HeapObject::StringObj(d) => &mut d.header,
HeapObject::BigNat(d) => &mut d.header,
HeapObject::BigInt(d) => &mut d.header,
HeapObject::Thunk(d) => &mut d.header,
HeapObject::IoAction(d) => &mut d.header,
HeapObject::Task(d) => &mut d.header,
HeapObject::External(d) => &mut d.header,
HeapObject::Pap(d) => &mut d.header,
HeapObject::MutRec(d) => &mut d.header,
HeapObject::BoxedFloat(d) => &mut d.header,
HeapObject::ByteArray(d) => &mut d.header,
}
}
}
#[derive(Clone, Debug)]
pub enum IoActionKind {
Pure(RtObject),
Bind {
action: Box<IoActionKind>,
continuation: RtObject,
},
PrintLn(String),
ReadLn,
ReadFile(String),
WriteFile {
path: String,
contents: String,
},
GetTime,
Exit(i32),
Throw(RtObject),
Catch {
action: Box<IoActionKind>,
handler: RtObject,
},
NewRef(RtObject),
ReadRef(u64),
WriteRef(u64, RtObject),
Spawn(RtObject),
Wait(u64),
}
pub struct ArrayOps;
impl ArrayOps {
pub fn len(obj: &RtObject) -> Option<usize> {
obj.with_heap(|heap| {
if let HeapObject::Array(data) = heap {
Some(data.elements.len())
} else {
None
}
})
.flatten()
}
pub fn is_empty(obj: &RtObject) -> Option<bool> {
Self::len(obj).map(|l| l == 0)
}
pub fn get(obj: &RtObject, index: usize) -> Option<RtObject> {
obj.with_heap(|heap| {
if let HeapObject::Array(data) = heap {
data.elements.get(index).cloned()
} else {
None
}
})
.flatten()
}
pub fn set(obj: &RtObject, index: usize, value: RtObject) -> Option<RtObject> {
let mutated = obj.with_heap_mut(|heap| {
if let HeapObject::Array(data) = heap {
if data.header.is_unique() && index < data.elements.len() {
data.elements[index] = value.clone();
return true;
}
}
false
});
if mutated == Some(true) {
return Some(obj.clone());
}
obj.with_heap(|heap| {
if let HeapObject::Array(data) = heap {
if index < data.elements.len() {
let mut new_elements = data.elements.clone();
new_elements[index] = value;
Some(RtObject::array(new_elements))
} else {
None
}
} else {
None
}
})
.flatten()
}
pub fn push(obj: &RtObject, value: RtObject) -> Option<RtObject> {
let pushed = obj.with_heap_mut(|heap| {
if let HeapObject::Array(data) = heap {
if data.header.is_unique() {
data.elements.push(value.clone());
return true;
}
}
false
});
if pushed == Some(true) {
return Some(obj.clone());
}
obj.with_heap(|heap| {
if let HeapObject::Array(data) = heap {
let mut new_elements = data.elements.clone();
new_elements.push(value);
Some(RtObject::array(new_elements))
} else {
None
}
})
.flatten()
}
pub fn pop(obj: &RtObject) -> Option<(RtObject, RtObject)> {
obj.with_heap(|heap| {
if let HeapObject::Array(data) = heap {
if data.elements.is_empty() {
return None;
}
let mut new_elements = data.elements.clone();
let last = new_elements
.pop()
.expect("elements is non-empty as verified by the is_empty check above");
Some((RtObject::array(new_elements), last))
} else {
None
}
})
.flatten()
}
pub fn mk_array(size: usize, default: RtObject) -> RtObject {
let elements = vec![default; size];
RtObject::array(elements)
}
pub fn concat(a: &RtObject, b: &RtObject) -> Option<RtObject> {
let elems_a = a
.with_heap(|heap| {
if let HeapObject::Array(data) = heap {
Some(data.elements.clone())
} else {
None
}
})
.flatten()?;
let elems_b = b
.with_heap(|heap| {
if let HeapObject::Array(data) = heap {
Some(data.elements.clone())
} else {
None
}
})
.flatten()?;
let mut combined = elems_a;
combined.extend(elems_b);
Some(RtObject::array(combined))
}
pub fn slice(obj: &RtObject, start: usize, end: usize) -> Option<RtObject> {
obj.with_heap(|heap| {
if let HeapObject::Array(data) = heap {
let end = end.min(data.elements.len());
if start > end {
return Some(RtObject::array(Vec::new()));
}
Some(RtObject::array(data.elements[start..end].to_vec()))
} else {
None
}
})
.flatten()
}
pub fn reverse(obj: &RtObject) -> Option<RtObject> {
obj.with_heap(|heap| {
if let HeapObject::Array(data) = heap {
let mut rev = data.elements.clone();
rev.reverse();
Some(RtObject::array(rev))
} else {
None
}
})
.flatten()
}
}
pub struct StringOps;
impl StringOps {
pub fn byte_len(obj: &RtObject) -> Option<usize> {
obj.with_heap(|heap| {
if let HeapObject::StringObj(data) = heap {
Some(data.value.len())
} else {
None
}
})
.flatten()
}
pub fn char_len(obj: &RtObject) -> Option<usize> {
obj.with_heap(|heap| {
if let HeapObject::StringObj(data) = heap {
Some(data.value.chars().count())
} else {
None
}
})
.flatten()
}
pub fn as_str(obj: &RtObject) -> Option<String> {
obj.with_heap(|heap| {
if let HeapObject::StringObj(data) = heap {
Some(data.value.clone())
} else {
None
}
})
.flatten()
}
pub fn concat(a: &RtObject, b: &RtObject) -> Option<RtObject> {
let sa = Self::as_str(a)?;
let sb = Self::as_str(b)?;
Some(RtObject::string(format!("{}{}", sa, sb)))
}
pub fn char_at(obj: &RtObject, index: usize) -> Option<RtObject> {
obj.with_heap(|heap| {
if let HeapObject::StringObj(data) = heap {
data.value.chars().nth(index).map(RtObject::char_val)
} else {
None
}
})
.flatten()
}
pub fn substring(obj: &RtObject, start: usize, len: usize) -> Option<RtObject> {
obj.with_heap(|heap| {
if let HeapObject::StringObj(data) = heap {
let s: String = data.value.chars().skip(start).take(len).collect();
Some(RtObject::string(s))
} else {
None
}
})
.flatten()
}
pub fn to_char_list(obj: &RtObject) -> Option<Vec<RtObject>> {
obj.with_heap(|heap| {
if let HeapObject::StringObj(data) = heap {
Some(data.value.chars().map(RtObject::char_val).collect())
} else {
None
}
})
.flatten()
}
pub fn nat_to_string(n: &RtObject) -> Option<RtObject> {
let v = n.as_small_nat()?;
Some(RtObject::string(format!("{}", v)))
}
pub fn push_char(s: &RtObject, c: &RtObject) -> Option<RtObject> {
let sv = Self::as_str(s)?;
let cv = c.as_char()?;
let mut result = sv;
result.push(cv);
Some(RtObject::string(result))
}
}
#[allow(dead_code)]
pub struct RtObjectCmp;
#[allow(dead_code)]
impl RtObjectCmp {
pub fn numeric_eq(a: &RtObject, b: &RtObject) -> bool {
match (a.as_small_int(), b.as_small_int()) {
(Some(x), Some(y)) => return x == y,
_ => {}
}
match (a.as_float_bits(), b.as_float_bits()) {
(Some(x), Some(y)) => return x == y,
_ => {}
}
false
}
pub fn int_lt(a: &RtObject, b: &RtObject) -> Option<bool> {
match (a.as_small_int(), b.as_small_int()) {
(Some(x), Some(y)) => Some(x < y),
_ => None,
}
}
}
#[derive(Clone, Debug)]
pub struct TypeInfo {
pub name: Name,
pub num_params: u32,
pub is_prop: bool,
pub constructors: Vec<CtorInfo>,
pub special_repr: Option<SpecialRepr>,
}
pub struct TypeRegistry {
types: HashMap<String, TypeInfo>,
}
impl TypeRegistry {
pub fn new() -> Self {
TypeRegistry {
types: HashMap::new(),
}
}
pub fn register(&mut self, info: TypeInfo) {
let key = format!("{}", info.name);
self.types.insert(key, info);
}
pub fn lookup(&self, name: &str) -> Option<&TypeInfo> {
self.types.get(name)
}
pub fn all_types(&self) -> impl Iterator<Item = &TypeInfo> {
self.types.values()
}
pub fn len(&self) -> usize {
self.types.len()
}
pub fn is_empty(&self) -> bool {
self.types.is_empty()
}
pub fn register_builtins(&mut self) {
self.register(TypeInfo {
name: Name::str("Nat"),
num_params: 0,
is_prop: false,
constructors: vec![
CtorInfo {
name: Name::str("Nat").append_str("zero"),
index: 0,
num_scalar_fields: 0,
num_object_fields: 0,
field_names: Vec::new(),
},
CtorInfo {
name: Name::str("Nat").append_str("succ"),
index: 1,
num_scalar_fields: 0,
num_object_fields: 1,
field_names: vec!["n".to_string()],
},
],
special_repr: Some(SpecialRepr::InlineNat),
});
self.register(TypeInfo {
name: Name::str("Bool"),
num_params: 0,
is_prop: false,
constructors: vec![
CtorInfo {
name: Name::str("Bool").append_str("false"),
index: 0,
num_scalar_fields: 0,
num_object_fields: 0,
field_names: Vec::new(),
},
CtorInfo {
name: Name::str("Bool").append_str("true"),
index: 1,
num_scalar_fields: 0,
num_object_fields: 0,
field_names: Vec::new(),
},
],
special_repr: Some(SpecialRepr::InlineBool),
});
self.register(TypeInfo {
name: Name::str("Unit"),
num_params: 0,
is_prop: false,
constructors: vec![CtorInfo {
name: Name::str("Unit").append_str("unit"),
index: 0,
num_scalar_fields: 0,
num_object_fields: 0,
field_names: Vec::new(),
}],
special_repr: Some(SpecialRepr::InlineUnit),
});
self.register(TypeInfo {
name: Name::str("Option"),
num_params: 1,
is_prop: false,
constructors: vec![
CtorInfo {
name: Name::str("Option").append_str("none"),
index: 0,
num_scalar_fields: 0,
num_object_fields: 0,
field_names: Vec::new(),
},
CtorInfo {
name: Name::str("Option").append_str("some"),
index: 1,
num_scalar_fields: 0,
num_object_fields: 1,
field_names: vec!["val".to_string()],
},
],
special_repr: None,
});
self.register(TypeInfo {
name: Name::str("List"),
num_params: 1,
is_prop: false,
constructors: vec![
CtorInfo {
name: Name::str("List").append_str("nil"),
index: 0,
num_scalar_fields: 0,
num_object_fields: 0,
field_names: Vec::new(),
},
CtorInfo {
name: Name::str("List").append_str("cons"),
index: 1,
num_scalar_fields: 0,
num_object_fields: 2,
field_names: vec!["head".to_string(), "tail".to_string()],
},
],
special_repr: None,
});
self.register(TypeInfo {
name: Name::str("Prod"),
num_params: 2,
is_prop: false,
constructors: vec![CtorInfo {
name: Name::str("Prod").append_str("mk"),
index: 0,
num_scalar_fields: 0,
num_object_fields: 2,
field_names: vec!["fst".to_string(), "snd".to_string()],
}],
special_repr: None,
});
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ObjectFlags(u8);
impl ObjectFlags {
pub fn empty() -> Self {
ObjectFlags(0)
}
pub fn moved() -> Self {
ObjectFlags(0x01)
}
pub fn pinned() -> Self {
ObjectFlags(0x02)
}
pub fn shared() -> Self {
ObjectFlags(0x04)
}
pub fn finalized() -> Self {
ObjectFlags(0x08)
}
pub fn immutable() -> Self {
ObjectFlags(0x10)
}
pub fn has(&self, flag: ObjectFlags) -> bool {
(self.0 & flag.0) != 0
}
pub fn set(&mut self, flag: ObjectFlags) {
self.0 |= flag.0;
}
pub fn clear(&mut self, flag: ObjectFlags) {
self.0 &= !flag.0;
}
pub fn bits(&self) -> u8 {
self.0
}
}
#[allow(dead_code)]
#[derive(Debug, Default)]
pub struct RtObjectPool {
free: Vec<RtObject>,
}
#[allow(dead_code)]
impl RtObjectPool {
pub fn new() -> Self {
Self::default()
}
pub fn acquire_unit(&mut self) -> RtObject {
self.free.pop().unwrap_or_else(RtObject::unit)
}
pub fn release(&mut self, obj: RtObject) {
if self.free.len() < 64 {
self.free.push(obj);
}
}
pub fn free_count(&self) -> usize {
self.free.len()
}
}
#[derive(Clone, Debug)]
pub struct ByteArrayData {
pub header: ObjectHeader,
pub bytes: Vec<u8>,
}
#[derive(Clone, Debug)]
pub struct CtorInfo {
pub name: Name,
pub index: u32,
pub num_scalar_fields: u16,
pub num_object_fields: u16,
pub field_names: Vec<String>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[repr(u8)]
pub enum TypeTag {
Closure = 0,
Constructor = 1,
Array = 2,
StringObj = 3,
BigNat = 4,
BigInt = 5,
Thunk = 6,
IoAction = 7,
Task = 8,
External = 9,
Pap = 10,
MutRec = 11,
ClosureEnv = 12,
BoxedFloat = 13,
ByteArray = 14,
Module = 15,
}
impl TypeTag {
pub fn from_u8(v: u8) -> Option<TypeTag> {
match v {
0 => Some(TypeTag::Closure),
1 => Some(TypeTag::Constructor),
2 => Some(TypeTag::Array),
3 => Some(TypeTag::StringObj),
4 => Some(TypeTag::BigNat),
5 => Some(TypeTag::BigInt),
6 => Some(TypeTag::Thunk),
7 => Some(TypeTag::IoAction),
8 => Some(TypeTag::Task),
9 => Some(TypeTag::External),
10 => Some(TypeTag::Pap),
11 => Some(TypeTag::MutRec),
12 => Some(TypeTag::ClosureEnv),
13 => Some(TypeTag::BoxedFloat),
14 => Some(TypeTag::ByteArray),
15 => Some(TypeTag::Module),
_ => None,
}
}
pub fn as_u8(self) -> u8 {
self as u8
}
}
#[derive(Clone, Debug)]
pub struct ObjectHeader {
pub rc_count: u32,
pub type_tag: TypeTag,
pub flags: ObjectFlags,
pub size_words: u16,
}
impl ObjectHeader {
pub fn new(type_tag: TypeTag, size_words: u16) -> Self {
ObjectHeader {
rc_count: 1,
type_tag,
flags: ObjectFlags::empty(),
size_words,
}
}
pub fn inc_ref(&mut self) {
self.rc_count = self.rc_count.saturating_add(1);
}
pub fn dec_ref(&mut self) -> bool {
if self.rc_count == 0 {
return true;
}
self.rc_count -= 1;
self.rc_count == 0
}
pub fn is_unique(&self) -> bool {
self.rc_count == 1
}
pub fn is_shared(&self) -> bool {
self.rc_count > 1 || self.flags.has(ObjectFlags::shared())
}
pub fn size_bytes(&self) -> usize {
self.size_words as usize * 8
}
pub fn encode(&self) -> u64 {
let rc = self.rc_count as u64;
let tag = self.type_tag.as_u8() as u64;
let flags = self.flags.bits() as u64;
let size = self.size_words as u64;
(rc << 32) | (tag << 24) | (flags << 16) | size
}
pub fn decode(bits: u64) -> Option<Self> {
let rc = (bits >> 32) as u32;
let tag_byte = ((bits >> 24) & 0xFF) as u8;
let flags_byte = ((bits >> 16) & 0xFF) as u8;
let size = (bits & 0xFFFF) as u16;
let type_tag = TypeTag::from_u8(tag_byte)?;
Some(ObjectHeader {
rc_count: rc,
type_tag,
flags: ObjectFlags(flags_byte),
size_words: size,
})
}
}
#[derive(Clone, Debug)]
pub struct PapData {
pub header: ObjectHeader,
pub closure: RtObject,
pub arity: u16,
pub args: Vec<RtObject>,
}
#[derive(Clone, Debug)]
pub struct TaskData {
pub header: ObjectHeader,
pub state: TaskState,
pub task_id: u64,
}
pub struct ThunkOps;
impl ThunkOps {
pub fn is_evaluated(obj: &RtObject) -> Option<bool> {
obj.with_heap(|heap| {
if let HeapObject::Thunk(data) = heap {
Some(matches!(data.state, ThunkState::Evaluated { .. }))
} else {
None
}
})
.flatten()
}
pub fn get_value(obj: &RtObject) -> Option<RtObject> {
obj.with_heap(|heap| {
if let HeapObject::Thunk(data) = heap {
if let ThunkState::Evaluated { ref value } = data.state {
Some(value.clone())
} else {
None
}
} else {
None
}
})
.flatten()
}
pub fn set_value(obj: &RtObject, value: RtObject) -> bool {
obj.with_heap_mut(|heap| {
if let HeapObject::Thunk(data) = heap {
data.state = ThunkState::Evaluated { value };
true
} else {
false
}
})
.unwrap_or(false)
}
pub fn mark_evaluating(obj: &RtObject) -> bool {
obj.with_heap_mut(|heap| {
if let HeapObject::Thunk(data) = heap {
data.state = ThunkState::Evaluating;
true
} else {
false
}
})
.unwrap_or(false)
}
pub fn is_evaluating(obj: &RtObject) -> Option<bool> {
obj.with_heap(|heap| {
if let HeapObject::Thunk(data) = heap {
Some(matches!(data.state, ThunkState::Evaluating))
} else {
None
}
})
.flatten()
}
}
#[derive(Clone, Debug, Default)]
pub struct AllocationStats {
pub total_allocations: u64,
pub total_deallocations: u64,
pub live_objects: u64,
pub peak_objects: u64,
pub total_bytes_allocated: u64,
}
#[derive(Clone, Debug)]
pub struct ConstructorData {
pub header: ObjectHeader,
pub ctor_index: u32,
pub num_fields: u16,
pub scalar_fields: Vec<u64>,
pub object_fields: Vec<RtObject>,
pub name: Option<Name>,
}
#[derive(Clone, Debug)]
pub struct ThunkData {
pub header: ObjectHeader,
pub state: ThunkState,
}
#[derive(Clone, Debug)]
pub struct ClosureData {
pub header: ObjectHeader,
pub fn_index: u32,
pub arity: u16,
pub env_size: u16,
pub env: Vec<RtObject>,
}
#[derive(Clone, Debug)]
pub enum SpecialRepr {
InlineNat,
InlineBool,
InlineUnit,
InlineChar,
EnumTag {
num_ctors: u32,
},
PackedStruct {
size_bytes: u32,
},
BoxedArray,
BoxedString,
}
pub struct ObjectStore {
objects: Vec<Option<HeapObject>>,
free_list: Vec<usize>,
stats: AllocationStats,
}
impl ObjectStore {
pub fn new() -> Self {
ObjectStore {
objects: Vec::new(),
free_list: Vec::new(),
stats: AllocationStats::default(),
}
}
pub fn with_capacity(cap: usize) -> Self {
ObjectStore {
objects: Vec::with_capacity(cap),
free_list: Vec::new(),
stats: AllocationStats::default(),
}
}
pub fn allocate(&mut self, obj: HeapObject) -> usize {
self.stats.total_allocations += 1;
self.stats.live_objects += 1;
if self.stats.live_objects > self.stats.peak_objects {
self.stats.peak_objects = self.stats.live_objects;
}
self.stats.total_bytes_allocated += obj.header().size_bytes() as u64;
if let Some(id) = self.free_list.pop() {
self.objects[id] = Some(obj);
id
} else {
let id = self.objects.len();
self.objects.push(Some(obj));
id
}
}
pub fn deallocate(&mut self, id: usize) -> Option<HeapObject> {
if id >= self.objects.len() {
return None;
}
let obj = self.objects[id].take();
if obj.is_some() {
self.free_list.push(id);
self.stats.total_deallocations += 1;
self.stats.live_objects = self.stats.live_objects.saturating_sub(1);
}
obj
}
pub fn get(&self, id: usize) -> Option<&HeapObject> {
self.objects.get(id).and_then(|o| o.as_ref())
}
pub fn get_mut(&mut self, id: usize) -> Option<&mut HeapObject> {
self.objects.get_mut(id).and_then(|o| o.as_mut())
}
pub fn stats(&self) -> &AllocationStats {
&self.stats
}
pub fn live_count(&self) -> usize {
self.stats.live_objects as usize
}
pub fn capacity(&self) -> usize {
self.objects.capacity()
}
pub(super) fn global_store<R>(f: impl FnOnce(&mut ObjectStore) -> R) -> R {
thread_local! {
static STORE : std::cell::RefCell < ObjectStore > =
std::cell::RefCell::new(ObjectStore::new());
}
STORE.with(|store| f(&mut store.borrow_mut()))
}
}
#[derive(Clone, Debug)]
pub struct ArrayData {
pub header: ObjectHeader,
pub elements: Vec<RtObject>,
pub capacity: usize,
}
#[derive(Clone, Debug)]
pub struct IoActionData {
pub header: ObjectHeader,
pub kind: IoActionKind,
}
#[derive(Clone, Debug)]
pub enum TaskState {
Pending,
Running,
Completed(RtObject),
Failed(RtObject),
Cancelled,
}
#[derive(Clone, Debug)]
pub struct ExternalData {
pub header: ObjectHeader,
pub type_name: String,
pub payload: Vec<u8>,
}
pub struct ObjectTable {
entries: HashMap<String, RtObject>,
order: Vec<String>,
}
impl ObjectTable {
pub fn new() -> Self {
ObjectTable {
entries: HashMap::new(),
order: Vec::new(),
}
}
pub fn insert(&mut self, name: String, obj: RtObject) {
if !self.entries.contains_key(&name) {
self.order.push(name.clone());
}
self.entries.insert(name, obj);
}
pub fn get(&self, name: &str) -> Option<&RtObject> {
self.entries.get(name)
}
pub fn contains(&self, name: &str) -> bool {
self.entries.contains_key(name)
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = (&str, &RtObject)> {
self.order
.iter()
.filter_map(move |name| self.entries.get(name).map(|obj| (name.as_str(), obj)))
}
pub fn remove(&mut self, name: &str) -> Option<RtObject> {
if let Some(obj) = self.entries.remove(name) {
self.order.retain(|n| n != name);
Some(obj)
} else {
None
}
}
pub fn clear(&mut self) {
self.entries.clear();
self.order.clear();
}
}
pub struct RtArith;
impl RtArith {
pub fn nat_add(a: &RtObject, b: &RtObject) -> Option<RtObject> {
let av = a.as_small_nat()?;
let bv = b.as_small_nat()?;
Some(RtObject::nat(av.wrapping_add(bv)))
}
pub fn nat_sub(a: &RtObject, b: &RtObject) -> Option<RtObject> {
let av = a.as_small_nat()?;
let bv = b.as_small_nat()?;
Some(RtObject::nat(av.saturating_sub(bv)))
}
pub fn nat_mul(a: &RtObject, b: &RtObject) -> Option<RtObject> {
let av = a.as_small_nat()?;
let bv = b.as_small_nat()?;
Some(RtObject::nat(av.wrapping_mul(bv)))
}
pub fn nat_div(a: &RtObject, b: &RtObject) -> Option<RtObject> {
let av = a.as_small_nat()?;
let bv = b.as_small_nat()?;
if bv == 0 {
return Some(RtObject::nat(0));
}
Some(RtObject::nat(av / bv))
}
pub fn nat_mod(a: &RtObject, b: &RtObject) -> Option<RtObject> {
let av = a.as_small_nat()?;
let bv = b.as_small_nat()?;
if bv == 0 {
return Some(RtObject::nat(av));
}
Some(RtObject::nat(av % bv))
}
pub fn nat_le(a: &RtObject, b: &RtObject) -> Option<RtObject> {
let av = a.as_small_nat()?;
let bv = b.as_small_nat()?;
Some(RtObject::bool_val(av <= bv))
}
pub fn nat_lt(a: &RtObject, b: &RtObject) -> Option<RtObject> {
let av = a.as_small_nat()?;
let bv = b.as_small_nat()?;
Some(RtObject::bool_val(av < bv))
}
pub fn nat_eq(a: &RtObject, b: &RtObject) -> Option<RtObject> {
let av = a.as_small_nat()?;
let bv = b.as_small_nat()?;
Some(RtObject::bool_val(av == bv))
}
pub fn bool_and(a: &RtObject, b: &RtObject) -> Option<RtObject> {
let av = a.as_bool()?;
let bv = b.as_bool()?;
Some(RtObject::bool_val(av && bv))
}
pub fn bool_or(a: &RtObject, b: &RtObject) -> Option<RtObject> {
let av = a.as_bool()?;
let bv = b.as_bool()?;
Some(RtObject::bool_val(av || bv))
}
pub fn bool_not(a: &RtObject) -> Option<RtObject> {
let av = a.as_bool()?;
Some(RtObject::bool_val(!av))
}
pub fn int_add(a: &RtObject, b: &RtObject) -> Option<RtObject> {
let av = a.as_small_int()?;
let bv = b.as_small_int()?;
Some(av.wrapping_add(bv).box_into())
}
pub fn int_sub(a: &RtObject, b: &RtObject) -> Option<RtObject> {
let av = a.as_small_int()?;
let bv = b.as_small_int()?;
Some(av.wrapping_sub(bv).box_into())
}
pub fn int_mul(a: &RtObject, b: &RtObject) -> Option<RtObject> {
let av = a.as_small_int()?;
let bv = b.as_small_int()?;
Some(av.wrapping_mul(bv).box_into())
}
pub fn int_neg(a: &RtObject) -> Option<RtObject> {
let av = a.as_small_int()?;
Some(av.wrapping_neg().box_into())
}
}