如何在编译时为每种类型生成一个位标志?

时间:2015-12-08 15:21:54

标签: rust

我正在开发一个我有结构和特征的应用程序:FooBar

Foo拥有一堆Bar个,不同的Foo拥有不同的Bar s。我需要根据Foo的{​​{1}}来过滤Bar。我尝试做的是给每个Bar一个标志的实现,然后使用所有标志来识别BarFoo拥有的。{/ p>

虽然我不确定这是进行此类过滤的最佳方法,但它确实有效。问题是我必须为每种类型管理每个标志,我不能重复标记或跳过它们所以我想在编译时(或运行时自动执行此操作,只要它遵循相同的约束) )。

这是我最近解决这个问题的尝试:

#[macro_use]
extern crate lazy_static;

static mut V : u32 = 0u32;
trait Mask<T> {
    fn mask() -> u32 {
        unsafe {
            V = V + 1;
            println!("v {}", V);
            lazy_static!(static ref VALUE : u32 = unsafe{V};);
            *VALUE
        }
    }
}

#[derive(Default)]
struct A;
#[derive(Default)]
struct B;

impl Mask<A> for A {}
impl Mask<B> for B {}

fn main() {
    println!("{}", A::mask());
    println!("{}", B::mask());
    println!("{}", A::mask());
    println!("{}", A::mask());
    println!("{}", B::mask());
}

结果:

v 1
1
v 2
1
v 3
1
v 4
1
v 5
1

这是我从C ++模板中获得的一个想法,如果我没记错的话,会为每个Mask<T>实现生成不同的类型,mask()调用对于同一类型将是唯一的,但是不同其他类型之间。它在Rust中不起作用,但我不太了解Rust的泛型类型来猜测原因。我也尝试过使用宏,但我不知道是否有办法在宏调用之间保存状态。

有没有办法实现这个目标?还有什么我可以尝试进行这种过滤吗?

这不是Generating unique ID's for types at compile time的重复。除非有办法使用17767285367811814831这样的数字为每种类型创建位标志,这是TypeId给我的。

我最终想要的是每种类型都是这样的:

struct A;
struct B;
//[...]
struct N;

impl Mask for A {
    fn mask() -> u32 {
        1 << 0
    }
}
impl Mask for B {
    fn mask() -> u32 {
        1 << 1
    }
}
//[...]
impl Mask for N {
    fn mask() -> u32 {
        1 << ?N?
    }
}

1 个答案:

答案 0 :(得分:2)

如果您可以将所有类型列在一起,则可以使用宏并使用增加的枚举判别符序列来完成此操作:

trait Mask {
    fn mask() -> u32;
}

macro_rules! make_masks {
    ($($t:ident),+) => {
        enum Masks {
            $($t),+
        }

        $(
            impl Mask for $t {
                fn mask() -> u32 {
                    1 << (Masks::$t as u32)
                }
            }
        )+
    };
}

struct A;
struct B;
struct C;

make_masks!(A, B, C);

fn main() {
    // Output is: 1, 2, 4
    println!("{:x}, {:x}, {:x}", A::mask(), B::mask(), C::mask());
}

(Playground link)