nlib 0.1.3

Nate's library. Various things or macro patterns I use to aid in more succint Rust programming.
Documentation
// Copyright 2025 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at http://mozilla.org/MPL/2.0/.

/// Receive from an `mpsc` receiver with a timeout, mapping each outcome to a value.
///
/// This macro wraps `Receiver::recv_timeout`, returning:
/// - the received value on `Ok(v)`;
/// - the result of `$on_timeout` when the wait times out;
/// - the result of `$on_disconnected` when the channel is disconnected.
///
/// ### Type constraints
/// The expressions/blocks passed as `$on_timeout` and `$on_disconnected` **must
/// evaluate to the same type** as the success value (the type carried by the channel),
/// so the whole macro expands to a single, consistent value.
///
/// ### Parameters
/// - `$rx`: an expression evaluating to `std::sync::mpsc::Receiver<T>`.
/// - `$dur`: an expression evaluating to `std::time::Duration`.
/// - `$on_timeout`: a **block** evaluated when `RecvTimeoutError::Timeout`.
/// - `$on_disconnected`: a **block** evaluated when `RecvTimeoutError::Disconnected`.
///
/// Blocks are used so you can place statements, logging, or even `return`/`break`
/// inside the handlers if desired.
///
/// ### Example
/// ```rust
/// # use std::sync::mpsc;
/// # use std::time::Duration;
/// # use your_crate::recv_timeout;
/// # let (_tx, rx) = mpsc::channel::<u32>();
/// let v: u32 = recv_timeout!(
///     rx,
///     Duration::from_millis(10),
///     { 0 },                // on timeout, default to 0
///     { 42 }                // on disconnect, sentinel value
/// );
/// assert!(v == 0 || v == 42); // depending on race
/// ```
#[macro_export]
macro_rules! recv_timeout {
    ($rx:expr, $dur:expr, $on_timeout:block, $on_disconnected:block) => {{
        match $rx.recv_timeout($dur) {
            Ok(v) => v,
            Err(std::sync::mpsc::RecvTimeoutError::Timeout) => $on_timeout,
            Err(std::sync::mpsc::RecvTimeoutError::Disconnected) => $on_disconnected,
        }
    }};
}

/// Convenience wrapper over [`recv_timeout!`] that takes the timeout in milliseconds.
///
/// This converts `$ms` to a `Duration` via `Duration::from_millis` and then
/// defers to `recv_timeout!`.
///
/// ### Parameters
/// - `$rx`: an expression evaluating to `std::sync::mpsc::Receiver<T>`.
/// - `$ms`: an integer-like expression convertible to `u64`.
/// - `$on_timeout`: a **block** evaluated when timeout occurs.
/// - `$on_disconnected`: a **block** evaluated when the channel is disconnected.
///
/// ### Example
/// ```rust
/// # use std::sync::mpsc;
/// # use your_crate::recv_timeout_ms;
/// # let (_tx, rx) = mpsc::channel::<&'static str>();
/// let s: &str = recv_timeout_ms!(
///     rx,
///     5,               // milliseconds
///     { "timeout" },
///     { "disconnected" }
/// );
/// ```
#[macro_export]
macro_rules! recv_timeout_ms {
    ($rx:expr, $ms:expr, $on_timeout:block, $on_disconnected:block) => {{
        $crate::recv_timeout!(
            $rx,
            std::time::Duration::from_millis($ms),
            $on_timeout,
            $on_disconnected
        )
    }};
}

// Copyright 2025 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at http://mozilla.org/MPL/2.0/.

/// Receive from an `mpsc` receiver with a timeout; on timeout, `continue` the loop.
///
/// This macro wraps `Receiver::recv_timeout`, returning:
/// - the received value on `Ok(v)`;
/// - `continue` (i.e., skip to next loop iteration) when the wait times out;
/// - the result of `$on_disconnected` when the channel is disconnected.
///
/// ⚠️ **Must be used inside a loop** because it expands `continue` on timeout.
///
/// ### Type constraints
/// `$on_disconnected` **must evaluate to the same type** as the success value
/// (the type carried by the channel), so the whole macro expands to a consistent value
/// in the non-timeout branches.
///
/// ### Parameters
/// - `$rx`: an expression evaluating to `std::sync::mpsc::Receiver<T>`.
/// - `$dur`: an expression evaluating to `std::time::Duration`.
/// - `$on_disconnected`: a **block** evaluated when `RecvTimeoutError::Disconnected`.
///
/// ### Example
/// ```rust
/// # use std::sync::mpsc;
/// # use std::time::Duration;
/// # let (_tx, rx) = mpsc::channel::<u32>();
/// loop {
///     let v: u32 = recv_timeout_or_continue!(
///         rx,
///         Duration::from_millis(10),
///         {  // on disconnected
///             42
///         }
///     );
///     // use v ...
/// }
/// ```
#[macro_export]
macro_rules! recv_timeout_or_continue {
    ($rx:expr, $dur:expr, $on_disconnected:block) => {{
        match $rx.recv_timeout($dur) {
            Ok(v) => v,
            Err(std::sync::mpsc::RecvTimeoutError::Timeout) => {
                continue;
            }
            Err(std::sync::mpsc::RecvTimeoutError::Disconnected) => $on_disconnected,
        }
    }};
}

/// Convenience wrapper over [`recv_timeout_or_continue!`] that takes milliseconds.
///
/// Converts `$ms` to a `Duration` via `Duration::from_millis` and then defers to
/// [`recv_timeout_or_continue!`]. On timeout, this **continues** the surrounding loop.
///
/// ⚠️ **Must be used inside a loop** because it expands `continue` on timeout.
///
/// ### Type constraints
/// `$on_disconnected` **must evaluate to the same type** as the channel’s success value.
///
/// ### Parameters
/// - `$rx`: an expression evaluating to `std::sync::mpsc::Receiver<T>`.
/// - `$ms`: an integer-like expression convertible to `u64`.
/// - `$on_disconnected`: a **block** evaluated when the channel is disconnected.
///
/// ### Example
/// ```rust
/// # use std::sync::mpsc;
/// # let (_tx, rx) = mpsc::channel::<&'static str>();
/// loop {
///     let s: &str = recv_timeout_ms_or_continue!(
///         rx,
///         250,
///         { // on disconnected
///             "disconnected"
///         }
///     );
///     // use s ...
/// }
/// ```
#[macro_export]
macro_rules! recv_timeout_ms_or_continue {
    ($rx:expr, $ms:expr, $on_disconnected:block) => {{
        $crate::recv_timeout_or_continue!(
            $rx,
            std::time::Duration::from_millis($ms),
            $on_disconnected
        )
    }};
}