Feature: Add Transaction Functions

You can now deposit, withdraw, and send money
This commit is contained in:
James Musselman 2024-08-27 10:43:21 -05:00
parent 581c06fc2f
commit b1b115b45c
Signed by: Musselman
GPG key ID: 1DAEFF35ECB5D6DB
2 changed files with 59 additions and 13 deletions

7
Cargo.lock generated Normal file
View 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"

View file

@ -1,6 +1,5 @@
use std::collections::HashMap; use std::collections::HashMap;
/// An application-specific error type /// An application-specific error type
#[derive(Debug)] #[derive(Debug)]
enum AccountingError { enum AccountingError {
@ -27,11 +26,10 @@ struct Accounts {
} }
impl Accounts { impl Accounts {
/// Returns an empty instance of the [`Accounts`] type /// Returns an empty instance of the [`Accounts`] type
pub fn new() -> Self { pub fn new() -> Self {
Accounts { 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> { pub fn deposit(&mut self, signer: &str, amount: u64) -> Result<Tx, AccountingError> {
if let Some(account) = self.accounts.get_mut(signer) { if let Some(account) = self.accounts.get_mut(signer) {
(*account) (*account)
// check the ammount to add and then add it
.checked_add(amount) .checked_add(amount)
.and_then(|r| { .and_then(|r| {
*account = r; *account = r;
Some(r) Some(r)
}) })
// if ok do nothing or if not ok throw error
.ok_or(AccountingError::AccountOverFunded( .ok_or(AccountingError::AccountOverFunded(
signer.to_string(), signer.to_string(),
amount, amount,
@ -68,8 +68,28 @@ impl Accounts {
/// # Errors /// # Errors
/// Attempted overflow /// Attempted overflow
pub fn withdraw(&mut self, signer: &str, amount: u64) -> Result<Tx, AccountingError> { pub fn withdraw(&mut self, signer: &str, amount: u64) -> Result<Tx, AccountingError> {
todo!(); //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. /// Withdraws the amount from the sender account and deposits it in the recipient account.
/// ///
@ -81,7 +101,26 @@ impl Accounts {
recipient: &str, recipient: &str,
amount: u64, amount: u64,
) -> Result<(Tx, Tx), AccountingError> { ) -> 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())),
}
} }
} }