summaryrefslogtreecommitdiff
path: root/util-macros/src
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2024-02-28 20:32:35 +0100
committerHampusM <hampus@hampusmat.com>2024-02-28 21:34:18 +0100
commitc1ec41dffb488109740bce2c2354db917fb6c20f (patch)
tree5755830de21d28c57ca08474779a885337ab2d48 /util-macros/src
parent815d04da602c58ed8b13eeb612fe73180204039d (diff)
feat: add utility macros library
Diffstat (limited to 'util-macros/src')
-rw-r--r--util-macros/src/lib.rs100
1 files changed, 100 insertions, 0 deletions
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()
+}