bms_rs/bms/parse/
prompt.rs

1//! Prompting interface and utilities.
2//!
3//! An object implementing [`PromptHandler`] is required by [`super::Bms::from_token_stream`]. It is used to handle conflicts and prompt workarounds on parsing the BMS file.
4
5use std::path::Path;
6
7use crate::bms::{
8    Decimal,
9    command::{
10        ObjId,
11        channel::Channel,
12        time::{ObjTime, Track},
13    },
14};
15
16use super::{ParseWarning, Result};
17use crate::bms::{
18    model::def::{AtBgaDef, BgaDef, Bmp, ExRankDef},
19    model::obj::{
20        BgaObj, BgmVolumeObj, BpmChangeObj, JudgeObj, KeyVolumeObj, ScrollingFactorObj,
21        SectionLenChangeObj, SpeedObj, TextObj,
22    },
23};
24
25#[cfg(feature = "minor-command")]
26use crate::bms::{
27    command::{
28        graphics::Argb,
29        minor_command::{StpEvent, SwBgaEvent, WavCmdEvent},
30    },
31    model::{
32        def::ExWavDef,
33        obj::{BgaArgbObj, BgaKeyboundObj, BgaOpacityObj, OptionObj, SeekObj},
34    },
35};
36
37/// An interface to prompt about handling conflicts on the BMS file.
38pub trait PromptHandler {
39    /// Determines a [`DuplicationWorkaround`] for [`DefDuplication`].
40    fn handle_def_duplication(&mut self, duplication: DefDuplication) -> DuplicationWorkaround;
41    /// Determines a [`DuplicationWorkaround`] for [`TrackDuplication`].
42    fn handle_track_duplication(&mut self, duplication: TrackDuplication) -> DuplicationWorkaround;
43    /// Determines a [`DuplicationWorkaround`] for [`ChannelDuplication`].
44    fn handle_channel_duplication(
45        &mut self,
46        duplication: ChannelDuplication,
47    ) -> DuplicationWorkaround;
48}
49
50/// It represents that there is a duplicated definition on the BMS file.
51#[derive(Debug, Clone, PartialEq)]
52#[non_exhaustive]
53pub enum DefDuplication<'a> {
54    /// BMP definition is duplicated.
55    Bmp {
56        /// Duplicated BMP object id.
57        id: ObjId,
58        /// Existing definition.
59        older: &'a Bmp,
60        /// Incoming definition.
61        newer: &'a Bmp,
62    },
63    /// BPM definition is duplicated.
64    BpmChange {
65        /// Duplicated BPM object id.
66        id: ObjId,
67        /// Existing definition.
68        older: Decimal,
69        /// Incoming definition.
70        newer: Decimal,
71    },
72    /// OPTION definition is duplicated.
73    ChangeOption {
74        /// Duplicated OPTION object id.
75        id: ObjId,
76        /// Existing definition.
77        older: &'a str,
78        /// Incoming definition.
79        newer: &'a str,
80    },
81    /// SPEED definition is duplicated.
82    SpeedFactorChange {
83        /// Duplicated SPEED object id.
84        id: ObjId,
85        /// Existing definition.
86        older: Decimal,
87        /// Incoming definition.
88        newer: Decimal,
89    },
90    /// SCROLL definition is duplicated.
91    ScrollingFactorChange {
92        /// Duplicated SCROLL object id.
93        id: ObjId,
94        /// Existing definition.
95        older: Decimal,
96        /// Incoming definition.
97        newer: Decimal,
98    },
99    /// TEXT is duplicated.
100    Text {
101        /// Duplicated TEXT object id.
102        id: ObjId,
103        /// Existing definition.
104        older: &'a str,
105        /// Incoming definition.
106        newer: &'a str,
107    },
108    /// WAV definition is duplicated.
109    Wav {
110        /// Duplicated WAV object id.
111        id: ObjId,
112        /// Existing definition.
113        older: &'a Path,
114        /// Incoming definition.
115        newer: &'a Path,
116    },
117    /// @BGA definition is duplicated.
118    AtBga {
119        /// Duplicated @BGA object id.
120        id: ObjId,
121        /// Existing definition.
122        older: &'a AtBgaDef,
123        /// Incoming definition.
124        newer: &'a AtBgaDef,
125    },
126    /// BGA definition is duplicated.
127    Bga {
128        /// Duplicated BGA object id.
129        id: ObjId,
130        /// Existing definition.
131        older: &'a BgaDef,
132        /// Incoming definition.
133        newer: &'a BgaDef,
134    },
135    /// EXRANK definition is duplicated.
136    ExRank {
137        /// Duplicated EXRANK object id.
138        id: ObjId,
139        /// Existing definition.
140        older: &'a ExRankDef,
141        /// Incoming definition.
142        newer: &'a ExRankDef,
143    },
144    /// EXWAV definition is duplicated.
145    #[cfg(feature = "minor-command")]
146    ExWav {
147        /// Duplicated EXWAV object id.
148        id: ObjId,
149        /// Existing definition.
150        older: &'a ExWavDef,
151        /// Incoming definition.
152        newer: &'a ExWavDef,
153    },
154    /// STOP definition is duplicated.
155    Stop {
156        /// Duplicated STOP object id.
157        id: ObjId,
158        /// Existing definition.
159        older: Decimal,
160        /// Incoming definition.
161        newer: Decimal,
162    },
163    /// BGA ARGB color definition is duplicated.
164    #[cfg(feature = "minor-command")]
165    BgaArgb {
166        /// Duplicated BGA ARGB object id.
167        id: ObjId,
168        /// Existing definition.
169        older: &'a Argb,
170        /// Incoming definition.
171        newer: &'a Argb,
172    },
173    /// `WAVCMD` event is duplicated.
174    #[cfg(feature = "minor-command")]
175    WavCmdEvent {
176        /// Duplicated `WAVCMD` event `wav_index`.
177        wav_index: ObjId,
178        /// Existing definition.
179        older: &'a WavCmdEvent,
180        /// Incoming definition.
181        newer: &'a WavCmdEvent,
182    },
183    /// SWBGA event is duplicated.
184    #[cfg(feature = "minor-command")]
185    SwBgaEvent {
186        /// Duplicated SWBGA event id.
187        id: ObjId,
188        /// Existing definition.
189        older: &'a SwBgaEvent,
190        /// Incoming definition.
191        newer: &'a SwBgaEvent,
192    },
193    /// Seek event is duplicated.
194    #[cfg(feature = "minor-command")]
195    SeekEvent {
196        /// Duplicated Seek event id.
197        id: ObjId,
198        /// Existing definition.
199        older: &'a Decimal,
200        /// Incoming definition.
201        newer: &'a Decimal,
202    },
203}
204
205/// It represents that there is a duplicated track object on the BMS file.
206pub enum TrackDuplication<'a> {
207    /// Section length change event is duplicated.
208    SectionLenChangeEvent {
209        /// Duplicated section length change track.
210        track: Track,
211        /// Existing definition.
212        older: &'a SectionLenChangeObj,
213        /// Incoming definition.
214        newer: &'a SectionLenChangeObj,
215    },
216}
217
218/// It represents that there is a duplicated channel object on the BMS file.
219pub enum ChannelDuplication<'a> {
220    /// BPM change event is duplicated.
221    BpmChangeEvent {
222        /// Duplicated BPM change time.
223        time: ObjTime,
224        /// Existing definition.
225        older: &'a BpmChangeObj,
226        /// Incoming definition.
227        newer: &'a BpmChangeObj,
228    },
229    /// Scrolling factor change event is duplicated.
230    ScrollingFactorChangeEvent {
231        /// Duplicated scrolling factor change time.
232        time: ObjTime,
233        /// Existing definition.
234        older: &'a ScrollingFactorObj,
235        /// Incoming definition.
236        newer: &'a ScrollingFactorObj,
237    },
238    /// Speed factor change event is duplicated.
239    SpeedFactorChangeEvent {
240        /// Duplicated speed factor change time.
241        time: ObjTime,
242        /// Existing definition.
243        older: &'a SpeedObj,
244        /// Incoming definition.
245        newer: &'a SpeedObj,
246    },
247    /// BGA change event is duplicated.
248    BgaChangeEvent {
249        /// Duplicated BGA change time.
250        time: ObjTime,
251        /// Existing definition.
252        older: &'a BgaObj,
253        /// Incoming definition.
254        newer: &'a BgaObj,
255    },
256    /// BGA opacity change event is duplicated.
257    #[cfg(feature = "minor-command")]
258    BgaOpacityChangeEvent {
259        /// Duplicated BGA opacity change time.
260        time: ObjTime,
261        /// Existing definition.
262        older: &'a BgaOpacityObj,
263        /// Incoming definition.
264        newer: &'a BgaOpacityObj,
265    },
266    /// BGA ARGB color change event is duplicated.
267    #[cfg(feature = "minor-command")]
268    BgaArgbChangeEvent {
269        /// Duplicated BGA ARGB change time.
270        time: ObjTime,
271        /// Existing definition.
272        older: &'a BgaArgbObj,
273        /// Incoming definition.
274        newer: &'a BgaArgbObj,
275    },
276    /// STP event is duplicated.
277    #[cfg(feature = "minor-command")]
278    StpEvent {
279        /// Duplicated STP event time.
280        time: ObjTime,
281        /// Existing definition.
282        older: &'a StpEvent,
283        /// Incoming definition.
284        newer: &'a StpEvent,
285    },
286    /// BGM volume change event is duplicated.
287    BgmVolumeChangeEvent {
288        /// Duplicated BGM volume change time.
289        time: ObjTime,
290        /// Existing definition.
291        older: &'a BgmVolumeObj,
292        /// Incoming definition.
293        newer: &'a BgmVolumeObj,
294    },
295    /// KEY volume change event is duplicated.
296    KeyVolumeChangeEvent {
297        /// Duplicated KEY volume change time.
298        time: ObjTime,
299        /// Existing definition.
300        older: &'a KeyVolumeObj,
301        /// Incoming definition.
302        newer: &'a KeyVolumeObj,
303    },
304    /// Seek message event is duplicated.
305    #[cfg(feature = "minor-command")]
306    SeekMessageEvent {
307        /// Duplicated seek time.
308        time: ObjTime,
309        /// Existing definition.
310        older: &'a SeekObj,
311        /// Incoming definition.
312        newer: &'a SeekObj,
313    },
314    /// Text event is duplicated.
315    TextEvent {
316        /// Duplicated text time.
317        time: ObjTime,
318        /// Existing definition.
319        older: &'a TextObj,
320        /// Incoming definition.
321        newer: &'a TextObj,
322    },
323    /// Judge event is duplicated.
324    JudgeEvent {
325        /// Duplicated judge time.
326        time: ObjTime,
327        /// Existing definition.
328        older: &'a JudgeObj,
329        /// Incoming definition.
330        newer: &'a JudgeObj,
331    },
332    /// BGA keybound event is duplicated.
333    #[cfg(feature = "minor-command")]
334    BgaKeyboundEvent {
335        /// Duplicated BGA keybound time.
336        time: ObjTime,
337        /// Existing definition.
338        older: &'a BgaKeyboundObj,
339        /// Incoming definition.
340        newer: &'a BgaKeyboundObj,
341    },
342    /// Option event is duplicated.
343    #[cfg(feature = "minor-command")]
344    OptionEvent {
345        /// Duplicated option time.
346        time: ObjTime,
347        /// Existing definition.
348        older: &'a OptionObj,
349        /// Incoming definition.
350        newer: &'a OptionObj,
351    },
352}
353
354/// A choice to handle the duplicated definition.
355#[derive(Debug, Clone, PartialEq, Eq, Hash)]
356#[non_exhaustive]
357pub enum DuplicationWorkaround {
358    /// Choose to use the existing one.
359    UseOlder,
360    /// Choose to use the incoming one.
361    UseNewer,
362    /// Choose to warn and use older values.
363    WarnAndUseOlder,
364    /// Choose to warn and use newer values.
365    WarnAndUseNewer,
366}
367
368impl DuplicationWorkaround {
369    pub(crate) fn apply_def<T>(self, target: &mut T, newer: T, id: ObjId) -> Result<()> {
370        match self {
371            Self::UseOlder => Ok(()),
372            Self::UseNewer => {
373                *target = newer;
374                Ok(())
375            }
376            Self::WarnAndUseOlder => Err(ParseWarning::DuplicatingDef(id)),
377            Self::WarnAndUseNewer => {
378                *target = newer;
379                Err(ParseWarning::DuplicatingDef(id))
380            }
381        }
382    }
383
384    pub(crate) fn apply_track<T>(
385        self,
386        target: &mut T,
387        newer: T,
388        track: Track,
389        channel: Channel,
390    ) -> Result<()> {
391        match self {
392            Self::UseOlder => Ok(()),
393            Self::UseNewer => {
394                *target = newer;
395                Ok(())
396            }
397            Self::WarnAndUseOlder => Err(ParseWarning::DuplicatingTrackObj(track, channel)),
398            Self::WarnAndUseNewer => {
399                *target = newer;
400                Err(ParseWarning::DuplicatingTrackObj(track, channel))
401            }
402        }
403    }
404
405    pub(crate) fn apply_channel<T>(
406        self,
407        target: &mut T,
408        newer: T,
409        time: ObjTime,
410        channel: Channel,
411    ) -> Result<()> {
412        match self {
413            Self::UseOlder => Ok(()),
414            Self::UseNewer => {
415                *target = newer;
416                Ok(())
417            }
418            Self::WarnAndUseOlder => Err(ParseWarning::DuplicatingChannelObj(time, channel)),
419            Self::WarnAndUseNewer => {
420                *target = newer;
421                Err(ParseWarning::DuplicatingChannelObj(time, channel))
422            }
423        }
424    }
425}
426
427/// The strategy that always using older ones.
428#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
429pub struct AlwaysUseOlder;
430
431impl PromptHandler for AlwaysUseOlder {
432    fn handle_def_duplication(&mut self, _: DefDuplication) -> DuplicationWorkaround {
433        DuplicationWorkaround::UseOlder
434    }
435
436    fn handle_track_duplication(&mut self, _: TrackDuplication) -> DuplicationWorkaround {
437        DuplicationWorkaround::UseOlder
438    }
439
440    fn handle_channel_duplication(&mut self, _: ChannelDuplication) -> DuplicationWorkaround {
441        DuplicationWorkaround::UseOlder
442    }
443}
444
445/// The strategy that always using newer ones.
446#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
447pub struct AlwaysUseNewer;
448
449impl PromptHandler for AlwaysUseNewer {
450    fn handle_def_duplication(&mut self, _: DefDuplication) -> DuplicationWorkaround {
451        DuplicationWorkaround::UseNewer
452    }
453
454    fn handle_track_duplication(&mut self, _: TrackDuplication) -> DuplicationWorkaround {
455        DuplicationWorkaround::UseNewer
456    }
457
458    fn handle_channel_duplication(&mut self, _: ChannelDuplication) -> DuplicationWorkaround {
459        DuplicationWorkaround::UseNewer
460    }
461}
462
463/// The strategy that always warns and uses older values.
464#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
465pub struct AlwaysWarnAndUseOlder;
466
467impl PromptHandler for AlwaysWarnAndUseOlder {
468    fn handle_def_duplication(&mut self, _: DefDuplication) -> DuplicationWorkaround {
469        DuplicationWorkaround::WarnAndUseOlder
470    }
471
472    fn handle_track_duplication(&mut self, _: TrackDuplication) -> DuplicationWorkaround {
473        DuplicationWorkaround::WarnAndUseOlder
474    }
475
476    fn handle_channel_duplication(&mut self, _: ChannelDuplication) -> DuplicationWorkaround {
477        DuplicationWorkaround::WarnAndUseOlder
478    }
479}
480
481/// The strategy that always warns and uses newer values.
482#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
483pub struct AlwaysWarnAndUseNewer;
484
485impl PromptHandler for AlwaysWarnAndUseNewer {
486    fn handle_def_duplication(&mut self, _: DefDuplication) -> DuplicationWorkaround {
487        DuplicationWorkaround::WarnAndUseNewer
488    }
489
490    fn handle_track_duplication(&mut self, _: TrackDuplication) -> DuplicationWorkaround {
491        DuplicationWorkaround::WarnAndUseNewer
492    }
493
494    fn handle_channel_duplication(&mut self, _: ChannelDuplication) -> DuplicationWorkaround {
495        DuplicationWorkaround::WarnAndUseNewer
496    }
497}