css_parse/traits/
peek.rs

1use crate::{Cursor, KindSet};
2
3use crate::Parser;
4
5/// This trait allows AST nodes to indicate whether the [Parser] is in the right position to potentially
6/// [Parse][crate::Parse] the node. Returning `true` from [Peek] is not a _guarantee_ that a node will successfully
7/// parse, instead it offers an indication that the node can successfully parse the first node. This is useful for
8/// cheaply comparing a set of Nodes to see which one might viably parse, rather than calling [Parser::try_parse()] on
9/// each.
10///
11/// Nodes that implement this trait are entitled to peek any number of [Cursors][Cursor] ahead from the [Parser], to
12/// determine if those [Cursors][Cursor] are viable to begin parsing, however there is a cost involved in peeking, so
13/// it is worth being conservative; peek the minimum amount ahead to determine this. Most implementations can peek just
14/// 1 [Cursor] ahead - this is provided as the second argument. To peek further, use the [Parser::peek_n()] method.
15/// Calling `peek_n(2)` will return the [Cursor] after the provided one `peek_n(3)` will return the second [Cursor]
16/// after, and so on.
17///
18/// For simple implementations it may be sufficient to just check the [Kind][crate::Kind] of the given [Cursor].
19/// Rather than implementing [Peek::peek()], supplying [Peek::PEEK_KINDSET] and relying on the provided [Peek::peek()]
20/// method will work well.
21///
22/// However it is likely that more complex checks will be needed. In order to reason about the given [Cursor] (or other
23/// cursors ahead) an implementation might want to call [Parser::parse_str()] - which takes a [Cursor] and returns the
24/// underlying string to reason about. When comparing lots of strings, consider implementing a [phf::Map]. If comparing
25/// just one string, consider [Parser::eq_ignore_ascii_case()] which can fail-fast, rather than parsing a whole string.
26///
27/// When peeking child nodes, implementations should _not_ call [Peek::peek()] directly. Instead - call
28/// [`Parser::peek<T>()`]. [`Parser::parse_if_peek<T>()`] also exists to conveniently parse a Node if it passes the peek
29/// test.
30///
31/// If a Node can construct itself from a single [Cursor][Cursor] it should also implement
32/// [Build][crate::Build], then it will get [Parse][crate::Parse] for free.
33pub trait Peek<'a>: Sized {
34	const PEEK_KINDSET: KindSet = KindSet::ANY;
35
36	fn peek(_: &Parser<'a>, c: Cursor) -> bool {
37		c == Self::PEEK_KINDSET
38	}
39}
40
41impl<'a, T> Peek<'a> for Option<T>
42where
43	T: Peek<'a>,
44{
45	fn peek(p: &Parser<'a>, c: Cursor) -> bool {
46		T::peek(p, c)
47	}
48}
49
50impl<'a, T> Peek<'a> for ::bumpalo::collections::Vec<'a, T>
51where
52	T: Peek<'a>,
53{
54	const PEEK_KINDSET: KindSet = T::PEEK_KINDSET;
55
56	fn peek(p: &Parser<'a>, c: Cursor) -> bool {
57		T::peek(p, c)
58	}
59}
60
61macro_rules! impl_tuple {
62    ($($T:ident),*) => {
63        impl<'a, $($T),*> Peek<'a> for ($($T),*)
64        where
65            $($T: Peek<'a>,)*
66        {
67            fn peek(p: &Parser<'a>, c: Cursor) -> bool {
68                A::peek(p, c)
69            }
70        }
71    };
72}
73
74impl_tuple!(A, B);
75impl_tuple!(A, B, C);
76impl_tuple!(A, B, C, D);
77impl_tuple!(A, B, C, D, E);
78impl_tuple!(A, B, C, D, E, F);
79impl_tuple!(A, B, C, D, E, F, G);
80impl_tuple!(A, B, C, D, E, F, G, H);
81impl_tuple!(A, B, C, D, E, F, G, H, I);
82impl_tuple!(A, B, C, D, E, F, G, H, I, J);
83impl_tuple!(A, B, C, D, E, F, G, H, I, J, K);
84impl_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);