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 }| {
|
||||
(
|
||||
quote! {
|
||||
match ::nih_plug::param::internals::PersistentField::map(
|
||||
match ::nih_plug::param::persist::PersistentField::map(
|
||||
&self.#field,
|
||||
::nih_plug::param::internals::serialize_field,
|
||||
::nih_plug::param::persist::serialize_field,
|
||||
) {
|
||||
Ok(data) => {
|
||||
serialized.insert(String::from(#key), data);
|
||||
|
@ -372,9 +372,9 @@ pub fn derive_params(input: TokenStream) -> TokenStream {
|
|||
},
|
||||
quote! {
|
||||
#key => {
|
||||
match ::nih_plug::param::internals::deserialize_field(&data) {
|
||||
match ::nih_plug::param::persist::deserialize_field(&data) {
|
||||
Ok(deserialized) => {
|
||||
::nih_plug::param::internals::PersistentField::set(
|
||||
::nih_plug::param::persist::PersistentField::set(
|
||||
&self.#field,
|
||||
deserialized,
|
||||
);
|
||||
|
|
|
@ -10,7 +10,7 @@ use baseview::{Size, WindowHandle, WindowOpenOptions, WindowScalePolicy};
|
|||
use crossbeam::atomic::AtomicCell;
|
||||
use egui::Context;
|
||||
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 parking_lot::RwLock;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -63,7 +63,7 @@ where
|
|||
#[derive(Serialize, Deserialize)]
|
||||
pub struct EguiState {
|
||||
/// 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)>,
|
||||
/// Whether the editor's window is currently open.
|
||||
#[serde(skip)]
|
||||
|
|
|
@ -92,7 +92,7 @@
|
|||
use baseview::{WindowOpenOptions, WindowScalePolicy};
|
||||
use crossbeam::atomic::AtomicCell;
|
||||
use crossbeam::channel;
|
||||
use nih_plug::param::internals::PersistentField;
|
||||
use nih_plug::param::persist::PersistentField;
|
||||
use nih_plug::prelude::{Editor, GuiContext, ParentWindowHandle};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Debug;
|
||||
|
|
|
@ -77,11 +77,11 @@ where
|
|||
#[derive(Serialize, Deserialize)]
|
||||
pub struct ViziaState {
|
||||
/// 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)>,
|
||||
/// 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.
|
||||
#[serde(with = "nih_plug::param::internals::serialize_atomic_cell")]
|
||||
#[serde(with = "nih_plug::param::persist::serialize_atomic_cell")]
|
||||
scale_factor: AtomicCell<f64>,
|
||||
/// Whether the editor's window is currently open.
|
||||
#[serde(skip)]
|
||||
|
|
|
@ -20,6 +20,7 @@ mod float;
|
|||
mod integer;
|
||||
|
||||
pub mod internals;
|
||||
pub mod persist;
|
||||
pub mod range;
|
||||
pub mod smoothing;
|
||||
|
||||
|
|
|
@ -2,34 +2,6 @@
|
|||
|
||||
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
|
||||
/// erasure.
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
|
||||
|
@ -48,27 +20,6 @@ pub enum ParamPtr {
|
|||
unsafe impl Send 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
|
||||
/// 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.
|
||||
|
@ -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