1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
//! This module defines the interface between platform binary and game library.

pub use std::time::Duration;

#[derive(Debug, Clone)]
pub struct GameInput {
  pub x_offset: i32,
  pub y_offset: i32,
  pub tone_hz: i32,
}

#[derive(Debug, Clone)]
pub struct Bitmap {
  pub memory: *mut u8,
  pub width: i32,
  pub height: i32,
  pub pitch: isize,
}

#[derive(Debug, Clone)]
pub struct SoundBuffer {
  pub samples_per_second: i32,
  pub sample_count: i32,
  pub samples: *mut i16,
}

pub type GameUpdateAndRenderFn = fn(Duration, &GameInput, &mut Bitmap, &mut SoundBuffer);

/// `file!():line!()> expr: expr_value`, one per expression
///
/// only works with `debug_assertions` on.
#[macro_export]
macro_rules! dump {
  ($($n:expr),*) => (if cfg!(debug_assertions) {
    $(println!(concat!("{}:{}> ",stringify!($n),": {:?}"),file!(),line!(),$n);)*
  })
}

/// `file!():line!()>`, a space, and then the message.
///
/// only works with `debug_assertions` on.
#[macro_export]
macro_rules! debugln {
  ($($arg:tt)*) => (if cfg!(debug_assertions) {
    // This particular prefix was chosen because that's what VS Code will
    // recognize and then let you ctrl+click to jump to that point in that file.
    print!("{}:{}> ",file!(),line!());
    println!($($arg)*);
  })
}

/// Read a value out of a [thread_local](std::thread_local)
/// [Cell](core::cell::Cell)
///
/// ```
/// use core::cell::Cell;
/// use thorium::tlc_read;
///
/// thread_local! {
///   static YES: Cell<bool> = Cell::new(true);
/// }
/// fn main() {
///   assert!(tlc_read!(YES));
/// }
/// ```
#[macro_export]
macro_rules! tlc_read {
  ($cell_name:ident) => {
    $cell_name.with(Cell::get)
  };
}

/// Write a new value to a [thread_local](std::thread_local)
/// [Cell](core::cell::Cell)
///
/// ```
/// use core::cell::Cell;
/// use thorium::{tlc_read, tlc_write};
///
/// thread_local! {
///   static VAL: Cell<i32> = Cell::new(0);
/// }
/// fn main() {
///   tlc_write!(VAL, 7);
///   assert_eq!(tlc_read!(VAL), 7);
/// }
/// ```
#[macro_export]
macro_rules! tlc_write {
  ($cell_name:ident, $new_value:expr) => {
    $cell_name.with(|cell| cell.set($new_value));
  };
}

/// Modify a [thread_local](std::thread_local) [Cell](core::cell::Cell) with the
/// provided function.
///
/// ```
/// use core::cell::Cell;
/// use thorium::{tlc_read, tlc_modify};
///
/// thread_local! {
///   static VAL: Cell<i32> = Cell::new(3);
/// }
/// fn main() {
///   tlc_modify!(VAL, |v| v + 2);
///   assert_eq!(tlc_read!(VAL), 5);
/// }
/// ```
#[macro_export]
macro_rules! tlc_modify {
  ($cell_name:ident, $modify_func:expr) => {
    $cell_name.with(|cell| cell.set($modify_func(cell.get())));
  };
}