#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Effects(u16);
impl Effects {
const PLAIN: Self = Effects(0);
pub const BOLD: Self = Effects(1 << 0);
pub const DIMMED: Self = Effects(1 << 1);
pub const ITALIC: Self = Effects(1 << 2);
pub const UNDERLINE: Self = Effects(1 << 3);
pub const DOUBLE_UNDERLINE: Self = Effects(1 << 4);
pub const CURLY_UNDERLINE: Self = Effects(1 << 5);
pub const DOTTED_UNDERLINE: Self = Effects(1 << 6);
pub const DASHED_UNDERLINE: Self = Effects(1 << 7);
pub const BLINK: Self = Effects(1 << 8);
pub const INVERT: Self = Effects(1 << 9);
pub const HIDDEN: Self = Effects(1 << 10);
pub const STRIKETHROUGH: Self = Effects(1 << 11);
#[inline]
pub const fn new() -> Self {
Self::PLAIN
}
#[inline]
pub const fn is_plain(self) -> bool {
self.0 == Self::PLAIN.0
}
#[inline(always)]
pub const fn contains(self, other: Effects) -> bool {
(other.0 & self.0) == other.0
}
#[inline(always)]
#[must_use]
pub const fn insert(mut self, other: Effects) -> Self {
self.0 |= other.0;
self
}
#[inline(always)]
#[must_use]
pub const fn remove(mut self, other: Effects) -> Self {
self.0 &= !other.0;
self
}
#[inline(always)]
#[must_use]
pub const fn clear(self) -> Self {
Self::new()
}
#[inline]
#[must_use]
pub const fn set(self, other: Self, enable: bool) -> Self {
if enable {
self.insert(other)
} else {
self.remove(other)
}
}
#[inline(always)]
pub fn iter(self) -> EffectIter {
EffectIter {
index: 0,
effects: self,
}
}
#[inline(always)]
pub(crate) fn index_iter(self) -> EffectIndexIter {
EffectIndexIter {
index: 0,
effects: self,
}
}
#[inline]
pub fn render(self) -> impl core::fmt::Display {
EffectsDisplay(self)
}
#[inline]
#[cfg(feature = "std")]
pub(crate) fn write_to(self, write: &mut dyn std::io::Write) -> std::io::Result<()> {
for index in self.index_iter() {
write.write_all(METADATA[index].escape.as_bytes())?;
}
Ok(())
}
}
impl core::fmt::Debug for Effects {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "Effects(")?;
for (i, index) in self.index_iter().enumerate() {
if i != 0 {
write!(f, " | ")?;
}
write!(f, "{}", METADATA[index].name)?;
}
write!(f, ")")?;
Ok(())
}
}
impl core::ops::BitOr for Effects {
type Output = Self;
#[inline(always)]
fn bitor(self, rhs: Self) -> Self {
self.insert(rhs)
}
}
impl core::ops::BitOrAssign for Effects {
#[inline]
fn bitor_assign(&mut self, other: Self) {
*self = self.insert(other);
}
}
impl core::ops::Sub for Effects {
type Output = Self;
#[inline]
fn sub(self, other: Self) -> Self {
self.remove(other)
}
}
impl core::ops::SubAssign for Effects {
#[inline]
fn sub_assign(&mut self, other: Self) {
*self = self.remove(other);
}
}
pub(crate) struct Metadata {
pub(crate) name: &'static str,
pub(crate) escape: &'static str,
}
pub(crate) const METADATA: [Metadata; 12] = [
Metadata {
name: "BOLD",
escape: escape!("1"),
},
Metadata {
name: "DIMMED",
escape: escape!("2"),
},
Metadata {
name: "ITALIC",
escape: escape!("3"),
},
Metadata {
name: "UNDERLINE",
escape: escape!("4"),
},
Metadata {
name: "DOUBLE_UNDERLINE",
escape: escape!("21"),
},
Metadata {
name: "CURLY_UNDERLINE",
escape: escape!("4:3"),
},
Metadata {
name: "DOTTED_UNDERLINE",
escape: escape!("4:4"),
},
Metadata {
name: "DASHED_UNDERLINE",
escape: escape!("4:5"),
},
Metadata {
name: "BLINK",
escape: escape!("5"),
},
Metadata {
name: "INVERT",
escape: escape!("7"),
},
Metadata {
name: "HIDDEN",
escape: escape!("8"),
},
Metadata {
name: "STRIKETHROUGH",
escape: escape!("9"),
},
];
struct EffectsDisplay(Effects);
impl core::fmt::Display for EffectsDisplay {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
for index in self.0.index_iter() {
METADATA[index].escape.fmt(f)?;
}
Ok(())
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct EffectIter {
index: usize,
effects: Effects,
}
impl Iterator for EffectIter {
type Item = Effects;
fn next(&mut self) -> Option<Self::Item> {
while self.index < METADATA.len() {
let index = self.index;
self.index += 1;
let effect = Effects(1 << index);
if self.effects.contains(effect) {
return Some(effect);
}
}
None
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) struct EffectIndexIter {
index: usize,
effects: Effects,
}
impl Iterator for EffectIndexIter {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
while self.index < METADATA.len() {
let index = self.index;
self.index += 1;
let effect = Effects(1 << index);
if self.effects.contains(effect) {
return Some(index);
}
}
None
}
}