1 use core::{mem, ptr};
2 
3 use winapi::ctypes::c_void;
4 
5 use crate::SysResult;
6 
7 const GHND: winapi::ctypes::c_uint = 0x42;
8 
9 const BYTES_LAYOUT: alloc::alloc::Layout = alloc::alloc::Layout::new::<u8>();
10 
11 #[inline]
noop(_: *mut c_void)12 fn noop(_: *mut c_void) {
13 }
14 
15 #[inline]
free_rust_mem(data: *mut c_void)16 fn free_rust_mem(data: *mut c_void) {
17     unsafe {
18         alloc::alloc::dealloc(data as _, BYTES_LAYOUT)
19     }
20 }
21 
22 #[inline]
unlock_data(data: *mut c_void)23 fn unlock_data(data: *mut c_void) {
24     unsafe {
25         winapi::um::winbase::GlobalUnlock(data);
26     }
27 }
28 
29 #[inline]
free_global_mem(data: *mut c_void)30 fn free_global_mem(data: *mut c_void) {
31     unsafe {
32         winapi::um::winbase::GlobalFree(data);
33     }
34 }
35 
36 pub struct Scope<T: Copy>(pub T, pub fn(T));
37 
38 impl<T: Copy> Drop for Scope<T> {
39     #[inline(always)]
drop(&mut self)40     fn drop(&mut self) {
41         (self.1)(self.0)
42     }
43 }
44 
45 pub struct RawMem(Scope<*mut c_void>);
46 
47 impl RawMem {
48     #[inline(always)]
new_rust_mem(size: usize) -> Self49     pub fn new_rust_mem(size: usize) -> Self {
50         let mem = unsafe {
51             alloc::alloc::alloc_zeroed(alloc::alloc::Layout::array::<u8>(size).expect("To create layout for bytes"))
52         };
53         debug_assert!(!mem.is_null());
54         Self(Scope(mem as _, free_rust_mem))
55     }
56 
57     #[inline(always)]
new_global_mem(size: usize) -> SysResult<Self>58     pub fn new_global_mem(size: usize) -> SysResult<Self> {
59         unsafe {
60             let mem = winapi::um::winbase::GlobalAlloc(GHND, size as _);
61             if mem.is_null() {
62                 Err(error_code::SystemError::last())
63             } else {
64                 Ok(Self(Scope(mem, free_global_mem)))
65             }
66         }
67     }
68 
69     #[inline(always)]
from_borrowed(ptr: ptr::NonNull<c_void>) -> Self70     pub fn from_borrowed(ptr: ptr::NonNull<c_void>) -> Self {
71         Self(Scope(ptr.as_ptr(), noop))
72     }
73 
74     #[inline(always)]
get(&self) -> *mut c_void75     pub fn get(&self) -> *mut c_void {
76         (self.0).0
77     }
78 
79     #[inline(always)]
release(self)80     pub fn release(self) {
81         mem::forget(self)
82     }
83 
lock(&self) -> SysResult<(ptr::NonNull<c_void>, Scope<*mut c_void>)>84     pub fn lock(&self) -> SysResult<(ptr::NonNull<c_void>, Scope<*mut c_void>)> {
85         let ptr = unsafe {
86             winapi::um::winbase::GlobalLock(self.get())
87         };
88 
89         match ptr::NonNull::new(ptr) {
90             Some(ptr) => Ok((ptr, Scope(self.get(), unlock_data))),
91             None => Err(error_code::SystemError::last()),
92         }
93     }
94 }
95