fuchsia_triage/metrics/
context.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use nom::error::{ErrorKind, ParseError};
6use nom::{AsBytes, Compare, CompareResult, Err, IResult, Input, Needed, Offset, ParseTo};
7use std::num::NonZero;
8use std::str::{CharIndices, Chars};
9
10/// Parsing context used to store additional information.
11#[derive(Debug, Clone, Copy, PartialEq)]
12pub struct ParsingContext<'a> {
13    /// The input of the parser.
14    input: &'a str,
15    // The current namespace.
16    namespace: &'a str,
17}
18
19impl<'a> ParsingContext<'a> {
20    pub fn new(input: &'a str, namespace: &'a str) -> Self {
21        Self { input, namespace }
22    }
23    pub fn into_inner(self) -> &'a str {
24        self.input
25    }
26}
27
28impl AsBytes for ParsingContext<'_> {
29    fn as_bytes(&self) -> &[u8] {
30        self.input.as_bytes()
31    }
32}
33
34impl<'a, T> Compare<T> for ParsingContext<'a>
35where
36    &'a str: Compare<T>,
37{
38    fn compare(&self, t: T) -> CompareResult {
39        self.input.compare(t)
40    }
41    fn compare_no_case(&self, t: T) -> CompareResult {
42        self.input.compare_no_case(t)
43    }
44}
45
46impl<'a> Input for ParsingContext<'a> {
47    type Item = char;
48    type IterIndices = CharIndices<'a>;
49    type Iter = Chars<'a>;
50
51    fn iter_indices(&self) -> Self::IterIndices {
52        self.input.char_indices()
53    }
54
55    fn iter_elements(&self) -> Self::Iter {
56        self.input.chars()
57    }
58
59    fn position<P>(&self, predicate: P) -> Option<usize>
60    where
61        P: Fn(Self::Item) -> bool,
62    {
63        self.input.position(predicate)
64    }
65
66    fn slice_index(&self, count: usize) -> Result<usize, Needed> {
67        self.input.slice_index(count)
68    }
69
70    fn input_len(&self) -> usize {
71        self.input.len()
72    }
73
74    fn take(&self, count: usize) -> Self {
75        Self::new(&self.input[..count], self.namespace)
76    }
77
78    fn take_from(&self, index: usize) -> Self {
79        Self::new(&self.input[index..], self.namespace)
80    }
81
82    fn take_split(&self, count: usize) -> (Self, Self) {
83        let (s0, s1) = self.input.split_at(count);
84        (ParsingContext::new(s1, self.namespace), ParsingContext::new(s0, self.namespace))
85    }
86
87    fn split_at_position<P, E: ParseError<Self>>(&self, predicate: P) -> IResult<Self, Self, E>
88    where
89        P: Fn(Self::Item) -> bool,
90    {
91        self.input
92            .position(predicate)
93            .map(|idx| Self::take_split(self, idx))
94            .ok_or(Err::Incomplete(Needed::Size(NonZero::new(1).unwrap())))
95    }
96
97    fn split_at_position1<P, E: ParseError<Self>>(
98        &self,
99        predicate: P,
100        e: ErrorKind,
101    ) -> IResult<Self, Self, E>
102    where
103        P: Fn(Self::Item) -> bool,
104    {
105        match self.input.position(predicate) {
106            Some(0) => Err(Err::Error(E::from_error_kind(*self, e))),
107            Some(idx) => Ok(Self::take_split(self, idx)),
108            None => Err(Err::Incomplete(Needed::Size(NonZero::new(1).unwrap()))),
109        }
110    }
111
112    fn split_at_position_complete<P, E: ParseError<Self>>(
113        &self,
114        predicate: P,
115    ) -> IResult<Self, Self, E>
116    where
117        P: Fn(Self::Item) -> bool,
118    {
119        match self.split_at_position(predicate) {
120            Err(Err::Incomplete(_)) => Ok(Self::take_split(self, self.input.input_len())),
121            elt => elt,
122        }
123    }
124    fn split_at_position1_complete<P, E: ParseError<Self>>(
125        &self,
126        predicate: P,
127        e: ErrorKind,
128    ) -> IResult<Self, Self, E>
129    where
130        P: Fn(Self::Item) -> bool,
131    {
132        match self.input.position(predicate) {
133            Some(0) => Err(Err::Error(E::from_error_kind(*self, e))),
134            Some(idx) => Ok(Self::take_split(self, idx)),
135            None => Ok(Self::take_split(self, self.input.input_len())),
136        }
137    }
138}
139
140impl Offset for ParsingContext<'_> {
141    fn offset(&self, second: &Self) -> usize {
142        self.input.offset(second.input)
143    }
144}
145
146impl<'a, R> ParseTo<R> for ParsingContext<'a>
147where
148    &'a str: ParseTo<R>,
149{
150    fn parse_to(&self) -> Option<R> {
151        self.input.parse_to()
152    }
153}