use bytes::Bytes;
use std::collections::HashMap;
#[derive(Debug, PartialEq, Eq)]
pub struct Response {
frames: Vec<Frame>,
error: Option<Error>,
}
#[derive(Debug, PartialEq, Eq)]
pub struct Frame {
pub values: Vec<(String, String)>,
pub binary: Option<Bytes>,
}
#[derive(Debug, Default, PartialEq, Eq)]
pub struct Error {
pub code: u64,
pub command_index: u64,
pub current_command: Option<String>,
pub message: String,
}
#[allow(clippy::len_without_is_empty)]
impl Response {
pub fn new(mut frames: Vec<Frame>, error: Option<Error>) -> Self {
assert!(
!frames.is_empty() || error.is_some(),
"attempted to construct an empty (no frames or error) response"
);
frames.reverse(); Self { frames, error }
}
pub fn empty() -> Self {
Self::new(vec![Frame::empty()], None)
}
pub fn is_error(&self) -> bool {
self.error.is_some()
}
pub fn is_success(&self) -> bool {
!self.is_error()
}
pub fn len(&self) -> usize {
self.frames.len()
}
pub fn next_frame(mut self) -> Result<(Frame, Option<Self>), Error> {
match self.frames.pop() {
Some(frame) => {
let remaining = if !self.frames.is_empty() || self.error.is_some() {
Some(self)
} else {
None
};
Ok((frame, remaining))
}
None => Err(self.error.unwrap()),
}
}
pub fn single_frame(self) -> Result<Frame, Error> {
self.next_frame().map(|(f, _)| f)
}
pub fn frames(self) -> impl Iterator<Item = Result<Frame, Error>> {
Frames(Some(self))
}
}
struct Frames(Option<Response>);
impl Iterator for Frames {
type Item = Result<Frame, Error>;
fn next(&mut self) -> Option<Self::Item> {
match self.0.take() {
None => None,
Some(r) => Some(match r.next_frame() {
Err(e) => Err(e),
Ok((value, remaining)) => {
self.0 = remaining;
Ok(value)
}
}),
}
}
}
impl Frame {
pub fn empty() -> Self {
Self {
values: Vec::new(),
binary: None,
}
}
pub fn values_as_map(&self) -> HashMap<&str, Vec<&str>> {
let mut map = HashMap::new();
for (k, v) in self.values.iter() {
map.entry(k.as_str())
.or_insert_with(Vec::new)
.push(v.as_str());
}
map
}
}