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}