Skip to content

Commit 2d720ff

Browse files
RefraggAlexKnauth
authored andcommitted
Run parser: deserialize the AutoSplitterSettings
This commit implements the deserialization of the AutoSplitterSettings XML section of a LiveSplit splits file. This can surely use some improvements regarding the compatibility without the auto-splitting feature and some other things. I think it is good as a first step though and we can keep iterating on it.
1 parent 7cdf265 commit 2d720ff

File tree

10 files changed

+666
-24
lines changed

10 files changed

+666
-24
lines changed

crates/livesplit-auto-splitting/src/settings/gui.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::sync::Arc;
22

33
/// A setting widget that is meant to be shown to and modified by the user.
44
#[non_exhaustive]
5-
#[derive(Clone)]
5+
#[derive(Clone, PartialEq)]
66
pub struct Widget {
77
/// A unique identifier for this setting. This is not meant to be shown to
88
/// the user and is only used to keep track of the setting. This key is used
@@ -19,7 +19,7 @@ pub struct Widget {
1919
}
2020

2121
/// The type of a [`Widget`] and additional information about it.
22-
#[derive(Clone)]
22+
#[derive(Debug, Clone, PartialEq)]
2323
pub enum WidgetKind {
2424
/// A title that is shown to the user. It doesn't by itself store a value
2525
/// and is instead used to group settings together.
@@ -51,7 +51,7 @@ pub enum WidgetKind {
5151
}
5252

5353
/// A filter for a file selection setting.
54-
#[derive(Clone)]
54+
#[derive(Clone, Debug, PartialEq)]
5555
pub enum FileFilter {
5656
/// A filter that matches on the name of the file.
5757
Name {
@@ -82,7 +82,7 @@ pub enum FileFilter {
8282
}
8383

8484
/// An option for a choice setting.
85-
#[derive(Clone, Eq, Hash, PartialEq)]
85+
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
8686
pub struct ChoiceOption {
8787
/// The unique identifier of the option. This is not meant to be shown to
8888
/// the user and is only used to keep track of the option. This key is used

src/auto_splitting/mod.rs

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -559,15 +559,16 @@ use crate::{
559559
use arc_swap::ArcSwapOption;
560560
pub use livesplit_auto_splitting::{settings, wasi_path};
561561
use livesplit_auto_splitting::{
562-
AutoSplitter, Config, CreationError, LogLevel, Timer as AutoSplitTimer, TimerState,
562+
AutoSplitter, CompiledAutoSplitter, Config, CreationError, LogLevel,
563+
Timer as AutoSplitTimer, TimerState,
563564
};
564565
use snafu::Snafu;
565566
use std::{
566567
fmt, fs, io,
567568
path::PathBuf,
568569
sync::{
569570
mpsc::{self, Receiver, RecvTimeoutError, Sender},
570-
Condvar, Mutex,
571+
Condvar, Mutex, RwLock,
571572
},
572573
thread,
573574
time::{Duration, Instant},
@@ -602,6 +603,7 @@ pub struct Runtime<T: event::CommandSink + TimerQuery + Send + 'static> {
602603
shared_state: Arc<SharedState<T>>,
603604
changed_sender: Sender<()>,
604605
runtime: livesplit_auto_splitting::Runtime,
606+
compiled_auto_splitter: RwLock<Option<CompiledAutoSplitter>>,
605607
}
606608

607609
struct SharedState<T> {
@@ -676,18 +678,32 @@ impl<T: event::CommandSink + TimerQuery + Send + 'static> Runtime<T> {
676678
changed_sender,
677679
// TODO: unwrap?
678680
runtime: livesplit_auto_splitting::Runtime::new(Config::default()).unwrap(),
681+
compiled_auto_splitter: RwLock::new(None),
679682
}
680683
}
681684

682685
/// Attempts to load a wasm file containing an auto splitter module.
683686
pub fn load(&self, path: PathBuf, timer: T) -> Result<(), Error> {
684687
let data = fs::read(path).map_err(|e| Error::ReadFileFailed { source: e })?;
685688

686-
let auto_splitter = self
689+
let compiled_auto_splitter = self
687690
.runtime
688691
.compile(&data)
689-
.map_err(|e| Error::LoadFailed { source: e })?
690-
.instantiate(Timer(timer), None, None)
692+
.map_err(|e| Error::LoadFailed { source: e })?;
693+
self.instantiate(&compiled_auto_splitter, timer)?;
694+
*self.compiled_auto_splitter.write().unwrap() = Some(compiled_auto_splitter);
695+
Ok(())
696+
}
697+
698+
/// Instantiates the compiled auto splitter.
699+
fn instantiate(
700+
&self,
701+
compiled_auto_splitter: &CompiledAutoSplitter,
702+
timer: T,
703+
) -> Result<(), Error> {
704+
let settings_map = timer.get_timer().run().auto_splitter_settings_map_load();
705+
let auto_splitter = compiled_auto_splitter
706+
.instantiate(Timer(timer), settings_map, None)
691707
.map_err(|e| Error::LoadFailed { source: e })?;
692708

693709
self.shared_state
@@ -710,6 +726,15 @@ impl<T: event::CommandSink + TimerQuery + Send + 'static> Runtime<T> {
710726
.map_err(|_| Error::ThreadStopped)
711727
}
712728

729+
/// Reloads the auto splitter without re-compiling.
730+
pub fn reload(&self, timer: T) -> Result<(), Error> {
731+
self.unload()?;
732+
if let Some(compiled_auto_splitter) = self.compiled_auto_splitter.read().unwrap().as_ref() {
733+
self.instantiate(compiled_auto_splitter, timer)?;
734+
}
735+
Ok(())
736+
}
737+
713738
/// Accesses a copy of the currently stored settings. The auto splitter can
714739
/// change these at any time. If you intend to make modifications to the
715740
/// settings, you need to set them again via

src/platform/no_std/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
mod time;
22
pub use self::time::*;
33

4+
#[allow(unused)]
45
pub struct RwLock<T>(core::cell::RefCell<T>);
56

7+
#[allow(unused)]
68
impl<T> RwLock<T> {
79
pub fn new(value: T) -> Self {
810
Self(core::cell::RefCell::new(value))

src/run/auto_splitter_settings.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
use crate::run::parser::livesplit::Version;
2+
use core::fmt::Debug;
3+
use livesplit_auto_splitting::settings;
4+
5+
#[derive(Debug, Default, Clone, PartialEq)]
6+
pub struct AutoSplitterSettings {
7+
pub version: Version,
8+
pub script_path: String,
9+
pub custom_settings: settings::Map,
10+
}
11+
12+
impl AutoSplitterSettings {
13+
pub fn set_version(&mut self, version: Version) {
14+
self.version = version;
15+
}
16+
17+
pub fn set_script_path(&mut self, script_path: String) {
18+
self.script_path = script_path;
19+
}
20+
21+
pub fn set_custom_settings(&mut self, custom_settings: settings::Map) {
22+
self.custom_settings = custom_settings;
23+
}
24+
}

src/run/mod.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
//! ```
1616
1717
mod attempt;
18+
19+
#[cfg(feature = "auto-splitting")]
20+
mod auto_splitter_settings;
1821
mod comparisons;
1922
pub mod editor;
2023
mod linked_layout;
@@ -35,6 +38,8 @@ pub use run_metadata::{CustomVariable, RunMetadata};
3538
pub use segment::Segment;
3639
pub use segment_history::SegmentHistory;
3740

41+
#[cfg(feature = "auto-splitting")]
42+
use crate::run::auto_splitter_settings::AutoSplitterSettings;
3843
use crate::{
3944
comparison::{default_generators, personal_best, ComparisonGenerator, RACE_COMPARISON_PREFIX},
4045
platform::prelude::*,
@@ -75,6 +80,8 @@ pub struct Run {
7580
custom_comparisons: Vec<String>,
7681
comparison_generators: ComparisonGenerators,
7782
auto_splitter_settings: String,
83+
#[cfg(feature = "auto-splitting")]
84+
parsed_auto_splitter_settings: Option<AutoSplitterSettings>,
7885
linked_layout: Option<LinkedLayout>,
7986
}
8087

@@ -128,6 +135,8 @@ impl Run {
128135
custom_comparisons: vec![personal_best::NAME.to_string()],
129136
comparison_generators: ComparisonGenerators(default_generators()),
130137
auto_splitter_settings: String::new(),
138+
#[cfg(feature = "auto-splitting")]
139+
parsed_auto_splitter_settings: None,
131140
linked_layout: None,
132141
}
133142
}
@@ -326,6 +335,40 @@ impl Run {
326335
&mut self.auto_splitter_settings
327336
}
328337

338+
/// Loads a copy of the Auto Splitter Settings as a settings map.
339+
#[inline]
340+
#[cfg(feature = "auto-splitting")]
341+
pub fn auto_splitter_settings_map_load(
342+
&self,
343+
) -> Option<livesplit_auto_splitting::settings::Map> {
344+
if let Some(p) = &self.parsed_auto_splitter_settings {
345+
return Some(p.custom_settings.clone());
346+
}
347+
None
348+
}
349+
350+
/// Stores a settings map into the parsed auto splitter settings.
351+
#[cfg(feature = "auto-splitting")]
352+
pub fn auto_splitter_settings_map_store(
353+
&mut self,
354+
settings_map: livesplit_auto_splitting::settings::Map,
355+
) {
356+
let p = &mut self.parsed_auto_splitter_settings;
357+
match p {
358+
None => {
359+
if settings_map.is_empty() {
360+
return;
361+
}
362+
let mut a = AutoSplitterSettings::default();
363+
a.set_custom_settings(settings_map);
364+
*p = Some(a);
365+
}
366+
Some(a) => {
367+
a.set_custom_settings(settings_map);
368+
}
369+
}
370+
}
371+
329372
/// Accesses the [`LinkedLayout`] of this `Run`. If a
330373
/// [`Layout`](crate::Layout) is linked, it is supposed to be loaded to
331374
/// visualize the `Run`.

0 commit comments

Comments
 (0)