From c1ec41dffb488109740bce2c2354db917fb6c20f Mon Sep 17 00:00:00 2001 From: HampusM Date: Wed, 28 Feb 2024 20:32:35 +0100 Subject: feat: add utility macros library --- util-macros/src/lib.rs | 100 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 util-macros/src/lib.rs (limited to 'util-macros/src/lib.rs') 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::(), TypeId::of::<[u8; 3]>()); +/// ``` +///
+/// +/// 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::(), 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::().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::().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() +} -- cgit v1.2.3-18-g5258