#Conditional `where` requirement with config flags

1 messages · Page 1 of 1 (latest)

strange anchor
#

I have a serde feature flag that i want to enable conditionally, i have this Spanned struct that can be serialized, and i want to enable the constraint of serialization only when the feature flag is enabled.

I can do this easily by duplicating the code but, is there a better way to do it?


//example duplicated code
#[derive(Clone, Debug)]
#[cfg(not(feature = "serde"))]
pub struct Spanned<T>
where
    //i'd like to optionally add Serialize here
    T: Debug + Clone,
{
    pub value: T,
    span: Span,
}

//i'd like to optionally add Serialize here
impl<T: Debug + Clone> Spanned<T> {
    pub fn new(value: T, span: Span) -> Self {
        Self { value, span }
    }
    pub fn get_span(&self) -> &Span {
        &self.span
    }

    pub fn into_tuple(self) -> (T, Span) {
        (self.value, self.span)
    }
    pub fn get_span_value(&self) -> &T {
        &self.value
    }
    pub fn into_span_value(self) -> T {
        self.value
    }
}


//example by duplicating code like i'm doing now
#[derive(Clone)]
#[cfg(feature = "serde")]
#[cfg_attr(feature = "serde", derive(Serialize))]
#[cfg_attr(feature = "serde", serde(crate = "serde_renamed"))]
pub struct Spanned<T>
where
    T: Debug + Clone + Serialize,
{
    pub value: T,
    span: Span,
}

impl<T: Debug + Clone + Serialize> Spanned<T> {
  ...
}

hasty pike
# strange anchor I have a `serde` feature flag that i want to enable conditionally, i have this S...

You can't have cfgs on wheres, but you can have them on generics, which means you can do this

pub struct Spanned<
  #[cfg(feature = "serde")] T: Debug + Clone + Serialize
  #[cfg(not(feature = "serde")] T: Debug + Clone
>
{
  pub value: T,
  span: Span
}
```Unrelated: you should put the bounds on `impl`s, putting them on the struct doesn't really do anything for you. This would also allow you to make the cfgs slightly nicer:
```rs
pub struct Spanned<T> {
    pub value: T,
    span: Span,
}
impl<T: Debug + Clone> Spanned<T> { ... }
#[cfg(feature = "serde")]
impl<T: Debug + Clone + Serialize> Spanned<T> { ... }
strange anchor
# hasty pike You can't have cfgs on `where`s, but you _can_ have them on generics, which mean...

there was a missing ) in the Spanned definition, but this gives me a syntax error:

pub struct Spanned<
  #[cfg(feature = "serde")] T: Debug + Clone + Serialize //here
  #[cfg(not(feature = "serde"))] T: Debug + Clone
>
{
  pub value: T,
  span: Span
}
'+', ',', '::', <path parameters>, <type argument list>, '=' or '>' expected, got '#'

Regarding the impl blocks, i wanted the Spanned struct to be serializable and derive Clone and debug, that's why i had put the requirements in the struct definition

hasty pike
#

derive already adds a T: Clone and T: Debug bound to the generated code appropriately, so you get an effect of "this struct is Clone if its contents are"

#

Then you add a Clone bound (which you would have had to add anyway, adding a bound to the struct doesn't prevent this) to the code that needs it

strange anchor
hasty pike
strange anchor
hasty pike
strange anchor
#

thanks for the help!

acoustic ingot