use crate::ascii::{
packet::Packet,
response::{AnyResponse, Response as _},
};
use crate::error::AsciiUnexpectedPacketError;
#[derive(Debug)]
pub(crate) struct Item {
packet: Option<Packet>,
response: AnyResponse,
}
impl Item {
fn response(&self) -> &AnyResponse {
&self.response
}
fn response_mut(&mut self) -> &mut AnyResponse {
&mut self.response
}
fn is_complete(&self) -> bool {
self.packet.is_none()
}
fn make_complete(&mut self) {
self.packet = None;
}
fn try_into_complete_response(self) -> Result<AnyResponse, Self> {
if self.packet.is_none() {
Ok(self.response)
} else {
Err(self)
}
}
fn try_into_packet(self) -> Result<Packet, Self> {
if let Some(packet) = self.packet {
Ok(packet)
} else {
Err(self)
}
}
}
#[derive(Debug, Default)]
pub(crate) struct ResponseBuilder {
items: Vec<Item>,
}
impl ResponseBuilder {
pub fn clear(&mut self) {
self.items.clear();
}
pub fn push(&mut self, packet: Packet) -> Result<(), AsciiUnexpectedPacketError> {
use super::private::DataMut as _;
if packet.cont() {
let mut found = false;
for item in &mut self.items {
if !item.is_complete()
&& item.response().target() == packet.target()
&& item.response().id() == packet.id()
{
let cont_data = packet.data();
if !cont_data.is_empty() {
if !item.response().data().is_empty() {
item.response_mut().data_mut().push(' ');
}
item.response_mut().data_mut().push_str(cont_data);
}
if !packet.more_packets() {
item.make_complete();
}
found = true;
break;
}
}
if !found {
return Err(AsciiUnexpectedPacketError::new(packet));
}
} else {
let Ok(response) = AnyResponse::try_from_packet(&packet) else {
return Err(AsciiUnexpectedPacketError::new(packet));
};
self.items.push(Item {
packet: if packet.more_packets() {
Some(packet)
} else {
None
},
response,
});
}
Ok(())
}
pub fn get_complete_response(&mut self) -> Option<AnyResponse> {
let has_response = self.items.first().is_some_and(Item::is_complete);
if has_response {
Some(self.items.remove(0).try_into_complete_response().unwrap())
} else {
None
}
}
pub fn get_incomplete_response_packet(&mut self) -> Option<Packet> {
let has_packet = self.items.first().is_some_and(|item| !item.is_complete());
if has_packet {
Some(self.items.remove(0).try_into_packet().unwrap())
} else {
None
}
}
}