rich_sdl2_rust/event/joystick/
guid.rs

1//! The GUID of joystick devices.
2
3use std::{
4    ffi::{CStr, CString},
5    os::raw::c_int,
6};
7
8use crate::bind;
9
10/// A GUID associated with joystick devices.
11#[derive(Debug, Clone)]
12pub struct Guid([u8; 16]);
13
14impl Guid {
15    /// Returns mapping string for the game controller having the GUID.
16    #[must_use]
17    pub fn mapping(&self) -> String {
18        let ptr = unsafe {
19            bind::SDL_GameControllerMappingForGUID(bind::SDL_JoystickGUID { data: self.0 })
20        };
21        let cstr = unsafe { CStr::from_ptr(ptr) };
22        let ret = cstr.to_string_lossy().to_string();
23        unsafe { bind::SDL_free(ptr.cast()) };
24        ret
25    }
26}
27
28impl std::fmt::Display for Guid {
29    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30        let mut buf = [0u8; 33];
31        unsafe {
32            bind::SDL_JoystickGetGUIDString(
33                bind::SDL_JoystickGUID { data: self.0 },
34                buf.as_mut_ptr().cast(),
35                buf.len() as c_int,
36            );
37        }
38        write!(f, "{}", String::from_utf8_lossy(&buf))
39    }
40}
41
42/// An error to tell the failure on parsing `Guid` from string, showing that it is invalid length to convert into.
43#[derive(Debug, Clone, PartialEq, Eq)]
44pub struct InvalidLengthError {
45    actual_length: usize,
46}
47
48impl std::fmt::Display for InvalidLengthError {
49    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50        write!(
51            f,
52            "length must equals to 16 but actual length was {}",
53            self.actual_length
54        )
55    }
56}
57
58impl std::error::Error for InvalidLengthError {}
59
60impl std::str::FromStr for Guid {
61    type Err = InvalidLengthError;
62
63    fn from_str(s: &str) -> Result<Self, Self::Err> {
64        if s.len() != 16 {
65            return Err(InvalidLengthError {
66                actual_length: s.len(),
67            });
68        }
69        let c_str = CString::new(s).expect("invalid string");
70        let raw_guid = unsafe { bind::SDL_JoystickGetGUIDFromString(c_str.as_ptr()) };
71        Ok(raw_guid.into())
72    }
73}
74
75impl From<bind::SDL_JoystickGUID> for Guid {
76    fn from(raw: bind::SDL_JoystickGUID) -> Self {
77        Self(raw.data)
78    }
79}