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}