1
//! Structural keyword recognition helpers
2

            
3
use super::*;
4

            
5
/// Predicate for testing whether a keyword is a structural one that we should stop at
6
///
7
/// This helper type allows us to compose predicates in curried form with `|`.
8
#[derive(Debug, Copy, Clone, derive_more::Deref)]
9
#[allow(clippy::exhaustive_structs)]
10
pub struct StopAt<P: StopPredicate>(pub P);
11

            
12
/// Raw predicate, usually a closure, that can appear within `StopAt`.
13
///
14
/// Implemented for suitable closures, and also for booleans.
15
pub trait StopPredicate: Copy {
16
    /// Is this keyword a structural one meaning we should stop parsing here?
17
    ///
18
    /// Precisely what the semantics are depends on the context.
19
    /// Typically, matched keywords will cause processing to continue
20
    /// in a subsequent document section, or in an outer (containing) document.
21
    fn stop_at(&self, kw: KeywordRef<'_>) -> bool;
22
}
23
impl<F: Copy + Fn(KeywordRef<'_>) -> bool> StopPredicate for F {
24
10466
    fn stop_at(&self, kw: KeywordRef<'_>) -> bool {
25
10466
        self(kw)
26
10466
    }
27
}
28
impl StopPredicate for bool {
29
6832
    fn stop_at(&self, _kw: KeywordRef<'_>) -> bool {
30
6832
        *self
31
6832
    }
32
}
33

            
34
/// "Type alias" for `StopAt<impl Fn(KeywordRef<'_>) -> Option<Stop>>`
35
///
36
/// This has to be a macro because the `impl` is a different type at each call site;
37
/// even TAIT wouldn't help with thaat.
38
#[macro_export]
39
macro_rules! stop_at { {} => {
40
    $crate::parse2::internal_prelude::StopAt<
41
        impl $crate::parse2::internal_prelude::StopPredicate
42
    >
43
} }
44

            
45
impl StopAt<bool> {
46
    /// Returns predicate flagging precisely the intro keywords for a parseable document
47
342
    pub fn doc_intro<D: NetdocParseable>() -> stop_at!() {
48
342
        StopAt(D::is_intro_item_keyword)
49
342
    }
50
}
51

            
52
/// Helper type: return value from `StopAt | StopAt`
53
#[derive(Debug, Copy, Clone)]
54
pub struct BitOrOutput<A, B>(A, B);
55

            
56
impl<A: StopPredicate, B: StopPredicate> std::ops::BitOr<StopAt<B>> for StopAt<A> {
57
    type Output = StopAt<BitOrOutput<A, B>>;
58
1191
    fn bitor(self, rhs: StopAt<B>) -> Self::Output {
59
1191
        StopAt(BitOrOutput(self.0, rhs.0))
60
1191
    }
61
}
62

            
63
impl<A: StopPredicate, B: StopPredicate> StopPredicate for BitOrOutput<A, B> {
64
13812
    fn stop_at(&self, kw: KeywordRef<'_>) -> bool {
65
13812
        self.0.stop_at(kw) || self.1.stop_at(kw)
66
13812
    }
67
}