1pub(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
30pub use codec::VALUE_DEPTH;
33
34use std::{collections::BTreeMap, fmt};
38use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as _};
40use time::{OffsetDateTime, UtcOffset, format_description::well_known::Rfc3339};
41use crate::MemorySize;
43
44struct DisplayText<'a, T>(&'a T);
53
54struct NumberText(f64);
55
56struct DatetimeText {
57 bytes: [u8; 30],
58 length: usize,
59}
60
61#[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
116impl 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
356fn datetime_text(value: OffsetDateTime) -> Result<DatetimeText, time::error::Format> {
361 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