Вызов функции рекурсивно для всех полей и подполей в procmacro - PullRequest
0 голосов
/ 21 апреля 2020

У меня есть процедурный макрос производного стиля, в котором я хотел бы рассчитать максимальную возможную длину сериализованной версии структуры. Например, учитывая приведенную ниже структуру TestStruct, я хотел бы вызвать некоторую функцию со всеми полями для вычисления длины наихудшего случая.

#[derive(MyLengthProcMacro)]
struct TestStruct {
    f1: u32,
    f2: i64,
    f3: SomeOtherStruct
}

Для примитивов это может выглядеть примерно так:

fn get_string_length(ty: &Type) -> usize {
    let type_string = quote! { #ty }.to_string();
    match type_string.replace(" ", "").as_str() {
        "str" => panic!("String slices must be annotated with a length using #[at_arg()]"),
        "tuple" => panic!("Tuples are not supported!"),
        "char" => "a".len(),
        "bool" => "false".len(),
        "isize" => format!("{:?}", std::isize::MAX).len(),
        "usize" => format!("{:?}", std::usize::MAX).len(),
        "u8" => format!("{:?}", std::u8::MAX).len(),
        "u16" => format!("{:?}", std::u16::MAX).len(),
        "u32" => format!("{:?}", std::u32::MAX).len(),
        "u64" => format!("{:?}", std::u64::MAX).len(),
        "u128" => format!("{:?}", std::u128::MAX).len(),
        "i8" => format!("{:?}", std::i8::MIN).len(),
        "i16" => format!("{:?}", std::i16::MIN).len(),
        "i32" => format!("{:?}", std::i32::MIN).len(),
        "i64" => format!("{:?}", std::i64::MIN).len(),
        "i128" => format!("{:?}", std::i128::MIN).len(),
        "f32" => format!("{:?}", std::f32::MIN).len(),
        "f64" => format!("{:?}", std::f64::MIN).len(),
        _ => {
            // println!("Unexpected type: {:?}", type_string);
            0
        }
    }
}

Проблема, которую я здесь задаю, касается любых не примитивных полей, например. f3: SomeOtherStruct. Есть ли способ получить доступ к полям полей, в pro c -macro?

1 Ответ

2 голосов
/ 21 апреля 2020

Нет.

Макросы расширяются до выполнения такого анализа, поэтому компилятор понятия не имеет, что означает SomeOtherStruct.


Однако это не так, как вы должны реализовать этот макрос! Ваш способ не позволяет пользователю использовать псевдонимы типов.

Что вам нужно сделать, это просто использовать рекурсивную черту и использовать сумму <T as MyLength>::my_length(), где T - это тип поля для каждого поля.

Они вручную реализуют вашу черту для примитивных типов.

...