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}