标签: rust-macros

处理传递给过程宏的编译时相关文本文件的正确方法

我需要将文本文件或文本文件的内容传递给过程宏,以便过程宏在编译时根据该文本文件的内容进行操作。也就是说,文本文件配置宏的输出。其用例是定义宏构建到库中的寄存器映射的文件。

第二个要求是文本文件由 正确处理Cargo,以便对文本文件的更改触发重新编译,就像对源文件的更改触发重新编译一样。

我最初的想法是使用宏创建一个static字符串include_str!。这解决了第二个要求,但我不知道如何将传递给宏 - 此时我只有要传入的字符串的标识符:

use my_macro_lib::my_macro;
static MYSTRING: &'static str = include_str!("myfile");
my_macro!(MYSTRING); // Not the string itself!
Run Code Online (Sandbox Code Playgroud)

我可以将一个字符串传递给宏,其中包含字符串文字中的文件名,然后在宏内打开该文件:

my_macro!("myfile");
Run Code Online (Sandbox Code Playgroud)

此时我有两个问题:

  1. 如何获取调用函数的路径以获取文件的路径并不明显。我最初认为这会通过 token 暴露Span,但似乎一般不会(也许我错过了一些东西?)。
  2. Cargo如何使文件 make触发更改后的重新编译并不明显。我必须强制执行的一个想法是在宏的输出中添加 an include_str!("myfile"),这有望导致编译器意识到“myfile”,但这有点麻烦。

有什么方法可以做我想做的事情吗?也许通过某种方式获取外部创建的宏内的字符串内容,或者可靠地获取调用 rust 文件的路径(然后Cargo正确进行处理更改)。

顺便说一句,我读过很多地方告诉我无法访问宏内变量的内容,但在我看来,这正是宏quote正在做的事情#variables。这是如何运作的?

rust rust-macros

6
推荐指数
1
解决办法
2148
查看次数

如何创建类似函数的程序宏?

应该如何a_proc_macro定义以便它“返回”一个 5?

fn main() {
    let a = a_proc_macro!();
    assert!(a == 5);
}
Run Code Online (Sandbox Code Playgroud)

rust rust-macros rust-proc-macros

6
推荐指数
1
解决办法
2360
查看次数

使用 Rust 时处理派生宏中的辅助属性的简化方法是什么?

使用 Rust 时处理派生宏中的辅助属性的简化方法是什么?为了说明我正在寻找的内容,我定义了一个名为 的派生宏Duplicate,它创建一个新结构,其中包含旧结构中已由辅助属性标记的所有元素。基本上就是这样转

#[derive(Duplicate)]
struct MyStruct {

    #[dupe_me]
    x : Vec <f64>,

    y : bool,     

    #[dupe_me]
    z : char,     
}
Run Code Online (Sandbox Code Playgroud)

进入

#[derive(Debug)]
struct MyStructDuplicated {
    x : Vec <f64>,
    z : char,     
}
Run Code Online (Sandbox Code Playgroud)

代码的结构是

./mymacro/src/lib.rs
./mymacro/Cargo.toml
./mybin/src/main.rs
./mybin/Cargo.toml
Run Code Online (Sandbox Code Playgroud)

mymacro/Cargo.toml作为

[package]
name = "mymacro"
version = "0.1.0"
authors = ["blank"]
edition = "2018"

[lib]
proc-macro = true

[dependencies]
syn = "1.0.11"
quote = "1.0.2"
proc-macro2 = "1.0.6"
Run Code Online (Sandbox Code Playgroud)

lib.rs作为

[package]
name = "mymacro"
version = …
Run Code Online (Sandbox Code Playgroud)

macros rust rust-macros

6
推荐指数
0
解决办法
1575
查看次数

我们可以在过程宏属性中获取调用者的源代码位置吗?

我需要获取每个方法的调用者的源位置。我正在尝试创建一个proc_macro_attribute来捕获位置并打印它。

#[proc_macro_attribute]
pub fn get_location(attr: TokenStream, item: TokenStream) -> TokenStream {
    // Get and print file!(), line!() of source
    // Should print line no. 11
    item
}
Run Code Online (Sandbox Code Playgroud)
#[get_location]
fn add(x: u32, y: u32) -> u32 {
    x + y
}

fn main() {
    add(1, 5); // Line No. 11
}
Run Code Online (Sandbox Code Playgroud)

rust rust-macros rust-proc-macros

6
推荐指数
2
解决办法
2589
查看次数

如何编写一个显示文件和行号以及可变数量参数的宏?

我在 Rust 中发现了几个有用的宏,即:file!(), line!(), stringify!()我还发现 Rust 允许带有可变参数的宏,如下所述

macro_rules! print_all {
    ($($args:expr),*) => {{
        $(
            println!("{}", $args);
        )*
    }}
}
Run Code Online (Sandbox Code Playgroud)

我的目标是以某种方式将所有这些宏合并到一个我将在故障排除/调试期间使用的宏中。trace!因此在以下示例中调用宏:

let a: i32 = 1;
let b: i32 = 2;
trace!(a,b)
Run Code Online (Sandbox Code Playgroud)

应该扩展到这样的东西:

println!("TRACE: file: {}, line: {}, a: {}, b: {}", file!(), line!(), a, b);
Run Code Online (Sandbox Code Playgroud)

是否可以?如果是,这样的宏将如何工作?

rust rust-macros rust-decl-macros

6
推荐指数
1
解决办法
2817
查看次数

用于重复数组元素的 Rust 宏

我正在尝试编写一个 Rust 宏,用重复元素填充数组,在本例中用零填充。这就是我想出的:

macro_rules! pad4  {
    () => {
        println!("0b00000000, 0b00000000, 0b00000000, 0b00000000");
    }
}

const arr: [u8; 8] = [pad4!(), 0b01111100, 0b10000010, 0b00000010, 0b01111110];
Run Code Online (Sandbox Code Playgroud)

但我收到以下错误:

macro_rules! pad4  {
    () => {
        println!("0b00000000, 0b00000000, 0b00000000, 0b00000000");
    }
}

const arr: [u8; 8] = [pad4!(), 0b01111100, 0b10000010, 0b00000010, 0b01111110];
Run Code Online (Sandbox Code Playgroud)

arrays macros rust rust-macros

6
推荐指数
1
解决办法
3519
查看次数

Macro_rules 是常规宏吗?

我试图理解 Rust 宏语法。在这里我读到宏通常可以通过 3 种方式调用:

mymacro!(<tokens>);
mymacro![<tokens>];
mymacro!{<tokens>};
Run Code Online (Sandbox Code Playgroud)

...然后我看到一个示例宏定义也使用宏 ( macro_rules),但语法不符合以下规则:

macro_rules! name {<tokens>}
Run Code Online (Sandbox Code Playgroud)

name一个标记,我们在这里有第四个合法的宏调用形式,或者macro_rules是一个关键字而不仅仅是宏,并且使用常规宏不可用的特殊语法?

rust rust-macros

6
推荐指数
1
解决办法
240
查看次数

在“macro_rules!”的字符串文字中插入“ident”

是否可以将macro_rules!类型的变量插入ident宏中的字符串文字中?换句话说,是否可以“转义”文字的双引号?

// `trace_macros!` requires nightly
#![feature(trace_macros)]
trace_macros!(true);

macro_rules! export_mod_if_feature {
    ($system:ident) => {
        #[cfg(target_os = "$system")] // <-- problem is here
        pub mod $system;
    };
}

export_mod_if_feature!(linux);

// ... should translate to:
#[cfg(target_os = "linux")]
pub mod linux;

// ... but instead it becomes:
#[cfg(target_os = "$system")]
pub mod linux;
Run Code Online (Sandbox Code Playgroud)

我尝试过使用#[cfg(target_os = stringify!($system))],但cfg需要一个实际的字符串文字target_os =,而不仅仅是一个编译时字符串。

rust rust-macros

6
推荐指数
1
解决办法
2947
查看次数

当代码位于宏内部时,为什么会抑制警告?

以下代码产生一个警告,但我预计会产生两个警告;我每次写一个CString::new("A CString").unwrap().as_ptr()

use std::ffi::CString;
use std::os::raw::c_char;

extern "C" {
    fn puts(s: *const c_char);
}

macro_rules! mymacro {
    () => {
        puts(CString::new("A CString").unwrap().as_ptr());
    };
}

fn main() {
    unsafe {
        puts(CString::new("A CString").unwrap().as_ptr());
        mymacro!();
    }
}
Run Code Online (Sandbox Code Playgroud)
warning: getting the inner pointer of a temporary `CString`
  --> src/main.rs:16:49
   |
16 |         puts(CString::new("A CString").unwrap().as_ptr());
   |              ---------------------------------- ^^^^^^ this pointer will be invalid
   |              |
   |              this `CString` is deallocated at the end of the statement, bind it to a variable to extend …
Run Code Online (Sandbox Code Playgroud)

rust rust-macros

6
推荐指数
1
解决办法
620
查看次数

需要括号的宏调用中的“不必要的括号”警告 - 这是编写宏的不好方法吗?

这是一个非常小的问题,我知道如何禁用该警告,但阅读它后我怀疑它可能表明我可能对我的宏做了一些不正确的事情。无论如何,我有一个Rational有理数结构:

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Rational {
    n: i128,
    d: i128,
}

impl Rational {
    pub fn new(n: i128, d: i128) -> Self {
        Rational { n, d }
    }
}
Run Code Online (Sandbox Code Playgroud)

为了以可读的方式创建它们,我使用宏:

macro_rules! rat {
    ($whole: tt $n : tt / $d : tt) => {
        crate::rational::Rational::new($n + $whole * $d, $d)
    };
    ($n : tt / $d : tt) => {
        crate::rational::Rational::new($n, $d)
    };

    ($n : tt) => {
        crate::rational::Rational::new($n, 1)
    };
} …
Run Code Online (Sandbox Code Playgroud)

macros rust rust-macros

6
推荐指数
1
解决办法
132
查看次数