Split Enum into Multiple Modular Repositories

Hi,
I am currently thinking about a modular structure of a core crate and possible modular extensions, which reside in different repositories. On compile time, I choose the core crate with one or more modules and build it.

Within the crate, I want to use an Enum of possible operations. However, the module should be able to extend this Enum. The Enum will most likely be #[non_exhaustive].

So, I am not quite sure how to tackle this problem. I imagine having to use some macro magic, to combine several enums from several files into one, united Enum at compile time.

Do you have any suggestions or are there existing solutions?

If the modules are included/excluded by cargo features, you can use

enum MyEnum {
    #[cfg(feature = "module_foo")]
    Foo,
    #[cfg(feature = "module_bar")]
    Bar,
}

to conditionally include a variant depending on a feature being turned on or not. If the variants are not selected using cargo features, I would make a trait instead of an enum.

1 Like

This. It really sounds like you want the set of variants to be arbitrarily extended based on crates which are not dependencies of the crate with the enum. The only way to achieve this is with dynamic polymorphism.

If you require pattern matching in downstream crates, you will want the trait to have a downcasting function a la Any, and it will need to be both part of the trait as well as an inherent method either on dyn Trait or some wrapper type, since a generic trait method is not object safe. See failure::Fail for an example (the inherent method is on the Error struct in that crate).

(This is an uncommon use case, however. In most use cases, downstream crates have no business knowing exactly which type is in a dyn Trait, so you should simply put all overridable behavior in trait methods)

Using features for including Enum variants seems to be a good idea.
Can I split these features over multiple repositories and compose them for compilation?

You can have features in one crate conditionally add another crate as a dependency, but the crate that defines the enum must know about all possible features. You can't magically import enum variants by saying "fetch stuff looking like this from other crates".

That is why I am thinking of getting several Enums together and preprocessing them with a macro into a usable composed Enum.

This means I want to stretch the "you can't magically import" sentence a little bit :wink:.

Coming from C++, there is generally a lot you can do with build scripts/processes and preprocessor instructions. I am not quite sure if it is worth the effort.

Re: magical downstream type discovery, there's linkme and inventory, which are not-your-usual-Rust, but may be useful.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.