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 92 93 94 95 96 97 98 99 100 101 102 103 104
use std::mem::transmute; use std::ops::Index; use std::iter::Iterator; use onig_sys; #[repr(C)] #[derive(Debug)] pub struct CaptureTreeNode { raw: onig_sys::OnigCaptureTreeNode, } impl CaptureTreeNode { pub fn group(&self) -> usize { self.raw.group as usize } pub fn pos(&self) -> (usize, usize) { (self.raw.beg as usize, self.raw.end as usize) } pub fn len(&self) -> usize { self.raw.num_childs as usize } pub fn children<'t>(&'t self) -> CaptureTreeNodeIter<'t> { CaptureTreeNodeIter { idx: 0, node: self, } } } impl Index<usize> for CaptureTreeNode { type Output = CaptureTreeNode; fn index(&self, index: usize) -> &CaptureTreeNode { if index >= self.len() { panic!("capture tree node index overflow") } unsafe { transmute(*self.raw.childs.offset(index as isize)) } } } #[derive(Debug)] pub struct CaptureTreeNodeIter<'t> { idx: usize, node: &'t CaptureTreeNode, } impl<'t> Iterator for CaptureTreeNodeIter<'t> { type Item = &'t CaptureTreeNode; fn next(&mut self) -> Option<&'t CaptureTreeNode> { if self.idx < self.node.len() { self.idx += 1; Some(&self.node[self.idx - 1]) } else { None } } fn size_hint(&self) -> (usize, Option<usize>) { let size = self.node.len(); (size, Some(size)) } } #[cfg(test)] mod tests { use super::super::*; #[test] fn test_regex_search_with_region_tree() { let mut region = Region::new(); let mut syntax = Syntax::ruby().clone(); syntax.enable_operators(SYNTAX_OPERATOR_ATMARK_CAPTURE_HISTORY); let regex = Regex::with_options("(?@a+(?@b+))|(?@c+(?@d+))", REGEX_OPTION_NONE, &syntax) .unwrap(); let r = regex.search_with_options("- cd aaabbb -", 0, 13, SEARCH_OPTION_NONE, Some(&mut region)); assert_eq!(r, Some(2)); assert_eq!(region.len(), 5); let tree = region.tree().unwrap(); assert_eq!(tree.len(), 1); assert_eq!(tree.group(), 0); assert_eq!(tree.pos(), (2, 4)); assert_eq!(tree[0].len(), 1); assert_eq!(tree[0].group(), 3); assert_eq!(tree[0].pos(), (2, 4)); assert_eq!(tree[0][0].len(), 0); assert_eq!(tree[0][0].group(), 4); assert_eq!(tree[0][0].pos(), (3, 4)); } }