mirror of
https://github.com/BurntSushi/ripgrep.git
synced 2025-03-03 14:32:22 +02:00
printer: drop dependency on serde_derive
As suggested by @epage[1]. Ad hoc timings on my i7-12900K: before cargo build: 4.91s before cargo build release: 8.05s after cargo build: 4.69s after cargo build release: 7.83s ... pretty underwhelming if you ask me. Ah well. And on my M2 mac mini: before cargo build: 6.18s before cargo build release: 14.50s after cargo build: 5.52s after cargo build release: 13.44s Still kind of underwhelming, but definitely better. It shaves a full second off of compile times in release mode. I went back to my i7-12900K, but passed `-j1` to `cargo build` to force single threaded mode: before cargo build: 19.44s before cargo build release: 50.64s after cargo build: 16.76s after cargo build release: 48.00s Which seems pretty consistent with the modest improvements above. Looking at `cargo build --timings`, the beefiest chunk of time is spent in compiling `regex-automata`, by far. This is fine because it's core functionality. I wish a fast general purpose regex engine with its internals exposed as a separately versioned library didn't require so much code... Blech. [1]: https://old.reddit.com/r/rust/comments/17rd8ww/faster_compilation_with_the_parallel_frontend_in/k8igjlg/
This commit is contained in:
parent
cddb5f57f8
commit
9c84575229
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -192,7 +192,6 @@ dependencies = [
|
||||
"grep-searcher",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"termcolor",
|
||||
]
|
||||
|
@ -16,7 +16,7 @@ edition = "2021"
|
||||
|
||||
[features]
|
||||
default = ["serde"]
|
||||
serde = ["dep:base64", "dep:serde", "dep:serde_derive", "dep:serde_json"]
|
||||
serde = ["dep:base64", "dep:serde", "dep:serde_json"]
|
||||
|
||||
[dependencies]
|
||||
base64 = { version = "0.21.4", optional = true }
|
||||
@ -26,7 +26,6 @@ grep-searcher = { version = "0.1.11", path = "../searcher" }
|
||||
log = "0.4.5"
|
||||
termcolor = "1.3.0"
|
||||
serde = { version = "1.0.193", optional = true }
|
||||
serde_derive = { version = "1.0.193", optional = true }
|
||||
serde_json = { version = "1.0.107", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
|
@ -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))
|
||||
}
|
||||
impl<'a> serde::Serialize for Data<'a> {
|
||||
fn serialize<S: serde::Serializer>(
|
||||
&self,
|
||||
s: S,
|
||||
) -> Result<S::Ok, S::Error> {
|
||||
use serde::ser::SerializeStruct;
|
||||
|
||||
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)
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ use crate::util::NiceDuration;
|
||||
/// When statistics are reported by a printer, they correspond to all searches
|
||||
/// executed with that printer.
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde_derive::Serialize))]
|
||||
pub struct Stats {
|
||||
elapsed: NiceDuration,
|
||||
searches: u64,
|
||||
@ -21,49 +20,6 @@ pub struct Stats {
|
||||
matches: u64,
|
||||
}
|
||||
|
||||
impl Add for Stats {
|
||||
type Output = Stats;
|
||||
|
||||
fn add(self, rhs: Stats) -> Stats {
|
||||
self + &rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Add<&'a Stats> for Stats {
|
||||
type Output = Stats;
|
||||
|
||||
fn add(self, rhs: &'a Stats) -> Stats {
|
||||
Stats {
|
||||
elapsed: NiceDuration(self.elapsed.0 + rhs.elapsed.0),
|
||||
searches: self.searches + rhs.searches,
|
||||
searches_with_match: self.searches_with_match
|
||||
+ rhs.searches_with_match,
|
||||
bytes_searched: self.bytes_searched + rhs.bytes_searched,
|
||||
bytes_printed: self.bytes_printed + rhs.bytes_printed,
|
||||
matched_lines: self.matched_lines + rhs.matched_lines,
|
||||
matches: self.matches + rhs.matches,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for Stats {
|
||||
fn add_assign(&mut self, rhs: Stats) {
|
||||
*self += &rhs;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AddAssign<&'a Stats> for Stats {
|
||||
fn add_assign(&mut self, rhs: &'a Stats) {
|
||||
self.elapsed.0 += rhs.elapsed.0;
|
||||
self.searches += rhs.searches;
|
||||
self.searches_with_match += rhs.searches_with_match;
|
||||
self.bytes_searched += rhs.bytes_searched;
|
||||
self.bytes_printed += rhs.bytes_printed;
|
||||
self.matched_lines += rhs.matched_lines;
|
||||
self.matches += rhs.matches;
|
||||
}
|
||||
}
|
||||
|
||||
impl Stats {
|
||||
/// Return a new value for tracking aggregate statistics across searches.
|
||||
///
|
||||
@ -147,3 +103,69 @@ impl Stats {
|
||||
self.matches += n;
|
||||
}
|
||||
}
|
||||
|
||||
impl Add for Stats {
|
||||
type Output = Stats;
|
||||
|
||||
fn add(self, rhs: Stats) -> Stats {
|
||||
self + &rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Add<&'a Stats> for Stats {
|
||||
type Output = Stats;
|
||||
|
||||
fn add(self, rhs: &'a Stats) -> Stats {
|
||||
Stats {
|
||||
elapsed: NiceDuration(self.elapsed.0 + rhs.elapsed.0),
|
||||
searches: self.searches + rhs.searches,
|
||||
searches_with_match: self.searches_with_match
|
||||
+ rhs.searches_with_match,
|
||||
bytes_searched: self.bytes_searched + rhs.bytes_searched,
|
||||
bytes_printed: self.bytes_printed + rhs.bytes_printed,
|
||||
matched_lines: self.matched_lines + rhs.matched_lines,
|
||||
matches: self.matches + rhs.matches,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AddAssign for Stats {
|
||||
fn add_assign(&mut self, rhs: Stats) {
|
||||
*self += &rhs;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> AddAssign<&'a Stats> for Stats {
|
||||
fn add_assign(&mut self, rhs: &'a Stats) {
|
||||
self.elapsed.0 += rhs.elapsed.0;
|
||||
self.searches += rhs.searches;
|
||||
self.searches_with_match += rhs.searches_with_match;
|
||||
self.bytes_searched += rhs.bytes_searched;
|
||||
self.bytes_printed += rhs.bytes_printed;
|
||||
self.matched_lines += rhs.matched_lines;
|
||||
self.matches += rhs.matches;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl serde::Serialize for Stats {
|
||||
fn serialize<S: serde::Serializer>(
|
||||
&self,
|
||||
s: S,
|
||||
) -> Result<S::Ok, S::Error> {
|
||||
use serde::ser::SerializeStruct;
|
||||
|
||||
let mut state = s.serialize_struct("Stats", 7)?;
|
||||
state.serialize_field("elapsed", &self.elapsed)?;
|
||||
state.serialize_field("searches", &self.searches)?;
|
||||
state.serialize_field(
|
||||
"searches_with_match",
|
||||
&self.searches_with_match,
|
||||
)?;
|
||||
state.serialize_field("bytes_searched", &self.bytes_searched)?;
|
||||
state.serialize_field("bytes_printed", &self.bytes_printed)?;
|
||||
state.serialize_field("matched_lines", &self.matched_lines)?;
|
||||
state.serialize_field("matches", &self.matches)?;
|
||||
state.end()
|
||||
}
|
||||
}
|
||||
|
@ -8,9 +8,6 @@ use {
|
||||
},
|
||||
};
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Serialize, Serializer};
|
||||
|
||||
use crate::{hyperlink::HyperlinkPath, MAX_LOOK_AHEAD};
|
||||
|
||||
/// A type for handling replacements while amortizing allocation.
|
||||
@ -385,11 +382,14 @@ impl NiceDuration {
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl Serialize for NiceDuration {
|
||||
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
|
||||
impl serde::Serialize for NiceDuration {
|
||||
fn serialize<S: serde::Serializer>(
|
||||
&self,
|
||||
ser: S,
|
||||
) -> Result<S::Ok, S::Error> {
|
||||
use serde::ser::SerializeStruct;
|
||||
|
||||
let mut state = ser.serialize_struct("Duration", 2)?;
|
||||
let mut state = ser.serialize_struct("Duration", 3)?;
|
||||
state.serialize_field("secs", &self.0.as_secs())?;
|
||||
state.serialize_field("nanos", &self.0.subsec_nanos())?;
|
||||
state.serialize_field("human", &format!("{}", self))?;
|
||||
|
Loading…
x
Reference in New Issue
Block a user