3个版本
新版本 0.1.2 | 2024年8月9日 |
---|---|
0.1.1 | 2021年1月26日 |
0.1.0 | 2021年1月25日 |
#110 在 进程宏 中
每月211次下载
在 5 个Crates中使用了 (直接使用2个)
19KB
153 行代码
tokenstream2-tmpl
此crate旨在与quote配合使用。虽然quote在编译时进行近似引号插值,但此crate在运行时进行插值。这对于接收来自客户端代码的模板的宏非常有用,当宏运行时,标记将被替换。
示例
use proc_macro2::TokenStream;
use tokenstream2-tmpl::interpolate;
use quote::ToTokens;
use std::collections::HashMap;
use syn::{Ident, parse_str};
let input: TokenStream = parse_str("let NAME: int = 5;")?;
let expected: TokenStream = parse_str("let age: int = 5;")?;
let mut replacements: HashMap<&str, &dyn ToTokens> = HashMap::new();
let ident = parse_str::<Ident>("age")?;
replacements.insert("NAME", &ident);
let output = interpolate(input, &replacements);
assert_eq!(
format!("{}", output),
format!("{}", expected)
);
在这里,input
可能是传递给作为模板运行的宏的某些输入。 quote会尝试在宏的编译时展开NAME
。 tokenstream2-tmpl将在宏的运行时展开它。
extern crate proc_macro;
use proc_macro2::TokenStream;
use std::collections::HashMap;
use syn::{Ident, parse::{Parse, ParseStream, Result}, parse_macro_input, punctuated::Punctuated, Token};
use tokenstream2-tmpl::{Interpolate, interpolate};
use quote::ToTokens;
/// Create a token for macro using [syn](syn)
/// Type that holds a key and the value it maps to.
/// An acceptable stream will have the following form:
/// ```text
/// key => value
/// ```
struct KeyValue {
pub key: Ident,
pub arrow_token: Token![=>],
pub value: Ident,
}
/// Make KeyValue parsable from a token stream
impl Parse for KeyValue {
fn parse(input: ParseStream) -> Result<Self> {
Ok(KeyValue {
key: input.parse()?,
arrow_token: input.parse()?,
value: input.parse()?,
})
}
}
/// Make KeyValue interpolatible
impl Interpolate for KeyValue {
fn interpolate(&self, stream: TokenStream) -> TokenStream {
let mut replacements: HashMap<_, &dyn ToTokens> = HashMap::new();
// Replace each "KEY" with the key
replacements.insert("KEY", &self.key);
// Replace each "VALUE" with the value
replacements.insert("VALUE", &self.value);
interpolate(stream, &replacements)
}
}
/// Macro to take a list of key-values with a template to expand each key-value
#[proc_macro_attribute]
pub fn map(tokens: proc_macro::TokenStream, template: proc_macro::TokenStream) -> proc_macro::TokenStream {
// Parse a comma separated list of key-values
let maps =
parse_macro_input!(tokens with Punctuated::<KeyValue, Token![,]>::parse_terminated);
maps.interpolate(template.into()).into()
}
pub fn main() {
#[map(
usize => 10,
isize => -2,
bool => false,
)]
let _: KEY = VALUE;
// Output:
// let _: usize = 10;
// let _: isize = -2;
// let _: bool = false;
}
许可协议:MIT
依赖关系
~260–710KB
~17K SLoC