【问题标题】:How can I parse a `syn::Signature` from a `syn::parse::ParseStream`?如何从 `syn::parse::ParseStream` 中解析 `syn::Signature`?
【发布时间】:2020-07-27 15:43:44
【问题描述】:

我正在试验 Rust 过程宏。

我希望能够创建一个用于生成 JNI 调用样板的宏。类似的东西

jni_method!{com.purplefrog.rust_callable.Widget, fn echo_str(&str)->String}

到目前为止,我有以下代码 (playground):

#[macro_use]
extern crate syn; // 1.0.33

use syn::parse::{Parse, ParseStream};
use syn::Signature;

struct Arguments {
    name: proc_macro2::Ident,
    signature: Signature,
}

impl Parse for Arguments {
    fn parse(tokens: ParseStream) -> Result<Arguments, syn::Error> {
        let name: proc_macro2::Ident = tokens.parse()?;
        let comma: Token![,] = tokens.parse()?;
        let signature: Signature = //tokens.parse()?;
            syn::item::parsing::parse_signature(tokens)?;

        Ok(Arguments {
            name: name,
            signature,
        })
    }
}

很遗憾,parse_signature 调用出错:

error[E0603]: module `item` is private
   --> src/lib.rs:17:18
    |
17  |             syn::item::parsing::parse_signature(tokens)?;
    |                  ^^^^ private module
    |
note: the module `item` is defined here
   --> /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/syn-1.0.33/src/lib.rs:363:1
    |
363 | mod item;
    | ^^^^^^^^^

从ParseStream 解析Signature 的正确方法是什么?

【问题讨论】:

    标签: rust macros rust-proc-macros


    【解决方案1】:

    为什么需要Signature?根据您实际尝试解析的内容,您应该使用以下方法之一:

    • Fn* 特征签名(例如FnMut(usize) -&gt; bool)

      解析成syn::TraitBound(为了捕获不存在于仅路径中的生命周期边界),然后您可以从特征边界路径的最后一段的括号中的参数中获取输入/输出。

    • 裸函数,又名函数指针(例如fn(usize) -&gt; bool)

      解析成syn::TypeBareFn,就可以直接得到输入/输出了。

    • 函数定义,包括主体(例如fn foo(x: usize) -&gt; bool { x &gt; 5 })

      解析成syn::ItemFn,其中包含一个签名。

    • 外来函数定义(例如fn foo(x: usize) -&gt; bool)

      解析成Struct syn::ForeignItemFn,其中包括一个签名。请注意,这适用于 extern 块中的声明,因此这可能不是您真正想要的。

    【讨论】:

    • TraitBound 缺少函数名称。我最终通过解析 Ident 和 TypeBareFn 解决了我的问题,但这使得语法有点不雅。 ItemFn 包含一个主体,这会使宏的用户感到困惑。 ForeignItemFn 可能是一个不错的选择,尽管它包含在技术上不是必需的参数名称,但可能会帮助人们稍后阅读代码。
    • 您的用例到底是什么?我担心你可能会以错误的方式解决这个问题。您能否更新您的问题以提供宏的示例输入以及如何使用它?
    • 我已经添加了关于如何使用宏的想法。
    【解决方案2】:

    我最终找到了一个如何解决此问题的示例 (https://github.com/dtolnay/syn/blob/master/examples/lazy-static/lazy-static/src/lib.rs)。你应该为它创建自己的struct 和impl Parse。我能够从 Parseable 元素构建自己的语法。

    struct MySignature {
        pub parameter_types: Vec<Type>,
    }
    
    impl Parse for MySignature {
        fn parse(tokens: ParseStream) -> Result<Self, syn::Error> {
            let mut parameter_types: Vec<Type> = Vec::new();
    
            let arg_types: ParseBuffer;
            parenthesized!(arg_types in tokens);
    
            while !arg_types.is_empty() {
                let arg_type: Type = arg_types.parse()?;
                parameter_types.push(arg_type);
    
                if !arg_types.is_empty() {
                    let _comma: Token![,] = arg_types.parse()?;
                }
            }
    
            Ok(MySignature { parameter_types })
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-07-05
      • 2016-02-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-11
      • 2016-11-04
      相关资源
      最近更新 更多