arcdps/
util.rs

1//! Miscellaneous utilities.
2
3use std::{
4    ffi::{CStr, OsStr},
5    iter,
6    os::{raw::c_char, windows::prelude::OsStrExt},
7    slice, str,
8};
9use windows::{
10    core::PCSTR,
11    Win32::{
12        Foundation::{FARPROC, HMODULE},
13        System::LibraryLoader::GetProcAddress,
14    },
15};
16
17/// Helper to store raw types as globals.
18#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
19#[repr(transparent)]
20pub struct Share<T>(T);
21
22impl<T> Share<T> {
23    /// Creates a new share value.
24    pub unsafe fn new(value: T) -> Self {
25        Self(value)
26    }
27
28    /// Returns a reference to the inner value-.
29    ///
30    /// The inner value must be safe to be accessed from this thread at this time.
31    pub unsafe fn get(&self) -> &T {
32        &self.0
33    }
34}
35
36unsafe impl<T> Sync for Share<T> {}
37
38unsafe impl<T> Send for Share<T> {}
39
40/// Helper to convert a string pointer to a [`prim@str`].
41#[inline]
42pub unsafe fn str_from_cstr<'a>(ptr: *const c_char) -> Option<&'a str> {
43    if ptr.is_null() {
44        None
45    } else {
46        CStr::from_ptr(ptr).to_str().ok()
47    }
48}
49
50/// Helper to convert a string pointer and a length to a [`prim@str`].
51///
52/// The pointer needs to be non-null. Panics if the string is invalid UTF-8.
53#[inline]
54#[allow(dead_code)]
55pub unsafe fn str_from_cstr_len<'a>(ptr: *const c_char, len: u64) -> &'a str {
56    let slice = slice::from_raw_parts(ptr as *const u8, len as usize);
57    str::from_utf8(slice).expect("cstr with invalid utf8")
58}
59
60/// Strips the `':'` prefix from an account name if present.
61#[inline]
62pub fn strip_account_prefix(account_name: &str) -> &str {
63    account_name.strip_prefix(':').unwrap_or(account_name)
64}
65
66/// Helper to retrieve an exported function.
67/// Name needs to be null-terminated.
68#[inline]
69pub unsafe fn exported_proc(handle: HMODULE, name: &'static str) -> FARPROC {
70    GetProcAddress(handle, PCSTR(name.as_ptr()))
71}
72
73/// Helper to convert a string to a Windows wide char string.
74#[inline]
75pub unsafe fn str_to_wide(string: impl AsRef<str>) -> Vec<u16> {
76    OsStr::new(string.as_ref())
77        .encode_wide()
78        .chain(iter::once(0))
79        .collect()
80}
81
82/// Helper to define function types with optional unwind ABI.
83macro_rules! abi {
84    ( $( $vis:vis type $name:ident = unsafe extern fn( $( $args:tt )* ) $( -> $ret:ty )? ; )* ) => {
85        $(
86            #[cfg(feature = "unwind")]
87            $vis type $name = unsafe extern "C-unwind" fn( $( $args )* ) $( -> $ret )?;
88
89            #[cfg(not(feature = "unwind"))]
90            $vis type $name = unsafe extern "C" fn( $( $args )* ) $( -> $ret )?;
91        )*
92    };
93}
94
95pub(crate) use abi;