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}