rust_libretro/
util.rs

1//! Utility functions
2use std::fmt::Display;
3
4use super::*;
5
6/// Tries to convert a pointer to a [`CString`] into a Rust [`str`]
7#[allow(clippy::not_unsafe_ptr_arg_deref)]
8pub fn get_str_from_pointer<'a>(ptr: *const c_char) -> Option<&'a str> {
9    if ptr.is_null() {
10        return None;
11    }
12
13    let slice = unsafe { CStr::from_ptr(ptr) };
14
15    std::str::from_utf8(slice.to_bytes()).ok()
16}
17
18/// Tries to convert a pointer to a [`CString`] into a Rust [`String`]
19pub fn get_string_from_pointer(ptr: *const c_char) -> Option<String> {
20    get_str_from_pointer(ptr).map(|s| s.to_owned())
21}
22
23/// Tries to convert a pointer to a [`CString`] into a Rust [`Path`]
24pub fn get_path_from_pointer<'a>(ptr: *const c_char) -> Option<&'a Path> {
25    if ptr.is_null() {
26        return None;
27    }
28
29    let slice = unsafe { CStr::from_ptr(ptr as *const _) };
30
31    cfg_if::cfg_if! {
32        if #[cfg(target_family = "unix")] {
33            use std::os::unix::ffi::OsStrExt;
34            let oss = OsStr::from_bytes(slice.to_bytes());
35            let path: &Path = oss.as_ref();
36            Some(path)
37        }
38        else {
39            let s = std::str::from_utf8(slice.to_bytes()).expect("valid UTF-8");
40            let path: &Path = s.as_ref();
41            Some(path)
42        }
43    }
44}
45
46/// Tries to convert a pointer to a [`CString`] into a Rust [`PathBuf`]
47pub fn get_path_buf_from_pointer(ptr: *mut c_char) -> Option<PathBuf> {
48    get_str_from_pointer(ptr).map(PathBuf::from)
49}
50
51#[derive(Debug, Copy, Clone)]
52pub struct Version {
53    major: u16,
54    minor: u16,
55    patch: u16,
56}
57
58impl Version {
59    pub const fn new(major: u16, minor: u16, patch: u16) -> Self {
60        if patch > 0xfff {
61            panic!("Invalid patch level");
62        }
63
64        if minor > 0x3ff {
65            panic!("Invalid minor level");
66        }
67
68        if major > 0x3ff {
69            panic!("Invalid major level");
70        }
71
72        Self {
73            major,
74            minor,
75            patch,
76        }
77    }
78
79    pub const fn from_u32(version: u32) -> Self {
80        // 0bMMMMMMMMMM_mmmmmmmmmm_pppppppppppp
81        Self {
82            major: ((version >> 22) & 0x3ff) as u16,
83            minor: ((version >> 12) & 0x3ff) as u16,
84            patch: (version & 0xfff) as u16,
85        }
86    }
87
88    pub const fn to_u32(self) -> u32 {
89        // 0bMMMMMMMMMM_mmmmmmmmmm_pppppppppppp
90        ((self.major as u32) << 22) | ((self.minor as u32) << 12) | (self.patch as u32)
91    }
92}
93
94impl Display for Version {
95    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96        write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
97    }
98}