Closed
Description
sync::one::Once
is often used for one-time initialisation (e.g. of C libraries), but non-trivial initialisations take arguments and can fail, and in the failure case, one might wish to retry with different arguments.
E.g.
#[link(name="my_lib")];
extern {
// negative return value indicates failure
fn my_lib_init(x: u32) -> i32;
}
fn start_up(x: u32) -> i32 {
static mut GUARD: Once = /* ... */;
let mut ret = -1;
GUARD.doit(|| {
ret = my_lib_init(x);
});
ret
}
fn main() {
// lets try with 0
if start_up(0) >= 0 { main_app() }
// that failed, maybe 1 will work
else if start_up(1) >= 0 { main_app() }
else { println!("failed to initialise") }
}
Unfortunately, that code is incorrect, because the second start_up
call will never call my_lib_init
: the first one consumed the guard.
One solution would be doit
having signature fn doit(...) -> bool;
with false
indicating the code path "failed" and the Once
should be allowed to rerun (i.e. no clean-up or anything). i.e. the current behaviour is when doit
returns true
.
(One could also add a new method try
and make doit(f)
just sugar for try(|| { f(); true })
.)
Metadata
Metadata
Assignees
Labels
No labels