Skip to main content

harmos_domain/
value.rs

1/* ***
2 *
3 * Harmos
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * ***
8 */
9
10/* === Modules === */
11
12pub(crate) mod codec;
13pub(crate) mod optional_datetime {
14    use super::*;
15
16    pub fn serialize<S: Serializer>(value: &Option<OffsetDateTime>, serializer: S) -> Result<S::Ok, S::Error> {
17        match value {
18            Some(value) => serializer.serialize_some(&datetime_text(*value).map_err(serde::ser::Error::custom)?),
19            None => serializer.serialize_none(),
20        }
21    }
22
23    pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Option<OffsetDateTime>, D::Error> {
24        Option::<String>::deserialize(deserializer)?
25            .map(|value| OffsetDateTime::parse(&value, &Rfc3339).map(|value| value.to_offset(UtcOffset::UTC)).map_err(D::Error::custom))
26            .transpose()
27    }
28}
29
30/* === Re-Exports === */
31
32pub use codec::VALUE_DEPTH;
33
34/* === Imports === */
35
36// Standard Library Imports
37use std::{collections::BTreeMap, fmt};
38// Third Party Imports
39use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as _};
40use time::{OffsetDateTime, UtcOffset, format_description::well_known::Rfc3339};
41// Local Imports
42use crate::MemorySize;
43
44/* === Constants === */
45
46/* === Macros === */
47
48/* === Type Aliases === */
49
50/* === Structs === */
51
52struct DisplayText<'a, T>(&'a T);
53
54struct NumberText(f64);
55
56struct DatetimeText {
57    bytes: [u8; 30],
58    length: usize,
59}
60
61/* === Enums === */
62
63#[derive(Clone, Debug)]
64pub enum Value {
65    Null,
66    Bool(bool),
67    Integer(i64),
68    Unsigned(u64),
69    Number(f64),
70    Text(String),
71    Datetime(OffsetDateTime),
72    Array(Vec<Value>),
73    Object(BTreeMap<String, Value>),
74}
75
76#[derive(Debug, thiserror::Error)]
77pub enum ValueError {
78    #[error("non-finite numbers have no plain JSON representation")]
79    NonFinite,
80
81    #[error("JSON number cannot be represented without loss")]
82    InvalidNumber,
83
84    #[error("datetime cannot be formatted as RFC3339: {0}")]
85    Datetime(#[from] time::error::Format),
86}
87
88#[derive(Deserialize)]
89#[serde(tag = "type", content = "value", rename_all = "snake_case", deny_unknown_fields)]
90enum Representation {
91    Null,
92    Bool(bool),
93    Integer(String),
94    Unsigned(String),
95    Number(String),
96    Text(String),
97    Datetime(String),
98    Array(Vec<Value>),
99    Object(BTreeMap<String, Value>),
100}
101
102#[derive(Serialize)]
103#[serde(tag = "type", content = "value", rename_all = "snake_case", rename = "Representation")]
104enum BorrowedRepresentation<'a> {
105    Null,
106    Bool(bool),
107    Integer(DisplayText<'a, i64>),
108    Unsigned(DisplayText<'a, u64>),
109    Number(NumberText),
110    Text(&'a str),
111    Datetime(DatetimeText),
112    Array(&'a [Value]),
113    Object(&'a BTreeMap<String, Value>),
114}
115
116/* === Traits === */
117
118/* === Implementations === */
119
120impl MemorySize for Value {
121    fn memory_size(&self) -> usize {
122        let allocation = match self {
123            Self::Text(value) => value.capacity(),
124            Self::Array(value) => {
125                let bytes = value.memory_size();
126                if bytes == usize::MAX {
127                    return usize::MAX;
128                }
129                bytes.saturating_sub(std::mem::size_of_val(value))
130            }
131            Self::Object(value) => {
132                let bytes = value.memory_size();
133                if bytes == usize::MAX {
134                    return usize::MAX;
135                }
136                bytes.saturating_sub(std::mem::size_of_val(value))
137            }
138            _ => 0,
139        };
140        std::mem::size_of::<Self>().saturating_add(allocation)
141    }
142}
143
144impl Value {
145    pub fn from_plain_json(value: serde_json::Value) -> Result<Self, ValueError> {
146        Ok(match value {
147            serde_json::Value::Null => Self::Null,
148            serde_json::Value::Bool(value) => Self::Bool(value),
149            serde_json::Value::String(value) => Self::Text(value),
150            serde_json::Value::Number(value) => {
151                if let Some(value) = value.as_i64() {
152                    Self::Integer(value)
153                } else if let Some(value) = value.as_u64() {
154                    Self::Unsigned(value)
155                } else {
156                    Self::Number(value.as_f64().ok_or(ValueError::InvalidNumber)?)
157                }
158            }
159            serde_json::Value::Array(values) => Self::Array(values.into_iter().map(Self::from_plain_json).collect::<Result<_, _>>()?),
160            serde_json::Value::Object(values) => Self::Object(
161                values.into_iter().map(|(key, value)| Ok((key, Self::from_plain_json(value)?))).collect::<Result<_, ValueError>>()?,
162            ),
163        })
164    }
165
166    pub fn to_plain_json(&self) -> Result<serde_json::Value, ValueError> {
167        Ok(match self {
168            Self::Null => serde_json::Value::Null,
169            Self::Bool(value) => (*value).into(),
170            Self::Integer(value) => (*value).into(),
171            Self::Unsigned(value) => (*value).into(),
172            Self::Number(value) => serde_json::Value::Number(serde_json::Number::from_f64(*value).ok_or(ValueError::NonFinite)?),
173            Self::Text(value) => value.clone().into(),
174            Self::Datetime(value) => format_datetime(*value)?.into(),
175            Self::Array(values) => serde_json::Value::Array(values.iter().map(Self::to_plain_json).collect::<Result<_, _>>()?),
176            Self::Object(values) => {
177                serde_json::Value::Object(values.iter().map(|(key, value)| Ok((key.clone(), value.to_plain_json()?))).collect::<Result<
178                    _,
179                    ValueError,
180                >>(
181                )?)
182            }
183        })
184    }
185}
186
187impl PartialEq for Value {
188    fn eq(&self, other: &Self) -> bool {
189        match (self, other) {
190            (Self::Null, Self::Null) => true,
191            (Self::Bool(a), Self::Bool(b)) => a == b,
192            (Self::Integer(a), Self::Integer(b)) => a == b,
193            (Self::Unsigned(a), Self::Unsigned(b)) => a == b,
194            (Self::Number(a), Self::Number(b)) => (a.is_nan() && b.is_nan()) || a.to_bits() == b.to_bits(),
195            (Self::Text(a), Self::Text(b)) => a == b,
196            (Self::Datetime(a), Self::Datetime(b)) => a == b,
197            (Self::Array(a), Self::Array(b)) => a == b,
198            (Self::Object(a), Self::Object(b)) => a == b,
199            _ => false,
200        }
201    }
202}
203
204impl Eq for Value {}
205
206impl Serialize for Value {
207    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
208        let representation = match self {
209            Self::Null => BorrowedRepresentation::Null,
210            Self::Bool(value) => BorrowedRepresentation::Bool(*value),
211            Self::Integer(value) => BorrowedRepresentation::Integer(DisplayText(value)),
212            Self::Unsigned(value) => BorrowedRepresentation::Unsigned(DisplayText(value)),
213            Self::Number(value) => BorrowedRepresentation::Number(NumberText(*value)),
214            Self::Text(value) => BorrowedRepresentation::Text(value),
215            Self::Datetime(value) => BorrowedRepresentation::Datetime(datetime_text(*value).map_err(serde::ser::Error::custom)?),
216            Self::Array(value) => BorrowedRepresentation::Array(value),
217            Self::Object(value) => BorrowedRepresentation::Object(value),
218        };
219        serializer.serialize_newtype_struct("harmos::Value", &representation)
220    }
221}
222
223impl<T: fmt::Display> Serialize for DisplayText<'_, T> {
224    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
225        serializer.collect_str(self.0)
226    }
227}
228
229impl Serialize for NumberText {
230    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
231        if self.0.is_nan() { serializer.serialize_str("nan") } else { serializer.collect_str(&self.0) }
232    }
233}
234
235impl Serialize for DatetimeText {
236    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
237        let text = std::str::from_utf8(&self.bytes[..self.length]).map_err(serde::ser::Error::custom)?;
238        serializer.serialize_str(text)
239    }
240}
241
242impl std::io::Write for DatetimeText {
243    fn write(&mut self, bytes: &[u8]) -> std::io::Result<usize> {
244        if bytes.len() > self.bytes.len() - self.length {
245            return Err(std::io::ErrorKind::WriteZero.into());
246        }
247        let end = self.length + bytes.len();
248        self.bytes[self.length..end].copy_from_slice(bytes);
249        self.length = end;
250        Ok(bytes.len())
251    }
252
253    fn flush(&mut self) -> std::io::Result<()> {
254        Ok(())
255    }
256}
257
258impl<'de> Deserialize<'de> for Value {
259    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
260        struct ValueVisitor;
261
262        impl<'de> serde::de::Visitor<'de> for ValueVisitor {
263            type Value = Value;
264
265            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
266                formatter.write_str("a canonical tagged Harmos value")
267            }
268
269            fn visit_newtype_struct<D: Deserializer<'de>>(self, deserializer: D) -> Result<Value, D::Error> {
270                Ok(match Representation::deserialize(deserializer)? {
271                    Representation::Null => Value::Null,
272                    Representation::Bool(value) => Value::Bool(value),
273                    Representation::Integer(value) => Value::Integer(value.parse().map_err(D::Error::custom)?),
274                    Representation::Unsigned(value) => Value::Unsigned(value.parse().map_err(D::Error::custom)?),
275                    Representation::Number(value) => Value::Number(value.parse().map_err(D::Error::custom)?),
276                    Representation::Text(value) => Value::Text(value),
277                    Representation::Datetime(value) => {
278                        Value::Datetime(OffsetDateTime::parse(&value, &Rfc3339).map_err(D::Error::custom)?.to_offset(UtcOffset::UTC))
279                    }
280                    Representation::Array(value) => Value::Array(value),
281                    Representation::Object(value) => Value::Object(value),
282                })
283            }
284        }
285
286        deserializer.deserialize_newtype_struct("harmos::Value", ValueVisitor)
287    }
288}
289
290impl<T: Into<Value>> From<Option<T>> for Value {
291    fn from(value: Option<T>) -> Self {
292        value.map_or(Self::Null, Into::into)
293    }
294}
295
296impl From<bool> for Value {
297    fn from(value: bool) -> Self {
298        Self::Bool(value)
299    }
300}
301
302impl From<i64> for Value {
303    fn from(value: i64) -> Self {
304        Self::Integer(value)
305    }
306}
307
308impl From<i32> for Value {
309    fn from(value: i32) -> Self {
310        Self::Integer(value.into())
311    }
312}
313
314impl From<u64> for Value {
315    fn from(value: u64) -> Self {
316        Self::Unsigned(value)
317    }
318}
319
320impl From<u32> for Value {
321    fn from(value: u32) -> Self {
322        Self::Unsigned(value.into())
323    }
324}
325
326impl From<f64> for Value {
327    fn from(value: f64) -> Self {
328        Self::Number(value)
329    }
330}
331
332impl From<String> for Value {
333    fn from(value: String) -> Self {
334        Self::Text(value)
335    }
336}
337
338impl From<&str> for Value {
339    fn from(value: &str) -> Self {
340        Self::Text(value.to_owned())
341    }
342}
343
344impl From<OffsetDateTime> for Value {
345    fn from(value: OffsetDateTime) -> Self {
346        Self::Datetime(value.to_offset(UtcOffset::UTC))
347    }
348}
349
350impl<T: Into<Value>> From<Vec<T>> for Value {
351    fn from(value: Vec<T>) -> Self {
352        Self::Array(value.into_iter().map(Into::into).collect())
353    }
354}
355
356/* === Public Functions === */
357
358/* === Private Functions === */
359
360fn datetime_text(value: OffsetDateTime) -> Result<DatetimeText, time::error::Format> {
361    // UTC RFC3339 Uses At Most 30 Bytes, Including All Nine Fractional Digits.
362    let mut text = DatetimeText { bytes: [0; 30], length: 0 };
363    value.to_offset(UtcOffset::UTC).format_into(&mut text, &Rfc3339)?;
364    Ok(text)
365}
366
367fn format_datetime(value: OffsetDateTime) -> Result<String, time::error::Format> {
368    value.to_offset(UtcOffset::UTC).format(&Rfc3339)
369}
370
371/* === Tests === */