Maik Klein
Maik Klein

Reputation: 16148

Which symbol inside a macro allows type construction when the type is inside another module?

I wrote a very simple macro which should implement a wrapper for a C struct:

macro_rules! features{
    ($struct_name: ident, $from_type: ident, $($name: ident => $vk: ident,)+) => {
        #[derive(Debug, Copy, Clone)]
        pub struct $struct_name{
            $(
                pub $name: bool,
            )+
        }
        impl $struct_name{
            pub fn empty() -> $struct_name{
                $struct_name{
                    $(
                        $name: false,
                    )+
                }
            }
            pub fn subset(&self, other: &Self) -> bool{
                $((!self.$name | other.$name))&&+
            }
        }

        //TODO: Probably just impl From with a cast?
        impl From<vk::$from_type> for $struct_name{
            fn from(features: vk::$from_type) -> $struct_name {
                $struct_name{
                    $(
                        $name: features.$vk != 0,
                    )+
                }
            }
        }

        impl From<$struct_name> for vk::$from_type {
            fn from(features: $struct_name) -> vk::$from_type {
                vk::$from_type{
                    $(
                        $vk: features.$name as u32,
                    )+
                }
            }
        }

        impl fmt::Display for $struct_name {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result{
                $(
                    if self.$name {
                        try!(writeln!(f, "{},", stringify!($name)));
                    }
                )+
                writeln!(f, "")
            }
        }
    }
}

I use it like this:

features!{
    Features,
    PhysicalDeviceFeatures,
    robust_buffer_access => robustBufferAccess,
    full_draw_index_uint32 => fullDrawIndexUint32,
    image_cube_array => imageCubeArray,
    ....
}

This works, but I had to make a very ugly hack $from_type: ident and then I use vk::$from_type inside the macro. What I really want to do is:

features!{
    Features,
    vk::PhysicalDeviceFeatures,
    robust_buffer_access => robustBufferAccess,
    full_draw_index_uint32 => fullDrawIndexUint32,
    image_cube_array => imageCubeArray,
    ....
}

Then I can fully supply the type, instead of relying on the ident being inside a hard coded module vk::.

The problem is that I can not do this with path or ty

$from_type{..}

Error:

error: expected expression, found `PhysicalDeviceFeatures`
  --> 
   |
38 |                 $from_type{
   |                 ^^^^^^^^^^

and

error: expected one of `.`, `;`, `?`, `}`, or an operator, found `{`
  --> /home/maik/projects/ashlib/ash/src/feature.rs:38:27
   |
38 |                 $from_type{
   | 

What symbol does $from_type need to be for this to work?


I created a shorter example to express the problem that I am having more clearly (Playground):

mod foo {
    struct Foo{
        i: i32
    }
}

macro_rules! c_enum {
    (
        $name:ty

    ) => {
        fn new() -> $name {
            $name{
                i: 42
            }
        }
    }
}
c_enum!{
    foo::Foo
}
fn main() {

}

Upvotes: 1

Views: 360

Answers (1)

Markus Unterwaditzer
Markus Unterwaditzer

Reputation: 8244

I don't know why path or ty fails, I would file a bug against Rust. In the past I've worked around this by using the tt specifier, which matches almost everything.

Upvotes: 1

Related Questions