emscripten_functions/emscripten.rs
1//! Select functions (with rust-native parameter and return value types) from the emscripten [`emscripten.h`] header file, and helper functions and types for them.
2//! Only most of the "Calling JavaScript From C/C++" and "Browser Execution Environment" functions are implemented.
3//!
4//! [`emscripten.h`]: https://emscripten.org/docs/api_reference/emscripten.h.html
5
6use std::{
7 cell::RefCell,
8 ffi::{CStr, CString},
9 fmt::Display,
10 os::raw::{c_char, c_double, c_int},
11};
12
13use emscripten_functions_sys::emscripten;
14
15// The function to run in `set_main_loop_with_arg` sits in this thread-local object so that it will remain permanent throughout the main loop's run.
16// It needs to stay in a global place so that the `wrapper_func` that is passed as argument to `emscripten_set_main_loop`, which must be an `extern "C"` function, can access it (it couldn't have been a closure).
17// As the `thread_local` thing only gives us an immutable reference, we use a `RefCell` to be able to change the data when the function gets called.
18thread_local! {
19 static MAIN_LOOP_FUNCTION: RefCell<Option<Box<dyn FnMut()>>> = RefCell::new(None);
20}
21
22/// Sets the given function as the main loop of the calling thread, using the emscripten-defined [`emscripten_set_main_loop`].
23/// The given function accepts a mutable reference (argument `arg`) to the variable that will contain the loop state and whatever else is needed for it to run.
24///
25/// If you don't need that state argument, check out [`set_main_loop`].
26///
27/// The main loop can be cancelled using the [`cancel_main_loop`] function.
28///
29/// [`emscripten_set_main_loop`]: https://emscripten.org/docs/api_reference/emscripten.h.html#c.emscripten_set_main_loop
30///
31/// # Arguments
32/// * `func` - The function to be set as main event loop for the calling thread.
33/// * `arg` - The variable that represents the state that the main event loop ought to interact with.
34/// It will be consumed so that it can be kept alive during the loop.
35/// It must be `'static`, that means `arg`'s type should only contain owned data and `'static` references, if any.
36/// * `fps` - The number of calls of the function per second.
37/// If set to a value <= 0, the browser's [`requestAnimationFrame()`] function will be used (recommended when using the main function for rendering) instead of a fixed rate.
38/// * `simulate_infinite_loop` - If `true`, no code after the function call will be executed, otherwise the code after the function call will be executed.
39///
40/// [`requestAnimationFrame()`]: https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
41///
42/// # Examples
43/// ```rust
44/// struct GameData {
45/// level: u32,
46/// score: u32
47/// }
48/// let mut game_data = GameData {
49/// level: 1,
50/// score: 0
51/// }
52///
53/// set_main_loop_with_arg(|data| {
54/// if data.score < data.level {
55/// data.score += 1;
56/// } else {
57/// data.score = 0;
58/// data.level += 1;
59/// }
60///
61/// // Here you call your display to screen functions.
62/// // For demonstration purposes I chose `println!`.
63/// println!("Score {}, level {}", data.score, data.level);
64/// }, game_data, 0, true);
65/// ```
66pub fn set_main_loop_with_arg<F, T>(
67 mut func: F,
68 mut arg: T,
69 fps: c_int,
70 simulate_infinite_loop: bool,
71) where
72 F: 'static + FnMut(&mut T),
73 T: 'static,
74{
75 // In `MAIN_LOOP_FUNCTION` we store a closure with no arguments, so that its type would be independent of `T`.
76 // That closure calls the `func` parameter with `arg` as parameter, and owns them both.
77 MAIN_LOOP_FUNCTION.with(|func_ref| {
78 *func_ref.borrow_mut() = Some(Box::new(move || {
79 func(&mut arg);
80 }));
81 });
82
83 unsafe extern "C" fn wrapper_func() {
84 MAIN_LOOP_FUNCTION.with(|func_ref| {
85 if let Some(function) = &mut *func_ref.borrow_mut() {
86 (*function)();
87 }
88 });
89 }
90
91 unsafe {
92 emscripten::emscripten_set_main_loop(Some(wrapper_func), fps, simulate_infinite_loop)
93 };
94}
95
96/// Sets the given function as the main loop of the calling thread, using the emscripten-defined [`emscripten_set_main_loop`].
97/// The given function has no parameters.
98///
99/// The main loop can be cancelled using the [`cancel_main_loop`] function.
100///
101/// [`emscripten_set_main_loop`]: https://emscripten.org/docs/api_reference/emscripten.h.html#c.emscripten_set_main_loop
102///
103/// # Arguments
104/// * `func` - The function to be set as main event loop for the calling thread.
105/// * `fps` - The number of calls of the function per second.
106/// If set to a value <= 0, the browser's [`requestAnimationFrame()`] function will be used (recommended when using the main function for rendering) instead of a fixed rate.
107/// * `simulate_infinite_loop` - If `true`, no code after the function call will be executed, otherwise the code after the function call will be executed.
108///
109/// [`requestAnimationFrame()`]: https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
110///
111/// # Examples
112/// ```rust
113/// set_main_loop(|| {
114/// println!("Hello world every half second!");
115/// }, 2, true);
116/// ```
117pub fn set_main_loop<F>(mut func: F, fps: c_int, simulate_infinite_loop: bool)
118where
119 F: 'static + FnMut(),
120{
121 set_main_loop_with_arg(move |_| func(), (), fps, simulate_infinite_loop);
122}
123
124/// Cancels the main loop of the calling thread that was set using [`set_main_loop_with_arg`] or [`set_main_loop`].
125pub fn cancel_main_loop() {
126 unsafe {
127 emscripten::emscripten_cancel_main_loop();
128 }
129
130 // Also let's not forget to free up the main loop function and its state arg.
131 MAIN_LOOP_FUNCTION.with(|func_ref| {
132 *func_ref.borrow_mut() = None;
133 });
134}
135
136/// Pauses the main loop of the calling thread.
137pub fn pause_main_loop() {
138 unsafe {
139 emscripten::emscripten_pause_main_loop();
140 }
141}
142
143/// Resumes the main loop of the calling thread.
144pub fn resume_main_loop() {
145 unsafe {
146 emscripten::emscripten_resume_main_loop();
147 }
148}
149
150/// Parameters of the main loop's scheduling mode.
151///
152/// While emscripten implements this using 2 `int` variables: `mode` and `value`; we put here only the valid modes.
153#[derive(Debug, Clone, PartialEq, Eq)]
154pub enum MainLoopTiming {
155 /// The main loop function gets called periodically using `setTimeout()`, with the payload being the interval between the calls of `setTimeout()`.
156 SetTimeout(c_int),
157 /// The main loop function gets called using `requestAnimationFrame()`, with the payload being the "swap interval" rate for the main loop:
158 /// * if the payload is `1`, the loop function gets called at every vsync (60fps for the common 60Hz display, 120fps for a 120Hz display, etc.),
159 /// * if the payload is `2`, the loop function gets called every second vsync (that usually means 30fps, depends on the display),
160 /// * in general, the rate is `{display frequency}/{the payload}` fps.
161 RequestAnimationFrame(c_int),
162 /// The main loop function gets called using `setImmediate()`, a function only available in Legacy Edge and partially in node.js.
163 /// While the said function can be emulated using `postMessage()`, this mode of running the main loop is discouraged by the Emscripten devs.
164 SetImmediate,
165}
166
167/// Applies the given main loop timing parameters to the main loop.
168///
169/// It returns:
170/// * `true` if the main loop function is set.
171/// * `false` if the main loop function isn't set.
172///
173/// If you're only interested in seeing whether the main loop function is set or not, check out the [`is_main_loop_set`] function.
174///
175/// # Arguments
176/// * `timing` - the timing parameters to apply to the main loop.
177///
178/// # Examples
179/// ```rust
180/// set_main_loop_timing(MainLoopTiming::SetTimeout(33));
181/// // the main function will now run at ~30fps
182/// ```
183pub fn set_main_loop_timing(timing: &MainLoopTiming) -> bool {
184 let (mode, value) = match timing {
185 MainLoopTiming::SetTimeout(ms) => (emscripten::EM_TIMING_SETTIMEOUT, *ms),
186 MainLoopTiming::RequestAnimationFrame(n) => (emscripten::EM_TIMING_RAF, *n),
187 MainLoopTiming::SetImmediate => (emscripten::EM_TIMING_SETIMMEDIATE, 0),
188 };
189
190 unsafe { emscripten::emscripten_set_main_loop_timing(mode as c_int, value) == 0 }
191}
192
193/// The main loop timing parameters can be set to other values than the ones with valid modes.
194/// If this is the case and we want to retrieve them, we use this error type.
195#[derive(Debug, Clone, PartialEq, Eq)]
196pub struct MainLoopInvalidTiming {
197 mode: c_int,
198 value: c_int,
199}
200impl Display for MainLoopInvalidTiming {
201 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
202 write!(
203 f,
204 "Invalid main loop timing parameters: mode = {}, value = {}",
205 self.mode, self.value
206 )
207 }
208}
209
210/// Returns the main loop timing parameters of the main loop.
211///
212/// If the parameters have an invalid mode, an error with the found parameters is returned instead.
213///
214/// # Examples
215/// ```rust
216/// match get_main_loop_timing() {
217/// Ok(MainLoopTiming::SetTimeout(ms)) => {
218/// println!("It runs every {} ms", ms);
219/// }
220/// Ok(MainLoopTiming::RequestAnimationFrame(_)) => {
221/// println!("You render stuff as you should");
222/// }
223/// Ok(MainLoopTiming::SetImmediate) => {
224/// println!("Why are you doing this???");
225/// }
226/// Err(err) => {
227/// println!("What??? {}", err);
228/// }
229/// };
230/// ```
231pub fn get_main_loop_timing() -> Result<MainLoopTiming, MainLoopInvalidTiming> {
232 let mut mode: c_int = 0;
233 let mut value: c_int = 0;
234
235 unsafe {
236 emscripten::emscripten_get_main_loop_timing(&mut mode, &mut value);
237 }
238
239 match mode as u32 {
240 emscripten::EM_TIMING_SETTIMEOUT => Ok(MainLoopTiming::SetTimeout(value)),
241 emscripten::EM_TIMING_RAF => Ok(MainLoopTiming::RequestAnimationFrame(value)),
242 emscripten::EM_TIMING_SETIMMEDIATE => Ok(MainLoopTiming::SetImmediate),
243 _ => Err(MainLoopInvalidTiming { mode, value }),
244 }
245}
246
247/// It returns `true` if the main loop function is set, and `false` if the main loop function isn't set.
248///
249/// # Examples
250/// ```rust
251/// if is_main_loop_set() {
252/// println!("It's set. It may be paused, but that should be pretty rare.");
253/// }
254/// ```
255pub fn is_main_loop_set() -> bool {
256 // This is done by setting the main loop timing to the values that it already is,
257 // and using the `emscripten_set_main_loop_timing` return value to see
258 // if the main loop function is set.
259 let mut mode = 0;
260 let mut value = 0;
261
262 unsafe {
263 emscripten::emscripten_get_main_loop_timing(&mut mode, &mut value);
264 emscripten::emscripten_set_main_loop_timing(mode, value) == 0
265 }
266}
267
268/// Exits the program immediately while keeping the runtime alive, using [`emscripten_exit_with_live_runtime`].
269///
270/// [`emscripten_exit_with_live_runtime`]: https://emscripten.org/docs/api_reference/emscripten.h.html#c.emscripten_exit_with_live_runtime
271pub fn exit_with_live_runtime() {
272 unsafe {
273 emscripten::emscripten_exit_with_live_runtime();
274 }
275}
276
277/// Exits the program and kills the runtime, using [`emscripten_force_exit`].
278/// Like libc's [`exit`], but works even if [`exit_with_live_runtime`] was run.
279///
280/// Only works if the project is built with `EXIT_RUNTIME` set - this is not the default.
281/// Build with `-sEXIT_RUNTIME` if you want to use this function.
282///
283/// [`emscripten_force_exit`]: https://emscripten.org/docs/api_reference/emscripten.h.html#c.emscripten_force_exit
284/// [`exit`]: https://linux.die.net/man/3/exit
285///
286/// # Arguments
287/// * `status` - the exit status, the same as for libc's `exit`.
288///
289/// # Examples
290/// ```rust
291/// force_exit(0); // Exits with status 0.
292/// ```
293/// ```rust
294/// force_exit(1); // Exits with status 1.
295/// ```
296/// ```rust
297/// force_exit(101); // Exits with status 101.
298/// ```
299pub fn force_exit(status: c_int) {
300 unsafe {
301 emscripten::emscripten_force_exit(status);
302 }
303}
304
305/// Returns the value of [`window.devicePixelRatio`], using the emscripten-defined [`emscripten_get_device_pixel_ratio`].
306///
307/// [`window.devicePixelRatio`]: https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio
308/// [`emscripten_get_device_pixel_ratio`]: https://emscripten.org/docs/api_reference/emscripten.h.html#c.emscripten_get_device_pixel_ratio
309///
310/// # Examples
311/// ```rust
312/// println!("Your device pixel ratio is {}", get_device_pixel_ratio());
313/// ```
314pub fn get_device_pixel_ratio() -> f64 {
315 unsafe { emscripten::emscripten_get_device_pixel_ratio() }
316}
317
318/// Returns the window title, using the emscripten-defined [`emscripten_get_window_title`].
319///
320/// [`emscripten_get_window_title`]: https://emscripten.org/docs/api_reference/emscripten.h.html#c.emscripten_get_window_title
321///
322/// # Examples
323/// ```rust
324/// println!("Your tab title should be '{}'", get_window_title());
325/// ```
326pub fn get_window_title() -> String {
327 let title = unsafe { emscripten::emscripten_get_window_title() };
328
329 let title_cstr = unsafe { CStr::from_ptr(title) };
330 title_cstr.to_str().unwrap().to_string()
331}
332
333/// Sets the window title, using the emscripten-defined [`emscripten_set_window_title`].
334///
335/// [`emscripten_set_window_title`]: https://emscripten.org/docs/api_reference/emscripten.h.html#c.emscripten_set_window_title
336///
337/// # Arguments
338/// * `title` - The new title
339///
340/// # Examples
341/// ```rust
342/// set_window_title("My Web App");
343/// set_window_title(format!("My app {} u", 3 + 1));
344/// ```
345pub fn set_window_title<T>(title: T)
346where
347 T: AsRef<str>,
348{
349 let title = CString::new(title.as_ref()).unwrap();
350
351 unsafe {
352 emscripten::emscripten_set_window_title(title.as_ptr());
353 }
354}
355
356/// The result of the [`get_screen_size`] function.
357///
358/// Implements [`Display`] as `{width}x{height}`.
359/// Useful for writing the screen size easily, e.g. using [`.to_string()`] in your app.
360///
361/// [`Display`]: https://doc.rust-lang.org/std/fmt/trait.Display.html
362/// [`.to_string()`]: https://doc.rust-lang.org/std/string/trait.ToString.html#tymethod.to_string
363///
364/// # Examples
365/// ```rust
366/// let screen_size = get_screen_size();
367///
368/// // This should display something like: "Your screen size is 800x600"
369/// println!("Your screen size is {}", screen_size);
370///
371/// let an_old_size = ScreenSize {
372/// width: 800,
373/// height: 600
374/// };
375/// if an_old_size == screen_size {
376/// println!("Wow, you have the 'old' size of 800x600");
377/// }
378///
379/// println!("You have {} pixels", screen_size.width * screen_size.height);
380/// ```
381#[derive(Debug, Clone, PartialEq, Eq)]
382pub struct ScreenSize {
383 pub width: c_int,
384 pub height: c_int,
385}
386impl Display for ScreenSize {
387 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
388 write!(f, "{}x{}", self.width, self.height)
389 }
390}
391
392/// Returns the width and height of the screen in a nice [`ScreenSize`] structure.
393///
394/// # Examples
395/// ```rust
396/// let screen_size = get_screen_size();
397///
398/// // This should display something like: "Your screen size is 800x600"
399/// println!("Your screen size is {}", screen_size);
400///
401/// println!("You have {} pixels", screen_size.width * screen_size.height);
402/// ```
403pub fn get_screen_size() -> ScreenSize {
404 let mut width = 0;
405 let mut height = 0;
406
407 unsafe {
408 emscripten::emscripten_get_screen_size(&mut width, &mut height);
409 }
410
411 ScreenSize { width, height }
412}
413
414/// Hides the OS mouse cursor over the canvas, unlike SDL's [`SDL_ShowCursor`], which works with the SDL cursor.
415///
416/// Useful if you draw your own cursor.
417///
418/// [`SDL_ShowCursor`]: https://wiki.libsdl.org/SDL2/SDL_ShowCursor
419pub fn hide_mouse() {
420 unsafe {
421 emscripten::emscripten_hide_mouse();
422 }
423}
424
425/// Returns the representation of the current app running time with the highest precision using the emscripten-defined [`emscripten_get_now`].
426/// It is most likely implemented using [`performance.now()`], and is relevant only in comparison with other calls to this function.
427///
428/// [`emscripten_get_now`]: https://emscripten.org/docs/api_reference/emscripten.h.html#c.emscripten_get_now
429/// [`performance.now()`]: https://developer.mozilla.org/en-US/docs/Web/API/Performance/now
430///
431/// # Examples
432/// ```rust
433/// let start_time = get_now();
434///
435/// let x = 0;
436/// for i in 1..100 {
437/// x += i;
438/// }
439///
440/// println!("It took {} seconds", get_now() - start_time);
441/// ```
442pub fn get_now() -> f64 {
443 unsafe { emscripten::emscripten_get_now() }
444}
445
446/// Returns a random number in range [0,1), with [`Math.random()`], using the emscripten-defined [`emscripten_random`].
447///
448/// [`Math.random()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
449/// [`emscripten_random`]: https://emscripten.org/docs/api_reference/emscripten.h.html#c.emscripten_random
450///
451/// # Examples
452/// ```rust
453/// assert!(random() >= 0);
454/// assert!(random() < 1);
455/// ```
456pub fn random() -> f32 {
457 unsafe { emscripten::emscripten_random() }
458}
459
460/// Runs the given JavaScript script string with the [`eval()`] JS function, in the calling thread,
461/// using the emscripten-defined [`emscripten_run_script`].
462///
463/// If you need to run the script in the main thread, check out [`run_script_main_thread`].
464///
465/// [`eval()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
466/// [`emscripten_run_script`]: https://emscripten.org/docs/api_reference/emscripten.h.html#c.emscripten_run_script
467///
468/// # Arguments
469/// * `script` - The script to execute.
470///
471/// # Examples
472/// ```rust
473/// run_script("alert('Hello world')");
474///
475/// // The `.escape_unicode()` method makes it safe to pass untrusted user input.
476/// run_script(
477/// format!(
478/// r##"
479/// document.querySelector("#this-is-secure").innerHTML = "{}"
480/// "##,
481/// "untrusted user input".escape_unicode()
482/// )
483/// );
484/// ```
485pub fn run_script<T>(script: T)
486where
487 T: AsRef<str>,
488{
489 let script_cstring = CString::new(script.as_ref()).unwrap();
490 unsafe { emscripten::emscripten_run_script(script_cstring.as_ptr()) }
491}
492
493/// Runs the given JavaScript script string with the [`eval()`] JS function, in the calling thread,
494/// using the emscripten-defined [`emscripten_run_script_int`].
495/// It returns the return result of the script, interpreted as a C int.
496/// Most probably the return result is passed to [`parseInt()`], with NaN represented as 0.
497///
498/// If you need to run the script in the main thread, check out [`run_script_main_thread_int`].
499///
500/// [`eval()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
501/// [`emscripten_run_script_int`]: https://emscripten.org/docs/api_reference/emscripten.h.html#c.emscripten_run_script_int
502/// [`parseInt()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt
503///
504/// # Arguments
505/// * `script` - The script to execute.
506///
507/// # Examples
508/// ```rust
509/// assert_eq!(run_script_int("1 + 2"), 3);
510/// ```
511pub fn run_script_int<T>(script: T) -> c_int
512where
513 T: AsRef<str>,
514{
515 let script_cstring = CString::new(script.as_ref()).unwrap();
516 unsafe { emscripten::emscripten_run_script_int(script_cstring.as_ptr()) }
517}
518
519/// Runs the given JavaScript script string with the [`eval()`] JS function, in the calling thread,
520/// using the emscripten-defined [`emscripten_run_script_string`].
521/// It returns the return result of the script, interpreted as a string if possible.
522/// Otherwise, it returns None.
523///
524/// [`eval()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
525/// [`emscripten_run_script_string`]: https://emscripten.org/docs/api_reference/emscripten.h.html#c.emscripten_run_script_string
526///
527/// # Arguments
528/// * `script` - The script to execute.
529///
530/// # Examples
531/// ```rust
532/// assert_eq!(run_script_string("alert('hi')"), None);
533/// assert_eq!(run_script_string("2"), Some("2"));
534/// assert_eq!(run_script_string("'hi'"), Some("hi"));
535/// ```
536pub fn run_script_string<T>(script: T) -> Option<String>
537where
538 T: AsRef<str>,
539{
540 let script_cstring = CString::new(script.as_ref()).unwrap();
541 let result = unsafe { emscripten::emscripten_run_script_string(script_cstring.as_ptr()) };
542
543 if result.is_null() {
544 return None;
545 }
546
547 let result_cstr = unsafe { CStr::from_ptr(result) };
548 Some(result_cstr.to_str().unwrap().to_string())
549}
550
551// The functions defined in `asm_in_main_thread.c`.
552extern "C" {
553 fn asm_in_main_thread(script: *const c_char);
554 fn asm_in_main_thread_int(script: *const c_char) -> c_int;
555 fn asm_in_main_thread_double(script: *const c_char) -> c_double;
556}
557
558/// Runs the given JavaScript script string with the [`eval()`] JS function, in the main thread,
559/// using the emscripten-defined [`MAIN_THREAD_EM_ASM`].
560///
561/// If you need to run the script in the calling thread, check out [`run_script`].
562///
563/// [`eval()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
564/// [`MAIN_THREAD_EM_ASM`]: https://emscripten.org/docs/api_reference/emscripten.h.html#c.MAIN_THREAD_EM_ASM
565///
566/// # Arguments
567/// * `script` - The script to execute.
568///
569/// # Examples
570/// ```rust
571/// run_script_main_thread("alert('Hello world')");
572///
573/// // The `.escape_unicode()` method makes it safe to pass untrusted user input.
574/// run_script_main_thread(
575/// format!(
576/// r##"
577/// document.querySelector("#this-is-secure").innerHTML = "{}"
578/// "##,
579/// "untrusted user input".escape_unicode()
580/// )
581/// );
582/// ```
583pub fn run_script_main_thread<T>(script: T)
584where
585 T: AsRef<str>,
586{
587 let script_cstring = CString::new(script.as_ref()).unwrap();
588 unsafe { asm_in_main_thread(script_cstring.as_ptr()) }
589}
590
591/// Runs the given JavaScript script string with the [`eval()`] JS function, in the main thread,
592/// using the emscripten-defined [`MAIN_THREAD_EM_ASM_INT`].
593/// It returns the return result of the script, interpreted as a C int.
594/// Most probably the return result is passed to [`parseInt()`], with NaN represented as 0.
595///
596/// If you need to run the script in the calling thread, check out [`run_script_int`].
597///
598/// [`eval()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
599/// [`MAIN_THREAD_EM_ASM_INT`]: https://emscripten.org/docs/api_reference/emscripten.h.html#c.MAIN_THREAD_EM_ASM_INT
600/// [`parseInt()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt
601///
602/// # Arguments
603/// * `script` - The script to execute.
604///
605/// # Examples
606/// ```rust
607/// assert_eq!(run_script_main_thread_int("1 + 2"), 3);
608/// ```
609pub fn run_script_main_thread_int<T>(script: T) -> c_int
610where
611 T: AsRef<str>,
612{
613 let script_cstring = CString::new(script.as_ref()).unwrap();
614 unsafe { asm_in_main_thread_int(script_cstring.as_ptr()) }
615}
616
617/// Runs the given JavaScript script string with the [`eval()`] JS function, in the main thread,
618/// using the emscripten-defined [`MAIN_THREAD_EM_ASM_DOUBLE`].
619/// It returns the return result of the script, interpreted as a C double.
620///
621/// [`eval()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
622/// [`MAIN_THREAD_EM_ASM_DOUBLE`]: https://emscripten.org/docs/api_reference/emscripten.h.html#c.MAIN_THREAD_EM_ASM_DOUBLE
623///
624/// # Arguments
625/// * `script` - The script to execute.
626///
627/// # Examples
628/// ```rust
629/// assert_eq!(run_script_main_thread_double("1.1 + 2.1"), 3.2);
630/// ```
631pub fn run_script_main_thread_double<T>(script: T) -> c_double
632where
633 T: AsRef<str>,
634{
635 let script_cstring = CString::new(script.as_ref()).unwrap();
636 unsafe { asm_in_main_thread_double(script_cstring.as_ptr()) }
637}