serde_hkx/bytes/ser/sub_ser/
structs.rs
1use crate::{align, lib::*, tri};
2
3use super::super::ByteSerializer;
4use crate::errors::ser::{Error, Result};
5use havok_serde::ser::{Serialize, SerializeStruct, Serializer, TypeSize};
6use havok_types::Ulong;
7use std::io::Write as _;
8
9pub struct StructSerializer<'a> {
14 ser: &'a mut ByteSerializer,
15 is_root: bool,
16}
17
18impl<'a> StructSerializer<'a> {
19 pub const fn new(ser: &'a mut ByteSerializer, is_root: bool) -> Self {
20 Self { ser, is_root }
21 }
22
23 fn serialize_array_inner<V, T>(
25 &mut self,
26 array: V,
27 size: TypeSize,
28 local_src: u32,
29 ) -> Result<()>
30 where
31 V: AsRef<[T]> + Serialize,
32 T: Serialize,
33 {
34 let next_src_pos = self.ser.output.position();
35
36 {
37 let pointed_pos = tri!(self.ser.goto_local_dst());
38 self.ser.write_local_fixup_pair(local_src, pointed_pos)?;
39 }
40 let array_base_pos = self.ser.current_last_local_dst;
41
42 let len = array.as_ref().len() as u32;
44 match size {
45 TypeSize::Struct {
46 size_x86,
47 size_x86_64,
48 } => {
49 let one_size = if self.ser.is_x86 {
50 size_x86
51 } else {
52 size_x86_64
53 };
54 let mut write_pointed_pos = { array_base_pos + (one_size * (len as u64)) };
55 #[cfg(feature = "tracing")]
56 tracing::trace!(
57 "Calculate Struct of Array local dst: array_base_pos({array_base_pos:#x}) + one_size({one_size}) * len({len}) = {write_pointed_pos:#x}"
58 );
59
60 if self.ser.pointed_pos.len() >= 2 {
63 let new_write_pointed_pos = align!(write_pointed_pos, 16_u64);
64 #[cfg(feature = "tracing")]
65 tracing::trace!(
66 "Apply special align16 to `next_struct_local_dst` because the hkArray is nested twice: {write_pointed_pos:#x} -> {new_write_pointed_pos:#x}"
67 );
68 write_pointed_pos = new_write_pointed_pos;
69 }
70 self.ser.pointed_pos.push(write_pointed_pos); }
72 TypeSize::String => {
73 self.ser.is_in_str_array = true;
74 let one_size = if self.ser.is_x86 { 4 } else { 8 };
75 let write_pointed_pos = { array_base_pos + (one_size * (len as u64)) };
76
77 #[cfg(feature = "tracing")]
78 tracing::trace!(
79 "Calculate String of Array local dst: array_base_pos({array_base_pos:#x}) + one_size({one_size}) * len({len}) = {write_pointed_pos:#x}"
80 );
81
82 self.ser.pointed_pos.push(write_pointed_pos); }
84 TypeSize::NonPtr => {}
85 }
86 #[cfg(feature = "tracing")]
87 tracing::trace!("pointed_pos:({:#x?})", self.ser.pointed_pos);
88
89 tri!(array.serialize(&mut *self.ser));
90 self.ser.is_in_str_array = false;
91
92 if size == TypeSize::NonPtr {
93 let next_pointed_ser_pos = align!(self.ser.output.position(), 16_u64);
94 self.ser.current_last_local_dst = next_pointed_ser_pos;
95 if let Some(last) = self.ser.pointed_pos.last_mut() {
96 *last = next_pointed_ser_pos; };
98 } else {
99 let pos = tri!(
101 self.ser
102 .pointed_pos
103 .pop()
104 .ok_or(Error::NotFoundPointedPosition)
105 );
106 let pos = align!(pos, 16_u64);
107 if let Some(last) = self.ser.pointed_pos.last_mut() {
108 *last = pos;
109 };
110 self.ser.current_last_local_dst = pos;
111 }
112
113 self.ser.output.set_position(next_src_pos); Ok(())
115 }
116
117 fn serialize_array_fixed<V, T>(
119 &mut self,
120 array: V,
121 size: TypeSize,
122 local_src: u32,
123 ) -> Result<()>
124 where
125 V: AsRef<[T]> + Serialize,
126 T: Serialize,
127 {
128 let need_local_jump = size != TypeSize::NonPtr;
129 if need_local_jump {
130 let pointed_pos = tri!(self.ser.goto_local_dst());
131 let array_base_pos = self.ser.current_last_local_dst;
132 self.ser.write_local_fixup_pair(local_src, pointed_pos)?;
133
134 let len = array.as_ref().len() as u32;
136 match size {
137 TypeSize::Struct {
138 size_x86,
139 size_x86_64,
140 } => {
141 let write_pointed_pos = {
142 let one_size = if self.ser.is_x86 {
143 size_x86
144 } else {
145 size_x86_64
146 };
147 array_base_pos + (one_size * (len as u64))
148 }; self.ser.pointed_pos.push(write_pointed_pos); }
151 TypeSize::String => {
152 let write_pointed_pos = {
153 let one_size = if self.ser.is_x86 { 4 } else { 8 };
154 array_base_pos + (one_size * (len as u64))
155 }; self.ser.pointed_pos.push(write_pointed_pos); }
159 TypeSize::NonPtr => {}
160 }
161 };
162 #[cfg(feature = "tracing")]
163 tracing::trace!("pointed_pos:({:#x?})", self.ser.pointed_pos);
164
165 tri!(array.serialize(&mut *self.ser));
166
167 if size != TypeSize::NonPtr {
168 let pos = tri!(
170 self.ser
171 .pointed_pos
172 .pop()
173 .ok_or(Error::NotFoundPointedPosition)
174 );
175 if let Some(last) = self.ser.pointed_pos.last_mut() {
176 *last = pos;
177 };
178 }
179 Ok(())
180 }
181}
182
183impl SerializeStruct for StructSerializer<'_> {
184 type Ok = ();
185 type Error = Error;
186
187 #[inline]
188 fn serialize_field<T>(&mut self, _key: &'static str, value: &T) -> Result<()>
189 where
190 T: ?Sized + Serialize,
191 {
192 #[cfg(feature = "tracing")]
193 tracing::trace!("serialize field({:#x}): {_key}", self.ser.output.position());
194 value.serialize(&mut *self.ser)
195 }
196
197 #[inline]
199 fn skip_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
200 where
201 T: ?Sized + Serialize,
202 {
203 self.serialize_field(key, value)
204 }
205
206 fn pad_field<T>(&mut self, x86_pads: &T, x64_pads: &T) -> Result<()>
207 where
208 T: ?Sized + AsRef<[u8]>,
209 {
210 let pads = match self.ser.is_x86 {
211 true => x86_pads.as_ref(),
212 false => x64_pads.as_ref(),
213 };
214
215 if pads.is_empty() {
216 return Ok(());
217 };
218 self.ser.output.write_all(pads)?;
219 #[cfg(feature = "tracing")]
220 {
221 let pads_len = pads.len();
222 let current_position = self.ser.output.position();
223 tracing::trace!("padding: {pads_len} -> current position: {current_position:#x}");
224 }
225 Ok(())
226 }
227
228 #[inline]
232 fn serialize_fixed_array_field<V, T>(
233 &mut self,
234 _key: &'static str,
235 value: V,
236 size: TypeSize,
237 ) -> Result<()>
238 where
239 V: AsRef<[T]> + Serialize,
240 T: Serialize,
241 {
242 #[cfg(feature = "tracing")]
243 tracing::trace!(
244 "serialize FixedArray field({:#x}): {_key}",
245 self.ser.output.position()
246 );
247
248 if value.as_ref().is_empty() {
249 return Ok(());
250 }
251 let start_relative = tri!(self.ser.relative_position()); self.serialize_array_fixed(value, size, start_relative)
253 }
254
255 #[inline]
256 fn skip_fixed_array_field<V, T>(
257 &mut self,
258 key: &'static str,
259 value: V,
260 size: TypeSize,
261 ) -> Result<()>
262 where
263 V: AsRef<[T]> + Serialize,
264 T: Serialize,
265 {
266 self.serialize_fixed_array_field(key, value, size)
267 }
268
269 fn serialize_array_field<V, T>(
278 &mut self,
279 _key: &'static str,
280 value: V,
281 size: TypeSize,
282 ) -> Result<()>
283 where
284 V: AsRef<[T]> + Serialize,
285 T: Serialize,
286 {
287 #[cfg(feature = "tracing")]
288 tracing::trace!(
289 "serialize Array field({:#x}): {_key}",
290 self.ser.output.position()
291 );
292
293 let local_src = tri!(self.ser.relative_position()); tri!(self.ser.serialize_ulong(Ulong::new(0))); let len = value.as_ref().len() as u32;
296 tri!(self.ser.serialize_uint32(len)); tri!(self.ser.serialize_uint32(len | (1 << 31))); if len == 0 {
300 return Ok(());
301 }
302 self.serialize_array_inner(value, size, local_src)
303 }
304
305 #[inline]
306 fn skip_array_field<V, T>(&mut self, key: &'static str, value: V, size: TypeSize) -> Result<()>
307 where
308 V: AsRef<[T]> + Serialize,
309 T: Serialize,
310 {
311 self.serialize_array_field(key, value, size)
312 }
313
314 #[inline]
317 fn end(self) -> Result<()> {
318 if self.is_root {
319 #[cfg(feature = "tracing")]
320 tracing::trace!("pointed_pos:({:#x?})", self.ser.pointed_pos);
321 self.ser.pointed_pos.clear();
322
323 #[cfg(feature = "tracing")]
324 tracing::trace!("current_last_pos:({:#x?})", self.ser.current_last_local_dst);
325 self.ser
326 .output
327 .set_position(self.ser.current_last_local_dst);
328 }
329 Ok(())
330 }
331}