Skip to main content

proof_engine/save/
serializer.rs

1//! Custom serialization layer for the save system.
2//!
3//! `SerializedValue` is a JSON-compatible value enum. The `Serialize` and
4//! `Deserialize` traits let any game type opt into save/load support without
5//! pulling in serde.
6//!
7//! A simple hand-written JSON encoder/decoder is included so save files are
8//! human-readable without any extra dependencies.
9
10use std::any::{Any, TypeId};
11use std::collections::HashMap;
12use glam::{Vec2, Vec3};
13
14// ─────────────────────────────────────────────
15//  DeserializeError
16// ─────────────────────────────────────────────
17
18/// Errors that can occur during deserialization.
19#[derive(Debug, Clone, PartialEq, Eq)]
20pub enum DeserializeError {
21    /// The value was the wrong variant (e.g. expected Int, got Str).
22    WrongType { expected: &'static str, got: &'static str },
23    /// A required key was missing from a Map.
24    MissingKey(String),
25    /// A list index was out of bounds.
26    IndexOutOfBounds { index: usize, len: usize },
27    /// The string could not be parsed as the target type.
28    ParseError(String),
29    /// A catch-all for structural/logic errors.
30    Custom(String),
31}
32
33impl std::fmt::Display for DeserializeError {
34    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35        match self {
36            DeserializeError::WrongType { expected, got } => {
37                write!(f, "type mismatch: expected {expected}, got {got}")
38            }
39            DeserializeError::MissingKey(k) => write!(f, "missing key: '{k}'"),
40            DeserializeError::IndexOutOfBounds { index, len } => {
41                write!(f, "index {index} out of bounds (len {len})")
42            }
43            DeserializeError::ParseError(s) => write!(f, "parse error: {s}"),
44            DeserializeError::Custom(s) => write!(f, "{s}"),
45        }
46    }
47}
48
49impl std::error::Error for DeserializeError {}
50
51// ─────────────────────────────────────────────
52//  SerializedValue
53// ─────────────────────────────────────────────
54
55/// A generic serialized value, analogous to `serde_json::Value`.
56#[derive(Debug, Clone, PartialEq)]
57pub enum SerializedValue {
58    Null,
59    Bool(bool),
60    Int(i64),
61    Float(f64),
62    Str(String),
63    Bytes(Vec<u8>),
64    List(Vec<SerializedValue>),
65    Map(HashMap<String, SerializedValue>),
66}
67
68impl SerializedValue {
69    // ── Constructors ───────────────────────────────────────────────────────
70
71    pub fn null() -> Self { SerializedValue::Null }
72    pub fn bool(b: bool) -> Self { SerializedValue::Bool(b) }
73    pub fn int(i: i64) -> Self { SerializedValue::Int(i) }
74    pub fn float(f: f64) -> Self { SerializedValue::Float(f) }
75    pub fn str(s: impl Into<String>) -> Self { SerializedValue::Str(s.into()) }
76    pub fn bytes(b: Vec<u8>) -> Self { SerializedValue::Bytes(b) }
77    pub fn list(v: Vec<SerializedValue>) -> Self { SerializedValue::List(v) }
78    pub fn map(m: HashMap<String, SerializedValue>) -> Self { SerializedValue::Map(m) }
79
80    pub fn empty_map() -> Self {
81        SerializedValue::Map(HashMap::new())
82    }
83
84    pub fn empty_list() -> Self {
85        SerializedValue::List(Vec::new())
86    }
87
88    // ── Type accessors ─────────────────────────────────────────────────────
89
90    pub fn as_bool(&self) -> Option<bool> {
91        if let SerializedValue::Bool(b) = self { Some(*b) } else { None }
92    }
93
94    pub fn as_int(&self) -> Option<i64> {
95        match self {
96            SerializedValue::Int(i) => Some(*i),
97            SerializedValue::Float(f) => Some(*f as i64),
98            _ => None,
99        }
100    }
101
102    pub fn as_float(&self) -> Option<f64> {
103        match self {
104            SerializedValue::Float(f) => Some(*f),
105            SerializedValue::Int(i) => Some(*i as f64),
106            _ => None,
107        }
108    }
109
110    pub fn as_str(&self) -> Option<&str> {
111        if let SerializedValue::Str(s) = self { Some(s.as_str()) } else { None }
112    }
113
114    pub fn as_bytes(&self) -> Option<&[u8]> {
115        if let SerializedValue::Bytes(b) = self { Some(b.as_slice()) } else { None }
116    }
117
118    pub fn as_list(&self) -> Option<&[SerializedValue]> {
119        if let SerializedValue::List(v) = self { Some(v.as_slice()) } else { None }
120    }
121
122    pub fn as_map(&self) -> Option<&HashMap<String, SerializedValue>> {
123        if let SerializedValue::Map(m) = self { Some(m) } else { None }
124    }
125
126    pub fn as_map_mut(&mut self) -> Option<&mut HashMap<String, SerializedValue>> {
127        if let SerializedValue::Map(m) = self { Some(m) } else { None }
128    }
129
130    pub fn is_null(&self) -> bool {
131        matches!(self, SerializedValue::Null)
132    }
133
134    // ── Key / index access ─────────────────────────────────────────────────
135
136    /// Get a value from a Map by key.
137    pub fn get(&self, key: &str) -> Option<&SerializedValue> {
138        self.as_map()?.get(key)
139    }
140
141    /// Get a value from a List by index.
142    pub fn index(&self, i: usize) -> Option<&SerializedValue> {
143        self.as_list()?.get(i)
144    }
145
146    /// Insert a key-value pair into a Map. Returns `false` if `self` is not a Map.
147    pub fn insert(&mut self, key: impl Into<String>, value: SerializedValue) -> bool {
148        if let SerializedValue::Map(m) = self {
149            m.insert(key.into(), value);
150            true
151        } else {
152            false
153        }
154    }
155
156    /// Push a value into a List. Returns `false` if `self` is not a List.
157    pub fn push(&mut self, value: SerializedValue) -> bool {
158        if let SerializedValue::List(v) = self {
159            v.push(value);
160            true
161        } else {
162            false
163        }
164    }
165
166    /// The variant name as a static string (for error messages).
167    pub fn type_name(&self) -> &'static str {
168        match self {
169            SerializedValue::Null => "Null",
170            SerializedValue::Bool(_) => "Bool",
171            SerializedValue::Int(_) => "Int",
172            SerializedValue::Float(_) => "Float",
173            SerializedValue::Str(_) => "Str",
174            SerializedValue::Bytes(_) => "Bytes",
175            SerializedValue::List(_) => "List",
176            SerializedValue::Map(_) => "Map",
177        }
178    }
179
180    // ── JSON encoding ──────────────────────────────────────────────────────
181
182    /// Encode to a JSON string. Bytes are encoded as a base64-like hex string.
183    pub fn to_json_string(&self) -> String {
184        let mut buf = String::with_capacity(64);
185        self.write_json(&mut buf);
186        buf
187    }
188
189    fn write_json(&self, buf: &mut String) {
190        match self {
191            SerializedValue::Null => buf.push_str("null"),
192            SerializedValue::Bool(b) => buf.push_str(if *b { "true" } else { "false" }),
193            SerializedValue::Int(i) => buf.push_str(&i.to_string()),
194            SerializedValue::Float(f) => {
195                if f.is_nan() {
196                    buf.push_str("null"); // JSON has no NaN
197                } else if f.is_infinite() {
198                    buf.push_str(if *f > 0.0 { "1e308" } else { "-1e308" });
199                } else {
200                    buf.push_str(&format!("{f:?}"));
201                }
202            }
203            SerializedValue::Str(s) => {
204                buf.push('"');
205                for ch in s.chars() {
206                    match ch {
207                        '"' => buf.push_str("\\\""),
208                        '\\' => buf.push_str("\\\\"),
209                        '\n' => buf.push_str("\\n"),
210                        '\r' => buf.push_str("\\r"),
211                        '\t' => buf.push_str("\\t"),
212                        c if (c as u32) < 0x20 => {
213                            buf.push_str(&format!("\\u{:04x}", c as u32));
214                        }
215                        c => buf.push(c),
216                    }
217                }
218                buf.push('"');
219            }
220            SerializedValue::Bytes(bytes) => {
221                // Encode as a JSON string containing lowercase hex
222                buf.push('"');
223                for b in bytes {
224                    buf.push_str(&format!("{b:02x}"));
225                }
226                buf.push('"');
227            }
228            SerializedValue::List(items) => {
229                buf.push('[');
230                for (i, item) in items.iter().enumerate() {
231                    if i > 0 {
232                        buf.push(',');
233                    }
234                    item.write_json(buf);
235                }
236                buf.push(']');
237            }
238            SerializedValue::Map(m) => {
239                buf.push('{');
240                let mut first = true;
241                // Sort keys for deterministic output
242                let mut keys: Vec<&String> = m.keys().collect();
243                keys.sort();
244                for key in keys {
245                    if !first {
246                        buf.push(',');
247                    }
248                    first = false;
249                    SerializedValue::Str(key.clone()).write_json(buf);
250                    buf.push(':');
251                    m[key].write_json(buf);
252                }
253                buf.push('}');
254            }
255        }
256    }
257
258    // ── JSON decoding ──────────────────────────────────────────────────────
259
260    /// Parse a JSON string into a `SerializedValue`.
261    pub fn from_json_str(s: &str) -> Result<Self, DeserializeError> {
262        let mut parser = JsonParser::new(s.trim());
263        let v = parser.parse_value()?;
264        parser.skip_whitespace();
265        Ok(v)
266    }
267}
268
269impl Default for SerializedValue {
270    fn default() -> Self {
271        SerializedValue::Null
272    }
273}
274
275// ─────────────────────────────────────────────
276//  Minimal JSON parser
277// ─────────────────────────────────────────────
278
279struct JsonParser<'a> {
280    src: &'a [u8],
281    pos: usize,
282}
283
284impl<'a> JsonParser<'a> {
285    fn new(s: &'a str) -> Self {
286        Self { src: s.as_bytes(), pos: 0 }
287    }
288
289    fn skip_whitespace(&mut self) {
290        while self.pos < self.src.len() && self.src[self.pos].is_ascii_whitespace() {
291            self.pos += 1;
292        }
293    }
294
295    fn peek(&self) -> Option<u8> {
296        self.src.get(self.pos).copied()
297    }
298
299    fn consume(&mut self) -> Option<u8> {
300        if self.pos < self.src.len() {
301            let b = self.src[self.pos];
302            self.pos += 1;
303            Some(b)
304        } else {
305            None
306        }
307    }
308
309    fn expect(&mut self, b: u8) -> Result<(), DeserializeError> {
310        match self.consume() {
311            Some(got) if got == b => Ok(()),
312            Some(got) => Err(DeserializeError::ParseError(format!(
313                "expected '{}' got '{}'",
314                b as char, got as char
315            ))),
316            None => Err(DeserializeError::ParseError("unexpected EOF".into())),
317        }
318    }
319
320    fn parse_value(&mut self) -> Result<SerializedValue, DeserializeError> {
321        self.skip_whitespace();
322        match self.peek() {
323            Some(b'n') => self.parse_null(),
324            Some(b't') | Some(b'f') => self.parse_bool(),
325            Some(b'"') => self.parse_string(),
326            Some(b'[') => self.parse_array(),
327            Some(b'{') => self.parse_object(),
328            Some(b'-') | Some(b'0'..=b'9') => self.parse_number(),
329            Some(c) => Err(DeserializeError::ParseError(format!("unexpected char '{}'", c as char))),
330            None => Err(DeserializeError::ParseError("unexpected EOF".into())),
331        }
332    }
333
334    fn parse_null(&mut self) -> Result<SerializedValue, DeserializeError> {
335        self.expect(b'n')?;
336        self.expect(b'u')?;
337        self.expect(b'l')?;
338        self.expect(b'l')?;
339        Ok(SerializedValue::Null)
340    }
341
342    fn parse_bool(&mut self) -> Result<SerializedValue, DeserializeError> {
343        if self.peek() == Some(b't') {
344            self.expect(b't')?; self.expect(b'r')?; self.expect(b'u')?; self.expect(b'e')?;
345            Ok(SerializedValue::Bool(true))
346        } else {
347            self.expect(b'f')?; self.expect(b'a')?; self.expect(b'l')?; self.expect(b's')?; self.expect(b'e')?;
348            Ok(SerializedValue::Bool(false))
349        }
350    }
351
352    fn parse_string(&mut self) -> Result<SerializedValue, DeserializeError> {
353        self.expect(b'"')?;
354        let mut s = String::new();
355        loop {
356            match self.consume() {
357                Some(b'"') => break,
358                Some(b'\\') => {
359                    match self.consume() {
360                        Some(b'"') => s.push('"'),
361                        Some(b'\\') => s.push('\\'),
362                        Some(b'/') => s.push('/'),
363                        Some(b'n') => s.push('\n'),
364                        Some(b'r') => s.push('\r'),
365                        Some(b't') => s.push('\t'),
366                        Some(b'u') => {
367                            // Read 4 hex digits
368                            let mut hex = String::new();
369                            for _ in 0..4 {
370                                hex.push(self.consume().unwrap_or(b'0') as char);
371                            }
372                            let code = u32::from_str_radix(&hex, 16).unwrap_or(0xFFFD);
373                            s.push(char::from_u32(code).unwrap_or('\u{FFFD}'));
374                        }
375                        Some(c) => s.push(c as char),
376                        None => return Err(DeserializeError::ParseError("unterminated string".into())),
377                    }
378                }
379                Some(c) => s.push(c as char),
380                None => return Err(DeserializeError::ParseError("unterminated string".into())),
381            }
382        }
383        Ok(SerializedValue::Str(s))
384    }
385
386    fn parse_number(&mut self) -> Result<SerializedValue, DeserializeError> {
387        let start = self.pos;
388        if self.peek() == Some(b'-') { self.pos += 1; }
389        while matches!(self.peek(), Some(b'0'..=b'9')) { self.pos += 1; }
390        let is_float = matches!(self.peek(), Some(b'.') | Some(b'e') | Some(b'E'));
391        if is_float {
392            if self.peek() == Some(b'.') {
393                self.pos += 1;
394                while matches!(self.peek(), Some(b'0'..=b'9')) { self.pos += 1; }
395            }
396            if matches!(self.peek(), Some(b'e') | Some(b'E')) {
397                self.pos += 1;
398                if matches!(self.peek(), Some(b'+') | Some(b'-')) { self.pos += 1; }
399                while matches!(self.peek(), Some(b'0'..=b'9')) { self.pos += 1; }
400            }
401        }
402        let slice = std::str::from_utf8(&self.src[start..self.pos])
403            .map_err(|e| DeserializeError::ParseError(e.to_string()))?;
404        if is_float {
405            let f: f64 = slice.parse()
406                .map_err(|e: std::num::ParseFloatError| DeserializeError::ParseError(e.to_string()))?;
407            Ok(SerializedValue::Float(f))
408        } else {
409            let i: i64 = slice.parse()
410                .map_err(|e: std::num::ParseIntError| DeserializeError::ParseError(e.to_string()))?;
411            Ok(SerializedValue::Int(i))
412        }
413    }
414
415    fn parse_array(&mut self) -> Result<SerializedValue, DeserializeError> {
416        self.expect(b'[')?;
417        let mut items = Vec::new();
418        self.skip_whitespace();
419        if self.peek() == Some(b']') {
420            self.pos += 1;
421            return Ok(SerializedValue::List(items));
422        }
423        loop {
424            items.push(self.parse_value()?);
425            self.skip_whitespace();
426            match self.peek() {
427                Some(b',') => { self.pos += 1; }
428                Some(b']') => { self.pos += 1; break; }
429                Some(c) => return Err(DeserializeError::ParseError(format!("expected ',' or ']' got '{}'", c as char))),
430                None => return Err(DeserializeError::ParseError("unterminated array".into())),
431            }
432        }
433        Ok(SerializedValue::List(items))
434    }
435
436    fn parse_object(&mut self) -> Result<SerializedValue, DeserializeError> {
437        self.expect(b'{')?;
438        let mut map = HashMap::new();
439        self.skip_whitespace();
440        if self.peek() == Some(b'}') {
441            self.pos += 1;
442            return Ok(SerializedValue::Map(map));
443        }
444        loop {
445            self.skip_whitespace();
446            let key_val = self.parse_string()?;
447            let key = match key_val {
448                SerializedValue::Str(s) => s,
449                _ => return Err(DeserializeError::ParseError("expected string key".into())),
450            };
451            self.skip_whitespace();
452            self.expect(b':')?;
453            let value = self.parse_value()?;
454            map.insert(key, value);
455            self.skip_whitespace();
456            match self.peek() {
457                Some(b',') => { self.pos += 1; }
458                Some(b'}') => { self.pos += 1; break; }
459                Some(c) => return Err(DeserializeError::ParseError(format!("expected ',' or '}}' got '{}'", c as char))),
460                None => return Err(DeserializeError::ParseError("unterminated object".into())),
461            }
462        }
463        Ok(SerializedValue::Map(map))
464    }
465}
466
467// ─────────────────────────────────────────────
468//  Serialize / Deserialize traits
469// ─────────────────────────────────────────────
470
471/// Convert a value to a `SerializedValue`.
472pub trait Serialize {
473    fn serialize(&self) -> SerializedValue;
474}
475
476/// Reconstruct a value from a `SerializedValue`.
477pub trait Deserialize: Sized {
478    fn deserialize(v: &SerializedValue) -> Result<Self, DeserializeError>;
479}
480
481// ── bool ───────────────────────────────────────────────────────────────────
482
483impl Serialize for bool {
484    fn serialize(&self) -> SerializedValue { SerializedValue::Bool(*self) }
485}
486
487impl Deserialize for bool {
488    fn deserialize(v: &SerializedValue) -> Result<Self, DeserializeError> {
489        v.as_bool().ok_or(DeserializeError::WrongType { expected: "Bool", got: v.type_name() })
490    }
491}
492
493// ── i32 ───────────────────────────────────────────────────────────────────
494
495impl Serialize for i32 {
496    fn serialize(&self) -> SerializedValue { SerializedValue::Int(*self as i64) }
497}
498
499impl Deserialize for i32 {
500    fn deserialize(v: &SerializedValue) -> Result<Self, DeserializeError> {
501        v.as_int().map(|i| i as i32)
502            .ok_or(DeserializeError::WrongType { expected: "Int", got: v.type_name() })
503    }
504}
505
506// ── i64 ───────────────────────────────────────────────────────────────────
507
508impl Serialize for i64 {
509    fn serialize(&self) -> SerializedValue { SerializedValue::Int(*self) }
510}
511
512impl Deserialize for i64 {
513    fn deserialize(v: &SerializedValue) -> Result<Self, DeserializeError> {
514        v.as_int().ok_or(DeserializeError::WrongType { expected: "Int", got: v.type_name() })
515    }
516}
517
518// ── u32 ───────────────────────────────────────────────────────────────────
519
520impl Serialize for u32 {
521    fn serialize(&self) -> SerializedValue { SerializedValue::Int(*self as i64) }
522}
523
524impl Deserialize for u32 {
525    fn deserialize(v: &SerializedValue) -> Result<Self, DeserializeError> {
526        v.as_int().map(|i| i as u32)
527            .ok_or(DeserializeError::WrongType { expected: "Int", got: v.type_name() })
528    }
529}
530
531// ── u64 ───────────────────────────────────────────────────────────────────
532
533impl Serialize for u64 {
534    fn serialize(&self) -> SerializedValue { SerializedValue::Int(*self as i64) }
535}
536
537impl Deserialize for u64 {
538    fn deserialize(v: &SerializedValue) -> Result<Self, DeserializeError> {
539        v.as_int().map(|i| i as u64)
540            .ok_or(DeserializeError::WrongType { expected: "Int", got: v.type_name() })
541    }
542}
543
544// ── f32 ───────────────────────────────────────────────────────────────────
545
546impl Serialize for f32 {
547    fn serialize(&self) -> SerializedValue { SerializedValue::Float(*self as f64) }
548}
549
550impl Deserialize for f32 {
551    fn deserialize(v: &SerializedValue) -> Result<Self, DeserializeError> {
552        v.as_float().map(|f| f as f32)
553            .ok_or(DeserializeError::WrongType { expected: "Float", got: v.type_name() })
554    }
555}
556
557// ── f64 ───────────────────────────────────────────────────────────────────
558
559impl Serialize for f64 {
560    fn serialize(&self) -> SerializedValue { SerializedValue::Float(*self) }
561}
562
563impl Deserialize for f64 {
564    fn deserialize(v: &SerializedValue) -> Result<Self, DeserializeError> {
565        v.as_float().ok_or(DeserializeError::WrongType { expected: "Float", got: v.type_name() })
566    }
567}
568
569// ── String ─────────────────────────────────────────────────────────────────
570
571impl Serialize for String {
572    fn serialize(&self) -> SerializedValue { SerializedValue::Str(self.clone()) }
573}
574
575impl Deserialize for String {
576    fn deserialize(v: &SerializedValue) -> Result<Self, DeserializeError> {
577        v.as_str().map(|s| s.to_string())
578            .ok_or(DeserializeError::WrongType { expected: "Str", got: v.type_name() })
579    }
580}
581
582// ── &str ──────────────────────────────────────────────────────────────────
583
584impl Serialize for &str {
585    fn serialize(&self) -> SerializedValue { SerializedValue::Str(self.to_string()) }
586}
587
588// ── Vec<T> ────────────────────────────────────────────────────────────────
589
590impl<T: Serialize> Serialize for Vec<T> {
591    fn serialize(&self) -> SerializedValue {
592        SerializedValue::List(self.iter().map(|v| v.serialize()).collect())
593    }
594}
595
596impl<T: Deserialize> Deserialize for Vec<T> {
597    fn deserialize(v: &SerializedValue) -> Result<Self, DeserializeError> {
598        let list = v.as_list()
599            .ok_or(DeserializeError::WrongType { expected: "List", got: v.type_name() })?;
600        list.iter().map(T::deserialize).collect()
601    }
602}
603
604// ── HashMap<String, V> ────────────────────────────────────────────────────
605
606impl<V: Serialize> Serialize for HashMap<String, V> {
607    fn serialize(&self) -> SerializedValue {
608        let mut m = HashMap::new();
609        for (k, v) in self {
610            m.insert(k.clone(), v.serialize());
611        }
612        SerializedValue::Map(m)
613    }
614}
615
616impl<V: Deserialize> Deserialize for HashMap<String, V> {
617    fn deserialize(sv: &SerializedValue) -> Result<Self, DeserializeError> {
618        let map = sv.as_map()
619            .ok_or(DeserializeError::WrongType { expected: "Map", got: sv.type_name() })?;
620        let mut out = HashMap::new();
621        for (k, v) in map {
622            out.insert(k.clone(), V::deserialize(v)?);
623        }
624        Ok(out)
625    }
626}
627
628// ── Option<T> ─────────────────────────────────────────────────────────────
629
630impl<T: Serialize> Serialize for Option<T> {
631    fn serialize(&self) -> SerializedValue {
632        match self {
633            Some(v) => v.serialize(),
634            None => SerializedValue::Null,
635        }
636    }
637}
638
639impl<T: Deserialize> Deserialize for Option<T> {
640    fn deserialize(v: &SerializedValue) -> Result<Self, DeserializeError> {
641        if v.is_null() {
642            Ok(None)
643        } else {
644            T::deserialize(v).map(Some)
645        }
646    }
647}
648
649// ── Vec2 (glam) ───────────────────────────────────────────────────────────
650
651impl Serialize for Vec2 {
652    fn serialize(&self) -> SerializedValue {
653        let mut m = HashMap::new();
654        m.insert("x".to_string(), SerializedValue::Float(self.x as f64));
655        m.insert("y".to_string(), SerializedValue::Float(self.y as f64));
656        SerializedValue::Map(m)
657    }
658}
659
660impl Deserialize for Vec2 {
661    fn deserialize(v: &SerializedValue) -> Result<Self, DeserializeError> {
662        let x = v.get("x")
663            .and_then(|v| v.as_float())
664            .ok_or_else(|| DeserializeError::MissingKey("x".into()))? as f32;
665        let y = v.get("y")
666            .and_then(|v| v.as_float())
667            .ok_or_else(|| DeserializeError::MissingKey("y".into()))? as f32;
668        Ok(Vec2::new(x, y))
669    }
670}
671
672// ── Vec3 (glam) ───────────────────────────────────────────────────────────
673
674impl Serialize for Vec3 {
675    fn serialize(&self) -> SerializedValue {
676        let mut m = HashMap::new();
677        m.insert("x".to_string(), SerializedValue::Float(self.x as f64));
678        m.insert("y".to_string(), SerializedValue::Float(self.y as f64));
679        m.insert("z".to_string(), SerializedValue::Float(self.z as f64));
680        SerializedValue::Map(m)
681    }
682}
683
684impl Deserialize for Vec3 {
685    fn deserialize(v: &SerializedValue) -> Result<Self, DeserializeError> {
686        let x = v.get("x").and_then(|v| v.as_float())
687            .ok_or_else(|| DeserializeError::MissingKey("x".into()))? as f32;
688        let y = v.get("y").and_then(|v| v.as_float())
689            .ok_or_else(|| DeserializeError::MissingKey("y".into()))? as f32;
690        let z = v.get("z").and_then(|v| v.as_float())
691            .ok_or_else(|| DeserializeError::MissingKey("z".into()))? as f32;
692        Ok(Vec3::new(x, y, z))
693    }
694}
695
696// ─────────────────────────────────────────────
697//  ComponentSerializer
698// ─────────────────────────────────────────────
699
700type SerializeFn = Box<dyn Fn(*const u8) -> SerializedValue + Send + Sync>;
701type DeserializeFn = Box<dyn Fn(&SerializedValue) -> Box<dyn Any + Send + Sync> + Send + Sync>;
702
703struct ComponentEntry {
704    type_id: TypeId,
705    name: String,
706    serialize: SerializeFn,
707    deserialize: DeserializeFn,
708}
709
710/// Registry mapping component type names to their serialize/deserialize functions.
711///
712/// Used by the snapshot system to serialize arbitrary component types by name.
713pub struct ComponentSerializer {
714    by_name: HashMap<String, usize>,
715    by_type: HashMap<TypeId, usize>,
716    entries: Vec<ComponentEntry>,
717}
718
719impl ComponentSerializer {
720    pub fn new() -> Self {
721        Self {
722            by_name: HashMap::new(),
723            by_type: HashMap::new(),
724            entries: Vec::new(),
725        }
726    }
727
728    /// Register a component type `T` under `name`.
729    pub fn register<T: Serialize + Deserialize + Any + Send + Sync + 'static>(
730        &mut self,
731        name: impl Into<String>,
732    ) {
733        let name = name.into();
734        let type_id = TypeId::of::<T>();
735        let idx = self.entries.len();
736        self.by_name.insert(name.clone(), idx);
737        self.by_type.insert(type_id, idx);
738        self.entries.push(ComponentEntry {
739            type_id,
740            name,
741            serialize: Box::new(|ptr| {
742                // SAFETY: caller must ensure ptr points to a valid T
743                let reference = unsafe { &*(ptr as *const T) };
744                reference.serialize()
745            }),
746            deserialize: Box::new(|v| {
747                match T::deserialize(v) {
748                    Ok(t) => Box::new(t) as Box<dyn Any + Send + Sync>,
749                    Err(_) => Box::new(()) as Box<dyn Any + Send + Sync>,
750                }
751            }),
752        });
753    }
754
755    /// Serialize a component by TypeId, given a raw pointer to its data.
756    ///
757    /// # Safety
758    /// `ptr` must point to a valid value of the type identified by `type_id`.
759    pub unsafe fn serialize_any(&self, type_id: TypeId, ptr: *const u8) -> Option<SerializedValue> {
760        let idx = self.by_type.get(&type_id)?;
761        Some((self.entries[*idx].serialize)(ptr))
762    }
763
764    /// Deserialize a component by name.
765    pub fn deserialize_any(&self, name: &str, v: &SerializedValue) -> Option<Box<dyn Any + Send + Sync>> {
766        let idx = self.by_name.get(name)?;
767        Some((self.entries[*idx].deserialize)(v))
768    }
769
770    /// Returns `true` if a type is registered under `name`.
771    pub fn has_name(&self, name: &str) -> bool {
772        self.by_name.contains_key(name)
773    }
774
775    /// All registered component names.
776    pub fn registered_names(&self) -> impl Iterator<Item = &str> {
777        self.by_name.keys().map(String::as_str)
778    }
779
780    /// Number of registered component types.
781    pub fn len(&self) -> usize {
782        self.entries.len()
783    }
784}
785
786impl Default for ComponentSerializer {
787    fn default() -> Self {
788        Self::new()
789    }
790}
791
792// ─────────────────────────────────────────────
793//  Tests
794// ─────────────────────────────────────────────
795
796#[cfg(test)]
797mod tests {
798    use super::*;
799
800    #[test]
801    fn serialize_primitives() {
802        assert_eq!(true.serialize(), SerializedValue::Bool(true));
803        assert_eq!(42i64.serialize(), SerializedValue::Int(42));
804        assert_eq!(3.14f64.serialize(), SerializedValue::Float(3.14));
805        assert_eq!("hello".serialize(), SerializedValue::Str("hello".into()));
806    }
807
808    #[test]
809    fn deserialize_primitives() {
810        assert_eq!(bool::deserialize(&SerializedValue::Bool(false)).unwrap(), false);
811        assert_eq!(i64::deserialize(&SerializedValue::Int(7)).unwrap(), 7);
812        assert_eq!(f64::deserialize(&SerializedValue::Float(1.5)).unwrap(), 1.5);
813        assert_eq!(String::deserialize(&SerializedValue::Str("hi".into())).unwrap(), "hi");
814    }
815
816    #[test]
817    fn serialize_vec2_roundtrip() {
818        let v = Vec2::new(1.0, 2.5);
819        let sv = v.serialize();
820        let v2 = Vec2::deserialize(&sv).unwrap();
821        assert!((v.x - v2.x).abs() < 1e-5);
822        assert!((v.y - v2.y).abs() < 1e-5);
823    }
824
825    #[test]
826    fn serialize_vec3_roundtrip() {
827        let v = Vec3::new(1.0, 2.0, 3.0);
828        let sv = v.serialize();
829        let v2 = Vec3::deserialize(&sv).unwrap();
830        assert!((v - v2).length() < 1e-5);
831    }
832
833    #[test]
834    fn serialize_vec_of_ints() {
835        let v: Vec<i64> = vec![10, 20, 30];
836        let sv = v.serialize();
837        let v2: Vec<i64> = Vec::deserialize(&sv).unwrap();
838        assert_eq!(v, v2);
839    }
840
841    #[test]
842    fn serialize_option_some_none() {
843        let some: Option<i64> = Some(99);
844        let none: Option<i64> = None;
845        assert_eq!(some.serialize(), SerializedValue::Int(99));
846        assert_eq!(none.serialize(), SerializedValue::Null);
847        assert_eq!(Option::<i64>::deserialize(&SerializedValue::Null).unwrap(), None);
848        assert_eq!(Option::<i64>::deserialize(&SerializedValue::Int(5)).unwrap(), Some(5));
849    }
850
851    #[test]
852    fn json_roundtrip_simple() {
853        let original = SerializedValue::Map({
854            let mut m = HashMap::new();
855            m.insert("name".into(), SerializedValue::Str("Alice".into()));
856            m.insert("score".into(), SerializedValue::Int(1000));
857            m.insert("alive".into(), SerializedValue::Bool(true));
858            m
859        });
860        let json = original.to_json_string();
861        let parsed = SerializedValue::from_json_str(&json).unwrap();
862        assert_eq!(parsed.get("name").and_then(|v| v.as_str()), Some("Alice"));
863        assert_eq!(parsed.get("score").and_then(|v| v.as_int()), Some(1000));
864        assert_eq!(parsed.get("alive").and_then(|v| v.as_bool()), Some(true));
865    }
866
867    #[test]
868    fn json_roundtrip_nested() {
869        let sv = SerializedValue::List(vec![
870            SerializedValue::Int(1),
871            SerializedValue::Float(2.5),
872            SerializedValue::Null,
873            SerializedValue::Bool(true),
874        ]);
875        let json = sv.to_json_string();
876        let parsed = SerializedValue::from_json_str(&json).unwrap();
877        assert_eq!(parsed.index(0).and_then(|v| v.as_int()), Some(1));
878        assert_eq!(parsed.index(2).map(|v| v.is_null()), Some(true));
879    }
880
881    #[test]
882    fn json_string_escape() {
883        let sv = SerializedValue::Str("say \"hello\"\nnewline".into());
884        let json = sv.to_json_string();
885        let parsed = SerializedValue::from_json_str(&json).unwrap();
886        assert_eq!(parsed.as_str(), Some("say \"hello\"\nnewline"));
887    }
888
889    #[test]
890    fn component_serializer_register_and_use() {
891        let mut cs = ComponentSerializer::new();
892        cs.register::<i64>("health");
893        assert!(cs.has_name("health"));
894        assert_eq!(cs.len(), 1);
895
896        let sv = SerializedValue::Int(100);
897        let boxed = cs.deserialize_any("health", &sv).unwrap();
898        let val = boxed.downcast_ref::<i64>().unwrap();
899        assert_eq!(*val, 100);
900    }
901
902    #[test]
903    fn wrong_type_error() {
904        let sv = SerializedValue::Str("not a bool".into());
905        let err = bool::deserialize(&sv).unwrap_err();
906        assert!(matches!(err, DeserializeError::WrongType { .. }));
907    }
908}