1use core::{
2 marker::PhantomData,
3 sync::atomic::{AtomicBool, Ordering},
4};
5
6use alloc::sync::Arc;
7use fermium::prelude::*;
8
9use crate::error::{get_error, SdlError};
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
12#[repr(transparent)]
13pub struct InitFlags(SDL_InitFlags);
14impl InitFlags {
15 pub const AUDIO: Self = Self(SDL_INIT_AUDIO);
16 pub const EVENTS: Self = Self(SDL_INIT_EVENTS);
17 pub const EVERYTHING: Self = Self(SDL_INIT_EVERYTHING);
18 pub const GAMECONTROLLER: Self = Self(SDL_INIT_GAMECONTROLLER);
19 pub const HAPTIC: Self = Self(SDL_INIT_HAPTIC);
20 pub const JOYSTICK: Self = Self(SDL_INIT_JOYSTICK);
21 pub const SENSOR: Self = Self(SDL_INIT_SENSOR);
22 pub const TIMER: Self = Self(SDL_INIT_TIMER);
23 pub const VIDEO: Self = Self(SDL_INIT_VIDEO);
24}
25impl core::ops::BitOr for InitFlags {
26 type Output = Self;
27 #[inline]
28 fn bitor(self, rhs: Self) -> Self::Output {
29 Self(self.0 | rhs.0)
30 }
31}
32
33static SDL_IS_ACTIVE: AtomicBool = AtomicBool::new(false);
34
35#[repr(transparent)]
36pub(crate) struct SdlInit(PhantomData<*mut ()>);
37impl SdlInit {
38 #[inline]
39 pub fn try_new_arc(flags: InitFlags) -> Result<Arc<Self>, SdlError> {
40 #[cfg(any(target_os = "macos", target_os = "ios"))]
41 {
42 use objc::{class, msg_send, sel, sel_impl};
43 let is_main: bool = unsafe { msg_send![class!(NSThread), isMainThread] };
44 if !is_main {
45 return Err(SdlError::new("beryllium: can only be init on the main thread."));
46 }
47 }
48 match SDL_IS_ACTIVE.compare_exchange(false, true, Ordering::Acquire, Ordering::Acquire) {
49 Ok(_) => {
50 let ret = unsafe { SDL_Init(flags.0) };
51 if ret == 0 {
52 #[allow(clippy::arc_with_non_send_sync)]
53 Ok(Arc::new(Self(PhantomData)))
54 } else {
55 Err(get_error())
56 }
57 }
58 Err(_) => Err(SdlError::new("beryllium: Double initialization.")),
59 }
60 }
61}
62impl Drop for SdlInit {
63 #[inline]
64 fn drop(&mut self) {
65 unsafe { SDL_Quit() }
66 SDL_IS_ACTIVE.store(false, Ordering::Release);
67 }
68}