96 lines
2.5 KiB
Rust
96 lines
2.5 KiB
Rust
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<NonNull<dyn Cell>>,
|
|
}
|
|
|
|
trait Cell {
|
|
fn get_prev(&self) -> Option<NonNull<dyn Cell>>;
|
|
fn set_prev(&mut self, p: Option<NonNull<dyn Cell>>);
|
|
fn get_next(&self) -> Option<NonNull<dyn Cell>>;
|
|
fn set_next(&mut self, p: Option<NonNull<dyn Cell>>);
|
|
}
|
|
|
|
struct CellImpl<T> {
|
|
prev: Option<NonNull<dyn Cell>>,
|
|
next: Option<NonNull<dyn Cell>>,
|
|
value: T,
|
|
}
|
|
|
|
impl<T> Cell for CellImpl<T> {
|
|
fn get_prev(&self) -> Option<NonNull<dyn Cell>> {
|
|
return self.prev;
|
|
}
|
|
|
|
fn set_prev(&mut self, p: Option<NonNull<dyn Cell>>) {
|
|
self.prev = p;
|
|
}
|
|
|
|
fn get_next(&self) -> Option<NonNull<dyn Cell>> {
|
|
return self.next;
|
|
}
|
|
|
|
fn set_next(&mut self, p: Option<NonNull<dyn Cell>>) {
|
|
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::<CellImpl<T>>(),
|
|
)
|
|
.cast::<CellImpl<T>>(),
|
|
)
|
|
.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<T: Drop>(&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<T>, value))
|
|
.cast::<CellImpl<T>>(),
|
|
);
|
|
}
|
|
}
|