⎇ 545dd59c727b2c6b9752ab4b29de64ad0d24b35c
crates/runtime/sandokan-lifecycle/src/ttl.rs
Ñawpa willay
Pi imata llamkarqan
ch'uya
feat(sandokan-lifecycle): A4 — primitivas de lifecycle agnósticas
1//! Time-to-live anclado a un `Instant`.
2
3use std::time::{Duration, Instant};
4
5/// Time-to-live. Marca un instante límite tras el cual una entidad
6/// supervisada se considera vencida. Runtime-only (no serializable:
7/// `Instant` no tiene representación estable).
8#[derive(Debug, Clone, Copy)]
9pub struct Ttl {
10 deadline: Instant,
11}
12
13impl Ttl {
14 /// TTL que vence `lifetime` después de ahora.
15 pub fn new(lifetime: Duration) -> Self {
16 Self { deadline: Instant::now() + lifetime }
17 }
18
19 /// TTL con un deadline absoluto explícito.
20 pub fn from_deadline(deadline: Instant) -> Self {
21 Self { deadline }
22 }
23
24 /// `true` si el deadline ya pasó.
25 pub fn expired(&self) -> bool {
26 Instant::now() >= self.deadline
27 }
28
29 /// Tiempo restante hasta el deadline. `Duration::ZERO` si ya venció.
30 pub fn remaining(&self) -> Duration {
31 self.deadline.saturating_duration_since(Instant::now())
32 }
33
34 /// El instante límite.
35 pub fn deadline(&self) -> Instant {
36 self.deadline
37 }
38}
39
40#[cfg(test)]
41mod tests {
42 use super::*;
43
44 #[test]
45 fn fresh_ttl_not_expired() {
46 let t = Ttl::new(Duration::from_secs(60));
47 assert!(!t.expired());
48 assert!(t.remaining() > Duration::from_secs(58));
49 }
50
51 #[test]
52 fn past_deadline_is_expired() {
53 let t = Ttl::from_deadline(Instant::now() - Duration::from_secs(1));
54 assert!(t.expired());
55 assert_eq!(t.remaining(), Duration::ZERO);
56 }
57}