timer-deque-rs

Crates.iotimer-deque-rs
lib.rstimer-deque-rs
version0.8.0
created_at2025-08-21 23:42:23.548714+00
updated_at2025-12-10 01:21:13.612623+00
descriptionA OS based timer and timer queue which implements timeout queues of different types.
homepage
repositoryhttps://codeberg.org/4neko/timer-deque-rs
max_upload_size
id1805625
size461,454
Aleksandr Morozov (eesekaj)

documentation

README

timer-deque-rs

Description

A OS based timer and timer event dequeue which can be used to create a simple timeout scheduling. Can be used just as OS timer or use it together with the timeout deque.

This crate is still incomplete and not properly tested. The proof of concept is now developed.

Policy
  • This crate i.e code is NOT an Open Source software. This is a FREE (gratis) software and follows the principle of Sources Available/Disclosed software which should be fairly used.
  • It is published under FSF/OSI approved licenses however author does not follow/share/respect OSI and FSF principles and phylosophy.
  • License is subject to be changed in further versions without warning.
  • If you are using code in non-free (in terms of gratis) software you MUST NEVER demand a development of any features which are missing and needed for your business if you are not sponsoring/contributing those changes.
  • Access to the code can be limited by author to specific entities due to the local laws (not my bad or fault)(despite what is said in the license).
AI policy
  • AI generated sloppy code is prohibited. AI generates slop "a priori" (anyway).
  • Licenses (thank you OSS sectarians ) do not anyhow limit AI training, but f^ck you all - ChatGPT, CockPilot, especially Claude and rest unidentified cr@p.
  • It is strongly discouraged from using the AI based tools to write or enhance the code. AI slope would 100% violate the license by introducing the 3rd party licensed code.
Pull requests

The pull requests are now supported because the repository was moved to Codeberg. The alternative way is to send patches over the email to patch[at]4neko.org.

In case if you would like to contribute the code, please use pull request. Your pull request should include:

  • Description of changes and why it is needed.

  • Test the pull request.

    In case of you prefer email and patch files please consider the following:

  • For each feature or fix, please send patches separatly.

  • Please write what your patch is implementing or fixing.

  • I can read the code and I am able to understand it, so don't write a poem or essay in the description to the patches.

  • Please test your patch.

Questions about license MPL-2.0
  • Can I use the MPL-2.0 licensed code (crate) in larger project licensed with more permissive license like BSD or MIT.

Yes, MPL- and Apache-licensed code can be used with an MIT codebase (so in that sense, they are "compatible"). However, the MPL- / Apache-licensed code remains under its original license. (So although compatible, you cannot relicense someone else's MPL or Apache code into the MIT license.) This means that your final codebase will contain a mix of MPL, Apache, and MIT licensed code. As an example, MPL has weak copyleft, so if you modified an MPL file, that file (including your changes) must remain under the MPL license.

Answer1

  • I want to distribute (outside my organization) executable programs or libraries that I have compiled from someone else's unchanged MPL-licensed source code, either standalone or part of a larger work. What do I have to do?

You must inform the recipients where they can get the source for the MPLed code in the executable program or library you are distributing (i.e., you must comply with Section 3.2). You may distribute any executables you create under a license of your choosing, as long as that license does not interfere with the recipients' rights to the source under the terms of the MPL.

MPL2.0 FAQ

Questions about license EUPL-1.2

You should use this license if you are located in the EU which gives you more advantages over GPL because in case of any disputes, the license allows you to defend your rights in a European Union country, in this case it will be Spain. It has also been translated into all languages of the EU member states.

Matrix of EUPL compatible open source licences

EUPL-1.2 is incompatiable with GPL according to GNU ORG

This is a free software license. By itself, it has a copyleft comparable to the GPL's, and incompatible with it.

Version

v 0.8.0-development, Rust edition 2024

Changelog
  • Added a crossplatform layer due to experimental Windows support introduction.

  • Added Windows support. Timer is based on CreateWaitableTimerExW and poll IOCP. mio crate is not supported because it is not able to associate timer's handle.

  • Added TimerId for timer identification.

Changelog v0.7.0
  • Added MIO support for TimerFd. This feature is not enbaled by default and should be enabled using feature = enable_mio_compat
  • A TimerExpMode new_* arguments changed to impl Into<RelativeTime> impl Into<AbsoluteTime>.
  • Added more From<> for AbsoluteTimer and RelativeTime.
Changelog v0.6.0

A large changes in API!

  • The TimerFd and poll are now separated. Any instance which implements FdTimerMarker trait can be added to poll. The instance is consumed and converted into PolledTimerFd.
  • Removed remove events from poll.
  • The poll is now tracking internally added TimerFd instances.
Changelog v0.5.2

Changes in the timer_portable.

  • c
  • Updated test.
Changelog v0.5.1

Changes in the timer_portable.

  • Fixed periodic timer timer_kqueue_fd_bsd.rs.
  • Fixed Tokio Async fd error. The AsyncFd::with_interest should be used instead of AsyncFd::new.
  • The ICoW was replaces with a beter option AtomicCell for this particular case.
Changelog v0.5.0

Changes in the timer_portable.

  • A BSD (timers) experimental support was introduced with a patch which is in master of the git before the crate release. It inclused a both KQueue and timerfd (Linux compat) based timer and poll. Features bsd_use_timerfd and bsd_use_poll enbales a specific subsystems. bsd_use_poll switches from KQueue to Poll, bsd_use_timerfd switches from KQueue to TimerFd.
  • Changes in the poll and timer interfaces.

Important

A tokio's AsyncFd throws error when trying to use it on all KQueue, timerfd, poll. The reason is unknown. Probably this is due regresson or because all three are read-only.

Changelog v0.4.0

Changes in the layout, poll system and tasks.

  • A poll now provides an option to interrupt the polling process from another thread. Also, polling can be interrupted by adding or removing timer.
  • Added a simple task spawner and executor based on the parallel execution.

License:

Source code is available as Free S-AS (Free Source-Available Software) and distributed under: MPL-2.0 OR MIT OR EUPL-1.2

Manifest

[!IMPORTANT]
In case if any of the behaviours from the "must never" list is/are detected, please stop using the crate immidiatly and report the problem to developer!

Capabilities

This crate makes call to the following OS APIs:

  • epoll (Linux)
  • timerfd (xBSD/Linux)
  • kqueue (xBSD)
  • poll (xBSD)
  • IOCP, CreateWaitableTimerExW (Windows)

This crate must never:

  • Must never open any network connections!
  • Must never access any files on the local/remote filesystems!
  • Must never create/use any shared memory!

Supports:

  • GNU/Linux.
  • Two deque types with the scheduling using absolute time.
  • Synchronious (parallel) task spawner and executor.
  • Async
  • FreeBSD (experimental)
  • TimerFd MIO compat (feature enable_mio_compat)
  • Windows (very experimental) (does not support mio crate)

ToDo

  • other BSD based systems (kqueue) i.e (OSX, OpenBSD, NetBSD, DragonflyBSD)
  • other timers types and queues i.e async task

Issues tracker:

The project has moved to Codeberg.

Features

MIO

  • enable_mio_compat - enables the crate MIO and adds support for OrderTimerDeque and TimerFd. On Windows it has no effect.

Below is related to BSD systems

  • bsd_use_timerfd - use timerfd instead of kqueue
  • bsd_use_poll - use poll instread of kqueue

Usage:

see ./examples/ there

Diagrams

OrderdTimerDequeOnce operation mode

Diagram
          ┌────────────────────────────┐                                
          │                            │                                
          │   OrderdTimerDequeOnce     │                                
          │                            │                                
          └────────────────────────────┘                                
┌─────────────────────────────┐           ┌────────────────────────────┐
│       Deque                 │           │        TimerFD             │
│                             │           │                            │
│                             │           │  timeout: 12332456         │
│   ┌─────────────────────┐   │           │      absoute time          │
│   │  ITEM               │   │           └───────────┬────────────────┘
│   │  TIMEOUT: 12332456  │ ──┼──────┐                │                 
│   └─────────────────────┘   │      │      ──────────┼─────────────    
│                             │      │                │                 
│                             │      │                ▼                 
│   ┌─────────────────────┐   │      │      ┌────────────────────┐      
│   │  ITEM               │   │      │      │                    │      
│   │  TIMOEUT: 12334543  ┼───┼────┐ │      │     timeout        │      
│   └─────────────────────┘   │    │ │      └─────────┬──────────┘      
│                             │    │ │                │                 
│                             │    │ │                │                 
│   ┌─────────────────────┐   │    │ │                ▼                 
│   │  ITEM               │   │    │ │      ┌────────────────────┐      
│   │  TIMEOUT: 12335654  │   │    │ │      │                    │      
│   └─────────────────────┘   │    │ └────► │      pop_front     │      
│                             │    │        │  timeout <= cur_tm │      
│                             │    │        └─────────┬──────────┘      
│       ............          │    │                  │                 
│                             │    │                  │                 
│                             │    │                  │                 
└─────────────────────────────┘    │                  ▼                 
                                   │        ┌──────────────────┐        
                                   │        │                  │        
                                   └───────►│    set_timer     │        
                                            │                  │        
                                            └─────────┬────────┘        
                                                      │                 
                                        ┌─────────────▼──────────────┐  
                                        │        TimerFD             │  
                                        │                            │  
                                        │  timeout: 12334543         │  
                                        │      absoute time          │  
                                        └──────────┬─────────────────┘  
                                                   │                    
                                           ┌───────▼────────────┐       
                                           │                    │       
                                           │     timeout        │       
                                           └─────────┬──────────┘       

OrderdTimerDequeuPeriodic operation mode

Diagram
                 ┌─────────────────────────────┐                                
                 │                             │                                
                 │   OrderdTimerDequeuPeriodic │                                
                 │                             │                                
                 └─────────────────────────────┘                                
       ┌─────────────────────────────┐           ┌────────────────────────────┐ 
       │       Deque                 │           │        TimerFD             │ 
       │                             │           │                            │ 
       │                             │           │  timeout: 12332456         │ 
       │   ┌─────────────────────┐   │           │      absoute time          │ 
       │   │  ITEM               │   │             ──────────┬────────────────┘ 
       │   │  TIMEOUT: 12332456  │ ──┼───────┐               │                  
       │   │  EXTEND: 100        │   │       │     ──────────┼─────────────     
       │   └─────────────────────┘   │       │               │                  
       │                             │       │               ▼                  
       │   ┌─────────────────────┐   │       │     ┌────────────────────┐       
       │   │  ITEM               │   │       │     │                    │       
       │   │  TIMOEUT: 12334543  ┼───┼────┐  │     │     timeout        │       
       │   │  EXTEND: 120        │   │    │  │     └─────────┬──────────┘       
       │   └─────────────────────┘   │    │  │               │                  
       │                             │    │  │               │                  
       │   ┌─────────────────────┐   │    │  │               ▼                  
       │   │  ITEM               │   │    │  │     ┌────────────────────┐       
       │   │  TIMEOUT: 12335654  │   │    │  │     │                    │       
       │   │  EXTEND: 150        │   │    │  └────►│      pop_front     │       
       │   └─────────────────────┘   │    │        │  timeout <= cur_tm │       
       │                             │    │        └─────────┬──────────┘       
┌──────┼───►   ............          │    │                  │                  
│      │                             │    │                  │                  
│      │                             │    │                  │                  
│      └─────────────────────────────┘    │                  ▼                  
│                                         │        ┌───────────────────────────┐
│                                         │        │  ITEM                     │
│              return back with new tm    │        │  TIMEOUT: 12332456+100    │
└─────────────────────────────────────────┼────────┼                           │
                                          │        │  NEW_TIMEOUT: 12332556    │
                                          │        └──────────┬────────────────┘
                                          │                   ▼                 
                                          │          ┌──────────────────┐       
                                          │          │                  │       
                                          │          │    set_timer     │       
                                          └─────────►│                  │       
                                                     └─────────┬────────┘       
                                                               │                
                                                 ┌─────────────▼──────────────┐ 
                                                 │        TimerFD             │ 
                                                 │                            │ 
                                                 │  timeout: 12334543         │ 
                                                 │      absoute time          │ 
                                                 └──────────┬─────────────────┘ 
                                                            │                   
                                                    ┌───────▼────────────┐      
                                                    │                    │      
                                                    │     timeout        │      
                                                    └─────────┬──────────┘      
                                                                                
                                                         ...                    

The items are stored sorted by timeout VecDeque. The identification of the item in the queue is perfomed by PartialEq and Eq by the instance or ID, and not by timeout value. The timer is set to the nearest (by time) value.

Examples

For every sync example, the event notification is used. In case of Linux, the EPoll is used.

Timer queue type consumer

This type of deque is consuming the instance.

Example
use std::{cmp::Ordering, fmt, sync::Arc};

use timer_deque_rs::
{
    AbsoluteTime, TimerDequeConsumer, TimerPoll, deque_timeout::{DequeOnce, OrderTimerDeque, OrderedTimerDequeMode}
};

#[derive(Debug, PartialEq, Eq, Clone)]
struct TestItem(u64);

impl fmt::Display for TestItem
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
    {
        write!(f, "0 = {}", self.0)
    }
}

fn main()
{
    let ev_watch = TimerPoll::new().unwrap();

    let time_list = 
        OrderTimerDeque
            ::<DequeOnce, TimerDequeConsumer<Arc<TestItem>, _>>
            ::new("test_label".into(), 4, false, true).unwrap();

    // add timer to event 
    let mut time_list_poll = ev_watch.add(time_list).unwrap();

    let abs_time = AbsoluteTime::now();
    
    let tss_set1 = DequeOnce::new(abs_time.clone().add_sec(3));
    let ent1 = Arc::new(TestItem(1));

    let tss_set2 = DequeOnce::new(abs_time.clone().add_sec(7));
    let ent2 = Arc::new(TestItem(2));

    let tss_set3 = DequeOnce::new(abs_time.clone().add_sec(10));
    let ent3 = Arc::new(TestItem(3));

    time_list_poll.get_inner_mut().add(ent1.clone(), tss_set1).unwrap();
    time_list_poll.get_inner_mut().add(ent2.clone(), tss_set2).unwrap();
    time_list_poll.get_inner_mut().add(ent3.clone(), tss_set3).unwrap();

    // poll timer for events (it can be done in separate thread)
    let res = ev_watch.poll(Option::None).unwrap();

    let poll_timeout = AbsoluteTime::now();

    println!("poll with result {:?}", res);

    assert_eq!(res.is_none(), false);
    assert_eq!(res.as_ref().unwrap().len(), 1);
    
    // get exact result
    let pet = res.unwrap().pop().unwrap();


    let timeout_items = time_list_poll.get_inner_mut().handle_timer_event(pet).unwrap();

    println!("timer timeout with result: {:?}", timeout_items);

    assert_eq!(timeout_items.is_some(), true);
    assert_eq!(timeout_items.as_ref().unwrap().len(), 1); // only one item
    assert_eq!(timeout_items.as_ref().unwrap()[0], ent1); // item 1


    let timeout_item = timeout_items.unwrap().pop().unwrap();

    println!("timer item: {}, timeout: {}, curtime: {}", timeout_item, tss_set1, poll_timeout);
    assert_eq!(tss_set1.get_absolut_timeout().seconds_cmp(&poll_timeout) == Ordering::Equal, true);

    // removing second item from queue, so ent3 should be next to fire
    let rem = time_list_poll.get_inner_mut().remove_from_queue(&ent2).unwrap();

    println!("item {:?} removed from shed. queue", rem);
    println!("queue len: {}", time_list_poll.get_inner().timer_queue_len());

    assert_eq!(rem.is_some(), true);
    assert_eq!(rem, Some(ent2));
    assert_eq!(time_list_poll.get_inner().timer_queue_len(), 1); // only ent3 left

    // -----
    // wait for events (ent3)
    let res = ev_watch.poll(Option::None).unwrap();

    let poll_timeout = AbsoluteTime::now();

    println!("poll with result {:?}", res);

    assert_eq!(res.is_none(), false);
    assert_eq!(res.as_ref().unwrap().len(), 1);
    
    // get exact result
    let pet = res.unwrap().pop().unwrap();


    let timeout_items = time_list_poll.get_inner_mut().handle_timer_event(pet).unwrap();

    println!("timer timeout with result: {:?}", timeout_items);

    assert_eq!(timeout_items.is_some(), true);
    assert_eq!(timeout_items.as_ref().unwrap().len(), 1); // only one item
    assert_eq!(timeout_items.as_ref().unwrap()[0], ent3); // item 1


    let timeout_item = timeout_items.unwrap().pop().unwrap();

    println!("timer item: {}, timeout: {}, curtime: {}", timeout_item, tss_set3, poll_timeout);
    assert_eq!(tss_set3.get_absolut_timeout().seconds_cmp(&poll_timeout) == Ordering::Equal, true);

    println!("timer queue len: {}", time_list_poll.get_inner().timer_queue_len());

    assert_eq!(time_list_poll.get_inner().timer_queue_len(), 0); // queue should be empty

    return;
}

Timer queue type ticket issuer

This type of dequeue is issuing the ticket for an instance which can be cancelled (ticket).

Example
use std::{cmp::Ordering, fmt};

use timer_deque_rs::
{
    AbsoluteTime, TimerDequeTicket, TimerDequeTicketIssuer, TimerPoll, 
    deque_timeout::{DequeOnce, OrderTimerDeque, OrderedTimerDequeMode}
};

#[derive(Debug, PartialEq, Eq)]
struct TestItem(TimerDequeTicket);

impl fmt::Display for TestItem
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
    {
        write!(f, "0 = {}", self.0)
    }
}

fn main()
{
    let ev_watch = TimerPoll::new().unwrap();

    let time_list = 
        OrderTimerDeque
            ::<DequeOnce, TimerDequeTicketIssuer<_>>
            ::new("test_label".into(), 4, false, true).unwrap();

    // add timer to event monitor
    let mut time_list_polled = ev_watch.add(time_list).unwrap();


    let abs_time = AbsoluteTime::now();

    // add to timer
    let tss_set1 = DequeOnce::new(abs_time.clone().add_sec(3));
    let ticket1 = time_list_polled.get_inner_mut().add(tss_set1).unwrap();
    let ent1 = TestItem(ticket1);

    let tss_set2 = DequeOnce::new(abs_time.clone().add_sec(7));
    let ticket2 = time_list_polled.get_inner_mut().add(tss_set2).unwrap();
    let ent2 = TestItem(ticket2);

    let tss_set3 = DequeOnce::new(abs_time.clone().add_sec(10));
    let ticket3 = time_list_polled.get_inner_mut().add(tss_set3).unwrap();
    let ent3 = TestItem(ticket3);

    // poll timer

    let res = ev_watch.poll(Option::None).unwrap();

    let poll_timeout = AbsoluteTime::now();

    println!("poll with result: {:?}", res);

    // call deque insance to handle the timer result

    assert_eq!(res.as_ref().unwrap().len(), 1); // only one item

    let res = res.unwrap().pop().unwrap();

    let timeout_items = 
        time_list_polled.get_inner_mut().handle_timer_event(res).unwrap();
    

    assert_eq!(timeout_items.is_some(), true); // only one item
    assert_eq!(timeout_items.as_ref().unwrap().len(), 1); // only one item
    assert_eq!(timeout_items.as_ref().unwrap()[0], ent1.0); // item 1
    assert_eq!(ent1.0.is_queued(), false);

    let timedout = timeout_items.unwrap()[0];

    println!("timer item: {}, timeout: {}, curtime: {}", &timedout, tss_set1, poll_timeout);
    assert_eq!(tss_set1.get_absolut_timeout().seconds_cmp(&poll_timeout) == Ordering::Equal, true);

    // removing second item from queue, so ent3 should be next to fire
    println!("item {} removing from shed. queue", ent2);

    let res = time_list_polled.get_inner_mut().remove_from_queue(&ent2.0.get_deque_id()).unwrap();
 
    println!("queue len: {}", time_list_polled.get_inner().timer_queue_len());
    assert_eq!(res, Some(*ent2.0.get_deque_id()));
    assert_eq!(time_list_polled.get_inner().timer_queue_len(), 1); // only ent3 left
   

    // -----
    // wait for events (ent3)
    let res = ev_watch.poll(Option::None).unwrap();

    let poll_timeout = AbsoluteTime::now();

    assert_eq!(res.as_ref().unwrap().len(), 1); // only one item

    let res = res.unwrap().pop().unwrap();

    println!("poll with result: {}", res);

    let timeout_items = 
        time_list_polled.get_inner_mut().handle_timer_event(res).unwrap();

    assert_eq!(timeout_items.as_ref().unwrap().len(), 1); // only one item
    assert_eq!(timeout_items.as_ref().unwrap()[0], ent3.0); // item 3

    let timeout_item = timeout_items.unwrap()[0];

    println!("timer item: {}, timeout: {}, curtime: {}", &timeout_item, tss_set3, poll_timeout);
    assert_eq!(tss_set3.get_absolut_timeout().seconds_cmp(&poll_timeout) == Ordering::Equal, true);

    println!("timer queue len: {}", time_list_polled.get_inner().timer_queue_len());

    assert_eq!(time_list_polled.get_inner().timer_queue_len(), 0); // queue should be empty

    return;
}

Timer queue type notifier (async) using more efficient AsyncFd

In this example, the notifier (signal) type of deque is used in async context by wrapping the timer deque in the AsyncFd. This is more efficient than jus polling the FD for events like in previous example.

Example
use std::{cmp::Ordering, fmt, sync::Arc};

use timer_deque_rs::
{
    AbsoluteTime, 
    TimerDequeConsumer, 
    DequeOnce, 
    OrderTimerDeque, 
    OrderedTimerDequeMode
};
use tokio::io::{Interest, unix::AsyncFd};


#[derive(Debug, PartialEq, Eq, Clone)]
struct TestItem(u64);

impl fmt::Display for TestItem
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
    {
        write!(f, "0 = {}", self.0)
    }
}

#[tokio::main]
async fn main()
{
    let time_list = 
        OrderTimerDeque
            ::<DequeOnce, TimerDequeConsumer<Arc<TestItem>, _>>
            ::new("test_label_async".into(), 4, false, true)
                .unwrap();

    let mut time_list = 
        AsyncFd::try_with_interest(time_list, Interest::READABLE).unwrap();

    let abs_time = AbsoluteTime::now();

    let tss_set1 = DequeOnce::new(abs_time.clone().add_sec(3));
    let ent1 = Arc::new(TestItem(1));

    let tss_set2 = DequeOnce::new(abs_time.clone().add_sec(7));
    let ent2 = Arc::new(TestItem(2));

    let tss_set3 = DequeOnce::new(abs_time.clone().add_sec(10));
    let ent3 = Arc::new(TestItem(3));

    time_list.get_mut().add(ent1.clone(), tss_set1).unwrap();
    time_list.get_mut().add(ent2.clone(), tss_set2).unwrap();
    time_list.get_mut().add(ent3.clone(), tss_set3).unwrap();

    // ---- 
    // poll for event
    let mut guard = time_list.readable_mut().await.unwrap();
    
    let poll_timeout = AbsoluteTime::now();

    // read event from timer
    let timeout_items = guard.get_inner_mut().async_poll_for_event_and_process().await.unwrap();
    drop(guard);

    println!("timer timeout with result: {:?}", timeout_items);

    assert_eq!(timeout_items.is_some(), true);
    assert_eq!(timeout_items.as_ref().unwrap().len(), 1); // only one item
    assert_eq!(timeout_items.as_ref().unwrap()[0], ent1); // item 1

    let timeout_item = timeout_items.unwrap().pop().unwrap();
    
    println!("timer item: {}, timeout: {}, curtime: {}", timeout_item, tss_set1, poll_timeout);
    assert_eq!(tss_set1.get_absolut_timeout().seconds_cmp(&poll_timeout) == Ordering::Equal, true);

    // removing second item from queue, so ent3 should be next to fire
    let rem = time_list.get_mut().remove_from_queue(&ent2).unwrap();

    println!("item {:?} removed from shed. queue", rem);
    println!("queue len: {}", time_list.get_ref().timer_queue_len());

    assert_eq!(rem.is_some(), true);
    assert_eq!(rem, Some(ent2));
    assert_eq!(time_list.get_ref().timer_queue_len(), 1); // only ent3 left

    // -----
    // wait for events (ent3)

    // poll for event
    let mut guard = time_list.readable_mut().await.unwrap();
    
    let poll_timeout = AbsoluteTime::now();

    // read event from timer
    let timeout_items = guard.get_inner_mut().async_poll_for_event_and_process().await.unwrap();
    drop(guard);

    println!("timer timeout with result: {:?}", timeout_items);

    assert_eq!(timeout_items.is_some(), true);
    assert_eq!(timeout_items.as_ref().unwrap().len(), 1); // only one item
    assert_eq!(timeout_items.as_ref().unwrap()[0], ent3); // item 1

    let timeout_item = timeout_items.unwrap().pop().unwrap();
    
    println!("timer item: {}, timeout: {}, curtime: {}", timeout_item, tss_set1, poll_timeout);
    assert_eq!(tss_set1.get_absolut_timeout().seconds_cmp(&poll_timeout) == Ordering::Equal, true);


    println!("queue len: {}", time_list.get_ref().timer_queue_len());

    assert_eq!(time_list.get_ref().timer_queue_len(), 0); // queue should be empty

    return;
}

Generic, OS based timer without queue

Just simple timer based on OS functionality.

Example
use std::{borrow::Cow, cmp::Ordering, time::Instant};

use timer_deque_rs::
{
    timer_portable::
    {
        timer::TimerFd, 
        FdTimerCom, 
        TimerExpMode, 
        TimerFlags, 
        TimerType
    }, 
    AbsoluteTime
};

fn main()
{
    // timer init as blocking
    let timer = 
        TimerFd::new(Cow::Borrowed("test"), TimerType::CLOCK_REALTIME, 
            TimerFlags::empty()).unwrap();

    let s = Instant::now();

    let abs_time = AbsoluteTime::now().add_sec(3);
    let exp_time = 
         TimerExpMode::<AbsoluteTime>::new_oneshot(abs_time);

    // setting timer
    let res = timer.set_time(exp_time);
    
    println!("timer was set: '{}'", exp_time);

    assert_eq!(res.is_ok(), true, "{}", res.err().unwrap());

    
    let ovf = timer.read().unwrap().unwrap();

    let now_abs = AbsoluteTime::now();
    let e = s.elapsed();

    assert_eq!(ovf, 1);
    assert_eq!(abs_time.seconds_cmp(&now_abs) == Ordering::Equal, true);

    println!("elapsed: {:?}, now: {}, set: {}", e, now_abs, abs_time);

    assert_eq!((e.as_millis() <= 3100), true);

    println!("Success");
    return;
}

A task spawn and executor

A simple parallel task spawner

Example
    use std::{sync::mpsc::{self, RecvTimeoutError, Sender}, time::{Duration, Instant}};

    use crate::{periodic_task::sync_tasks::{PeriodicTask, PeriodicTaskResult, PeriodicTaskTime, SyncPeriodicTasks}, AbsoluteTime, RelativeTime};

    #[derive(Debug)]
    struct TaskStruct1
    {
        a1: u64,
        s: Sender<u64>,
    }

    impl TaskStruct1
    {
        fn new(a1: u64, s: Sender<u64>) -> Self
        {
            return Self{ a1: a1, s };
        }
    }

    impl PeriodicTask for TaskStruct1
    {
        fn exec(&mut self) -> PeriodicTaskResult
        {
            println!("taskstruct1 val: {}", self.a1);

            let _ = self.s.send(self.a1);

            return PeriodicTaskResult::Ok;
        }
    }

    fn main()
    {
        let s = SyncPeriodicTasks::new(1.try_into().unwrap()).unwrap();

        let (send, recv) = mpsc::channel::<u64>();

        let task1 = TaskStruct1::new(2, send);
        let task1_ptt = PeriodicTaskTime::exact_time(AbsoluteTime::now() + RelativeTime::new_time(3, 0));
        let task1_guard = s.add("task1", task1, task1_ptt).unwrap();

        println!("added");
        let val = recv.recv();

        println!("{:?}", val);

        drop(task1_guard);
    }

MIO poll

A poll using MIO (Unix only!)

Feature enable_mio_compat must be enabled.

Example
    use std::{cmp, sync::Arc, time::Duration};

    use mio::{Events, Interest, Poll};

    use crate::
    {
      AbsoluteTime, 
      TimerDequeConsumer, 
      TimerDequeTicketIssuer, 
      TimerFdMioCompat, 
      deque_timeout::{DequeOnce, OrderTimerDeque, tests::TestItem}
    };

    fn main()
    {
        let mut poll = Poll::new().unwrap();
        let mut events = Events::with_capacity(2);

        let mut timer1 = 
            OrderTimerDeque
                ::<DequeOnce, TimerDequeTicketIssuer<_>>
                ::new("test_label1".into(), 4, false, true).unwrap();

        let tok = timer1.get_token();
        poll
          .registry()
          .register(&mut timer1, tok, Interest::READABLE)
          .unwrap();

        let tss_set = DequeOnce::new(AbsoluteTime::now() + Duration::from_secs(2));

        let ticket = timer1.add(tss_set).unwrap();

        poll.poll(&mut events, None).unwrap();

        for ev in events.iter()
        {
           if ev.token() == timer1.get_token()
           {
            
            // wait for event
            let res = timer1.wait_for_event_and_process().unwrap().unwrap();
            assert_eq!(res.len(), 1);

            println!("res: {:?}", res);
           }
           else
           {
             panic!("unknown token");
           }
        }
    }
Commit count: 0

cargo fmt