Skip to content

Commit e14807a

Browse files
committed
Speech API without global state
1 parent ca4b933 commit e14807a

16 files changed

Lines changed: 1112 additions & 793 deletions

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ repository = "https://github.com/NSoiffer/MathCAT"
88
homepage = "https://nsoiffer.github.io/MathCAT/"
99
documentation = "https://nsoiffer.github.io/MathCAT/"
1010
edition = "2018"
11-
exclude = ["src/main.rs", "docs", "PythonScripts"] # should have "Rules/", but then one can't run build.rs to build the zip file
11+
exclude = ["src/main.rs", "examples/**", "docs", "PythonScripts"] # should have "Rules/", but then one can't run build.rs to build the zip file
1212

1313

1414
[features]

examples/stateless-example.rs

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
use env_logger;
2+
use lazy_static::lazy_static;
3+
use libmathcat::{errors::Error, stateless_interface::*};
4+
use std::{ops::Deref, path::Path, sync::mpsc, thread};
5+
6+
const EXPR_1: &'static str = r#"<math><mrow><msup><mi>sin</mi><mn>2</mn></msup><mo>⁡</mo><mspace></mspace><mi>x</mi></mrow></math>"#;
7+
const EXPR_2: &'static str = r#"<math><mrow><msup><mi>cos</mi><mn>2</mn></msup><mo>⁡</mo><mspace></mspace><mi>x</mi></mrow></math>"#;
8+
9+
struct MathCatHolder {
10+
language: &'static str,
11+
mathcat: MathCat,
12+
}
13+
14+
// `mathcat` is full of RCs, need to figure out what to do here to explain to Rust
15+
// that it's OK to use a non-mut MathCat across threads because all Rcs are actually
16+
// owned by the `MathCat` instance.
17+
unsafe impl Sync for MathCatHolder {}
18+
19+
fn build_mathcat(language: &'static str) -> Result<MathCatHolder, Error> {
20+
let rules_dir = std::env::current_exe().unwrap().parent().unwrap().join("../../../Rules");
21+
let rules_dir = rules_dir.as_os_str().to_str().unwrap().to_string();
22+
23+
let mut builder = MathCatBuilder::new();
24+
builder.set_rules_dir(Path::new(&rules_dir));
25+
builder.set_pref("Language", language);
26+
Ok(MathCatHolder { language: language, mathcat: builder.build()? })
27+
}
28+
29+
fn main() -> Result<(), Error> {
30+
// Run with RUST_LOG=debug to see some debugging information.l
31+
env_logger::builder()
32+
.format_timestamp(None)
33+
.format_module_path(false)
34+
.format_indent(Some(2))
35+
.format_level(false)
36+
.init();
37+
38+
lazy_static! {
39+
static ref mathcat_en: MathCatHolder = build_mathcat("en").unwrap();
40+
static ref mathcat_es: MathCatHolder = build_mathcat("es").unwrap();
41+
}
42+
43+
// Initialization is not thread-safe, ensure everything is initialized:
44+
let _ = mathcat_en.deref();
45+
let _ = mathcat_es.deref();
46+
47+
// Once initialized, MathCat instances are thread-compatible.
48+
let (tx, rx) = mpsc::channel();
49+
let mut threads = Vec::<thread::JoinHandle<Result<(), mpsc::SendError<(&'static str, Result<String, libmathcat::errors::Error>)>>>>::new();
50+
{
51+
let tx = tx.clone();
52+
threads.push(thread::spawn(move || {
53+
tx.send((
54+
mathcat_en.language,
55+
mathcat_en.mathcat.mathml_to_spoken_text(EXPR_1)))
56+
}));
57+
}
58+
{
59+
let tx = tx.clone();
60+
threads.push(thread::spawn(move || {
61+
tx.send((
62+
mathcat_en.language,
63+
mathcat_en.mathcat.mathml_to_spoken_text(EXPR_2)))
64+
}));
65+
}
66+
{
67+
let tx = tx.clone();
68+
threads.push(thread::spawn(move || {
69+
tx.send((
70+
mathcat_es.language,
71+
mathcat_es.mathcat.mathml_to_spoken_text(EXPR_1)))
72+
}));
73+
}
74+
{
75+
let tx = tx.clone();
76+
threads.push(thread::spawn(move || {
77+
tx.send((
78+
mathcat_es.language,
79+
mathcat_es.mathcat.mathml_to_spoken_text(EXPR_2)))
80+
}));
81+
}
82+
83+
let rcv_thread = thread::spawn(move || {
84+
let mut pending = 4;
85+
let mut has_errors = false;
86+
while let Ok((language, result)) = rx.recv() {
87+
match result {
88+
Ok(text) => println!("{}: {}", language, text),
89+
Err(e) => {
90+
has_errors = true;
91+
println!("{}: Error!\n{:?}", language, e);
92+
}
93+
};
94+
pending -= 1;
95+
if pending == 0 { break; }
96+
}
97+
has_errors
98+
});
99+
100+
for thread in threads {
101+
let _ = thread.join().unwrap();
102+
}
103+
let has_errors = rcv_thread.join().unwrap();
104+
if has_errors { std::process::exit(1); }
105+
Ok(())
106+
}

0 commit comments

Comments
 (0)