diff --git a/Cargo.toml b/Cargo.toml index 52bc7e17..ce610397 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,3 +23,9 @@ travis-ci = { repository = "rust-lang-nursery/bitflags" } [features] default = ["example_generated"] example_generated = [] +iterator = ["num-traits"] + +[dependencies.num-traits] +version = "0.2" +default-features = false +optional = true diff --git a/src/iterator.rs b/src/iterator.rs new file mode 100644 index 00000000..6233f8f6 --- /dev/null +++ b/src/iterator.rs @@ -0,0 +1,67 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use num_traits::int::PrimInt; +use num_traits::ops::wrapping::WrappingSub; +use num_traits::{One, Zero}; + +pub trait BitFlags { + type Bits; + type Flags; + + fn as_bits(&self) -> Self::Bits; + fn from_bits(Self::Bits) -> Self::Flags; +} + +/// An iterator over each flag set in a `BitFlags` struct. +/// +/// This `struct` is create by the [`iter`] function. +#[derive(Debug)] +pub struct BitFlagsIter +where + B: BitFlags, +{ + flags: B, + bit: B::Bits, +} + +impl BitFlagsIter +where + B: BitFlags, + B::Bits: PrimInt, +{ + pub fn new(flags: B) -> Self { + BitFlagsIter { + flags, + bit: B::Bits::one(), + } + } +} + +impl Iterator for BitFlagsIter +where + B: BitFlags, + B::Bits: PrimInt + WrappingSub, +{ + type Item = B::Flags; + + fn next(&mut self) -> Option { + let flags = self.flags.as_bits(); + let t = self.bit.wrapping_sub(&B::Bits::one()); + while (flags & !t) != B::Bits::zero() { + let test_bit = self.bit; + self.bit = self.bit.unsigned_shl(1); + if (flags & test_bit) != B::Bits::zero() { + return Some(B::from_bits(test_bit)); + } + } + None + } +} diff --git a/src/lib.rs b/src/lib.rs index f5bca98e..9ed0e64f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -215,11 +215,21 @@ //! assert_eq!(implemented_default, (Flags::A | Flags::C)); //! } //! ``` +//! +//! # Iterator +//! +//! #![no_std] #![doc(html_root_url = "https://docs.rs/bitflags/1.0.1")] +#[cfg(feature = "iterator")] +extern crate num_traits; + +#[cfg(feature = "iterator")] +pub mod iterator; + #[cfg(test)] #[macro_use] extern crate std; @@ -579,6 +589,12 @@ macro_rules! __impl_bitflags { self.remove(other); } } + + /// Returns an iterator over the possibly contained set of flags. + #[cfg(feature = "iterator")] + pub fn iter<'a>(&'a self) -> $crate::iterator::BitFlagsIter<&'a $BitFlags> { + $crate::iterator::BitFlagsIter::new(self) + } } impl $crate::_core::ops::BitOr for $BitFlags { @@ -682,6 +698,54 @@ macro_rules! __impl_bitflags { result } } + + #[cfg(feature = "iterator")] + impl $crate::iterator::BitFlags for $BitFlags { + type Bits = $T; + type Flags = $BitFlags; + + fn as_bits(&self) -> Self::Bits { + self.bits() + } + + fn from_bits(bits: Self::Bits) -> Self::Flags { + $BitFlags::from_bits_truncate(bits) + } + } + + #[cfg(feature = "iterator")] + impl $crate::_core::iter::IntoIterator for $BitFlags { + type Item = $BitFlags; + type IntoIter = $crate::iterator::BitFlagsIter<$BitFlags>; + + fn into_iter(self) -> Self::IntoIter { + $crate::iterator::BitFlagsIter::new(self) + } + } + + #[cfg(feature = "iterator")] + impl<'a> $crate::iterator::BitFlags for &'a $BitFlags { + type Bits = $T; + type Flags = $BitFlags; + + fn as_bits(&self) -> Self::Bits { + self.bits() + } + + fn from_bits(bits: Self::Bits) -> Self::Flags { + $BitFlags::from_bits_truncate(bits) + } + } + + #[cfg(feature = "iterator")] + impl<'a> $crate::_core::iter::IntoIterator for &'a $BitFlags { + type Item = $BitFlags; + type IntoIter = $crate::iterator::BitFlagsIter<&'a $BitFlags>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } + } }; // Every attribute that the user writes on a const is applied to the @@ -1158,3 +1222,100 @@ mod tests { assert_eq!(module::value(), 1) } } + +#[cfg(all(test, feature = "iterator"))] +mod iter_tests { + bitflags! { + struct Flags: u32 { + const A = 0b00000001; + const B = 0b00001000; + const D = 0b00010000; + const C = 0b10000000; + const ABCD = Self::A.bits | Self::B.bits | Self::C.bits | Self::D.bits; + } + } + + bitflags! { + struct SignedFlags: i8 { + const U = 0; + const A = 0b00000001; + const B = 0b00000010; + const C = 0b00000100; + const D = 0b00001000; + const E = 0b00010000; + const F = 0b00100000; + const G = 0b01000000; + } + } + + #[test] + fn test_iterator_simple() { + let mut iter = Flags::A.into_iter(); + assert_eq!(iter.next(), Some(Flags::A)); + assert_eq!(iter.next(), None); + + let mut iter = Flags::B.into_iter(); + assert_eq!(iter.next(), Some(Flags::B)); + assert_eq!(iter.next(), None); + + let mut iter = Flags::C.into_iter(); + assert_eq!(iter.next(), Some(Flags::C)); + assert_eq!(iter.next(), None); + + let mut iter = Flags::D.into_iter(); + assert_eq!(iter.next(), Some(Flags::D)); + assert_eq!(iter.next(), None); + } + + #[test] + fn test_iterator_complex() { + let mut iter = Flags::ABCD.into_iter(); + assert_eq!(iter.next(), Some(Flags::A)); + assert_eq!(iter.next(), Some(Flags::B)); + assert_eq!(iter.next(), Some(Flags::D)); + assert_eq!(iter.next(), Some(Flags::C)); + assert_eq!(iter.next(), None); + } + + #[test] + fn test_iterator_simple_complex() { + let mut iter = SignedFlags::all().into_iter(); + assert_eq!(iter.next(), Some(SignedFlags::A)); + assert_eq!(iter.next(), Some(SignedFlags::B)); + assert_eq!(iter.next(), Some(SignedFlags::C)); + assert_eq!(iter.next(), Some(SignedFlags::D)); + assert_eq!(iter.next(), Some(SignedFlags::E)); + assert_eq!(iter.next(), Some(SignedFlags::F)); + assert_eq!(iter.next(), Some(SignedFlags::G)); + assert_eq!(iter.next(), None); + } + + #[test] + fn test_iterator_for() { + let flags = Flags::all(); + let expected = vec![Flags::A, Flags::B, Flags::D, Flags::C]; + + for (x, y) in flags.iter().zip(expected.iter()) { + assert_eq!(x, *y); + } + } + + #[test] + fn test_iterator_for_signed() { + let flags = SignedFlags::all(); + let expected = vec![ + SignedFlags::A, + SignedFlags::B, + SignedFlags::C, + SignedFlags::D, + SignedFlags::E, + SignedFlags::F, + SignedFlags::G, + ]; + + for (x, y) in flags.iter().zip(expected.iter()) { + assert_eq!(x, *y); + } + } + +}