Replace JSON with RON for persistence (epi/eframe/glium/web)
This commit is contained in:
parent
4fc3c6d375
commit
aba2108159
9 changed files with 55 additions and 40 deletions
17
Cargo.lock
generated
17
Cargo.lock
generated
|
@ -785,8 +785,8 @@ dependencies = [
|
||||||
"egui",
|
"egui",
|
||||||
"epi",
|
"epi",
|
||||||
"glium",
|
"glium",
|
||||||
|
"ron",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
|
||||||
"tts",
|
"tts",
|
||||||
"ureq",
|
"ureq",
|
||||||
"webbrowser",
|
"webbrowser",
|
||||||
|
@ -799,8 +799,8 @@ dependencies = [
|
||||||
"egui",
|
"egui",
|
||||||
"epi",
|
"epi",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
|
"ron",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
|
||||||
"tts",
|
"tts",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
|
@ -851,8 +851,8 @@ name = "epi"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"egui",
|
"egui",
|
||||||
|
"ron",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1865,6 +1865,17 @@ dependencies = [
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ron"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "064ea8613fb712a19faf920022ec8ddf134984f100090764a4e1d768f3827f1f"
|
||||||
|
dependencies = [
|
||||||
|
"base64",
|
||||||
|
"bitflags",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-demangle"
|
name = "rustc-demangle"
|
||||||
version = "0.1.18"
|
version = "0.1.18"
|
||||||
|
|
|
@ -30,8 +30,8 @@ ureq = { version = "2.0", optional = true }
|
||||||
|
|
||||||
# feature "persistence":
|
# feature "persistence":
|
||||||
directories-next = { version = "2", optional = true }
|
directories-next = { version = "2", optional = true }
|
||||||
|
ron = { version = "0.6", optional = true }
|
||||||
serde = { version = "1", optional = true }
|
serde = { version = "1", optional = true }
|
||||||
serde_json = { version = "1", optional = true }
|
|
||||||
|
|
||||||
# feature screen_reader
|
# feature screen_reader
|
||||||
tts = { version = "0.14", optional = true }
|
tts = { version = "0.14", optional = true }
|
||||||
|
@ -45,9 +45,8 @@ http = ["ureq"]
|
||||||
persistence = [
|
persistence = [
|
||||||
"directories-next",
|
"directories-next",
|
||||||
"egui/persistence",
|
"egui/persistence",
|
||||||
"epi/serde_json",
|
"epi/persistence",
|
||||||
"epi/serde",
|
"ron",
|
||||||
"serde_json",
|
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
time = ["chrono"] # for seconds_since_midnight
|
time = ["chrono"] # for seconds_since_midnight
|
||||||
|
|
|
@ -111,7 +111,7 @@ fn create_storage(app_name: &str) -> Option<Box<dyn epi::Storage>> {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
let mut config_dir = data_dir;
|
let mut config_dir = data_dir;
|
||||||
config_dir.push("app.json");
|
config_dir.push("app.ron");
|
||||||
let storage = crate::persistence::FileStorage::from_path(config_dir);
|
let storage = crate::persistence::FileStorage::from_path(config_dir);
|
||||||
Some(Box::new(storage))
|
Some(Box::new(storage))
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use std::{
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/// A key-value store backed by a JSON file on disk.
|
/// A key-value store backed by a [RON](https://github.com/ron-rs/ron) file on disk.
|
||||||
/// Used to restore egui state, glium window position/size and app state.
|
/// Used to restore egui state, glium window position/size and app state.
|
||||||
pub struct FileStorage {
|
pub struct FileStorage {
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
|
@ -17,7 +17,7 @@ impl FileStorage {
|
||||||
pub fn from_path(path: impl Into<PathBuf>) -> Self {
|
pub fn from_path(path: impl Into<PathBuf>) -> Self {
|
||||||
let path: PathBuf = path.into();
|
let path: PathBuf = path.into();
|
||||||
Self {
|
Self {
|
||||||
kv: read_json(&path).unwrap_or_default(),
|
kv: read_ron(&path).unwrap_or_default(),
|
||||||
path,
|
path,
|
||||||
dirty: false,
|
dirty: false,
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,9 @@ impl epi::Storage for FileStorage {
|
||||||
fn flush(&mut self) {
|
fn flush(&mut self) {
|
||||||
if self.dirty {
|
if self.dirty {
|
||||||
// eprintln!("Persisted to {}", self.path.display());
|
// eprintln!("Persisted to {}", self.path.display());
|
||||||
serde_json::to_writer(std::fs::File::create(&self.path).unwrap(), &self.kv).unwrap();
|
let file = std::fs::File::create(&self.path).unwrap();
|
||||||
|
let config = Default::default();
|
||||||
|
ron::ser::to_writer_pretty(file, &self.kv, config).unwrap();
|
||||||
self.dirty = false;
|
self.dirty = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,17 +49,17 @@ impl epi::Storage for FileStorage {
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
pub fn read_json<T>(json_path: impl AsRef<Path>) -> Option<T>
|
pub fn read_ron<T>(ron_path: impl AsRef<Path>) -> Option<T>
|
||||||
where
|
where
|
||||||
T: serde::de::DeserializeOwned,
|
T: serde::de::DeserializeOwned,
|
||||||
{
|
{
|
||||||
match std::fs::File::open(json_path) {
|
match std::fs::File::open(ron_path) {
|
||||||
Ok(file) => {
|
Ok(file) => {
|
||||||
let reader = std::io::BufReader::new(file);
|
let reader = std::io::BufReader::new(file);
|
||||||
match serde_json::from_reader(reader) {
|
match ron::de::from_reader(reader) {
|
||||||
Ok(value) => Some(value),
|
Ok(value) => Some(value),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
eprintln!("ERROR: Failed to parse json: {}", err);
|
eprintln!("ERROR: Failed to parse RON: {}", err);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,8 +73,8 @@ where
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/// Alternative to `FileStorage`
|
/// Alternative to `FileStorage`
|
||||||
pub fn read_memory(ctx: &egui::Context, memory_json_path: impl AsRef<std::path::Path>) {
|
pub fn read_memory(ctx: &egui::Context, memory_file_path: impl AsRef<std::path::Path>) {
|
||||||
let memory: Option<egui::Memory> = read_json(memory_json_path);
|
let memory: Option<egui::Memory> = read_ron(memory_file_path);
|
||||||
if let Some(memory) = memory {
|
if let Some(memory) = memory {
|
||||||
*ctx.memory() = memory;
|
*ctx.memory() = memory;
|
||||||
}
|
}
|
||||||
|
@ -81,8 +83,10 @@ pub fn read_memory(ctx: &egui::Context, memory_json_path: impl AsRef<std::path::
|
||||||
/// Alternative to `FileStorage`
|
/// Alternative to `FileStorage`
|
||||||
pub fn write_memory(
|
pub fn write_memory(
|
||||||
ctx: &egui::Context,
|
ctx: &egui::Context,
|
||||||
memory_json_path: impl AsRef<std::path::Path>,
|
memory_file_path: impl AsRef<std::path::Path>,
|
||||||
) -> Result<(), Box<dyn std::error::Error>> {
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
serde_json::to_writer_pretty(std::fs::File::create(memory_json_path)?, &*ctx.memory())?;
|
let file = std::fs::File::create(memory_file_path)?;
|
||||||
|
let ron_config = Default::default();
|
||||||
|
ron::ser::to_writer_pretty(file, &*ctx.memory(), ron_config)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,10 +10,8 @@ pub struct WindowSettings {
|
||||||
|
|
||||||
impl WindowSettings {
|
impl WindowSettings {
|
||||||
#[cfg(feature = "persistence")]
|
#[cfg(feature = "persistence")]
|
||||||
pub fn from_json_file(
|
pub fn from_ron_file(settings_ron_path: impl AsRef<std::path::Path>) -> Option<WindowSettings> {
|
||||||
settings_json_path: impl AsRef<std::path::Path>,
|
crate::persistence::read_ron(settings_ron_path)
|
||||||
) -> Option<WindowSettings> {
|
|
||||||
crate::persistence::read_json(settings_json_path)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_display(display: &glium::Display) -> Self {
|
pub fn from_display(display: &glium::Display) -> Self {
|
||||||
|
|
|
@ -25,8 +25,8 @@ crate-type = ["cdylib", "rlib"]
|
||||||
egui = { version = "0.10.0", path = "../egui" }
|
egui = { version = "0.10.0", path = "../egui" }
|
||||||
epi = { version = "0.10.0", path = "../epi" }
|
epi = { version = "0.10.0", path = "../epi" }
|
||||||
js-sys = "0.3"
|
js-sys = "0.3"
|
||||||
|
ron = { version = "0.6", optional = true }
|
||||||
serde = { version = "1", optional = true }
|
serde = { version = "1", optional = true }
|
||||||
serde_json = { version = "1", optional = true }
|
|
||||||
tts = { version = "0.14", optional = true } # feature screen_reader
|
tts = { version = "0.14", optional = true } # feature screen_reader
|
||||||
wasm-bindgen = "0.2"
|
wasm-bindgen = "0.2"
|
||||||
wasm-bindgen-futures = "0.4"
|
wasm-bindgen-futures = "0.4"
|
||||||
|
@ -41,7 +41,7 @@ http = [
|
||||||
"web-sys/RequestMode",
|
"web-sys/RequestMode",
|
||||||
"web-sys/Response",
|
"web-sys/Response",
|
||||||
]
|
]
|
||||||
persistence = ["egui/persistence", "serde", "serde_json"]
|
persistence = ["egui/persistence", "ron", "serde"]
|
||||||
screen_reader = ["tts"] # experimental
|
screen_reader = ["tts"] # experimental
|
||||||
|
|
||||||
[dependencies.web-sys]
|
[dependencies.web-sys]
|
||||||
|
|
|
@ -189,13 +189,13 @@ pub fn local_storage_remove(key: &str) {
|
||||||
|
|
||||||
#[cfg(feature = "persistence")]
|
#[cfg(feature = "persistence")]
|
||||||
pub fn load_memory(ctx: &egui::Context) {
|
pub fn load_memory(ctx: &egui::Context) {
|
||||||
if let Some(memory_string) = local_storage_get("egui_memory_json") {
|
if let Some(memory_string) = local_storage_get("egui_memory_ron") {
|
||||||
match serde_json::from_str(&memory_string) {
|
match ron::from_str(&memory_string) {
|
||||||
Ok(memory) => {
|
Ok(memory) => {
|
||||||
*ctx.memory() = memory;
|
*ctx.memory() = memory;
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
console_error(format!("Failed to parse memory json: {}", err));
|
console_error(format!("Failed to parse memory RON: {}", err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -206,12 +206,12 @@ pub fn load_memory(_: &egui::Context) {}
|
||||||
|
|
||||||
#[cfg(feature = "persistence")]
|
#[cfg(feature = "persistence")]
|
||||||
pub fn save_memory(ctx: &egui::Context) {
|
pub fn save_memory(ctx: &egui::Context) {
|
||||||
match serde_json::to_string(&*ctx.memory()) {
|
match ron::to_string(&*ctx.memory()) {
|
||||||
Ok(json) => {
|
Ok(ron) => {
|
||||||
local_storage_set("egui_memory_json", &json);
|
local_storage_set("egui_memory_ron", &ron);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
console_error(format!("Failed to serialize memory as json: {}", err));
|
console_error(format!("Failed to serialize memory as RON: {}", err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,10 +21,10 @@ include = [
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
egui = { version = "0.10.0", path = "../egui" }
|
egui = { version = "0.10.0", path = "../egui" }
|
||||||
|
ron = { version = "0.6", optional = true }
|
||||||
serde = { version = "1", optional = true }
|
serde = { version = "1", optional = true }
|
||||||
serde_json = { version = "1", optional = true }
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
http = []
|
http = []
|
||||||
persistence = ["serde", "serde_json"]
|
persistence = ["ron", "serde"]
|
||||||
|
|
|
@ -294,18 +294,21 @@ impl Storage for DummyStorage {
|
||||||
fn flush(&mut self) {}
|
fn flush(&mut self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an deserialize the JSON stored at the given key.
|
/// Get an deserialize the [RON](https://github.com/ron-rs/ron] stored at the given key.
|
||||||
#[cfg(feature = "serde_json")]
|
#[cfg(feature = "ron")]
|
||||||
pub fn get_value<T: serde::de::DeserializeOwned>(storage: &dyn Storage, key: &str) -> Option<T> {
|
pub fn get_value<T: serde::de::DeserializeOwned>(storage: &dyn Storage, key: &str) -> Option<T> {
|
||||||
storage
|
storage
|
||||||
.get_string(key)
|
.get_string(key)
|
||||||
.and_then(|value| serde_json::from_str(&value).ok())
|
.and_then(|value| ron::from_str(&value).ok())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Serialize the given value as JSON and store with the given key.
|
/// Serialize the given value as [RON](https://github.com/ron-rs/ron] and store with the given key.
|
||||||
#[cfg(feature = "serde_json")]
|
#[cfg(feature = "ron")]
|
||||||
pub fn set_value<T: serde::Serialize>(storage: &mut dyn Storage, key: &str, value: &T) {
|
pub fn set_value<T: serde::Serialize>(storage: &mut dyn Storage, key: &str, value: &T) {
|
||||||
storage.set_string(key, serde_json::to_string_pretty(value).unwrap());
|
storage.set_string(
|
||||||
|
key,
|
||||||
|
ron::ser::to_string_pretty(value, Default::default()).unwrap(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// [`Storage`] key used for app
|
/// [`Storage`] key used for app
|
||||||
|
|
Loading…
Reference in a new issue