1use std::{
2 collections::hash_map::{Entry, HashMap, IntoIter},
3 hash::Hash,
4 iter::FromIterator,
5 ops::{Deref, DerefMut},
6};
7
8use crate::question::OrderSelectItem;
9
10#[derive(Debug, Clone, PartialEq, PartialOrd)]
14pub enum Answer {
15 String(String),
21 ListItem(ListItem),
26 ExpandItem(ExpandItem),
30 Int(i64),
34 Float(f64),
38 Bool(bool),
42 ListItems(Vec<ListItem>),
47}
48
49impl Answer {
50 pub fn is_string(&self) -> bool {
52 matches!(self, Self::String(..))
53 }
54
55 pub fn as_string(&self) -> Option<&str> {
57 match self {
58 Self::String(v) => Some(v),
59 _ => None,
60 }
61 }
62
63 pub fn try_into_string(self) -> Result<String, Self> {
65 match self {
66 Self::String(v) => Ok(v),
67 _ => Err(self),
68 }
69 }
70
71 pub fn is_list_item(&self) -> bool {
73 matches!(self, Self::ListItem(..))
74 }
75
76 pub fn as_list_item(&self) -> Option<&ListItem> {
78 match self {
79 Self::ListItem(v) => Some(v),
80 _ => None,
81 }
82 }
83
84 pub fn try_into_list_item(self) -> Result<ListItem, Self> {
86 match self {
87 Self::ListItem(v) => Ok(v),
88 _ => Err(self),
89 }
90 }
91
92 pub fn is_expand_item(&self) -> bool {
94 matches!(self, Self::ExpandItem(..))
95 }
96
97 pub fn as_expand_item(&self) -> Option<&ExpandItem> {
99 match self {
100 Self::ExpandItem(v) => Some(v),
101 _ => None,
102 }
103 }
104
105 pub fn try_into_expand_item(self) -> Result<ExpandItem, Self> {
107 match self {
108 Self::ExpandItem(v) => Ok(v),
109 _ => Err(self),
110 }
111 }
112
113 pub fn is_int(&self) -> bool {
115 matches!(self, Self::Int(..))
116 }
117
118 pub fn as_int(&self) -> Option<i64> {
120 match self {
121 Self::Int(v) => Some(*v),
122 _ => None,
123 }
124 }
125
126 pub fn try_into_int(self) -> Result<i64, Self> {
128 match self {
129 Self::Int(v) => Ok(v),
130 _ => Err(self),
131 }
132 }
133
134 pub fn is_float(&self) -> bool {
136 matches!(self, Self::Float(..))
137 }
138
139 pub fn as_float(&self) -> Option<f64> {
141 match self {
142 Self::Float(v) => Some(*v),
143 _ => None,
144 }
145 }
146
147 pub fn try_into_float(self) -> Result<f64, Self> {
149 match self {
150 Self::Float(v) => Ok(v),
151 _ => Err(self),
152 }
153 }
154
155 pub fn is_bool(&self) -> bool {
157 matches!(self, Self::Bool(..))
158 }
159
160 pub fn as_bool(&self) -> Option<bool> {
162 match self {
163 Self::Bool(v) => Some(*v),
164 _ => None,
165 }
166 }
167
168 pub fn try_into_bool(self) -> Result<bool, Self> {
170 match self {
171 Self::Bool(v) => Ok(v),
172 _ => Err(self),
173 }
174 }
175
176 pub fn is_list_items(&self) -> bool {
178 matches!(self, Self::ListItems(..))
179 }
180
181 pub fn as_list_items(&self) -> Option<&[ListItem]> {
183 match self {
184 Self::ListItems(v) => Some(v),
185 _ => None,
186 }
187 }
188
189 pub fn try_into_list_items(self) -> Result<Vec<ListItem>, Self> {
191 match self {
192 Self::ListItems(v) => Ok(v),
193 _ => Err(self),
194 }
195 }
196}
197
198macro_rules! impl_from {
199 ($from:ty => $storage:ident) => {
200 impl From<$from> for Answer {
201 fn from(ans: $from) -> Self {
202 Self::$storage(ans)
203 }
204 }
205 };
206}
207
208impl_from!(String => String);
209impl_from!(i64 => Int);
210impl_from!(f64 => Float);
211impl_from!(bool => Bool);
212impl_from!(ExpandItem => ExpandItem);
213impl_from!(ListItem => ListItem);
214impl_from!(Vec<ListItem> => ListItems);
215
216impl From<Vec<OrderSelectItem>> for Answer {
217 fn from(v: Vec<OrderSelectItem>) -> Self {
218 Answer::ListItems(v.into_iter().map(|o| o.into()).collect())
219 }
220}
221
222#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
230pub struct ListItem {
231 pub index: usize,
233 pub text: String,
235}
236
237impl<I: Into<String>> From<(usize, I)> for ListItem {
238 fn from((index, text): (usize, I)) -> Self {
239 Self {
240 index,
241 text: text.into(),
242 }
243 }
244}
245
246impl From<OrderSelectItem> for ListItem {
247 fn from(o: OrderSelectItem) -> Self {
248 ListItem {
249 index: o.initial_index,
250 text: o.text.text,
251 }
252 }
253}
254
255#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
262pub struct ExpandItem {
263 pub key: char,
265 pub text: String,
267}
268
269impl<I: Into<String>> From<(char, I)> for ExpandItem {
270 fn from((key, text): (char, I)) -> Self {
271 Self {
272 key,
273 text: text.into(),
274 }
275 }
276}
277
278#[derive(Default, Clone, PartialEq)]
282pub struct Answers {
283 answers: HashMap<String, Answer>,
284}
285
286impl std::fmt::Debug for Answers {
287 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
288 self.answers.fmt(f)
289 }
290}
291
292impl Answers {
293 pub(crate) fn insert(&mut self, name: String, answer: Answer) -> &mut Answer {
294 match self.answers.entry(name) {
295 Entry::Occupied(entry) => {
296 let entry = entry.into_mut();
297 *entry = answer;
298 entry
299 }
300 Entry::Vacant(entry) => entry.insert(answer),
301 }
302 }
303}
304
305impl From<HashMap<String, Answer>> for Answers {
306 fn from(answers: HashMap<String, Answer>) -> Self {
307 Self { answers }
308 }
309}
310
311impl FromIterator<(String, Answer)> for Answers {
312 fn from_iter<T: IntoIterator<Item = (String, Answer)>>(iter: T) -> Self {
313 Self {
314 answers: iter.into_iter().collect(),
315 }
316 }
317}
318
319impl Extend<(String, Answer)> for Answers {
320 fn extend<T: IntoIterator<Item = (String, Answer)>>(&mut self, iter: T) {
321 self.answers.extend(iter)
322 }
323}
324
325impl Deref for Answers {
326 type Target = HashMap<String, Answer>;
327
328 fn deref(&self) -> &Self::Target {
329 &self.answers
330 }
331}
332
333impl DerefMut for Answers {
334 fn deref_mut(&mut self) -> &mut Self::Target {
335 &mut self.answers
336 }
337}
338
339impl IntoIterator for Answers {
340 type Item = (String, Answer);
341 type IntoIter = IntoIter<String, Answer>;
342
343 fn into_iter(self) -> Self::IntoIter {
344 self.answers.into_iter()
345 }
346}