use std::fmt;
use std::fmt::Debug;
use std::ops::Deref;
use failure::Error;
use nom::{
combinator::{cond, verify},
error::ParseError,
multi::{count, length_value},
number::complete::*,
sequence::preceded,
IResult,
};
use crate::{
core::parsers::*, core::types::*, tree_reader::branch::tbranch_hdr,
tree_reader::branch::TBranch, tree_reader::leafs::TLeaf,
};
struct Pointer(pub Vec<u8>);
impl Deref for Pointer {
type Target = Vec<u8>;
fn deref(&self) -> &Vec<u8> {
&self.0
}
}
impl fmt::Debug for Pointer {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "Buffer of {} bytes ", self.len())
}
}
#[derive(Debug)]
pub struct Tree {
ver: u16,
tnamed: TNamed,
fentries: i64,
ftotbytes: i64,
fzipbytes: i64,
fsavedbytes: i64,
fflushedbytes: Option<i64>,
fweight: f64,
ftimerinterval: i32,
fscanfield: i32,
fupdate: i32,
fmaxentries: i64,
fmaxentryloop: i64,
festimate: i64,
pub(crate) fbranches: Vec<TBranch>,
pub(crate) fleaves: Vec<TLeaf>,
faliases: Option<Vec<u8>>,
findexvalues: Vec<f64>,
findex: Vec<i32>,
ftreeindex: Option<Pointer>,
ffriends: Option<Pointer>,
fuserinfo: Option<Pointer>,
fbranchref: Option<Pointer>,
}
impl<'s> Tree {
pub(crate) fn branches(&self) -> Vec<&TBranch> {
self.fbranches
.iter()
.flat_map(|b| vec![b].into_iter().chain(b.branches().into_iter()))
.collect()
}
pub fn branch_names_and_types(&self) -> Vec<(String, Vec<String>)> {
self.fbranches
.iter()
.flat_map(|b| vec![b].into_iter().chain(b.branches().into_iter()))
.map(|b| (b.name(), b.element_types()))
.collect()
}
pub fn branch_by_name(&self, name: &str) -> Result<&TBranch, Error> {
self.branches()
.into_iter()
.find(|b| b.name == name)
.ok_or_else(|| {
format_err!(
"Branch {} not found in tree: \n {:#?}",
name,
self.branches()
.iter()
.map(|b| b.name.to_owned())
.collect::<Vec<_>>()
)
})
}
}
#[allow(clippy::unnecessary_unwrap)]
pub fn ttree<'s, E>(i: &'s [u8], context: &'s Context) -> IResult<&'s [u8], Tree, E>
where
E: ParseError<&'s [u8]> + Debug,
{
let _curried_raw = |i| raw(i, context);
let none_or_u8_buf = |i: &'s [u8]| {
switch!(i, peek!(be_u32),
0 => map!(call!(be_u32), | _ | None) |
_ => map!(
map!(call!(_curried_raw), |r| r.obj.to_vec()),
Some)
)
};
let grab_checked_byte_count = |i| length_data!(i, checked_byte_count);
let (i, ver) = verify(be_u16, |v| [16, 17, 18, 19].contains(v))(i)?;
let (i, tnamed) = length_value(checked_byte_count, tnamed)(i)?;
let (i, _tattline) = grab_checked_byte_count(i)?;
let (i, _tattfill) = grab_checked_byte_count(i)?;
let (i, _tattmarker) = grab_checked_byte_count(i)?;
let (i, fentries) = be_i64(i)?;
let (i, ftotbytes) = be_i64(i)?;
let (i, fzipbytes) = be_i64(i)?;
let (i, fsavedbytes) = be_i64(i)?;
let (i, fflushedbytes) = cond(ver >= 18, be_i64)(i)?;
let (i, fweight) = be_f64(i)?;
let (i, ftimerinterval) = be_i32(i)?;
let (i, fscanfield) = be_i32(i)?;
let (i, fupdate) = be_i32(i)?;
let (i, _fdefaultentryoffsetlen) = cond(ver >= 17, be_i32)(i)?;
let (i, fnclusterrange) = cond(ver >= 19, be_i32)(i)?;
let (i, fmaxentries) = be_i64(i)?;
let (i, fmaxentryloop) = be_i64(i)?;
let (i, _fmaxvirtualsize) = be_i64(i)?;
let (i, _fautosave) = be_i64(i)?;
let (i, _fautoflush) = cond(ver >= 18, be_i64)(i)?;
let (i, festimate) = be_i64(i)?;
let (i, _fclusterrangeend) = {
if let Some(n_clst_range) = fnclusterrange {
preceded(be_u8, count(be_i64, n_clst_range as usize))(i)
.map(|(i, ends)| (i, Some(ends)))?
} else {
(i, None)
}
};
let (i, _fclustersize) = {
if let Some(n_clst_range) = fnclusterrange {
preceded(be_u8, count(be_i64, n_clst_range as usize))(i)
.map(|(i, ends)| (i, Some(ends)))?
} else {
(i, None)
}
};
let (i, fbranches) =
length_value(checked_byte_count, |i| tobjarray(tbranch_hdr, i, context))(i)?;
let (i, fleaves) = length_value(checked_byte_count, |i| {
tobjarray(TLeaf::parse_from_raw, i, context)
})(i)?;
let (i, faliases) = none_or_u8_buf(i)?;
let (i, findexvalues) = tarray(be_f64, i)?;
let (i, findex) = tarray(be_i32, i)?;
let (i, ftreeindex) = none_or_u8_buf(i)?;
let (i, ffriends) = none_or_u8_buf(i)?;
let (i, fuserinfo) = none_or_u8_buf(i)?;
let (i, fbranchref) = none_or_u8_buf(i)?;
let ftreeindex = ftreeindex.map(Pointer);
let ffriends = ffriends.map(Pointer);
let fuserinfo = fuserinfo.map(Pointer);
let fbranchref = fbranchref.map(Pointer);
Ok((
i,
Tree {
ver,
tnamed,
fentries,
ftotbytes,
fzipbytes,
fsavedbytes,
fflushedbytes,
fweight,
ftimerinterval,
fscanfield,
fupdate,
fmaxentries,
fmaxentryloop,
festimate,
fbranches,
fleaves,
faliases,
findexvalues,
findex,
ftreeindex,
ffriends,
fuserinfo,
fbranchref,
},
))
}