| 1 | use std::ops::{BitAnd, BitOr, BitXor};
|
| 2 |
|
| 3 | use crate::style::Attribute;
|
| 4 |
|
| 5 | /// a bitset for all possible attributes
|
| 6 | #[derive (Debug, Default, Clone, Copy, PartialEq, Eq)]
|
| 7 | pub struct Attributes(u32);
|
| 8 |
|
| 9 | impl From<Attribute> for Attributes {
|
| 10 | fn from(attribute: Attribute) -> Self {
|
| 11 | Self(attribute.bytes())
|
| 12 | }
|
| 13 | }
|
| 14 |
|
| 15 | impl From<&[Attribute]> for Attributes {
|
| 16 | fn from(arr: &[Attribute]) -> Self {
|
| 17 | let mut attributes: Attributes = Attributes::default();
|
| 18 | for &attr: Attribute in arr {
|
| 19 | attributes.set(attribute:attr);
|
| 20 | }
|
| 21 | attributes
|
| 22 | }
|
| 23 | }
|
| 24 |
|
| 25 | impl BitAnd<Attribute> for Attributes {
|
| 26 | type Output = Self;
|
| 27 | fn bitand(self, rhs: Attribute) -> Self {
|
| 28 | Self(self.0 & rhs.bytes())
|
| 29 | }
|
| 30 | }
|
| 31 | impl BitAnd for Attributes {
|
| 32 | type Output = Self;
|
| 33 | fn bitand(self, rhs: Self) -> Self {
|
| 34 | Self(self.0 & rhs.0)
|
| 35 | }
|
| 36 | }
|
| 37 |
|
| 38 | impl BitOr<Attribute> for Attributes {
|
| 39 | type Output = Self;
|
| 40 | fn bitor(self, rhs: Attribute) -> Self {
|
| 41 | Self(self.0 | rhs.bytes())
|
| 42 | }
|
| 43 | }
|
| 44 | impl BitOr for Attributes {
|
| 45 | type Output = Self;
|
| 46 | fn bitor(self, rhs: Self) -> Self {
|
| 47 | Self(self.0 | rhs.0)
|
| 48 | }
|
| 49 | }
|
| 50 |
|
| 51 | impl BitXor<Attribute> for Attributes {
|
| 52 | type Output = Self;
|
| 53 | fn bitxor(self, rhs: Attribute) -> Self {
|
| 54 | Self(self.0 ^ rhs.bytes())
|
| 55 | }
|
| 56 | }
|
| 57 | impl BitXor for Attributes {
|
| 58 | type Output = Self;
|
| 59 | fn bitxor(self, rhs: Self) -> Self {
|
| 60 | Self(self.0 ^ rhs.0)
|
| 61 | }
|
| 62 | }
|
| 63 |
|
| 64 | impl Attributes {
|
| 65 | /// Returns the empty bitset.
|
| 66 | #[inline (always)]
|
| 67 | pub const fn none() -> Self {
|
| 68 | Self(0)
|
| 69 | }
|
| 70 |
|
| 71 | /// Returns a copy of the bitset with the given attribute set.
|
| 72 | /// If it's already set, this returns the bitset unmodified.
|
| 73 | #[inline (always)]
|
| 74 | pub const fn with(self, attribute: Attribute) -> Self {
|
| 75 | Self(self.0 | attribute.bytes())
|
| 76 | }
|
| 77 |
|
| 78 | /// Returns a copy of the bitset with the given attribute unset.
|
| 79 | /// If it's not set, this returns the bitset unmodified.
|
| 80 | #[inline (always)]
|
| 81 | pub const fn without(self, attribute: Attribute) -> Self {
|
| 82 | Self(self.0 & !attribute.bytes())
|
| 83 | }
|
| 84 |
|
| 85 | /// Sets the attribute.
|
| 86 | /// If it's already set, this does nothing.
|
| 87 | #[inline (always)]
|
| 88 | pub fn set(&mut self, attribute: Attribute) {
|
| 89 | self.0 |= attribute.bytes();
|
| 90 | }
|
| 91 |
|
| 92 | /// Unsets the attribute.
|
| 93 | /// If it's not set, this changes nothing.
|
| 94 | #[inline (always)]
|
| 95 | pub fn unset(&mut self, attribute: Attribute) {
|
| 96 | self.0 &= !attribute.bytes();
|
| 97 | }
|
| 98 |
|
| 99 | /// Sets the attribute if it's unset, unset it
|
| 100 | /// if it is set.
|
| 101 | #[inline (always)]
|
| 102 | pub fn toggle(&mut self, attribute: Attribute) {
|
| 103 | self.0 ^= attribute.bytes();
|
| 104 | }
|
| 105 |
|
| 106 | /// Returns whether the attribute is set.
|
| 107 | #[inline (always)]
|
| 108 | pub const fn has(self, attribute: Attribute) -> bool {
|
| 109 | self.0 & attribute.bytes() != 0
|
| 110 | }
|
| 111 |
|
| 112 | /// Sets all the passed attributes. Removes none.
|
| 113 | #[inline (always)]
|
| 114 | pub fn extend(&mut self, attributes: Attributes) {
|
| 115 | self.0 |= attributes.0;
|
| 116 | }
|
| 117 |
|
| 118 | /// Returns whether there is no attribute set.
|
| 119 | #[inline (always)]
|
| 120 | pub const fn is_empty(self) -> bool {
|
| 121 | self.0 == 0
|
| 122 | }
|
| 123 | }
|
| 124 |
|
| 125 | #[cfg (test)]
|
| 126 | mod tests {
|
| 127 | use super::{Attribute, Attributes};
|
| 128 |
|
| 129 | #[test ]
|
| 130 | fn test_attributes() {
|
| 131 | let mut attributes: Attributes = Attribute::Bold.into();
|
| 132 | assert!(attributes.has(Attribute::Bold));
|
| 133 | attributes.set(Attribute::Italic);
|
| 134 | assert!(attributes.has(Attribute::Italic));
|
| 135 | attributes.unset(Attribute::Italic);
|
| 136 | assert!(!attributes.has(Attribute::Italic));
|
| 137 | attributes.toggle(Attribute::Bold);
|
| 138 | assert!(attributes.is_empty());
|
| 139 | }
|
| 140 |
|
| 141 | #[test ]
|
| 142 | fn test_attributes_const() {
|
| 143 | const ATTRIBUTES: Attributes = Attributes::none()
|
| 144 | .with(Attribute::Bold)
|
| 145 | .with(Attribute::Italic)
|
| 146 | .without(Attribute::Bold);
|
| 147 | assert!(!ATTRIBUTES.has(Attribute::Bold));
|
| 148 | assert!(ATTRIBUTES.has(Attribute::Italic));
|
| 149 | }
|
| 150 | }
|
| 151 | |