use crate::errors::throw_from_windows_err_code; use std::mem::{offset_of, uninitialized}; use std::pin::Pin; use std::ptr; use std::ptr::{NonNull, null_mut}; use windows::Win32::Foundation::{GetLastError, HANDLE}; use windows::Win32::System::Memory::{HEAP_FLAGS, HEAP_NO_SERIALIZE, HeapAlloc, HeapCreate}; pub(crate) struct Allocator { win_heap: HANDLE, last: Option>, } trait Cell { fn get_prev(&self) -> Option>; fn set_prev(&mut self, p: Option>); fn get_next(&self) -> Option>; fn set_next(&mut self, p: Option>); } struct CellImpl { prev: Option>, next: Option>, value: T, } impl Cell for CellImpl { fn get_prev(&self) -> Option> { return self.prev; } fn set_prev(&mut self, p: Option>) { self.prev = p; } fn get_next(&self) -> Option> { return self.next; } fn set_next(&mut self, p: Option>) { self.next = p; } } impl Allocator { pub fn new() -> Self { unsafe { let h; match HeapCreate(HEAP_NO_SERIALIZE, 0, 0) { Ok(hh) => h = hh, Err(err) => throw_from_windows_err_code(err.code()), } return Allocator { win_heap: h, last: None, }; } } pub unsafe fn alloc<'s, T: Drop + 'static>( &'s mut self, init: impl FnOnce(Pin<&mut T>), ) -> Pin<&'s mut T> { let mut p = NonNull::new( HeapAlloc( self.win_heap, HEAP_FLAGS::default(), size_of::>(), ) .cast::>(), ) .unwrap_or_else(|| throw_from_windows_err_code(GetLastError())); if let Some(mut last) = self.last { last.as_mut().set_next(Some(p)); } p.as_mut().prev = self.last; p.as_mut().next = None; self.last = Some(p); init(Pin::new_unchecked(&mut p.as_mut().value)); return Pin::new_unchecked(&mut p.as_mut().value); } pub unsafe fn free(&mut self, p: Pin<&mut T>) { let p = Pin::into_inner_unchecked(p); let c = NonNull::new_unchecked( NonNull::new_unchecked(p) .as_ptr() .map_addr(|a| a - offset_of!(CellImpl, value)) .cast::>(), ); } }