1use 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 unsafe { error::raise(guard, exception) }
439 }
440 }
441}