1use crate::value_map::ValueMap;
2use crate::{Error, Value};
3use base64::prelude::BASE64_STANDARD;
4use base64::Engine;
5use serde_json::{Map, Number, Value as JsonValue};
6use std::collections::BTreeMap;
7
8impl Value {
9 pub fn convert_from_serde_json_map<I, R>(map: I) -> R
10 where
11 I: IntoIterator<Item = (String, JsonValue)>,
12 R: FromIterator<(String, Value)>,
13 {
14 map.into_iter()
15 .map(|(key, serde_json_value)| (key, serde_json_value.into()))
16 .collect()
17 }
18
19 pub fn try_into_validating_json(self) -> Result<JsonValue, Error> {
20 Ok(match self {
21 Value::U128(i) => {
22 if i > u64::MAX as u128 {
23 return Err(Error::IntegerSizeError);
24 }
25 JsonValue::Number((i as u64).into())
26 }
27 Value::I128(i) => {
28 if i > i64::MAX as i128 {
29 return Err(Error::IntegerSizeError);
30 }
31 if i < i64::MIN as i128 {
32 return Err(Error::IntegerSizeError);
33 }
34 JsonValue::Number((i as i64).into())
35 }
36 Value::U64(i) => JsonValue::Number(i.into()),
37 Value::I64(i) => JsonValue::Number(i.into()),
38 Value::U32(i) => JsonValue::Number(i.into()),
39 Value::I32(i) => JsonValue::Number(i.into()),
40 Value::U16(i) => JsonValue::Number(i.into()),
41 Value::I16(i) => JsonValue::Number(i.into()),
42 Value::U8(i) => JsonValue::Number(i.into()),
43 Value::I8(i) => JsonValue::Number(i.into()),
44 Value::Float(float) => JsonValue::Number(Number::from_f64(float).unwrap_or(0.into())),
45 Value::Text(string) => JsonValue::String(string),
46 Value::Bool(value) => JsonValue::Bool(value),
47 Value::Null => JsonValue::Null,
48 Value::Array(array) => JsonValue::Array(
49 array
50 .into_iter()
51 .map(|value| value.try_into_validating_json())
52 .collect::<Result<Vec<JsonValue>, Error>>()?,
53 ),
54 Value::Map(map) => JsonValue::Object(
55 map.into_iter()
56 .map(|(k, v)| {
57 let string = k.into_text()?;
58 Ok((string, v.try_into_validating_json()?))
59 })
60 .collect::<Result<Map<String, JsonValue>, Error>>()?,
61 ),
62 Value::Identifier(bytes) => {
63 JsonValue::Array(
65 bytes
66 .into_iter()
67 .map(|a| JsonValue::Number(a.into()))
68 .collect(),
69 )
70 }
71 Value::Bytes(bytes) => JsonValue::Array(
72 bytes
73 .into_iter()
74 .map(|byte| JsonValue::Number(byte.into()))
75 .collect(),
76 ),
77 Value::Bytes20(bytes) => JsonValue::Array(
78 bytes
79 .into_iter()
80 .map(|byte| JsonValue::Number(byte.into()))
81 .collect(),
82 ),
83 Value::Bytes32(bytes) => JsonValue::Array(
84 bytes
85 .into_iter()
86 .map(|byte| JsonValue::Number(byte.into()))
87 .collect(),
88 ),
89 Value::Bytes36(bytes) => JsonValue::Array(
90 bytes
91 .into_iter()
92 .map(|byte| JsonValue::Number(byte.into()))
93 .collect(),
94 ),
95 Value::EnumU8(_) => {
96 return Err(Error::Unsupported(
97 "No support for conversion of EnumU8 to JSONValue".to_string(),
98 ))
99 }
100 Value::EnumString(_) => {
101 return Err(Error::Unsupported(
102 "No support for conversion of EnumString to JSONValue".to_string(),
103 ))
104 }
105 })
106 }
107
108 pub fn try_into_validating_btree_map_json(self) -> Result<BTreeMap<String, JsonValue>, Error> {
109 self.into_btree_string_map()?
110 .into_iter()
111 .map(|(key, value)| Ok((key, value.try_into_validating_json()?)))
112 .collect()
113 }
114
115 pub fn try_to_validating_json(&self) -> Result<JsonValue, Error> {
116 Ok(match self {
117 Value::U128(i) => {
118 if *i > u64::MAX as u128 {
119 return Err(Error::IntegerSizeError);
120 }
121 JsonValue::Number((*i as u64).into())
122 }
123 Value::I128(i) => {
124 if *i > i64::MAX as i128 {
125 return Err(Error::IntegerSizeError);
126 }
127 if *i < i64::MIN as i128 {
128 return Err(Error::IntegerSizeError);
129 }
130 JsonValue::Number((*i as i64).into())
131 }
132 Value::U64(i) => JsonValue::Number((*i).into()),
133 Value::I64(i) => JsonValue::Number((*i).into()),
134 Value::U32(i) => JsonValue::Number((*i).into()),
135 Value::I32(i) => JsonValue::Number((*i).into()),
136 Value::U16(i) => JsonValue::Number((*i).into()),
137 Value::I16(i) => JsonValue::Number((*i).into()),
138 Value::U8(i) => JsonValue::Number((*i).into()),
139 Value::I8(i) => JsonValue::Number((*i).into()),
140 Value::Float(float) => JsonValue::Number(Number::from_f64(*float).unwrap_or(0.into())),
141 Value::Text(string) => JsonValue::String(string.clone()),
142 Value::Bool(value) => JsonValue::Bool(*value),
143 Value::Null => JsonValue::Null,
144 Value::Array(array) => JsonValue::Array(
145 array
146 .iter()
147 .map(|value| value.try_to_validating_json())
148 .collect::<Result<Vec<JsonValue>, Error>>()?,
149 ),
150 Value::Map(map) => JsonValue::Object(
151 map.iter()
152 .map(|(k, v)| {
153 let string = k.to_text()?;
154 Ok((string, v.try_to_validating_json()?))
155 })
156 .collect::<Result<Map<String, JsonValue>, Error>>()?,
157 ),
158 Value::Identifier(bytes) => {
159 JsonValue::Array(
161 bytes
162 .iter()
163 .map(|a| JsonValue::Number((*a).into()))
164 .collect(),
165 )
166 }
167 Value::Bytes(bytes) => JsonValue::Array(
168 bytes
169 .iter()
170 .map(|byte| JsonValue::Number((*byte).into()))
171 .collect(),
172 ),
173 Value::Bytes20(bytes) => JsonValue::Array(
174 bytes
175 .iter()
176 .map(|byte| JsonValue::Number((*byte).into()))
177 .collect(),
178 ),
179 Value::Bytes32(bytes) => JsonValue::Array(
180 bytes
181 .iter()
182 .map(|byte| JsonValue::Number((*byte).into()))
183 .collect(),
184 ),
185 Value::Bytes36(bytes) => JsonValue::Array(
186 bytes
187 .iter()
188 .map(|byte| JsonValue::Number((*byte).into()))
189 .collect(),
190 ),
191 Value::EnumU8(_) => {
192 return Err(Error::Unsupported(
193 "No support for conversion of EnumU8 to JSONValue".to_string(),
194 ))
195 }
196 Value::EnumString(_) => {
197 return Err(Error::Unsupported(
198 "No support for conversion of EnumString to JSONValue".to_string(),
199 ))
200 }
201 })
202 }
203}
204
205impl From<JsonValue> for Value {
206 fn from(value: JsonValue) -> Self {
207 match value {
208 JsonValue::Null => Self::Null,
209 JsonValue::Bool(value) => Self::Bool(value),
210 JsonValue::Number(number) => {
211 if let Some(value) = number.as_u64() {
212 return Self::U64(value);
213 } else if let Some(value) = number.as_i64() {
214 return Self::I64(value);
215 } else if let Some(value) = number.as_f64() {
216 return Self::Float(value);
217 }
218 unreachable!("this shouldn't be reachable")
219 }
220 JsonValue::String(string) => Self::Text(string),
221 JsonValue::Array(array) => {
222 let u8_max = u8::MAX as u64;
223 let len = array.len();
225 if len >= 10
226 && array.iter().all(|v| {
227 let Some(int) = v.as_u64() else {
228 return false;
229 };
230 int.le(&u8_max)
231 })
232 {
233 Self::Bytes(
235 array
236 .into_iter()
237 .map(|v| v.as_u64().unwrap() as u8)
238 .collect(),
239 )
240 } else {
241 Self::Array(array.into_iter().map(|v| v.into()).collect())
242 }
243 }
244 JsonValue::Object(map) => {
245 Self::Map(map.into_iter().map(|(k, v)| (k.into(), v.into())).collect())
246 }
247 }
248 }
249}
250
251impl From<&JsonValue> for Value {
252 fn from(value: &JsonValue) -> Self {
253 match value {
254 JsonValue::Null => Self::Null,
255 JsonValue::Bool(value) => Self::Bool(*value),
256 JsonValue::Number(number) => {
257 if let Some(value) = number.as_u64() {
258 return Self::U64(value);
259 } else if let Some(value) = number.as_i64() {
260 return Self::I64(value);
261 } else if let Some(value) = number.as_f64() {
262 return Self::Float(value);
263 }
264 unreachable!("this shouldn't be reachable")
265 }
266 JsonValue::String(string) => Self::Text(string.clone()),
267 JsonValue::Array(array) => {
268 let u8_max = u8::MAX as u64;
269 let len = array.len();
271 if len >= 10
272 && array.iter().all(|v| {
273 let Some(int) = v.as_u64() else {
274 return false;
275 };
276 int.le(&u8_max)
277 })
278 {
279 Self::Bytes(array.iter().map(|v| v.as_u64().unwrap() as u8).collect())
281 } else {
282 Self::Array(array.iter().map(|v| v.into()).collect())
283 }
284 }
285 JsonValue::Object(map) => Self::Map(
286 map.into_iter()
287 .map(|(k, v)| (k.clone().into(), v.into()))
288 .collect(),
289 ),
290 }
291 }
292}
293
294impl TryInto<JsonValue> for Value {
295 type Error = Error;
296
297 fn try_into(self) -> Result<JsonValue, Self::Error> {
298 Ok(match self {
299 Value::U128(i) => JsonValue::String(i.to_string()),
301 Value::I128(i) => JsonValue::String(i.to_string()),
302 Value::U64(i) => JsonValue::Number(i.into()),
303 Value::I64(i) => JsonValue::Number(i.into()),
304 Value::U32(i) => JsonValue::Number(i.into()),
305 Value::I32(i) => JsonValue::Number(i.into()),
306 Value::U16(i) => JsonValue::Number(i.into()),
307 Value::I16(i) => JsonValue::Number(i.into()),
308 Value::U8(i) => JsonValue::Number(i.into()),
309 Value::I8(i) => JsonValue::Number(i.into()),
310 Value::Bytes(bytes) => JsonValue::String(BASE64_STANDARD.encode(bytes.as_slice())),
311 Value::Bytes20(bytes) => JsonValue::String(BASE64_STANDARD.encode(bytes.as_slice())),
312 Value::Bytes32(bytes) => JsonValue::String(BASE64_STANDARD.encode(bytes.as_slice())),
313 Value::Bytes36(bytes) => JsonValue::String(BASE64_STANDARD.encode(bytes.as_slice())),
314 Value::Float(float) => JsonValue::Number(Number::from_f64(float).unwrap_or(0.into())),
315 Value::Text(string) => JsonValue::String(string),
316 Value::Bool(value) => JsonValue::Bool(value),
317 Value::Null => JsonValue::Null,
318 Value::Array(array) => JsonValue::Array(
319 array
320 .into_iter()
321 .map(|value| value.try_into())
322 .collect::<Result<Vec<JsonValue>, Error>>()?,
323 ),
324 Value::Map(map) => JsonValue::Object(
325 map.into_iter()
326 .map(|(k, v)| {
327 let string = k.into_text()?;
328 Ok((string, v.try_into()?))
329 })
330 .collect::<Result<Map<String, JsonValue>, Error>>()?,
331 ),
332 Value::Identifier(bytes) => {
333 JsonValue::String(bs58::encode(bytes.as_slice()).into_string())
334 }
335 Value::EnumU8(_) => {
336 return Err(Error::Unsupported(
337 "No support for conversion of EnumU8 to JSONValue".to_string(),
338 ))
339 }
340 Value::EnumString(_) => {
341 return Err(Error::Unsupported(
342 "No support for conversion of EnumString to JSONValue".to_string(),
343 ))
344 }
345 })
346 }
347}
348
349pub trait BTreeValueJsonConverter {
350 fn into_json_value(self) -> Result<JsonValue, Error>;
351 fn into_validating_json_value(self) -> Result<JsonValue, Error>;
352 fn to_json_value(&self) -> Result<JsonValue, Error>;
353 fn to_validating_json_value(&self) -> Result<JsonValue, Error>;
354 fn from_json_value(value: JsonValue) -> Result<Self, Error>
355 where
356 Self: Sized;
357}
358
359impl BTreeValueJsonConverter for BTreeMap<String, Value> {
360 fn into_json_value(self) -> Result<JsonValue, Error> {
361 Ok(JsonValue::Object(
362 self.into_iter()
363 .map(|(key, value)| Ok((key, value.try_into()?)))
364 .collect::<Result<Map<String, JsonValue>, Error>>()?,
365 ))
366 }
367
368 fn into_validating_json_value(self) -> Result<JsonValue, Error> {
369 Ok(JsonValue::Object(
370 self.into_iter()
371 .map(|(key, value)| Ok((key, value.try_into_validating_json()?)))
372 .collect::<Result<Map<String, JsonValue>, Error>>()?,
373 ))
374 }
375
376 fn to_json_value(&self) -> Result<JsonValue, Error> {
377 Ok(JsonValue::Object(
378 self.iter()
379 .map(|(key, value)| Ok((key.clone(), value.clone().try_into()?)))
380 .collect::<Result<Map<String, JsonValue>, Error>>()?,
381 ))
382 }
383
384 fn to_validating_json_value(&self) -> Result<JsonValue, Error> {
385 Ok(JsonValue::Object(
386 self.iter()
387 .map(|(key, value)| Ok((key.to_owned(), value.try_to_validating_json()?)))
388 .collect::<Result<Map<String, JsonValue>, Error>>()?,
389 ))
390 }
391
392 fn from_json_value(value: JsonValue) -> Result<Self, Error> {
393 let platform_value: Value = value.into();
394 platform_value.into_btree_string_map()
395 }
396}
397
398impl From<BTreeMap<String, JsonValue>> for Value {
399 fn from(value: BTreeMap<String, JsonValue>) -> Self {
400 let map: ValueMap = value
401 .into_iter()
402 .map(|(key, json_value)| {
403 let value: Value = json_value.into();
404 (Value::Text(key), value)
405 })
406 .collect();
407 Value::Map(map)
408 }
409}
410
411impl From<&BTreeMap<String, JsonValue>> for Value {
412 fn from(value: &BTreeMap<String, JsonValue>) -> Self {
413 let map: ValueMap = value
414 .iter()
415 .map(|(key, json_value)| {
416 let value: Value = json_value.into();
417 (Value::Text(key.clone()), value)
418 })
419 .collect();
420 Value::Map(map)
421 }
422}
423
424#[cfg(test)]
425mod tests {
426 use crate::Value;
427 use serde_json::json;
428
429 #[test]
430 fn test_json_array() {
431 let json = json!({
432 "type": 5,
433 "protocolVersion": 1,
434 "revision": 0,
435 "signature": "HxtcTSpRdACokorvpx/f4ezM40e0WtgW2GUvjiwNkHPwKDppkIoS2cirhqpZURlhDuYdu+E0KllbHNlYghcK9Bg=",
436 "signaturePublicKeyId": 1,
437 "addPublicKeys": [
438 {
439 "id": 0,
440 "purpose": 0,
441 "securityLevel": 0,
442 "type": 0,
443 "data": "Aya0WP8EhKQ6Dq+51sAnqdPah664X9CUciVJYAfvfTnX",
444 "readOnly": false,
445 "signature": "HxtcTSpRdACokorvpx/f4ezM40e0WtgW2GUvjiwNkHPwKDppkIoS2cirhqpZURlhDuYdu+E0KllbHNlYghcK9Bg="
446 }
447 ],
448 "disablePublicKeys": [ 0 ],
449 "identityId": "62DHhTfZV3NvUbXUha1mavLqSEy2GaWYja2qeTYNUhk"
450 });
451
452 let value: Value = json.into();
453 let array = value
454 .get_optional_array_slice("addPublicKeys")
455 .expect("expected to get array slice")
456 .unwrap();
457 assert_eq!(array.len(), 1);
458 assert!(array.first().unwrap().is_map());
459 let array = value
460 .get_optional_array_slice("disablePublicKeys")
461 .expect("expected to get array slice")
462 .unwrap();
463 assert_eq!(array.len(), 1);
464 }
465}