1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
//! # `#[bit]` Attribute //! //! The `#[bit]` attribute is composed of three parts, two of which are optional //! in some cases. The components can be provided in any order. //! //! ## Type: //! //! The type used to represent individual bits. This part is required. //! //! ```txt //! #[bit(Type, ...)] //! ``` //! //! ## Mask: //! A mask indicating the valid bits of the collection. This should be a //! constant expression. //! //! If not provided, the mask is assumed to have all bits set (i.e. `!0`). //! //! `BitCollection::full()` returns this value. //! //! ```txt //! #[bit(..., mask = "0b11", ...)] //! ``` //! //! ## Retriever: //! The suffix for retrieving the inner integer value of the bit type. It //! expands to `$value.$retr`. Because of this, the provided retriever must be //! visible where the derive is located. //! //! If not provided, the bit type is assumed to be an `enum` that can be //! casted to an integer. //! //! ```txt //! #[bit(..., retr = "inner", ...)] //! ``` //! //! # Examples //! //! In computer chess, one popular way of representing the occupants of a board //! is through a [`Bitboard`][bitboard] type. In this type, each individual bit //! is a square on a chess board. //! //! ``` //! # #[cfg(not(feature = "std"))] //! # extern crate core; //! #[macro_use] //! extern crate bit_collection; //! use bit_collection::BitCollection; //! //! #[derive(Copy, Clone)] //! pub struct Square(u8); //! //! /// A set of sixty-four `Square`s. //! #[bit(Square, mask = "!0", retr = "0")] //! #[derive(BitCollection)] //! pub struct Bitboard(u64); //! //! # fn main() {} //! ``` //! //! We can also represent castle rights this way. //! //! ``` //! # #[cfg(not(feature = "std"))] //! # extern crate core; //! # #[macro_use] //! # extern crate bit_collection; //! # use bit_collection::BitCollection; //! #[derive(Copy, Clone)] //! pub enum CastleRight { //! WhiteKingside, //! BlackKingside, //! WhiteQueenside, //! BlackQueenside, //! } //! //! /// A set of `CastleRight`s. //! #[bit(CastleRight, mask = "0b1111")] //! #[derive(BitCollection)] //! pub struct CastleRights { //! bits: u8 //! } //! //! fn iterate_over(rights: CastleRights) { //! for right in rights { //! match right { //! CastleRight::WhiteKingside => { /* ... */ }, //! CastleRight::BlackKingside => { /* ... */ }, //! CastleRight::WhiteQueenside => { /* ... */ }, //! CastleRight::BlackQueenside => { /* ... */ }, //! } //! } //! } //! //! # fn main() {} //! ``` //! //! [bitboard]: https://chessprogramming.wikispaces.com/Bitboards #![cfg_attr(not(feature = "std"), no_std)] // Reexport derive macro. #[allow(unused_imports)] #[macro_use] extern crate bit_collection_derive; #[doc(hidden)] pub use bit_collection_derive::*; /// A type that represents a collection of bits that can be iterated over. pub trait BitCollection: DoubleEndedIterator + ExactSizeIterator { /// Returns a full instance with all bits set. fn full() -> Self; /// Returns an empty instance with no bits set. fn empty() -> Self; /// Returns whether `self` is empty. fn is_empty(&self) -> bool; /// Returns the least significant bit in `self` if `self` is not empty. #[inline] fn lsb(&self) -> Option<Self::Item> { if BitCollection::is_empty(self) { None } else { unsafe { Some(self.lsb_unchecked()) } } } /// Returns the most significant bit in `self` if `self` is not empty. #[inline] fn msb(&self) -> Option<Self::Item> { if BitCollection::is_empty(self) { None } else { unsafe { Some(self.msb_unchecked()) } } } /// Returns the least significant bit in `self` without checking whether /// `self` is empty. unsafe fn lsb_unchecked(&self) -> Self::Item; /// Returns the most significant bit in `self` without checking whether /// `self` is empty. unsafe fn msb_unchecked(&self) -> Self::Item; /// Removes the least significant bit from `self`. fn remove_lsb(&mut self); /// Removes the most significant bit from `self`. fn remove_msb(&mut self); /// Removes the least significant bit from `self` and returns it. fn pop_lsb(&mut self) -> Option<Self::Item>; /// Removes the most significant bit from `self` and returns it. fn pop_msb(&mut self) -> Option<Self::Item>; /// Returns whether `self` contains the value. fn contains<T: Into<Self>>(&self, T) -> bool where Self: Sized; /// Returns the result of removing the value from `self`. fn removing<T: Into<Self>>(self, T) -> Self where Self: Sized; /// Returns the result of inserting the value into `self`. fn inserting<T: Into<Self>>(self, T) -> Self where Self: Sized; /// Returns the result of toggling the bits of the value in `self`. fn toggling<T: Into<Self>>(self, T) -> Self where Self: Sized; /// Returns the result of intersecting the bits of the value with `self`. fn intersecting<T: Into<Self>>(self, T) -> Self where Self: Sized; /// Returns the result of setting the bits of the value in `self` based on /// `condition`. #[inline] fn setting<T: Into<Self>>(self, x: T, condition: bool) -> Self where Self: Sized { if condition { self.inserting(x) } else { self.removing(x) } } /// Removes the value from `self`. fn remove<T: Into<Self>>(&mut self, T) where Self: Sized; /// Inserts the value into `self`. fn insert<T: Into<Self>>(&mut self, T) where Self: Sized; /// Toggles bits of the value in `self`. fn toggle<T: Into<Self>>(&mut self, T) where Self: Sized; /// Intersects the bits of the value with `self`. fn intersect<T: Into<Self>>(&mut self, T) where Self: Sized; /// Sets the bits of the value in `self` based on `condition`. #[inline] fn set<T: Into<Self>>(&mut self, x: T, condition: bool) where Self: Sized { if condition { self.insert(x); } else { self.remove(x); } } }