summaryrefslogtreecommitdiffstats
path: root/crates/printer/src/jsont.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/printer/src/jsont.rs')
-rw-r--r--crates/printer/src/jsont.rs184
1 files changed, 129 insertions, 55 deletions
diff --git a/crates/printer/src/jsont.rs b/crates/printer/src/jsont.rs
index 5d901041..6e5e85df 100644
--- a/crates/printer/src/jsont.rs
+++ b/crates/printer/src/jsont.rs
@@ -8,13 +8,6 @@
use std::{borrow::Cow, path::Path};
-use {base64, serde::Serializer, serde_derive::Serialize};
-
-use crate::stats::Stats;
-
-#[derive(Serialize)]
-#[serde(tag = "type", content = "data")]
-#[serde(rename_all = "snake_case")]
pub(crate) enum Message<'a> {
Begin(Begin<'a>),
End(End<'a>),
@@ -22,51 +15,145 @@ pub(crate) enum Message<'a> {
Context(Context<'a>),
}
-#[derive(Serialize)]
+impl<'a> serde::Serialize for Message<'a> {
+ fn serialize<S: serde::Serializer>(
+ &self,
+ s: S,
+ ) -> Result<S::Ok, S::Error> {
+ use serde::ser::SerializeStruct;
+
+ let mut state = s.serialize_struct("Message", 2)?;
+ match *self {
+ Message::Begin(ref msg) => {
+ state.serialize_field("type", &"begin")?;
+ state.serialize_field("data", msg)?;
+ }
+ Message::End(ref msg) => {
+ state.serialize_field("type", &"end")?;
+ state.serialize_field("data", msg)?;
+ }
+ Message::Match(ref msg) => {
+ state.serialize_field("type", &"match")?;
+ state.serialize_field("data", msg)?;
+ }
+ Message::Context(ref msg) => {
+ state.serialize_field("type", &"context")?;
+ state.serialize_field("data", msg)?;
+ }
+ }
+ state.end()
+ }
+}
+
pub(crate) struct Begin<'a> {
- #[serde(serialize_with = "ser_path")]
pub(crate) path: Option<&'a Path>,
}
-#[derive(Serialize)]
+impl<'a> serde::Serialize for Begin<'a> {
+ fn serialize<S: serde::Serializer>(
+ &self,
+ s: S,
+ ) -> Result<S::Ok, S::Error> {
+ use serde::ser::SerializeStruct;
+
+ let mut state = s.serialize_struct("Begin", 1)?;
+ state.serialize_field("path", &self.path.map(Data::from_path))?;
+ state.end()
+ }
+}
+
pub(crate) struct End<'a> {
- #[serde(serialize_with = "ser_path")]
pub(crate) path: Option<&'a Path>,
pub(crate) binary_offset: Option<u64>,
- pub(crate) stats: Stats,
+ pub(crate) stats: crate::stats::Stats,
+}
+
+impl<'a> serde::Serialize for End<'a> {
+ fn serialize<S: serde::Serializer>(
+ &self,
+ s: S,
+ ) -> Result<S::Ok, S::Error> {
+ use serde::ser::SerializeStruct;
+
+ let mut state = s.serialize_struct("End", 3)?;
+ state.serialize_field("path", &self.path.map(Data::from_path))?;
+ state.serialize_field("binary_offset", &self.binary_offset)?;
+ state.serialize_field("stats", &self.stats)?;
+ state.end()
+ }
}
-#[derive(Serialize)]
pub(crate) struct Match<'a> {
- #[serde(serialize_with = "ser_path")]
pub(crate) path: Option<&'a Path>,
- #[serde(serialize_with = "ser_bytes")]
pub(crate) lines: &'a [u8],
pub(crate) line_number: Option<u64>,
pub(crate) absolute_offset: u64,
pub(crate) submatches: &'a [SubMatch<'a>],
}
-#[derive(Serialize)]
+impl<'a> serde::Serialize for Match<'a> {
+ fn serialize<S: serde::Serializer>(
+ &self,
+ s: S,
+ ) -> Result<S::Ok, S::Error> {
+ use serde::ser::SerializeStruct;
+
+ let mut state = s.serialize_struct("Match", 5)?;
+ state.serialize_field("path", &self.path.map(Data::from_path))?;
+ state.serialize_field("lines", &Data::from_bytes(self.lines))?;
+ state.serialize_field("line_number", &self.line_number)?;
+ state.serialize_field("absolute_offset", &self.absolute_offset)?;
+ state.serialize_field("submatches", &self.submatches)?;
+ state.end()
+ }
+}
+
pub(crate) struct Context<'a> {
- #[serde(serialize_with = "ser_path")]
pub(crate) path: Option<&'a Path>,
- #[serde(serialize_with = "ser_bytes")]
pub(crate) lines: &'a [u8],
pub(crate) line_number: Option<u64>,
pub(crate) absolute_offset: u64,
pub(crate) submatches: &'a [SubMatch<'a>],
}
-#[derive(Serialize)]
+impl<'a> serde::Serialize for Context<'a> {
+ fn serialize<S: serde::Serializer>(
+ &self,
+ s: S,
+ ) -> Result<S::Ok, S::Error> {
+ use serde::ser::SerializeStruct;
+
+ let mut state = s.serialize_struct("Context", 5)?;
+ state.serialize_field("path", &self.path.map(Data::from_path))?;
+ state.serialize_field("lines", &Data::from_bytes(self.lines))?;
+ state.serialize_field("line_number", &self.line_number)?;
+ state.serialize_field("absolute_offset", &self.absolute_offset)?;
+ state.serialize_field("submatches", &self.submatches)?;
+ state.end()
+ }
+}
+
pub(crate) struct SubMatch<'a> {
- #[serde(rename = "match")]
- #[serde(serialize_with = "ser_bytes")]
pub(crate) m: &'a [u8],
pub(crate) start: usize,
pub(crate) end: usize,
}
+impl<'a> serde::Serialize for SubMatch<'a> {
+ fn serialize<S: serde::Serializer>(
+ &self,
+ s: S,
+ ) -> Result<S::Ok, S::Error> {
+ use serde::ser::SerializeStruct;
+
+ let mut state = s.serialize_struct("SubMatch", 3)?;
+ state.serialize_field("match", &Data::from_bytes(self.m))?;
+ state.serialize_field("start", &self.start)?;
+ state.serialize_field("end", &self.end)?;
+ state.end()
+ }
+}
+
/// Data represents things that look like strings, but may actually not be
/// valid UTF-8. To handle this, `Data` is serialized as an object with one
/// of two keys: `text` (for valid UTF-8) or `bytes` (for invalid UTF-8).
@@ -74,16 +161,10 @@ pub(crate) struct SubMatch<'a> {
/// The happy path is valid UTF-8, which streams right through as-is, since
/// it is natively supported by JSON. When invalid UTF-8 is found, then it is
/// represented as arbitrary bytes and base64 encoded.
-#[derive(Clone, Debug, Hash, PartialEq, Eq, Serialize)]
-#[serde(untagged)]
+#[derive(Clone, Debug, Hash, PartialEq, Eq)]
enum Data<'a> {
- Text {
- text: Cow<'a, str>,
- },
- Bytes {
- #[serde(serialize_with = "to_base64")]
- bytes: &'a [u8],
- },
+ Text { text: Cow<'a, str> },
+ Bytes { bytes: &'a [u8] },
}
impl<'a> Data<'a> {
@@ -115,29 +196,22 @@ impl<'a> Data<'a> {
}
}
-fn to_base64<T, S>(bytes: T, ser: S) -> Result<S::Ok, S::Error>
-where
- T: AsRef<[u8]>,
- S: Serializer,
-{
- use base64::engine::{general_purpose::STANDARD, Engine};
- ser.serialize_str(&STANDARD.encode(&bytes))
-}
-
-fn ser_bytes<T, S>(bytes: T, ser: S) -> Result<S::Ok, S::Error>
-where
- T: AsRef<[u8]>,
- S: Serializer,
-{
- use serde::Serialize;
- Data::from_bytes(bytes.as_ref()).serialize(ser)
-}
-
-fn ser_path<P, S>(path: &Option<P>, ser: S) -> Result<S::Ok, S::Error>
-where
- P: AsRef<Path>,
- S: Serializer,
-{
- use serde::Serialize;
- path.as_ref().map(|p| Data::from_path(p.as_ref())).serialize(ser)
+impl<'a> serde::Serialize for Data<'a> {
+ fn serialize<S: serde::Serializer>(
+ &self,
+ s: S,
+ ) -> Result<S::Ok, S::Error> {
+ use serde::ser::SerializeStruct;
+
+ let mut state = s.serialize_struct("Data", 1)?;
+ match *self {
+ Data::Text { ref text } => state.serialize_field("text", text)?,
+ Data::Bytes { bytes } => {
+ use base64::engine::{general_purpose::STANDARD, Engine};
+ let encoded = STANDARD.encode(bytes);
+ state.serialize_field("bytes", &encoded)?;
+ }
+ }
+ state.end()
+ }
}