From 90cf0ae86f488c7ad7eb620bb036d1b43e502fcf Mon Sep 17 00:00:00 2001 From: Charlie Zhang Date: Mon, 8 Jun 2026 09:47:24 -0400 Subject: [PATCH 1/3] Support x-keep-typed-in-additional-properties in Rust model generator When a schema sets `x-keep-typed-in-additional-properties: true`, pre-insert every key into `additional_properties` before the match dispatch so typed and untyped fields are both accessible from a single map. Co-Authored-By: Claude Sonnet 4.6 --- .generator/src/generator/templates/model_simple.j2 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.generator/src/generator/templates/model_simple.j2 b/.generator/src/generator/templates/model_simple.j2 index b0c4649890..d791fadb49 100644 --- a/.generator/src/generator/templates/model_simple.j2 +++ b/.generator/src/generator/templates/model_simple.j2 @@ -118,6 +118,11 @@ impl<'de> Deserialize<'de> for {{ name }} { let mut _unparsed = false; while let Some((k, v)) = map.next_entry::()? { + {%- if additionalProperties != false and model.get("x-keep-typed-in-additional-properties") %} + if let Ok(ap_value) = serde_json::from_value(v.clone()) { + additional_properties.insert(k.clone(), ap_value); + } + {%- endif %} match k.as_str() { {%- for attr, schema in model.get("properties", {}).items() %} {%- set required = attr in model.required %} From c5693d0e0e1124a3716932f9406100ff151ce446 Mon Sep 17 00:00:00 2001 From: Charlie Zhang Date: Mon, 8 Jun 2026 10:11:02 -0400 Subject: [PATCH 2/3] docs: clarify that if let Ok guard on from_value is infallible for serde_json::Value Add inline comment explaining that deserializing into serde_json::Value always succeeds, so the Ok branch always fires. The guard future-proofs against typed additionalProperties schemas where the conversion could fail. Co-Authored-By: Claude Sonnet 4.6 --- .generator/src/generator/templates/model_simple.j2 | 1 + 1 file changed, 1 insertion(+) diff --git a/.generator/src/generator/templates/model_simple.j2 b/.generator/src/generator/templates/model_simple.j2 index d791fadb49..b843cae277 100644 --- a/.generator/src/generator/templates/model_simple.j2 +++ b/.generator/src/generator/templates/model_simple.j2 @@ -119,6 +119,7 @@ impl<'de> Deserialize<'de> for {{ name }} { while let Some((k, v)) = map.next_entry::()? { {%- if additionalProperties != false and model.get("x-keep-typed-in-additional-properties") %} + // from_value:: is infallible; the Ok guard future-proofs typed AP schemas. if let Ok(ap_value) = serde_json::from_value(v.clone()) { additional_properties.insert(k.clone(), ap_value); } From e78662bef59f93a505929cfffa6da274cccfa108 Mon Sep 17 00:00:00 2001 From: Charlie Zhang Date: Mon, 8 Jun 2026 10:59:10 -0400 Subject: [PATCH 3/3] docs: clarify silent-drop behavior for typed AP schemas in if let Ok comment "future-proofs" implied graceful handling; the comment now accurately notes that a type mismatch silently drops the entry, same as the catch-all arm. Co-Authored-By: Claude Sonnet 4.6 --- .generator/src/generator/templates/model_simple.j2 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.generator/src/generator/templates/model_simple.j2 b/.generator/src/generator/templates/model_simple.j2 index b843cae277..ebeeae3f3a 100644 --- a/.generator/src/generator/templates/model_simple.j2 +++ b/.generator/src/generator/templates/model_simple.j2 @@ -119,7 +119,8 @@ impl<'de> Deserialize<'de> for {{ name }} { while let Some((k, v)) = map.next_entry::()? { {%- if additionalProperties != false and model.get("x-keep-typed-in-additional-properties") %} - // from_value:: is infallible; the Ok guard future-proofs typed AP schemas. + // from_value:: is infallible so Ok always fires; + // for typed AP schemas a type mismatch silently drops the entry (same as the catch-all arm). if let Ok(ap_value) = serde_json::from_value(v.clone()) { additional_properties.insert(k.clone(), ap_value); }