0

I don't mean to ask too much, but I think I have surpassed the basic requirements using the Rust VS Code formatter. I'm positive futures are needed, and I believe the run_until local pool method can execute the operation. I think a lifetime elide is required, which I think exclusively is interpolated by the 'a Type declaration.

use futures::executor::LocalPool;

pub fn pathify(path: &str) -> std::path::PathBuf {
    let mut input_file = std::path::PathBuf::new();

    let arr: () = path.split("/").map(|x| input_file.push(x)).collect();
    return input_file;
}

struct DropOnce{  //ERROR: "expected named lifetime parameter"
    _bosun: dyn Mak<std::sync::Once, Output = cc::Build>, //::new()
}
trait Mak<'a,T:'a> { //fn resolve(self) -> cc::Build;
    type Output; //static types before compilation! (concrete type)
    fn _bosun() {
        let lock: std::path::PathBuf = pathify("./exec.c");
        cc::Build::new().file(lock).expand(); //= Default::default().await
    }
}
impl<'a> std::future::Future for DropOnce{
    fn poll(&'a mut self) -> &'a mut Self {
        println!("poll");
        self
    }
}
fn main() {
    let mut pool = LocalPool::new();
    let _bosun = DropOnce; //ERROR: "expected value, found struct `DropOnce`"
    pool.run_until(_bosun);
}

full code

use wasm_bindgen::prelude::wasm_bindgen;
#[wasm_bindgen(start)]
fn main () {}

If this example is still too nascent to make work in a SO answer I would appreciate community documentation references. I think I may be confusing definitions in a trait and impl, like, '[are member functions of an impl as mutable as its trait definition+declaration, but for names]?'

1 Answers1

0

Turns out, wasm-bindgen is not required for the cc::Build use case/the only use case for the latter.

use serde::Serialize;
use std::{
    collections::HashMap,
    future::Future,
    mem,
    pin::Pin,
    sync::mpsc::{channel, Sender},
    sync::{Arc, Mutex},
    task::{Context, Poll, Waker},
    thread::{self, JoinHandle},
    time::Duration,
};
#[derive(Serialize)]
struct Product {
    ivity: String,
}

Evidently, the following is the minimum requirement of making a Future from an async{block.await} 'Task'.

//(1) Reactor
enum TaskState {
    Ready,
    NotReady(Waker),
    Finished,
} //https://cfsamson.github.io/books-futures-explained/6_future_example.html
struct Reactor {
    dispatcher: Sender<Event>,
    handle: Option<JoinHandle<()>>,
    tasks: HashMap<usize, TaskState>,
}
#[derive(Debug)]
enum Event {
    Close,
    Timeout(u64, usize),
}
impl Reactor {
    fn new() -> Arc<Mutex<Box<Self>>> {
        let (tx, rx) = channel::<Event>();
        let reactor = Arc::new(Mutex::new(Box::new(Reactor {
            dispatcher: tx,
            handle: None,
            tasks: HashMap::new(),
        })));
        let reactor_clone = Arc::downgrade(&reactor);
        let handle = thread::spawn(move || {
            let mut handles = vec![];
            for event in rx {
                println!("REACTOR: {:?}", event);
                let reactor = reactor_clone.clone();
                match event {
                    Event::Close => break,
                    Event::Timeout(duration, id) => {
                        let event_handle = thread::spawn(move || {
                            thread::sleep(Duration::from_secs(duration));
                            let reactor = reactor.upgrade().unwrap();
                            reactor.lock().map(|mut r| r.wake(id)).unwrap();
                        });
                        handles.push(event_handle);
                    }
                }
            }
            handles
                .into_iter()
                .for_each(|handle| handle.join().unwrap());
        });
        reactor.lock().map(|mut r| r.handle = Some(handle)).unwrap();
        reactor
    }
    fn wake(&mut self, id: usize) {
        self.tasks
            .get_mut(&id)
            .map(|state| {
                match mem::replace(state, TaskState::Ready) {
                    TaskState::NotReady(waker) => waker.wake(),
                    TaskState::Finished => {
                        panic!("Called 'wake' twice on task: {}", id)
                    }
                    _ => unreachable!(),
                }
            })
            .unwrap();
    }
    fn register(&mut self, duration: u64, waker: Waker, id: usize) {
        if self.tasks.insert(id, TaskState::NotReady(waker)).is_some() {
            panic!("Tried to insert a task with id: '{}', twice!", id);
        }
        self.dispatcher.send(Event::Timeout(duration, id)).unwrap();
    }
    fn is_ready(&self, id: usize) -> bool {
        self.tasks
            .get(&id)
            .map(|state| match state {
                TaskState::Ready => true,
                _ => false,
            })
            .unwrap_or(false)
    }
}

impl Drop for Reactor {
    fn drop(&mut self) {
        self.dispatcher.send(Event::Close).unwrap();
        self.handle.take().map(|h| h.join().unwrap()).unwrap();
    }
}
//(2) Task
#[derive(Clone)]
pub struct Task {
    app: u64,
    reactor: Arc<Mutex<Box<Reactor>>>,
    id: usize,
}
impl Task {
    fn new(pathstr: &str, reactor: Arc<Mutex<Box<Reactor>>>, id: usize) -> Self {
        //Task {
        Task {
            app: match pathstr {
                //let s: String = match pathstr {
                "/" => {
                    fn pathify(path: &str) -> std::path::PathBuf {
                        let mut input_file = std::path::PathBuf::new();
                        let _arr: () =
                            path.split("/").map(|x| input_file.push(x)).collect();
                        return input_file;
                    }
                    let lock: std::path::PathBuf = pathify("./exec.c");
                    let appel = cc::Build::new().file(lock).expand();
                    //String::from_utf8(appel).unwrap()
                    u64::from_be_bytes(appel.try_into().expect(""))
                    //.iter().collect()
                }
                &_ => u64::from_be_bytes("".as_bytes().try_into().expect("")),
                //};
                //u64::from_str_radix(s.expect("")) //,16
            },
            reactor,
            id,
        }
    }
}
// (3) Future implementation
impl Future for Task {
    type Output = usize;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        //let mut r = self.app;
        let mut r = self.reactor.lock().unwrap();
        if r.is_ready(self.id) {
            *r.tasks.get_mut(&self.id).unwrap() = TaskState::Finished;
            Poll::Ready(self.id)
        } else if r.tasks.contains_key(&self.id) {
            r.tasks
                .insert(self.id, TaskState::NotReady(cx.waker().clone()));
            Poll::Pending
        } else {
            r.register(self.app, cx.waker().clone(), self.id);
            Poll::Pending
        }
    }
}
let path = req.path(); //longer lived with let
let pathstr: &str = path.as_str();
let reactor = Reactor::new();
let id = 1;
let future1 = Task::new(pathstr, reactor.clone(), id);
let fut1 = async {
    future1.await
    //let val = future1.await;
    //println!("Got {} at time: {:.2}.", val, start.elapsed().as_secs_f32());
};
Response::from_json(&Product {
    ivity: fut1.await.to_string(),
})

I'll edit this with use wasm_bindgen::prelude::*; use wasm_bindgen_futures::{JsFuture, future_to_promise}; as I build that out, yet I would not like to mislead with the question further with this passing rustup analyzer (a.k.a. I'm testing now, remember, VS code is obtuse like terminal which may require closing once).