Support #[nested] prefixes/suffixes w/ #[persist]
This makes nested fields behave the same as nested parameters, allowing multiple copies of a persistent field to exist.
This commit is contained in:
parent
5d9f1b109c
commit
753ca201a6
|
@ -8,6 +8,14 @@ code then it will not be listed here.
|
|||
|
||||
## [2022-11-17]
|
||||
|
||||
- The `Params` derive macro now also properly supports persistent fields in
|
||||
`#[nested]` parameter structs. This takes `#[nested(id_prefix = "...")]` and
|
||||
`#[nested(array)]` into account to allow multiple copies of a persistent
|
||||
field. This may break existing usages as serialized field data without a
|
||||
matching preffix or suffix is no longer passed to the child object.
|
||||
|
||||
## [2022-11-17]
|
||||
|
||||
- The order of `#[nested]` parameters in the parameter list now always follows
|
||||
the declaration order instead of nested parameters being ordered below regular
|
||||
parameters.
|
||||
|
|
|
@ -313,6 +313,7 @@ pub fn derive_params(input: TokenStream) -> TokenStream {
|
|||
})
|
||||
.unzip();
|
||||
|
||||
// ID prefixes are also added for nested objects
|
||||
let (serialize_fields_nested_tokens, deserialize_fields_nested_tokens): (Vec<_>, Vec<_>) =
|
||||
params
|
||||
.iter()
|
||||
|
@ -321,23 +322,60 @@ pub fn derive_params(input: TokenStream) -> TokenStream {
|
|||
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
|
||||
NestedParams::Inline { field, .. } => (
|
||||
quote! { serialized.extend(self.#field.serialize_fields()); },
|
||||
quote! { self.#field.deserialize_fields(serialized); },
|
||||
),
|
||||
NestedParams::Prefixed {
|
||||
field, id_prefix, ..
|
||||
} => (
|
||||
quote! {
|
||||
let inlineme = self.#field.serialize_fields();
|
||||
serialized.extend(inlineme);
|
||||
let prefixed = self
|
||||
.#field
|
||||
.serialize_fields()
|
||||
.into_iter()
|
||||
.map(|(key, value)| (format!("{}_{}", #id_prefix, key), value));
|
||||
|
||||
serialized.extend(prefixed);
|
||||
},
|
||||
quote! {
|
||||
let prefix = format!("{}_", #id_prefix);
|
||||
let matching_fields = serialized
|
||||
.iter()
|
||||
.filter_map(|(key, value)| {
|
||||
let original_key = key.strip_prefix(&prefix)?;
|
||||
Some((original_key.to_owned(), value.to_owned()))
|
||||
})
|
||||
.collect();
|
||||
|
||||
self.#field.deserialize_fields(&matching_fields);
|
||||
},
|
||||
quote! { self.#field.deserialize_fields(serialized) },
|
||||
),
|
||||
NestedParams::Array { field, .. } => (
|
||||
quote! {
|
||||
for field in self.#field.iter() {
|
||||
serialized.extend(field.serialize_fields());
|
||||
for (field_idx, field) in self.#field.iter().enumerate() {
|
||||
let idx = field_idx + 1;
|
||||
let suffixed = field
|
||||
.serialize_fields()
|
||||
.into_iter()
|
||||
.map(|(key, value)| (format!("{}_{}", key, idx), value));
|
||||
|
||||
serialized.extend(suffixed);
|
||||
}
|
||||
},
|
||||
quote! {
|
||||
for field in self.#field.iter() {
|
||||
field.deserialize_fields(serialized);
|
||||
for (field_idx, field) in self.#field.iter().enumerate() {
|
||||
let idx = field_idx + 1;
|
||||
let suffix = format!("_{}", idx);
|
||||
let matching_fields = serialized
|
||||
.iter()
|
||||
.filter_map(|(key, value)| {
|
||||
let original_key = key.strip_suffix(&suffix)?;
|
||||
Some((original_key.to_owned(), value.to_owned()))
|
||||
})
|
||||
.collect();
|
||||
|
||||
field.deserialize_fields(&matching_fields);
|
||||
}
|
||||
},
|
||||
),
|
||||
|
|
|
@ -230,10 +230,7 @@ pub(crate) trait ParamMut: Param {
|
|||
/// Finally, the `Params` object may include parameters from other objects. Setting a group name is
|
||||
/// optional, but some hosts can use this information to display the parameters in a tree structure.
|
||||
/// Parameter IDs and persisting keys still need to be **unique** when using nested parameter
|
||||
/// structs. This currently has the following caveats:
|
||||
///
|
||||
/// - Enforcing that parameter IDs and persist keys are unique does not work across nested structs.
|
||||
/// - Deserializing persisted fields will give false positives about fields not existing.
|
||||
/// structs.
|
||||
///
|
||||
/// Take a look at the example gain example plugin to see how this is used.
|
||||
///
|
||||
|
@ -242,20 +239,17 @@ pub(crate) trait ParamMut: Param {
|
|||
/// Adding this attribute to a `Params` sub-object works similarly to the regular `#[nested]`
|
||||
/// attribute, but it also adds an ID to all parameters from the nested object. If a parameter in
|
||||
/// the nested nested object normally has parameter ID `bar`, the parameter's ID will now be renamed
|
||||
/// to `foo_bar`. _This makes it possible to reuse same parameter struct with different names and
|
||||
/// to `foo_bar`. The same thing happens with persistent field keys to support multiple copies of
|
||||
/// the field. _This makes it possible to reuse the same parameter struct with different names and
|
||||
/// parameter indices._
|
||||
///
|
||||
/// This does **not** support persistent fields.
|
||||
///
|
||||
/// ## `#[nested(array, group_name = "Foo")]`
|
||||
///
|
||||
/// This can be applied to an array-like data structure and it works similar to a `nested` attribute
|
||||
/// with an `id_name`, except that it will iterate over the array and create unique indices for all
|
||||
/// nested parameters. If the nested parameters object has a parameter called `bar`, then that
|
||||
/// parameter will belong to the group `Foo {array_index + 1}`, and it will have the renamed
|
||||
/// parameter ID `bar_{array_index + 1}`.
|
||||
///
|
||||
/// This does **not** support persistent fields.
|
||||
/// parameter ID `bar_{array_index + 1}`. The same thing applies to persistent field keys.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
|
|
Loading…
Reference in a new issue