2

我正在试验 Rust 过程宏。

我希望能够创建一个用于生成 JNI 调用样板的宏。就像是

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

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

#[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;
    | ^^^^^^^^^

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

4

2 回答 2

1

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

  • Fn*特征签名(例如FnMut(usize) -> bool

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

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

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

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

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

  • 外部函数定义(例如fn foo(x: usize) -> bool

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

于 2020-07-28T22:13:37.433 回答
0

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

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 })
    }
}
于 2021-09-01T13:19:03.213 回答