vesys-bank-server/bank/src/bank.rs

110 lines
2.8 KiB
Rust

use std::collections::{HashMap, HashSet};
use std::sync::{RwLock, RwLockReadGuard};
#[cfg(test)]
use anyhow::Result;
use crate::account::{Account, AccountError};
#[derive(Default)]
pub struct Bank {
pub accounts: HashMap<String, RwLock<Account>>,
}
impl Bank {
pub fn new() -> Self {
Default::default()
}
pub fn account_action<F: Fn(&mut Account) -> Result<f64, AccountError>>(
bank: RwLockReadGuard<'_, Bank>,
nr: &str,
action: F,
) -> Result<f64, AccountError> {
match bank.accounts.get(nr) {
None => Err(AccountError::NotFound),
Some(account) => {
let mut account = account.write().unwrap();
action(&mut account)
}
}
}
pub fn account_numbers(&self) -> HashSet<String> {
self.accounts
.iter()
.filter(|(_, acc)| acc.read().unwrap().is_active)
.map(|(_, acc)| acc.read().unwrap().number.clone())
.collect()
}
pub fn create_account(&mut self, owner: String) -> String {
let acc = Account {
owner,
..Default::default()
};
let nr = acc.number.clone();
self.accounts.insert(acc.number.clone(), RwLock::new(acc));
nr
}
pub fn transfer(
&self,
from: &mut Account,
to: &mut Account,
amount: f64,
) -> Result<(), AccountError> {
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());
assert!(bank.accounts.get("thisisnotauuid").is_none());
}
#[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());
}
}