pub trait ROI {
fn h_return_on_investment(&self, new_value: f64) -> f64;
}
impl<T> ROI for T
where
T: Copy + Into<f64>,
{
fn h_return_on_investment(&self, new_value: f64) -> f64 {
let start = (*self).into();
(new_value - start) / start * 100.0
}
}
pub trait DiscountedPrice {
fn h_decreased_price(&self, decrease_percent: f64) -> f64;
}
impl<T> DiscountedPrice for T
where
T: Copy + Into<f64>,
{
fn h_decreased_price(&self, decrease_percent: f64) -> f64 {
let percent_discount_opposite: f64 = 1.0 - decrease_percent / 100.0;
percent_discount_opposite * (*self).into()
}
}
pub trait IncreasedPrice {
fn h_increased_price(&self, increase_percent: f64) -> f64;
}
impl<T> IncreasedPrice for T
where
T: Copy + Into<f64>,
{
fn h_increased_price(&self, increase_percent: f64) -> f64 {
let percent_increas_plus_one: f64 = 1.0 + increase_percent / 100.0;
percent_increas_plus_one * (*self).into()
}
}
pub trait IncreasePercentFromOriginal {
fn h_increase_percent_from_original(&self, new_value: f64) -> f64;
}
impl<T> IncreasePercentFromOriginal for T
where
T: Copy + Into<f64>,
{
fn h_increase_percent_from_original(&self, new_value: f64) -> f64 {
let original_value = (*self).into();
((new_value - original_value) / original_value) * 100.0
}
}
pub trait DecreasePercentFromOriginal {
fn h_decrease_percent_from_original(&self, new_value: f64) -> f64;
}
impl<T> DecreasePercentFromOriginal for T
where
T: Copy + Into<f64>,
{
fn h_decrease_percent_from_original(&self, new_value: f64) -> f64 {
let original_value = (*self).into();
((original_value - new_value) / original_value) * 100.0
}
}
pub trait BracketTaxPaid<Start, End, Percent>
where
Start: Copy + Into<f64>,
End: Copy + Into<f64>,
Percent: Copy + Into<f64>,
{
fn h_bracket_tax_paid(&self, brackets: Vec<(Start, End, Percent)>) -> Option<f64>;
}
impl<V, Start, End, Percent> BracketTaxPaid<Start, End, Percent> for V
where
V: Copy + PartialEq + Into<f64>,
Start: Copy + PartialEq + Into<f64>,
End: Copy + PartialEq + Into<f64>,
Percent: Copy + PartialEq + Into<f64>,
{
fn h_bracket_tax_paid(&self, brackets: Vec<(Start, End, Percent)>) -> Option<f64> {
if (*self).into() <= 0.0 {
return None;
}
let mut prev_item: Option<&(Start, End, Percent)> = None;
let income: f64 = (*self).into();
let mut sum: f64 = 0.0;
for item in &brackets {
if item.2.into() > 100.0 {
return None;
}
if let Some(prev) = prev_item {
if prev.0.into() > item.0.into() || prev.1.into() >= item.1.into() {
return None;
}
}
prev_item = Some(item);
let start: f64 = item.0.into() - 1.0;
let end: f64 = item.1.into();
let rate: f64 = item.2.into() / 100.0;
if income <= start {
break;
}
let taxable = end.min(income) - start;
sum += taxable * rate;
if income < end {
break;
}
}
return Some(sum);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_roi() {
assert_eq!(100.0.h_return_on_investment(150.0), 50.0);
assert_eq!(200.0.h_return_on_investment(180.0), -10.0);
}
#[test]
fn test_decreased_price() {
assert_eq!(100.0.h_decreased_price(20.0), 80.0);
assert_eq!(200.0.h_decreased_price(10.0), 180.0);
}
#[test]
fn test_increased_price() {
assert!((100.0.h_increased_price(20.0) - 120.0).abs() < 1e-10);
assert!((200.0.h_increased_price(10.0) - 220.0).abs() < 1e-10);
}
#[test]
fn test_increase_percent_from_original() {
assert_eq!(100.0.h_increase_percent_from_original(150.0), 50.0);
assert_eq!(200.0.h_increase_percent_from_original(180.0), -10.0);
}
#[test]
fn test_decrease_percent_from_original() {
assert_eq!(100.0.h_decrease_percent_from_original(80.0), 20.0);
assert_eq!(200.0.h_decrease_percent_from_original(220.0), -10.0);
}
#[test]
fn test_bracket_tax_paid() {
let brackets = vec![(1, 50, 10), (51, 100, 20)];
assert_eq!(100_i32.h_bracket_tax_paid(brackets), Some(15.0));
let brackets = vec![(1, 50, 10), (51, 100, 20)];
assert_eq!(75_i32.h_bracket_tax_paid(brackets), Some(10.0));
let brackets = vec![(1, 50, 10), (51, 100, 20)];
assert_eq!(0_i32.h_bracket_tax_paid(brackets), None);
let brackets = vec![(1, 50, 101)];
assert_eq!(100_i32.h_bracket_tax_paid(brackets), None);
}
}