vuot 0.0.1

Run recursive async functions without overflowing the stack
Documentation
//! Run recursive async functions without overflowing the stack.
//!
//! ```
//! # pollster::block_on(async {
//! use std::future::Future;
//! use vuot::{run, StacklessFn, Stack};
//!
//! async fn count(stack: Stack<'_>, n: u64) -> u64 {
//!     if n == 0 {
//!         n
//!     } else {
//!         stack.run(count(stack, n - 1)).await + 1
//!     }
//! }
//!
//! struct Count(u64);
//! impl<'a> StacklessFn<'a, u64> for Count {
//!     fn call(self, stack: Stack<'a>) -> impl Future<Output = u64> {
//!         count(stack, self.0)
//!     }
//! }
//!
//! assert_eq!(1_000_000, run(Count(1_000_000)).await);
//! # });
//! ```

#![cfg_attr(feature = "bumpalo", feature(allocator_api))]
#![deny(unsafe_op_in_unsafe_fn)]
#![warn(clippy::missing_safety_doc, clippy::undocumented_unsafe_blocks)]
#![warn(missing_docs)]

mod frame;
mod sender;
mod side_channel;
mod stack;
mod stackless_fn;

#[cfg(test)]
mod tests;

pub use stack::{run, Stack};
pub use stackless_fn::StacklessFn;

use allocator::Alloc;

#[cfg(not(feature = "bumpalo"))]
mod allocator {
    pub(crate) struct Alloc;

    pub(crate) type AllocBox<'a, T> = Box<T>;

    impl Alloc {
        pub fn new() -> Self {
            Self
        }

        pub fn new_raw<T>(&self, value: T) -> *mut T {
            Box::into_raw(Box::new(value))
        }

        /// # Safety
        ///
        /// See [`Box::from_raw`]
        pub unsafe fn box_from_raw<T: ?Sized>(&self, raw: *mut T) -> AllocBox<'static, T> {
            // Safety: identical contracts
            unsafe { Box::from_raw(raw) }
        }
    }
}

#[cfg(feature = "bumpalo")]
mod allocator {
    use bumpalo::Bump;

    pub(crate) struct Alloc(Bump);

    pub(crate) type AllocBox<'a, T> = Box<T, &'a Bump>;

    impl Alloc {
        pub fn new() -> Self {
            Self(Bump::new())
        }

        pub fn new_raw<T>(&self, value: T) -> *mut T {
            Box::into_raw(Box::new_in(value, &self.0))
        }

        /// # Safety
        ///
        /// See [`Box::from_raw_in`]
        pub unsafe fn box_from_raw<T: ?Sized>(&self, raw: *mut T) -> AllocBox<'_, T> {
            // Safety: identical contracts
            unsafe { Box::from_raw_in(raw, &self.0) }
        }
    }
}