use std::sync::{Arc, Mutex};
use std::pin::Pin;
use webcore::once::Once;
use webcore::value::Value;
use futures_core::{Future, Poll};
use futures_core::task::{Waker, LocalWaker};
use futures_core::stream::Stream;
use futures_util::FutureExt;
use futures_channel::oneshot;
#[inline]
fn convert_to_i32( ms: u32 ) -> i32 {
let ms: i32 = ms as i32;
assert!( ms >= 0, "ms must be less than 2147483648" );
ms
}
#[derive( Debug )]
pub struct Wait {
receiver: oneshot::Receiver< () >,
timer: Value,
}
impl Wait {
fn new( ms: u32 ) -> Self {
let ms = convert_to_i32( ms );
let ( sender, receiver ) = oneshot::channel();
let callback = move || {
match sender.send( () ) {
Ok( _ ) => {},
Err( _ ) => {},
};
};
let timer = js!(
var callback = @{Once( callback )};
return {
callback: callback,
id: setTimeout( function () {
callback();
}, @{ms} )
};
);
Self {
receiver,
timer,
}
}
}
impl Future for Wait {
type Output = ();
#[inline]
fn poll( mut self: Pin< &mut Self >, waker: &LocalWaker ) -> Poll< Self::Output > {
self.receiver.poll_unpin( waker ).map( |x| x.unwrap() )
}
}
impl Drop for Wait {
#[inline]
fn drop( &mut self ) {
js! { @(no_return)
var timer = @{&self.timer};
clearTimeout( timer.id );
timer.callback.drop();
}
}
}
#[inline]
pub fn wait( ms: u32 ) -> Wait {
Wait::new( ms )
}
#[derive( Debug )]
struct IntervalBufferedState {
waker: Option< Waker >,
count: usize,
}
#[derive( Debug )]
pub struct IntervalBuffered {
state: Arc< Mutex< IntervalBufferedState > >,
timer: Value,
}
impl IntervalBuffered {
fn new( ms: u32 ) -> Self {
let ms = convert_to_i32( ms );
let state = Arc::new( Mutex::new( IntervalBufferedState {
waker: None,
count: 0,
} ) );
let callback = {
let state = state.clone();
move || {
let mut lock = state.lock().unwrap();
lock.count += 1;
if let Some( waker ) = lock.waker.take() {
drop( lock );
waker.wake();
}
}
};
let timer = js!(
var callback = @{callback};
return {
callback: callback,
id: setInterval( function () {
callback();
}, @{ms} )
};
);
Self {
state,
timer,
}
}
}
impl Stream for IntervalBuffered {
type Item = ();
fn poll_next( self: Pin< &mut Self >, waker: &LocalWaker ) -> Poll< Option< Self::Item > > {
let mut lock = self.state.lock().unwrap();
if lock.count == 0 {
lock.waker = Some( waker.clone().into() );
Poll::Pending
} else {
lock.count -= 1;
Poll::Ready( Some( () ) )
}
}
}
impl Drop for IntervalBuffered {
#[inline]
fn drop( &mut self ) {
js! { @(no_return)
var timer = @{&self.timer};
clearInterval( timer.id );
timer.callback.drop();
}
}
}
#[inline]
pub fn interval_buffered( ms: u32 ) -> IntervalBuffered {
IntervalBuffered::new( ms )
}