weakauras_codec_lib_serialize/serialization/
mod.rs1use crate::{
8 EmbeddedTypeTag, FORMAT_VERSION, TypeTag, error::SerializationError, macros::check_recursion,
9};
10use weakauras_codec_lua_value::{LuaMapKey, LuaValue, Map};
11
12const TYPE_TAG_SHIFT: u8 = 3;
13const EMBEDDED_TYPE_TAG_SHIFT: u8 = 2;
14const EMBEDDED_LEN_SHIFT: u8 = 4;
15
16fn required_bytes(v: u64) -> u8 {
17 match v {
18 0..=255 => 1,
19 256..=65_535 => 2,
20 65_536..=16_777_215 => 3,
21 16_777_216..=4_294_967_295 => 4,
22 _ => 7,
23 }
24}
25
26pub struct Serializer {
42 remaining_depth: usize,
43 result: Vec<u8>,
44
45 string_refs: Map<String, usize>,
46}
47
48impl Serializer {
49 pub fn serialize_one(
51 value: &LuaValue,
52 approximate_len: Option<usize>,
53 ) -> Result<Vec<u8>, SerializationError> {
54 let mut serializer = Self {
55 remaining_depth: 128,
56 result: Vec::with_capacity(approximate_len.unwrap_or(1024)),
57
58 string_refs: Map::new(),
59 };
60
61 serializer.result.push(FORMAT_VERSION);
62 serializer.serialize_helper(value)?;
63
64 Ok(serializer.result)
65 }
66
67 fn serialize_helper(&mut self, value: &LuaValue) -> Result<(), SerializationError> {
68 match *value {
69 LuaValue::Null => self.result.push(TypeTag::Null.to_u8() << TYPE_TAG_SHIFT),
70 LuaValue::Boolean(b) => {
71 if b {
72 self.result.push(TypeTag::True.to_u8() << TYPE_TAG_SHIFT);
73 } else {
74 self.result.push(TypeTag::False.to_u8() << TYPE_TAG_SHIFT);
75 }
76 }
77 LuaValue::String(ref s) => self.serialize_string(s)?,
78 LuaValue::Number(n) => self.serialize_number(n),
79 LuaValue::Array(ref v) => self.serialize_slice(v)?,
80 LuaValue::Map(ref m) => self.serialize_map(m)?,
81 }
82
83 Ok(())
84 }
85
86 #[allow(clippy::manual_range_contains)]
87 fn serialize_number(&mut self, value: f64) {
88 const MAX_7_BIT: f64 = (2i64.pow(56) - 1) as f64;
89
90 if value.is_nan() {
91 self.result.push(TypeTag::Float.to_u8() << TYPE_TAG_SHIFT);
93 self.result
94 .extend_from_slice(&[0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
95 } else if value.fract() != 0.0 || (value < -MAX_7_BIT || value > MAX_7_BIT) {
96 self.result.push(TypeTag::Float.to_u8() << TYPE_TAG_SHIFT);
97 self.result.extend_from_slice(&value.to_be_bytes());
98 } else {
99 let value = unsafe { value.to_int_unchecked::<i64>() };
104
105 if value > -4096 && value < 4096 {
106 if value >= 0 && value < 128 {
107 self.result.push(((value as u8) << 1) | 1);
108 } else {
109 let (value, neg_bit) = if value < 0 {
110 (-value, 1 << TYPE_TAG_SHIFT)
111 } else {
112 (value, 0)
113 };
114
115 let value = (value << 4) | neg_bit | 4;
116 self.result.push(value as u8);
117 self.result.push((value >> 8) as u8);
118 }
119 } else {
120 let (value, neg_bit) = if value < 0 {
121 ((-value) as u64, 1)
122 } else {
123 (value as u64, 0)
124 };
125
126 match required_bytes(value) {
127 2 => {
128 self.result
129 .push((TypeTag::Int16Pos.to_u8() + neg_bit) << TYPE_TAG_SHIFT);
130 self.serialize_int(value, 2);
131 }
132 3 => {
133 self.result
134 .push((TypeTag::Int24Pos.to_u8() + neg_bit) << TYPE_TAG_SHIFT);
135 self.serialize_int(value, 3);
136 }
137 4 => {
138 self.result
139 .push((TypeTag::Int32Pos.to_u8() + neg_bit) << TYPE_TAG_SHIFT);
140 self.serialize_int(value, 4);
141 }
142 _ => {
143 self.result
144 .push((TypeTag::Int64Pos.to_u8() + neg_bit) << TYPE_TAG_SHIFT);
145 self.serialize_int(value, 7);
146 }
147 }
148 }
149 }
150 }
151
152 fn serialize_int(&mut self, value: u64, len: usize) {
153 let bytes = value.to_be_bytes();
154 self.result.extend_from_slice(&bytes[bytes.len() - len..]);
155 }
156
157 fn serialize_string(&mut self, value: &str) -> Result<(), SerializationError> {
158 match self.string_refs.get(value) {
159 Some(index) => {
160 let index = *index as u64;
161
162 match required_bytes(index) {
163 1 => {
164 self.result.push(TypeTag::StrRef8.to_u8() << TYPE_TAG_SHIFT);
165 self.serialize_int(index, 1);
166 }
167 2 => {
168 self.result
169 .push(TypeTag::StrRef16.to_u8() << TYPE_TAG_SHIFT);
170 self.serialize_int(index, 2);
171 }
172 3 => {
173 self.result
174 .push(TypeTag::StrRef24.to_u8() << TYPE_TAG_SHIFT);
175 self.serialize_int(index, 3);
176 }
177 _ => return Err(SerializationError::TooManyUniqueStrings),
178 }
179 }
180 None => {
181 let len = value.len();
182
183 if len < 16 {
184 self.result.push(
185 (EmbeddedTypeTag::Str.to_u8() << EMBEDDED_TYPE_TAG_SHIFT)
186 | ((len as u8) << EMBEDDED_LEN_SHIFT)
187 | 2,
188 );
189 } else {
190 let len = value.len() as u64;
191
192 match required_bytes(len) {
193 1 => {
194 self.result.push(TypeTag::Str8.to_u8() << TYPE_TAG_SHIFT);
195 self.serialize_int(len, 1);
196 }
197 2 => {
198 self.result.push(TypeTag::Str16.to_u8() << TYPE_TAG_SHIFT);
199 self.serialize_int(len, 2);
200 }
201 3 => {
202 self.result.push(TypeTag::Str24.to_u8() << TYPE_TAG_SHIFT);
203 self.serialize_int(len, 3);
204 }
205 _ => return Err(SerializationError::StringIsTooLarge),
206 }
207 }
208
209 if len > 2 {
210 self.string_refs
211 .insert(value.into(), self.string_refs.len() + 1);
212 }
213
214 self.result.extend_from_slice(value.as_bytes());
215 }
216 }
217
218 Ok(())
219 }
220
221 fn serialize_map(&mut self, map: &Map<LuaMapKey, LuaValue>) -> Result<(), SerializationError> {
222 let len = map.len();
223 if len < 16 {
224 self.result.push(
225 (EmbeddedTypeTag::Map.to_u8() << EMBEDDED_TYPE_TAG_SHIFT)
226 | ((len as u8) << EMBEDDED_LEN_SHIFT)
227 | 2,
228 );
229 } else {
230 let len = len as u64;
231 match required_bytes(len) {
232 1 => {
233 self.result.push(TypeTag::Map8.to_u8() << TYPE_TAG_SHIFT);
234 self.serialize_int(len, 1);
235 }
236 2 => {
237 self.result.push(TypeTag::Map16.to_u8() << TYPE_TAG_SHIFT);
238 self.serialize_int(len, 2);
239 }
240 3 => {
241 self.result.push(TypeTag::Map24.to_u8() << TYPE_TAG_SHIFT);
242 self.serialize_int(len, 3);
243 }
244 _ => return Err(SerializationError::MapIsTooLarge),
245 }
246 }
247
248 for (key, value) in map {
249 check_recursion!(self, SerializationError, {
250 self.serialize_helper(key.as_value())?;
251 self.serialize_helper(value)?;
252 });
253 }
254
255 Ok(())
256 }
257
258 fn serialize_slice(&mut self, slice: &[LuaValue]) -> Result<(), SerializationError> {
259 let len = slice.len();
260 if len < 16 {
261 self.result.push(
262 (EmbeddedTypeTag::Array.to_u8() << EMBEDDED_TYPE_TAG_SHIFT)
263 | ((len as u8) << EMBEDDED_LEN_SHIFT)
264 | 2,
265 );
266 } else {
267 let len = len as u64;
268 match required_bytes(len) {
269 1 => {
270 self.result.push(TypeTag::Array8.to_u8() << TYPE_TAG_SHIFT);
271 self.serialize_int(len, 1);
272 }
273 2 => {
274 self.result.push(TypeTag::Array16.to_u8() << TYPE_TAG_SHIFT);
275 self.serialize_int(len, 2);
276 }
277 3 => {
278 self.result.push(TypeTag::Array24.to_u8() << TYPE_TAG_SHIFT);
279 self.serialize_int(len, 3);
280 }
281 _ => return Err(SerializationError::ArrayIsTooLarge),
282 }
283 }
284
285 for el in slice {
286 check_recursion!(self, SerializationError, {
287 self.serialize_helper(el)?;
288 });
289 }
290
291 Ok(())
292 }
293}