rich_sdl2_rust/
sdl.rs

1use static_assertions::assert_not_impl_all;
2use std::{cell::Cell, ffi::CStr, marker::PhantomData};
3
4use crate::bind;
5
6/// A version for SDL2.
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub struct SdlVersion {
9    /// A major number in the version.
10    pub major: u8,
11    /// A minor number in the version.
12    pub minor: u8,
13    /// A patch number in the version.
14    pub patch: u8,
15}
16
17impl From<bind::SDL_version> for SdlVersion {
18    fn from(
19        bind::SDL_version {
20            major,
21            minor,
22            patch,
23        }: bind::SDL_version,
24    ) -> Self {
25        Self {
26            major,
27            minor,
28            patch,
29        }
30    }
31}
32
33/// A root controller for SDL2. But some sub-feature does not require `Sdl`.
34pub struct Sdl {
35    _phantom: PhantomData<Cell<u8>>,
36}
37
38assert_not_impl_all!(Sdl: Send, Sync);
39
40impl Sdl {
41    /// Setup the SDL2 system.
42    ///
43    /// # Panics
44    ///
45    /// Panics if SDL2 system is already initialized such as there are existing `Sdl` instances
46    #[must_use]
47    pub fn new() -> Self {
48        let ret = unsafe {
49            bind::SDL_SetMainReady();
50            bind::SDL_Init(0)
51        };
52        if ret != 0 {
53            Self::error_then_panic("Sdl")
54        }
55        Self {
56            _phantom: PhantomData,
57        }
58    }
59
60    /// Returns the version of SDL2.
61    #[must_use]
62    pub fn version() -> SdlVersion {
63        use bind::SDL_version;
64        let mut ver = SDL_version {
65            major: 0,
66            minor: 0,
67            patch: 0,
68        };
69        unsafe { bind::SDL_GetVersion(&mut ver) }
70        ver.into()
71    }
72
73    /// Returns the revision string.
74    #[must_use]
75    pub fn revision_str() -> &'static str {
76        let raw_str = unsafe { bind::SDL_GetRevision() };
77        unsafe { std::ffi::CStr::from_ptr(raw_str) }
78            .to_str()
79            .expect("Getting revision failed")
80    }
81
82    /// Returns the revision number.
83    #[must_use]
84    pub fn revision_num() -> u32 {
85        (unsafe { bind::SDL_GetRevisionNumber() }) as u32
86    }
87
88    /// Gets the platform string.
89    #[must_use]
90    pub fn platform() -> &'static str {
91        let cstr = unsafe { CStr::from_ptr(bind::SDL_GetPlatform()) };
92        cstr.to_str().unwrap()
93    }
94
95    /// On an unrecoverable error detected, panics with the provided `context`.
96    #[inline(always)]
97    pub fn error_then_panic(context: &'static str) -> ! {
98        eprintln!("{} error: {}", context, Self::error());
99        panic!("Unrecoverable Sdl error occurred");
100    }
101
102    /// Reads the error string from SDL2.
103    #[must_use]
104    pub fn error() -> String {
105        let raw_str = unsafe { bind::SDL_GetError() };
106        let error = unsafe { std::ffi::CStr::from_ptr(raw_str) }
107            .to_str()
108            .expect("Getting error failed")
109            .to_owned();
110        unsafe { bind::SDL_ClearError() }
111        error
112    }
113}
114
115impl Default for Sdl {
116    fn default() -> Self {
117        Self::new()
118    }
119}
120
121impl Drop for Sdl {
122    fn drop(&mut self) {
123        unsafe { bind::SDL_Quit() }
124    }
125}