diff --git a/Cargo.lock b/Cargo.lock index 234c314067..c974022a2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1831,6 +1831,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "write-json" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b3f9a784c809a99e38d2e825907617cb03bd880d5421153bc4548e9317f59d0" + [[package]] name = "ws2_32-sys" version = "0.2.1" @@ -1852,4 +1858,5 @@ dependencies = [ "quote", "ungrammar", "walkdir", + "write-json", ] diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 8140da87f9..72a2ae26b8 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -17,3 +17,4 @@ proc-macro2 = "1.0.8" quote = "1.0.2" ungrammar = "0.1.0" walkdir = "2.3.1" +write-json = "0.1.0" diff --git a/xtask/src/metrics.rs b/xtask/src/metrics.rs index 9ac3fa51d0..4bade2c7e2 100644 --- a/xtask/src/metrics.rs +++ b/xtask/src/metrics.rs @@ -1,7 +1,6 @@ use std::{ collections::BTreeMap, env, - fmt::{self, Write as _}, io::Write as _, path::Path, time::{Instant, SystemTime, UNIX_EPOCH}, @@ -127,40 +126,21 @@ impl Metrics { self.metrics.insert(name.into(), (value, unit)); } - fn json(&self) -> Json { - let mut json = Json::default(); - self.to_json(&mut json); - json + fn json(&self) -> String { + let mut buf = String::new(); + self.to_json(write_json::object(&mut buf)); + buf } - fn to_json(&self, json: &mut Json) { - json.begin_object(); - { - json.field("host"); - self.host.to_json(json); - json.field("timestamp"); - let timestamp = self.timestamp.duration_since(UNIX_EPOCH).unwrap(); - json.number(timestamp.as_secs() as f64); - - json.field("revision"); - json.string(&self.revision); - - json.field("metrics"); - json.begin_object(); - { - for (k, (value, unit)) in &self.metrics { - json.field(k); - json.begin_array(); - { - json.number(*value as f64); - json.string(unit); - } - json.end_array(); - } - } - json.end_object() + fn to_json(&self, mut obj: write_json::Object<'_>) { + self.host.to_json(obj.object("host")); + let timestamp = self.timestamp.duration_since(UNIX_EPOCH).unwrap(); + obj.number("timestamp", timestamp.as_secs() as f64); + obj.string("revision", &self.revision); + let mut metrics = obj.object("metrics"); + for (k, (value, unit)) in &self.metrics { + metrics.array(k).number(*value as f64).string(unit); } - json.end_object(); } } @@ -189,91 +169,7 @@ impl Host { Ok(line[field.len()..].trim().to_string()) } } - fn to_json(&self, json: &mut Json) { - json.begin_object(); - { - json.field("os"); - json.string(&self.os); - - json.field("cpu"); - json.string(&self.cpu); - - json.field("mem"); - json.string(&self.mem); - } - json.end_object(); - } -} - -struct State { - obj: bool, - first: bool, -} - -#[derive(Default)] -struct Json { - stack: Vec, - buf: String, -} - -impl Json { - fn begin_object(&mut self) { - self.stack.push(State { obj: true, first: true }); - self.buf.push('{'); - } - fn end_object(&mut self) { - self.stack.pop(); - self.buf.push('}') - } - fn begin_array(&mut self) { - self.stack.push(State { obj: false, first: true }); - self.buf.push('['); - } - fn end_array(&mut self) { - self.stack.pop(); - self.buf.push(']') - } - fn field(&mut self, name: &str) { - self.object_comma(); - self.string_token(name); - self.buf.push(':'); - } - fn string(&mut self, value: &str) { - self.array_comma(); - self.string_token(value); - } - fn string_token(&mut self, value: &str) { - self.buf.push('"'); - self.buf.extend(value.escape_default()); - self.buf.push('"'); - } - fn number(&mut self, value: f64) { - self.array_comma(); - write!(self.buf, "{}", value).unwrap(); - } - - fn array_comma(&mut self) { - let state = self.stack.last_mut().unwrap(); - if state.obj { - return; - } - if !state.first { - self.buf.push(','); - } - state.first = false; - } - - fn object_comma(&mut self) { - let state = self.stack.last_mut().unwrap(); - if !state.first { - self.buf.push(','); - } - state.first = false; - } -} - -impl fmt::Display for Json { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.buf) + fn to_json(&self, mut obj: write_json::Object<'_>) { + obj.string("os", &self.os).string("cpu", &self.cpu).string("mem", &self.mem); } }