2022-03-12 15:19:54 +00:00
|
|
|
use std::collections::{HashMap, HashSet};
|
2022-03-18 18:35:34 +00:00
|
|
|
use std::sync::{RwLock, RwLockReadGuard};
|
2022-03-12 15:19:54 +00:00
|
|
|
|
2022-03-18 18:35:34 +00:00
|
|
|
use crate::account::{Account, AccountError};
|
2022-03-12 15:19:54 +00:00
|
|
|
|
2022-03-18 18:35:34 +00:00
|
|
|
#[derive(Default)]
|
2022-03-12 15:19:54 +00:00
|
|
|
pub struct Bank {
|
|
|
|
pub accounts: HashMap<String, RwLock<Account>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Bank {
|
|
|
|
pub fn new() -> Self {
|
2022-03-18 18:35:34 +00:00
|
|
|
Default::default()
|
|
|
|
}
|
|
|
|
|
2022-03-30 07:36:59 +00:00
|
|
|
pub fn account_action<F: Fn(&mut Account) -> Result<R, AccountError>, R>(
|
2022-03-18 18:35:34 +00:00
|
|
|
bank: RwLockReadGuard<'_, Bank>,
|
|
|
|
nr: &str,
|
|
|
|
action: F,
|
2022-03-30 07:36:59 +00:00
|
|
|
) -> Result<R, AccountError> {
|
2022-03-18 18:35:34 +00:00
|
|
|
match bank.accounts.get(nr) {
|
|
|
|
None => Err(AccountError::NotFound),
|
|
|
|
Some(account) => {
|
|
|
|
let mut account = account.write().unwrap();
|
|
|
|
action(&mut account)
|
|
|
|
}
|
|
|
|
}
|
2022-03-12 15:19:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn account_numbers(&self) -> HashSet<String> {
|
2022-03-18 18:35:34 +00:00
|
|
|
self.accounts
|
|
|
|
.iter()
|
2022-03-12 15:19:54 +00:00
|
|
|
.filter(|(_, acc)| acc.read().unwrap().is_active)
|
|
|
|
.map(|(_, acc)| acc.read().unwrap().number.clone())
|
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn create_account(&mut self, owner: String) -> String {
|
2022-03-18 18:35:34 +00:00
|
|
|
let acc = Account {
|
|
|
|
owner,
|
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
let nr = acc.number.clone();
|
2022-03-12 15:19:54 +00:00
|
|
|
|
|
|
|
self.accounts.insert(acc.number.clone(), RwLock::new(acc));
|
|
|
|
|
2022-03-18 18:35:34 +00:00
|
|
|
nr
|
2022-03-12 15:19:54 +00:00
|
|
|
}
|
|
|
|
|
2022-03-18 18:35:34 +00:00
|
|
|
pub fn transfer(
|
|
|
|
&self,
|
|
|
|
from: &mut Account,
|
|
|
|
to: &mut Account,
|
|
|
|
amount: f64,
|
|
|
|
) -> Result<(), AccountError> {
|
2022-03-12 15:19:54 +00:00
|
|
|
from.withdraw(amount)?;
|
|
|
|
to.deposit(amount)?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn creation() {
|
|
|
|
let mut bank = Bank::new();
|
|
|
|
let nr = bank.create_account("Rohaja".into());
|
|
|
|
|
|
|
|
assert!(bank.accounts.get(&nr).is_some());
|
2022-03-16 08:51:29 +00:00
|
|
|
assert!(bank.accounts.get("thisisnotauuid").is_none());
|
2022-03-12 15:19:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn transfer() {
|
|
|
|
let mut bank = Bank::new();
|
|
|
|
let nr1 = bank.create_account("Rohaja".into());
|
|
|
|
let nr2 = bank.create_account("Hal".into());
|
|
|
|
|
|
|
|
{
|
|
|
|
let mut acc1 = bank.accounts.get(&nr1).unwrap().write().unwrap();
|
|
|
|
let mut acc2 = bank.accounts.get(&nr2).unwrap().write().unwrap();
|
|
|
|
|
|
|
|
let result = bank.transfer(&mut acc1, &mut acc2, 100_f64);
|
|
|
|
assert!(result.is_err());
|
|
|
|
|
|
|
|
acc1.deposit(100_f64).unwrap();
|
|
|
|
let result = bank.transfer(&mut acc1, &mut acc2, 50_f64);
|
|
|
|
assert!(result.is_ok());
|
|
|
|
assert_eq!(acc2.balance, 50_f64);
|
|
|
|
|
|
|
|
let result = bank.transfer(&mut acc1, &mut acc2, -50_f64);
|
|
|
|
assert!(result.is_err());
|
|
|
|
|
|
|
|
acc2.withdraw(50_f64).unwrap();
|
|
|
|
assert!(acc2.passivate());
|
|
|
|
|
|
|
|
let result = bank.transfer(&mut acc1, &mut acc2, 50_f64);
|
|
|
|
assert!(result.is_err());
|
|
|
|
}
|
|
|
|
|
|
|
|
assert_eq!(1, bank.account_numbers().len());
|
|
|
|
}
|
2022-03-18 18:35:34 +00:00
|
|
|
}
|