Можно ли составить путь из кусков в декларативном макросе?


#1

Затупил тут с макросами.

#[derive(Debug)]
struct LongNameA;

#[derive(Debug)]
struct LongNameB(u8);

#[derive(Debug)]
enum LongNameE {
    LongNameA(LongNameA),
    LongNameB(LongNameB),
}

// I want to get rid of `$variant_name:path` argument somehow
macro_rules! gen_struct_enum_conversion {
    ($enum_name:path, $struct_name:path, $variant_name:path) => {
        impl From<$struct_name> for $enum_name {
            fn from(e: $struct_name) -> Self {
                $variant_name(e)
                // $enum_name::$struct_name(e) // doesn't work
            }
        }
    };
}

gen_struct_enum_conversion! { LongNameE, LongNameA, LongNameE::LongNameA }
gen_struct_enum_conversion! { LongNameE, LongNameB, LongNameE::LongNameB }

// Desired "DRY" macro call:
// gen_struct_enum_conversion! { LongNameE, LongNameB }

fn x(e: &LongNameE) {
    println!("{:?}", e);
}

fn main() {
    x(&LongNameE::LongNameA(LongNameA));
    x(&LongNameE::LongNameB(LongNameB(0)));
    
    x(&LongNameA.into());
    x(&LongNameB(0).into());
}

Playground

Вопрос, собственно, в том, как (и можно ли вообще) добиться возможности вызывать gen_struct_enum_conversion! { LongNameE, LongNameB }?


#2

О, откопал таки на SO ответ, причем 1 в 1 что мне надо было:

TLDR: конкретно в моем случае (и структура, и перечисление в текущем пространстве имен) мне нужны были identы, а не pathы:

macro_rules! gen_struct_enum_conversion {
    ($enum_name:ident, $struct_name:ident) => {
        impl From<$struct_name> for $enum_name {
            fn from(e: $struct_name) -> Self {
                $enum_name::$struct_name(e)
            }
        }
    };
}

UPD: Дополнение из гиттера:

@chtotut: вообще, на мой взгляд, для твоего случая вроде как подходит derive_more, глянь, вдруг поможет :slight_smile:
@ozkriff: Хм. Да, спасибо, пожалуй derive_more::From тут очень даже в тему будет, тем более что зависимостей новых в мою свалку проект не тянет. Заодно код ошибок упрощу.