0

I am trying to have an async fn pointer that i can call inside my match block. I don't necessarily think this is the right approach, but, while attempting to make this work i stumbled against the error in the title

pub type Adapter = Box<dyn FnOnce(Arc<MessageComponentInteraction>, Context) -> Pin<Box<dyn Future<Output = ()>>>>;

pub fn force_boxed<T>(f: fn(mci : Arc<MessageComponentInteraction>, ctx : Context) -> T) -> Adapter
where
    T: Future<Output = ()> + 'static,
{
    Box::new(move |n, u| Box::pin(f(n, u)))
}

pub struct YouSureBuilder<'a> {
    inner_message : &'a String,
    on_continue : Adapter,
    on_nevermind : Adapter,
    cache_http : &'a Http,
    bot_avatar_url : &'a String,
    bot_name : &'a String,
    ctx : &'a Context}

 match mci.data.custom_id.as_str() {
            "n" => {(self.on_nevermind)(mci, self.ctx.clone()).await;},
            "c" => {(self.on_continue)(mci, self.ctx.clone()).await;},
            _ => {},
            };

value is being passed like:

        on_continue: force_boxed(Self::on_nevermind),
        on_nevermind: force_boxed(Self::on_nevermind),

functions are:

    async fn on_continue(mci : Arc<MessageComponentInteraction>, ctx : Context) {
    let result = mci.channel_id.delete(ctx.http).await;
    match result.is_ok() {
        true => {}, // Implement error builders
        false => {}
    }
    }

    async fn on_nevermind(mci : Arc<MessageComponentInteraction>, ctx : Context) {
    let result = mci.message.delete(ctx.http).await;
    match result.is_ok() {
        true => {}, // Implement error builders
        false => {}
    }
    

i have tried googling and debugging myself for like an hour now. i simply dont know how this is even possible

reproducible example.

use std::pin::Pin;
use std::future::Future;

pub type Adapter = Box<dyn FnOnce(i32, i32) -> Pin<Box<dyn Future<Output = ()>>>>;

pub fn force_boxed<T>(f: fn(arg1 : i32, arg2: i32) -> T) -> Adapter
where
    T: Future<Output = ()> + 'static,
{
    Box::new(move |n, u| Box::pin(f(n, u)))
}

struct err {
    on_something : Adapter,
}

impl err {
    async fn do_something(&self) {
    (self.on_something)(8, 2).await; // errors here
    }
}


async fn on_something_thing(arg1 : i32, arg2: i32) {
    // do things
}

#[tokio::main]
async fn main() {
    let new_bug_thing = err {
    on_something: force_boxed(on_something_thing)
    };

    new_bug_thing.do_something().await;
}

you dont need to have tokio necessarily, the error will still reproduce

  • Please add the complete error message from your compiler. Also please provide a [mre] so we can reproduce the error. – cafce25 Aug 17 '23 at 11:14
  • i will edit the question – Bigchungusonketamime Aug 17 '23 at 11:49
  • Do **not** paste relevant info into comments, [edit] your question instead. – cafce25 Aug 17 '23 at 11:50
  • Use `Box` instead of `Box`. – Chayim Friedman Aug 17 '23 at 11:55
  • that was it. appreciate it. but why did this happen? – Bigchungusonketamime Aug 17 '23 at 11:58
  • @Bigchungusonketamime `FnOnce` is invoked with `self` but `Fn` is invoked with `&self`. Basically, an `FnOnce` gets _consumed_ when it's invoked. To invoke it, you therefore need to be able to move the closure into its (hidden) call function. – cdhowie Aug 17 '23 at 12:04
  • I see. Thank you all! – Bigchungusonketamime Aug 17 '23 at 12:07
  • @Bigchungusonketamime No problem. Note that if `FnOnce` makes sense for semantic reasons (the function can really only be called once) then you can store it as `Option>` and use `on_nevermind.take()` to "steal" the `Option` (`on_nevermind` will be replaced with `None`). Then you can obtain the box from the `Some` variant, and invoke the closure. Something like `if let Some(f) = on_nevermind.take() { f(...); }`. Note you will have to take `&mut self` or use interior mutability. – cdhowie Aug 17 '23 at 16:05
  • @cdhowie They can use `Cell – Chayim Friedman Aug 17 '23 at 17:25

0 Answers0