Skip to content
This repository was archived by the owner on Jun 8, 2021. It is now read-only.

Commit 66a9c53

Browse files
authored
Merge pull request #476 from sdroege/futures-0.3
Port to futures 0.3
2 parents 2384ad8 + d8e6f65 commit 66a9c53

File tree

4 files changed

+202
-154
lines changed

4 files changed

+202
-154
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ name = "glib"
2424
lazy_static = "1.2"
2525
libc = "0.2"
2626
bitflags = "1.0"
27-
futures-preview = { version = "0.2", optional = true }
27+
futures-preview = { version = "0.3.0-alpha", optional = true }
2828
glib-sys = { git = "https://github.com/gtk-rs/sys" }
2929
gobject-sys = { git = "https://github.com/gtk-rs/sys" }
3030

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
7878
#![allow(clippy::doc_markdown)]
7979
#![allow(clippy::unreadable_literal)]
80+
#![cfg_attr(feature = "futures", feature(futures_api, arbitrary_self_types))]
8081

8182
#[macro_use]
8283
extern crate bitflags;

src/main_context_futures.rs

Lines changed: 126 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,18 @@
33
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>
44

55
use futures;
6-
use futures::executor::{Executor, SpawnError};
6+
use futures::future::{FutureObj, LocalFutureObj};
77
use futures::prelude::*;
8-
use futures::task::{LocalMap, UnsafeWake, Waker};
9-
use futures::{Async, Future, Never};
8+
use futures::task::{
9+
Context, LocalSpawn, Poll, RawWaker, RawWakerVTable, Spawn, SpawnError, Waker,
10+
};
1011
use get_thread_id;
1112
use glib_sys;
1213
use std::mem;
1314
use std::ptr;
1415
use std::sync::atomic::{AtomicUsize, Ordering};
1516
use translate::{from_glib_full, from_glib_none, mut_override, ToGlib};
17+
1618
use MainContext;
1719
use MainLoop;
1820
use Priority;
@@ -28,27 +30,48 @@ const DONE: usize = 3;
2830
#[repr(C)]
2931
struct TaskSource {
3032
source: glib_sys::GSource,
31-
future: Option<(Box<Future<Item = (), Error = Never>>, Box<LocalMap>)>,
33+
future: Option<FutureObj<'static, ()>>,
3234
thread: Option<usize>,
3335
state: AtomicUsize,
3436
}
3537

36-
unsafe impl UnsafeWake for TaskSource {
37-
unsafe fn clone_raw(&self) -> Waker {
38-
Waker::new(glib_sys::g_source_ref(mut_override(&self.source)) as *const TaskSource)
39-
}
38+
static TASK_SOURCE_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(
39+
TaskSource::clone_raw,
40+
TaskSource::wake_raw,
41+
TaskSource::wake_by_ref_raw,
42+
TaskSource::drop_raw,
43+
);
4044

41-
unsafe fn drop_raw(&self) {
42-
glib_sys::g_source_unref(mut_override(&self.source));
45+
impl TaskSource {
46+
unsafe fn clone_raw(waker: *const ()) -> RawWaker {
47+
let waker = &*(waker as *const TaskSource);
48+
glib_sys::g_source_ref(mut_override(&waker.source));
49+
RawWaker::new(waker as *const Self as *const (), &TASK_SOURCE_WAKER_VTABLE)
50+
}
51+
unsafe fn wake_raw(waker: *const ()) {
52+
Self::wake_by_ref_raw(waker);
53+
Self::drop_raw(waker);
4354
}
4455

45-
unsafe fn wake(&self) {
46-
if self.state
47-
.compare_and_swap(NOT_READY, READY, Ordering::SeqCst) == NOT_READY
56+
unsafe fn wake_by_ref_raw(waker: *const ()) {
57+
let waker = &*(waker as *const TaskSource);
58+
if waker
59+
.state
60+
.compare_and_swap(NOT_READY, READY, Ordering::SeqCst)
61+
== NOT_READY
4862
{
49-
glib_sys::g_source_set_ready_time(mut_override(&self.source), 0);
63+
glib_sys::g_source_set_ready_time(mut_override(&waker.source), 0);
5064
}
5165
}
66+
67+
unsafe fn drop_raw(waker: *const ()) {
68+
let waker = &*(waker as *const TaskSource);
69+
glib_sys::g_source_unref(mut_override(&waker.source));
70+
}
71+
72+
fn as_waker(&self) -> Waker {
73+
unsafe { Waker::from_raw(Self::clone_raw(self as *const Self as *const ())) }
74+
}
5275
}
5376

5477
unsafe extern "C" fn prepare(
@@ -66,7 +89,7 @@ unsafe extern "C" fn prepare(
6689
// XXX: This is not actually correct, we should not dispatch the
6790
// GSource here already but we need to know its current status so
6891
// that if it is not ready yet something can register to the waker
69-
if let Async::Ready(()) = source.poll() {
92+
if let Poll::Ready(()) = source.poll() {
7093
source.state.store(DONE, Ordering::SeqCst);
7194
cur = DONE;
7295
} else {
@@ -105,7 +128,7 @@ unsafe extern "C" fn dispatch(
105128
.state
106129
.compare_and_swap(READY, NOT_READY, Ordering::SeqCst);
107130
if cur == READY {
108-
if let Async::Ready(()) = source.poll() {
131+
if let Poll::Ready(()) = source.poll() {
109132
source.state.store(DONE, Ordering::SeqCst);
110133
cur = DONE;
111134
} else {
@@ -134,39 +157,31 @@ static SOURCE_FUNCS: glib_sys::GSourceFuncs = glib_sys::GSourceFuncs {
134157
closure_marshal: None,
135158
};
136159

160+
unsafe impl Send for TaskSource {}
161+
unsafe impl Sync for TaskSource {}
162+
137163
impl TaskSource {
138164
#[allow(clippy::new_ret_no_self)]
139-
fn new(
140-
priority: Priority,
141-
future: Box<Future<Item = (), Error = Never> + 'static + Send>,
142-
) -> Source {
143-
unsafe { Self::new_unsafe(priority, None, future) }
144-
}
145-
146-
// NOTE: This does not have the Send bound and requires to be called from the same
147-
// thread where the main context is running
148-
unsafe fn new_unsafe(
149-
priority: Priority,
150-
thread: Option<usize>,
151-
future: Box<Future<Item = (), Error = Never> + 'static>,
152-
) -> Source {
153-
let source = glib_sys::g_source_new(
154-
mut_override(&SOURCE_FUNCS),
155-
mem::size_of::<TaskSource>() as u32,
156-
);
157-
{
158-
let source = &mut *(source as *mut TaskSource);
159-
ptr::write(&mut source.future, Some((future, Box::new(LocalMap::new()))));
160-
source.thread = thread;
161-
source.state = AtomicUsize::new(INIT);
162-
}
165+
fn new(priority: Priority, thread: Option<usize>, future: FutureObj<'static, ()>) -> Source {
166+
unsafe {
167+
let source = glib_sys::g_source_new(
168+
mut_override(&SOURCE_FUNCS),
169+
mem::size_of::<TaskSource>() as u32,
170+
);
171+
{
172+
let source = &mut *(source as *mut TaskSource);
173+
ptr::write(&mut source.future, Some(future));
174+
source.thread = thread;
175+
source.state = AtomicUsize::new(INIT);
176+
}
163177

164-
glib_sys::g_source_set_priority(source, priority.to_glib());
178+
glib_sys::g_source_set_priority(source, priority.to_glib());
165179

166-
from_glib_full(source)
180+
from_glib_full(source)
181+
}
167182
}
168183

169-
fn poll(&mut self) -> Async<()> {
184+
fn poll(&mut self) -> Poll<()> {
170185
// Make sure that the first time we're polled that the current thread is remembered
171186
// and from there one we ensure that we're always polled from exactly the same thread.
172187
//
@@ -178,32 +193,34 @@ impl TaskSource {
178193
*thread = Some(get_thread_id());
179194
}
180195
&mut Some(thread_id) => {
181-
assert_eq!(get_thread_id(), thread_id,
182-
"Task polled on a different thread than before");
196+
assert_eq!(
197+
get_thread_id(),
198+
thread_id,
199+
"Task polled on a different thread than before"
200+
);
183201
}
184202
}
185203

186-
let waker = unsafe { self.clone_raw() };
204+
let waker = self.as_waker();
187205
let source = &self.source as *const _;
188206
if let Some(ref mut future) = self.future {
189-
let (ref mut future, ref mut local_map) = *future;
190-
191-
let mut executor: MainContext = unsafe {
192-
from_glib_none(glib_sys::g_source_get_context(mut_override(source)))
193-
};
207+
let mut executor: MainContext =
208+
unsafe { from_glib_none(glib_sys::g_source_get_context(mut_override(source))) };
194209

195-
assert!(executor.is_owner(), "Polling futures only allowed if the thread is owning the MainContext");
210+
assert!(
211+
executor.is_owner(),
212+
"Polling futures only allowed if the thread is owning the MainContext"
213+
);
196214

197215
// Clone that we store in the task local data so that
198216
// it can be retrieved as needed
199217
executor.push_thread_default();
200218

201219
let res = {
202220
let enter = futures::executor::enter().unwrap();
203-
let mut context =
204-
futures::task::Context::new(local_map, &waker, &mut executor);
221+
let mut context = Context::from_waker(&waker);
205222

206-
let res = future.poll(&mut context).unwrap_or(Async::Ready(()));
223+
let res = future.poll_unpin(&mut context);
207224

208225
drop(enter);
209226

@@ -213,7 +230,7 @@ impl TaskSource {
213230
executor.pop_thread_default();
214231
res
215232
} else {
216-
Async::Ready(())
233+
Poll::Ready(())
217234
}
218235
}
219236
}
@@ -223,7 +240,7 @@ impl MainContext {
223240
///
224241
/// This can be called from any thread and will execute the future from the thread
225242
/// where main context is running, e.g. via a `MainLoop`.
226-
pub fn spawn<F: Future<Item = (), Error = Never> + Send + 'static>(&self, f: F) {
243+
pub fn spawn<F: Future<Output = ()> + Send + 'static>(&self, f: F) {
227244
self.spawn_with_priority(::PRIORITY_DEFAULT, f);
228245
}
229246

@@ -234,17 +251,21 @@ impl MainContext {
234251
/// This can be called only from the thread where the main context is running, e.g.
235252
/// from any other `Future` that is executed on this main context, or after calling
236253
/// `push_thread_default` or `acquire` on the main context.
237-
pub fn spawn_local<F: Future<Item = (), Error = Never> + 'static>(&self, f: F) {
254+
pub fn spawn_local<F: Future<Output = ()> + 'static>(&self, f: F) {
238255
self.spawn_local_with_priority(::PRIORITY_DEFAULT, f);
239256
}
240257

241258
/// Spawn a new infallible `Future` on the main context, with a non-default priority.
242259
///
243260
/// This can be called from any thread and will execute the future from the thread
244261
/// where main context is running, e.g. via a `MainLoop`.
245-
pub fn spawn_with_priority<F: Future<Item = (), Error = Never> + Send + 'static>(&self, priority: Priority, f: F) {
246-
let f = Box::new(f);
247-
let source = TaskSource::new(priority, f);
262+
pub fn spawn_with_priority<F: Future<Output = ()> + Send + 'static>(
263+
&self,
264+
priority: Priority,
265+
f: F,
266+
) {
267+
let f = FutureObj::new(Box::new(f));
268+
let source = TaskSource::new(priority, None, f);
248269
source.attach(Some(&*self));
249270
}
250271

@@ -255,13 +276,23 @@ impl MainContext {
255276
/// This can be called only from the thread where the main context is running, e.g.
256277
/// from any other `Future` that is executed on this main context, or after calling
257278
/// `push_thread_default` or `acquire` on the main context.
258-
pub fn spawn_local_with_priority<F: Future<Item = (), Error = Never> + 'static>(&self, priority: Priority, f: F) {
259-
assert!(self.is_owner(), "Spawning local futures only allowed on the thread owning the MainContext");
260-
let f = Box::new(f);
279+
pub fn spawn_local_with_priority<F: Future<Output = ()> + 'static>(
280+
&self,
281+
priority: Priority,
282+
f: F,
283+
) {
284+
assert!(
285+
self.is_owner(),
286+
"Spawning local futures only allowed on the thread owning the MainContext"
287+
);
261288
unsafe {
262-
// Ensure that this task is never polled on another thread
263-
// than this one where it was spawned now.
264-
let source = TaskSource::new_unsafe(priority, Some(get_thread_id()), f);
289+
let f = LocalFutureObj::new(Box::new(f));
290+
// We ensure here that we only ever run the future on this very task
291+
// and that the futures executor is running on this task. Otherwise
292+
// we will panic later.
293+
// As such we can add the Send impl here safely
294+
let f = f.into_future_obj();
295+
let source = TaskSource::new(priority, Some(get_thread_id()), f);
265296
source.attach(Some(&*self));
266297
}
267298
}
@@ -274,7 +305,7 @@ impl MainContext {
274305
/// This must only be called if no `MainLoop` or anything else is running on this specific main
275306
/// context.
276307
#[allow(clippy::transmute_ptr_to_ptr)]
277-
pub fn block_on<F: Future>(&self, f: F) -> Result<F::Item, F::Error> {
308+
pub fn block_on<F: Future>(&self, f: F) -> F::Output {
278309
let mut res = None;
279310
let l = MainLoop::new(Some(&*self), false);
280311
let l_clone = l.clone();
@@ -283,17 +314,17 @@ impl MainContext {
283314
let f = f.then(|r| {
284315
res = Some(r);
285316
l_clone.quit();
286-
Ok::<(), Never>(())
317+
future::ready(())
287318
});
288319

289-
let f: *mut Future<Item = (), Error = Never> = Box::into_raw(Box::new(f));
290-
// XXX: Transmute to get a 'static lifetime here, super unsafe
291-
let f: *mut (Future<Item = (), Error = Never> + 'static) = mem::transmute(f);
292-
let f: Box<Future<Item = (), Error = Never> + 'static> = Box::from_raw(f);
320+
// Super-unsafe: We transmute here to get rid of the 'static lifetime
321+
let f = LocalFutureObj::new(Box::new(f));
322+
let f: (LocalFutureObj<'static, ()>) = mem::transmute(f);
323+
324+
// And ensure that we are only ever running on this very thread.
325+
let f = f.into_future_obj();
293326

294-
// Ensure that this task is never polled on another thread
295-
// than this one where it was spawned now.
296-
let source = TaskSource::new_unsafe(::PRIORITY_DEFAULT, Some(get_thread_id()), f);
327+
let source = TaskSource::new(::PRIORITY_DEFAULT, Some(get_thread_id()), f);
297328
source.attach(Some(&*self));
298329
}
299330

@@ -303,10 +334,19 @@ impl MainContext {
303334
}
304335
}
305336

306-
impl Executor for MainContext {
307-
fn spawn(&mut self, f: Box<Future<Item = (), Error = Never> + Send>) -> Result<(), SpawnError> {
308-
let f = Box::new(f);
309-
let source = TaskSource::new(::PRIORITY_DEFAULT, f);
337+
impl Spawn for MainContext {
338+
fn spawn_obj(&mut self, f: FutureObj<'static, ()>) -> Result<(), SpawnError> {
339+
let source = TaskSource::new(::PRIORITY_DEFAULT, None, f);
340+
source.attach(Some(&*self));
341+
Ok(())
342+
}
343+
}
344+
345+
impl LocalSpawn for MainContext {
346+
fn spawn_local_obj(&mut self, f: LocalFutureObj<'static, ()>) -> Result<(), SpawnError> {
347+
let source = TaskSource::new(::PRIORITY_DEFAULT, Some(get_thread_id()), unsafe {
348+
f.into_future_obj()
349+
});
310350
source.attach(Some(&*self));
311351
Ok(())
312352
}
@@ -315,10 +355,9 @@ impl Executor for MainContext {
315355
#[cfg(test)]
316356
mod tests {
317357
use super::*;
318-
use std::thread;
319-
use std::sync::mpsc;
320-
use futures::future;
321358
use futures::channel::oneshot;
359+
use std::sync::mpsc;
360+
use std::thread;
322361

323362
#[test]
324363
fn test_spawn() {
@@ -329,14 +368,15 @@ mod tests {
329368
let (o_sender, o_receiver) = oneshot::channel();
330369

331370
let l_clone = l.clone();
332-
c.spawn(o_receiver
333-
.map_err(|_| unimplemented!())
371+
c.spawn(
372+
o_receiver
334373
.and_then(move |()| {
335374
sender.send(()).unwrap();
336375
l_clone.quit();
337376

338-
Ok(())
377+
future::ok(())
339378
})
379+
.then(|res| future::ready(res.unwrap())),
340380
);
341381

342382
thread::spawn(move || {
@@ -357,8 +397,6 @@ mod tests {
357397
let l_clone = l.clone();
358398
c.spawn_local(future::lazy(move |_ctx| {
359399
l_clone.quit();
360-
361-
Ok(())
362400
}));
363401

364402
l.run();

0 commit comments

Comments
 (0)