1use std::borrow::Cow;
4use std::error;
5use std::fmt;
6use std::ptr;
7
8use artichoke_core::convert::{Convert, ConvertMut, TryConvertMut};
9use artichoke_core::intern::Intern;
10use artichoke_core::value::Value as ValueCore;
11use spinoso_exception::{ArgumentError, Fatal};
12
13use crate::Artichoke;
14use crate::core::ClassRegistry;
15use crate::error::{Error, RubyException};
16use crate::exception_handler;
17use crate::gc::MrbGarbageCollection;
18use crate::sys::{self, protect};
19use crate::types::{self, Ruby};
20
21pub const MRB_FUNCALL_ARGC_MAX: usize = 16;
23
24#[derive(Default, Debug, Clone, Copy)]
26pub struct Value(sys::mrb_value);
27
28impl From<Value> for sys::mrb_value {
29 fn from(value: Value) -> Self {
31 value.0
32 }
33}
34
35impl From<sys::mrb_value> for Value {
36 fn from(value: sys::mrb_value) -> Self {
38 Self(value)
39 }
40}
41
42impl From<Option<sys::mrb_value>> for Value {
43 fn from(value: Option<sys::mrb_value>) -> Self {
44 let Some(value) = value else {
45 return Self::nil();
46 };
47 Self::from(value)
48 }
49}
50
51impl From<Option<Value>> for Value {
52 fn from(value: Option<Value>) -> Self {
53 value.unwrap_or_else(Value::nil)
54 }
55}
56
57impl PartialEq for Value {
58 fn eq(&self, other: &Self) -> bool {
59 let this = unsafe { sys::mrb_sys_basic_ptr(self.inner()) };
60 let other = unsafe { sys::mrb_sys_basic_ptr(other.inner()) };
61 ptr::eq(this, other)
62 }
63}
64
65impl Value {
66 #[inline]
70 #[must_use]
71 pub fn new() -> Self {
72 Self::default()
73 }
74
75 #[inline]
77 #[must_use]
78 pub fn nil() -> Self {
79 Self::default()
80 }
81
82 #[inline]
84 #[must_use]
85 pub(crate) const fn inner(&self) -> sys::mrb_value {
86 self.0
87 }
88
89 #[must_use]
100 #[inline]
101 pub fn is_unreachable(&self) -> bool {
102 matches!(self.ruby_type(), Ruby::Unreachable)
103 }
104
105 #[must_use]
107 pub fn is_dead(&self, interp: &mut Artichoke) -> bool {
108 let value = self.inner();
109 let is_dead = unsafe { interp.with_ffi_boundary(|mrb| sys::mrb_sys_value_is_dead(mrb, value)) };
110 is_dead.unwrap_or_default()
111 }
112
113 pub fn is_range(&self, interp: &mut Artichoke, len: i64) -> Result<Option<protect::Range>, Error> {
114 let mut arena = interp.create_arena_savepoint()?;
115 let result = unsafe {
116 arena
117 .interp()
118 .with_ffi_boundary(|mrb| protect::is_range(mrb, self.inner(), len))?
119 };
120 match result {
121 Ok(range) => Ok(range),
122 Err(exception) => {
123 let exception = Self::from(exception);
124 Err(exception_handler::last_error(&mut arena, exception)?)
125 }
126 }
127 }
128}
129
130impl ValueCore for Value {
131 type Artichoke = Artichoke;
132 type Arg = Self;
133 type Value = Self;
134 type Block = Self;
135 type Error = Error;
136
137 fn funcall(
138 &self,
139 interp: &mut Self::Artichoke,
140 func: &str,
141 args: &[Self::Arg],
142 block: Option<Self::Block>,
143 ) -> Result<Self::Value, Self::Error> {
144 if self.is_dead(interp) {
145 let message = "Value receiver for function call is dead. \
146 This indicates a bug in the mruby garbage collector. \
147 Please leave a comment at https://github.com/artichoke/artichoke/issues/1336.";
148 return Err(Fatal::with_message(message).into());
149 }
150 if let Ok(arg_count_error) = ArgCountError::try_from(args) {
151 emit_fatal_warning!("Value::funcall invoked with too many arguments: {}", arg_count_error);
152 return Err(arg_count_error.into());
153 }
154 let args = args.iter().map(Self::inner).collect::<Vec<_>>();
155 let func = interp.intern_string(func.to_string())?;
156 let result = unsafe {
157 interp.with_ffi_boundary(|mrb| {
158 protect::funcall(
159 mrb,
160 self.inner(),
161 func,
162 args.as_slice(),
163 block.as_ref().map(Self::inner),
164 )
165 })?
166 };
167 match result {
168 Ok(value) => {
169 let value = Self::from(value);
170 if value.is_unreachable() {
171 Err(Fatal::from("Unreachable Ruby value").into())
177 } else {
178 Ok(interp.protect(value))
179 }
180 }
181 Err(exception) => {
182 let exception = interp.protect(Self::from(exception));
183 Err(exception_handler::last_error(interp, exception)?)
184 }
185 }
186 }
187
188 fn freeze(&mut self, interp: &mut Self::Artichoke) -> Result<(), Self::Error> {
189 self.funcall(interp, "freeze", &[], None)?;
190 Ok(())
191 }
192
193 fn is_frozen(&self, interp: &mut Self::Artichoke) -> bool {
194 let value = self.inner();
195 let is_frozen = unsafe { interp.with_ffi_boundary(|mrb| sys::mrb_sys_obj_frozen(mrb, value)) };
196 is_frozen.unwrap_or_default()
197 }
198
199 fn inspect(&self, interp: &mut Self::Artichoke) -> Vec<u8> {
200 let Ok(display) = self.funcall(interp, "inspect", &[], None) else {
201 return vec![];
202 };
203 display.try_convert_into_mut(interp).unwrap_or_default()
204 }
205
206 fn is_nil(&self) -> bool {
207 matches!(self.ruby_type(), Ruby::Nil)
208 }
209
210 fn respond_to(&self, interp: &mut Self::Artichoke, method: &str) -> Result<bool, Self::Error> {
211 let method_sym = if let Some(sym) = interp.check_interned_string(method)? {
214 sym
215 } else {
216 interp.intern_string(String::from(method))?
217 };
218 let has_method =
219 unsafe { interp.with_ffi_boundary(|mrb| sys::mrb_sys_value_has_method(mrb, self.inner(), method_sym))? };
220 Ok(has_method)
221 }
222
223 fn to_s(&self, interp: &mut Self::Artichoke) -> Vec<u8> {
224 let Ok(display) = self.funcall(interp, "to_s", &[], None) else {
225 return vec![];
226 };
227 display.try_convert_into_mut(interp).unwrap_or_default()
228 }
229
230 fn ruby_type(&self) -> Ruby {
231 types::ruby_from_mrb_value(self.inner())
232 }
233}
234
235impl Convert<Value, Value> for Artichoke {
236 fn convert(&self, value: Value) -> Value {
237 value
238 }
239}
240
241impl ConvertMut<Value, Value> for Artichoke {
242 fn convert_mut(&mut self, value: Value) -> Value {
243 value
244 }
245}
246
247#[derive(Default, Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
249pub struct ArgCountError {
250 pub given: usize,
252 pub max: usize,
254}
255
256impl TryFrom<Vec<Value>> for ArgCountError {
257 type Error = ();
258
259 fn try_from(args: Vec<Value>) -> Result<Self, Self::Error> {
260 args.as_slice().try_into()
261 }
262}
263
264impl TryFrom<Vec<sys::mrb_value>> for ArgCountError {
265 type Error = ();
266
267 fn try_from(args: Vec<sys::mrb_value>) -> Result<Self, Self::Error> {
268 args.as_slice().try_into()
269 }
270}
271
272impl TryFrom<&[Value]> for ArgCountError {
273 type Error = ();
274
275 fn try_from(args: &[Value]) -> Result<Self, Self::Error> {
276 if args.len() <= MRB_FUNCALL_ARGC_MAX {
278 return Err(());
279 }
280 let err = Self {
281 given: args.len(),
282 max: MRB_FUNCALL_ARGC_MAX,
283 };
284 Ok(err)
285 }
286}
287
288impl TryFrom<&[sys::mrb_value]> for ArgCountError {
289 type Error = ();
290
291 fn try_from(args: &[sys::mrb_value]) -> Result<Self, Self::Error> {
292 if args.len() <= MRB_FUNCALL_ARGC_MAX {
294 return Err(());
295 }
296 let err = Self {
297 given: args.len(),
298 max: MRB_FUNCALL_ARGC_MAX,
299 };
300 Ok(err)
301 }
302}
303
304impl ArgCountError {
305 #[must_use]
307 pub fn new() -> Self {
308 Self {
309 given: 0,
310 max: MRB_FUNCALL_ARGC_MAX,
311 }
312 }
313}
314
315impl fmt::Display for ArgCountError {
316 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
317 f.write_str("Too many arguments for function call: ")?;
318 write!(
319 f,
320 "gave {} arguments, but Artichoke only supports a maximum of {} arguments",
321 self.given, self.max
322 )
323 }
324}
325
326impl error::Error for ArgCountError {}
327
328impl RubyException for ArgCountError {
329 fn message(&self) -> Cow<'_, [u8]> {
330 Cow::Borrowed(b"Too many arguments")
331 }
332
333 fn name(&self) -> Cow<'_, str> {
334 "ArgumentError".into()
335 }
336
337 fn vm_backtrace(&self, interp: &mut Artichoke) -> Option<Vec<Vec<u8>>> {
338 let _ = interp;
339 None
340 }
341
342 fn as_mrb_value(&self, interp: &mut Artichoke) -> Option<sys::mrb_value> {
343 let message = interp.try_convert_mut(self.to_string()).ok()?;
344 let value = interp.new_instance::<ArgumentError>(&[message]).ok().flatten()?;
345 Some(value.inner())
346 }
347}
348
349impl From<ArgCountError> for Error {
350 fn from(exception: ArgCountError) -> Self {
351 let err: Box<dyn RubyException> = Box::new(exception);
352 Self::from(err)
353 }
354}
355
356#[cfg(test)]
357mod tests {
358 use core::panic;
359
360 use bstr::ByteSlice;
361
362 use super::{ArgCountError, MRB_FUNCALL_ARGC_MAX};
363 use crate::gc::MrbGarbageCollection;
364 use crate::test::prelude::*;
365
366 #[test]
367 fn to_s_true() {
368 let mut interp = interpreter();
369
370 let value = interp.convert(true);
371 let string = value.to_s(&mut interp);
372 assert_eq!(string.as_bstr(), b"true".as_bstr());
373 }
374
375 #[test]
376 fn inspect_true() {
377 let mut interp = interpreter();
378
379 let value = interp.convert(true);
380 let debug = value.inspect(&mut interp);
381 assert_eq!(debug.as_bstr(), b"true".as_bstr());
382 }
383
384 #[test]
385 fn to_s_false() {
386 let mut interp = interpreter();
387
388 let value = interp.convert(false);
389 let string = value.to_s(&mut interp);
390 assert_eq!(string.as_bstr(), b"false".as_bstr());
391 }
392
393 #[test]
394 fn inspect_false() {
395 let mut interp = interpreter();
396
397 let value = interp.convert(false);
398 let debug = value.inspect(&mut interp);
399 assert_eq!(debug.as_bstr(), b"false".as_bstr());
400 }
401
402 #[test]
403 fn to_s_nil() {
404 let mut interp = interpreter();
405
406 let value = Value::nil();
407 let string = value.to_s(&mut interp);
408 assert_eq!(string.as_bstr(), b"".as_bstr());
409 }
410
411 #[test]
412 fn inspect_nil() {
413 let mut interp = interpreter();
414
415 let value = Value::nil();
416 let debug = value.inspect(&mut interp);
417 assert_eq!(debug.as_bstr(), b"nil".as_bstr());
418 }
419
420 #[test]
421 fn to_s_fixnum() {
422 let mut interp = interpreter();
423
424 let value = Convert::<_, Value>::convert(&*interp, 255);
425 let string = value.to_s(&mut interp);
426 assert_eq!(string.as_bstr(), b"255".as_bstr());
427 }
428
429 #[test]
430 fn inspect_fixnum() {
431 let mut interp = interpreter();
432
433 let value = Convert::<_, Value>::convert(&*interp, 255);
434 let debug = value.inspect(&mut interp);
435 assert_eq!(debug.as_bstr(), b"255".as_bstr());
436 }
437
438 #[test]
439 fn to_s_string() {
440 let mut interp = interpreter();
441
442 let value = interp.try_convert_mut("interstate").unwrap();
443 let string = value.to_s(&mut interp);
444 assert_eq!(string.as_bstr(), b"interstate".as_bstr());
445 }
446
447 #[test]
448 fn inspect_string() {
449 let mut interp = interpreter();
450
451 let value = interp.try_convert_mut("interstate").unwrap();
452 let debug = value.inspect(&mut interp);
453 assert_eq!(debug.as_bstr(), br#""interstate""#.as_bstr());
454 }
455
456 #[test]
457 fn to_s_empty_string() {
458 let mut interp = interpreter();
459
460 let value = interp.try_convert_mut("").unwrap();
461 let string = value.to_s(&mut interp);
462 assert_eq!(string.as_bstr(), b"".as_bstr());
463 }
464
465 #[test]
466 fn inspect_empty_string() {
467 let mut interp = interpreter();
468
469 let value = interp.try_convert_mut("").unwrap();
470 let debug = value.inspect(&mut interp);
471 assert_eq!(debug.as_bstr(), br#""""#.as_bstr());
472 }
473
474 #[test]
475 fn is_dead() {
476 let mut interp = interpreter();
477 let mut arena = interp.create_arena_savepoint().unwrap();
478 let live = arena.eval(b"'dead'").unwrap();
479 assert!(!live.is_dead(&mut arena));
480
481 let dead = live;
482 let live = arena.eval(b"'live'").unwrap();
483 arena.restore();
484 interp.full_gc().unwrap();
485
486 assert!(dead.is_dead(&mut interp));
488 assert!(!live.is_dead(&mut interp));
491 }
492
493 #[test]
494 fn funcall_is_dead() {
495 let mut interp = interpreter();
496 let mut arena = interp.create_arena_savepoint().unwrap();
497
498 let dead = arena.eval(b"'dead'").unwrap();
499 arena.eval(b"'live'").unwrap();
500 arena.restore();
501 interp.full_gc().unwrap();
502
503 assert!(dead.is_dead(&mut interp));
504
505 let error = dead.funcall(&mut interp, "nil?", &[], None).unwrap_err();
506 assert_eq!(error.name().as_ref(), "fatal");
507 }
508
509 #[test]
510 fn immediate_is_dead() {
511 let mut interp = interpreter();
512 let mut arena = interp.create_arena_savepoint().unwrap();
513 let live = arena.eval(b"27").unwrap();
514 assert!(!live.is_dead(&mut arena));
515
516 let immediate = live;
517 let live = arena.eval(b"64").unwrap();
518 arena.restore();
519 interp.full_gc().unwrap();
520
521 assert!(!immediate.is_dead(&mut interp));
523 assert!(!live.is_dead(&mut interp));
526
527 let fixnum = Convert::<_, Value>::convert(&*interp, 99);
530 assert!(!fixnum.is_dead(&mut interp));
531 }
532
533 #[test]
534 fn funcall_nil_nil() {
535 let mut interp = interpreter();
536
537 let nil = Value::nil();
538 let result = nil
539 .funcall(&mut interp, "nil?", &[], None)
540 .and_then(|value| value.try_convert_into::<bool>(&interp));
541 let nil_is_nil = unwrap_or_panic_with_backtrace(&mut interp, "Value::funcall", result);
542 assert!(nil_is_nil);
543 }
544
545 #[test]
546 fn funcall_string_nil() {
547 let mut interp = interpreter();
548
549 let s = interp.try_convert_mut("foo").unwrap();
550 let result = s
551 .funcall(&mut interp, "nil?", &[], None)
552 .and_then(|value| value.try_convert_into::<bool>(&interp));
553 let string_is_nil = unwrap_or_panic_with_backtrace(&mut interp, "Value::funcall", result);
554 assert!(!string_is_nil);
555 }
556
557 #[test]
558 #[cfg(feature = "core-regexp")]
559 fn funcall_string_split_regexp() {
560 let mut interp = interpreter();
561
562 let s = interp.try_convert_mut("foo").unwrap();
563 let delim = interp.try_convert_mut("").unwrap();
564 let result = s
565 .funcall(&mut interp, "split", &[delim], None)
566 .and_then(|value| value.try_convert_into_mut::<Vec<&str>>(&mut interp));
567 let split = unwrap_or_panic_with_backtrace(&mut interp, "Value::funcall", result);
568 assert_eq!(split, vec!["f", "o", "o"]);
569 }
570
571 #[test]
572 fn funcall_different_types() {
573 let mut interp = interpreter();
574 let nil = Value::nil();
575 let s = interp.try_convert_mut("foo").unwrap();
576 let result = nil
577 .funcall(&mut interp, "==", &[s], None)
578 .and_then(|value| value.try_convert_into::<bool>(&interp));
579 let eql = unwrap_or_panic_with_backtrace(&mut interp, "Value::funcall", result);
580 assert!(!eql);
581 }
582
583 #[test]
584 fn funcall_type_error() {
585 let mut interp = interpreter();
586 let nil = Value::nil();
587 let s = interp.try_convert_mut("foo").unwrap();
588 let err = s
589 .funcall(&mut interp, "+", &[nil], None)
590 .and_then(|value| value.try_convert_into_mut::<String>(&mut interp))
591 .unwrap_err();
592 assert_eq!("TypeError", err.name().as_ref());
593 assert_eq!(
594 b"no implicit conversion of nil into String".as_bstr(),
595 err.message().as_ref().as_bstr()
596 );
597 }
598
599 #[test]
600 fn funcall_method_not_exists() {
601 let mut interp = interpreter();
602 let nil = Value::nil();
603 let s = interp.try_convert_mut("foo").unwrap();
604 let err = nil.funcall(&mut interp, "garbage_method_name", &[s], None).unwrap_err();
605 assert_eq!("NoMethodError", err.name().as_ref());
606 assert_eq!(
607 b"undefined method 'garbage_method_name'".as_bstr(),
608 err.message().as_ref().as_bstr()
609 );
610 }
611
612 #[test]
613 fn value_respond_to() {
614 let mut interp = interpreter();
615 let nil = Value::nil();
616 assert!(nil.respond_to(&mut interp, "nil?").unwrap());
617 assert!(nil.respond_to(&mut interp, "class").unwrap());
618 assert!(!nil.respond_to(&mut interp, "zyxw_not_a_method").unwrap());
619
620 let object = interp.eval(b"Object.new").unwrap();
621 assert!(object.respond_to(&mut interp, "class").unwrap());
622 assert!(object.respond_to(&mut interp, "freeze").unwrap());
623 assert!(!object.respond_to(&mut interp, "zyxw_not_a_method").unwrap());
624
625 let array = interp.eval(b"[1, 2, 3]").unwrap();
626 assert!(array.respond_to(&mut interp, "class").unwrap());
627 assert!(array.respond_to(&mut interp, "length").unwrap());
628 assert!(!array.respond_to(&mut interp, "zyxw_not_a_method").unwrap());
629 }
630
631 #[test]
632 fn value_respond_to_basic_object() {
633 let mut interp = interpreter();
634
635 let basic_object = interp.eval(b"BasicObject.new").unwrap();
638 assert!(basic_object.respond_to(&mut interp, "__send__").unwrap());
639 assert!(!basic_object.respond_to(&mut interp, "class").unwrap());
640 assert!(!basic_object.respond_to(&mut interp, "zyxw_not_a_method").unwrap());
641 }
642
643 #[test]
644 fn arg_count_error_no_error_for_valid_count_values() {
645 let args = vec![Value::nil(); MRB_FUNCALL_ARGC_MAX];
647 let err = ArgCountError::try_from(args.as_slice());
649 assert!(
650 err.is_err(),
651 "Expected no ArgCountError for {MRB_FUNCALL_ARGC_MAX} arguments",
652 );
653 }
654
655 #[test]
656 fn arg_count_error_error_for_excess_count_values() {
657 let count = MRB_FUNCALL_ARGC_MAX + 1;
658 let args = vec![Value::nil(); count];
659 let err = ArgCountError::try_from(args.as_slice());
661 let arg_err = err.unwrap_or_else(|()| {
662 panic!("Expected an ArgCountError for {count} arguments, but conversion failed");
663 });
664 assert_eq!(arg_err.given, count);
665 assert_eq!(arg_err.max, MRB_FUNCALL_ARGC_MAX);
666 }
667
668 #[test]
669 fn arg_count_error_no_error_for_valid_count_sys_values() {
670 let args: Vec<sys::mrb_value> = vec![Value::nil().inner(); MRB_FUNCALL_ARGC_MAX];
671 let err = ArgCountError::try_from(args.as_slice());
673 assert!(
674 err.is_err(),
675 "Expected no ArgCountError for {MRB_FUNCALL_ARGC_MAX} sys values"
676 );
677 }
678
679 #[test]
680 fn arg_count_error_error_for_excess_count_sys_values() {
681 let count = MRB_FUNCALL_ARGC_MAX + 1;
682 let args: Vec<sys::mrb_value> = vec![Value::nil().inner(); count];
683 let arg_err = ArgCountError::try_from(args.as_slice()).unwrap_or_else(|()| {
685 panic!("Expected an ArgCountError for {count} sys values, but conversion failed");
686 });
687 assert_eq!(arg_err.given, count);
688 assert_eq!(arg_err.max, MRB_FUNCALL_ARGC_MAX);
689 }
690
691 #[test]
692 fn arg_count_error_display_format() {
693 let given = MRB_FUNCALL_ARGC_MAX + 2;
694 let error = ArgCountError {
695 given,
696 max: MRB_FUNCALL_ARGC_MAX,
697 };
698 let display = format!("{error}");
699 let expected = format!(
700 "Too many arguments for function call: gave {given} arguments, but Artichoke only supports a maximum of {MRB_FUNCALL_ARGC_MAX} arguments",
701 );
702 assert_eq!(display, expected);
703 }
704
705 #[test]
706 fn integration_funcall_with_excess_arguments() {
707 let mut interp = interpreter();
708 let nil = Value::nil();
709 let args = vec![Value::nil(); MRB_FUNCALL_ARGC_MAX + 1];
710 let result = nil.funcall(&mut interp, "nil?", &args, None);
711 let err = result.expect_err("Expected an error due to too many arguments, but funcall succeeded");
712 assert_eq!(err.name().as_ref(), "ArgumentError");
714 let message = err.message();
715 assert!(
716 message.as_bstr().contains_str("Too many arguments"),
717 "Error message does not indicate too many arguments"
718 );
719 }
720}