faf_replay_parser/
parser_builder.rs

1use crate::parser::{Parser, ParserOptions, StreamParser};
2use crate::version::{CommandId, Version};
3use std::collections::HashSet;
4
5/// A builder for configuring replay [`Parser`]s. See [`build`] for an example.
6///
7/// [`build`]: struct.ParserBuilder.html#method.build
8#[derive(Debug)]
9pub struct ParserBuilder<V: Version> {
10    options: ParserOptions<V>,
11}
12
13impl<V: Version> ParserBuilder<V> {
14    /// Initialize with default options
15    pub fn new() -> ParserBuilder<V> {
16        ParserBuilder {
17            options: ParserOptions {
18                commands: HashSet::new(),
19                limit: None,
20                save_commands: true,
21                stop_on_desync: true,
22            },
23        }
24    }
25
26    /// Creates a new [`Parser`] by moving the internal [`ParserOptions`] and consuming self.
27    ///
28    /// # Example
29    ///
30    /// ```rust
31    /// use faf_replay_parser::scfa::{replay_command, ReplayCommandId};
32    /// use faf_replay_parser::{ParserBuilder, SCFA};
33    /// use std::convert::TryFrom;
34    ///
35    /// let parser = ParserBuilder::<SCFA>::new()
36    ///     .commands(&[
37    ///         ReplayCommandId::try_from(replay_command::ADVANCE).unwrap(),
38    ///         ReplayCommandId::try_from(replay_command::VERIFY_CHECKSUM).unwrap(),
39    ///         ReplayCommandId::try_from(replay_command::END_GAME).unwrap(),
40    ///     ])
41    ///     .build();
42    /// ```
43    pub fn build(self) -> Parser<V> {
44        Parser::with_options(self.options)
45    }
46
47    /// Like [`build`] but creates a new [`StreamParser`].
48    ///
49    /// [`build`]: struct.ParserBuilder.html#method.build
50    pub fn build_stream(self) -> StreamParser<V> {
51        StreamParser::with_options(self.options)
52    }
53
54    /// Creates a new [`Parser`] by cloning the internal [`ParserOptions`]. Useful when constructing
55    /// many parsers with similar options.
56    ///
57    /// Example
58    ///
59    /// ```rust
60    /// use faf_replay_parser::scfa::{replay_command, ReplayCommandId};
61    /// use faf_replay_parser::{ParserBuilder, SCFA};
62    /// use std::convert::TryFrom;
63    ///
64    /// let mut builder = ParserBuilder::<SCFA>::new().commands(&[
65    ///     ReplayCommandId::try_from(replay_command::ADVANCE).unwrap(),
66    ///     ReplayCommandId::try_from(replay_command::END_GAME).unwrap(),
67    /// ]);
68    ///
69    /// // Can only count game ticks
70    /// let tick_parser = builder.build_clone();
71    ///
72    /// let builder =
73    ///     builder.command(ReplayCommandId::try_from(replay_command::VERIFY_CHECKSUM).unwrap());
74    /// // Can count game ticks and detect desyncs
75    /// let desync_parser = builder.build_clone();
76    ///
77    /// let builder =
78    ///     builder.command(ReplayCommandId::try_from(replay_command::LUA_SIM_CALLBACK).unwrap());
79    /// // Can count game ticks, detect desyncs, and extract chat messages
80    /// let message_parser = builder.build();
81    /// ```
82    pub fn build_clone(&self) -> Parser<V> {
83        Parser::with_options(self.options.clone())
84    }
85
86    /// Like [`build_clone`] but creates a new [`StreamParser`].
87    ///
88    /// [`build_clone`]: struct.ParserBuilder.html#method.build_clone
89    pub fn build_stream_clone(&self) -> StreamParser<V> {
90        StreamParser::with_options(self.options.clone())
91    }
92
93    /// Add a command to the [`ParserOptions`].
94    pub fn command(mut self, command: V::CommandId) -> ParserBuilder<V> {
95        self.options.commands.insert(command);
96        self
97    }
98
99    /// Add multiple commands to the [`ParserOptions`].
100    pub fn commands(mut self, commands: &[V::CommandId]) -> ParserBuilder<V> {
101        commands.iter().for_each(|cmd| {
102            self.options.commands.insert(*cmd);
103        });
104        self
105    }
106
107    /// Add all supported commands to the [`ParserOptions`].
108    pub fn commands_all(self) -> ParserBuilder<V> {
109        self.commands(
110            V::CommandId::builder_all()
111                .collect::<Vec<V::CommandId>>()
112                .as_slice(),
113        )
114    }
115
116    /// Add the default set of commands to the [`ParserOptions`].
117    ///
118    /// Default commands are `ADVANCE`, `SET_COMMAND_SOURCE`, `COMMAND_SOURCE_TERMINATED`,
119    /// `VERIFY_CHECKSUM`, and `END_GAME`
120    pub fn commands_default(self) -> ParserBuilder<V> {
121        self.commands(
122            V::CommandId::builder_defaults()
123                .collect::<Vec<V::CommandId>>()
124                .as_slice(),
125        )
126    }
127
128    /// Set a limit on the number of commands to parse. This only applies to commands in the
129    /// `ParserOptions.commands` field.
130    pub fn limit(mut self, limit: Option<usize>) -> ParserBuilder<V> {
131        self.options.limit = limit;
132        self
133    }
134
135    /// Whether or not to store the parsed commands in the parsed `ReplayBody`. When set to false,
136    /// `Replay.body.commands.len()` will always be `0`.
137    pub fn save_commands(mut self, save_commands: bool) -> ParserBuilder<V> {
138        self.options.save_commands = save_commands;
139        self
140    }
141
142    /// Whether or not to return an error if a desync is detected. When set to false,
143    /// `Replay.sim.desync_ticks` will be a list of all desynced ticks.
144    pub fn stop_on_desync(mut self, stop_on_desync: bool) -> ParserBuilder<V> {
145        self.options.stop_on_desync = stop_on_desync;
146        self
147    }
148}