ordered/
lib.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! Provides a wrapper for types that can technically implement `PartialOrd`/`Ord` but for semantic
4//! reasons it is nonsensical.
5//!
6//! `PartialOrd` and `Ord` are often useful and/or required. For example, [`Ordered`] allows one to
7//! use such a type as a key in a `BTreeMap` (which requires ordered keys).
8//!
9//! For a full example see [`examples/point.rs`].
10//!
11//! # Examples
12//!
13//! ```
14//! # #![allow(unused)] // Because of `Adt`.
15//! use core::cmp::Ordering;
16//! use ordered::{ArbitraryOrd, Ordered};
17//!
18//! /// A point in 2D space.
19//! ///
20//! /// We do not want users to be able to write `a < b` because it is not well defined.
21//! #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
22//! struct Point {
23//!     x: u32,
24//!     y: u32,
25//! }
26//!
27//! impl ArbitraryOrd for Point {
28//!     fn arbitrary_cmp(&self, other: &Self) -> Ordering {
29//!         // Just use whatever order tuple cmp gives us.
30//!         (self.x, self.y).cmp(&(other.x, other.y))
31//!     }
32//! }
33//!
34//! /// `Ordered` allows users to derive `PartialOrd` on types that include a `Point`.
35//! #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
36//! struct Adt {
37//!     name: String,
38//!     point: Ordered<Point>,
39//! }
40//! ```
41//!
42//! [`examples/point.rs`]: <https://github.com/rust-bitcoin/rust-ordered/blob/master/examples/point.rs>
43
44#![no_std]
45// Experimental features we need.
46#![cfg_attr(docsrs, feature(doc_auto_cfg))]
47// Coding conventions.
48#![warn(missing_docs)]
49#![warn(deprecated_in_future)]
50#![doc(test(attr(warn(unused))))]
51
52use core::borrow::{Borrow, BorrowMut};
53use core::cmp::Ordering;
54use core::fmt;
55use core::ops::{Deref, DerefMut};
56
57/// Trait for types that perform an arbitrary ordering.
58///
59/// More specifically, this trait is for types that perform either a partial or
60/// total order but semantically it is nonsensical.
61///
62/// # Examples
63///
64/// ```
65/// # #![allow(unused)] // Because of `Adt`.
66/// use core::cmp::Ordering;
67/// use ordered::ArbitraryOrd;
68///
69/// /// A point in 2D space.
70/// ///
71/// /// We do not want users to be able to write `a < b` because it is not well defined.
72/// #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
73/// struct Point {
74///     x: u32,
75///     y: u32,
76/// }
77///
78/// impl ArbitraryOrd for Point {
79///     fn arbitrary_cmp(&self, other: &Self) -> Ordering {
80///         // Just use whatever order tuple cmp gives us.
81///         (self.x, self.y).cmp(&(other.x, other.y))
82///     }
83/// }
84/// ```
85pub trait ArbitraryOrd<Rhs = Self>: PartialEq<Rhs> {
86    /// Implements a meaningless, arbitrary ordering.
87    fn arbitrary_cmp(&self, other: &Rhs) -> Ordering;
88}
89
90/// A wrapper type that implements `PartialOrd` and `Ord`.
91///
92/// # Examples
93///
94/// ```
95/// # #![allow(unused)] // Because of `Adt`.
96/// use core::cmp::Ordering;
97/// use ordered::{ArbitraryOrd, Ordered};
98///
99/// /// A point in 2D space.
100/// ///
101/// /// We do not want users to be able to write `a < b` because it is not well defined.
102/// #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
103/// struct Point {
104///     x: u32,
105///     y: u32,
106/// }
107///
108/// impl ArbitraryOrd for Point {
109///     fn arbitrary_cmp(&self, other: &Self) -> Ordering {
110///         // Just use whatever order tuple cmp gives us.
111///         (self.x, self.y).cmp(&(other.x, other.y))
112///     }
113/// }
114///
115/// let point = Point { x: 0, y: 1 };
116/// let ordered = Ordered(point);
117///
118/// assert_eq!(*ordered, point); // Use `ops::Deref`.
119/// assert_eq!(&ordered.0, ordered.as_ref()); // Use the public inner field or `AsRef`.
120/// ```
121#[derive(Debug, Clone, PartialEq, Eq, Hash)]
122#[repr(transparent)]
123pub struct Ordered<T>(pub T);
124
125impl<T: Copy> Copy for Ordered<T> {}
126
127impl<T> Ordered<T> {
128    /// Creates a new wrapped ordered type.
129    ///
130    /// The inner type is public so this function is never explicitly needed.
131    pub const fn new(inner: T) -> Self { Self(inner) }
132
133    /// Creates an `Ordered<T>` from a reference.
134    ///
135    /// This allows: `let found = map.get(Ordered::from_ref(&a));`
136    #[allow(clippy::ptr_as_ptr)]
137    pub fn from_ref(value: &T) -> &Self { unsafe { &*(value as *const _ as *const Self) } }
138
139    /// Returns a reference to the inner object.
140    ///
141    /// We also implement [`core::borrow::Borrow`] so this function is never explicitly needed.
142    #[deprecated(since = "0.3.0", note = "use `ops::Deref` instead")]
143    pub const fn as_inner(&self) -> &T { &self.0 }
144
145    /// Returns the inner object.
146    ///
147    /// We also implement [`core::ops::Deref`] so this function is never explicitly needed.
148    #[deprecated(since = "0.3.0", note = "use `ops::Deref` instead")]
149    pub fn into_inner(self) -> T { self.0 }
150}
151
152impl<T: ArbitraryOrd> ArbitraryOrd for &T {
153    fn arbitrary_cmp(&self, other: &Self) -> Ordering { (*self).arbitrary_cmp(other) }
154}
155
156impl<T: ArbitraryOrd> PartialOrd for Ordered<T> {
157    fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some((*self).arbitrary_cmp(other)) }
158}
159
160impl<T: ArbitraryOrd + Eq> Ord for Ordered<T> {
161    fn cmp(&self, other: &Self) -> Ordering { (*self).arbitrary_cmp(other) }
162}
163
164impl<T: fmt::Display> fmt::Display for Ordered<T> {
165    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
166}
167
168impl<T> From<T> for Ordered<T> {
169    fn from(inner: T) -> Self { Self(inner) }
170}
171
172impl<T> AsRef<T> for Ordered<T> {
173    fn as_ref(&self) -> &T { &self.0 }
174}
175
176impl<T> AsMut<T> for Ordered<T> {
177    fn as_mut(&mut self) -> &mut T { &mut self.0 }
178}
179
180impl<T> Borrow<T> for Ordered<T> {
181    fn borrow(&self) -> &T { &self.0 }
182}
183
184impl<T> BorrowMut<T> for Ordered<T> {
185    fn borrow_mut(&mut self) -> &mut T { &mut self.0 }
186}
187
188impl<T> Deref for Ordered<T> {
189    type Target = T;
190
191    fn deref(&self) -> &Self::Target { &self.0 }
192}
193
194impl<T> DerefMut for Ordered<T> {
195    fn deref_mut(&mut self) -> &mut T { &mut self.0 }
196}
197
198#[cfg(test)]
199mod tests {
200    use super::*;
201
202    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
203    struct Point {
204        x: u32,
205        y: u32,
206    }
207
208    impl Point {
209        fn new(x: u32, y: u32) -> Self { Point { x, y } }
210    }
211
212    impl ArbitraryOrd for Point {
213        fn arbitrary_cmp(&self, other: &Self) -> Ordering {
214            (self.x, self.y).cmp(&(other.x, other.y))
215        }
216    }
217
218    #[test]
219    fn can_compare() {
220        let a = Point::new(2, 3);
221        let b = Point::new(5, 7);
222
223        assert!(Ordered(a) < Ordered(b));
224    }
225
226    #[test]
227    fn can_compare_with_from_ref() {
228        let a = Point::new(2, 3);
229        let b = Point::new(5, 7);
230
231        assert!(Ordered::from_ref(&a) < Ordered::from_ref(&b));
232    }
233
234    #[test]
235    fn can_compare_with_reference() {
236        let a = Point::new(2, 3);
237        let b = Point::new(5, 7);
238
239        assert!(Ordered(&a) < Ordered(&b));
240    }
241
242    // Copied from https://rust-lang.github.io/api-guidelines/interoperability.html#c-send-sync
243    #[test]
244    fn send() {
245        #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
246        struct Point {
247            x: u32,
248            y: u32,
249        }
250
251        impl ArbitraryOrd for Point {
252            fn arbitrary_cmp(&self, other: &Self) -> Ordering {
253                (self.x, self.y).cmp(&(other.x, other.y))
254            }
255        }
256
257        fn assert_send<T: Send>() {}
258        fn assert_sync<T: Sync>() {}
259
260        assert_send::<Ordered<Point>>();
261        assert_sync::<Ordered<Point>>();
262    }
263
264    #[test]
265    fn trait_is_object_safe() {
266        extern crate std;
267        use std::boxed::Box;
268
269        // If this test builds then `ArbitraryOrd` is object safe.
270        #[allow(dead_code)]
271        struct ObjectSafe {
272            p: Box<dyn ArbitraryOrd<Self>>,
273            q: Box<dyn PartialOrd<Self>>, // Sanity check.
274        }
275    }
276}