shape_jit/ffi/
conversion.rs1use super::super::jit_array::JitArray;
12use super::super::nan_boxing::*;
13
14pub extern "C" fn jit_typeof(value_bits: u64) -> u64 {
20 let type_str = if is_number(value_bits) {
21 "number"
22 } else if value_bits == TAG_NULL {
23 "null"
24 } else if value_bits == TAG_BOOL_TRUE || value_bits == TAG_BOOL_FALSE {
25 "boolean"
26 } else if is_ok_tag(value_bits) || is_err_tag(value_bits) {
27 "result"
28 } else if is_inline_function(value_bits) {
29 "function"
30 } else {
31 match heap_kind(value_bits) {
32 Some(HK_STRING) => "string",
33 Some(HK_ARRAY) => "array",
34 Some(HK_JIT_OBJECT) | Some(HK_TYPED_OBJECT) => "object",
35 Some(HK_CLOSURE) => "function",
36 Some(HK_RANGE) => "range",
37 Some(HK_COLUMN_REF) => "series",
38 Some(HK_JIT_TABLE_REF) => "series_ref",
39 Some(HK_DURATION) => "duration",
40 Some(HK_TIME) => "time",
41 Some(HK_TIMEFRAME) => "timeframe",
42 _ => "unknown",
43 }
44 };
45 jit_box(HK_STRING, type_str.to_string())
46}
47
48pub extern "C" fn jit_to_string(value_bits: u64) -> u64 {
54 let s = if is_number(value_bits) {
55 format!("{}", unbox_number(value_bits))
56 } else if value_bits == TAG_NULL {
57 "null".to_string()
58 } else if value_bits == TAG_BOOL_TRUE {
59 "true".to_string()
60 } else if value_bits == TAG_BOOL_FALSE {
61 "false".to_string()
62 } else {
63 match heap_kind(value_bits) {
64 Some(HK_STRING) => {
65 let s = unsafe { jit_unbox::<String>(value_bits) };
66 s.clone()
67 }
68 Some(HK_ARRAY) => "[array]".to_string(),
69 Some(HK_JIT_OBJECT) | Some(HK_TYPED_OBJECT) => "[object]".to_string(),
70 _ => "[unknown]".to_string(),
71 }
72 };
73 jit_box(HK_STRING, s)
74}
75
76pub extern "C" fn jit_type_check(value_bits: u64, type_name_bits: u64) -> u64 {
79 let type_name = unsafe {
81 if !is_heap_kind(type_name_bits, HK_STRING) {
82 return TAG_BOOL_FALSE;
83 }
84 jit_unbox::<String>(type_name_bits).clone()
85 };
86
87 let matches = check_type_recursive(value_bits, &type_name);
88
89 if matches {
90 TAG_BOOL_TRUE
91 } else {
92 TAG_BOOL_FALSE
93 }
94}
95
96fn check_type_recursive(value_bits: u64, type_spec: &str) -> bool {
98 if let Some((prefix, rest)) = type_spec.split_once(':') {
100 match prefix {
101 "basic" => check_basic_type(value_bits, rest),
102 "optional" => {
103 value_bits == TAG_NULL || check_type_recursive(value_bits, rest)
105 }
106 "array" => {
107 if !is_heap_kind(value_bits, HK_ARRAY) {
109 return false;
110 }
111 let arr = unsafe { jit_unbox::<JitArray>(value_bits) };
112 arr.iter().all(|elem| check_type_recursive(*elem, rest))
113 }
114 "tuple" => {
115 if !is_heap_kind(value_bits, HK_ARRAY) {
117 return false;
118 }
119 let types: Vec<&str> = rest.split(',').collect();
120 let arr = unsafe { jit_unbox::<JitArray>(value_bits) };
121 if arr.len() != types.len() {
122 return false;
123 }
124 arr.iter()
125 .zip(types.iter())
126 .all(|(elem, ty)| check_type_recursive(*elem, ty))
127 }
128 "generic" => {
129 match rest {
131 "Array" => is_heap_kind(value_bits, HK_ARRAY),
132 "Series" => is_heap_kind(value_bits, HK_COLUMN_REF),
133 _ => false,
134 }
135 }
136 "ref" => {
137 false
139 }
140 "dyn" => {
141 false
143 }
144 _ => false,
145 }
146 } else {
147 match type_spec {
149 "function" => is_inline_function(value_bits) || is_heap_kind(value_bits, HK_CLOSURE),
150 "object" => is_heap_kind(value_bits, HK_TYPED_OBJECT),
151 "any" => true,
152 "void" => value_bits == TAG_UNIT,
153 "never" => false,
154 "null" => value_bits == TAG_NULL,
155 "undefined" => value_bits == TAG_NULL || value_bits == TAG_UNIT,
156 "unknown" => false,
157 _ => check_basic_type(value_bits, type_spec),
158 }
159 }
160}
161
162fn check_basic_type(value_bits: u64, type_name: &str) -> bool {
164 if is_number(value_bits) {
165 return type_name == "number";
166 }
167 if value_bits == TAG_NULL {
168 return type_name == "null";
169 }
170 if value_bits == TAG_BOOL_TRUE || value_bits == TAG_BOOL_FALSE {
171 return type_name == "boolean" || type_name == "bool";
172 }
173 if value_bits == TAG_UNIT {
174 return type_name == "void" || type_name == "unit";
175 }
176 if is_inline_function(value_bits) {
177 return type_name == "function";
178 }
179 if is_data_row(value_bits) {
180 return type_name == "data_row";
181 }
182 if is_ok_tag(value_bits) || is_err_tag(value_bits) {
183 return type_name == "result";
184 }
185
186 match heap_kind(value_bits) {
187 Some(HK_STRING) => type_name == "string",
188 Some(HK_ARRAY) => type_name == "array",
189 Some(HK_JIT_OBJECT) | Some(HK_TYPED_OBJECT) => type_name == "object",
190 Some(HK_CLOSURE) => type_name == "function",
191 Some(HK_COLUMN_REF) => type_name == "series",
192 Some(HK_TIME) => type_name == "time",
193 Some(HK_DURATION) => type_name == "duration",
194 Some(HK_TIMEFRAME) => type_name == "timeframe",
195 Some(HK_RANGE) => type_name == "range",
196 _ => false,
197 }
198}
199
200fn format_nan_boxed(value_bits: u64) -> String {
202 use shape_value::tags::{TAG_INT, get_payload, get_tag, is_tagged, sign_extend_i48};
203
204 if is_number(value_bits) {
205 let n = unbox_number(value_bits);
206 if n.is_finite() && n == n.trunc() && n.abs() < 1e15 {
207 format!("{}", n as i64)
208 } else {
209 format!("{}", n)
210 }
211 } else if value_bits == TAG_BOOL_TRUE {
212 "true".to_string()
213 } else if value_bits == TAG_BOOL_FALSE {
214 "false".to_string()
215 } else if value_bits == TAG_NULL {
216 "null".to_string()
217 } else if is_tagged(value_bits) && get_tag(value_bits) == TAG_INT {
218 let int_val = sign_extend_i48(get_payload(value_bits));
219 format!("{}", int_val)
220 } else {
221 match heap_kind(value_bits) {
222 Some(HK_STRING) => {
223 let s = unsafe { jit_unbox::<String>(value_bits) };
224 s.clone()
225 }
226 Some(HK_ARRAY) => {
227 let arr = unsafe { jit_unbox::<JitArray>(value_bits) };
228 let elems: Vec<String> = arr.iter().map(|&bits| format_nan_boxed(bits)).collect();
229 format!("[{}]", elems.join(", "))
230 }
231 Some(HK_OK) => {
232 let inner = unsafe { *jit_unbox::<u64>(value_bits) };
233 format!("Ok({})", format_nan_boxed(inner))
234 }
235 Some(HK_ERR) => {
236 let inner = unsafe { *jit_unbox::<u64>(value_bits) };
237 format!("Err({})", format_nan_boxed(inner))
238 }
239 Some(HK_SOME) => {
240 let inner = unsafe { *jit_unbox::<u64>(value_bits) };
241 format!("Some({})", format_nan_boxed(inner))
242 }
243 _ => "[object]".to_string(),
244 }
245 }
246}
247
248pub extern "C" fn jit_print(value_bits: u64) {
250 println!("{}", format_nan_boxed(value_bits));
251}
252
253pub extern "C" fn jit_to_number(value_bits: u64) -> u64 {
255 if is_number(value_bits) {
256 return value_bits;
257 }
258
259 if value_bits == TAG_NULL {
260 return box_number(0.0);
261 }
262 if value_bits == TAG_BOOL_TRUE {
263 return box_number(1.0);
264 }
265 if value_bits == TAG_BOOL_FALSE {
266 return box_number(0.0);
267 }
268
269 let num = match heap_kind(value_bits) {
270 Some(HK_STRING) => {
271 let s = unsafe { jit_unbox::<String>(value_bits) };
272 s.parse::<f64>().unwrap_or(f64::NAN)
273 }
274 _ => f64::NAN,
275 };
276 box_number(num)
277}