Store persistent fields as plain JSON strings
On second thought, this is much better. The resulting file size will be much smaller because only double quotes need to be escaped. It's also easier to read at a glance.
This commit is contained in:
parent
3111d75b29
commit
6494d1ed5f
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -8,12 +8,6 @@ version = "1.0.53"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "94a45b455c14666b85fc40a019e8ab9eb75e3a124e05494f5397122bc9eb06e0"
|
checksum = "94a45b455c14666b85fc40a019e8ab9eb75e3a124e05494f5397122bc9eb06e0"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "base64"
|
|
||||||
version = "0.13.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gain"
|
name = "gain"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -37,7 +31,6 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
name = "nih_plug"
|
name = "nih_plug"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"nih_plug_derive",
|
"nih_plug_derive",
|
||||||
"serde",
|
"serde",
|
||||||
|
|
|
@ -10,7 +10,6 @@ members = ["nih_plug_derive", "plugins/gain", "xtask"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
nih_plug_derive = { path = "nih_plug_derive" }
|
nih_plug_derive = { path = "nih_plug_derive" }
|
||||||
base64 = "0.13"
|
|
||||||
lazy_static = "1.4"
|
lazy_static = "1.4"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
|
|
|
@ -158,7 +158,7 @@ pub fn derive_params(input: TokenStream) -> TokenStream {
|
||||||
param_map
|
param_map
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_fields(&self) -> ::std::collections::HashMap<String, Vec<u8>> {
|
fn serialize_fields(&self) -> ::std::collections::HashMap<String, String> {
|
||||||
let mut serialized = ::std::collections::HashMap::new();
|
let mut serialized = ::std::collections::HashMap::new();
|
||||||
|
|
||||||
#(#field_serialize_tokens)*
|
#(#field_serialize_tokens)*
|
||||||
|
@ -166,7 +166,7 @@ pub fn derive_params(input: TokenStream) -> TokenStream {
|
||||||
serialized
|
serialized
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_fields(&self, serialized: &::std::collections::HashMap<String, Vec<u8>>) {
|
fn deserialize_fields(&self, serialized: &::std::collections::HashMap<String, String>) {
|
||||||
for (field_name, data) in serialized {
|
for (field_name, data) in serialized {
|
||||||
match field_name.as_str() {
|
match field_name.as_str() {
|
||||||
#(#field_deserialize_tokens)*
|
#(#field_deserialize_tokens)*
|
||||||
|
|
|
@ -25,9 +25,9 @@ pub type FloatParam = PlainParam<f32>;
|
||||||
pub type IntParam = PlainParam<i32>;
|
pub type IntParam = PlainParam<i32>;
|
||||||
|
|
||||||
/// Re-export for use in the [Params] proc-macro.
|
/// Re-export for use in the [Params] proc-macro.
|
||||||
pub use serde_json::from_slice as deserialize_field;
|
pub use serde_json::from_str as deserialize_field;
|
||||||
/// Re-export for use in the [Params] proc-macro.
|
/// Re-export for use in the [Params] proc-macro.
|
||||||
pub use serde_json::to_vec as serialize_field;
|
pub use serde_json::to_string as serialize_field;
|
||||||
|
|
||||||
/// The functinoality needed for persisting a field to the plugin's state, and for restoring values
|
/// The functinoality needed for persisting a field to the plugin's state, and for restoring values
|
||||||
/// when loading old state.
|
/// when loading old state.
|
||||||
|
@ -357,13 +357,13 @@ pub trait Params {
|
||||||
/// Serialize all fields marked with `#[persist = "stable_name"]` into a hash map containing
|
/// Serialize all fields marked with `#[persist = "stable_name"]` into a hash map containing
|
||||||
/// JSON-representations of those fields so they can be written to the plugin's state and
|
/// JSON-representations of those fields so they can be written to the plugin's state and
|
||||||
/// recalled later. This uses [serialize_field] under the hood.
|
/// recalled later. This uses [serialize_field] under the hood.
|
||||||
fn serialize_fields(&self) -> HashMap<String, Vec<u8>>;
|
fn serialize_fields(&self) -> HashMap<String, String>;
|
||||||
|
|
||||||
/// Restore all fields marked with `#[persist = "stable_name"]` from a hashmap created by
|
/// Restore all fields marked with `#[persist = "stable_name"]` from a hashmap created by
|
||||||
/// [Self::serialize_fields]. All of thse fields should be wrapped in a [PersistentField] with
|
/// [Self::serialize_fields]. All of thse fields should be wrapped in a [PersistentField] with
|
||||||
/// thread safe interior mutability, like an `RwLock` or a `Mutex`. This gets called when the
|
/// thread safe interior mutability, like an `RwLock` or a `Mutex`. This gets called when the
|
||||||
/// plugin's state is being restored. This uses [deserialize_field] under the hood.
|
/// plugin's state is being restored. This uses [deserialize_field] under the hood.
|
||||||
fn deserialize_fields(&self, serialized: &HashMap<String, Vec<u8>>);
|
fn deserialize_fields(&self, serialized: &HashMap<String, String>);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Internal pointers to parameters. This is an implementation detail used by the wrappers.
|
/// Internal pointers to parameters. This is an implementation detail used by the wrappers.
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
//! Utilities for saving a [crate::plugin::Plugin]'s state.
|
//! Utilities for saving a [crate::plugin::Plugin]'s state.
|
||||||
|
|
||||||
use serde::de::Error;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
@ -40,38 +39,7 @@ pub(crate) struct State {
|
||||||
/// on the [Params] struct that's annotated with `#[persist = "stable_name"]` will be persisted
|
/// on the [Params] struct that's annotated with `#[persist = "stable_name"]` will be persisted
|
||||||
/// this way.
|
/// this way.
|
||||||
///
|
///
|
||||||
/// The individual JSON-serialized fields are encoded as base64 strings so they don't take up as
|
/// The individual fields are also serialized as JSON so they can safely be restored
|
||||||
/// much space in the preset. Storing them as a plain JSON string would have also been possible,
|
/// independently of the other fields.
|
||||||
/// but that can get messy with escaping since those will likely also contain double quotes.
|
pub fields: HashMap<String, String>,
|
||||||
#[serde(serialize_with = "encode_fields")]
|
|
||||||
#[serde(deserialize_with = "decode_fields")]
|
|
||||||
pub fields: HashMap<String, Vec<u8>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn encode_fields<S>(bytes: &HashMap<String, Vec<u8>>, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: serde::Serializer,
|
|
||||||
{
|
|
||||||
serializer.collect_map(
|
|
||||||
bytes
|
|
||||||
.into_iter()
|
|
||||||
.map(|(id, json)| (id, base64::encode(json))),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn decode_fields<'de, D>(deserializer: D) -> Result<HashMap<String, Vec<u8>>, D::Error>
|
|
||||||
where
|
|
||||||
D: serde::Deserializer<'de>,
|
|
||||||
{
|
|
||||||
let base64_map: HashMap<String, String> = HashMap::deserialize(deserializer)?;
|
|
||||||
let decoded_map: Result<HashMap<String, Vec<u8>>, D::Error> = base64_map
|
|
||||||
.into_iter()
|
|
||||||
.map(|(id, base64)| {
|
|
||||||
base64::decode(base64)
|
|
||||||
.map(|decoded| (id, decoded))
|
|
||||||
.map_err(|err| D::Error::custom(format!("base64 decode failed: {}", err)))
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Ok(decoded_map?)
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue