fapolicy_rules/parser/
trace.rs

1/*
2 * Copyright Concurrent Technologies Corporation 2021
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
7 */
8
9use nom::error::{ErrorKind, ParseError};
10use nom::{
11    AsBytes, Compare, CompareResult, FindSubstring, IResult, InputIter, InputLength, InputTake,
12    InputTakeAtPosition, Needed, Offset, Slice,
13};
14use std::ops::{RangeFrom, RangeTo};
15
16pub trait Position {
17    fn position(&self) -> usize;
18}
19
20/// Trace is a nom custom input type that provides context to the parse
21/// The trace carries along a copy of the original rule input text
22#[derive(Debug, Copy, Clone)]
23pub struct Trace<I> {
24    // current context input data
25    pub current: I,
26    // original input data
27    original: I,
28    // current position, relative to original
29    pub position: usize,
30}
31
32impl<I> Trace<I>
33where
34    I: AsBytes + Clone,
35{
36    pub fn new(i: I) -> Self {
37        Trace {
38            current: i.clone(),
39            original: i,
40            position: 0,
41        }
42    }
43
44    pub fn is_empty(&self) -> bool {
45        self.as_bytes().is_empty()
46    }
47}
48
49impl<I: PartialEq> PartialEq for Trace<I> {
50    fn eq(&self, other: &Self) -> bool {
51        self.current == other.current
52    }
53}
54
55///
56
57impl<I> Position for Trace<I> {
58    fn position(&self) -> usize {
59        self.position
60    }
61}
62
63///
64
65impl<I: Offset> Offset for Trace<I> {
66    fn offset(&self, second: &Self) -> usize {
67        self.current.offset(&second.current)
68    }
69}
70
71impl<I: InputLength> InputLength for Trace<I> {
72    fn input_len(&self) -> usize {
73        self.current.input_len()
74    }
75}
76
77impl<'a, I> InputIter for Trace<I>
78where
79    I: InputIter,
80{
81    type Item = I::Item;
82    type Iter = I::Iter;
83    type IterElem = I::IterElem;
84
85    fn iter_indices(&self) -> Self::Iter {
86        self.current.iter_indices()
87    }
88
89    fn iter_elements(&self) -> Self::IterElem {
90        self.current.iter_elements()
91    }
92
93    fn position<P>(&self, predicate: P) -> Option<usize>
94    where
95        P: Fn(Self::Item) -> bool,
96    {
97        self.current.position(predicate)
98    }
99
100    fn slice_index(&self, count: usize) -> Result<usize, Needed> {
101        self.current.slice_index(count)
102    }
103}
104
105impl<I> InputTake for Trace<I>
106where
107    Self: Slice<RangeFrom<usize>> + Slice<RangeTo<usize>>,
108{
109    fn take(&self, count: usize) -> Self {
110        self.slice(..count)
111    }
112
113    fn take_split(&self, count: usize) -> (Self, Self) {
114        (self.slice(count..), self.slice(..count))
115    }
116}
117
118impl<T: AsBytes> AsBytes for Trace<T> {
119    fn as_bytes(&self) -> &[u8] {
120        self.current.as_bytes()
121    }
122}
123
124impl<'a, I, R> Slice<R> for Trace<I>
125where
126    I: Slice<R> + Offset + AsBytes + Slice<RangeTo<usize>> + Clone,
127{
128    fn slice(&self, range: R) -> Self {
129        let current = self.current.slice(range);
130        let position = self.original.as_bytes().len() - current.as_bytes().len();
131        Trace {
132            original: self.original.clone(),
133            current,
134            position,
135        }
136    }
137}
138
139impl<T: AsBytes + Clone> From<T> for Trace<T> {
140    fn from(i: T) -> Self {
141        Self::new(i)
142    }
143}
144
145impl<T, U> FindSubstring<U> for Trace<T>
146where
147    T: FindSubstring<U>,
148{
149    #[inline]
150    fn find_substring(&self, substr: U) -> Option<usize> {
151        self.current.find_substring(substr)
152    }
153}
154
155impl<T: InputLength + InputIter + InputTake + Clone> InputTakeAtPosition for Trace<T>
156where
157    T: InputTakeAtPosition + InputLength + InputIter,
158    Self: Slice<RangeFrom<usize>> + Slice<RangeTo<usize>> + Clone,
159{
160    type Item = <T as InputIter>::Item;
161
162    fn split_at_position<P, E: ParseError<Self>>(&self, predicate: P) -> IResult<Self, Self, E>
163    where
164        P: Fn(Self::Item) -> bool,
165    {
166        match self.current.position(predicate) {
167            Some(n) => Ok(self.take_split(n)),
168            None => Err(nom::Err::Incomplete(nom::Needed::new(1))),
169        }
170    }
171
172    fn split_at_position1<P, E: ParseError<Self>>(
173        &self,
174        _predicate: P,
175        _e: ErrorKind,
176    ) -> IResult<Self, Self, E>
177    where
178        P: Fn(Self::Item) -> bool,
179    {
180        todo!()
181    }
182
183    fn split_at_position_complete<P, E: ParseError<Self>>(
184        &self,
185        predicate: P,
186    ) -> IResult<Self, Self, E>
187    where
188        P: Fn(Self::Item) -> bool,
189    {
190        match self.split_at_position(predicate) {
191            Err(nom::Err::Incomplete(_)) => Ok(self.take_split(self.input_len())),
192            res => res,
193        }
194    }
195
196    fn split_at_position1_complete<P, E: ParseError<Self>>(
197        &self,
198        predicate: P,
199        e: ErrorKind,
200    ) -> IResult<Self, Self, E>
201    where
202        P: Fn(Self::Item) -> bool,
203    {
204        match self.current.position(predicate) {
205            Some(0) => Err(nom::Err::Error(E::from_error_kind(self.clone(), e))),
206            Some(n) => Ok(self.take_split(n)),
207            None => {
208                if self.current.input_len() == 0 {
209                    Err(nom::Err::Error(E::from_error_kind(self.clone(), e)))
210                } else {
211                    Ok(self.take_split(self.input_len()))
212                }
213            }
214        }
215    }
216}
217
218impl<T: Compare<B>, B: Into<Trace<B>>> Compare<B> for Trace<T> {
219    fn compare(&self, t: B) -> CompareResult {
220        self.current.compare(t.into().current)
221    }
222
223    fn compare_no_case(&self, t: B) -> CompareResult {
224        self.current.compare_no_case(t.into().current)
225    }
226}
227
228#[cfg(test)]
229mod tests {
230    #[test]
231    fn trace_tag() {
232        //let r = tag("=")(Trace::new("=")).is_ok();
233    }
234}