Skip to main content

honzo_chunks/data/
math.rs

1use std::str;
2use std::string::String;
3
4use quick_xml::Reader;
5
6use honzo_core::{HonzoError, MathType};
7use pulldown_latex::{push_mathml, Parser as LatexParser, RenderConfig, Storage as LatexStorage};
8
9pub const MATH_TAG: [u8; 4] = *b"MATH";
10
11pub fn validate_mathml(bytes: &[u8]) -> Result<(), HonzoError> {
12    let mut reader = Reader::from_reader(bytes);
13    let mut buf = Vec::new();
14    loop {
15        match reader.read_event_into(&mut buf) {
16            Ok(quick_xml::events::Event::Eof) => break,
17            Ok(_) => buf.clear(),
18            Err(_) => return Err(HonzoError::InvalidMathML),
19        }
20    }
21    Ok(())
22}
23
24pub fn latex_to_mathml(bytes: &[u8]) -> Result<String, HonzoError> {
25    let s = match str::from_utf8(bytes) {
26        Ok(v) => v,
27        Err(_) => return Err(HonzoError::Truncated),
28    };
29
30    // Use pulldown-latex to render LaTeX math to MathML.
31    let storage = LatexStorage::new();
32    let parser = LatexParser::new(s, &storage);
33    let mut out = String::new();
34    let cfg = RenderConfig {
35        xml: true,
36        ..Default::default()
37    };
38    push_mathml(&mut out, parser, cfg).map_err(|_| HonzoError::InvalidMathML)?;
39    Ok(out)
40}
41
42pub fn render_math(bytes: &[u8], math_type: MathType) -> Result<String, HonzoError> {
43    match math_type {
44        MathType::MathML => {
45            validate_mathml(bytes)?;
46            let s = str::from_utf8(bytes).map_err(|_| HonzoError::Truncated)?;
47            Ok(s.to_string())
48        }
49        MathType::LaTeX => latex_to_mathml(bytes),
50    }
51}
52
53// Wrappers that return byte buffers rather than `String` so FFI layers
54// can consume the data without exposing Rust `String` in signatures.
55fn map_honzo_error_code(err: HonzoError) -> u8 {
56    match err {
57        HonzoError::InvalidMathML => 6,
58        HonzoError::Truncated => 7,
59        _ => 255,
60    }
61}
62
63pub fn latex_to_mathml_bytes(bytes: &[u8]) -> Result<Vec<u8>, u8> {
64    match latex_to_mathml(bytes) {
65        Ok(s) => Ok(s.into_bytes()),
66        Err(e) => Err(map_honzo_error_code(e)),
67    }
68}
69
70pub fn render_math_bytes(bytes: &[u8], math_type: u8) -> Result<Vec<u8>, u8> {
71    let math_type = match MathType::from_u8(math_type) {
72        Ok(value) => value,
73        Err(err) => return Err(map_honzo_error_code(err)),
74    };
75    match render_math(bytes, math_type) {
76        Ok(s) => Ok(s.into_bytes()),
77        Err(e) => Err(map_honzo_error_code(e)),
78    }
79}
80
81pub fn validate_mathml_bytes(bytes: &[u8]) -> Result<(), u8> {
82    match validate_mathml(bytes) {
83        Ok(()) => Ok(()),
84        Err(e) => Err(map_honzo_error_code(e)),
85    }
86}