mathhook_core/formatter/latex.rs
1use super::{FormattingContext, FormattingError};
2use crate::core::Expression;
3
4mod expressions;
5mod functions;
6
7const MAX_RECURSION_DEPTH: usize = 1000;
8const MAX_TERMS_PER_OPERATION: usize = 10000;
9
10/// LaTeX formatting context
11#[derive(Debug, Default, Clone)]
12pub struct LaTeXContext {
13 pub needs_parentheses: bool,
14}
15
16impl FormattingContext for LaTeXContext {}
17
18/// Format the expression to LaTeX
19pub trait LaTeXFormatter {
20 /// Format an Expression as LaTeX mathematical notation
21 ///
22 /// Converts mathematical expressions into LaTeX format suitable for
23 /// rendering in mathematical documents and publications.
24 ///
25 /// # Arguments
26 /// * `context` - LaTeX formatting configuration
27 ///
28 /// # Context Options
29 /// * `needs_parentheses` - Whether to wrap the entire expression in parentheses
30 ///
31 /// # Examples
32 /// ```
33 /// use mathhook_core::{Expression, expr};
34 /// use mathhook_core::formatter::latex::{LaTeXFormatter, LaTeXContext};
35 ///
36 /// let expression = expr!(x ^ 2);
37 /// let context = LaTeXContext::default();
38 /// let result = expression.to_latex(context).unwrap();
39 /// assert!(result.contains("x"));
40 /// assert!(result.contains("2"));
41 /// ```
42 ///
43 /// # Error Handling
44 /// Returns error messages for expressions that exceed safety limits:
45 /// - Maximum recursion depth (1000 levels)
46 /// - Maximum terms per operation (10000 terms)
47 fn to_latex<C>(&self, context: C) -> Result<String, FormattingError>
48 where
49 C: Into<Option<LaTeXContext>>,
50 {
51 let context = context.into().unwrap_or_default();
52 self.to_latex_with_depth(&context, 0)
53 }
54
55 /// Format with explicit recursion depth tracking
56 ///
57 /// Internal method that provides stack overflow protection by tracking
58 /// recursion depth. This method returns a Result to allow proper error
59 /// propagation during recursive formatting.
60 ///
61 /// # Arguments
62 /// * `context` - LaTeX formatting configuration
63 /// * `depth` - Current recursion depth (starts at 0)
64 ///
65 /// # Returns
66 /// * `Ok(String)` - Successfully formatted LaTeX expression
67 /// * `Err(String)` - Error message if limits exceeded
68 ///
69 /// # Safety Limits
70 /// * Maximum recursion depth: 1000 levels
71 /// * Maximum terms per operation: 10000 terms/factors/arguments
72 fn to_latex_with_depth(
73 &self,
74 context: &LaTeXContext,
75 depth: usize,
76 ) -> Result<String, FormattingError>;
77
78 /// Convert function to LaTeX with context and depth tracking
79 fn function_to_latex_with_depth(
80 &self,
81 name: &str,
82 args: &[Expression],
83 context: &LaTeXContext,
84 depth: usize,
85 ) -> Result<String, FormattingError>;
86
87 /// Convert function to LaTeX (convenience method)
88 fn function_to_latex(
89 &self,
90 name: &str,
91 args: &[Expression],
92 context: &LaTeXContext,
93 ) -> Result<String, FormattingError> {
94 match self.function_to_latex_with_depth(name, args, context, 0) {
95 Ok(result) => Ok(result),
96 Err(error) => Err(FormattingError::InvalidMathConstruct {
97 reason: error.to_string(),
98 }),
99 }
100 }
101}
102
103impl LaTeXFormatter for Expression {
104 fn to_latex_with_depth(
105 &self,
106 context: &LaTeXContext,
107 depth: usize,
108 ) -> Result<String, FormattingError> {
109 expressions::to_latex_with_depth_impl(self, context, depth)
110 }
111
112 fn function_to_latex_with_depth(
113 &self,
114 name: &str,
115 args: &[Expression],
116 context: &LaTeXContext,
117 depth: usize,
118 ) -> Result<String, FormattingError> {
119 functions::function_to_latex_with_depth_impl(self, name, args, context, depth)
120 }
121}