#![allow(dead_code)] #[path = "defs.rs"] pub mod defs; #[inline(never)] fn __do_panic() -> ! { panic!("Called panic from external code."); } #[unsafe(no_mangle)] extern "C" fn panic() -> ! { __do_panic() } #[repr(C)] #[derive(Debug, PartialEq, Eq)] pub struct FFISlice { pub ptr: *const u8, pub len: usize, } #[repr(transparent)] #[derive(Debug, PartialEq, Eq)] pub struct MaybeFFISlice { inner: FFISlice, } impl MaybeFFISlice { pub fn is_none(&self) -> bool { self.inner.ptr.is_null() } pub fn into_option(self) -> Option { if self.is_none() { None } else { Some(self.inner) } } } impl FFISlice { pub unsafe fn as_slice(&self) -> &[T] { unsafe { core::slice::from_raw_parts(self.ptr.cast(), self.len) } } pub unsafe fn as_bytes(&self) -> &[u8] { unsafe { core::slice::from_raw_parts(self.ptr, self.len) } } pub unsafe fn as_str(&self) -> &str { unsafe { core::str::from_utf8_unchecked(self.as_bytes()) } } } #[repr(C)] #[derive(Debug)] pub struct BlobVec { pub data: *mut u8, pub len: usize, pub cap: usize, pub elem_size: usize, pub drop: Option, } impl Default for BlobVec { fn default() -> Self { Self { data: core::ptr::null_mut(), len: 0, cap: 0, elem_size: 0, drop: None, } } } unsafe impl Send for BlobVec {} unsafe impl Sync for BlobVec {} pub mod vec { #![allow(dead_code)] use super::ffi::*; use super::*; #[repr(transparent)] #[derive(Debug)] pub struct Vec { pub vec: BlobVec, _marker: core::marker::PhantomData, } impl Vec { pub fn new() -> Self { Self::new_with(32) } pub fn new_with(capacity: usize) -> Self { let mut vec = BlobVec { data: core::ptr::null_mut(), len: 0, cap: 0, elem_size: 0, drop: None, }; extern "C" fn drop_fn(ptr: *mut u8) { unsafe { core::ptr::drop_in_place::(ptr as *mut T); } } unsafe { vec_init_with( &mut vec, core::mem::size_of::(), Some(drop_fn::), capacity, ); } Self { vec, _marker: core::marker::PhantomData, } } pub fn as_slice(&self) -> &[T] { assert_eq!(self.vec.elem_size, core::mem::size_of::()); unsafe { core::slice::from_raw_parts(self.vec.data as *const T, self.vec.len) } } pub fn as_slice_mut(&mut self) -> &mut [T] { assert_eq!(self.vec.elem_size, core::mem::size_of::()); unsafe { core::slice::from_raw_parts_mut(self.vec.data as *mut T, self.vec.len) } } pub fn push(&mut self, value: T) { let value = core::mem::ManuallyDrop::new(value); unsafe { vec_push(&mut self.vec, &raw const value as *const T as *const u8); } } pub fn insert(&mut self, value: T, index: usize) { if index > self.vec.len { return; } let value = core::mem::ManuallyDrop::new(value); unsafe { vec_insert( &mut self.vec, index, &raw const value as *const T as *const u8, ); } } pub fn pop(&mut self) -> Option { if self.vec.len == 0 { return None; } unsafe { let ptr = vec_get(&mut self.vec, self.vec.len - 1) as *mut T; let value = ptr.read(); vec_pop(&mut self.vec); Some(value) } } pub fn get(&self, index: usize) -> Option<&T> { if index >= self.vec.len { return None; } unsafe { let ptr = vec_get(&raw const self.vec as *mut _, index) as *mut T; Some(&*ptr) } } pub fn get_mut(&mut self, index: usize) -> Option<&mut T> { if index >= self.vec.len { return None; } unsafe { let ptr = vec_get(&raw mut self.vec, index) as *mut T; Some(&mut *ptr) } } pub fn remove(&mut self, index: usize) { if index >= self.vec.len { return; } unsafe { vec_remove(&mut self.vec, index); } } pub fn len(&self) -> usize { self.vec.len } pub fn position(&self, elem: &T, mut cmp: F) -> Option where F: FnMut(&T, &T) -> bool, { extern "C" fn cmp_trampoline bool>( f: *const (), a: *const u8, b: *const u8, ) -> bool { let f = unsafe { &mut *(f as *mut F) }; let a = unsafe { &*(a as *const T) }; let b = unsafe { &*(b as *const T) }; f(a, b) } unsafe { let index = vec_find( &raw const self.vec as *mut _, elem as *const T as *const u8, cmp_trampoline::, &raw mut cmp as *mut F as *mut (), ); if index == usize::MAX { None } else { Some(index) } } } pub fn binary_search_by(&self, elem: &T, mut cmp: F) -> Result where F: FnMut(&T, &T) -> i32, { extern "C" fn cmp_trampoline i32>( f: *const (), a: *const u8, b: *const u8, ) -> i32 { let f = unsafe { &mut *(f as *mut F) }; let a = unsafe { &*(a as *const T) }; let b = unsafe { &*(b as *const T) }; f(a, b) } unsafe { let (index, vacant) = vec_binary_search_by( &raw const self.vec as *mut _, elem as *const T as *const u8, cmp_trampoline::, &raw mut cmp as *mut F as *mut (), ); if vacant { Err(index) } else { Ok(index) } } } pub fn insert_sorted(&self, elem: T, mut cmp: F) -> Result where F: FnMut(&T, &T) -> i32, { extern "C" fn cmp_trampoline i32>( f: *const (), a: *const u8, b: *const u8, ) -> i32 { let f = unsafe { &mut *(f as *mut F) }; let a = unsafe { &*(a as *const T) }; let b = unsafe { &*(b as *const T) }; f(a, b) } let mut elem = core::mem::ManuallyDrop::new(elem); unsafe { let (index, _inserted) = vec_insert_sorted( &raw const self.vec as *mut _, &raw mut elem as *const u8, cmp_trampoline::, &raw mut cmp as *mut F as *mut (), ); Ok(index) } } } } pub mod ffi { #![allow(improper_ctypes)] use super::*; #[allow(dead_code)] unsafe extern "C" { pub unsafe fn vec_init( vec: *mut BlobVec, elem_size: usize, drop: Option, ); pub unsafe fn vec_init_with( vec: *mut BlobVec, elem_size: usize, drop: Option, cap: usize, ); pub unsafe fn vec_push(vec: *mut BlobVec, elem: *const u8); pub unsafe fn vec_insert(vec: *mut BlobVec, index: usize, elem: *const u8); pub unsafe fn vec_pop(vec: *mut BlobVec); pub unsafe fn vec_drop_last(vec: *mut BlobVec); pub unsafe fn vec_get(vec: *mut BlobVec, index: usize) -> *mut u8; pub unsafe fn vec_remove(vec: *mut BlobVec, index: usize); pub unsafe fn vec_drop(vec: *mut BlobVec); pub unsafe fn vec_find( vec: *mut BlobVec, elem: *const u8, cmp: extern "C" fn(*const (), *const u8, *const u8) -> bool, cmp_data: *mut (), ) -> usize; pub unsafe fn vec_binary_search_by( vec: *mut BlobVec, elem: *const u8, cmp: extern "C" fn(*const (), *const u8, *const u8) -> i32, cmp_data: *mut (), ) -> (usize, bool); pub unsafe fn vec_insert_sorted( vec: *mut BlobVec, elem: *const u8, cmp: extern "C" fn(*const (), *const u8, *const u8) -> i32, cmp_data: *mut (), ) -> (usize, bool); } } pub struct DisplaySlice<'a, T>(pub &'a [T]); impl<'a, T: core::fmt::Display> core::fmt::Display for DisplaySlice<'a, T> { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "[")?; for (i, item) in self.0.iter().enumerate() { if i > 0 { write!(f, ", ")?; } write!(f, "{}", item)?; } write!(f, "]") } } impl core::fmt::Display for defs::Type { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self.kind { defs::TYPE_VOID => { write!(f, "void") } defs::TYPE_BOOL => { write!(f, "bool") } defs::TYPE_I32 => { write!(f, "i32") } defs::TYPE_U32 => { write!(f, "u32") } defs::TYPE_STR => { write!(f, "str") } defs::TYPE_POINTER => { let pointee = unsafe { (self.data as *const defs::Type).read() }; write!(f, "*{pointee}",) } _ => { write!(f, "UnknownType") } } } } #[repr(transparent)] pub struct Displayed(pub T); impl core::fmt::Debug for Displayed { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "{}", self.0) } } pub trait DisplayedSliceExt { type Displayed: core::fmt::Debug; fn displayed(self) -> Self::Displayed; } impl<'a, T: core::fmt::Display> DisplayedSliceExt for &'a [T] { type Displayed = &'a [Displayed]; fn displayed(self) -> Self::Displayed { unsafe { core::mem::transmute(self) } } }