diff options
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | util-macros/Cargo.toml | 11 | ||||
-rw-r--r-- | util-macros/src/lib.rs | 100 |
3 files changed, 112 insertions, 1 deletions
@@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [workspace] -members = ["glfw", "engine", "ecs", "ecs-macros"] +members = ["glfw", "engine", "ecs", "ecs-macros", "util-macros"] [dependencies] engine = { path = "./engine", features = ["debug"] } diff --git a/util-macros/Cargo.toml b/util-macros/Cargo.toml new file mode 100644 index 0000000..b8a14e5 --- /dev/null +++ b/util-macros/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "util-macros" +version = "0.1.0" +edition = "2021" + +[lib] +proc-macro = true + +[dependencies] +quote = "1.0.35" +proc-macro2 = "1.0.78" diff --git a/util-macros/src/lib.rs b/util-macros/src/lib.rs new file mode 100644 index 0000000..036ffc8 --- /dev/null +++ b/util-macros/src/lib.rs @@ -0,0 +1,100 @@ +use proc_macro::{TokenStream, TokenTree}; +use quote::quote; + +/// Subtracts two numbers and calls a given callback macro with the result. +/// +/// # Input +/// `number - number, callback` +/// +/// # Examples +/// ``` +/// # use std::any::TypeId; +/// use util_macros::sub; +/// +/// macro_rules! sub_cb { +/// ($num: literal) => { +/// $num +/// }; +/// } +/// +/// type Foo = [u8; sub!(5 - 2, sub_cb)]; +/// +/// assert_eq!(TypeId::of::<Foo>(), TypeId::of::<[u8; 3]>()); +/// ``` +/// <br> +/// +/// The callback is called with the identifier `overflow` if a overflow occurs. +/// ``` +/// # use std::any::TypeId; +/// use util_macros::sub; +/// +/// macro_rules! sub_cb { +/// ($num: literal) => { +/// $num +/// }; +/// +/// (overflow) => { +/// 128 +/// }; +/// } +/// +/// type Foo = [u8; sub!(3 - 10, sub_cb)]; +/// +/// assert_eq!(TypeId::of::<Foo>(), TypeId::of::<[u8; 128]>()); +/// ``` +#[proc_macro] +pub fn sub(input: TokenStream) -> TokenStream +{ + let mut input_tt_iter = input.into_iter(); + + let num_a = match input_tt_iter.next().unwrap() { + TokenTree::Literal(lit) => lit.to_string().parse::<u32>().unwrap(), + _ => { + panic!("Expected a number literal"); + } + }; + + match input_tt_iter.next().unwrap() { + TokenTree::Punct(punct) if punct.as_char() == '-' => {} + _ => { + panic!("Expected a '-' token"); + } + }; + + let num_b = match input_tt_iter.next().unwrap() { + TokenTree::Literal(lit) => lit.to_string().parse::<u32>().unwrap(), + _ => { + panic!("Expected a number literal"); + } + }; + + match input_tt_iter.next().unwrap() { + TokenTree::Punct(punct) if punct.as_char() == ',' => {} + _ => { + panic!("Expected a ',' token"); + } + }; + + let cb_ident = match input_tt_iter.next().unwrap() { + TokenTree::Ident(cb_ident) => { + proc_macro2::Ident::new(&cb_ident.to_string(), cb_ident.span().into()) + } + _ => { + panic!("Expected a identifier"); + } + }; + + let Some(subtracted) = num_a.checked_sub(num_b) else { + return quote! { + #cb_ident!(overflow) + } + .into(); + }; + + let subtracted_lit = proc_macro2::Literal::u32_unsuffixed(subtracted); + + quote! { + #cb_ident!(#subtracted_lit) + } + .into() +} |