Skip to main content

root_io/tree_reader/
leafs.rs

1use std::fmt::Debug;
2
3use nom::{
4    combinator::{map_res, verify},
5    error::ParseError,
6    multi::length_value,
7    number::complete::*,
8    IResult,
9};
10
11use quote::{Ident, Tokens};
12
13use crate::{code_gen::rust::ToRustType, core::*};
14
15/// Parse a bool from a big endian u8
16fn be_bool<'a, E: ParseError<&'a [u8]>>(i: &'a [u8]) -> IResult<&[u8], bool, E> {
17    let (i, byte) = verify(be_u8, |&byte| byte == 0 || byte == 1)(i)?;
18    Ok((i, byte == 1))
19}
20
21// Wrap everything once more to avoid exporting the enum variants.
22#[derive(Debug, Clone)]
23pub struct TLeaf {
24    variant: TLeafVariant,
25}
26
27impl TLeaf {
28    pub fn parse<'s, E>(
29        i: &'s [u8],
30        context: &'s Context,
31        c_name: &str,
32    ) -> IResult<&'s [u8], Self, E>
33    where
34        E: ParseError<&'s [u8]> + Debug,
35    {
36        TLeafVariant::parse(i, context, c_name).map(|(i, var)| (i, Self { variant: var }))
37    }
38
39    // A helper function to get around some lifetime issues on the caller sider
40    pub(crate) fn parse_from_raw<'s, E>(
41        raw: &Raw<'s>,
42        ctxt: &'s Context,
43    ) -> IResult<&'s [u8], Self, E>
44    where
45        E: ParseError<&'s [u8]> + Debug,
46    {
47        Self::parse(raw.obj, ctxt, &raw.classinfo)
48    }
49}
50
51#[derive(Debug, Clone)]
52enum TLeafVariant {
53    TLeafB(TLeafB),
54    TLeafS(TLeafS),
55    TLeafI(TLeafI),
56    TLeafL(TLeafL),
57    TLeafF(TLeafF),
58    TLeafD(TLeafD),
59    TLeafC(TLeafC),
60    TLeafO(TLeafO),
61    TLeafD32(TLeafD32),
62    TLeafElement(TLeafElement),
63}
64
65impl TLeafVariant {
66    fn parse<'s, E>(i: &'s [u8], context: &'s Context, c_name: &str) -> IResult<&'s [u8], Self, E>
67    where
68        E: ParseError<&'s [u8]> + Debug,
69    {
70        match c_name {
71            "TLeafB" => TLeafB::parse(i, context).map(|(i, l)| (i, TLeafVariant::TLeafB(l))),
72            "TLeafS" => TLeafS::parse(i, context).map(|(i, l)| (i, TLeafVariant::TLeafS(l))),
73            "TLeafI" => TLeafI::parse(i, context).map(|(i, l)| (i, TLeafVariant::TLeafI(l))),
74            "TLeafL" => TLeafL::parse(i, context).map(|(i, l)| (i, TLeafVariant::TLeafL(l))),
75            "TLeafF" => TLeafF::parse(i, context).map(|(i, l)| (i, TLeafVariant::TLeafF(l))),
76            "TLeafD" => TLeafD::parse(i, context).map(|(i, l)| (i, TLeafVariant::TLeafD(l))),
77            "TLeafC" => TLeafC::parse(i, context).map(|(i, l)| (i, TLeafVariant::TLeafC(l))),
78            "TLeafO" => TLeafO::parse(i, context).map(|(i, l)| (i, TLeafVariant::TLeafO(l))),
79            "TLeafD32" => TLeafD32::parse(i, context).map(|(i, l)| (i, TLeafVariant::TLeafD32(l))),
80            "TLeafElement" => {
81                TLeafElement::parse(i, context).map(|(i, l)| (i, TLeafVariant::TLeafElement(l)))
82            }
83            name => unimplemented!("Unexpected Leaf type {}", name),
84        }
85    }
86}
87
88macro_rules! make_tleaf_variant {
89    // Usually the element size ish what we also use for min/max, but not always
90    ($struct_name:ident, $field_type:ty, $parser:ident) => {
91        make_tleaf_variant! {$struct_name, $field_type, $parser, std::mem::size_of::<$field_type>()}
92    };
93    ($struct_name:ident, $field_type:ty, $parser:ident, $size_of_el:expr) => {
94        #[derive(Debug, Clone)]
95        struct $struct_name {
96            base: TLeafBase,
97            fminimum: $field_type,
98            fmaximum: $field_type,
99        }
100        impl $struct_name {
101            fn parse<'s, E>(i: &'s [u8], context: &'s Context) -> IResult<&'s [u8], Self, E>
102            where
103                E: ParseError<&'s [u8]> + Debug,
104            {
105                // All known descendens have version 1
106                let (i, _) = verify(be_u16, |&ver| ver == 1)(i)?;
107                let (i, base) =
108                    length_value(checked_byte_count, |i| TLeafBase::parse(i, context))(i)?;
109                let (i, fminimum) = $parser(i)?;
110                let (i, fmaximum) = $parser(i)?;
111                let obj = Self {
112                    base,
113                    fminimum,
114                    fmaximum,
115                };
116                obj.verify_consistency().unwrap();
117                Ok((i, obj))
118            }
119
120            fn verify_consistency(&self) -> Result<(), String> {
121                if self.base.flentype as usize != $size_of_el {
122                    return Err(String::from("Unexpected type length"));
123                }
124                if self.base.fisunsigned {
125                    // The minimum and maximum values are possibly wrong
126                    // return Err(String::from("Expected signed value"));
127                }
128                Ok(())
129            }
130        }
131    };
132}
133
134make_tleaf_variant! {TLeafB, i8, be_i8}
135make_tleaf_variant! {TLeafS, i16, be_i16}
136make_tleaf_variant! {TLeafI, i32, be_i32}
137make_tleaf_variant! {TLeafL, i64, be_i64}
138make_tleaf_variant! {TLeafF, f32, be_f32}
139make_tleaf_variant! {TLeafD, f64, be_f64}
140// TLeafC has chars as elements
141make_tleaf_variant! {TLeafC, i32, be_i32, 1}
142make_tleaf_variant! {TLeafO, bool, be_bool}
143make_tleaf_variant! {TLeafD32, f32, be_f32}
144
145#[derive(Debug, Clone)]
146struct TLeafElement {
147    base: TLeafBase,
148    fid: i32,
149    ftype: TypeID,
150}
151
152impl TLeafElement {
153    fn parse<'s, E>(i: &'s [u8], context: &'s Context) -> IResult<&'s [u8], Self, E>
154    where
155        E: ParseError<&'s [u8]> + Debug,
156    {
157        let (i, _) = verify(be_u16, |&ver| ver == 1)(i)?;
158        let (i, base) = length_value(checked_byte_count, |i| TLeafBase::parse(i, context))(i)?;
159        let (i, fid) = be_i32(i)?;
160        let (i, ftype) = map_res(be_i32, TypeID::new)(i)?;
161        Ok((i, Self { base, fid, ftype }))
162    }
163}
164
165#[derive(Debug, Clone)]
166struct TLeafBase {
167    /// Version of the read layout
168    ver: u16,
169    /// The basis for a named object (name, title)
170    tnamed: TNamed,
171    /// Number of fixed length elements
172    flen: i32,
173    /// Number of bytes for this data type
174    flentype: i32,
175    /// Offset in ClonesArray object (if one)
176    foffset: i32,
177    /// (=kTRUE if leaf has a range, kFALSE otherwise)
178    fisrange: bool,
179    /// (=kTRUE if unsigned, kFALSE otherwise)
180    fisunsigned: bool,
181    /// Pointer to Leaf count if variable length (we do not own the counter)
182    fleafcount: Option<Box<TLeafVariant>>,
183}
184
185impl TLeafBase {
186    fn parse<'s, E>(i: &'s [u8], context: &'s Context) -> IResult<&'s [u8], Self, E>
187    where
188        E: ParseError<&'s [u8]> + std::fmt::Debug,
189    {
190        let (i, ver) = be_u16(i)?;
191        let (i, tnamed) = length_value(checked_byte_count, tnamed)(i)?;
192        let (i, flen) = be_i32(i)?;
193        let (i, flentype) = be_i32(i)?;
194        let (i, foffset) = be_i32(i)?;
195        let (i, fisrange) = be_bool(i)?;
196        let (i, fisunsigned) = be_bool(i)?;
197        let (i, fleafcount) = {
198            if peek!(i, be_u32)?.1 == 0 {
199                // Consume the bytes but we have no nested leafs
200                be_u32(i).map(|(i, _)| (i, None))?
201            } else {
202                let (i, r) = raw(i, context)?;
203                // We don't parse from the input buffer. TODO: Check
204                // that we consumed all bytes
205                let (_, tleaf) = TLeafVariant::parse(r.obj, context, &r.classinfo)?;
206                (i, Some(Box::new(tleaf)))
207            }
208        };
209        Ok((
210            i,
211            Self {
212                ver,
213                tnamed,
214                flen,
215                flentype,
216                foffset,
217                fisrange,
218                fisunsigned,
219                fleafcount,
220            },
221        ))
222    }
223}
224
225/// If we have more than one element make this
226fn arrayfy_maybe(ty_name: &str, len: usize) -> Tokens {
227    // not an array
228    let t = Ident::new(ty_name);
229    if len == 1 {
230        quote! {#t}
231    } else {
232        // array
233        quote! {[#t; #len]}
234    }
235}
236
237impl ToRustType for TLeaf {
238    fn type_name(&self) -> Tokens {
239        use TLeafVariant::*;
240        let (type_name, len) = match &self.variant {
241            TLeafO(l) => ("bool", l.base.flen),
242            TLeafB(l) => (if l.base.fisunsigned { "u8" } else { "i8" }, l.base.flen),
243            TLeafS(l) => (if l.base.fisunsigned { "u16" } else { "i16" }, l.base.flen),
244            TLeafI(l) => (if l.base.fisunsigned { "u32" } else { "i32" }, l.base.flen),
245            TLeafL(l) => (if l.base.fisunsigned { "u64" } else { "i64" }, l.base.flen),
246            TLeafF(l) => ("f32", l.base.flen),
247            TLeafD(l) => ("f64", l.base.flen),
248            TLeafC(l) => ("String", l.base.flen),
249            l => todo!("{:?}", l),
250        };
251        arrayfy_maybe(type_name, len as usize)
252    }
253}