split bank ad socket server up
This commit is contained in:
parent
3d9c98eeca
commit
c69654a924
22 changed files with 342 additions and 43 deletions
143
bank/src/account.rs
Normal file
143
bank/src/account.rs
Normal file
|
@ -0,0 +1,143 @@
|
|||
use std::hash::{Hash, Hasher};
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use thiserror::Error;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::account::AccountError::{Inactive, InvalidAmount, Overdraw};
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum AccountError {
|
||||
#[error("can not overdraw account")]
|
||||
Overdraw(),
|
||||
#[error("account is inactive")]
|
||||
Inactive(),
|
||||
#[error("amount must be > 0")]
|
||||
InvalidAmount(),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Account {
|
||||
pub number: String,
|
||||
pub owner: String,
|
||||
pub balance: f64,
|
||||
pub is_active: bool,
|
||||
}
|
||||
|
||||
impl Default for Account {
|
||||
fn default() -> Self {
|
||||
Account {
|
||||
number: Uuid::new_v4().to_string(),
|
||||
owner: "".into(),
|
||||
balance: 0_f64,
|
||||
is_active: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Account {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.number == other.number
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Account {}
|
||||
|
||||
impl Hash for Account {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.number.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl Account {
|
||||
#[cfg(test)]
|
||||
pub fn new() -> Self {
|
||||
Self { ..Default::default() }
|
||||
}
|
||||
|
||||
pub fn deposit(&mut self, amount: f64) -> Result<()> {
|
||||
self.check_account(amount)?;
|
||||
self.balance += amount;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn withdraw(&mut self, amount: f64) -> Result<()> {
|
||||
self.check_account(amount)?;
|
||||
|
||||
if self.balance - amount < 0 as f64 {
|
||||
bail!(Overdraw());
|
||||
}
|
||||
self.balance -= amount;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_account(&self, amount: f64) -> Result<()> {
|
||||
if !self.is_active {
|
||||
bail!(Inactive());
|
||||
}
|
||||
|
||||
if amount < 0 as f64 {
|
||||
bail!(InvalidAmount());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn passivate(&mut self) -> bool {
|
||||
let is_passivated = self.balance <= 0 as f64 && self.is_active;
|
||||
|
||||
if is_passivated {
|
||||
self.is_active = false;
|
||||
}
|
||||
|
||||
is_passivated
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn deposits() {
|
||||
let mut acc = Account::new();
|
||||
|
||||
let ok_result = acc.deposit(10.56);
|
||||
assert!(ok_result.is_ok());
|
||||
|
||||
let err_result = acc.deposit(-5.89);
|
||||
assert!(err_result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn withdrawals() {
|
||||
let mut acc = Account::new();
|
||||
|
||||
let ok_result1 = acc.deposit(10_f64);
|
||||
assert!(ok_result1.is_ok());
|
||||
|
||||
let ok_result2 = acc.withdraw(5_f64);
|
||||
assert!(ok_result2.is_ok());
|
||||
|
||||
let err_result1 = acc.withdraw(10_f64);
|
||||
assert!(err_result1.is_err());
|
||||
|
||||
let err_result2 = acc.withdraw(-10_f64);
|
||||
assert!(err_result2.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn passivation() {
|
||||
let mut acc = Account::new();
|
||||
let deposit_amount = 100_f64;
|
||||
|
||||
acc.deposit(deposit_amount).unwrap();
|
||||
|
||||
assert!(!acc.passivate());
|
||||
acc.withdraw(deposit_amount).unwrap();
|
||||
|
||||
assert!(acc.passivate());
|
||||
assert!(!acc.passivate());
|
||||
}
|
||||
}
|
86
bank/src/bank.rs
Normal file
86
bank/src/bank.rs
Normal file
|
@ -0,0 +1,86 @@
|
|||
use std::collections::{HashMap, HashSet};
|
||||
use std::sync::RwLock;
|
||||
|
||||
#[cfg(test)]
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::account::Account;
|
||||
|
||||
pub struct Bank {
|
||||
pub accounts: HashMap<String, RwLock<Account>>,
|
||||
}
|
||||
|
||||
impl Bank {
|
||||
pub fn new() -> Self {
|
||||
Self { accounts: HashMap::new() }
|
||||
}
|
||||
|
||||
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 number = acc.number.clone();
|
||||
|
||||
self.accounts.insert(acc.number.clone(), RwLock::new(acc));
|
||||
|
||||
number
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn transfer(&self, from: &mut Account, to: &mut Account, amount: f64) -> Result<()> {
|
||||
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());
|
||||
}
|
||||
}
|
2
bank/src/lib.rs
Normal file
2
bank/src/lib.rs
Normal file
|
@ -0,0 +1,2 @@
|
|||
pub mod account;
|
||||
pub mod bank;
|
Loading…
Add table
Add a link
Reference in a new issue