about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorBrendan Zabarauskas <bjzaba@yahoo.com.au>2014-04-29 20:05:51 -0700
committerBrendan Zabarauskas <bjzaba@yahoo.com.au>2014-04-30 10:01:14 -0700
commit464e375d2f14de91aeb3263fa9331270667f8a79 (patch)
tree4761d175c01202e73aac05525dd9dc06802e7996 /src/libstd
parent43320e584738113f1e5fb379fc34a1b38de10db5 (diff)
downloadrust-464e375d2f14de91aeb3263fa9331270667f8a79.tar.gz
rust-464e375d2f14de91aeb3263fa9331270667f8a79.zip
Move bitflags module to libstd
This will allow us to provide type-safe APIs in libstd that are C-compatible.
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/bitflags.rs257
-rw-r--r--src/libstd/lib.rs3
2 files changed, 260 insertions, 0 deletions
diff --git a/src/libstd/bitflags.rs b/src/libstd/bitflags.rs
new file mode 100644
index 00000000000..3caa5b5ab3c
--- /dev/null
+++ b/src/libstd/bitflags.rs
@@ -0,0 +1,257 @@
+// 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.
+
+//! The `bitflags!` macro generates a `struct` that holds a set of C-style
+//! bitmask flags. It is useful for creating typesafe wrappers for C APIs.
+//!
+//! The flags should only be defined for integer types, otherwise unexpected
+//! type errors may occur at compile time.
+//!
+//! # Example
+//!
+//! ~~~rust
+//! bitflags!(Flags: u32 {
+//!     FlagA       = 0x00000001,
+//!     FlagB       = 0x00000010,
+//!     FlagC       = 0x00000100,
+//!     FlagABC     = FlagA.bits
+//!                 | FlagB.bits
+//!                 | FlagC.bits
+//! })
+//!
+//! fn main() {
+//!     let e1 = FlagA | FlagC;
+//!     let e2 = FlagB | FlagC;
+//!     assert!((e1 | e2) == FlagABC);   // union
+//!     assert!((e1 & e2) == FlagC);     // intersection
+//!     assert!((e1 - e2) == FlagA);     // set difference
+//! }
+//! ~~~
+//!
+//! The generated `struct`s can also be extended with type and trait implementations:
+//!
+//! ~~~rust
+//! use std::fmt;
+//!
+//! bitflags!(Flags: u32 {
+//!     FlagA   = 0x00000001,
+//!     FlagB   = 0x00000010
+//! })
+//!
+//! impl Flags {
+//!     pub fn clear(&mut self) {
+//!         self.bits = 0;  // The `bits` field can be accessed from within the
+//!                         // same module where the `bitflags!` macro was invoked.
+//!     }
+//! }
+//!
+//! impl fmt::Show for Flags {
+//!     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+//!         write!(f.buf, "hi!")
+//!     }
+//! }
+//!
+//! fn main() {
+//!     let mut flags = FlagA | FlagB;
+//!     flags.clear();
+//!     assert!(flags.is_empty());
+//!     assert_eq!(format!("{}", flags), ~"hi!");
+//! }
+//! ~~~
+//!
+//! # Derived traits
+//!
+//! The `Eq`, `TotalEq`, and `Clone` traits are automatically derived for the
+//! `struct` using the `deriving` attribute.
+//!
+//! # Operators
+//!
+//! The following operator traits are implemented for the generated `struct`:
+//!
+//! - `BitOr`: union
+//! - `BitAnd`: intersection
+//! - `Sub`: set difference
+//!
+//! # Methods
+//!
+//! The following methods are defined for the generated `struct`:
+//!
+//! - `empty`: an empty set of flags
+//! - `bits`: the raw value of the flags currently stored
+//! - `is_empty`: `true` if no flags are currently stored
+//! - `intersects`: `true` if there are flags common to both `self` and `other`
+//! - `contains`: `true` all of the flags in `other` are contained within `self`
+//! - `insert`: inserts the specified flags in-place
+//! - `remove`: removes the specified flags in-place
+
+#[macro_export]
+macro_rules! bitflags(
+    ($BitFlags:ident: $T:ty {
+        $($Flag:ident = $value:expr),+
+    }) => (
+        #[deriving(Eq, TotalEq, Clone)]
+        pub struct $BitFlags {
+            priv bits: $T,
+        }
+
+        $(pub static $Flag: $BitFlags = $BitFlags { bits: $value };)+
+
+        impl $BitFlags {
+            /// Returns an empty set of flags.
+            pub fn empty() -> $BitFlags {
+                $BitFlags { bits: 0 }
+            }
+
+            /// Returns the raw value of the flags currently stored.
+            pub fn bits(&self) -> $T {
+                self.bits
+            }
+
+            /// Returns `true` if no flags are currently stored.
+            pub fn is_empty(&self) -> bool {
+                *self == $BitFlags::empty()
+            }
+
+            /// Returns `true` if there are flags common to both `self` and `other`.
+            pub fn intersects(&self, other: $BitFlags) -> bool {
+                !(self & other).is_empty()
+            }
+
+            /// Returns `true` all of the flags in `other` are contained within `self`.
+            pub fn contains(&self, other: $BitFlags) -> bool {
+                (self & other) == other
+            }
+
+            /// Inserts the specified flags in-place.
+            pub fn insert(&mut self, other: $BitFlags) {
+                self.bits |= other.bits;
+            }
+
+            /// Removes the specified flags in-place.
+            pub fn remove(&mut self, other: $BitFlags) {
+                self.bits &= !other.bits;
+            }
+        }
+
+        impl BitOr<$BitFlags, $BitFlags> for $BitFlags {
+            /// Returns the union of the two sets of flags.
+            #[inline]
+            fn bitor(&self, other: &$BitFlags) -> $BitFlags {
+                $BitFlags { bits: self.bits | other.bits }
+            }
+        }
+
+        impl BitAnd<$BitFlags, $BitFlags> for $BitFlags {
+            /// Returns the intersection between the two sets of flags.
+            #[inline]
+            fn bitand(&self, other: &$BitFlags) -> $BitFlags {
+                $BitFlags { bits: self.bits & other.bits }
+            }
+        }
+
+        impl Sub<$BitFlags, $BitFlags> for $BitFlags {
+            /// Returns the set difference of the two sets of flags.
+            #[inline]
+            fn sub(&self, other: &$BitFlags) -> $BitFlags {
+                $BitFlags { bits: self.bits & !other.bits }
+            }
+        }
+    )
+)
+
+#[cfg(test)]
+mod tests {
+    use ops::{BitOr, BitAnd, Sub};
+
+    bitflags!(Flags: u32 {
+        FlagA       = 0x00000001,
+        FlagB       = 0x00000010,
+        FlagC       = 0x00000100,
+        FlagABC     = FlagA.bits
+                    | FlagB.bits
+                    | FlagC.bits
+    })
+
+    #[test]
+    fn test_bits(){
+        assert_eq!(Flags::empty().bits(), 0x00000000);
+        assert_eq!(FlagA.bits(), 0x00000001);
+        assert_eq!(FlagABC.bits(), 0x00000111);
+    }
+
+    #[test]
+    fn test_is_empty(){
+        assert!(Flags::empty().is_empty());
+        assert!(!FlagA.is_empty());
+        assert!(!FlagABC.is_empty());
+    }
+
+    #[test]
+    fn test_two_empties_do_not_intersect() {
+        let e1 = Flags::empty();
+        let e2 = Flags::empty();
+        assert!(!e1.intersects(e2));
+    }
+
+    #[test]
+    fn test_empty_does_not_intersect_with_full() {
+        let e1 = Flags::empty();
+        let e2 = FlagABC;
+        assert!(!e1.intersects(e2));
+    }
+
+    #[test]
+    fn test_disjoint_intersects() {
+        let e1 = FlagA;
+        let e2 = FlagB;
+        assert!(!e1.intersects(e2));
+    }
+
+    #[test]
+    fn test_overlapping_intersects() {
+        let e1 = FlagA;
+        let e2 = FlagA | FlagB;
+        assert!(e1.intersects(e2));
+    }
+
+    #[test]
+    fn test_contains() {
+        let e1 = FlagA;
+        let e2 = FlagA | FlagB;
+        assert!(!e1.contains(e2));
+        assert!(e2.contains(e1));
+        assert!(FlagABC.contains(e2));
+    }
+
+    #[test]
+    fn test_insert(){
+        let mut e1 = FlagA;
+        let e2 = FlagA | FlagB;
+        e1.insert(e2);
+        assert!(e1 == e2);
+    }
+
+    #[test]
+    fn test_remove(){
+        let mut e1 = FlagA | FlagB;
+        let e2 = FlagA | FlagC;
+        e1.remove(e2);
+        assert!(e1 == FlagB);
+    }
+
+    #[test]
+    fn test_operators() {
+        let e1 = FlagA | FlagC;
+        let e2 = FlagB | FlagC;
+        assert!((e1 | e2) == FlagABC);   // union
+        assert!((e1 & e2) == FlagC);     // intersection
+        assert!((e1 - e2) == FlagA);     // set difference
+    }
+}
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 841a73fa01f..c34ebfdf7c2 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -142,7 +142,10 @@ fn start(argc: int, argv: **u8) -> int {
     green::start(argc, argv, rustuv::event_loop, __test::main)
 }
 
+/* Exported macros */
+
 pub mod macros;
+pub mod bitflags;
 
 mod rtdeps;