vuot 0.0.1

Run recursive async functions without overflowing the stack
Documentation
//! This example recursively traverses a directory as a showcase of combining
//! vuot and an async executor (smol, in this case).

use std::error::Error;
use std::io;
use std::path::Path;

use smol::fs::read_dir;
use smol::stream::StreamExt;
use vuot::{run, Stack, StacklessFn};

smol_macros::main! {
    async fn main() -> Result<(), Box<dyn Error>> {
        let current_dir = std::env::current_dir()?;
        run(Traversal(&current_dir)).await?;
        Ok(())
    }
}

struct Traversal<'local>(&'local Path);

impl<'a> StacklessFn<'a, Result<(), io::Error>> for Traversal<'_> {
    async fn call(self, stack: Stack<'a>) -> Result<(), io::Error> {
        traverse(stack, 0, self.0).await
    }
}

async fn traverse(stack: Stack<'_>, nesting: usize, dir: &Path) -> Result<(), io::Error> {
    let mut entries = read_dir(dir).await?;
    while let Some(entry) = entries.next().await {
        let entry = entry?;

        let name = entry.file_name();
        let name = name.to_string_lossy();

        let file_type = entry.metadata().await?.file_type();

        if file_type.is_dir() {
            indented(nesting, format!("directory {name}"));
            let path = entry.path();
            stack.run(traverse(stack, nesting + 1, &path)).await?;
        } else {
            indented(nesting, format!("file {name}"));
        }
    }

    Ok(())
}

fn indented(n: usize, s: String) {
    for _ in 0..n {
        print!("| ");
    }

    println!("{s}");
}