rustrust-macros

How can I correctly pass a path that include double colons to this macro?


I'm using schemars widely in my code base, and I'm populating a rather large vector with the following (simplified) type:

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct CommandDescription {
    /// The name for the command/action as it would appear in the JSON.
    pub cmd: String,
    /// Parameters the command takes
    pub parameters: Option<RootSchema>,
}

The full definition of the structure has many more fields, that are combinations of String and RootSchema types.

In my code I've got hundreds of these types of definitions:

CommandDescription {
    cmd: String::from(api_schema::about::ABOUT_CMD),
    parameters: Some(schema_for!(api_schema::about::AboutCmd)),
},

And I would like to create a macro, but I'm having difficulty with the schema_for!() macro.

My macro definition is this:

macro_rules! command_description {
    ($api_path:path, $prefix:ident, $type_name_cmd:ident) => {
        CommandDescription {
            cmd: String::from(concat!(
                stringify!($api_path),
                "::",
                stringify!($prefix),
                "_CMD"
            )),
            parameters: Some(schema_for!($api_path::$type_name_cmd)),
        }
    };
}

which I invoke:

    command_description!(
        api_schema::about,
        ABOUT,
        AboutCmd
    )

But the compiler is suggesting that I wrap $api_path in the schema_for!() macro in angled brackets, but it's a path, not a type: I know this because if I add the <$api_path> I'm told it's not a type.

error: missing angle brackets in associated item path
   --> src/bin/rudi-service.rs:674:42
    |
674 |               parameters: Some(schema_for!($api_path::$type_name_cmd)),
    |                                            ^^^^^^^^^
    = note: this error originates in the macro `command_description` (in Nightly builds, run with -Z macro-backtrace for more info)
help: types that don't start with an identifier need to be surrounded with angle brackets in qualified paths
    |
674 |             parameters: Some(schema_for!(<$api_path>::$type_name_cmd)),
    |                                          +         +

Am I using the wrong fragment specifier for the $api_path parameter?


Solution

  • The problem is that once something is captured as path (or most other fragment specifiers), it cannot be decomposed anymore, nor extended with more segments. The solution is to capture the segments individually:

    macro_rules! command_description {
        ($($api_path:ident)::+, $prefix:ident, $type_name_cmd:ident) => {
            CommandDescription {
                cmd: String::from(concat!(
                    stringify!($($api_path)::+),
                    "::",
                    stringify!($prefix),
                    "_CMD"
                )),
                parameters: Some(schema_for!($($api_path)::+::$type_name_cmd)),
            }
        };
    }