onig/
tree.rs

1#![allow(clippy::transmute_ptr_to_ref)]
2
3use std::iter::FusedIterator;
4use std::mem::transmute;
5use std::ops::Index;
6
7/// Capture Tree Node
8///
9/// Represents a single node in the capture tree. Can be queried for
10/// information about the given capture and any child-captures that
11/// took place.
12#[derive(Debug)]
13#[repr(transparent)]
14pub struct CaptureTreeNode {
15    raw: onig_sys::OnigCaptureTreeNode,
16}
17
18impl CaptureTreeNode {
19    /// The capture group number for this capture
20    pub fn group(&self) -> usize {
21        self.raw.group as usize
22    }
23
24    /// The extent of this capture
25    pub fn pos(&self) -> (usize, usize) {
26        (self.raw.beg as usize, self.raw.end as usize)
27    }
28
29    /// The number of child captures this group contains
30    pub fn len(&self) -> usize {
31        self.raw.num_childs as usize
32    }
33
34    /// Does the node have any child captures?
35    pub fn is_empty(&self) -> bool {
36        self.len() == 0
37    }
38
39    /// An iterator over thie children of this capture group
40    pub fn children(&self) -> CaptureTreeNodeIter<'_> {
41        CaptureTreeNodeIter { idx: 0, node: self }
42    }
43}
44
45impl Index<usize> for CaptureTreeNode {
46    type Output = CaptureTreeNode;
47
48    fn index(&self, index: usize) -> &CaptureTreeNode {
49        if index >= self.len() {
50            panic!("capture tree node index overflow")
51        }
52        unsafe { transmute(*self.raw.childs.add(index)) }
53    }
54}
55
56/// Captures iterator
57#[derive(Debug)]
58pub struct CaptureTreeNodeIter<'t> {
59    idx: usize,
60    node: &'t CaptureTreeNode,
61}
62
63impl<'t> Iterator for CaptureTreeNodeIter<'t> {
64    type Item = &'t CaptureTreeNode;
65
66    fn next(&mut self) -> Option<&'t CaptureTreeNode> {
67        if self.idx < self.node.len() {
68            self.idx += 1;
69            Some(&self.node[self.idx - 1])
70        } else {
71            None
72        }
73    }
74
75    fn size_hint(&self) -> (usize, Option<usize>) {
76        let size = self.node.len();
77        (size, Some(size))
78    }
79
80    fn count(self) -> usize {
81        self.node.len()
82    }
83}
84
85impl<'t> FusedIterator for CaptureTreeNodeIter<'t> {}
86
87impl<'t> ExactSizeIterator for CaptureTreeNodeIter<'t> {}
88
89#[cfg(test)]
90mod tests {
91    use super::super::*;
92
93    #[test]
94    fn test_regex_search_with_region_tree() {
95        let mut region = Region::new();
96        let mut syntax = Syntax::ruby().clone();
97        syntax.enable_operators(SyntaxOperator::SYNTAX_OPERATOR_ATMARK_CAPTURE_HISTORY);
98
99        let regex = Regex::with_options(
100            "(?@a+(?@b+))|(?@c+(?@d+))",
101            RegexOptions::REGEX_OPTION_NONE,
102            &syntax,
103        )
104        .unwrap();
105
106        let r = regex.search_with_options(
107            "- cd aaabbb -",
108            0,
109            13,
110            SearchOptions::SEARCH_OPTION_NONE,
111            Some(&mut region),
112        );
113
114        assert_eq!(r, Some(2));
115        assert_eq!(region.len(), 5);
116
117        let tree = region.tree().unwrap();
118
119        assert_eq!(tree.len(), 1);
120        assert_eq!(tree.group(), 0);
121        assert_eq!(tree.pos(), (2, 4));
122
123        assert_eq!(tree[0].len(), 1);
124        assert_eq!(tree[0].group(), 3);
125        assert_eq!(tree[0].pos(), (2, 4));
126
127        assert_eq!(tree[0][0].len(), 0);
128        assert_eq!(tree[0][0].group(), 4);
129        assert_eq!(tree[0][0].pos(), (3, 4));
130    }
131}