oxygengine_overworld/resources/
bank.rs

1use crate::resources::market::Currency;
2use oxygengine_core::id::ID;
3use std::collections::HashMap;
4
5pub type BankAccountId = ID<BankAccount<()>>;
6
7#[derive(Debug, Clone)]
8pub enum BankError<T>
9where
10    T: Currency,
11{
12    AccountDoesNotExists(BankAccountId),
13    CouldNotDeposit(BankAccountId, T),
14    CouldNotWithdraw(BankAccountId, T),
15    CouldNotTransfer(BankAccountId, BankAccountId, T),
16}
17
18#[derive(Debug, Default, Clone)]
19pub struct BankAccount<T>
20where
21    T: Currency + std::fmt::Debug + Default + Clone + Send + Sync,
22{
23    pub value: T,
24}
25
26#[derive(Debug, Clone)]
27pub struct Bank<T>
28where
29    T: Currency + std::fmt::Debug + Default + Clone + Send + Sync,
30{
31    accounts: HashMap<BankAccountId, BankAccount<T>>,
32}
33
34impl<T> Default for Bank<T>
35where
36    T: Currency + std::fmt::Debug + Default + Clone + Send + Sync,
37{
38    fn default() -> Self {
39        Self {
40            accounts: Default::default(),
41        }
42    }
43}
44
45impl<T> Bank<T>
46where
47    T: Currency + std::fmt::Debug + Default + Clone + Send + Sync,
48{
49    pub fn create_account(&mut self) -> BankAccountId {
50        let id = BankAccountId::new();
51        self.accounts.insert(id, Default::default());
52        id
53    }
54
55    pub fn remove_account(&mut self, id: BankAccountId) -> Result<T, BankError<T>> {
56        match self.accounts.remove(&id) {
57            Some(account) => Ok(account.value),
58            None => Err(BankError::AccountDoesNotExists(id)),
59        }
60    }
61
62    pub fn accounts(&self) -> impl Iterator<Item = (BankAccountId, &BankAccount<T>)> {
63        self.accounts.iter().map(|(id, account)| (*id, account))
64    }
65
66    pub fn deposit(&mut self, id: BankAccountId, value: T) -> Result<(), BankError<T>> {
67        match self.accounts.get_mut(&id) {
68            Some(account) => match account.value.accumulate(value) {
69                Ok(value) => {
70                    account.value = value;
71                    Ok(())
72                }
73                Err(_) => Err(BankError::CouldNotDeposit(id, value)),
74            },
75            None => Err(BankError::AccountDoesNotExists(id)),
76        }
77    }
78
79    pub fn withdraw(&mut self, id: BankAccountId, value: T) -> Result<T, BankError<T>> {
80        match self.accounts.get_mut(&id) {
81            Some(account) => match account.value.take(value) {
82                Ok((left, taken)) => {
83                    account.value = left;
84                    Ok(taken)
85                }
86                Err(_) => Err(BankError::CouldNotDeposit(id, value)),
87            },
88            None => Err(BankError::AccountDoesNotExists(id)),
89        }
90    }
91
92    pub fn transfer(
93        &mut self,
94        from: BankAccountId,
95        to: BankAccountId,
96        value: T,
97    ) -> Result<(), BankError<T>> {
98        if from == to {
99            return Ok(());
100        }
101        let from_value = match self.accounts.get(&from) {
102            Some(from) => from.value,
103            None => return Err(BankError::AccountDoesNotExists(from)),
104        };
105        let to_value = match self.accounts.get(&to) {
106            Some(to) => to.value,
107            None => return Err(BankError::AccountDoesNotExists(to)),
108        };
109        let (from_value, to_value) = match from_value.exchange(to_value, value) {
110            Ok(result) => result,
111            Err(_) => return Err(BankError::CouldNotTransfer(from, to, value)),
112        };
113        self.accounts.get_mut(&from).unwrap().value = from_value;
114        self.accounts.get_mut(&to).unwrap().value = to_value;
115        Ok(())
116    }
117
118    pub fn batched_transfers<'a>(
119        &'a mut self,
120        iter: impl Iterator<Item = (BankAccountId, BankAccountId, T)> + 'a,
121    ) -> impl Iterator<Item = BankError<T>> + 'a {
122        iter.filter_map(|(from, to, value)| match self.transfer(from, to, value) {
123            Ok(_) => None,
124            Err(error) => Some(error),
125        })
126    }
127}