Method
Specify hooked methods via #[hooq::method(...)] or by flavors. The ... has two modes:
- If it starts with
., it is in insertion mode, inserting the method between the expression and?(or at the end forreturn/tail). - Otherwise it is in replacement mode, replacing the expression. Use
$exprto reference the original expression (already recursively hooked where needed).
Meta variables (see Meta Variables) can be used in these expressions.
Insertion Mode
use hooq::hooq;
fn failable<T>(val: T) -> Result<T, String> {
Ok(val)
}
#[hooq]
#[hooq::method(.inspect_err(|_| {
let _ = "inserted mode";
}))]
fn main() -> Result<(), Box<dyn std::error::Error>> {
failable(())?;
#[hooq::method(.inspect_err(|_| {
let _ = "before chainned";
}).$so_far)]
failable(())?;
#[hooq::method(.$so_far.inspect_err(|_| {
let _ = "after chainned";
}))]
failable(())?;
Ok(())
}
You can chain with .$so_far to prepend/append relative to the existing chain.
Expansion:
#![feature(prelude_import)]
#[macro_use]
extern crate std;
#[prelude_import]
use std::prelude::rust_2024::*;
use hooq::hooq;
fn failable<T>(val: T) -> Result<T, String> {
Ok(val)
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
failable(())
.inspect_err(|_| {
let _ = "inserted mode";
})?;
failable(())
.inspect_err(|_| {
let _ = "before chainned";
})
.inspect_err(|_| {
let _ = "inserted mode";
})?;
failable(())
.inspect_err(|_| {
let _ = "inserted mode";
})
.inspect_err(|_| {
let _ = "after chainned";
})?;
Ok(())
}
Replacement Mode
If it does not start with . (dot), it is treated as a replacement function, replacing the original expression with the configured expression. The expression being replaced can be accessed using the $expr meta variable. (While it’s possible to write without using $expr, it would likely not be useful.)
use hooq::hooq;
fn failable<T>(val: T) -> Result<T, String> {
Ok(val)
}
fn wrapper<T, E>(r: Result<T, E>) -> Result<T, E>
where
E: std::fmt::Debug,
{
if let Err(e) = &r {
println!("Error occurred: {:?}", e);
}
r
}
#[hooq]
#[hooq::method(wrapper($expr))]
fn main() -> Result<(), String> {
failable(())?;
Ok(())
}
Expansion:
#![feature(prelude_import)]
#[macro_use]
extern crate std;
#[prelude_import]
use std::prelude::rust_2024::*;
use hooq::hooq;
fn failable<T>(val: T) -> Result<T, String> {
Ok(val)
}
fn wrapper<T, E>(r: Result<T, E>) -> Result<T, E>
where
E: std::fmt::Debug,
{
if let Err(e) = &r {
{
::std::io::_print(format_args!("Error occurred: {0:?}\n", e));
};
}
r
}
fn main() -> Result<(), String> {
wrapper(failable(()))?;
Ok(())
}
Use $expr (not $source) in replacement mode. $expr holds the expression after inner hooks have been applied, while $source is for logging/display of the original tokens.
Removing ? via Trailing !
When hooking the ? operator, appending ! to the method consumes the trailing ?.
Requires the
consume-questionfeature.
cargo add hooq --features consume-question
Example aliasing ? to .unwrap():
use hooq::hooq;
fn failable<T>(val: T) -> Result<T, &'static str> {
Ok(val)
}
#[hooq]
#[hooq::hook_targets("?")]
#[hooq::method(.unwrap()!)]
fn main() {
failable(())?;
}
Expansion:
#![feature(prelude_import)]
#[macro_use]
extern crate std;
#[prelude_import]
use std::prelude::rust_2024::*;
use hooq::hooq;
fn failable<T>(val: T) -> Result<T, &'static str> {
Ok(val)
}
fn main() {
failable(()).unwrap();
}