1#![cfg_attr(not(test), no_std)]
2#![cfg_attr(feature = "try-trait-v2", feature(try_trait_v2))]
3
4extern crate sys;
5extern crate alloc;
6
7use core::ffi::c_float;
8use core::ffi::c_int;
9use core::ffi::c_uint;
10use core::time::Duration;
11use alloc::string::String;
12
13
14pub mod time;
15pub mod lang;
16pub mod update;
17pub mod event;
18
19pub mod prelude {
20 pub use crate::System;
21 pub use crate::time::*;
22 pub use crate::lang::*;
23 pub use crate::update::*;
24 pub use crate::event::*;
25}
26
27use time::*;
28use lang::*;
29
30
31#[derive(Debug, Clone, Copy)]
32pub struct System<Api = api::Default>(Api);
33
34impl System<api::Default> {
35 #[allow(non_snake_case)]
39 pub fn Default() -> Self { Self(Default::default()) }
40}
41
42impl System<api::Cache> {
43 #[allow(non_snake_case)]
47 pub fn Cached() -> Self { Self(Default::default()) }
48}
49
50impl<Api: Default + api::Api> Default for System<Api> {
51 fn default() -> Self { Self(Default::default()) }
52}
53
54impl<Api: Default + api::Api> System<Api> {
55 pub fn new() -> Self { Self(Default::default()) }
56}
57
58impl<Api: api::Api> System<Api> {
59 pub fn new_with(api: Api) -> Self { Self(api) }
60
61 #[inline(always)]
62 pub const fn inner(&self) -> Api
63 where Api: Copy {
64 self.0
65 }
66}
67
68
69impl<Api: api::Api> System<Api> {
70 #[doc(alias = "sys::ffi::playdate_sys::getLanguage")]
72 #[inline(always)]
73 pub fn language(&self) -> PDLanguage {
74 let f = self.0.get_language();
75 unsafe { f() }
76 }
77
78 #[doc(alias = "sys::ffi::playdate_sys::getCurrentTimeMilliseconds")]
80 #[inline(always)]
81 pub fn current_time(&self) -> Duration { Duration::from_millis(self.current_time_ms().into()) }
82
83 #[doc(alias = "sys::ffi::playdate_sys::getCurrentTimeMilliseconds")]
85 pub fn current_time_ms(&self) -> c_uint {
86 let f = self.0.get_current_time_milliseconds();
87 unsafe { f() }
88 }
89
90 #[doc(alias = "sys::ffi::playdate_sys::getSecondsSinceEpoch")]
96 #[inline(always)]
97 pub fn seconds_since_epoch(&self) -> c_uint {
98 let f = self.0.get_seconds_since_epoch();
99 unsafe { f(core::ptr::null_mut()) }
100 }
101
102 #[doc(alias = "sys::ffi::playdate_sys::getSecondsSinceEpoch")]
107 #[inline(always)]
108 pub fn seconds_since_epoch_with_ms(&self) -> (c_uint, c_uint) {
109 let f = self.0.get_seconds_since_epoch();
110 let mut millis: c_uint = 0;
111 let secs = unsafe { f(&mut millis) };
112 (secs, millis)
113 }
114
115 #[doc(alias = "sys::ffi::playdate_sys::getSecondsSinceEpoch")]
117 #[inline(always)]
118 pub fn time_since_epoch(&self) -> Duration {
119 let f = self.0.get_seconds_since_epoch();
120 let mut millis: c_uint = 0;
121 let secs = unsafe { f(&mut millis) };
122 Duration::new(secs.into(), 0) + Duration::from_millis(millis.into())
123 }
124
125 #[doc(alias = "sys::ffi::playdate_sys::drawFPS")]
127 #[inline(always)]
128 pub fn draw_fps(&self, x: c_int, y: c_int) {
129 let f = self.0.draw_fps();
130 unsafe { f(x, y) }
131 }
132
133 #[doc(alias = "sys::ffi::playdate_sys::getFlipped")]
135 #[inline(always)]
136 pub fn flipped(&self) -> bool {
137 let f = self.0.get_flipped();
138 unsafe { f() == 1 }
139 }
140
141 #[doc(alias = "sys::ffi::playdate_sys::setAutoLockDisabled")]
143 #[inline(always)]
144 pub fn set_auto_lock_disabled(&self, disable: bool) {
145 let f = self.0.set_auto_lock_disabled();
146 unsafe { f(disable as _) }
147 }
148
149 #[doc(alias = "sys::ffi::playdate_sys::getReduceFlashing")]
151 #[inline(always)]
152 pub fn reduce_flashing(&self) -> bool {
153 let f = self.0.get_reduce_flashing();
154 unsafe { f() == 1 }
155 }
156
157 #[doc(alias = "sys::ffi::playdate_sys::getElapsedTime")]
165 #[inline(always)]
166 pub fn elapsed_time_secs(&self) -> c_float {
167 let f = self.0.get_elapsed_time();
168 unsafe { f() }
169 }
170
171 #[doc(alias = "sys::ffi::playdate_sys::getElapsedTime")]
173 #[inline(always)]
174 pub fn elapsed_time(&self) -> Duration {
175 let f = self.0.get_elapsed_time();
176 let secs = unsafe { f() };
177 Duration::from_secs_f32(secs)
178 }
179
180 #[doc(alias = "sys::ffi::playdate_sys::resetElapsedTime")]
182 #[inline(always)]
183 pub fn reset_elapsed_time(&self) {
184 let f = self.0.reset_elapsed_time();
185 unsafe { f() }
186 }
187
188 #[doc(alias = "sys::ffi::playdate_sys::getBatteryPercentage")]
190 #[inline(always)]
191 pub fn battery_percentage(&self) -> c_float {
192 let f = self.0.get_battery_percentage();
193 unsafe { f() }
194 }
195
196
197 #[doc(alias = "sys::ffi::playdate_sys::getBatteryVoltage")]
199 #[inline(always)]
200 pub fn battery_voltage(&self) -> c_float {
201 let f = self.0.get_battery_voltage();
202 unsafe { f() }
203 }
204
205 #[doc(alias = "sys::ffi::playdate_sys::getTimezoneOffset")]
207 #[inline(always)]
208 pub fn timezone_offset(&self) -> i32 {
209 let f = self.0.get_timezone_offset();
210 unsafe { f() }
211 }
212
213 #[doc(alias = "sys::ffi::playdate_sys::shouldDisplay24HourTime")]
215 #[inline(always)]
216 pub fn should_display_24_hour_time(&self) -> bool {
217 let f = self.0.should_display_24_hour_time();
218 unsafe { f() == 1 }
219 }
220
221 #[doc(alias = "sys::ffi::playdate_sys::convertEpochToDateTime")]
223 #[inline(always)]
224 pub fn convert_epoch_to_date_time(&self, epoch: u32) -> PDDateTime {
225 let mut dt = PDDateTime { year: 0,
226 month: 0,
227 day: 0,
228 weekday: 0,
229 hour: 0,
230 minute: 0,
231 second: 0 };
232 self.convert_epoch_to_date_time_to(epoch, &mut dt);
233 dt
234 }
235
236 #[doc(alias = "sys::ffi::playdate_sys::convertEpochToDateTime")]
238 #[inline(always)]
239 pub fn convert_epoch_to_date_time_to(&self, epoch: u32, dt: &mut PDDateTime) {
240 let f = self.0.convert_epoch_to_date_time();
241 unsafe { f(epoch, dt) }
242 }
243
244 #[doc(alias = "sys::ffi::playdate_sys::convertDateTimeToEpoch")]
246 pub fn convert_date_time_to_epoch(&self, dt: &PDDateTime) -> u32 {
247 let f = self.0.convert_date_time_to_epoch();
248 let epoch = unsafe { f(dt as *const _ as *mut _) };
249 let _ = dt; epoch
251 }
252
253 #[doc(alias = "sys::ffi::playdate_sys::setSerialMessageCallback")]
255 pub fn set_serial_message_callback<F>(&self, callback: Option<F>)
256 where F: 'static + FnMut(String) + Sized {
257 use core::ffi::c_char;
258 use core::ffi::CStr;
259 use alloc::boxed::Box;
260 use alloc::string::String;
261
262
263 static mut STORE: Option<Box<dyn FnMut(String)>> = None;
264
265 pub unsafe extern "C" fn proxy_serial_message_callback<F: FnMut(String)>(data: *const c_char) {
266 let data = CStr::from_ptr(data as _).to_string_lossy().into_owned();
267 if let Some(ref mut f) = STORE.as_mut() {
268 f(data)
269 } else {
270 panic!("missed callback")
278 }
279 }
280
281
282 let f = self.0.set_serial_message_callback();
283
284 if let Some(callback) = callback {
285 let boxed = Box::new(callback);
286 unsafe { STORE = Some(boxed as _) }
288 unsafe { f(Some(proxy_serial_message_callback::<F>)) }
289 } else {
290 unsafe { f(None) }
292 unsafe { STORE = None }
293 }
294 }
295}
296
297pub mod api {
298 use core::ffi::c_char;
299 use core::ffi::c_float;
300 use core::ffi::c_int;
301 use core::ffi::c_uint;
302 use core::ffi::c_void;
303 use core::ptr::NonNull;
304
305 use sys::ffi::PDCallbackFunction;
306 use sys::ffi::PDDateTime;
307 use sys::ffi::PDLanguage;
308 use sys::ffi::playdate_sys;
309
310
311 pub type FnSerialMessageCallback = Option<unsafe extern "C" fn(data: *const c_char)>;
312
313
314 #[derive(Debug, Clone, Copy, core::default::Default)]
318 pub struct Default;
319 impl Api for Default {}
320
321
322 #[derive(Clone, Copy)]
328 #[cfg_attr(feature = "bindings-derive-debug", derive(Debug))]
329 pub struct Cache(&'static playdate_sys);
330
331 impl core::default::Default for Cache {
332 fn default() -> Self { Self(sys::api!(system)) }
333 }
334
335 impl From<*const playdate_sys> for Cache {
336 #[inline(always)]
337 fn from(ptr: *const playdate_sys) -> Self { Self(unsafe { ptr.as_ref() }.expect("system")) }
338 }
339
340 impl From<&'static playdate_sys> for Cache {
341 #[inline(always)]
342 fn from(r: &'static playdate_sys) -> Self { Self(r) }
343 }
344
345 impl From<NonNull<playdate_sys>> for Cache {
346 #[inline(always)]
347 fn from(ptr: NonNull<playdate_sys>) -> Self { Self(unsafe { ptr.as_ref() }) }
348 }
349
350 impl From<&'_ NonNull<playdate_sys>> for Cache {
351 #[inline(always)]
352 fn from(ptr: &NonNull<playdate_sys>) -> Self { Self(unsafe { ptr.as_ref() }) }
353 }
354
355 impl Cache {
356 #[inline(always)]
357 pub fn as_inner(&self) -> &'static playdate_sys { self.0 }
358 }
359
360
361 impl Api for Cache {
362 #[doc(alias = "sys::ffi::playdate_sys::getLanguage")]
364 #[inline(always)]
365 fn get_language(&self) -> unsafe extern "C" fn() -> PDLanguage { self.0.getLanguage.expect("getLanguage") }
366
367 #[doc(alias = "sys::ffi::playdate_sys::getCurrentTimeMilliseconds")]
369 #[inline(always)]
370 fn get_current_time_milliseconds(&self) -> unsafe extern "C" fn() -> c_uint {
371 self.0
372 .getCurrentTimeMilliseconds
373 .expect("getCurrentTimeMilliseconds")
374 }
375
376 #[doc(alias = "sys::ffi::playdate_sys::getSecondsSinceEpoch")]
378 #[inline(always)]
379 fn get_seconds_since_epoch(&self) -> unsafe extern "C" fn(milliseconds: *mut c_uint) -> c_uint {
380 self.0.getSecondsSinceEpoch.expect("getSecondsSinceEpoch")
381 }
382
383 #[doc(alias = "sys::ffi::playdate_sys::drawFPS")]
385 #[inline(always)]
386 fn draw_fps(&self) -> unsafe extern "C" fn(x: c_int, y: c_int) { self.0.drawFPS.expect("drawFPS") }
387
388 #[doc(alias = "sys::ffi::playdate_sys::setUpdateCallback")]
390 #[inline(always)]
391 fn set_update_callback(&self) -> unsafe extern "C" fn(update: PDCallbackFunction, userdata: *mut c_void) {
392 self.0.setUpdateCallback.expect("setUpdateCallback")
393 }
394
395 #[doc(alias = "sys::ffi::playdate_sys::getFlipped")]
397 #[inline(always)]
398 fn get_flipped(&self) -> unsafe extern "C" fn() -> c_int { self.0.getFlipped.expect("getFlipped") }
399
400 #[doc(alias = "sys::ffi::playdate_sys::setAutoLockDisabled")]
402 #[inline(always)]
403 fn set_auto_lock_disabled(&self) -> unsafe extern "C" fn(disable: c_int) {
404 self.0.setAutoLockDisabled.expect("setAutoLockDisabled")
405 }
406
407 #[doc(alias = "sys::ffi::playdate_sys::getReduceFlashing")]
409 #[inline(always)]
410 fn get_reduce_flashing(&self) -> unsafe extern "C" fn() -> c_int {
411 self.0.getReduceFlashing.expect("getReduceFlashing")
412 }
413
414 #[doc(alias = "sys::ffi::playdate_sys::getElapsedTime")]
416 #[inline(always)]
417 fn get_elapsed_time(&self) -> unsafe extern "C" fn() -> c_float {
418 self.0.getElapsedTime.expect("getElapsedTime")
419 }
420
421 #[doc(alias = "sys::ffi::playdate_sys::resetElapsedTime")]
423 #[inline(always)]
424 fn reset_elapsed_time(&self) -> unsafe extern "C" fn() {
425 self.0.resetElapsedTime.expect("resetElapsedTime")
426 }
427
428 #[doc(alias = "sys::ffi::playdate_sys::getBatteryPercentage")]
430 #[inline(always)]
431 fn get_battery_percentage(&self) -> unsafe extern "C" fn() -> c_float {
432 self.0.getBatteryPercentage.expect("getBatteryPercentage")
433 }
434
435 #[doc(alias = "sys::ffi::playdate_sys::getBatteryVoltage")]
437 #[inline(always)]
438 fn get_battery_voltage(&self) -> unsafe extern "C" fn() -> c_float {
439 self.0.getBatteryVoltage.expect("getBatteryVoltage")
440 }
441
442 #[doc(alias = "sys::ffi::playdate_sys::getTimezoneOffset")]
444 #[inline(always)]
445 fn get_timezone_offset(&self) -> unsafe extern "C" fn() -> i32 {
446 self.0.getTimezoneOffset.expect("getTimezoneOffset")
447 }
448
449 #[doc(alias = "sys::ffi::playdate_sys::shouldDisplay24HourTime")]
451 #[inline(always)]
452 fn should_display_24_hour_time(&self) -> unsafe extern "C" fn() -> c_int {
453 self.0.shouldDisplay24HourTime.expect("shouldDisplay24HourTime")
454 }
455
456 #[doc(alias = "sys::ffi::playdate_sys::convertEpochToDateTime")]
458 #[inline(always)]
459 fn convert_epoch_to_date_time(&self) -> unsafe extern "C" fn(epoch: u32, datetime: *mut PDDateTime) {
460 self.0.convertEpochToDateTime.expect("convertEpochToDateTime")
461 }
462
463 #[doc(alias = "sys::ffi::playdate_sys::convertDateTimeToEpoch")]
465 #[inline(always)]
466 fn convert_date_time_to_epoch(&self) -> unsafe extern "C" fn(datetime: *mut PDDateTime) -> u32 {
467 self.0.convertDateTimeToEpoch.expect("convertDateTimeToEpoch")
468 }
469
470 #[doc(alias = "sys::ffi::playdate_sys::setSerialMessageCallback")]
472 #[inline(always)]
473 fn set_serial_message_callback(&self) -> unsafe extern "C" fn(callback: FnSerialMessageCallback) {
474 self.0.setSerialMessageCallback.expect("setSerialMessageCallback")
475 }
476 }
477
478
479 pub trait Api {
480 #[doc(alias = "sys::ffi::playdate_sys::getLanguage")]
482 #[inline(always)]
483 fn get_language(&self) -> unsafe extern "C" fn() -> PDLanguage { *sys::api!(system.getLanguage) }
484
485 #[doc(alias = "sys::ffi::playdate_sys::getCurrentTimeMilliseconds")]
487 #[inline(always)]
488 fn get_current_time_milliseconds(&self) -> unsafe extern "C" fn() -> c_uint {
489 *sys::api!(system.getCurrentTimeMilliseconds)
490 }
491
492 #[doc(alias = "sys::ffi::playdate_sys::getSecondsSinceEpoch")]
494 #[inline(always)]
495 fn get_seconds_since_epoch(&self) -> unsafe extern "C" fn(milliseconds: *mut c_uint) -> c_uint {
496 *sys::api!(system.getSecondsSinceEpoch)
497 }
498
499 #[doc(alias = "sys::ffi::playdate_sys::drawFPS")]
501 #[inline(always)]
502 fn draw_fps(&self) -> unsafe extern "C" fn(x: c_int, y: c_int) { *sys::api!(system.drawFPS) }
503
504 #[doc(alias = "sys::ffi::playdate_sys::setUpdateCallback")]
506 #[inline(always)]
507 fn set_update_callback(&self) -> unsafe extern "C" fn(update: PDCallbackFunction, userdata: *mut c_void) {
508 *sys::api!(system.setUpdateCallback)
509 }
510
511 #[doc(alias = "sys::ffi::playdate_sys::getFlipped")]
513 #[inline(always)]
514 fn get_flipped(&self) -> unsafe extern "C" fn() -> c_int { *sys::api!(system.getFlipped) }
515
516 #[doc(alias = "sys::ffi::playdate_sys::setAutoLockDisabled")]
518 #[inline(always)]
519 fn set_auto_lock_disabled(&self) -> unsafe extern "C" fn(disable: c_int) {
520 *sys::api!(system.setAutoLockDisabled)
521 }
522
523 #[doc(alias = "sys::ffi::playdate_sys::getReduceFlashing")]
525 #[inline(always)]
526 fn get_reduce_flashing(&self) -> unsafe extern "C" fn() -> c_int { *sys::api!(system.getReduceFlashing) }
527
528 #[doc(alias = "sys::ffi::playdate_sys::getElapsedTime")]
530 #[inline(always)]
531 fn get_elapsed_time(&self) -> unsafe extern "C" fn() -> c_float { *sys::api!(system.getElapsedTime) }
532
533 #[doc(alias = "sys::ffi::playdate_sys::resetElapsedTime")]
535 #[inline(always)]
536 fn reset_elapsed_time(&self) -> unsafe extern "C" fn() { *sys::api!(system.resetElapsedTime) }
537
538 #[doc(alias = "sys::ffi::playdate_sys::getBatteryPercentage")]
540 #[inline(always)]
541 fn get_battery_percentage(&self) -> unsafe extern "C" fn() -> c_float {
542 *sys::api!(system.getBatteryPercentage)
543 }
544
545
546 #[doc(alias = "sys::ffi::playdate_sys::getBatteryVoltage")]
548 #[inline(always)]
549 fn get_battery_voltage(&self) -> unsafe extern "C" fn() -> c_float { *sys::api!(system.getBatteryVoltage) }
550
551 #[doc(alias = "sys::ffi::playdate_sys::getTimezoneOffset")]
553 #[inline(always)]
554 fn get_timezone_offset(&self) -> unsafe extern "C" fn() -> i32 { *sys::api!(system.getTimezoneOffset) }
555
556 #[doc(alias = "sys::ffi::playdate_sys::shouldDisplay24HourTime")]
558 #[inline(always)]
559 fn should_display_24_hour_time(&self) -> unsafe extern "C" fn() -> c_int {
560 *sys::api!(system.shouldDisplay24HourTime)
561 }
562
563 #[doc(alias = "sys::ffi::playdate_sys::convertEpochToDateTime")]
565 #[inline(always)]
566 fn convert_epoch_to_date_time(&self) -> unsafe extern "C" fn(epoch: u32, datetime: *mut PDDateTime) {
567 *sys::api!(system.convertEpochToDateTime)
568 }
569
570 #[doc(alias = "sys::ffi::playdate_sys::convertDateTimeToEpoch")]
572 #[inline(always)]
573 fn convert_date_time_to_epoch(&self) -> unsafe extern "C" fn(datetime: *mut PDDateTime) -> u32 {
574 *sys::api!(system.convertDateTimeToEpoch)
575 }
576
577 #[doc(alias = "sys::ffi::playdate_sys::setSerialMessageCallback")]
579 #[inline(always)]
580 fn set_serial_message_callback(&self) -> unsafe extern "C" fn(callback: FnSerialMessageCallback) {
581 *sys::api!(system.setSerialMessageCallback)
582 }
583 }
584}