use crate::{NotEnoughSpace, SixelColor};
#[doc = crate::_tags!(color term)]
#[doc = crate::_doc_location!("media/visual/image")]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct SixelPalette<const CAP: usize> {
colors: [Option<SixelColor>; CAP],
len: usize,
}
#[rustfmt::skip]
impl<const CAP: usize> Default for SixelPalette<CAP> { fn default() -> Self { Self::new() } }
#[rustfmt::skip]
impl<const CAP: usize> SixelPalette<CAP> {
pub const fn new() -> Self { Self { colors: [None; CAP], len: 0 } }
pub const fn with_colors(colors: &[SixelColor]) -> Self {
let mut palette = Self::new();
let mut i = 0;
while i < colors.len() {
palette.colors[i] = Some(colors[i]);
i += 1;
}
palette.len = CAP;
palette
}
pub const fn len(&self) -> usize { self.len }
pub const fn is_empty(&self) -> bool { self.len == 0 }
pub const fn is_full(&self) -> bool { self.len >= CAP }
pub const fn get(&self, index: u16) -> Option<SixelColor> {
if (index as usize) < self.colors.len() { self.colors[index as usize] } else { None }
}
pub const fn add_color(&mut self, color: SixelColor) -> Result<u16, NotEnoughSpace> {
if self.is_full() { return Err(NotEnoughSpace(Some(1))); }
let index = self.len;
self.colors[index] = Some(color);
self.len += 1;
Ok(index as u16)
}
#[must_use]
pub const fn find(&self, color: SixelColor) -> Option<u16> {
let mut i = 0;
while i < self.len {
if let Some(existing_color) = self.colors[i] {
if existing_color.eq(color) { return Some(i as u16); }
}
i += 1;
}
None
}
pub const fn find_or_add(&mut self, color: SixelColor) -> Result<u16, NotEnoughSpace> {
let mut i = 0;
while i < self.len {
if let Some(existing_color) = self.colors[i] {
if existing_color.eq(color) { return Ok(i as u16); }
}
i += 1;
}
self.add_color(color)
}
#[allow(private_interfaces)]
pub const fn defined_colors(&self) -> SixelPaletteIter<'_, CAP> {
SixelPaletteIter { palette: self, index: 0 }
}
pub const fn write_definitions(&self, buffer: &mut [u8]) -> usize {
let mut offset = 0;
let mut iter = self.defined_colors();
while let Some((index, color)) = iter.next() {
let written = color.write_definition_bytes(index, buffer, offset);
offset += written;
}
offset
}
}
impl<const CAP: usize> SixelPalette<CAP> {
pub const BLACK_WHITE: SixelPalette<2> =
SixelPalette::<2>::with_colors(&[SixelColor::BLACK, SixelColor::WHITE]);
pub const ANSI_BASIC: SixelPalette<8> = SixelPalette::<8>::with_colors(&[
SixelColor::BLACK,
SixelColor::RED,
SixelColor::GREEN,
SixelColor::YELLOW,
SixelColor::BLUE,
SixelColor::MAGENTA,
SixelColor::CYAN,
SixelColor::WHITE,
]);
}
#[doc = crate::_tags!(color iterator term)]
#[doc = crate::_doc_location!("media/visual/image")]
#[derive(Debug)]
pub struct SixelPaletteIter<'a, const CAP: usize> {
palette: &'a SixelPalette<CAP>,
index: usize,
}
impl<'a, const CAP: usize> SixelPaletteIter<'a, CAP> {
pub const fn next(&mut self) -> Option<(u16, SixelColor)> {
while self.index < self.palette.len {
let current_index = self.index;
self.index += 1;
if let Some(color) = self.palette.colors[current_index] {
return Some((current_index as u16, color));
}
}
None
}
}
impl<'a, const CAP: usize> Iterator for SixelPaletteIter<'a, CAP> {
type Item = (u16, SixelColor);
fn next(&mut self) -> Option<(u16, SixelColor)> {
self.next()
}
}
#[cfg(test)]
mod tests {
#[test]
fn write_definitions() {}
}