use std::io::{self, Write, Cursor, Read};
use std::fmt;
use thiserror::Error;
use super::packet::{Packet, PACKET_FLAGS_LEN, PACKET_MAX_BODY_LEN};
use super::element::reply::{Reply, ReplyHeader, REPLY_ID};
use super::element::{Element, TopElement};
use crate::util::io::*;
use crate::util::BytesFmt;
#[derive(Debug)]
pub struct Bundle {
packets: Vec<Box<Packet>>,
force_new_packet: bool,
available_len: usize,
last_request_header_offset: usize,
}
impl Bundle {
pub fn new() -> Bundle {
Self::with_multiple(vec![])
}
pub fn with_single(packet: Box<Packet>) -> Self {
Self::with_multiple(vec![packet])
}
pub fn with_multiple(packets: Vec<Box<Packet>>) -> Self {
Self {
available_len: packets.last().map(|p| p.content_available_len()).unwrap_or(0),
packets,
force_new_packet: true,
last_request_header_offset: 0,
}
}
pub fn element_reader(&self) -> BundleElementReader<'_> {
BundleElementReader::new(self)
}
pub fn element_writer(&mut self) -> BundleElementWriter<'_> {
BundleElementWriter::new(self)
}
#[inline]
pub fn len(&self) -> usize {
self.packets.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.packets.is_empty()
}
pub fn clear(&mut self) {
self.packets.clear();
self.force_new_packet = true;
self.available_len = 0;
self.last_request_header_offset = 0;
}
#[inline]
pub fn packets(&self) -> &[Box<Packet>] {
&self.packets[..]
}
#[inline]
pub fn packets_mut(&mut self) -> &mut [Box<Packet>] {
&mut self.packets[..]
}
fn add_packet(&mut self) {
let packet = Packet::new_boxed();
self.available_len = packet.content_available_len();
self.packets.push(packet);
self.last_request_header_offset = 0;
self.force_new_packet = false;
}
fn add_packet_if_forced(&mut self) {
if self.force_new_packet {
self.add_packet();
}
}
fn reserve_exact(&mut self, len: usize) -> &mut [u8] {
debug_assert!(len <= PACKET_MAX_BODY_LEN);
let new_packet = self.available_len < len;
if new_packet {
self.add_packet();
}
let packet = self.packets.last_mut().unwrap();
self.available_len -= len;
packet.grow(len)
}
fn reserve(&mut self, len: usize) -> &mut [u8] {
let new_packet = self.available_len == 0;
if new_packet {
self.add_packet();
}
let packet = self.packets.last_mut().unwrap();
let len = len.min(self.available_len);
self.available_len -= len;
packet.grow(len)
}
}
struct BundleWriter<'a> {
bundle: &'a mut Bundle,
}
impl<'a> BundleWriter<'a> {
fn new(bundle: &'a mut Bundle) -> Self {
Self { bundle }
}
}
impl<'a> Write for BundleWriter<'a> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let slice = self.bundle.reserve(buf.len());
slice.copy_from_slice(&buf[..slice.len()]);
Ok(slice.len())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
#[derive(Clone)]
struct BundleReader<'a> {
packets: &'a [Box<Packet>],
body: &'a [u8],
pos: usize,
}
impl<'a> BundleReader<'a> {
fn new(bundle: &'a Bundle) -> Self {
let packets = bundle.packets();
Self {
packets,
body: packets.get(0)
.map(|p| p.content())
.unwrap_or(&[]),
pos: 0,
}
}
fn packet(&self) -> Option<&'a Packet> {
self.packets.get(0).map(|b| &**b)
}
fn ensure(&mut self) -> bool {
while self.body.is_empty() {
if self.packets.is_empty() {
return false; } else {
self.packets = &self.packets[1..];
if let Some(p) = self.packets.get(0) {
self.body = p.content();
}
}
}
true
}
fn goto(&mut self, pos: usize) {
assert!(pos >= self.pos, "given pos is lower than current pos");
let mut remaining = pos - self.pos;
while remaining != 0 && self.ensure() {
let len = self.body.len().min(remaining);
self.pos += len;
remaining -= len;
}
}
}
impl<'a> Read for BundleReader<'a> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
if !self.ensure() {
return Ok(0);
}
let len = buf.len().min(self.body.len());
buf[..len].copy_from_slice(&self.body[..len]);
self.body = &self.body[len..];
self.pos += len;
Ok(len)
}
}
impl fmt::Debug for BundleReader<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BundleReader")
.field("packets", &self.packets)
.field("body", &format_args!("{:X}", BytesFmt(self.body)))
.field("pos", &self.pos)
.finish()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BundleElement<E> {
pub id: u8,
pub element: E,
pub request_id: Option<u32>
}
impl<E> BundleElement<E> {
pub fn map<U, F: FnOnce(E) -> U>(self, f: F) -> BundleElement<U> {
BundleElement {
id: self.id,
element: f(self.element),
request_id: self.request_id
}
}
}
impl<E: Element> From<BundleElement<Reply<E>>> for BundleElement<E> {
fn from(read: BundleElement<Reply<E>>) -> Self {
BundleElement {
id: REPLY_ID,
element: read.element.element,
request_id: read.request_id
}
}
}
pub struct BundleElementWriter<'a> {
bundle: &'a mut Bundle,
}
impl<'a> BundleElementWriter<'a> {
fn new(bundle: &'a mut Bundle) -> Self {
Self {
bundle,
}
}
#[inline]
pub fn write<E: TopElement>(&mut self, id: u8, element: E, config: &E::Config) {
self.write_raw(BundleElement { id, element, request_id: None }, config)
}
#[inline]
pub fn write_simple<E: TopElement<Config = ()>>(&mut self, id: u8, element: E) {
self.write(id, element, &())
}
#[inline]
pub fn write_request<E: TopElement>(&mut self, id: u8, element: E, config: &E::Config, request_id: u32) {
self.write_raw(BundleElement { id, element, request_id: Some(request_id) }, config)
}
#[inline]
pub fn write_simple_request<E: TopElement<Config = ()>>(&mut self, id: u8, element: E, request_id: u32) {
self.write_request(id, element, &(), request_id)
}
#[inline]
pub fn write_reply<E: Element>(&mut self, element: E, config: &E::Config, request_id: u32) {
self.write(REPLY_ID, Reply::new(request_id, element), config)
}
#[inline]
pub fn write_simple_reply<E: Element<Config = ()>>(&mut self, element: E, request_id: u32) {
self.write_reply(element, &(), request_id)
}
pub fn write_raw<E: TopElement>(&mut self, element: BundleElement<E>, config: &E::Config) {
self.bundle.add_packet_if_forced();
const REQUEST_HEADER_LEN: usize = 6;
let header_len = 1 + E::LEN.len() + if element.request_id.is_some() { REQUEST_HEADER_LEN } else { 0 };
let header_slice = self.bundle.reserve_exact(header_len);
header_slice[0] = element.id;
if let Some(request_id) = element.request_id {
let mut request_header_cursor = Cursor::new(&mut header_slice[header_len - 6..]);
request_header_cursor.write_u32(request_id).unwrap();
request_header_cursor.write_u16(0).unwrap(); }
let cur_packet_idx = self.bundle.packets.len() - 1;
let cur_packet = &mut self.bundle.packets[cur_packet_idx];
let cur_packet_len = cur_packet.content_len();
let cur_packet_elt_offset = cur_packet_len - header_len;
if element.request_id.is_some() {
if self.bundle.last_request_header_offset == 0 {
cur_packet.set_first_request_offset(PACKET_FLAGS_LEN + cur_packet_elt_offset);
} else {
Cursor::new(&mut cur_packet.content_mut()[self.bundle.last_request_header_offset + 4..])
.write_u16((PACKET_FLAGS_LEN + cur_packet_elt_offset) as u16).unwrap();
}
self.bundle.last_request_header_offset = cur_packet_len - REQUEST_HEADER_LEN;
}
let mut writer = IoCounter::new(BundleWriter::new(&mut *self.bundle));
element.element.encode(&mut writer, config).unwrap();
let length = writer.count() as u32;
let header_slice = &mut self.bundle.packets[cur_packet_idx].content_mut()[cur_packet_elt_offset..];
E::LEN.write(Cursor::new(&mut header_slice[1..]), length).unwrap();
}
}
pub struct BundleElementReader<'a> {
bundle_reader: BundleReader<'a>,
next_request_offset: usize
}
impl<'a> BundleElementReader<'a> {
fn new(bundle: &'a Bundle) -> Self {
let bundle_reader = BundleReader::new(bundle);
Self {
next_request_offset: bundle_reader.packet()
.map(|p| p.first_request_offset().unwrap_or(0))
.unwrap_or(0),
bundle_reader
}
}
pub fn is_request(&self) -> bool {
let data_pos = self.bundle_reader.pos + PACKET_FLAGS_LEN;
self.next_request_offset != 0 && data_pos == self.next_request_offset
}
pub fn next_id(&self) -> Option<u8> {
self.bundle_reader.body.get(0).copied()
}
pub fn next_element(&mut self) -> Option<ElementReader<'_, 'a>> {
match self.next_id() {
Some(REPLY_ID) => {
match self.read_element::<ReplyHeader>(&(), false) {
Ok(elt) => {
debug_assert!(elt.request_id.is_none(), "Replies should not be request at the same time.");
Some(ElementReader::Reply(ReplyElementReader(self, elt.element.request_id)))
}
Err(_) => None
}
}
Some(id) => {
Some(ElementReader::Top(TopElementReader(self, id)))
}
None => None
}
}
pub fn read_element<E>(&mut self, config: &E::Config, next: bool) -> BundleResult<BundleElement<E>>
where
E: TopElement
{
let request = self.is_request();
let header_len = E::LEN.len() + 1 + if request { 6 } else { 0 };
if self.bundle_reader.body.len() < header_len {
return Err(BundleError::TooShort)
}
let reader_save = self.bundle_reader.clone();
match self.read_element_internal::<E>(config, next, request) {
Ok(elt) if next => Ok(elt),
Ok(elt) => {
self.bundle_reader.clone_from(&reader_save);
Ok(elt)
}
Err(e) => {
self.bundle_reader.clone_from(&reader_save);
Err(BundleError::Io(e))
}
}
}
#[inline(always)]
fn read_element_internal<E>(&mut self, config: &E::Config, next: bool, request: bool) -> io::Result<BundleElement<E>>
where
E: TopElement
{
let start_packet = self.bundle_reader.packet().unwrap();
let elt_id = self.bundle_reader.read_u8()?;
let elt_len = E::LEN.read(&mut self.bundle_reader, elt_id)?;
let reply_id = if request {
let reply_id = self.bundle_reader.read_u32()?;
self.next_request_offset = self.bundle_reader.read_u16()? as usize;
Some(reply_id)
} else {
None
};
let elt_data_begin = self.bundle_reader.pos;
let mut elt_reader = Read::take(&mut self.bundle_reader, elt_len as u64);
let element = E::decode(&mut elt_reader, elt_len as usize, config)?;
if next {
self.bundle_reader.goto(elt_data_begin + elt_len as usize);
match self.bundle_reader.packet() {
Some(end_packet) => {
if !std::ptr::eq(start_packet, end_packet) {
self.next_request_offset = end_packet.first_request_offset().unwrap_or(0);
}
}
None => self.next_request_offset = 0
}
}
Ok(BundleElement {
id: elt_id,
element,
request_id: reply_id
})
}
}
impl fmt::Debug for BundleElementReader<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("BundleElementReader")
.field("bundle_reader", &self.bundle_reader)
.field("next_request_offset", &self.next_request_offset)
.field("next_id()", &self.next_id())
.field("is_request()", &self.is_request())
.finish()
}
}
#[derive(Debug)]
pub enum ElementReader<'reader, 'bundle> {
Top(TopElementReader<'reader, 'bundle>),
Reply(ReplyElementReader<'reader, 'bundle>)
}
impl ElementReader<'_, '_> {
pub fn is_simple(&self) -> bool {
matches!(self, ElementReader::Top(_))
}
pub fn is_reply(&self) -> bool {
matches!(self, ElementReader::Reply(_))
}
}
#[derive(Debug)]
pub struct TopElementReader<'reader, 'bundle>(&'reader mut BundleElementReader<'bundle>, u8);
impl TopElementReader<'_, '_> {
#[inline]
pub fn id(&self) -> u8 {
self.1
}
pub fn read_stable<E: TopElement>(&mut self, config: &E::Config) -> BundleResult<BundleElement<E>> {
self.0.read_element(config, false)
}
#[inline]
pub fn read_simple_stable<E: TopElement<Config = ()>>(&mut self) -> BundleResult<BundleElement<E>> {
self.read_stable::<E>(&())
}
pub fn read<E: TopElement>(self, config: &E::Config) -> BundleResult<BundleElement<E>> {
self.0.read_element(config, true)
}
#[inline]
pub fn read_simple<E: TopElement<Config = ()>>(self) -> BundleResult<BundleElement<E>> {
self.read::<E>(&())
}
}
#[derive(Debug)]
pub struct ReplyElementReader<'reader, 'bundle>(&'reader mut BundleElementReader<'bundle>, u32);
impl<'reader, 'bundle> ReplyElementReader<'reader, 'bundle> {
#[inline]
pub fn request_id(&self) -> u32 {
self.1
}
pub fn read_stable<E: Element>(&mut self, config: &E::Config) -> BundleResult<BundleElement<E>> {
self.0.read_element::<Reply<E>>(config, false).map(Into::into)
}
#[inline]
pub fn read_simple_stable<E: Element<Config = ()>>(&mut self) -> BundleResult<BundleElement<E>> {
self.read_stable::<E>(&())
}
pub fn read<E: Element>(self, config: &E::Config) -> BundleResult<BundleElement<E>> {
self.0.read_element::<Reply<E>>(config, true).map(Into::into)
}
#[inline]
pub fn read_simple<E: Element<Config = ()>>(self) -> BundleResult<BundleElement<E>> {
self.read::<E>(&())
}
}
#[derive(Debug, Error)]
pub enum BundleError {
#[error("bundle is too short for reading element")]
TooShort,
#[error("io error: {0}")]
Io(#[from] io::Error),
}
pub type BundleResult<T> = Result<T, BundleError>;