Skip to main content

shape_jit/ffi/
result.rs

1// Heap allocation audit (PR-9 V8 Gap Closure):
2//   Category A (NaN-boxed returns): 5 sites
3//     box_ok, box_err, box_some — jit_make_ok, jit_make_err, jit_make_some
4//     (these use sub-tag encoding, not jit_box — allocation via Box::into_raw
5//      in the Ok/Err/Some wrapper fns in nan_boxing.rs)
6//   Category B (intermediate/consumed): 0 sites
7//   Category C (heap islands): 0 sites
8//!
9//! Result Type FFI Functions for JIT
10//!
11//! Functions for creating and manipulating Result types (Ok/Err) in JIT-compiled code.
12
13use super::super::nan_boxing::*;
14
15// ============================================================================
16// Result Type Creation
17// ============================================================================
18
19/// Create an Ok result wrapping the inner value
20pub extern "C" fn jit_make_ok(inner_bits: u64) -> u64 {
21    box_ok(inner_bits)
22}
23
24/// Create an Err result wrapping the inner value
25pub extern "C" fn jit_make_err(inner_bits: u64) -> u64 {
26    box_err(inner_bits)
27}
28
29// ============================================================================
30// Result Type Checking
31// ============================================================================
32
33/// Check if a value is Ok (returns TAG_BOOL_TRUE or TAG_BOOL_FALSE)
34pub extern "C" fn jit_is_ok(bits: u64) -> u64 {
35    if is_ok_tag(bits) {
36        TAG_BOOL_TRUE
37    } else {
38        TAG_BOOL_FALSE
39    }
40}
41
42/// Check if a value is Err (returns TAG_BOOL_TRUE or TAG_BOOL_FALSE)
43pub extern "C" fn jit_is_err(bits: u64) -> u64 {
44    if is_err_tag(bits) {
45        TAG_BOOL_TRUE
46    } else {
47        TAG_BOOL_FALSE
48    }
49}
50
51/// Check if a value is any Result type (Ok or Err)
52pub extern "C" fn jit_is_result(bits: u64) -> u64 {
53    if is_result_tag(bits) {
54        TAG_BOOL_TRUE
55    } else {
56        TAG_BOOL_FALSE
57    }
58}
59
60// ============================================================================
61// Result Type Unwrapping
62// ============================================================================
63
64/// Unwrap an Ok value, returning the inner value
65/// If not Ok, returns TAG_NULL
66pub extern "C" fn jit_unwrap_ok(bits: u64) -> u64 {
67    if is_ok_tag(bits) {
68        unsafe { unbox_result_inner(bits) }
69    } else {
70        TAG_NULL
71    }
72}
73
74/// Unwrap an Err value, returning the inner value
75/// If not Err, returns TAG_NULL
76pub extern "C" fn jit_unwrap_err(bits: u64) -> u64 {
77    if is_err_tag(bits) {
78        unsafe { unbox_result_inner(bits) }
79    } else {
80        TAG_NULL
81    }
82}
83
84/// Unwrap Ok or return default value
85/// If Ok, returns the inner value; otherwise returns the default
86pub extern "C" fn jit_unwrap_or(bits: u64, default_bits: u64) -> u64 {
87    if is_ok_tag(bits) {
88        unsafe { unbox_result_inner(bits) }
89    } else {
90        default_bits
91    }
92}
93
94// ============================================================================
95// Result Type Transformation
96// ============================================================================
97
98/// Map over Ok value - if Ok, applies function and returns new Ok
99/// This is a simplified version that just returns the inner value for now
100/// (full map support would require function call machinery)
101pub extern "C" fn jit_result_inner(bits: u64) -> u64 {
102    if is_ok_tag(bits) || is_err_tag(bits) {
103        unsafe { unbox_result_inner(bits) }
104    } else {
105        bits
106    }
107}
108
109// ============================================================================
110// Option Type Functions
111// ============================================================================
112
113/// Create a Some value wrapping the inner value
114pub extern "C" fn jit_make_some(inner_bits: u64) -> u64 {
115    box_some(inner_bits)
116}
117
118/// Check if a value is Some (returns TAG_BOOL_TRUE or TAG_BOOL_FALSE)
119pub extern "C" fn jit_is_some(bits: u64) -> u64 {
120    if is_some_tag(bits) {
121        TAG_BOOL_TRUE
122    } else {
123        TAG_BOOL_FALSE
124    }
125}
126
127/// Check if a value is None (returns TAG_BOOL_TRUE or TAG_BOOL_FALSE)
128pub extern "C" fn jit_is_none(bits: u64) -> u64 {
129    if is_none_tag(bits) {
130        TAG_BOOL_TRUE
131    } else {
132        TAG_BOOL_FALSE
133    }
134}
135
136/// Unwrap a Some value, returning the inner value
137/// If not Some, returns TAG_NULL
138pub extern "C" fn jit_unwrap_some(bits: u64) -> u64 {
139    if is_some_tag(bits) {
140        unsafe { unbox_some_inner(bits) }
141    } else {
142        TAG_NULL
143    }
144}
145
146#[cfg(test)]
147mod tests {
148    use super::*;
149
150    #[test]
151    fn test_result_ok_roundtrip() {
152        // Test that Ok wrapping and unwrapping preserves the value
153        // This test previously caused SIGSEGV due to 44-bit pointer truncation
154        let inner = box_number(42.0);
155        let ok_result = jit_make_ok(inner);
156
157        assert_eq!(jit_is_ok(ok_result), TAG_BOOL_TRUE);
158        assert_eq!(jit_is_err(ok_result), TAG_BOOL_FALSE);
159        assert_eq!(jit_is_result(ok_result), TAG_BOOL_TRUE);
160
161        let unwrapped = jit_unwrap_ok(ok_result);
162        assert_eq!(unbox_number(unwrapped), 42.0);
163    }
164
165    #[test]
166    fn test_result_err_roundtrip() {
167        // Test that Err wrapping and unwrapping preserves the value
168        let inner = box_number(-1.0);
169        let err_result = jit_make_err(inner);
170
171        assert_eq!(jit_is_ok(err_result), TAG_BOOL_FALSE);
172        assert_eq!(jit_is_err(err_result), TAG_BOOL_TRUE);
173        assert_eq!(jit_is_result(err_result), TAG_BOOL_TRUE);
174
175        let unwrapped = jit_unwrap_err(err_result);
176        assert_eq!(unbox_number(unwrapped), -1.0);
177    }
178
179    #[test]
180    fn test_unwrap_or_with_ok() {
181        let ok_result = jit_make_ok(box_number(100.0));
182        let default = box_number(0.0);
183
184        let result = jit_unwrap_or(ok_result, default);
185        assert_eq!(unbox_number(result), 100.0);
186    }
187
188    #[test]
189    fn test_unwrap_or_with_err() {
190        let err_result = jit_make_err(box_number(-1.0));
191        let default = box_number(999.0);
192
193        let result = jit_unwrap_or(err_result, default);
194        assert_eq!(unbox_number(result), 999.0);
195    }
196
197    #[test]
198    fn test_option_some_roundtrip() {
199        // This test previously caused SIGSEGV due to 44-bit pointer truncation
200        let inner = box_number(3.14159);
201        let some_opt = jit_make_some(inner);
202
203        assert_eq!(jit_is_some(some_opt), TAG_BOOL_TRUE);
204        assert_eq!(jit_is_none(some_opt), TAG_BOOL_FALSE);
205
206        let unwrapped = jit_unwrap_some(some_opt);
207        assert!((unbox_number(unwrapped) - 3.14159).abs() < 0.0001);
208    }
209
210    #[test]
211    fn test_option_none() {
212        // TAG_NULL represents None
213        assert_eq!(jit_is_none(TAG_NULL), TAG_BOOL_TRUE);
214        assert_eq!(jit_is_some(TAG_NULL), TAG_BOOL_FALSE);
215    }
216
217    #[test]
218    fn test_non_result_values() {
219        // Regular numbers should not be results
220        let num = box_number(42.0);
221        assert_eq!(jit_is_result(num), TAG_BOOL_FALSE);
222        assert_eq!(jit_is_ok(num), TAG_BOOL_FALSE);
223        assert_eq!(jit_is_err(num), TAG_BOOL_FALSE);
224    }
225
226    #[test]
227    fn test_result_inner() {
228        // Test jit_result_inner which extracts inner regardless of Ok/Err
229        let ok_val = jit_make_ok(box_number(123.0));
230        let err_val = jit_make_err(box_number(456.0));
231
232        let ok_inner = jit_result_inner(ok_val);
233        let err_inner = jit_result_inner(err_val);
234
235        assert_eq!(unbox_number(ok_inner), 123.0);
236        assert_eq!(unbox_number(err_inner), 456.0);
237    }
238}