0

I am making a macro to expand geometric algebra expressions, and in order for the macro to work, it needs to know to know the type of geometric algebra (3D VGA, 2D PGA, etc.) at compile time.

I could do this easily by passing the type (3D PGA) in implicitly at each call of eq!:

let a = eq!((3, 0, 1): e1 + e2); let b = eq!((3, 0, 1): 3 + e12); println!("{:?}", eq!((3, 0, 1): a + b)) 

or

let a = eq!("PGA3d": e1 + e2); let b = eq!("PGA3d": 3 + e12); println!("{:?}", eq!("PGA3d": a + b)) 

or by creating a specific macro for each type:

let a = pga_3d!(e1 + e2); let b = pga_3d!(3 + e12); println!("{:?}", pga_3d!(a + b)) 

but I'd rather not have to write out the type at every single eq! call or create a specific macro for every single type someone could want (there are an infinite amount of types and I want to be able to, at least theoretically, handle them all). Is there a way to define the type as a const or with another procedural macro in order to have all eq! calls to know the specified type? (eq! needs to know what the type actually is in order to expand.) Ideally, I'd like the code to look like this:

const TYPE: (usize, usize, usize) = (3, 0, 1); // or set_type!(3, 0, 1); fn main() { let a = eq!(e1 + e2); // eq somehow knows to use 3D PGA because of TYPE or set_type! let b = eq!(3 + e12); println!("{:?}", eq!(a + b)); } 
11
  • Did you try just using TYPE inside the macro, and then requiring per your macro documentation that a suitable TYPE must be in scope? Commented Jun 29, 2022 at 17:49
  • @rodrigo No, because I need to know the actual value of type in order to expand the expression the way i want to (the macro expands to an array and the length of that array is dependent on the type). I edited the post to clarify this. Commented Jun 29, 2022 at 18:14
  • 1
    Why not simply creating a new macro, like eq_pga3d! that, in turn, calls eq! with a default argument before the colon? You can make the name of that new macro shorter if it's a length issue. Commented Jun 29, 2022 at 18:52
  • @BlackBeans I could, but my end-goal is to be able to make switching types as easy as editing one constant (many expression that I would write in 3D VGA would work in 4D VGA and 5D VGA, so I want to allow switching types to be extremely easy). I'll edit the post to acknowledge these solutions. Commented Jun 29, 2022 at 20:18
  • 1
    Does this answer your question? Is there a way to get the type of a variable in a macro? or How do I match the type of an expression in a Rust macro? Commented Jun 29, 2022 at 22:48

1 Answer 1

2

I believe I've found a workable solution to the problem I was having. The solution I found was to have the lib.rs file containing the procedural macros, read from a json file created alongside the cargo.toml file where the library was imported:

ga_macros_test │ cargo.toml <-- ga_macros is imported as a dependency here │ type.json <-- type is specified here └───src │ │ main.rs <-- eq! can be used here with the specified type │ └───ga_macros │ cargo.toml <-- proc_macro imported here as dependency └───src │ lib.rs <-- eq defined here along with a read for "type.json" 

Inside the lib.rs file:

extern crate proc_macro; use proc_macro::*; use lazy_static::lazy_static; use std::{fs, collections::HashMap}; extern crate serde_json; lazy_static! { static ref TYPE: (usize, usize, usize) = { if let Ok(str) = fs::read_to_string("type.json") { let json: HashMap<&str, Vec<usize>> = serde_json::from_str(str.as_str()).expect("The json file couldn't be parsed"); (json["algebra"][0], json["algebra"][1], json["algebra"][2]) } else { (3, 0, 0) // 3D Vectorspace Geometric Algebra is the default } }; } #[proc_macro] pub fn eq(tokens: TokenStream) -> TokenStream { /*Expand expression using TYPE*/ } 

This allows ga_macros to support arbitrary types, read the type while expanding the macro, and provide a single place where type is defined and can be changed. Another benefit is that more information could be added to type.json which could then better specialize eq! to the user's needs. Link to example

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.