hassle_rs/
os.rs

1// Allow uppercase names to match Windows API:
2#![allow(clippy::upper_case_acronyms)]
3
4#[cfg(windows)]
5mod os_defs {
6    pub use winapi::shared::{
7        ntdef::{HRESULT, LPCSTR, LPCWSTR, LPSTR, LPWSTR, WCHAR},
8        wtypes::BSTR,
9    };
10
11    pub use winapi::um::combaseapi::CoTaskMemFree;
12    pub use winapi::um::oleauto::{SysFreeString, SysStringLen};
13}
14
15#[cfg(not(windows))]
16mod os_defs {
17    pub type CHAR = std::os::raw::c_char;
18    pub type UINT = u32;
19    pub type WCHAR = widestring::WideChar;
20    pub type OLECHAR = WCHAR;
21    pub type LPSTR = *mut CHAR;
22    pub type LPWSTR = *mut WCHAR;
23    pub type LPCSTR = *const CHAR;
24    pub type LPCWSTR = *const WCHAR;
25    pub type BSTR = *mut OLECHAR;
26    pub type LPBSTR = *mut BSTR;
27    pub type HRESULT = i32;
28
29    /// Returns a mutable pointer to the length prefix of the string
30    fn len_ptr(p: BSTR) -> *mut UINT {
31        // The first four bytes before the pointer contain the length prefix:
32        // https://docs.microsoft.com/en-us/previous-versions/windows/desktop/automat/bstr#remarks
33        unsafe { p.cast::<UINT>().offset(-1) }
34    }
35
36    #[allow(non_snake_case)]
37    /// # Safety
38    /// `p` must be a valid pointer to an allocation made with `malloc`, or null.
39    pub unsafe fn CoTaskMemFree(p: *mut libc::c_void) {
40        // https://github.com/microsoft/DirectXShaderCompiler/blob/56e22b30c5e43632f56a1f97865f37108ec35463/include/dxc/Support/WinAdapter.h#L46
41        if !p.is_null() {
42            libc::free(p)
43        }
44    }
45
46    #[allow(non_snake_case)]
47    /// # Safety
48    /// `p` must be a valid pointer to an allocation made with `malloc`, or null.
49    pub unsafe fn SysFreeString(p: BSTR) {
50        // https://github.com/microsoft/DirectXShaderCompiler/blob/56e22b30c5e43632f56a1f97865f37108ec35463/lib/DxcSupport/WinAdapter.cpp#L50-L53
51        if !p.is_null() {
52            libc::free(len_ptr(p).cast::<_>())
53        }
54    }
55
56    #[allow(non_snake_case)]
57    /// Returns the size of `p` in bytes, excluding terminating NULL character
58    ///
59    /// # Safety
60    /// `p` must be a valid pointer to a [`BSTR`] with size-prefix in the `4` leading bytes, or null.
61    ///
62    /// https://docs.microsoft.com/en-us/previous-versions/windows/desktop/automat/bstr#remarks
63    pub unsafe fn SysStringByteLen(p: BSTR) -> UINT {
64        if p.is_null() {
65            0
66        } else {
67            *len_ptr(p)
68        }
69    }
70
71    #[allow(non_snake_case)]
72    /// Returns the size of `p` in characters, excluding terminating NULL character
73    ///
74    /// # Safety
75    /// `p` must be a valid pointer to a [`BSTR`] with size-prefix in the `4` leading bytes, or null.
76    ///
77    /// https://docs.microsoft.com/en-us/previous-versions/windows/desktop/automat/bstr#remarks
78    pub unsafe fn SysStringLen(p: BSTR) -> UINT {
79        SysStringByteLen(p) / std::mem::size_of::<OLECHAR>() as UINT
80    }
81}
82
83pub use os_defs::*;
84
85#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
86#[repr(transparent)]
87#[must_use]
88pub struct HRESULT(pub os_defs::HRESULT);
89impl HRESULT {
90    pub fn is_err(&self) -> bool {
91        self.0 < 0
92    }
93}
94
95impl From<i32> for HRESULT {
96    fn from(v: i32) -> Self {
97        Self(v)
98    }
99}
100
101impl std::fmt::Debug for HRESULT {
102    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103        <Self as std::fmt::Display>::fmt(self, f)
104    }
105}
106
107impl std::fmt::Display for HRESULT {
108    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
109        f.write_fmt(format_args!("{:#x}", self))
110    }
111}
112
113impl std::fmt::LowerHex for HRESULT {
114    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
115        let prefix = if f.alternate() { "0x" } else { "" };
116        let bare_hex = format!("{:x}", self.0.abs());
117        // https://stackoverflow.com/a/44712309
118        f.pad_integral(self.0 >= 0, prefix, &bare_hex)
119        // <i32 as std::fmt::LowerHex>::fmt(&self.0, f)
120    }
121}