Skip to main content

weakauras_codec_ace_serialize/deserialization/
mod.rs

1// Copyright 2020-2025 Velithris
2// SPDX-License-Identifier: MIT
3
4mod reader;
5
6use crate::{error::DeserializationError, macros::check_recursion};
7use reader::StrReader;
8use weakauras_codec_lua_value::{LuaMapKey, LuaValue};
9
10/// A structure for deserializing strings produced by AceSerialize.
11///
12/// # Example
13///
14/// ```
15/// use weakauras_codec_ace_serialize::{deserialization::Deserializer, error::DeserializationError};
16///
17/// fn main() -> Result<(), DeserializationError> {
18///     assert_eq!(
19///         Deserializer::from_str("^1^SHello,~`world!^^")
20///             .deserialize_first()?
21///             .unwrap(),
22///         "Hello, world!".into()
23///     );
24///     Ok(())
25/// }
26/// ```
27pub struct Deserializer<'s> {
28    remaining_depth: usize,
29    reader: StrReader<'s>,
30}
31
32impl<'s> Deserializer<'s> {
33    /// Create a deserializer from a string slice.
34    #[allow(clippy::should_implement_trait)]
35    pub fn from_str(slice: &'s str) -> Self {
36        Self {
37            remaining_depth: 128,
38            reader: StrReader::new(slice),
39        }
40    }
41
42    /// Deserialize all values.
43    pub fn deserialize_all(mut self) -> Result<Vec<LuaValue>, DeserializationError> {
44        self.reader.read_identifier().and_then(|v| {
45            if v == "^1" {
46                Ok(())
47            } else {
48                Err(DeserializationError::InvalidPrefix)
49            }
50        })?;
51
52        let mut result = Vec::new();
53
54        while self.reader.peek_identifier().is_ok() {
55            if let Some(v) = self.deserialize_helper()? {
56                result.push(v);
57            }
58        }
59
60        Ok(result)
61    }
62
63    /// Deserialize the first value.
64    pub fn deserialize_first(mut self) -> Result<Option<LuaValue>, DeserializationError> {
65        self.reader.read_identifier().and_then(|v| {
66            if v == "^1" {
67                Ok(())
68            } else {
69                Err(DeserializationError::InvalidPrefix)
70            }
71        })?;
72
73        self.deserialize_helper()
74    }
75
76    fn deserialize_helper(&mut self) -> Result<Option<LuaValue>, DeserializationError> {
77        Ok(Some(match self.reader.read_identifier()? {
78            "^^" => return Ok(None),
79            "^Z" => LuaValue::Null,
80            "^B" => LuaValue::Boolean(true),
81            "^b" => LuaValue::Boolean(false),
82            "^S" => LuaValue::String(String::from(self.reader.parse_str()?)),
83            "^N" => LuaValue::Number(
84                self.reader
85                    .read_until_next()
86                    .and_then(Self::deserialize_number)?,
87            ),
88            "^F" => {
89                let mantissa = self
90                    .reader
91                    .read_until_next()
92                    .and_then(|v| v.parse::<f64>().map_err(Into::into))?;
93                let exponent = match self.reader.read_identifier()? {
94                    "^f" => self
95                        .reader
96                        .read_until_next()
97                        .and_then(|v| v.parse::<f64>().map_err(Into::into))?,
98                    _ => return Err(DeserializationError::MissingExponent),
99                };
100
101                LuaValue::Number(mantissa * (2f64.powf(exponent)))
102            }
103            "^T" => {
104                let mut keys = Vec::with_capacity(16);
105                let mut values = Vec::with_capacity(16);
106                loop {
107                    match self.reader.peek_identifier()? {
108                        "^t" => {
109                            let _ = self.reader.read_identifier();
110                            break;
111                        }
112                        _ => {
113                            check_recursion!(self, DeserializationError, {
114                                let key = LuaMapKey::try_from(
115                                    self.deserialize_helper()?
116                                        .ok_or(DeserializationError::UnclosedMap)?,
117                                )?;
118
119                                let value = match self.reader.peek_identifier()? {
120                                    "^t" => {
121                                        return Err(DeserializationError::MapMissingValue);
122                                    }
123                                    _ => self
124                                        .deserialize_helper()?
125                                        .ok_or(DeserializationError::UnclosedMap)?,
126                                };
127                                keys.push(key);
128                                values.push(value);
129                            });
130                        }
131                    }
132                }
133
134                debug_assert_eq!(keys.len(), values.len());
135                let is_array = keys.iter().enumerate().all(|(i, key)| {
136                    if let LuaValue::Number(key) = key.as_value() {
137                        *key == (i + 1) as f64
138                    } else {
139                        false
140                    }
141                });
142
143                if is_array {
144                    LuaValue::Array(values)
145                } else {
146                    LuaValue::Map(keys.into_iter().zip(values).collect())
147                }
148            }
149            _ => return Err(DeserializationError::InvalidIdentifier),
150        }))
151    }
152
153    fn deserialize_number(data: &str) -> Result<f64, DeserializationError> {
154        match data {
155            "1.#INF" | "inf" => Ok(f64::INFINITY),
156            "-1.#INF" | "-inf" => Ok(f64::NEG_INFINITY),
157            v => v.parse().map_err(Into::into),
158        }
159    }
160}