Skip to main content

arcdps/
util.rs

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