diff --git a/.jules/bolt.md b/.jules/bolt.md new file mode 100644 index 00000000..02c58cc2 --- /dev/null +++ b/.jules/bolt.md @@ -0,0 +1,3 @@ +## 2026-06-13 - Optimization: deserialize vs from_value +**Learning:** Performance memory pattern states that when deserializing from intermediate `serde_json::Value` or `serde_yaml::Value`, prefer `T::deserialize(&value)` over `from_value(value.clone())` to avoid expensive deep clones. However, when consuming the entire `Value` tree at the end of parsing, prefer `from_value(value)` (without cloning) so Serde can move strings and data directly without re-allocating. +**Action:** Identified redundant `clone()` calls in `xdk-openapi/src/parser.rs` when pre-loading OpenAPI components into the context from intermediate `serde_json::Value` / `serde_yaml::Value` trees. Patched code to use `T::deserialize(&value)` instead of `serde_json::from_value(value.clone())` and `serde_yaml::from_value(value.clone())` to avoid unnecessary deep clones of JSON/YAML subtrees. diff --git a/xdk-openapi/src/parser.rs b/xdk-openapi/src/parser.rs index 6a92b4e5..209efa1b 100644 --- a/xdk-openapi/src/parser.rs +++ b/xdk-openapi/src/parser.rs @@ -56,9 +56,9 @@ pub fn parse_yaml(yaml: &str) -> Result { if let Some(schemas) = components.get("schemas").and_then(|s| s.as_mapping()) { for (name, schema_val) in schemas { if let Some(name_str) = name.as_str() { - match serde_yaml::from_value::( - schema_val.clone(), - ) { + use serde::Deserialize; + // Optimization: Use T::deserialize(&value) to avoid expensive deep clones of JSON/YAML values + match crate::components::Schema::deserialize(schema_val) { Ok(schema) => ctx.add_schema(name_str.to_string(), schema), Err(e) => { eprintln!("Warning: Failed to parse schema {name_str}: {e}") @@ -70,9 +70,9 @@ pub fn parse_yaml(yaml: &str) -> Result { if let Some(parameters) = components.get("parameters").and_then(|p| p.as_mapping()) { for (name, param_val) in parameters { if let Some(name_str) = name.as_str() { - match serde_yaml::from_value::( - param_val.clone(), - ) { + use serde::Deserialize; + // Optimization: Use T::deserialize(&value) to avoid expensive deep clones of JSON/YAML values + match crate::components::Parameter::deserialize(param_val) { Ok(param) => ctx.add_parameter(name_str.to_string(), param), Err(e) => { eprintln!("Warning: Failed to parse parameter {name_str}: {e}") @@ -84,7 +84,9 @@ pub fn parse_yaml(yaml: &str) -> Result { if let Some(responses) = components.get("responses").and_then(|r| r.as_mapping()) { for (name, resp_val) in responses { if let Some(name_str) = name.as_str() { - match serde_yaml::from_value::(resp_val.clone()) { + use serde::Deserialize; + // Optimization: Use T::deserialize(&value) to avoid expensive deep clones of JSON/YAML values + match crate::core::Response::deserialize(resp_val) { Ok(resp) => ctx.add_response(name_str.to_string(), resp), Err(e) => { eprintln!("Warning: Failed to parse response {name_str}: {e}") @@ -99,7 +101,9 @@ pub fn parse_yaml(yaml: &str) -> Result { { for (name, rb_val) in request_bodies { if let Some(name_str) = name.as_str() { - match serde_yaml::from_value::(rb_val.clone()) { + use serde::Deserialize; + // Optimization: Use T::deserialize(&value) to avoid expensive deep clones of JSON/YAML values + match crate::core::RequestBody::deserialize(rb_val) { Ok(rb) => ctx.add_request_body(name_str.to_string(), rb), Err(e) => { eprintln!("Warning: Failed to parse requestBody {name_str}: {e}") @@ -114,9 +118,9 @@ pub fn parse_yaml(yaml: &str) -> Result { { for (name, ss_val) in security_schemes { if let Some(name_str) = name.as_str() { - match serde_yaml::from_value::( - ss_val.clone(), - ) { + use serde::Deserialize; + // Optimization: Use T::deserialize(&value) to avoid expensive deep clones of JSON/YAML values + match crate::components::SecurityScheme::deserialize(ss_val) { Ok(ss) => ctx.add_security_scheme(name_str.to_string(), ss), Err(e) => { eprintln!("Warning: Failed to parse securityScheme {name_str}: {e}") @@ -211,7 +215,9 @@ pub fn parse_json(json: &str) -> Result { OpenApiContextGuard::with_context_mut(|ctx| { if let Some(schemas) = components.get("schemas").and_then(|s| s.as_object()) { for (name, schema_val) in schemas { - match serde_json::from_value::(schema_val.clone()) { + use serde::Deserialize; + // Optimization: Use T::deserialize(&value) to avoid expensive deep clones of JSON/YAML values + match crate::components::Schema::deserialize(schema_val) { Ok(schema) => ctx.add_schema(name.clone(), schema), Err(e) => eprintln!("Warning: Failed to parse schema {name}: {e}"), } @@ -219,8 +225,9 @@ pub fn parse_json(json: &str) -> Result { } if let Some(parameters) = components.get("parameters").and_then(|p| p.as_object()) { for (name, param_val) in parameters { - match serde_json::from_value::(param_val.clone()) - { + use serde::Deserialize; + // Optimization: Use T::deserialize(&value) to avoid expensive deep clones of JSON/YAML values + match crate::components::Parameter::deserialize(param_val) { Ok(param) => ctx.add_parameter(name.clone(), param), Err(e) => eprintln!("Warning: Failed to parse parameter {name}: {e}"), } @@ -228,7 +235,9 @@ pub fn parse_json(json: &str) -> Result { } if let Some(responses) = components.get("responses").and_then(|r| r.as_object()) { for (name, resp_val) in responses { - match serde_json::from_value::(resp_val.clone()) { + use serde::Deserialize; + // Optimization: Use T::deserialize(&value) to avoid expensive deep clones of JSON/YAML values + match crate::core::Response::deserialize(resp_val) { Ok(resp) => ctx.add_response(name.clone(), resp), Err(e) => eprintln!("Warning: Failed to parse response {name}: {e}"), } @@ -239,7 +248,9 @@ pub fn parse_json(json: &str) -> Result { .and_then(|rb| rb.as_object()) { for (name, rb_val) in request_bodies { - match serde_json::from_value::(rb_val.clone()) { + use serde::Deserialize; + // Optimization: Use T::deserialize(&value) to avoid expensive deep clones of JSON/YAML values + match crate::core::RequestBody::deserialize(rb_val) { Ok(rb) => ctx.add_request_body(name.clone(), rb), Err(e) => eprintln!("Warning: Failed to parse requestBody {name}: {e}"), } @@ -250,9 +261,9 @@ pub fn parse_json(json: &str) -> Result { .and_then(|ss| ss.as_object()) { for (name, ss_val) in security_schemes { - match serde_json::from_value::( - ss_val.clone(), - ) { + use serde::Deserialize; + // Optimization: Use T::deserialize(&value) to avoid expensive deep clones of JSON/YAML values + match crate::components::SecurityScheme::deserialize(ss_val) { Ok(ss) => ctx.add_security_scheme(name.clone(), ss), Err(e) => { eprintln!("Warning: Failed to parse securityScheme {name}: {e}")