Move PersistentField and helpers to dedicated mod
As mentioned in the previous commit's breaking changes entry.
This commit is contained in:
parent
fb71d0fcce
commit
2a0ed0c5ec
|
@ -354,9 +354,9 @@ pub fn derive_params(input: TokenStream) -> TokenStream {
|
||||||
.map(|PersistentField { field, key }| {
|
.map(|PersistentField { field, key }| {
|
||||||
(
|
(
|
||||||
quote! {
|
quote! {
|
||||||
match ::nih_plug::param::internals::PersistentField::map(
|
match ::nih_plug::param::persist::PersistentField::map(
|
||||||
&self.#field,
|
&self.#field,
|
||||||
::nih_plug::param::internals::serialize_field,
|
::nih_plug::param::persist::serialize_field,
|
||||||
) {
|
) {
|
||||||
Ok(data) => {
|
Ok(data) => {
|
||||||
serialized.insert(String::from(#key), data);
|
serialized.insert(String::from(#key), data);
|
||||||
|
@ -372,9 +372,9 @@ pub fn derive_params(input: TokenStream) -> TokenStream {
|
||||||
},
|
},
|
||||||
quote! {
|
quote! {
|
||||||
#key => {
|
#key => {
|
||||||
match ::nih_plug::param::internals::deserialize_field(&data) {
|
match ::nih_plug::param::persist::deserialize_field(&data) {
|
||||||
Ok(deserialized) => {
|
Ok(deserialized) => {
|
||||||
::nih_plug::param::internals::PersistentField::set(
|
::nih_plug::param::persist::PersistentField::set(
|
||||||
&self.#field,
|
&self.#field,
|
||||||
deserialized,
|
deserialized,
|
||||||
);
|
);
|
||||||
|
|
|
@ -10,7 +10,7 @@ use baseview::{Size, WindowHandle, WindowOpenOptions, WindowScalePolicy};
|
||||||
use crossbeam::atomic::AtomicCell;
|
use crossbeam::atomic::AtomicCell;
|
||||||
use egui::Context;
|
use egui::Context;
|
||||||
use egui_baseview::EguiWindow;
|
use egui_baseview::EguiWindow;
|
||||||
use nih_plug::param::internals::PersistentField;
|
use nih_plug::param::persist::PersistentField;
|
||||||
use nih_plug::prelude::{Editor, GuiContext, ParamSetter, ParentWindowHandle};
|
use nih_plug::prelude::{Editor, GuiContext, ParamSetter, ParentWindowHandle};
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -63,7 +63,7 @@ where
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct EguiState {
|
pub struct EguiState {
|
||||||
/// The window's size in logical pixels before applying `scale_factor`.
|
/// The window's size in logical pixels before applying `scale_factor`.
|
||||||
#[serde(with = "nih_plug::param::internals::serialize_atomic_cell")]
|
#[serde(with = "nih_plug::param::persist::serialize_atomic_cell")]
|
||||||
size: AtomicCell<(u32, u32)>,
|
size: AtomicCell<(u32, u32)>,
|
||||||
/// Whether the editor's window is currently open.
|
/// Whether the editor's window is currently open.
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
|
|
|
@ -92,7 +92,7 @@
|
||||||
use baseview::{WindowOpenOptions, WindowScalePolicy};
|
use baseview::{WindowOpenOptions, WindowScalePolicy};
|
||||||
use crossbeam::atomic::AtomicCell;
|
use crossbeam::atomic::AtomicCell;
|
||||||
use crossbeam::channel;
|
use crossbeam::channel;
|
||||||
use nih_plug::param::internals::PersistentField;
|
use nih_plug::param::persist::PersistentField;
|
||||||
use nih_plug::prelude::{Editor, GuiContext, ParentWindowHandle};
|
use nih_plug::prelude::{Editor, GuiContext, ParentWindowHandle};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
|
@ -77,11 +77,11 @@ where
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct ViziaState {
|
pub struct ViziaState {
|
||||||
/// The window's size in logical pixels before applying `scale_factor`.
|
/// The window's size in logical pixels before applying `scale_factor`.
|
||||||
#[serde(with = "nih_plug::param::internals::serialize_atomic_cell")]
|
#[serde(with = "nih_plug::param::persist::serialize_atomic_cell")]
|
||||||
size: AtomicCell<(u32, u32)>,
|
size: AtomicCell<(u32, u32)>,
|
||||||
/// A scale factor that should be applied to `size` separate from from any system HiDPI scaling.
|
/// A scale factor that should be applied to `size` separate from from any system HiDPI scaling.
|
||||||
/// This can be used to allow GUIs to be scaled uniformly.
|
/// This can be used to allow GUIs to be scaled uniformly.
|
||||||
#[serde(with = "nih_plug::param::internals::serialize_atomic_cell")]
|
#[serde(with = "nih_plug::param::persist::serialize_atomic_cell")]
|
||||||
scale_factor: AtomicCell<f64>,
|
scale_factor: AtomicCell<f64>,
|
||||||
/// Whether the editor's window is currently open.
|
/// Whether the editor's window is currently open.
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
|
|
|
@ -20,6 +20,7 @@ mod float;
|
||||||
mod integer;
|
mod integer;
|
||||||
|
|
||||||
pub mod internals;
|
pub mod internals;
|
||||||
|
pub mod persist;
|
||||||
pub mod range;
|
pub mod range;
|
||||||
pub mod smoothing;
|
pub mod smoothing;
|
||||||
|
|
||||||
|
|
|
@ -2,34 +2,6 @@
|
||||||
|
|
||||||
use super::{Param, ParamFlags, ParamMut};
|
use super::{Param, ParamFlags, ParamMut};
|
||||||
|
|
||||||
/// Re-export for use in the [`Params`] proc-macro.
|
|
||||||
pub use serde_json::from_str as deserialize_field;
|
|
||||||
/// Re-export for use in the [`Params`] proc-macro.
|
|
||||||
pub use serde_json::to_string as serialize_field;
|
|
||||||
|
|
||||||
/// Can be used with the `#[serde(with = "nih_plug::param::internals::serialize_atomic_cell")]`
|
|
||||||
/// attribute to serialize `AtomicCell<T>`s.
|
|
||||||
pub mod serialize_atomic_cell {
|
|
||||||
use crossbeam::atomic::AtomicCell;
|
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
|
||||||
|
|
||||||
pub fn serialize<S, T>(cell: &AtomicCell<T>, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: Serializer,
|
|
||||||
T: Serialize + Copy,
|
|
||||||
{
|
|
||||||
cell.load().serialize(serializer)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deserialize<'de, D, T>(deserializer: D) -> Result<AtomicCell<T>, D::Error>
|
|
||||||
where
|
|
||||||
D: Deserializer<'de>,
|
|
||||||
T: Deserialize<'de> + Copy,
|
|
||||||
{
|
|
||||||
T::deserialize(deserializer).map(AtomicCell::new)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
||||||
/// erasure.
|
/// erasure.
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
|
||||||
|
@ -48,27 +20,6 @@ pub enum ParamPtr {
|
||||||
unsafe impl Send for ParamPtr {}
|
unsafe impl Send for ParamPtr {}
|
||||||
unsafe impl Sync for ParamPtr {}
|
unsafe impl Sync for ParamPtr {}
|
||||||
|
|
||||||
/// Handles the functionality needed for persisting a non-parameter fields in a plugin's state.
|
|
||||||
/// These types can be used with [`Params`]' `#[persist = "..."]` attributes.
|
|
||||||
///
|
|
||||||
/// This should be implemented for some type with interior mutability containing a `T`.
|
|
||||||
//
|
|
||||||
// TODO: Modifying these fields (or any parameter for that matter) should mark the plugin's state
|
|
||||||
// as dirty.
|
|
||||||
pub trait PersistentField<'a, T>: Send + Sync
|
|
||||||
where
|
|
||||||
T: serde::Serialize + serde::Deserialize<'a>,
|
|
||||||
{
|
|
||||||
/// Update the stored `T` value using interior mutability.
|
|
||||||
fn set(&self, new_value: T);
|
|
||||||
|
|
||||||
/// Get a reference to the stored `T` value, and apply a function to it. This is used to
|
|
||||||
/// serialize the `T` value.
|
|
||||||
fn map<F, R>(&self, f: F) -> R
|
|
||||||
where
|
|
||||||
F: Fn(&T) -> R;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Generate a [`ParamPtr`] function that forwards the function call to the underlying `Param`. We
|
/// Generate a [`ParamPtr`] function that forwards the function call to the underlying `Param`. We
|
||||||
/// can't have an `.as_param()` function since the return type would differ depending on the
|
/// can't have an `.as_param()` function since the return type would differ depending on the
|
||||||
/// underlying parameter type, so instead we need to type erase all of the functions individually.
|
/// underlying parameter type, so instead we need to type erase all of the functions individually.
|
||||||
|
@ -217,85 +168,3 @@ impl ParamPtr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> PersistentField<'a, T> for std::sync::RwLock<T>
|
|
||||||
where
|
|
||||||
T: serde::Serialize + serde::Deserialize<'a> + Send + Sync,
|
|
||||||
{
|
|
||||||
fn set(&self, new_value: T) {
|
|
||||||
*self.write().expect("Poisoned RwLock on write") = new_value;
|
|
||||||
}
|
|
||||||
fn map<F, R>(&self, f: F) -> R
|
|
||||||
where
|
|
||||||
F: Fn(&T) -> R,
|
|
||||||
{
|
|
||||||
f(&self.read().expect("Poisoned RwLock on read"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T> PersistentField<'a, T> for parking_lot::RwLock<T>
|
|
||||||
where
|
|
||||||
T: serde::Serialize + serde::Deserialize<'a> + Send + Sync,
|
|
||||||
{
|
|
||||||
fn set(&self, new_value: T) {
|
|
||||||
*self.write() = new_value;
|
|
||||||
}
|
|
||||||
fn map<F, R>(&self, f: F) -> R
|
|
||||||
where
|
|
||||||
F: Fn(&T) -> R,
|
|
||||||
{
|
|
||||||
f(&self.read())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T> PersistentField<'a, T> for std::sync::Mutex<T>
|
|
||||||
where
|
|
||||||
T: serde::Serialize + serde::Deserialize<'a> + Send + Sync,
|
|
||||||
{
|
|
||||||
fn set(&self, new_value: T) {
|
|
||||||
*self.lock().expect("Poisoned Mutex") = new_value;
|
|
||||||
}
|
|
||||||
fn map<F, R>(&self, f: F) -> R
|
|
||||||
where
|
|
||||||
F: Fn(&T) -> R,
|
|
||||||
{
|
|
||||||
f(&self.lock().expect("Poisoned Mutex"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_persistent_field_parking_lot_mutex {
|
|
||||||
($ty:ty) => {
|
|
||||||
impl<'a, T> PersistentField<'a, T> for $ty
|
|
||||||
where
|
|
||||||
T: serde::Serialize + serde::Deserialize<'a> + Send + Sync,
|
|
||||||
{
|
|
||||||
fn set(&self, new_value: T) {
|
|
||||||
*self.lock() = new_value;
|
|
||||||
}
|
|
||||||
fn map<F, R>(&self, f: F) -> R
|
|
||||||
where
|
|
||||||
F: Fn(&T) -> R,
|
|
||||||
{
|
|
||||||
f(&self.lock())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T> PersistentField<'a, T> for atomic_refcell::AtomicRefCell<T>
|
|
||||||
where
|
|
||||||
T: serde::Serialize + serde::Deserialize<'a> + Send + Sync,
|
|
||||||
{
|
|
||||||
fn set(&self, new_value: T) {
|
|
||||||
*self.borrow_mut() = new_value;
|
|
||||||
}
|
|
||||||
fn map<F, R>(&self, f: F) -> R
|
|
||||||
where
|
|
||||||
F: Fn(&T) -> R,
|
|
||||||
{
|
|
||||||
f(&self.borrow())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_persistent_field_parking_lot_mutex!(parking_lot::Mutex<T>);
|
|
||||||
impl_persistent_field_parking_lot_mutex!(parking_lot::FairMutex<T>);
|
|
||||||
|
|
133
src/param/persist.rs
Normal file
133
src/param/persist.rs
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
//! Traits and helpers for persistent fields. See the [`Params`][super::Params] trait for more
|
||||||
|
//! information.
|
||||||
|
|
||||||
|
/// Re-export for use in the [`Params`] proc-macro.
|
||||||
|
pub use serde_json::from_str as deserialize_field;
|
||||||
|
/// Re-export for use in the [`Params`] proc-macro.
|
||||||
|
pub use serde_json::to_string as serialize_field;
|
||||||
|
|
||||||
|
/// Handles the functionality needed for persisting a non-parameter fields in a plugin's state.
|
||||||
|
/// These types can be used with [`Params`]' `#[persist = "..."]` attributes.
|
||||||
|
///
|
||||||
|
/// This should be implemented for some type with interior mutability containing a `T`.
|
||||||
|
//
|
||||||
|
// TODO: Modifying these fields (or any parameter for that matter) should mark the plugin's state
|
||||||
|
// as dirty.
|
||||||
|
pub trait PersistentField<'a, T>: Send + Sync
|
||||||
|
where
|
||||||
|
T: serde::Serialize + serde::Deserialize<'a>,
|
||||||
|
{
|
||||||
|
/// Update the stored `T` value using interior mutability.
|
||||||
|
fn set(&self, new_value: T);
|
||||||
|
|
||||||
|
/// Get a reference to the stored `T` value, and apply a function to it. This is used to
|
||||||
|
/// serialize the `T` value.
|
||||||
|
fn map<F, R>(&self, f: F) -> R
|
||||||
|
where
|
||||||
|
F: Fn(&T) -> R;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> PersistentField<'a, T> for std::sync::RwLock<T>
|
||||||
|
where
|
||||||
|
T: serde::Serialize + serde::Deserialize<'a> + Send + Sync,
|
||||||
|
{
|
||||||
|
fn set(&self, new_value: T) {
|
||||||
|
*self.write().expect("Poisoned RwLock on write") = new_value;
|
||||||
|
}
|
||||||
|
fn map<F, R>(&self, f: F) -> R
|
||||||
|
where
|
||||||
|
F: Fn(&T) -> R,
|
||||||
|
{
|
||||||
|
f(&self.read().expect("Poisoned RwLock on read"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> PersistentField<'a, T> for parking_lot::RwLock<T>
|
||||||
|
where
|
||||||
|
T: serde::Serialize + serde::Deserialize<'a> + Send + Sync,
|
||||||
|
{
|
||||||
|
fn set(&self, new_value: T) {
|
||||||
|
*self.write() = new_value;
|
||||||
|
}
|
||||||
|
fn map<F, R>(&self, f: F) -> R
|
||||||
|
where
|
||||||
|
F: Fn(&T) -> R,
|
||||||
|
{
|
||||||
|
f(&self.read())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> PersistentField<'a, T> for std::sync::Mutex<T>
|
||||||
|
where
|
||||||
|
T: serde::Serialize + serde::Deserialize<'a> + Send + Sync,
|
||||||
|
{
|
||||||
|
fn set(&self, new_value: T) {
|
||||||
|
*self.lock().expect("Poisoned Mutex") = new_value;
|
||||||
|
}
|
||||||
|
fn map<F, R>(&self, f: F) -> R
|
||||||
|
where
|
||||||
|
F: Fn(&T) -> R,
|
||||||
|
{
|
||||||
|
f(&self.lock().expect("Poisoned Mutex"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_persistent_field_parking_lot_mutex {
|
||||||
|
($ty:ty) => {
|
||||||
|
impl<'a, T> PersistentField<'a, T> for $ty
|
||||||
|
where
|
||||||
|
T: serde::Serialize + serde::Deserialize<'a> + Send + Sync,
|
||||||
|
{
|
||||||
|
fn set(&self, new_value: T) {
|
||||||
|
*self.lock() = new_value;
|
||||||
|
}
|
||||||
|
fn map<F, R>(&self, f: F) -> R
|
||||||
|
where
|
||||||
|
F: Fn(&T) -> R,
|
||||||
|
{
|
||||||
|
f(&self.lock())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> PersistentField<'a, T> for atomic_refcell::AtomicRefCell<T>
|
||||||
|
where
|
||||||
|
T: serde::Serialize + serde::Deserialize<'a> + Send + Sync,
|
||||||
|
{
|
||||||
|
fn set(&self, new_value: T) {
|
||||||
|
*self.borrow_mut() = new_value;
|
||||||
|
}
|
||||||
|
fn map<F, R>(&self, f: F) -> R
|
||||||
|
where
|
||||||
|
F: Fn(&T) -> R,
|
||||||
|
{
|
||||||
|
f(&self.borrow())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_persistent_field_parking_lot_mutex!(parking_lot::Mutex<T>);
|
||||||
|
impl_persistent_field_parking_lot_mutex!(parking_lot::FairMutex<T>);
|
||||||
|
|
||||||
|
/// Can be used with the `#[serde(with = "nih_plug::param::internals::serialize_atomic_cell")]`
|
||||||
|
/// attribute to serialize `AtomicCell<T>`s.
|
||||||
|
pub mod serialize_atomic_cell {
|
||||||
|
use crossbeam::atomic::AtomicCell;
|
||||||
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
|
||||||
|
pub fn serialize<S, T>(cell: &AtomicCell<T>, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
T: Serialize + Copy,
|
||||||
|
{
|
||||||
|
cell.load().serialize(serializer)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deserialize<'de, D, T>(deserializer: D) -> Result<AtomicCell<T>, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
T: Deserialize<'de> + Copy,
|
||||||
|
{
|
||||||
|
T::deserialize(deserializer).map(AtomicCell::new)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue