dtolnay / seq-macro

Macro to repeat sequentially indexed copies of a fragment of code
Apache License 2.0
137 stars 5 forks source link

How to use `seq!` inside `phf!`? #12

Closed bet4it closed 2 years ago

bet4it commented 3 years ago

For example:


use phf::phf_map;
use seq_macro::seq;

//static MY_MAP: phf::Map<u32, u32> = phf_map! {
//    1u32 => 1,
//    2u32 => 2,
//};

static MY_MAP: phf::Map<u32, u32> = phf_map! {
    seq!(N in 0..2 {
        #Nu32 => #N,
    });
};

fn main() {
    println!("{:?}", MY_MAP); // prints {2: 2, 1: 1}
}

Will get the error:

error: unsupported key expression
  --> src/main.rs:10:5
   |
10 | /     seq!(N in 0..2 {
11 | |         #Nu32 => #N,
12 | |     });
   | |______^
   |
   = note: this error originates in the macro `proc_macro_call` (in Nightly builds, run with -Z macro-backtrace for more info)
dtolnay commented 3 years ago

Like this:

static MY_MAP: phf::Map<u32, u32> = seq!(N in 0u32..2 {
    phf_map! {
        #(N => N,)*
    }
});
bet4it commented 3 years ago

But what if there are more than one sequence in the map?

static MY_MAP: phf::Map<u32, u32> = phf_map! {
    1u32 => 1,
    2u32 => 2,
    ...
    10u32 => 10,
    221u32 => 21,
    222u32 => 22,
    ...
    240u32 => 40,
    999u32 => 999,
};
dtolnay commented 3 years ago

It would be exactly the same, with as many seq! invocations as you need. If there are 2 sequences then that's 2 seq calls.

macro_rules! my_map {
    // first range
    () => {
        seq!(N in 1u32..=10 {
            my_map! { #(N => N,)* }
        })
    };
    // second range
    ($($k:expr => $v:expr,)*) => {
        seq!(N in 221u32..=240 {
            phf_map! {
                $($k => $v,)*
                #(N => N-200,)*
                999u32 => 999,
            }
        })
    };
}

static MY_MAP: phf::Map<u32, u32> = my_map!();
bet4it commented 3 years ago

Oh sorry that I still have a question. What I really want to get is something like this:

static MY_MAP: phf::Map<u32, Demo> = phf_map! {
    1u32 => Demo::Variant1,
    2u32 => Demo::Variant2,
    ...
    10u32 => Demo::Variant10,
    221u32 => Demo::Variant21,
    222u32 => Demo::Variant22,
    ...
    240u32 => Demo::Variant40,
    999u32 => Demo::Variant999,
};

How to do calculation of #N?

use phf::phf_map;
use seq_macro::seq;

seq!(N in 1..=999 {
    #[derive(Debug)]
    #[allow(dead_code)]
    enum Demo {
        #(
            Variant#N,
        )*
    }
});

macro_rules! my_map {
    // first range
    () => {
        seq!(N in 1u32..=10 {
            my_map! { #(N => Demo::Variant#N,)* }
        })
    };
    // second range
    ($($k:expr => $v:expr,)*) => {
        seq!(N in 221u32..=240 {
            phf_map! {
                $($k => $v,)*
                #(N => Demo::Variant(#N-200),)* // get an error here
                999u32 => Demo::Variant999,
            }
        })
    };
}

static MY_MAP: phf::Map<u32, Demo> = my_map!();

fn main() {
    println!("{:?}", MY_MAP);
}
dtolnay commented 3 years ago

I would do:

seq!(N in 1..=999 {
    #[derive(Debug)]
    enum Demo {
        #(Variant#N,)*
    }

    impl Demo {
        const fn new(n: u32) -> Self {
            match n {
                #(N => Demo::Variant#N,)*
                _ => Demo::Variant999,
            }
        }
    }
});

The in the second range:

                #(N => Demo::new(N-200),)*
bet4it commented 3 years ago

Oh no, Demo is defined in another crate ( library ) and I can't change it, likes this: https://github.com/unicorn-engine/unicorn/blob/772558119af66269742fe4dcc45ec6000a5a6ea7/bindings/rust/src/arm64.rs#L206-L266

bet4it commented 3 years ago

What I want in actually:

static MY_MAP: phf::Map<u32, RegisterARM64> = phf_map! {
    0u32 => X0,
    1u32 => X1,
    ...
    30u32 => X30,
    40u32 => V0,
    41u32 => V1,
    ...
    71u32 => V31,
    100u32 => PC,
};