Conditional bounds on trait impl based on feature flag?

Viewed 149

Suppose I have code like:


impl<A> Stream for MyStruct<A> 
where
    A: MyTrait
{
    // ...
}

But if a certain feature flag is enabled, then A also needs to be Send + Sync, so I need A: MyTrait + Send + Sync if that feature is enabled. Is there a way to do this without having to duplicate the implementation? It appears I can't use #[cfg(feature = "...")] in a where clause.

2 Answers

The cargo documentation states:

[..] features should be additive. That is, enabling a feature should not disable functionality.

By adding bounds to an implement block, you are essentially removing functionality, as that implement now works for fewer types.

You should instead find a design that adds functionality when a feature is enabled. For example, you could split your trait in two, where one of them has the additional bounds.

As @Emoun points out, this is not such a good idea, but it is possible:

#[cfg(feature = "asdf")]
trait MyTraitConditional: MyTrait {}
#[cfg(feature = "asdf")]
impl<T: MyTrait> MyTraitConditional for T {}
#[cfg(all(not(feature = "asdf"), feature = "bsdf"))]
trait MyTraitConditional: MyTrait + Send {}
#[cfg(all(not(feature = "asdf"), feature = "bsdf"))]
impl<T: MyTrait + Send> MyTraitConditional for T {}

Playground (with cfg_if for lowered verbosity)

Alternatively, you can shove the entire impl into a macro_rules that takes only the trait bound as a parameter, and then invoke the macro differently depending on features. (I've encountered similar in the wild, but I'm not a fan.)

Related