mirror of
				https://github.com/BurntSushi/ripgrep.git
				synced 2025-10-30 23:17:47 +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:
		
							
								
								
									
										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))?; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user