use crate::{IArena, IField, IHeap, IRuntime, IShape, IShapeStore, IStructType, Idx};
use facet_core::{Field, Shape, StructType, Type, UserType};
pub struct LRuntime;
impl IRuntime for LRuntime {
type Shape = &'static Shape;
type Heap = LHeap;
type Arena<T> = LArena<T>;
fn heap() -> Self::Heap {
LHeap::new()
}
fn arena<T>() -> Self::Arena<T> {
LArena::new()
}
}
#[derive(Clone, Copy, Default)]
pub struct LShapeStore;
impl IShapeStore for LShapeStore {
type Handle = &'static Shape;
type View<'a>
= &'static Shape
where
Self: 'a;
fn get<'a>(&'a self, handle: Self::Handle) -> Self::View<'a> {
handle
}
}
impl IShape for &'static Shape {
type StructType = &'static StructType;
type Field = &'static Field;
#[inline]
fn layout(&self) -> Option<std::alloc::Layout> {
self.layout.sized_layout().ok()
}
#[inline]
fn is_struct(&self) -> bool {
matches!(self.ty, Type::User(UserType::Struct(_)))
}
#[inline]
fn as_struct(&self) -> Option<Self::StructType> {
match &self.ty {
Type::User(UserType::Struct(st)) => Some(st),
_ => None,
}
}
}
impl IStructType for &'static StructType {
type Field = &'static Field;
#[inline]
fn field_count(&self) -> usize {
self.fields.len()
}
#[inline]
fn field(&self, idx: usize) -> Option<Self::Field> {
self.fields.get(idx)
}
}
impl IField for &'static Field {
type Shape = &'static Shape;
#[inline]
fn offset(&self) -> usize {
self.offset
}
#[inline]
fn shape(&self) -> Self::Shape {
self.shape.get()
}
}
#[derive(Debug)]
pub struct LHeap;
impl LHeap {
pub const fn new() -> Self {
Self
}
}
impl Default for LHeap {
fn default() -> Self {
Self::new()
}
}
impl IHeap<&'static Shape> for LHeap {
type Ptr = *mut u8;
unsafe fn alloc(&mut self, shape: &'static Shape) -> *mut u8 {
let layout = shape.layout();
if let Some(layout) = layout {
if layout.size() == 0 {
core::ptr::NonNull::dangling().as_ptr()
} else {
let ptr = unsafe { std::alloc::alloc(layout) };
if ptr.is_null() {
std::alloc::handle_alloc_error(layout);
}
ptr
}
} else {
core::ptr::NonNull::dangling().as_ptr()
}
}
unsafe fn dealloc(&mut self, ptr: *mut u8, shape: &'static Shape) {
if let Some(layout) = shape.layout() {
if layout.size() > 0 {
unsafe { std::alloc::dealloc(ptr, layout) };
}
}
}
unsafe fn memcpy(&mut self, dst: *mut u8, src: *mut u8, len: usize) {
if len > 0 {
unsafe {
core::ptr::copy_nonoverlapping(src, dst, len);
}
}
}
unsafe fn drop_in_place(&mut self, ptr: *mut u8, shape: &'static Shape) {
unsafe { shape.call_drop_in_place(facet_core::PtrMut::new(ptr)) };
}
unsafe fn default_in_place(&mut self, ptr: *mut u8, shape: &'static Shape) -> bool {
unsafe {
shape
.call_default_in_place(facet_core::PtrMut::new(ptr).into())
.is_some()
}
}
}
pub struct LArena<T> {
slots: Vec<Option<T>>,
free_list: Vec<u32>,
}
impl<T> LArena<T> {
pub fn new() -> Self {
Self {
slots: vec![None], free_list: Vec::new(),
}
}
}
impl<T> Default for LArena<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> IArena<T> for LArena<T> {
fn alloc(&mut self, value: T) -> Idx<T> {
let raw = if let Some(idx) = self.free_list.pop() {
debug_assert!(self.slots[idx as usize].is_none());
self.slots[idx as usize] = Some(value);
idx
} else {
let idx = self.slots.len();
assert!(idx < u32::MAX as usize, "arena full");
self.slots.push(Some(value));
idx as u32
};
Idx::from_raw(raw)
}
fn free(&mut self, id: Idx<T>) -> T {
debug_assert!(id.is_valid());
let value = self.slots[id.index()].take().expect("double-free");
self.free_list.push(id.raw);
value
}
fn get(&self, id: Idx<T>) -> &T {
debug_assert!(id.is_valid());
self.slots[id.index()].as_ref().expect("slot empty")
}
fn get_mut(&mut self, id: Idx<T>) -> &mut T {
debug_assert!(id.is_valid());
self.slots[id.index()].as_mut().expect("slot empty")
}
}
#[cfg(test)]
mod tests;