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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
//! Utils for working with Date objects

use crate::jsutils::JsError;
use crate::quickjs_utils;
use crate::quickjs_utils::{functions, objects, primitives};
use crate::quickjsrealmadapter::QuickJsRealmAdapter;
use crate::quickjsvalueadapter::QuickJsValueAdapter;
use libquickjs_sys as q;

/// create a new instance of a Date object
pub fn new_date_q(context: &QuickJsRealmAdapter) -> Result<QuickJsValueAdapter, JsError> {
    unsafe { new_date(context.context) }
}

/// create a new instance of a Date object
/// # Safety
/// When passing a context pointer please make sure the corresponding QuickJsContext is still valid
pub unsafe fn new_date(context: *mut q::JSContext) -> Result<QuickJsValueAdapter, JsError> {
    let constructor = quickjs_utils::get_constructor(context, "Date")?;
    let date_ref = functions::call_constructor(context, &constructor, &[])?;
    Ok(date_ref)
}

/// check if a JSValueRef is an instance of Date
pub fn is_date_q(context: &QuickJsRealmAdapter, obj_ref: &QuickJsValueAdapter) -> bool {
    unsafe { is_date(context.context, obj_ref) }
}

/// check if a JSValueRef is an instance of Date
/// # Safety
/// When passing a context pointer please make sure the corresponding QuickJsContext is still valid
pub unsafe fn is_date(context: *mut q::JSContext, obj_ref: &QuickJsValueAdapter) -> bool {
    objects::is_instance_of_by_name(context, obj_ref, "Date").unwrap_or(false)
}

/// set the timestamp for a Date object
pub fn set_time_q(
    context: &QuickJsRealmAdapter,
    date_ref: &QuickJsValueAdapter,
    timestamp: f64,
) -> Result<(), JsError> {
    unsafe { set_time(context.context, date_ref, timestamp) }
}

/// set the timestamp for a Date object
/// # Safety
/// When passing a context pointer please make sure the corresponding QuickJsContext is still valid
pub unsafe fn set_time(
    context: *mut q::JSContext,
    date_ref: &QuickJsValueAdapter,
    timestamp: f64,
) -> Result<(), JsError> {
    functions::invoke_member_function(
        context,
        date_ref,
        "setTime",
        &[primitives::from_f64(timestamp)],
    )?;
    Ok(())
}
/// get the timestamp from a Date object
pub fn get_time_q(
    context: &QuickJsRealmAdapter,
    date_ref: &QuickJsValueAdapter,
) -> Result<f64, JsError> {
    unsafe { get_time(context.context, date_ref) }
}
/// get the timestamp from a Date object
/// # Safety
/// When passing a context pointer please make sure the corresponding QuickJsContext is still valid
pub unsafe fn get_time(
    context: *mut q::JSContext,
    date_ref: &QuickJsValueAdapter,
) -> Result<f64, JsError> {
    let time_ref = functions::invoke_member_function(context, date_ref, "getTime", &[])?;
    if time_ref.is_f64() {
        primitives::to_f64(&time_ref)
    } else {
        primitives::to_i32(&time_ref).map(|i| i as f64)
    }
}

#[cfg(test)]
pub mod tests {

    use crate::facades::tests::init_test_rt;
    use crate::quickjs_utils::dates;
    use crate::quickjs_utils::dates::{get_time_q, is_date_q, set_time_q};

    #[test]
    fn test_date() {
        let rt = init_test_rt();
        rt.exe_rt_task_in_event_loop(|q_js_rt| {
            let q_ctx = q_js_rt.get_main_realm();
            let date_ref = dates::new_date_q(q_ctx).expect("new_date failed");
            assert!(is_date_q(q_ctx, &date_ref));

            set_time_q(q_ctx, &date_ref, 2147483648f64).expect("could not set time");
            let gt_res = get_time_q(q_ctx, &date_ref);
            match gt_res {
                Ok(t) => {
                    assert_eq!(t, 2147483648f64);
                }
                Err(e) => {
                    panic!("get time failed: {}", e);
                }
            }

            set_time_q(q_ctx, &date_ref, 2f64).expect("could not set time");
            let gt_res = get_time_q(q_ctx, &date_ref);
            match gt_res {
                Ok(t) => {
                    assert_eq!(t, 2f64);
                }
                Err(e) => {
                    panic!("get time 2 failed: {}", e);
                }
            }
        });
    }
}