1use crate::{ffi, mem};
7
8pub mod format {
10 pub const UNIX: &str = "unix";
12 pub const MILLIS: &str = "ms";
14 pub const NANOS: &str = "ns";
16 pub const RFC3339: &str = "rfc3339";
18 pub const HTTP: &str = "http";
20 pub const ISO8601: &str = "iso8601";
22}
23
24pub fn now(fmt: &str) -> String {
30 let args = serde_json::json!({ "format": fmt });
31 let args_str = args.to_string();
32 let (args_ptr, args_len) = mem::host_arg_str(&args_str);
33 let result = unsafe { ffi::timestamp(args_ptr, args_len) };
34 unsafe { mem::read_packed_string(result) }.unwrap_or_default()
36}
37
38pub fn now_ms() -> u64 {
43 now(format::MILLIS).parse().unwrap_or(0)
44}
45
46pub fn now_unix() -> u64 {
48 now(format::UNIX).parse().unwrap_or(0)
49}
50
51pub fn now_rfc3339() -> String {
53 now(format::RFC3339)
54}
55
56#[cfg(test)]
57mod tests {
58 use super::*;
59 use crate::ffi::test_host;
60
61 #[test]
62 fn now_passes_format_in_args() {
63 test_host::reset();
64 test_host::with_mock(|m| m.timestamp_response = Some("2026-04-07T11:12:13Z".into()));
65 let s = now(format::RFC3339);
66 assert_eq!(s, "2026-04-07T11:12:13Z");
67
68 let captured = test_host::read_mock(|m| m.last_timestamp_args.clone()).unwrap();
69 let parsed: serde_json::Value = serde_json::from_str(&captured).unwrap();
70 assert_eq!(parsed["format"], "rfc3339");
71 }
72
73 #[test]
74 fn now_ms_parses_decimal_response() {
75 test_host::reset();
76 test_host::with_mock(|m| m.timestamp_response = Some("1759839133000".into()));
77 assert_eq!(now_ms(), 1_759_839_133_000);
78 }
79
80 #[test]
81 fn now_unix_parses_decimal_response() {
82 test_host::reset();
83 test_host::with_mock(|m| m.timestamp_response = Some("1759839133".into()));
84 assert_eq!(now_unix(), 1_759_839_133);
85 }
86
87 #[test]
88 fn now_unparseable_response_zero() {
89 test_host::reset();
90 test_host::with_mock(|m| m.timestamp_response = Some("not-a-number".into()));
91 assert_eq!(now_ms(), 0);
92 assert_eq!(now_unix(), 0);
93 }
94
95 #[test]
96 fn now_rfc3339_uses_rfc3339_format() {
97 test_host::reset();
98 test_host::with_mock(|m| m.timestamp_response = Some("2026-04-07T00:00:00Z".into()));
99 let s = now_rfc3339();
100 assert_eq!(s, "2026-04-07T00:00:00Z");
101 let captured = test_host::read_mock(|m| m.last_timestamp_args.clone()).unwrap();
102 assert!(captured.contains("rfc3339"));
103 }
104
105 #[test]
106 fn format_constants_match_expected_strings() {
107 assert_eq!(format::UNIX, "unix");
108 assert_eq!(format::MILLIS, "ms");
109 assert_eq!(format::NANOS, "ns");
110 assert_eq!(format::RFC3339, "rfc3339");
111 assert_eq!(format::HTTP, "http");
112 assert_eq!(format::ISO8601, "iso8601");
113 }
114}