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}