use std::fmt::{Debug, Display};
use std::marker::PhantomData;
use std::sync::Arc;
use super::internals::ParamPtr;
use super::range::IntRange;
use super::{IntParam, InternalParamMut, Param, ParamFlags};
pub use nice_plug_derive::Enum;
pub trait Enum {
fn variants() -> &'static [&'static str];
fn ids() -> Option<&'static [&'static str]>;
fn to_index(self) -> usize;
fn from_index(index: usize) -> Self;
}
pub struct EnumParam<T: Enum + PartialEq> {
inner: EnumParamInner,
_marker: PhantomData<T>,
}
pub struct EnumParamInner {
pub(crate) inner: IntParam,
variants: &'static [&'static str],
ids: Option<&'static [&'static str]>,
}
impl<T: Enum + PartialEq> Display for EnumParam<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Display::fmt(&self.inner, f)
}
}
impl Display for EnumParamInner {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
self.variants[self.inner.modulated_plain_value() as usize]
)
}
}
impl<T: Enum + PartialEq> Debug for EnumParam<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Debug::fmt(&self.inner, f)
}
}
impl Debug for EnumParamInner {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.inner.modulated_plain_value() != self.inner.unmodulated_plain_value() {
write!(f, "{}: {} (modulated)", &self.name(), &self)
} else {
write!(f, "{}: {}", &self.name(), &self)
}
}
}
impl<T: Enum + PartialEq> super::Sealed for EnumParam<T> {}
impl<T: Enum + PartialEq> Param for EnumParam<T> {
type Plain = T;
fn name(&self) -> &str {
self.inner.name()
}
fn unit(&self) -> &'static str {
self.inner.unit()
}
fn poly_modulation_id(&self) -> Option<u32> {
self.inner.poly_modulation_id()
}
#[inline]
fn modulated_plain_value(&self) -> Self::Plain {
T::from_index(self.inner.modulated_plain_value() as usize)
}
#[inline]
fn modulated_normalized_value(&self) -> f32 {
self.inner.modulated_normalized_value()
}
#[inline]
fn unmodulated_plain_value(&self) -> Self::Plain {
T::from_index(self.inner.unmodulated_plain_value() as usize)
}
#[inline]
fn unmodulated_normalized_value(&self) -> f32 {
self.inner.unmodulated_normalized_value()
}
#[inline]
fn default_plain_value(&self) -> Self::Plain {
T::from_index(self.inner.default_plain_value() as usize)
}
fn step_count(&self) -> Option<usize> {
self.inner.step_count()
}
fn previous_step(&self, from: Self::Plain, finer: bool) -> Self::Plain {
T::from_index(self.inner.previous_step(T::to_index(from) as i32, finer) as usize)
}
fn next_step(&self, from: Self::Plain, finer: bool) -> Self::Plain {
T::from_index(self.inner.next_step(T::to_index(from) as i32, finer) as usize)
}
fn normalized_value_to_string(&self, normalized: f32, include_unit: bool) -> String {
self.inner
.normalized_value_to_string(normalized, include_unit)
}
fn string_to_normalized_value(&self, string: &str) -> Option<f32> {
self.inner.string_to_normalized_value(string)
}
#[inline]
fn preview_normalized(&self, plain: Self::Plain) -> f32 {
self.inner.preview_normalized(T::to_index(plain) as i32)
}
#[inline]
fn preview_plain(&self, normalized: f32) -> Self::Plain {
T::from_index(self.inner.preview_plain(normalized) as usize)
}
fn flags(&self) -> ParamFlags {
self.inner.flags()
}
fn as_ptr(&self) -> ParamPtr {
self.inner.as_ptr()
}
}
impl super::Sealed for EnumParamInner {}
impl Param for EnumParamInner {
type Plain = i32;
fn name(&self) -> &str {
self.inner.name()
}
fn unit(&self) -> &'static str {
""
}
fn poly_modulation_id(&self) -> Option<u32> {
self.inner.poly_modulation_id()
}
#[inline]
fn modulated_plain_value(&self) -> Self::Plain {
self.inner.modulated_plain_value()
}
#[inline]
fn modulated_normalized_value(&self) -> f32 {
self.inner.modulated_normalized_value()
}
#[inline]
fn default_plain_value(&self) -> Self::Plain {
self.inner.default_plain_value()
}
#[inline]
fn unmodulated_plain_value(&self) -> Self::Plain {
self.inner.unmodulated_plain_value()
}
#[inline]
fn unmodulated_normalized_value(&self) -> f32 {
self.inner.unmodulated_normalized_value()
}
fn step_count(&self) -> Option<usize> {
Some(self.len() - 1)
}
fn previous_step(&self, from: Self::Plain, finer: bool) -> Self::Plain {
self.inner.previous_step(from, finer)
}
fn next_step(&self, from: Self::Plain, finer: bool) -> Self::Plain {
self.inner.next_step(from, finer)
}
fn normalized_value_to_string(&self, normalized: f32, _include_unit: bool) -> String {
let index = self.preview_plain(normalized);
self.variants[index as usize].to_string()
}
fn string_to_normalized_value(&self, string: &str) -> Option<f32> {
let string = string.trim();
self.variants
.iter()
.position(|variant| variant == &string)
.map(|idx| self.preview_normalized(idx as i32))
}
#[inline]
fn preview_normalized(&self, plain: Self::Plain) -> f32 {
self.inner.preview_normalized(plain)
}
#[inline]
fn preview_plain(&self, normalized: f32) -> Self::Plain {
self.inner.preview_plain(normalized)
}
fn flags(&self) -> ParamFlags {
self.inner.flags()
}
fn as_ptr(&self) -> ParamPtr {
ParamPtr::EnumParam(self as *const EnumParamInner as *mut EnumParamInner)
}
}
impl<T: Enum + PartialEq> InternalParamMut for EnumParam<T> {
unsafe fn _internal_set_plain_value(&self, plain: Self::Plain) -> bool {
unsafe {
self.inner
._internal_set_plain_value(T::to_index(plain) as i32)
}
}
unsafe fn _internal_set_normalized_value(&self, normalized: f32) -> bool {
unsafe { self.inner._internal_set_normalized_value(normalized) }
}
unsafe fn _internal_modulate_value(&self, modulation_offset: f32) -> bool {
unsafe { self.inner._internal_modulate_value(modulation_offset) }
}
unsafe fn _internal_update_smoother(&self, sample_rate: f32, reset: bool) {
unsafe { self.inner._internal_update_smoother(sample_rate, reset) }
}
}
impl InternalParamMut for EnumParamInner {
unsafe fn _internal_set_plain_value(&self, plain: Self::Plain) -> bool {
unsafe { self.inner._internal_set_plain_value(plain) }
}
unsafe fn _internal_set_normalized_value(&self, normalized: f32) -> bool {
unsafe { self.inner._internal_set_normalized_value(normalized) }
}
unsafe fn _internal_modulate_value(&self, modulation_offset: f32) -> bool {
unsafe { self.inner._internal_modulate_value(modulation_offset) }
}
unsafe fn _internal_update_smoother(&self, sample_rate: f32, reset: bool) {
unsafe { self.inner._internal_update_smoother(sample_rate, reset) }
}
}
impl<T: Enum + PartialEq + 'static> EnumParam<T> {
pub fn new(name: impl Into<String>, default: T) -> Self {
let variants = T::variants();
let ids = T::ids();
Self {
inner: EnumParamInner {
inner: IntParam::new(
name,
T::to_index(default) as i32,
IntRange::Linear {
min: 0,
max: variants.len() as i32 - 1,
},
),
variants,
ids,
},
_marker: PhantomData,
}
}
#[inline]
pub fn value(&self) -> T {
self.modulated_plain_value()
}
pub fn with_poly_modulation_id(mut self, id: u32) -> Self {
self.inner.inner = self.inner.inner.with_poly_modulation_id(id);
self
}
pub fn with_callback(mut self, callback: Arc<dyn Fn(T) + Send + Sync>) -> Self {
self.inner.inner = self.inner.inner.with_callback(Arc::new(move |value| {
callback(T::from_index(value as usize))
}));
self
}
pub fn non_automatable(mut self) -> Self {
self.inner.inner = self.inner.inner.non_automatable();
self
}
pub fn hide(mut self) -> Self {
self.inner.inner = self.inner.inner.hide();
self
}
pub fn hide_in_generic_ui(mut self) -> Self {
self.inner.inner = self.inner.inner.hide_in_generic_ui();
self
}
}
impl EnumParamInner {
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
self.variants.len()
}
pub fn unmodulated_plain_id(&self) -> Option<&'static str> {
let ids = &self.ids?;
Some(ids[self.unmodulated_plain_value() as usize])
}
pub fn set_from_id(&self, id: &str) -> bool {
match self
.ids
.and_then(|ids| ids.iter().position(|candidate| *candidate == id))
{
Some(index) => {
unsafe {
self._internal_set_plain_value(index as i32);
}
true
}
None => false,
}
}
}