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]
|
## [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 order of `#[nested]` parameters in the parameter list now always follows
|
||||||
the declaration order instead of nested parameters being ordered below regular
|
the declaration order instead of nested parameters being ordered below regular
|
||||||
parameters.
|
parameters.
|
||||||
|
|
|
@ -313,6 +313,7 @@ pub fn derive_params(input: TokenStream) -> TokenStream {
|
||||||
})
|
})
|
||||||
.unzip();
|
.unzip();
|
||||||
|
|
||||||
|
// ID prefixes are also added for nested objects
|
||||||
let (serialize_fields_nested_tokens, deserialize_fields_nested_tokens): (Vec<_>, Vec<_>) =
|
let (serialize_fields_nested_tokens, deserialize_fields_nested_tokens): (Vec<_>, Vec<_>) =
|
||||||
params
|
params
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -321,23 +322,60 @@ pub fn derive_params(input: TokenStream) -> TokenStream {
|
||||||
Param::Nested(nested) => Some(nested),
|
Param::Nested(nested) => Some(nested),
|
||||||
})
|
})
|
||||||
.map(|nested| match nested {
|
.map(|nested| match nested {
|
||||||
NestedParams::Inline { field, .. } | NestedParams::Prefixed { field, .. } => (
|
NestedParams::Inline { field, .. } => (
|
||||||
// TODO: For some reason the macro won't parse correctly if you inline this
|
quote! { serialized.extend(self.#field.serialize_fields()); },
|
||||||
|
quote! { self.#field.deserialize_fields(serialized); },
|
||||||
|
),
|
||||||
|
NestedParams::Prefixed {
|
||||||
|
field, id_prefix, ..
|
||||||
|
} => (
|
||||||
quote! {
|
quote! {
|
||||||
let inlineme = self.#field.serialize_fields();
|
let prefixed = self
|
||||||
serialized.extend(inlineme);
|
.#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, .. } => (
|
NestedParams::Array { field, .. } => (
|
||||||
quote! {
|
quote! {
|
||||||
for field in self.#field.iter() {
|
for (field_idx, field) in self.#field.iter().enumerate() {
|
||||||
serialized.extend(field.serialize_fields());
|
let idx = field_idx + 1;
|
||||||
|
let suffixed = field
|
||||||
|
.serialize_fields()
|
||||||
|
.into_iter()
|
||||||
|
.map(|(key, value)| (format!("{}_{}", key, idx), value));
|
||||||
|
|
||||||
|
serialized.extend(suffixed);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
quote! {
|
quote! {
|
||||||
for field in self.#field.iter() {
|
for (field_idx, field) in self.#field.iter().enumerate() {
|
||||||
field.deserialize_fields(serialized);
|
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
|
/// 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.
|
/// 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
|
/// Parameter IDs and persisting keys still need to be **unique** when using nested parameter
|
||||||
/// structs. This currently has the following caveats:
|
/// structs.
|
||||||
///
|
|
||||||
/// - 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.
|
|
||||||
///
|
///
|
||||||
/// Take a look at the example gain example plugin to see how this is used.
|
/// 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]`
|
/// 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
|
/// 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
|
/// 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._
|
/// parameter indices._
|
||||||
///
|
///
|
||||||
/// This does **not** support persistent fields.
|
|
||||||
///
|
|
||||||
/// ## `#[nested(array, group_name = "Foo")]`
|
/// ## `#[nested(array, group_name = "Foo")]`
|
||||||
///
|
///
|
||||||
/// This can be applied to an array-like data structure and it works similar to a `nested` attribute
|
/// 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
|
/// 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
|
/// 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 will belong to the group `Foo {array_index + 1}`, and it will have the renamed
|
||||||
/// parameter ID `bar_{array_index + 1}`.
|
/// parameter ID `bar_{array_index + 1}`. The same thing applies to persistent field keys.
|
||||||
///
|
|
||||||
/// This does **not** support persistent fields.
|
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
|
|
Loading…
Reference in a new issue