about summary refs log tree commit diff
path: root/src/libcore/task/task.rs
blob: c5a41873db42725fbaccfa588996cf0a4ebab68d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![unstable(feature = "futures_api",
            reason = "futures in libcore are unstable",
            issue = "50547")]

use fmt;
use future::Future;
use mem::PinMut;
use super::{Context, Poll};

/// A custom trait object for polling tasks, roughly akin to
/// `Box<Future<Output = ()>>`.
/// Contrary to `TaskObj`, `LocalTaskObj` does not have a `Send` bound.
pub struct LocalTaskObj {
    ptr: *mut (),
    poll_fn: unsafe fn(*mut (), &mut Context) -> Poll<()>,
    drop_fn: unsafe fn(*mut ()),
}

impl LocalTaskObj {
    /// Create a `LocalTaskObj` from a custom trait object representation.
    #[inline]
    pub fn new<T: UnsafeTask>(t: T) -> LocalTaskObj {
        LocalTaskObj {
            ptr: t.into_raw(),
            poll_fn: T::poll,
            drop_fn: T::drop,
        }
    }

    /// Converts the `LocalTaskObj` into a `TaskObj`
    /// To make this operation safe one has to ensure that the `UnsafeTask`
    /// instance from which this `LocalTaskObj` was created actually implements
    /// `Send`.
    pub unsafe fn as_task_obj(self) -> TaskObj {
        TaskObj(self)
    }
}

impl fmt::Debug for LocalTaskObj {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("LocalTaskObj")
            .finish()
    }
}

impl From<TaskObj> for LocalTaskObj {
    fn from(task: TaskObj) -> LocalTaskObj {
        task.0
    }
}

impl Future for LocalTaskObj {
    type Output = ();

    #[inline]
    fn poll(self: PinMut<Self>, cx: &mut Context) -> Poll<()> {
        unsafe {
            (self.poll_fn)(self.ptr, cx)
        }
    }
}

impl Drop for LocalTaskObj {
    fn drop(&mut self) {
        unsafe {
            (self.drop_fn)(self.ptr)
        }
    }
}

/// A custom trait object for polling tasks, roughly akin to
/// `Box<Future<Output = ()> + Send>`.
pub struct TaskObj(LocalTaskObj);

unsafe impl Send for TaskObj {}

impl TaskObj {
    /// Create a `TaskObj` from a custom trait object representation.
    #[inline]
    pub fn new<T: UnsafeTask + Send>(t: T) -> TaskObj {
        TaskObj(LocalTaskObj::new(t))
    }
}

impl fmt::Debug for TaskObj {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("TaskObj")
            .finish()
    }
}

impl Future for TaskObj {
    type Output = ();

    #[inline]
    fn poll(self: PinMut<Self>, cx: &mut Context) -> Poll<()> {
        let pinned_field = unsafe { PinMut::map_unchecked(self, |x| &mut x.0) };
        pinned_field.poll(cx)
    }
}

/// A custom implementation of a task trait object for `TaskObj`, providing
/// a hand-rolled vtable.
///
/// This custom representation is typically used only in `no_std` contexts,
/// where the default `Box`-based implementation is not available.
///
/// The implementor must guarantee that it is safe to call `poll` repeatedly (in
/// a non-concurrent fashion) with the result of `into_raw` until `drop` is
/// called.
pub unsafe trait UnsafeTask: 'static {
    /// Convert a owned instance into a (conceptually owned) void pointer.
    fn into_raw(self) -> *mut ();

    /// Poll the task represented by the given void pointer.
    ///
    /// # Safety
    ///
    /// The trait implementor must guarantee that it is safe to repeatedly call
    /// `poll` with the result of `into_raw` until `drop` is called; such calls
    /// are not, however, allowed to race with each other or with calls to `drop`.
    unsafe fn poll(task: *mut (), cx: &mut Context) -> Poll<()>;

    /// Drops the task represented by the given void pointer.
    ///
    /// # Safety
    ///
    /// The trait implementor must guarantee that it is safe to call this
    /// function once per `into_raw` invocation; that call cannot race with
    /// other calls to `drop` or `poll`.
    unsafe fn drop(task: *mut ());
}