use winapi::shared::windef::*;
use winapi::um::winuser::*;
use std::marker::PhantomData;
pub unsafe trait AsHWND {
#[allow(missing_docs)]
fn as_hwnd(&self) -> HWND;
}
unsafe impl AsHWND for () {
fn as_hwnd(&self) -> HWND { std::ptr::null_mut() }
}
pub struct SafeHWND<'w> {
hwnd: HWND,
phantom: PhantomData<&'w HWND>,
}
impl<'w> SafeHWND<'w> {
pub unsafe fn assert(hwnd: &'w HWND) -> Self {
let hwnd = *hwnd;
assert!(hwnd.is_null() || IsWindow(hwnd) != 0);
Self { hwnd, phantom: PhantomData }
}
}
impl std::ops::Drop for SafeHWND<'_> {
fn drop(&mut self) {
assert!(self.hwnd.is_null() || unsafe { IsWindow(self.hwnd) } != 0);
}
}
unsafe impl AsHWND for SafeHWND<'_> {
fn as_hwnd(&self) -> HWND { self.hwnd }
}
#[cfg(test)] mod tests {
use super::*;
use dev::win32::*;
#[test] #[should_panic] fn should_panic_on_create() {
let _safe = unsafe { SafeHWND::assert(&(42 as HWND)) };
}
#[test] #[should_panic] fn should_panic_on_drop() {
let window = create_window("destroyed before dropped");
let safe = unsafe { SafeHWND::assert(&(42 as HWND)) };
unsafe { CloseWindow(window) };
std::mem::drop(safe);
}
#[test] fn should_not_panic_null() {
let safe = unsafe { SafeHWND::assert(&std::ptr::null_mut()) };
std::mem::drop(safe);
}
#[test] fn should_not_panic_outlived() {
let window = create_window("destroyed before dropped");
let safe = unsafe { SafeHWND::assert(&window) };
std::mem::drop(safe);
unsafe { CloseWindow(window) };
}
}