rb_sys/
stable_api.rs

1//! Stable ABI functions which provide access to Ruby internals that
2//! is compatible across Ruby versions, and are guaranteed to be not break due
3//! to Ruby binary changes.
4//!
5//! ### Goals
6//!
7//! 1. To provide access to Ruby internals that are not exposed by the libruby
8//!    (i.e. C macros and inline functions).
9//! 2. Provide support for Ruby development versions, which can make breaking
10//!    changes without semantic versioning. We want to support these versions
11//!    to ensure Rust extensions don't prevent the Ruby core team from testing
12//!    changes in production.
13
14use crate::VALUE;
15use std::{
16    os::raw::{c_char, c_long},
17    ptr::NonNull,
18    time::Duration,
19};
20
21pub trait StableApiDefinition {
22    const VERSION_MAJOR: u32;
23    const VERSION_MINOR: u32;
24
25    fn version(&self) -> (u32, u32) {
26        (Self::VERSION_MAJOR, Self::VERSION_MINOR)
27    }
28
29    /// Get the length of a Ruby string (akin to `RSTRING_LEN`).
30    ///
31    /// # Safety
32    /// This function is unsafe because it dereferences a raw pointer to get
33    /// access to underlying Ruby data. The caller must ensure that the pointer
34    /// is valid.
35    unsafe fn rstring_len(&self, obj: VALUE) -> c_long;
36
37    /// Get a pointer to the bytes of a Ruby string (akin to `RSTRING_PTR`).
38    ///
39    /// # Safety
40    /// This function is unsafe because it dereferences a raw pointer to get
41    /// access to underlying Ruby data. The caller must ensure that the pointer
42    /// is valid.
43    unsafe fn rstring_ptr(&self, obj: VALUE) -> *const c_char;
44
45    /// Get the length of a Ruby array (akin to `RARRAY_LEN`).
46    ///
47    /// # Safety
48    /// This function is unsafe because it dereferences a raw pointer to get
49    /// access to underlying Ruby data. The caller must ensure that the pointer
50    /// is valid.
51    unsafe fn rarray_len(&self, obj: VALUE) -> c_long;
52
53    /// Get a pointer to the elements of a Ruby array (akin to `RARRAY_CONST_PTR`).
54    ///
55    /// # Safety
56    /// This function is unsafe because it dereferences a raw pointer to get
57    /// access to underlying Ruby data. The caller must ensure that the pointer
58    /// is valid.
59    unsafe fn rarray_const_ptr(&self, obj: VALUE) -> *const VALUE;
60
61    /// Get the class from a VALUE which contains an RBasic struct.
62    ///
63    /// `VALUE` is a valid pointer to a non-immediate object.
64    ///
65    /// # Safety
66    /// This function is unsafe because it dereferences a raw pointer to get
67    /// access to underlying RBasic struct. The caller must ensure that the
68    /// `VALUE` is a valid pointer to an RBasic struct.
69    unsafe fn rbasic_class(&self, obj: VALUE) -> Option<NonNull<VALUE>>;
70
71    /// Checks if the given object is frozen.
72    ///
73    /// `VALUE` is a valid pointer to a non-immediate object.
74    ///
75    /// # Safety
76    /// This function is unsafe because it may dereference a raw pointer to get
77    /// access to underlying RBasic struct. The caller must ensure that the
78    /// `VALUE` is a valid pointer to an RBasic struct.
79    unsafe fn frozen_p(&self, obj: VALUE) -> bool;
80
81    /// Tests if a bignum is positive.
82    ///
83    /// # Safety
84    /// This function is unsafe because it dereferences a raw pointer to get
85    /// access to underlying RBasic struct. The caller must ensure that the
86    /// `VALUE` is a valid pointer to a bignum.
87    unsafe fn bignum_positive_p(&self, obj: VALUE) -> bool;
88
89    /// Tests if a bignum is negative.
90    ///
91    /// # Safety
92    /// This function is unsafe because it dereferences a raw pointer to get
93    /// access to underlying RBasic struct. The caller must ensure that the
94    /// `VALUE` is a valid pointer to a bignum.
95    #[inline]
96    unsafe fn bignum_negative_p(&self, obj: VALUE) -> bool {
97        !self.bignum_positive_p(obj)
98    }
99
100    /// Tests if the given value is a special constant.
101    fn special_const_p(&self, value: VALUE) -> bool;
102
103    /// Queries the type of the object.
104    ///
105    /// # Note
106    /// The input `obj` must not be a special constant.
107    ///
108    /// # Safety
109    /// This function is unsafe because it could dereference a raw pointer when
110    /// attemping to access the underlying [`RBasic`] struct.
111    unsafe fn builtin_type(&self, obj: VALUE) -> crate::ruby_value_type;
112
113    /// Tests if the object's type is the given type.
114    ///
115    /// # Safety
116    /// This function is unsafe because it could dereference a raw pointer when
117    /// attemping to access the underlying [`RBasic`] struct.
118    unsafe fn type_p(&self, obj: VALUE, ty: crate::ruby_value_type) -> bool;
119
120    /// Checks if the given object is nil.
121    fn nil_p(&self, obj: VALUE) -> bool;
122
123    /// Checks if the given object is a so-called Fixnum.
124    fn fixnum_p(&self, obj: VALUE) -> bool;
125
126    /// Checks if the given object is a dynamic symbol.
127    ///
128    /// # Safety
129    /// This function is unsafe because it could dereference a raw pointer when
130    /// attemping to access the underlying [`RBasic`] struct.
131    unsafe fn dynamic_sym_p(&self, obj: VALUE) -> bool;
132
133    /// Checks if the given object is a static symbol.
134    fn static_sym_p(&self, obj: VALUE) -> bool;
135
136    /// Checks if the given object is a symbol.
137    ///
138    /// # Safety
139    /// This function is unsafe because it could dereference a raw pointer when
140    /// attemping to access the underlying [`RBasic`] struct.
141    unsafe fn symbol_p(&self, obj: VALUE) -> bool;
142
143    /// Checks if the given object is a so-called Flonum.
144    ///
145    /// # Safety
146    /// This function is unsafe because it could dereference a raw pointer when
147    /// attemping to access the underlying [`RBasic`] struct.
148    unsafe fn float_type_p(&self, obj: VALUE) -> bool;
149
150    /// Checks if the given object is an integer type
151    ///
152    /// # Safety
153    /// This function is unsafe because it could dereference a raw pointer when
154    /// attemping to access the underlying [`RBasic`] struct.
155    unsafe fn integer_type_p(&self, obj: VALUE) -> bool;
156
157    /// Checks if the given object is a so-called Flonum.
158    fn flonum_p(&self, obj: VALUE) -> bool;
159
160    /// Checks if the given  object is  an immediate  i.e. an  object which  has
161    /// no corresponding storage inside of the object space.
162    fn immediate_p(&self, obj: VALUE) -> bool;
163
164    /// Emulates Ruby's "if" statement by testing if the given `obj` is neither `Qnil` or `Qfalse`.
165    ///
166    /// # Safety
167    /// This function is unsafe because it could dereference a raw pointer when
168    /// attemping to access the underlying [`RBasic`] struct.
169    fn rb_test(&self, ob: VALUE) -> bool;
170
171    /// Queries the type of the object. Identical to `StableApi.builtin_type`,
172    /// except it can also accept special constants.
173    ///
174    /// # Safety
175    /// This function is unsafe because it could dereference a raw pointer when
176    /// attemping to access the underlying [`RBasic`] struct.
177    unsafe fn rb_type(&self, obj: VALUE) -> crate::ruby_value_type;
178
179    /// Check if a Ruby string is interned (akin to `RSTRING_FSTR`).
180    ///
181    /// # Safety
182    /// This function is unsafe because it dereferences a raw pointer to get
183    /// access to underlying flags of the RString. The caller must ensure that
184    /// the `VALUE` is a valid pointer to an RString.
185    unsafe fn rstring_interned_p(&self, obj: VALUE) -> bool;
186
187    /// Blocks the current thread until the given duration has passed.
188    fn thread_sleep(&self, duration: Duration);
189}
190
191#[cfg(stable_api_enable_compiled_mod)]
192mod compiled;
193#[cfg(stable_api_export_compiled_as_api)]
194use compiled as api;
195
196#[cfg(stable_api_include_rust_impl)]
197#[cfg_attr(ruby_eq_2_6, path = "stable_api/ruby_2_6.rs")]
198#[cfg_attr(ruby_eq_2_7, path = "stable_api/ruby_2_7.rs")]
199#[cfg_attr(ruby_eq_3_0, path = "stable_api/ruby_3_0.rs")]
200#[cfg_attr(ruby_eq_3_1, path = "stable_api/ruby_3_1.rs")]
201#[cfg_attr(ruby_eq_3_2, path = "stable_api/ruby_3_2.rs")]
202#[cfg_attr(ruby_eq_3_3, path = "stable_api/ruby_3_3.rs")]
203#[cfg_attr(ruby_eq_3_4, path = "stable_api/ruby_3_4.rs")]
204mod rust;
205#[cfg(not(stable_api_export_compiled_as_api))]
206use rust as api;
207
208impl std::fmt::Debug for api::Definition {
209    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
210        f.debug_struct("StableApiDefinition")
211            .field("VERSION_MAJOR", &api::Definition::VERSION_MAJOR)
212            .field("VERSION_MINOR", &api::Definition::VERSION_MINOR)
213            .finish()
214    }
215}
216
217/// Get the default stable API definition for the current Ruby version.
218pub const fn get_default() -> &'static api::Definition {
219    const API: api::Definition = api::Definition {};
220    &API
221}
222
223/// Get the fallback stable API definition for the current Ruby version, which
224/// is compiled C code that is linked into to this crate.
225#[cfg(stable_api_enable_compiled_mod)]
226pub const fn get_compiled() -> &'static compiled::Definition {
227    const COMPILED_API: compiled::Definition = compiled::Definition {};
228    &COMPILED_API
229}