Can a non-procedural macro parse a string, transforming "543ef1" to [0x54, 0x3e, 0xf1]?

I have a bunch of object IDs represented as 24-digit hex strings, for example in Javascript: ObjectId("543ef1f380da5b0c476373c1")

In Rust, I represent these as struct ObjectId([u8; 12]). so far so good. I can initialize an ObjectId using ObjectId([0x54, 0x3e, 0xf1, 0xf3, 0x80, 0xda, 0x5b, 0x0c, 0x47, 0x63, 0x73, 0xa6])

But what I'd really like is to have a macro that converts "543ef1f380da5b0c476373c1" to [0x54, 0x3e, ...]. I'm pretty sure that this is possible as a procedural macro, but that involves writing a separate crate. Is it possible to write a normal macro that parses out a string to a set of integer constants?

No, declarative macros can't do this, you need to use proc-macros to tear apart or combine strings or identifiers

In the long term / future Rust you could have a

impl ObjectId {
    const
    fn from_hex (code: &str) -> Option<Self>
    {
        ... // parsing code
    }
}

ObjectId::from_hex("deadbeef").unwrap()

and have it parsed ar compile-time (with a compile-time error on bad input).
In the meantime, proc-macros are the only solution. On the other hand, you do not need to pull the quote/syn/proc-macro2 trio for your macro.

2 Likes

Take a look at hex-literal, it already does what you want. Although it uses a proc macro and not a declarative one. Also it has to use proc-macro-hack, since proc macros in expression position are not allowed on stable yet, so you'll get a bunch of crates in your dependency tree instead of a single one.

1 Like