root_io/core/
file_item.rs

1use failure::Error;
2use nom::{error::VerboseError, multi::length_value};
3
4use crate::core::{checked_byte_count, decompress, Context, Source, TKeyHeader};
5use crate::tree_reader::{ttree, Tree};
6
7/// Describes a single item within this file (e.g. a `Tree`)
8#[derive(Debug)]
9pub struct FileItem {
10    source: Source,
11    tkey_hdr: TKeyHeader,
12}
13
14impl FileItem {
15    /// New file item from the information in a TKeyHeader and the associated file
16    pub(crate) fn new(tkey_hdr: &TKeyHeader, source: Source) -> FileItem {
17        FileItem {
18            source,
19            tkey_hdr: tkey_hdr.to_owned(),
20        }
21    }
22
23    /// Information about this file item in Human readable form
24    pub fn verbose_info(&self) -> String {
25        format!("{:#?}", self.tkey_hdr)
26    }
27    pub fn name(&self) -> String {
28        format!(
29            "`{}` of type `{}`",
30            self.tkey_hdr.obj_name, self.tkey_hdr.class_name
31        )
32    }
33
34    async fn get_buffer(&self) -> Result<Vec<u8>, Error> {
35        let start = self.tkey_hdr.seek_key + self.tkey_hdr.key_len as u64;
36        let len = self.tkey_hdr.total_size - self.tkey_hdr.key_len as u32;
37        let comp_buf = self.source.fetch(start, len as u64).await?;
38
39        let buf = if self.tkey_hdr.total_size < self.tkey_hdr.uncomp_len {
40            // Decompress the read buffer; buf is Vec<u8>
41            let (_, buf) = decompress(comp_buf.as_slice()).unwrap();
42            buf
43        } else {
44            comp_buf
45        };
46        Ok(buf)
47    }
48
49    pub(crate) async fn get_context<'s>(&self) -> Result<Context, Error> {
50        let buffer = self.get_buffer().await?;
51        let k_map_offset = 2;
52        Ok(Context {
53            source: self.source.clone(),
54            offset: (self.tkey_hdr.key_len + k_map_offset) as u64,
55            s: buffer,
56        })
57    }
58
59    /// Parse this `FileItem` as a `Tree`
60    pub async fn as_tree(&self) -> Result<Tree, Error> {
61        let ctx = self.get_context().await?;
62        let buf = ctx.s.as_slice();
63
64        let res = length_value(checked_byte_count, |i| ttree::<VerboseError<_>>(i, &ctx))(&buf);
65        match res {
66            Ok((_, obj)) => Ok(obj),
67            Err(nom::Err::Error(e)) | Err(nom::Err::Failure(e)) => {
68                Err(format_err!("Supplied parser failed! {:?}", e.errors))
69            }
70            _ => panic!(),
71        }
72    }
73}
74
75#[cfg(all(test, not(target_arch = "wasm32")))]
76mod tests {
77    use crate::core::RootFile;
78    use std::path::Path;
79
80    #[tokio::test]
81    async fn open_simple() {
82        let path = Path::new("./src/test_data/simple.root");
83        let f = RootFile::new(path).await.expect("Failed to open file");
84        assert_eq!(f.items().len(), 1);
85        assert_eq!(f.items()[0].tkey_hdr.obj_name, "tree");
86        // Only streamers; not rules
87        assert_eq!(f.streamer_infos().await.unwrap().len(), 18);
88    }
89
90    // Skip this test on MacOs since the downloaded file is not working on Travis
91    #[tokio::test]
92    #[cfg(all(not(target_os = "macos"), not(target_arch = "wasm32")))]
93    async fn open_esd() {
94        use alice_open_data;
95        let path = alice_open_data::test_file().unwrap();
96
97        let f = RootFile::new(path.as_path())
98            .await
99            .expect("Failed to open file");
100
101        assert_eq!(f.items().len(), 2);
102        assert_eq!(f.items()[0].tkey_hdr.obj_name, "esdTree");
103        assert_eq!(f.items()[1].tkey_hdr.obj_name, "HLTesdTree");
104        assert_eq!(f.streamer_infos().await.unwrap().len(), 87);
105    }
106}