diff --git a/nih_plug_derive/src/params.rs b/nih_plug_derive/src/params.rs index 8986e25f..7564be5b 100644 --- a/nih_plug_derive/src/params.rs +++ b/nih_plug_derive/src/params.rs @@ -27,13 +27,12 @@ pub fn derive_params(input: TokenStream) -> TokenStream { // parameters. For the `persist` function we'll create functions that serialize and deserialize // those fields individually (so they can be added and removed independently of eachother) using // JSON. The `nested` fields should also implement the `Params` trait and their fields will be - // inherited and added to this field's lists. We'll also enforce that there are no duplicate - // keys at compile time. + // inherited and added to this field's param mapping list. The order follows the declaration + // order We'll also enforce that there are no duplicate keys for `id` fields at compile time. // TODO: This duplication check doesn't work for nested fields since we don't know anything // about the fields on the nested structs let mut params: Vec = Vec::new(); let mut persistent_fields: Vec = Vec::new(); - let mut group_params: Vec = Vec::new(); for field in fields.named { let field_name = match &field.ident { Some(ident) => ident, @@ -133,7 +132,7 @@ pub fn derive_params(input: TokenStream) -> TokenStream { } }; } else if attr.path.is_ident("nested") { - // This one is more complicated. Support an `array` attribute, an `id_prefix = + // This one is more complicated. Supports an `array` attribute, an `id_prefix = // "foo"` attribute, and a `group = "group name"` attribute. All are optional, and // the first two are mutually exclusive. let mut nested_array = false; @@ -207,7 +206,7 @@ pub fn derive_params(input: TokenStream) -> TokenStream { } } - let param = match (nested_array, nested_id_prefix) { + params.push(Param::Nested(match (nested_array, nested_id_prefix) { (true, None) => NestedParams::Array { field: field_name.clone(), group: nested_group, @@ -229,20 +228,7 @@ pub fn derive_params(input: TokenStream) -> TokenStream { .to_compile_error() .into() } - }; - - // Grouped parameters are handled differently than nested parameters: - // DAWs that support grouped parameters usually display parameter groups below "regular" ones - // in a tree view. To keep the order consistent with those, group parameters are collected - // separately, so they can be inserted at the end of the parameter list. - // Nested parameters without a group on the other hand are merely an implementation detail of - // the plugin and thus should not behave different than regular parameters to the user. Because - // of this, they are inserted alongside the "regular" ones. - if param.is_group() { - group_params.push(param); - } else { - params.push(Param::Nested(param)); - } + })); processed_attribute = true; } @@ -263,8 +249,7 @@ pub fn derive_params(input: TokenStream) -> TokenStream { // The next step is build the gathered information into tokens that can be spliced into a // `Params` implementation let param_map_tokens = { - let param_mapping_self_tokens = params.into_iter().map(|p| p.to_token()); - let param_mapping_group_tokens = group_params.iter().map(|p| p.to_token()); + let param_mapping_tokens = params.iter().map(|p| p.param_map_tokens()); quote! { // This may not be in scope otherwise, used to call .as_ptr() @@ -272,8 +257,7 @@ pub fn derive_params(input: TokenStream) -> TokenStream { #[allow(unused_mut)] let mut param_map = Vec::new(); - #(param_map.extend(#param_mapping_self_tokens); )* - #(param_map.extend(#param_mapping_group_tokens); )* + #(param_map.extend(#param_mapping_tokens); )* param_map } @@ -330,8 +314,12 @@ pub fn derive_params(input: TokenStream) -> TokenStream { .unzip(); let (serialize_fields_nested_tokens, deserialize_fields_nested_tokens): (Vec<_>, Vec<_>) = - group_params + params .iter() + .filter_map(|p| match p { + Param::Single { .. } => None, + Param::Nested(nested) => Some(nested), + }) .map(|nested| match nested { NestedParams::Inline { field, .. } | NestedParams::Prefixed { field, .. } => ( // TODO: For some reason the macro won't parse correctly if you inline this @@ -419,12 +407,14 @@ enum Param { } impl Param { - fn to_token(&self) -> proc_macro2::TokenStream { + /// Generate the tokens needed for a field (or nested parameter struct) to add itself to the + /// parameter map. + fn param_map_tokens(&self) -> proc_macro2::TokenStream { match self { Param::Single { field, id } => { quote! { [(String::from(#id), self.#field.as_ptr(), String::new())] } } - Param::Nested(params) => params.to_token(), + Param::Nested(params) => params.param_map_tokens(), } } } @@ -464,27 +454,15 @@ enum NestedParams { } impl NestedParams { - fn is_group(&self) -> bool { - let group = match self { - NestedParams::Inline { field: _, group } => group, - NestedParams::Prefixed { - field: _, - id_prefix: _, - group, - } => group, - NestedParams::Array { field: _, group } => group, - }; - - group.is_some() - } - - fn to_token(&self) -> proc_macro2::TokenStream { + /// Constrruct an iterator that iterates over all parmaeters of a nested parameter object. This + /// takes ID prefixes and suffixes into account, and prefixes the group to the parameter's + /// existing groups if the `group` attribute on the `#[nested]` macro was specified. + fn param_map_tokens(&self) -> proc_macro2::TokenStream { // How nested parameters are handled depends on the `NestedParams` variant. // These are pairs of `(parameter_id, param_ptr, param_group)`. The specific // parameter types know how to convert themselves into the correct ParamPtr variant. // Top-level parameters have no group, and we'll prefix the group name specified in - // the `#[nested(...)]` attribute to fields coming from nested groups - + // the `#[nested(...)]` attribute to fields coming from nested groups. match self { // TODO: No idea how to splice this as an `Option<&str>`, so this involves some // copy-pasting