1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
use std::str;
use memchr::memchr;
use bytes::Captures;
pub fn expand(caps: &Captures, mut replacement: &[u8], dst: &mut Vec<u8>) {
while !replacement.is_empty() {
match memchr(b'$', replacement) {
None => break,
Some(i) => {
dst.extend(&replacement[..i]);
replacement = &replacement[i..];
}
}
if replacement.get(1).map_or(false, |&b| b == b'$') {
dst.push(b'$');
replacement = &replacement[2..];
continue;
}
debug_assert!(!replacement.is_empty());
let cap_ref = match find_cap_ref(replacement) {
Some(cap_ref) => cap_ref,
None => {
dst.push(b'$');
replacement = &replacement[1..];
continue;
}
};
replacement = cap_ref.rest;
match cap_ref.cap {
Ref::Number(i) => dst.extend(caps.at(i).unwrap_or(b"")),
Ref::Named(name) => dst.extend(caps.name(name).unwrap_or(b"")),
}
}
dst.extend(replacement);
}
struct CaptureRef<'a> {
rest: &'a [u8],
cap: Ref<'a>,
}
enum Ref<'a> {
Named(&'a str),
Number(usize),
}
fn find_cap_ref(mut replacement: &[u8]) -> Option<CaptureRef> {
if replacement.len() <= 1 || replacement[0] != b'$' {
return None;
}
let mut brace = false;
replacement = &replacement[1..];
if replacement[0] == b'{' {
brace = true;
replacement = &replacement[1..];
}
let mut cap_end = 0;
while replacement.get(cap_end).map_or(false, is_valid_cap_letter) {
cap_end += 1;
}
if cap_end == 0 {
return None;
}
let cap = str::from_utf8(&replacement[..cap_end])
.ok().expect("valid UTF-8 capture name");
if brace {
if !replacement.get(cap_end).map_or(false, |&b| b == b'}') {
return None;
}
cap_end += 1;
}
Some(CaptureRef {
rest: &replacement[cap_end..],
cap: match cap.parse::<u32>() {
Ok(i) => Ref::Number(i as usize),
Err(_) => Ref::Named(cap),
},
})
}
fn is_valid_cap_letter(b: &u8) -> bool {
match *b {
b'0' ... b'9' | b'a' ... b'z' | b'A' ... b'Z' | b'_' => true,
_ => false,
}
}