Meta Variables
Inside #[hooq::method(...)], you can use special meta variables (prefixed with $) that are replaced with values.
Quick Reference
| Name | Literal Kind | Description |
|---|---|---|
$line | usize | Line number of the target. |
$column or $col | usize | Column number of the target. |
$path | string | Relative path to the file of the target. |
$file | string | File name of the target. |
$source | expression | Original tokens of the target (for logging; differs from $expr). |
$count or $nth | string | Display which numbered target within the function. |
$fn_name or $fnname | string | Name of the function containing the target. |
$fn_sig or $fnsig | string | Signature of the function/closure containing the target. |
$xxx | (any) | User‑defined meta variable via inert attribute. |
$bindings or $vars | HashMap | All user bindings. |
$hooq_meta or $hooqmeta | hooq::HooqMeta | Struct bundling key meta information. |
$expr | expression | Original expression for replacement mode (after inner hooks). |
$so_far or $sofar | expression | Current insertion chain, used to chain further. |
Example using most variables:
use hooq::hooq;
fn failable<T>(val: T) -> Result<T, String> {
Ok(val)
}
#[hooq]
#[hooq::xxx = "user defined binding."]
#[hooq::method(.inspect_err(|_| {
// Fundamental information provided by hooq.
let _line = $line;
let _column = $column;
let _path = $path;
let _file = $file;
let _source = stringify!($source);
let _count = $count;
let _fn_name = $fn_name;
let _fn_sig = $fn_sig;
// Meta vars defined by user.
let _xxx = $xxx;
let _bindings = $bindings;
// All information summarized up to this point.
let _hooq_meta = $hooq_meta;
}))]
fn main() -> Result<(), Box<dyn std::error::Error>> {
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 main() -> Result<(), Box<dyn std::error::Error>> {
failable(())
.inspect_err(|_| {
let _line = 28usize;
let _column = 17usize;
let _path = "mdbook-source-code/meta-vars-all/src/main.rs";
let _file = "main.rs";
let _source = "failable(()) ?";
let _count = "1st ?";
let _fn_name = "main";
let _fn_sig = "fn main() -> Result < (), Box < dyn std :: error :: Error > >";
let _xxx = "user defined binding.";
let _bindings = ::std::collections::HashMap::from([
(
::std::string::ToString::to_string("xxx"),
{
let expr = ::std::string::ToString::to_string(
"\"user defined binding.\"",
);
let value: ::std::rc::Rc<dyn ::std::any::Any> = ::std::rc::Rc::new(
"user defined binding.",
);
::hooq::BindingPayload {
expr,
value,
}
},
),
]);
let _hooq_meta = ::hooq::HooqMeta {
line: 28usize,
column: 17usize,
path: "mdbook-source-code/meta-vars-all/src/main.rs",
file: "main.rs",
source_str: "failable(()) ?",
count: "1st ?",
bindings: ::std::collections::HashMap::from([
(
::std::string::ToString::to_string("xxx"),
{
let expr = ::std::string::ToString::to_string(
"\"user defined binding.\"",
);
let value: ::std::rc::Rc<dyn ::std::any::Any> = ::std::rc::Rc::new(
"user defined binding.",
);
::hooq::BindingPayload {
expr,
value,
}
},
),
]),
};
})?;
Ok(())
}
Target Information
line
use hooq::hooq;
fn failable<T>(val: T) -> Result<T, String> {
Ok(val)
}
#[hooq]
#[hooq::method(.inspect_err(|_| {
let _line = $line;
}))]
fn main() -> Result<(), Box<dyn std::error::Error>> {
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 main() -> Result<(), Box<dyn std::error::Error>> {
failable(())
.inspect_err(|_| {
let _line = 12usize;
})?;
Ok(())
}
Prefer $line over line!(); the latter points to the attribute location, not the actual target.
column
use hooq::hooq;
fn failable<T>(val: T) -> Result<T, String> {
Ok(val)
}
#[hooq]
#[hooq::method(.inspect_err(|_| {
let _column = $column;
}))]
fn main() -> Result<(), Box<dyn std::error::Error>> {
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 main() -> Result<(), Box<dyn std::error::Error>> {
failable(())
.inspect_err(|_| {
let _column = 17usize;
})?;
Ok(())
}
path
Replaced with the relative path from the crate root (CARGO_MANIFEST_DIR) to the file containing the hook target.
However, the relative path’s starting point may not be the crate root in cases such as when using workspaces. Since procedural macros are designed not to obtain accurate absolute file paths, hooq does not provide meta variables for retrieving absolute paths.
use hooq::hooq;
fn failable<T>(val: T) -> Result<T, String> {
Ok(val)
}
#[hooq]
#[hooq::method(.inspect_err(|_| {
let _path = $path;
}))]
fn main() -> Result<(), Box<dyn std::error::Error>> {
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 main() -> Result<(), Box<dyn std::error::Error>> {
failable(())
.inspect_err(|_| {
let _path = "mdbook-source-code/meta-vars-path/src/main.rs";
})?;
Ok(())
}
file
use hooq::hooq;
fn failable<T>(val: T) -> Result<T, String> {
Ok(val)
}
#[hooq]
#[hooq::method(.inspect_err(|_| {
let _file = $file;
}))]
fn main() -> Result<(), Box<dyn std::error::Error>> {
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 main() -> Result<(), Box<dyn std::error::Error>> {
failable(())
.inspect_err(|_| {
let _file = "main.rs";
})?;
Ok(())
}
source
This meta variable provides the token stream (expression) of the hook target before any hooks are applied by the hooq macro. It is intended for debugging purposes.
In contrast, $expr represents the expression after hooks have already been applied internally. $expr is used in replacement mode to determine where to embed the original expression.
use hooq::hooq;
fn failable<T>(val: T) -> Result<T, String> {
Ok(val)
}
#[hooq]
#[hooq::method(.inspect_err(|_| {
let _source = stringify!($source);
}))]
fn main() -> Result<(), Box<dyn std::error::Error>> {
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 main() -> Result<(), Box<dyn std::error::Error>> {
failable(())
.inspect_err(|_| {
let _source = "failable(()) ?";
})?;
Ok(())
}
Stringification helpers commonly used with $source:
Example with summary!:
use hooq::hooq;
#[hooq]
#[hooq::method(.inspect_err(|_| {
let source = ::hooq::summary!($source);
eprintln!("{source}");
}))]
fn main() -> Result<(), Box<dyn std::error::Error>> {
Err((
"aaaaaaaaaaaaaaaaaaaa",
"bbbbbbbbbbbbbbbbbbbb",
"cccccccccccccccccccc",
"dddddddddddddddddddd",
"errorerrorerrorerrorerror",
)
.4
.into())
}
Result excerpt:
10> Err((
...
15| "erro..rror",
16| )
17| .4
18| .into())
|
count
Indicates which numbered target this is within the function for each target type (?, return, or tail expression).
This meta variable is a remnant from when $line could only be obtained on nightly. In most cases, $line is more straightforward.
use hooq::hooq;
fn failable<T>(val: T) -> Result<T, String> {
Ok(val)
}
#[hooq]
#[hooq::method(.inspect_err(|_| {
let _count = $count;
}))]
fn main() -> Result<(), Box<dyn std::error::Error>> {
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 main() -> Result<(), Box<dyn std::error::Error>> {
failable(())
.inspect_err(|_| {
let _count = "1st ?";
})?;
Ok(())
}
fn_name
use hooq::hooq;
fn failable<T>(val: T) -> Result<T, String> {
Ok(val)
}
#[hooq]
#[hooq::method(.inspect_err(|_| {
let _fn_name = $fn_name;
}))]
fn main() -> Result<(), Box<dyn std::error::Error>> {
failable(())?;
(|| -> Result<(), String> {
failable(())?;
Ok(())
})()?;
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 main() -> Result<(), Box<dyn std::error::Error>> {
failable(())
.inspect_err(|_| {
let _fn_name = "main";
})?;
(|| -> Result<(), String> {
failable(())
.inspect_err(|_| {
let _fn_name = "__closure_in_main__";
})?;
Ok(())
})()
.inspect_err(|_| {
let _fn_name = "main";
})?;
Ok(())
}
fn_sig
use hooq::hooq;
fn failable<T>(val: T) -> Result<T, String> {
Ok(val)
}
#[hooq]
#[hooq::method(.inspect_err(|_| {
let _fn_sig = $fn_sig;
}))]
fn main() -> Result<(), Box<dyn std::error::Error>> {
failable(())?;
(|| -> Result<(), String> {
failable(())?;
Ok(())
})()?;
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 main() -> Result<(), Box<dyn std::error::Error>> {
failable(())
.inspect_err(|_| {
let _fn_sig = "fn main() -> Result < (), Box < dyn std :: error :: Error > >";
})?;
(|| -> Result<(), String> {
failable(())
.inspect_err(|_| {
let _fn_sig = "| | -> Result < (), String > {}";
})?;
Ok(())
})()
.inspect_err(|_| {
let _fn_sig = "fn main() -> Result < (), Box < dyn std :: error :: Error > >";
})?;
Ok(())
}
User‑Defined Meta Variables (Bindings)
Define via inert attributes #[hooq::xxx = ...] or in hooq.toml under bindings.
For details on how to define them, see the respective pages:
Example (inert attribute):
use hooq::hooq;
fn failable<T>(val: T) -> Result<T, String> {
Ok(val)
}
enum CauseKind {
DataBase,
Server,
}
#[hooq]
// Can be defined in the format #[hooq::xxx = value]
#[hooq::string = "hello!"] // string literal
#[hooq::integer = 10] // integer literal
#[hooq::cause_kind = CauseKind::Server] // some value
#[hooq::method(.inspect_err(|_| {
let _string = $string;
let _integer = $integer;
let _cause_kind = $cause_kind;
}))]
fn main() -> Result<(), Box<dyn std::error::Error>> {
failable(())?;
// Overriding meta variables.
#[hooq::cause_kind = CauseKind::DataBase]
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)
}
enum CauseKind {
DataBase,
Server,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
failable(())
.inspect_err(|_| {
let _string = "hello!";
let _integer = 10;
let _cause_kind = CauseKind::Server;
})?;
failable(())
.inspect_err(|_| {
let _string = "hello!";
let _integer = 10;
let _cause_kind = CauseKind::DataBase;
})?;
Ok(())
}
bindings
Retrieve all user-defined meta variables (bindings) as a HashMap<String, BindingPayload>.
BindingPayload stores the stringified binding expression and a value using Rc<dyn Any>.
use hooq::hooq;
fn failable<T>(val: T) -> Result<T, String> {
Ok(val)
}
enum CauseKind {
#[allow(unused)]
DataBase,
Server,
}
#[hooq]
// Can be defined in the format #[hooq::xxx = value]
#[hooq::string = "hello!"] // string literal
#[hooq::integer = 10] // integer literal
#[hooq::cause_kind = CauseKind::Server] // some value
#[hooq::method(.inspect_err(|_| {
let _bindings = $bindings;
}))]
fn main() -> Result<(), Box<dyn std::error::Error>> {
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)
}
enum CauseKind {
#[allow(unused)]
DataBase,
Server,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
failable(())
.inspect_err(|_| {
let _bindings = ::std::collections::HashMap::from([
(
::std::string::ToString::to_string("cause_kind"),
{
let expr = ::std::string::ToString::to_string(
"CauseKind :: Server",
);
let value: ::std::rc::Rc<dyn ::std::any::Any> = ::std::rc::Rc::new(
CauseKind::Server,
);
::hooq::BindingPayload {
expr,
value,
}
},
),
(
::std::string::ToString::to_string("integer"),
{
let expr = ::std::string::ToString::to_string("10");
let value: ::std::rc::Rc<dyn ::std::any::Any> = ::std::rc::Rc::new(
10,
);
::hooq::BindingPayload {
expr,
value,
}
},
),
(
::std::string::ToString::to_string("string"),
{
let expr = ::std::string::ToString::to_string("\"hello!\"");
let value: ::std::rc::Rc<dyn ::std::any::Any> = ::std::rc::Rc::new(
"hello!",
);
::hooq::BindingPayload {
expr,
value,
}
},
),
]);
})?;
Ok(())
}
hooq_meta
Bundle meta info into hooq::HooqMeta.
use hooq::hooq;
fn failable<T>(val: T) -> Result<T, String> {
Ok(val)
}
#[hooq]
#[hooq::string = "hello!"]
#[hooq::method(.inspect_err(|_| {
let _hooq_meta = $hooq_meta;
}))]
fn main() -> Result<(), Box<dyn std::error::Error>> {
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 main() -> Result<(), Box<dyn std::error::Error>> {
failable(())
.inspect_err(|_| {
let _hooq_meta = ::hooq::HooqMeta {
line: 13usize,
column: 17usize,
path: "mdbook-source-code/meta-vars-hooq_meta/src/main.rs",
file: "main.rs",
source_str: "failable(()) ?",
count: "1st ?",
bindings: ::std::collections::HashMap::from([
(
::std::string::ToString::to_string("string"),
{
let expr = ::std::string::ToString::to_string("\"hello!\"");
let value: ::std::rc::Rc<dyn ::std::any::Any> = ::std::rc::Rc::new(
"hello!",
);
::hooq::BindingPayload {
expr,
value,
}
},
),
]),
};
})?;
Ok(())
}
See also the hook flavor.
Advanced Meta Variables for Hook Construction
The meta variables introduced so far are primarily for obtaining meta information for logging and debugging.
The remaining two, $expr and $so_far, are meta variables that assist in making methods.
expr
Use in replacement mode to access the (already hooked internally) expression.
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(())
}
so_far
Represents the chain of insertion‑mode hooks so far. Drop the leading dot when stored; write as .$so_far when inserting.
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(())
}
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(())
}