1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
//! Miscellaneous utilities.

use std::{
    ffi::{CStr, OsStr},
    iter,
    os::{raw::c_char, windows::prelude::OsStrExt},
    slice, str,
};
use windows::{
    core::PCSTR,
    Win32::{
        Foundation::{FARPROC, HMODULE},
        System::LibraryLoader::GetProcAddress,
    },
};

/// Helper to convert a string pointer to a [`prim@str`].
#[inline]
pub unsafe fn str_from_cstr<'a>(ptr: *const c_char) -> Option<&'a str> {
    if ptr.is_null() {
        None
    } else {
        CStr::from_ptr(ptr).to_str().ok()
    }
}

/// Helper to convert a string pointer and a length to a [`prim@str`].
///
/// The pointer needs to be non-null. Panics if the string is invalid UTF-8.
#[inline]
#[allow(dead_code)]
pub unsafe fn str_from_cstr_len<'a>(ptr: *const c_char, len: u64) -> &'a str {
    let slice = slice::from_raw_parts(ptr as *const u8, len as usize);
    str::from_utf8(slice).expect("cstr with invalid utf8")
}

/// Strips the `':'` prefix from an account name if present.
#[inline]
pub fn strip_account_prefix(account_name: &str) -> &str {
    account_name.strip_prefix(':').unwrap_or(account_name)
}

/// Helper to retrieve an exported function.
/// Name needs to be null-terminated.
#[inline]
pub unsafe fn exported_proc(handle: HMODULE, name: &'static str) -> FARPROC {
    GetProcAddress(handle, PCSTR(name.as_ptr()))
}

/// Helper to convert a string to a Windows wide char string.
#[inline]
pub unsafe fn str_to_wide(string: impl AsRef<str>) -> Vec<u16> {
    OsStr::new(string.as_ref())
        .encode_wide()
        .chain(iter::once(0))
        .collect()
}

/// Helper to define function types with optional unwind ABI.
macro_rules! abi {
    ( $( $vis:vis type $name:ident = unsafe extern fn( $( $args:tt )* ) $( -> $ret:ty )? ; )* ) => {
        $(
            #[cfg(feature = "unwind")]
            $vis type $name = unsafe extern "C-unwind" fn( $( $args )* ) $( -> $ret )?;

            #[cfg(not(feature = "unwind"))]
            $vis type $name = unsafe extern "C" fn( $( $args )* ) $( -> $ret )?;
        )*
    };
}

pub(crate) use abi;