/// `select!` macro that multiplexes multiple channel recv operations.
///
/// Supports 1-3 recv branches plus an optional `default` non-blocking branch.
/// Runtime-agnostic: uses `poll_fn` internally, no backend dependency.
///
/// # Examples
///
/// ```ignore
/// select! {
///     v = rx1.recv() => { /* use v */ },
///     _ = rx2.recv() => { ... },
///     default => { ... },
/// }
/// ```
#[macro_export]
macro_rules! select {
    // Recursive accumulator: all branches consumed, no default
    (@ [$($arms:tt)*]) => {
        $crate::__select_impl!($($arms)* ; no_default)
    };
    // Recursive accumulator: hit the `default` terminator
    (@ [$($arms:tt)*] default => $default:expr $(,)?) => {
        $crate::__select_impl!($($arms)* ; default { $default })
    };
    // Recursive accumulator: consume one branch and continue
    (@ [$($arms:tt)*] $var:pat = $fut:expr => $body:expr, $($rest:tt)*) => {
        $crate::select!(@ [$($arms)* $var = $fut => $body,] $($rest)*)
    };
    // Recursive accumulator: last branch (no trailing comma), no default
    (@ [$($arms:tt)*] $var:pat = $fut:expr => $body:expr) => {
        $crate::__select_impl!($($arms)* $var = $fut => $body, ; no_default)
    };
    // Entry point
    ($($input:tt)*) => {
        $crate::select!(@ [] $($input)*)
    };
}

#[macro_export]
#[doc(hidden)]
macro_rules! __select_impl {
    // Single branch, no default (just await it)
    ($v1:pat = $f1:expr => $b1:expr, ; no_default) => {{
        let $v1 = $f1.await;
        $b1
    }};
    // Single branch + default
    ($v1:pat = $f1:expr => $b1:expr, ; default { $default:expr }) => {{
        let mut f1 = core::pin::pin!($f1);
        ::futures_lite::future::poll_fn(|cx| {
            if let core::task::Poll::Ready(v) = f1.as_mut().poll(cx) {
                let $v1 = v;
                return core::task::Poll::Ready($b1);
            }
            core::task::Poll::Ready($default)
        })
        .await
    }};
    // Two branches, no default
    ($v1:pat = $f1:expr => $b1:expr, $v2:pat = $f2:expr => $b2:expr, ; no_default) => {{
        let mut f1 = core::pin::pin!($f1);
        let mut f2 = core::pin::pin!($f2);
        ::futures_lite::future::poll_fn(|cx| {
            if let core::task::Poll::Ready(v) = f1.as_mut().poll(cx) {
                let $v1 = v;
                return core::task::Poll::Ready($b1);
            }
            if let core::task::Poll::Ready(v) = f2.as_mut().poll(cx) {
                let $v2 = v;
                return core::task::Poll::Ready($b2);
            }
            core::task::Poll::Pending
        })
        .await
    }};
    // Two branches + default
    ($v1:pat = $f1:expr => $b1:expr, $v2:pat = $f2:expr => $b2:expr, ; default { $default:expr }) => {{
        let mut f1 = core::pin::pin!($f1);
        let mut f2 = core::pin::pin!($f2);
        ::futures_lite::future::poll_fn(|cx| {
            if let core::task::Poll::Ready(v) = f1.as_mut().poll(cx) {
                let $v1 = v;
                return core::task::Poll::Ready($b1);
            }
            if let core::task::Poll::Ready(v) = f2.as_mut().poll(cx) {
                let $v2 = v;
                return core::task::Poll::Ready($b2);
            }
            core::task::Poll::Ready($default)
        })
        .await
    }};
    // Three branches, no default
    ($v1:pat = $f1:expr => $b1:expr, $v2:pat = $f2:expr => $b2:expr, $v3:pat = $f3:expr => $b3:expr, ; no_default) => {{
        let mut f1 = core::pin::pin!($f1);
        let mut f2 = core::pin::pin!($f2);
        let mut f3 = core::pin::pin!($f3);
        ::futures_lite::future::poll_fn(|cx| {
            if let core::task::Poll::Ready(v) = f1.as_mut().poll(cx) {
                let $v1 = v;
                return core::task::Poll::Ready($b1);
            }
            if let core::task::Poll::Ready(v) = f2.as_mut().poll(cx) {
                let $v2 = v;
                return core::task::Poll::Ready($b2);
            }
            if let core::task::Poll::Ready(v) = f3.as_mut().poll(cx) {
                let $v3 = v;
                return core::task::Poll::Ready($b3);
            }
            core::task::Poll::Pending
        })
        .await
    }};
    // Three branches + default
    ($v1:pat = $f1:expr => $b1:expr, $v2:pat = $f2:expr => $b2:expr, $v3:pat = $f3:expr => $b3:expr, ; default { $default:expr }) => {{
        let mut f1 = core::pin::pin!($f1);
        let mut f2 = core::pin::pin!($f2);
        let mut f3 = core::pin::pin!($f3);
        ::futures_lite::future::poll_fn(|cx| {
            if let core::task::Poll::Ready(v) = f1.as_mut().poll(cx) {
                let $v1 = v;
                return core::task::Poll::Ready($b1);
            }
            if let core::task::Poll::Ready(v) = f2.as_mut().poll(cx) {
                let $v2 = v;
                return core::task::Poll::Ready($b2);
            }
            if let core::task::Poll::Ready(v) = f3.as_mut().poll(cx) {
                let $v3 = v;
                return core::task::Poll::Ready($b3);
            }
            core::task::Poll::Ready($default)
        })
        .await
    }};
}
