apollo_parser/
limit.rs

1use std::fmt;
2
3/// A LimitTracker enforces a particular limit within the parser. It keeps
4/// track of utilization so that we can report how close to a limit we
5/// approached over the lifetime of the tracker.
6/// ```rust
7/// use apollo_parser::Parser;
8///
9/// let query = "
10/// {
11///     animal
12///     ...snackSelection
13///     ... on Pet {
14///       playmates {
15///         count
16///       }
17///     }
18/// }
19/// ";
20/// // Create a new instance of a parser given a query and a
21/// // recursion limit
22/// let parser = Parser::new(query).recursion_limit(4);
23/// // Parse the query, and return a SyntaxTree.
24/// let cst = parser.parse();
25/// // Retrieve the limits
26/// let usage = cst.recursion_limit();
27/// // Print out some of the usage details to see what happened during
28/// // our parse. `limit` just reports the limit we set, `high` is the
29/// // high-water mark of recursion usage.
30/// println!("{:?}", usage);
31/// println!("{:?}", usage.limit);
32/// println!("{:?}", usage.high);
33/// // Check that are no errors. These are not part of the CST.
34/// assert_eq!(0, cst.errors().len());
35///
36/// // Get the document root node
37/// let doc = cst.document();
38/// // ... continue
39/// ```
40#[derive(PartialEq, Eq, Clone, Copy)]
41pub struct LimitTracker {
42    pub(crate) current: usize,
43    /// High Water mark for this limit
44    pub high: usize,
45    /// Limit.
46    pub limit: usize,
47}
48
49impl LimitTracker {
50    pub fn new(limit: usize) -> Self {
51        Self {
52            current: 0,
53            high: 0,
54            limit,
55        }
56    }
57
58    /// Return whether the limit was reached
59    #[must_use]
60    pub fn check_and_increment(&mut self) -> bool {
61        self.current += 1;
62        if self.current > self.high {
63            self.high = self.current;
64        }
65        let reached = self.current > self.limit;
66        if reached {
67            // Caller is gonna return early, keep increments and decrements balanced:
68            self.decrement()
69        }
70        reached
71    }
72
73    pub fn decrement(&mut self) {
74        self.current -= 1;
75    }
76}
77
78impl fmt::Debug for LimitTracker {
79    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80        write!(f, "recursion limit: {}, high: {}", self.limit, self.high)
81    }
82}