pgn_reader/
visitor.rs

1use std::ops::ControlFlow;
2
3use crate::{Nag, Outcome, RawComment, RawTag, SanPlus};
4
5/// Tell the reader to skip over a variation.
6#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)]
7#[must_use]
8pub struct Skip(pub bool);
9
10/// Visits games from a [`Reader`](crate::Reader).
11///
12/// Visitor methods are called in these phases:
13///
14/// 1. [`Visitor::begin_tags()`]
15///    - [`Visitor::tag()`]
16/// 2. [`Visitor::begin_movetext()`]
17///    - [`Visitor::san()`]
18///    - [`Visitor::nag()`]
19///    - [`Visitor::partial_comment()`]
20///    - [`Visitor::comment()`]
21///    - [`Visitor::begin_variation()`] or skip
22///    - [`Visitor::end_variation()`]
23///    - [`Visitor::outcome()`]
24/// 3. [`Visitor::end_game()`]
25pub trait Visitor {
26    /// Produced by [`Visitor::begin_tags()`].
27    type Tags;
28    /// Produced by [`Visitor::begin_movetext()`].
29    type Movetext;
30    /// Produced by [`Visitor::end_game()`] or a short-circuiting
31    /// `ControlFlow::Break(_)` returned from any of the other methods.
32    type Output;
33
34    /// Called at the start of the game, directly before reading game tags.
35    fn begin_tags(&mut self) -> ControlFlow<Self::Output, Self::Tags>;
36
37    /// Called when parsing a game tag pair, like `[White "Deep Blue"]`.
38    fn tag(
39        &mut self,
40        tags: &mut Self::Tags,
41        name: &[u8],
42        value: RawTag<'_>,
43    ) -> ControlFlow<Self::Output> {
44        let _tags = tags;
45        let _name = name;
46        let _value = value;
47        ControlFlow::Continue(())
48    }
49
50    /// Called after reading the tags of a game, before reading the movetext.
51    fn begin_movetext(&mut self, tags: Self::Tags) -> ControlFlow<Self::Output, Self::Movetext>;
52
53    /// Called for each move, like `Nf3+`.
54    fn san(
55        &mut self,
56        movetext: &mut Self::Movetext,
57        san_plus: SanPlus,
58    ) -> ControlFlow<Self::Output> {
59        let _movetext = movetext;
60        let _san_plus = san_plus;
61        ControlFlow::Continue(())
62    }
63
64    /// Called for each numeric annotation glyph, like `!?` or `$7`.
65    fn nag(&mut self, movetext: &mut Self::Movetext, nag: Nag) -> ControlFlow<Self::Output> {
66        let _movetext = movetext;
67        let _nag = nag;
68        ControlFlow::Continue(())
69    }
70
71    /// Called for `{ comment }`s which exceed the size of the reader's movetext
72    /// token buffer.
73    ///
74    /// This method will be called once for every buffer-sized chunk of the
75    /// comment, except for the last one in which the closing `}` is finally
76    /// encountered, for which [`Visitor::comment()`] will be called
77    /// instead. This method's default implementation simply forwards its
78    /// arguments to `comment()`, so if you don't override it, long comments
79    /// will look like a series of several short ones.
80    ///
81    /// The reader will avoid splitting chunks in the middle of a multibyte
82    /// UTF-8 sequence, therefore it's guaranteed that if the comment is valid
83    /// UTF-8, then so is every chunk.
84    ///
85    /// Buffer size is configurable via
86    /// [`ReaderBuilder::set_supported_comment_length()`](crate::reader::ReaderBuilder::set_supported_comment_length).
87    fn partial_comment(
88        &mut self,
89        movetext: &mut Self::Movetext,
90        comment: RawComment<'_>,
91    ) -> ControlFlow<Self::Output> {
92        self.comment(movetext, comment)
93    }
94
95    /// Called for each `{ comment }`.
96    fn comment(
97        &mut self,
98        movetext: &mut Self::Movetext,
99        comment: RawComment<'_>,
100    ) -> ControlFlow<Self::Output> {
101        let _movetext = movetext;
102        let _comment = comment;
103        ControlFlow::Continue(())
104    }
105
106    /// Called for each `(`.
107    ///
108    /// Defaults to skip over the following variation directly to
109    /// [`Visitor::end_variation()`] (or to [`Visitor::end_game()`] if no
110    /// matching `)` follows before the end of the game.
111    fn begin_variation(
112        &mut self,
113        movetext: &mut Self::Movetext,
114    ) -> ControlFlow<Self::Output, Skip> {
115        let _movetext = movetext;
116        ControlFlow::Continue(Skip(true))
117    }
118
119    /// Called for each `)`. It is *not* guaranteed that there was a
120    /// matching `(`.
121    fn end_variation(&mut self, movetext: &mut Self::Movetext) -> ControlFlow<Self::Output> {
122        let _movetext = movetext;
123        ControlFlow::Continue(())
124    }
125
126    /// Called for each game termination, like `*` or `1-0`.
127    fn outcome(
128        &mut self,
129        movetext: &mut Self::Movetext,
130        outcome: Outcome,
131    ) -> ControlFlow<Self::Output> {
132        let _movetext = movetext;
133        let _outcome = outcome;
134        ControlFlow::Continue(())
135    }
136
137    /// Called after parsing a game.
138    fn end_game(&mut self, movetext: Self::Movetext) -> Self::Output;
139}