use std::{
collections::hash_map::{Entry, HashMap, IntoIter},
hash::Hash,
iter::FromIterator,
ops::{Deref, DerefMut},
};
use crate::question::OrderSelectItem;
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum Answer {
String(String),
ListItem(ListItem),
ExpandItem(ExpandItem),
Int(i64),
Float(f64),
Bool(bool),
ListItems(Vec<ListItem>),
}
impl Answer {
pub fn is_string(&self) -> bool {
matches!(self, Self::String(..))
}
pub fn as_string(&self) -> Option<&str> {
match self {
Self::String(v) => Some(v),
_ => None,
}
}
pub fn try_into_string(self) -> Result<String, Self> {
match self {
Self::String(v) => Ok(v),
_ => Err(self),
}
}
pub fn is_list_item(&self) -> bool {
matches!(self, Self::ListItem(..))
}
pub fn as_list_item(&self) -> Option<&ListItem> {
match self {
Self::ListItem(v) => Some(v),
_ => None,
}
}
pub fn try_into_list_item(self) -> Result<ListItem, Self> {
match self {
Self::ListItem(v) => Ok(v),
_ => Err(self),
}
}
pub fn is_expand_item(&self) -> bool {
matches!(self, Self::ExpandItem(..))
}
pub fn as_expand_item(&self) -> Option<&ExpandItem> {
match self {
Self::ExpandItem(v) => Some(v),
_ => None,
}
}
pub fn try_into_expand_item(self) -> Result<ExpandItem, Self> {
match self {
Self::ExpandItem(v) => Ok(v),
_ => Err(self),
}
}
pub fn is_int(&self) -> bool {
matches!(self, Self::Int(..))
}
pub fn as_int(&self) -> Option<i64> {
match self {
Self::Int(v) => Some(*v),
_ => None,
}
}
pub fn try_into_int(self) -> Result<i64, Self> {
match self {
Self::Int(v) => Ok(v),
_ => Err(self),
}
}
pub fn is_float(&self) -> bool {
matches!(self, Self::Float(..))
}
pub fn as_float(&self) -> Option<f64> {
match self {
Self::Float(v) => Some(*v),
_ => None,
}
}
pub fn try_into_float(self) -> Result<f64, Self> {
match self {
Self::Float(v) => Ok(v),
_ => Err(self),
}
}
pub fn is_bool(&self) -> bool {
matches!(self, Self::Bool(..))
}
pub fn as_bool(&self) -> Option<bool> {
match self {
Self::Bool(v) => Some(*v),
_ => None,
}
}
pub fn try_into_bool(self) -> Result<bool, Self> {
match self {
Self::Bool(v) => Ok(v),
_ => Err(self),
}
}
pub fn is_list_items(&self) -> bool {
matches!(self, Self::ListItems(..))
}
pub fn as_list_items(&self) -> Option<&[ListItem]> {
match self {
Self::ListItems(v) => Some(v),
_ => None,
}
}
pub fn try_into_list_items(self) -> Result<Vec<ListItem>, Self> {
match self {
Self::ListItems(v) => Ok(v),
_ => Err(self),
}
}
}
macro_rules! impl_from {
($from:ty => $storage:ident) => {
impl From<$from> for Answer {
fn from(ans: $from) -> Self {
Self::$storage(ans)
}
}
};
}
impl_from!(String => String);
impl_from!(i64 => Int);
impl_from!(f64 => Float);
impl_from!(bool => Bool);
impl_from!(ExpandItem => ExpandItem);
impl_from!(ListItem => ListItem);
impl_from!(Vec<ListItem> => ListItems);
impl From<Vec<OrderSelectItem>> for Answer {
fn from(v: Vec<OrderSelectItem>) -> Self {
Answer::ListItems(v.into_iter().map(|o| o.into()).collect())
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ListItem {
pub index: usize,
pub text: String,
}
impl<I: Into<String>> From<(usize, I)> for ListItem {
fn from((index, text): (usize, I)) -> Self {
Self {
index,
text: text.into(),
}
}
}
impl From<OrderSelectItem> for ListItem {
fn from(o: OrderSelectItem) -> Self {
ListItem {
index: o.initial_index,
text: o.text.text,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ExpandItem {
pub key: char,
pub text: String,
}
impl<I: Into<String>> From<(char, I)> for ExpandItem {
fn from((key, text): (char, I)) -> Self {
Self {
key,
text: text.into(),
}
}
}
#[derive(Default, Clone, PartialEq)]
pub struct Answers {
answers: HashMap<String, Answer>,
}
impl std::fmt::Debug for Answers {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.answers.fmt(f)
}
}
impl Answers {
pub(crate) fn insert(&mut self, name: String, answer: Answer) -> &mut Answer {
match self.answers.entry(name) {
Entry::Occupied(entry) => {
let entry = entry.into_mut();
*entry = answer;
entry
}
Entry::Vacant(entry) => entry.insert(answer),
}
}
}
impl From<HashMap<String, Answer>> for Answers {
fn from(answers: HashMap<String, Answer>) -> Self {
Self { answers }
}
}
impl FromIterator<(String, Answer)> for Answers {
fn from_iter<T: IntoIterator<Item = (String, Answer)>>(iter: T) -> Self {
Self {
answers: iter.into_iter().collect(),
}
}
}
impl Extend<(String, Answer)> for Answers {
fn extend<T: IntoIterator<Item = (String, Answer)>>(&mut self, iter: T) {
self.answers.extend(iter)
}
}
impl Deref for Answers {
type Target = HashMap<String, Answer>;
fn deref(&self) -> &Self::Target {
&self.answers
}
}
impl DerefMut for Answers {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.answers
}
}
impl IntoIterator for Answers {
type Item = (String, Answer);
type IntoIter = IntoIter<String, Answer>;
fn into_iter(self) -> Self::IntoIter {
self.answers.into_iter()
}
}