artichoke_backend/extn/core/math/
mruby.rs

1//! FFI glue between the Rust trampolines and the mruby C interpreter.
2
3use std::ffi::CStr;
4
5use crate::extn::core::math::trampoline;
6use crate::extn::core::math::{self, DomainError, Math};
7use crate::extn::prelude::*;
8
9const MATH_CSTR: &CStr = c"Math";
10const DOMAIN_ERROR_CSTR: &CStr = c"DomainError";
11
12pub fn init(interp: &mut Artichoke) -> InitializeResult<()> {
13    if interp.is_module_defined::<Math>() {
14        return Ok(());
15    }
16
17    let spec = module::Spec::new(interp, "Math", MATH_CSTR, None)?;
18    module::Builder::for_spec(interp, &spec)
19        .add_module_method("acos", math_acos, sys::mrb_args_req(1))?
20        .add_module_method("acosh", math_acosh, sys::mrb_args_req(1))?
21        .add_module_method("asin", math_asin, sys::mrb_args_req(1))?
22        .add_module_method("asinh", math_asinh, sys::mrb_args_req(1))?
23        .add_module_method("atan", math_atan, sys::mrb_args_req(1))?
24        .add_module_method("atan2", math_atan2, sys::mrb_args_req(2))?
25        .add_module_method("atanh", math_atanh, sys::mrb_args_req(1))?
26        .add_module_method("cbrt", math_cbrt, sys::mrb_args_req(1))?
27        .add_module_method("cos", math_cos, sys::mrb_args_req(1))?
28        .add_module_method("cosh", math_cosh, sys::mrb_args_req(1))?
29        .add_module_method("erf", math_erf, sys::mrb_args_req(1))?
30        .add_module_method("erfc", math_erfc, sys::mrb_args_req(1))?
31        .add_module_method("exp", math_exp, sys::mrb_args_req(1))?
32        .add_module_method("frexp", math_frexp, sys::mrb_args_req(1))?
33        .add_module_method("gamma", math_gamma, sys::mrb_args_req(1))?
34        .add_module_method("hypot", math_hypot, sys::mrb_args_req(2))?
35        .add_module_method("ldexp", math_ldexp, sys::mrb_args_req(2))?
36        .add_module_method("lgamma", math_lgamma, sys::mrb_args_req(1))?
37        .add_module_method("log", math_log, sys::mrb_args_req_and_opt(1, 1))?
38        .add_module_method("log10", math_log10, sys::mrb_args_req(1))?
39        .add_module_method("log2", math_log2, sys::mrb_args_req(1))?
40        .add_module_method("sin", math_sin, sys::mrb_args_req(1))?
41        .add_module_method("sinh", math_sinh, sys::mrb_args_req(1))?
42        .add_module_method("sqrt", math_sqrt, sys::mrb_args_req(1))?
43        .add_module_method("tan", math_tan, sys::mrb_args_req(1))?
44        .add_module_method("tanh", math_tanh, sys::mrb_args_req(1))?
45        .define()?;
46
47    let domainerror = class::Spec::new(
48        "DomainError",
49        DOMAIN_ERROR_CSTR,
50        Some(EnclosingRubyScope::module(&spec)),
51        None,
52    )?;
53    class::Builder::for_spec(interp, &domainerror)
54        .with_super_class::<StandardError, _>("StandardError")?
55        .define()?;
56    interp.def_class::<DomainError>(domainerror)?;
57
58    interp.def_module::<Math>(spec)?;
59    let e = interp.convert_mut(math::E);
60    interp.define_module_constant::<Math>("E", e)?;
61    let pi = interp.convert_mut(math::PI);
62    interp.define_module_constant::<Math>("PI", pi)?;
63
64    Ok(())
65}
66
67unsafe extern "C-unwind" fn math_acos(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
68    let value = mrb_get_args!(mrb, required = 1);
69    unwrap_interpreter!(mrb, to => guard);
70    let value = Value::from(value);
71    let result = trampoline::acos(&mut guard, value).map(|result| guard.convert_mut(result));
72    match result {
73        Ok(value) => value.inner(),
74        Err(exception) => {
75            // SAFETY: only Copy objects remain on the stack
76            unsafe { error::raise(guard, exception) }
77        }
78    }
79}
80
81unsafe extern "C-unwind" fn math_acosh(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
82    let value = mrb_get_args!(mrb, required = 1);
83    unwrap_interpreter!(mrb, to => guard);
84    let value = Value::from(value);
85    let result = trampoline::acosh(&mut guard, value).map(|result| guard.convert_mut(result));
86    match result {
87        Ok(value) => value.inner(),
88        Err(exception) => {
89            // SAFETY: only Copy objects remain on the stack
90            unsafe { error::raise(guard, exception) }
91        }
92    }
93}
94
95unsafe extern "C-unwind" fn math_asin(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
96    let value = mrb_get_args!(mrb, required = 1);
97    unwrap_interpreter!(mrb, to => guard);
98    let value = Value::from(value);
99    let result = trampoline::asin(&mut guard, value).map(|result| guard.convert_mut(result));
100    match result {
101        Ok(value) => value.inner(),
102        Err(exception) => {
103            // SAFETY: only Copy objects remain on the stack
104            unsafe { error::raise(guard, exception) }
105        }
106    }
107}
108
109unsafe extern "C-unwind" fn math_asinh(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
110    let value = mrb_get_args!(mrb, required = 1);
111    unwrap_interpreter!(mrb, to => guard);
112    let value = Value::from(value);
113    let result = trampoline::asinh(&mut guard, value).map(|result| guard.convert_mut(result));
114    match result {
115        Ok(value) => value.inner(),
116        Err(exception) => {
117            // SAFETY: only Copy objects remain on the stack
118            unsafe { error::raise(guard, exception) }
119        }
120    }
121}
122
123unsafe extern "C-unwind" fn math_atan(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
124    let value = mrb_get_args!(mrb, required = 1);
125    unwrap_interpreter!(mrb, to => guard);
126    let value = Value::from(value);
127    let result = trampoline::atan(&mut guard, value).map(|result| guard.convert_mut(result));
128    match result {
129        Ok(value) => value.inner(),
130        Err(exception) => {
131            // SAFETY: only Copy objects remain on the stack
132            unsafe { error::raise(guard, exception) }
133        }
134    }
135}
136
137unsafe extern "C-unwind" fn math_atan2(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
138    let (value, other) = mrb_get_args!(mrb, required = 2);
139    unwrap_interpreter!(mrb, to => guard);
140    let value = Value::from(value);
141    let other = Value::from(other);
142    let result = trampoline::atan2(&mut guard, value, other).map(|result| guard.convert_mut(result));
143    match result {
144        Ok(value) => value.inner(),
145        Err(exception) => {
146            // SAFETY: only Copy objects remain on the stack
147            unsafe { error::raise(guard, exception) }
148        }
149    }
150}
151
152unsafe extern "C-unwind" fn math_atanh(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
153    let value = mrb_get_args!(mrb, required = 1);
154    unwrap_interpreter!(mrb, to => guard);
155    let value = Value::from(value);
156    let result = trampoline::atanh(&mut guard, value).map(|result| guard.convert_mut(result));
157    match result {
158        Ok(value) => value.inner(),
159        Err(exception) => {
160            // SAFETY: only Copy objects remain on the stack
161            unsafe { error::raise(guard, exception) }
162        }
163    }
164}
165
166unsafe extern "C-unwind" fn math_cbrt(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
167    let value = mrb_get_args!(mrb, required = 1);
168    unwrap_interpreter!(mrb, to => guard);
169    let value = Value::from(value);
170    let result = trampoline::cbrt(&mut guard, value).map(|result| guard.convert_mut(result));
171    match result {
172        Ok(value) => value.inner(),
173        Err(exception) => {
174            // SAFETY: only Copy objects remain on the stack
175            unsafe { error::raise(guard, exception) }
176        }
177    }
178}
179
180unsafe extern "C-unwind" fn math_cos(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
181    let value = mrb_get_args!(mrb, required = 1);
182    unwrap_interpreter!(mrb, to => guard);
183    let value = Value::from(value);
184    let result = trampoline::cos(&mut guard, value).map(|result| guard.convert_mut(result));
185    match result {
186        Ok(value) => value.inner(),
187        Err(exception) => {
188            // SAFETY: only Copy objects remain on the stack
189            unsafe { error::raise(guard, exception) }
190        }
191    }
192}
193
194unsafe extern "C-unwind" fn math_cosh(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
195    let value = mrb_get_args!(mrb, required = 1);
196    unwrap_interpreter!(mrb, to => guard);
197    let value = Value::from(value);
198    let result = trampoline::cosh(&mut guard, value).map(|result| guard.convert_mut(result));
199    match result {
200        Ok(value) => value.inner(),
201        Err(exception) => {
202            // SAFETY: only Copy objects remain on the stack
203            unsafe { error::raise(guard, exception) }
204        }
205    }
206}
207
208unsafe extern "C-unwind" fn math_erf(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
209    let value = mrb_get_args!(mrb, required = 1);
210    unwrap_interpreter!(mrb, to => guard);
211    let value = Value::from(value);
212    let result = trampoline::erf(&mut guard, value).map(|result| guard.convert_mut(result));
213    match result {
214        Ok(value) => value.inner(),
215        Err(exception) => {
216            // SAFETY: only Copy objects remain on the stack
217            unsafe { error::raise(guard, exception) }
218        }
219    }
220}
221
222unsafe extern "C-unwind" fn math_erfc(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
223    let value = mrb_get_args!(mrb, required = 1);
224    unwrap_interpreter!(mrb, to => guard);
225    let value = Value::from(value);
226    let result = trampoline::erfc(&mut guard, value).map(|result| guard.convert_mut(result));
227    match result {
228        Ok(value) => value.inner(),
229        Err(exception) => {
230            // SAFETY: only Copy objects remain on the stack
231            unsafe { error::raise(guard, exception) }
232        }
233    }
234}
235
236unsafe extern "C-unwind" fn math_exp(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
237    let value = mrb_get_args!(mrb, required = 1);
238    unwrap_interpreter!(mrb, to => guard);
239    let value = Value::from(value);
240    let result = trampoline::exp(&mut guard, value).map(|result| guard.convert_mut(result));
241    match result {
242        Ok(value) => value.inner(),
243        Err(exception) => {
244            // SAFETY: only Copy objects remain on the stack
245            unsafe { error::raise(guard, exception) }
246        }
247    }
248}
249
250unsafe extern "C-unwind" fn math_frexp(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
251    let value = mrb_get_args!(mrb, required = 1);
252    unwrap_interpreter!(mrb, to => guard);
253    let value = Value::from(value);
254    let result: Result<Value, Error> = trampoline::frexp(&mut guard, value).and_then(|(fraction, exponent)| {
255        let fraction = guard.convert_mut(fraction);
256        let exponent = guard.convert(exponent);
257        guard.try_convert_mut(&[fraction, exponent][..])
258    });
259    match result {
260        Ok(value) => value.inner(),
261        Err(exception) => {
262            // SAFETY: only Copy objects remain on the stack
263            unsafe { error::raise(guard, exception) }
264        }
265    }
266}
267
268unsafe extern "C-unwind" fn math_gamma(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
269    let value = mrb_get_args!(mrb, required = 1);
270    unwrap_interpreter!(mrb, to => guard);
271    let value = Value::from(value);
272    let result = trampoline::gamma(&mut guard, value).map(|result| guard.convert_mut(result));
273    match result {
274        Ok(value) => value.inner(),
275        Err(exception) => {
276            // SAFETY: only Copy objects remain on the stack
277            unsafe { error::raise(guard, exception) }
278        }
279    }
280}
281
282unsafe extern "C-unwind" fn math_hypot(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
283    let (value, other) = mrb_get_args!(mrb, required = 2);
284    unwrap_interpreter!(mrb, to => guard);
285    let value = Value::from(value);
286    let other = Value::from(other);
287    let result = trampoline::hypot(&mut guard, value, other).map(|result| guard.convert_mut(result));
288    match result {
289        Ok(value) => value.inner(),
290        Err(exception) => {
291            // SAFETY: only Copy objects remain on the stack
292            unsafe { error::raise(guard, exception) }
293        }
294    }
295}
296
297unsafe extern "C-unwind" fn math_ldexp(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
298    let (fraction, exponent) = mrb_get_args!(mrb, required = 2);
299    unwrap_interpreter!(mrb, to => guard);
300    let fraction = Value::from(fraction);
301    let exponent = Value::from(exponent);
302    let result = trampoline::ldexp(&mut guard, fraction, exponent).map(|result| guard.convert_mut(result));
303    match result {
304        Ok(value) => value.inner(),
305        Err(exception) => {
306            // SAFETY: only Copy objects remain on the stack
307            unsafe { error::raise(guard, exception) }
308        }
309    }
310}
311
312unsafe extern "C-unwind" fn math_lgamma(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
313    let value = mrb_get_args!(mrb, required = 1);
314    unwrap_interpreter!(mrb, to => guard);
315    let value = Value::from(value);
316    let result: Result<Value, Error> = trampoline::lgamma(&mut guard, value).and_then(|(result, sign)| {
317        let result = guard.convert_mut(result);
318        let sign = guard.convert(sign);
319        guard.try_convert_mut(&[result, sign][..])
320    });
321    match result {
322        Ok(value) => value.inner(),
323        Err(exception) => {
324            // SAFETY: only Copy objects remain on the stack
325            unsafe { error::raise(guard, exception) }
326        }
327    }
328}
329
330unsafe extern "C-unwind" fn math_log(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
331    let (value, base) = mrb_get_args!(mrb, required = 1, optional = 1);
332    unwrap_interpreter!(mrb, to => guard);
333    let value = Value::from(value);
334    let base = base.map(Value::from);
335    let result = trampoline::log(&mut guard, value, base).map(|result| guard.convert_mut(result));
336    match result {
337        Ok(value) => value.inner(),
338        Err(exception) => {
339            // SAFETY: only Copy objects remain on the stack
340            unsafe { error::raise(guard, exception) }
341        }
342    }
343}
344
345unsafe extern "C-unwind" fn math_log10(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
346    let value = mrb_get_args!(mrb, required = 1);
347    unwrap_interpreter!(mrb, to => guard);
348    let value = Value::from(value);
349    let result = trampoline::log10(&mut guard, value).map(|result| guard.convert_mut(result));
350    match result {
351        Ok(value) => value.inner(),
352        Err(exception) => {
353            // SAFETY: only Copy objects remain on the stack
354            unsafe { error::raise(guard, exception) }
355        }
356    }
357}
358
359unsafe extern "C-unwind" fn math_log2(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
360    let value = mrb_get_args!(mrb, required = 1);
361    unwrap_interpreter!(mrb, to => guard);
362    let value = Value::from(value);
363    let result = trampoline::log2(&mut guard, value).map(|result| guard.convert_mut(result));
364    match result {
365        Ok(value) => value.inner(),
366        Err(exception) => {
367            // SAFETY: only Copy objects remain on the stack
368            unsafe { error::raise(guard, exception) }
369        }
370    }
371}
372
373unsafe extern "C-unwind" fn math_sin(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
374    let value = mrb_get_args!(mrb, required = 1);
375    unwrap_interpreter!(mrb, to => guard);
376    let value = Value::from(value);
377    let result = trampoline::sin(&mut guard, value).map(|result| guard.convert_mut(result));
378    match result {
379        Ok(value) => value.inner(),
380        Err(exception) => {
381            // SAFETY: only Copy objects remain on the stack
382            unsafe { error::raise(guard, exception) }
383        }
384    }
385}
386
387unsafe extern "C-unwind" fn math_sinh(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
388    let value = mrb_get_args!(mrb, required = 1);
389    unwrap_interpreter!(mrb, to => guard);
390    let value = Value::from(value);
391    let result = trampoline::sinh(&mut guard, value).map(|result| guard.convert_mut(result));
392    match result {
393        Ok(value) => value.inner(),
394        Err(exception) => {
395            // SAFETY: only Copy objects remain on the stack
396            unsafe { error::raise(guard, exception) }
397        }
398    }
399}
400
401unsafe extern "C-unwind" fn math_sqrt(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
402    let value = mrb_get_args!(mrb, required = 1);
403    unwrap_interpreter!(mrb, to => guard);
404    let value = Value::from(value);
405    let result = trampoline::sqrt(&mut guard, value).map(|result| guard.convert_mut(result));
406    match result {
407        Ok(value) => value.inner(),
408        Err(exception) => {
409            // SAFETY: only Copy objects remain on the stack
410            unsafe { error::raise(guard, exception) }
411        }
412    }
413}
414
415unsafe extern "C-unwind" fn math_tan(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
416    let value = mrb_get_args!(mrb, required = 1);
417    unwrap_interpreter!(mrb, to => guard);
418    let value = Value::from(value);
419    let result = trampoline::tan(&mut guard, value).map(|result| guard.convert_mut(result));
420    match result {
421        Ok(value) => value.inner(),
422        Err(exception) => {
423            // SAFETY: only Copy objects remain on the stack
424            unsafe { error::raise(guard, exception) }
425        }
426    }
427}
428
429unsafe extern "C-unwind" fn math_tanh(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
430    let value = mrb_get_args!(mrb, required = 1);
431    unwrap_interpreter!(mrb, to => guard);
432    let value = Value::from(value);
433    let result = trampoline::tanh(&mut guard, value).map(|result| guard.convert_mut(result));
434    match result {
435        Ok(value) => value.inner(),
436        Err(exception) => {
437            // SAFETY: only Copy objects remain on the stack
438            unsafe { error::raise(guard, exception) }
439        }
440    }
441}