Skip to main content

polyester/codecs/decode/
money.rs

1//! Read-side money decoders (Go `codecs.DecodePriceTicks` / `DecodeQtyScaled` parity).
2
3use crate::types::{AssetAmount, Price, Quantity, QuantityDomain};
4
5pub fn decode_price_ticks(ticks: i64, symbol: Option<String>) -> Option<Price> {
6    if ticks == 0 {
7        return None;
8    }
9    Price::from_ticks(ticks, symbol).ok()
10}
11
12/// Decode price ticks where a present zero is meaningful.
13pub fn decode_price_ticks_allow_zero(ticks: i64, symbol: Option<String>) -> Option<Price> {
14    Price::from_ticks(ticks, symbol).ok()
15}
16
17pub fn decode_qty_scaled(
18    scaled: i64,
19    scale: Option<u32>,
20    symbol: Option<String>,
21    symbol_id: Option<u32>,
22) -> Option<Quantity> {
23    if scaled == 0 {
24        return None;
25    }
26    Quantity::from_scaled(scaled, scale, QuantityDomain::OrderBase, symbol, symbol_id).ok()
27}
28
29/// Decode qty where zero is meaningful (e.g. fully filled `leaves_qty` / `cum_qty`).
30///
31/// Negative wire values are invalid and map to [`None`] (corruption), distinct from
32/// a present zero quantity.
33pub fn decode_qty_scaled_allow_zero(
34    scaled: i64,
35    scale: Option<u32>,
36    symbol: Option<String>,
37    symbol_id: Option<u32>,
38) -> Option<Quantity> {
39    if scaled < 0 {
40        return None;
41    }
42    Quantity::from_scaled(scaled, scale, QuantityDomain::OrderBase, symbol, symbol_id).ok()
43}
44
45/// Decode protobuf U128 hi/lo into an [`AssetAmount`] (ledger/asset domains).
46pub fn decode_asset_amount_u128(
47    hi: u64,
48    lo: u64,
49    scale: Option<u32>,
50    domain: QuantityDomain,
51    asset_id: Option<u32>,
52) -> Option<AssetAmount> {
53    let value = (u128::from(hi) << 64) | u128::from(lo);
54    let scaled = i128::try_from(value).ok()?;
55    AssetAmount::from_scaled(scaled, scale, domain, asset_id).ok()
56}