Skip to main content

oxc_graphql_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 oxc_graphql_parser::{Allocator, 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 allocator = Allocator::default();
23/// let parser = Parser::new(&allocator, query).recursion_limit(4);
24/// // Parse the query, and return an AST.
25/// let ast = parser.parse();
26/// // Retrieve the limits
27/// let usage = ast.recursion_limit();
28/// // Print out some of the usage details to see what happened during
29/// // our parse. `limit` just reports the limit we set, `high` is the
30/// // high-water mark of recursion usage.
31/// println!("{:?}", usage);
32/// println!("{:?}", usage.limit);
33/// println!("{:?}", usage.high);
34/// // Check that are no errors. These are not part of the AST.
35/// assert_eq!(0, ast.errors().len());
36///
37/// // Get the document root node
38/// let doc = ast.document();
39/// // ... continue
40/// ```
41#[derive(PartialEq, Eq, Clone, Copy)]
42pub struct LimitTracker {
43    pub(crate) current: usize,
44    /// High Water mark for this limit
45    pub high: usize,
46    /// Limit.
47    pub limit: usize,
48}
49
50impl LimitTracker {
51    pub fn new(limit: usize) -> Self {
52        Self { current: 0, high: 0, limit }
53    }
54
55    /// Return whether the limit was reached
56    #[must_use]
57    pub fn check_and_increment(&mut self) -> bool {
58        self.current += 1;
59        if self.current > self.high {
60            self.high = self.current;
61        }
62        let reached = self.current > self.limit;
63        if reached {
64            // Caller is gonna return early, keep increments and decrements balanced:
65            self.decrement()
66        }
67        reached
68    }
69
70    pub fn decrement(&mut self) {
71        self.current -= 1;
72    }
73}
74
75impl fmt::Debug for LimitTracker {
76    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
77        write!(f, "recursion limit: {}, high: {}", self.limit, self.high)
78    }
79}