apc 0.0.2

An arbitrary precision calculator
use std::{
    fmt,
    io::{self, Write},
    ops,
};

/// Store operands as a list of bytes, where each byte represents a place in the base 10 numeral
/// system. The first index (0) is the 1s place (a * 10^0), the second index (1) is the 10s place
/// (a * 10^1), and so on.
#[derive(Clone, Debug)]
struct Operand(Vec<u8>);

impl Operand {
    /// Create a new [Operand] with empty storage
    fn new() -> Self {
        Self(Vec::new())
    }
}

impl From<&str> for Operand {
    /// Create a new [Operand] from a string of numbers
    ///
    /// The [Vec<u8>] inside of [Operand] stores the number in reverse. That is, the lowest
    /// significant digit is stored at index 0.
    fn from(operand: &str) -> Self {
        let mut storage = Self::new();
        for c in operand.chars().rev() {
            let n = c
                .to_digit(10)
                .expect("Operands must be a number in base 10");
            storage.0.push(n as u8);
        }
        storage
    }
}

impl From<&Operand> for String {
    /// Get the [Operand] as a [String]
    fn from(operand: &Operand) -> Self {
        let mut s = String::new();
        for n in operand.0.clone().iter().rev() {
            s.push_str(&n.to_string());
        }
        if s.len() == 0 {
            s.push_str("0");
        }
        s
    }
}

impl ops::Add<Operand> for Operand {
    type Output = Operand;
    fn add(self, rhs: Operand) -> Self {
        // Check if operands have the same number of digits
        let mut lhs = self.0;
        let mut rhs = rhs.0;
        let max = lhs.len().max(rhs.len());
        lhs.resize(max, 0);
        rhs.resize(max, 0);

        // Perform and add w/ carry
        let mut result = Vec::new();
        let mut carry = 0;
        for (a, b) in lhs.iter().zip(rhs.iter()) {
            let mut r = a + b + carry;
            if r > 9 {
                r = r - 10;
                carry = 1;
            } else {
                carry = 0;
            }
            result.push(r);
        }
        if carry > 0 {
            result.push(carry);
        }
        Operand(result)
    }
}

impl fmt::Display for Operand {
    /// Display the [Operand] appropriately as a [String]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", String::from(self))
    }
}

/// Possible operations
#[derive(Clone, Debug)]
enum Operator {
    /// Addition (a + b)
    Add,
    /// Subtraction (a - b)
    Sub,
    /// Multiplication (a * b)
    Mul,
    /// Division (a / b)
    Div,
    /// No operation, prints the operands
    Non,
}

impl Operator {
    /// Create a new [Operator] with the default value
    fn new() -> Self {
        Self::Non
    }
}

impl From<&str> for Operator {
    /// Create a new [Operator] from the given symbol
    fn from(operator: &str) -> Self {
        match operator {
            "+" => Operator::Add,
            "-" => Operator::Sub,
            "*" => Operator::Mul,
            "/" => Operator::Div,
            "," => Operator::Non,
            _ => Operator::new(),
        }
    }
}

impl From<&Operator> for String {
    /// Get the [Operator] as a [String]
    fn from(operator: &Operator) -> Self {
        match operator {
            Operator::Add => "+",
            Operator::Sub => "-",
            Operator::Mul => "*",
            Operator::Div => "/",
            Operator::Non => ",",
        }
        .to_string()
    }
}

impl fmt::Display for Operator {
    /// Display the [Operator] appropriately as a [String]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", String::from(self))
    }
}

/// Program entry
fn main() {
    let mut operand1: String = String::new();
    let mut operand2: String = String::new();
    let mut operator: String = String::new();

    print!("Enter the first operand: ");
    io::stdout().flush().unwrap();
    io::stdin()
        .read_line(&mut operand1)
        .expect("Failed to read the first operand");

    print!("Enter the second operand: ");
    io::stdout().flush().unwrap();
    io::stdin()
        .read_line(&mut operand2)
        .expect("Failed to read the second operand");

    print!("Enter the operator (+, -, *, /, or else): ");
    io::stdout().flush().unwrap();
    io::stdin()
        .read_line(&mut operator)
        .expect("Failed to read the operator");

    let operand1: Operand = operand1.trim().into();
    let operand2: Operand = operand2.trim().into();
    let operator: Operator = operator.trim().into();
    print!("{} {} {} = ", &operand1, &operator, &operand2);
    println!("{}", operand1 + operand2);
}