adapters.rs (3117B)
1 //! Adapter Pattern 2 3 use std::{collections::HashMap, f64::consts::PI}; 4 5 use crate::{number::AngleMode, token::VariableToken, utilities::Expression}; 6 7 pub trait ScientificOperations { 8 fn sin(&self, angle: f64) -> f64; 9 fn cos(&self, angle: f64) -> f64; 10 fn tan(&self, angle: f64) -> f64; 11 fn log(&self, value: f64, base: f64) -> Result<f64, String>; 12 } 13 14 pub struct StandardScientificOperations { 15 pub angle_mode: AngleMode, 16 } 17 18 impl ScientificOperations for StandardScientificOperations { 19 fn sin(&self, angle: f64) -> f64 { 20 match self.angle_mode { 21 AngleMode::Radians => angle.sin(), 22 AngleMode::Degrees => (angle * PI / 180.0).sin(), 23 } 24 } 25 26 fn cos(&self, angle: f64) -> f64 { 27 match self.angle_mode { 28 AngleMode::Radians => angle.cos(), 29 AngleMode::Degrees => (angle * PI / 180.0).cos(), 30 } 31 } 32 33 fn tan(&self, angle: f64) -> f64 { 34 todo!() 35 } 36 37 fn log(&self, value: f64, base: f64) -> Result<f64, String> { 38 if value <= 0.0 { 39 return Err("Cannot take logarithm of non-positive number".to_string()); 40 } 41 if base <= 0.0 || base == 1.0 { 42 return Err("Invalid logarithm base".to_string()); 43 } 44 Ok(value.ln() / base.ln()) 45 } 46 } 47 48 pub struct ExternalLibraryAdapter { 49 angle_mode: AngleMode, 50 } 51 52 impl ExternalLibraryAdapter { 53 pub fn new(angle_mode: AngleMode) -> Self { 54 Self { angle_mode } 55 } 56 57 fn convert_angle(&self, angle: f64) -> f64 { 58 match self.angle_mode { 59 AngleMode::Radians => angle, 60 AngleMode::Degrees => angle * PI / 180.0, 61 } 62 } 63 } 64 65 impl ScientificOperations for ExternalLibraryAdapter { 66 fn sin(&self, angle: f64) -> f64 { 67 let converted = self.convert_angle(angle); 68 converted.sin() 69 } 70 71 fn cos(&self, angle: f64) -> f64 { 72 todo!() 73 } 74 75 fn tan(&self, angle: f64) -> f64 { 76 todo!() 77 } 78 79 fn log(&self, value: f64, base: f64) -> Result<f64, String> { 80 todo!() 81 } 82 } 83 84 /// This struct uses a closure (Box<dyn Fn(f64) -> f64) to capture a specific 85 /// scientific operation. 86 pub struct ScientificFunctionExpression { 87 operation: Box<dyn Fn(f64) -> f64>, 88 arg_expression: Box<dyn Expression>, 89 description: String, 90 } 91 92 impl Expression for ScientificFunctionExpression { 93 fn evaluate(&self, variables: &HashMap<String, f64>) -> Result<f64, String> { 94 let arg_value = self.arg_expression.evaluate(variables)?; 95 Ok((self.operation)(arg_value)) 96 } 97 98 fn to_string(&self) -> String { 99 format!("{}({})", self.description, self.arg_expression.to_string()) 100 } 101 } 102 103 /// The move keyword transfers ownership of the `sci_ops` trait object into 104 /// the closure. 105 impl ScientificFunctionExpression { 106 pub fn new_sin(sci_ops: Box<dyn ScientificOperations>, arg: Box<dyn Expression>) -> Self { 107 let operation = Box::new(move |angle: f64| sci_ops.sin(angle)); 108 Self { 109 operation, 110 arg_expression: arg, 111 description: "sin".to_string(), 112 } 113 } 114 }