Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,10 @@ unseparated_literal_suffix = "warn"
unused_trait_names = "warn"
unwrap_used = "warn"

[profile.release]
lto = "thin" # Link-Time Optimization: enables cross-crate inlining
codegen-units = 1 # Single codegen unit allows more aggressive optimizations

[profile.bench]
lto = "thin" # Link-Time Optimization: enables cross-crate inlining
codegen-units = 1 # Single codegen unit allows more aggressive optimizations
10 changes: 8 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,8 +285,14 @@ async fn request<Response: DeserializeOwned>(
return Err(Error::status(status_code, method, path, message));
}

let json_value = response.json::<serde_json::Value>().await?;
let response_data: Option<Response> = serde_helpers::deserialize_with_warnings(json_value)?;
#[cfg(feature = "tracing")]
let response_data: Option<Response> = {
let json_value = response.json::<serde_json::Value>().await?;
serde_helpers::deserialize_with_warnings(json_value)?
};

#[cfg(not(feature = "tracing"))]
let response_data: Option<Response> = response.json().await?;

if let Some(response) = response_data {
Ok(response)
Expand Down
27 changes: 13 additions & 14 deletions src/serde_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
//! When the `tracing` feature is enabled, this module also logs warnings for any
//! unknown fields encountered during deserialization, helping detect API changes.

#[cfg(any(
feature = "bridge",
feature = "clob",
feature = "data",
feature = "gamma",
#[cfg(all(
any(feature = "tracing", test),
any(
feature = "bridge",
feature = "clob",
feature = "data",
feature = "gamma",
)
))]
use {serde::de::DeserializeOwned, serde_json::Value};

Expand Down Expand Up @@ -122,23 +125,19 @@ pub fn deserialize_with_warnings<T: DeserializeOwned>(value: Value) -> crate::Re
"deserializing JSON"
);

// Clone the value so we can look up unknown field values later
let original = value.clone();

// Collect unknown field paths during deserialization
let raw_json = value.to_string();
let mut unknown_paths: Vec<String> = Vec::new();

let result: T = serde_ignored::deserialize(value, |path| {
unknown_paths.push(path.to_string());
})
.inspect_err(|_| {
// Re-deserialize with serde_path_to_error to get the error path
let json_str = original.to_string();
let jd = &mut serde_json::Deserializer::from_str(&json_str);
let jd = &mut serde_json::Deserializer::from_str(&raw_json);
let path_result: Result<T, _> = serde_path_to_error::deserialize(jd);
if let Err(path_err) = path_result {
let path = path_err.path().to_string();
let inner_error = path_err.inner();
let original: Value = serde_json::from_str(&raw_json).unwrap_or_default();
let value_at_path = lookup_value(&original, &path);
let value_display = format_value(value_at_path);

Expand All @@ -152,8 +151,8 @@ pub fn deserialize_with_warnings<T: DeserializeOwned>(value: Value) -> crate::Re
}
})?;

// Log warnings for unknown fields with their values
if !unknown_paths.is_empty() {
let original: Value = serde_json::from_str(&raw_json).unwrap_or_default();
let type_name = type_name::<T>();
for path in unknown_paths {
let field_value = lookup_value(&original, &path);
Expand All @@ -171,8 +170,8 @@ pub fn deserialize_with_warnings<T: DeserializeOwned>(value: Value) -> crate::Re
Ok(result)
}

/// Pass-through deserialization when tracing is disabled.
#[cfg(all(
test,
not(feature = "tracing"),
any(
feature = "bridge",
Expand Down
Loading