Skip to main content

zen_types/variable/
ref_deser.rs

1use crate::rcvalue::RcValue;
2use crate::variable::Variable;
3use crate::variable::VariableMap;
4use std::rc::Rc;
5use thiserror::Error;
6
7pub struct RefDeserializer {
8    refs: Vec<Option<Variable>>,
9}
10
11impl RefDeserializer {
12    pub fn new() -> Self {
13        Self { refs: Vec::new() }
14    }
15
16    pub fn deserialize(&mut self, value: RcValue) -> Result<Variable, RefDeserializeError> {
17        let RcValue::Object(mut root_obj) = value else {
18            return Err(RefDeserializeError::InvalidFormat(
19                "Expected root object".into(),
20            ));
21        };
22
23        if let Some(RcValue::Array(refs_array)) = root_obj.remove(&Rc::from("$refs")) {
24            self.refs = vec![None; refs_array.len()];
25
26            for (i, _) in refs_array.iter().enumerate() {
27                match &refs_array[i] {
28                    RcValue::Array(_) => {
29                        self.refs[i] = Some(Variable::from_array(Vec::new()));
30                    }
31                    RcValue::Object(_) => {
32                        self.refs[i] = Some(Variable::from_object(VariableMap::default()));
33                    }
34                    _ => {
35                        self.refs[i] = Some(self.deserialize_value(&refs_array[i])?);
36                    }
37                }
38            }
39
40            for (i, ref_value) in refs_array.iter().enumerate() {
41                match ref_value {
42                    RcValue::Array(arr) => {
43                        if let Some(Variable::Array(target)) = &self.refs[i] {
44                            let mut items = Vec::with_capacity(arr.len());
45                            for item in arr {
46                                items.push(self.deserialize_value(item)?);
47                            }
48                            *target.borrow_mut() = items;
49                        }
50                    }
51                    RcValue::Object(obj) => {
52                        if let Some(Variable::Object(target)) = &self.refs[i] {
53                            let mut map = VariableMap::with_capacity(obj.len());
54                            for (key, value) in obj {
55                                let key_var = self.deserialize_key(key)?;
56                                let value_var = self.deserialize_value(value)?;
57                                map.insert(key_var, value_var);
58                            }
59                            *target.borrow_mut() = map;
60                        }
61                    }
62                    _ => {}
63                }
64            }
65        }
66
67        let root_value = root_obj
68            .remove("$root")
69            .ok_or_else(|| RefDeserializeError::InvalidFormat("Missing $root".into()))?;
70
71        self.deserialize_value(&root_value)
72    }
73
74    fn deserialize_key(&self, key: &Rc<str>) -> Result<crate::symbol::Symbol, RefDeserializeError> {
75        if let Some(ref_id) = parse_ref_id(key) {
76            if ref_id >= self.refs.len() {
77                return Err(RefDeserializeError::InvalidReference(ref_id));
78            }
79
80            match &self.refs[ref_id] {
81                Some(Variable::String(s)) => Ok(s.clone()),
82                Some(_) => Err(RefDeserializeError::InvalidFormat(
83                    "Reference used as key must be a string".into(),
84                )),
85                None => Err(RefDeserializeError::UnresolvedReference(ref_id)),
86            }
87        } else {
88            Ok(unescape_at_string(key))
89        }
90    }
91
92    fn deserialize_value(&self, value: &RcValue) -> Result<Variable, RefDeserializeError> {
93        match value {
94            RcValue::Null => Ok(Variable::Null),
95            RcValue::Bool(b) => Ok(Variable::Bool(*b)),
96            RcValue::Number(n) => Ok(Variable::Number(*n)),
97            RcValue::String(s) => {
98                if let Some(ref_id) = parse_ref_id(s) {
99                    if ref_id >= self.refs.len() {
100                        return Err(RefDeserializeError::InvalidReference(ref_id));
101                    }
102
103                    self.refs[ref_id]
104                        .clone()
105                        .ok_or(RefDeserializeError::UnresolvedReference(ref_id))
106                } else {
107                    Ok(Variable::String(unescape_at_string(s)))
108                }
109            }
110            RcValue::Array(arr) => {
111                let mut items = Vec::with_capacity(arr.len());
112                for item in arr {
113                    items.push(self.deserialize_value(item)?);
114                }
115                Ok(Variable::from_array(items))
116            }
117            RcValue::Object(obj) => {
118                let mut map = VariableMap::with_capacity(obj.len());
119                for (key, value) in obj {
120                    let key_var = self.deserialize_key(key)?;
121                    let value_var = self.deserialize_value(value)?;
122                    map.insert(key_var, value_var);
123                }
124                Ok(Variable::from_object(map))
125            }
126        }
127    }
128}
129
130#[derive(Debug, Error)]
131pub enum RefDeserializeError {
132    #[error("Invalid format: {0}")]
133    InvalidFormat(String),
134    #[error("Invalid reference: {0}")]
135    InvalidReference(usize),
136    #[error("UnresolvedReference: {0}")]
137    UnresolvedReference(usize),
138}
139
140fn unescape_at_string(s: &Rc<str>) -> crate::symbol::Symbol {
141    match s.starts_with("@@") {
142        true => crate::symbol::Symbol::from(&s[1..]),
143        false => crate::symbol::Symbol::from(s.as_ref()),
144    }
145}
146
147fn parse_ref_id(s: &str) -> Option<usize> {
148    s.strip_prefix('@')?.parse().ok()
149}