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}