use std::cell::RefCell;
use std::rc::Rc;
use super::reject::AccountBlock;
use crate::core::account_control::DeferredAccountOperations;
use crate::core::{
AccountControl, AccountGroups, AccountGroupsHandle, Accounts, BlockedAccounts, GroupLookup,
};
use crate::param::{AccountGroupId, AccountId, Asset};
use crate::storage::{self, StorageBuilder};
use crate::{Mutation, Mutations};
struct DropCopyState<StorageFactory>
where
StorageFactory: storage::LockingPolicyFactory + storage::CreateStorageFor<AccountId> + 'static,
{
account_control: AccountControl<StorageFactory>,
account_operations: DeferredAccountOperations,
start_mutations: DropCopyStartMutationRecorder,
account: AccountId,
}
#[doc(hidden)]
#[derive(Clone)]
pub struct DropCopyStartMutationRecorder {
mutations: Rc<RefCell<Option<Mutations>>>,
}
impl DropCopyStartMutationRecorder {
fn new() -> Self {
Self {
mutations: Rc::new(RefCell::new(Some(Mutations::new()))),
}
}
#[doc(hidden)]
pub fn record(&self, mutation: Mutation) -> Result<(), Mutation> {
let mut mutations = self.mutations.borrow_mut();
let Some(mutations) = mutations.as_mut() else {
return Err(mutation);
};
mutations.push(mutation);
Ok(())
}
#[doc(hidden)]
pub fn record_with(&self, create: impl FnOnce() -> Mutation) -> bool {
let mut mutations = self.mutations.borrow_mut();
let Some(mutations) = mutations.as_mut() else {
return false;
};
mutations.push(create());
true
}
#[doc(hidden)]
pub fn is_active(&self) -> bool {
self.mutations.borrow().is_some()
}
fn take(&self) -> Mutations {
self.mutations.borrow_mut().take().unwrap_or_default()
}
}
pub struct PreTradeContext<StorageFactory>
where
StorageFactory: storage::LockingPolicyFactory + storage::CreateStorageFor<AccountId> + 'static,
{
pub account_control: Option<AccountControl<StorageFactory>>,
accounts: Option<Accounts<StorageFactory>>,
account: Option<AccountId>,
group_lookup: GroupLookup<StorageFactory>,
drop_copy: Option<Box<DropCopyState<StorageFactory>>>,
}
impl<StorageFactory> PreTradeContext<StorageFactory>
where
StorageFactory: storage::LockingPolicyFactory + storage::CreateStorageFor<AccountId> + 'static,
{
pub(crate) fn with_groups(
account_control: Option<AccountControl<StorageFactory>>,
account_groups: AccountGroupsHandle<StorageFactory>,
account: Option<AccountId>,
) -> Self {
Self {
account_control,
accounts: None,
account,
group_lookup: GroupLookup::new(account_groups, account),
drop_copy: None,
}
}
pub(crate) fn with_accounts(
account_control: Option<AccountControl<StorageFactory>>,
accounts: Accounts<StorageFactory>,
account_groups: AccountGroupsHandle<StorageFactory>,
account: Option<AccountId>,
) -> Self {
Self {
account_control,
accounts: Some(accounts),
account,
group_lookup: GroupLookup::new(account_groups, account),
drop_copy: None,
}
}
pub(crate) fn with_accounts_and_drop_copy(
account_control: AccountControl<StorageFactory>,
accounts: Accounts<StorageFactory>,
account_groups: AccountGroupsHandle<StorageFactory>,
account: AccountId,
) -> Self {
let account_operations = DeferredAccountOperations::default();
let account_control = account_control.with_deferred_operations(account_operations.clone());
Self {
account_control: Some(account_control.clone()),
accounts: Some(accounts),
account: Some(account),
group_lookup: GroupLookup::new(account_groups, Some(account)),
drop_copy: Some(Box::new(DropCopyState {
account_control,
account_operations,
start_mutations: DropCopyStartMutationRecorder::new(),
account,
})),
}
}
pub fn new(account_control: Option<AccountControl<StorageFactory>>) -> Self
where
StorageFactory: Default,
{
let builder = StorageBuilder::new(StorageFactory::default());
let handle = AccountGroupsHandle::from_inner(StorageFactory::new_shared(
AccountGroups::new(&builder),
));
Self::with_groups(account_control, handle, None)
}
pub fn account_group(&self) -> Option<AccountGroupId> {
self.group_lookup.group()
}
pub(crate) fn state_account_group(&self) -> Option<AccountGroupId> {
match (self.accounts.as_ref(), self.account) {
(Some(accounts), Some(account)) => accounts.group_of(account),
_ => self.group_lookup.group(),
}
}
pub(crate) fn account_currency(&self, account_group: Option<AccountGroupId>) -> Option<Asset> {
self.account.and_then(|account| {
self.accounts
.as_ref()?
.currency_of_in_group(account, account_group)
})
}
pub(crate) fn with_state_writer<R>(&self, operation: impl FnOnce() -> R) -> R {
match self.accounts.as_ref() {
Some(accounts) => accounts.with_state_writer(operation),
None => operation(),
}
}
pub(crate) fn state_accounts(&self) -> Option<Accounts<StorageFactory>> {
self.accounts.clone()
}
pub fn is_drop_copy(&self) -> bool {
self.drop_copy.is_some()
}
pub(crate) fn record_drop_copy_account_block(&self, block: AccountBlock) {
if let Some(state) = &self.drop_copy {
state.account_control.block(block);
}
}
pub(crate) fn drop_copy_account_id(&self) -> Option<AccountId> {
self.drop_copy.as_ref().map(|state| state.account)
}
pub fn record_drop_copy_start_mutation(&self, mutation: Mutation) -> Result<(), Mutation> {
let Some(drop_copy) = &self.drop_copy else {
return Err(mutation);
};
drop_copy.start_mutations.record(mutation)
}
#[doc(hidden)]
pub fn drop_copy_start_mutation_recorder(&self) -> Option<DropCopyStartMutationRecorder> {
self.drop_copy
.as_ref()
.map(|state| state.start_mutations.clone())
}
pub(crate) fn drop_copy_account_block(&self) -> Option<AccountBlock> {
self.drop_copy
.as_ref()
.and_then(|state| state.account_operations.first_block())
}
pub(crate) fn apply_drop_copy_account_operations(
&self,
blocked_accounts: &BlockedAccounts<StorageFactory>,
) {
if let Some(state) = &self.drop_copy {
state.account_operations.apply(blocked_accounts);
}
}
pub(crate) fn abandon_drop_copy_account_operations(&self) {
if let Some(state) = &self.drop_copy {
state.account_operations.abandon();
}
}
pub(crate) fn take_drop_copy_start_mutations(&self) -> Mutations {
self.drop_copy
.as_ref()
.map(|state| state.start_mutations.take())
.unwrap_or_default()
}
}
impl<StorageFactory> crate::marketdata::AccountInfo for PreTradeContext<StorageFactory>
where
StorageFactory: storage::LockingPolicyFactory + storage::CreateStorageFor<AccountId> + 'static,
{
fn group(&self) -> Option<AccountGroupId> {
self.account_group()
}
}