Crate guard_macros
source ·Expand description
Usage
// returns when (expr) is evaluated to false
guard!( (expr) );
// returns when refuted (i.e. (expr) doesn't match (pat))
guard!( (pat) = (expr) );
// panics instead of returning (called "Refute Handler")
guard!( (expr) => panic!("false") );
guard!( (pat) = (expr) => panic!("refuted") );
guard! {
// can be repeated
(expr),
(pat) = (expr) => panic!("refuted"),
// can be scoped and nested
{
(expr),
(pat) = (expr),
{
(expr),
(pat) = (expr) => panic!("baz"),
} => _, // inherit refute handler
} => panic!("foo"),
}
Overview
guard_macros
provides two macros:
guard!
which replaces recurringlet
-else
andif
statements.make_guard!
which defines new guard macros with different default Refute Handlers.
Refute Handler
A “Refute Handler” is an expression that is executed when the condition of
a clause is not met. It can be specified by appending =>
followed by an
expression, either:
- to a single clause
guard! { (pat) = (expr) => panic!("refuted"), (expr) => panic!("false"), }
- or to a group of clauses enclosed by
{
}
.guard! { { (pat) = (expr), (expr), } => panic!("unmet") }
Note: By default, blocks create a new scope, but it can be disabled by prepending a
*
to the opening brace.
Example
#![allow(dead_code)]
/// Ignores any tokens inside the block.
macro_rules! comment {
( $($_:tt)* ) => {};
}
use guard_macros::guard;
#[cfg_attr(test, test)]
fn main() {
let event = Event::Message {
author: "yuki".into(),
message: "hello world".into(),
};
println!("{event:?}");
handle_message(&event);
handle_error(&event);
}
#[derive(Debug)]
enum Event {
Message { author: String, message: String },
Error { error: String },
}
enum Action {
SendMessage { message: String },
}
fn handle_message(event: &Event) -> Option<Action> {
guard!(Event::Message { author, message } = event);
// expands to:
comment! {
let Event::Message { author, message } = event else {
return ::core::default::Default::default()
};
}
println!("{author}: {message}");
guard! {
*author == "yuki",
message.starts_with("/ping"),
};
// expands to:
comment! {
if !(*author == "yuki") {
return ::core::default::Default::default()
}
if !(message.starts_with("/ping")) {
return ::core::default::Default::default()
}
}
Some(Action::SendMessage {
message: "pong!".into(),
})
}
fn handle_error(event: &Event) -> Option<Action> {
guard!(Event::Error { error } = event);
// expands to:
comment! {
let Event::Error { error } = event else {
return ::core::default::Default::default()
};
}
println!("ERR: {error}");
None
}
Specification
-
Syntax
GuardBody :
GuardDecl (,
GuardDecl )*,
?GuardDecl :
*
?{
GuardBody}
RefuteHandlerInheritable
| GuardClause RefuteHandler?GuardClause :
PatternNoTopAlt=
Expression
| ExpressionRefuteHandler :
=>
ExpressionRefuteHandlerInheritable :
RefuteHandler
|=>
_
-
Syntax
MakeGuardBody :
MakeGuardDecl (,
MakeGuardDecl )*,
?MakeGuardDecl :
Identifier RefuteHandler
Macros
- A macro that replaces
let
-else
andif
clause(s). - A macro that defines new guard macro(s).