I am using Rust 1.62.0 and would like to add a variant to an enum
based on whether a feature is enabled.
The following compiles without issues.
enum MyEnum<#[cfg(feature="my-feature")] T> {
Always,
#[cfg(feature = "my-feature")]
OnlyWithFeature(T),
}
So I thought that all I need to do is to "guard" T
with a cfg
attribute wherever it occurs.
However, the second T
in the following seems to be an issue.
impl<#[cfg(feature="my-feature")] T> MyEnum<#[cfg(feature="my-feature")] T> {
pub fn new() -> Self {
Self::Always
}
}
The error messages are as follows.
With no features:
--> src/main.rs:7:74
|
7 | impl<#[cfg(feature="my-feature")] T> MyEnum<#[cfg(feature="my-feature")] T> {
| ^
|
help: expressions must be enclosed in braces to be used as const generic arguments
|
7 | impl<#[cfg(feature="my-feature")] T> MyEnum<#[cfg(feature="my-feature")] { T }> {
|
error[E0107]: this enum takes 0 generic arguments but 1 generic argument was supplied
--> src/main.rs:7:38
|
7 | impl<#[cfg(feature="my-feature")] T> MyEnum<#[cfg(feature="my-feature")] T> {
| ^^^^^^-------------------------------- help: remove these generics
| |
| expected 0 generic arguments
|
note: enum defined here, with 0 generic parameters
--> src/main.rs:1:6
|
1 | enum MyEnum<#[cfg(feature="my-feature")] T> {
| ^^^^^^
For more information about this error, try `rustc --explain E0107`.
With --features my-feature
:
error: invalid const generic expression
--> src/main.rs:7:74
|
7 | impl<#[cfg(feature="my-feature")] T> MyEnum<#[cfg(feature="my-feature")] T> {
| ^
|
help: expressions must be enclosed in braces to be used as const generic arguments
|
7 | impl<#[cfg(feature="my-feature")] T> MyEnum<#[cfg(feature="my-feature")] { T }> {
|
error[E0747]: constant provided when a type was expected
--> src/main.rs:7:74
|
7 | impl<#[cfg(feature="my-feature")] T> MyEnum<#[cfg(feature="my-feature")] T> {
| ^
For more information about this error, try `rustc --explain E0747`.
I have the impression that the compiler tries to parse T
as a const generic, so I guess the cfg
attribute doesn't belong there...
Guarding the whole impl
block seems to work fine, for example the following compiles.
#[cfg(not(feature="my-feature"))]
impl MyEnum {
pub fn new() -> Self {
Self::Always
}
}
#[cfg(feature="my-feature")]
impl<T> MyEnum<T> {
pub fn new() -> Self {
Self::Always
}
}
However, this would essentially require me to write a big impl
block twice.
Is there a simpler way to use a different number of generic parameters based on a feature?
CodePudding user response:
You can use a macro_rules!
declarative macro to prevent needing to duplicate code:
enum MyEnum<#[cfg(feature="my-feature")] T> {
Always,
#[cfg(feature = "my-feature")]
OnlyWithFeature(T),
}
// Produces impl blocks for feature enabled and disabled
macro_rules! impl_MyEnum_with_without_feature {
// Matches `impl MyEnum` followed by a block
{ impl MyEnum $implementations:tt } => {
#[cfg(not(feature="my-feature"))]
impl MyEnum $implementations
#[cfg(feature="my-feature")]
impl<T> MyEnum<T> $implementations
}
}
impl_MyEnum_with_without_feature! {
impl MyEnum {
pub fn new() -> Self {
Self::Always
}
}
}
Of course you will still need to create a separate impl block for anything that needs the generic parameter.