use pamoja_core::{Error, Result};
pub fn json_to_cbor(json: &[u8]) -> Result<Vec<u8>> {
let value: serde_json::Value =
serde_json::from_slice(json).map_err(|error| Error::Codec(error.to_string()))?;
let mut buffer = Vec::new();
ciborium::into_writer(&value, &mut buffer).map_err(|error| Error::Codec(error.to_string()))?;
Ok(buffer)
}
pub fn cbor_to_json(cbor: &[u8]) -> Result<Vec<u8>> {
let value: ciborium::Value =
ciborium::from_reader(cbor).map_err(|error| Error::Codec(error.to_string()))?;
let value: serde_json::Value = value
.deserialized()
.map_err(|error| Error::Codec(error.to_string()))?;
serde_json::to_vec(&value).map_err(|error| Error::Codec(error.to_string()))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn object_keys_come_back_sorted() {
let cbor = json_to_cbor(br#"{"c":21.5,"a":1}"#).expect("to cbor");
assert_eq!(
cbor_to_json(&cbor).expect("to json"),
br#"{"a":1,"c":21.5}"#
);
}
#[test]
fn round_trips_a_document() {
let json = br#"{"battery":88,"id":"probe-1","reading":21.5}"#;
let cbor = json_to_cbor(json).expect("to cbor");
assert_eq!(cbor_to_json(&cbor).expect("to json"), json);
}
#[test]
fn cbor_is_smaller_than_the_json_it_came_from() {
let json = br#"{"a":1,"b":2,"c":3,"d":4,"e":5}"#;
let cbor = json_to_cbor(json).expect("to cbor");
assert!(cbor.len() < json.len());
}
#[test]
fn round_trips_nested_and_empty_containers() {
let json = br#"{"empty":{},"list":[1,[2,3],{"deep":true}],"none":null}"#;
let cbor = json_to_cbor(json).expect("to cbor");
assert_eq!(cbor_to_json(&cbor).expect("to json"), json);
}
#[test]
fn invalid_json_is_a_codec_error() {
assert!(matches!(json_to_cbor(b"not json"), Err(Error::Codec(_))));
}
#[test]
fn invalid_cbor_is_a_codec_error() {
assert!(matches!(cbor_to_json(&[0xff, 0xff]), Err(Error::Codec(_))));
}
#[test]
fn a_non_string_map_key_has_no_json_form() {
let mut cbor = Vec::new();
let value = ciborium::Value::Map(vec![(
ciborium::Value::Integer(1.into()),
ciborium::Value::Bool(true),
)]);
ciborium::into_writer(&value, &mut cbor).expect("write cbor");
assert!(matches!(cbor_to_json(&cbor), Err(Error::Codec(_))));
}
#[test]
fn a_document_transcodes_to_the_bytes_rfc_8949_fixes() {
let json = br#"{"c":21.5,"ok":true}"#;
let cbor = json_to_cbor(json).expect("a valid document");
assert_eq!(
cbor,
[0xA2, 0x61, 0x63, 0xF9, 0x4D, 0x60, 0x62, 0x6F, 0x6B, 0xF5]
);
assert_eq!(cbor_to_json(&cbor).expect("a valid document"), json);
}
}