From 6e0cbbe9ebaba25b2170e78f87adc75c7dc13758 Mon Sep 17 00:00:00 2001 From: Corwin Kuiper Date: Sat, 4 Dec 2021 02:44:57 +0000 Subject: [PATCH] create a number macro that can use floating point numbes --- agb-macros/src/lib.rs | 13 ++++++++++ agb/src/number.rs | 59 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/agb-macros/src/lib.rs b/agb-macros/src/lib.rs index 40cc44aa..a00985eb 100644 --- a/agb-macros/src/lib.rs +++ b/agb-macros/src/lib.rs @@ -45,6 +45,19 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream { .into() } +#[proc_macro] +pub fn num(input: TokenStream) -> TokenStream { + let f = syn::parse_macro_input!(input as syn::LitFloat); + let v: f64 = f.base10_parse().expect("The number should be parsable"); + + let integer = v.trunc(); + let fractional = v.fract() * (1_u64 << 30) as f64; + + let integer = integer as i32; + let fractional = fractional as i32; + quote!((#integer, #fractional)).into() +} + fn random_ident() -> Ident { let mut rng = rand::thread_rng(); Ident::new( diff --git a/agb/src/number.rs b/agb/src/number.rs index 1b6068f5..8785382e 100644 --- a/agb/src/number.rs +++ b/agb/src/number.rs @@ -2,8 +2,8 @@ use core::{ cmp::{Eq, Ord, PartialEq, PartialOrd}, fmt::{Debug, Display}, ops::{ - Add, AddAssign, BitAnd, Div, DivAssign, Mul, MulAssign, Neg, Not, Rem, RemAssign, Shl, Shr, - Sub, SubAssign, + Add, AddAssign, BitAnd, BitOr, Div, DivAssign, Mul, MulAssign, Neg, Not, Rem, RemAssign, + Shl, Shr, Sub, SubAssign, }, }; @@ -40,6 +40,7 @@ pub trait FixedWidthUnsignedInteger: + Sub + Not + BitAnd + + BitOr + Rem + Div + Mul @@ -50,6 +51,7 @@ pub trait FixedWidthUnsignedInteger: fn zero() -> Self; fn one() -> Self; fn ten() -> Self; + fn from_as_i32(v: i32) -> Self; } pub trait FixedWidthSignedInteger: FixedWidthUnsignedInteger + Neg { @@ -68,6 +70,9 @@ macro_rules! fixed_width_unsigned_integer_impl { fn ten() -> Self { 10 } + fn from_as_i32(v: i32) -> Self { + v as $T + } } }; } @@ -291,6 +296,56 @@ impl Num { pub fn new(integral: I) -> Self { Self(integral << N) } + + pub fn new_from_parts(num: (i32, i32)) -> Self { + Self(I::from_as_i32(((num.0) << N) + (num.1 >> (30 - N)))) + } +} + +#[macro_export] +macro_rules! num { + ($value:literal) => {{ + $crate::number::Num::new_from_parts(agb_macros::num!($value)) + }}; +} + +#[test_case] +fn test_macro_conversion(_gba: &mut super::Gba) { + fn test_positive() { + let a: Num = num!(1.5); + let one = A::one() << B; + let b = Num::from_raw(one + (one >> 1)); + + assert_eq!(a, b); + } + + fn test_negative() { + let a: Num = num!(-1.5); + let one = A::one() << B; + let b = Num::from_raw(one + (one >> 1)); + + assert_eq!(a, -b); + } + + fn test_base() { + test_positive::(); + test_positive::(); + test_positive::(); + test_positive::(); + + test_negative::(); + test_negative::(); + } + // some nice powers of two + test_base::<8>(); + test_base::<4>(); + test_base::<16>(); + // not a power of two + test_base::<10>(); + // an odd number + test_base::<9>(); + // and a prime + test_base::<11>(); } impl Num {