litext
Literal extraction for proc-macro authors. Pull typed values out of TokenStream input without the boilerplate.
let value: String = litext!;
let count: u32 = litext!;
let : = litext!;
What is this?
When you write a procedural macro, you often receive a TokenStream that contains a single literal and need to pull out its value. Doing this correctly means handling every literal kind, every radix, escape sequences, raw strings, byte strings, C strings, and all the edge cases. litext does all that for you.
The library supports every Rust literal kind, span-aware wrapper types for precise diagnostics, a ToTokens round-trip trait, a FromLit extension point for custom types, and a variadic multi-extraction form for pulling several values out of one TokenStream at once.
Installation
Your proc-macro entry point needs to bridge proc_macro and proc_macro2:
Quick Start
Extract a string literal:
use ;
Extract other literal types:
let num: i32 = litext!;
let val: f64 = litext!;
let ch: char = litext!;
let flag: bool = litext!;
Keep the Result instead of returning early:
let result: = litext!;
match result
// Same with an explicit type:
let result: = litext!;
Extracting Multiple Literals at Once
litext! can extract several values from one TokenStream in a single call. Wrap the types in a tuple and put the separator token between them:
// Input TokenStream: "hello" , 42
let : = litext!;
// Three values separated by commas:
// Input: "hello" , 3.14 , true
let : = litext!;
// Semicolon separator:
// Input: "key" ; 100
let : = litext!;
The try form also works for tuples:
let result: = litext!;
Up to 12 values can be extracted in one call.
Separator rules: The separator written in the macro call and the separator in the actual TokenStream must be the same single punctuation character. Any single ASCII punctuation character works: ,, ;, |, &, +, -, *, /, %, ^, !, ?, <, >, =, ., :, @, ~.
Multi-character punctuation sequences such as ->, =>, and :: do not work as separators. Rust tokenizes them as multiple tokens, so only the first character would be consumed and the extraction would fail. Grouping delimiters ((, ), [, ], {, }) and $ are also not valid separators.
Note: Type arguments in tuple position must be single-token identifiers. Generic types like LitInt<u8> span multiple tokens and cannot appear in this position. Use the default forms (LitInt, LitFloat) which carry their default type parameters.
Span-Aware Types
Every literal kind has a span-aware wrapper that bundles the parsed value with its source location. Use these when you need to emit a compiler diagnostic pointing at the exact literal in the user's code.
| Plain Type | Span-Aware Type | Literal Kind |
|---|---|---|
String |
LitStr |
"...", r#"..."# |
i8 to i128, isize |
LitInt<T> (default: i32) |
42, 0xFF, 0b1010 |
u8 to u128, usize |
LitInt<T> (default: i32) |
same as above |
f32, f64 |
LitFloat<T> (default: f64) |
3.14, 1e10 |
bool |
LitBool |
true, false |
char |
LitChar |
'a', '\n' |
u8 |
LitByte |
b'a', b'\xff' |
Vec<u8> |
LitByteStr |
b"...", br#"..."# |
CString |
LitCStr |
c"...", cr#"..."# |
use ;
use LitStr;
use LitInt;
let lit: = litext!;
let value: u8 = *lit.value;
if value == 0
All span-aware types expose:
.value()- the parsed value.span()- the source location.suffix()- the explicit type suffix if present ("i32"for42i32,Nonefor42)
Round-Tripping with ToTokens
All span-aware types implement ToTokens, which converts them back into a TokenStream. This enables an extract, validate, emit pattern:
use ;
let lit: LitStr = litext!;
if lit.value.starts_with
// Emit the literal back into the output with its original span preserved.
lit.to_token_stream
Custom Literal Types
Implement FromLit to make litext!(input as MyType) work for your own types:
use FromLit;
use ;
;
// Then in your macro:
let val: NonEmpty = litext!;
Override from_ident if your type is represented as an identifier token (like bool):
What Is Supported
Strings
| Format | Example |
|---|---|
| Regular | "hello world" |
| Escape sequences | "\n", "\t", "\\", "\"", "\0", "\x41", "\u{1F600}" |
| Line continuation | "hello \ + newline + world" |
| Raw | r#"no escapes here"# |
| Raw (multiple hashes) | r##"can contain #"## |
Integers
| Format | Example |
|---|---|
| Decimal | 42 |
| Hexadecimal | 0xFF, 0XFF |
| Octal | 0o77, 0O77 |
| Binary | 0b1010, 0B1010 |
| Underscore separators | 1_000_000, 0xFF_FF |
| Type suffix | 42i32, 255u8, 100usize |
All integer types are supported: i8 to i128, isize, u8 to u128, usize. Overflow returns a compile error.
Floats
| Format | Example |
|---|---|
| Standard | 3.14 |
| Scientific | 1e10, 2.5e-3, 1E10 |
| Underscore separators | 1_000.5 |
| Type suffix | 3.14f32, 1e10f64 |
Characters
Full escape support: 'a', '\n', '\t', '\\', '\'', '\"', '\0', '\x41', '\u{1F600}'.
Booleans
true and false are parsed as identifier tokens, not literals. All litext extraction handles this transparently.
Byte Literals
b'a', b'\n', b'\xff'. The full 0x00..=0xFF range is valid for \x escapes in byte literals.
Byte Strings
b"hello", b"\xff\x80", br#"raw bytes"#. The full byte range is supported for \x escapes.
C Strings
c"hello", cr#"raw"#. Interior null bytes are rejected with a compile error.
Error Handling
All errors are returned as TokenStream values containing compile_error! invocations. When returned from a proc-macro entry point, the compiler displays the error at the correct source location.
Negative numbers (-42) are two tokens in Rust's token stream: a - punctuation token followed by a positive literal. litext does not support them. Parse the sign and magnitude separately if needed.
Planned Features
Planned
- Feature flag gates to
FromLitimpls for standard types, makeslitextlighter (2.0) - Multi-character separators if possible (<=2.0)
- Negative numbers maybe (<=2.0)
Requirements
- Rust 2024 edition (Rust 1.85)
proc_macro2as a direct dependency in your crate
License
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Cheers, RazkarStudio
© 2026 RazkarStudio. All rights reserved.