Skip to main content

hyeong/core/
area.rs

1use crate::number::number::Num;
2use crate::util::error::Error;
3use std::cmp::Ordering;
4use std::fmt;
5
6/// Area Part of each code
7/// Since the area has binary operator,
8/// It is saved as binary tree(ast).
9///
10/// # Type
11///
12/// Each value of `type_` that is representing
13///
14/// - ` 0: ?`
15/// - ` 1: !`
16/// - ` 2: ♥`
17/// - ` 3: ❤`
18/// - ` 4: 💕`
19/// - ` 5: 💖`
20/// - ` 6: 💗`
21/// - ` 7: 💘`
22/// - ` 8: 💙`
23/// - ` 9: 💚`
24/// - `10: 💛`
25/// - `11: 💜`
26/// - `12: 💝`
27/// - `13: ♡`
28///
29/// # Examples
30///
31/// ```
32/// use hyeong::core::area::Area;
33///
34/// let a = Area::Val {
35///     type_: 0,
36///     left: Box::new(Area::new(2)),
37///     right: Box::new(Area::Nil),
38/// };
39///
40/// assert_eq!("[♥]?[_]", format!("{}", a));
41/// ```
42#[derive(Clone)]
43pub enum Area {
44    Val {
45        type_: u8,
46        left: Box<Area>,
47        right: Box<Area>,
48    },
49    Nil,
50}
51
52impl Area {
53    /// New `Area` that is leaf node
54    ///
55    /// # Examples
56    ///
57    /// ```
58    /// use hyeong::core::area::Area;
59    ///
60    /// let a = Area::new(10);
61    /// ```
62    pub fn new(type_: u8) -> Area {
63        Area::Val {
64            type_,
65            left: Box::new(Area::Nil),
66            right: Box::new(Area::Nil),
67        }
68    }
69}
70
71/// Calculates Area when value and stack is given.
72///
73/// # Examples
74/// ```
75/// use hyeong::number::number::Num;
76/// use hyeong::core::area::{Area, calc};
77///
78/// let a = Area::new(10);
79/// assert_eq!(10, calc(&a, 1, || Result::Ok(Num::one())).unwrap());
80/// ```
81pub fn calc<T>(area: &Area, area_value: usize, mut pop: T) -> Result<u8, Error>
82where
83    T: FnMut() -> Result<Num, Error>,
84{
85    let mut area = area;
86
87    loop {
88        match area {
89            Area::Val { type_, left, right } => {
90                if *type_ == 0 {
91                    let v = pop();
92                    area = match v?.partial_cmp(&Num::from_num(area_value as isize)) {
93                        Some(Ordering::Less) => left,
94                        _ => right,
95                    }
96                } else if *type_ == 1 {
97                    let v = pop();
98                    area = match v?.partial_cmp(&Num::from_num(area_value as isize)) {
99                        Some(Ordering::Equal) => left,
100                        _ => right,
101                    }
102                } else {
103                    break Ok(*type_);
104                }
105            }
106            Area::Nil => {
107                break Ok(0);
108            }
109        }
110    }
111}
112
113/// `Area` to string in debug mode
114/// it builds the string as it iterates post-order
115pub fn area_to_string_debug(s: &mut String, area: &Area) {
116    match area {
117        Area::Val {
118            ref type_,
119            ref left,
120            ref right,
121        } => {
122            let c = "?!♥❤💕💖💗💘💙💚💛💜💝♡".chars().collect::<Vec<char>>()[*type_ as usize];
123            s.push(c);
124            if *type_ <= 1 {
125                area_to_string_debug(s, left);
126                area_to_string_debug(s, right);
127            }
128        }
129        Area::Nil => {
130            s.push('_');
131        }
132    }
133}
134
135impl fmt::Debug for Area {
136    /// `Area` to string in debug mode
137    ///
138    /// # Examples
139    ///
140    /// ```
141    /// use hyeong::core::area::Area;
142    ///
143    /// let a = Area::Val {
144    ///     type_: 0,
145    ///     left: Box::new(Area::new(2)),
146    ///     right: Box::new(Area::Nil),
147    /// };
148    ///
149    /// assert_eq!("?♥_", format!("{:?}", a));
150    /// ```
151    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152        let mut s = String::new();
153        area_to_string_debug(&mut s, self);
154        write!(f, "{}", s)
155    }
156}
157
158/// `Area` to string in formatting
159/// it builds the string as it iterates infix-order.
160pub fn area_to_string_display(s: &mut String, area: &Area) {
161    match area {
162        Area::Val {
163            ref type_,
164            ref left,
165            ref right,
166        } => {
167            let c = "?!♥❤💕💖💗💘💙💚💛💜💝♡".chars().collect::<Vec<char>>()[*type_ as usize];
168            if *type_ <= 1 {
169                s.push('[');
170                area_to_string_display(s, left);
171                s.push(']');
172                s.push(c);
173                s.push('[');
174                area_to_string_display(s, right);
175                s.push(']');
176            } else {
177                s.push(c);
178            }
179        }
180        Area::Nil => {
181            s.push('_');
182        }
183    }
184}
185
186impl fmt::Display for Area {
187    /// `Area` to string in formatting
188    ///
189    /// # Examples
190    ///
191    /// ```
192    /// use hyeong::core::area::Area;
193    ///
194    /// let a = Area::Val {
195    ///     type_: 0,
196    ///     left: Box::new(Area::new(2)),
197    ///     right: Box::new(Area::Nil),
198    /// };
199    ///
200    /// assert_eq!("[♥]?[_]", format!("{}", a));
201    /// ```
202    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
203        let mut s = String::new();
204        area_to_string_display(&mut s, self);
205        write!(f, "{}", s)
206    }
207}