ord_subset/
ord_var.rs

1// Licensed under the Apache License, Version 2.0
2// http://www.apache.org/licenses/LICENSE-2.0 or the MIT license
3// http://opensource.org/licenses/MIT, at your
4// option. This file may not be copied, modified, or distributed
5// except according to those terms.
6
7use core::cmp::Ordering;
8use core::fmt::Debug;
9use core::ops::Deref;
10use ord_subset_trait::*;
11
12/// Wrapper to signal that the contained variables have a total order. It's illegal to compare two `OrdVar`s that are not ordered.
13/// For this reason, it's unsafe to create `OrdVar`s without checking. Checked constructors are available for `OrdSubset` types.
14///
15/// # Panics
16///
17/// Panics when `a.partial_cmp(b)` returns `None` for two values `a`,`b`.
18#[derive(PartialEq, PartialOrd, Clone, Copy, Debug, Hash)]
19pub struct OrdVar<T: PartialOrd + PartialEq>(T);
20
21impl<T: PartialOrd + PartialEq> OrdVar<T> {
22    /// Construct an ```OrdVar``` out of the argument.
23    ///
24    /// # Panics
25    ///
26    /// Panics if the argument is outside of the total order.
27    #[inline]
28    pub fn new(data: T) -> OrdVar<T>
29    where
30        T: Debug + OrdSubset,
31    {
32        if data.is_outside_order() {
33            panic!(
34                "Attempted saving data outside of total order into OrdVar: {:?}",
35                data
36            )
37        };
38        OrdVar(data)
39    }
40
41    /// Constructs an ```Option<OrdVar>``` out of the argument. Returns None if the argument is outside the total order.
42    #[inline]
43    pub fn new_checked(data: T) -> Option<OrdVar<T>>
44    where
45        T: OrdSubset,
46    {
47        match data.is_outside_order() {
48            true => None,
49            false => Some(OrdVar(data)),
50        }
51    }
52
53    /// Constructs an `OrdVar` without validity check. Incorrectly constructed `OrdVar`s may panic on calls to `.cmp()`.
54    /// The comparison operators (`>`, `>=`, `=`, `!=`, `<`, `<=`) will not panic but may result in surprising behaviour.
55    #[inline(always)]
56    pub fn new_unchecked(data: T) -> OrdVar<T> {
57        OrdVar(data)
58    }
59
60    #[inline(always)]
61    pub fn into_inner(self) -> T {
62        self.0
63    }
64}
65
66impl<T: PartialOrd + PartialEq> Eq for OrdVar<T> {}
67
68#[cfg_attr(clippy, allow(clippy::derive_ord_xor_partial_ord))]
69impl<T: PartialOrd + PartialEq> Ord for OrdVar<T> {
70    #[inline]
71    fn cmp(&self, other: &Self) -> Ordering {
72        self.partial_cmp(other)
73            .expect("OrdVar contains value outside total order")
74    }
75}
76
77impl<T: PartialOrd + PartialEq> Deref for OrdVar<T> {
78    type Target = T;
79
80    #[inline(always)]
81    fn deref(&self) -> &Self::Target {
82        &self.0
83    }
84}
85
86impl<T: PartialOrd + PartialEq> AsRef<T> for OrdVar<T> {
87    #[inline(always)]
88    fn as_ref(&self) -> &T {
89        &self.0
90    }
91}
92
93impl<T: Default + OrdSubset + Debug> Default for OrdVar<T> {
94    #[inline(always)]
95    fn default() -> Self {
96        OrdVar::new(T::default())
97    }
98}
99
100#[cfg(feature = "ops")]
101mod ops {
102    // would love to be able to macro these away somehow
103    #[cfg_attr(rustfmt, rustfmt_skip)]
104	use core::ops::{Add, Sub, Mul, Div, Rem, BitAnd, BitOr, BitXor, Shl, Shr, Neg, Not,
105                AddAssign, SubAssign, MulAssign, DivAssign, RemAssign, BitAndAssign, BitOrAssign, BitXorAssign, ShlAssign, ShrAssign,};
106    use super::OrdVar;
107    use core::fmt::Debug;
108    use ord_subset_trait::*;
109
110    #[inline(always)]
111    fn construct<T: OrdSubset + Debug>(t: T) -> OrdVar<T> {
112        match cfg!(feature = "unchecked_ops") {
113            true => OrdVar::new_unchecked(t),
114            false => OrdVar::new(t),
115        }
116    }
117
118    // -----------------  binary ops -----------------------------------------------
119
120    impl<T, RHS> Add<RHS> for OrdVar<T>
121    where
122        T: PartialOrd + PartialEq + Add<RHS>,
123        T::Output: PartialOrd + PartialEq + Debug + OrdSubset,
124    {
125        type Output = OrdVar<T::Output>;
126        fn add(self, rhs: RHS) -> Self::Output {
127            construct(self.into_inner().add(rhs))
128        }
129    }
130
131    impl<T, RHS> Sub<RHS> for OrdVar<T>
132    where
133        T: PartialOrd + PartialEq + Sub<RHS>,
134        T::Output: PartialOrd + PartialEq + Debug + OrdSubset,
135    {
136        type Output = OrdVar<T::Output>;
137        fn sub(self, rhs: RHS) -> Self::Output {
138            construct(self.into_inner().sub(rhs))
139        }
140    }
141
142    impl<T, RHS> Mul<RHS> for OrdVar<T>
143    where
144        T: PartialOrd + PartialEq + Mul<RHS>,
145        T::Output: PartialOrd + PartialEq + Debug + OrdSubset,
146    {
147        type Output = OrdVar<T::Output>;
148        fn mul(self, rhs: RHS) -> Self::Output {
149            construct(self.into_inner().mul(rhs))
150        }
151    }
152
153    impl<T, RHS> Div<RHS> for OrdVar<T>
154    where
155        T: PartialOrd + PartialEq + Div<RHS>,
156        T::Output: PartialOrd + PartialEq + Debug + OrdSubset,
157    {
158        type Output = OrdVar<T::Output>;
159        fn div(self, rhs: RHS) -> Self::Output {
160            construct(self.into_inner().div(rhs))
161        }
162    }
163
164    impl<T, RHS> Rem<RHS> for OrdVar<T>
165    where
166        T: PartialOrd + PartialEq + Rem<RHS>,
167        T::Output: PartialOrd + PartialEq + Debug + OrdSubset,
168    {
169        type Output = OrdVar<T::Output>;
170        fn rem(self, rhs: RHS) -> Self::Output {
171            construct(self.into_inner().rem(rhs))
172        }
173    }
174
175    impl<T, RHS> BitAnd<RHS> for OrdVar<T>
176    where
177        T: PartialOrd + PartialEq + BitAnd<RHS>,
178        T::Output: PartialOrd + PartialEq + Debug + OrdSubset,
179    {
180        type Output = OrdVar<T::Output>;
181        fn bitand(self, rhs: RHS) -> Self::Output {
182            construct(self.into_inner().bitand(rhs))
183        }
184    }
185
186    impl<T, RHS> BitOr<RHS> for OrdVar<T>
187    where
188        T: PartialOrd + PartialEq + BitOr<RHS>,
189        T::Output: PartialOrd + PartialEq + Debug + OrdSubset,
190    {
191        type Output = OrdVar<T::Output>;
192        fn bitor(self, rhs: RHS) -> Self::Output {
193            construct(self.into_inner().bitor(rhs))
194        }
195    }
196
197    impl<T, RHS> BitXor<RHS> for OrdVar<T>
198    where
199        T: PartialOrd + PartialEq + BitXor<RHS>,
200        T::Output: PartialOrd + PartialEq + Debug + OrdSubset,
201    {
202        type Output = OrdVar<T::Output>;
203        fn bitxor(self, rhs: RHS) -> Self::Output {
204            construct(self.into_inner().bitxor(rhs))
205        }
206    }
207
208    impl<T, RHS> Shl<RHS> for OrdVar<T>
209    where
210        T: PartialOrd + PartialEq + Shl<RHS>,
211        T::Output: PartialOrd + PartialEq + Debug + OrdSubset,
212    {
213        type Output = OrdVar<T::Output>;
214        fn shl(self, rhs: RHS) -> Self::Output {
215            construct(self.into_inner().shl(rhs))
216        }
217    }
218
219    impl<T, RHS> Shr<RHS> for OrdVar<T>
220    where
221        T: PartialOrd + PartialEq + Shr<RHS>,
222        T::Output: PartialOrd + PartialEq + Debug + OrdSubset,
223    {
224        type Output = OrdVar<T::Output>;
225        fn shr(self, rhs: RHS) -> Self::Output {
226            construct(self.into_inner().shr(rhs))
227        }
228    }
229
230    // ------------------------ binary assign ops ----------------------------------
231
232    impl<T, RHS> AddAssign<RHS> for OrdVar<T>
233    where
234        T: PartialOrd + PartialEq + AddAssign<RHS> + OrdSubset,
235    {
236        fn add_assign(&mut self, rhs: RHS) {
237            self.0.add_assign(rhs);
238            if !cfg!(feature = "unchecked_ops") {
239                assert!(
240                    !self.0.is_outside_order(),
241                    "Result of {}= operation is outside order",
242                    "+"
243                );
244            }
245        }
246    }
247
248    impl<T, RHS> SubAssign<RHS> for OrdVar<T>
249    where
250        T: PartialOrd + PartialEq + SubAssign<RHS> + OrdSubset,
251    {
252        fn sub_assign(&mut self, rhs: RHS) {
253            self.0.sub_assign(rhs);
254            if !cfg!(feature = "unchecked_ops") {
255                assert!(
256                    !self.0.is_outside_order(),
257                    "Result of {}= operation is outside order",
258                    "-"
259                );
260            }
261        }
262    }
263
264    impl<T, RHS> MulAssign<RHS> for OrdVar<T>
265    where
266        T: PartialOrd + PartialEq + MulAssign<RHS> + OrdSubset,
267    {
268        fn mul_assign(&mut self, rhs: RHS) {
269            self.0.mul_assign(rhs);
270            if !cfg!(feature = "unchecked_ops") {
271                assert!(
272                    !self.0.is_outside_order(),
273                    "Result of {}= operation is outside order",
274                    "*"
275                );
276            }
277        }
278    }
279
280    impl<T, RHS> DivAssign<RHS> for OrdVar<T>
281    where
282        T: PartialOrd + PartialEq + DivAssign<RHS> + OrdSubset,
283    {
284        fn div_assign(&mut self, rhs: RHS) {
285            self.0.div_assign(rhs);
286            if !cfg!(feature = "unchecked_ops") {
287                assert!(
288                    !self.0.is_outside_order(),
289                    "Result of {}= operation is outside order",
290                    "/"
291                );
292            }
293        }
294    }
295
296    impl<T, RHS> RemAssign<RHS> for OrdVar<T>
297    where
298        T: PartialOrd + PartialEq + RemAssign<RHS> + OrdSubset,
299    {
300        fn rem_assign(&mut self, rhs: RHS) {
301            self.0.rem_assign(rhs);
302            if !cfg!(feature = "unchecked_ops") {
303                assert!(
304                    !self.0.is_outside_order(),
305                    "Result of {}= operation is outside order",
306                    "%"
307                );
308            }
309        }
310    }
311
312    impl<T, RHS> BitAndAssign<RHS> for OrdVar<T>
313    where
314        T: PartialOrd + PartialEq + BitAndAssign<RHS> + OrdSubset,
315    {
316        fn bitand_assign(&mut self, rhs: RHS) {
317            self.0.bitand_assign(rhs);
318            if !cfg!(feature = "unchecked_ops") {
319                assert!(
320                    !self.0.is_outside_order(),
321                    "Result of {}= operation is outside order",
322                    "&"
323                );
324            }
325        }
326    }
327
328    impl<T, RHS> BitOrAssign<RHS> for OrdVar<T>
329    where
330        T: PartialOrd + PartialEq + BitOrAssign<RHS> + OrdSubset,
331    {
332        fn bitor_assign(&mut self, rhs: RHS) {
333            self.0.bitor_assign(rhs);
334            if !cfg!(feature = "unchecked_ops") {
335                assert!(
336                    !self.0.is_outside_order(),
337                    "Result of {}= operation is outside order",
338                    "|"
339                );
340            }
341        }
342    }
343
344    impl<T, RHS> BitXorAssign<RHS> for OrdVar<T>
345    where
346        T: PartialOrd + PartialEq + BitXorAssign<RHS> + OrdSubset,
347    {
348        fn bitxor_assign(&mut self, rhs: RHS) {
349            self.0.bitxor_assign(rhs);
350            if !cfg!(feature = "unchecked_ops") {
351                assert!(
352                    !self.0.is_outside_order(),
353                    "Result of {}= operation is outside order",
354                    "^"
355                );
356            }
357        }
358    }
359
360    impl<T, RHS> ShlAssign<RHS> for OrdVar<T>
361    where
362        T: PartialOrd + PartialEq + ShlAssign<RHS> + OrdSubset,
363    {
364        fn shl_assign(&mut self, rhs: RHS) {
365            self.0.shl_assign(rhs);
366            if !cfg!(feature = "unchecked_ops") {
367                assert!(
368                    !self.0.is_outside_order(),
369                    "Result of {}= operation is outside order",
370                    "<<"
371                );
372            }
373        }
374    }
375
376    impl<T, RHS> ShrAssign<RHS> for OrdVar<T>
377    where
378        T: PartialOrd + PartialEq + ShrAssign<RHS> + OrdSubset,
379    {
380        fn shr_assign(&mut self, rhs: RHS) {
381            self.0.shr_assign(rhs);
382            if !cfg!(feature = "unchecked_ops") {
383                assert!(
384                    !self.0.is_outside_order(),
385                    "Result of {}= operation is outside order",
386                    ">>"
387                );
388            }
389        }
390    }
391
392    // ------------------------ unary ops ------------------------------------------
393    impl<T> Neg for OrdVar<T>
394    where
395        T: PartialOrd + PartialEq + Neg,
396        T::Output: PartialOrd + PartialEq + Debug + OrdSubset,
397    {
398        type Output = OrdVar<T::Output>;
399        fn neg(self) -> Self::Output {
400            construct(self.into_inner().neg())
401        }
402    }
403
404    impl<T> Not for OrdVar<T>
405    where
406        T: PartialOrd + PartialEq + Not,
407        T::Output: PartialOrd + PartialEq + Debug + OrdSubset,
408    {
409        type Output = OrdVar<T::Output>;
410        fn not(self) -> Self::Output {
411            construct(self.into_inner().not())
412        }
413    }
414}