object_rainbow_json/
distributed.rs1use std::{collections::BTreeMap, num::NonZero};
2
3use futures_concurrency::future::TryJoin;
4use object_rainbow::{
5 Enum, InlineOutput, ListHashes, MaybeHasNiche, Parse, ParseInline, Tagged, ToOutput,
6 Topological, length_prefixed::LpString, numeric::Le,
7};
8use object_rainbow_point::{IntoPoint, Point};
9use serde::{Deserialize, Serialize};
10
11#[derive(
12 Enum,
13 ToOutput,
14 InlineOutput,
15 ListHashes,
16 Topological,
17 Parse,
18 ParseInline,
19 Clone,
20 Default,
21 Serialize,
22 Deserialize,
23 MaybeHasNiche,
24)]
25#[serde(untagged)]
26#[topology(recursive)]
27#[enumtag("NonZero<u8>")]
28#[niche(tag)]
29pub enum Distributed {
30 #[default]
31 Null,
32 Bool(bool),
33 I64(Le<i64>),
34 U64(Le<u64>),
35 F64(Le<f64>),
36 String(Point<String>),
37 Array(#[parse(unchecked)] Point<Vec<Self>>),
38 Object(#[parse(unchecked)] Point<BTreeMap<LpString, Self>>),
39}
40
41impl Tagged for Distributed {}
42
43impl Distributed {
44 pub async fn to_value(&self) -> object_rainbow::Result<serde_json::Value> {
45 Ok(match *self {
46 Distributed::Null => serde_json::Value::Null,
47 Distributed::Bool(x) => x.into(),
48 Distributed::I64(x) => x.0.into(),
49 Distributed::U64(x) => x.0.into(),
50 Distributed::F64(x) => x.0.into(),
51 Distributed::String(ref point) => point.fetch().await?.into(),
52 Distributed::Array(ref point) => point
53 .fetch()
54 .await?
55 .into_iter()
56 .map(async |x| x.to_value().await)
57 .collect::<Vec<_>>()
58 .try_join()
59 .await?
60 .into(),
61 Distributed::Object(ref point) => point
62 .fetch()
63 .await?
64 .into_iter()
65 .map(async |(k, x)| Ok::<_, object_rainbow::Error>((k.0, x.to_value().await?)))
66 .collect::<Vec<_>>()
67 .try_join()
68 .await?
69 .into_iter()
70 .collect::<serde_json::Map<_, _>>()
71 .into(),
72 })
73 }
74}
75
76#[derive(Debug, thiserror::Error)]
77#[non_exhaustive]
78pub enum DistributedParseError {
79 #[error("invalid number")]
80 InvalidNumber,
81}
82
83impl TryFrom<serde_json::Value> for Distributed {
84 type Error = DistributedParseError;
85
86 fn try_from(value: serde_json::Value) -> Result<Self, Self::Error> {
87 Ok(match value {
88 serde_json::Value::Null => Self::Null,
89 serde_json::Value::Bool(x) => Self::Bool(x),
90 serde_json::Value::Number(x) => {
91 if let Some(x) = x.as_u64() {
92 Self::U64(x.into())
93 } else if let Some(x) = x.as_i64() {
94 Self::I64(x.into())
95 } else if let Some(x) = x.as_f64() {
96 Self::F64(x.into())
97 } else {
98 return Err(DistributedParseError::InvalidNumber);
99 }
100 }
101 serde_json::Value::String(x) => Self::String(x.point()),
102 serde_json::Value::Array(vec) => Self::Array(
103 vec.into_iter()
104 .map(Self::try_from)
105 .collect::<Result<Vec<_>, _>>()?
106 .point(),
107 ),
108 serde_json::Value::Object(map) => Self::Object(
109 map.into_iter()
110 .map(|(k, v)| Ok((LpString(k), Self::try_from(v)?)))
111 .collect::<Result<BTreeMap<_, _>, _>>()?
112 .point(),
113 ),
114 })
115 }
116}