Search code examples
rustclamp

How to implement the Ord trait without getting the error "use of unstable library feature 'clamp'"?


I have a struct that I want to use it as a key in BTreeMap, so I implement PartialEq, Eq, PartialOrd and Ord. The last causes a problem as there is an unsafe clamp trait method.

I implement it this way:

use std::cmp::Ordering;

#[derive(Debug, Eq, Copy, Clone)]
struct Baz(usize);

impl PartialEq for Baz {
    fn eq(&self, other: &Self) -> bool {
        self.0.eq(&other.0)
    }

    fn ne(&self, other: &Self) -> bool {
        self.0.ne(&other.0)
    }
}

impl PartialOrd for Baz {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.0.partial_cmp(&other.0)
    }

    fn lt(&self, other: &Self) -> bool {
        self.0.lt(&other.0)
    }

    fn le(&self, other: &Self) -> bool {
        self.0.le(&other.0)
    }

    fn gt(&self, other: &Self) -> bool {
        self.0.gt(&other.0)
    }

    fn ge(&self, other: &Self) -> bool {
        self.0.ge(&other.0)
    }
}

impl Ord for Baz {
    fn cmp(&self, other: &Self) -> Ordering {
        self.0.cmp(&other.0)
    }

    fn max(self, other: Self) -> Self
    where
        Self: Sized,
    {
        Self(self.0.max(other.0))
    }

    fn min(self, other: Self) -> Self
    where
        Self: Sized,
    {
        Self(self.0.min(other.0))
    }

    fn clamp(self, min: Self, max: Self) -> Self
    where
        Self: Sized,
    {
        Self(self.0.clamp(min.0, max.0))
    }
}

fn main() {
    Baz(1);
}

Playground

As far as I know, clamp for integers is safe and should work just fine, but Rust gives me the error

error[E0658]: use of unstable library feature 'clamp'
  --> src/main.rs:57:5
   |
57 | /     fn clamp(self, min: Self, max: Self) -> Self
58 | |     where
59 | |         Self: Sized,
60 | |     {
61 | |         Self(self.0.clamp(min.0, max.0))
62 | |     }
   | |_____^
   |
   = note: for more information, see https://github.com/rust-lang/rust/issues/44095

error[E0658]: use of unstable library feature 'clamp'
  --> src/main.rs:61:21
   |
61 |         Self(self.0.clamp(min.0, max.0))
   |                     ^^^^^
   |
   = note: for more information, see https://github.com/rust-lang/rust/issues/44095

How can I solve this? I'm using Rust 1.41.


Solution

  • As far as I know, clamp for integers is safe and should work just fine, but Rust gives me the error

    That's because the Ord::clamp method is unstable — the compiler isn't lying to you. However, that's a method with a default implementation, so you don't need to implement it (and shouldn't, unless you can improve on the default implementation).

    Helpfully, there's a section in the documentation for Ord titled How can I implement Ord? which describes exactly what you need to do:

    Ord requires that the type also be PartialOrd and Eq (which requires PartialEq).

    Then you must define an implementation for cmp(). You may find it useful to use cmp() on your type's fields.

    Of special relevance is the fact that Ord can be derived:

    This trait can be used with #[derive]. When derived on structs, it will produce a lexicographic ordering based on the top-to-bottom declaration order of the struct's members. When derived on enums, variants are ordered by their top-to-bottom declaration order.

    Your entire code can likely be

    #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
    struct Baz(usize);
    

    See also: