Function/type registration at startup

#1

Hey all,

I’m trying to create a global registry of types and associated functionality generated on program startup. For my use case, this sort of registry has a lot of advantages over maintaining a function with some long list of calls (I’ve tried both ways in the past with C).

In C, I’ve done this with attribute((constructor)) for the desired types which would populate some hash table with the required metadata, and that worked fairly well. In Rust, I can use the ctor crate, but from the documentation documentation that doesn’t appear to play very well with using anything from stdlib. I don’t want to play with fire and use the allocator beforehand if it may not be in a good state. Instead, I keep a massive static array and write constructor function pointers into it so I can later at runtime generate the actual data.

Is there a better way to do this in rust? Can I assume that jemalloc has been properly initialized when static constructors run? This current method is opaque enough where I have to wrap it with a fairly gnarly macro to keep it sensible to users

0 Likes

#2

If you’re just trying to associate methods with a type, why not just impl them? As for continuing what you were saying, rust has doesn’t really have a constructor method built into types, it lets creators decide on a function to build the type, so you end up with something like so:

struct MyStruct { /**/ }
impl MyStruct {
    pub fn new() -> Self {
        MyStruct { /**/ }
    }
}

In which case you might store fn new. But then again, if you’re just looking to save associated functions (Methods), then the type for that could be either:

let once: FnOnce(MyStruct) -> ();
let multiple: Fn(&MyStruct) -> ();
let fn_pointer = fn(&MyStruct) -> ();

Note that the first two are trait objects, and therefore unsized, and the last one is sized because it is a function pointer

0 Likes

#3

Thanks for the reply! I need to use a registry because I need to do this lookup dynamically - basically, I need to assemble some actors based on some user-supplied configuration at runtime, type check the setup, allocate memory properly, etc. Saving fn new is basically what I’m doing. I don’t actually need these functions just metadata about the various types.

I also don’t want to maintain a “library init” function which has to know about all actor types.

However, I don’t want to rely on these types being constructive without stdlib available and use the functions as a way to delay creation.

I’m very familiar with rust’s initialization methods and would just use plain imply and news if I could, trust me. In general, I don’t like these roundabout coordinations and was hoping there is a better mechanism for doing this sort of thing

1 Like

#4

So you’re doing something like this, or perhaps with a different model of flow, but similar idea, where you take a user input and create a value depending on that?

0 Likes

#5

It’s a little similar, but I also don’t know the types or really any information about them ahead of time, and in fact, probably won’t be able to link all of them into the same binary not to mention building them together.

Basically, somebody tells this library what types to instantiate via some runtime config, and if the library has beeen made aware of them somehow, it allocates space, runs their initialization code, assembled the actual sort of program the user desired. The total set of types is not known to the library at compile time and some types cannot coexist in the same program for reasons.

That’s what I solved with the module load-time code (in rust, running before and after main). Types register themselves at that point so the library can do lookup without knowing about the types ahead of time

0 Likes

#6

I believe you can generate such a function either from build.rs or using procedure macro with some effort but nothing very hard.

0 Likes

#7

I realize now this is might be impossible, except through build.rs, since the types will be very distributed code wise and strictly cannot be in the same codebases, or even all brought in as dependencies.

If this could be built in an incremental fashion that macro solution would be preferred to a registry

1 Like