"Hook" into the start of the process from a library


#1

Hi,
I have some code in my library that I would prefer always runs at the very start of main(). Is there a way to “hook” into that so that some code is always inserted into the beginning of main? Ideally I would like to allow the user of the library to write their code completely normally without having to worry about the special code I need to run at the beginning of the process.

It might be that there actually is no way, but I thought I would ask anyway in case I’m wrong. :slight_smile:

Thanks

Example

// Adding my crate "hooks" into main and runs some special code at the beginning.
extern crate foo;

// The goal is to leave the code below looking as normal as possible while
// also sneaking in some code at the beginning of main
fn main() {
    // Regardless of what code is in main, I would like to run some
    // code before all of it right here

    // Main could have any code in it at all...
    let x = 1 + 2;
    let y = x * 33;
    println!("My special code runs before all of these lines!\n  x = {}, y = {}", x, y);
}

#2

I think there’s no real way to do it, but, for a similar method, you may wrap your initialization into std::sync::Once and call it from every API function.

https://doc.rust-lang.org/std/sync/struct.Once.html


#3

Thanks!


#4

Another idea might be to change your API to make this requirement explicit. Admittedly, this conflicts with the “sneaky” requirement you mentioned.

For example, database libraries put their init logic into the connect() method, which will return a connection struct. Then, anything that needs a connection requires this token, or is a trait method on this struct, as in

let my_conn = Connection::new(params);
my_connn.do_something();
other.do_stuff_with(my_conn);

The advantage here is less “surprise” code: the programmer will know what is happening, when and why. This can avoid a lot of debugging headaches…

What is your reason for preferring “sneaky” over explicit?


#5

Thanks! Yes that is essentially the approach I have gone with already.

The reason for the sneakiness is because the code I want to inject is entirely an implementation detail that isn’t relevant to any of the calls being made using the library. If I can slip it in automatically, I don’t have to worry about anything breaking in the future if the implemention changes. Also, not having to deal with that extra call makes the library just a bit easier to teach. That concern is particularly important in this case.

I’ve managed to make it so that no call is needed in the most common usage of my library and it’s only required for people doing more advanced things. This works well enough for what I needed.

Thanks for your help!