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

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}