✨ 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;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
|
||||||
/// An application-specific error type
|
/// An application-specific error type
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum AccountingError {
|
enum AccountingError {
|
||||||
// Add variants here for account not found, account underfunded and account overfunded
|
// Add variants here for account not found, account underfunded and account overfunded
|
||||||
AccountNotFound(String) ,
|
AccountNotFound(String),
|
||||||
AccountUnderFunded(String, u64),
|
AccountUnderFunded(String, u64),
|
||||||
AccountOverFunded(String, u64),
|
AccountOverFunded(String, u64),
|
||||||
}
|
}
|
||||||
|
@ -15,8 +14,8 @@ enum AccountingError {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Tx {
|
pub enum Tx {
|
||||||
// Add variants for storing withdraw/deposit transactions
|
// Add variants for storing withdraw/deposit transactions
|
||||||
Withdraw{account:String, amount:u64},
|
Withdraw { account: String, amount: u64 },
|
||||||
Deposit{account:String, amount:u64},
|
Deposit { account: String, amount: u64 },
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A type for managing accounts and their current currency balance
|
/// A type for managing accounts and their current currency balance
|
||||||
|
@ -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,
|
||||||
|
@ -64,12 +64,32 @@ impl Accounts {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Withdraws the `amount` from the `signer` account.
|
/// Withdraws the `amount` from the `signer` account.
|
||||||
/// # 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())),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue