1use std::collections::HashMap;
2
3use camino::Utf8PathBuf;
4use tracing::{error, warn};
5
6use crate::{address::Address, parser, Error, GdbError, ParseHexError};
7
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub enum Message {
10 Response(Response),
11 General(GeneralMessage),
12}
13
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub enum Response {
16 Notify(NotifyResponse),
17 Result(ResultResponse),
18}
19
20#[derive(Debug, Clone, PartialEq, Eq)]
21pub struct ResultResponse {
22 message: String,
23 payload: Option<Dict>,
24}
25
26#[derive(Debug, Clone, PartialEq, Eq)]
27pub struct NotifyResponse {
28 message: String,
29 payload: Dict,
30}
31
32#[derive(Debug, Clone, PartialEq, Eq)]
33pub enum GeneralMessage {
34 Console(String),
35 Log(String),
36 Target(String),
37 Done,
38 InferiorStdout(String),
41 InferiorStderr(String),
42}
43
44#[derive(Debug, Clone, Eq, PartialEq)]
45pub enum Value {
46 String(String),
47 List(List),
48 Dict(Dict),
49}
50
51#[derive(Debug, Clone, Eq, PartialEq)]
52pub struct Dict(HashMap<String, Value>);
53
54pub type List = Vec<Value>;
55
56impl Response {
57 pub fn expect_result(self) -> Result<ResultResponse, Error> {
58 if let Self::Result(result) = self {
59 Ok(result)
60 } else {
61 error!("Expected Response to be Result, got: {:?}", self);
62 Err(Error::ExpectedResultResponse)
63 }
64 }
65
66 pub(crate) fn from_parsed(response: parser::Response) -> Result<Self, Error> {
67 match response {
68 parser::Response::Notify {
69 message, payload, ..
70 } => Ok(Self::Notify(NotifyResponse { message, payload })),
71 parser::Response::Result {
72 message, payload, ..
73 } => {
74 if message == "error" {
75 let gdb_error = Self::_into_error(payload)?;
76 Err(Error::Gdb(gdb_error))
77 } else {
78 Ok(Self::Result(ResultResponse { message, payload }))
79 }
80 }
81 }
82 }
83
84 fn _into_error(payload: Option<Dict>) -> Result<GdbError, Error> {
85 let mut payload = if let Some(payload) = payload {
86 payload
87 } else {
88 return Err(Error::ExpectedPayload);
89 };
90
91 let code = payload
92 .remove("code")
93 .map(Value::expect_string)
94 .transpose()?;
95 let msg = payload
96 .remove("msg")
97 .map(Value::expect_string)
98 .transpose()?;
99
100 Ok(GdbError { code, msg })
101 }
102}
103
104impl ResultResponse {
105 pub fn expect_payload(self) -> Result<Dict, Error> {
106 self.payload.ok_or(Error::ExpectedPayload)
107 }
108
109 pub fn expect_msg_is(&self, msg: &str) -> Result<(), Error> {
110 if self.message == msg {
111 Ok(())
112 } else {
113 Err(Error::UnexpectedResponseMessage {
114 expected: msg.to_owned(),
115 actual: self.message.clone(),
116 })
117 }
118 }
119}
120
121impl Dict {
122 #[must_use]
123 pub fn new(map: HashMap<String, Value>) -> Self {
124 Self(map)
125 }
126
127 #[must_use]
128 pub fn as_map(&self) -> &HashMap<String, Value> {
129 &self.0
130 }
131
132 pub fn as_map_mut(&mut self) -> &mut HashMap<String, Value> {
133 &mut self.0
134 }
135
136 pub fn remove_expect(&mut self, key: &str) -> Result<Value, Error> {
137 self.0.remove(key).map_or_else(
138 || {
139 warn!("Expected key {} to be present in {:?}", key, self);
140 Err(Error::ExpectedDifferentPayload)
141 },
142 Ok,
143 )
144 }
145
146 pub fn remove(&mut self, key: &str) -> Option<Value> {
147 self.0.remove(key)
148 }
149}
150
151impl Value {
152 pub(crate) fn into_appended(self, other: Self) -> Self {
153 let mut list = match self {
154 val @ Self::String(_) => vec![val],
155 Self::List(list) => list,
156 Self::Dict(_) => panic!(
157 "Attempted to workaround duplicate key bug, but can't combine dict with anything"
158 ),
159 };
160
161 let mut other = match other {
162 val @ Self::String(_) => vec![val],
163 Self::List(list) => list,
164 Self::Dict(_) => panic!(
165 "Attempted to workaround duplicate key bug, but can't combine anything with dict"
166 ),
167 };
168
169 for val in other.drain(..) {
170 list.push(val);
171 }
172
173 Self::List(list)
174 }
175
176 pub fn expect_string(self) -> Result<String, Error> {
177 if let Self::String(val) = self {
178 Ok(val)
179 } else {
180 error!("Expected string, got: {:?}", self);
181 Err(Error::ExpectedDifferentPayload)
182 }
183 }
184
185 pub fn expect_dict(self) -> Result<Dict, Error> {
186 if let Self::Dict(val) = self {
187 Ok(val)
188 } else {
189 error!("Expected dict, got: {:?}", self);
190 Err(Error::ExpectedDifferentPayload)
191 }
192 }
193
194 pub fn expect_list(self) -> Result<List, Error> {
195 if let Self::List(val) = self {
196 Ok(val)
197 } else {
198 error!("Expected dict, got: {:?}", self);
199 Err(Error::ExpectedDifferentPayload)
200 }
201 }
202
203 pub fn expect_number(self) -> Result<u32, Error> {
204 let val = if let Self::String(val) = self {
205 Ok(val)
206 } else {
207 error!("Expected dict, got: {:?}", self);
208 Err(Error::ExpectedDifferentPayload)
209 }?;
210
211 Ok(val.parse()?)
212 }
213
214 pub fn expect_path(self) -> Result<Utf8PathBuf, Error> {
215 let path = self.expect_string()?.into();
216 Ok(path)
217 }
218
219 pub fn expect_hex(self) -> Result<u64, Error> {
220 parse_hex(&self.expect_string()?)
221 }
222
223 pub fn expect_address(self) -> Result<Address, Error> {
224 self.expect_hex().map(Address)
225 }
226}
227
228pub fn parse_hex(s: &str) -> Result<u64, Error> {
229 if let Some(hex) = s.strip_prefix("0x") {
230 let num = u64::from_str_radix(hex, 16)?;
231 Ok(num)
232 } else {
233 Err(ParseHexError::InvalidPrefix.into())
234 }
235}