aarty/
sympols.rs

1use crate::Rgba;
2
3/// An empty sympols set.
4pub const EMPTY_SET: Sympols = Sympols::new(vec![]);
5
6pub const EMPTY_CHAR: char = ' ';
7
8/// The sympols (characters) that we will use to represent our pixels based on their color.
9#[derive(Debug, PartialEq, PartialOrd, Clone, Hash)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11pub struct Sympols {
12    set: Vec<char>,
13}
14
15impl Sympols {
16    /// Construct an new sympols set.
17    pub const fn new(set: Vec<char>) -> Sympols {
18        Sympols { set }
19    }
20
21    /// Construct a new empty set.
22    pub const fn empty() -> Self {
23        EMPTY_SET
24    }
25
26    /// Get the char that in a spicfic index, if the set is [`EMPTY_SET`] it'll always return an [`EMPTY_CHAR`].
27    #[inline(always)]
28    pub fn get(&self, i: usize) -> char {
29        if self.is_empty() {
30            return EMPTY_CHAR;
31        }
32        self.set[i]
33    }
34
35    /// The set length.
36    #[inline(always)]
37    pub fn len(&self) -> usize {
38        self.set.len()
39    }
40
41    /// Return true if the set is empty.
42    #[inline(always)]
43    pub fn is_empty(&self) -> bool {
44        self.set.is_empty()
45    }
46
47    /// Calculate the index of the sympol in the set based on the [`RGBA`] value.
48    #[inline]
49    pub(crate) fn sym_index(&self, pixel: &Rgba) -> usize {
50        if self.is_empty() {
51            return 0;
52        }
53        let len = self.len();
54        // FIXME: handle the alpha channel
55        let mut idx = (pixel.r as usize + pixel.g as usize + pixel.b as usize) / 3;
56
57        if idx == 0 {
58            return 0;
59        }
60
61        if pixel.a < 120 {
62            idx = pixel.a as usize % idx;
63        }
64
65        // I'll kill my self if this didn't work.
66        idx /= 255 / len;
67        if idx >= len {
68            return len - 1;
69        }
70        idx
71    }
72
73    /// Calculate the index if the sympol in the set based on th [`RGBA`] value, and return it.
74    #[inline]
75    pub(crate) fn sym_and_index(&self, pixel: &Rgba) -> (char, usize) {
76        let idx = self.sym_index(pixel);
77        (self.get(idx), idx)
78    }
79}
80
81impl From<&[char]> for Sympols {
82    fn from(value: &[char]) -> Self {
83        Self::new(value.into())
84    }
85}
86
87impl From<Vec<char>> for Sympols {
88    fn from(value: Vec<char>) -> Self {
89        Self::new(value)
90    }
91}