Crate permafrost

Source
Expand description

§Permafrost

This crate provides a procedural macro for embedding data into your Rust code.

§Example

use permafrost::embed;

/// Expands to a const item that contains a greeting.
macro_rules! greet {
    (
        $who:literal
    ) => {
        embed! {
            #[allow(dead_code)]
            const [< HELLO _ $who:case{upper} >]:concatenate : &str = [< "Hello" " " $who "!" >]:concatenate{string};
        }
    }
}

greet!("Jonas");
// Recursive expansion of greet! macro
// ====================================

const HELLO_JONAS: &str = r#"Hello Jonas!"#;

§Usage

Add the following to your Cargo.toml:

permafrost = "1"

§Background

This originally started as a replacement for the paste crate, which allows you to concatenate identifiers and apply case transformations to them.

But seeing how the paste crate is not regurarly updated anymore, and that I needed case transformations for kebab case, I decided to create a more powerful and flexible alternative.

§Structure

All is passed to the embed macro, which is the entry point for the underlying engine. //! Initially, only a token tree is passed to be top-level transformer in an arbitrary transformer chain, then computations are done purely through token streams.

§Blocks

Blocks are the main building blocks of the embed macro, as they denote a transformer-capable token stream.

Blocks are defined by square brackets, annotated by < >, thus, [< (..) >] denotes a block, where (..) is the target token stream. Blocks can also have their own transformer chain, which is to follow the block.

Block syntax is given in EBNF as:

token-stream = token-tree | segment;

token-tree = group | ident | literal | punct | ...;

segment = block transformer-chain;

transformer = ident | ident "{" token-stream "}";

transformer-chain = ":" transformer { "," transformer };

block = "[" "<" token-stream { token-stream } ">" "]" [ transformer-chain ];

§Transformers

All currently available transformers are:

TransformerDescriptionArgumentsExample
concatenateConcatenate the target token streamident, string, r#ident[< (hello [world]):concatenate{ident} >]
ungroupUngroup the target token stream[< (hello [world]):ungroup >]
flattenFlatten the target token stream[< (hello [world]):flatten >]
reverseReverse the target token stream[< (hello [world]):reverse >]
stringifyStringify the target token stream[< (hello [world]):stringify >]
unstringifyUnstringify the target token stream[< "hello world":unstringify >]
caseConvert the target token stream to a specific casekebab, snake, camel, pascal, upper, lower, title[< (hello [world]):case{pascal} >]
countCount the number of elements in the target token stream[< (hello [world]):count >]
appendAppend the target token stream with another token stream[< (hello [world]):append{[!]} >]
prefixPrefix the target token stream with another token stream[< (hello [world]):prefix{[!]} >]

If you believe that a fundamental transformer is missing, please open an issue.

Macros§

embed
Embed a sequence of tokens.