2

I have some code from hex_literal crate and it look like this:

#[proc_macro]
pub fn hex(input: TokenStream) -> TokenStream {
    let ts = TokenStream::from_iter(TokenTreeIter::new(input));
    TokenStream::from(TokenTree::Group(Group::new(Delimiter::Bracket, ts)))
}

This code won't compile with error:

error: the `#[proc_macro]` attribute is only usable with crates of the `proc-macro` crate type

Question: how to re-write this macro in normal module?

William Taylor
  • 549
  • 3
  • 22

2 Answers2

3

Question: how to re-write this macro in normal module?

It sounds a bit like you're asking how you can express it as a macro in a "normal" module. Which I interpret as using macro_rules, given that the hex proc macro is simply adding [...] square brackets around the input.

You can easily do that with macro_rules! like this:

macro_rules! hex {
    ($($tt:tt)*) => {
        [$($tt)*]
    };
}

Otherwise, as @MaxV already answered you need to create a separate crate and specify proc-macro = true.

Just to give a short an straightforward example. First, let's consider the following Cargo.toml:

[package]
name = "proc"
version = "0.1.0"
authors = []
edition = "2018"

[lib]
name = "hex"
path = "src/hex.rs"
proc-macro = true

[[bin]]
name = "bin"
path = "src/main.rs"

[dependencies]
syn = "1.0"

Then you create src/hex.rs, with the code you provided (just including the missing use declarations):

use proc_macro::{Delimiter, Group, TokenStream, TokenTree};
use std::iter::FromIterator;

#[proc_macro]
pub fn hex(input: TokenStream) -> TokenStream {
    let ts = TokenStream::from_iter(input.into_iter());
    TokenStream::from(TokenTree::Group(Group::new(Delimiter::Bracket, ts)))
}

Then to use it, you can create src/main.rs:

fn main() {
    let x = hex::hex!(1 + 2, 3 + 4, 5 + 6);
}

Which expands to:

fn main() {
    let x = [1 + 2, 3 + 4, 5 + 6];
}
vallentin
  • 23,478
  • 6
  • 59
  • 81
  • The problem is, i don't want to create another crate, just want that code in a module. But i guess that isn't supported right now. – William Taylor Jan 21 '21 at 09:34
  • @WilliamTaylor Yes, that is not supported. However, with the solution I provided, you can easily have both `main.rs` and `hex.rs` in the same `src/` directory. You also only need the single `Cargo.toml` file, instead of having 1 for a workspace, and 2 for the library and binary crates. – vallentin Jan 21 '21 at 16:33
0

You have to create separated crate with

[lib]
proc-macro = true

You can't put proc-macro implementation into regular crate.

more details

MaxV
  • 2,601
  • 3
  • 18
  • 25