beryllium/
init.rs

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}