Thanks to visit codestin.com
Credit goes to docs.rs

magnus/
block.rs

1//! Types and functions for working with Ruby blocks and Procs.
2//!
3//! See also [`Ruby`](Ruby#blocks) for more block related methods.
4
5use std::{
6    fmt,
7    mem::{forget, size_of},
8    os::raw::c_int,
9    slice,
10};
11
12use rb_sys::{
13    rb_block_given_p, rb_block_proc, rb_data_typed_object_wrap, rb_obj_is_proc, rb_proc_arity,
14    rb_proc_call_kw, rb_proc_lambda_p, rb_proc_new, rb_yield, rb_yield_splat, rb_yield_values_kw,
15    VALUE,
16};
17
18use crate::{
19    data_type_builder,
20    enumerator::Enumerator,
21    error::{ensure, protect, Error},
22    gc,
23    into_value::{kw_splat, ArgList, IntoValue, RArrayArgList},
24    method::{Block, BlockReturn},
25    object::Object,
26    r_array::RArray,
27    try_convert::TryConvert,
28    typed_data::{DataType, DataTypeFunctions},
29    value::{
30        private::{self, ReprValue as _},
31        NonZeroValue, ReprValue, Value,
32    },
33    Ruby,
34};
35
36/// # `Proc`
37///
38/// Functions that can be used to create instances of [`Proc`], Ruby's
39/// representation of a block as an object.
40///
41/// See also the [`Proc`] type.
42impl Ruby {
43    /// Create a new `Proc`.
44    ///
45    /// As `block` is a function pointer, only functions and closures that do
46    /// not capture any variables are permitted. For more flexibility (at the
47    /// cost of allocating) see [`proc_from_fn`](Ruby::proc_from_fn).
48    ///
49    /// # Examples
50    ///
51    /// ```
52    /// use magnus::{prelude::*, rb_assert, Error, Ruby};
53    ///
54    /// fn example(ruby: &Ruby) -> Result<(), Error> {
55    ///     let proc = ruby.proc_new(|_ruby, args, _block| {
56    ///         let acc = i64::try_convert(*args.get(0).unwrap())?;
57    ///         let i = i64::try_convert(*args.get(1).unwrap())?;
58    ///         Ok(acc + i)
59    ///     });
60    ///
61    ///     rb_assert!(ruby, "proc.call(1, 2) == 3", proc);
62    ///
63    ///     rb_assert!(ruby, "[1, 2, 3, 4, 5].inject(&proc) == 15", proc);
64    ///
65    ///     Ok(())
66    /// }
67    /// # Ruby::init(example).unwrap()
68    /// ```
69    pub fn proc_new<R>(&self, block: fn(&Ruby, &[Value], Option<Proc>) -> R) -> Proc
70    where
71        R: BlockReturn,
72    {
73        unsafe extern "C" fn call<R>(
74            _yielded_arg: VALUE,
75            callback_arg: VALUE,
76            argc: c_int,
77            argv: *const VALUE,
78            blockarg: VALUE,
79        ) -> VALUE
80        where
81            R: BlockReturn,
82        {
83            let func =
84                std::mem::transmute::<VALUE, fn(&Ruby, &[Value], Option<Proc>) -> R>(callback_arg);
85            func.call_handle_error(argc, argv as *const Value, Value::new(blockarg))
86                .as_rb_value()
87        }
88
89        let call_func =
90            call::<R> as unsafe extern "C" fn(VALUE, VALUE, c_int, *const VALUE, VALUE) -> VALUE;
91
92        unsafe {
93            #[allow(clippy::fn_to_numeric_cast)]
94            Proc::from_rb_value_unchecked(rb_proc_new(Some(call_func), block as VALUE))
95        }
96    }
97
98    /// Create a new `Proc`.
99    ///
100    /// See also [`proc_new`](Ruby::proc_new), which is more efficient when
101    /// `block` is a function or closure that does not capture any variables.
102    ///
103    /// # Examples
104    ///
105    /// ```
106    /// use magnus::{prelude::*, rb_assert, Error, Ruby};
107    ///
108    /// fn example(ruby: &Ruby) -> Result<(), Error> {
109    ///     let mut count = 0;
110    ///
111    ///     let proc = ruby.proc_from_fn(move |_ruby, args, _block| {
112    ///         let step = i64::try_convert(*args.get(0).unwrap())?;
113    ///         count += step;
114    ///         Ok(count)
115    ///     });
116    ///
117    ///     rb_assert!(ruby, "proc.call(1) == 1", proc);
118    ///     rb_assert!(ruby, "proc.call(1) == 2", proc);
119    ///     rb_assert!(ruby, "proc.call(2) == 4", proc);
120    ///
121    ///     Ok(())
122    /// }
123    /// # Ruby::init(example).unwrap()
124    /// ```
125    pub fn proc_from_fn<F, R>(&self, block: F) -> Proc
126    where
127        F: 'static + Send + FnMut(&Ruby, &[Value], Option<Proc>) -> R,
128        R: BlockReturn,
129    {
130        unsafe extern "C" fn call<F, R>(
131            _yielded_arg: VALUE,
132            callback_arg: VALUE,
133            argc: c_int,
134            argv: *const VALUE,
135            blockarg: VALUE,
136        ) -> VALUE
137        where
138            F: FnMut(&Ruby, &[Value], Option<Proc>) -> R,
139            R: BlockReturn,
140        {
141            let closure = &mut *(callback_arg as *mut F);
142            closure
143                .call_handle_error(argc, argv as *const Value, Value::new(blockarg))
144                .as_rb_value()
145        }
146
147        let (closure, keepalive) = wrap_closure(block);
148        let call_func =
149            call::<F, R> as unsafe extern "C" fn(VALUE, VALUE, c_int, *const VALUE, VALUE) -> VALUE;
150
151        let proc = unsafe {
152            Proc::from_rb_value_unchecked(rb_proc_new(Some(call_func), closure as VALUE))
153        };
154        // ivar without @ prefix is invisible from Ruby
155        proc.ivar_set("__rust_closure", keepalive).unwrap();
156        proc
157    }
158}
159
160/// Wrapper type for a Value known to be an instance of Ruby’s Proc class.
161///
162/// See the [`ReprValue`] and [`Object`] traits for additional methods
163/// available on this type. See [`Ruby`](Ruby#proc) for methods to create a
164/// `Proc`.
165#[derive(Clone, Copy)]
166#[repr(transparent)]
167pub struct Proc(NonZeroValue);
168
169impl Proc {
170    /// Return `Some(Proc)` if `val` is a `Proc`, `None` otherwise.
171    ///
172    /// # Examples
173    ///
174    /// ```
175    /// use magnus::{block::Proc, eval, Value};
176    /// # let _cleanup = unsafe { magnus::embed::init() };
177    ///
178    /// let val: Value = eval("Proc.new {|a, b| a + b}").unwrap();
179    /// assert!(Proc::from_value(val).is_some());
180    ///
181    /// let val: Value = eval("1 + 2").unwrap();
182    /// assert!(Proc::from_value(val).is_none());
183    /// ```
184    #[inline]
185    pub fn from_value(val: Value) -> Option<Self> {
186        unsafe {
187            Value::new(rb_obj_is_proc(val.as_rb_value()))
188                .to_bool()
189                .then(|| Self(NonZeroValue::new_unchecked(val)))
190        }
191    }
192
193    #[inline]
194    pub(crate) unsafe fn from_rb_value_unchecked(val: VALUE) -> Self {
195        Self(NonZeroValue::new_unchecked(Value::new(val)))
196    }
197
198    /// Create a new `Proc`.
199    ///
200    /// As `block` is a function pointer, only functions and closures that do
201    /// not capture any variables are permitted. For more flexibility (at the
202    /// cost of allocating) see [`from_fn`](Proc::from_fn).
203    ///
204    /// # Panics
205    ///
206    /// Panics if called from a non-Ruby thread. See [`Ruby::proc_new`] for the
207    /// non-panicking version.
208    ///
209    /// # Examples
210    ///
211    /// ```
212    /// # #![allow(deprecated)]
213    /// use magnus::{block::Proc, prelude::*, rb_assert};
214    /// # let _cleanup = unsafe { magnus::embed::init() };
215    ///
216    /// let proc = Proc::new(|_ruby, args, _block| {
217    ///     let acc = i64::try_convert(*args.get(0).unwrap())?;
218    ///     let i = i64::try_convert(*args.get(1).unwrap())?;
219    ///     Ok(acc + i)
220    /// });
221    ///
222    /// rb_assert!("proc.call(1, 2) == 3", proc);
223    ///
224    /// rb_assert!("[1, 2, 3, 4, 5].inject(&proc) == 15", proc);
225    /// ```
226    #[cfg_attr(
227        not(feature = "old-api"),
228        deprecated(note = "please use `Ruby::proc_new` instead")
229    )]
230    #[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
231    #[inline]
232    pub fn new<R>(block: fn(&Ruby, &[Value], Option<Proc>) -> R) -> Self
233    where
234        R: BlockReturn,
235    {
236        get_ruby!().proc_new(block)
237    }
238
239    /// Create a new `Proc`.
240    ///
241    /// See also [`Proc::new`], which is more efficient when `block` is a
242    /// function or closure that does not capture any variables.
243    ///
244    /// # Panics
245    ///
246    /// Panics if called from a non-Ruby thread. See [`Ruby::proc_from_fn`] for
247    /// the non-panicking version.
248    ///
249    /// # Examples
250    ///
251    /// ```
252    /// # #![allow(deprecated)]
253    /// use magnus::{block::Proc, prelude::*, rb_assert};
254    /// # let _cleanup = unsafe { magnus::embed::init() };
255    ///
256    /// let mut count = 0;
257    ///
258    /// let proc = Proc::from_fn(move |_ruby, args, _block| {
259    ///     let step = i64::try_convert(*args.get(0).unwrap())?;
260    ///     count += step;
261    ///     Ok(count)
262    /// });
263    ///
264    /// rb_assert!("proc.call(1) == 1", proc);
265    /// rb_assert!("proc.call(1) == 2", proc);
266    /// rb_assert!("proc.call(2) == 4", proc);
267    /// ```
268    #[cfg_attr(
269        not(feature = "old-api"),
270        deprecated(note = "please use `Ruby::proc_from_fn` instead")
271    )]
272    #[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
273    #[inline]
274    pub fn from_fn<F, R>(block: F) -> Self
275    where
276        F: 'static + Send + FnMut(&Ruby, &[Value], Option<Proc>) -> R,
277        R: BlockReturn,
278    {
279        get_ruby!().proc_from_fn(block)
280    }
281
282    /// Call the proc with `args`.
283    ///
284    /// Returns `Ok(T)` if the proc runs without error and the return value
285    /// converts into a `T`, or returns `Err` if the proc raises or the
286    /// conversion fails.
287    ///
288    /// # Examples
289    ///
290    /// ```
291    /// use magnus::{block::Proc, Error, Ruby};
292    ///
293    /// fn example(ruby: &Ruby) -> Result<(), Error> {
294    ///     let proc: Proc = ruby.eval("Proc.new {|a, b| a + b}").unwrap();
295    ///
296    ///     // call with a tuple
297    ///     let result: i64 = proc.call((1, 2)).unwrap();
298    ///     assert_eq!(3, result);
299    ///
300    ///     // call with a slice
301    ///     let result: i64 = proc
302    ///         .call(&[ruby.integer_from_i64(3), ruby.integer_from_i64(4)][..])
303    ///         .unwrap();
304    ///     assert_eq!(7, result);
305    ///
306    ///     // call with an array
307    ///     let result: i64 = proc
308    ///         .call([ruby.integer_from_i64(5), ruby.integer_from_i64(6)])
309    ///         .unwrap();
310    ///     assert_eq!(11, result);
311    ///
312    ///     // call with a Ruby array
313    ///     let array = ruby.ary_from_vec(vec![7, 8]);
314    ///     let result: i64 = proc.call(array).unwrap();
315    ///     assert_eq!(15, result);
316    ///
317    ///     Ok(())
318    /// }
319    /// # Ruby::init(example).unwrap()
320    /// ```
321    ///
322    /// With keyword arguments:
323    ///
324    /// ```
325    /// use magnus::{block::Proc, kwargs, Error, Ruby};
326    ///
327    /// fn example(ruby: &Ruby) -> Result<(), Error> {
328    ///     let proc: Proc = ruby.eval("Proc.new {|a, b:, c:| a + b + c}").unwrap();
329    ///
330    ///     let result: i64 = proc.call((1, kwargs!("b" => 2, "c" => 3))).unwrap();
331    ///     assert_eq!(6, result);
332    ///
333    ///     Ok(())
334    /// }
335    /// # Ruby::init(example).unwrap()
336    /// ```
337    ///
338    /// Ignoring return value:
339    ///
340    /// ```
341    /// use magnus::{block::Proc, rb_assert, Error, Ruby, Value};
342    ///
343    /// fn example(ruby: &Ruby) -> Result<(), Error> {
344    ///     let proc: Proc = ruby.eval("Proc.new { $called = true }").unwrap();
345    ///
346    ///     let _: Value = proc.call(()).unwrap();
347    ///
348    ///     rb_assert!(ruby, "$called == true");
349    ///
350    ///     Ok(())
351    /// }
352    /// # Ruby::init(example).unwrap()
353    /// ```
354    pub fn call<A, T>(self, args: A) -> Result<T, Error>
355    where
356        A: RArrayArgList,
357        T: TryConvert,
358    {
359        let kw_splat = kw_splat(&args);
360        let args = args.into_array_arg_list_with(&Ruby::get_with(self));
361        unsafe {
362            protect(|| {
363                Value::new(rb_proc_call_kw(
364                    self.as_rb_value(),
365                    args.as_rb_value(),
366                    kw_splat as c_int,
367                ))
368            })
369            .and_then(TryConvert::try_convert)
370        }
371    }
372
373    /// Returns the number of arguments `self` takes.
374    ///
375    /// If `self` takes no arguments, returns `0`.
376    /// If `self` takes only required arguments, returns the number of required
377    /// arguments.
378    /// If `self` is a lambda and has optional arguments, or is not a lambda
379    /// and takes a splat argument, returns `-n-1`, where `n` is the number of
380    /// required arguments.
381    /// If `self` is not a lambda, and takes a finite number of optional
382    /// arguments, returns the number of required arguments.
383    /// Keyword arguments are considered as a single additional argument, that
384    /// argument being required if any keyword argument is required.
385    ///
386    /// # Examples
387    ///
388    /// ```
389    /// use magnus::{block::Proc, eval};
390    /// # let _cleanup = unsafe { magnus::embed::init() };
391    ///
392    /// let proc: Proc = eval("proc {nil}").unwrap();
393    /// assert_eq!(proc.arity(), 0);
394    ///
395    /// let proc: Proc = eval("proc {|a| a + 1}").unwrap();
396    /// assert_eq!(proc.arity(), 1);
397    ///
398    /// let proc: Proc = eval("proc {|a, b| a + b}").unwrap();
399    /// assert_eq!(proc.arity(), 2);
400    ///
401    /// let proc: Proc = eval("proc {|*args| args.sum}").unwrap();
402    /// assert_eq!(proc.arity(), -1);
403    /// ```
404    pub fn arity(self) -> i64 {
405        unsafe { rb_proc_arity(self.as_rb_value()) as i64 }
406    }
407
408    /// Returns whether or not `self` is a lambda.
409    ///
410    /// # Examples
411    ///
412    /// ```
413    /// use magnus::{block::Proc, eval};
414    /// # let _cleanup = unsafe { magnus::embed::init() };
415    ///
416    /// let proc: Proc = eval("proc {|a, b| a + b}").unwrap();
417    /// assert!(!proc.is_lambda());
418    ///
419    /// let proc: Proc = eval("lambda {|a, b| a + b}").unwrap();
420    /// assert!(proc.is_lambda());
421    /// ```
422    pub fn is_lambda(self) -> bool {
423        unsafe { Value::new(rb_proc_lambda_p(self.as_rb_value())).to_bool() }
424    }
425}
426
427impl fmt::Display for Proc {
428    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
429        write!(f, "{}", unsafe { self.to_s_infallible() })
430    }
431}
432
433impl fmt::Debug for Proc {
434    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
435        write!(f, "{}", self.inspect())
436    }
437}
438
439impl IntoValue for Proc {
440    #[inline]
441    fn into_value_with(self, _: &Ruby) -> Value {
442        self.0.get()
443    }
444}
445
446impl Object for Proc {}
447
448unsafe impl private::ReprValue for Proc {}
449
450impl ReprValue for Proc {}
451
452impl TryConvert for Proc {
453    fn try_convert(val: Value) -> Result<Self, Error> {
454        let handle = Ruby::get_with(val);
455        if let Some(p) = Proc::from_value(val) {
456            return Ok(p);
457        }
458        let p_val: Value = match val.funcall("to_proc", ()) {
459            Ok(v) => v,
460            Err(_) => {
461                return Err(Error::new(
462                    handle.exception_type_error(),
463                    format!("no implicit conversion of {} into Proc", unsafe {
464                        val.classname()
465                    },),
466                ))
467            }
468        };
469        Proc::from_value(val).ok_or_else(|| {
470            Error::new(
471                handle.exception_type_error(),
472                format!(
473                    "can't convert {0} to Proc ({0}#to_proc gives {1})",
474                    unsafe { val.classname() },
475                    unsafe { p_val.classname() },
476                ),
477            )
478        })
479    }
480}
481
482/// Wrap a closure in a Ruby object with no class.
483///
484/// This effectivly makes the closure's lifetime managed by Ruby. It will be
485/// dropped when the returned `Value` is garbage collected.
486fn wrap_closure<F, R>(func: F) -> (*mut F, Value)
487where
488    F: FnMut(&Ruby, &[Value], Option<Proc>) -> R,
489    R: BlockReturn,
490{
491    struct Closure<F>(F, DataType);
492    unsafe impl<F> Send for Closure<F> {}
493    impl<F> DataTypeFunctions for Closure<F> {
494        fn mark(&self, marker: &gc::Marker) {
495            // Attempt to mark any Ruby values captured in a closure.
496            // Rust's closures are structs that contain all the values they
497            // have captured. This reads that struct as a slice of VALUEs and
498            // calls rb_gc_mark_locations which calls gc_mark_maybe which
499            // marks VALUEs and ignores non-VALUEs
500            marker.mark_slice(unsafe {
501                slice::from_raw_parts(
502                    &self.0 as *const _ as *const Value,
503                    size_of::<F>() / size_of::<Value>(),
504                )
505            });
506        }
507    }
508
509    let data_type = data_type_builder!(Closure<F>, "rust closure")
510        .free_immediately()
511        .mark()
512        .build();
513
514    let boxed = Box::new(Closure(func, data_type));
515    let ptr = Box::into_raw(boxed);
516    let value = unsafe {
517        Value::new(rb_data_typed_object_wrap(
518            0, // using 0 for the class will hide the object from ObjectSpace
519            ptr as *mut _,
520            (*ptr).1.as_rb_data_type() as *const _,
521        ))
522    };
523    unsafe { (&mut (*ptr).0 as *mut F, value) }
524}
525
526/// # Blocks
527///
528/// Functions to enable working with Ruby blocks.
529///
530/// See also the [`block`](self) module.
531impl Ruby {
532    /// Returns whether a Ruby block has been supplied to the current method.
533    ///
534    /// # Examples
535    ///
536    /// ```
537    /// use magnus::{function, rb_assert, Error, Ruby};
538    ///
539    /// fn got_block(ruby: &Ruby) -> bool {
540    ///     ruby.block_given()
541    /// }
542    ///
543    /// fn example(ruby: &Ruby) -> Result<(), Error> {
544    ///     ruby.define_global_function("got_block?", function!(got_block, 0));
545    ///
546    ///     rb_assert!(ruby, "got_block? {} == true");
547    ///     rb_assert!(ruby, "got_block? == false");
548    ///
549    ///     Ok(())
550    /// }
551    /// # Ruby::init(example).unwrap()
552    /// ```
553    pub fn block_given(&self) -> bool {
554        unsafe { rb_block_given_p() != 0 }
555    }
556
557    /// Returns the block given to the current method as a [`Proc`] instance.
558    ///
559    /// # Examples
560    ///
561    /// ```
562    /// use magnus::{block::Proc, function, rb_assert, Error, Ruby};
563    ///
564    /// fn make_proc(ruby: &Ruby) -> Result<Proc, Error> {
565    ///     ruby.block_proc()
566    /// }
567    ///
568    /// fn example(ruby: &Ruby) -> Result<(), Error> {
569    ///     ruby.define_global_function("make_proc", function!(make_proc, 0));
570    ///
571    ///     rb_assert!(ruby, "make_proc {}.is_a?(Proc)");
572    ///
573    ///     Ok(())
574    /// }
575    /// # Ruby::init(example).unwrap()
576    /// ```
577    pub fn block_proc(&self) -> Result<Proc, Error> {
578        let val = unsafe { protect(|| Value::new(rb_block_proc()))? };
579        Ok(Proc::from_value(val).unwrap())
580    }
581
582    /// Yields a value to the block given to the current method.
583    ///
584    /// **Note:** A method using `yield_value` converted to an Enumerator with
585    /// `to_enum`/[`Value::enumeratorize`] will result in a non-functional
586    /// Enumerator on versions of Ruby before 3.1. See [`Yield`] for an
587    /// alternative.
588    ///
589    /// # Examples
590    ///
591    /// ```
592    /// use magnus::{function, rb_assert, Error, Ruby, Value};
593    ///
594    /// fn metasyntactic_variables(ruby: &Ruby) -> Result<(), Error> {
595    ///     let _: Value = ruby.yield_value("foo")?;
596    ///     let _: Value = ruby.yield_value("bar")?;
597    ///     let _: Value = ruby.yield_value("baz")?;
598    ///     Ok(())
599    /// }
600    ///
601    /// fn example(ruby: &Ruby) -> Result<(), Error> {
602    ///     ruby.define_global_function(
603    ///         "metasyntactic_variables",
604    ///         function!(metasyntactic_variables, 0),
605    ///     );
606    ///
607    ///     let vars = ruby.ary_new();
608    ///     rb_assert!(
609    ///         ruby,
610    ///         "metasyntactic_variables {|var| vars << var} == nil",
611    ///         vars
612    ///     );
613    ///     rb_assert!(ruby, r#"vars == ["foo", "bar", "baz"]"#, vars);
614    ///
615    ///     Ok(())
616    /// }
617    /// # Ruby::init(example).unwrap()
618    /// ```
619    pub fn yield_value<T, U>(&self, val: T) -> Result<U, Error>
620    where
621        T: IntoValue,
622        U: TryConvert,
623    {
624        let val = self.into_value(val);
625        unsafe {
626            protect(|| Value::new(rb_yield(val.as_rb_value()))).and_then(TryConvert::try_convert)
627        }
628    }
629
630    /// Yields multiple values to the block given to the current method.
631    ///
632    /// **Note:** A method using `yield_values` converted to an Enumerator with
633    /// `to_enum`/[`Value::enumeratorize`] will result in a non-functional
634    /// Enumerator on versions of Ruby before 3.1. See [`YieldValues`] for an
635    /// alternative.
636    ///
637    /// # Examples
638    ///
639    /// ```
640    /// use magnus::{function, kwargs, rb_assert, Error, Ruby, Value};
641    ///
642    /// fn metasyntactic_variables(ruby: &Ruby) -> Result<(), Error> {
643    ///     let _: Value = ruby.yield_values((0, kwargs!("var" => "foo")))?;
644    ///     let _: Value = ruby.yield_values((1, kwargs!("var" => "bar")))?;
645    ///     let _: Value = ruby.yield_values((2, kwargs!("var" => "baz")))?;
646    ///     Ok(())
647    /// }
648    ///
649    /// fn example(ruby: &Ruby) -> Result<(), Error> {
650    ///     ruby.define_global_function(
651    ///         "metasyntactic_variables",
652    ///         function!(metasyntactic_variables, 0),
653    ///     );
654    ///
655    ///     let vars = ruby.ary_new();
656    ///     rb_assert!(
657    ///         ruby,
658    ///         "metasyntactic_variables {|pos, var:| vars << [pos, var]} == nil",
659    ///         vars
660    ///     );
661    ///     rb_assert!(
662    ///         ruby,
663    ///         r#"vars == [[0, "foo"], [1, "bar"], [2, "baz"]]"#,
664    ///         vars
665    ///     );
666    ///
667    ///     Ok(())
668    /// }
669    /// # Ruby::init(example).unwrap()
670    /// ```
671    pub fn yield_values<T, U>(&self, vals: T) -> Result<U, Error>
672    where
673        T: ArgList,
674        U: TryConvert,
675    {
676        let kw_splat = kw_splat(&vals);
677        let vals = vals.into_arg_list_with(self);
678        let slice = vals.as_ref();
679        unsafe {
680            protect(|| {
681                Value::new(rb_yield_values_kw(
682                    slice.len() as c_int,
683                    slice.as_ptr() as *const VALUE,
684                    kw_splat as c_int,
685                ))
686            })
687            .and_then(TryConvert::try_convert)
688        }
689    }
690
691    /// Yields a Ruby Array to the block given to the current method.
692    ///
693    /// **Note:** A method using `yield_splat` converted to an Enumerator with
694    /// `to_enum`/[`Value::enumeratorize`] will result in a non-functional
695    /// Enumerator on versions of Ruby before 3.1. See [`YieldSplat`] for an
696    /// alternative.
697    ///
698    /// # Examples
699    ///
700    /// ```
701    /// use magnus::{function, rb_assert, Error, Ruby, Value};
702    ///
703    /// fn metasyntactic_variables(ruby: &Ruby) -> Result<(), Error> {
704    ///     let ary = ruby.ary_new();
705    ///     ary.push(0)?;
706    ///     ary.push("foo")?;
707    ///     let _: Value = ruby.yield_splat(ary)?;
708    ///     let ary = ruby.ary_new();
709    ///     ary.push(1)?;
710    ///     ary.push("bar")?;
711    ///     let _: Value = ruby.yield_splat(ary)?;
712    ///     let ary = ruby.ary_new();
713    ///     ary.push(2)?;
714    ///     ary.push("baz")?;
715    ///     let _: Value = ruby.yield_splat(ary)?;
716    ///     Ok(())
717    /// }
718    ///
719    /// fn example(ruby: &Ruby) -> Result<(), Error> {
720    ///     ruby.define_global_function(
721    ///         "metasyntactic_variables",
722    ///         function!(metasyntactic_variables, 0),
723    ///     );
724    ///
725    ///     let vars = ruby.ary_new();
726    ///     rb_assert!(
727    ///         ruby,
728    ///         "metasyntactic_variables {|pos, var| vars << [pos, var]} == nil",
729    ///         vars
730    ///     );
731    ///     rb_assert!(
732    ///         ruby,
733    ///         r#"vars == [[0, "foo"], [1, "bar"], [2, "baz"]]"#,
734    ///         vars
735    ///     );
736    ///
737    ///     Ok(())
738    /// }
739    /// # Ruby::init(example).unwrap()
740    /// ```
741    pub fn yield_splat<T>(&self, vals: RArray) -> Result<T, Error>
742    where
743        T: TryConvert,
744    {
745        unsafe {
746            protect(|| Value::new(rb_yield_splat(vals.as_rb_value())))
747                .and_then(TryConvert::try_convert)
748        }
749    }
750}
751
752/// Returns whether a Ruby block has been supplied to the current method.
753///
754/// # Panics
755///
756/// Panics if called from a non-Ruby thread. See [`Ruby::block_given`] for the
757/// non-panicking version.
758///
759/// # Examples
760///
761/// ```
762/// # #![allow(deprecated)]
763/// use magnus::{block::block_given, define_global_function, function, rb_assert};
764/// # let _cleanup = unsafe { magnus::embed::init() };
765///
766/// fn got_block() -> bool {
767///     block_given()
768/// }
769///
770/// define_global_function("got_block?", function!(got_block, 0));
771///
772/// rb_assert!("got_block? {} == true");
773/// rb_assert!("got_block? == false");
774/// ```
775#[cfg_attr(
776    not(feature = "old-api"),
777    deprecated(note = "please use `Ruby::block_given` instead")
778)]
779#[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
780#[inline]
781pub fn block_given() -> bool {
782    get_ruby!().block_given()
783}
784
785/// Returns the block given to the current method as a [`Proc`] instance.
786///
787/// # Panics
788///
789/// Panics if called from a non-Ruby thread. See [`Ruby::block_proc`] for the
790/// non-panicking version.
791///
792/// # Examples
793///
794/// ```
795/// # #![allow(deprecated)]
796/// use magnus::{
797///     block::{block_proc, Proc},
798///     define_global_function, function, rb_assert, Error,
799/// };
800/// # let _cleanup = unsafe { magnus::embed::init() };
801///
802/// fn make_proc() -> Result<Proc, Error> {
803///     block_proc()
804/// }
805///
806/// define_global_function("make_proc", function!(make_proc, 0));
807///
808/// rb_assert!("make_proc {}.is_a?(Proc)");
809/// ```
810#[cfg_attr(
811    not(feature = "old-api"),
812    deprecated(note = "please use `Ruby::block_proc` instead")
813)]
814#[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
815#[inline]
816pub fn block_proc() -> Result<Proc, Error> {
817    get_ruby!().block_proc()
818}
819
820/// Yields a value to the block given to the current method.
821///
822/// **Note:** A method using `yield_value` converted to an Enumerator with
823/// `to_enum`/[`Value::enumeratorize`] will result in a non-functional
824/// Enumerator on versions of Ruby before 3.1. See [`Yield`] for an
825/// alternative.
826///
827/// # Panics
828///
829/// Panics if called from a non-Ruby thread. See [`Ruby::yield_value`] for the
830/// non-panicking version.
831///
832/// # Examples
833///
834/// ```
835/// # #![allow(deprecated)]
836/// use magnus::{
837///     block::yield_value, define_global_function, function, rb_assert, Error, RArray, Value,
838/// };
839/// # let _cleanup = unsafe { magnus::embed::init() };
840///
841/// fn metasyntactic_variables() -> Result<(), Error> {
842///     let _: Value = yield_value("foo")?;
843///     let _: Value = yield_value("bar")?;
844///     let _: Value = yield_value("baz")?;
845///     Ok(())
846/// }
847///
848/// define_global_function(
849///     "metasyntactic_variables",
850///     function!(metasyntactic_variables, 0),
851/// );
852///
853/// let vars = RArray::new();
854/// rb_assert!("metasyntactic_variables {|var| vars << var} == nil", vars);
855/// rb_assert!(r#"vars == ["foo", "bar", "baz"]"#, vars);
856/// ```
857#[cfg_attr(
858    not(feature = "old-api"),
859    deprecated(note = "please use `Ruby::yield_value` instead")
860)]
861#[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
862#[inline]
863pub fn yield_value<T, U>(val: T) -> Result<U, Error>
864where
865    T: IntoValue,
866    U: TryConvert,
867{
868    get_ruby!().yield_value(val)
869}
870
871/// Yields multiple values to the block given to the current method.
872///
873/// **Note:** A method using `yield_values` converted to an Enumerator with
874/// `to_enum`/[`Value::enumeratorize`] will result in a non-functional
875/// Enumerator on versions of Ruby before 3.1. See [`YieldValues`] for an
876/// alternative.
877///
878/// # Panics
879///
880/// Panics if called from a non-Ruby thread. See [`Ruby::yield_values`] for the
881/// non-panicking version.
882///
883/// # Examples
884///
885/// ```
886/// # #![allow(deprecated)]
887/// use magnus::{
888///     block::yield_values, define_global_function, function, rb_assert, Error, RArray, Value,
889/// };
890/// # let _cleanup = unsafe { magnus::embed::init() };
891///
892/// fn metasyntactic_variables() -> Result<(), Error> {
893///     let _: Value = yield_values((0, "foo"))?;
894///     let _: Value = yield_values((1, "bar"))?;
895///     let _: Value = yield_values((2, "baz"))?;
896///     Ok(())
897/// }
898///
899/// define_global_function(
900///     "metasyntactic_variables",
901///     function!(metasyntactic_variables, 0),
902/// );
903///
904/// let vars = RArray::new();
905/// rb_assert!(
906///     "metasyntactic_variables {|pos, var| vars << [pos, var]} == nil",
907///     vars
908/// );
909/// rb_assert!(r#"vars == [[0, "foo"], [1, "bar"], [2, "baz"]]"#, vars);
910/// ```
911#[cfg_attr(
912    not(feature = "old-api"),
913    deprecated(note = "please use `Ruby::yield_values` instead")
914)]
915#[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
916#[inline]
917pub fn yield_values<T, U>(vals: T) -> Result<U, Error>
918where
919    T: ArgList,
920    U: TryConvert,
921{
922    get_ruby!().yield_values(vals)
923}
924
925/// Yields a Ruby Array to the block given to the current method.
926///
927/// **Note:** A method using `yield_splat` converted to an Enumerator with
928/// `to_enum`/[`Value::enumeratorize`] will result in a non-functional
929/// Enumerator on versions of Ruby before 3.1. See [`YieldSplat`] for an
930/// alternative.
931///
932/// # Panics
933///
934/// Panics if called from a non-Ruby thread. See [`Ruby::yield_splat`] for the
935/// non-panicking version.
936///
937/// # Examples
938///
939/// ```
940/// # #![allow(deprecated)]
941/// use magnus::{
942///     block::yield_splat, define_global_function, function, rb_assert, Error, RArray, Value,
943/// };
944/// # let _cleanup = unsafe { magnus::embed::init() };
945///
946/// fn metasyntactic_variables() -> Result<(), Error> {
947///     let ary = RArray::new();
948///     ary.push(0)?;
949///     ary.push("foo")?;
950///     let _: Value = yield_splat(ary)?;
951///     let ary = RArray::new();
952///     ary.push(1)?;
953///     ary.push("bar")?;
954///     let _: Value = yield_splat(ary)?;
955///     let ary = RArray::new();
956///     ary.push(2)?;
957///     ary.push("baz")?;
958///     let _: Value = yield_splat(ary)?;
959///     Ok(())
960/// }
961///
962/// define_global_function(
963///     "metasyntactic_variables",
964///     function!(metasyntactic_variables, 0),
965/// );
966///
967/// let vars = RArray::new();
968/// rb_assert!(
969///     "metasyntactic_variables {|pos, var| vars << [pos, var]} == nil",
970///     vars
971/// );
972/// rb_assert!(r#"vars == [[0, "foo"], [1, "bar"], [2, "baz"]]"#, vars);
973/// ```
974#[cfg_attr(
975    not(feature = "old-api"),
976    deprecated(note = "please use `Ruby::yield_splat` instead")
977)]
978#[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
979#[inline]
980pub fn yield_splat<T>(vals: RArray) -> Result<T, Error>
981where
982    T: TryConvert,
983{
984    get_ruby!().yield_splat(vals)
985}
986
987// Our regular implementation of `yield` breaks yielding methods being
988// converted to Enumerators because of the protect call not being compatible
989// with the fibers used in Ruby itself to implement `Enumerator#next`.
990// We have to use protect in `yield` because otherwise Ruby code can
991// `break`/`return` through Rust code and break Rust invariants.
992// This gives up using `protect` by instead using `ensure`, not exposing the
993// `yield` call to user code, and maintaining the invariants ourselves. As it
994// can still be `brake`/`return`ed though it can't be public as it's only safe
995// to call as the last thing in one of our method wrappers (where the raise
996// would normally go). Returning an iterator from a method will trigger this.
997pub(crate) unsafe fn do_yield_iter<I, T>(mut iter: I)
998where
999    I: Iterator<Item = T>,
1000    T: IntoValue,
1001{
1002    let handle = Ruby::get_unchecked();
1003    let ptr = &mut iter as *mut I;
1004    forget(iter); // we're going to drop this ourself;
1005                  // ensure runs the first closure, but yield may raise, so the first
1006                  // closure might never reach the end, so wouldn't drop. The second
1007                  // closure is always run, and always after the first, so we do the
1008                  // drop there
1009    ensure(
1010        || {
1011            for val in &mut *ptr {
1012                rb_yield(handle.into_value(val).as_rb_value());
1013            }
1014            handle.qnil()
1015        },
1016        || {
1017            ptr.drop_in_place();
1018        },
1019    );
1020}
1021
1022// see do_yield_iter
1023pub(crate) unsafe fn do_yield_values_iter<I, T>(mut iter: I)
1024where
1025    I: Iterator<Item = T>,
1026    T: ArgList,
1027{
1028    let handle = Ruby::get_unchecked();
1029    let ptr = &mut iter as *mut I;
1030    forget(iter);
1031    ensure(
1032        || {
1033            for val in &mut *ptr {
1034                let kw_splat = kw_splat(&val);
1035                let vals = val.into_arg_list_with(&handle);
1036                let slice = vals.as_ref();
1037                rb_yield_values_kw(
1038                    slice.len() as c_int,
1039                    slice.as_ptr() as *const VALUE,
1040                    kw_splat as c_int,
1041                );
1042            }
1043            handle.qnil()
1044        },
1045        || {
1046            ptr.drop_in_place();
1047        },
1048    );
1049}
1050
1051// see do_yield_iter
1052pub(crate) unsafe fn do_yield_splat_iter<I>(mut iter: I)
1053where
1054    I: Iterator<Item = RArray>,
1055{
1056    let ptr = &mut iter as *mut I;
1057    forget(iter);
1058    ensure(
1059        || {
1060            for val in &mut *ptr {
1061                rb_yield_splat(val.as_rb_value());
1062            }
1063            Ruby::get_unchecked().qnil()
1064        },
1065        || {
1066            ptr.drop_in_place();
1067        },
1068    );
1069}
1070
1071/// Helper type for functions that either yield a single value to a block or
1072/// return an Enumerator.
1073///
1074/// `I` must implement `Iterator<Item = T>`, where `T` implements [`IntoValue`].
1075///
1076/// # Examples
1077///
1078/// ```
1079/// use magnus::{block::Yield, method, prelude::*, rb_assert, Error, Ruby, Value};
1080///
1081/// fn count_to_3(ruby: &Ruby, rb_self: Value) -> Yield<impl Iterator<Item = u8>> {
1082///     if ruby.block_given() {
1083///         Yield::Iter(1..=3)
1084///     } else {
1085///         Yield::Enumerator(rb_self.enumeratorize("count_to_3", ()))
1086///     }
1087/// }
1088///
1089/// fn example(ruby: &Ruby) -> Result<(), Error> {
1090///     ruby.define_global_function("count_to_3", method!(count_to_3, 0));
1091///
1092///     // call Ruby method with a block.
1093///     let a = ruby.ary_new();
1094///     rb_assert!(ruby, "count_to_3 {|i| a << i} == nil", a);
1095///     rb_assert!(ruby, "a == [1, 2, 3]", a);
1096///
1097///     // call Ruby method without a block.
1098///     let enumerator: Value = ruby.eval("count_to_3").unwrap();
1099///
1100///     rb_assert!(ruby, "enumerator.next == 1", enumerator);
1101///     rb_assert!(ruby, "enumerator.next == 2", enumerator);
1102///
1103///     Ok(())
1104/// }
1105/// # Ruby::init(example).unwrap()
1106/// ```
1107pub enum Yield<I> {
1108    /// Yields `I::Item` to given block.
1109    Iter(I),
1110    /// Returns `Enumerator` from the method.
1111    Enumerator(Enumerator),
1112}
1113
1114/// Helper type for functions that either yield multiple values to a block or
1115/// return an Enumerator.
1116///
1117/// `I` must implement `Iterator<Item = T>`, where `T` implements [`ArgList`].
1118///
1119/// # Examples
1120///
1121/// ```
1122/// use magnus::{block::YieldValues, method, prelude::*, rb_assert, Error, Ruby, Value};
1123///
1124/// fn count_to_3_abc(
1125///     ruby: &Ruby,
1126///     rb_self: Value,
1127/// ) -> YieldValues<impl Iterator<Item = (u8, char)>> {
1128///     if ruby.block_given() {
1129///         YieldValues::Iter((1..=3).zip('a'..='c'))
1130///     } else {
1131///         YieldValues::Enumerator(rb_self.enumeratorize("count_to_3_abc", ()))
1132///     }
1133/// }
1134///
1135/// fn example(ruby: &Ruby) -> Result<(), Error> {
1136///     ruby.define_global_function("count_to_3_abc", method!(count_to_3_abc, 0));
1137///
1138///     // call Ruby method with a block.
1139///     let a = ruby.ary_new();
1140///     rb_assert!(ruby, "count_to_3_abc {|i, c| a << [i, c]} == nil", a);
1141///     rb_assert!(ruby, r#"a == [[1, "a"], [2, "b"], [3, "c"]]"#, a);
1142///
1143///     // call Ruby method without a block.
1144///     let enumerator: Value = ruby.eval("count_to_3_abc").unwrap();
1145///
1146///     rb_assert!(ruby, r#"enumerator.next == [1, "a"]"#, enumerator);
1147///     rb_assert!(ruby, r#"enumerator.next == [2, "b"]"#, enumerator);
1148///
1149///     Ok(())
1150/// }
1151/// # Ruby::init(example).unwrap()
1152/// ```
1153pub enum YieldValues<I> {
1154    /// Yields `I::Item` to given block.
1155    Iter(I),
1156    /// Returns `Enumerator` from the method.
1157    Enumerator(Enumerator),
1158}
1159
1160/// Helper type for functions that either yield an array to a block or
1161/// return an Enumerator.
1162///
1163/// `I` must implement `Iterator<Item = RArray>`.
1164///
1165/// # Examples
1166///
1167/// ```
1168/// use magnus::{block::YieldSplat, method, prelude::*, rb_assert, Error, RArray, Ruby, Value};
1169///
1170/// fn count_to_3_abc(ruby: &Ruby, rb_self: Value) -> YieldSplat<impl Iterator<Item = RArray>> {
1171///     if ruby.block_given() {
1172///         YieldSplat::Iter((1..=3).zip('a'..='c').map(|(i, c)| {
1173///             // we know this will be called on a Ruby thread so it's safe
1174///             // to get a handle to Ruby, but we don't want to be tied to the
1175///             // lifetime of the existing `ruby`.
1176///             let ary = unsafe { Ruby::get_unchecked() }.ary_new();
1177///             ary.push(i).unwrap();
1178///             ary.push(c).unwrap();
1179///             ary
1180///         }))
1181///     } else {
1182///         YieldSplat::Enumerator(rb_self.enumeratorize("count_to_3_abc", ()))
1183///     }
1184/// }
1185///
1186/// fn example(ruby: &Ruby) -> Result<(), Error> {
1187///     ruby.define_global_function("count_to_3_abc", method!(count_to_3_abc, 0));
1188///
1189///     // call Ruby method with a block.
1190///     let a = ruby.ary_new();
1191///     rb_assert!(ruby, "count_to_3_abc {|i, c| a << [i, c]} == nil", a);
1192///     rb_assert!(ruby, r#"a == [[1, "a"], [2, "b"], [3, "c"]]"#, a);
1193///
1194///     // call Ruby method without a block.
1195///     let enumerator: Value = ruby.eval("count_to_3_abc").unwrap();
1196///
1197///     rb_assert!(ruby, r#"enumerator.next == [1, "a"]"#, enumerator);
1198///     rb_assert!(ruby, r#"enumerator.next == [2, "b"]"#, enumerator);
1199///
1200///     Ok(())
1201/// }
1202/// # Ruby::init(example).unwrap()
1203/// ```
1204pub enum YieldSplat<I> {
1205    /// Yields `I::Item` to given block.
1206    Iter(I),
1207    /// Returns `Enumerator` from the method.
1208    Enumerator(Enumerator),
1209}