Skip to content

Commit 5231436

Browse files
committed
Expand traits implemented by BitFlags
PartialOrd and Ord are now implemented. The values returned by the traits aren't meaningful, but they allow using BitFlags as a key in a BTreeMap. I wish the traits had a distinction between "meaningful order" (overloaded comparison operators) and "arbitrary order" (can be used in BTreeMap). Moreover, the implementation for Hash is improved, so that code that is generic over BitFlag can still access it. Closes #47
1 parent b61a59e commit 5231436

File tree

2 files changed

+43
-18
lines changed

2 files changed

+43
-18
lines changed

src/lib.rs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@
9090
#![warn(missing_docs)]
9191
#![cfg_attr(all(not(test), not(feature = "std")), no_std)]
9292

93+
use core::hash::{Hash, Hasher};
9394
use core::iter::{FromIterator, FusedIterator};
9495
use core::marker::PhantomData;
9596
use core::{cmp, ops};
@@ -218,6 +219,7 @@ pub mod _internal {
218219
use ::core::cmp::PartialOrd;
219220
use ::core::fmt;
220221
use ::core::ops::{BitAnd, BitOr, BitXor, Not, Sub};
222+
use ::core::hash::Hash;
221223

222224
pub trait BitFlagNum:
223225
Default
@@ -227,6 +229,8 @@ pub mod _internal {
227229
+ Sub<Self, Output = Self>
228230
+ Not<Output = Self>
229231
+ PartialOrd<Self>
232+
+ Ord
233+
+ Hash
230234
+ fmt::Debug
231235
+ fmt::Binary
232236
+ Copy
@@ -373,7 +377,7 @@ pub use crate::fallible::FromBitsError;
373377
/// The types substituted for `T` and `N` must always match, creating a
374378
/// `BitFlags` value where that isn't the case is only possible with
375379
/// incorrect unsafe code.
376-
#[derive(Copy, Clone, Eq)]
380+
#[derive(Copy, Clone)]
377381
#[repr(transparent)]
378382
pub struct BitFlags<T, N = <T as _internal::RawBitFlags>::Numeric> {
379383
val: N,
@@ -876,17 +880,33 @@ for_each_uint! { $ty $hide_docs =>
876880
}
877881
}
878882

879-
impl<T, N: PartialEq> cmp::PartialEq for BitFlags<T, N> {
883+
impl<T, N: PartialEq> PartialEq for BitFlags<T, N> {
880884
#[inline(always)]
881885
fn eq(&self, other: &Self) -> bool {
882886
self.val == other.val
883887
}
884888
}
885889

890+
impl<T, N: Eq> Eq for BitFlags<T, N> {}
891+
892+
impl<T, N: PartialOrd> PartialOrd for BitFlags<T, N> {
893+
#[inline(always)]
894+
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
895+
self.val.partial_cmp(&other.val)
896+
}
897+
}
898+
899+
impl<T, N: Ord> Ord for BitFlags<T, N> {
900+
#[inline(always)]
901+
fn cmp(&self, other: &Self) -> cmp::Ordering {
902+
self.val.cmp(&other.val)
903+
}
904+
}
905+
886906
// Clippy complains when Hash is derived while PartialEq is implemented manually
887-
impl<T, N: core::hash::Hash> core::hash::Hash for BitFlags<T, N> {
907+
impl<T, N: Hash> Hash for BitFlags<T, N> {
888908
#[inline(always)]
889-
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
909+
fn hash<H: Hasher>(&self, state: &mut H) {
890910
self.val.hash(state)
891911
}
892912
}

test_suite/tests/requires_std.rs

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
use enumflags2::{bitflags, BitFlags};
1+
#![allow(dead_code)]
2+
use enumflags2::{bitflags, BitFlag, BitFlags};
23

34
include!("../common.rs");
45

56
#[test]
67
fn debug_format() {
7-
use enumflags2::BitFlags;
8-
98
// Assert that our Debug output format meets expectations
109

1110
assert_eq!(
@@ -63,8 +62,6 @@ fn debug_format_alternate() {
6362

6463
#[test]
6564
fn display_format() {
66-
use enumflags2::BitFlags;
67-
6865
// Assert that our Debug output format meets expectations
6966

7067
assert_eq!(
@@ -85,8 +82,6 @@ fn display_format() {
8582

8683
#[test]
8784
fn format() {
88-
use enumflags2::BitFlags;
89-
9085
// Assert BitFlags<T> impls fmt::{Binary, Octal, LowerHex, UpperHex}
9186

9287
assert_eq!(format!("{:b}", BitFlags::<Test>::all()), "1111");
@@ -100,18 +95,28 @@ fn format() {
10095

10196
#[test]
10297
fn debug_generic() {
103-
use enumflags2::{BitFlag, BitFlags};
104-
10598
#[derive(Debug)]
10699
struct Debug<T: BitFlag>(BitFlags<T>);
107100

108101
let _ = format!("{:?}", Debug(BitFlags::<Test>::all()));
109102
}
110103

111-
#[test]
112-
fn works_in_hashmap() {
113-
// Assert that BitFlags<T> implements Hash.
104+
fn works_in_maps() {
105+
// Assert that BitFlags<T> implements Hash and Ord.
106+
107+
use std::collections::{BTreeSet, HashSet};
108+
let mut map: BTreeSet<BitFlags<Test>> = BTreeSet::new();
109+
map.insert(BitFlags::empty());
110+
let mut map: HashSet<BitFlags<Test>> = HashSet::new();
111+
map.insert(BitFlags::empty());
112+
}
113+
114+
fn works_in_maps_generic<T: BitFlag>() {
115+
// Assert that BitFlags<T> implements Hash and Ord.
114116

115-
use std::collections::HashMap;
116-
let _map: HashMap<BitFlags<Test>, u8> = HashMap::new();
117+
use std::collections::{BTreeSet, HashSet};
118+
let mut map: BTreeSet<BitFlags<T>> = BTreeSet::new();
119+
map.insert(BitFlags::empty());
120+
let mut map: HashSet<BitFlags<T>> = HashSet::new();
121+
map.insert(BitFlags::empty());
117122
}

0 commit comments

Comments
 (0)