1use std::collections::HashMap;
2
3#[derive(Debug, thiserror::Error)]
4pub enum AnswerError {
5 #[error("Missing key: {0}")]
6 MissingKey(String),
7
8 #[error("Type mismatch for key '{key}': expected {expected}")]
9 TypeMismatch { key: String, expected: &'static str },
10}
11
12#[derive(Debug, Clone, Default)]
14pub struct Answers {
15 values: HashMap<String, AnswerValue>,
16}
17
18#[derive(Debug, Clone)]
20pub enum AnswerValue {
21 String(String),
22 Int(i64),
23 Float(f64),
24 Bool(bool),
25 Nested(Box<Answers>),
26 IntList(Vec<i64>),
28}
29
30impl Answers {
31 pub fn new() -> Self {
32 Self {
33 values: HashMap::new(),
34 }
35 }
36
37 pub fn insert(&mut self, key: String, value: AnswerValue) {
38 self.values.insert(key, value);
39 }
40
41 pub fn get(&self, key: &str) -> Option<&AnswerValue> {
42 self.values.get(key)
43 }
44
45 pub fn merge(&mut self, other: Self) {
46 self.values.extend(other.values);
47 }
48
49 pub fn as_string(&self, key: &str) -> Result<String, AnswerError> {
50 match self.get(key) {
51 Some(AnswerValue::String(s)) => Ok(s.clone()),
52 Some(_) => Err(AnswerError::TypeMismatch {
53 key: key.to_string(),
54 expected: "String",
55 }),
56 None => Err(AnswerError::MissingKey(key.to_string())),
57 }
58 }
59
60 pub fn as_int(&self, key: &str) -> Result<i64, AnswerError> {
61 match self.get(key) {
62 Some(AnswerValue::Int(i)) => Ok(*i),
63 Some(_) => Err(AnswerError::TypeMismatch {
64 key: key.to_string(),
65 expected: "Int",
66 }),
67 None => Err(AnswerError::MissingKey(key.to_string())),
68 }
69 }
70
71 pub fn as_float(&self, key: &str) -> Result<f64, AnswerError> {
72 match self.get(key) {
73 Some(AnswerValue::Float(f)) => Ok(*f),
74 Some(_) => Err(AnswerError::TypeMismatch {
75 key: key.to_string(),
76 expected: "Float",
77 }),
78 None => Err(AnswerError::MissingKey(key.to_string())),
79 }
80 }
81
82 pub fn as_bool(&self, key: &str) -> Result<bool, AnswerError> {
83 match self.get(key) {
84 Some(AnswerValue::Bool(b)) => Ok(*b),
85 Some(_) => Err(AnswerError::TypeMismatch {
86 key: key.to_string(),
87 expected: "Bool",
88 }),
89 None => Err(AnswerError::MissingKey(key.to_string())),
90 }
91 }
92
93 pub fn as_nested(&self, key: &str) -> Result<&Self, AnswerError> {
94 match self.get(key) {
95 Some(AnswerValue::Nested(nested)) => Ok(nested),
96 Some(_) => Err(AnswerError::TypeMismatch {
97 key: key.to_string(),
98 expected: "Nested",
99 }),
100 None => Err(AnswerError::MissingKey(key.to_string())),
101 }
102 }
103
104 pub fn as_int_list(&self, key: &str) -> Result<Vec<i64>, AnswerError> {
106 match self.get(key) {
107 Some(AnswerValue::IntList(list)) => Ok(list.clone()),
108 Some(_) => Err(AnswerError::TypeMismatch {
109 key: key.to_string(),
110 expected: "IntList",
111 }),
112 None => Err(AnswerError::MissingKey(key.to_string())),
113 }
114 }
115
116 pub fn iter(&self) -> impl Iterator<Item = (&String, &AnswerValue)> {
118 self.values.iter()
119 }
120}
121
122impl From<&derive_wizard_types::AssumedAnswer> for AnswerValue {
123 fn from(assumed: &derive_wizard_types::AssumedAnswer) -> Self {
124 use derive_wizard_types::AssumedAnswer;
125 match assumed {
126 AssumedAnswer::String(s) => Self::String(s.clone()),
127 AssumedAnswer::Int(i) => Self::Int(*i),
128 AssumedAnswer::Float(f) => Self::Float(*f),
129 AssumedAnswer::Bool(b) => Self::Bool(*b),
130 }
131 }
132}