1use libc::size_t;
2use std::mem;
3use std::convert::From;
4
5use types::{InternalValue, RBasic};
6
7const SPECIAL_SHIFT: usize = 8;
8
9#[cfg(not(target_arch = "x86_64"))]
12pub enum RubySpecialConsts {
13 False = 0,
14 True = 0x02,
15 Nil = 0x04,
16 Undef = 0x06,
17}
18
19#[cfg(not(target_arch = "x86_64"))]
20pub enum RubySpecialFlags {
21 ImmediateMask = 0x03,
22 FixnumFlag = 0x01,
23 FlonumMask = 0x00,
24 FlonumFlag = 0x02,
25 SymbolFlag = 0x0e,
26}
27
28#[cfg(target_arch = "x86_64")]
29pub enum RubySpecialConsts {
30 False = 0,
31 True = 0x14,
32 Nil = 0x08,
33 Undef = 0x34,
34}
35
36#[cfg(target_arch = "x86_64")]
37pub enum RubySpecialFlags {
38 ImmediateMask = 0x07,
39 FixnumFlag = 0x01,
40 FlonumMask = 0x03,
41 FlonumFlag = 0x02,
42 SymbolFlag = 0x0c,
43}
44
45#[derive(Debug, PartialEq)]
46#[link_name = "ruby_value_type"]
47#[repr(C)]
48pub enum ValueType {
49 None = 0x00,
50 Object = 0x01,
51 Class = 0x02,
52 Module = 0x03,
53 Float = 0x04,
54 RString = 0x05,
55 Regexp = 0x06,
56 Array = 0x07,
57 Hash = 0x08,
58 Struct = 0x09,
59 Bignum = 0x0a,
60 File = 0x0b,
61 Data = 0x0c,
62 Match = 0x0d,
63 Complex = 0x0e,
64 Rational = 0x0f,
65 Nil = 0x11,
66 True = 0x12,
67 False = 0x13,
68 Symbol = 0x14,
69 Fixnum = 0x15,
70 Undef = 0x1b,
71 Node = 0x1c,
72 IClass = 0x1d,
73 Zombie = 0x1e,
74 Mask = 0x1f,
75}
76
77#[repr(C)]
78#[derive(Copy, Clone, Debug, PartialEq)]
79pub struct Value {
80 pub value: InternalValue,
81}
82
83impl Value {
84 pub fn is_true(&self) -> bool {
85 self.value == (RubySpecialConsts::True as InternalValue)
86 }
87
88 pub fn is_false(&self) -> bool {
89 self.value == (RubySpecialConsts::False as InternalValue)
90 }
91
92 pub fn is_nil(&self) -> bool {
93 self.value == (RubySpecialConsts::Nil as InternalValue)
94 }
95
96 pub fn is_undef(&self) -> bool {
97 self.value == (RubySpecialConsts::Undef as InternalValue)
98 }
99
100 pub fn is_symbol(&self) -> bool {
101 (self.value & !((!0) << SPECIAL_SHIFT)) == (RubySpecialFlags::SymbolFlag as InternalValue)
102 }
103
104 pub fn is_fixnum(&self) -> bool {
105 (self.value & (RubySpecialFlags::FixnumFlag as InternalValue)) != 0
106 }
107
108 pub fn is_flonum(&self) -> bool {
109 (self.value & (RubySpecialFlags::FlonumMask as InternalValue)) ==
110 (RubySpecialFlags::FlonumFlag as InternalValue)
111 }
112
113 pub fn ty(&self) -> ValueType {
114 if self.is_immediate() {
115 if self.is_fixnum() {
116 ValueType::Fixnum
117 } else if self.is_flonum() {
118 ValueType::Float
119 } else if self.is_true() {
120 ValueType::True
121 } else if self.is_symbol() {
122 ValueType::Symbol
123 } else if self.is_undef() {
124 ValueType::Undef
125 } else {
126 self.builtin_type()
127 }
128 } else if !self.test() {
129 if self.is_nil() {
130 ValueType::Nil
131 } else if self.is_false() {
132 ValueType::False
133 } else {
134 self.builtin_type()
135 }
136 } else {
137 self.builtin_type()
138 }
139 }
140
141 fn is_immediate(&self) -> bool {
142 (self.value & (RubySpecialFlags::ImmediateMask as InternalValue)) != 0
143 }
144
145 fn test(&self) -> bool {
146 (self.value & !(RubySpecialConsts::Nil as InternalValue)) != 0
147 }
148
149 fn builtin_type(&self) -> ValueType {
150 unsafe {
151 let basic: *const RBasic = mem::transmute(self.value);
152 let masked = (*basic).flags & (ValueType::Mask as size_t);
153 mem::transmute(masked as u32)
154 }
155 }
156}
157
158impl From<InternalValue> for Value {
159 fn from(internal_value: InternalValue) -> Self {
160 Value { value: internal_value }
161 }
162}