#[repr(C)] pub struct BlobVec { pub data: *mut u8, pub len: usize, pub cap: usize, pub elem_size: usize, pub drop: Option, } #[unsafe(no_mangle)] extern "C" fn panic() -> ! { panic!("Called panic from external code."); } unsafe impl Send for BlobVec {} unsafe impl Sync for BlobVec {} unsafe extern "C" { unsafe fn vec_init(vec: *mut BlobVec, elem_size: usize, drop: Option); unsafe fn vec_push(vec: *mut BlobVec, elem: *const u8, size: usize); unsafe fn vec_pop(vec: *mut BlobVec); unsafe fn vec_get(vec: *mut BlobVec, index: usize) -> *mut u8; #[allow(dead_code)] unsafe fn vec_remove(vec: *mut BlobVec, index: usize); #[allow(dead_code)] unsafe fn vec_drop(vec: *mut BlobVec); } fn main() { static mut DROPS: usize = 1; fn get_drops() -> usize { unsafe { (&raw const DROPS).read() } } unsafe fn update_drops(f: impl FnOnce(&mut usize)) { unsafe { let drops = &raw mut DROPS; f(&mut *drops); } } let mut vec = BlobVec { data: core::ptr::null_mut(), len: 0, cap: 0, elem_size: 1, drop: None, }; fn as_slice(vec: &BlobVec) -> &[T] { assert_eq!(vec.elem_size, core::mem::size_of::()); unsafe { core::slice::from_raw_parts(vec.data as *const T, vec.len) } } extern "C" fn drop(ptr: *mut u8) { unsafe { update_drops(|drops| { *drops *= ptr.cast::().read() as usize; }); } } unsafe { vec_init(&mut vec, 4, Some(drop)); let mut value: u32 = 2; assert_eq!(vec.len, 0); vec_push(&mut vec, &value as *const u32 as *const u8, 4); assert_eq!(vec.len, 1); assert_eq!(as_slice::(&vec), &[2]); let retrieved = *(vec_get(&mut vec, 0) as *mut u32); assert_eq!(retrieved, 2); assert_eq!(get_drops(), 1); vec_pop(&mut vec); assert_eq!(vec.len, 0); assert_eq!(get_drops(), 2); value = 3; vec_push(&mut vec, &value as *const u32 as *const u8, 4); assert_eq!(as_slice::(&vec), &[3]); value = 5; vec_push(&mut vec, &value as *const u32 as *const u8, 4); assert_eq!(as_slice::(&vec), &[3, 5]); assert_eq!(vec.len, 2); vec_pop(&mut vec); vec_pop(&mut vec); assert_eq!(get_drops(), 2 * 3 * 5); eprintln!("Push/pop test passed\n"); } }