We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Modules, Visibility, Testing and Docs step 10 of 22
macro_rules! scoping is not item scoping
Fix the visibility and behavior of my_assert_eq!, then use it to collect
assertion outcomes:
pub fn run(cases: Vec<(i64, i64, Option<String>)>) -> Vec<Option<String>>
Define the macro inside mod asserts, make it available within the crate with
pub(crate) use, and import it where run calls it. Add two arms: one for two
expressions, with an optional trailing comma, and one for two expressions
followed by formatting arguments.
For each case, compare the operands. Equal values return None. Unequal values
panic inside catch_unwind; return the captured message as Some(String).
Use the message arm whenever the case carries Some(message), including an
empty string. Preserve case order, and return an empty vector for no cases.
Match the required message exactly
Without a message, comparing 4 and 5 must produce:
assertion `left == right` failed
left: 4
right: 5
With the message ctx, it must produce:
assertion `left == right` failed: ctx
left: 4
right: 5
There are two spaces before left, one before right, and no final newline.
These are the strings this exercise requires. Panic-hook output such as a
thread name, source location or backtrace is not part of the captured payload.
Give the macro a path
The starter places an unqualified macro definition after its uses. Unlike a
function item, a macro_rules! definition has textual scope starting after
the definition. That scope can extend into later nested modules, but ends
with the enclosing scope unless explicitly extended or imported.
Give this macro a module path instead:
mod asserts {
macro_rules! my_assert_eq { /* your two arms */ }
pub(crate) use my_assert_eq;
}
use asserts::my_assert_eq;
The re-export makes the macro available by path within the crate. Its original textual scope still exists; the import provides an additional way to find it. A path-based import does not need to appear before the calls that use it.
#[macro_export] serves a different purpose: it exposes a macro at the crate
root for other crates. It is unnecessary for this task. When an exported macro
needs an item from its defining crate, $crate::... names that crate; ordinary
crate::... refers to the invoking crate. $crate does not bypass privacy.
Borrow each operand once
Both arms should evaluate each operand once and borrow the results. This avoids moving a value just to compare it and avoids repeating side effects:
let (l, r) = (&$left, &$right);
Compare the borrowed values and format them with Debug only on failure.
Keep format_args!($($arg)+) inside that failure branch too, so message
arguments are not evaluated for a passing assertion. Pass it directly to
panic! rather than storing it in a temporary with borrowed formatting data.
The two patterns can be written as:
($left:expr, $right:expr, $($arg:tt)+) => { /* message arm */ };
($left:expr, $right:expr $(,)?) => { /* plain arm */ };
Either order works for these patterns. Rust chooses the first arm that matches the entire invocation; a two-argument call cannot match the message arm.
Capture the payload and restore the hook
catch_unwind captures unwinding panics, not aborting panics. The supplied
runner temporarily installs a silent panic hook so expected failures do not
print diagnostics. Preserve its restoration of the previous hook after all
cases, including an empty input.
Hooks are process-global. This temporary replacement suits the exercise's sequential runner; it is not isolated from other threads and is not a general pattern for concurrently running tests. The supplied restoration also assumes the runner reaches its final cleanup rather than unexpectedly unwinding first.
Keep the supplied describe helper. It handles the string payloads used here
and provides a fallback for other payload types. The tests compare returned
values; they do not enforce the requested module layout or prove that a hook
was restored, so follow those structural requirements as well.
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
Rust reference solution
Sign in to track your attempts toward unlocking the reference solution.