timer_deque_rs/
common.rs

1/*-
2 * timer-deque-rs - a Rust crate which provides timer and timer queues based on target OS
3 *  functionality.
4 * 
5 * Copyright (C) 2025 Aleksandr Morozov alex@nixd.org
6 *  4neko.org alex@4neko.org
7 * 
8 * The timer-rs crate can be redistributed and/or modified
9 * under the terms of either of the following licenses:
10 *
11 *   1. the Mozilla Public License Version 2.0 (the “MPL”) OR
12 *                     
13 *   2. The MIT License (MIT)
14 *                     
15 *   3. EUROPEAN UNION PUBLIC LICENCE v. 1.2 EUPL © the European Union 2007, 2016
16 */
17
18use std::fmt;
19
20use chrono::{DateTime, Local};
21
22
23/// Returns the current [DateTime].
24#[inline]
25pub 
26fn get_current_timestamp() -> DateTime<Local>
27{
28    return chrono::offset::Local::now();
29}
30
31/// The "sequenceId" parameter tracks the sequence in which the
32/// originator submits messages to the syslog transport for sending.
33#[cfg(target_has_atomic = "64")]
34static ORD_ID: std::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32::new(0);
35
36/// The "sequenceId" parameter tracks the sequence in which the
37/// originator submits messages to the syslog transport for sending.
38#[cfg(not(target_has_atomic = "64"))]
39static ORD_ID: std::sync::Mutex<u32> = std::sync::Mutex::new(0);
40
41/// A uniq ID which is generated for every ticket. It is a 128bit
42/// value which consists from timestamp sec and ns and random number.
43#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
44pub struct TimerDequeId
45{
46    /// seconds
47    pub(crate) timestamp: i64,
48
49    /// nanoseconds
50    pub(crate) timestamp_ns: u32,
51
52    /// random number
53    pub(crate) ran_id: u32,
54}
55
56
57impl fmt::Display for TimerDequeId
58{
59    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
60    {
61        write!(f, "{:X}/{:X}/{:X}", self.timestamp, self.timestamp_ns, self.ran_id)
62    }
63}
64
65impl TimerDequeId
66{
67    #[cfg(target_has_atomic = "64")] 
68    fn generate_ord_numer() -> u32
69    {
70        use std::sync::atomic::{Ordering};
71
72        let mut last = ORD_ID.load(Ordering::Relaxed);
73        
74        loop 
75        {
76            let seq_id = 
77                match last.checked_add(1) 
78                {
79                    Some(id) => id,
80                    None =>
81                    {
82                        0
83                    }
84                };
85
86            match ORD_ID.compare_exchange_weak(last, seq_id, Ordering::Relaxed, Ordering::Relaxed) 
87            {
88                Ok(_) => 
89                    return seq_id,
90                Err(id) => 
91                    last = id,
92            }
93        }
94    }
95
96    #[cfg(not(target_has_atomic = "64"))]
97    fn generate_sequence_num() -> u32
98    {
99        let mut seq_id_cnt = 
100            ORD_ID.lock().unwrap_or_else(std::sync::PoisonError::into_inner);
101
102        let seq_id = 
103            match seq_id_cnt.checked_add(1) 
104            {
105                Some(id) => id,
106                None =>
107                {
108                    0
109                }
110            };
111
112        *seq_id_cnt = seq_id;
113        drop(seq_id_cnt);
114
115        return seq_id;
116    }
117
118    pub(crate) 
119    fn new() -> Self
120    {
121        let ts = get_current_timestamp();
122        let ord_num = Self::generate_ord_numer();
123
124        return 
125            Self
126            { 
127                timestamp: 
128                    ts.timestamp(), 
129                timestamp_ns: 
130                    ts.timestamp_subsec_nanos(), 
131                ran_id: 
132                    ord_num, 
133            }; 
134    }
135}
136