rb_sys/macros.rs
1//! Implementation of Ruby macros.
2//!
3//! Since macros are rely on the C preprocessor, or defined as `inline` C
4//! functions, they are not available when linking libruby. In order to use the
5//! libruby macros from Rust, `rb-sys` implements them using the following
6//! strategies:
7//!
8//! 1. For stable versions of Ruby, the macros are implemented as Rust functions
9//! 2. For ruby-head, the macros are implemented as C functions that are linked
10//! into the crate.
11
12#![allow(rustdoc::broken_intra_doc_links)]
13#![allow(non_upper_case_globals)]
14#![allow(non_snake_case)]
15
16use crate::rb_data_type_t;
17use crate::ruby_value_type;
18use crate::stable_api::get_default as api;
19use crate::StableApiDefinition;
20use crate::VALUE;
21use std::ffi::c_void;
22use std::os::raw::{c_char, c_long};
23
24/// Emulates Ruby's "if" statement.
25///
26/// - @param[in] obj An arbitrary ruby object.
27/// - @retval false `obj` is either ::RUBY_Qfalse or ::RUBY_Qnil.
28/// - @retval true Anything else.
29///
30/// ```
31/// use rb_sys::special_consts::*;
32///
33/// assert!(!TEST(Qfalse));
34/// assert!(!TEST(Qnil));
35/// assert!(TEST(Qtrue));
36/// ```
37#[inline(always)]
38pub fn TEST(obj: VALUE) -> bool {
39 api().rb_test(obj)
40}
41
42/// Checks if the given object is nil.
43///
44/// - @param[in] obj An arbitrary ruby object.
45/// - @retval true `obj` is ::RUBY_Qnil.
46/// - @retval false Anything else.
47///
48/// ### Example
49///
50/// ```
51/// use rb_sys::special_consts::*;
52///
53/// assert!(NIL_P(Qnil));
54/// assert!(!NIL_P(Qtrue));
55/// ```
56#[inline(always)]
57pub fn NIL_P(obj: VALUE) -> bool {
58 api().nil_p(obj)
59}
60
61/// Checks if the given object is a so-called Fixnum.
62///
63/// - @param[in] obj An arbitrary ruby object.
64/// - @retval true `obj` is a Fixnum.
65/// - @retval false Anything else.
66/// - @note Fixnum was a thing in the 20th century, but it is rather an implementation detail today.
67#[inline(always)]
68pub fn FIXNUM_P(obj: VALUE) -> bool {
69 api().fixnum_p(obj)
70}
71
72/// Checks if the given object is a static symbol.
73///
74/// - @param[in] obj An arbitrary ruby object.
75/// - @retval true `obj` is a static symbol
76/// - @retval false Anything else.
77/// - @see RB_DYNAMIC_SYM_P()
78/// - @see RB_SYMBOL_P()
79/// - @note These days there are static and dynamic symbols, just like we once had Fixnum/Bignum back in the old days.
80#[inline(always)]
81pub fn STATIC_SYM_P(obj: VALUE) -> bool {
82 api().static_sym_p(obj)
83}
84
85/// Get the backend storage of a Ruby array.
86///
87/// ### Safety
88///
89/// This function is unsafe because it dereferences a raw pointer and returns
90/// raw pointers to Ruby memory. The caller must ensure that the pointer stays live
91/// for the duration of usage the the underlying array (by either GC marking or
92/// keeping the RArray on the stack).
93///
94/// - @param[in] a An object of ::RArray.
95/// - @return Its backend storage.
96#[inline(always)]
97pub unsafe fn RARRAY_CONST_PTR(obj: VALUE) -> *const VALUE {
98 api().rarray_const_ptr(obj)
99}
100
101/// Get the length of a Ruby array.
102///
103/// ### Safety
104///
105/// This function is unsafe because it dereferences a raw pointer in order to
106/// access internal Ruby memory.
107///
108/// - @param[in] a An object of ::RArray.
109/// - @return Its length.
110#[inline(always)]
111pub unsafe fn RARRAY_LEN(obj: VALUE) -> c_long {
112 api().rarray_len(obj)
113}
114
115/// Get the length of a Ruby string.
116///
117/// ### Safety
118///
119/// This function is unsafe because it dereferences a raw pointer in order to
120/// access internal Ruby memory.
121///
122/// - @param[in] a An object of ::RString.
123/// - @return Its length.
124#[inline(always)]
125pub unsafe fn RSTRING_LEN(obj: VALUE) -> c_long {
126 api().rstring_len(obj)
127}
128
129/// Get the backend storage of a Ruby string.
130///
131/// ### Safety
132///
133/// This function is unsafe because it dereferences a raw pointer and returns
134/// raw pointers to Ruby memory. The caller must ensure that the pointer stays live
135/// for the duration of usage the the underlying array (by either GC marking or
136/// keeping the RArray on the stack).
137///
138/// - @param[in] a An object of ::RString.
139/// - @return Its backend storage
140#[inline(always)]
141pub unsafe fn RSTRING_PTR(obj: VALUE) -> *const c_char {
142 api().rstring_ptr(obj)
143}
144
145/// Checks if the given object is a so-called Flonum.
146///
147/// @param[in] obj An arbitrary ruby object.
148/// @retval true `obj` is a Flonum.
149/// @retval false Anything else.
150/// @see RB_FLOAT_TYPE_P()
151/// @note These days there are Flonums and non-Flonum floats, just like we
152/// once had Fixnum/Bignum back in the old days.
153#[inline(always)]
154pub fn FLONUM_P(obj: VALUE) -> bool {
155 api().flonum_p(obj)
156}
157
158/// Checks if the given object is an immediate i.e. an object which has no
159/// corresponding storage inside of the object space.
160///
161/// @param[in] obj An arbitrary ruby object.
162/// @retval true `obj` is a Flonum.
163/// @retval false Anything else.
164/// @see RB_FLOAT_TYPE_P()
165/// @note The concept of "immediate" is purely C specific.
166#[inline(always)]
167pub fn IMMEDIATE_P(obj: VALUE) -> bool {
168 api().immediate_p(obj)
169}
170
171/// Checks if the given object is of enum ::ruby_special_consts.
172///
173/// @param[in] obj An arbitrary ruby object.
174/// @retval true `obj` is a special constant.
175/// @retval false Anything else.
176///
177/// ### Example
178///
179/// ```
180/// use rb_sys::special_consts::*;
181///
182/// assert!(SPECIAL_CONST_P(Qnil));
183/// assert!(SPECIAL_CONST_P(Qtrue));
184/// assert!(SPECIAL_CONST_P(Qfalse));
185/// ```
186#[inline(always)]
187pub fn SPECIAL_CONST_P(obj: VALUE) -> bool {
188 api().special_const_p(obj)
189}
190
191/// Queries the type of the object.
192///
193/// @param[in] obj Object in question.
194/// @pre `obj` must not be a special constant.
195/// @return The type of `obj`.
196///
197/// # Safety
198/// This function is unsafe because it could dereference a raw pointer when
199/// attemping to access the underlying [`RBasic`] struct.
200#[inline(always)]
201pub unsafe fn RB_BUILTIN_TYPE(obj: VALUE) -> ruby_value_type {
202 api().builtin_type(obj)
203}
204
205/// Queries if the object is an instance of ::rb_cInteger.
206///
207/// @param[in] obj Object in question.
208/// @retval true It is.
209/// @retval false It isn't.
210///
211/// # Safety
212/// This function is unsafe because it could dereference a raw pointer when
213/// attemping to access the underlying [`RBasic`] struct.
214#[inline(always)]
215pub unsafe fn RB_INTEGER_TYPE_P(obj: VALUE) -> bool {
216 api().integer_type_p(obj)
217}
218
219/// Queries if the object is a dynamic symbol.
220///
221/// @param[in] obj Object in question.
222/// @retval true It is.
223/// @retval false It isn't.
224///
225/// # Safety
226/// This function is unsafe because it could dereference a raw pointer when
227/// attemping to access the underlying [`RBasic`] struct.
228#[inline(always)]
229pub unsafe fn RB_DYNAMIC_SYM_P(obj: VALUE) -> bool {
230 api().dynamic_sym_p(obj)
231}
232
233/// Queries if the object is an instance of ::rb_cSymbol.
234///
235/// @param[in] obj Object in question.
236/// @retval true It is.
237/// @retval false It isn't.
238///
239/// # Safety
240/// This function is unsafe because it could dereference a raw pointer when
241/// attemping to access the underlying [`RBasic`] struct.
242#[inline(always)]
243pub unsafe fn RB_SYMBOL_P(obj: VALUE) -> bool {
244 api().symbol_p(obj)
245}
246
247/// Identical to RB_BUILTIN_TYPE(), except it can also accept special constants.
248///
249/// @param[in] obj Object in question.
250/// @return The type of `obj`.
251///
252/// # Safety
253/// This function is unsafe because it could dereference a raw pointer when
254/// attemping to access the underlying [`RBasic`] struct.
255#[inline(always)]
256pub unsafe fn RB_TYPE(value: VALUE) -> ruby_value_type {
257 api().rb_type(value)
258}
259
260/// Queries if the given object is of given type.
261///
262/// @param[in] obj An object.
263/// @param[in] t A type.
264/// @retval true `obj` is of type `t`.
265/// @retval false Otherwise.
266///
267/// # Safety
268/// This function is unsafe because it could dereference a raw pointer when
269/// attemping to access the underlying [`RBasic`] struct.
270#[inline(always)]
271#[cfg(ruby_engine = "mri")] // truffleruby provides its own implementation
272pub unsafe fn RB_TYPE_P(obj: VALUE, ty: ruby_value_type) -> bool {
273 api().type_p(obj, ty)
274}
275
276/// Queries if the object is an instance of ::rb_cFloat.
277///
278/// @param[in] obj Object in question.
279/// @retval true It is.
280/// @retval false It isn't.
281///
282/// # Safety
283/// This function is unsafe because it could dereference a raw pointer when
284/// attemping to access the underlying [`RBasic`] struct.
285#[inline(always)]
286pub unsafe fn RB_FLOAT_TYPE_P(obj: VALUE) -> bool {
287 api().float_type_p(obj)
288}
289
290/// Checks if the given object is an RTypedData.
291///
292/// @param[in] obj Object in question.
293/// @retval true It is an RTypedData.
294/// @retval false It isn't an RTypedData.
295///
296/// # Safety
297/// This function is unsafe because it could dereference a raw pointer when
298/// accessing the underlying data structure.
299#[inline(always)]
300pub unsafe fn RTYPEDDATA_P(obj: VALUE) -> bool {
301 api().rtypeddata_p(obj)
302}
303
304/// Checks if the given RTypedData is embedded.
305///
306/// @param[in] obj An RTypedData object.
307/// @retval true The data is embedded in the object itself.
308/// @retval false The data is stored separately.
309///
310/// # Safety
311/// This function is unsafe because it could dereference a raw pointer when
312/// accessing the underlying data structure. The caller must ensure the object
313/// is a valid RTypedData.
314#[inline(always)]
315pub unsafe fn RTYPEDDATA_EMBEDDED_P(obj: VALUE) -> bool {
316 api().rtypeddata_embedded_p(obj)
317}
318
319/// Gets the data type information from an RTypedData object.
320///
321/// @param[in] obj An RTypedData object.
322/// @return Pointer to the rb_data_type_t structure for this object.
323///
324/// # Safety
325/// This function is unsafe because it dereferences a raw pointer to get
326/// access to the underlying data type. The caller must ensure the object
327/// is a valid RTypedData.
328#[inline(always)]
329pub unsafe fn RTYPEDDATA_TYPE(obj: VALUE) -> *const rb_data_type_t {
330 api().rtypeddata_type(obj)
331}
332
333/// Gets the data pointer from an RTypedData object.
334///
335/// @param[in] obj An RTypedData object.
336/// @return Pointer to the wrapped C struct.
337///
338/// # Safety
339/// This function is unsafe because it dereferences a raw pointer to get
340/// access to the underlying data. The caller must ensure the object
341/// is a valid RTypedData.
342#[inline(always)]
343pub unsafe fn RTYPEDDATA_GET_DATA(obj: VALUE) -> *mut c_void {
344 api().rtypeddata_get_data(obj)
345}
346
347/// Checks if the bignum is positive.
348///
349/// @param[in] b An object of RBignum.
350/// @retval false `b` is less than zero.
351/// @retval true Otherwise.
352///
353/// # Safety
354/// This function is unsafe because it could dereference a raw pointer when
355/// accessing the underlying bignum structure.
356#[inline(always)]
357pub unsafe fn RBIGNUM_POSITIVE_P(b: VALUE) -> bool {
358 api().bignum_positive_p(b)
359}
360
361/// Checks if the bignum is negative.
362///
363/// @param[in] b An object of RBignum.
364/// @retval true `b` is less than zero.
365/// @retval false Otherwise.
366///
367/// # Safety
368/// This function is unsafe because it could dereference a raw pointer when
369/// accessing the underlying bignum structure.
370#[inline(always)]
371pub unsafe fn RBIGNUM_NEGATIVE_P(b: VALUE) -> bool {
372 api().bignum_negative_p(b)
373}
374
375/// Convert ID to Symbol (akin to `ID2SYM` or `RB_ID2SYM`).
376///
377/// Converts an internal ID to its corresponding Symbol VALUE.
378/// This is a safe operation - just bit manipulation for static symbols.
379///
380/// @param[in] id An ID value.
381/// @return The Symbol VALUE corresponding to the ID.
382#[inline(always)]
383pub fn ID2SYM(id: crate::ID) -> VALUE {
384 api().id2sym(id)
385}
386
387/// Alias for ID2SYM for compatibility with Ruby naming conventions.
388#[inline(always)]
389pub fn RB_ID2SYM(id: crate::ID) -> VALUE {
390 api().id2sym(id)
391}
392
393/// Convert Symbol to ID (akin to `SYM2ID` or `RB_SYM2ID`).
394///
395/// Converts a Symbol VALUE to its internal ID representation.
396///
397/// @param[in] obj A Symbol VALUE.
398/// @return The ID corresponding to the Symbol.
399///
400/// # Safety
401/// - `obj` must be a valid Symbol VALUE
402/// - For dynamic symbols, this may access the heap
403#[inline(always)]
404pub unsafe fn SYM2ID(obj: VALUE) -> crate::ID {
405 api().sym2id(obj)
406}
407
408/// Alias for SYM2ID for compatibility with Ruby naming conventions.
409///
410/// # Safety
411/// - `obj` must be a valid Symbol VALUE
412/// - For dynamic symbols, this may access the heap
413#[inline(always)]
414pub unsafe fn RB_SYM2ID(obj: VALUE) -> crate::ID {
415 api().sym2id(obj)
416}
417
418/// Convert Fixnum to long (akin to `FIX2LONG`).
419///
420/// Extracts the integer value from a Fixnum VALUE by performing an arithmetic right shift.
421///
422/// # Safety
423/// - `obj` must be a valid Fixnum VALUE (checked with FIXNUM_P)
424/// - Behavior is undefined if called on non-Fixnum values
425#[inline(always)]
426pub unsafe fn FIX2LONG(obj: VALUE) -> std::os::raw::c_long {
427 api().fix2long(obj)
428}
429
430/// Convert Fixnum to unsigned long (akin to `FIX2ULONG`).
431///
432/// Extracts the unsigned integer value from a Fixnum VALUE.
433///
434/// # Safety
435/// - `obj` must be a valid positive Fixnum VALUE
436/// - Behavior is undefined for negative fixnums
437#[inline(always)]
438pub unsafe fn FIX2ULONG(obj: VALUE) -> std::os::raw::c_ulong {
439 api().fix2ulong(obj)
440}
441
442/// Convert long to Fixnum (akin to `LONG2FIX`).
443///
444/// Creates a Fixnum VALUE from a long integer.
445///
446/// # Safety
447/// - `val` must be within the valid Fixnum range (use FIXABLE to check)
448/// - Behavior is undefined if value is out of range
449#[inline(always)]
450pub unsafe fn LONG2FIX(val: std::os::raw::c_long) -> VALUE {
451 api().long2fix(val)
452}
453
454/// Check if long value can be represented as Fixnum (akin to `FIXABLE`).
455///
456/// Returns true if the value fits within the Fixnum range.
457#[inline(always)]
458pub fn FIXABLE(val: std::os::raw::c_long) -> bool {
459 api().fixable(val)
460}
461
462/// Check if unsigned long value can be represented as positive Fixnum (akin to `POSFIXABLE`).
463///
464/// Returns true if the unsigned value fits within the positive Fixnum range.
465#[inline(always)]
466pub fn POSFIXABLE(val: std::os::raw::c_ulong) -> bool {
467 api().posfixable(val)
468}
469
470/// Convert Ruby Integer to long (akin to `NUM2LONG`).
471///
472/// Converts any Ruby Integer (Fixnum or Bignum) to a C long.
473/// May raise a RangeError exception if the value is out of range.
474///
475/// # Safety
476/// - `obj` must be a valid Integer VALUE
477/// - May call into Ruby runtime and potentially raise exceptions
478/// - May trigger garbage collection
479#[inline(always)]
480pub unsafe fn NUM2LONG(obj: VALUE) -> std::os::raw::c_long {
481 api().num2long(obj)
482}
483
484/// Convert Ruby Integer to unsigned long (akin to `NUM2ULONG`).
485///
486/// Converts any Ruby Integer (Fixnum or Bignum) to a C unsigned long.
487/// May raise a RangeError exception if the value is out of range or negative.
488///
489/// # Safety
490/// - `obj` must be a valid Integer VALUE
491/// - May call into Ruby runtime and potentially raise exceptions
492/// - May trigger garbage collection
493#[inline(always)]
494pub unsafe fn NUM2ULONG(obj: VALUE) -> std::os::raw::c_ulong {
495 api().num2ulong(obj)
496}
497
498/// Convert long to Ruby Integer (akin to `LONG2NUM`).
499///
500/// Creates a Ruby Integer (Fixnum or Bignum) from a C long.
501/// Uses Fixnum if possible, otherwise allocates a Bignum.
502#[inline(always)]
503pub fn LONG2NUM(val: std::os::raw::c_long) -> VALUE {
504 api().long2num(val)
505}
506
507/// Convert unsigned long to Ruby Integer (akin to `ULONG2NUM`).
508///
509/// Creates a Ruby Integer (Fixnum or Bignum) from a C unsigned long.
510/// Uses Fixnum if possible, otherwise allocates a Bignum.
511#[inline(always)]
512pub fn ULONG2NUM(val: std::os::raw::c_ulong) -> VALUE {
513 api().ulong2num(val)
514}