1use super::*;
2
3use thiserror::Error;
4
5#[derive(Clone, Debug, Error)]
7pub enum DecodeError {
8 #[error("Couldn't convert array item {loc}")]
10 Array {
11 loc: usize,
12 #[source]
13 err: Box<DecodeError>
14 },
15 #[error("Couldn't convert object value with key {key}")]
17 Map {
18 key: String,
19 #[source]
20 err: Box<DecodeError>
21 },
22 #[error("Invalid Base64")]
24 Base64(base64::DecodeError),
25 #[error("Invalid hexadecimal")]
27 Hex(#[from] hex::FromHexError),
28 #[error("Unrecognized fog-pack type \"{0}\"")]
30 UnrecognizedType(String),
31 #[error("Invalid Time")]
33 InvalidTime(#[from] chrono::format::ParseError),
34 #[error("Invalid floating-point value")]
36 InvalidFloat,
37 #[error("Invalid integer")]
39 InvalidInteger,
40 #[error("Bad fogpack type (missing a colon at end of type)")]
42 BadFogType,
43 #[error("Invalid Base58")]
45 InvalidBase58,
46 #[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
56pub 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}