easy-macros-helpers

Crates.ioeasy-macros-helpers
lib.rseasy-macros-helpers
version0.1.0
created_at2025-11-15 15:46:13.979089+00
updated_at2025-11-15 15:46:13.979089+00
descriptionEasy Macros support library
homepagehttps://github.com/LimitLost/easy-macros
repositoryhttps://github.com/LimitLost/easy-macros
max_upload_size
id1934482
size106,996
JQ (LimitLost)

documentation

https://docs.rs/easy-macros

README

Easy Macros

Crates.io Documentation License

Use the parent crate instead.

What is this?

Crates.io

Easy Macros Helpers is a collection of utility functions provided and used by the Easy Macros crate

Core Features

Error Context Generation

  • context! - Generate context strings for error handling with automatic file/line information

Token Stream Management

Error Handling

Code Generation Utilities

  • indexed_name - Generate indexed identifiers (field0, field1, etc.)
  • find_crate - Locate crate references for generated code (supports renaming)
  • find_crate_list - Try multiple crates, return first found

Examples

Using context! for Error Handling

use std::fs;

fn load_config() -> anyhow::Result<String> {
    // Context with a custom message - this will be the failing operation
    fs::read_to_string("settings.json")
        .with_context(context!("Failed to load application settings"))
}

let result = load_config();
assert!(result.is_err());

let error_msg = format!("{:?}", result.unwrap_err());
assert!(
    error_msg.contains(
        format!(
            "src/examples.rs:{}\r\nFailed to load application settings",
            line!() - 11 // context! is called 11 lines above
        )
        .as_str()
    )
);

Using TokensBuilder for Token Accumulation

let mut result = TokensBuilder::default();

// Add multiple token streams
result.add(quote! {
    println!("Hello");
});
result.add(quote! {
    println!("World");
});

// Wrap everything in braces
result.braced();

// Get final result
let tokens = result.finalize();
assert_eq!(
    readable_token_stream(&tokens.to_string()),
    "{ println!(\"Hello\"); println!(\"World\"); }"
);

Support for Result<TokenStream, ...> with parse_macro_input!

#[proc_macro]
#[anyhow_result]
fn my_macro(input: TokenStream) -> anyhow::Result<TokenStream> {
    //This doesn't return TokenStream on compile errors, but Ok(TokenStream) with compile_error! inside
    let parsed = parse_macro_input!(input as syn::DeriveInput);

    // Process parsed input...
    Ok(quote::quote! {
        // Generated code
    }.into())
}

Generating Indexed Names

let field_names = indexed_name(syn::parse_quote!(field), 3);
let output = quote! {
    struct MyStruct {
        #(#field_names: i32,)*
    }
};
assert_eq!(
    readable_token_stream(&output.to_string()),
    "struct MyStruct { field0: i32, field1: i32, field2: i32, }"
);

Error Wrapping for Better Diagnostics

let mut errors = Vec::<String>::new();
let mut expr = syn::parse_quote!(some_expression);

// Add some errors
errors.push("This field is required".to_string());
errors.push("Invalid type specified".to_string());

// Wrap expression with compile errors
expr_error_wrap(&mut expr, &mut errors);
assert_eq!(
    quote! { #expr }.to_string(),
    quote! {
        {
            compile_error!("This field is required");
            compile_error!("Invalid type specified");
            some_expression
        }
    }
    .to_string()
);

Finding Crate References (with Renaming Support)

if let Some(path) = find_crate("serde", quote!(::Serialize)) {
    // Use path in generated code
}

// Handles renamed crates automatically
// If Cargo.toml has: serde_renamed = { package = "serde", version = "1.0" }
// The above will return: serde_renamed::Serialize

// Try multiple crates with fallbacks
let async_crates = &[
    ("tokio", quote!(::runtime::Runtime)),
    ("async-std", quote!(::task)),
    ("smol", quote!()),
];

if let Some(async_path) = find_crate_list(async_crates) {
    // Uses first available async runtime
}
Commit count: 0

cargo fmt