Pardoxa
Pardoxa

Reputation: 103

Rust - trait bound depending on feature?

I recently started using rust and am working on a library. The following works, but seems like code duplication

#[cfg(feature = "serde_support")]
use serde::Serialize;

#[cfg(not(feature = "serde_support"))]
pub struct Teststruct<T>
{

    graph: T
}

#[cfg(feature = "serde_support")]
#[derive(Serialize)]
pub struct Teststruct<T>
where T: Serialize
{
    graph: T
}

Note, that, while the trait bound where T: Serialize in not strictly required in this example, it is required in the problem I am facing currently.

So the above looks like needless code duplication to me, especially if the structs contains more fields. I would rather write something like:

#[cfg(feature = "serde_support")]
use serde::Serialize;

#[cfg_attr(feature = "serde_support", derive(Serialize))]
pub struct Teststruct<T: Node>
where T: Serialize,
      Graph<T>: Serialize + DeserializeOwned
{

    graph: Graph<T>
}

Now, however, I can only compile with the feature "serde_support" - without the feature, I obviously get the error: Serialize is not found in this scope.

I have tried to find something like cfg_attr for the trait bound, but to no avail.

Is there an elegant way to avoid the code duplication?

Upvotes: 10

Views: 1579

Answers (2)

Hadus
Hadus

Reputation: 1674

Or just by using conditional compilation:

#[cfg_attr(feature = "serde_support", derive(Serialize))]
pub struct TestStruct<
    #[cfg(feature = "serde_support")] T: serde::Serialize,
    #[cfg(not(feature = "serde_support"))] T,
> {
    graph: T
}

For some reason, you can't yet do this inside a where block where it would look much nicer. (rustc 1.55.0-nightly)

Upvotes: 5

phimuemue
phimuemue

Reputation: 36081

You could introduce a new intermediate trait MySerialize, so that you always require MySerialize instead of Serialize, thus doing this switch only in one place.

The derive could be solved via cfg_attr.

#[cfg(feature = "serde_support")]
use serde::Serialize;

#[cfg(feature = "serde_support")]
pub trait MySerialize : Serialize {}

#[cfg(not(feature = "serde_support"))]
pub trait MySerialize {}

#[cfg_attr(feature = "serde_support", derive(Serialize))]
pub struct Teststruct<T>
    where T: MySerialize
{
    graph: T
}

Upvotes: 8

Related Questions