d2_stampede/
serializer.rs

1use crate::decoder::Decoder;
2use crate::field::{Field, FieldModel, FieldPath, FieldState, FieldType};
3use hashbrown::HashMap;
4use std::cell::RefCell;
5use std::rc::Rc;
6
7#[derive(Clone, Default)]
8pub(crate) struct Serializer {
9    pub(crate) fields: Vec<Rc<Field>>,
10    pub(crate) fp_cache: RefCell<HashMap<Box<str>, FieldPath>>,
11}
12
13#[derive(thiserror::Error, Debug)]
14pub enum SerializerError {
15    #[error("No field path for given name {0}")]
16    NoFieldPath(String),
17}
18
19impl Serializer {
20    #[inline]
21    pub(crate) fn get_name_for_field_path(&self, fp: &FieldPath) -> String {
22        let mut i = 0;
23        let mut current_serializer = self;
24        let mut current_field = &current_serializer.fields[fp.path[i] as usize];
25        let mut name = String::new();
26        loop {
27            name += &current_field.var_name;
28            i += 1;
29            match &current_field.model {
30                FieldModel::FixedArray | FieldModel::VariableArray(_) => {
31                    if fp.last == i {
32                        name += &format!(".{:04}", fp.path[i]);
33                        break;
34                    }
35                }
36                FieldModel::VariableTable(serializer) => {
37                    if fp.last + 1 == i {
38                        break;
39                    }
40                    name += &format!(".{:04}.", fp.path[i]);
41                    i += 1;
42                    current_serializer = serializer;
43                }
44                FieldModel::FixedTable(serializer) => {
45                    if fp.last + 1 == i {
46                        break;
47                    }
48                    name += ".";
49                    current_serializer = serializer;
50                }
51                FieldModel::Simple => break,
52            }
53            current_field = &current_serializer.fields[fp.path[i] as usize];
54        }
55        name
56    }
57
58    #[inline]
59    pub(crate) fn get_type_for_field_path(&self, fp: &FieldPath) -> &FieldType {
60        let mut i = 0;
61        let mut current_serializer = self;
62        let mut current_field = &current_serializer.fields[fp.path[i] as usize];
63        loop {
64            i += 1;
65            match &current_field.model {
66                FieldModel::Simple | FieldModel::FixedArray => {
67                    return current_field.field_type.as_ref()
68                }
69                FieldModel::FixedTable(serializer) => {
70                    if fp.last + 1 == i {
71                        return current_field.field_type.as_ref();
72                    }
73                    current_serializer = serializer;
74                }
75                FieldModel::VariableArray(_) => {
76                    if fp.last == i {
77                        return current_field.field_type.as_ref().generic.as_ref().unwrap();
78                    }
79                    return current_field.field_type.as_ref();
80                }
81                FieldModel::VariableTable(serializer) => {
82                    if i >= fp.last {
83                        return current_field.field_type.as_ref();
84                    }
85                    i += 1;
86                    current_serializer = serializer;
87                }
88            }
89            current_field = &current_serializer.fields[fp.path[i] as usize];
90        }
91    }
92
93    #[inline]
94    pub(crate) fn get_decoder_for_field_path(&self, fp: &FieldPath) -> &Decoder {
95        let mut i = 0;
96        let mut current_serializer = self;
97        let mut current_field = &current_serializer.fields[fp.path[i] as usize];
98        loop {
99            i += 1;
100            match &current_field.model {
101                FieldModel::Simple | FieldModel::FixedArray => return &current_field.decoder,
102                FieldModel::FixedTable(serializer) => {
103                    if fp.last + 1 == i {
104                        return &current_field.decoder;
105                    }
106                    current_serializer = serializer;
107                }
108                FieldModel::VariableArray(child_decoder) => {
109                    if fp.last == i {
110                        return child_decoder;
111                    }
112                    return &current_field.decoder;
113                }
114                FieldModel::VariableTable(serializer) => {
115                    if i >= fp.last {
116                        return &current_field.decoder;
117                    }
118                    i += 1;
119                    current_serializer = serializer;
120                }
121            }
122            current_field = &current_serializer.fields[fp.path[i] as usize];
123        }
124    }
125
126    #[inline]
127    pub(crate) fn get_field_path_for_name(&self, name: &str) -> Result<FieldPath, SerializerError> {
128        if !self.fp_cache.borrow().contains_key(name) {
129            let mut current_serializer = self;
130            let mut fp = FieldPath::new();
131            let mut offset = 0;
132            'outer: loop {
133                for (i, f) in current_serializer.fields.iter().enumerate() {
134                    if &name[offset..] == f.var_name.as_ref() {
135                        fp.path[fp.last] = i as u8;
136                        break 'outer;
137                    }
138                    if name[offset..].as_bytes().get(f.var_name.len()) == Some(&b"."[0])
139                        && &name[offset..(offset + f.var_name.len())] == f.var_name.as_ref()
140                    {
141                        fp.path[fp.last] = i as u8;
142                        fp.last += 1;
143                        offset += f.var_name.len() + 1;
144                        match &f.model {
145                            FieldModel::FixedArray | FieldModel::VariableArray(_) => {
146                                fp.path[fp.last] = name[offset..].parse::<u8>().unwrap();
147                                break 'outer;
148                            }
149                            FieldModel::FixedTable(serializer) => {
150                                current_serializer = serializer;
151                                continue 'outer;
152                            }
153                            FieldModel::VariableTable(serializer) => {
154                                fp.path[fp.last] =
155                                    name[offset..(offset + 4)].parse::<u8>().unwrap();
156                                fp.last += 1;
157                                offset += 5;
158                                current_serializer = serializer;
159                                continue 'outer;
160                            }
161                            FieldModel::Simple => unreachable!(),
162                        }
163                    }
164                }
165                return Err(SerializerError::NoFieldPath(name.to_string()));
166            }
167            self.fp_cache.borrow_mut().insert(name.into(), fp);
168        }
169        Ok(self.fp_cache.borrow()[name])
170    }
171
172    pub(crate) fn get_field_paths<'a>(
173        &'a self,
174        fp: &'a mut FieldPath,
175        st: &'a FieldState,
176    ) -> Vec<FieldPath> {
177        self.fields
178            .iter()
179            .enumerate()
180            .flat_map(|(i, f)| {
181                fp.path[fp.last] = i as u8;
182                f.get_field_paths(fp, st)
183            })
184            .collect::<Vec<_>>()
185    }
186}