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 }