Use BTreeMaps in the state
This ensures that the order is consistent when saving the same state file multiple times.
This commit is contained in:
parent
71efe779a5
commit
5e6e920418
|
@ -6,6 +6,14 @@ new and what's changed, this document lists all breaking changes in reverse
|
||||||
chronological order. If a new feature did not require any changes to existing
|
chronological order. If a new feature did not require any changes to existing
|
||||||
code then it will not be listed here.
|
code then it will not be listed here.
|
||||||
|
|
||||||
|
## [2022-07-02]
|
||||||
|
|
||||||
|
- The `Params::serialize_fields()` and `Params::deserialize_fields()` methods
|
||||||
|
and the `State` struct now use `BTreeMap`s instead of `HashMap`s so the order
|
||||||
|
is consistent the plugin's state to JSON multiple times. These things are part
|
||||||
|
of NIH-plug's internals, so unless you're implementing the `Params` trait by
|
||||||
|
hand you will not notice any changes.
|
||||||
|
|
||||||
## [2022-06-01]
|
## [2022-06-01]
|
||||||
|
|
||||||
- The `ClapPlugin::CLAP_FEATURES` field now uses an array of `ClapFeature`
|
- The `ClapPlugin::CLAP_FEATURES` field now uses an array of `ClapFeature`
|
||||||
|
|
|
@ -255,8 +255,8 @@ pub fn derive_params(input: TokenStream) -> TokenStream {
|
||||||
param_map
|
param_map
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_fields(&self) -> ::std::collections::HashMap<String, String> {
|
fn serialize_fields(&self) -> ::std::collections::BTreeMap<String, String> {
|
||||||
let mut serialized = ::std::collections::HashMap::new();
|
let mut serialized = ::std::collections::BTreeMap::new();
|
||||||
#(#field_serialize_tokens)*
|
#(#field_serialize_tokens)*
|
||||||
|
|
||||||
let nested_params_fields: &[&dyn Params] = &[#(&self.#nested_params_field_idents),*];
|
let nested_params_fields: &[&dyn Params] = &[#(&self.#nested_params_field_idents),*];
|
||||||
|
@ -267,7 +267,7 @@ pub fn derive_params(input: TokenStream) -> TokenStream {
|
||||||
serialized
|
serialized
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_fields(&self, serialized: &::std::collections::HashMap<String, String>) {
|
fn deserialize_fields(&self, serialized: &::std::collections::BTreeMap<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)*
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! Implementation details for the parameter management.
|
//! Implementation details for the parameter management.
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use super::{Param, ParamFlags, ParamMut};
|
use super::{Param, ParamFlags, ParamMut};
|
||||||
|
|
||||||
|
@ -59,8 +59,8 @@ pub unsafe trait Params: 'static + Send + Sync {
|
||||||
/// 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, String> {
|
fn serialize_fields(&self) -> BTreeMap<String, String> {
|
||||||
HashMap::new()
|
BTreeMap::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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
|
||||||
|
@ -69,7 +69,7 @@ pub unsafe trait Params: 'static + Send + Sync {
|
||||||
/// This gets called when the plugin's state is being restored. This uses [deserialize_field()]
|
/// This gets called when the plugin's state is being restored. This uses [deserialize_field()]
|
||||||
/// under the hood.
|
/// under the hood.
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn deserialize_fields(&self, serialized: &HashMap<String, String>) {}
|
fn deserialize_fields(&self, serialized: &BTreeMap<String, String>) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Internal pointers to parameters. This is an implementation detail used by the wrappers for type
|
/// Internal pointers to parameters. This is an implementation detail used by the wrappers for type
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
//! to plugins through the [`GuiContext`][crate::prelude::GuiContext].
|
//! to plugins through the [`GuiContext`][crate::prelude::GuiContext].
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::{BTreeMap, HashMap};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::param::internals::{ParamPtr, Params};
|
use crate::param::internals::{ParamPtr, Params};
|
||||||
|
@ -25,19 +25,21 @@ pub enum ParamValue {
|
||||||
|
|
||||||
/// A plugin's state so it can be restored at a later point. This object can be serialized and
|
/// A plugin's state so it can be restored at a later point. This object can be serialized and
|
||||||
/// deserialized using serde.
|
/// deserialized using serde.
|
||||||
|
///
|
||||||
|
/// The fields are stored as `BTreeMap`s so the order in the serialized file is consistent.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct PluginState {
|
pub struct PluginState {
|
||||||
/// The plugin's parameter values. These are stored unnormalized. This mean sthe old values will
|
/// The plugin's parameter values. These are stored unnormalized. This mean sthe old values will
|
||||||
/// be recalled when when the parameter's range gets increased. Doing so may still mess with
|
/// be recalled when when the parameter's range gets increased. Doing so may still mess with
|
||||||
/// parameter automation though, depending on how the host impelments that.
|
/// parameter automation though, depending on how the host impelments that.
|
||||||
pub params: HashMap<String, ParamValue>,
|
pub params: BTreeMap<String, ParamValue>,
|
||||||
/// Arbitrary fields that should be persisted together with the plugin's parameters. Any field
|
/// Arbitrary fields that should be persisted together with the plugin's parameters. Any field
|
||||||
/// on the [`Params`][crate::param::internals::Params] struct that's annotated with `#[persist =
|
/// on the [`Params`][crate::param::internals::Params] struct that's annotated with `#[persist =
|
||||||
/// "stable_name"]` will be persisted this way.
|
/// "stable_name"]` will be persisted this way.
|
||||||
///
|
///
|
||||||
/// The individual fields are also serialized as JSON so they can safely be restored
|
/// The individual fields are also serialized as JSON so they can safely be restored
|
||||||
/// independently of the other fields.
|
/// independently of the other fields.
|
||||||
pub fields: HashMap<String, String>,
|
pub fields: BTreeMap<String, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a parameters iterator from the hashtables stored in the plugin wrappers. This avoids
|
/// Create a parameters iterator from the hashtables stored in the plugin wrappers. This avoids
|
||||||
|
@ -77,7 +79,7 @@ pub(crate) unsafe fn serialize_object<'a>(
|
||||||
// We'll serialize parameter values as a simple `string_param_id: display_value` map.
|
// We'll serialize parameter values as a simple `string_param_id: display_value` map.
|
||||||
// NOTE: If the plugin is being modulated (and the plugin is a CLAP plugin in Bitwig Studio),
|
// NOTE: If the plugin is being modulated (and the plugin is a CLAP plugin in Bitwig Studio),
|
||||||
// then this should save the values without any modulation applied to it
|
// then this should save the values without any modulation applied to it
|
||||||
let params: HashMap<_, _> = params_iter
|
let params: BTreeMap<_, _> = params_iter
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(param_id_str, param_ptr)| match param_ptr {
|
.map(|(param_id_str, param_ptr)| match param_ptr {
|
||||||
ParamPtr::FloatParam(p) => (
|
ParamPtr::FloatParam(p) => (
|
||||||
|
|
Loading…
Reference in a new issue