diff options
author | PradeepKiruvale <PRADEEPKIRUVALE@gmail.com> | 2021-06-17 18:22:36 +0530 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-06-17 18:22:36 +0530 |
commit | 197eae5e5c0fea07b6a7c77a89b86bc98bdefa59 (patch) | |
tree | 71526cf3c38e03f563c2c7f1a4c354078ffb1b30 /common | |
parent | 6529965a3cc2b2c69a899df1709826c117c5f555 (diff) |
[cit-415] Refactor TEJ/C8Y Serializer code (#292)
* Use String for serialization
* Add a JsonWriter abstraction
* [CIT-415] add unit tests
* [CIT-415] addressed review comments
* [CIT-415] updated test cases
* [CIT-415] Add key type
* Use serde_json::to_writer for serialization
* use serde_json for serializing
* fix azure_converter tests
* [CIT-415] Add test for key with quote
Co-authored-by: Michael Neumann <mneumann@ntecs.de>
Co-authored-by: Pradeep K J <Pradeep K J pradeekumar.kj@softwareag.com>
Diffstat (limited to 'common')
-rw-r--r-- | common/json_writer/Cargo.toml | 11 | ||||
-rw-r--r-- | common/json_writer/src/lib.rs | 163 |
2 files changed, 174 insertions, 0 deletions
diff --git a/common/json_writer/Cargo.toml b/common/json_writer/Cargo.toml new file mode 100644 index 00000000..4ea07748 --- /dev/null +++ b/common/json_writer/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "json-writer" +version = "0.1.0" +edition = "2018" + +[dependencies] +thiserror = "1.0" +serde_json = "1" + +[dev-dependencies] +anyhow = "1.0.40" diff --git a/common/json_writer/src/lib.rs b/common/json_writer/src/lib.rs new file mode 100644 index 00000000..c3c372bf --- /dev/null +++ b/common/json_writer/src/lib.rs @@ -0,0 +1,163 @@ +use std::num::FpCategory; + +#[derive(Debug, Clone)] +pub struct JsonWriter { + buffer: Vec<u8>, +} + +#[derive(thiserror::Error, Debug)] +pub enum JsonWriterError { + #[error("JsonWriter produced invalid UTF8 string")] + InvalidUtf8Conversion(#[from] std::string::FromUtf8Error), + + #[error("IoError")] + IoError(#[from] std::io::Error), + + #[error("Serde Json error")] + SerdeJsonError(#[from] serde_json::Error), + + #[error("Invalid f64 value {value:?}")] + InvalidF64Value { value: f64 }, +} + +impl JsonWriter { + pub fn new() -> Self { + Self { buffer: Vec::new() } + } + + pub fn with_capacity(capacity: usize) -> Self { + Self { + buffer: Vec::with_capacity(capacity), + } + } + + pub fn write_key(&mut self, key: &str) -> Result<(), JsonWriterError> { + self.write_str(key)?; + self.buffer.push(b':'); + Ok(()) + } + + pub fn write_str(&mut self, s: &str) -> Result<(), JsonWriterError> { + Ok(serde_json::to_writer(&mut self.buffer, s)?) + } + + pub fn write_f64(&mut self, value: f64) -> Result<(), JsonWriterError> { + match value.classify() { + FpCategory::Normal | FpCategory::Zero | FpCategory::Subnormal => { + Ok(serde_json::to_writer(&mut self.buffer, &value)?) + } + FpCategory::Infinite | FpCategory::Nan => { + Err(JsonWriterError::InvalidF64Value { value }) + } + } + } + + pub fn write_separator(&mut self) { + self.buffer.push(b','); + } + + pub fn write_open_obj(&mut self) { + self.buffer.push(b'{'); + } + + pub fn write_close_obj(&mut self) { + self.buffer.push(b'}'); + } + + pub fn into_string(self) -> Result<String, JsonWriterError> { + Ok(String::from_utf8(self.buffer)?) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn write_empty_message() -> anyhow::Result<()> { + let mut jw = JsonWriter::new(); + jw.write_open_obj(); + jw.write_close_obj(); + assert_eq!(jw.into_string()?, "{}"); + Ok(()) + } + + #[test] + fn write_invalid_f64_message() -> anyhow::Result<()> { + let mut jw = JsonWriter::new(); + let value = 1.0 / 0.0; + let error = jw.write_f64(value).unwrap_err(); + assert_eq!(error.to_string(), "Invalid f64 value inf"); + Ok(()) + } + + #[test] + fn write_key_with_quote() -> anyhow::Result<()> { + let mut jw = JsonWriter::with_capacity(128); + jw.write_key("va\"lue")?; + assert_eq!(jw.into_string()?, "\"va\\\"lue\":"); + Ok(()) + } + + #[test] + fn write_timestamp_message() -> anyhow::Result<()> { + let mut jw = JsonWriter::with_capacity(128); + jw.write_open_obj(); + jw.write_key("time")?; + jw.write_str("2013-06-22T17:03:14.123+02:00")?; + jw.write_close_obj(); + assert_eq!( + jw.into_string()?, + r#"{"time":"2013-06-22T17:03:14.123+02:00"}"# + ); + Ok(()) + } + + #[test] + fn write_single_value_message() -> anyhow::Result<()> { + let mut jw = JsonWriter::with_capacity(128); + jw.write_open_obj(); + jw.write_key("time")?; + jw.write_str("2013-06-22T17:03:14.123+02:00")?; + jw.write_separator(); + jw.write_key("temperature")?; + jw.write_f64(128.0)?; + jw.write_close_obj(); + assert_eq!( + jw.into_string()?, + r#"{"time":"2013-06-22T17:03:14.123+02:00","temperature":128.0}"# + ); + Ok(()) + } + + #[test] + fn write_multivalue_message() -> anyhow::Result<()> { + let mut jw = JsonWriter::with_capacity(128); + jw.write_open_obj(); + jw.write_key("time")?; + jw.write_str("2013-06-22T17:03:14.123+02:00")?; + jw.write_separator(); + jw.write_key("temperature")?; + jw.write_f64(128.0)?; + jw.write_separator(); + jw.write_key("location")?; + jw.write_open_obj(); + jw.write_key("altitude")?; + jw.write_f64(1028.0)?; + jw.write_separator(); + jw.write_key("longitude")?; + jw.write_f64(1288.0)?; + jw.write_separator(); + jw.write_key("longitude")?; + jw.write_f64(1280.0)?; + jw.write_close_obj(); + jw.write_close_obj(); + + assert_eq!( + jw.into_string()?, + r#"{"time":"2013-06-22T17:03:14.123+02:00","temperature":128.0,"location":{"altitude":1028.0,"longitude":1288.0,"longitude":1280.0}}"# + ); + + Ok(()) + } +} |