1use std::os::raw::{c_int, c_void};
2use std::slice;
3use std::str::from_utf8_unchecked;
4
5use onig_sys::{OnigRegex, OnigUChar};
6
7use super::Regex;
8
9impl Regex {
10 pub fn capture_names_len(&self) -> usize {
12 unsafe { onig_sys::onig_number_of_names(self.raw) as usize }
13 }
14
15 pub fn foreach_name<F>(&self, mut callback: F) -> i32
18 where
19 F: FnMut(&str, &[u32]) -> bool,
20 {
21 unsafe extern "C" fn foreach_cb<F>(
22 name: *const OnigUChar,
23 name_end: *const OnigUChar,
24 ngroup_num: c_int,
25 group_nums: *mut c_int,
26 _regex: OnigRegex,
27 arg: *mut c_void,
28 ) -> c_int
29 where
30 F: FnMut(&str, &[u32]) -> bool,
31 {
32 let name = from_utf8_unchecked(slice::from_raw_parts(
33 name,
34 name_end as usize - name as usize,
35 ));
36
37 let groups = slice::from_raw_parts(group_nums as *const u32, ngroup_num as usize);
38
39 let callback = &mut *(arg as *mut F);
40
41 if callback(name, groups) {
42 0
43 } else {
44 -1
45 }
46 }
47
48 unsafe {
49 onig_sys::onig_foreach_name(
50 self.raw,
51 Some(foreach_cb::<F>),
52 &mut callback as *mut F as *mut c_void,
53 )
54 }
55 }
56}
57
58#[cfg(test)]
59mod tests {
60 use super::super::*;
61
62 #[test]
63 fn test_regex_names_len() {
64 let regex = Regex::new("(he)(l+)(o)").unwrap();
65 assert_eq!(regex.capture_names_len(), 0);
66 let regex = Regex::new("(?<foo>he)(?<bar>l+)(?<bar>o)").unwrap();
67 assert_eq!(regex.capture_names_len(), 2);
68 assert_eq!(regex.capture_histories_len(), 0);
69 }
70
71 #[test]
72 fn test_regex_names() {
73 let regex = Regex::new("(he)(l+)(o)").unwrap();
74 let mut names = Vec::new();
75 regex.foreach_name(|n, i| {
76 names.push((n.to_string(), i.iter().cloned().collect::<Vec<_>>()));
77 true
78 });
79 assert_eq!(names, vec![]);
80 let regex = Regex::new("(?<foo>he)(?<bar>l+)(?<bar>o)").unwrap();
81 let mut names = Vec::new();
82 regex.foreach_name(|n, i| {
83 names.push((n.to_string(), i.iter().cloned().collect::<Vec<_>>()));
84 true
85 });
86 assert_eq!(
87 names,
88 vec![("foo".into(), vec![1u32]), ("bar".into(), vec![2u32, 3])]
89 );
90 }
91}