#![feature(decl_macro, generic_atomic)]
use std::{
alloc::{Layout, alloc, dealloc},
ffi::c_char,
ptr,
};
pub(crate) mod fs;
pub(crate) mod input;
pub(crate) mod logger;
pub(crate) mod net;
pub(crate) mod string;
macro c_enum {
(
$ty:ident : $base_ty:ty {
$($rest:tt),* $(,)?
}
) => {
type $ty = $base_ty;
c_enum!(@impl $base_ty, 0, $($rest),*);
},
(
$ty:ident {
$($rest:tt),* $(,)?
}
) => {
type $ty = i32;
c_enum!(@impl i32, 0, $($rest),*);
},
(@impl $base_ty:ty, $_idx:expr,) => {},
(@impl $base_ty:ty, $_idx:expr,
$name:ident = $val:literal, $($rest:tt),*
) => {
const $name: $base_ty = $val;
c_enum!(@impl $base_ty, ($val + 1), $($rest),*);
},
(@impl $base_ty:ty, $idx:expr,
$name:ident, $($rest:tt),*
) => {
const $name: $base_ty = $idx;
c_enum!(@impl $base_ty, ($idx + 1), $($rest),*);
},
(@impl $base_ty:ty, $_idx:expr,
$name:ident = $val:literal
) => {
const $name: $base_ty = $val;
},
(@impl $base_ty:ty, $idx:expr,
$name:ident
) => {
const $name: $base_ty = $idx;
},
}
unsafe fn move_to_heap<T>(value: T) -> *mut T {
return Box::into_raw(Box::new(value));
}
unsafe fn drop_from_heap<T>(ptr: *mut T) {
unsafe {
if !ptr.is_aligned() || ptr.is_null() {
return;
}
drop(Box::from_raw(ptr));
}
}
unsafe fn move_to_stack<T>(ptr: *mut T) -> Option<T> {
unsafe {
if !ptr.is_aligned() || ptr.is_null() {
return None;
}
return Some(*Box::from_raw(ptr));
}
}
unsafe fn ptr_to_slice_mut<'a, T>(ptr: *mut T, size: usize) -> Option<&'a mut [T]> {
unsafe {
if size == 0 {
return Some(&mut []);
}
if !ptr.is_aligned() || ptr.is_null() {
return None;
}
return Some(std::slice::from_raw_parts_mut(ptr, size));
}
}
unsafe fn ptr_to_slice<'a, T>(ptr: *const T, size: usize) -> Option<&'a [T]> {
unsafe {
if size == 0 {
return Some(&[]);
}
if !ptr.is_aligned() || ptr.is_null() {
return None;
}
return Some(std::slice::from_raw_parts(ptr, size));
}
}
unsafe fn ptr_to_ref_mut<'a, T>(ptr: *mut T) -> Option<&'a mut T> {
unsafe {
if !ptr.is_aligned() || ptr.is_null() {
return None;
}
return Some(&mut *ptr);
}
}
unsafe fn ptr_to_ref<'a, T>(ptr: *const T) -> Option<&'a T> {
unsafe {
if !ptr.is_aligned() || ptr.is_null() {
return None;
}
return Some(&*ptr);
}
}
unsafe fn move_slice_to_heap<T: Copy>(slice: &[T], size: &mut usize) -> *mut T {
*size = slice.len();
unsafe {
let layout = Layout::array::<T>(slice.len()).unwrap();
let ptr = alloc(layout) as *mut T;
if ptr.is_null() {
std::alloc::handle_alloc_error(layout);
}
ptr::copy_nonoverlapping(slice.as_ptr(), ptr, slice.len());
return ptr;
}
}
unsafe fn drop_slice_from_heap<T>(ptr: *mut T, size: usize) {
if ptr.is_null() || size == 0 {
return;
}
let layout = Layout::array::<T>(size).unwrap();
unsafe {
dealloc(ptr as *mut u8, layout);
}
}
unsafe fn set_if_valid<T>(ptr: *mut T, value: T) {
unsafe {
let Some(ptr) = ptr_to_ref_mut(ptr) else {
return;
};
*ptr = value;
}
}
#[unsafe(no_mangle)]
unsafe extern "C" fn pawkit_free_array(slice: *mut u8, size: usize) {
unsafe {
drop_slice_from_heap(slice, size);
}
}
#[unsafe(no_mangle)]
unsafe extern "C" fn pawkit_free_string(str: *const c_char, size: usize) {
unsafe {
drop_slice_from_heap(str as *mut u8, size);
}
}
unsafe fn cstr_to_str<'a>(cstr: *const c_char, len: usize) -> Option<&'a str> {
if cstr.is_null() {
return None;
}
let bytes = unsafe { ptr_to_slice(cstr as *const u8, len)? };
return std::str::from_utf8(bytes).ok();
}
unsafe fn str_to_cstr<'a>(s: &'a str, len: &mut usize) -> *const c_char {
*len = s.len();
return s.as_ptr() as *const c_char;
}
unsafe fn disown_str_to_cstr(s: &str, len: &mut usize) -> *const c_char {
unsafe {
return move_slice_to_heap(s.as_bytes(), len) as *const c_char;
}
}