magnus/value.rs
1//! Types for working with Ruby's VALUE type, representing all objects, and
2//! 'immediate' values such as Fixnum.
3
4#[cfg(ruby_use_flonum)]
5mod flonum;
6
7use std::{
8 borrow::{Borrow, Cow},
9 cell::UnsafeCell,
10 ffi::CStr,
11 fmt,
12 hash::{Hash, Hasher},
13 marker::PhantomData,
14 mem::transmute,
15 num::NonZeroUsize,
16 ops::{Deref, DerefMut},
17 os::raw::{c_char, c_int, c_long, c_ulong},
18 ptr,
19 sync::Once,
20};
21
22#[cfg(ruby_use_flonum)]
23pub use flonum::Flonum;
24use rb_sys::{
25 rb_any_to_s, rb_block_call_kw, rb_check_funcall_kw, rb_check_id, rb_check_id_cstr,
26 rb_check_symbol_cstr, rb_enumeratorize_with_size_kw, rb_eql, rb_equal,
27 rb_funcall_with_block_kw, rb_funcallv_kw, rb_funcallv_public_kw, rb_gc_register_address,
28 rb_gc_unregister_address, rb_hash, rb_id2name, rb_id2sym, rb_inspect, rb_intern3, rb_ll2inum,
29 rb_obj_as_string, rb_obj_classname, rb_obj_freeze, rb_obj_is_kind_of, rb_obj_respond_to,
30 rb_sym2id, rb_ull2inum, ruby_fl_type, ruby_special_consts, ruby_value_type, RBasic, ID, VALUE,
31};
32
33// These don't seem to appear consistently in bindgen output, not sure if they
34// aren't consistently defined in the headers or what. Lets just do it
35// ourselves.
36const RUBY_FIXNUM_MAX: c_ulong = (c_long::MAX / 2) as c_ulong;
37const RUBY_FIXNUM_MIN: c_long = c_long::MIN / 2;
38
39use crate::{
40 block::Proc,
41 class::RClass,
42 encoding::EncodingCapable,
43 enumerator::Enumerator,
44 error::{protect, Error},
45 gc,
46 integer::{Integer, IntegerType},
47 into_value::{kw_splat, ArgList, IntoValue, IntoValueFromNative},
48 method::{Block, BlockReturn},
49 module::Module,
50 numeric::Numeric,
51 r_bignum::RBignum,
52 r_string::RString,
53 symbol::{IntoSymbol, Symbol},
54 try_convert::{TryConvert, TryConvertOwned},
55 Ruby,
56};
57
58/// Ruby's `VALUE` type, which can represent any Ruby object.
59///
60/// Methods for `Value` are implemented on the [`ReprValue`] trait, which is
61/// also implemented for all Ruby types.
62#[derive(Clone, Copy)]
63#[repr(transparent)]
64pub struct Value(VALUE, PhantomData<*mut RBasic>);
65
66impl Value {
67 #[inline]
68 pub(crate) const fn new(val: VALUE) -> Self {
69 Self(val, PhantomData)
70 }
71
72 #[inline]
73 pub(crate) const fn as_rb_value(self) -> VALUE {
74 self.0
75 }
76}
77
78impl fmt::Display for Value {
79 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80 write!(f, "{}", unsafe { self.to_s_infallible() })
81 }
82}
83
84impl fmt::Debug for Value {
85 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86 write!(f, "{}", self.inspect())
87 }
88}
89
90impl IntoValue for Value {
91 #[inline]
92 fn into_value_with(self, _: &Ruby) -> Value {
93 self
94 }
95}
96
97impl IntoValue for i8 {
98 #[inline]
99 fn into_value_with(self, handle: &Ruby) -> Value {
100 handle.integer_from_i64(self as i64).into_value_with(handle)
101 }
102}
103
104unsafe impl IntoValueFromNative for i8 {}
105
106impl IntoValue for i16 {
107 #[inline]
108 fn into_value_with(self, handle: &Ruby) -> Value {
109 handle.integer_from_i64(self as i64).into_value_with(handle)
110 }
111}
112
113unsafe impl IntoValueFromNative for i16 {}
114
115impl IntoValue for i32 {
116 #[inline]
117 fn into_value_with(self, handle: &Ruby) -> Value {
118 handle.integer_from_i64(self as i64).into_value_with(handle)
119 }
120}
121
122unsafe impl IntoValueFromNative for i32 {}
123
124impl IntoValue for i64 {
125 #[inline]
126 fn into_value_with(self, handle: &Ruby) -> Value {
127 handle.integer_from_i64(self).into_value_with(handle)
128 }
129}
130
131unsafe impl IntoValueFromNative for i64 {}
132
133impl IntoValue for i128 {
134 #[inline]
135 fn into_value_with(self, handle: &Ruby) -> Value {
136 handle.integer_from_i128(self).into_value_with(handle)
137 }
138}
139
140unsafe impl IntoValueFromNative for i128 {}
141
142impl IntoValue for isize {
143 #[inline]
144 fn into_value_with(self, handle: &Ruby) -> Value {
145 handle.integer_from_i64(self as i64).into_value_with(handle)
146 }
147}
148
149unsafe impl IntoValueFromNative for isize {}
150
151impl IntoValue for u8 {
152 #[inline]
153 fn into_value_with(self, handle: &Ruby) -> Value {
154 handle.integer_from_u64(self as u64).into_value_with(handle)
155 }
156}
157
158unsafe impl IntoValueFromNative for u8 {}
159
160impl IntoValue for u16 {
161 #[inline]
162 fn into_value_with(self, handle: &Ruby) -> Value {
163 handle.integer_from_u64(self as u64).into_value_with(handle)
164 }
165}
166
167unsafe impl IntoValueFromNative for u16 {}
168
169impl IntoValue for u32 {
170 #[inline]
171 fn into_value_with(self, handle: &Ruby) -> Value {
172 handle.integer_from_u64(self as u64).into_value_with(handle)
173 }
174}
175
176unsafe impl IntoValueFromNative for u32 {}
177
178impl IntoValue for u64 {
179 #[inline]
180 fn into_value_with(self, handle: &Ruby) -> Value {
181 handle.integer_from_u64(self).into_value_with(handle)
182 }
183}
184
185unsafe impl IntoValueFromNative for u64 {}
186
187impl IntoValue for u128 {
188 #[inline]
189 fn into_value_with(self, handle: &Ruby) -> Value {
190 handle.integer_from_u128(self).into_value_with(handle)
191 }
192}
193
194unsafe impl IntoValueFromNative for u128 {}
195
196impl IntoValue for usize {
197 #[inline]
198 fn into_value_with(self, handle: &Ruby) -> Value {
199 handle.integer_from_u64(self as u64).into_value_with(handle)
200 }
201}
202
203unsafe impl IntoValueFromNative for usize {}
204
205impl IntoValue for f32 {
206 #[inline]
207 fn into_value_with(self, handle: &Ruby) -> Value {
208 handle.float_from_f64(self as f64).into_value_with(handle)
209 }
210}
211
212unsafe impl IntoValueFromNative for f32 {}
213
214impl IntoValue for f64 {
215 #[inline]
216 fn into_value_with(self, handle: &Ruby) -> Value {
217 handle.float_from_f64(self).into_value_with(handle)
218 }
219}
220
221unsafe impl IntoValueFromNative for f64 {}
222
223impl TryConvert for Value {
224 #[inline]
225 fn try_convert(val: Value) -> Result<Self, Error> {
226 Ok(val)
227 }
228}
229
230/// A wrapper to make a Ruby type [`Send`] + [`Sync`].
231///
232/// Ruby types are not [`Send`] or [`Sync`] as they provide a way to call
233/// Ruby's APIs, which it is not safe to do from a non-Ruby thread.
234///
235/// Ruby types are safe to send between Ruby threads, but Rust's trait system
236/// currently can not model this detail.
237///
238/// To resolve this, the `Opaque` type makes a Ruby type [`Send`] + [`Sync`]
239/// by removing the ability to do anything with it, making it impossible to
240/// call Ruby's API on non-Ruby threads.
241///
242/// An `Opaque<T>` can be unwrapped to `T` with [`Ruby::get_inner`],
243/// as it is only possible to instantiate a [`Ruby`] on a Ruby thread.
244///
245/// # Examples
246///
247/// ```
248/// use magnus::{rb_assert, value::Opaque, Ruby};
249/// # let _cleanup = unsafe { magnus::embed::init() };
250///
251/// let ruby = Ruby::get().unwrap();
252/// let opaque_str = Opaque::from(ruby.str_new("example"));
253///
254/// // send to another Ruby thread
255///
256/// let ruby = Ruby::get().unwrap(); // errors on non-Ruby thread
257/// let str = ruby.get_inner(opaque_str);
258/// rb_assert!(ruby, r#"str == "example""#, str);
259/// ```
260#[derive(Clone, Copy)]
261#[repr(transparent)]
262pub struct Opaque<T>(T);
263
264// implementation detail for opaque_attr_accessor proc macro attribute
265#[doc(hidden)]
266pub trait OpaqueVal {
267 type Val: ReprValue;
268}
269
270impl<T> OpaqueVal for Opaque<T>
271where
272 T: ReprValue,
273{
274 type Val = T;
275}
276
277impl<T> From<T> for Opaque<T>
278where
279 T: ReprValue,
280{
281 #[inline]
282 fn from(val: T) -> Self {
283 Self(val)
284 }
285}
286
287impl<T> IntoValue for Opaque<T>
288where
289 T: IntoValue,
290{
291 #[inline]
292 fn into_value_with(self, handle: &Ruby) -> Value {
293 self.0.into_value_with(handle)
294 }
295}
296
297/// Helper trait for [`Ruby::get_inner`].
298///
299/// This trait allows for [`Ruby::get_inner`] to get the inner value of both
300/// [`Opaque`] and [`Lazy`].
301pub trait InnerValue {
302 /// The specific Ruby value type.
303 type Value: ReprValue;
304
305 /// Get the inner value from `self`.
306 ///
307 /// `ruby` acts as a token proving this is called from a Ruby thread and
308 /// thus it is safe to return the inner value.
309 ///
310 /// # Examples
311 ///
312 /// ```
313 /// use magnus::{
314 /// rb_assert,
315 /// value::{InnerValue, Opaque},
316 /// Ruby,
317 /// };
318 /// # let _cleanup = unsafe { magnus::embed::init() };
319 ///
320 /// let ruby = Ruby::get().unwrap();
321 /// let opaque_str = Opaque::from(ruby.str_new("example"));
322 ///
323 /// // send to another Ruby thread
324 ///
325 /// let ruby = Ruby::get().unwrap(); // errors on non-Ruby thread
326 /// let str = opaque_str.get_inner_with(&ruby);
327 /// rb_assert!(ruby, r#"str == "example""#, str);
328 /// ```
329 ///
330 /// ```
331 /// use magnus::{
332 /// rb_assert,
333 /// value::{InnerValue, Lazy},
334 /// RString, Ruby,
335 /// };
336 ///
337 /// static STATIC_STR: Lazy<RString> = Lazy::new(|ruby| ruby.str_new("example"));
338 /// # let _cleanup = unsafe { magnus::embed::init() };
339 ///
340 /// let ruby = Ruby::get().unwrap(); // errors if Ruby not initialised
341 /// let str = STATIC_STR.get_inner_with(&ruby);
342 /// rb_assert!(ruby, r#"str == "example""#, str);
343 /// ```
344 fn get_inner_with(self, ruby: &Ruby) -> Self::Value;
345}
346
347impl<T> InnerValue for Opaque<T>
348where
349 T: ReprValue,
350{
351 type Value = T;
352
353 #[inline]
354 fn get_inner_with(self, _: &Ruby) -> Self::Value {
355 self.0
356 }
357}
358
359/// Helper trait for [`Ruby::get_inner_ref`].
360///
361/// This trait allows for [`Ruby::get_inner_ref`] to get a reference to the
362/// inner value of both [`Opaque`] and [`Lazy`].
363pub trait InnerRef {
364 /// The specific Ruby value type.
365 type Value: ReprValue;
366
367 /// Get a reference to the inner value from `self`.
368 ///
369 /// `ruby` acts as a token proving this is called from a Ruby thread and
370 /// thus it is safe to access the inner value.
371 fn get_inner_ref_with<'a>(&'a self, ruby: &Ruby) -> &'a Self::Value;
372}
373
374impl<T> InnerRef for Opaque<T>
375where
376 T: ReprValue,
377{
378 type Value = T;
379
380 #[inline]
381 fn get_inner_ref_with<'a>(&'a self, _: &Ruby) -> &'a Self::Value {
382 &self.0
383 }
384}
385
386/// # Extracting values from `Opaque`/`Lazy`
387///
388/// Magnus has a number of container types where it is only safe to access the
389/// inner Ruby value when you can provide a `Ruby` handle. The functions here
390/// provide a unified api to access those container types.
391///
392/// See also the [`Opaque`] and [`Lazy`] types.
393impl Ruby {
394 /// Get the inner value from `wrapper`.
395 ///
396 /// `self` acts as a token proving this is called from a Ruby thread and
397 /// thus it is safe to return the inner value. See [`Opaque`] and [`Lazy`].
398 ///
399 /// # Examples
400 ///
401 /// ```
402 /// use magnus::{rb_assert, value::Opaque, Ruby};
403 /// # let _cleanup = unsafe { magnus::embed::init() };
404 ///
405 /// let ruby = Ruby::get().unwrap();
406 /// let opaque_str = Opaque::from(ruby.str_new("example"));
407 ///
408 /// // send to another Ruby thread
409 ///
410 /// let ruby = Ruby::get().unwrap(); // errors on non-Ruby thread
411 /// let str = ruby.get_inner(opaque_str);
412 /// rb_assert!(ruby, r#"str == "example""#, str);
413 /// ```
414 ///
415 /// ```
416 /// use magnus::{rb_assert, value::Lazy, RString, Ruby};
417 ///
418 /// static STATIC_STR: Lazy<RString> = Lazy::new(|ruby| ruby.str_new("example"));
419 /// # let _cleanup = unsafe { magnus::embed::init() };
420 ///
421 /// let ruby = Ruby::get().unwrap(); // errors if Ruby not initialised
422 /// let str = ruby.get_inner(&STATIC_STR);
423 /// rb_assert!(ruby, r#"str == "example""#, str);
424 /// ```
425 #[inline]
426 pub fn get_inner<T>(&self, wrapper: impl InnerValue<Value = T>) -> T
427 where
428 T: ReprValue,
429 {
430 wrapper.get_inner_with(self)
431 }
432
433 /// Get a reference to the inner value of `wrapper`.
434 ///
435 /// `self` acts as a token proving this is called from a Ruby thread and
436 /// thus it is safe to access the inner value. See [`Opaque`] and [`Lazy`].
437 #[inline]
438 pub fn get_inner_ref<'a, T>(&self, wrapper: &'a impl InnerRef<Value = T>) -> &'a T
439 where
440 T: ReprValue,
441 {
442 wrapper.get_inner_ref_with(self)
443 }
444}
445
446unsafe impl<T: ReprValue> Send for Opaque<T> {}
447unsafe impl<T: ReprValue> Sync for Opaque<T> {}
448
449/// Lazily initialise a Ruby value so it can be assigned to a `static`.
450///
451/// Ruby types require the Ruby VM to be started before they can be initialise,
452/// so can't be assigned to `static`s. They also can't safely be used from
453/// non-Ruby threads, which a `static` Ruby value would allow.
454///
455/// Lazy allows assigning a Ruby value to a static by lazily initialising it
456/// on first use, and by requiring a value of [`Ruby`] to access the inner
457/// value, which it is only possible to obtain once the Ruby VM has started and
458/// on on a Ruby thread.
459///
460/// # Examples
461///
462/// ```
463/// use magnus::{rb_assert, value::Lazy, RString, Ruby};
464///
465/// static STATIC_STR: Lazy<RString> = Lazy::new(|ruby| ruby.str_new("example"));
466/// # let _cleanup = unsafe { magnus::embed::init() };
467///
468/// let ruby = Ruby::get().unwrap(); // errors if Ruby not initialised
469/// let str = ruby.get_inner(&STATIC_STR);
470/// rb_assert!(ruby, r#"str == "example""#, str);
471/// ```
472pub struct Lazy<T: ReprValue> {
473 init: Once,
474 mark: bool,
475 func: fn(&Ruby) -> T,
476 value: UnsafeCell<Value>,
477}
478
479impl<T> Lazy<T>
480where
481 T: ReprValue,
482{
483 /// Create a new `Lazy<T>`.
484 ///
485 /// This function can be called in a `const` context. `func` is evaluated
486 /// when the `Lazy<T>` is first accessed (see [`Ruby::get_inner`]). If
487 /// multiple threads attempt first access at the same time `func` may be
488 /// called more than once, but all threads will recieve the same value.
489 ///
490 /// This function assumes the `Lazy<T>` will be assinged to a `static`, so
491 /// marks the inner Ruby value with Ruby's garbage collector to never be
492 /// garbage collected. See [`Lazy::new_without_mark`] if this is not wanted.
493 ///
494 /// # Examples
495 ///
496 /// ```
497 /// use magnus::{rb_assert, value::Lazy, RString, Ruby};
498 ///
499 /// static STATIC_STR: Lazy<RString> = Lazy::new(|ruby| ruby.str_new("example"));
500 ///
501 /// # let _cleanup = unsafe { magnus::embed::init() };
502 /// let ruby = Ruby::get().unwrap();
503 /// let str = ruby.get_inner(&STATIC_STR);
504 /// rb_assert!(ruby, r#"str == "example""#, str);
505 /// ```
506 pub const fn new(func: fn(&Ruby) -> T) -> Self {
507 Self {
508 init: Once::new(),
509 mark: true,
510 func,
511 value: UnsafeCell::new(QNIL.0.get()),
512 }
513 }
514
515 /// Create a new `Lazy<T>` without protecting the inner value from Ruby's
516 /// garbage collector.
517 ///
518 /// # Safety
519 ///
520 /// The `Lazy<T>` returned from this function must be kept on the stack, or
521 /// the inner value otherwise protected from Ruby's garbage collector.
522 pub const unsafe fn new_without_mark(func: fn(&Ruby) -> T) -> Self {
523 Self {
524 init: Once::new(),
525 mark: false,
526 func,
527 value: UnsafeCell::new(QNIL.0.get()),
528 }
529 }
530
531 /// Force evaluation of a `Lazy<T>`.
532 ///
533 /// This can be used in, for example, your [`init`](macro@crate::init)
534 /// function to force initialisation of the `Lazy<T>`.
535 ///
536 /// # Examples
537 ///
538 /// ```
539 /// use magnus::{value::Lazy, RString, Ruby};
540 ///
541 /// static STATIC_STR: Lazy<RString> = Lazy::new(|ruby| ruby.str_new("example"));
542 ///
543 /// #[magnus::init]
544 /// fn init(ruby: &Ruby) {
545 /// Lazy::force(&STATIC_STR, ruby);
546 ///
547 /// assert!(Lazy::try_get_inner(&STATIC_STR).is_some());
548 /// }
549 /// # let ruby = unsafe { magnus::embed::init() };
550 /// # init(&ruby);
551 /// ```
552 #[inline]
553 pub fn force(this: &Self, handle: &Ruby) {
554 handle.get_inner(this);
555 }
556
557 /// Get the inner value as an [`Opaque<T>`](Opaque) from a `Lazy<T>`, if
558 /// it has already been initialised.
559 ///
560 /// This function will not call Ruby and will not initialise the inner
561 /// value. If the `Lazy<T>` has not yet been initialised, returns `None`.
562 ///
563 /// # Examples
564 ///
565 /// ```
566 /// use magnus::{rb_assert, value::Lazy, RString, Ruby};
567 ///
568 /// static STATIC_STR: Lazy<RString> = Lazy::new(|ruby| ruby.str_new("example"));
569 ///
570 /// # let _cleanup = unsafe { magnus::embed::init() };
571 /// assert!(Lazy::try_get_inner(&STATIC_STR).is_none());
572 ///
573 /// let ruby = Ruby::get().unwrap();
574 /// let str = ruby.get_inner(&STATIC_STR);
575 /// rb_assert!(ruby, r#"str == "example""#, str);
576 ///
577 /// assert!(Lazy::try_get_inner(&STATIC_STR).is_some());
578 /// ```
579 pub fn try_get_inner(this: &Self) -> Option<Opaque<T>> {
580 unsafe {
581 this.init
582 .is_completed()
583 .then(|| T::from_value_unchecked(*this.value.get()).into())
584 }
585 }
586}
587
588unsafe impl<T: ReprValue> Sync for Lazy<T> {}
589
590impl<T> InnerValue for &Lazy<T>
591where
592 T: ReprValue,
593{
594 type Value = T;
595
596 #[inline]
597 fn get_inner_with(self, ruby: &Ruby) -> Self::Value {
598 *self.get_inner_ref_with(ruby)
599 }
600}
601
602impl<T> InnerRef for Lazy<T>
603where
604 T: ReprValue,
605{
606 type Value = T;
607
608 fn get_inner_ref_with<'a>(&'a self, ruby: &Ruby) -> &'a Self::Value {
609 unsafe {
610 if !self.init.is_completed() {
611 let value = (self.func)(ruby);
612 self.init.call_once(|| {
613 if self.mark {
614 gc::register_mark_object(value);
615 }
616 *self.value.get() = value.as_value();
617 });
618 }
619 T::ref_from_ref_value_unchecked(&*self.value.get())
620 }
621 }
622}
623
624pub(crate) mod private {
625 use super::*;
626 use crate::value::ReprValue as _;
627
628 /// Marker trait for types that have the same representation as [`Value`].
629 ///
630 /// Types that are `ReprValue` can be safely transmuted to Value.
631 ///
632 /// # Safety
633 ///
634 /// This trait should only be implemented for types that a guaranteed to
635 /// have the same layout as [`Value`] and have come from the Ruby VM.
636 pub unsafe trait ReprValue: Copy {
637 /// Convert `val` to a `Self`.
638 ///
639 /// # Safety
640 ///
641 /// This should only be used when `val` is known to uphold all the
642 // invariants of `Self`. It is recommended not to use this method.
643 #[inline]
644 unsafe fn from_value_unchecked(val: Value) -> Self {
645 *(&val as *const Value as *const Self)
646 }
647
648 #[inline]
649 unsafe fn ref_from_ref_value_unchecked(val: &Value) -> &Self {
650 &*(val as *const Value as *const Self)
651 }
652
653 #[inline]
654 fn copy_as_value(self) -> Value {
655 // This trait is only ever implemented for things with the same
656 // representation as Value
657 unsafe { *(&self as *const Self as *const Value) }
658 }
659
660 #[inline]
661 fn as_value_ref(&self) -> &Value {
662 // This trait is only ever implemented for things with the same
663 // representation as Value
664 unsafe { &*(self as *const Self as *const Value) }
665 }
666
667 #[inline]
668 fn as_rb_value(self) -> VALUE {
669 self.copy_as_value().0
670 }
671
672 #[inline]
673 unsafe fn r_basic_unchecked(self) -> ptr::NonNull<RBasic> {
674 #[cfg(debug_assertions)]
675 if self.is_immediate() {
676 panic!("attempting to access immediate value as pointer");
677 }
678 ptr::NonNull::new_unchecked(self.copy_as_value().0 as *mut RBasic)
679 }
680
681 /// Returns whether `self` is an 'immediate' value.
682 ///
683 /// 'immediate' values are encoded directly into the `Value` and
684 /// require no additional lookup. They will never be garbage
685 /// collected.
686 ///
687 /// non-immediate values are pointers to other memory holding the data
688 /// for the object.
689 #[inline]
690 fn is_immediate(self) -> bool {
691 let value_p = self.as_rb_value();
692 let immediate_p = value_p & ruby_special_consts::RUBY_IMMEDIATE_MASK as VALUE != 0;
693 let test = value_p & !(ruby_special_consts::RUBY_Qnil as VALUE) != 0;
694 immediate_p || !test // special_const_p
695 }
696
697 #[inline]
698 fn r_basic(self) -> Option<ptr::NonNull<RBasic>> {
699 unsafe { (!self.is_immediate()).then(|| self.r_basic_unchecked()) }
700 }
701
702 #[inline]
703 fn is_false(self) -> bool {
704 self.as_rb_value() == ruby_special_consts::RUBY_Qfalse as VALUE
705 }
706
707 #[inline]
708 fn is_true(self) -> bool {
709 self.as_rb_value() == ruby_special_consts::RUBY_Qtrue as VALUE
710 }
711
712 #[inline]
713 fn is_undef(self) -> bool {
714 self.as_rb_value() == ruby_special_consts::RUBY_Qundef as VALUE
715 }
716
717 #[inline]
718 fn is_fixnum(self) -> bool {
719 self.as_rb_value() & ruby_special_consts::RUBY_FIXNUM_FLAG as VALUE != 0
720 }
721
722 #[inline]
723 fn is_static_symbol(self) -> bool {
724 const MASK: usize = !(usize::MAX << ruby_special_consts::RUBY_SPECIAL_SHIFT as usize);
725 self.as_rb_value() as usize & MASK == ruby_special_consts::RUBY_SYMBOL_FLAG as usize
726 }
727
728 #[inline]
729 fn is_flonum(self) -> bool {
730 self.as_rb_value() & ruby_special_consts::RUBY_FLONUM_MASK as VALUE
731 == ruby_special_consts::RUBY_FLONUM_FLAG as VALUE
732 }
733
734 // derefs a raw pointer that under GC compaction may be outside the
735 // process's memory space if the Value has been allowed to get GC'd
736 #[inline]
737 fn rb_type(self) -> ruby_value_type {
738 match self.r_basic() {
739 Some(r_basic) => {
740 unsafe {
741 let ret = r_basic.as_ref().flags & (ruby_value_type::RUBY_T_MASK as VALUE);
742 // this bit is safe, ruby_value_type is #[repr(u32)], the flags
743 // value set by Ruby, and Ruby promises that flags masked like
744 // this will always be a valid entry in this enum
745 std::mem::transmute(ret as u32)
746 }
747 }
748 None => {
749 if self.is_false() {
750 ruby_value_type::RUBY_T_FALSE
751 } else if self.copy_as_value().is_nil() {
752 ruby_value_type::RUBY_T_NIL
753 } else if self.is_true() {
754 ruby_value_type::RUBY_T_TRUE
755 } else if self.is_undef() {
756 ruby_value_type::RUBY_T_UNDEF
757 } else if self.is_fixnum() {
758 ruby_value_type::RUBY_T_FIXNUM
759 } else if self.is_static_symbol() {
760 ruby_value_type::RUBY_T_SYMBOL
761 } else if self.is_flonum() {
762 ruby_value_type::RUBY_T_FLOAT
763 } else {
764 unreachable!()
765 }
766 }
767 }
768 }
769
770 /// Convert `self` to a string. If an error is encountered returns a
771 /// generic string (usually the object's class name).
772 ///
773 /// # Safety
774 ///
775 /// This may return a direct view of memory owned and managed by Ruby.
776 /// Ruby may modify or free the memory backing the returned
777 /// str, the caller must ensure this does not happen.
778 #[allow(clippy::wrong_self_convention)]
779 unsafe fn to_s_infallible(&self) -> Cow<'_, str> {
780 match self.as_value_ref().to_s() {
781 Ok(v) => v,
782 Err(_) => Cow::Owned(
783 RString::from_rb_value_unchecked(rb_any_to_s(self.as_rb_value()))
784 .to_string_lossy()
785 .into_owned(),
786 ),
787 }
788 }
789 }
790}
791
792use private::ReprValue as _;
793
794/// Marker trait for types that have the same representation as [`Value`].
795///
796/// Types that are `ReprValue` can be safely transmuted to Value.
797pub trait ReprValue: private::ReprValue {
798 /// Return `self` as a [`Value`].
799 #[inline]
800 fn as_value(self) -> Value {
801 // This trait is only ever implemented for things with the same
802 // representation as Value
803 unsafe { *(&self as *const Self as *const Value) }
804 }
805
806 /// Returns whether `self` is Ruby's `nil` value.
807 ///
808 /// # Examples
809 ///
810 /// ```
811 /// use magnus::{prelude::*, Error, Ruby, Value};
812 ///
813 /// fn example(ruby: &Ruby) -> Result<(), Error> {
814 /// assert!(ruby.eval::<Value>("nil")?.is_nil());
815 /// assert!(!ruby.eval::<Value>("Object.new")?.is_nil());
816 /// assert!(!ruby.eval::<Value>("0")?.is_nil());
817 /// assert!(!ruby.eval::<Value>("[]")?.is_nil());
818 ///
819 /// Ok(())
820 /// }
821 /// # Ruby::init(example).unwrap()
822 /// ```
823 #[inline]
824 fn is_nil(self) -> bool {
825 self.as_rb_value() == ruby_special_consts::RUBY_Qnil as VALUE
826 }
827
828 /// Checks for equality, delegating to the Ruby method `#==`.
829 ///
830 /// Ruby optimises this check if `self` and `other` are the same object
831 /// or some built-in types, then calling the `#==` method will be skipped.
832 ///
833 /// Returns `Err` if `#==` raises.
834 ///
835 /// # Examples
836 ///
837 /// ```
838 /// use magnus::{prelude::*, Error, Ruby};
839 ///
840 /// fn example(ruby: &Ruby) -> Result<(), Error> {
841 /// let a = ruby.ary_from_vec(vec![1, 2, 3]);
842 /// let b = ruby.ary_from_vec(vec![1, 2, 3]);
843 /// let c = ruby.ary_from_vec(vec![4, 5, 6]);
844 /// let d = ruby.integer_from_i64(1);
845 /// assert!(a.equal(a)?);
846 /// assert!(a.equal(b)?);
847 /// assert!(!a.equal(c)?);
848 /// assert!(!a.equal(d)?);
849 ///
850 /// Ok(())
851 /// }
852 /// # Ruby::init(example).unwrap()
853 /// ```
854 ///
855 /// ```
856 /// use magnus::{eval, prelude::*, Error, Ruby, Value};
857 ///
858 /// fn example(ruby: &Ruby) -> Result<(), Error> {
859 /// let (a, b): (Value, Value) = eval!(
860 /// ruby,
861 /// "
862 /// class Example
863 /// def ==(other)
864 /// raise
865 /// end
866 /// end
867 /// [Example.new, Example.new]
868 /// "
869 /// )?;
870 ///
871 /// assert!(a.equal(b).is_err());
872 ///
873 /// Ok(())
874 /// }
875 /// # Ruby::init(example).unwrap()
876 /// ```
877 fn equal<T>(self, other: T) -> Result<bool, Error>
878 where
879 T: ReprValue,
880 {
881 unsafe {
882 protect(|| Value::new(rb_equal(self.as_rb_value(), other.as_rb_value())))
883 .map(Value::to_bool)
884 }
885 }
886
887 /// Checks for equality, delegating to the Ruby method `#eql?`.
888 ///
889 /// See [`Value::equal`] for the equivalent of the `#==` method.
890 ///
891 /// Ruby optimises this check if `self` and `other` are the same object
892 /// for some built-in types, then calling the `#==` method will be skipped.
893 ///
894 /// Returns `Err` if `#eql?` raises.
895 ///
896 /// # Examples
897 ///
898 /// ```
899 /// use magnus::{prelude::*, Error, Ruby};
900 ///
901 /// fn example(ruby: &Ruby) -> Result<(), Error> {
902 /// let a = ruby.ary_from_vec(vec![1, 2, 3]);
903 /// let b = ruby.ary_from_vec(vec![1, 2, 3]);
904 /// let c = ruby.ary_from_vec(vec![4, 5, 6]);
905 /// let d = ruby.integer_from_i64(1);
906 /// assert!(a.eql(a)?);
907 /// assert!(a.eql(b)?);
908 /// assert!(!a.eql(c)?);
909 /// assert!(!a.eql(d)?);
910 ///
911 /// Ok(())
912 /// }
913 /// # Ruby::init(example).unwrap()
914 /// ```
915 ///
916 /// ```
917 /// use magnus::{eval, prelude::*, Error, Ruby, Value};
918 ///
919 /// fn example(ruby: &Ruby) -> Result<(), Error> {
920 /// let (a, b): (Value, Value) = eval!(
921 /// ruby,
922 /// "
923 /// class Example
924 /// def eql?(other)
925 /// raise
926 /// end
927 /// end
928 /// [Example.new, Example.new]
929 /// "
930 /// )?;
931 ///
932 /// assert!(a.eql(b).is_err());
933 ///
934 /// Ok(())
935 /// }
936 /// # Ruby::init(example).unwrap()
937 /// ```
938 fn eql<T>(self, other: T) -> Result<bool, Error>
939 where
940 T: ReprValue,
941 {
942 unsafe {
943 protect(|| Value::new(rb_eql(self.as_rb_value(), other.as_rb_value()) as VALUE))
944 .map(Value::to_bool)
945 }
946 }
947
948 /// Returns an integer non-uniquely identifying `self`.
949 ///
950 /// The return value is not stable between different Ruby processes.
951 ///
952 /// Ruby guarantees the return value will be in the range of a C `long`,
953 /// this is usually equivalent to a `i64`, though will be `i32` on Windows.
954 ///
955 /// Ruby built-in classes will not error, but it is possible for badly
956 /// behaving 3rd party classes (or collections such as `Array` containing
957 /// them) to error in this function.
958 ///
959 /// # Examples
960 ///
961 /// ```
962 /// use magnus::{prelude::*, Error, Ruby};
963 ///
964 /// fn example(ruby: &Ruby) -> Result<(), Error> {
965 /// assert!(ruby
966 /// .str_new("test")
967 /// .hash()?
968 /// .equal(ruby.str_new("test").hash()?)?);
969 ///
970 /// Ok(())
971 /// }
972 /// # Ruby::init(example).unwrap()
973 /// ```
974 fn hash(self) -> Result<Integer, Error> {
975 unsafe { protect(|| Integer::from_rb_value_unchecked(rb_hash(self.as_rb_value()))) }
976 }
977
978 /// Returns the class that `self` is an instance of.
979 ///
980 /// # Panics
981 ///
982 /// panics if self is `Qundef`.
983 ///
984 /// # Examples
985 ///
986 /// ```
987 /// use magnus::{prelude::*, Error, Ruby, Value};
988 ///
989 /// fn example(ruby: &Ruby) -> Result<(), Error> {
990 /// assert_eq!(ruby.eval::<Value>("true")?.class().inspect(), "TrueClass");
991 /// assert_eq!(ruby.eval::<Value>("[1,2,3]")?.class().inspect(), "Array");
992 ///
993 /// Ok(())
994 /// }
995 /// # Ruby::init(example).unwrap()
996 /// ```
997 fn class(self) -> RClass {
998 let handle = Ruby::get_with(self);
999 unsafe {
1000 match self.r_basic() {
1001 Some(r_basic) => RClass::from_rb_value_unchecked(r_basic.as_ref().klass),
1002 None => {
1003 if self.is_false() {
1004 handle.class_false_class()
1005 } else if self.is_nil() {
1006 handle.class_nil_class()
1007 } else if self.is_true() {
1008 handle.class_true_class()
1009 } else if self.is_undef() {
1010 panic!("undef does not have a class")
1011 } else if self.is_fixnum() {
1012 handle.class_integer()
1013 } else if self.is_static_symbol() {
1014 handle.class_symbol()
1015 } else if self.is_flonum() {
1016 handle.class_float()
1017 } else {
1018 unreachable!()
1019 }
1020 }
1021 }
1022 }
1023 }
1024
1025 /// Returns whether `self` is 'frozen'.
1026 ///
1027 /// Ruby prevents modifying frozen objects.
1028 ///
1029 /// # Examples
1030 ///
1031 /// ```
1032 /// use magnus::{prelude::*, Error, Ruby, Value};
1033 ///
1034 /// fn example(ruby: &Ruby) -> Result<(), Error> {
1035 /// assert!(ruby.eval::<Value>(":foo")?.is_frozen());
1036 /// assert!(ruby.eval::<Value>("42")?.is_frozen());
1037 /// assert!(!ruby.eval::<Value>("[]")?.is_frozen());
1038 ///
1039 /// Ok(())
1040 /// }
1041 /// # Ruby::init(example).unwrap()
1042 /// ```
1043 fn is_frozen(self) -> bool {
1044 match self.r_basic() {
1045 None => true,
1046 Some(r_basic) => unsafe {
1047 r_basic.as_ref().flags & ruby_fl_type::RUBY_FL_FREEZE as VALUE != 0
1048 },
1049 }
1050 }
1051
1052 /// Returns an error if `self` is 'frozen'.
1053 ///
1054 /// Useful for checking if an object is frozen in a function that would
1055 /// modify it.
1056 ///
1057 /// # Examples
1058 /// ```
1059 /// use magnus::{prelude::*, Error, Ruby, Value};
1060 ///
1061 /// fn mutate(val: Value) -> Result<(), Error> {
1062 /// val.check_frozen()?;
1063 ///
1064 /// // ...
1065 /// Ok(())
1066 /// }
1067 ///
1068 /// fn example(ruby: &Ruby) -> Result<(), Error> {
1069 /// assert!(mutate(ruby.eval("Object.new")?).is_ok());
1070 /// assert!(mutate(ruby.eval(":foo")?).is_err());
1071 ///
1072 /// Ok(())
1073 /// }
1074 /// # Ruby::init(example).unwrap()
1075 /// ```
1076 fn check_frozen(self) -> Result<(), Error> {
1077 if self.is_frozen() {
1078 Err(Error::new(
1079 Ruby::get_with(self).exception_frozen_error(),
1080 format!("can't modify frozen {}", unsafe { self.classname() }),
1081 ))
1082 } else {
1083 Ok(())
1084 }
1085 }
1086
1087 /// Mark `self` as frozen.
1088 ///
1089 /// # Examples
1090 ///
1091 /// ```
1092 /// use magnus::{prelude::*, Error, Ruby};
1093 ///
1094 /// fn example(ruby: &Ruby) -> Result<(), Error> {
1095 /// let ary = ruby.ary_new();
1096 /// assert!(!ary.is_frozen());
1097 /// ary.freeze();
1098 /// assert!(ary.is_frozen());
1099 ///
1100 /// Ok(())
1101 /// }
1102 /// # Ruby::init(example).unwrap()
1103 /// ```
1104 fn freeze(self) {
1105 unsafe { rb_obj_freeze(self.as_rb_value()) };
1106 }
1107
1108 /// Convert `self` to a `bool`, following Ruby's rules of `false` and `nil`
1109 /// as boolean `false` and everything else boolean `true`.
1110 ///
1111 /// # Examples
1112 ///
1113 /// ```
1114 /// use magnus::{prelude::*, Error, Ruby, Value};
1115 ///
1116 /// fn example(ruby: &Ruby) -> Result<(), Error> {
1117 /// assert!(!ruby.eval::<Value>("false")?.to_bool());
1118 /// assert!(!ruby.eval::<Value>("nil")?.to_bool());
1119 ///
1120 /// assert!(ruby.eval::<Value>("true")?.to_bool());
1121 /// assert!(ruby.eval::<Value>("0")?.to_bool());
1122 /// assert!(ruby.eval::<Value>("[]")?.to_bool());
1123 /// assert!(ruby.eval::<Value>(":foo")?.to_bool());
1124 /// assert!(ruby.eval::<Value>("Object.new")?.to_bool());
1125 ///
1126 /// Ok(())
1127 /// }
1128 /// # Ruby::init(example).unwrap()
1129 /// ```
1130 #[inline]
1131 fn to_bool(self) -> bool {
1132 self.as_rb_value() & !(ruby_special_consts::RUBY_Qnil as VALUE) != 0
1133 }
1134
1135 /// Call the method named `method` on `self` with `args`.
1136 ///
1137 /// Returns `Ok(T)` if the method returns without error and the return
1138 /// value converts to a `T`, or returns `Err` if the method raises or the
1139 /// conversion fails.
1140 ///
1141 /// # Examples
1142 ///
1143 /// ```
1144 /// use magnus::{prelude::*, Error, RArray, Ruby};
1145 ///
1146 /// fn example(ruby: &Ruby) -> Result<(), Error> {
1147 /// let values = ruby.eval::<RArray>(r#"["foo", 1, :bar]"#)?;
1148 /// let result: String = values.funcall("join", (" & ",))?;
1149 /// assert_eq!(result, "foo & 1 & bar");
1150 ///
1151 /// Ok(())
1152 /// }
1153 /// # Ruby::init(example).unwrap()
1154 /// ```
1155 ///
1156 /// ```
1157 /// use magnus::{eval, kwargs, prelude::*, Error, RObject, Ruby};
1158 ///
1159 /// fn example(ruby: &Ruby) -> Result<(), Error> {
1160 /// let object: RObject = eval!(
1161 /// ruby,
1162 /// r#"
1163 /// class Adder
1164 /// def add(a, b, c:)
1165 /// a + b + c
1166 /// end
1167 /// end
1168 ///
1169 /// Adder.new
1170 /// "#
1171 /// )?;
1172 ///
1173 /// let result: i32 = object.funcall("add", (1, 2, kwargs!("c" => 3)))?;
1174 /// assert_eq!(result, 6);
1175 ///
1176 /// Ok(())
1177 /// }
1178 /// # Ruby::init(example).unwrap()
1179 /// ```
1180 fn funcall<M, A, T>(self, method: M, args: A) -> Result<T, Error>
1181 where
1182 M: IntoId,
1183 A: ArgList,
1184 T: TryConvert,
1185 {
1186 let handle = Ruby::get_with(self);
1187 let id = method.into_id_with(&handle);
1188 let kw_splat = kw_splat(&args);
1189 let args = args.into_arg_list_with(&handle);
1190 let slice = args.as_ref();
1191 unsafe {
1192 protect(|| {
1193 Value::new(rb_funcallv_kw(
1194 self.as_rb_value(),
1195 id.as_rb_id(),
1196 slice.len() as c_int,
1197 slice.as_ptr() as *const VALUE,
1198 kw_splat as c_int,
1199 ))
1200 })
1201 .and_then(TryConvert::try_convert)
1202 }
1203 }
1204
1205 /// Call the public method named `method` on `self` with `args`.
1206 ///
1207 /// Returns `Ok(T)` if the method returns without error and the return
1208 /// value converts to a `T`, or returns `Err` if the method raises or the
1209 /// conversion fails.
1210 ///
1211 /// # Examples
1212 ///
1213 /// ```
1214 /// use magnus::{eval, prelude::*, Error, RObject, Ruby, Symbol};
1215 ///
1216 /// fn example(ruby: &Ruby) -> Result<(), Error> {
1217 /// let object: RObject = eval!(
1218 /// ruby,
1219 /// r#"
1220 /// class Foo
1221 /// def bar
1222 /// :bar
1223 /// end
1224 ///
1225 /// private
1226 ///
1227 /// def baz
1228 /// :baz
1229 /// end
1230 /// end
1231 ///
1232 /// Foo.new
1233 /// "#
1234 /// )?;
1235 ///
1236 /// let result: Symbol = object.funcall_public("bar", ())?;
1237 /// assert_eq!(result.name()?, "bar");
1238 ///
1239 /// let result: Result<Symbol, Error> = object.funcall_public("baz", ());
1240 /// assert!(result.is_err());
1241 ///
1242 /// Ok(())
1243 /// }
1244 /// # Ruby::init(example).unwrap()
1245 /// ```
1246 fn funcall_public<M, A, T>(self, method: M, args: A) -> Result<T, Error>
1247 where
1248 M: IntoId,
1249 A: ArgList,
1250 T: TryConvert,
1251 {
1252 let handle = Ruby::get_with(self);
1253 let id = method.into_id_with(&handle);
1254 let kw_splat = kw_splat(&args);
1255 let args = args.into_arg_list_with(&handle);
1256 let slice = args.as_ref();
1257 unsafe {
1258 protect(|| {
1259 Value::new(rb_funcallv_public_kw(
1260 self.as_rb_value(),
1261 id.as_rb_id(),
1262 slice.len() as c_int,
1263 slice.as_ptr() as *const VALUE,
1264 kw_splat as c_int,
1265 ))
1266 })
1267 .and_then(TryConvert::try_convert)
1268 }
1269 }
1270
1271 /// If `self` responds to the method named `method`, call it with `args`.
1272 ///
1273 /// Returns `Some(Ok(T))` if the method exists and returns without error,
1274 /// `None` if it does not exist, or `Some(Err)` if an exception was raised.
1275 ///
1276 /// # Examples
1277 ///
1278 /// ```
1279 /// use magnus::{prelude::*, Error, Integer, Ruby};
1280 ///
1281 /// fn example(ruby: &Ruby) -> Result<(), Error> {
1282 /// let val = ruby.float_from_f64(1.23);
1283 /// let res: Integer = val.check_funcall("to_int", ()).unwrap()?;
1284 /// assert_eq!(res.to_i64()?, 1);
1285 ///
1286 /// let val = ruby.str_new("1.23");
1287 /// let res: Option<Result<Integer, _>> = val.check_funcall("to_int", ());
1288 /// assert!(res.is_none());
1289 ///
1290 /// Ok(())
1291 /// }
1292 /// # Ruby::init(example).unwrap()
1293 /// ```
1294 fn check_funcall<M, A, T>(self, method: M, args: A) -> Option<Result<T, Error>>
1295 where
1296 M: IntoId,
1297 A: ArgList,
1298 T: TryConvert,
1299 {
1300 let handle = Ruby::get_with(self);
1301 let id = method.into_id_with(&handle);
1302 let kw_splat = kw_splat(&args);
1303 let args = args.into_arg_list_with(&handle);
1304 let slice = args.as_ref();
1305 unsafe {
1306 let result = protect(|| {
1307 Value::new(rb_check_funcall_kw(
1308 self.as_rb_value(),
1309 id.as_rb_id(),
1310 slice.len() as c_int,
1311 slice.as_ptr() as *const VALUE,
1312 kw_splat as c_int,
1313 ))
1314 });
1315 match result {
1316 Ok(v) if v.is_undef() => None,
1317 Ok(v) => Some(T::try_convert(v)),
1318 Err(e) => Some(Err(e)),
1319 }
1320 }
1321 }
1322
1323 /// Call the method named `method` on `self` with `args` and `block`.
1324 ///
1325 /// Similar to [`funcall`](Value::funcall), but passes `block` as a Ruby
1326 /// block to the method.
1327 ///
1328 /// See also [`block_call`](Value::block_call).
1329 ///
1330 /// # Examples
1331 ///
1332 /// ```
1333 /// use magnus::{prelude::*, Error, RArray, Ruby, Value};
1334 ///
1335 /// fn example(ruby: &Ruby) -> Result<(), Error> {
1336 /// let values = ruby.eval::<RArray>(r#"["foo", 1, :bar]"#)?;
1337 /// let block = ruby.proc_new(|_ruby, args, _block| args.first().unwrap().to_r_string());
1338 /// let _: Value = values.funcall_with_block("map!", (), block)?;
1339 /// assert_eq!(values.to_vec::<String>()?, vec!["foo", "1", "bar"]);
1340 ///
1341 /// Ok(())
1342 /// }
1343 /// # Ruby::init(example).unwrap()
1344 /// ```
1345 fn funcall_with_block<M, A, T>(self, method: M, args: A, block: Proc) -> Result<T, Error>
1346 where
1347 M: IntoId,
1348 A: ArgList,
1349 T: TryConvert,
1350 {
1351 let handle = Ruby::get_with(self);
1352 let id = method.into_id_with(&handle);
1353 let kw_splat = kw_splat(&args);
1354 let args = args.into_arg_list_with(&handle);
1355 let slice = args.as_ref();
1356 unsafe {
1357 protect(|| {
1358 Value::new(rb_funcall_with_block_kw(
1359 self.as_rb_value(),
1360 id.as_rb_id(),
1361 slice.len() as c_int,
1362 slice.as_ptr() as *const VALUE,
1363 block.as_rb_value(),
1364 kw_splat as c_int,
1365 ))
1366 })
1367 .and_then(TryConvert::try_convert)
1368 }
1369 }
1370
1371 /// Call the method named `method` on `self` with `args` and `block`.
1372 ///
1373 /// Similar to [`funcall`](Value::funcall), but passes `block` as a Ruby
1374 /// block to the method.
1375 ///
1376 /// As `block` is a function pointer, only functions and closures that do
1377 /// not capture any variables are permitted. For more flexibility (at the
1378 /// cost of allocating) see [`Proc::from_fn`] and
1379 /// [`funcall_with_block`](Value::funcall_with_block).
1380 ///
1381 /// The function passed as `block` will receive values yielded to the block
1382 /// as a slice of [`Value`]s, plus `Some(Proc)` if the block itself was
1383 /// called with a block, or `None` otherwise.
1384 ///
1385 /// The `block` function may return any `R` or `Result<R, Error>` where `R`
1386 /// implements [`IntoValue`]. Returning `Err(Error)` will raise the error
1387 /// as a Ruby exception.
1388 ///
1389 /// # Examples
1390 ///
1391 /// ```
1392 /// use magnus::{prelude::*, Error, RArray, Ruby, Value};
1393 ///
1394 /// fn example(ruby: &Ruby) -> Result<(), Error> {
1395 /// let values = ruby.eval::<RArray>(r#"["foo", 1, :bar]"#)?;
1396 /// let _: Value = values.block_call("map!", (), |_ruby, args, _block| {
1397 /// args.first().unwrap().to_r_string()
1398 /// })?;
1399 /// assert_eq!(values.to_vec::<String>()?, vec!["foo", "1", "bar"]);
1400 ///
1401 /// Ok(())
1402 /// }
1403 /// # Ruby::init(example).unwrap()
1404 /// ```
1405 fn block_call<M, A, R, T>(
1406 self,
1407 method: M,
1408 args: A,
1409 block: fn(&Ruby, &[Value], Option<Proc>) -> R,
1410 ) -> Result<T, Error>
1411 where
1412 M: IntoId,
1413 A: ArgList,
1414 R: BlockReturn,
1415 T: TryConvert,
1416 {
1417 unsafe extern "C" fn call<R>(
1418 _yielded_arg: VALUE,
1419 callback_arg: VALUE,
1420 argc: c_int,
1421 argv: *const VALUE,
1422 blockarg: VALUE,
1423 ) -> VALUE
1424 where
1425 R: BlockReturn,
1426 {
1427 let func =
1428 std::mem::transmute::<VALUE, fn(&Ruby, &[Value], Option<Proc>) -> R>(callback_arg);
1429 func.call_handle_error(argc, argv as *const Value, Value::new(blockarg))
1430 .as_rb_value()
1431 }
1432
1433 let handle = Ruby::get_with(self);
1434 let id = method.into_id_with(&handle);
1435 let kw_splat = kw_splat(&args);
1436 let args = args.into_arg_list_with(&handle);
1437 let slice = args.as_ref();
1438 let call_func =
1439 call::<R> as unsafe extern "C" fn(VALUE, VALUE, c_int, *const VALUE, VALUE) -> VALUE;
1440
1441 protect(|| unsafe {
1442 #[allow(clippy::fn_to_numeric_cast)]
1443 Value::new(rb_block_call_kw(
1444 self.as_rb_value(),
1445 id.as_rb_id(),
1446 slice.len() as c_int,
1447 slice.as_ptr() as *const VALUE,
1448 Some(call_func),
1449 block as VALUE,
1450 kw_splat as c_int,
1451 ))
1452 })
1453 .and_then(TryConvert::try_convert)
1454 }
1455
1456 /// Check if `self` responds to the given Ruby method.
1457 ///
1458 /// The `include_private` argument controls whether `self`'s private methods
1459 /// are checked. If `false` they are not, if `true` they are.
1460 ///
1461 /// See also [`Value::check_funcall`].
1462 ///
1463 /// # Examples
1464 ///
1465 /// ```
1466 /// use magnus::{prelude::*, Error, Ruby};
1467 ///
1468 /// fn example(ruby: &Ruby) -> Result<(), Error> {
1469 /// let s = ruby.str_new("example");
1470 /// assert!(s.respond_to("to_str", false)?);
1471 /// assert!(!s.respond_to("puts", false)?);
1472 /// assert!(s.respond_to("puts", true)?);
1473 /// assert!(!s.respond_to("non_existent", false)?);
1474 /// assert!(!s.respond_to("non_existent", true)?);
1475 ///
1476 /// Ok(())
1477 /// }
1478 /// # Ruby::init(example).unwrap()
1479 /// ```
1480 fn respond_to<M>(self, method: M, include_private: bool) -> Result<bool, Error>
1481 where
1482 M: IntoId,
1483 {
1484 let handle = Ruby::get_with(self);
1485 let id = method.into_id_with(&handle);
1486 let mut res = false;
1487 protect(|| {
1488 unsafe {
1489 res = rb_obj_respond_to(self.as_rb_value(), id.as_rb_id(), include_private as c_int)
1490 != 0
1491 };
1492 handle.qnil()
1493 })?;
1494 Ok(res)
1495 }
1496
1497 /// Convert `self` to a Ruby `String`.
1498 ///
1499 /// If `self` is already a `String` is it wrapped as a `RString`, otherwise
1500 /// the Ruby `to_s` method is called.
1501 ///
1502 /// # Examples
1503 ///
1504 /// ```
1505 /// use magnus::{prelude::*, Error, Ruby, Value};
1506 ///
1507 /// fn example(ruby: &Ruby) -> Result<(), Error> {
1508 /// let value = ruby.eval::<Value>("[]")?;
1509 /// assert!(value.to_r_string()?.is_kind_of(ruby.class_string()));
1510 ///
1511 /// Ok(())
1512 /// }
1513 /// # Ruby::init(example).unwrap()
1514 /// ```
1515 fn to_r_string(self) -> Result<RString, Error> {
1516 match RString::from_value(self.as_value()) {
1517 Some(v) => Ok(v),
1518 None => protect(|| unsafe {
1519 RString::from_rb_value_unchecked(rb_obj_as_string(self.as_rb_value()))
1520 }),
1521 }
1522 }
1523
1524 /// Convert `self` to a Rust string.
1525 ///
1526 /// # Safety
1527 ///
1528 /// This may return a direct view of memory owned and managed by Ruby. Ruby
1529 /// may modify or free the memory backing the returned str, the caller must
1530 /// ensure this does not happen.
1531 ///
1532 /// This can be used safely by immediately calling
1533 /// [`into_owned`](Cow::into_owned) on the return value.
1534 ///
1535 /// # Examples
1536 ///
1537 /// ```
1538 /// use magnus::{prelude::*, Error, Ruby};
1539 ///
1540 /// fn example(ruby: &Ruby) -> Result<(), Error> {
1541 /// let value = ruby.qtrue();
1542 /// // safe as we never give Ruby a chance to free the string.
1543 /// let s = unsafe { value.to_s() }?.into_owned();
1544 /// assert_eq!(s, "true");
1545 ///
1546 /// Ok(())
1547 /// }
1548 /// # Ruby::init(example).unwrap()
1549 /// ```
1550 #[allow(clippy::wrong_self_convention)]
1551 unsafe fn to_s(&self) -> Result<Cow<'_, str>, Error> {
1552 if let Some(s) = RString::ref_from_value(self.as_value_ref()) {
1553 if s.is_utf8_compatible_encoding() {
1554 return s.as_str().map(Cow::Borrowed);
1555 } else {
1556 return (*s).to_string().map(Cow::Owned);
1557 }
1558 }
1559 self.to_r_string()
1560 .and_then(|s| s.to_string().map(Cow::Owned))
1561 }
1562
1563 /// Convert `self` to its Ruby debug representation.
1564 ///
1565 /// # Examples
1566 ///
1567 /// ```
1568 /// use magnus::{prelude::*, Error, Ruby};
1569 ///
1570 /// fn example(ruby: &Ruby) -> Result<(), Error> {
1571 /// assert_eq!(ruby.qnil().inspect(), "nil");
1572 /// assert_eq!(ruby.to_symbol("foo").inspect(), ":foo");
1573 ///
1574 /// Ok(())
1575 /// }
1576 /// # Ruby::init(example).unwrap()
1577 /// ```
1578 fn inspect(self) -> String {
1579 let handle = Ruby::get_with(self);
1580 unsafe {
1581 let s = protect(|| RString::from_rb_value_unchecked(rb_inspect(self.as_rb_value())))
1582 .unwrap_or_else(|_| {
1583 RString::from_rb_value_unchecked(rb_any_to_s(self.as_rb_value()))
1584 });
1585 s.conv_enc(handle.utf8_encoding())
1586 .unwrap_or(s)
1587 .to_string_lossy()
1588 .into_owned()
1589 }
1590 }
1591
1592 /// Return the name of `self`'s class.
1593 ///
1594 /// # Safety
1595 ///
1596 /// Ruby may modify or free the memory backing the returned str, the caller
1597 /// must ensure this does not happen.
1598 ///
1599 /// This can be used safely by immediately calling
1600 /// [`into_owned`](Cow::into_owned) on the return value.
1601 ///
1602 /// # Examples
1603 ///
1604 /// ```
1605 /// use magnus::{prelude::*, Error, Ruby};
1606 ///
1607 /// fn example(ruby: &Ruby) -> Result<(), Error> {
1608 /// let value = ruby.hash_new();
1609 /// // safe as we never give Ruby a chance to free the string.
1610 /// let s = unsafe { value.classname() }.into_owned();
1611 /// assert_eq!(s, "Hash");
1612 ///
1613 /// Ok(())
1614 /// }
1615 /// # Ruby::init(example).unwrap()
1616 /// ```
1617 unsafe fn classname(&self) -> Cow<'_, str> {
1618 let ptr = rb_obj_classname(self.as_rb_value());
1619 let cstr = CStr::from_ptr(ptr);
1620 cstr.to_string_lossy()
1621 }
1622
1623 /// Returns whether or not `self` is an instance of `class`.
1624 ///
1625 /// # Examples
1626 ///
1627 /// ```
1628 /// use magnus::{prelude::*, Error, Ruby, Value};
1629 ///
1630 /// fn example(ruby: &Ruby) -> Result<(), Error> {
1631 /// let value = ruby.eval::<Value>("[]")?;
1632 /// assert!(value.is_kind_of(ruby.class_array()));
1633 ///
1634 /// Ok(())
1635 /// }
1636 /// # Ruby::init(example).unwrap()
1637 /// ```
1638 fn is_kind_of<T>(self, class: T) -> bool
1639 where
1640 T: ReprValue + Module,
1641 {
1642 unsafe { Value::new(rb_obj_is_kind_of(self.as_rb_value(), class.as_rb_value())).to_bool() }
1643 }
1644
1645 /// Generate an [`Enumerator`] from `method` on `self`, passing `args` to
1646 /// `method`.
1647 ///
1648 /// # Examples
1649 ///
1650 /// ```
1651 /// use magnus::{prelude::*, r_string, Error, Ruby};
1652 ///
1653 /// fn example(ruby: &Ruby) -> Result<(), Error> {
1654 /// let s = r_string!("foo\\bar\\baz");
1655 /// let mut i = 0;
1656 /// for line in s.enumeratorize("each_line", ("\\",)) {
1657 /// assert!(line?.is_kind_of(ruby.class_string()));
1658 /// i += 1;
1659 /// }
1660 /// assert_eq!(i, 3);
1661 ///
1662 /// Ok(())
1663 /// }
1664 /// # Ruby::init(example).unwrap()
1665 /// ```
1666 fn enumeratorize<M, A>(self, method: M, args: A) -> Enumerator
1667 where
1668 M: IntoSymbol,
1669 A: ArgList,
1670 {
1671 let handle = Ruby::get_with(self);
1672 let kw_splat = kw_splat(&args);
1673 let args = args.into_arg_list_with(&handle);
1674 let slice = args.as_ref();
1675 unsafe {
1676 Enumerator::from_rb_value_unchecked(rb_enumeratorize_with_size_kw(
1677 self.as_rb_value(),
1678 method.into_symbol_with(&handle).as_rb_value(),
1679 slice.len() as c_int,
1680 slice.as_ptr() as *const VALUE,
1681 None,
1682 kw_splat as c_int,
1683 ))
1684 }
1685 }
1686}
1687
1688unsafe impl private::ReprValue for Value {}
1689
1690impl ReprValue for Value {}
1691
1692#[derive(Clone, Copy, Eq, Hash, PartialEq)]
1693#[repr(transparent)]
1694pub(crate) struct NonZeroValue(NonZeroUsize, PhantomData<ptr::NonNull<RBasic>>);
1695
1696impl NonZeroValue {
1697 #[inline]
1698 pub(crate) const unsafe fn new_unchecked(val: Value) -> Self {
1699 Self(
1700 NonZeroUsize::new_unchecked(val.as_rb_value() as usize),
1701 PhantomData,
1702 )
1703 }
1704
1705 #[inline]
1706 pub(crate) const fn get(self) -> Value {
1707 Value::new(self.0.get() as VALUE)
1708 }
1709}
1710
1711/// Protects a Ruby Value from the garbage collector.
1712///
1713/// See also [`gc::register_mark_object`] for a value that should be
1714/// permanently excluded from garbage collection.
1715pub struct BoxValue<T>(Box<T>);
1716
1717impl<T> BoxValue<T>
1718where
1719 T: ReprValue,
1720{
1721 /// Create a new `BoxValue`.
1722 ///
1723 /// # Examples
1724 ///
1725 /// ```
1726 /// use magnus::{eval, value::BoxValue, Error, RString, Ruby, Value};
1727 ///
1728 /// # #[inline(never)]
1729 /// fn box_value(ruby: &Ruby) -> BoxValue<RString> {
1730 /// BoxValue::new(ruby.str_new("foo"))
1731 /// }
1732 ///
1733 /// fn example(ruby: &Ruby) -> Result<(), Error> {
1734 /// # // get the Value in a different stack frame and copy it to a BoxValue
1735 /// # // test is invalid if this is done in this function.
1736 /// let boxed = box_value(ruby);
1737 ///
1738 /// # // make some garbage
1739 /// # ruby.eval::<Value>(r#"1024.times.map {|i| "test#{i}"}"#)?;
1740 /// // run garbage collector
1741 /// ruby.gc_start();
1742 ///
1743 /// # // try and use value
1744 /// // boxed is still useable
1745 /// let result: String = eval!(ruby, r#"foo + "bar""#, foo = boxed)?;
1746 ///
1747 /// assert_eq!(result, "foobar");
1748 ///
1749 /// # // didn't segfault? we passed!
1750 ///
1751 /// Ok(())
1752 /// }
1753 /// # Ruby::init(example).unwrap()
1754 /// ```
1755 pub fn new(val: T) -> Self {
1756 let mut boxed = Box::new(val);
1757 unsafe { rb_gc_register_address(boxed.as_mut() as *mut _ as *mut VALUE) };
1758 Self(boxed)
1759 }
1760}
1761
1762impl<T> Drop for BoxValue<T> {
1763 fn drop(&mut self) {
1764 unsafe {
1765 rb_gc_unregister_address(self.0.as_mut() as *mut _ as *mut VALUE);
1766 }
1767 }
1768}
1769
1770impl<T> AsRef<T> for BoxValue<T> {
1771 #[inline]
1772 fn as_ref(&self) -> &T {
1773 &self.0
1774 }
1775}
1776
1777impl<T> AsMut<T> for BoxValue<T> {
1778 #[inline]
1779 fn as_mut(&mut self) -> &mut T {
1780 &mut self.0
1781 }
1782}
1783
1784impl<T> Deref for BoxValue<T> {
1785 type Target = T;
1786
1787 #[inline]
1788 fn deref(&self) -> &Self::Target {
1789 &self.0
1790 }
1791}
1792
1793impl<T> DerefMut for BoxValue<T> {
1794 #[inline]
1795 fn deref_mut(&mut self) -> &mut Self::Target {
1796 &mut self.0
1797 }
1798}
1799
1800impl<T> fmt::Display for BoxValue<T>
1801where
1802 T: ReprValue,
1803{
1804 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1805 write!(f, "{}", unsafe { self.as_value().to_s_infallible() })
1806 }
1807}
1808
1809impl<T> fmt::Debug for BoxValue<T>
1810where
1811 T: ReprValue,
1812{
1813 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1814 write!(f, "{}", self.as_value().inspect())
1815 }
1816}
1817
1818impl<T> IntoValue for BoxValue<T>
1819where
1820 T: ReprValue,
1821{
1822 #[inline]
1823 fn into_value_with(self, _: &Ruby) -> Value {
1824 self.as_value()
1825 }
1826}
1827
1828unsafe impl<T> IntoValueFromNative for BoxValue<T> where T: ReprValue {}
1829
1830/// # `false`
1831///
1832/// Get Ruby's `false` value.
1833///
1834/// See also the [`Qfalse`] type.
1835impl Ruby {
1836 /// Returns Ruby's `false` value.
1837 ///
1838 /// # Examples
1839 ///
1840 /// ```
1841 /// use magnus::{rb_assert, Error, Ruby};
1842 ///
1843 /// fn example(ruby: &Ruby) -> Result<(), Error> {
1844 /// rb_assert!(ruby, "val == false", val = ruby.qfalse());
1845 ///
1846 /// Ok(())
1847 /// }
1848 /// # Ruby::init(example).unwrap()
1849 /// ```
1850 #[inline]
1851 pub fn qfalse(&self) -> Qfalse {
1852 QFALSE
1853 }
1854}
1855
1856/// Ruby's `false` value.
1857///
1858/// See [`Ruby::qfalse`]/[`qfalse`] to obtain a value of this type.
1859///
1860/// See the [`ReprValue`] trait for additional methods available on this type.
1861#[derive(Clone, Copy)]
1862#[repr(transparent)]
1863pub struct Qfalse(Value);
1864
1865/// Ruby's `false` value.
1866const QFALSE: Qfalse = Qfalse::new();
1867
1868/// Returns Ruby's `false` value.
1869///
1870/// This should optimise to a constant reference.
1871///
1872/// # Panics
1873///
1874/// Panics if called from a non-Ruby thread. See [`Ruby::qfalse`] for the
1875/// non-panicking version.
1876///
1877/// # Examples
1878///
1879/// ```
1880/// # #![allow(deprecated)]
1881/// use magnus::{rb_assert, value::qfalse};
1882/// # let _cleanup = unsafe { magnus::embed::init() };
1883///
1884/// rb_assert!("val == false", val = qfalse());
1885/// ```
1886#[cfg_attr(
1887 not(feature = "old-api"),
1888 deprecated(note = "please use `Ruby::qfalse` instead")
1889)]
1890#[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
1891#[inline]
1892pub fn qfalse() -> Qfalse {
1893 get_ruby!().qfalse()
1894}
1895
1896impl Qfalse {
1897 /// Create a new `Qfalse`.
1898 #[inline]
1899 const fn new() -> Self {
1900 Qfalse(Value::new(ruby_special_consts::RUBY_Qfalse as VALUE))
1901 }
1902
1903 /// Return `Some(Qfalse)` if `val` is a `Qfalse`, `None` otherwise.
1904 ///
1905 /// # Examples
1906 ///
1907 /// ```
1908 /// use magnus::{eval, value::Qfalse};
1909 /// # let _cleanup = unsafe { magnus::embed::init() };
1910 ///
1911 /// assert!(Qfalse::from_value(eval("false").unwrap()).is_some());
1912 /// assert!(Qfalse::from_value(eval("0").unwrap()).is_none());
1913 /// ```
1914 #[inline]
1915 pub fn from_value(val: Value) -> Option<Self> {
1916 val.is_false().then(Self::new)
1917 }
1918}
1919
1920impl fmt::Display for Qfalse {
1921 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1922 write!(f, "{}", unsafe { self.to_s_infallible() })
1923 }
1924}
1925
1926impl fmt::Debug for Qfalse {
1927 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1928 write!(f, "{}", self.inspect())
1929 }
1930}
1931
1932impl IntoValue for Qfalse {
1933 #[inline]
1934 fn into_value_with(self, _: &Ruby) -> Value {
1935 self.0
1936 }
1937}
1938
1939unsafe impl private::ReprValue for Qfalse {}
1940
1941impl ReprValue for Qfalse {}
1942
1943impl TryConvert for Qfalse {
1944 fn try_convert(val: Value) -> Result<Self, Error> {
1945 Self::from_value(val).ok_or_else(|| {
1946 Error::new(
1947 Ruby::get_with(val).exception_type_error(),
1948 format!("no implicit conversion of {} into FalseClass", unsafe {
1949 val.classname()
1950 },),
1951 )
1952 })
1953 }
1954}
1955unsafe impl TryConvertOwned for Qfalse {}
1956
1957/// # `nil`
1958///
1959/// Get Ruby's `nil` value.
1960///
1961/// See also the [`Qnil`] type.
1962impl Ruby {
1963 /// Returns Ruby's `nil` value.
1964 ///
1965 /// This should optimise to a constant reference.
1966 ///
1967 /// # Examples
1968 ///
1969 /// ```
1970 /// use magnus::{rb_assert, Error, Ruby};
1971 ///
1972 /// fn example(ruby: &Ruby) -> Result<(), Error> {
1973 /// rb_assert!(ruby, "val == nil", val = ruby.qnil());
1974 ///
1975 /// Ok(())
1976 /// }
1977 /// # Ruby::init(example).unwrap()
1978 /// ```
1979 #[inline]
1980 pub fn qnil(&self) -> Qnil {
1981 QNIL
1982 }
1983}
1984
1985/// Ruby's `nil` value.
1986///
1987/// See [`Ruby::qnil`]/[`qnil`] to obtain a value of this type.
1988///
1989/// See the [`ReprValue`] trait for additional methods available on this type.
1990#[derive(Clone, Copy)]
1991#[repr(transparent)]
1992pub struct Qnil(NonZeroValue);
1993
1994/// Ruby's `nil` value.
1995const QNIL: Qnil = Qnil::new();
1996
1997/// Returns Ruby's `nil` value.
1998///
1999/// This should optimise to a constant reference.
2000///
2001/// # Panics
2002///
2003/// Panics if called from a non-Ruby thread. See [`Ruby::qnil`] for the
2004/// non-panicking version.
2005///
2006/// # Examples
2007///
2008/// ```
2009/// # #![allow(deprecated)]
2010/// use magnus::{rb_assert, value::qnil};
2011/// # let _cleanup = unsafe { magnus::embed::init() };
2012///
2013/// rb_assert!("val == nil", val = qnil());
2014/// ```
2015#[cfg_attr(
2016 not(feature = "old-api"),
2017 deprecated(note = "please use `Ruby::qnil` instead")
2018)]
2019#[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
2020#[inline]
2021pub fn qnil() -> Qnil {
2022 get_ruby!().qnil()
2023}
2024
2025impl Qnil {
2026 /// Create a new `Qnil`.
2027 #[inline]
2028 const fn new() -> Self {
2029 unsafe {
2030 Self(NonZeroValue::new_unchecked(Value::new(
2031 ruby_special_consts::RUBY_Qnil as VALUE,
2032 )))
2033 }
2034 }
2035
2036 /// Return `Some(Qnil)` if `val` is a `Qnil`, `None` otherwise.
2037 ///
2038 /// # Examples
2039 ///
2040 /// ```
2041 /// use magnus::{eval, value::Qnil};
2042 /// # let _cleanup = unsafe { magnus::embed::init() };
2043 ///
2044 /// assert!(Qnil::from_value(eval("nil").unwrap()).is_some());
2045 /// assert!(Qnil::from_value(eval("0").unwrap()).is_none());
2046 /// ```
2047 #[inline]
2048 pub fn from_value(val: Value) -> Option<Self> {
2049 val.is_nil().then(Self::new)
2050 }
2051}
2052
2053impl fmt::Display for Qnil {
2054 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2055 write!(f, "{}", unsafe { self.to_s_infallible() })
2056 }
2057}
2058
2059impl fmt::Debug for Qnil {
2060 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2061 write!(f, "{}", self.inspect())
2062 }
2063}
2064
2065impl IntoValue for Qnil {
2066 #[inline]
2067 fn into_value_with(self, _: &Ruby) -> Value {
2068 self.0.get()
2069 }
2070}
2071
2072impl IntoValue for () {
2073 #[inline]
2074 fn into_value_with(self, handle: &Ruby) -> Value {
2075 handle.qnil().as_value()
2076 }
2077}
2078
2079unsafe impl IntoValueFromNative for () {}
2080
2081impl<T> IntoValue for Option<T>
2082where
2083 T: IntoValue,
2084{
2085 #[inline]
2086 fn into_value_with(self, handle: &Ruby) -> Value {
2087 match self {
2088 Some(t) => handle.into_value(t),
2089 None => handle.qnil().as_value(),
2090 }
2091 }
2092}
2093
2094unsafe impl<T> IntoValueFromNative for Option<T> where T: IntoValueFromNative {}
2095
2096unsafe impl private::ReprValue for Qnil {}
2097
2098impl ReprValue for Qnil {}
2099
2100impl TryConvert for Qnil {
2101 fn try_convert(val: Value) -> Result<Self, Error> {
2102 Self::from_value(val).ok_or_else(|| {
2103 Error::new(
2104 Ruby::get_with(val).exception_type_error(),
2105 format!("no implicit conversion of {} into NilClass", unsafe {
2106 val.classname()
2107 },),
2108 )
2109 })
2110 }
2111}
2112unsafe impl TryConvertOwned for Qnil {}
2113
2114/// # `true`
2115///
2116/// Get Ruby's `true` value.
2117///
2118/// See also the [`Qtrue`] type.
2119impl Ruby {
2120 /// Returns Ruby's `true` value.
2121 ///
2122 /// This should optimise to a constant reference.
2123 ///
2124 /// # Examples
2125 ///
2126 /// ```
2127 /// use magnus::{rb_assert, Error, Ruby};
2128 ///
2129 /// fn example(ruby: &Ruby) -> Result<(), Error> {
2130 /// rb_assert!(ruby, "val == true", val = ruby.qtrue());
2131 ///
2132 /// Ok(())
2133 /// }
2134 /// # Ruby::init(example).unwrap()
2135 /// ```
2136 #[inline]
2137 pub fn qtrue(&self) -> Qtrue {
2138 QTRUE
2139 }
2140}
2141
2142/// Ruby's `true` value.
2143///
2144/// See [`Ruby::qtrue`]/[`qtrue`] to obtain a value of this type.
2145///
2146/// See the [`ReprValue`] trait for additional methods available on this type.
2147#[derive(Clone, Copy)]
2148#[repr(transparent)]
2149pub struct Qtrue(NonZeroValue);
2150
2151/// Ruby's `true` value.
2152const QTRUE: Qtrue = Qtrue::new();
2153
2154/// Returns Ruby's `true` value.
2155///
2156/// This should optimise to a constant reference.
2157///
2158/// # Panics
2159///
2160/// Panics if called from a non-Ruby thread. See [`Ruby::qtrue`] for the
2161/// non-panicking version.
2162///
2163/// # Examples
2164///
2165/// ```
2166/// # #![allow(deprecated)]
2167/// use magnus::{rb_assert, value::qtrue};
2168/// # let _cleanup = unsafe { magnus::embed::init() };
2169///
2170/// rb_assert!("val == true", val = qtrue());
2171/// ```
2172#[cfg_attr(
2173 not(feature = "old-api"),
2174 deprecated(note = "please use `Ruby::qtrue` instead")
2175)]
2176#[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
2177#[inline]
2178pub fn qtrue() -> Qtrue {
2179 get_ruby!().qtrue()
2180}
2181
2182impl Qtrue {
2183 /// Create a new `Qtrue`.
2184 #[inline]
2185 const fn new() -> Self {
2186 unsafe {
2187 Self(NonZeroValue::new_unchecked(Value::new(
2188 ruby_special_consts::RUBY_Qtrue as VALUE,
2189 )))
2190 }
2191 }
2192
2193 /// Return `Some(Qtrue)` if `val` is a `Qtrue`, `None` otherwise.
2194 ///
2195 /// # Examples
2196 ///
2197 /// ```
2198 /// use magnus::{eval, value::Qtrue};
2199 /// # let _cleanup = unsafe { magnus::embed::init() };
2200 ///
2201 /// assert!(Qtrue::from_value(eval("true").unwrap()).is_some());
2202 /// assert!(Qtrue::from_value(eval("1").unwrap()).is_none());
2203 /// ```
2204 #[inline]
2205 pub fn from_value(val: Value) -> Option<Self> {
2206 val.is_true().then(Self::new)
2207 }
2208}
2209
2210impl fmt::Display for Qtrue {
2211 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2212 write!(f, "{}", unsafe { self.to_s_infallible() })
2213 }
2214}
2215
2216impl fmt::Debug for Qtrue {
2217 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2218 write!(f, "{}", self.inspect())
2219 }
2220}
2221
2222impl IntoValue for Qtrue {
2223 #[inline]
2224 fn into_value_with(self, _: &Ruby) -> Value {
2225 self.0.get()
2226 }
2227}
2228
2229impl IntoValue for bool {
2230 #[inline]
2231 fn into_value_with(self, handle: &Ruby) -> Value {
2232 if self {
2233 handle.qtrue().as_value()
2234 } else {
2235 handle.qfalse().as_value()
2236 }
2237 }
2238}
2239
2240unsafe impl IntoValueFromNative for bool {}
2241
2242unsafe impl private::ReprValue for Qtrue {}
2243
2244impl ReprValue for Qtrue {}
2245
2246impl TryConvert for Qtrue {
2247 fn try_convert(val: Value) -> Result<Self, Error> {
2248 Self::from_value(val).ok_or_else(|| {
2249 Error::new(
2250 Ruby::get_with(val).exception_type_error(),
2251 format!("no implicit conversion of {} into TrueClass", unsafe {
2252 val.classname()
2253 },),
2254 )
2255 })
2256 }
2257}
2258unsafe impl TryConvertOwned for Qtrue {}
2259
2260/// A placeholder value that represents an undefined value. Not exposed to
2261/// Ruby level code.
2262///
2263/// See [`QUNDEF`] to obtain a value of this type.
2264#[derive(Clone, Copy)]
2265#[repr(transparent)]
2266pub struct Qundef(NonZeroValue);
2267
2268/// A placeholder value that represents an undefined value. Not exposed to
2269/// Ruby level code.
2270pub const QUNDEF: Qundef = Qundef::new();
2271
2272impl Qundef {
2273 /// Create a new `Qundef`.
2274 #[inline]
2275 const fn new() -> Self {
2276 unsafe {
2277 Self(NonZeroValue::new_unchecked(Value::new(
2278 ruby_special_consts::RUBY_Qundef as VALUE,
2279 )))
2280 }
2281 }
2282
2283 /// Return `Some(Qundef)` if `val` is a `Qundef`, `None` otherwise.
2284 ///
2285 /// # Examples
2286 ///
2287 /// ```
2288 /// use magnus::{eval, value::Qundef};
2289 /// # let _cleanup = unsafe { magnus::embed::init() };
2290 ///
2291 /// // nil is not undef
2292 /// assert!(Qundef::from_value(eval("nil").unwrap()).is_none());
2293 /// ```
2294 #[inline]
2295 pub fn from_value(val: Value) -> Option<Self> {
2296 val.is_undef().then(Self::new)
2297 }
2298
2299 /// Return `self` as a [`Value`].
2300 ///
2301 /// # Safety
2302 ///
2303 /// It is not a good idea to return this to Ruby code, bad things will
2304 /// happen. There are only a handful of places in Ruby's API where it is
2305 /// appropriate to pass a [`Value`] created from `Qundef` (hence this
2306 /// method, rather than implementing [`IntoValue`]).
2307 #[inline]
2308 pub unsafe fn as_value(self) -> Value {
2309 self.0.get()
2310 }
2311}
2312
2313/// # `Fixnum`
2314///
2315/// Functions that can be used to create instances of Ruby's small/fast integer
2316/// representation.
2317///
2318/// See also the [`Fixnum`] type.
2319impl Ruby {
2320 /// Create a new `Fixnum` from an `i64.`
2321 ///
2322 /// Returns `Ok(Fixnum)` if `n` is in range for `Fixnum`, otherwise returns
2323 /// `Err(RBignum)`.
2324 ///
2325 /// # Examples
2326 ///
2327 /// ```
2328 /// use magnus::{Error, Ruby};
2329 ///
2330 /// fn example(ruby: &Ruby) -> Result<(), Error> {
2331 /// assert!(ruby.fixnum_from_i64(0).is_ok());
2332 /// // too big
2333 /// assert!(ruby.fixnum_from_i64(4611686018427387904).is_err());
2334 /// assert!(ruby.fixnum_from_i64(-4611686018427387905).is_err());
2335 ///
2336 /// Ok(())
2337 /// }
2338 /// # Ruby::init(example).unwrap()
2339 /// ```
2340 #[inline]
2341 pub fn fixnum_from_i64(&self, n: i64) -> Result<Fixnum, RBignum> {
2342 Fixnum::from_i64_impl(n)
2343 .ok_or_else(|| unsafe { RBignum::from_rb_value_unchecked(rb_ll2inum(n)) })
2344 }
2345
2346 /// Create a new `Fixnum` from a `u64.`
2347 ///
2348 /// Returns `Ok(Fixnum)` if `n` is in range for `Fixnum`, otherwise returns
2349 /// `Err(RBignum)`.
2350 ///
2351 /// # Examples
2352 ///
2353 /// ```
2354 /// use magnus::{Error, Ruby};
2355 ///
2356 /// fn example(ruby: &Ruby) -> Result<(), Error> {
2357 /// assert!(ruby.fixnum_from_u64(0).is_ok());
2358 /// // too big
2359 /// assert!(ruby.fixnum_from_u64(4611686018427387904).is_err());
2360 ///
2361 /// Ok(())
2362 /// }
2363 /// # Ruby::init(example).unwrap()
2364 /// ```
2365 #[inline]
2366 pub fn fixnum_from_u64(&self, n: u64) -> Result<Fixnum, RBignum> {
2367 Fixnum::from_i64_impl(i64::try_from(n).unwrap_or(i64::MAX))
2368 .ok_or_else(|| unsafe { RBignum::from_rb_value_unchecked(rb_ull2inum(n)) })
2369 }
2370}
2371
2372/// A Value known to be a fixnum, Ruby's internal representation of small
2373/// integers.
2374///
2375/// See also [`Integer`].
2376///
2377/// See the [`ReprValue`] trait for additional methods available on this type.
2378/// See [`Ruby`](Ruby#fixnum) for methods to create a `Fixnum`.
2379#[derive(Clone, Copy)]
2380#[repr(transparent)]
2381pub struct Fixnum(NonZeroValue);
2382
2383impl Fixnum {
2384 /// Return `Some(Fixnum)` if `val` is a `Fixnum`, `None` otherwise.
2385 ///
2386 /// # Examples
2387 ///
2388 /// ```
2389 /// use magnus::{eval, Fixnum};
2390 /// # let _cleanup = unsafe { magnus::embed::init() };
2391 ///
2392 /// assert!(Fixnum::from_value(eval("0").unwrap()).is_some());
2393 /// // too big
2394 /// assert!(Fixnum::from_value(eval("9223372036854775807").unwrap()).is_none());
2395 /// // not an int
2396 /// assert!(Fixnum::from_value(eval("1.23").unwrap()).is_none());
2397 /// ```
2398 #[inline]
2399 pub fn from_value(val: Value) -> Option<Self> {
2400 unsafe {
2401 val.is_fixnum()
2402 .then(|| Self(NonZeroValue::new_unchecked(val)))
2403 }
2404 }
2405
2406 #[inline]
2407 pub(crate) unsafe fn from_rb_value_unchecked(val: VALUE) -> Self {
2408 Self(NonZeroValue::new_unchecked(Value::new(val)))
2409 }
2410
2411 #[inline]
2412 pub(crate) fn from_i64_impl(n: i64) -> Option<Self> {
2413 #[allow(clippy::useless_conversion)] // not useless when c_long != i64
2414 (c_ulong::try_from(n)
2415 .map(|n| n < RUBY_FIXNUM_MAX + 1)
2416 .unwrap_or(false)
2417 && c_long::try_from(n)
2418 .map(|n| n >= RUBY_FIXNUM_MIN)
2419 .unwrap_or(false))
2420 .then(|| unsafe {
2421 let x = transmute::<_, usize>(n as isize);
2422 Self::from_rb_value_unchecked(x.wrapping_add(x.wrapping_add(1)) as VALUE)
2423 })
2424 }
2425
2426 /// Create a new `Fixnum` from an `i64.`
2427 ///
2428 /// Returns `Ok(Fixnum)` if `n` is in range for `Fixnum`, otherwise returns
2429 /// `Err(RBignum)`.
2430 ///
2431 /// # Panics
2432 ///
2433 /// Panics if called from a non-Ruby thread. See [`Ruby::fixnum_from_i64`]
2434 /// for the non-panicking version.
2435 ///
2436 /// # Examples
2437 ///
2438 /// ```
2439 /// # #![allow(deprecated)]
2440 /// use magnus::Fixnum;
2441 /// # let _cleanup = unsafe { magnus::embed::init() };
2442 ///
2443 /// assert!(Fixnum::from_i64(0).is_ok());
2444 /// // too big
2445 /// assert!(Fixnum::from_i64(4611686018427387904).is_err());
2446 /// assert!(Fixnum::from_i64(-4611686018427387905).is_err());
2447 /// ```
2448 #[cfg_attr(
2449 not(feature = "old-api"),
2450 deprecated(note = "please use `Ruby::fixnum_from_i64` instead")
2451 )]
2452 #[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
2453 #[inline]
2454 pub fn from_i64(n: i64) -> Result<Self, RBignum> {
2455 get_ruby!().fixnum_from_i64(n)
2456 }
2457
2458 /// Create a new `Fixnum` from a `u64.`
2459 ///
2460 /// Returns `Ok(Fixnum)` if `n` is in range for `Fixnum`, otherwise returns
2461 /// `Err(RBignum)`.
2462 ///
2463 /// # Panics
2464 ///
2465 /// Panics if called from a non-Ruby thread. See [`Ruby::fixnum_from_u64`]
2466 /// for the non-panicking version.
2467 ///
2468 /// # Examples
2469 ///
2470 /// ```
2471 /// # #![allow(deprecated)]
2472 /// use magnus::Fixnum;
2473 /// # let _cleanup = unsafe { magnus::embed::init() };
2474 ///
2475 /// assert!(Fixnum::from_u64(0).is_ok());
2476 /// // too big
2477 /// assert!(Fixnum::from_u64(4611686018427387904).is_err());
2478 /// ```
2479 #[cfg_attr(
2480 not(feature = "old-api"),
2481 deprecated(note = "please use `Ruby::fixnum_from_u64` instead")
2482 )]
2483 #[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
2484 #[inline]
2485 pub fn from_u64(n: u64) -> Result<Self, RBignum> {
2486 get_ruby!().fixnum_from_u64(n)
2487 }
2488
2489 fn is_negative(self) -> bool {
2490 unsafe { transmute::<_, isize>(self.0) < 0 }
2491 }
2492
2493 /// Convert `self` to an `i8`. Returns `Err` if `self` is out of range for
2494 /// `i8`.
2495 ///
2496 /// # Examples
2497 ///
2498 /// ```
2499 /// use magnus::{Error, Fixnum, Ruby};
2500 ///
2501 /// fn example(ruby: &Ruby) -> Result<(), Error> {
2502 /// assert_eq!(ruby.eval::<Fixnum>("127")?.to_i8()?, 127);
2503 /// assert!(ruby.eval::<Fixnum>("128")?.to_i8().is_err());
2504 /// assert_eq!(ruby.eval::<Fixnum>("-128")?.to_i8()?, -128);
2505 /// assert!(ruby.eval::<Fixnum>("-129")?.to_i8().is_err());
2506 ///
2507 /// Ok(())
2508 /// }
2509 /// # Ruby::init(example).unwrap()
2510 /// ```
2511 #[inline]
2512 pub fn to_i8(self) -> Result<i8, Error> {
2513 let res = self.to_isize();
2514 if res > i8::MAX as isize || res < i8::MIN as isize {
2515 return Err(Error::new(
2516 Ruby::get_with(self).exception_range_error(),
2517 "fixnum too big to convert into `i8`",
2518 ));
2519 }
2520 Ok(res as i8)
2521 }
2522
2523 /// Convert `self` to an `i16`. Returns `Err` if `self` is out of range for
2524 /// `i16`.
2525 ///
2526 /// # Examples
2527 ///
2528 /// ```
2529 /// use magnus::{Error, Fixnum, Ruby};
2530 ///
2531 /// fn example(ruby: &Ruby) -> Result<(), Error> {
2532 /// assert_eq!(ruby.eval::<Fixnum>("32767")?.to_i16()?, 32767);
2533 /// assert!(ruby.eval::<Fixnum>("32768")?.to_i16().is_err());
2534 /// assert_eq!(ruby.eval::<Fixnum>("-32768")?.to_i16()?, -32768);
2535 /// assert!(ruby.eval::<Fixnum>("-32769")?.to_i16().is_err());
2536 ///
2537 /// Ok(())
2538 /// }
2539 /// # Ruby::init(example).unwrap()
2540 /// ```
2541 #[inline]
2542 pub fn to_i16(self) -> Result<i16, Error> {
2543 let res = self.to_isize();
2544 if res > i16::MAX as isize || res < i16::MIN as isize {
2545 return Err(Error::new(
2546 Ruby::get_with(self).exception_range_error(),
2547 "fixnum too big to convert into `i16`",
2548 ));
2549 }
2550 Ok(res as i16)
2551 }
2552
2553 /// Convert `self` to an `i32`. Returns `Err` if `self` is out of range for
2554 /// `i32`.
2555 ///
2556 /// # Examples
2557 ///
2558 /// ```
2559 /// use magnus::{Error, Fixnum, Ruby};
2560 ///
2561 /// fn example(ruby: &Ruby) -> Result<(), Error> {
2562 /// # #[cfg(not(windows))]
2563 /// # {
2564 /// assert_eq!(ruby.eval::<Fixnum>("2147483647")?.to_i32()?, 2147483647);
2565 /// assert!(ruby.eval::<Fixnum>("2147483648")?.to_i32().is_err());
2566 /// assert_eq!(ruby.eval::<Fixnum>("-2147483648")?.to_i32()?, -2147483648);
2567 /// assert!(ruby.eval::<Fixnum>("-2147483649")?.to_i32().is_err());
2568 /// # }
2569 ///
2570 /// Ok(())
2571 /// }
2572 /// # Ruby::init(example).unwrap()
2573 /// ```
2574 #[inline]
2575 pub fn to_i32(self) -> Result<i32, Error> {
2576 let res = self.to_isize();
2577 if res > i32::MAX as isize || res < i32::MIN as isize {
2578 return Err(Error::new(
2579 Ruby::get_with(self).exception_range_error(),
2580 "fixnum too big to convert into `i32`",
2581 ));
2582 }
2583 Ok(res as i32)
2584 }
2585
2586 /// Convert `self` to an `i64`. This is infallible as `i64` can represent a
2587 /// larger range than `Fixnum`.
2588 ///
2589 /// # Examples
2590 ///
2591 /// ```
2592 /// use magnus::{Error, Fixnum, Ruby};
2593 ///
2594 /// fn example(ruby: &Ruby) -> Result<(), Error> {
2595 /// # #[cfg(not(windows))]
2596 /// assert_eq!(
2597 /// ruby.eval::<Fixnum>("4611686018427387903")?.to_i64(),
2598 /// 4611686018427387903
2599 /// );
2600 /// # #[cfg(not(windows))]
2601 /// assert_eq!(
2602 /// ruby.eval::<Fixnum>("-4611686018427387904")?.to_i64(),
2603 /// -4611686018427387904
2604 /// );
2605 ///
2606 /// Ok(())
2607 /// }
2608 /// # Ruby::init(example).unwrap()
2609 /// ```
2610 #[inline]
2611 pub fn to_i64(self) -> i64 {
2612 self.to_isize() as i64
2613 }
2614
2615 /// Convert `self` to an `i128`. This is infallible as `i128` can represent a
2616 /// larger range than `Fixnum`.
2617 ///
2618 /// # Examples
2619 ///
2620 /// ```
2621 /// use magnus::{Error, Fixnum, Ruby};
2622 ///
2623 /// fn example(ruby: &Ruby) -> Result<(), Error> {
2624 /// # #[cfg(not(windows))]
2625 /// assert_eq!(
2626 /// ruby.eval::<Fixnum>("4611686018427387903")?.to_i128(),
2627 /// 4611686018427387903
2628 /// );
2629 /// # #[cfg(not(windows))]
2630 /// assert_eq!(
2631 /// ruby.eval::<Fixnum>("-4611686018427387904")?.to_i128(),
2632 /// -4611686018427387904
2633 /// );
2634 ///
2635 /// Ok(())
2636 /// }
2637 /// # Ruby::init(example).unwrap()
2638 /// ```
2639 #[inline]
2640 pub fn to_i128(self) -> i128 {
2641 self.to_isize() as i128
2642 }
2643
2644 /// Convert `self` to an `isize`. Returns `Err` if `self` is out of range
2645 /// for `isize`.
2646 ///
2647 /// # Examples
2648 ///
2649 /// ```
2650 /// use magnus::{Error, Fixnum, Ruby};
2651 ///
2652 /// fn example(ruby: &Ruby) -> Result<(), Error> {
2653 /// # #[cfg(not(windows))]
2654 /// assert_eq!(
2655 /// ruby.eval::<Fixnum>("4611686018427387903")?.to_isize(),
2656 /// 4611686018427387903
2657 /// );
2658 /// # #[cfg(not(windows))]
2659 /// assert_eq!(
2660 /// ruby.eval::<Fixnum>("-4611686018427387904")?.to_isize(),
2661 /// -4611686018427387904
2662 /// );
2663 ///
2664 /// Ok(())
2665 /// }
2666 /// # Ruby::init(example).unwrap()
2667 /// ```
2668 #[inline]
2669 pub fn to_isize(self) -> isize {
2670 unsafe { transmute::<_, isize>(self) >> 1 }
2671 }
2672
2673 /// Convert `self` to a `u8`. Returns `Err` if `self` is negative or out of
2674 /// range for `u8`.
2675 ///
2676 /// # Examples
2677 ///
2678 /// ```
2679 /// use magnus::{Error, Fixnum, Ruby};
2680 ///
2681 /// fn example(ruby: &Ruby) -> Result<(), Error> {
2682 /// assert_eq!(ruby.eval::<Fixnum>("255")?.to_u8()?, 255);
2683 /// assert!(ruby.eval::<Fixnum>("256")?.to_u8().is_err());
2684 /// assert!(ruby.eval::<Fixnum>("-1")?.to_u8().is_err());
2685 ///
2686 /// Ok(())
2687 /// }
2688 /// # Ruby::init(example).unwrap()
2689 /// ```
2690 #[inline]
2691 pub fn to_u8(self) -> Result<u8, Error> {
2692 let handle = Ruby::get_with(self);
2693 if self.is_negative() {
2694 return Err(Error::new(
2695 handle.exception_range_error(),
2696 "can't convert negative integer to unsigned",
2697 ));
2698 }
2699 let res = self.to_isize();
2700 if res > u8::MAX as isize {
2701 return Err(Error::new(
2702 handle.exception_range_error(),
2703 "fixnum too big to convert into `u8`",
2704 ));
2705 }
2706 Ok(res as u8)
2707 }
2708
2709 /// Convert `self` to a `u16`. Returns `Err` if `self` is negative or out
2710 /// of range for `u16`.
2711 ///
2712 /// # Examples
2713 ///
2714 /// ```
2715 /// use magnus::{Error, Fixnum, Ruby};
2716 ///
2717 /// fn example(ruby: &Ruby) -> Result<(), Error> {
2718 /// assert_eq!(ruby.eval::<Fixnum>("65535")?.to_u16()?, 65535);
2719 /// assert!(ruby.eval::<Fixnum>("65536")?.to_u16().is_err());
2720 /// assert!(ruby.eval::<Fixnum>("-1")?.to_u16().is_err());
2721 ///
2722 /// Ok(())
2723 /// }
2724 /// # Ruby::init(example).unwrap()
2725 /// ```
2726 #[inline]
2727 pub fn to_u16(self) -> Result<u16, Error> {
2728 let handle = Ruby::get_with(self);
2729 if self.is_negative() {
2730 return Err(Error::new(
2731 handle.exception_range_error(),
2732 "can't convert negative integer to unsigned",
2733 ));
2734 }
2735 let res = self.to_isize();
2736 if res > u16::MAX as isize {
2737 return Err(Error::new(
2738 handle.exception_range_error(),
2739 "fixnum too big to convert into `u16`",
2740 ));
2741 }
2742 Ok(res as u16)
2743 }
2744
2745 /// Convert `self` to a `u32`. Returns `Err` if `self` is negative or out
2746 /// of range for `u32`.
2747 ///
2748 /// # Examples
2749 ///
2750 /// ```
2751 /// use magnus::{Error, Fixnum, Ruby};
2752 ///
2753 /// fn example(ruby: &Ruby) -> Result<(), Error> {
2754 /// # #[cfg(not(windows))]
2755 /// # {
2756 /// assert_eq!(ruby.eval::<Fixnum>("4294967295")?.to_u32()?, 4294967295);
2757 /// assert!(ruby.eval::<Fixnum>("4294967296")?.to_u32().is_err());
2758 /// # }
2759 /// assert!(ruby.eval::<Fixnum>("-1")?.to_u32().is_err());
2760 ///
2761 /// Ok(())
2762 /// }
2763 /// # Ruby::init(example).unwrap()
2764 /// ```
2765 #[inline]
2766 pub fn to_u32(self) -> Result<u32, Error> {
2767 let handle = Ruby::get_with(self);
2768 if self.is_negative() {
2769 return Err(Error::new(
2770 handle.exception_range_error(),
2771 "can't convert negative integer to unsigned",
2772 ));
2773 }
2774 let res = self.to_isize();
2775 if res > u32::MAX as isize {
2776 return Err(Error::new(
2777 handle.exception_range_error(),
2778 "fixnum too big to convert into `u32`",
2779 ));
2780 }
2781 Ok(res as u32)
2782 }
2783
2784 /// Convert `self` to a `u64`. Returns `Err` if `self` is negative.
2785 ///
2786 /// # Examples
2787 ///
2788 /// ```
2789 /// use magnus::{Error, Fixnum, Ruby};
2790 ///
2791 /// fn example(ruby: &Ruby) -> Result<(), Error> {
2792 /// # #[cfg(not(windows))]
2793 /// assert_eq!(
2794 /// ruby.eval::<Fixnum>("4611686018427387903")?.to_u64()?,
2795 /// 4611686018427387903
2796 /// );
2797 /// assert!(ruby.eval::<Fixnum>("-1")?.to_u64().is_err());
2798 ///
2799 /// Ok(())
2800 /// }
2801 /// # Ruby::init(example).unwrap()
2802 /// ```
2803 #[inline]
2804 pub fn to_u64(self) -> Result<u64, Error> {
2805 if self.is_negative() {
2806 return Err(Error::new(
2807 Ruby::get_with(self).exception_range_error(),
2808 "can't convert negative integer to unsigned",
2809 ));
2810 }
2811 Ok(self.to_isize() as u64)
2812 }
2813
2814 /// Convert `self` to a `u128`. Returns `Err` if `self` is negative.
2815 ///
2816 /// # Examples
2817 ///
2818 /// ```
2819 /// use magnus::{Error, Fixnum, Ruby};
2820 ///
2821 /// fn example(ruby: &Ruby) -> Result<(), Error> {
2822 /// # #[cfg(not(windows))]
2823 /// assert_eq!(
2824 /// ruby.eval::<Fixnum>("4611686018427387903")?.to_u128()?,
2825 /// 4611686018427387903
2826 /// );
2827 /// assert!(ruby.eval::<Fixnum>("-1")?.to_u128().is_err());
2828 ///
2829 /// Ok(())
2830 /// }
2831 /// # Ruby::init(example).unwrap()
2832 /// ```
2833 #[inline]
2834 pub fn to_u128(self) -> Result<u128, Error> {
2835 if self.is_negative() {
2836 return Err(Error::new(
2837 Ruby::get_with(self).exception_range_error(),
2838 "can't convert negative integer to unsigned",
2839 ));
2840 }
2841 Ok(self.to_isize() as u128)
2842 }
2843
2844 /// Convert `self` to a `usize`. Returns `Err` if `self` is negative or out
2845 /// of range for `usize`.
2846 ///
2847 /// # Examples
2848 ///
2849 /// ```
2850 /// use magnus::{Error, Fixnum, Ruby};
2851 ///
2852 /// fn example(ruby: &Ruby) -> Result<(), Error> {
2853 /// # #[cfg(not(windows))]
2854 /// assert_eq!(
2855 /// ruby.eval::<Fixnum>("4611686018427387903")?.to_usize()?,
2856 /// 4611686018427387903
2857 /// );
2858 /// assert!(ruby.eval::<Fixnum>("-1")?.to_usize().is_err());
2859 ///
2860 /// Ok(())
2861 /// }
2862 /// # Ruby::init(example).unwrap()
2863 /// ```
2864 #[inline]
2865 pub fn to_usize(self) -> Result<usize, Error> {
2866 if self.is_negative() {
2867 return Err(Error::new(
2868 Ruby::get_with(self).exception_range_error(),
2869 "can't convert negative integer to unsigned",
2870 ));
2871 }
2872 Ok(self.to_isize() as usize)
2873 }
2874}
2875
2876impl fmt::Display for Fixnum {
2877 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2878 write!(f, "{}", unsafe { self.to_s_infallible() })
2879 }
2880}
2881
2882impl fmt::Debug for Fixnum {
2883 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2884 write!(f, "{}", self.inspect())
2885 }
2886}
2887
2888impl IntoValue for Fixnum {
2889 #[inline]
2890 fn into_value_with(self, _: &Ruby) -> Value {
2891 self.0.get()
2892 }
2893}
2894
2895unsafe impl private::ReprValue for Fixnum {}
2896
2897impl Numeric for Fixnum {}
2898
2899impl ReprValue for Fixnum {}
2900
2901impl TryConvert for Fixnum {
2902 fn try_convert(val: Value) -> Result<Self, Error> {
2903 match Integer::try_convert(val)?.integer_type() {
2904 IntegerType::Fixnum(fix) => Ok(fix),
2905 IntegerType::Bignum(_) => Err(Error::new(
2906 Ruby::get_with(val).exception_range_error(),
2907 "integer too big for fixnum",
2908 )),
2909 }
2910 }
2911}
2912unsafe impl TryConvertOwned for Fixnum {}
2913
2914/// # `StaticSymbol`
2915///
2916/// Functions to create Ruby `Symbol`s that will never be garbage collected.
2917///
2918/// See also the [`StaticSymbol`] type.
2919impl Ruby {
2920 /// Create a new StaticSymbol.
2921 ///
2922 /// # Examples
2923 ///
2924 /// ```
2925 /// use magnus::{rb_assert, Error, Ruby};
2926 ///
2927 /// fn example(ruby: &Ruby) -> Result<(), Error> {
2928 /// let sym = ruby.sym_new("example");
2929 /// rb_assert!(ruby, ":example == sym", sym);
2930 ///
2931 /// Ok(())
2932 /// }
2933 /// # Ruby::init(example).unwrap()
2934 /// ```
2935 #[inline]
2936 pub fn sym_new<T>(&self, name: T) -> StaticSymbol
2937 where
2938 T: IntoId,
2939 {
2940 name.into_id_with(self).into()
2941 }
2942
2943 /// Return the `StaticSymbol` for `name`, if one exists.
2944 ///
2945 /// # Examples
2946 ///
2947 /// ```
2948 /// use magnus::{Error, Ruby, StaticSymbol};
2949 ///
2950 /// fn example(ruby: &Ruby) -> Result<(), Error> {
2951 /// assert!(ruby.check_symbol("example").is_none());
2952 /// let _: StaticSymbol = ruby.eval(":example")?;
2953 /// assert!(ruby.check_symbol("example").is_some());
2954 ///
2955 /// Ok(())
2956 /// }
2957 /// # Ruby::init(example).unwrap()
2958 /// ```
2959 pub fn check_symbol(&self, name: &str) -> Option<StaticSymbol> {
2960 unsafe {
2961 let res = Value::new(rb_check_symbol_cstr(
2962 name.as_ptr() as *mut c_char,
2963 name.len() as c_long,
2964 self.utf8_encoding().as_ptr(),
2965 ));
2966 (!res.is_nil()).then(|| StaticSymbol::from_rb_value_unchecked(res.as_rb_value()))
2967 }
2968 }
2969}
2970
2971/// A static Ruby symbol that will live for the life of the program and never
2972/// be garbage collected.
2973///
2974/// See also [`Symbol`].
2975///
2976/// See the [`ReprValue`] trait for additional methods available on this type.
2977/// See [`Ruby`](Ruby#staticsymbol) for methods to create a `StaticSymbol`.
2978#[derive(Clone, Copy, Eq, Hash, PartialEq)]
2979#[repr(transparent)]
2980pub struct StaticSymbol(NonZeroValue);
2981
2982impl StaticSymbol {
2983 /// Return `Some(StaticSymbol)` if `val` is a `StaticSymbol`, `None`
2984 /// otherwise.
2985 ///
2986 /// # Examples
2987 ///
2988 /// ```
2989 /// use magnus::{eval, StaticSymbol};
2990 /// # let _cleanup = unsafe { magnus::embed::init() };
2991 ///
2992 /// assert!(StaticSymbol::from_value(eval(":foo").unwrap()).is_some());
2993 /// assert!(StaticSymbol::from_value(eval(r#""bar""#).unwrap()).is_none());
2994 /// assert!(StaticSymbol::from_value(eval(r#""baz".to_sym"#).unwrap()).is_none());
2995 /// ```
2996 #[inline]
2997 pub fn from_value(val: Value) -> Option<Self> {
2998 fn is_static_or_permanent_symbol(val: Value) -> bool {
2999 if val.is_static_symbol() {
3000 return true;
3001 }
3002 debug_assert_value!(val);
3003 if val.rb_type() != ruby_value_type::RUBY_T_SYMBOL {
3004 return false;
3005 }
3006 let mut p = val.as_rb_value();
3007 unsafe { rb_check_id(&mut p as *mut _) != 0 }
3008 }
3009 unsafe {
3010 is_static_or_permanent_symbol(val).then(|| Self(NonZeroValue::new_unchecked(val)))
3011 }
3012 }
3013
3014 #[inline]
3015 pub(crate) unsafe fn from_rb_value_unchecked(val: VALUE) -> Self {
3016 Self(NonZeroValue::new_unchecked(Value::new(val)))
3017 }
3018
3019 /// Create a new StaticSymbol.
3020 ///
3021 /// # Panics
3022 ///
3023 /// Panics if called from a non-Ruby thread. See [`Ruby::sym_new`] for the
3024 /// non-panicking version.
3025 ///
3026 /// # Examples
3027 /// ```
3028 /// # #![allow(deprecated)]
3029 /// use magnus::{rb_assert, StaticSymbol};
3030 /// # let _cleanup = unsafe { magnus::embed::init() };
3031 ///
3032 /// let sym = StaticSymbol::new("example");
3033 /// rb_assert!(":example == sym", sym);
3034 /// ```
3035 #[cfg_attr(
3036 not(feature = "old-api"),
3037 deprecated(note = "please use `Ruby::sym_new` instead")
3038 )]
3039 #[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
3040 #[inline]
3041 pub fn new<T>(name: T) -> Self
3042 where
3043 T: IntoId,
3044 {
3045 get_ruby!().sym_new(name)
3046 }
3047
3048 /// Return the `StaticSymbol` for `name`, if one exists.
3049 ///
3050 /// # Panics
3051 ///
3052 /// Panics if called from a non-Ruby thread. See [`Ruby::check_symbol`] for
3053 /// the non-panicking version.
3054 ///
3055 /// # Examples
3056 ///
3057 /// ```
3058 /// # #![allow(deprecated)]
3059 /// use magnus::{eval, StaticSymbol};
3060 /// # let _cleanup = unsafe { magnus::embed::init() };
3061 ///
3062 /// assert!(StaticSymbol::check("example").is_none());
3063 /// let _: StaticSymbol = eval(":example").unwrap();
3064 /// assert!(StaticSymbol::check("example").is_some());
3065 /// ```
3066 #[cfg_attr(
3067 not(feature = "old-api"),
3068 deprecated(note = "please use `Ruby::check_symbol` instead")
3069 )]
3070 #[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
3071 #[inline]
3072 pub fn check(name: &str) -> Option<Self> {
3073 get_ruby!().check_symbol(name)
3074 }
3075
3076 /// Return the symbol as a static string reference.
3077 ///
3078 /// May error if the name is not valid utf-8.
3079 ///
3080 /// # Examples
3081 ///
3082 /// ```
3083 /// use magnus::{Error, Ruby};
3084 ///
3085 /// fn example(ruby: &Ruby) -> Result<(), Error> {
3086 /// let sym = ruby.sym_new("example");
3087 /// assert_eq!(sym.name()?, "example");
3088 ///
3089 /// Ok(())
3090 /// }
3091 /// # Ruby::init(example).unwrap()
3092 /// ```
3093 #[inline]
3094 pub fn name(self) -> Result<&'static str, Error> {
3095 Id::from(self).name()
3096 }
3097}
3098
3099impl Borrow<Symbol> for StaticSymbol {
3100 fn borrow(&self) -> &Symbol {
3101 unsafe { &*(self as *const Self as *const Symbol) }
3102 }
3103}
3104
3105impl fmt::Display for StaticSymbol {
3106 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3107 write!(f, "{}", unsafe { self.to_s_infallible() })
3108 }
3109}
3110
3111impl fmt::Debug for StaticSymbol {
3112 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3113 write!(f, "{}", self.inspect())
3114 }
3115}
3116
3117impl EncodingCapable for StaticSymbol {}
3118
3119impl From<Id> for StaticSymbol {
3120 fn from(id: Id) -> Self {
3121 unsafe { Self::from_rb_value_unchecked(rb_id2sym(id.as_rb_id())) }
3122 }
3123}
3124
3125impl IntoValue for StaticSymbol {
3126 #[inline]
3127 fn into_value_with(self, _: &Ruby) -> Value {
3128 self.0.get()
3129 }
3130}
3131
3132impl PartialEq<Id> for StaticSymbol {
3133 #[inline]
3134 fn eq(&self, other: &Id) -> bool {
3135 self.into_id_with(&Ruby::get_with(*self)) == *other
3136 }
3137}
3138
3139impl PartialEq<OpaqueId> for StaticSymbol {
3140 #[inline]
3141 fn eq(&self, other: &OpaqueId) -> bool {
3142 self.into_id_with(&Ruby::get_with(*self)).0 == other.0
3143 }
3144}
3145
3146impl PartialEq<LazyId> for StaticSymbol {
3147 /// # Panics
3148 ///
3149 /// Panics if the first call is from a non-Ruby thread. The `LazyId` will
3150 /// then be *poisoned* and all future use of it will panic.
3151 #[inline]
3152 fn eq(&self, other: &LazyId) -> bool {
3153 self.into_id_with(&Ruby::get_with(*self)).0 == other.0
3154 }
3155}
3156
3157impl PartialEq<Symbol> for StaticSymbol {
3158 #[inline]
3159 fn eq(&self, other: &Symbol) -> bool {
3160 other.as_static().map(|o| *self == o).unwrap_or(false)
3161 }
3162}
3163
3164unsafe impl private::ReprValue for StaticSymbol {}
3165
3166impl ReprValue for StaticSymbol {}
3167
3168impl TryConvert for StaticSymbol {
3169 fn try_convert(val: Value) -> Result<Self, Error> {
3170 Symbol::try_convert(val).map(|s| s.to_static())
3171 }
3172}
3173unsafe impl TryConvertOwned for StaticSymbol {}
3174
3175/// # `Id`
3176///
3177/// Functions to create Ruby's low-level `Symbol` representation.
3178///
3179/// See also the [`Id`] type.
3180impl Ruby {
3181 /// Create a new `Id` for `name`.
3182 ///
3183 /// # Examples
3184 ///
3185 /// ```
3186 /// use magnus::{Error, Ruby};
3187 ///
3188 /// fn example(ruby: &Ruby) -> Result<(), Error> {
3189 /// let id = ruby.intern("example");
3190 /// assert_eq!(id.name()?, "example");
3191 ///
3192 /// Ok(())
3193 /// }
3194 /// # Ruby::init(example).unwrap()
3195 /// ```
3196 pub fn intern(&self, name: &str) -> Id {
3197 Id::from_rb_id(unsafe {
3198 rb_intern3(
3199 name.as_ptr() as *const c_char,
3200 name.len() as c_long,
3201 self.utf8_encoding().as_ptr(),
3202 )
3203 })
3204 }
3205
3206 /// Return the `Id` for `name`, if one exists.
3207 ///
3208 /// # Examples
3209 ///
3210 /// ```
3211 /// use magnus::{Error, Ruby};
3212 ///
3213 /// fn example(ruby: &Ruby) -> Result<(), Error> {
3214 /// assert!(ruby.check_id("example").is_none());
3215 /// ruby.intern("example");
3216 /// assert!(ruby.check_id("example").is_some());
3217 ///
3218 /// Ok(())
3219 /// }
3220 /// # Ruby::init(example).unwrap()
3221 /// ```
3222 pub fn check_id(&self, name: &str) -> Option<Id> {
3223 let res = unsafe {
3224 rb_check_id_cstr(
3225 name.as_ptr() as *mut c_char,
3226 name.len() as c_long,
3227 self.utf8_encoding().as_ptr(),
3228 )
3229 };
3230 (res != 0).then(|| Id::from_rb_id(res))
3231 }
3232}
3233
3234/// The internal value of a Ruby symbol.
3235///
3236/// See [`Ruby`](Ruby#id) for methods to create an `Id`.
3237#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
3238#[repr(transparent)]
3239pub struct Id(ID, PhantomData<*mut u8>);
3240
3241impl Id {
3242 /// Create a new `Id` for `name`.
3243 ///
3244 /// # Panics
3245 ///
3246 /// Panics if called from a non-Ruby thread. See [`Ruby::intern`] for the
3247 /// non-panicking version.
3248 ///
3249 /// # Examples
3250 ///
3251 /// ```
3252 /// # #![allow(deprecated)]
3253 /// use magnus::value::Id;
3254 /// # let _cleanup = unsafe { magnus::embed::init() };
3255 ///
3256 /// let id = Id::new("example");
3257 /// assert_eq!(id.name().unwrap(), "example");
3258 /// ```
3259 #[cfg_attr(
3260 not(feature = "old-api"),
3261 deprecated(note = "please use `Ruby::intern` instead")
3262 )]
3263 #[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
3264 pub fn new<T>(name: T) -> Self
3265 where
3266 T: AsRef<str>,
3267 {
3268 get_ruby!().intern(name.as_ref())
3269 }
3270
3271 #[inline]
3272 pub(crate) fn from_rb_id(id: ID) -> Self {
3273 Self(id, PhantomData)
3274 }
3275
3276 #[inline]
3277 pub(crate) fn as_rb_id(self) -> ID {
3278 self.0
3279 }
3280
3281 /// Return the `Id` for `name`, if one exists.
3282 ///
3283 /// # Panics
3284 ///
3285 /// Panics if called from a non-Ruby thread. See [`Ruby::check_id`] for the
3286 /// non-panicking version.
3287 ///
3288 /// # Examples
3289 ///
3290 /// ```
3291 /// # #![allow(deprecated)]
3292 /// use magnus::{value::Id, StaticSymbol};
3293 /// # let _cleanup = unsafe { magnus::embed::init() };
3294 ///
3295 /// assert!(Id::check("example").is_none());
3296 /// StaticSymbol::new("example");
3297 /// assert!(Id::check("example").is_some());
3298 /// ```
3299 #[cfg_attr(
3300 not(feature = "old-api"),
3301 deprecated(note = "please use `Ruby::check_id` instead")
3302 )]
3303 #[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
3304 #[inline]
3305 pub fn check(name: &str) -> Option<Self> {
3306 get_ruby!().check_id(name)
3307 }
3308
3309 /// Return the symbol name associated with this Id as a static string
3310 /// reference.
3311 ///
3312 /// May error if the name is not valid utf-8.
3313 ///
3314 /// # Examples
3315 ///
3316 /// ```
3317 /// use magnus::{Error, Ruby};
3318 ///
3319 /// fn example(ruby: &Ruby) -> Result<(), Error> {
3320 /// let id = ruby.intern("example");
3321 /// assert_eq!(id.name()?, "example");
3322 ///
3323 /// Ok(())
3324 /// }
3325 /// # Ruby::init(example).unwrap()
3326 /// ```
3327 pub fn name(self) -> Result<&'static str, Error> {
3328 unsafe {
3329 let ptr = rb_id2name(self.as_rb_id());
3330 let cstr = CStr::from_ptr(ptr);
3331 cstr.to_str().map_err(|e| {
3332 Error::new(
3333 Ruby::get_unchecked().exception_encoding_error(),
3334 e.to_string(),
3335 )
3336 })
3337 }
3338 }
3339}
3340
3341impl Borrow<OpaqueId> for Id {
3342 fn borrow(&self) -> &OpaqueId {
3343 unsafe { &*(self as *const Self as *const OpaqueId) }
3344 }
3345}
3346
3347/// Conversions from Rust types into [`Id`].
3348pub trait IntoId: Sized {
3349 /// Convert `self` into [`Id`].
3350 ///
3351 /// # Panics
3352 ///
3353 /// Panics if called from a non-Ruby thread. See [`IntoId::into_id_with`]
3354 /// for the non-panicking version.
3355 #[cfg_attr(
3356 not(feature = "old-api"),
3357 deprecated(note = "please use `IntoId::into_id_with` instead")
3358 )]
3359 #[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
3360 #[inline]
3361 fn into_id(self) -> Id {
3362 self.into_id_with(&get_ruby!())
3363 }
3364
3365 /// Convert `self` into [`Id`].
3366 ///
3367 /// # Safety
3368 ///
3369 /// This method should only be called from a Ruby thread.
3370 #[inline]
3371 unsafe fn into_id_unchecked(self) -> Id {
3372 self.into_id_with(&Ruby::get_unchecked())
3373 }
3374
3375 /// Convert `self` into [`Id`].
3376 fn into_id_with(self, handle: &Ruby) -> Id;
3377}
3378
3379impl IntoId for Id {
3380 #[inline]
3381 fn into_id_with(self, _: &Ruby) -> Id {
3382 self
3383 }
3384}
3385
3386impl IntoId for &str {
3387 #[inline]
3388 fn into_id_with(self, handle: &Ruby) -> Id {
3389 handle.intern(self)
3390 }
3391}
3392
3393impl IntoId for String {
3394 #[inline]
3395 fn into_id_with(self, handle: &Ruby) -> Id {
3396 self.as_str().into_id_with(handle)
3397 }
3398}
3399
3400impl IntoId for StaticSymbol {
3401 #[inline]
3402 fn into_id_with(self, handle: &Ruby) -> Id {
3403 self.into_symbol_with(handle).into_id_with(handle)
3404 }
3405}
3406
3407impl From<StaticSymbol> for Id {
3408 #[inline]
3409 fn from(sym: StaticSymbol) -> Self {
3410 sym.into_id_with(&Ruby::get_with(sym))
3411 }
3412}
3413
3414impl IntoId for Symbol {
3415 #[inline]
3416 fn into_id_with(self, _: &Ruby) -> Id {
3417 if self.is_static_symbol() {
3418 Id::from_rb_id(self.as_rb_value() >> ruby_special_consts::RUBY_SPECIAL_SHIFT as VALUE)
3419 } else {
3420 Id::from_rb_id(unsafe { rb_sym2id(self.as_rb_value()) })
3421 }
3422 }
3423}
3424
3425impl IntoValue for Id {
3426 #[inline]
3427 fn into_value_with(self, handle: &Ruby) -> Value {
3428 StaticSymbol::from(self).into_value_with(handle)
3429 }
3430}
3431
3432impl From<Symbol> for Id {
3433 #[inline]
3434 fn from(sym: Symbol) -> Self {
3435 sym.into_id_with(&Ruby::get_with(sym))
3436 }
3437}
3438
3439impl PartialEq<OpaqueId> for Id {
3440 #[inline]
3441 fn eq(&self, other: &OpaqueId) -> bool {
3442 self.0 == other.0
3443 }
3444}
3445
3446impl PartialEq<LazyId> for Id {
3447 #[inline]
3448 fn eq(&self, other: &LazyId) -> bool {
3449 self.0 == other.0
3450 }
3451}
3452
3453impl PartialEq<StaticSymbol> for Id {
3454 #[inline]
3455 fn eq(&self, other: &StaticSymbol) -> bool {
3456 *self == other.into_id_with(&Ruby::get_with(*other))
3457 }
3458}
3459
3460impl PartialEq<Symbol> for Id {
3461 #[inline]
3462 fn eq(&self, other: &Symbol) -> bool {
3463 other.as_static().map(|o| *self == o).unwrap_or(false)
3464 }
3465}
3466
3467/// A wrapper to make a Ruby [`Id`] [`Send`] + [`Sync`].
3468///
3469/// [`Id`] is not [`Send`] or [`Sync`] as it provides a way to call some of
3470/// Ruby's APIs, which are not safe to call from a non-Ruby thread.
3471///
3472/// [`Id`] is safe to send between Ruby threads, but Rust's trait system
3473/// currently can not model this detail.
3474///
3475/// To resolve this, the `OpaqueId` type makes an [`Id`] [`Send`] + [`Sync`]
3476/// by removing the ability use it with any Ruby APIs.
3477///
3478/// [`IntoId`] and [`IntoSymbol`] can be used to convert an `OpaqueId` back
3479/// into a type that can be used with Ruby's APIs. These traits can only be
3480/// used from a Ruby thread.
3481///
3482/// `OpaqueId` implements [`Eq`]/[`PartialEq`] and [`Hash`], so can be used as
3483/// a key or id on non-Ruby threads, or in data structures that must be
3484/// [`Send`] or [`Sync`].
3485#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
3486#[repr(transparent)]
3487pub struct OpaqueId(ID);
3488
3489impl From<Id> for OpaqueId {
3490 #[inline]
3491 fn from(id: Id) -> Self {
3492 Self(id.0)
3493 }
3494}
3495
3496impl From<StaticSymbol> for OpaqueId {
3497 #[inline]
3498 fn from(sym: StaticSymbol) -> Self {
3499 sym.into_id_with(&Ruby::get_with(sym)).into()
3500 }
3501}
3502
3503impl From<Symbol> for OpaqueId {
3504 #[inline]
3505 fn from(sym: Symbol) -> Self {
3506 sym.into_id_with(&Ruby::get_with(sym)).into()
3507 }
3508}
3509
3510impl IntoId for OpaqueId {
3511 #[inline]
3512 fn into_id_with(self, _: &Ruby) -> Id {
3513 Id::from_rb_id(self.0)
3514 }
3515}
3516
3517impl IntoSymbol for OpaqueId {
3518 #[inline]
3519 fn into_symbol_with(self, handle: &Ruby) -> Symbol {
3520 self.into_id_with(handle).into_symbol_with(handle)
3521 }
3522}
3523
3524impl IntoValue for OpaqueId {
3525 #[inline]
3526 fn into_value_with(self, handle: &Ruby) -> Value {
3527 self.into_symbol_with(handle).into_value_with(handle)
3528 }
3529}
3530
3531impl PartialEq<Id> for OpaqueId {
3532 #[inline]
3533 fn eq(&self, other: &Id) -> bool {
3534 self.0 == other.0
3535 }
3536}
3537
3538impl PartialEq<LazyId> for OpaqueId {
3539 #[inline]
3540 fn eq(&self, other: &LazyId) -> bool {
3541 *self == **other
3542 }
3543}
3544
3545impl PartialEq<StaticSymbol> for OpaqueId {
3546 #[inline]
3547 fn eq(&self, other: &StaticSymbol) -> bool {
3548 *self == other.into_id_with(&Ruby::get_with(*other))
3549 }
3550}
3551
3552impl PartialEq<Symbol> for OpaqueId {
3553 #[inline]
3554 fn eq(&self, other: &Symbol) -> bool {
3555 other.as_static().map(|o| *self == o).unwrap_or(false)
3556 }
3557}
3558
3559/// An [`Id`] that can be assigned to a `static` and [`Deref`]s to [`OpaqueId`].
3560///
3561/// The underlying Ruby Symbol will be lazily initialised when the `LazyId` is
3562/// first used. This initialisation must happen on a Ruby thread. If the first
3563/// use is from a non-Ruby thread the `LazyId` will panic and then become
3564/// *poisoned* and all future use of it will panic.
3565pub struct LazyId {
3566 init: Once,
3567 inner: UnsafeCell<LazyIdInner>,
3568}
3569
3570union LazyIdInner {
3571 name: &'static str,
3572 value: OpaqueId,
3573}
3574
3575impl LazyId {
3576 /// Create a new `LazyId`.
3577 ///
3578 /// # Examples
3579 ///
3580 /// ```
3581 /// use magnus::{rb_assert, value::LazyId, Error, Ruby};
3582 ///
3583 /// static EXAMPLE: LazyId = LazyId::new("example");
3584 ///
3585 /// fn example(ruby: &Ruby) -> Result<(), Error> {
3586 /// rb_assert!(ruby, "val == :example", val = *EXAMPLE);
3587 ///
3588 /// Ok(())
3589 /// }
3590 /// # Ruby::init(example).unwrap()
3591 /// ```
3592 pub const fn new(name: &'static str) -> Self {
3593 Self {
3594 init: Once::new(),
3595 inner: UnsafeCell::new(LazyIdInner { name }),
3596 }
3597 }
3598
3599 /// Force evaluation of a `LazyId`.
3600 ///
3601 /// This can be used in, for example, your [`init`](macro@crate::init)
3602 /// function to force initialisation of the `LazyId`, to ensure that use
3603 /// of the `LazyId` can't possibly panic.
3604 ///
3605 /// # Panics
3606 ///
3607 /// Panics if the `LazyId` is *poisoned*. See [`LazyId`].
3608 ///
3609 /// # Examples
3610 ///
3611 /// ```
3612 /// use magnus::{value::LazyId, Ruby};
3613 ///
3614 /// static EXAMPLE: LazyId = LazyId::new("example");
3615 ///
3616 /// #[magnus::init]
3617 /// fn init(ruby: &Ruby) {
3618 /// LazyId::force(&EXAMPLE, ruby);
3619 ///
3620 /// assert!(LazyId::try_get_inner(&EXAMPLE).is_some());
3621 /// }
3622 /// # let ruby = unsafe { magnus::embed::init() };
3623 /// # init(&ruby);
3624 /// ```
3625 #[inline]
3626 pub fn force(this: &Self, handle: &Ruby) {
3627 Self::get_inner_with(this, handle);
3628 }
3629
3630 /// Get a [`Id`] from a `LazyId`.
3631 ///
3632 /// # Panics
3633 ///
3634 /// Panics if the `LazyId` is *poisoned*. See [`LazyId`].
3635 ///
3636 /// # Examples
3637 ///
3638 /// ```
3639 /// use magnus::{value::LazyId, Error, Ruby};
3640 ///
3641 /// static EXAMPLE: LazyId = LazyId::new("example");
3642 ///
3643 /// fn example(ruby: &Ruby) -> Result<(), Error> {
3644 /// assert!(ruby.intern("example") == LazyId::get_inner_with(&EXAMPLE, &ruby));
3645 ///
3646 /// Ok(())
3647 /// }
3648 /// # Ruby::init(example).unwrap()
3649 /// ```
3650 #[inline]
3651 pub fn get_inner_with(this: &Self, handle: &Ruby) -> Id {
3652 unsafe {
3653 this.init.call_once(|| {
3654 let inner = this.inner.get();
3655 (*inner).value = handle.intern((*inner).name).into();
3656 });
3657 (*this.inner.get()).value.into_id_with(handle)
3658 }
3659 }
3660
3661 /// Get an [`OpaqueId`] from a `LazyId`, if it has already been evaluated.
3662 ///
3663 /// This function will not call Ruby and will not initialise the inner
3664 /// `OpaqueId`. If the `LazyId` has not yet been initialised, returns
3665 /// `None`.
3666 ///
3667 /// This function will not panic, if the `LazyId` is *poisoned* it will
3668 /// return `None`.
3669 ///
3670 /// # Examples
3671 ///
3672 /// ```
3673 /// use magnus::{rb_assert, value::LazyId, Error, Ruby};
3674 ///
3675 /// static EXAMPLE: LazyId = LazyId::new("example");
3676 ///
3677 /// fn example(ruby: &Ruby) -> Result<(), Error> {
3678 /// assert!(LazyId::try_get_inner(&EXAMPLE).is_none());
3679 ///
3680 /// rb_assert!(ruby, "val == :example", val = *EXAMPLE);
3681 ///
3682 /// assert!(LazyId::try_get_inner(&EXAMPLE).is_some());
3683 ///
3684 /// Ok(())
3685 /// }
3686 /// # Ruby::init(example).unwrap()
3687 /// ```
3688 pub fn try_get_inner(this: &Self) -> Option<OpaqueId> {
3689 unsafe { this.init.is_completed().then(|| (*this.inner.get()).value) }
3690 }
3691}
3692
3693unsafe impl Send for LazyId {}
3694unsafe impl Sync for LazyId {}
3695
3696impl fmt::Debug for LazyId {
3697 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3698 #[allow(non_camel_case_types)]
3699 #[derive(Debug)]
3700 struct uninit();
3701
3702 f.debug_tuple("LazyId")
3703 .field(
3704 Self::try_get_inner(self)
3705 .as_ref()
3706 .map(|v| v as &dyn fmt::Debug)
3707 .unwrap_or(&uninit()),
3708 )
3709 .finish()
3710 }
3711}
3712
3713impl Deref for LazyId {
3714 type Target = OpaqueId;
3715
3716 /// # Panics
3717 ///
3718 /// Panics if the first call is from a non-Ruby thread. This `LazyId` will
3719 /// then be *poisoned* and all future use of it will panic.
3720 fn deref(&self) -> &Self::Target {
3721 unsafe {
3722 self.init.call_once(|| {
3723 let inner = self.inner.get();
3724 (*inner).value = Ruby::get().unwrap().intern((*inner).name).into();
3725 });
3726 &(*self.inner.get()).value
3727 }
3728 }
3729}
3730
3731impl Hash for LazyId {
3732 /// # Panics
3733 ///
3734 /// Panics if the first call is from a non-Ruby thread. This `LazyId` will
3735 /// then be *poisoned* and all future use of it will panic.
3736 #[inline]
3737 fn hash<H: Hasher>(&self, state: &mut H) {
3738 self.deref().hash(state);
3739 }
3740}
3741
3742impl PartialEq for LazyId {
3743 /// # Panics
3744 ///
3745 /// Panics if the first call is from a non-Ruby thread. This `LazyId` will
3746 /// then be *poisoned* and all future use of it will panic.
3747 #[inline]
3748 fn eq(&self, other: &Self) -> bool {
3749 self.deref() == other.deref()
3750 }
3751}
3752impl Eq for LazyId {}
3753
3754impl PartialEq<Id> for LazyId {
3755 /// # Panics
3756 ///
3757 /// Panics if the first call is from a non-Ruby thread. This `LazyId` will
3758 /// then be *poisoned* and all future use of it will panic.
3759 #[inline]
3760 fn eq(&self, other: &Id) -> bool {
3761 *self.deref() == *other
3762 }
3763}
3764
3765impl PartialEq<StaticSymbol> for LazyId {
3766 /// # Panics
3767 ///
3768 /// Panics if the first call is from a non-Ruby thread. This `LazyId` will
3769 /// then be *poisoned* and all future use of it will panic.
3770 #[inline]
3771 fn eq(&self, other: &StaticSymbol) -> bool {
3772 *self == other.into_id_with(&Ruby::get_with(*other))
3773 }
3774}
3775
3776impl PartialEq<Symbol> for LazyId {
3777 /// # Panics
3778 ///
3779 /// Panics if the first call is from a non-Ruby thread. This `LazyId` will
3780 /// then be *poisoned* and all future use of it will panic.
3781 #[inline]
3782 fn eq(&self, other: &Symbol) -> bool {
3783 other.as_static().map(|o| *self == o).unwrap_or(false)
3784 }
3785}