1use crate::{
2 UserDefinedType, advance_window, read_advance_string, read_any, read_consume_pod,
3 value::{Object, Value},
4};
5use anyhow::{Context, Result, bail};
6use std::{collections::HashMap, sync::Arc};
7
8pub type CustomReader =
9 Arc<dyn Fn(&UserDefinedType, &[UserDefinedType], &HashMap<u64, Value>, &[u8]) -> Result<Value>>;
10pub type CustomReaderMap = HashMap<String, CustomReader>;
11
12pub fn read_dependencies(
13 custom_readers: &CustomReaderMap,
14 udts: &[UserDefinedType],
15 buffer: &[u8],
16) -> Result<HashMap<u64, Value>> {
17 let mut hash = HashMap::new();
18 let mut offset = 0;
19 while offset < buffer.len() {
20 let type_index = buffer[offset] as usize;
21 if type_index >= udts.len() {
22 bail!(
23 "Invalid type index parsing transit dependencies: {}",
24 type_index
25 );
26 }
27 offset += 1;
28 let udt = &udts[type_index];
29 let object_size = match udt.size {
30 0 => {
31 unsafe {
33 let size_ptr = buffer.as_ptr().add(offset);
34 let obj_size = read_any::<u32>(size_ptr);
35 offset += std::mem::size_of::<u32>();
36 obj_size as usize
37 }
38 }
39 static_size => static_size,
40 };
41
42 match udt.name.as_str() {
43 "StaticString" => unsafe {
44 let id_ptr = buffer.as_ptr().add(offset);
45 let string_id = read_any::<u64>(id_ptr);
46 let nb_utf8_bytes = object_size - std::mem::size_of::<usize>();
47 let utf8_ptr = buffer.as_ptr().add(offset + std::mem::size_of::<usize>());
48 let slice = std::ptr::slice_from_raw_parts(utf8_ptr, nb_utf8_bytes);
49 let string =
50 String::from(std::str::from_utf8(&*slice).with_context(|| "str::from_utf8")?);
51 let insert_res = hash.insert(string_id, Value::String(Arc::new(string)));
52 assert!(insert_res.is_none());
53 },
54 "StaticStringDependency" => {
55 let mut window = advance_window(buffer, offset);
56 let string_id: u64 = read_consume_pod(&mut window);
57 let string = read_advance_string(&mut window).with_context(|| "parsing string")?;
58
59 let insert_res = hash.insert(string_id, Value::String(Arc::new(string)));
60 assert!(insert_res.is_none());
61 }
62 type_name => {
63 if let Some(reader) = custom_readers.get(type_name) {
64 let window = advance_window(buffer, offset);
65 if let Value::Object(obj) = (*reader)(udt, udts, &hash, window)
66 .with_context(|| "parsing custom dependency")?
67 {
68 let id: u64 = obj
69 .get("id")
70 .with_context(|| "reading id of custom dependency")?;
71 let value = obj
72 .get_ref("value")
73 .with_context(|| "reading value of custom dependency")?
74 .clone();
75 let insert_res = hash.insert(id, value);
76 assert!(insert_res.is_none());
77 } else {
78 anyhow::bail!("custom dependency is not an object");
79 }
80 } else {
81 if udt.size == 0 {
82 anyhow::bail!("invalid user-defined type {:?}", udt);
83 }
84 let instance =
85 parse_pod_instance(udt, udts, &hash, &buffer[offset..offset + udt.size])
86 .with_context(|| "parse_pod_instance")?;
87 if let Value::Object(obj) = instance {
88 let insert_res = hash.insert(obj.get::<u64>("id")?, Value::Object(obj));
89 assert!(insert_res.is_none());
90 }
91 }
92 }
93 }
94 offset += object_size;
95 }
96
97 Ok(hash)
98}
99
100fn parse_custom_instance(
101 custom_readers: &CustomReaderMap,
102 udt: &UserDefinedType,
103 udts: &[UserDefinedType],
104 dependencies: &HashMap<u64, Value>,
105 object_window: &[u8],
106) -> Result<Value> {
107 if let Some(reader) = custom_readers.get(&*udt.name) {
108 (*reader)(udt, udts, dependencies, object_window)
109 } else {
110 log::warn!("unknown custom object {}", &udt.name);
111 Ok(Value::Object(Arc::new(Object {
112 type_name: udt.name.clone(),
113 members: vec![],
114 })))
115 }
116}
117
118pub fn parse_pod_instance(
119 udt: &UserDefinedType,
120 udts: &[UserDefinedType],
121 dependencies: &HashMap<u64, Value>,
122 object_window: &[u8],
123) -> Result<Value> {
124 let mut members: Vec<(Arc<String>, Value)> = vec![];
125 for member_meta in &udt.members {
126 let name = member_meta.name.clone();
127 let type_name = member_meta.type_name.clone();
128 let value = if member_meta.is_reference {
129 if member_meta.size < std::mem::size_of::<u64>() {
130 bail!(
131 "member references have to be at least 8 bytes {:?}",
132 member_meta
133 );
134 }
135 let key = unsafe { read_any::<u64>(object_window.as_ptr().add(member_meta.offset)) };
136 if let Some(v) = dependencies.get(&key) {
137 v.clone()
138 } else {
139 bail!("dependency not found: member={member_meta:?} key={key}");
140 }
141 } else {
142 match type_name.as_str() {
143 "u8" | "uint8" => {
144 assert_eq!(std::mem::size_of::<u8>(), member_meta.size);
145 unsafe {
146 Value::U8(read_any::<u8>(
147 object_window.as_ptr().add(member_meta.offset),
148 ))
149 }
150 }
151 "u32" | "uint32" => {
152 assert_eq!(std::mem::size_of::<u32>(), member_meta.size);
153 unsafe {
154 Value::U32(read_any::<u32>(
155 object_window.as_ptr().add(member_meta.offset),
156 ))
157 }
158 }
159 "u64" | "uint64" => {
160 assert_eq!(std::mem::size_of::<u64>(), member_meta.size);
161 unsafe {
162 Value::U64(read_any::<u64>(
163 object_window.as_ptr().add(member_meta.offset),
164 ))
165 }
166 }
167 "i64" | "int64" => {
168 assert_eq!(std::mem::size_of::<i64>(), member_meta.size);
169 unsafe {
170 Value::I64(read_any::<i64>(
171 object_window.as_ptr().add(member_meta.offset),
172 ))
173 }
174 }
175 "f64" => {
176 assert_eq!(std::mem::size_of::<f64>(), member_meta.size);
177 unsafe {
178 Value::F64(read_any::<f64>(
179 object_window.as_ptr().add(member_meta.offset),
180 ))
181 }
182 }
183 non_intrinsic_member_type_name => {
184 if let Some(index) = udts
185 .iter()
186 .position(|t| *t.name == non_intrinsic_member_type_name)
187 {
188 let member_udt = &udts[index];
189 parse_pod_instance(
190 member_udt,
191 udts,
192 dependencies,
193 &object_window
194 [member_meta.offset..member_meta.offset + member_udt.size],
195 )
196 .with_context(|| "parse_pod_instance")?
197 } else {
198 bail!("unknown member type {}", non_intrinsic_member_type_name);
199 }
200 }
201 }
202 };
203 members.push((name, value));
204 }
205
206 if udt.is_reference {
207 if let Some(id_index) = members.iter().position(|m| *m.0 == "id") {
209 return Ok(members[id_index].1.clone());
210 }
211 bail!("reference object has no 'id' member");
212 }
213
214 Ok(Value::Object(Arc::new(Object {
215 type_name: udt.name.clone(),
216 members,
217 })))
218}
219
220pub fn parse_object_buffer<F>(
223 custom_readers: &CustomReaderMap,
224 dependencies: &HashMap<u64, Value>,
225 udts: &[UserDefinedType],
226 buffer: &[u8],
227 mut fun: F,
228) -> Result<bool>
229where
230 F: FnMut(Value) -> Result<bool>,
231{
232 let mut offset = 0;
233 while offset < buffer.len() {
234 let type_index = buffer[offset] as usize;
235 if type_index >= udts.len() {
236 bail!("Invalid type index parsing transit objects: {}", type_index);
237 }
238 offset += 1;
239 let udt = &udts[type_index];
240 let (object_size, is_size_dynamic) = match udt.size {
241 0 => {
242 unsafe {
244 let size_ptr = buffer.as_ptr().add(offset);
245 let obj_size = read_any::<u32>(size_ptr);
246 offset += std::mem::size_of::<u32>();
247 (obj_size as usize, true)
248 }
249 }
250 static_size => (static_size, false),
251 };
252 let instance = if is_size_dynamic {
253 parse_custom_instance(
254 custom_readers,
255 udt,
256 udts,
257 dependencies,
258 &buffer[offset..offset + object_size],
259 )
260 .with_context(|| "parse_custom_instance")?
261 } else {
262 parse_pod_instance(udt, udts, dependencies, &buffer[offset..offset + udt.size])
263 .with_context(|| "parse_pod_instance")?
264 };
265 if !fun(instance)? {
266 return Ok(false);
267 }
268 offset += object_size;
269 }
270 Ok(true)
271}