fix: deserialize makeup_db = "auto" in profiles
`MakeupGain` was a derived `#[serde(untagged)]` enum, and an untagged unit variant can't be deserialized from the string `"auto"` under the `toml` crate (untagged matches unit variants against `null`, not a name). So every profile carrying `makeup_db = "auto"` — including the shipped default/night/speech — silently failed to parse and was skipped by `scan_dir_into`, falling back to the builtin default. Hand-roll Serialize/Deserialize: number → `Db`, case-insensitive `"auto"` → `Auto`, bogus string is a hard error. Serializes back to a lowercase `"auto"` token.
This commit is contained in:
parent
031f47f560
commit
c8c221ba45
1 changed files with 57 additions and 6 deletions
|
|
@ -239,8 +239,16 @@ impl Default for CompressorSection {
|
|||
}
|
||||
|
||||
/// `makeup_db` field: either an explicit number of dB or `"auto"`.
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Default)]
|
||||
#[serde(untagged)]
|
||||
///
|
||||
/// De/serialization is hand-rolled rather than derived. A derived
|
||||
/// `#[serde(untagged)]` enum cannot deserialize the unit variant
|
||||
/// `Auto` from the string `"auto"` (untagged matches unit variants
|
||||
/// against `null`, not a name), so every shipped profile carrying
|
||||
/// `makeup_db = "auto"` silently failed to parse under the `toml`
|
||||
/// crate and got skipped. We accept a number → `Db`, or the
|
||||
/// case-insensitive string `"auto"` → `Auto`, and serialize back to
|
||||
/// the same shapes.
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub enum MakeupGain {
|
||||
/// Numeric dB value.
|
||||
Db(f32),
|
||||
|
|
@ -249,6 +257,34 @@ pub enum MakeupGain {
|
|||
Auto,
|
||||
}
|
||||
|
||||
impl Serialize for MakeupGain {
|
||||
fn serialize<S: serde::Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
|
||||
match self {
|
||||
MakeupGain::Db(v) => ser.serialize_f32(*v),
|
||||
MakeupGain::Auto => ser.serialize_str("auto"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for MakeupGain {
|
||||
fn deserialize<D: serde::Deserializer<'de>>(de: D) -> Result<Self, D::Error> {
|
||||
// Buffer into an untagged number-or-string, then interpret.
|
||||
#[derive(Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum Repr {
|
||||
Num(f32),
|
||||
Str(String),
|
||||
}
|
||||
match Repr::deserialize(de)? {
|
||||
Repr::Num(v) => Ok(MakeupGain::Db(v)),
|
||||
Repr::Str(s) if s.eq_ignore_ascii_case("auto") => Ok(MakeupGain::Auto),
|
||||
Repr::Str(s) => Err(serde::de::Error::custom(format!(
|
||||
"invalid makeup_db {s:?}: expected a number or \"auto\""
|
||||
))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `[limiter]` section.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
|
|
@ -517,11 +553,10 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn makeup_gain_serialises_as_string_or_number() {
|
||||
// Auto serialises to the lowercase string `"auto"` — the same
|
||||
// token profiles use on disk — and round-trips.
|
||||
let auto = serde_json::to_string(&MakeupGain::Auto).unwrap();
|
||||
// Untagged enum: Auto serialises as its discriminant variant —
|
||||
// serde_json renders unit variant Auto as `"Auto"`. We don't
|
||||
// promise wire-format here; this is a profile concern. Just
|
||||
// verify round-trip works.
|
||||
assert_eq!(auto, "\"auto\"");
|
||||
let back: MakeupGain = serde_json::from_str(&auto).unwrap();
|
||||
assert!(matches!(back, MakeupGain::Auto));
|
||||
|
||||
|
|
@ -529,4 +564,20 @@ mod tests {
|
|||
let back: MakeupGain = serde_json::from_str(&db).unwrap();
|
||||
assert!(matches!(back, MakeupGain::Db(v) if (v - 3.0).abs() < 1e-6));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn makeup_gain_parses_auto_from_toml_case_insensitively() {
|
||||
#[derive(Deserialize)]
|
||||
struct Holder {
|
||||
makeup_db: MakeupGain,
|
||||
}
|
||||
for tok in ["\"auto\"", "\"Auto\"", "\"AUTO\""] {
|
||||
let h: Holder = toml::from_str(&format!("makeup_db = {tok}")).unwrap();
|
||||
assert!(matches!(h.makeup_db, MakeupGain::Auto), "token {tok}");
|
||||
}
|
||||
let h: Holder = toml::from_str("makeup_db = -3.5").unwrap();
|
||||
assert!(matches!(h.makeup_db, MakeupGain::Db(v) if (v + 3.5).abs() < 1e-6));
|
||||
// A bogus string is a hard error, not a silent skip.
|
||||
assert!(toml::from_str::<Holder>("makeup_db = \"loud\"").is_err());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue