mirror of
https://github.com/floor-licker/polyfill-rs.git
synced 2026-08-09 18:50:59 +00:00
feat(book): align /book response fields
This commit is contained in:
+14
-2
@@ -1914,7 +1914,11 @@ mod tests {
|
||||
],
|
||||
"asks": [
|
||||
{"price": "0.76", "size": "50.0"}
|
||||
]
|
||||
],
|
||||
"min_order_size": "1",
|
||||
"neg_risk": false,
|
||||
"tick_size": "0.01",
|
||||
"last_trade_price": "0.755"
|
||||
}"#;
|
||||
|
||||
let mock = server
|
||||
@@ -1935,6 +1939,10 @@ mod tests {
|
||||
assert_eq!(book.market, "0x123");
|
||||
assert_eq!(book.bids.len(), 1);
|
||||
assert_eq!(book.asks.len(), 1);
|
||||
assert_eq!(book.min_order_size, Decimal::from_str("1").unwrap());
|
||||
assert!(!book.neg_risk);
|
||||
assert_eq!(book.tick_size, Decimal::from_str("0.01").unwrap());
|
||||
assert_eq!(book.last_trade_price, Some(Decimal::from_str("0.755").unwrap()));
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
@@ -2349,7 +2357,11 @@ mod tests {
|
||||
"hash": "test-hash",
|
||||
"timestamp": "1234567890",
|
||||
"bids": [{"price": "0.75", "size": "100.0"}],
|
||||
"asks": [{"price": "0.76", "size": "50.0"}]
|
||||
"asks": [{"price": "0.76", "size": "50.0"}],
|
||||
"min_order_size": "1",
|
||||
"neg_risk": false,
|
||||
"tick_size": "0.01",
|
||||
"last_trade_price": null
|
||||
}
|
||||
]"#;
|
||||
|
||||
|
||||
@@ -108,6 +108,71 @@ pub mod deserializers {
|
||||
None => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserialize a vec that may be `null` (treat `null` as empty vec).
|
||||
pub fn vec_from_null<'de, D, T>(deserializer: D) -> std::result::Result<Vec<T>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
T: serde::Deserialize<'de>,
|
||||
{
|
||||
Ok(Option::<Vec<T>>::deserialize(deserializer)?.unwrap_or_default())
|
||||
}
|
||||
|
||||
/// Deserialize an optional Decimal from string/number/null.
|
||||
///
|
||||
/// - `null` => `None`
|
||||
/// - `""` => `None`
|
||||
/// - invalid values => error
|
||||
pub fn optional_decimal_from_string<'de, D>(
|
||||
deserializer: D,
|
||||
) -> std::result::Result<Option<Decimal>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let value = serde_json::Value::deserialize(deserializer)?;
|
||||
match value {
|
||||
serde_json::Value::Null => Ok(None),
|
||||
serde_json::Value::String(s) => {
|
||||
let s = s.trim();
|
||||
if s.is_empty() {
|
||||
Ok(None)
|
||||
} else {
|
||||
s.parse::<Decimal>()
|
||||
.map(Some)
|
||||
.map_err(serde::de::Error::custom)
|
||||
}
|
||||
}
|
||||
serde_json::Value::Number(n) => Decimal::from_str(&n.to_string())
|
||||
.map(Some)
|
||||
.map_err(serde::de::Error::custom),
|
||||
other => Err(serde::de::Error::custom(format!(
|
||||
"Expected decimal as string/number/null, got {other}"
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
/// Like `optional_decimal_from_string`, but returns `None` on parse errors.
|
||||
pub fn optional_decimal_from_string_default_on_error<'de, D>(
|
||||
deserializer: D,
|
||||
) -> std::result::Result<Option<Decimal>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let value = serde_json::Value::deserialize(deserializer)?;
|
||||
match value {
|
||||
serde_json::Value::Null => Ok(None),
|
||||
serde_json::Value::String(s) => {
|
||||
let s = s.trim();
|
||||
if s.is_empty() {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(s.parse::<Decimal>().ok())
|
||||
}
|
||||
}
|
||||
serde_json::Value::Number(n) => Ok(Decimal::from_str(&n.to_string()).ok()),
|
||||
_ => Ok(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Raw API response types for efficient parsing
|
||||
|
||||
+13
-2
@@ -1024,14 +1024,25 @@ pub struct BookParams {
|
||||
pub struct OrderBookSummary {
|
||||
pub market: String,
|
||||
pub asset_id: String,
|
||||
pub hash: String,
|
||||
#[serde(default)]
|
||||
pub hash: Option<String>,
|
||||
#[serde(deserialize_with = "crate::decode::deserializers::number_from_string")]
|
||||
pub timestamp: u64,
|
||||
#[serde(default, deserialize_with = "crate::decode::deserializers::vec_from_null")]
|
||||
pub bids: Vec<OrderSummary>,
|
||||
#[serde(default, deserialize_with = "crate::decode::deserializers::vec_from_null")]
|
||||
pub asks: Vec<OrderSummary>,
|
||||
pub min_order_size: Decimal,
|
||||
pub neg_risk: bool,
|
||||
pub tick_size: Decimal,
|
||||
#[serde(
|
||||
default,
|
||||
deserialize_with = "crate::decode::deserializers::optional_decimal_from_string_default_on_error"
|
||||
)]
|
||||
pub last_trade_price: Option<Decimal>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct OrderSummary {
|
||||
#[serde(with = "rust_decimal::serde::str")]
|
||||
pub price: Decimal,
|
||||
|
||||
Reference in New Issue
Block a user