d2_stampede/
serializer.rs1use 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 = ¤t_serializer.fields[fp.path[i] as usize];
25 let mut name = String::new();
26 loop {
27 name += ¤t_field.var_name;
28 i += 1;
29 match ¤t_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 = ¤t_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 = ¤t_serializer.fields[fp.path[i] as usize];
63 loop {
64 i += 1;
65 match ¤t_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 = ¤t_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 = ¤t_serializer.fields[fp.path[i] as usize];
98 loop {
99 i += 1;
100 match ¤t_field.model {
101 FieldModel::Simple | FieldModel::FixedArray => return ¤t_field.decoder,
102 FieldModel::FixedTable(serializer) => {
103 if fp.last + 1 == i {
104 return ¤t_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 ¤t_field.decoder;
113 }
114 FieldModel::VariableTable(serializer) => {
115 if i >= fp.last {
116 return ¤t_field.decoder;
117 }
118 i += 1;
119 current_serializer = serializer;
120 }
121 }
122 current_field = ¤t_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}