pdk-token-introspection-lib 1.7.0

PDK Token Introspection Library
Documentation
// Copyright (c) 2026, Salesforce, Inc.,
// All rights reserved.
// For full license text, see the LICENSE.txt file

use serde::{Deserialize, Serialize};

/// Represents a fixed time frame with start time and duration.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct FixedTimeFrame {
    /// Start time in milliseconds.
    start_time: i64,
    /// End time in milliseconds.
    end_time: i64,
    /// Duration in milliseconds.
    period: i64,
}

#[allow(dead_code)]
impl FixedTimeFrame {
    /// Creates a new time frame starting at start_time with the given period duration.
    pub fn new(start_time: i64, period: i64) -> Self {
        Self {
            start_time,
            period,
            end_time: start_time + period,
        }
    }
    /// Returns the duration in milliseconds.
    pub fn period(&self) -> i64 {
        self.period
    }

    /// Returns the start time in milliseconds.
    pub fn start_time(&self) -> i64 {
        self.start_time
    }

    /// Returns the end time in milliseconds.
    pub fn end_time(&self) -> i64 {
        self.end_time
    }

    /// Returns the duration as unsigned milliseconds.
    pub fn in_millis(&self) -> u64 {
        self.period.unsigned_abs()
    }

    /// Returns true if the given time is past the end of this time frame.
    pub fn has_finished(&self, now: i64) -> bool {
        !self.in_range(now) && !self.is_border(now)
    }

    fn is_border(&self, now: i64) -> bool {
        now == self.start_time || now == self.end_time
    }

    fn in_range(&self, now: i64) -> bool {
        now > self.start_time && now < self.end_time
    }
}

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

    #[test]
    fn new_creates_correct_time_frame() {
        let frame = FixedTimeFrame::new(1000, 500);
        assert_eq!(frame.start_time(), 1000);
        assert_eq!(frame.end_time(), 1500);
        assert_eq!(frame.period(), 500);
        assert_eq!(frame.in_millis(), 500);
        assert_ne!(frame.start_time(), 999);
        assert_ne!(frame.end_time(), 1501);
    }

    #[test]
    fn has_finished_returns_false_when_in_range() {
        let frame = FixedTimeFrame::new(1000, 500);
        assert!(frame.has_finished(999)); // before start
        assert!(!frame.has_finished(1000)); // start border
        assert!(!frame.has_finished(1250)); // middle
        assert!(!frame.has_finished(1500)); // end border
        assert!(frame.has_finished(1501)); // after end
    }

    #[test]
    fn has_finished_returns_true_when_past_end() {
        let frame = FixedTimeFrame::new(1000, 500);
        assert!(frame.has_finished(1501));
        assert!(frame.has_finished(2000));
        // At end border -> false (proves the distinction)
        assert!(!frame.has_finished(1500));
    }

    #[test]
    fn has_finished_returns_true_when_before_start() {
        let frame = FixedTimeFrame::new(1000, 500);
        // Before start
        assert!(frame.has_finished(0));
        assert!(frame.has_finished(999));
        // At start border
        assert!(!frame.has_finished(1000));
    }

    #[test]
    fn zero_period_creates_instant_frame() {
        let frame = FixedTimeFrame::new(1000, 0);
        assert_eq!(frame.in_millis(), 0);
        // At border
        assert!(!frame.has_finished(1000));
        // Off border
        assert!(frame.has_finished(999));
        assert!(frame.has_finished(1001));
    }
}