✨ Feature: Add Transaction Functions
You can now deposit, withdraw, and send money
This commit is contained in:
parent
581c06fc2f
commit
b1b115b45c
2 changed files with 59 additions and 13 deletions
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
|
@ -0,0 +1,7 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "accounting-with-fundamental-rust-1"
|
||||
version = "0.1.0"
|
65
src/main.rs
65
src/main.rs
|
@ -1,11 +1,10 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
|
||||
/// An application-specific error type
|
||||
#[derive(Debug)]
|
||||
enum AccountingError {
|
||||
// Add variants here for account not found, account underfunded and account overfunded
|
||||
AccountNotFound(String) ,
|
||||
AccountNotFound(String),
|
||||
AccountUnderFunded(String, u64),
|
||||
AccountOverFunded(String, u64),
|
||||
}
|
||||
|
@ -15,8 +14,8 @@ enum AccountingError {
|
|||
#[derive(Debug)]
|
||||
pub enum Tx {
|
||||
// Add variants for storing withdraw/deposit transactions
|
||||
Withdraw{account:String, amount:u64},
|
||||
Deposit{account:String, amount:u64},
|
||||
Withdraw { account: String, amount: u64 },
|
||||
Deposit { account: String, amount: u64 },
|
||||
}
|
||||
|
||||
/// A type for managing accounts and their current currency balance
|
||||
|
@ -27,11 +26,10 @@ struct Accounts {
|
|||
}
|
||||
|
||||
impl Accounts {
|
||||
|
||||
/// Returns an empty instance of the [`Accounts`] type
|
||||
pub fn new() -> Self {
|
||||
Accounts {
|
||||
accounts: Default::default()
|
||||
accounts: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,11 +39,13 @@ impl Accounts {
|
|||
pub fn deposit(&mut self, signer: &str, amount: u64) -> Result<Tx, AccountingError> {
|
||||
if let Some(account) = self.accounts.get_mut(signer) {
|
||||
(*account)
|
||||
// check the ammount to add and then add it
|
||||
.checked_add(amount)
|
||||
.and_then(|r| {
|
||||
*account = r;
|
||||
Some(r)
|
||||
})
|
||||
// if ok do nothing or if not ok throw error
|
||||
.ok_or(AccountingError::AccountOverFunded(
|
||||
signer.to_string(),
|
||||
amount,
|
||||
|
@ -64,12 +64,32 @@ impl Accounts {
|
|||
}
|
||||
}
|
||||
|
||||
/// Withdraws the `amount` from the `signer` account.
|
||||
/// # Errors
|
||||
/// Attempted overflow
|
||||
pub fn withdraw(&mut self, signer: &str, amount: u64) -> Result<Tx, AccountingError> {
|
||||
todo!();
|
||||
}
|
||||
/// Withdraws the `amount` from the `signer` account.
|
||||
/// # Errors
|
||||
/// Attempted overflow
|
||||
pub fn withdraw(&mut self, signer: &str, amount: u64) -> Result<Tx, AccountingError> {
|
||||
//check if account exists
|
||||
if let Some(account) = self.accounts.get_mut(signer) {
|
||||
(*account)
|
||||
.checked_sub(amount)
|
||||
.and_then(|r| {
|
||||
*account = r;
|
||||
Some(r)
|
||||
})
|
||||
.ok_or(AccountingError::AccountUnderFunded(
|
||||
signer.to_string(),
|
||||
amount,
|
||||
))
|
||||
.map(|_| Tx::Withdraw {
|
||||
account: signer.to_string(),
|
||||
amount,
|
||||
})
|
||||
} else {
|
||||
//if acount does not exist
|
||||
Err(AccountingError::AccountNotFound(signer.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Withdraws the amount from the sender account and deposits it in the recipient account.
|
||||
///
|
||||
|
@ -81,7 +101,26 @@ impl Accounts {
|
|||
recipient: &str,
|
||||
amount: u64,
|
||||
) -> Result<(Tx, Tx), AccountingError> {
|
||||
todo!();
|
||||
match self.accounts.get(sender) {
|
||||
Some(amt) if self.accounts.contains_key(recipient) && *amt >= amount => {
|
||||
// The ? operator is a built-in shorthand for
|
||||
// if let Err(e) = my_func_call() { return Err(e); }
|
||||
let tx_withdraw = self.withdraw(sender, amount)?;
|
||||
self.deposit(recipient, amount)
|
||||
.map_err(|e| {
|
||||
// return the funds to the sender on error
|
||||
self.deposit(sender, amount).unwrap();
|
||||
e
|
||||
})
|
||||
.map(|tx_deposit| (tx_withdraw, tx_deposit))
|
||||
}
|
||||
Some(amt) if self.accounts.contains_key(recipient) && *amt < amount => Err(
|
||||
AccountingError::AccountUnderFunded(sender.to_owned(), amount),
|
||||
),
|
||||
// The matching rules are evaluated from top to bottom and since all other cases where covered before, this rule means that the recipient's account wasn't found
|
||||
Some(_) => Err(AccountingError::AccountNotFound(recipient.to_owned())),
|
||||
None => Err(AccountingError::AccountNotFound(sender.to_string())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue