Expand description
This crate provides a macro to generate aux macros for on-demand usage.
§Examples
use on_demand::generate_on_demand_macro;
fn foo() {
generate_on_demand_macro!(a: usize = None, {
println!("a");
1
});
generate_on_demand_macro!(b: usize = None, {
println!("b");
let a_data = on_demand_get_a!();
2 + *a_data
});
generate_on_demand_macro!(c: usize = None, {
println!("c");
let a_data = on_demand_get_a!();
let b_data = on_demand_get_b!();
3 + *a_data + *b_data
});
let c_data = on_demand_get_c!();
assert_eq!(*c_data, 6);
}After calling generate_on_demand_macro to the variable (for example, a),
three new macros on_demand_get_a, on_demand_get_a_mut and on_demand_into_a are generated.
When on_demand_get_a is called, it determines whether a has been calculated. If it is,
then returns the reference to its data, otherwise calls the expression given as the second
parameter of generate_on_demand_macro, then assigns the returned value to a. The other two
generated macros do the similar job, but returns the mutable reference to, or takes ownership
of a.
In all, this means calculating a lazily using the expression.
§Notes
The returned value of on_demand_get_a is essentially a Ref, and
on_demand_get_a_mut is RefMut. So remember to dereference it
when necessary.
When calling this macro, we assign a default value by generate_on_demand_macro!(a: MyType = default_value_of_optional_my_type), { /* block */ });. The default_value_of_optional_my_type should
be of type Option<MyType>. If it is not None, then a is considered calculated already, and the expression
given in block will never be called.
There are some crates providing lazy feature, such as spin. However, those methods are based on closure, which could not handle some situations such as below (error handlings are omitted for simplicity):
fn foo<T: Seek + Read>(binary: &mut T) {
generate_on_demand_macro!(a: u32 = None, {
let mut buf = [0; 4];
binary.seek(SeekFrom::Start(0)).unwrap();
binary.read(&mut buf).unwrap();
u32::from_be_bytes(buf)
});
generate_on_demand_macro!(b: u32 = None, {
let a_data = on_demand_get_a!();
let mut buf = [0; 4];
binary.seek(SeekFrom::Start(0)).unwrap();
binary.read(&mut buf).unwrap();
u32::from_be_bytes(buf) + *a_data
});
generate_on_demand_macro!(c: u32 = None, {
let a_data = on_demand_get_a!();
let b_data = on_demand_get_b!();
let mut buf = [0; 4];
binary.seek(SeekFrom::Start(0)).unwrap();
binary.read(&mut buf).unwrap();
u32::from_be_bytes(buf) + *a_data + *b_data
});
let a_data = on_demand_get_a!();
let b_data = on_demand_get_b_mut!();
drop(b_data); // drop here since c will take ownership
let c_data = on_demand_into_c!();
}binary is considered as uniquely borrowed if closure is used, then the borrow checker
won’t allow us do above things. However, macros can do such things.
Macros§
- generate_
on_ demand_ macro - Macro to generate on-demand macro