timer-deque-rs 0.8.0

A OS based timer and timer queue which implements timeout queues of different types.
Documentation
/*-
 * timer-deque-rs - a Rust crate which provides timer and timer queues based on target OS
 *  functionality.
 * 
 * Copyright (C) 2025 Aleksandr Morozov alex@nixd.org
 *  4neko.org alex@4neko.org
 * 
 * The timer-rs crate can be redistributed and/or modified
 * under the terms of either of the following licenses:
 *
 *   1. the Mozilla Public License Version 2.0 (the “MPL”) OR
 *                     
 *   2. The MIT License (MIT)
 *                     
 *   3. EUROPEAN UNION PUBLIC LICENCE v. 1.2 EUPL © the European Union 2007, 2016
 */

use std::{borrow::Cow, fmt, os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, OwnedHandle, RawHandle}, ptr::{self, null}, task::Poll};

use crossbeam_utils::atomic::AtomicCell;
use windows::
{
    Win32::
    {
        Foundation::{HANDLE, WAIT_OBJECT_0, WAIT_TIMEOUT}, Security::SECURITY_ATTRIBUTES, System::Threading::
        {
            CancelWaitableTimer, 
            CreateWaitableTimerExW, 
            EVENT_ALL_ACCESS, 
            INFINITE, 
            SetWaitableTimer, 
            WaitForSingleObject
        }
    }, 
    core::{Error, PCWSTR}
};

use crate::
{
    FdTimerCom, 
    TimerReadRes, 
    map_portable_err, 
    portable_err, 
    timer_portable::
    {
        AsTimerId, TimerExpMode, TimerId, portable_error::TimerPortResult, timer::{FdTimerRead, ModeTimeType}, windows::{UnixFd, itimerspec}
    }
};

use super::{TimerFlags, TimerType};

/// Internal implementation of the timer for `Windows`.
#[derive(Debug)]
pub struct TimerFdInternal
{
    /// A timer's label.
    label: Cow<'static, str>,

    /// A timer's FD [std::os::windows::raw::HANDLE]
    timer_fd: OwnedHandle,

    /// A timer flags to detect the fd mode
    timer_flags: AtomicCell<TimerFlags>,
}

impl AsHandle for TimerFdInternal
{
    fn as_handle(&self) -> BorrowedHandle<'_> 
    {
        return self.timer_fd.as_handle();
    }
}

impl AsRawHandle for TimerFdInternal
{
    fn as_raw_handle(&self) -> RawHandle 
    {
        return self.timer_fd.as_raw_handle();
    }
}

impl Eq for TimerFdInternal {}

impl PartialEq for TimerFdInternal 
{
    fn eq(&self, other: &Self) -> bool 
    {
        return self.timer_fd.as_raw_handle() == other.timer_fd.as_raw_handle();
    }
}

impl PartialEq<str> for TimerFdInternal
{
    fn eq(&self, other: &str) -> bool 
    {
        return self.label == other;
    }
}

impl AsRef<str> for TimerFdInternal
{
    fn as_ref(&self) -> &str 
    {
        return &self.label;
    }
}

impl fmt::Display for TimerFdInternal
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result 
    {
        write!(f, "{:p}", self.timer_fd.as_raw_handle())
    }
}

impl PartialEq<RawHandle> for TimerFdInternal
{
    fn eq(&self, other: &RawHandle) -> bool 
    {
        return self.timer_fd.as_raw_handle() == *other;
    }
}


impl UnixFd for TimerFdInternal
{

}

impl AsTimerId for TimerFdInternal
{
    fn as_timer_id(&self) -> TimerId 
    {
        return TimerId::from(self.timer_fd.as_raw_handle());
    }
}

impl FdTimerRead for TimerFdInternal
{
    /// Returns [TimerReadRes::Ok] or [TimerReadRes::WouldBlock].
    #[inline]
    fn read(&self) -> TimerPortResult<TimerReadRes<u64>>
    {
        let timeout = 
            if self.timer_flags.load().intersects(TimerFlags::TFD_NONBLOCK) == true
            {
                0
            }
            else
            {
                INFINITE
            };


        let res =
            unsafe { WaitForSingleObject(HANDLE(self.timer_fd.as_raw_handle()), timeout) };

        if res == WAIT_OBJECT_0
        {
            return Ok(TimerReadRes::ok());
        }
        else if res == WAIT_TIMEOUT
        {
            // would block
            return Ok(TimerReadRes::WouldBlock);
        }
        else
        {            
            portable_err!(Error::empty(), "read timer overflow error for timer: '{}'", self.label)
        }
    }
}

impl FdTimerCom for TimerFdInternal
{
    fn new(label: Cow<'static, str>, _timer_type: TimerType, timer_flags: TimerFlags) -> TimerPortResult<Self>
    where 
        Self: Sized 
    {
        let mut label_cstr: Vec<u16> = label.as_ref().encode_utf16().collect();
        label_cstr.push(0);

        // CLOEXEC
        let timer_attr = None;
            /*if timer_flags.intersects(TimerFlags::TFD_CLOEXEC) == true
            {
                None
            }
            else
            {
                Some(
                    SECURITY_ATTRIBUTES
                    {
                        nLength: size_of::<SECURITY_ATTRIBUTES>() as u32,
                        lpSecurityDescriptor: ptr::null_mut(),
                        bInheritHandle: true.into(),
                    }
                )
            };*/

        let hndl = 
            unsafe
            { 
                CreateWaitableTimerExW(
                    timer_attr.map(|f| &f as *const _),  
                    PCWSTR::from_raw(label_cstr.as_ptr()),
                    0,
                    EVENT_ALL_ACCESS.0
                ) 
            }
            .map_err(|e|
                map_portable_err!(e, "timer: '{}' create timer error", label)
            )?;

        return Ok(
            Self
            {
                label: 
                    label,
                timer_fd: 
                    unsafe { OwnedHandle::from_raw_handle(hndl.0) },
                timer_flags: 
                    AtomicCell::new(timer_flags)
            }
        );
    }

    fn set_time<TIMERTYPE: ModeTimeType>(&self, timer_exp: TimerExpMode<TIMERTYPE>) -> TimerPortResult<()> 
    {
        let timeout: itimerspec = timer_exp.try_into()?;
        
        return
            unsafe
            {
                SetWaitableTimer(
                    HANDLE(self.timer_fd.as_raw_handle()), 
                    &timeout.it_value as *const i64,
                    timeout.it_interval,
                    None,
                    None,
                    false
                )
            }
            .map_err(|e|
                map_portable_err!(e, "timer: '{}'set timer error", self.label)
            );
    }

    fn unset_time(&self) -> TimerPortResult<()> 
    {
        return 
            unsafe { CancelWaitableTimer(HANDLE(self.timer_fd.as_raw_handle())) }
                .map_err(|e|
                    map_portable_err!(e, "timer: '{}' unset timer error", self.label)
                );
    }

    fn set_nonblocking(&self, flag: bool) -> TimerPortResult<()> 
    {
        let old_timer_flags = self.timer_flags.load();
        let mut timer_flags = old_timer_flags.clone();

        timer_flags.set(TimerFlags::TFD_NONBLOCK, flag);

        if self.timer_flags.swap(timer_flags) != old_timer_flags
        {
            map_portable_err!(Error::empty(), "changed from another thread");
        }

        return Ok(());
    }

    fn is_nonblocking(&self) -> TimerPortResult<bool> 
    {
        let old_timer_flags = self.timer_flags.load();

        return Ok(old_timer_flags.intersects(TimerFlags::TFD_NONBLOCK));
    }
}

impl Future for &TimerFdInternal
{
    type Output = TimerPortResult<TimerReadRes<u64>>;

    fn poll(self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> std::task::Poll<Self::Output> 
    {
        let res = self.read();

        if let Ok(TimerReadRes::WouldBlock) = res
        {
            cx.waker().wake_by_ref();

            return Poll::Pending;
        }
        else
        {
            return Poll::Ready(res);
        } 
    }
}

impl Future for TimerFdInternal
{
    type Output = TimerPortResult<TimerReadRes<u64>>;

    fn poll(self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> std::task::Poll<Self::Output> 
    {
        let res = self.read();

        if let Ok(TimerReadRes::WouldBlock) = res
        {
            cx.waker().wake_by_ref();

            return Poll::Pending;
        }
        else
        {
            return Poll::Ready(res);
        } 
    }
}