Use HachMap<TypeId,Boolean>
Every type defined in rust codes has the unique id, and std::any::TypeId provides a function that allows for you to get the id of the certain while 'runtime'
Basic usage is
let a = std::any::TypeId::of::<i32>()
// TypeId { t: 13431306602944299956 }
println!("{}",format!("{:?}",a));
Then you can make a Hashmap::<TypeId_instance,Boolean> that records whether certain function is called twice.
// decleare the hashmap as a global variable
const recorder = Hashmap::<TypeId,Boolean>();
// inside bar.whiz
impl Bar {
fn whiz<T>() {
let id = TypeId::of::<T>();
if !recorder.contains_key(id) {
recorder.push(TypeId,true)
} else {
// do other stuff
}
}
}
or if you hate to mass around with the function
macro_rules! check_typeId {
(... $type:ty...) => { // place if statemens here }
}
check_typeId! {
bar.whie::<i32>();
}
std::sync::Once
'Once' struct guarantees that a closure assigned is called only one time. After calling it, the struct caches the return value of funcntion.
The example from the docs is
use std::sync::Once;
static mut VAL: usize = 0;
static INIT: Once = Once::new();
// Accessing a `static mut` is unsafe much of the time, but if we do so
// in a synchronized fashion (e.g., write once or read all) then we're
// good to go!
//
// This function will only call `expensive_computation` once, and will
// otherwise always return the value returned from the first invocation.
fn get_cached_val() -> usize {
unsafe {
INIT.call_once(|| {
VAL = expensive_computation();
});
VAL
}
}
fn expensive_computation() -> usize {
// ...
}
Once has a helper function 'is_completd' which gives a boolean value that indicate whether the closure is called or not.
Since your function is a method of Bar, you can use a method function pointer or just pass a bar to get_cached_val function as a reference.
create your own runtime context
There is a crate 'Rhai' that run an embedded dynamic function within rust codes. It works like lua in C++. The way the crate implments a domain-specific-language is through making a seperated runtime context.
Remind that every functions and struct definition in rust is actually pointer. Then you can have a bunch of hashmap that contains pointers and their metadata. Let's call a top level struct as engine. It would look like this
struct Engine {
// ...
recorder:Hashmap
}
impl Engine {
// ....
fn register_fun(&self,func_name,key) {
self.recorder.insert(key,func_name);
}
fn run_func(key,args) {
let f = self.recorder.get(key);
f(args);
}
}
let engine = Engine();
engine.register_fun(func_name,"register_key1")
engine.register_struct(struct_name,"register_key2")
// ...
engine.run_func("register_key1",args);
let output = engine.make_struct("register_key2",args);
If you place codes that check runtime information of function in run_func it menas you can handle. Check rhai/src/engine.rs to get more inspiration.