mirror of
https://github.com/italicsjenga/gba.git
synced 2024-12-23 19:01:30 +11:00
Update mGBA usage, stuff it in a macros module
This commit is contained in:
parent
2ca888b572
commit
61218d99f2
183
src/macros.rs
Normal file
183
src/macros.rs
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
//! Contains the macros for the crate.
|
||||||
|
//!
|
||||||
|
//! Because (unlike everything else in Rust) a macro has to be declared before
|
||||||
|
//! use, we place them in their own module and then declare that module at the
|
||||||
|
//! start of the crate.
|
||||||
|
|
||||||
|
/// Assists in defining a newtype wrapper over some base type.
|
||||||
|
///
|
||||||
|
/// Note that rustdoc and derives are all the "meta" stuff, so you can write all
|
||||||
|
/// of your docs and derives in front of your newtype in the same way you would
|
||||||
|
/// for a normal struct. Then the inner type to be wrapped it name.
|
||||||
|
///
|
||||||
|
/// The macro _assumes_ that you'll be using it to wrap numeric types and that
|
||||||
|
/// it's safe to have a `0` value, so it automatically provides a `const fn`
|
||||||
|
/// method for `new` that just wraps `0`. Also, it derives Debug, Clone, Copy,
|
||||||
|
/// Default, PartialEq, and Eq. If all this is not desired you can add `, no
|
||||||
|
/// frills` to the invocation.
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// newtype! {
|
||||||
|
/// /// Records a particular key press combination.
|
||||||
|
/// KeyInput, u16
|
||||||
|
/// }
|
||||||
|
/// newtype! {
|
||||||
|
/// /// You can't derive most stuff above array size 32, so we add
|
||||||
|
/// /// the `, no frills` modifier to this one.
|
||||||
|
/// BigArray, [u8; 200], no frills
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! newtype {
|
||||||
|
($(#[$attr:meta])* $new_name:ident, $v:vis $old_name:ty) => {
|
||||||
|
$(#[$attr])*
|
||||||
|
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct $new_name($v $old_name);
|
||||||
|
impl $new_name {
|
||||||
|
/// A `const` "zero value" constructor
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
$new_name(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
($(#[$attr:meta])* $new_name:ident, $v:vis $old_name:ty, no frills) => {
|
||||||
|
$(#[$attr])*
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct $new_name($v $old_name);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Assists in defining a newtype that's an enum.
|
||||||
|
///
|
||||||
|
/// First give `NewType = OldType,`, then define the tags and their explicit
|
||||||
|
/// values with zero or more entries of `TagName = base_value,`. In both cases
|
||||||
|
/// you can place doc comments or other attributes directly on to the type
|
||||||
|
/// declaration or the tag declaration.
|
||||||
|
///
|
||||||
|
/// The generated enum will get an appropriate `repr` attribute as well as
|
||||||
|
/// Debug, Clone, Copy, PartialEq, and Eq
|
||||||
|
///
|
||||||
|
/// ```no_run
|
||||||
|
/// newtype_enum! {
|
||||||
|
/// /// The Foo
|
||||||
|
/// Foo = u16,
|
||||||
|
/// /// The Bar
|
||||||
|
/// Bar = 0,
|
||||||
|
/// /// The Zap
|
||||||
|
/// Zap = 1,
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! newtype_enum {
|
||||||
|
(
|
||||||
|
$(#[$struct_attr:meta])*
|
||||||
|
$new_name:ident = $old_name:ident,
|
||||||
|
$($(#[$tag_attr:meta])* $tag_name:ident = $base_value:expr,)*
|
||||||
|
) => {
|
||||||
|
$(#[$struct_attr])*
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
#[repr($old_name)]
|
||||||
|
pub enum $new_name {
|
||||||
|
$(
|
||||||
|
$(#[$tag_attr])*
|
||||||
|
$tag_name = $base_value,
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delivers a fatal message to the mGBA output, halting emulation.
|
||||||
|
///
|
||||||
|
/// This works basically like `println`. mGBA is a C program and all, so you
|
||||||
|
/// should only attempt to print non-null ASCII values through this. There's
|
||||||
|
/// also a maximum length of 255 bytes per message.
|
||||||
|
///
|
||||||
|
/// This has no effect if you're not using mGBA.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! fatal {
|
||||||
|
($($arg:tt)*) => {{
|
||||||
|
use $crate::mgba::{MGBADebug, MGBADebugLevel};
|
||||||
|
use core::fmt::Write;
|
||||||
|
if let Some(mut mgba) = MGBADebug::new() {
|
||||||
|
let _ = write!(mgba, $($arg)*);
|
||||||
|
mgba.send(MGBADebugLevel::Fatal);
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delivers an error message to the mGBA output.
|
||||||
|
///
|
||||||
|
/// This works basically like `println`. mGBA is a C program and all, so you
|
||||||
|
/// should only attempt to print non-null ASCII values through this. There's
|
||||||
|
/// also a maximum length of 255 bytes per message.
|
||||||
|
///
|
||||||
|
/// This has no effect if you're not using mGBA.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! error {
|
||||||
|
($($arg:tt)*) => {{
|
||||||
|
use $crate::mgba::{MGBADebug, MGBADebugLevel};
|
||||||
|
use core::fmt::Write;
|
||||||
|
if let Some(mut mgba) = MGBADebug::new() {
|
||||||
|
let _ = write!(mgba, $($arg)*);
|
||||||
|
mgba.send(MGBADebugLevel::Error);
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delivers a warning message to the mGBA output.
|
||||||
|
///
|
||||||
|
/// This works basically like `println`. mGBA is a C program and all, so you
|
||||||
|
/// should only attempt to print non-null ASCII values through this. There's
|
||||||
|
/// also a maximum length of 255 bytes per message.
|
||||||
|
///
|
||||||
|
/// This has no effect if you're not using mGBA.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! warn {
|
||||||
|
($($arg:tt)*) => {{
|
||||||
|
use $crate::mgba::{MGBADebug, MGBADebugLevel};
|
||||||
|
use core::fmt::Write;
|
||||||
|
if let Some(mut mgba) = MGBADebug::new() {
|
||||||
|
let _ = write!(mgba, $($arg)*);
|
||||||
|
mgba.send(MGBADebugLevel::Warning);
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delivers an info message to the mGBA output.
|
||||||
|
///
|
||||||
|
/// This works basically like `println`. mGBA is a C program and all, so you
|
||||||
|
/// should only attempt to print non-null ASCII values through this. There's
|
||||||
|
/// also a maximum length of 255 bytes per message.
|
||||||
|
///
|
||||||
|
/// This has no effect if you're not using mGBA.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! info {
|
||||||
|
($($arg:tt)*) => {{
|
||||||
|
use $crate::mgba::{MGBADebug, MGBADebugLevel};
|
||||||
|
use core::fmt::Write;
|
||||||
|
if let Some(mut mgba) = MGBADebug::new() {
|
||||||
|
let _ = write!(mgba, $($arg)*);
|
||||||
|
mgba.send(MGBADebugLevel::Info);
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delivers a debug message to the mGBA output.
|
||||||
|
///
|
||||||
|
/// This works basically like `println`. mGBA is a C program and all, so you
|
||||||
|
/// should only attempt to print non-null ASCII values through this. There's
|
||||||
|
/// also a maximum length of 255 bytes per message.
|
||||||
|
///
|
||||||
|
/// This has no effect if you're not using mGBA.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! debug {
|
||||||
|
($($arg:tt)*) => {{
|
||||||
|
use $crate::mgba::{MGBADebug, MGBADebugLevel};
|
||||||
|
use core::fmt::Write;
|
||||||
|
if let Some(mut mgba) = MGBADebug::new() {
|
||||||
|
let _ = write!(mgba, $($arg)*);
|
||||||
|
mgba.send(MGBADebugLevel::Debug);
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
|
@ -55,8 +55,6 @@ impl MGBADebug {
|
||||||
/// it might accidentally be discarded.
|
/// it might accidentally be discarded.
|
||||||
pub fn send(&mut self, level: MGBADebugLevel) {
|
pub fn send(&mut self, level: MGBADebugLevel) {
|
||||||
if level == MGBADebugLevel::Fatal {
|
if level == MGBADebugLevel::Fatal {
|
||||||
Self::SEND_ADDRESS.write(Self::SEND_FLAG | MGBADebugLevel::Error as u16);
|
|
||||||
|
|
||||||
// Note(Lokathor): A Fatal send causes the emulator to halt!
|
// Note(Lokathor): A Fatal send causes the emulator to halt!
|
||||||
Self::SEND_ADDRESS.write(Self::SEND_FLAG | MGBADebugLevel::Fatal as u16);
|
Self::SEND_ADDRESS.write(Self::SEND_FLAG | MGBADebugLevel::Fatal as u16);
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue