vertigo/driver_module/js_value/
js_value_struct.rs1use std::collections::HashMap;
2
3use super::{
4 js_json_struct::{decode_js_json_inner, JsJson},
5 js_value_list_decoder::JsValueListDecoder,
6 memory_block::MemoryBlock,
7 memory_block_read::MemoryBlockRead,
8 memory_block_write::MemoryBlockWrite,
9};
10
11const PARAM_TYPE: u32 = 1;
12const STRING_SIZE: u32 = 4;
13const VEC_SIZE: u32 = 4;
14const LIST_COUNT: u32 = 4;
15const OBJECT_COUNT: u32 = 2;
16
17enum JsValueConst {
18 U32 = 1,
19 I32 = 2,
20 U64 = 3,
21 I64 = 4,
22 F64 = 5,
23
24 True = 6,
25 False = 7,
26 Null = 8,
27 Undefined = 9,
28
29 Vec = 10,
30 String = 11,
31 List = 12,
32 Object = 13,
33 Json = 14,
34}
35
36impl JsValueConst {
37 fn from_byte(byte: u8) -> Option<JsValueConst> {
38 match byte {
39 1 => Some(JsValueConst::U32),
40 2 => Some(JsValueConst::I32),
41 3 => Some(JsValueConst::U64),
42 4 => Some(JsValueConst::I64),
43 5 => Some(JsValueConst::F64),
44 6 => Some(JsValueConst::True),
45 7 => Some(JsValueConst::False),
46 8 => Some(JsValueConst::Null),
47 9 => Some(JsValueConst::Undefined),
48 10 => Some(JsValueConst::Vec),
49 11 => Some(JsValueConst::String),
50 12 => Some(JsValueConst::List),
51 13 => Some(JsValueConst::Object),
52 14 => Some(JsValueConst::Json),
53 _ => None,
54 }
55 }
56}
57
58impl From<JsValueConst> for u8 {
59 fn from(value: JsValueConst) -> Self {
60 value as u8
61 }
62}
63
64#[derive(Debug, PartialEq, Clone)]
66pub enum JsValue {
67 U32(u32),
68 I32(i32),
69 U64(u64),
70 I64(i64),
71 F64(f64),
72
73 True,
74 False,
75 Null,
76 Undefined,
77
78 Vec(Vec<u8>), String(String), List(Vec<JsValue>), Object(HashMap<String, JsValue>),
82
83 Json(JsJson),
84}
85
86impl JsValue {
87 pub fn str(value: impl Into<String>) -> JsValue {
88 JsValue::String(value.into())
89 }
90
91 pub fn from_block(block: MemoryBlock) -> Result<JsValue, std::string::String> {
92 let mut buffer = MemoryBlockRead::new(block);
93 decode_js_value_inner(&mut buffer)
94 }
95
96 pub fn bool(value: bool) -> JsValue {
97 if value {
98 JsValue::True
99 } else {
100 JsValue::False
101 }
102 }
103
104 pub fn string_option(value: Option<String>) -> JsValue {
105 match value {
106 Some(body) => JsValue::String(body),
107 None => JsValue::Null,
108 }
109 }
110
111 fn get_string_size(value: &str) -> u32 {
112 value.len() as u32
113 }
114
115 fn get_size(&self) -> u32 {
116 match self {
117 Self::U32(_) => PARAM_TYPE + 4,
118 Self::I32(_) => PARAM_TYPE + 4,
119 Self::U64(_) => PARAM_TYPE + 8,
120 Self::I64(_) => PARAM_TYPE + 8,
121 Self::F64(_) => PARAM_TYPE + 8,
122
123 Self::True => PARAM_TYPE,
124 Self::False => PARAM_TYPE,
125 Self::Null => PARAM_TYPE,
126 Self::Undefined => PARAM_TYPE,
127
128 Self::Vec(value) => PARAM_TYPE + VEC_SIZE + value.len() as u32,
129 Self::String(value) => PARAM_TYPE + STRING_SIZE + JsValue::get_string_size(value),
130 Self::List(items) => {
131 let mut sum = PARAM_TYPE + LIST_COUNT;
132
133 for param in items {
134 sum += param.get_size();
135 }
136
137 sum
138 }
139 Self::Object(map) => {
140 let mut sum = PARAM_TYPE + OBJECT_COUNT;
141
142 for (key, value) in map {
143 sum += STRING_SIZE + Self::get_string_size(key);
144 sum += value.get_size();
145 }
146
147 sum
148 }
149 Self::Json(json) => PARAM_TYPE + json.get_size(),
150 }
151 }
152
153 fn write_to(&self, buff: &mut MemoryBlockWrite) {
154 match self {
155 Self::U32(value) => {
156 buff.write_u8(JsValueConst::U32);
157 buff.write_u32(*value);
158 }
159 Self::I32(value) => {
160 buff.write_u8(JsValueConst::I32);
161 buff.write_i32(*value);
162 }
163 Self::U64(value) => {
164 buff.write_u8(JsValueConst::U64);
165 buff.write_u64(*value);
166 }
167 Self::I64(value) => {
168 buff.write_u8(JsValueConst::I64);
169 buff.write_i64(*value);
170 }
171 Self::F64(value)=> {
172 buff.write_u8(JsValueConst::F64);
173 buff.write_f64(*value);
174 }
175
176 Self::True => {
177 buff.write_u8(JsValueConst::True);
178 }
179 Self::False => {
180 buff.write_u8(JsValueConst::False);
181 }
182 Self::Null => {
183 buff.write_u8(JsValueConst::Null);
184 }
185 Self::Undefined => {
186 buff.write_u8(JsValueConst::Undefined);
187 }
188
189 Self::Vec(inner_buff) => {
190 buff.write_u8(JsValueConst::Vec);
191 let data = inner_buff.as_slice();
192 buff.write_u32(data.len() as u32);
193 buff.write(inner_buff.as_slice());
194 }
195 Self::String(value) => {
196 buff.write_u8(JsValueConst::String);
197 write_string_to(value.as_str(), buff);
198 }
199 Self::List(list) => {
200 buff.write_u8(JsValueConst::List);
201 buff.write_u32(list.len() as u32);
202
203 for param in list {
204 param.write_to(buff);
205 }
206 }
207 Self::Object(map) => {
208 buff.write_u8(JsValueConst::Object);
209 buff.write_u16(map.len() as u16);
210
211 for (key, value) in map {
212 write_string_to(key.as_str(), buff);
213 value.write_to(buff);
214 }
215 }
216 Self::Json(json) => {
217 buff.write_u8(JsValueConst::Json);
218 json.write_to(buff);
219 }
220 }
221 }
222
223 pub fn to_snapshot(&self) -> MemoryBlock {
224 let buff_size = self.get_size();
225 let block = MemoryBlock::new(buff_size);
226
227 let mut buff = MemoryBlockWrite::new(block);
228 self.write_to(&mut buff);
229 buff.get_block()
230 }
231
232 pub fn typename(&self) -> &'static str {
233 match self {
234 Self::U32(_) => "u32",
235 Self::I32(_) => "i32",
236 Self::U64(_) => "u64",
237 Self::I64(_) => "i64",
238 Self::F64(_) => "f64",
239 Self::True => "true",
240 Self::False => "false",
241 Self::Null => "null",
242 Self::Undefined => "undefined",
243 Self::Vec(_) => "vec",
244 Self::String(_) => "string",
245 Self::List(_) => "list",
246 Self::Object(_) => "object",
247 Self::Json(_) => "json",
248 }
249 }
250
251 pub fn convert<T, F: FnOnce(JsValueListDecoder) -> Result<T, String>>(
252 self,
253 convert: F,
254 ) -> Result<T, String> {
255 match self {
256 JsValue::List(list) => {
257 let decoder = JsValueListDecoder::new(list);
258 convert(decoder)
259 }
260 _ => Err(String::from("convert => ParamItem::Vec expected")),
261 }
262 }
263}
264
265impl Default for JsValue {
266 fn default() -> Self {
267 JsValue::List(Vec::new())
268 }
269}
270
271fn write_string_to(value: &str, buff: &mut MemoryBlockWrite) {
272 let data = value.as_bytes();
273 buff.write_u32(data.len() as u32);
274 buff.write(data);
275}
276
277fn decode_js_value_inner(buffer: &mut MemoryBlockRead) -> Result<JsValue, String> {
278 let type_param = buffer.get_byte();
279
280 let Some(type_param) = JsValueConst::from_byte(type_param) else {
281 return Err(format!("JsValue: Unknown data type prefix {type_param}"));
282 };
283
284 let result = match type_param {
285 JsValueConst::U32 => {
286 let value = buffer.get_u32();
287 JsValue::U32(value)
288 }
289 JsValueConst::I32 => {
290 let value = buffer.get_i32();
291 JsValue::I32(value)
292 }
293 JsValueConst::U64 => {
294 let value = buffer.get_u64();
295 JsValue::U64(value)
296 }
297 JsValueConst::I64 => {
298 let value = buffer.get_i64();
299 JsValue::I64(value)
300 }
301 JsValueConst::F64 => {
302 let value = buffer.get_f64();
303 JsValue::F64(value)
304 }
305 JsValueConst::True => JsValue::True,
306 JsValueConst::False => JsValue::False,
307 JsValueConst::Null => JsValue::Null,
308 JsValueConst::Undefined => JsValue::Undefined,
309 JsValueConst::Vec => {
310 let len = buffer.get_u32();
311 let param = buffer.get_vec(len);
312 JsValue::Vec(param)
313 }
314 JsValueConst::String => {
315 let str_len = buffer.get_u32();
316 let param = buffer.get_string(str_len)?;
317 JsValue::String(param)
318 }
319 JsValueConst::List => {
320 let mut param_list = Vec::new();
321
322 let list_size = buffer.get_u32();
323
324 for _ in 0..list_size {
325 let param = decode_js_value_inner(buffer)?;
326 param_list.push(param);
327 }
328
329 JsValue::List(param_list)
330 }
331 JsValueConst::Object => {
332 let mut props = HashMap::new();
333 let object_size = buffer.get_u16();
334
335 for _ in 0..object_size {
336 let prop_name = decode_js_value_inner(buffer)?;
337 let JsValue::String(prop_name) = prop_name else {
338 return Err("string expected".into());
339 };
340
341 let prop_value = decode_js_value_inner(buffer)?;
342
343 props.insert(prop_name, prop_value);
344 }
345
346 JsValue::Object(props)
347 }
348 JsValueConst::Json => {
349 let json = decode_js_json_inner(buffer)?;
350 JsValue::Json(json)
351 }
352 };
353
354 Ok(result)
355}
356
357macro_rules! impl_from {
358 ($from:ty, $to:ty, $js_type:ident) => {
359 impl From<$from> for JsValue {
360 fn from(value: $from) -> Self {
361 Self::$js_type(value as $to)
362 }
363 }
364 };
365}
366
367impl_from!(i8, i32, I32);
368impl_from!(i16, i32, I32);
369impl_from!(i32, i32, I32);
370impl_from!(i64, i64, I64);
371impl_from!(isize, i64, I64);
372
373impl_from!(u8, u32, U32);
374impl_from!(u16, u32, U32);
375impl_from!(u32, u32, U32);
376impl_from!(u64, u64, U64);
377impl_from!(usize, u64, U64);
378
379impl_from!(f64, f64, F64);
380
381impl From<&str> for JsValue {
382 fn from(value: &str) -> Self {
383 Self::str(value)
384 }
385}
386
387impl From<String> for JsValue {
388 fn from(value: String) -> Self {
389 Self::String(value)
390 }
391}
392
393impl From<bool> for JsValue {
394 fn from(value: bool) -> Self {
395 if value {
396 Self::True
397 } else {
398 Self::False
399 }
400 }
401}
402
403impl From<HashMap<String, JsValue>> for JsValue {
404 fn from(value: HashMap<String, JsValue>) -> Self {
405 Self::Object(value)
406 }
407}
408
409impl FromIterator<(String, JsValue)> for JsValue {
410 fn from_iter<T: IntoIterator<Item = (String, JsValue)>>(iter: T) -> Self {
411 let hash_map = HashMap::from_iter(iter);
412 JsValue::Object(hash_map)
413 }
414}
415
416impl From<Vec<(String, JsValue)>> for JsValue {
417 fn from(value: Vec<(String, JsValue)>) -> Self {
418 JsValue::from_iter(value)
419 }
420}
421
422impl<'a> FromIterator<(&'a str, JsValue)> for JsValue {
423 fn from_iter<T: IntoIterator<Item = (&'a str, JsValue)>>(iter: T) -> Self {
424 let iter = iter.into_iter()
425 .map(|(k, v)| (k.to_string(), v));
426 let hash_map = HashMap::from_iter(iter);
427 JsValue::Object(hash_map)
428 }
429}
430
431impl From<Vec<(&str, JsValue)>> for JsValue {
432 fn from(value: Vec<(&str, JsValue)>) -> Self {
433 JsValue::from_iter(value)
434 }
435}
436