Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for iterating set bits in flags. #152

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions Cargo.toml
Expand Up @@ -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
67 changes: 67 additions & 0 deletions 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<B>
where
B: BitFlags,
{
flags: B,
bit: B::Bits,
}

impl<B> BitFlagsIter<B>
where
B: BitFlags,
B::Bits: PrimInt,
{
pub fn new(flags: B) -> Self {
BitFlagsIter {
flags,
bit: B::Bits::one(),
}
}
}

impl<B> Iterator for BitFlagsIter<B>
where
B: BitFlags,
B::Bits: PrimInt + WrappingSub,
{
type Item = B::Flags;

fn next(&mut self) -> Option<Self::Item> {
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
}
}
161 changes: 161 additions & 0 deletions src/lib.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
}

}