I want to implement PartialOrd
manually for a enum type with several variants, for example:
enum Foo<T> {
Struct0 {},
Struct1 { foo: u32 },
Struct2 { foo: u32, bar: PhantomData<T> },
Tuple0(),
Tuple1(u32),
Tuple2(u32, PhantomData<T>),
Unit,
}
I don’t want to use #[derive(PartialOrd)]
because it requires T
being PartialOrd
, which I don’t want. I imagine an implementation like this should work:
impl<T> PartialOrd for Foo<T> {
fn partial_cmp(&self, other: &Foo<T>) -> Option<Ordering> {
match (self, other) {
(Self::Struct0 {}, Self::Struct0 {}) => ...,
(Self::Struct1 { .. }, Self::Struct1 { .. }) => ...,
(Self::Struct2 { .. }, Self::Struct2 { .. }) => ...,
(Self::Tuple0(), Self::Tuple0()) => ...,
(Self::Tuple1(..), Self::Tuple1(..)) => ...,
(Self::Tuple2(..), Self::Tuple2(..)) => ...,
(Self::Unit, Self::Unit) => ...,
_ => std::mem::discriminant(&self).partial_cmp(&std::mem::discriminant(&other)),
}
}
}
But It does not, because Discriminant
does not implement PartialOrd
.
I tried to expand the PartialOrd
macro, and saw it uses ::core::intrinsics::discriminant_value
function, which is not stabilized, so I can’t copy its behavior. I also don’t want to write 49 match arms like this:
impl<T> PartialOrd for Foo<T> {
fn partial_cmp(&self, other: &Foo<T>) -> Option<Ordering> {
match self {
Foo::Struct0 {} => match other {
Foo::Struct0 {} => ...,
Foo::Struct1 { .. } => ...,
Foo::Struct2 { .. } => ...,
Foo::Tuple0() => ...,
Foo::Tuple1(..) => ...,
Foo::Tuple2(..) => ...,
Foo::Unit => ...,
},
Foo::Struct1 { .. } => match other {
Foo::Struct0 {} => ...,
Foo::Struct1 { .. } => ...,
Foo::Struct2 { .. } => ...,
Foo::Tuple0() => ...,
Foo::Tuple1(..) => ...,
Foo::Tuple2(..) => ...,
Foo::Unit => ...,
},
Foo::Struct2 { .. } => match other {
Foo::Struct0 {} => ...,
Foo::Struct1 { .. } => ...,
Foo::Struct2 { .. } => ...,
Foo::Tuple0() => ...,
Foo::Tuple1(..) => ...,
Foo::Tuple2(..) => ...,
Foo::Unit => ...,
},
Foo::Tuple0() => match other {
Foo::Struct0 {} => ...,
Foo::Struct1 { .. } => ...,
Foo::Struct2 { .. } => ...,
Foo::Tuple0() => ...,
Foo::Tuple1(..) => ...,
Foo::Tuple2(..) => ...,
Foo::Unit => ...,
},
Foo::Tuple1(..) => match other {
Foo::Struct0 {} => ...,
Foo::Struct1 { .. } => ...,
Foo::Struct2 { .. } => ...,
Foo::Tuple0() => ...,
Foo::Tuple1(..) => ...,
Foo::Tuple2(..) => ...,
Foo::Unit => ...,
},
Foo::Tuple2(..) => match other {
Foo::Struct0 {} => ...,
Foo::Struct1 { .. } => ...,
Foo::Struct2 { .. } => ...,
Foo::Tuple0() => ...,
Foo::Tuple1(..) => ...,
Foo::Tuple2(..) => ...,
Foo::Unit => ...,
},
Foo::Unit => match other {
Foo::Struct0 {} => ...,
Foo::Struct1 { .. } => ...,
Foo::Struct2 { .. } => ...,
Foo::Tuple0() => ...,
Foo::Tuple1(..) => ...,
Foo::Tuple2(..) => ...,
Foo::Unit => ...,
},
}
}
}
What do you recommend for implementing PartialOrd
for enums like this? Also, what’s preventing Discriminant
from implementing PartialOrd
?