use crate::core::sync_mode::SyncMode;
use crate::core::AccountControl;
use crate::marketdata::MarketDataSync;
use crate::param::{AccountId, PositionSize};
use crate::pretrade::holdings::Holdings;
use crate::pretrade::{AccountBlock, RejectCode};
use crate::{Mutation, Mutations};
use super::{HoldingsKey, SpotFundsPolicy};
fn record_rollback_overflow<StorageFactory>(
account_control: &Option<AccountControl<StorageFactory>>,
details: impl FnOnce() -> String,
) where
StorageFactory: crate::storage::LockingPolicyFactory
+ crate::storage::CreateStorageFor<AccountId>
+ 'static,
{
if let Some(ctrl) = account_control {
let block = AccountBlock::new(
SpotFundsPolicyName::NAME,
RejectCode::ArithmeticOverflow,
"rollback overflow: slot left inconsistent",
details(),
);
ctrl.block(block);
}
}
struct SpotFundsPolicyName;
impl SpotFundsPolicyName {
const NAME: &'static str = "SpotFundsPolicy";
}
impl<Sync, MarketDataSyncMode> SpotFundsPolicy<Sync, MarketDataSyncMode>
where
Sync: SyncMode,
MarketDataSyncMode: MarketDataSync,
{
pub(super) fn register_hold_rollback(
&self,
mutations: &mut Mutations,
account_control: Option<AccountControl<<Sync as SyncMode>::StorageLockingPolicyFactory>>,
key: HoldingsKey,
amount: PositionSize,
) where
<<Sync as SyncMode>::StorageLockingPolicyFactory as crate::storage::LockingPolicyFactory>::Policy: 'static,
{
let holdings_arc = self.holdings.clone();
mutations.push(Mutation::new(
|| {},
move || {
let key_for_remove = key.clone();
let account_id = key.0;
let asset_for_diagnostic = key.1.clone();
let became_zero = holdings_arc.with_mut(key, Holdings::zero, |slot, _| {
match slot.release(amount) {
Ok(undone) => {
*slot = undone;
undone.is_zero()
}
Err(_) => {
record_rollback_overflow(&account_control, || {
format!(
"hold rollback overflow: account {account_id}, \
asset {asset_for_diagnostic}, release {amount}, \
slot {slot:?}",
)
});
slot.is_zero()
}
}
});
if became_zero {
holdings_arc.remove_if_zero(&key_for_remove);
}
},
));
}
pub(super) fn register_adjustment_rollback(
&self,
mutations: &mut Mutations,
account_control: Option<AccountControl<<Sync as SyncMode>::StorageLockingPolicyFactory>>,
key: HoldingsKey,
available_delta: PositionSize,
held_delta: PositionSize,
incoming_delta: PositionSize,
) where
<<Sync as SyncMode>::StorageLockingPolicyFactory as crate::storage::LockingPolicyFactory>::Policy: 'static,
{
let holdings_arc = self.holdings.clone();
mutations.push(Mutation::new(
|| {},
move || {
let key_for_remove = key.clone();
let account_id = key.0;
let asset_for_diagnostic = key.1.clone();
let became_zero = holdings_arc.with_mut(key, Holdings::zero, |slot, _| {
match slot.apply_delta_rollback(available_delta, held_delta, incoming_delta) {
Ok(rolled_back) => {
*slot = rolled_back;
rolled_back.is_zero()
}
Err(_) => {
record_rollback_overflow(&account_control, || {
format!(
"adjustment rollback overflow: account {account_id}, \
asset {asset_for_diagnostic}, \
available_delta {available_delta}, \
held_delta {held_delta}, \
incoming_delta {incoming_delta}, \
slot {slot:?}",
)
});
slot.is_zero()
}
}
});
if became_zero {
holdings_arc.remove_if_zero(&key_for_remove);
}
},
));
}
}