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);
}
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]?'
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).