artichoke_backend/extn/core/array/
mruby.rs

1use std::ffi::CStr;
2
3use crate::extn::core::array::{Array, trampoline};
4use crate::extn::prelude::*;
5
6const ARRAY_CSTR: &CStr = c"Array";
7static ARRAY_RUBY_SOURCE: &[u8] = include_bytes!("array.rb");
8
9pub fn init(interp: &mut Artichoke) -> InitializeResult<()> {
10    if interp.is_class_defined::<Array>() {
11        return Ok(());
12    }
13
14    let spec = class::Spec::new("Array", ARRAY_CSTR, None, Some(def::box_unbox_free::<Array>))?;
15    class::Builder::for_spec(interp, &spec)
16        .add_self_method("[]", ary_cls_constructor, sys::mrb_args_rest())?
17        .add_method("+", ary_plus, sys::mrb_args_req(1))?
18        .add_method("*", ary_mul, sys::mrb_args_req(1))?
19        .add_method("<<", ary_push_single, sys::mrb_args_req(1))?
20        .add_method("push", ary_push, sys::mrb_args_rest())?
21        .add_method("[]", ary_element_reference, sys::mrb_args_req_and_opt(1, 1))?
22        .add_method("[]=", ary_element_assignment, sys::mrb_args_req_and_opt(2, 1))?
23        .add_method("clear", ary_clear, sys::mrb_args_none())?
24        .add_method("concat", ary_concat, sys::mrb_args_rest())?
25        .add_method("first", ary_first, sys::mrb_args_opt(1))?
26        .add_method(
27            "initialize",
28            ary_initialize,
29            sys::mrb_args_opt(2) | sys::mrb_args_block(),
30        )?
31        .add_method("initialize_copy", ary_initialize_copy, sys::mrb_args_req(1))?
32        .add_method("last", ary_last, sys::mrb_args_opt(1))?
33        .add_method("length", ary_len, sys::mrb_args_none())?
34        .add_method("pop", ary_pop, sys::mrb_args_none())?
35        .add_method("reverse", ary_reverse, sys::mrb_args_none())?
36        .add_method("reverse!", ary_reverse_bang, sys::mrb_args_none())?
37        .add_method("shift", ary_shift, sys::mrb_args_opt(1))?
38        .add_method("size", ary_len, sys::mrb_args_none())?
39        .define()?;
40    interp.def_class::<Array>(spec)?;
41    interp.eval(ARRAY_RUBY_SOURCE)?;
42
43    Ok(())
44}
45
46unsafe extern "C-unwind" fn ary_cls_constructor(mrb: *mut sys::mrb_state, ary: sys::mrb_value) -> sys::mrb_value {
47    let rest = mrb_get_args!(mrb, *args);
48    unwrap_interpreter!(mrb, to => guard);
49    let result = Array::from(rest);
50    let result = Array::alloc_value(result, &mut guard);
51    match result {
52        Ok(value) => {
53            let rclass = ary.value.p.cast::<sys::RClass>();
54            let value = value.inner();
55            let target_rbasic = value.value.p.cast::<sys::RBasic>();
56
57            // Copy `RClass` from source class to newly allocated `Array`.
58            (*target_rbasic).c = rclass;
59
60            value
61        }
62        Err(exception) => {
63            // SAFETY: only Copy objects remain on the stack
64            unsafe { error::raise(guard, exception) }
65        }
66    }
67}
68
69unsafe extern "C-unwind" fn ary_plus(mrb: *mut sys::mrb_state, ary: sys::mrb_value) -> sys::mrb_value {
70    let other = mrb_get_args!(mrb, required = 1);
71    unwrap_interpreter!(mrb, to => guard);
72    let array = Value::from(ary);
73    let other = Value::from(other);
74    let result = trampoline::plus(&mut guard, array, other);
75    match result {
76        Ok(value) => {
77            let basic = sys::mrb_sys_basic_ptr(ary);
78            sys::mrb_write_barrier(mrb, basic);
79            value.inner()
80        }
81        Err(exception) => {
82            // SAFETY: only Copy objects remain on the stack
83            unsafe { error::raise(guard, exception) }
84        }
85    }
86}
87
88unsafe extern "C-unwind" fn ary_mul(mrb: *mut sys::mrb_state, ary: sys::mrb_value) -> sys::mrb_value {
89    let joiner = mrb_get_args!(mrb, required = 1);
90    unwrap_interpreter!(mrb, to => guard);
91    let array = Value::from(ary);
92    let joiner = Value::from(joiner);
93    let result = trampoline::mul(&mut guard, array, joiner);
94    match result {
95        Ok(value) => {
96            let basic = sys::mrb_sys_basic_ptr(ary);
97            sys::mrb_write_barrier(mrb, basic);
98            value.inner()
99        }
100        Err(exception) => {
101            // SAFETY: only Copy objects remain on the stack
102            unsafe { error::raise(guard, exception) }
103        }
104    }
105}
106
107unsafe extern "C-unwind" fn ary_push_single(mrb: *mut sys::mrb_state, ary: sys::mrb_value) -> sys::mrb_value {
108    let elem = mrb_get_args!(mrb, required = 1);
109    unwrap_interpreter!(mrb, to => guard);
110    let array = Value::from(ary);
111    let elem = Value::from(elem);
112    let result = trampoline::push_single(&mut guard, array, elem);
113    match result {
114        Ok(value) => {
115            let basic = sys::mrb_sys_basic_ptr(ary);
116            sys::mrb_write_barrier(mrb, basic);
117            value.inner()
118        }
119        Err(exception) => {
120            // SAFETY: only Copy objects remain on the stack
121            unsafe { error::raise(guard, exception) }
122        }
123    }
124}
125
126unsafe extern "C-unwind" fn ary_push(mrb: *mut sys::mrb_state, ary: sys::mrb_value) -> sys::mrb_value {
127    let others = mrb_get_args!(mrb, *args);
128    unwrap_interpreter!(mrb, to => guard);
129    let array = Value::from(ary);
130    let others = others.iter().map(|&other| Value::from(other));
131    let result = trampoline::push(&mut guard, array, others);
132    match result {
133        Ok(value) => {
134            let basic = sys::mrb_sys_basic_ptr(ary);
135            sys::mrb_write_barrier(mrb, basic);
136            value.inner()
137        }
138        Err(exception) => {
139            // SAFETY: only Copy objects remain on the stack
140            unsafe { error::raise(guard, exception) }
141        }
142    }
143}
144
145unsafe extern "C-unwind" fn ary_element_reference(mrb: *mut sys::mrb_state, ary: sys::mrb_value) -> sys::mrb_value {
146    let (elem, len) = mrb_get_args!(mrb, required = 1, optional = 1);
147    unwrap_interpreter!(mrb, to => guard);
148    let elem = Value::from(elem);
149    let len = len.map(Value::from);
150    let array = Value::from(ary);
151    let result = trampoline::element_reference(&mut guard, array, elem, len);
152    match result {
153        Ok(value) => value.inner(),
154        Err(exception) => {
155            // SAFETY: only Copy objects remain on the stack
156            unsafe { error::raise(guard, exception) }
157        }
158    }
159}
160
161unsafe extern "C-unwind" fn ary_element_assignment(mrb: *mut sys::mrb_state, ary: sys::mrb_value) -> sys::mrb_value {
162    let (first, second, third) = mrb_get_args!(mrb, required = 2, optional = 1);
163    unwrap_interpreter!(mrb, to => guard);
164    let first = Value::from(first);
165    let second = Value::from(second);
166    let third = third.map(Value::from);
167    let array = Value::from(ary);
168    let result = trampoline::element_assignment(&mut guard, array, first, second, third);
169    match result {
170        Ok(value) => {
171            let basic = sys::mrb_sys_basic_ptr(ary);
172            sys::mrb_write_barrier(mrb, basic);
173            value.inner()
174        }
175        Err(exception) => {
176            // SAFETY: only Copy objects remain on the stack
177            unsafe { error::raise(guard, exception) }
178        }
179    }
180}
181
182unsafe extern "C-unwind" fn ary_clear(mrb: *mut sys::mrb_state, ary: sys::mrb_value) -> sys::mrb_value {
183    mrb_get_args!(mrb, none);
184    unwrap_interpreter!(mrb, to => guard);
185    let array = Value::from(ary);
186    let result = trampoline::clear(&mut guard, array);
187    match result {
188        Ok(value) => {
189            let basic = sys::mrb_sys_basic_ptr(ary);
190            sys::mrb_write_barrier(mrb, basic);
191            value.inner()
192        }
193        Err(exception) => {
194            // SAFETY: only Copy objects remain on the stack
195            unsafe { error::raise(guard, exception) }
196        }
197    }
198}
199
200unsafe extern "C-unwind" fn ary_concat(mrb: *mut sys::mrb_state, ary: sys::mrb_value) -> sys::mrb_value {
201    let others = mrb_get_args!(mrb, *args);
202    unwrap_interpreter!(mrb, to => guard);
203    let array = Value::from(ary);
204    let others = others.iter().map(|&other| Value::from(other));
205    let result = trampoline::concat(&mut guard, array, others);
206    match result {
207        Ok(value) => {
208            let basic = sys::mrb_sys_basic_ptr(ary);
209            sys::mrb_write_barrier(mrb, basic);
210            value.inner()
211        }
212        Err(exception) => {
213            // SAFETY: only Copy objects remain on the stack
214            unsafe { error::raise(guard, exception) }
215        }
216    }
217}
218
219unsafe extern "C-unwind" fn ary_first(mrb: *mut sys::mrb_state, ary: sys::mrb_value) -> sys::mrb_value {
220    let num = mrb_get_args!(mrb, optional = 1);
221    unwrap_interpreter!(mrb, to => guard);
222    let array = Value::from(ary);
223    let num = num.map(Value::from);
224    let result = trampoline::first(&mut guard, array, num);
225    match result {
226        Ok(value) => {
227            let basic = sys::mrb_sys_basic_ptr(ary);
228            sys::mrb_write_barrier(mrb, basic);
229            value.inner()
230        }
231        Err(exception) => {
232            // SAFETY: only Copy objects remain on the stack
233            unsafe { error::raise(guard, exception) }
234        }
235    }
236}
237
238unsafe extern "C-unwind" fn ary_initialize(mrb: *mut sys::mrb_state, ary: sys::mrb_value) -> sys::mrb_value {
239    let (first, second, block) = mrb_get_args!(mrb, optional = 2, &block);
240    unwrap_interpreter!(mrb, to => guard);
241    let array = Value::from(ary);
242    let first = first.map(Value::from);
243    let second = second.map(Value::from);
244    let result = trampoline::initialize(&mut guard, array, first, second, block);
245    match result {
246        Ok(value) => {
247            let basic = sys::mrb_sys_basic_ptr(ary);
248            sys::mrb_write_barrier(mrb, basic);
249            value.inner()
250        }
251        Err(exception) => {
252            // SAFETY: only Copy objects remain on the stack
253            unsafe { error::raise(guard, exception) }
254        }
255    }
256}
257
258unsafe extern "C-unwind" fn ary_initialize_copy(mrb: *mut sys::mrb_state, ary: sys::mrb_value) -> sys::mrb_value {
259    let other = mrb_get_args!(mrb, required = 1);
260    unwrap_interpreter!(mrb, to => guard);
261    let array = Value::from(ary);
262    let other = Value::from(other);
263    let result = trampoline::initialize_copy(&mut guard, array, other);
264    match result {
265        Ok(value) => {
266            let basic = sys::mrb_sys_basic_ptr(ary);
267            sys::mrb_write_barrier(mrb, basic);
268            value.inner()
269        }
270        Err(exception) => {
271            // SAFETY: only Copy objects remain on the stack
272            unsafe { error::raise(guard, exception) }
273        }
274    }
275}
276
277unsafe extern "C-unwind" fn ary_last(mrb: *mut sys::mrb_state, ary: sys::mrb_value) -> sys::mrb_value {
278    let num = mrb_get_args!(mrb, optional = 1);
279    unwrap_interpreter!(mrb, to => guard);
280    let array = Value::from(ary);
281    let num = num.map(Value::from);
282    let result = trampoline::last(&mut guard, array, num);
283    match result {
284        Ok(value) => {
285            let basic = sys::mrb_sys_basic_ptr(ary);
286            sys::mrb_write_barrier(mrb, basic);
287            value.inner()
288        }
289        Err(exception) => {
290            // SAFETY: only Copy objects remain on the stack
291            unsafe { error::raise(guard, exception) }
292        }
293    }
294}
295
296unsafe extern "C-unwind" fn ary_len(mrb: *mut sys::mrb_state, ary: sys::mrb_value) -> sys::mrb_value {
297    mrb_get_args!(mrb, none);
298    unwrap_interpreter!(mrb, to => guard);
299    let ary = Value::from(ary);
300    let result = trampoline::len(&mut guard, ary).and_then(|len| {
301        if let Ok(len) = sys::mrb_int::try_from(len) {
302            Ok(len)
303        } else {
304            Err(Fatal::from("Array length does not fit in mruby Integer max").into())
305        }
306    });
307    match result {
308        Ok(len) => {
309            let len = guard.convert(len);
310            len.inner()
311        }
312        Err(exception) => {
313            // SAFETY: only Copy objects remain on the stack
314            unsafe { error::raise(guard, exception) }
315        }
316    }
317}
318
319unsafe extern "C-unwind" fn ary_pop(mrb: *mut sys::mrb_state, ary: sys::mrb_value) -> sys::mrb_value {
320    mrb_get_args!(mrb, none);
321    unwrap_interpreter!(mrb, to => guard);
322    let array = Value::from(ary);
323    let result = trampoline::pop(&mut guard, array);
324    match result {
325        Ok(value) => {
326            let basic = sys::mrb_sys_basic_ptr(ary);
327            sys::mrb_write_barrier(mrb, basic);
328            value.inner()
329        }
330        Err(exception) => {
331            // SAFETY: only Copy objects remain on the stack
332            unsafe { error::raise(guard, exception) }
333        }
334    }
335}
336
337unsafe extern "C-unwind" fn ary_reverse(mrb: *mut sys::mrb_state, ary: sys::mrb_value) -> sys::mrb_value {
338    mrb_get_args!(mrb, none);
339    unwrap_interpreter!(mrb, to => guard);
340    let array = Value::from(ary);
341    let result = trampoline::reverse(&mut guard, array);
342    match result {
343        Ok(value) => {
344            let basic = sys::mrb_sys_basic_ptr(ary);
345            sys::mrb_write_barrier(mrb, basic);
346            value.inner()
347        }
348        Err(exception) => {
349            // SAFETY: only Copy objects remain on the stack
350            unsafe { error::raise(guard, exception) }
351        }
352    }
353}
354
355unsafe extern "C-unwind" fn ary_reverse_bang(mrb: *mut sys::mrb_state, ary: sys::mrb_value) -> sys::mrb_value {
356    mrb_get_args!(mrb, none);
357    unwrap_interpreter!(mrb, to => guard);
358    let array = Value::from(ary);
359    let result = trampoline::reverse_bang(&mut guard, array);
360    match result {
361        Ok(value) => {
362            let basic = sys::mrb_sys_basic_ptr(ary);
363            sys::mrb_write_barrier(mrb, basic);
364            value.inner()
365        }
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 ary_shift(mrb: *mut sys::mrb_state, ary: sys::mrb_value) -> sys::mrb_value {
374    let count = mrb_get_args!(mrb, optional = 1);
375    unwrap_interpreter!(mrb, to => guard);
376    let count = count.map(Value::from);
377    let array = Value::from(ary);
378    let result = trampoline::shift(&mut guard, array, count);
379    match result {
380        Ok(value) => {
381            let basic = sys::mrb_sys_basic_ptr(ary);
382            sys::mrb_write_barrier(mrb, basic);
383            value.inner()
384        }
385        Err(exception) => {
386            // SAFETY: only Copy objects remain on the stack
387            unsafe { error::raise(guard, exception) }
388        }
389    }
390}