Skip to content

thepacketgeek/rust-macros-demo

master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
 
 
 
 
 
 

Rust Macros Demo

Practical (but not-exhaustive) examples of declarative macro_rules!. For an introduction check out the accompanying blog series.

Timeit

First up is a macro called timeit!() which allows you to wrap a function and print out a message of how long it took (inspired by similar @timeit decorators in Python). This demo will cover the basics with macro_rules! and using multiple match rules for flexibility with macro usage.

fn wait_for_it() -> String {
    std::thread::sleep(std::time::Duration::from_secs(2));
    return String::from("...Legendary!");
}

fn main() {
    eprintln!("This is going to be...");
    let res = timeit!(wait_for_it());
    eprintln!("{}", res);
}

Outputs:

This is going to be...
'wait_for_it' took 2002 ms
...Legendary!

Retryable

Next we'll get a bit more advanced with variadic arguments to allow retrying of a function like: retry!(do_something_maybe()). We can use our macro_rules! knowledge to build a new macro to help us test:

/// Macro to make testing retryable easier
///
/// Returns a closure that will fail for the given count,
/// afterwhich Ok(()) is returned for each call
/// ```
/// let eventually_succeed = succeed_after!(1);
/// assert!(eventually_succeed().is_err());
/// assert!(eventually_succeed().is_ok());
/// ```
#[macro_use]
macro_rules! succeed_after {
    ($count:expr) => {{
        let mut _iter = (0..$count).into_iter();
        let _func = move || {
            if let Some(_) = _iter.next() {
                return Err(());
            }
            Ok(())
        };
        _func
    }};
}

We'll write two different macros retry!() and retryable!(), the latter with even more capabilities:

fn main() {
    let mut eventually_succeed = succeed_after!(2);
    let res = retry!(eventually_succeed); // Default is 3 retries
    assert!(res.is_ok());
}
fn main() {
    let res = retryable!(succeed_after!(3); retries = 5; delay = 1);
    assert!(res.is_ok());
}

Resources

This is just a small intro to building macros and there are some great resources for diving in and learning more!

About

Examples of some Rust macro_rules

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages