flaron-sdk 0.99.0

Official Rust SDK for writing Flaron edge flares - WebAssembly modules that run on the Flaron CDN edge runtime.
Documentation
//! Edge-side timestamps in a variety of formats.
//!
//! All timestamps are produced by the host so they reflect the wall clock of
//! the edge node serving the request, not the (non-existent) Wasm clock.

use crate::{ffi, mem};

/// Supported timestamp formats accepted by [`now`] and [`format`].
pub mod format {
    /// Seconds since the Unix epoch as a decimal string.
    pub const UNIX: &str = "unix";
    /// Milliseconds since the Unix epoch as a decimal string.
    pub const MILLIS: &str = "ms";
    /// Nanoseconds since the Unix epoch as a decimal string.
    pub const NANOS: &str = "ns";
    /// RFC 3339 (`2026-04-07T11:12:13Z`).
    pub const RFC3339: &str = "rfc3339";
    /// HTTP date header format (`Tue, 07 Apr 2026 11:12:13 GMT`).
    pub const HTTP: &str = "http";
    /// ISO 8601 (alias of RFC 3339).
    pub const ISO8601: &str = "iso8601";
}

/// Get the current edge time formatted according to `fmt`.
///
/// Use one of the constants in [`format`] for `fmt`. Unknown formats fall
/// back to RFC 3339 host-side. Returns an empty string if the host returned
/// no result (which should never happen).
pub fn now(fmt: &str) -> String {
    let args = serde_json::json!({ "format": fmt });
    let args_str = args.to_string();
    let (args_ptr, args_len) = mem::host_arg_str(&args_str);
    let result = unsafe { ffi::timestamp(args_ptr, args_len) };
    // SAFETY: host writes a valid UTF-8 timestamp into the bump arena.
    unsafe { mem::read_packed_string(result) }.unwrap_or_default()
}

/// Convenience: current time as Unix milliseconds.
///
/// Returns `0` if the host response could not be parsed (which should never
/// happen - the host always returns a decimal integer).
pub fn now_ms() -> u64 {
    now(format::MILLIS).parse().unwrap_or(0)
}

/// Convenience: current time as Unix seconds.
pub fn now_unix() -> u64 {
    now(format::UNIX).parse().unwrap_or(0)
}

/// Convenience: current time as an RFC 3339 string.
pub fn now_rfc3339() -> String {
    now(format::RFC3339)
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::ffi::test_host;

    #[test]
    fn now_passes_format_in_args() {
        test_host::reset();
        test_host::with_mock(|m| m.timestamp_response = Some("2026-04-07T11:12:13Z".into()));
        let s = now(format::RFC3339);
        assert_eq!(s, "2026-04-07T11:12:13Z");

        let captured = test_host::read_mock(|m| m.last_timestamp_args.clone()).unwrap();
        let parsed: serde_json::Value = serde_json::from_str(&captured).unwrap();
        assert_eq!(parsed["format"], "rfc3339");
    }

    #[test]
    fn now_ms_parses_decimal_response() {
        test_host::reset();
        test_host::with_mock(|m| m.timestamp_response = Some("1759839133000".into()));
        assert_eq!(now_ms(), 1_759_839_133_000);
    }

    #[test]
    fn now_unix_parses_decimal_response() {
        test_host::reset();
        test_host::with_mock(|m| m.timestamp_response = Some("1759839133".into()));
        assert_eq!(now_unix(), 1_759_839_133);
    }

    #[test]
    fn now_unparseable_response_zero() {
        test_host::reset();
        test_host::with_mock(|m| m.timestamp_response = Some("not-a-number".into()));
        assert_eq!(now_ms(), 0);
        assert_eq!(now_unix(), 0);
    }

    #[test]
    fn now_rfc3339_uses_rfc3339_format() {
        test_host::reset();
        test_host::with_mock(|m| m.timestamp_response = Some("2026-04-07T00:00:00Z".into()));
        let s = now_rfc3339();
        assert_eq!(s, "2026-04-07T00:00:00Z");
        let captured = test_host::read_mock(|m| m.last_timestamp_args.clone()).unwrap();
        assert!(captured.contains("rfc3339"));
    }

    #[test]
    fn format_constants_match_expected_strings() {
        assert_eq!(format::UNIX, "unix");
        assert_eq!(format::MILLIS, "ms");
        assert_eq!(format::NANOS, "ns");
        assert_eq!(format::RFC3339, "rfc3339");
        assert_eq!(format::HTTP, "http");
        assert_eq!(format::ISO8601, "iso8601");
    }
}