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
15fn 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#[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 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 ($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 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 }
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}
140make_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 ver: u16,
169 tnamed: TNamed,
171 flen: i32,
173 flentype: i32,
175 foffset: i32,
177 fisrange: bool,
179 fisunsigned: bool,
181 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 be_u32(i).map(|(i, _)| (i, None))?
201 } else {
202 let (i, r) = raw(i, context)?;
203 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
225fn arrayfy_maybe(ty_name: &str, len: usize) -> Tokens {
227 let t = Ident::new(ty_name);
229 if len == 1 {
230 quote! {#t}
231 } else {
232 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}