fog_human_json/
dec.rs

1use super::*;
2
3use thiserror::Error;
4
5/// An error that occurred while converting from JSON to a fog-pack value.
6#[derive(Clone, Debug, Error)]
7pub enum DecodeError {
8    /// Conversion failed on a specific value inside an array
9    #[error("Couldn't convert array item {loc}")]
10    Array {
11        loc: usize,
12        #[source]
13        err: Box<DecodeError>
14    },
15    /// Conversion failed on a specific value inside an object
16    #[error("Couldn't convert object value with key {key}")]
17    Map {
18        key: String,
19        #[source]
20        err: Box<DecodeError>
21    },
22    /// Base64 encoding for a fog-pack value was expected, but the encoding was invalid
23    #[error("Invalid Base64")]
24    Base64(base64::DecodeError),
25    /// Hex encoding for a fog-pack value was expected, but the encoding was invalid
26    #[error("Invalid hexadecimal")]
27    Hex(#[from] hex::FromHexError),
28    /// An unrecognized `$fog-TYPE:` was found
29    #[error("Unrecognized fog-pack type \"{0}\"")]
30    UnrecognizedType(String),
31    /// The time format couldn't be parsed as RFC3339
32    #[error("Invalid Time")]
33    InvalidTime(#[from] chrono::format::ParseError),
34    /// The floating-point value was invalid
35    #[error("Invalid floating-point value")]
36    InvalidFloat,
37    /// The Integer value was invalid
38    #[error("Invalid integer")]
39    InvalidInteger,
40    /// The `$fog-TYPE` was missing a colon between it and the type data
41    #[error("Bad fogpack type (missing a colon at end of type)")]
42    BadFogType,
43    /// Base58 encoding for a fog-pack value was expected, but the encoding was invalid
44    #[error("Invalid Base58")]
45    InvalidBase58,
46    /// A lockbox's data was invalid in some way
47    #[error("Invalid Lockbox")]
48    InvalidLockbox,
49}
50
51fn base64_decode<T: AsRef<[u8]>>(input: T) -> Result<Vec<u8>, DecodeError> {
52    use base64::engine::Engine;
53    base64::engine::general_purpose::STANDARD_NO_PAD.decode(input).map_err(DecodeError::Base64)
54}
55
56/// Convert a JSON Value to a fog-pack value.
57pub fn json_to_fog(val: &JsonValue) -> Result<FogValue, DecodeError> {
58    Ok(match val {
59        JsonValue::Null => FogValue::Null,
60        JsonValue::Bool(b) => FogValue::Bool(*b),
61        JsonValue::Array(a) => {
62            let mut new_a = Vec::with_capacity(a.len());
63            for (loc, v) in a.iter().enumerate() {
64                new_a.push(json_to_fog(v).map_err(|e| DecodeError::Array { loc, err: Box::new(e) })?);
65            }
66            FogValue::Array(new_a)
67        },
68        JsonValue::Object(o) => {
69            let mut map = std::collections::BTreeMap::new();
70            for (k, v) in o.iter() {
71                let new_v = json_to_fog(v).map_err(|e| DecodeError::Map { key: k.to_string(), err: Box::new(e) })?;
72                map.insert(k.to_string(), new_v);
73            }
74            FogValue::Map(map)
75        },
76        JsonValue::Number(n) => {
77            if let Some(v) = n.as_u64() {
78                FogValue::Int(fog_pack::types::Integer::from(v))
79            }
80            else if let Some(v) = n.as_i64() {
81                FogValue::Int(fog_pack::types::Integer::from(v))
82            }
83            else {
84                FogValue::F64(n.as_f64().unwrap())
85            }
86        },
87        JsonValue::String(s) => {
88            if let Some(s) = s.strip_prefix(FOG_PREFIX) {
89                let (ty, untrimmed_val) = s.split_once(':').ok_or(DecodeError::BadFogType)?;
90                let val = untrimmed_val.trim();
91                match ty {
92                    "Str" => FogValue::Str(untrimmed_val.to_owned()),
93                    "F32" => {
94                        let f = val.parse::<f32>().map_err(|_| DecodeError::InvalidFloat)?;
95                        FogValue::F32(f)
96                    }
97                    "F64" => {
98                        let f = val.parse::<f64>().map_err(|_| DecodeError::InvalidFloat)?;
99                        FogValue::F64(f)
100                    }
101                    "Int" => {
102                        if val.starts_with('-') {
103                            let v = val.parse::<i64>().map_err(|_| DecodeError::InvalidInteger)?;
104                            FogValue::Int(fog_pack::types::Integer::from(v))
105                        }
106                        else {
107                            let v = val.parse::<u64>().map_err(|_| DecodeError::InvalidInteger)?;
108                            FogValue::Int(fog_pack::types::Integer::from(v))
109                        }
110                    },
111                    "F32Hex" => {
112                        use hex::FromHex;
113                        let bytes = <[u8;4]>::from_hex(val)?;
114                        FogValue::F32(f32::from_be_bytes(bytes))
115                    },
116                    "F64Hex" => {
117                        use hex::FromHex;
118                        let bytes = <[u8;8]>::from_hex(val)?;
119                        FogValue::F64(f64::from_be_bytes(bytes))
120                    },
121                    "Bin" => FogValue::Bin(base64_decode(val)?),
122                    "Hash" => {
123                        let v = fog_pack::types::Hash::from_base58(val).map_err(|_| DecodeError::InvalidBase58)?;
124                        FogValue::Hash(v)
125                    },
126                    "Identity" => {
127                        let v = fog_pack::types::Identity::from_base58(val).map_err(|_| DecodeError::InvalidBase58)?;
128                        FogValue::Identity(v)
129                    },
130                    "StreamId" => {
131                        let v = fog_pack::types::StreamId::from_base58(val).map_err(|_| DecodeError::InvalidBase58)?;
132                        FogValue::StreamId(v)
133                    },
134                    "LockId" => {
135                        let v = fog_pack::types::LockId::from_base58(val).map_err(|_| DecodeError::InvalidBase58)?;
136                        FogValue::LockId(v)
137                    },
138                    "DataLockbox" => {
139                        let bytes = base64_decode(val)?;
140                        let lockbox = fog_pack::types::DataLockboxRef::from_bytes(&bytes)
141                            .map_err(|_| DecodeError::InvalidLockbox)?
142                            .to_owned();
143                        FogValue::DataLockbox(lockbox)
144                    },
145                    "IdentityLockbox" => {
146                        let bytes = base64_decode(val)?;
147                        let lockbox = fog_pack::types::IdentityLockboxRef::from_bytes(&bytes)
148                            .map_err(|_| DecodeError::InvalidLockbox)?
149                            .to_owned();
150                        FogValue::IdentityLockbox(lockbox)
151                    },
152                    "StreamLockbox" => {
153                        let bytes = base64_decode(val)?;
154                        let lockbox = fog_pack::types::StreamLockboxRef::from_bytes(&bytes)
155                            .map_err(|_| DecodeError::InvalidLockbox)?
156                            .to_owned();
157                        FogValue::StreamLockbox(lockbox)
158                    },
159                    "LockLockbox" => {
160                        let bytes = base64_decode(val)?;
161                        let lockbox = fog_pack::types::LockLockboxRef::from_bytes(&bytes)
162                            .map_err(|_| DecodeError::InvalidLockbox)?
163                            .to_owned();
164                        FogValue::LockLockbox(lockbox)
165                    },
166                    "Time" => {
167                        let time = chrono::DateTime::parse_from_rfc3339(val)?;
168                        let sec = time.timestamp();
169                        let nano = time.timestamp_subsec_nanos();
170                        FogValue::Timestamp(fog_pack::types::Timestamp::from_utc(sec, nano).unwrap())
171                    },
172                    _ => return Err(DecodeError::UnrecognizedType(ty.to_owned())),
173                }
174            }
175            else {
176                FogValue::Str(s.to_owned())
177            }
178        }
179    })
180}