summaryrefslogtreecommitdiffstats
path: root/mapper/thin_edge_json/src/serialize.rs
diff options
context:
space:
mode:
Diffstat (limited to 'mapper/thin_edge_json/src/serialize.rs')
-rw-r--r--mapper/thin_edge_json/src/serialize.rs162
1 files changed, 77 insertions, 85 deletions
diff --git a/mapper/thin_edge_json/src/serialize.rs b/mapper/thin_edge_json/src/serialize.rs
index 329700c8..805087de 100644
--- a/mapper/thin_edge_json/src/serialize.rs
+++ b/mapper/thin_edge_json/src/serialize.rs
@@ -1,10 +1,10 @@
use chrono::offset::FixedOffset;
use chrono::DateTime;
-use std::io::Write;
+use json_writer::{JsonWriter, JsonWriterError};
use crate::measurement::GroupedMeasurementVisitor;
pub struct ThinEdgeJsonSerializer {
- buffer: String,
+ json: JsonWriter,
is_within_group: bool,
needs_separator: bool,
default_timestamp: Option<DateTime<FixedOffset>>,
@@ -21,6 +21,9 @@ pub enum ThinEdgeJsonSerializationError {
#[error("Serializer produced invalid Utf8 string")]
InvalidUtf8ConversionToString(std::string::FromUtf8Error),
+
+ #[error(transparent)]
+ JsonWriterError(#[from] JsonWriterError),
}
#[derive(thiserror::Error, Debug)]
@@ -45,11 +48,11 @@ impl ThinEdgeJsonSerializer {
pub fn new_with_timestamp(default_timestamp: Option<DateTime<FixedOffset>>) -> Self {
let capa = 1024; // XXX: Choose a capacity based on expected JSON length.
- let mut buffer = String::with_capacity(capa);
- buffer.push('{');
+ let mut json = JsonWriter::with_capacity(capa);
+ json.write_open_obj();
Self {
- buffer,
+ json,
is_within_group: false,
needs_separator: false,
default_timestamp,
@@ -68,35 +71,17 @@ impl ThinEdgeJsonSerializer {
}
}
- self.buffer.push('}');
+ self.json.write_close_obj();
Ok(())
}
pub fn bytes(mut self) -> Result<Vec<u8>, ThinEdgeJsonSerializationError> {
- self.end()?;
- Ok(self.buffer.into())
+ Ok(self.into_string()?.into_bytes())
}
- // XXX: We need to abstract all this into a JsonSerializer.
- fn write_key(&mut self, key: &str) {
- self.write_str(key);
- self.buffer.push(':');
- }
-
- fn write_str(&mut self, s: &str) {
- self.buffer.push('"');
- self.buffer.push_str(s);
- self.buffer.push('"');
- }
-
- fn write_f64(&mut self, value: f64) -> std::fmt::Result {
- use std::fmt::Write;
- self.buffer.write_fmt(format_args!("{}", value))
- }
-
- pub fn into_string(self) -> Result<String, ThinEdgeJsonSerializationError> {
- String::from_utf8(self.bytes()?)
- .map_err(ThinEdgeJsonSerializationError::InvalidUtf8ConversionToString)
+ pub fn into_string(&mut self) -> Result<String, ThinEdgeJsonSerializationError> {
+ self.end()?;
+ Ok(self.json.clone().into_string()?)
}
}
@@ -115,10 +100,11 @@ impl GroupedMeasurementVisitor for ThinEdgeJsonSerializer {
}
if self.needs_separator {
- self.buffer.push(',');
+ self.json.write_separator();
}
- self.write_key("time");
- self.write_str(timestamp.to_rfc3339().as_str());
+
+ self.json.write_key("time")?;
+ self.json.write_str(timestamp.to_rfc3339().as_str())?;
self.needs_separator = true;
self.timestamp_present = true;
Ok(())
@@ -126,10 +112,10 @@ impl GroupedMeasurementVisitor for ThinEdgeJsonSerializer {
fn measurement(&mut self, name: &str, value: f64) -> Result<(), Self::Error> {
if self.needs_separator {
- self.buffer.push(',');
+ self.json.write_separator();
}
- self.write_key(name);
- self.write_f64(value)?;
+ self.json.write_key(name)?;
+ self.json.write_f64(value)?;
self.needs_separator = true;
Ok(())
}
@@ -140,10 +126,10 @@ impl GroupedMeasurementVisitor for ThinEdgeJsonSerializer {
}
if self.needs_separator {
- self.buffer.push(',');
+ self.json.write_separator();
}
- self.write_key(group);
- self.buffer.push('{');
+ self.json.write_key(group)?;
+ self.json.write_open_obj();
self.needs_separator = false;
self.is_within_group = true;
Ok(())
@@ -154,7 +140,7 @@ impl GroupedMeasurementVisitor for ThinEdgeJsonSerializer {
return Err(MeasurementStreamError::UnexpectedEndOfGroup.into());
}
- self.buffer.push('}');
+ self.json.write_close_obj();
self.needs_separator = true;
self.is_within_group = false;
Ok(())
@@ -172,106 +158,112 @@ mod tests {
}
#[test]
- fn serialize_single_value_message() {
+ fn serialize_single_value_message() -> anyhow::Result<()> {
let mut serializer = ThinEdgeJsonSerializer::new();
let timestamp = test_timestamp();
- serializer.timestamp(timestamp).unwrap();
- serializer.measurement("temperature", 25.5).unwrap();
+ serializer.timestamp(timestamp)?;
+ serializer.measurement("temperature", 25.5)?;
let body = r#""temperature":25.5"#;
- let expected_output: Vec<u8> =
- format!(r#"{{"time":"{}",{}}}"#, timestamp.to_rfc3339(), body).into();
- let output = serializer.bytes().unwrap();
+ let expected_output = format!(r#"{{"time":"{}",{}}}"#, timestamp.to_rfc3339(), body);
+ let output = serializer.into_string()?;
assert_eq!(output, expected_output);
+ Ok(())
}
#[test]
- fn serialize_single_value_no_timestamp_message() {
+ fn serialize_single_value_no_timestamp_message() -> anyhow::Result<()> {
let mut serializer = ThinEdgeJsonSerializer::new();
- serializer.measurement("temperature", 25.5).unwrap();
- let expected_output = b"{\"temperature\":25.5}";
- let output = serializer.bytes().unwrap();
+ serializer.measurement("temperature", 25.5)?;
+ let expected_output = r#"{"temperature":25.5}"#;
+ let output = serializer.into_string()?;
assert_eq!(output, expected_output);
+ Ok(())
}
#[test]
- fn serialize_multi_value_message() {
+ fn serialize_multi_value_message() -> anyhow::Result<()> {
let mut serializer = ThinEdgeJsonSerializer::new();
let timestamp = test_timestamp();
- serializer.timestamp(timestamp).unwrap();
- serializer.measurement("temperature", 25.5).unwrap();
- serializer.start_group("location").unwrap();
- serializer.measurement("alti", 2100.4).unwrap();
- serializer.measurement("longi", 2200.4).unwrap();
- serializer.measurement("lati", 2300.4).unwrap();
- serializer.end_group().unwrap();
- serializer.measurement("pressure", 255.0).unwrap();
- let body = r#""temperature":25.5,"location":{"alti":2100.4,"longi":2200.4,"lati":2300.4},"pressure":255}"#;
- let expected_output: Vec<u8> =
- format!(r#"{{"time":"{}",{}"#, timestamp.to_rfc3339(), body).into();
- let output = serializer.bytes().unwrap();
+ serializer.timestamp(timestamp)?;
+ serializer.measurement("temperature", 25.5)?;
+ serializer.start_group("location")?;
+ serializer.measurement("alti", 2100.4)?;
+ serializer.measurement("longi", 2200.4)?;
+ serializer.measurement("lati", 2300.4)?;
+ serializer.end_group()?;
+ serializer.measurement("pressure", 255.0)?;
+ let body = r#""temperature":25.5,"location":{"alti":2100.4,"longi":2200.4,"lati":2300.4},"pressure":255.0}"#;
+ let expected_output = format!(r#"{{"time":"{}",{}"#, timestamp.to_rfc3339(), body);
+ let output = serializer.into_string()?;
assert_eq!(expected_output, output);
+ Ok(())
}
#[test]
- fn serialize_empty_message() {
- let serializer = ThinEdgeJsonSerializer::new();
- let expected_output = b"{}";
- let output = serializer.bytes().unwrap();
- assert_eq!(expected_output.to_vec(), output);
+ fn serialize_empty_message() -> anyhow::Result<()> {
+ let mut serializer = ThinEdgeJsonSerializer::new();
+ let expected_output = "{}";
+ let output = serializer.into_string()?;
+ assert_eq!(expected_output, output);
+ Ok(())
}
#[test]
- fn serialize_timestamp_message() {
+ fn serialize_timestamp_message() -> anyhow::Result<()> {
let mut serializer = ThinEdgeJsonSerializer::new();
let timestamp = test_timestamp();
- serializer.timestamp(timestamp).unwrap();
- let expected_output: Vec<u8> =
- format!(r#"{{"time":"{}"{}"#, timestamp.to_rfc3339(), "}").into();
- let output = serializer.bytes().unwrap();
+ serializer.timestamp(timestamp)?;
+ let expected_output = format!(r#"{{"time":"{}"{}"#, timestamp.to_rfc3339(), "}");
+ let output = serializer.into_string()?;
assert_eq!(expected_output, output);
+ Ok(())
}
#[test]
- fn serialize_timestamp_within_group() {
+ fn serialize_timestamp_within_group() -> anyhow::Result<()> {
let mut serializer = ThinEdgeJsonSerializer::new();
let timestamp = test_timestamp();
- serializer.start_group("location").unwrap();
+ serializer.start_group("location")?;
let result = serializer.timestamp(timestamp);
let expected_error = "Unexpected time stamp within a group";
assert_eq!(expected_error, result.unwrap_err().to_string());
+ Ok(())
}
#[test]
- fn serialize_unexpected_end_of_group() {
+ fn serialize_unexpected_end_of_group() -> anyhow::Result<()> {
let mut serializer = ThinEdgeJsonSerializer::new();
- serializer.measurement("alti", 2100.4).unwrap();
- serializer.measurement("longi", 2200.4).unwrap();
+ serializer.measurement("alti", 2100.4)?;
+ serializer.measurement("longi", 2200.4)?;
let result = serializer.end_group();
let expected_error = "Unexpected end of group";
assert_eq!(expected_error, result.unwrap_err().to_string());
+ Ok(())
}
#[test]
- fn serialize_unexpected_start_of_group() {
+ fn serialize_unexpected_start_of_group() -> anyhow::Result<()> {
let mut serializer = ThinEdgeJsonSerializer::new();
- serializer.start_group("location").unwrap();
- serializer.measurement("alti", 2100.4).unwrap();
- serializer.measurement("longi", 2200.4).unwrap();
+ serializer.start_group("location")?;
+ serializer.measurement("alti", 2100.4)?;
+ serializer.measurement("longi", 2200.4)?;
let result = serializer.start_group("location");
let expected_error = "Unexpected start of group";
assert_eq!(expected_error, result.unwrap_err().to_string());
+ Ok(())
}
#[test]
- fn serialize_unexpected_end_of_message() {
+ fn serialize_unexpected_end_of_message() -> anyhow::Result<()> {
let mut serializer = ThinEdgeJsonSerializer::new();
- serializer.start_group("location").unwrap();
- serializer.measurement("alti", 2100.4).unwrap();
- serializer.measurement("longi", 2200.4).unwrap();
+ serializer.start_group("location")?;
+ serializer.measurement("alti", 2100.4)?;
+ serializer.measurement("longi", 2200.4)?;
let expected_error = "Unexpected end of data";
- let result = serializer.bytes();
+ let result = serializer.into_string();
assert_eq!(expected_error, result.unwrap_err().to_string());
+ Ok(())
}
}