use std::{
alloc::Layout,
fmt::{Debug, Formatter, Result as FmtResult},
};
pub mod exports;
pub mod imports;
pub const EXPORTS: &str = include_str!("exports.rs");
pub const IMPORTS: &str = include_str!("imports.rs");
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct AllocatorPtr(pub *mut u8);
unsafe impl Send for AllocatorPtr {}
unsafe impl Sync for AllocatorPtr {}
#[repr(C)]
#[derive(Clone, PartialEq)]
pub struct Allocation(pub AllocatorPtr, pub StableLayout);
impl Debug for Allocation {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
let Self(AllocatorPtr(ptr), StableLayout { size, .. }) = self;
write!(f, "({ptr:?}, {size:?})")
}
}
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Debug)]
pub struct StableLayout {
size: usize,
align: usize,
}
impl From<Layout> for StableLayout {
fn from(layout: Layout) -> Self {
Self {
size: layout.size(),
align: layout.align(),
}
}
}
impl From<StableLayout> for Layout {
fn from(value: StableLayout) -> Self {
unsafe { Layout::from_size_align_unchecked(value.size, value.align) }
}
}
impl From<&StableLayout> for Layout {
fn from(value: &StableLayout) -> Self {
Layout::from(*value)
}
}
#[repr(C)]
#[derive(Clone, PartialEq, Debug)]
pub enum AllocatorOp {
Alloc(Allocation),
Dealloc(Allocation),
}
pub type SliceAllocatorOp = RawSlice<AllocatorOp>;
pub type SliceAllocation = RawSlice<Allocation>;
#[repr(C)]
pub struct RawSlice<T> {
pub ptr: *const T,
pub len: usize,
}
impl<T> RawSlice<T> {
pub unsafe fn into_slice<'a>(self) -> &'a [T] {
unsafe { std::slice::from_raw_parts(self.ptr, self.len) }
}
pub unsafe fn to_vec(&self) -> Vec<T>
where
T: Clone,
{
unsafe { std::slice::from_raw_parts(self.ptr, self.len).to_vec() }
}
}
impl<T> From<&[T]> for RawSlice<T> {
fn from(value: &[T]) -> Self {
RawSlice {
ptr: value.as_ptr(),
len: value.len(),
}
}
}
#[repr(C)]
pub struct Str(RawSlice<u8>);
impl Str {
pub unsafe fn into_str<'a>(self) -> &'a str {
let bytes = unsafe { self.0.into_slice() };
std::str::from_utf8(bytes).expect("Failed to get valid UTF-8 string slice back")
}
pub unsafe fn to_string(&self) -> String {
let bytes = unsafe { self.0.to_vec() };
String::from_utf8(bytes).expect("Failed to convert to valid UTF-8 string")
}
pub const fn const_from(value: &str) -> Self {
let bytes = value.as_bytes();
Self(RawSlice {
ptr: bytes.as_ptr(),
len: bytes.len(),
})
}
}
impl From<&str> for Str {
fn from(value: &str) -> Self {
Self(value.as_bytes().into())
}
}
unsafe impl Send for Str {}
unsafe impl Sync for Str {}
pub type ModuleId = u64;
#[macro_export]
macro_rules! output_to_return_type {
($output:ident) => {
match &$output {
syn::ReturnType::Default => {
quote! { () }
}
syn::ReturnType::Type(_, ty) => quote::ToTokens::to_token_stream(ty),
}
};
}
#[macro_export]
macro_rules! fn_inputs_without_types {
($inputs:expr) => {
$inputs
.iter()
.map(|arg| {
let syn::FnArg::Typed(arg) = arg else {
unreachable!();
};
let ts = quote::ToTokens::to_token_stream(&arg.pat);
quote! { #ts, }
})
.collect::<Vec<_>>()
};
}
pub fn type_needs_box(type_: &str) -> bool {
let stable_copy_type = [
"()", "bool", "u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", "usize", "isize", "f32",
"f64", "char", "u128", "i128",
]
.contains(&type_)
|| type_.starts_with(['*', '&']);
!stable_copy_type
}