#proc-macro #string-literal #prefix #string #attributes #formatted #proc-macro-attributes

nightly prefixes

Attribute-like macros imitating literal prefixes, e.g. #[f]"Hello, {world}"

1 unstable release

0.1.0 Apr 20, 2024

#2044 in Rust patterns

Custom license

17KB

prefixes

Important note

This project is currently only an experiment. At this point, it is highly uncertain if the project will be continued or dropped soon.See the on-going discussion on literal prefixes here

Description

Prefixes delivers various prefix-like proc macro attributes for literals to easily create common types.

Quick example:

#![feature(stmt_expr_attributes, proc_macro_hygiene)]

use prefixes::{f, ms, P, s};

fn _deep_thought2() -> String {
    let answer_path = #[P]"./answer.txt";
    let answer = if answer_path.exists() {
        std::fs::read_to_string(&answer_path).unwrap()
    } else {
        std::thread::sleep(#[s]6 + #[ms]9);
        #[f]"42"
    };

    #[f]"Answer to the Ultimate Question of Life, the Universe, and Everything = {answer}"
}

Usage

To use prefixes, first add it to your project in Cargo.toml:

[dependencies]
prefixes = "0.1.0"

Then enable stmt_expr_attributes and proc_macro_hygiene features (this is possible only on nightly Rust):

#![feature(stmt_expr_attributes, proc_macro_hygiene)]

Finally, use prefixes that you need, e.g.

#![feature(stmt_expr_attributes, proc_macro_hygiene)]
use prefixes::f;

fn greeting(name: &str) -> String {
    #[f]"Welcome, {name}!"
}

Prefixes

Prefix #[f]

Build formatted string from a string literal using the format! macro.

#![feature(stmt_expr_attributes, proc_macro_hygiene)]
use prefixes::f;

let n = 2137;
let s1 = format!("n = {n}");
let s2 = #[f]"n = {n}";

assert_eq!(s1, s2);

Might be also useful for creating owned strings, e.g.

#![feature(stmt_expr_attributes, proc_macro_hygiene)]
use prefixes::f;

let s1 = #[f]"2137";
let s2 = "2137".to_string();

assert_eq!(s1, s2);

Prefixes #[ms], #[s]

Build builds std::time::Duration from an integer literal using from_millis (#[ms]) or from_secs[_f32|_f64] methods (#[s]).

#![feature(stmt_expr_attributes, proc_macro_hygiene)]
use std::time::Duration;
use prefixes::{ms, s};

let d1 = Duration::from_millis(1000);
let d2 = #[ms]1000;

assert_eq!(d1, d2);

let d3 = Duration::from_secs(2);
let d4 = #[s]2;

assert_eq!(d3, d4);

let d5 = Duration::from_secs_f32(3.0f32);
let d6 = #[s]3.0f32;

assert_eq!(d5, d6);

let d7 = Duration::from_secs_f64(4.0f64);
let d8 = #[s]4.0f64;

assert_eq!(d7, d8);

Prefixes #[os], #[OS]

Build OsStr (#[os]) or OsString (#[OS]) from a string literal. Additionally, #[OS] supports string interpolation like #[f].

#![feature(stmt_expr_attributes, proc_macro_hygiene)]
use std::ffi::{OsStr, OsString};
use prefixes::{os, OS};

let os1 = OsStr::new("foo");
let os2 = #[os]"foo";

assert_eq!(os1, os2);

let n = 42;
let os3 = OsString::from(format!("n = 42"));
let os4 = #[OS]"n = 42";

assert_eq!(os3, os4);

Prefixes #[p], #[P]

Build Path (#[p]) or PathBuf (#[P]) from a string literal. Additionally, #[P] supports string interpolation.

#![feature(stmt_expr_attributes, proc_macro_hygiene)]
use std::path::{Path, PathBuf};
use prefixes::{p, P};

let p1 = Path::new("/foo");
let p2 = #[p]"/foo";

assert_eq!(p1, p2);

let ext = "txt";
let p3 = PathBuf::from(format!("/foo.{ext}"));
let p4 = #[P]"/foo.{ext}";

assert_eq!(p3, p4);

Prefixes #[re], #[RE]

Build Regex from a string literal. Additionally, #[RE] calls .unwrap() on the result. Works only if regex crate is included in the dependencies. Doesn't require explicit use regex::Regex.

#![feature(stmt_expr_attributes, proc_macro_hygiene)]
use regex::Regex;
use prefixes::{re, RE};

let re1 = Regex::new("1|2");
let re2 = #[re]"1|2";

assert_eq!(format!("{re1:?}"), format!("{re2:?}"));

let re3 = Regex::new("[A-Z]").unwrap();
let re4 = #[RE]"[A-Z]";

assert_eq!(format!("{re3:?}"), format!("{re4:?}"));

License

This project is licensed under the MIT License - see the LICENSE file for details.

Dependencies

~220–660KB
~16K SLoC