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#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
18#[repr(transparent)]
19pub struct Share<T>(pub T);
20
21unsafe impl<T> Sync for Share<T> {}
22
23unsafe impl<T> Send for Share<T> {}
24
25/// Helper to convert a string pointer to a [`prim@str`].
26#[inline]
27pub unsafe fn str_from_cstr<'a>(ptr: *const c_char) -> Option<&'a str> {
28    if ptr.is_null() {
29        None
30    } else {
31        CStr::from_ptr(ptr).to_str().ok()
32    }
33}
34
35/// Helper to convert a string pointer and a length to a [`prim@str`].
36///
37/// The pointer needs to be non-null. Panics if the string is invalid UTF-8.
38#[inline]
39#[allow(dead_code)]
40pub unsafe fn str_from_cstr_len<'a>(ptr: *const c_char, len: u64) -> &'a str {
41    let slice = slice::from_raw_parts(ptr as *const u8, len as usize);
42    str::from_utf8(slice).expect("cstr with invalid utf8")
43}
44
45/// Strips the `':'` prefix from an account name if present.
46#[inline]
47pub fn strip_account_prefix(account_name: &str) -> &str {
48    account_name.strip_prefix(':').unwrap_or(account_name)
49}
50
51/// Helper to retrieve an exported function.
52/// Name needs to be null-terminated.
53#[inline]
54pub unsafe fn exported_proc(handle: HMODULE, name: &'static str) -> FARPROC {
55    GetProcAddress(handle, PCSTR(name.as_ptr()))
56}
57
58/// Helper to convert a string to a Windows wide char string.
59#[inline]
60pub unsafe fn str_to_wide(string: impl AsRef<str>) -> Vec<u16> {
61    OsStr::new(string.as_ref())
62        .encode_wide()
63        .chain(iter::once(0))
64        .collect()
65}
66
67/// Helper to define function types with optional unwind ABI.
68macro_rules! abi {
69    ( $( $vis:vis type $name:ident = unsafe extern fn( $( $args:tt )* ) $( -> $ret:ty )? ; )* ) => {
70        $(
71            #[cfg(feature = "unwind")]
72            $vis type $name = unsafe extern "C-unwind" fn( $( $args )* ) $( -> $ret )?;
73
74            #[cfg(not(feature = "unwind"))]
75            $vis type $name = unsafe extern "C" fn( $( $args )* ) $( -> $ret )?;
76        )*
77    };
78}
79
80pub(crate) use abi;