2017-02-02 16 views
2

Я пытаюсь написать макрос Rust, который позволяет мне использовать имена полей и типы объявления структуры, но мне все еще нужно выделять структуру.Сохранение видимости поля структуры с помощью макроса

У меня есть работа с дополнительными атрибутами, видимостью структуры (спасибо The Little Book of Rust Macros), но не могу понять, как бороться с необязательным присутствием pub в отдельных полях.

До сих пор я получил:

macro_rules! with_generic { 
    ($(#[$struct_meta:meta])* 
    pub struct $name:ident { $($fname:ident : $ftype:ty), *} 
    ) => { 
     with_generic![(pub) $(#[$struct_meta])* struct $name {$($fname: $ftype) ,*}]; 
    }; 

    ($(#[$struct_meta:meta])* 
    struct $name:ident { $($fname:ident : $ftype:ty), *} 
    ) => { 
     with_generic![() $(#[$struct_meta])* struct $name {$($fname: $ftype), *}]; 
    }; 

    (
    ($($vis:tt)*) 
    $(#[$struct_meta:meta])* 
    struct $name:ident { $($fname:ident : $ftype:ty), *} 
    ) => { 
     // emit the struct here 
     $(#[$struct_meta])* 
     $($vis)* struct $name { 
      $($fname: $ftype,)* 
     } 

     // I work with fname and ftypes here 
    } 
} 

И это работает с чем-то вроде

with_generic! { 
    #[derive(PartialEq, Eq, Debug)] 
    pub struct Person { 
     first_name: String, 
     last_name: String 
    } 
} 

или

with_generic! { 
    #[derive(PartialEq, Eq, Debug)] 
    struct PrivatePerson { 
     first_name: String, 
     last_name: String 
    } 
} 

, но не работает с

with_generic! { 
    #[derive(PartialEq, Eq, Debug)] 
    struct MixedPerson { 
     pub first_name: String, 
     last_name: String 
    } 
} 

Я хотел бы получить некоторую помощь о том, как заставить макрос работать с этим последним случаем. Я чувствую, что, возможно, мне не хватает чего-то основного, такого как тип, используемый для привязки видимости. Если есть способ привязать все дерево структуры при получении имен полей и типов, это тоже будет хорошо.

Я также хотел бы узнать, как заставить его работать с структурами, имеющими параметры времени жизни, но, возможно, это должен быть отдельный вопрос.

ответ

2

Вы не можете. По крайней мере, не с одним, нерекурсивным правилом. Это связано с тем, что у Rust нет макроса для видимости.

Ящик parse-macros содержит макрос parse_struct!, который показывает работу, необходимую для полного анализа определения struct. Короткий вариант: вам нужно разобрать каждое поле индивидуально, с одним правилом для каждого из них «есть pub» и «не имеет pub».

Я также хотел бы отметить, что есть еще еще один случай, который ваш макрос еще не учитывает: атрибуты полей, которые необходимы для комментариев к ним для работы.

Совсем скоро макросы 1.1 должны быть стабилизированы, что может обеспечить более легкий подход (при условии, что вы можете выразить свой макрос как деривацию и не заботятся о более старых версиях Rust).

+0

«Я также хотел бы отметить, что есть еще один случай, когда ваш макрос еще не учитывает: атрибуты полей, которые необходимы для комментариев doc для их работы». Фу, спасибо, что я знал, что что-то забыл. Глядя на ваш код (btw ... amazing stuff), я теперь понимаю, что забыл * много * других вещей, например, где предложения. Вы правы, хотя, по сути, мне нужен пользовательский вывод: есть ли где-нибудь я могу узнать больше о том, как там работает макрос 1.1? – lloydmeta

+0

@lloydmeta На данный момент я не знаю. Я бы просто пошел к источнику чего-то вроде «serde-dedive». –

+1

https://doc.rust-lang.org/beta/book/procedural-macros.html – Shepmaster

1

Rust 1.15 был officially released вскоре после того, как я задал этот вопрос и привел procedural macros (custom derive) поддержку, такую ​​как @DK. сказал.

Перейти к началу страницы Я думаю, что пользовательский интерфейс будет получать/синхронизировать, а цитата будет стандартным способом делать такие вещи и делать побочные шаги этой проблемы полностью, так как вам больше не нужно вручную переизбирать структуру.