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    /// Checks if the given object is an RTypedData.
191    ///
192    /// # Safety
193    /// This function is unsafe because it dereferences a raw pointer to get
194    /// access to underlying Ruby data. The caller must ensure that the pointer
195    /// is valid and points to a T_DATA object.
196    unsafe fn rtypeddata_p(&self, obj: VALUE) -> bool;
197
198    /// Checks if the given RTypedData is embedded.
199    ///
200    /// # Safety
201    /// This function is unsafe because it dereferences a raw pointer to get
202    /// access to underlying Ruby data. The caller must ensure that the pointer
203    /// is valid and points to an RTypedData object.
204    unsafe fn rtypeddata_embedded_p(&self, obj: VALUE) -> bool;
205
206    /// Gets the data type from an RTypedData object.
207    ///
208    /// # Safety
209    /// This function is unsafe because it dereferences a raw pointer to get
210    /// access to underlying Ruby data. The caller must ensure that the pointer
211    /// is valid and points to an RTypedData object.
212    unsafe fn rtypeddata_type(&self, obj: VALUE) -> *const crate::rb_data_type_t;
213
214    /// Gets the data pointer from an RTypedData object.
215    ///
216    /// # Safety
217    /// This function is unsafe because it dereferences a raw pointer to get
218    /// access to underlying Ruby data. The caller must ensure that the pointer
219    /// is valid and points to an RTypedData object.
220    unsafe fn rtypeddata_get_data(&self, obj: VALUE) -> *mut std::ffi::c_void;
221}
222
223#[cfg(stable_api_enable_compiled_mod)]
224mod compiled;
225#[cfg(stable_api_export_compiled_as_api)]
226use compiled as api;
227
228#[cfg(stable_api_include_rust_impl)]
229#[cfg_attr(ruby_eq_2_7, path = "stable_api/ruby_2_7.rs")]
230#[cfg_attr(ruby_eq_3_0, path = "stable_api/ruby_3_0.rs")]
231#[cfg_attr(ruby_eq_3_1, path = "stable_api/ruby_3_1.rs")]
232#[cfg_attr(ruby_eq_3_2, path = "stable_api/ruby_3_2.rs")]
233#[cfg_attr(ruby_eq_3_3, path = "stable_api/ruby_3_3.rs")]
234#[cfg_attr(ruby_eq_3_4, path = "stable_api/ruby_3_4.rs")]
235mod rust;
236#[cfg(not(stable_api_export_compiled_as_api))]
237use rust as api;
238
239impl std::fmt::Debug for api::Definition {
240    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
241        f.debug_struct("StableApiDefinition")
242            .field("VERSION_MAJOR", &api::Definition::VERSION_MAJOR)
243            .field("VERSION_MINOR", &api::Definition::VERSION_MINOR)
244            .finish()
245    }
246}
247
248/// Get the default stable API definition for the current Ruby version.
249pub const fn get_default() -> &'static api::Definition {
250    const API: api::Definition = api::Definition {};
251    &API
252}
253
254/// Get the fallback stable API definition for the current Ruby version, which
255/// is compiled C code that is linked into to this crate.
256#[cfg(stable_api_enable_compiled_mod)]
257pub const fn get_compiled() -> &'static compiled::Definition {
258    const COMPILED_API: compiled::Definition = compiled::Definition {};
259    &COMPILED_API
260}