Using in Functions Returning Option
We previously introduced controlling hook target decisions via attributes, which may feel abstract. Here is a more concrete scenario: target only Option values.
In the example below, we hook functions defined inside main (nesting is supported; see Batch apply). We want to inspect when a value is Some.
tail_expr_idents: set toSometo hook onlySome.ignore_tail_expr_idents: set toNoneto avoid wasteful hooks.result_types: set toOptionso tail/return values are considered.
use std::fmt::Debug;
use hooq::hooq;
#[hooq]
#[hooq::method(.my_inspect())]
#[hooq::tail_expr_idents("Some")]
#[hooq::ignore_tail_expr_idents("None")]
#[hooq::result_types("Option")]
fn main() {
fn option_fn_1() -> Option<i32> {
// hook target
Some(42)
}
fn option_fn_2<T: Debug>(flag: bool, val: T) -> Option<T> {
// hook target
let _ = option_fn_1()?;
// hook target because the return type of the function is Option
if flag {
// hook target
Some(val)
} else {
// NOT hook target
None
}
}
fn result_fn_1() -> Result<i32, ()> {
// NOT hook target because the return type of the function is Result not Option
Ok(42)
}
fn result_fn_2() -> Result<i32, ()> {
// HOOK TARGET because of `?`
// so, #[hooq::skip_all] is needed
#[hooq::skip_all]
let _ = result_fn_1()?;
// NOT hook target because the return type of the function is Result not Option
Ok(42)
}
let _ = option_fn_1();
let _ = option_fn_2(true, 123);
let _ = result_fn_1();
let _ = result_fn_2();
}
trait MyInspect {
fn my_inspect(self) -> Self;
}
impl<T> MyInspect for Option<T>
where
T: Debug,
{
fn my_inspect(self) -> Self {
match self {
Some(val) => {
println!("Inspecting value: {:?}", val);
Some(val)
}
None => None,
}
}
}
Expansion:
#![feature(prelude_import)]
#[macro_use]
extern crate std;
#[prelude_import]
use std::prelude::rust_2024::*;
use std::fmt::Debug;
use hooq::hooq;
fn main() {
fn option_fn_1() -> Option<i32> {
Some(42).my_inspect()
}
fn option_fn_2<T: Debug>(flag: bool, val: T) -> Option<T> {
let _ = option_fn_1().my_inspect()?;
if flag { Some(val).my_inspect() } else { None }.my_inspect()
}
fn result_fn_1() -> Result<i32, ()> {
Ok(42)
}
fn result_fn_2() -> Result<i32, ()> {
let _ = result_fn_1()?;
Ok(42)
}
let _ = option_fn_1();
let _ = option_fn_2(true, 123);
let _ = result_fn_1();
let _ = result_fn_2();
}
trait MyInspect {
fn my_inspect(self) -> Self;
}
impl<T> MyInspect for Option<T>
where
T: Debug,
{
fn my_inspect(self) -> Self {
match self {
Some(val) => {
{
::std::io::_print(format_args!("Inspecting value: {0:?}\n", val));
};
Some(val)
}
None => None,
}
}
}
The point: while Result/Ok/Err are common defaults, hooq does not hard‑code these; you can target other types/idents.
Potentially useful once Try trait stabilizes.