Lotus 0.2.1

Currency and Number formatting library
Documentation
//! # Lotus
//! `Lotus` is a simple library to provide formatting for currency and numbers.  
//! It makes pretty printing of monetary values convenient.
//!
//! # Usage
//! ```
//! # #[macro_use]
//! # use crate::Lotus::*;
//! // Builder format (recommended)
//! let rupee = LotusBuilder::default()
//!     .symbol("Rs.")
//!     .precision(1)
//!     .format_positive("{symbol} {value}")
//!     .format_negative("{symbol} ({value})")
//!     .format_zero("{symbol} 0.00")
//!     .decimal_str(".")
//!     .thousand_str(" ")
//!     .build()
//!     .unwrap();
//! assert_eq!("Rs. 2 000 000.0", rupee.format(2_000_000));
//! assert_eq!("Rs. (2 000.0)", rupee.format(-2000));
//! assert_eq!("Rs. 0.00", rupee.format(0));
//!
//! // Using Lotus::new()
//! let dollar = Lotus::new("$", 3); // Lotus::new(symbol, precision)
//! assert_eq!("$ 50,000.035", dollar.format(50_000.035));
//!
//! // Using lotus! macro
//! let f = lotus!(150, "$");     // lotus!(number, symbol)
//! assert_eq!("$ 150.00", f);
//! 
//! let g = lotus!(2_000_000);    // lotus!(number)
//! assert_eq!("2,000,000.00", g);
//! ```

use std::default::Default;

#[macro_use]
extern crate derive_builder;

#[macro_use]
mod macros;
mod tests;

#[derive(Debug, Builder)]
#[builder(default)]
pub struct Lotus<'a> {
    symbol: &'a str,
    precision: u8,
    thousand_str: &'a str,
    decimal_str: &'a str,
    format_positive: &'a str,
    format_negative: &'a str,
    format_zero: &'a str
}

impl<'a> Lotus<'a> {
    /// Creates a Lotus instance with the give symbol and precision
    /// and precision
    ///
    /// # Example:
    /// ```
    /// use crate::Lotus::*;
    /// let dollar = Lotus::new("$", 2);
    /// let f = dollar.format(3500);
    /// assert_eq!("$ 3,500.00", f);
    /// ```
    pub fn new(symbol: &str, precision: u8) -> Lotus {
        Lotus {
            symbol,
            precision,
            ..Default::default()
        }
    }

    /// Formats a (generic) number according to the object 
    /// configuration
    ///
    /// # Example:
    /// ```
    /// use crate::Lotus::*;
    /// let rupee = LotusBuilder::default()
    ///     .symbol("Rs.")
    ///     .precision(4)
    ///     .format_positive("{symbol} {value}")
    ///     .format_negative("{symbol} ({value})")
    ///     .format_zero("{symbol} 0.00")
    ///     .decimal_str(".")
    ///     .thousand_str(" ")
    ///     .build()
    ///     .unwrap();
    /// assert_eq!("Rs. 2 000 000.0000", rupee.format(2_000_000));
    /// ```
    pub fn format<T: Into<f64>>(&self, in_number: T) -> String {
        let number: f64 = in_number.into();
        if number == 0. {
            let value = format!("{:.*}", self.precision as usize, number);
            let currencied = self.format_zero.replace("{value}", value.as_str());
            return currencied.replace("{symbol}", self.symbol)
        } else {
            let value = format!("{:.*}", self.precision as usize, number.abs());
            let mut float_iter = value.split(".");
            let integral   = float_iter.next().unwrap();
            let fractional = float_iter.next().unwrap();

            let mut formatted_integral = String::new();

            for ( i, letter ) in integral.chars().rev().enumerate() {
                if i % 3 == 0 && i != 0 && letter != '-' {
                    formatted_integral.push_str(&self.thousand_str[..]);
                }
                formatted_integral.push(letter);
            }

            let formatted_integral = formatted_integral.chars().rev().collect::<String>();
            let formatted_float = format!("{}{}{}", formatted_integral, self.decimal_str, fractional);

            let mut currencied = String::new();
            if number.is_sign_negative() {
                currencied.push_str(self.format_negative);
            } else {
                currencied.push_str(self.format_positive);
            }
            currencied = currencied.replace("{value}", formatted_float.as_str());
            currencied = currencied.replace("{symbol}", &self.symbol[..]);
            return currencied;
        }
    }
}

impl<'a> Default for Lotus<'a> {
    fn default() -> Self {
        Lotus {
            symbol: "$",
            precision: 2,
            thousand_str: ",",
            decimal_str: ".",
            format_positive: "{symbol} {value}",
            format_negative: "{symbol} ({value})",
            format_zero: "{symbol} --",
        }
    }
}