Skip to content

Commit c7b0905

Browse files
committed
Little refactor of persistent library
1 parent eca22fd commit c7b0905

File tree

14 files changed

+84
-75
lines changed

14 files changed

+84
-75
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ members = [
2222
"midi-udp-widgets-app-lib",
2323
"modules",
2424
"patches",
25-
"persistent",
25+
"persist",
2626
"player",
2727
"sdl2",
2828
"utils",
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[package]
2-
name = "caw_persistent"
2+
name = "caw_persist"
33
version = "0.1.0"
44
edition = "2024"
55
description = "Helpers for persisting data within the CAW synthesizer framework"
Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -75,51 +75,63 @@ where
7575
}
7676
}
7777

78-
/// The type itself knows how to save and load itself
79-
pub trait PersistentData: Serialize + for<'a> Deserialize<'a> {
80-
const NAME: &'static str;
78+
/// Implement this when there may be multiple different directories where values of the type will
79+
/// be persisted. It's probably more convenient to just use the `&'static str` impl of this trait
80+
/// in such a case.
81+
pub trait Persist<T>
82+
where
83+
T: Serialize + for<'a> Deserialize<'a>,
84+
{
85+
fn name(&self) -> &'static str;
8186

82-
fn save(&self, title: impl AsRef<str>) -> anyhow::Result<()> {
83-
save(Self::NAME, self, title)
87+
fn save(&self, data: &T, title: impl AsRef<str>) -> anyhow::Result<()> {
88+
save(self.name(), data, title)
8489
}
8590

8691
/// Like `save` but prints a warning on failure rather than returning an error value.
87-
fn save_(&self, title: impl AsRef<str>) {
88-
save_(Self::NAME, self, title)
92+
fn save_(&self, data: &T, title: impl AsRef<str>) {
93+
save_(self.name(), data, title)
8994
}
9095

91-
fn load(title: impl AsRef<str>) -> anyhow::Result<Self> {
92-
load(Self::NAME, title)
96+
fn load(&self, title: impl AsRef<str>) -> anyhow::Result<T> {
97+
load(self.name(), title)
9398
}
9499

95100
/// Like `load` but prints a warning on failure rather than returning an error value.
96-
fn load_(title: impl AsRef<str>) -> Option<Self> {
97-
load_(Self::NAME, title)
101+
fn load_(&self, title: impl AsRef<str>) -> Option<T> {
102+
load_(self.name(), title)
98103
}
99104
}
100105

101-
/// Knows how to save and load some type `T`
102-
pub trait PersistentWitness<T>
106+
impl<T> Persist<T> for &'static str
103107
where
104108
T: Serialize + for<'a> Deserialize<'a>,
105109
{
110+
fn name(&self) -> &'static str {
111+
self
112+
}
113+
}
114+
115+
/// Implement this when the type uniquely determines the directory where values of that type will
116+
/// be persisted.
117+
pub trait PersistData: Serialize + for<'a> Deserialize<'a> {
106118
const NAME: &'static str;
107119

108-
fn save(&self, data: &T, title: impl AsRef<str>) -> anyhow::Result<()> {
109-
save(Self::NAME, data, title)
120+
fn save(&self, title: impl AsRef<str>) -> anyhow::Result<()> {
121+
Self::NAME.save(self, title)
110122
}
111123

112124
/// Like `save` but prints a warning on failure rather than returning an error value.
113-
fn save_(&self, data: &T, title: impl AsRef<str>) {
114-
save_(Self::NAME, data, title)
125+
fn save_(&self, title: impl AsRef<str>) {
126+
Self::NAME.save_(self, title)
115127
}
116128

117-
fn load(&self, title: impl AsRef<str>) -> anyhow::Result<T> {
118-
load(Self::NAME, title)
129+
fn load(title: impl AsRef<str>) -> anyhow::Result<Self> {
130+
Self::NAME.load(title)
119131
}
120132

121133
/// Like `load` but prints a warning on failure rather than returning an error value.
122-
fn load_(&self, title: impl AsRef<str>) -> Option<T> {
123-
load_(Self::NAME, title)
134+
fn load_(title: impl AsRef<str>) -> Option<Self> {
135+
Self::NAME.load_(title)
124136
}
125137
}

utils/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ web = ["getrandom/wasm_js"]
1616
caw_core = { version = "0.5", path = "../core" }
1717
caw_builder_proc_macros = { version = "0.1", path = "../builder-proc-macros" }
1818
serde = { version = "1.0", features = ["serde_derive"] }
19-
caw_persistent = { version = "0.1", path = "../persistent" }
19+
caw_persist = { version = "0.1", path = "../persist" }
2020
rand = "0.9"
2121
getrandom = "0.3"
2222
itertools = "0.14"

utils/src/looper.rs

Lines changed: 32 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use caw_builder_proc_macros::builder;
22
use caw_core::{Buf, Sig, SigCtx, SigT};
3-
use caw_persistent::PersistentWitness;
3+
use caw_persist::Persist;
44
use itertools::izip;
55
use serde::{Deserialize, Serialize};
66

@@ -42,54 +42,51 @@ impl<T> Sequence<T> {
4242
}
4343
}
4444

45-
struct KeyLooperPersistentWitness;
46-
impl<T> PersistentWitness<Sequence<Option<T>>> for KeyLooperPersistentWitness
47-
where
48-
T: Serialize + for<'a> Deserialize<'a>,
49-
{
50-
const NAME: &'static str = "key_looper";
51-
}
45+
const KEY_LOOPER_PERSIST: &'static str = "key_looper";
5246

53-
pub trait KeyLooperPersist<T> {
47+
/// Driver for saving and loading a sequence state to a file.
48+
pub trait KeyLooperIo<T> {
5449
fn load(&self) -> Sequence<Option<T>>;
5550
fn save(&self, sequence: &Sequence<Option<T>>);
5651
}
5752

58-
pub struct KeyLooperPersistNone;
59-
impl<T> KeyLooperPersist<T> for KeyLooperPersistNone {
53+
/// Implementation of `KeyLooperIo` which doesn't actually save or load any data.
54+
pub struct KeyLooperIoNull;
55+
impl<T> KeyLooperIo<T> for KeyLooperIoNull {
6056
fn load(&self) -> Sequence<Option<T>> {
6157
Sequence::new_with(1, || None)
6258
}
6359

6460
fn save(&self, _sequence: &Sequence<Option<T>>) {}
6561
}
6662

67-
pub struct KeyLooperPersistWithName(pub String);
68-
impl<T> KeyLooperPersist<T> for KeyLooperPersistWithName
63+
/// Implementation of `KeyLooperIo` which saves state into a file of a given name.
64+
pub struct KeyLooperIoWithName(pub String);
65+
impl<T> KeyLooperIo<T> for KeyLooperIoWithName
6966
where
7067
T: Serialize + for<'a> Deserialize<'a>,
7168
{
7269
fn load(&self) -> Sequence<Option<T>> {
73-
if let Some(sequence) = KeyLooperPersistentWitness.load_(&self.0) {
70+
if let Some(sequence) = KEY_LOOPER_PERSIST.load_(&self.0) {
7471
sequence
7572
} else {
7673
Sequence::new_with(1, || None)
7774
}
7875
}
7976

8077
fn save(&self, sequence: &Sequence<Option<T>>) {
81-
KeyLooperPersistentWitness.save_(sequence, &self.0)
78+
KEY_LOOPER_PERSIST.save_(sequence, &self.0)
8279
}
8380
}
8481

85-
pub struct KeyLooper<X, S, T, C, N, P>
82+
pub struct KeyLooper<X, S, T, C, N, I>
8683
where
8784
X: Clone,
8885
S: SigT<Item = Option<X>>,
8986
T: SigT<Item = bool>,
9087
C: SigT<Item = bool>,
9188
N: SigT<Item = u32>,
92-
P: KeyLooperPersist<X>,
89+
I: KeyLooperIo<X>,
9390
{
9491
sig: S,
9592
last_value: Option<X>,
@@ -98,17 +95,17 @@ where
9895
length: N,
9996
sequence: Sequence<S::Item>,
10097
buf: Vec<S::Item>,
101-
persist: P,
98+
io: I,
10299
}
103100

104-
impl<X, S, T, C, N, P> SigT for KeyLooper<X, S, T, C, N, P>
101+
impl<X, S, T, C, N, I> SigT for KeyLooper<X, S, T, C, N, I>
105102
where
106103
X: Clone,
107104
S: SigT<Item = Option<X>>,
108105
T: SigT<Item = bool>,
109106
C: SigT<Item = bool>,
110107
N: SigT<Item = u32>,
111-
P: KeyLooperPersist<X>,
108+
I: KeyLooperIo<X>,
112109
{
113110
type Item = S::Item;
114111

@@ -144,31 +141,31 @@ where
144141
*out = self.sequence.current().clone();
145142
}
146143
if changed_this_frame {
147-
self.persist.save(&self.sequence);
144+
self.io.save(&self.sequence);
148145
}
149146
&self.buf
150147
}
151148
}
152149

153-
impl<X, S, T, C, N, P> KeyLooper<X, S, T, C, N, P>
150+
impl<X, S, T, C, N, I> KeyLooper<X, S, T, C, N, I>
154151
where
155152
X: Clone,
156153
S: SigT<Item = Option<X>>,
157154
T: SigT<Item = bool>,
158155
C: SigT<Item = bool>,
159156
N: SigT<Item = u32>,
160-
P: KeyLooperPersist<X>,
157+
I: KeyLooperIo<X>,
161158
{
162-
fn new(sig: S, tick: T, clearing: C, length: N, persist: P) -> Sig<Self> {
159+
fn new(sig: S, tick: T, clearing: C, length: N, io: I) -> Sig<Self> {
163160
Sig(KeyLooper {
164161
sig,
165162
last_value: None,
166163
tick,
167164
clearing,
168165
length,
169-
sequence: persist.load(),
166+
sequence: io.load(),
170167
buf: Vec::new(),
171-
persist,
168+
io,
172169
})
173170
}
174171
}
@@ -178,7 +175,7 @@ builder! {
178175
#[constructor_doc = "A looper for key presses"]
179176
#[generic_setter_type_name = "X"]
180177
#[build_fn = "KeyLooper::new"]
181-
#[build_ty = "Sig<KeyLooper<V, S, T, C, N, P>>"]
178+
#[build_ty = "Sig<KeyLooper<V, S, T, C, N, I>>"]
182179
#[extra_generic("V", "Clone")]
183180
pub struct KeyLooperBuilder {
184181
#[generic_with_constraint = "SigT<Item = Option<V>>"]
@@ -195,26 +192,26 @@ builder! {
195192
#[generic_name = "N"]
196193
#[default = 16]
197194
length: u32,
198-
#[generic_with_constraint = "KeyLooperPersist<V>"]
199-
#[default = KeyLooperPersistNone]
200-
#[generic_name = "P"]
201-
persist: KeyLooperPersistNone,
195+
#[generic_with_constraint = "KeyLooperIo<V>"]
196+
#[default = KeyLooperIoNull]
197+
#[generic_name = "I"]
198+
io: KeyLooperIoNull,
202199
}
203200
}
204201

205-
impl<X, S, T, C, N, P> KeyLooperBuilder<X, S, T, C, N, P>
202+
impl<X, S, T, C, N, I> KeyLooperBuilder<X, S, T, C, N, I>
206203
where
207204
X: Clone + Serialize + for<'a> Deserialize<'a>,
208205
S: SigT<Item = Option<X>>,
209206
T: SigT<Item = bool>,
210207
C: SigT<Item = bool>,
211208
N: SigT<Item = u32>,
212-
P: KeyLooperPersist<X>,
209+
I: KeyLooperIo<X>,
213210
{
214211
pub fn persist_with_name(
215212
self,
216213
name: impl AsRef<str>,
217-
) -> KeyLooperBuilder<X, S, T, C, N, KeyLooperPersistWithName> {
214+
) -> KeyLooperBuilder<X, S, T, C, N, KeyLooperIoWithName> {
218215
let Self {
219216
sig,
220217
trig,
@@ -227,7 +224,7 @@ where
227224
trig,
228225
clearing,
229226
length,
230-
persist: KeyLooperPersistWithName(name.as_ref().to_string()),
227+
io: KeyLooperIoWithName(name.as_ref().to_string()),
231228
}
232229
}
233230
}

viz-udp-app/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ clap = { version = "4", features = ["derive"] }
1717
caw_viz_udp_app_lib = { version = "0.1", path = "../viz-udp-app-lib" }
1818
log = "0.4"
1919
caw_window_utils = { version = "0.1", path = "../window-utils" }
20-
caw_persistent = { version = "0.1", path = "../persistent" }
20+
caw_persist = { version = "0.1", path = "../persist" }
2121
serde = { version = "1.0", features = ["serde_derive"] }
2222
rgb_int = "0.1"

viz-udp-app/src/main.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
/// A udp client which receives visualization data from a corresponding udp server and renders
22
/// visualizations in a graphical window.
33
use anyhow::anyhow;
4-
use caw_persistent::PersistentData;
4+
use caw_persist::PersistData;
55
use caw_viz_udp_app_lib::{blink, oscilloscope};
66
use caw_window_utils::{
77
font::load_font,
8-
persistent::{WindowPosition, WindowSize},
8+
persist::{WindowPosition, WindowSize},
99
};
1010
use clap::{Parser, Subcommand, ValueEnum};
1111
use line_2d::Coord;
@@ -114,7 +114,7 @@ struct OscilloscopeUiState {
114114
alpha_scale: u8,
115115
}
116116

117-
impl PersistentData for OscilloscopeUiState {
117+
impl PersistData for OscilloscopeUiState {
118118
const NAME: &'static str = "oscilloscope_ui";
119119
}
120120

widgets/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ caw_computer_keyboard = { version = "0.4", path = "../computer-keyboard" }
1818
caw_keyboard = { version = "0.4", path = "../keyboard" }
1919
caw_sdl2 = { version = "0.1", path = "../sdl2" }
2020
caw_window_utils = { version = "0.1", path = "../window-utils" }
21-
caw_persistent = { version = "0.1", path = "../persistent" }
21+
caw_persist = { version = "0.1", path = "../persist" }
2222
itertools = "0.14"
2323
log = "0.4"
2424
serde = { version = "1.0", features = ["serde_derive"] }

widgets/src/knob.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::window::{TitlePosition, Window};
22
use anyhow::anyhow;
3-
use caw_persistent::PersistentData;
3+
use caw_persist::PersistData;
44
use line_2d::Coord;
55
use midly::num::u7;
66
use sdl2::{
@@ -20,7 +20,7 @@ struct State {
2020
value_01: f32,
2121
}
2222

23-
impl PersistentData for State {
23+
impl PersistData for State {
2424
const NAME: &'static str = "knob_state";
2525
}
2626

widgets/src/window.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use anyhow::anyhow;
2-
use caw_persistent::PersistentData;
2+
use caw_persist::PersistData;
33
use caw_window_utils::{
44
font::{Font, load_font},
5-
persistent::WindowPosition,
5+
persist::WindowPosition,
66
};
77
use sdl2::{
88
EventPump,

0 commit comments

Comments
 (0)