diff --git a/Cargo.lock b/Cargo.lock index b70dfdc0e..02e4ecf7b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -2738,6 +2738,7 @@ dependencies = [ "maybe-async", "prost", "regex", + "serde", "serde_json", "serial_test", "smol", diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 6bba6ed19..597fbdfad 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -53,6 +53,11 @@ [dependencies] + [dependencies.serde] + features = ["derive"] + version = "1.0" + default-features = false + [dependencies.tokio] features = ["bytes", "default", "fs", "full", "io-std", "io-util", "libc", "macros", "mio", "net", "parking_lot", "process", "rt", "rt-multi-thread", "signal", "signal-hook-registry", "socket2", "sync", "time", "tokio-macros"] version = "1.44.2" diff --git a/rust/src/answer/json.rs b/rust/src/answer/json.rs index ce28296b0..dbc26987e 100644 --- a/rust/src/answer/json.rs +++ b/rust/src/answer/json.rs @@ -23,6 +23,8 @@ use std::{ fmt::{self, Write}, }; +use serde::{ser::SerializeMap, ser::SerializeSeq, Serialize, Serializer}; + #[derive(Clone, Debug)] pub enum JSON { Object(HashMap, JSON>), @@ -65,6 +67,34 @@ impl fmt::Display for JSON { } } +impl Serialize for JSON { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self { + JSON::Object(object) => { + let mut map = serializer.serialize_map(Some(object.len()))?; + for (key, value) in object { + map.serialize_entry(key, value)?; + } + map.end() + } + JSON::Array(array) => { + let mut seq = serializer.serialize_seq(Some(array.len()))?; + for element in array { + seq.serialize_element(element)?; + } + seq.end() + } + JSON::String(string) => serializer.serialize_str(string), + JSON::Number(number) => serializer.serialize_f64(*number), + JSON::Boolean(boolean) => serializer.serialize_bool(*boolean), + JSON::Null => serializer.serialize_unit(), + } + } +} + fn write_escaped_string(string: &str, f: &mut fmt::Formatter<'_>) -> fmt::Result { const HEX: u8 = 0; const BSP: u8 = b'b'; @@ -126,4 +156,64 @@ mod test { let json_string = JSON::String(Cow::Owned(string)); assert_eq!(serde_json::to_string(&serde_json_value).unwrap(), json_string.to_string()); } + + #[test] + fn test_serialize_implementation() { + use std::collections::HashMap; + + // Test Null + let null_json = JSON::Null; + assert_eq!(serde_json::to_string(&null_json).unwrap(), "null"); + + // Test Boolean + let bool_json = JSON::Boolean(true); + assert_eq!(serde_json::to_string(&bool_json).unwrap(), "true"); + + // Test Number + let number_json = JSON::Number(42.5); + assert_eq!(serde_json::to_string(&number_json).unwrap(), "42.5"); + + // Test String + let string_json = JSON::String(Cow::Borrowed("hello world")); + assert_eq!(serde_json::to_string(&string_json).unwrap(), r#""hello world""#); + + // Test Array + let array_json = JSON::Array(vec![ + JSON::Number(1.0), + JSON::String(Cow::Borrowed("test")), + JSON::Boolean(false), + JSON::Null, + ]); + assert_eq!(serde_json::to_string(&array_json).unwrap(), r#"[1.0,"test",false,null]"#); + + // Test Object + let mut object = HashMap::new(); + object.insert(Cow::Borrowed("key1"), JSON::String(Cow::Borrowed("value1"))); + object.insert(Cow::Borrowed("key2"), JSON::Number(123.0)); + let object_json = JSON::Object(object); + let serialized = serde_json::to_string(&object_json).unwrap(); + + // Since HashMap order is not guaranteed, check that both possible orders are valid + assert!( + serialized == r#"{"key1":"value1","key2":123.0}"# || + serialized == r#"{"key2":123.0,"key1":"value1"}"# + ); + + // Test complex nested structure + let mut complex_object = HashMap::new(); + complex_object.insert(Cow::Borrowed("array"), JSON::Array(vec![ + JSON::Number(1.0), + JSON::Number(2.0), + ])); + complex_object.insert(Cow::Borrowed("nested"), JSON::Object({ + let mut nested = HashMap::new(); + nested.insert(Cow::Borrowed("inner"), JSON::Boolean(true)); + nested + })); + let complex_json = JSON::Object(complex_object); + let complex_serialized = serde_json::to_string(&complex_json).unwrap(); + + // Verify the serialized JSON can be parsed back + let _: serde_json::Value = serde_json::from_str(&complex_serialized).unwrap(); + } }