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}