@@ -129,11 +129,11 @@ pub(crate) enum Fragment<'doc> {
129129 /// might contain multiple lines, e.g. a multi-line GitHub Actions
130130 /// expression, since the subfeature's indentation won't necessarily match
131131 /// the surrounding feature's YAML-level indentation.
132- Regex ( #[ serde( serialize_with = "Fragment::serialize_regex" ) ] regex:: Regex ) ,
132+ Regex ( #[ serde( serialize_with = "Fragment::serialize_regex" ) ] regex:: bytes :: Regex ) ,
133133}
134134
135135impl < ' doc > Fragment < ' doc > {
136- fn serialize_regex < S > ( regex : & regex:: Regex , serializer : S ) -> Result < S :: Ok , S :: Error >
136+ fn serialize_regex < S > ( regex : & regex:: bytes :: Regex , serializer : S ) -> Result < S :: Ok , S :: Error >
137137 where
138138 S : serde:: Serializer ,
139139 {
@@ -172,7 +172,7 @@ impl<'doc> Fragment<'doc> {
172172 static WHITESPACE : LazyLock < Regex > = LazyLock :: new ( || Regex :: new ( r"\s+" ) . unwrap ( ) ) ;
173173 let regex = WHITESPACE . replace_all ( & escaped, "\\ s+" ) ;
174174
175- Fragment :: Regex ( Regex :: new ( & regex) . unwrap ( ) )
175+ Fragment :: Regex ( regex :: bytes :: Regex :: new ( & regex) . unwrap ( ) )
176176 }
177177 }
178178}
@@ -211,14 +211,26 @@ impl<'doc> Subfeature<'doc> {
211211 /// can't be found. The returned span is relative to the feature's
212212 /// start.
213213 fn locate_within ( & self , feature : & str ) -> Option < Span > {
214+ // NOTE: Our inputs are always valid UTF-8 but `after` may not
215+ // be a valid UTF-8 codepoint index, so everything below operates
216+ // on a byte slice.
217+ // Why, you might ask, might `after` not be a valid codepoint index?
218+ // Because `after` is a fuzzy anchor: we know our subfeature starts
219+ // *somewhere* after `after`, but we don't know exactly where.
220+ // This happens because we have a rough sense of where the subfeature
221+ // is *after* YAML parsing, but we don't know exactly where it is
222+ // in the original YAML feature due to significant whitespace.
223+ let feature = feature. as_bytes ( ) ;
214224 let bias = self . after ;
215225 let focus = & feature[ bias..] ;
216226
217227 match & self . fragment {
218- Fragment :: Raw ( fragment) => focus. find ( fragment) . map ( |start| {
219- let end = start + fragment. len ( ) ;
220- Span :: from ( start..end) . adjust ( bias)
221- } ) ,
228+ Fragment :: Raw ( fragment) => {
229+ memchr:: memmem:: find ( focus, fragment. as_bytes ( ) ) . map ( |start| {
230+ let end = start + fragment. len ( ) ;
231+ Span :: from ( start..end) . adjust ( bias)
232+ } )
233+ }
222234 Fragment :: Regex ( regex) => regex
223235 . find ( focus)
224236 . map ( |m| Span :: from ( m. range ( ) ) . adjust ( bias) ) ,
0 commit comments