root_io/tree_reader/
tree.rs

1use std::fmt;
2use std::fmt::Debug;
3use std::ops::Deref;
4
5use failure::Error;
6use nom::{
7    combinator::{cond, verify},
8    error::ParseError,
9    multi::{count, length_value},
10    number::complete::*,
11    sequence::preceded,
12    IResult,
13};
14
15use crate::{
16    core::parsers::*, core::types::*, tree_reader::branch::tbranch_hdr,
17    tree_reader::branch::TBranch, tree_reader::leafs::TLeaf,
18};
19
20/// `TTree` potentially has members with very large `Vec<u8>` buffers
21/// The `Pointer` type is used to overwrite the default `Debug` trait
22/// for those members
23struct Pointer(pub Vec<u8>);
24
25impl Deref for Pointer {
26    type Target = Vec<u8>;
27    fn deref(&self) -> &Vec<u8> {
28        &self.0
29    }
30}
31
32impl fmt::Debug for Pointer {
33    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
34        writeln!(f, "Buffer of {} bytes ", self.len())
35    }
36}
37
38/// A `Tree` is the default "container" for datasets in Root files The
39/// data is oranized in so-called branches. This type is exposed only
40/// for the purpose of creating `ColumnFixedIntoIter` and
41/// `ColumnVarIntoIter` objects from it.
42#[derive(Debug)]
43pub struct Tree {
44    /// Version of the read layout
45    ver: u16,
46    /// The basis for a named object (name, title)
47    tnamed: TNamed,
48    /// Number of entries
49    fentries: i64,
50    /// Total number of bytes in all branches before compression
51    ftotbytes: i64,
52    /// Total number of bytes in all branches after compression
53    fzipbytes: i64,
54    /// Number of autosaved bytes
55    fsavedbytes: i64,
56    /// Number of autoflushed bytes
57    fflushedbytes: Option<i64>,
58    /// Tree weight (see TTree::SetWeight)
59    fweight: f64,
60    /// Timer interval in milliseconds
61    ftimerinterval: i32,
62    /// Number of runs before prompting in Scan
63    fscanfield: i32,
64    /// Update frequency for EntryLoop
65    fupdate: i32,
66    /// Maximum number of entries in case of circular buffers
67    fmaxentries: i64,
68    /// Maximum number of entries to process
69    fmaxentryloop: i64,
70    /// Number of entries to estimate histogram limits
71    festimate: i64,
72    /// List of Branches
73    pub(crate) fbranches: Vec<TBranch>,
74    /// Direct pointers to individual branch leaves
75    pub(crate) fleaves: Vec<TLeaf>,
76    /// List of aliases for expressions based on the tree branches.
77    faliases: Option<Vec<u8>>,
78    /// Sorted index values
79    findexvalues: Vec<f64>,
80    /// Index of sorted values
81    findex: Vec<i32>,
82    /// Pointer to the tree Index (if any)
83    ftreeindex: Option<Pointer>,
84    /// pointer to list of friend elements
85    ffriends: Option<Pointer>,
86    /// pointer to a list of user objects associated to this Tree
87    fuserinfo: Option<Pointer>,
88    /// Branch supporting the TRefTable (if any)
89    fbranchref: Option<Pointer>,
90}
91
92impl<'s> Tree {
93    /// Get all branches of a tree (including nested ones)
94    pub(crate) fn branches(&self) -> Vec<&TBranch> {
95        self.fbranches
96            .iter()
97            .flat_map(|b| vec![b].into_iter().chain(b.branches().into_iter()))
98            .collect()
99    }
100    /// Get all the branch names and types (including nested ones) of this tree
101    /// The first element is the name, the second one is the type
102    pub fn branch_names_and_types(&self) -> Vec<(String, Vec<String>)> {
103        self.fbranches
104            .iter()
105            .flat_map(|b| vec![b].into_iter().chain(b.branches().into_iter()))
106            .map(|b| (b.name(), b.element_types()))
107            .collect()
108    }
109
110    pub fn branch_by_name(&self, name: &str) -> Result<&TBranch, Error> {
111        self.branches()
112            .into_iter()
113            .find(|b| b.name == name)
114            .ok_or_else(|| {
115                format_err!(
116                    "Branch {} not found in tree: \n {:#?}",
117                    name,
118                    self.branches()
119                        .iter()
120                        .map(|b| b.name.to_owned())
121                        .collect::<Vec<_>>()
122                )
123            })
124    }
125}
126
127/// Parse a `Tree` from the given buffer. Usually used through `FileItem::parse_with`.
128#[allow(clippy::unnecessary_unwrap)]
129pub fn ttree<'s, E>(i: &'s [u8], context: &'s Context) -> IResult<&'s [u8], Tree, E>
130where
131    E: ParseError<&'s [u8]> + Debug,
132{
133    let _curried_raw = |i| raw(i, context);
134    let none_or_u8_buf = |i: &'s [u8]| {
135        switch!(i, peek!(be_u32),
136                0 => map!(call!(be_u32), | _ | None) |
137                _ => map!(
138                    map!(call!(_curried_raw), |r| r.obj.to_vec()),
139                    Some)
140        )
141    };
142    let grab_checked_byte_count = |i| length_data!(i, checked_byte_count);
143    let (i, ver) = verify(be_u16, |v| [16, 17, 18, 19].contains(v))(i)?;
144    let (i, tnamed) = length_value(checked_byte_count, tnamed)(i)?;
145    let (i, _tattline) = grab_checked_byte_count(i)?;
146    let (i, _tattfill) = grab_checked_byte_count(i)?;
147    let (i, _tattmarker) = grab_checked_byte_count(i)?;
148    let (i, fentries) = be_i64(i)?;
149    let (i, ftotbytes) = be_i64(i)?;
150    let (i, fzipbytes) = be_i64(i)?;
151    let (i, fsavedbytes) = be_i64(i)?;
152    let (i, fflushedbytes) = cond(ver >= 18, be_i64)(i)?;
153    let (i, fweight) = be_f64(i)?;
154    let (i, ftimerinterval) = be_i32(i)?;
155    let (i, fscanfield) = be_i32(i)?;
156    let (i, fupdate) = be_i32(i)?;
157    let (i, _fdefaultentryoffsetlen) = cond(ver >= 17, be_i32)(i)?;
158    let (i, fnclusterrange) = cond(ver >= 19, be_i32)(i)?;
159    let (i, fmaxentries) = be_i64(i)?;
160    let (i, fmaxentryloop) = be_i64(i)?;
161    let (i, _fmaxvirtualsize) = be_i64(i)?;
162    let (i, _fautosave) = be_i64(i)?;
163    let (i, _fautoflush) = cond(ver >= 18, be_i64)(i)?;
164    let (i, festimate) = be_i64(i)?;
165    let (i, _fclusterrangeend) = {
166        if let Some(n_clst_range) = fnclusterrange {
167            preceded(be_u8, count(be_i64, n_clst_range as usize))(i)
168                .map(|(i, ends)| (i, Some(ends)))?
169        } else {
170            (i, None)
171        }
172    };
173    let (i, _fclustersize) = {
174        if let Some(n_clst_range) = fnclusterrange {
175            preceded(be_u8, count(be_i64, n_clst_range as usize))(i)
176                .map(|(i, ends)| (i, Some(ends)))?
177        } else {
178            (i, None)
179        }
180    };
181    let (i, fbranches) =
182        length_value(checked_byte_count, |i| tobjarray(tbranch_hdr, i, context))(i)?;
183    let (i, fleaves) = length_value(checked_byte_count, |i| {
184        tobjarray(TLeaf::parse_from_raw, i, context)
185    })(i)?;
186
187    let (i, faliases) = none_or_u8_buf(i)?;
188    let (i, findexvalues) = tarray(be_f64, i)?;
189    let (i, findex) = tarray(be_i32, i)?;
190    let (i, ftreeindex) = none_or_u8_buf(i)?;
191    let (i, ffriends) = none_or_u8_buf(i)?;
192    let (i, fuserinfo) = none_or_u8_buf(i)?;
193    let (i, fbranchref) = none_or_u8_buf(i)?;
194    let ftreeindex = ftreeindex.map(Pointer);
195    let ffriends = ffriends.map(Pointer);
196    let fuserinfo = fuserinfo.map(Pointer);
197    let fbranchref = fbranchref.map(Pointer);
198    Ok((
199        i,
200        Tree {
201            ver,
202            tnamed,
203            fentries,
204            ftotbytes,
205            fzipbytes,
206            fsavedbytes,
207            fflushedbytes,
208            fweight,
209            ftimerinterval,
210            fscanfield,
211            fupdate,
212            fmaxentries,
213            fmaxentryloop,
214            festimate,
215            fbranches,
216            fleaves,
217            faliases,
218            findexvalues,
219            findex,
220            ftreeindex,
221            ffriends,
222            fuserinfo,
223            fbranchref,
224        },
225    ))
226}