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.into())
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.into())
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.into())
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.into())
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.into())
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.into())
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.into())
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.
135///
136/// - @param[in]  a  An object of ::RString.
137/// - @return     Its backend storage
138#[inline(always)]
139pub unsafe fn RSTRING_PTR(obj: VALUE) -> *const c_char {
140    api().rstring_ptr(obj.into())
141}
142
143/// Checks if the given object is a so-called Flonum.
144///
145/// @param[in]  obj    An arbitrary ruby object.
146/// @retval     true   `obj` is a Flonum.
147/// @retval     false  Anything else.
148/// @see        RB_FLOAT_TYPE_P()
149/// @note       These days there are Flonums and non-Flonum floats, just like we
150///             once had Fixnum/Bignum back in the old days.
151#[inline(always)]
152pub fn FLONUM_P(obj: VALUE) -> bool {
153    api().flonum_p(obj.into())
154}
155
156/// Checks if  the given  object is  an immediate  i.e. an  object which  has no
157/// corresponding storage inside of the object space.
158///
159/// @param[in]  obj    An arbitrary ruby object.
160/// @retval     true   `obj` is a Flonum.
161/// @retval     false  Anything else.
162/// @see        RB_FLOAT_TYPE_P()
163/// @note       The concept of "immediate" is purely C specific.
164#[inline(always)]
165pub fn IMMEDIATE_P(obj: VALUE) -> bool {
166    api().immediate_p(obj.into())
167}
168
169/// Checks if the given object is of enum ::ruby_special_consts.
170///
171/// @param[in]  obj    An arbitrary ruby object.
172/// @retval     true   `obj` is a special constant.
173/// @retval     false  Anything else.
174///
175/// ### Example
176///
177/// ```
178/// use rb_sys::special_consts::*;
179///
180/// assert!(SPECIAL_CONST_P(Qnil));
181/// assert!(SPECIAL_CONST_P(Qtrue));
182/// assert!(SPECIAL_CONST_P(Qfalse));
183/// ```
184#[inline(always)]
185pub fn SPECIAL_CONST_P(obj: VALUE) -> bool {
186    api().special_const_p(obj.into())
187}
188
189/// Queries the type of the object.
190///
191/// @param[in]  obj  Object in question.
192/// @pre        `obj` must not be a special constant.
193/// @return     The type of `obj`.
194///
195/// # Safety
196/// This function is unsafe because it could dereference a raw pointer when
197/// attemping to access the underlying [`RBasic`] struct.
198#[inline(always)]
199pub unsafe fn RB_BUILTIN_TYPE(obj: VALUE) -> ruby_value_type {
200    api().builtin_type(obj)
201}
202
203/// Queries if the object is an instance of ::rb_cInteger.
204///
205/// @param[in]  obj    Object in question.
206/// @retval     true   It is.
207/// @retval     false  It isn't.
208///
209/// # Safety
210/// This function is unsafe because it could dereference a raw pointer when
211/// attemping to access the underlying [`RBasic`] struct.
212#[inline(always)]
213pub unsafe fn RB_INTEGER_TYPE_P(obj: VALUE) -> bool {
214    api().integer_type_p(obj)
215}
216
217/// Queries if the object is a dynamic symbol.
218///
219/// @param[in]  obj    Object in question.
220/// @retval     true   It is.
221/// @retval     false  It isn't.
222///
223/// # Safety
224/// This function is unsafe because it could dereference a raw pointer when
225/// attemping to access the underlying [`RBasic`] struct.
226#[inline(always)]
227pub unsafe fn RB_DYNAMIC_SYM_P(obj: VALUE) -> bool {
228    api().dynamic_sym_p(obj)
229}
230
231/// Queries if the object is an instance of ::rb_cSymbol.
232///
233/// @param[in]  obj    Object in question.
234/// @retval     true   It is.
235/// @retval     false  It isn't.
236///
237/// # Safety
238/// This function is unsafe because it could dereference a raw pointer when
239/// attemping to access the underlying [`RBasic`] struct.
240#[inline(always)]
241pub unsafe fn RB_SYMBOL_P(obj: VALUE) -> bool {
242    api().symbol_p(obj)
243}
244
245/// Identical to RB_BUILTIN_TYPE(), except it can also accept special constants.
246///
247/// @param[in]  obj  Object in question.
248/// @return     The type of `obj`.
249///
250/// # Safety
251/// This function is unsafe because it could dereference a raw pointer when
252/// attemping to access the underlying [`RBasic`] struct.
253#[inline(always)]
254pub unsafe fn RB_TYPE(value: VALUE) -> ruby_value_type {
255    api().rb_type(value)
256}
257
258/// Queries if the given object is of given type.
259///
260/// @param[in]  obj    An object.
261/// @param[in]  t      A type.
262/// @retval     true   `obj` is of type `t`.
263/// @retval     false  Otherwise.
264///
265/// # Safety
266/// This function is unsafe because it could dereference a raw pointer when
267/// attemping to access the underlying [`RBasic`] struct.
268#[inline(always)]
269#[cfg(ruby_engine = "mri")] // truffleruby provides its own implementation
270pub unsafe fn RB_TYPE_P(obj: VALUE, ty: ruby_value_type) -> bool {
271    api().type_p(obj, ty)
272}
273
274/// Queries if the object is an instance of ::rb_cFloat.
275///
276/// @param[in]  obj    Object in question.
277/// @retval     true   It is.
278/// @retval     false  It isn't.
279///
280/// # Safety
281/// This function is unsafe because it could dereference a raw pointer when
282/// attemping to access the underlying [`RBasic`] struct.
283#[inline(always)]
284pub unsafe fn RB_FLOAT_TYPE_P(obj: VALUE) -> bool {
285    api().float_type_p(obj)
286}
287
288/// Checks if the given object is an RTypedData.
289///
290/// @param[in]  obj    Object in question.
291/// @retval     true   It is an RTypedData.
292/// @retval     false  It isn't an RTypedData.
293///
294/// # Safety
295/// This function is unsafe because it could dereference a raw pointer when
296/// accessing the underlying data structure.
297#[inline(always)]
298pub unsafe fn RTYPEDDATA_P(obj: VALUE) -> bool {
299    api().rtypeddata_p(obj)
300}
301
302/// Checks if the given RTypedData is embedded.
303///
304/// @param[in]  obj    An RTypedData object.
305/// @retval     true   The data is embedded in the object itself.
306/// @retval     false  The data is stored separately.
307///
308/// # Safety
309/// This function is unsafe because it could dereference a raw pointer when
310/// accessing the underlying data structure. The caller must ensure the object
311/// is a valid RTypedData.
312#[inline(always)]
313pub unsafe fn RTYPEDDATA_EMBEDDED_P(obj: VALUE) -> bool {
314    api().rtypeddata_embedded_p(obj)
315}
316
317/// Gets the data type information from an RTypedData object.
318///
319/// @param[in]  obj    An RTypedData object.
320/// @return     Pointer to the rb_data_type_t structure for this object.
321///
322/// # Safety
323/// This function is unsafe because it dereferences a raw pointer to get
324/// access to the underlying data type. The caller must ensure the object
325/// is a valid RTypedData.
326#[inline(always)]
327pub unsafe fn RTYPEDDATA_TYPE(obj: VALUE) -> *const rb_data_type_t {
328    api().rtypeddata_type(obj)
329}
330
331/// Gets the data pointer from an RTypedData object.
332///
333/// @param[in]  obj    An RTypedData object.
334/// @return     Pointer to the wrapped C struct.
335///
336/// # Safety
337/// This function is unsafe because it dereferences a raw pointer to get
338/// access to the underlying data. The caller must ensure the object
339/// is a valid RTypedData.
340#[inline(always)]
341pub unsafe fn RTYPEDDATA_GET_DATA(obj: VALUE) -> *mut c_void {
342    api().rtypeddata_get_data(obj)
343}
344
345/// Checks if the bignum is positive.
346///
347/// @param[in]  b      An object of RBignum.
348/// @retval     false  `b` is less than zero.
349/// @retval     true   Otherwise.
350///
351/// # Safety
352/// This function is unsafe because it could dereference a raw pointer when
353/// accessing the underlying bignum structure.
354#[inline(always)]
355pub unsafe fn RBIGNUM_POSITIVE_P(b: VALUE) -> bool {
356    api().bignum_positive_p(b)
357}
358
359/// Checks if the bignum is negative.
360///
361/// @param[in]  b      An object of RBignum.
362/// @retval     true   `b` is less than zero.
363/// @retval     false  Otherwise.
364///
365/// # Safety
366/// This function is unsafe because it could dereference a raw pointer when
367/// accessing the underlying bignum structure.
368#[inline(always)]
369pub unsafe fn RBIGNUM_NEGATIVE_P(b: VALUE) -> bool {
370    api().bignum_negative_p(b)
371}
372
373/// Convert ID to Symbol (akin to `ID2SYM` or `RB_ID2SYM`).
374///
375/// Converts an internal ID to its corresponding Symbol VALUE.
376/// This is a safe operation - just bit manipulation for static symbols.
377///
378/// @param[in]  id     An ID value.
379/// @return     The Symbol VALUE corresponding to the ID.
380#[inline(always)]
381pub fn ID2SYM(id: crate::ID) -> VALUE {
382    api().id2sym(id)
383}
384
385/// Alias for ID2SYM for compatibility with Ruby naming conventions.
386#[inline(always)]
387pub fn RB_ID2SYM(id: crate::ID) -> VALUE {
388    api().id2sym(id)
389}
390
391/// Convert Symbol to ID (akin to `SYM2ID` or `RB_SYM2ID`).
392///
393/// Converts a Symbol VALUE to its internal ID representation.
394///
395/// @param[in]  obj    A Symbol VALUE.
396/// @return     The ID corresponding to the Symbol.
397///
398/// # Safety
399/// - `obj` must be a valid Symbol VALUE
400/// - For dynamic symbols, this may access the heap
401#[inline(always)]
402pub unsafe fn SYM2ID(obj: VALUE) -> crate::ID {
403    api().sym2id(obj)
404}
405
406/// Alias for SYM2ID for compatibility with Ruby naming conventions.
407#[inline(always)]
408pub unsafe fn RB_SYM2ID(obj: VALUE) -> crate::ID {
409    api().sym2id(obj)
410}
411
412/// Convert Fixnum to long (akin to `FIX2LONG`).
413///
414/// Extracts the integer value from a Fixnum VALUE by performing an arithmetic right shift.
415///
416/// # Safety
417/// - `obj` must be a valid Fixnum VALUE (checked with FIXNUM_P)
418/// - Behavior is undefined if called on non-Fixnum values
419#[inline(always)]
420pub unsafe fn FIX2LONG(obj: VALUE) -> std::os::raw::c_long {
421    api().fix2long(obj)
422}
423
424/// Convert Fixnum to unsigned long (akin to `FIX2ULONG`).
425///
426/// Extracts the unsigned integer value from a Fixnum VALUE.
427///
428/// # Safety
429/// - `obj` must be a valid positive Fixnum VALUE
430/// - Behavior is undefined for negative fixnums
431#[inline(always)]
432pub unsafe fn FIX2ULONG(obj: VALUE) -> std::os::raw::c_ulong {
433    api().fix2ulong(obj)
434}
435
436/// Convert long to Fixnum (akin to `LONG2FIX`).
437///
438/// Creates a Fixnum VALUE from a long integer.
439///
440/// # Safety
441/// - `val` must be within the valid Fixnum range (use FIXABLE to check)
442/// - Behavior is undefined if value is out of range
443#[inline(always)]
444pub unsafe fn LONG2FIX(val: std::os::raw::c_long) -> VALUE {
445    api().long2fix(val)
446}
447
448/// Check if long value can be represented as Fixnum (akin to `FIXABLE`).
449///
450/// Returns true if the value fits within the Fixnum range.
451#[inline(always)]
452pub fn FIXABLE(val: std::os::raw::c_long) -> bool {
453    api().fixable(val)
454}
455
456/// Check if unsigned long value can be represented as positive Fixnum (akin to `POSFIXABLE`).
457///
458/// Returns true if the unsigned value fits within the positive Fixnum range.
459#[inline(always)]
460pub fn POSFIXABLE(val: std::os::raw::c_ulong) -> bool {
461    api().posfixable(val)
462}
463
464/// Convert Ruby Integer to long (akin to `NUM2LONG`).
465///
466/// Converts any Ruby Integer (Fixnum or Bignum) to a C long.
467/// May raise a RangeError exception if the value is out of range.
468///
469/// # Safety
470/// - `obj` must be a valid Integer VALUE
471/// - May call into Ruby runtime and potentially raise exceptions
472/// - May trigger garbage collection
473#[inline(always)]
474pub unsafe fn NUM2LONG(obj: VALUE) -> std::os::raw::c_long {
475    api().num2long(obj)
476}
477
478/// Convert Ruby Integer to unsigned long (akin to `NUM2ULONG`).
479///
480/// Converts any Ruby Integer (Fixnum or Bignum) to a C unsigned long.
481/// May raise a RangeError exception if the value is out of range or negative.
482///
483/// # Safety
484/// - `obj` must be a valid Integer VALUE
485/// - May call into Ruby runtime and potentially raise exceptions
486/// - May trigger garbage collection
487#[inline(always)]
488pub unsafe fn NUM2ULONG(obj: VALUE) -> std::os::raw::c_ulong {
489    api().num2ulong(obj)
490}
491
492/// Convert long to Ruby Integer (akin to `LONG2NUM`).
493///
494/// Creates a Ruby Integer (Fixnum or Bignum) from a C long.
495/// Uses Fixnum if possible, otherwise allocates a Bignum.
496#[inline(always)]
497pub fn LONG2NUM(val: std::os::raw::c_long) -> VALUE {
498    api().long2num(val)
499}
500
501/// Convert unsigned long to Ruby Integer (akin to `ULONG2NUM`).
502///
503/// Creates a Ruby Integer (Fixnum or Bignum) from a C unsigned long.
504/// Uses Fixnum if possible, otherwise allocates a Bignum.
505#[inline(always)]
506pub fn ULONG2NUM(val: std::os::raw::c_ulong) -> VALUE {
507    api().ulong2num(val)
508}