Skip to main content

object_rainbow_json/
distributed.rs

1use std::collections::BTreeMap;
2
3use futures_util::future::try_join_all;
4use object_rainbow::{
5    Enum, Fetch, InlineOutput, ListHashes, MaybeHasNiche, NicheForUnsized, NoNiche, Parse,
6    ParseInline, Tagged, ToOutput, 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)]
24#[serde(untagged)]
25#[topology(recursive)]
26pub enum Distributed {
27    #[default]
28    Null,
29    Bool(bool),
30    I64(Le<i64>),
31    U64(Le<u64>),
32    F64(Le<f64>),
33    String(Point<String>),
34    Array(#[parse(unchecked)] Point<Vec<Self>>),
35    Object(#[parse(unchecked)] Point<BTreeMap<LpString, Self>>),
36}
37
38impl Tagged for Distributed {}
39impl MaybeHasNiche for Distributed {
40    type MnArray = NoNiche<NicheForUnsized>;
41}
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) => try_join_all(
53                point
54                    .fetch()
55                    .await?
56                    .into_iter()
57                    .map(async |x| x.to_value().await),
58            )
59            .await?
60            .into(),
61            Distributed::Object(ref point) => {
62                try_join_all(
63                    point.fetch().await?.into_iter().map(async |(k, x)| {
64                        Ok::<_, object_rainbow::Error>((k.0, x.to_value().await?))
65                    }),
66                )
67                .await?
68                .into_iter()
69                .collect::<serde_json::Map<_, _>>()
70                .into()
71            }
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}