derive_wizard/
answer.rs

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/// Represents the answers collected from an interview
13#[derive(Debug, Clone, Default)]
14pub struct Answers {
15    values: HashMap<String, AnswerValue>,
16}
17
18/// A single answer value
19#[derive(Debug, Clone)]
20pub enum AnswerValue {
21    String(String),
22    Int(i64),
23    Float(f64),
24    Bool(bool),
25    Nested(Box<Answers>),
26    /// List of selected indices (for multi-select questions)
27    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    /// Get a list of integers (for multi-select answers)
105    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    /// Iterate over all key-value pairs
117    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}