root_io/tree_reader/container.rs
1use failure::Error;
2use nom::combinator::rest;
3use nom::number::complete::*;
4use nom::*;
5
6use crate::core::*;
7
8#[derive(Debug, Clone)]
9pub(crate) enum Container {
10 /// Decompressed content of a `TBasket`
11 InMemory(Vec<u8>),
12 /// Filename, start byte, and len of a `TBasket` on disk
13 OnDisk(Source, u64, u64),
14}
15
16impl Container {
17 /// Return the number of entries and the data; reading it from disk if necessary
18 pub(crate) async fn raw_data(self) -> Result<(u32, Vec<u8>), Error> {
19 let buf = match self {
20 Container::InMemory(buf) => buf,
21 Container::OnDisk(source, seek, len) => source.fetch(seek, len).await?,
22 };
23 match tbasket2vec(buf.as_slice()) {
24 Ok((_, v)) => Ok(v),
25 _ => Err(format_err!("tbasket2vec parser failed")),
26 }
27 }
28 // /// For debugging: Try to find the file of this container. Out of luck if the container was inlined
29 // pub(crate) fn file(&self) -> Option<PathBuf> {
30 // match *self {
31 // // No file name available
32 // Container::InMemory(_) => None,
33 // Container::OnDisk(ref p, _, _) => Some(p.to_owned())
34 // }
35 // }
36}
37
38/// Return a tuple indicating the number of elements in this basket
39/// and the content as a Vec<u8>
40#[rustfmt::skip::macros(do_parse)]
41fn tbasket2vec(input: &[u8]) -> IResult<&[u8], (u32, Vec<u8>)> {
42 do_parse!(input,
43 hdr: tkey_header >>
44 _ver: be_u16 >>
45 _buf_size: be_u32 >>
46 _entry_size: be_u32 >>
47 n_entry_buf: be_u32 >>
48 last: be_u32 >>
49 _flag: be_i8 >>
50 buf: rest >>
51 ({
52 let buf = if hdr.uncomp_len as usize > buf.len() {
53 decompress(buf).unwrap().1
54 } else {
55 buf.to_vec()
56 };
57 // Not the whole buffer is filled, no, no, no, that
58 // would be to easy! Its only filled up to `last`,
59 // whereby we have to take the key_len into account...
60 let useful_bytes = (last - hdr.key_len as u32) as usize;
61 (n_entry_buf, buf.as_slice()[..useful_bytes].to_vec())
62 }))
63}
64
65#[cfg(test)]
66mod tests {
67 use crate::core::tkey_header;
68 use nom::*;
69 use std::fs::File;
70 use std::io::{BufReader, Read, Seek, SeekFrom};
71
72 use super::tbasket2vec;
73
74 #[test]
75 fn basket_simple() {
76 let path = "./src/test_data/simple.root";
77 let f = File::open(&path).unwrap();
78 let mut reader = BufReader::new(f);
79 // Go to first basket
80 reader.seek(SeekFrom::Start(218)).unwrap();
81 // size from fbasketbytes
82 let mut buf = vec![0; 86];
83 // let mut buf = vec![0; 386];
84 reader.read_exact(&mut buf).unwrap();
85
86 println!("{}", buf.to_hex(16));
87 println!("{:?}", tkey_header(&buf));
88 // println!("{:#?}", tbasket(&buf, be_u32));
89 println!("{:#?}", tbasket2vec(&buf));
90 }
91
92 // /// Test the first basket of the "Tracks.fP[5]" branch
93 // #[test]
94 // fn basket_esd() {
95 // // This test is broken since the numbers were hardcoded for a specific file
96 // use alice_open_data;
97 // let path = alice_open_data::test_file().unwrap();
98
99 // let f = File::open(&path).unwrap();
100 // let mut reader = BufReader::new(f);
101 // // Go to first basket
102 // reader.seek(SeekFrom::Start(77881)).unwrap();
103 // // size from fbasketbytes
104 // let mut buf = vec![0; 87125];
105 // reader.read_exact(&mut buf).unwrap();
106
107 // println!("{:?}", tkey_header(&buf).unwrap().1);
108 // // println!("{:#?}", tbasket(&buf, |i| count!(i, be_f32, 15)).unwrap().1);
109 // println!("{:#?}", tbasket2vec(&buf));
110 // }
111}