1#![no_std]
2
3#[cfg(feature = "alloc")]
4extern crate alloc;
5#[cfg(feature = "std")]
6extern crate std;
7
8#[cfg(feature = "args")]
9use alloc::ffi::CString;
10#[cfg(feature = "alloc")]
11use alloc::format;
12use core::ffi::{c_char, c_int, c_void};
13use sdl_sys_bindgen::*;
14
15pub trait SdlApp: Sized + Send {
22 type Error: core::fmt::Debug;
24
25 #[cfg(feature = "args")]
32 fn init(args: &[CString]) -> Result<Self, Self::Error>;
33 #[cfg(not(feature = "args"))]
40 fn init() -> Result<Self, Self::Error>;
41
42 fn iterate(&mut self) -> SDL_AppResult;
44
45 fn event(&mut self, event: &SDL_Event) -> SDL_AppResult;
47
48 fn quit(&mut self, result: SDL_AppResult);
52}
53
54pub fn run_app<A: SdlApp>() -> i32 {
56 extern "C" fn c_init<A: SdlApp>(
58 appstate: *mut *mut c_void,
59 #[allow(unused_variables)] argc: c_int,
60 #[allow(unused_variables)] argv: *mut *mut c_char,
61 ) -> SDL_AppResult {
62 let init_result = {
63 #[cfg(feature = "args")]
64 {
65 let args = unsafe {
66 let argc = argc as usize;
67 std::vec::Vec::from_raw_parts(argv, argc, argc)
68 .iter()
69 .map(|arg| CString::from_raw(*arg))
70 .collect::<std::vec::Vec<CString>>()
71 };
72 A::init(args.as_slice())
73 }
74 #[cfg(not(feature = "args"))]
75 {
76 A::init()
77 }
78 };
79
80 match init_result {
81 Ok(app) => {
82 unsafe {
83 let ptr = SDL_malloc(core::mem::size_of::<A>());
84 if ptr.is_null() {
85 log_error(SDL_GetError());
86 return SDL_AppResult::SDL_APP_FAILURE;
87 }
88 let state_ptr = ptr as *mut A;
89 core::ptr::write(state_ptr, app);
90 *appstate = ptr;
91 }
92 SDL_AppResult::SDL_APP_CONTINUE
93 }
94 #[allow(unused_variables)]
95 Err(e) => {
96 #[cfg(feature = "alloc")]
97 let err_msg = format!("{:?}\0", e);
98 #[cfg(not(feature = "alloc"))]
99 let err_msg = "SDL app initialization failed\0";
100 log_error(err_msg.as_ptr() as *const c_char);
101 SDL_AppResult::SDL_APP_FAILURE
102 }
103 }
104 }
105
106 extern "C" fn c_iter<A: SdlApp>(appstate: *mut c_void) -> SDL_AppResult {
108 if appstate.is_null() {
109 return SDL_AppResult::SDL_APP_FAILURE;
110 }
111 let app = unsafe { &mut *(appstate as *mut A) };
112 app.iterate()
113 }
114
115 extern "C" fn c_event<A: SdlApp>(
117 appstate: *mut c_void,
118 event: *mut SDL_Event,
119 ) -> SDL_AppResult {
120 if appstate.is_null() || event.is_null() {
121 return SDL_AppResult::SDL_APP_FAILURE;
122 }
123 let app = unsafe { &mut *(appstate as *mut A) };
124 app.event(unsafe { &*event })
125 }
126
127 extern "C" fn c_quit<A: SdlApp>(appstate: *mut c_void, result: SDL_AppResult) {
129 if !appstate.is_null() {
130 unsafe {
131 let mut app = core::ptr::read(appstate as *mut A);
132 app.quit(result);
133 SDL_free(appstate);
134 }
135 }
136 }
137
138 extern "C" fn enter_callbacks<A: SdlApp>(argc: c_int, argv: *mut *mut c_char) -> i32 {
139 unsafe {
140 SDL_EnterAppMainCallbacks(
141 argc,
142 argv,
143 Some(c_init::<A>),
144 Some(c_iter::<A>),
145 Some(c_event::<A>),
146 Some(c_quit::<A>),
147 )
148 }
149 }
150
151 unsafe {
152 #[cfg(feature = "args")]
153 let arg_count = std::env::args().count();
154 SDL_RunApp(
155 {
156 #[cfg(feature = "args")]
157 {
158 arg_count as c_int
159 }
160 #[cfg(not(feature = "args"))]
161 {
162 0
163 }
164 },
165 {
166 #[cfg(feature = "args")]
167 {
168 let mut vec: std::vec::Vec<*mut c_char> =
169 std::vec::Vec::with_capacity(arg_count);
170 for arg in std::env::args() {
171 let c_string = CString::new(arg);
172 if let Ok(c_string) = c_string {
173 vec.push(c_string.into_raw());
174 }
175 }
176 vec.into_raw_parts().0
177 }
178 #[cfg(not(feature = "args"))]
179 {
180 core::ptr::null_mut()
181 }
182 },
183 Some(enter_callbacks::<A>),
184 core::ptr::null_mut(), )
186 }
187}
188
189fn log_error(msg: *const c_char) {
190 unsafe {
191 SDL_LogError(
192 SDL_LogCategory::SDL_LOG_CATEGORY_APPLICATION.0 as c_int,
193 msg,
194 );
195 }
196}