Skip to content

sync::one::Once should be able to "ignore" a run #13357

Closed
@huonw

Description

@huonw

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

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions