use core::fmt;
use core::marker::PhantomData;
use {Poll, Future, Stream, Sink, StartSend};
mod atomic_task;
pub use self::atomic_task::AtomicTask;
mod core;
#[cfg(feature = "use_std")]
mod std;
#[cfg(feature = "use_std")]
pub use self::std::*;
#[cfg(not(feature = "use_std"))]
pub use self::core::*;
pub struct BorrowedTask<'a> {
id: usize,
unpark: BorrowedUnpark<'a>,
events: BorrowedEvents<'a>,
map: &'a LocalMap,
}
fn fresh_task_id() -> usize {
use core::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
static NEXT_ID: AtomicUsize = ATOMIC_USIZE_INIT;
let id = NEXT_ID.fetch_add(1, Ordering::Relaxed);
assert!(id < usize::max_value() / 2,
"too many previous tasks have been allocated");
id
}
fn with<F: FnOnce(&BorrowedTask) -> R, R>(f: F) -> R {
unsafe {
let task = get_ptr().expect("no Task is currently running");
assert!(!task.is_null(), "no Task is currently running");
f(&*(task as *const BorrowedTask))
}
}
#[derive(Clone)]
pub struct Task {
id: usize,
unpark: TaskUnpark,
events: UnparkEvents,
}
trait AssertSend: Send {}
impl AssertSend for Task {}
pub fn current() -> Task {
with(|borrowed| {
let unpark = borrowed.unpark.to_owned();
let events = borrowed.events.to_owned();
Task {
id: borrowed.id,
unpark: unpark,
events: events,
}
})
}
#[doc(hidden)]
#[deprecated(note = "renamed to `current`")]
pub fn park() -> Task {
current()
}
impl Task {
pub fn notify(&self) {
self.events.notify();
self.unpark.notify();
}
#[doc(hidden)]
#[deprecated(note = "renamed to `notify`")]
pub fn unpark(&self) {
self.notify()
}
#[deprecated(note = "intended to be removed, see docs for details")]
pub fn is_current(&self) -> bool {
with(|current| current.id == self.id)
}
#[allow(deprecated)]
pub fn will_notify_current(&self) -> bool {
with(|current| {
self.unpark.will_notify(¤t.unpark) &&
self.events.will_notify(¤t.events)
})
}
}
impl fmt::Debug for Task {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Task")
.finish()
}
}
pub struct Spawn<T: ?Sized> {
id: usize,
data: LocalMap,
obj: T,
}
pub fn spawn<T>(obj: T) -> Spawn<T> {
Spawn {
id: fresh_task_id(),
obj: obj,
data: local_map(),
}
}
impl<T: ?Sized> Spawn<T> {
pub fn get_ref(&self) -> &T {
&self.obj
}
pub fn get_mut(&mut self) -> &mut T {
&mut self.obj
}
pub fn into_inner(self) -> T where T: Sized {
self.obj
}
pub fn poll_future_notify<N>(&mut self,
notify: &N,
id: usize) -> Poll<T::Item, T::Error>
where N: Clone + Into<NotifyHandle>,
T: Future,
{
let mk = || notify.clone().into();
self.enter(BorrowedUnpark::new(&mk, id), |f| f.poll())
}
pub fn poll_stream_notify<N>(&mut self,
notify: &N,
id: usize)
-> Poll<Option<T::Item>, T::Error>
where N: Clone + Into<NotifyHandle>,
T: Stream,
{
let mk = || notify.clone().into();
self.enter(BorrowedUnpark::new(&mk, id), |s| s.poll())
}
pub fn start_send_notify<N>(&mut self,
value: T::SinkItem,
notify: &N,
id: usize)
-> StartSend<T::SinkItem, T::SinkError>
where N: Clone + Into<NotifyHandle>,
T: Sink,
{
let mk = || notify.clone().into();
self.enter(BorrowedUnpark::new(&mk, id), |s| s.start_send(value))
}
pub fn poll_flush_notify<N>(&mut self,
notify: &N,
id: usize)
-> Poll<(), T::SinkError>
where N: Clone + Into<NotifyHandle>,
T: Sink,
{
let mk = || notify.clone().into();
self.enter(BorrowedUnpark::new(&mk, id), |s| s.poll_complete())
}
pub fn close_notify<N>(&mut self,
notify: &N,
id: usize)
-> Poll<(), T::SinkError>
where N: Clone + Into<NotifyHandle>,
T: Sink,
{
let mk = || notify.clone().into();
self.enter(BorrowedUnpark::new(&mk, id), |s| s.close())
}
fn enter<F, R>(&mut self, unpark: BorrowedUnpark, f: F) -> R
where F: FnOnce(&mut T) -> R
{
let borrowed = BorrowedTask {
id: self.id,
unpark: unpark,
events: BorrowedEvents::new(),
map: &self.data,
};
let obj = &mut self.obj;
set(&borrowed, || f(obj))
}
}
impl<T: fmt::Debug + ?Sized> fmt::Debug for Spawn<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Spawn")
.field("obj", &&self.obj)
.finish()
}
}
pub trait Notify: Send + Sync {
fn notify(&self, id: usize);
fn clone_id(&self, id: usize) -> usize {
id
}
fn drop_id(&self, id: usize) {
drop(id);
}
}
pub fn with_notify<F, T, R>(notify: &T, id: usize, f: F) -> R
where F: FnOnce() -> R,
T: Clone + Into<NotifyHandle>,
{
with(|task| {
let mk = || notify.clone().into();
let new_task = BorrowedTask {
id: task.id,
unpark: BorrowedUnpark::new(&mk, id),
events: task.events,
map: task.map,
};
set(&new_task, f)
})
}
pub unsafe trait UnsafeNotify: Notify {
unsafe fn clone_raw(&self) -> NotifyHandle;
unsafe fn drop_raw(&self);
}
pub struct NotifyHandle {
inner: *mut UnsafeNotify,
}
unsafe impl Send for NotifyHandle {}
unsafe impl Sync for NotifyHandle {}
impl NotifyHandle {
#[inline]
pub unsafe fn new(inner: *mut UnsafeNotify) -> NotifyHandle {
NotifyHandle { inner: inner }
}
pub fn notify(&self, id: usize) {
unsafe { (*self.inner).notify(id) }
}
fn clone_id(&self, id: usize) -> usize {
unsafe { (*self.inner).clone_id(id) }
}
fn drop_id(&self, id: usize) {
unsafe { (*self.inner).drop_id(id) }
}
}
impl Clone for NotifyHandle {
#[inline]
fn clone(&self) -> Self {
unsafe {
(*self.inner).clone_raw()
}
}
}
impl fmt::Debug for NotifyHandle {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("NotifyHandle")
.finish()
}
}
impl Drop for NotifyHandle {
fn drop(&mut self) {
unsafe {
(*self.inner).drop_raw()
}
}
}
struct StaticRef<T>(PhantomData<T>);
impl<T: Notify> Notify for StaticRef<T> {
fn notify(&self, id: usize) {
let me = unsafe { &*(self as *const _ as *const T) };
me.notify(id);
}
fn clone_id(&self, id: usize) -> usize {
let me = unsafe { &*(self as *const _ as *const T) };
me.clone_id(id)
}
fn drop_id(&self, id: usize) {
let me = unsafe { &*(self as *const _ as *const T) };
me.drop_id(id);
}
}
unsafe impl<T: Notify + 'static> UnsafeNotify for StaticRef<T> {
unsafe fn clone_raw(&self) -> NotifyHandle {
NotifyHandle::new(self as *const _ as *mut StaticRef<T>)
}
unsafe fn drop_raw(&self) {}
}
impl<T: Notify> From<&'static T> for NotifyHandle {
fn from(src : &'static T) -> NotifyHandle {
unsafe { NotifyHandle::new(src as *const _ as *mut StaticRef<T>) }
}
}