pub mod binary_packer;
pub mod binary_unpacker;
pub mod compression;
pub mod display96;
pub mod frame;
pub mod parsers;
pub mod serializers;
pub mod stele;
pub mod stele_analyzer;
pub mod types;
#[cfg(test)]
mod edge_cases;
pub use binary_packer::pack;
pub use binary_unpacker::unpack;
pub use compression::SchemaCompressionAlgo;
pub use frame::{decode_framed, encode_framed};
pub use parsers::{InputParser, JsonParser};
pub use serializers::{JsonSerializer, OutputSerializer};
pub use types::{
FieldDef, FieldType, IntermediateRepresentation, SchemaError, SchemaHeader, SchemaValue,
};
#[allow(unused_imports)]
pub use stele::{parse as parse_stele, serialize as serialize_stele};
pub fn encode_schema(
json: &str,
compress: Option<SchemaCompressionAlgo>,
) -> Result<String, SchemaError> {
use parsers::{InputParser, JsonParser};
let ir = JsonParser::parse(json)?;
let binary = pack(&ir);
let compressed = compression::compress_with_prefix(&binary, compress)?;
Ok(frame::encode_framed(&compressed))
}
pub fn decode_schema(encoded: &str, pretty: bool) -> Result<String, SchemaError> {
use serializers::{JsonSerializer, OutputSerializer};
let compressed = frame::decode_framed(encoded)?;
let binary = compression::decompress_with_prefix(&compressed)?;
let ir = unpack(&binary)?;
JsonSerializer::serialize(&ir, pretty)
}
pub fn encode_stele(json: &str, minify: bool) -> Result<String, SchemaError> {
encode_stele_with_options(json, minify, true, true)
}
pub fn encode_stele_minified(json: &str) -> Result<String, SchemaError> {
encode_stele_with_options(json, true, true, true)
}
pub fn encode_stele_readable(json: &str, minify: bool) -> Result<String, SchemaError> {
encode_stele_with_options(json, minify, false, false)
}
pub fn encode_stele_light(json: &str, minify: bool) -> Result<String, SchemaError> {
encode_stele_with_options(json, minify, true, false)
}
pub fn encode_stele_path(json: &str) -> Result<String, SchemaError> {
stele::serialize_path_mode(json)
}
pub fn decode_stele_path(path_input: &str) -> Result<String, SchemaError> {
stele::parse_path_mode(path_input)
}
pub fn encode_stele_ascii(json: &str) -> Result<String, SchemaError> {
use parsers::{InputParser, JsonParser};
let ir = JsonParser::parse(json)?;
stele::serialize_ascii(&ir)
}
pub fn encode_markdown_stele_ascii(markdown: &str) -> Result<String, SchemaError> {
use parsers::{InputParser, MarkdownDocParser};
let ir = MarkdownDocParser::parse(markdown)?;
stele::serialize_ascii(&ir)
}
pub fn encode_markdown_stele_markdown(markdown: &str) -> Result<String, SchemaError> {
use parsers::{InputParser, MarkdownDocParser};
let ir = MarkdownDocParser::parse(markdown)?;
stele::serialize_markdown(&ir)
}
pub fn encode_markdown_stele(markdown: &str, minify: bool) -> Result<String, SchemaError> {
encode_markdown_stele_with_options(markdown, minify, true, true)
}
pub fn encode_markdown_stele_readable(markdown: &str, minify: bool) -> Result<String, SchemaError> {
encode_markdown_stele_with_options(markdown, minify, false, false)
}
pub fn encode_markdown_stele_light(markdown: &str, minify: bool) -> Result<String, SchemaError> {
encode_markdown_stele_with_options(markdown, minify, true, false)
}
fn encode_markdown_stele_with_options(
markdown: &str,
minify: bool,
tokenize_fields: bool,
tokenize_values: bool,
) -> Result<String, SchemaError> {
use parsers::{InputParser, MarkdownDocParser};
let ir = MarkdownDocParser::parse(markdown)?;
match (tokenize_fields, tokenize_values) {
(true, true) => stele::serialize(&ir, minify),
(true, false) => stele::serialize_light(&ir, minify),
(false, false) => stele::serialize_readable(&ir, minify),
(false, true) => {
stele::serialize_readable(&ir, minify)
}
}
}
fn encode_stele_with_options(
json: &str,
minify: bool,
tokenize_fields: bool,
tokenize_values: bool,
) -> Result<String, SchemaError> {
use parsers::{InputParser, JsonParser};
let ir = JsonParser::parse(json)?;
match (tokenize_fields, tokenize_values) {
(true, true) => stele::serialize(&ir, minify),
(true, false) => stele::serialize_light(&ir, minify),
(false, false) => stele::serialize_readable(&ir, minify),
(false, true) => {
stele::serialize_readable(&ir, minify)
}
}
}
pub fn decode_stele(stele_input: &str, pretty: bool) -> Result<String, SchemaError> {
use serializers::{JsonSerializer, OutputSerializer};
let ir = stele::parse(stele_input)?;
JsonSerializer::serialize(&ir, pretty)
}
#[cfg(test)]
mod integration_tests {
use super::*;
use crate::encoders::algorithms::schema::types::{
FLAG_HAS_NULLS, FLAG_HAS_ROOT_KEY, FieldDef, FieldType, IntermediateRepresentation,
SchemaHeader, SchemaValue,
};
use parsers::{InputParser, JsonParser};
use serializers::{JsonSerializer, OutputSerializer};
#[test]
fn test_round_trip_simple() {
let fields = vec![
FieldDef::new("id", FieldType::U64),
FieldDef::new("name", FieldType::String),
];
let header = SchemaHeader::new(2, fields);
let values = vec![
SchemaValue::U64(1),
SchemaValue::String("Alice".to_string()),
SchemaValue::U64(2),
SchemaValue::String("Bob".to_string()),
];
let original = IntermediateRepresentation::new(header, values).unwrap();
let packed = pack(&original);
let unpacked = unpack(&packed).unwrap();
assert_eq!(original, unpacked);
}
#[test]
fn test_round_trip_all_types() {
let fields = vec![
FieldDef::new("u64_field", FieldType::U64),
FieldDef::new("i64_field", FieldType::I64),
FieldDef::new("f64_field", FieldType::F64),
FieldDef::new("string_field", FieldType::String),
FieldDef::new("bool_field", FieldType::Bool),
];
let header = SchemaHeader::new(1, fields);
let values = vec![
SchemaValue::U64(42),
SchemaValue::I64(-42),
SchemaValue::F64(std::f64::consts::PI),
SchemaValue::String("test".to_string()),
SchemaValue::Bool(true),
];
let original = IntermediateRepresentation::new(header, values).unwrap();
let packed = pack(&original);
let unpacked = unpack(&packed).unwrap();
assert_eq!(original, unpacked);
}
#[test]
fn test_round_trip_with_root_key() {
let mut header = SchemaHeader::new(1, vec![FieldDef::new("id", FieldType::U64)]);
header.root_key = Some("users".to_string());
header.set_flag(FLAG_HAS_ROOT_KEY);
let values = vec![SchemaValue::U64(42)];
let original = IntermediateRepresentation::new(header, values).unwrap();
let packed = pack(&original);
let unpacked = unpack(&packed).unwrap();
assert_eq!(original, unpacked);
}
#[test]
fn test_round_trip_with_nulls() {
let mut header = SchemaHeader::new(
2,
vec![
FieldDef::new("id", FieldType::U64),
FieldDef::new("name", FieldType::String),
],
);
let total_values: usize = 2 * 2; let bitmap_bytes = total_values.div_ceil(8); let mut null_bitmap = vec![0u8; bitmap_bytes];
null_bitmap[0] |= 1 << 1;
header.null_bitmap = Some(null_bitmap);
header.set_flag(FLAG_HAS_NULLS);
let values = vec![
SchemaValue::U64(1),
SchemaValue::Null, SchemaValue::U64(2),
SchemaValue::String("Bob".to_string()),
];
let original = IntermediateRepresentation::new(header, values).unwrap();
let packed = pack(&original);
let unpacked = unpack(&packed).unwrap();
assert_eq!(original, unpacked);
}
#[test]
fn test_round_trip_array() {
let fields = vec![FieldDef::new(
"tags",
FieldType::Array(Box::new(FieldType::U64)),
)];
let header = SchemaHeader::new(1, fields);
let values = vec![SchemaValue::Array(vec![
SchemaValue::U64(1),
SchemaValue::U64(2),
SchemaValue::U64(3),
])];
let original = IntermediateRepresentation::new(header, values).unwrap();
let packed = pack(&original);
let unpacked = unpack(&packed).unwrap();
assert_eq!(original, unpacked);
}
#[test]
fn test_round_trip_large_values() {
let fields = vec![
FieldDef::new("large_u64", FieldType::U64),
FieldDef::new("large_i64", FieldType::I64),
];
let header = SchemaHeader::new(1, fields);
let values = vec![SchemaValue::U64(u64::MAX), SchemaValue::I64(i64::MIN)];
let original = IntermediateRepresentation::new(header, values).unwrap();
let packed = pack(&original);
let unpacked = unpack(&packed).unwrap();
assert_eq!(original, unpacked);
}
#[test]
fn test_round_trip_empty_string() {
let fields = vec![FieldDef::new("name", FieldType::String)];
let header = SchemaHeader::new(1, fields);
let values = vec![SchemaValue::String("".to_string())];
let original = IntermediateRepresentation::new(header, values).unwrap();
let packed = pack(&original);
let unpacked = unpack(&packed).unwrap();
assert_eq!(original, unpacked);
}
#[test]
fn test_round_trip_multiple_rows() {
let fields = vec![
FieldDef::new("id", FieldType::U64),
FieldDef::new("score", FieldType::F64),
FieldDef::new("active", FieldType::Bool),
];
let header = SchemaHeader::new(3, fields);
let values = vec![
SchemaValue::U64(1),
SchemaValue::F64(95.5),
SchemaValue::Bool(true),
SchemaValue::U64(2),
SchemaValue::F64(87.3),
SchemaValue::Bool(false),
SchemaValue::U64(3),
SchemaValue::F64(92.1),
SchemaValue::Bool(true),
];
let original = IntermediateRepresentation::new(header, values).unwrap();
let packed = pack(&original);
let unpacked = unpack(&packed).unwrap();
assert_eq!(original, unpacked);
}
#[test]
fn test_invalid_data() {
let result = unpack(&[]);
assert!(matches!(
result,
Err(SchemaError::UnexpectedEndOfData { .. })
));
let result = unpack(&[0, 1, 2]);
assert!(result.is_err());
}
#[test]
fn test_json_full_roundtrip() {
let input = r#"{"users":[{"id":1,"name":"alice"},{"id":2,"name":"bob"}]}"#;
let ir = JsonParser::parse(input).unwrap();
let binary = pack(&ir);
let compressed = compression::compress_with_prefix(&binary, None).unwrap();
let decompressed = compression::decompress_with_prefix(&compressed).unwrap();
let ir2 = unpack(&decompressed).unwrap();
let output = JsonSerializer::serialize(&ir2, false).unwrap();
let input_value: serde_json::Value = serde_json::from_str(input).unwrap();
let output_value: serde_json::Value = serde_json::from_str(&output).unwrap();
assert_eq!(input_value, output_value);
}
#[test]
fn test_json_simple_object() {
let input = r#"{"id":1,"name":"alice","score":95.5}"#;
let ir = JsonParser::parse(input).unwrap();
let binary = pack(&ir);
let ir2 = unpack(&binary).unwrap();
let output = JsonSerializer::serialize(&ir2, false).unwrap();
let input_value: serde_json::Value = serde_json::from_str(input).unwrap();
let output_value: serde_json::Value = serde_json::from_str(&output).unwrap();
assert_eq!(input_value, output_value);
}
#[test]
fn test_json_swapi_nested_arrays() {
let input = r#"{"people":[{"name":"Luke","height":"172","films":["film/1","film/2"],"vehicles":[]},{"name":"C-3PO","height":"167","films":["film/1","film/2","film/3"],"vehicles":[]}]}"#;
let ir = JsonParser::parse(input).unwrap();
let stele_output = stele::serialize_readable(&ir, false).unwrap();
assert!(stele_output.starts_with("@people"));
assert!(stele_output.contains("filmsˢ⟦⟧"));
assert!(stele_output.contains("vehiclesˢ⟦⟧"));
let binary = pack(&ir);
let ir2 = unpack(&binary).unwrap();
let output = JsonSerializer::serialize(&ir2, false).unwrap();
let output_value: serde_json::Value = serde_json::from_str(&output).unwrap();
let people = output_value
.as_object()
.unwrap()
.get("people")
.unwrap()
.as_array()
.unwrap();
let luke = &people[0];
assert_eq!(luke["name"], "Luke");
assert_eq!(luke["height"], "172");
let luke_films = luke["films"].as_array().unwrap();
assert_eq!(luke_films[0], "film/1");
assert_eq!(luke_films[1], "film/2");
}
#[test]
fn test_json_wrapper_keys() {
let test_cases = vec![
r#"{"results":[{"id":1,"name":"a"},{"id":2,"name":"b"}]}"#,
r#"{"data":[{"id":1,"name":"a"},{"id":2,"name":"b"}]}"#,
r#"{"items":[{"id":1,"name":"a"},{"id":2,"name":"b"}]}"#,
r#"{"records":[{"id":1,"name":"a"},{"id":2,"name":"b"}]}"#,
];
for input in test_cases {
let ir = JsonParser::parse(input).unwrap();
assert!(ir.header.root_key.is_some());
let root = ir.header.root_key.as_ref().unwrap();
assert!(root == "results" || root == "data" || root == "items" || root == "records");
assert_eq!(ir.header.row_count, 2);
let binary = pack(&ir);
let ir2 = unpack(&binary).unwrap();
let output = JsonSerializer::serialize(&ir2, false).unwrap();
let input_value: serde_json::Value = serde_json::from_str(input).unwrap();
let output_value: serde_json::Value = serde_json::from_str(&output).unwrap();
assert_eq!(input_value, output_value);
}
}
#[test]
fn test_json_nested_objects() {
let input = r#"{"user":{"profile":{"name":"alice","age":30}}}"#;
let ir = JsonParser::parse(input).unwrap();
let binary = pack(&ir);
let ir2 = unpack(&binary).unwrap();
let output = JsonSerializer::serialize(&ir2, false).unwrap();
let input_value: serde_json::Value = serde_json::from_str(input).unwrap();
let output_value: serde_json::Value = serde_json::from_str(&output).unwrap();
assert_eq!(input_value, output_value);
}
#[test]
fn test_json_with_nulls() {
let input = r#"{"name":"alice","age":null,"active":true}"#;
let ir = JsonParser::parse(input).unwrap();
assert!(ir.header.has_flag(FLAG_HAS_NULLS));
let binary = pack(&ir);
let ir2 = unpack(&binary).unwrap();
let output = JsonSerializer::serialize(&ir2, false).unwrap();
let input_value: serde_json::Value = serde_json::from_str(input).unwrap();
let output_value: serde_json::Value = serde_json::from_str(&output).unwrap();
assert_eq!(input_value, output_value);
}
#[test]
fn test_json_with_arrays() {
let input = r#"{"scores":[95,87,92],"tags":["rust","json"]}"#;
let ir = JsonParser::parse(input).unwrap();
let binary = pack(&ir);
let ir2 = unpack(&binary).unwrap();
let output = JsonSerializer::serialize(&ir2, false).unwrap();
let expected = r#"{"scores":[95,87,92],"tags":["rust","json"]}"#;
let expected_value: serde_json::Value = serde_json::from_str(expected).unwrap();
let output_value: serde_json::Value = serde_json::from_str(&output).unwrap();
assert_eq!(expected_value, output_value);
}
#[test]
fn test_encode_schema_roundtrip() {
let input = r#"{"users":[{"id":1,"name":"alice"},{"id":2,"name":"bob"}]}"#;
let encoded = encode_schema(input, None).unwrap();
assert!(encoded.starts_with(frame::FRAME_START));
assert!(encoded.ends_with(frame::FRAME_END));
let decoded = decode_schema(&encoded, false).unwrap();
let input_value: serde_json::Value = serde_json::from_str(input).unwrap();
let output_value: serde_json::Value = serde_json::from_str(&decoded).unwrap();
assert_eq!(input_value, output_value);
}
#[test]
fn test_encode_schema_simple() {
let input = r#"{"id":1,"name":"alice","score":95.5}"#;
let encoded = encode_schema(input, None).unwrap();
let decoded = decode_schema(&encoded, false).unwrap();
let input_value: serde_json::Value = serde_json::from_str(input).unwrap();
let output_value: serde_json::Value = serde_json::from_str(&decoded).unwrap();
assert_eq!(input_value, output_value);
}
#[test]
fn test_encode_schema_with_nulls() {
let input = r#"{"name":"alice","age":null,"active":true}"#;
let encoded = encode_schema(input, None).unwrap();
let decoded = decode_schema(&encoded, false).unwrap();
let input_value: serde_json::Value = serde_json::from_str(input).unwrap();
let output_value: serde_json::Value = serde_json::from_str(&decoded).unwrap();
assert_eq!(input_value, output_value);
}
#[test]
fn test_encode_schema_empty_object() {
let input = r#"{}"#;
let result = encode_schema(input, None);
println!("Empty object result: {:?}", result);
}
#[test]
fn test_decode_schema_invalid_frame() {
let invalid = "not_framed_data";
let result = decode_schema(invalid, false);
assert!(matches!(result, Err(SchemaError::InvalidFrame(_))));
}
#[test]
fn test_decode_schema_invalid_chars() {
let invalid = format!("{}ABC{}", frame::FRAME_START, frame::FRAME_END);
let result = decode_schema(&invalid, false);
assert!(matches!(result, Err(SchemaError::InvalidCharacter(_))));
}
#[test]
fn test_visual_wire_format() {
let input = r#"{"users":[{"id":1,"name":"alice"},{"id":2,"name":"bob"}]}"#;
let encoded = encode_schema(input, None).unwrap();
println!("\n=== Visual Wire Format ===");
println!("Input JSON: {}", input);
println!("Input length: {} bytes", input.len());
println!("\nEncoded output: {}", encoded);
println!(
"Encoded length: {} chars ({} bytes UTF-8)",
encoded.chars().count(),
encoded.len()
);
let compression_ratio = input.len() as f64 / encoded.len() as f64;
println!("Compression ratio: {:.2}x", compression_ratio);
let decoded = decode_schema(&encoded, false).unwrap();
let input_value: serde_json::Value = serde_json::from_str(input).unwrap();
let output_value: serde_json::Value = serde_json::from_str(&decoded).unwrap();
assert_eq!(input_value, output_value);
println!("Roundtrip verified ✓\n");
}
#[test]
fn test_compression_comparison() {
let test_cases = [
r#"{"id":1}"#,
r#"{"id":1,"name":"alice"}"#,
r#"{"users":[{"id":1,"name":"alice"},{"id":2,"name":"bob"}]}"#,
r#"{"data":[1,2,3,4,5,6,7,8,9,10]}"#,
];
println!("\n=== Compression Comparison ===");
for (i, input) in test_cases.iter().enumerate() {
let encoded = encode_schema(input, None).unwrap();
let ratio = input.len() as f64 / encoded.len() as f64;
println!(
"Test case {}: {} bytes → {} bytes ({:.2}x)",
i + 1,
input.len(),
encoded.len(),
ratio
);
}
println!();
}
#[test]
fn test_encode_schema_with_compression() {
use super::SchemaCompressionAlgo;
let input = r#"{"users":[{"id":1,"name":"alice"},{"id":2,"name":"bob"},{"id":3,"name":"charlie"}]}"#;
for algo in [
SchemaCompressionAlgo::Brotli,
SchemaCompressionAlgo::Lz4,
SchemaCompressionAlgo::Zstd,
] {
let encoded = encode_schema(input, Some(algo)).unwrap();
let decoded = decode_schema(&encoded, false).unwrap();
let input_value: serde_json::Value = serde_json::from_str(input).unwrap();
let output_value: serde_json::Value = serde_json::from_str(&decoded).unwrap();
assert_eq!(
input_value, output_value,
"Failed for compression algorithm: {:?}",
algo
);
}
}
#[test]
fn test_compression_size_comparison() {
use super::SchemaCompressionAlgo;
let input = r#"{"users":[{"id":1,"name":"alice","active":true,"score":95.5},{"id":2,"name":"bob","active":false,"score":87.3},{"id":3,"name":"charlie","active":true,"score":92.1}]}"#;
println!("\n=== Compression Size Comparison ===");
println!("Input JSON: {} bytes", input.len());
let no_compress = encode_schema(input, None).unwrap();
println!("No compression: {} bytes", no_compress.len());
for algo in [
SchemaCompressionAlgo::Brotli,
SchemaCompressionAlgo::Lz4,
SchemaCompressionAlgo::Zstd,
] {
let compressed = encode_schema(input, Some(algo)).unwrap();
let ratio = no_compress.len() as f64 / compressed.len() as f64;
println!(
"{:?}: {} bytes ({:.2}x vs uncompressed)",
algo,
compressed.len(),
ratio
);
}
println!();
}
#[test]
fn test_nested_object_roundtrip_single_level() {
let input = r#"{"id":"A1","name":"Jim","grade":{"math":60,"physics":66,"chemistry":61}}"#;
let ir = JsonParser::parse(input).unwrap();
let stele = stele::serialize_readable(&ir, false).unwrap();
assert!(stele.contains("grade჻mathⁱ"));
assert!(stele.contains("grade჻physicsⁱ"));
assert!(stele.contains("grade჻chemistryⁱ"));
let tokenized = stele::serialize(&ir, false).unwrap();
let ir2 = stele::parse(&tokenized).unwrap();
let output = JsonSerializer::serialize(&ir2, false).unwrap();
let input_value: serde_json::Value = serde_json::from_str(input).unwrap();
let output_value: serde_json::Value = serde_json::from_str(&output).unwrap();
assert_eq!(input_value, output_value);
}
#[test]
fn test_nested_object_roundtrip_deep() {
let input = r#"{"a":{"b":{"c":{"d":42}}}}"#;
let ir = JsonParser::parse(input).unwrap();
let stele = stele::serialize_readable(&ir, false).unwrap();
assert!(stele.contains("a჻b჻c჻dⁱ"));
let tokenized = stele::serialize(&ir, false).unwrap();
let ir2 = stele::parse(&tokenized).unwrap();
let output = JsonSerializer::serialize(&ir2, false).unwrap();
let input_value: serde_json::Value = serde_json::from_str(input).unwrap();
let output_value: serde_json::Value = serde_json::from_str(&output).unwrap();
assert_eq!(input_value, output_value);
}
#[test]
fn test_nested_object_roundtrip_array_of_objects() {
let input = r#"{"students":[{"id":"A1","name":"Jim","grade":{"math":60,"physics":66}},{"id":"B2","name":"Sara","grade":{"math":85,"physics":90}}]}"#;
let ir = JsonParser::parse(input).unwrap();
let stele = stele::serialize_readable(&ir, false).unwrap();
assert!(stele.starts_with("@students"));
assert!(stele.contains("grade჻mathⁱ"));
assert!(stele.contains("grade჻physicsⁱ"));
let tokenized = stele::serialize(&ir, false).unwrap();
let ir2 = stele::parse(&tokenized).unwrap();
let output = JsonSerializer::serialize(&ir2, false).unwrap();
let input_value: serde_json::Value = serde_json::from_str(input).unwrap();
let output_value: serde_json::Value = serde_json::from_str(&output).unwrap();
assert_eq!(input_value, output_value);
}
#[test]
fn test_nested_object_roundtrip_mixed_with_arrays() {
let input = r#"{"person":{"name":"Alice","tags":["admin","user"],"address":{"city":"Boston","zip":"02101"}}}"#;
let ir = JsonParser::parse(input).unwrap();
let stele = stele::serialize_readable(&ir, false).unwrap();
assert!(stele.contains("person჻nameˢ"));
assert!(stele.contains("person჻tagsˢ⟦⟧"));
assert!(stele.contains("person჻address჻cityˢ"));
assert!(stele.contains("person჻address჻zipˢ"));
let tokenized = stele::serialize(&ir, false).unwrap();
let ir2 = stele::parse(&tokenized).unwrap();
let output = JsonSerializer::serialize(&ir2, false).unwrap();
let expected = r#"{"person":{"address":{"city":"Boston","zip":"02101"},"name":"Alice","tags":["admin","user"]}}"#;
let expected_value: serde_json::Value = serde_json::from_str(expected).unwrap();
let output_value: serde_json::Value = serde_json::from_str(&output).unwrap();
assert_eq!(expected_value, output_value);
}
#[test]
fn test_nested_object_roundtrip_schema_encode() {
let input = r#"{"data":{"user":{"profile":{"name":"alice","age":30}}}}"#;
let encoded = encode_schema(input, None).unwrap();
let decoded = decode_schema(&encoded, false).unwrap();
let input_value: serde_json::Value = serde_json::from_str(input).unwrap();
let output_value: serde_json::Value = serde_json::from_str(&decoded).unwrap();
assert_eq!(input_value, output_value);
}
}