use aws_smithy_types::{Document, Number};
use serde_json::{Map, Value};
use std::collections::HashMap;
#[derive(Debug)]
pub struct AwsDocument(pub Document);
impl From<AwsDocument> for Value {
fn from(value: AwsDocument) -> Self {
match value.0 {
Document::Object(obj) => {
let documents = obj
.into_iter()
.map(|(k, v)| (k, AwsDocument(v).into()))
.collect::<Map<_, _>>();
Value::Object(documents)
}
Document::Array(arr) => {
let documents = arr.into_iter().map(|v| AwsDocument(v).into()).collect();
Value::Array(documents)
}
Document::Number(Number::PosInt(number)) => {
Value::Number(serde_json::Number::from(number))
}
Document::Number(Number::NegInt(number)) => {
Value::Number(serde_json::Number::from(number))
}
Document::Number(Number::Float(number)) => match serde_json::Number::from_f64(number) {
Some(n) => Value::Number(n),
None => Value::Null,
},
Document::String(s) => Value::String(s),
Document::Bool(b) => Value::Bool(b),
Document::Null => Value::Null,
}
}
}
impl From<Value> for AwsDocument {
fn from(value: Value) -> Self {
match value {
Value::Null => AwsDocument(Document::Null),
Value::Bool(b) => AwsDocument(Document::Bool(b)),
Value::Number(num) => {
if let Some(i) = num.as_i64() {
match i > 0 {
true => AwsDocument(Document::Number(Number::PosInt(i as u64))),
false => AwsDocument(Document::Number(Number::NegInt(i))),
}
} else if let Some(f) = num.as_f64() {
AwsDocument(Document::Number(Number::Float(f)))
} else {
AwsDocument(Document::Null)
}
}
Value::String(s) => AwsDocument(Document::String(s)),
Value::Array(arr) => {
let documents = arr
.into_iter()
.map(|json| json.into())
.map(|aws: AwsDocument| aws.0)
.collect();
AwsDocument(Document::Array(documents))
}
Value::Object(obj) => {
let documents = obj
.into_iter()
.map(|(k, v)| {
let doc: AwsDocument = v.into();
(k, doc.0)
})
.collect::<HashMap<_, _>>();
AwsDocument(Document::Object(documents))
}
}
}
}
#[cfg(test)]
mod tests {
use std::collections::HashMap;
use aws_smithy_types::{Document, Number};
use serde_json::Value;
use crate::types::json::AwsDocument;
#[test]
fn test_json_to_aws_document() {
let json = r#"
{
"type": "object",
"is_enabled": true,
"version": 42,
"fraction": 1.23,
"negative": -11,
"properties": {
"x": {
"type": "number",
"description": "The first number to add"
},
"y": {
"type": "number",
"description": "The second number to add"
}
},
"required":["x", "y", null]
}
"#;
let value: Value = serde_json::from_str(json).unwrap();
let document: AwsDocument = value.into();
println!("{document:?}");
}
#[test]
fn test_aws_document_to_json() {
let document = AwsDocument(Document::Object(HashMap::from([
(
String::from("type"),
Document::String(String::from("object")),
),
(
String::from("version"),
Document::Number(Number::PosInt(42)),
),
(
String::from("fraction"),
Document::Number(Number::Float(1.23)),
),
(
String::from("negative"),
Document::Number(Number::NegInt(-11)),
),
(String::from("is_enabled"), Document::Bool(true)),
(
String::from("properties"),
Document::Object(HashMap::from([
(
String::from("x"),
Document::Object(HashMap::from([
(
String::from("type"),
Document::String(String::from("number")),
),
(
String::from("description"),
Document::String(String::from("The first number to add")),
),
])),
),
(
String::from("y"),
Document::Object(HashMap::from([
(
String::from("type"),
Document::String(String::from("number")),
),
(
String::from("description"),
Document::String(String::from("The second number to add")),
),
])),
),
])),
),
(
String::from("required"),
Document::Array(vec![
Document::String(String::from("x")),
Document::String(String::from("y")),
Document::Null,
]),
),
])));
let json: Value = document.into();
println!("{json:?}");
}
}