exercises

Log | Files | Refs | README

main.rs (3843B)


      1 //! This is a bad example of trying to apply OO principles in rust
      2 //! and make it worse
      3 
      4 use std::{
      5     io::{Write, stdin, stdout},
      6     ops::{Deref, DerefMut},
      7     process::exit,
      8 };
      9 
     10 trait Operand {
     11     fn evaluate(&self) -> f64;
     12 }
     13 
     14 /// There are a lot of box dyn types showing up, which is bit
     15 /// concerning, but lets continue to make the bad calculator
     16 trait Operator {
     17     fn precedence(&self) -> u8;
     18     fn symbol(&self) -> char;
     19     fn push_operand(&mut self, operand: Box<dyn Operand>);
     20     fn pop_operand(&mut self) -> Box<dyn Operand>;
     21     fn apply(&mut self) -> Box<dyn Operand>;
     22 }
     23 
     24 trait UnaryOperator: crate::Operator {
     25     fn apply_unary(&self, operand: Box<dyn Operand>) -> Box<dyn Operand>;
     26 
     27     fn apply(&mut self) -> Box<dyn Operand> {
     28         let operand = self.pop_operand();
     29         self.apply_unary(operand)
     30     }
     31 }
     32 
     33 trait BinaryOperator: Operator {
     34     fn apply_binary(
     35         &self,
     36         operand1: Box<dyn Operand>,
     37         operand2: Box<dyn Operand>,
     38     ) -> Box<dyn Operand>;
     39 
     40     fn apply(&mut self) -> Box<dyn Operand> {
     41         let operand2 = self.pop_operand();
     42         let operand1 = self.pop_operand();
     43         self.apply_binary(operand1, operand2)
     44     }
     45 }
     46 
     47 struct OperandStack(Vec<Box<dyn Operand>>);
     48 
     49 impl OperandStack {
     50     fn new() -> Self {
     51         Self(Vec::new())
     52     }
     53 
     54     fn push_operand(&mut self, operand: Box<dyn Operand>) {
     55         self.0.push(operand);
     56     }
     57 
     58     fn pop_operand(&mut self) -> Box<dyn Operand> {
     59         self.0.pop().unwrap()
     60     }
     61 
     62     fn clear_stack(&mut self) {
     63         self.0.clear();
     64     }
     65 }
     66 
     67 struct AdditionOperator {
     68     stack: OperandStack,
     69 }
     70 
     71 impl AdditionOperator {
     72     fn new() -> Self {
     73         Self {
     74             stack: OperandStack::new(),
     75         }
     76     }
     77 }
     78 
     79 impl BinaryOperator for AdditionOperator {
     80     fn apply_binary(
     81         &self,
     82         operand1: Box<dyn Operand>,
     83         operand2: Box<dyn Operand>,
     84     ) -> Box<dyn Operand> {
     85         let inner_operand2 = operand2.as_ref().evaluate();
     86         let inner_operand1 = operand1.evaluate();
     87         let result = inner_operand1 + inner_operand2;
     88         Box::new(Value(result))
     89     }
     90 }
     91 
     92 impl Operator for AdditionOperator {
     93     fn precedence(&self) -> u8 {
     94         0
     95     }
     96 
     97     fn symbol(&self) -> char {
     98         '+'
     99     }
    100 
    101     fn push_operand(&mut self, operand: Box<dyn Operand>) {
    102         self.stack.push_operand(operand);
    103     }
    104 
    105     fn pop_operand(&mut self) -> Box<dyn Operand> {
    106         self.stack.pop_operand()
    107     }
    108 
    109     fn apply(&mut self) -> Box<dyn Operand> {
    110         let operand2 = self.pop_operand();
    111         let operand1 = self.pop_operand();
    112         self.apply_binary(operand1, operand2)
    113     }
    114 }
    115 
    116 impl Deref for AdditionOperator {
    117     type Target = OperandStack;
    118 
    119     fn deref(&self) -> &Self::Target {
    120         &self.stack
    121     }
    122 }
    123 
    124 impl DerefMut for AdditionOperator {
    125     fn deref_mut(&mut self) -> &mut Self::Target {
    126         &mut self.stack
    127     }
    128 }
    129 
    130 struct Value(f64);
    131 
    132 impl Operand for Value {
    133     fn evaluate(&self) -> f64 {
    134         self.0
    135     }
    136 }
    137 
    138 fn evaluate_expression(expression: &str) -> Result<String, String> {
    139     let some_operand = Box::new(Value(0.0));
    140     let mut addition_operator = AdditionOperator::new();
    141     addition_operator.push_operand(some_operand);
    142     addition_operator.clear_stack();
    143     let popped_operand = addition_operator.pop_operand();
    144     Ok("Finished".to_string())
    145 }
    146 
    147 /// This is a project to demonstrate BAD practices in Rust in order to learn
    148 fn main() {
    149     let mut buf = String::new();
    150     loop {
    151         print!("> ");
    152 
    153         stdout().flush().unwrap();
    154 
    155         buf.clear();
    156         stdin().read_line(&mut buf).unwrap();
    157 
    158         if buf.trim() == "exit" {
    159             exit(0)
    160         }
    161 
    162         match evaluate_expression(&buf) {
    163             Ok(result) => println!("{result}"),
    164             Err(error) => println!("Error: {error}"),
    165         }
    166     }
    167 }