Skip to main content

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/// Gets the data type information from an RTypedData object.
305///
306/// @param[in]  obj    An RTypedData object.
307/// @return     Pointer to the rb_data_type_t structure for this object.
308///
309/// # Safety
310/// This function is unsafe because it dereferences a raw pointer to get
311/// access to the underlying data type. The caller must ensure the object
312/// is a valid RTypedData.
313#[inline(always)]
314pub unsafe fn RTYPEDDATA_TYPE(obj: VALUE) -> *const rb_data_type_t {
315    api().rtypeddata_type(obj)
316}
317
318/// Gets the data pointer from an RTypedData object.
319///
320/// @param[in]  obj    An RTypedData object.
321/// @return     Pointer to the wrapped C struct.
322///
323/// # Safety
324/// This function is unsafe because it dereferences a raw pointer to get
325/// access to the underlying data. The caller must ensure the object
326/// is a valid RTypedData.
327#[inline(always)]
328pub unsafe fn RTYPEDDATA_GET_DATA(obj: VALUE) -> *mut c_void {
329    api().rtypeddata_get_data(obj)
330}
331
332/// Checks if the bignum is positive.
333///
334/// @param[in]  b      An object of RBignum.
335/// @retval     false  `b` is less than zero.
336/// @retval     true   Otherwise.
337///
338/// # Safety
339/// This function is unsafe because it could dereference a raw pointer when
340/// accessing the underlying bignum structure.
341#[inline(always)]
342pub unsafe fn RBIGNUM_POSITIVE_P(b: VALUE) -> bool {
343    api().bignum_positive_p(b)
344}
345
346/// Checks if the bignum is negative.
347///
348/// @param[in]  b      An object of RBignum.
349/// @retval     true   `b` is less than zero.
350/// @retval     false  Otherwise.
351///
352/// # Safety
353/// This function is unsafe because it could dereference a raw pointer when
354/// accessing the underlying bignum structure.
355#[inline(always)]
356pub unsafe fn RBIGNUM_NEGATIVE_P(b: VALUE) -> bool {
357    api().bignum_negative_p(b)
358}
359
360/// Convert ID to Symbol (akin to `ID2SYM` or `RB_ID2SYM`).
361///
362/// Converts an internal ID to its corresponding Symbol VALUE.
363/// This is a safe operation - just bit manipulation for static symbols.
364///
365/// @param[in]  id     An ID value.
366/// @return     The Symbol VALUE corresponding to the ID.
367#[inline(always)]
368pub fn ID2SYM(id: crate::ID) -> VALUE {
369    api().id2sym(id)
370}
371
372/// Alias for ID2SYM for compatibility with Ruby naming conventions.
373#[inline(always)]
374pub fn RB_ID2SYM(id: crate::ID) -> VALUE {
375    api().id2sym(id)
376}
377
378/// Convert Symbol to ID (akin to `SYM2ID` or `RB_SYM2ID`).
379///
380/// Converts a Symbol VALUE to its internal ID representation.
381///
382/// @param[in]  obj    A Symbol VALUE.
383/// @return     The ID corresponding to the Symbol.
384///
385/// # Safety
386/// - `obj` must be a valid Symbol VALUE
387/// - For dynamic symbols, this may access the heap
388#[inline(always)]
389pub unsafe fn SYM2ID(obj: VALUE) -> crate::ID {
390    api().sym2id(obj)
391}
392
393/// Alias for SYM2ID for compatibility with Ruby naming conventions.
394///
395/// # Safety
396/// - `obj` must be a valid Symbol VALUE
397/// - For dynamic symbols, this may access the heap
398#[inline(always)]
399pub unsafe fn RB_SYM2ID(obj: VALUE) -> crate::ID {
400    api().sym2id(obj)
401}
402
403/// Convert Fixnum to long (akin to `FIX2LONG`).
404///
405/// Extracts the integer value from a Fixnum VALUE by performing an arithmetic right shift.
406///
407/// # Safety
408/// - `obj` must be a valid Fixnum VALUE (checked with FIXNUM_P)
409/// - Behavior is undefined if called on non-Fixnum values
410#[inline(always)]
411pub unsafe fn FIX2LONG(obj: VALUE) -> std::os::raw::c_long {
412    api().fix2long(obj)
413}
414
415/// Convert Fixnum to unsigned long (akin to `FIX2ULONG`).
416///
417/// Extracts the unsigned integer value from a Fixnum VALUE.
418///
419/// # Safety
420/// - `obj` must be a valid positive Fixnum VALUE
421/// - Behavior is undefined for negative fixnums
422#[inline(always)]
423pub unsafe fn FIX2ULONG(obj: VALUE) -> std::os::raw::c_ulong {
424    api().fix2ulong(obj)
425}
426
427/// Convert long to Fixnum (akin to `LONG2FIX`).
428///
429/// Creates a Fixnum VALUE from a long integer.
430///
431/// # Safety
432/// - `val` must be within the valid Fixnum range (use FIXABLE to check)
433/// - Behavior is undefined if value is out of range
434#[inline(always)]
435pub unsafe fn LONG2FIX(val: std::os::raw::c_long) -> VALUE {
436    api().long2fix(val)
437}
438
439/// Check if long value can be represented as Fixnum (akin to `FIXABLE`).
440///
441/// Returns true if the value fits within the Fixnum range.
442#[inline(always)]
443pub fn FIXABLE(val: std::os::raw::c_long) -> bool {
444    api().fixable(val)
445}
446
447/// Check if unsigned long value can be represented as positive Fixnum (akin to `POSFIXABLE`).
448///
449/// Returns true if the unsigned value fits within the positive Fixnum range.
450#[inline(always)]
451pub fn POSFIXABLE(val: std::os::raw::c_ulong) -> bool {
452    api().posfixable(val)
453}
454
455/// Convert Ruby Integer to long (akin to `NUM2LONG`).
456///
457/// Converts any Ruby Integer (Fixnum or Bignum) to a C long.
458/// May raise a RangeError exception if the value is out of range.
459///
460/// # Safety
461/// - `obj` must be a valid Integer VALUE
462/// - May call into Ruby runtime and potentially raise exceptions
463/// - May trigger garbage collection
464#[inline(always)]
465pub unsafe fn NUM2LONG(obj: VALUE) -> std::os::raw::c_long {
466    api().num2long(obj)
467}
468
469/// Convert Ruby Integer to unsigned long (akin to `NUM2ULONG`).
470///
471/// Converts any Ruby Integer (Fixnum or Bignum) to a C unsigned long.
472/// May raise a RangeError exception if the value is out of range or negative.
473///
474/// # Safety
475/// - `obj` must be a valid Integer VALUE
476/// - May call into Ruby runtime and potentially raise exceptions
477/// - May trigger garbage collection
478#[inline(always)]
479pub unsafe fn NUM2ULONG(obj: VALUE) -> std::os::raw::c_ulong {
480    api().num2ulong(obj)
481}
482
483/// Convert long to Ruby Integer (akin to `LONG2NUM`).
484///
485/// Creates a Ruby Integer (Fixnum or Bignum) from a C long.
486/// Uses Fixnum if possible, otherwise allocates a Bignum.
487#[inline(always)]
488pub fn LONG2NUM(val: std::os::raw::c_long) -> VALUE {
489    api().long2num(val)
490}
491
492/// Convert unsigned long to Ruby Integer (akin to `ULONG2NUM`).
493///
494/// Creates a Ruby Integer (Fixnum or Bignum) from a C unsigned long.
495/// Uses Fixnum if possible, otherwise allocates a Bignum.
496#[inline(always)]
497pub fn ULONG2NUM(val: std::os::raw::c_ulong) -> VALUE {
498    api().ulong2num(val)
499}