Skip to main content

shape_jit/ffi/call_method/
duration.rs

1// Heap allocation audit (PR-9 V8 Gap Closure):
2//   Category A (NaN-boxed returns): 1 site
3//     jit_box(HK_DURATION, ...) — to() unit conversion
4//   Category B (intermediate/consumed): 0 sites
5//   Category C (heap islands): 0 sites
6//!
7//! Duration method implementations for JIT
8
9use crate::context::JITDuration;
10use crate::ffi::jit_kinds::*;
11use crate::ffi::value_ffi::*;
12
13/// Call a method on a duration value
14#[inline(always)]
15pub fn call_duration_method(receiver_bits: u64, method_name: &str, args: &[u64]) -> u64 {
16    unsafe {
17        if !is_heap_kind(receiver_bits, HK_DURATION) {
18            return TAG_NULL;
19        }
20        let dur = unified_unbox::<JITDuration>(receiver_bits);
21
22        match method_name {
23            "to_seconds" | "toSeconds" | "as_seconds" => {
24                let seconds = match dur.unit {
25                    0 => dur.value,              // seconds
26                    1 => dur.value * 60.0,       // minutes
27                    2 => dur.value * 3600.0,     // hours
28                    3 => dur.value * 86400.0,    // days
29                    4 => dur.value * 604800.0,   // weeks
30                    5 => dur.value * 2592000.0,  // months (30 days)
31                    6 => dur.value * 31536000.0, // years (365 days)
32                    _ => dur.value,
33                };
34                box_number(seconds)
35            }
36            "to_minutes" | "toMinutes" | "as_minutes" => {
37                let minutes = match dur.unit {
38                    0 => dur.value / 60.0,
39                    1 => dur.value,
40                    2 => dur.value * 60.0,
41                    3 => dur.value * 1440.0,
42                    4 => dur.value * 10080.0,
43                    5 => dur.value * 43200.0,
44                    6 => dur.value * 525600.0,
45                    _ => dur.value,
46                };
47                box_number(minutes)
48            }
49            "to_hours" | "toHours" | "as_hours" => {
50                let hours = match dur.unit {
51                    0 => dur.value / 3600.0,
52                    1 => dur.value / 60.0,
53                    2 => dur.value,
54                    3 => dur.value * 24.0,
55                    4 => dur.value * 168.0,
56                    5 => dur.value * 720.0,
57                    6 => dur.value * 8760.0,
58                    _ => dur.value,
59                };
60                box_number(hours)
61            }
62            "to_days" | "toDays" | "as_days" => {
63                let days = match dur.unit {
64                    0 => dur.value / 86400.0,
65                    1 => dur.value / 1440.0,
66                    2 => dur.value / 24.0,
67                    3 => dur.value,
68                    4 => dur.value * 7.0,
69                    5 => dur.value * 30.0,
70                    6 => dur.value * 365.0,
71                    _ => dur.value,
72                };
73                box_number(days)
74            }
75            "value" => box_number(dur.value),
76            "unit" => box_number(dur.unit as f64),
77            "to" => {
78                // to("seconds"), to("minutes"), etc. - returns a new Duration in the target unit
79                if args.is_empty() {
80                    return TAG_NULL;
81                }
82                // Get target unit from first argument (should be a string)
83                let target_unit_str = if is_heap_kind(args[0], HK_STRING) {
84                    unbox_string(args[0])
85                } else {
86                    return TAG_NULL;
87                };
88
89                // Convert to seconds first (as intermediate)
90                let seconds = match dur.unit {
91                    0 => dur.value,              // seconds
92                    1 => dur.value * 60.0,       // minutes
93                    2 => dur.value * 3600.0,     // hours
94                    3 => dur.value * 86400.0,    // days
95                    4 => dur.value * 604800.0,   // weeks
96                    5 => dur.value * 2592000.0,  // months (30 days)
97                    6 => dur.value * 31536000.0, // years (365 days)
98                    _ => dur.value,
99                };
100
101                // Convert from seconds to target unit
102                let (new_value, new_unit) = match target_unit_str {
103                    "seconds" | "second" | "s" => (seconds, 0u8),
104                    "minutes" | "minute" | "m" => (seconds / 60.0, 1u8),
105                    "hours" | "hour" | "h" => (seconds / 3600.0, 2u8),
106                    "days" | "day" | "d" => (seconds / 86400.0, 3u8),
107                    "weeks" | "week" | "w" => (seconds / 604800.0, 4u8),
108                    "months" | "month" => (seconds / 2592000.0, 5u8),
109                    "years" | "year" | "y" => (seconds / 31536000.0, 6u8),
110                    _ => return TAG_NULL,
111                };
112
113                // Create a new JITDuration and return it
114                unified_box(
115                    HK_DURATION,
116                    JITDuration {
117                        value: new_value,
118                        unit: new_unit,
119                    },
120                )
121            }
122            _ => TAG_NULL,
123        }
124    }
125}