mathhook_core/educational/
traits.rs1use crate::educational::step_by_step::StepByStepExplanation;
7
8#[derive(Debug, Clone, PartialEq)]
13pub struct OperationContext {
14 pub operation_type: String,
16 pub difficulty_level: u8,
18 pub domain: String,
20 pub prerequisites: Vec<String>,
22}
23
24impl OperationContext {
25 pub fn new<S: Into<String>>(operation_type: S, difficulty_level: u8, domain: S) -> Self {
47 Self {
48 operation_type: operation_type.into(),
49 difficulty_level: difficulty_level.min(10),
50 domain: domain.into(),
51 prerequisites: Vec::new(),
52 }
53 }
54
55 pub fn add_prerequisite<S: Into<String>>(&mut self, prerequisite: S) {
68 self.prerequisites.push(prerequisite.into());
69 }
70
71 pub fn equation_solving(difficulty_level: u8) -> Self {
73 let mut context = Self::new("solving_equation", difficulty_level, "algebra");
74 context.add_prerequisite("basic_algebra");
75 context
76 }
77
78 pub fn differentiation(difficulty_level: u8) -> Self {
80 let mut context = Self::new("differentiation", difficulty_level, "calculus");
81 context.add_prerequisite("limits");
82 context.add_prerequisite("functions");
83 context
84 }
85
86 pub fn simplification(difficulty_level: u8) -> Self {
88 let mut context = Self::new("simplification", difficulty_level, "algebra");
89 context.add_prerequisite("basic_operations");
90 context
91 }
92}
93
94pub trait EducationalOperation {
104 type Output;
106 fn execute_with_steps(&self) -> (Self::Output, StepByStepExplanation);
107 fn educational_context(&self) -> OperationContext;
108 fn execute_fast(&self) -> Self::Output {
109 let (result, _explanation) = self.execute_with_steps();
110 result
111 }
112 fn can_explain(&self) -> bool {
113 true
114 }
115 fn estimated_steps(&self) -> Option<usize> {
116 None
117 }
118}
119
120pub trait EducationalExt {
125 fn with_education(self) -> impl EducationalOperation<Output = Self>
130 where
131 Self: Sized + Clone;
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137
138 #[test]
139 fn test_operation_context_creation() {
140 let context = OperationContext::new("test_operation", 5, "algebra");
141 assert_eq!(context.operation_type, "test_operation");
142 assert_eq!(context.difficulty_level, 5);
143 assert_eq!(context.domain, "algebra");
144 assert!(context.prerequisites.is_empty());
145 }
146
147 #[test]
148 fn test_operation_context_difficulty_clamping() {
149 let context = OperationContext::new("test", 15, "algebra");
150 assert_eq!(context.difficulty_level, 10);
151 }
152
153 #[test]
154 fn test_operation_context_prerequisites() {
155 let mut context = OperationContext::new("advanced_operation", 8, "calculus");
156 context.add_prerequisite("limits");
157 context.add_prerequisite("derivatives");
158
159 assert_eq!(context.prerequisites.len(), 2);
160 assert!(context.prerequisites.contains(&"limits".to_string()));
161 assert!(context.prerequisites.contains(&"derivatives".to_string()));
162 }
163
164 #[test]
165 fn test_context_factory_methods() {
166 let eq_context = OperationContext::equation_solving(5);
167 assert_eq!(eq_context.operation_type, "solving_equation");
168 assert_eq!(eq_context.domain, "algebra");
169 assert!(!eq_context.prerequisites.is_empty());
170
171 let diff_context = OperationContext::differentiation(7);
172 assert_eq!(diff_context.operation_type, "differentiation");
173 assert_eq!(diff_context.domain, "calculus");
174
175 let simp_context = OperationContext::simplification(3);
176 assert_eq!(simp_context.operation_type, "simplification");
177 assert_eq!(simp_context.domain, "algebra");
178 }
179
180 struct TestOperation {
181 value: i64,
182 }
183
184 impl EducationalOperation for TestOperation {
185 type Output = i64;
186
187 fn execute_with_steps(&self) -> (Self::Output, StepByStepExplanation) {
188 use crate::educational::step_by_step::Step;
189
190 let steps = vec![
191 Step::new("Initialize", "Starting with value"),
192 Step::new("Calculate", "Performing operation"),
193 Step::new("Result", "Final result obtained"),
194 ];
195
196 (self.value * 2, StepByStepExplanation::new(steps))
197 }
198
199 fn educational_context(&self) -> OperationContext {
200 OperationContext::new("test_operation", 3, "testing")
201 }
202
203 fn execute_fast(&self) -> Self::Output {
204 self.value * 2
205 }
206
207 fn estimated_steps(&self) -> Option<usize> {
208 Some(3)
209 }
210 }
211
212 #[test]
213 fn test_educational_operation_implementation() {
214 let operation = TestOperation { value: 21 };
215
216 let (result, explanation) = operation.execute_with_steps();
217 assert_eq!(result, 42);
218 assert_eq!(explanation.steps.len(), 3);
219 assert_eq!(explanation.total_steps, 3);
220
221 let fast_result = operation.execute_fast();
222 assert_eq!(fast_result, 42);
223
224 let context = operation.educational_context();
225 assert_eq!(context.operation_type, "test_operation");
226 assert_eq!(context.difficulty_level, 3);
227
228 assert!(operation.can_explain());
229 assert_eq!(operation.estimated_steps(), Some(3));
230 }
231}