pub mod chunks;
mod compat;
mod error;
mod parser;
mod ser;
pub use bufread::{ThBufRead, ThBufReader};
pub use chunks::Chunk;
pub use compat::{ThCompat, ThStream};
pub use error::{Error, ErrorKind};
pub use ser::ThWriter;
pub use ser::serialize_into;
mod bufread;
use crate::parser::cstring;
use uuid::Uuid;
#[derive(Debug)]
pub struct Th<T: ThBufRead> {
buf: T,
parsed_header: bool,
parsed_chunk: bool,
num_consume: usize,
}
impl<T: ThBufRead> Th<T> {
pub fn parse(inp: T) -> Result<Self, crate::error::Error> {
let mut inp = inp;
if inp.fill_buf()? == 0 && inp.get_buf().is_empty() {
return Err(crate::error::ErrorKind::NotTeehistorian(None).into());
}
loop {
let buf = inp.get_buf();
if buf.len() >= 16 {
let (input, uuid) = parser::uuid(buf).unwrap();
if uuid != Uuid::from_u128(0x699db17b_8efb_34ff_b1d8_da6f60c15dd1) {
return Err(ErrorKind::NotTeehistorian(Some(uuid)).into());
}
let num_consumed = unsafe { input.as_ptr().offset_from(buf.as_ptr()) };
inp.consume(num_consumed as usize);
break;
}
if inp.fill_buf()? == 0 {
return Err(crate::error::ErrorKind::NotTeehistorian(None).into());
}
}
Ok(Th {
buf: inp,
parsed_header: false,
parsed_chunk: false,
num_consume: 0,
})
}
pub fn header(&mut self) -> Result<&[u8], crate::error::Error> {
if self.parsed_chunk {
panic!("Teehistorian library misuse. Accessing the header is only allowed before accessing the first chunk");
}
self.parsed_header = true;
loop {
let buf = self.buf.get_buf();
let buf = unsafe { std::slice::from_raw_parts(buf.as_ptr(), buf.len()) };
match cstring(buf) {
Ok((new_input, header)) => {
self.num_consume =
unsafe { new_input.as_ptr().offset_from(buf.as_ptr()) } as usize;
return Ok(header);
}
Err(nom::Err::Error(err)) | Err(nom::Err::Failure(err)) => {
self.num_consume = 0;
return Err(err.into());
}
Err(nom::Err::Incomplete(_)) => {
if self.buf.fill_buf()? == 0 {
return Err(crate::error::Error::Eof);
}
}
}
}
}
pub fn next_chunk(&mut self) -> Result<chunks::Chunk, crate::error::Error> {
if !self.parsed_header {
self.header()?;
}
self.parsed_chunk = true;
if self.num_consume != 0 {
self.buf.consume(self.num_consume);
self.num_consume = 0;
}
loop {
let buf = self.buf.get_buf();
let buf = unsafe { std::slice::from_raw_parts(buf.as_ptr(), buf.len()) };
match chunks::chunk(buf) {
Ok((new_input, chunk)) => {
self.num_consume =
unsafe { new_input.as_ptr().offset_from(buf.as_ptr()) } as usize;
return Ok(chunk);
}
Err(nom::Err::Error(err)) | Err(nom::Err::Failure(err)) => {
self.num_consume = 0;
return Err(err.into());
}
Err(nom::Err::Incomplete(_)) => {
if self.buf.fill_buf()? == 0 {
return Err(crate::error::Error::Eof);
}
}
}
}
}
pub fn reset_chunk(&mut self) {
assert!(self.num_consume > 0);
self.num_consume = 0;
}
pub fn reuse_buffer(self) -> T {
self.buf
}
}