Error in project

async unsafe fn filename<'a>(path: &'a Result<DirEntry, Error>) -> &'a str {
    //join hell
    &join!(async {
        join!(async {
            join!(async {
                join!(async { join!(async { path.as_ref() }).0.unwrap_unchecked() })
                    .0
                    .file_name()
            })
            .0
            .to_str()
        })
        .0
        .unwrap_unchecked()
    })
    .0
}

hmmm. Returns a value referencing data owned by the current function. join is from tokio.

file_name returns an owned value, not a borrowed one.

Try using into_string and returning a String, not a &str.

No comment on the rest.

1 Like

Rip. You think I can implement the same code here?

join!(async { println!("Choose an existing brain file:") });
        unsafe {
            join!(async {
                for path in brainpath.unwrap_unchecked() {
                    join!(async {
                        println!(
                            "{}",
                            &path
                                .unwrap_unchecked()
                                .file_name()
                                .to_str()
                                .unwrap_unchecked()
                        )
                    });
                }
            })
            .0
        }

Please let me know if join hell is a runtime problem

Okay… where to start… let’s add imports.

use std::io::Error;
use tokio::fs::DirEntry;
use tokio::join;

async unsafe fn filename<'a>(path: &'a Result<DirEntry, Error>) -> &'a str {
    &join!(async {
        join!(async {
            join!(async {
                join!(async { join!(async { path.as_ref() }).0.unwrap_unchecked() })
                    .0
                    .file_name()
            })
            .0
            .to_str()
        })
        .0
        .unwrap_unchecked()
    })
    .0
}

join! is intended to join multiple futures. Using it with a single one defeats its purpose, just .await the thing…

use std::io::Error;
use tokio::fs::DirEntry;
use tokio::join;

async unsafe fn filename<'a>(path: &'a Result<DirEntry, Error>) -> &'a str {
    &async {
        async {
            async {
                async { async { path.as_ref() }.await.unwrap_unchecked() }
                    .await
                    .file_name()
            }
            .await
            .to_str()
        }
        .await
        .unwrap_unchecked()
    }
    .await
}

async { … } blocks are meant for building futures, which can support calling other asynchronous APIs. Inside of an async { … } block, you can call async fns with .await syntax. None of the functions called here are async. Starting from the innermost block, async { path.as_ref() }.await just becomes path.as_ref(), eliminating the only remaining await in the surrounding async { … } block, and so on…

use std::io::Error;
use tokio::fs::DirEntry;
use tokio::join;

async unsafe fn filename<'a>(path: &'a Result<DirEntry, Error>) -> &'a str {
    &path.as_ref().unwrap_unchecked().file_name().to_str().unwrap_unchecked()
}

The unwrap_unchecked function is meant for cases where you can prove that errors are never encountered. Otherwise, it’s forbidden to use this function. Since these are run-time errors, I fail to see how they can be known not to fail, so let’s not use the unchecked version.

use std::io::Error;
use tokio::fs::DirEntry;
use tokio::join;

async unsafe fn filename<'a>(path: &'a Result<DirEntry, Error>) -> &'a str {
    &path.as_ref().unwrap().file_name().to_str().unwrap()
}

The function filename itself contains no .await nor unsafe operation anymore, so it needs to be neither unsafe nor async.

use std::io::Error;
use tokio::fs::DirEntry;
use tokio::join;

fn filename<'a>(path: &'a Result<DirEntry, Error>) -> &'a str {
    &path.as_ref().unwrap().file_name().to_str().unwrap()
}

There is no “hell” left that you hadn’t constructed yourself.

Onto addressing the compilation error that stayed essentially the same, throughout:

error[E0515]: cannot return value referencing temporary value
 --> src/lib.rs:6:5
  |
6 |     &path.as_ref().unwrap().file_name().to_str().unwrap()
  |     ^----------------------------------^^^^^^^^^^^^^^^^^^
  |     ||
  |     |temporary value created here
  |     returns a value referencing data owned by the current function

The problem is, in this chain of functions, that file_name (or maybe this is the version from the std type) returns an owned OsString value. This value owns some string data that was not part of the existing DirEntry value in your program’s memory. It is thus impossible to implement your function signature as suggested. fn(&'a Something) -> &'a str would always require that the returned string data was already existing inside of Something (or in other, even longer-lived memory).

As @quinedot already suggested, this can be fixed in a straightforward manner, by producing a String instead.

use std::io::Error;
use tokio::fs::DirEntry;
use tokio::join;

fn filename<'a>(path: &'a Result<DirEntry, Error>) -> String {
    path.as_ref().unwrap().file_name().into_string().unwrap()
}

As for your second code example, it’s missing all context [what is brainpath’s type? What’s the error you’re facing? Can you perhaps even provide a full reproduction of the example in the playground?] and utilizing the same unnecessarily hellish code style, so there’s not much to say in addition to the above.

8 Likes

Here's the new code thanks to your advice.

use anyhow::Result;
use std::fs::{read_dir, DirEntry};
use std::io::{stdin, Error};
use tokio::fs::{create_dir, try_exists, File};
use tokio::io::AsyncReadExt;
use tokio::join;
use wgpu::Instance;
#[tokio::main]
async fn main() -> Result<()> {
    let mut words = String::new();
    let stdin = stdin();
    let mut file: File;
    let mut brain = Brain::new();
    let mut brainpath = read_dir(r"brains\");
    let mut exists = try_exists("brains/default.brain").await?;
    if exists {
        file = File::open("brains/default.brain").await?;
    } else if brainpath.iter().next().is_none() {
        tokio::join!(async { println!("No brains files found, creating default brain.") });
        if brainpath.is_err() {
            create_dir("brains").await?
        }
        file = File::create("brains/default.brain").await?;
        println!("Hi! My name is _. Ask or say anything.");
    } else {
        join!(async { println!("Choose an existing brain file:") });
        unsafe {
            join!(async {
                for path in brainpath.unwrap_unchecked() {
                    join!(async {
                        println!(
                            "{}",
                            &path
                                .unwrap_unchecked()
                                .file_name()
                                .to_str()
                                .unwrap_unchecked()
                        )
                    });
                }
            })
            .0
        }
        stdin.read_line(&mut words)?;
        file = File::open(format!("brains/{words}.brain")).await?;
    }
    println!("{}", &join!(greeting(&brain)).0);
    loop {
        stdin.read_line(&mut words)?;
        println!("{}", &join!(readandwrite(&brain, &exists, &words)).0);
    }
    Ok(())
}
async fn readandwrite(brain: &Brain, exists: &bool, words: &String) -> String {
    if words.trim().is_empty() {
        if *exists {}
    }
    let mut aiwords = String::new();
    for word in words.split_whitespace() {}
    aiwords
}
async fn greeting(brain: &Brain) -> String {
    let mut aiwords = String::new();

    aiwords
}
struct Brain {}
impl Brain {
    pub fn new() -> Brain {
        Brain {}
    }
}

Why are you insisting on using join! and async in places where they're 100% pointless? What makes you think you're supposed to use them? Are you trying to learn Rust from a hallucinating AI?

1 Like

Feedback would be nice.

For example, this line:

        join!(async { println!("Choose an existing brain file:") });

should be simplified to:

        println!("Choose an existing brain file:");

But it's hard to give advice without understanding what you are trying to do. Why did you write join! and async in the original code?

2 Likes

multithreaded magic.

As mentioned above, join! is not magic. It will only provide concurrency if you pass multiple arguments to it, like join!(future1, future2). In your code, you call it with just one argument like join!(future1), so it adds nothing.

5 Likes

Ah. I thought it would just go to the next line while another thread worked on it.

I mean if there's another tokio function I should be using for single functions, i'd like to know. But technically it's printing while doing a for loop (which should take it straight to the read_line line), and asynchronously printing all the paths in brainpath.unwrap_unchecked() at once(I think)

Like you use join and async I think you have not understood the concept of asynchronous code and mix-up multithreading, parallelism and concurrency.

Are you looking for async { println!(...)}.await ?
Makes no sense.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.