4

我正在使用引号生成代码来解码汇编操作。我的芯片的说明手册使用二进制值来描述操作,所以我希望我生成的代码也将文字表达为二进制值,以便我更容易抽查正确性。

我找不到指定这一点的方法。proc_macro2::Literal提供了多种控制文字后缀u8( ,i32等)的方法,但我没有看到任何可以控制文字基础的方法。

我的理想格式是基数 2,每四位使用一个下划线,并以适当的后缀结尾,但只需要基数。

use quote::quote; // 1.0.6

fn main() {
    let value = 0b0101_0101_u8;

    let code = format!("{}", quote! { #value });
    
    assert_eq!("0b0101_0101_u8", code);
}
thread 'main' panicked at 'assertion failed: `(left == right)`
  left: `"0b0101_0101_u8"`,
 right: `"85u8"`', src/main.rs:8:5
4

2 回答 2

3

您可以使用将数字格式化为字符串format!,然后TokenStream从中构造一个,然后您可以在中使用quote!

use proc_macro2::TokenStream;
use quote::quote; // 1.0.6
use std::str::FromStr;

fn main() {
    let value = 0b0101_0101_u8;
    let value_formatted = TokenStream::from_str(&format!("0b{:08b}_u8", value)).unwrap();
    let code = format!(
        "{}",
        quote! {
            #value_formatted
        }
    );

    assert_eq!("0b01010101_u8", code);
}

format!宏不支持下划线,但这可以很容易地扩展以使用自定义格式化程序插入它们。

于 2020-07-04T11:16:29.110 回答
2

这是我使用Peter Hall 概述的实现以及来自 E_net4的下划线建议制作的包装器类型:

use quote::quote; // 1.0.6

fn main() {
    let value = AsBits(0b0101_0101_u8);

    let code = format!("{}", quote! { #value });

    assert_eq!("0b0101_0101_u8", code);
}
use proc_macro2::TokenStream; // 1.0.17
use quote::ToTokens; // 1.0.6
use std::str::FromStr;

struct AsBits<T>(T);

impl ToTokens for AsBits<u8> {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let b = format!(
            "0b{:04b}_{:04b}_u8",
            (self.0 & 0xF0) >> 4,
            (self.0 & 0x0F) >> 0,
        );

        tokens.extend(TokenStream::from_str(&b).unwrap());
    }
}
于 2020-07-06T13:29:45.783 回答