Update mGBA usage, stuff it in a macros module

This commit is contained in:
Lokathor 2019-02-13 01:45:23 -07:00
parent 2ca888b572
commit 61218d99f2
2 changed files with 183 additions and 2 deletions

183
src/macros.rs Normal file
View 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);
}
}};
}

View file

@ -55,8 +55,6 @@ impl MGBADebug {
/// it might accidentally be discarded.
pub fn send(&mut self, level: MGBADebugLevel) {
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!
Self::SEND_ADDRESS.write(Self::SEND_FLAG | MGBADebugLevel::Fatal as u16);
} else {