tokenstream2-tmpl

![github]![crates-io]![docs-rs]![workflow]

This crate is meant to be a complement to [quote]. Where as [quote] does quasi-quote interpolations at compile-time, this crate does them at run-time. This is handy for macros receiving templates from client code with markers to be replaced when the macro is run.

Examples

```rust use procmacro2::TokenStream; use tokenstream2-tmpl::interpolate; use quote::ToTokens; use std::collections::HashMap; use syn::{Ident, parsestr};

let input: TokenStream = parsestr("let NAME: int = 5;")?; let expected: TokenStream = parsestr("let age: int = 5;")?;

let mut replacements: HashMap<&str, &dyn ToTokens> = HashMap::new(); let ident = parse_str::("age")?; replacements.insert("NAME", &ident);

let output = interpolate(input, &replacements); assert_eq!( format!("{}", output), format!("{}", expected) );

```

Here input might be some input to a macro that functions as a template. [quote] would have tried to expand NAME at the macro's compile-time. [tokenstream2-tmpl] will expand it at the macro's run-time.

```rust extern crate procmacro; use procmacro2::TokenStream; use std::collections::HashMap; use syn::{Ident, parse::{Parse, ParseStream, Result}, parsemacroinput, punctuated::Punctuated, Token}; use tokenstream2-tmpl::{Interpolate, interpolate}; use quote::ToTokens;

/// Create a token for macro using 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 { 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

[procmacroattribute]

pub fn map(tokens: procmacro::TokenStream, template: procmacro::TokenStream) -> procmacro::TokenStream { // Parse a comma separated list of key-values let maps = parsemacroinput!(tokens with Punctuated::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; } ```

License: MIT