nrbf_parser/
interleaved.rs

1use crate::records::{
2    AdditionalTypeInfo, BinaryArray, BinaryType, ClassInfo, ClassWithId, ClassWithMembers,
3    ClassWithMembersAndTypes, MemberTypeInfo, ObjectValue, PrimitiveType, PrimitiveValue, Record,
4    SystemClassWithMembers, SystemClassWithMembersAndTypes,
5};
6use serde_json::{Map, Value, json};
7
8pub fn to_interleaved(records: &[Record]) -> Value {
9    let mut result = Vec::new();
10    for record in records {
11        if let Some(val) = record_to_value(record) {
12            result.push(val);
13        }
14    }
15    Value::Array(result)
16}
17
18fn record_to_value(record: &Record) -> Option<Value> {
19    match record {
20        Record::SerializationHeader(h) => Some(json!({
21            "$record": "SerializationHeader",
22            "root_id": h.root_id,
23            "header_id": h.header_id,
24            "major_version": h.major_version,
25            "minor_version": h.minor_version,
26        })),
27        Record::BinaryLibrary(l) => Some(json!({
28            "$record": "BinaryLibrary",
29            "library_id": l.library_id,
30            "library_name": l.library_name,
31        })),
32        Record::ClassWithMembersAndTypes(c) => {
33            let mut val = class_to_value(
34                &c.class_info.name,
35                c.class_info.object_id,
36                &c.class_info.member_names,
37                &c.member_values,
38                Some(c.library_id),
39            );
40            if let Value::Object(ref mut map) = val {
41                map.insert("$record".to_string(), json!("ClassWithMembersAndTypes"));
42                map.insert("$member_type_info".to_string(), json!(c.member_type_info));
43            }
44            Some(val)
45        }
46        Record::SystemClassWithMembersAndTypes(c) => {
47            let mut val = class_to_value(
48                &c.class_info.name,
49                c.class_info.object_id,
50                &c.class_info.member_names,
51                &c.member_values,
52                None,
53            );
54            if let Value::Object(ref mut map) = val {
55                map.insert(
56                    "$record".to_string(),
57                    json!("SystemClassWithMembersAndTypes"),
58                );
59                map.insert("$member_type_info".to_string(), json!(c.member_type_info));
60            }
61            Some(val)
62        }
63        Record::SystemClassWithMembers(c) => {
64            let mut val = class_to_value(
65                &c.class_info.name,
66                c.class_info.object_id,
67                &c.class_info.member_names,
68                &c.member_values,
69                None,
70            );
71            if let Value::Object(ref mut map) = val {
72                map.insert("$record".to_string(), json!("SystemClassWithMembers"));
73            }
74            Some(val)
75        }
76        Record::ClassWithMembers(c) => {
77            let mut val = class_to_value(
78                &c.class_info.name,
79                c.class_info.object_id,
80                &c.class_info.member_names,
81                &c.member_values,
82                Some(c.library_id),
83            );
84            if let Value::Object(ref mut map) = val {
85                map.insert("$record".to_string(), json!("ClassWithMembers"));
86            }
87            Some(val)
88        }
89        Record::ClassWithId(c) => Some(json!({
90            "$record": "ClassWithId",
91            "object_id": c.object_id,
92            "metadata_id": c.metadata_id,
93            "$values": c.member_values.iter().map(object_value_to_json).collect::<Vec<_>>(),
94        })),
95        Record::BinaryObjectString { object_id, value } => Some(json!({
96            "$record": "BinaryObjectString",
97            "object_id": *object_id,
98            "value": value,
99        })),
100        Record::BinaryArray(a) => Some(json!({
101            "$record": "BinaryArray",
102            "object_id": a.object_id,
103            "binary_array_type_enum": a.binary_array_type_enum,
104            "rank": a.rank,
105            "lengths": a.lengths,
106            "lower_bounds": a.lower_bounds,
107            "type_enum": a.type_enum,
108            "additional_type_info": a.additional_type_info,
109            "$values": a.element_values.iter().map(object_value_to_json).collect::<Vec<_>>(),
110        })),
111        Record::ArraySingleObject(a) => Some(json!({
112            "$record": "ArraySingleObject",
113            "object_id": a.object_id,
114            "length": a.length,
115            "$values": a.element_values.iter().map(object_value_to_json).collect::<Vec<_>>(),
116        })),
117        Record::ArraySinglePrimitive(a) => Some(json!({
118            "$record": "ArraySinglePrimitive",
119            "object_id": a.object_id,
120            "length": a.length,
121            "primitive_type_enum": a.primitive_type_enum,
122            "$values": a.element_values.iter().map(primitive_value_to_json).collect::<Vec<_>>(),
123        })),
124        Record::ArraySingleString(a) => Some(json!({
125            "$record": "ArraySingleString",
126            "object_id": a.object_id,
127            "length": a.length,
128            "$values": a.element_values.iter().map(object_value_to_json).collect::<Vec<_>>(),
129        })),
130        Record::MemberPrimitiveTyped {
131            primitive_type_enum,
132            value,
133        } => Some(json!({
134            "$record": "MemberPrimitiveTyped",
135            "primitive_type_enum": primitive_type_enum,
136            "value": primitive_value_to_json(value),
137        })),
138        Record::MemberReference { id_ref } => Some(json!({
139            "$record": "MemberReference",
140            "id_ref": *id_ref,
141        })),
142        Record::ObjectNull => Some(json!({ "$record": "ObjectNull" })),
143        Record::ObjectNullMultiple(n) => Some(json!({
144            "$record": "ObjectNullMultiple",
145            "null_count": n.null_count,
146        })),
147        Record::ObjectNullMultiple256(n) => Some(json!({
148            "$record": "ObjectNullMultiple256",
149            "null_count": n.null_count,
150        })),
151        Record::MessageEnd => Some(json!({ "$record": "MessageEnd" })),
152    }
153}
154
155fn class_to_value(
156    name: &str,
157    object_id: i32,
158    member_names: &[String],
159    member_values: &[ObjectValue],
160    library_id: Option<i32>,
161) -> Value {
162    let mut map = Map::new();
163    map.insert("$type".to_string(), Value::String(name.to_string()));
164    map.insert("$id".to_string(), json!(object_id));
165    if let Some(lib_id) = library_id {
166        map.insert("library_id".to_string(), json!(lib_id));
167    }
168
169    for (name, val) in member_names.iter().zip(member_values.iter()) {
170        map.insert(name.clone(), object_value_to_json(val));
171    }
172
173    Value::Object(map)
174}
175
176fn object_value_to_json(val: &ObjectValue) -> Value {
177    match val {
178        ObjectValue::Primitive(p) => primitive_value_to_json(p),
179        ObjectValue::Record(r) => record_to_value(r).unwrap_or(Value::Null),
180    }
181}
182
183fn primitive_value_to_json(val: &PrimitiveValue) -> Value {
184    match val {
185        PrimitiveValue::Boolean(b) => Value::Bool(*b),
186        PrimitiveValue::Byte(b) => json!(b),
187        PrimitiveValue::Char(c) => json!(c.to_string()),
188        PrimitiveValue::Decimal(s) => json!(s),
189        PrimitiveValue::Double(f) => json!(f),
190        PrimitiveValue::Int16(i) => json!(i),
191        PrimitiveValue::Int32(i) => json!(i),
192        PrimitiveValue::Int64(i) => json!(i),
193        PrimitiveValue::SByte(i) => json!(i),
194        PrimitiveValue::Single(f) => json!(f),
195        PrimitiveValue::TimeSpan(i) => json!(i),
196        PrimitiveValue::DateTime(u) => json!(u),
197        PrimitiveValue::UInt16(u) => json!(u),
198        PrimitiveValue::UInt32(u) => json!(u),
199        PrimitiveValue::UInt64(u) => json!(u),
200        PrimitiveValue::String(s) => Value::String(s.clone()),
201        PrimitiveValue::Null => Value::Null,
202    }
203}
204
205use std::collections::HashMap;
206
207pub fn from_interleaved(value: Value) -> Vec<Record> {
208    let mut deserializer = InterleavedDeserializer::new();
209    deserializer.deserialize(value)
210}
211
212struct InterleavedDeserializer {
213    metadata_registry: HashMap<i32, MemberTypeInfo>,
214}
215
216impl InterleavedDeserializer {
217    fn new() -> Self {
218        Self {
219            metadata_registry: HashMap::new(),
220        }
221    }
222
223    fn deserialize(&mut self, value: Value) -> Vec<Record> {
224        let mut records = Vec::new();
225        if let Value::Array(arr) = value {
226            for v in arr {
227                if let Some(record) = self.value_to_record(&v) {
228                    records.push(record);
229                }
230            }
231        }
232        records
233    }
234
235    fn value_to_record(&mut self, v: &Value) -> Option<Record> {
236        let obj = v.as_object()?;
237        let record_type = obj.get("$record")?.as_str()?;
238
239        match record_type {
240            "SerializationHeader" => Some(Record::SerializationHeader(
241                serde_json::from_value(v.clone()).ok()?,
242            )),
243            "BinaryLibrary" => Some(Record::BinaryLibrary(
244                serde_json::from_value(v.clone()).ok()?,
245            )),
246            "ClassWithMembersAndTypes" => {
247                let class_info = self.value_to_class_info(v);
248                let member_type_info: MemberTypeInfo =
249                    serde_json::from_value(obj.get("$member_type_info")?.clone()).ok()?;
250                let library_id = obj.get("library_id")?.as_i64()? as i32;
251
252                self.metadata_registry
253                    .insert(class_info.object_id, member_type_info.clone());
254
255                let member_values = self.value_to_member_values_typed(
256                    v,
257                    &class_info.member_names,
258                    &member_type_info,
259                );
260                Some(Record::ClassWithMembersAndTypes(ClassWithMembersAndTypes {
261                    class_info,
262                    member_type_info,
263                    library_id,
264                    member_values,
265                }))
266            }
267            "SystemClassWithMembersAndTypes" => {
268                let class_info = self.value_to_class_info(v);
269                let member_type_info: MemberTypeInfo =
270                    serde_json::from_value(obj.get("$member_type_info")?.clone()).ok()?;
271
272                self.metadata_registry
273                    .insert(class_info.object_id, member_type_info.clone());
274
275                let member_values = self.value_to_member_values_typed(
276                    v,
277                    &class_info.member_names,
278                    &member_type_info,
279                );
280                Some(Record::SystemClassWithMembersAndTypes(
281                    SystemClassWithMembersAndTypes {
282                        class_info,
283                        member_type_info,
284                        member_values,
285                    },
286                ))
287            }
288            "SystemClassWithMembers" => {
289                let class_info = self.value_to_class_info(v);
290                let member_values = self.value_to_member_values(v, &class_info.member_names);
291                Some(Record::SystemClassWithMembers(SystemClassWithMembers {
292                    class_info,
293                    member_values,
294                }))
295            }
296            "ClassWithMembers" => {
297                let class_info = self.value_to_class_info(v);
298                let library_id = obj.get("library_id")?.as_i64()? as i32;
299                let member_values = self.value_to_member_values(v, &class_info.member_names);
300                Some(Record::ClassWithMembers(ClassWithMembers {
301                    class_info,
302                    library_id,
303                    member_values,
304                }))
305            }
306            "ClassWithId" => {
307                let object_id = obj.get("object_id")?.as_i64()? as i32;
308                let metadata_id = obj.get("metadata_id")?.as_i64()? as i32;
309                let member_values =
310                    if let Some(mti) = self.metadata_registry.get(&metadata_id).cloned() {
311                        let vals = obj.get("$values")?.as_array()?;
312                        let mut result = Vec::new();
313                        for (i, v) in vals.iter().enumerate() {
314                            let bt = &mti.binary_type_enums[i];
315                            let add_info = &mti.additional_infos[i];
316                            match bt {
317                                BinaryType::Primitive => {
318                                    if let AdditionalTypeInfo::Primitive(p_type) = add_info {
319                                        result.push(ObjectValue::Primitive(
320                                            self.json_to_primitive_value(v, p_type),
321                                        ));
322                                    } else {
323                                        result.push(self.json_to_object_value(v));
324                                    }
325                                }
326                                _ => result.push(self.json_to_object_value(v)),
327                            }
328                        }
329                        result
330                    } else {
331                        obj.get("$values")?
332                            .as_array()?
333                            .iter()
334                            .map(|v| self.json_to_object_value(v))
335                            .collect()
336                    };
337                Some(Record::ClassWithId(ClassWithId {
338                    object_id,
339                    metadata_id,
340                    member_values,
341                }))
342            }
343            "BinaryObjectString" => Some(Record::BinaryObjectString {
344                object_id: obj.get("object_id")?.as_i64()? as i32,
345                value: obj.get("value")?.as_str()?.to_string(),
346            }),
347            "BinaryArray" => {
348                let type_enum: BinaryType =
349                    serde_json::from_value(obj.get("type_enum")?.clone()).ok()?;
350                let additional_type_info: AdditionalTypeInfo =
351                    serde_json::from_value(obj.get("additional_type_info")?.clone()).ok()?;
352                let element_values = obj
353                    .get("$values")?
354                    .as_array()?
355                    .iter()
356                    .map(|v| match type_enum {
357                        BinaryType::Primitive => {
358                            if let AdditionalTypeInfo::Primitive(p_type) = &additional_type_info {
359                                ObjectValue::Primitive(self.json_to_primitive_value(v, p_type))
360                            } else {
361                                self.json_to_object_value(v)
362                            }
363                        }
364                        _ => self.json_to_object_value(v),
365                    })
366                    .collect();
367                Some(Record::BinaryArray(BinaryArray {
368                    object_id: obj.get("object_id")?.as_i64()? as i32,
369                    binary_array_type_enum: obj.get("binary_array_type_enum")?.as_i64()? as u8,
370                    rank: obj.get("rank")?.as_i64()? as i32,
371                    lengths: serde_json::from_value(obj.get("lengths")?.clone()).ok()?,
372                    lower_bounds: serde_json::from_value(obj.get("lower_bounds")?.clone()).ok()?,
373                    type_enum,
374                    additional_type_info,
375                    element_values,
376                }))
377            }
378            "ArraySingleObject" => Some(Record::ArraySingleObject(
379                crate::records::ArraySingleObject {
380                    object_id: obj.get("object_id")?.as_i64()? as i32,
381                    length: obj.get("length")?.as_i64()? as i32,
382                    element_values: obj
383                        .get("$values")?
384                        .as_array()?
385                        .iter()
386                        .map(|v| self.json_to_object_value(v))
387                        .collect(),
388                },
389            )),
390            "ArraySinglePrimitive" => {
391                let primitive_type_enum: PrimitiveType =
392                    serde_json::from_value(obj.get("primitive_type_enum")?.clone()).ok()?;
393                let element_values = obj
394                    .get("$values")?
395                    .as_array()?
396                    .iter()
397                    .map(
398                        |v| match self.json_to_primitive_value(v, &primitive_type_enum) {
399                            PrimitiveValue::Null => PrimitiveValue::Null,
400                            p => p,
401                        },
402                    )
403                    .collect();
404                Some(Record::ArraySinglePrimitive(
405                    crate::records::ArraySinglePrimitive {
406                        object_id: obj.get("object_id")?.as_i64()? as i32,
407                        length: obj.get("length")?.as_i64()? as i32,
408                        primitive_type_enum,
409                        element_values,
410                    },
411                ))
412            }
413            "ArraySingleString" => Some(Record::ArraySingleString(
414                crate::records::ArraySingleString {
415                    object_id: obj.get("object_id")?.as_i64()? as i32,
416                    length: obj.get("length")?.as_i64()? as i32,
417                    element_values: obj
418                        .get("$values")?
419                        .as_array()?
420                        .iter()
421                        .map(|v| self.json_to_object_value(v))
422                        .collect(),
423                },
424            )),
425            "MemberPrimitiveTyped" => {
426                let primitive_type_enum: PrimitiveType =
427                    serde_json::from_value(obj.get("primitive_type_enum")?.clone()).ok()?;
428                let value = self.json_to_primitive_value(obj.get("value")?, &primitive_type_enum);
429                Some(Record::MemberPrimitiveTyped {
430                    primitive_type_enum,
431                    value,
432                })
433            }
434            "MemberReference" => Some(Record::MemberReference {
435                id_ref: obj.get("id_ref")?.as_i64()? as i32,
436            }),
437            "ObjectNull" => Some(Record::ObjectNull),
438            "ObjectNullMultiple" => Some(Record::ObjectNullMultiple(
439                crate::records::ObjectNullMultiple {
440                    null_count: obj.get("null_count")?.as_i64()? as i32,
441                },
442            )),
443            "ObjectNullMultiple256" => Some(Record::ObjectNullMultiple256(
444                crate::records::ObjectNullMultiple256 {
445                    null_count: obj.get("null_count")?.as_i64()? as u8,
446                },
447            )),
448            "MessageEnd" => Some(Record::MessageEnd),
449            _ => None,
450        }
451    }
452
453    fn value_to_class_info(&self, v: &Value) -> ClassInfo {
454        let obj = v.as_object().unwrap();
455        let name = obj.get("$type").unwrap().as_str().unwrap().to_string();
456        let object_id = obj.get("$id").unwrap().as_i64().unwrap() as i32;
457        let mut member_names = Vec::new();
458        for key in obj.keys() {
459            if !key.starts_with('$') && key != "library_id" {
460                member_names.push(key.clone());
461            }
462        }
463
464        ClassInfo {
465            object_id,
466            name,
467            member_count: member_names.len() as i32,
468            member_names,
469        }
470    }
471
472    fn value_to_member_values(&mut self, v: &Value, member_names: &[String]) -> Vec<ObjectValue> {
473        let obj = v.as_object().unwrap();
474        let mut values = Vec::new();
475        for name in member_names {
476            if let Some(val) = obj.get(name) {
477                values.push(self.json_to_object_value(val));
478            }
479        }
480        values
481    }
482
483    fn value_to_member_values_typed(
484        &mut self,
485        v: &Value,
486        member_names: &[String],
487        member_type_info: &MemberTypeInfo,
488    ) -> Vec<ObjectValue> {
489        let obj = v.as_object().unwrap();
490        let mut values = Vec::new();
491        for (i, name) in member_names.iter().enumerate() {
492            if let Some(val) = obj.get(name) {
493                let binary_type = &member_type_info.binary_type_enums[i];
494                let additional_info = &member_type_info.additional_infos[i];
495
496                match binary_type {
497                    BinaryType::Primitive => {
498                        if let AdditionalTypeInfo::Primitive(p_type) = additional_info {
499                            values.push(ObjectValue::Primitive(
500                                self.json_to_primitive_value(val, p_type),
501                            ));
502                        } else {
503                            values.push(self.json_to_object_value(val));
504                        }
505                    }
506                    _ => {
507                        values.push(self.json_to_object_value(val));
508                    }
509                }
510            }
511        }
512        values
513    }
514
515    fn json_to_primitive_value(&self, v: &Value, t: &PrimitiveType) -> PrimitiveValue {
516        match t {
517            PrimitiveType::Boolean => PrimitiveValue::Boolean(v.as_bool().unwrap_or(false)),
518            PrimitiveType::Byte => PrimitiveValue::Byte(v.as_i64().unwrap_or(0) as u8),
519            PrimitiveType::UInt16 => PrimitiveValue::UInt16(v.as_u64().unwrap_or(0) as u16),
520            PrimitiveType::UInt32 => PrimitiveValue::UInt32(v.as_u64().unwrap_or(0) as u32),
521            PrimitiveType::Char => {
522                PrimitiveValue::Char(v.as_str().and_then(|s| s.chars().next()).unwrap_or('\0'))
523            }
524            PrimitiveType::Decimal => {
525                PrimitiveValue::Decimal(v.as_str().unwrap_or("0").to_string())
526            }
527            PrimitiveType::Double => PrimitiveValue::Double(v.as_f64().unwrap_or(0.0)),
528            PrimitiveType::Int16 => PrimitiveValue::Int16(v.as_i64().unwrap_or(0) as i16),
529            PrimitiveType::Int32 => PrimitiveValue::Int32(v.as_i64().unwrap_or(0) as i32),
530            PrimitiveType::Int64 => PrimitiveValue::Int64(v.as_i64().unwrap_or(0)),
531            PrimitiveType::SByte => PrimitiveValue::SByte(v.as_i64().unwrap_or(0) as i8),
532            PrimitiveType::Single => PrimitiveValue::Single(v.as_f64().unwrap_or(0.0) as f32),
533            PrimitiveType::TimeSpan => PrimitiveValue::TimeSpan(v.as_i64().unwrap_or(0)),
534            PrimitiveType::DateTime => PrimitiveValue::DateTime(
535                v.as_u64()
536                    .or_else(|| v.as_i64().map(|i| i as u64))
537                    .unwrap_or(0),
538            ),
539            PrimitiveType::UInt64 => PrimitiveValue::UInt64(
540                v.as_u64()
541                    .or_else(|| v.as_i64().map(|i| i as u64))
542                    .unwrap_or(0),
543            ),
544            PrimitiveType::String => PrimitiveValue::String(v.as_str().unwrap_or("").to_string()),
545            PrimitiveType::Null => PrimitiveValue::Null,
546        }
547    }
548
549    fn json_to_object_value(&mut self, v: &Value) -> ObjectValue {
550        if let Some(record) = self.value_to_record(v) {
551            return ObjectValue::Record(Box::new(record));
552        }
553
554        // Fallback for primitive/basic types
555        if v.is_boolean() {
556            ObjectValue::Primitive(PrimitiveValue::Boolean(v.as_bool().unwrap()))
557        } else if v.is_number() {
558            if v.is_i64() {
559                ObjectValue::Primitive(PrimitiveValue::Int32(v.as_i64().unwrap() as i32))
560            } else if v.is_u64() {
561                ObjectValue::Primitive(PrimitiveValue::UInt32(v.as_u64().unwrap() as u32))
562            } else {
563                ObjectValue::Primitive(PrimitiveValue::Double(v.as_f64().unwrap()))
564            }
565        } else if v.is_string() {
566            ObjectValue::Primitive(PrimitiveValue::String(v.as_str().unwrap().to_string()))
567        } else {
568            ObjectValue::Primitive(PrimitiveValue::Null)
569        }
570    }
571}