Skip to main content

aarty/
sympols.rs

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