diff --git a/benches/parse_patterns.rs b/benches/parse_patterns.rs index 130112c..a02db3c 100644 --- a/benches/parse_patterns.rs +++ b/benches/parse_patterns.rs @@ -6,7 +6,7 @@ fn bench_parse_shipping_groups_summary(c: &mut Criterion) { b.iter(|| { let input = quirks::process_construct_pattern_input( black_box(quirks::StringOrInit::String( - "component-ShippingGroupsSummary.*.js".to_owned() + "component-ShippingGroupsSummary.*.js".into() )), black_box(Some("https://example.test/web/")), ); diff --git a/src/lib.rs b/src/lib.rs index 3baa9fd..af67bf1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -659,10 +659,11 @@ mod tests { #[derive(Debug, Deserialize)] #[serde(untagged)] + #[serde(bound(deserialize = "'de: 'a"))] #[allow(clippy::large_enum_variant)] - enum ExpectedMatch { + enum ExpectedMatch<'a> { String(String), - MatchResult(MatchResult), + MatchResult(MatchResult<'a>), } #[derive(Debug, Deserialize)] @@ -674,28 +675,30 @@ mod tests { #[allow(clippy::large_enum_variant)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(untagged)] - pub enum StringOrInitOrOptions { + pub enum StringOrInitOrOptions<'a> { Options(UrlPatternOptions), - StringOrInit(quirks::StringOrInit), + StringOrInit(quirks::StringOrInit<'a>), } #[derive(Debug, Deserialize)] - struct TestCase { + #[serde(bound(deserialize = "'de: 'a"))] + struct TestCase<'a> { skip: Option, - pattern: Vec, + pattern: Vec>, #[serde(default)] - inputs: Vec, - expected_obj: Option, - expected_match: Option, + inputs: Vec>, + expected_obj: Option>, + expected_match: Option>, #[serde(default)] exactly_empty_components: Vec, } #[derive(Debug, Deserialize)] - struct MatchResult { + #[serde(bound(deserialize = "'de: 'a"))] + struct MatchResult<'a> { #[serde(deserialize_with = "deserialize_match_result_inputs")] #[serde(default)] - inputs: Option<(quirks::StringOrInit, Option)>, + inputs: Option<(quirks::StringOrInit<'a>, Option)>, protocol: Option, username: Option, @@ -707,17 +710,17 @@ mod tests { hash: Option, } - fn deserialize_match_result_inputs<'de, D>( + fn deserialize_match_result_inputs<'a, D>( deserializer: D, - ) -> Result)>, D::Error> + ) -> Result, Option)>, D::Error> where - D: serde::Deserializer<'de>, + D: serde::Deserializer<'a>, { #[derive(Debug, Deserialize)] #[serde(untagged)] - enum MatchResultInputs { - OneArgument((quirks::StringOrInit,)), - TwoArguments(quirks::StringOrInit, String), + enum MatchResultInputs<'a> { + OneArgument((quirks::StringOrInit<'a>,)), + TwoArguments(quirks::StringOrInit<'a>, String), } let res = Option::::deserialize(deserializer)?; @@ -811,7 +814,7 @@ mod tests { .. }) = &input { - base_url = Some(url.clone()) + base_url = Some(url.clone().into()) } macro_rules! assert_field { @@ -921,7 +924,8 @@ mod tests { let input = input.unwrap_or_else(|| StringOrInit::Init(Default::default())); - let expected_input = (input.clone(), base_url.clone()); + let expected_input = + (input.clone(), base_url.clone().map(|s| s.to_string())); let match_input = quirks::process_match_input(input, base_url.as_deref()); @@ -1058,7 +1062,7 @@ mod tests { #[test] fn issue46() { quirks::process_construct_pattern_input( - quirks::StringOrInit::String(":café://:foo".to_owned()), + quirks::StringOrInit::String(":café://:foo".to_owned().into()), None, ) .unwrap(); diff --git a/src/quirks.rs b/src/quirks.rs index 19de090..baf34b0 100644 --- a/src/quirks.rs +++ b/src/quirks.rs @@ -3,6 +3,7 @@ use serde::Deserialize; use serde::Serialize; +use std::borrow::Cow; use url::Url; pub use crate::Error; @@ -36,8 +37,8 @@ pub struct UrlPatternInit { #[allow(clippy::large_enum_variant)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(untagged)] -pub enum StringOrInit { - String(String), +pub enum StringOrInit<'a> { + String(Cow<'a, str>), Init(UrlPatternInit), } @@ -106,7 +107,7 @@ impl From> for UrlPatternComponent { fn from(component: Component) -> Self { let regexp_string = component .regexp - .map(|r| r.pattern_string()) + .map(|r| r.pattern_string().to_owned()) .unwrap_or_default(); Self { pattern_string: component.pattern_string, @@ -166,7 +167,9 @@ impl From> for InnerMatcher { allow_empty, }, crate::matcher::InnerMatcher::RegExp { regexp } => Self::RegExp { - regexp: regexp.map(|r| r.pattern_string()).unwrap_or_default(), + regexp: regexp + .map(|r| r.pattern_string().to_owned()) + .unwrap_or_default(), }, } } @@ -196,8 +199,8 @@ impl RegExp for EcmaRegexp { regexp.matches(text) } - fn pattern_string(&self) -> String { - self.0.clone() + fn pattern_string(&self) -> &str { + self.0.as_ref() } } @@ -230,12 +233,12 @@ pub fn parse_pattern_as_lib( Ok(pattern) } -pub type Inputs = (StringOrInit, Option); +pub type Inputs<'a> = (StringOrInit<'a>, Option); -pub fn process_match_input( - input: StringOrInit, +pub fn process_match_input<'a>( + input: StringOrInit<'a>, base_url_str: Option<&str>, -) -> Result, Error> { +) -> Result)>, Error> { let mut inputs = (input.clone(), None); let init = match input { StringOrInit::String(url) => { diff --git a/src/regexp.rs b/src/regexp.rs index ac90d77..01b97ec 100644 --- a/src/regexp.rs +++ b/src/regexp.rs @@ -17,7 +17,7 @@ pub trait RegExp: Sized { /// Returns `None` if the text does not match the regular expression. fn matches<'a>(&self, text: &'a str) -> Option>>; - fn pattern_string(&self) -> String; + fn pattern_string(&self) -> &str; } impl RegExp for regex::Regex { @@ -41,7 +41,7 @@ impl RegExp for regex::Regex { Some(captures) } - fn pattern_string(&self) -> String { - self.as_str().to_string() + fn pattern_string(&self) -> &str { + self.as_str() } }