1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#![allow(non_snake_case)]

use super::*;
use std::mem;
use libc;

/// Gets the class of a `VALUE`.
/// This is actually defined in the Ruby library, but it is inline.
/// This is a port of it.
pub unsafe fn rb_class_of(obj: VALUE) -> VALUE {
    if IMMEDIATE_P(obj) {
        if FIXNUM_P(obj) { return rb_cInteger; }
        if FLONUM_P(obj) { return rb_cFloat; }
        if obj == Qtrue { return rb_cTrueClass; }
        if STATIC_SYM_P(obj) { return rb_cSymbol; }
    } else if !RTEST(obj) {
        if obj == Qnil   { return rb_cNilClass; }
        if obj == Qfalse { return rb_cFalseClass; }
    }
    return (*RBasic::from_pointer(obj)).klass;
}

pub fn TYPE_P(obj: VALUE, ty: value_type) -> bool {
    match ty {
        value_type::T_FIXNUM => FIXNUM_P(obj),
        value_type::T_TRUE => obj == Qtrue,
        value_type::T_FALSE => obj == Qfalse,
        value_type::T_NIL => obj == Qnil,
        value_type::T_UNDEF => obj == Qundef,
        value_type::T_SYMBOL => SYMBOL_P(obj),
        value_type::T_FLOAT => FLOAT_TYPE_P(obj),
        _ => !SPECIAL_CONST_P(obj) && BUILTIN_TYPE(obj) == ty
    }
}

pub fn FLOAT_TYPE_P(obj: VALUE) -> bool {
    FLONUM_P(obj) || (!SPECIAL_CONST_P(obj) &&
                      BUILTIN_TYPE(obj) == T_FLOAT)
}

pub fn BUILTIN_TYPE(x: VALUE) -> value_type {
    unsafe {
        let basic: *const RBasic = mem::transmute(x);
        let masked = (*basic).flags.0 & (T_MASK as libc::size_t);
        mem::transmute(masked as u32)
    }
}

#[cfg(not(mri_use_flonum))]
pub fn FLONUM_P(_: VALUE) -> bool { false }

#[cfg(mri_use_flonum)]
pub fn FLONUM_P(x: VALUE) -> bool {
    x & FLONUM_MASK == FLONUM_FLAG.0
}

pub fn FIXNUM_P(f: VALUE) -> bool {
    (f & FIXNUM_FLAG) != 0
}

pub fn DYNAMIC_SYM_P(x: VALUE) -> bool {
    !SPECIAL_CONST_P(x) && BUILTIN_TYPE(x) == T_SYMBOL
}

pub fn STATIC_SYM_P(x: VALUE) -> bool {
    (x.0 & !((!0 as libc::uintptr_t) << SPECIAL_SHIFT)) == SYMBOL_FLAG.0
}

pub fn SYMBOL_P(x: VALUE) -> bool {
    STATIC_SYM_P(x) || DYNAMIC_SYM_P(x)
}

pub fn SPECIAL_CONST_P(x: VALUE) -> bool {
    IMMEDIATE_P(x) || !RTEST(x)
}

pub fn IMMEDIATE_P(x: VALUE) -> bool {
    (x & IMMEDIATE_MASK) != 0
}

pub fn RTEST(v: VALUE) -> bool {
    (v.0 & !Qnil.0) != 0
}

pub fn NIL_P(v: VALUE) -> bool {
    v == Qnil
}