#![doc = include_str!("../README.md")]
pub mod de;
mod error;
pub mod lexer;
pub mod parser;
pub(crate) mod unescape;
pub use self::error::Error;
use serde::de::DeserializeOwned;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Response<T: DeserializeOwned, Tkn: DeserializeOwned = u64> {
pub token: Option<Tkn>,
pub body: ResponseBody<T>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ResponseBody<T: DeserializeOwned> {
Result(T),
AsyncExec(T),
AsyncEnvironment(T),
AsyncStatus(T),
Console(String),
TargetOutput(String),
InternalLogging(String),
Prompt,
}
impl<T: DeserializeOwned> ResponseBody<T> {
pub fn simple(&self) -> Option<SimpleResponseBodyRef<'_, T>> {
match self {
Self::Result(v)
| Self::AsyncExec(v)
| Self::AsyncEnvironment(v)
| Self::AsyncStatus(v) => Some(SimpleResponseBodyRef::Data(v)),
Self::Console(s) | Self::TargetOutput(s) | Self::InternalLogging(s) => {
Some(SimpleResponseBodyRef::Stream(s))
}
Self::Prompt => None,
}
}
pub fn into_simple(self) -> Option<SimpleResponseBody<T>> {
match self {
Self::Result(v)
| Self::AsyncExec(v)
| Self::AsyncEnvironment(v)
| Self::AsyncStatus(v) => Some(SimpleResponseBody::Data(v)),
Self::Console(s) | Self::TargetOutput(s) | Self::InternalLogging(s) => {
Some(SimpleResponseBody::Stream(s))
}
Self::Prompt => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SimpleResponseBodyRef<'a, T: DeserializeOwned> {
Data(&'a T),
Stream(&'a String),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SimpleResponseBody<T: DeserializeOwned> {
Data(T),
Stream(String),
}
pub fn from_str<T: DeserializeOwned>(line: &str) -> Result<Response<T>, Error> {
from_str_with_token(line)
}
fn from_str_with_token<T: DeserializeOwned, Tkn: DeserializeOwned>(
line: &str,
) -> Result<Response<T, Tkn>, Error> {
if line.trim() == "(gdb)" {
return Ok(Response {
token: None,
body: ResponseBody::Prompt,
});
}
let parsed = parser::Response::try_from(line)?;
let token = if let Some(ref token_str) = parsed.token {
let deserializer = de::TokenDeserializer::from_str(token_str);
Some(Tkn::deserialize(deserializer)?)
} else {
None
};
let body = match &parsed.body {
parser::ResponseBody::Stream(stream) => {
use parser::StreamSymbol;
match stream.symbol {
StreamSymbol::Console => ResponseBody::Console(stream.text.clone()),
StreamSymbol::TargetOutput => ResponseBody::TargetOutput(stream.text.clone()),
StreamSymbol::InternalLogging => ResponseBody::InternalLogging(stream.text.clone()),
}
}
parser::ResponseBody::Data(data) => {
let data_de = de::DataDeserializer::from_data(&data.class, &data.variables);
let inner = T::deserialize(data_de)?;
use parser::DataSymbol;
match data.symbol {
DataSymbol::Result => ResponseBody::Result(inner),
DataSymbol::AsyncExec => ResponseBody::AsyncExec(inner),
DataSymbol::AsyncEnvironment => ResponseBody::AsyncEnvironment(inner),
DataSymbol::AsyncStatus => ResponseBody::AsyncStatus(inner),
}
}
};
Ok(Response { token, body })
}