futures_glib/lib.rs
1//! A crate to bring a `futures` executor to the glib event loop
2
3extern crate bytes;
4extern crate futures;
5extern crate glib_sys;
6extern crate libc;
7extern crate net2;
8extern crate slab;
9#[macro_use]
10extern crate tokio_io;
11#[cfg(windows)]
12extern crate winapi;
13
14#[macro_use]
15mod rt;
16mod future;
17mod interval;
18mod stack;
19mod timeout;
20mod utils;
21mod io;
22mod error;
23pub mod net;
24
25use std::cmp;
26use std::marker;
27use std::mem;
28use std::ptr;
29use std::rc::Rc;
30use std::time::{Duration, Instant};
31
32use libc::{c_int, c_uint};
33
34pub use future::{Executor, Remote};
35pub use interval::Interval;
36pub use rt::init;
37pub use timeout::Timeout;
38pub use io::{IoChannel, IoCondition};
39pub use error::Error;
40
41const FALSE: c_int = 0;
42const TRUE: c_int = !FALSE;
43
44/// A small type to avoid running the destructor of `T`
45struct ManuallyDrop<T> { inner: Option<T> }
46
47impl<T> ManuallyDrop<T> {
48 fn new(t: T) -> ManuallyDrop<T> {
49 ManuallyDrop { inner: Some(t) }
50 }
51
52 fn get_ref(&self) -> &T {
53 self.inner.as_ref().unwrap()
54 }
55}
56
57impl<T> Drop for ManuallyDrop<T> {
58 fn drop(&mut self) {
59 mem::forget(self.inner.take())
60 }
61}
62
63/// Binding to the underlying `GMainContext` type.
64pub struct MainContext {
65 inner: *mut glib_sys::GMainContext,
66}
67
68unsafe impl Send for MainContext {}
69unsafe impl Sync for MainContext {}
70
71impl MainContext {
72 /// Creates a new context to execute within.
73 pub fn new() -> MainContext {
74 unsafe {
75 let ptr = glib_sys::g_main_context_new();
76 assert!(!ptr.is_null());
77 MainContext { inner: ptr }
78 }
79 }
80
81 /// Acquires a reference to this thread's default context.
82 ///
83 /// This is the main context used for main loop functions when a main loop
84 /// is not explicitly specified, and corresponds to the "main" main loop.
85 pub fn default<F, R>(f: F) -> R
86 where F: FnOnce(&MainContext) -> R
87 {
88 unsafe {
89 let ptr = glib_sys::g_main_context_default();
90 assert!(!ptr.is_null());
91 let cx = ManuallyDrop::new(MainContext { inner: ptr });
92 f(cx.get_ref())
93
94 }
95 }
96
97 /// Gets the thread-default `MainContext` for this thread.
98 ///
99 /// Asynchronous operations that want to be able to be run in contexts other
100 /// than the default one should call this method or to get a `MainContext`
101 /// to add their `Source`s to. (Note that even in single-threaded programs
102 /// applications may sometimes want to temporarily push a non-default
103 /// context, so it is not safe to assume that this will always yield `None`
104 /// if you are running in the default thread.)
105 pub fn thread_default<F, R>(f: F) -> R
106 where F: FnOnce(Option<&MainContext>) -> R
107 {
108 unsafe {
109 let ptr = glib_sys::g_main_context_get_thread_default();
110 if ptr.is_null() {
111 f(None)
112 } else {
113 let cx = ManuallyDrop::new(MainContext { inner: ptr });
114 f(Some(cx.get_ref()))
115 }
116 }
117 }
118
119 /// Attempts to become the owner of the specified context.
120 ///
121 /// If some other thread is the owner of the context, returns `Err`
122 /// immediately. Ownership is properly recursive: the owner can require
123 /// ownership again.
124 ///
125 /// If the context is successfully locked then a locked version is
126 /// returned, otherwise an `Err` is returned with this context.
127 pub fn try_lock(&self) -> Option<LockedMainContext> {
128 if unsafe { glib_sys::g_main_context_acquire(self.inner) } != 0 {
129 Some(LockedMainContext { inner: self, _marker: marker::PhantomData })
130 } else {
131 None
132 }
133 }
134
135 /// Determines whether this thread holds the (recursive) ownership of this
136 /// `MainContext`.
137 ///
138 /// This is useful to know before waiting on another thread that may be
139 /// blocking to get ownership of context .
140 pub fn is_owner(&self) -> bool {
141 unsafe { glib_sys::g_main_context_is_owner(self.inner) != 0 }
142 }
143
144 /// If context is currently blocking in `iteration` waiting for a source to
145 /// become ready, cause it to stop blocking and return. Otherwise, cause
146 /// the next invocation of `iteration` to return without blocking.
147 ///
148 /// This API is useful for low-level control over `MainContext`; for
149 /// example, integrating it with main loop implementations such as
150 /// `MainLoop`.
151 ///
152 /// Another related use for this function is when implementing a main loop
153 /// with a termination condition, computed from multiple threads.
154 pub fn wakeup(&self) {
155 unsafe {
156 glib_sys::g_main_context_wakeup(self.inner)
157 }
158 }
159
160 /// Acquires context and sets it as the thread-default context for the
161 /// current thread.
162 ///
163 /// This will cause certain asynchronous operations (such as most gio-based
164 /// I/O) which are started in this thread to run under context and deliver
165 /// their results to its main loop, rather than running under the global
166 /// default context in the main thread. Note that calling this function
167 /// changes the context returned by `thread_default` not the one returned
168 /// by `default`.
169 ///
170 /// Normally you would call this function shortly after creating a new
171 /// thread, passing it a `MainContext` which will be run by a `MainLoop` in
172 /// that thread, to set a new default context for all async operations in
173 /// that thread.
174 ///
175 /// If you don't have control over how the new thread was created (e.g. in
176 /// the new thread isn't newly created, or if the thread life cycle is
177 /// managed by a `ThreadPool`), it is always suggested to wrap the logic
178 /// that needs to use the new `MainContext` inside `push_thread_default` block.
179 /// otherwise threads that are re-used will end up never explicitly
180 /// releasing the `MainContext` reference they hold.
181 ///
182 /// In some cases you may want to schedule a single operation in a
183 /// non-default context, or temporarily use a non-default context in the
184 /// main thread. In that case, you can wrap the call to the asynchronous
185 /// operation inside a `push_thread_default` block, but it is up to you to
186 /// ensure that no other asynchronous operations accidentally get started
187 /// while the non-default context is active.
188 ///
189 /// This context will be popped from the default scope when the returned
190 /// `PushThreadDefault` value goes out of scope.
191 pub fn push_thread_default(&self) -> PushThreadDefault {
192 unsafe {
193 glib_sys::g_main_context_push_thread_default(self.inner);
194 }
195 PushThreadDefault { inner: self }
196 }
197}
198
199impl Clone for MainContext {
200 fn clone(&self) -> MainContext {
201 unsafe {
202 let ptr = glib_sys::g_main_context_ref(self.inner);
203 assert!(!ptr.is_null());
204 MainContext { inner: ptr }
205 }
206 }
207}
208
209impl Drop for MainContext {
210 fn drop(&mut self) {
211 unsafe {
212 glib_sys::g_main_context_unref(self.inner);
213 }
214 }
215}
216
217pub struct LockedMainContext<'a> {
218 inner: &'a MainContext,
219 _marker: marker::PhantomData<Rc<()>>, // cannot share across threads
220}
221
222impl<'a> LockedMainContext<'a> {
223 /// Runs a single iteration for the given main loop.
224 ///
225 /// This involves checking to see if any event sources are ready to be
226 /// processed, then if no events sources are ready and may_block is `true`,
227 /// waiting for a source to become ready, then dispatching the highest
228 /// priority events sources that are ready. Otherwise, if may_block is
229 /// `false` sources are not waited to become ready, only those highest
230 /// priority events sources will be dispatched (if any), that are ready at
231 /// this given moment without further waiting.
232 ///
233 /// Note that even when may_block is `true`, it is still possible for
234 /// `iteration` to return `false`, since the wait may be interrupted for other
235 /// reasons than an event source becoming ready.
236 ///
237 /// Returns `true` if events were dispatched.
238 pub fn iteration(&self, may_block: bool) -> bool {
239 let r = unsafe {
240 glib_sys::g_main_context_iteration(self.inner.inner, may_block as c_int)
241 };
242 r != 0
243 }
244
245 /// Checks if any sources have pending events for the given context.
246 pub fn pending(&self) -> bool {
247 unsafe {
248 glib_sys::g_main_context_pending(self.inner.inner) != 0
249 }
250 }
251}
252
253impl<'a> Drop for LockedMainContext<'a> {
254 fn drop(&mut self) {
255 unsafe {
256 glib_sys::g_main_context_release(self.inner.inner);
257 }
258 }
259}
260
261/// An RAII struct that is returned from `push_thread_default` to pop the
262/// default when it goes out of scope.
263pub struct PushThreadDefault<'a> {
264 inner: &'a MainContext,
265}
266
267impl<'a> Drop for PushThreadDefault<'a> {
268 fn drop(&mut self) {
269 unsafe {
270 glib_sys::g_main_context_pop_thread_default(self.inner.inner);
271 }
272 }
273}
274
275pub struct MainLoop {
276 inner: *mut glib_sys::GMainLoop, // TODO: send/sync ?
277}
278
279impl MainLoop {
280 /// Creates a new event loop using the provided context.
281 ///
282 /// If `None` is provided then the default context will be used.
283 pub fn new(cx: Option<&MainContext>) -> MainLoop {
284 let cx = cx.map(|c| c.inner).unwrap_or(0 as *mut _);
285 let ptr = unsafe {
286 glib_sys::g_main_loop_new(cx, FALSE)
287 };
288 assert!(!ptr.is_null());
289 MainLoop { inner: ptr }
290 }
291
292 /// Runs a main loop until `quit` is called on the loop.
293 ///
294 /// If this is called for the thread of the loop's `MainContext`, it will
295 /// process events from the loop, otherwise it will simply wait.
296 pub fn run(&self) {
297 unsafe {
298 glib_sys::g_main_loop_run(self.inner)
299 }
300 }
301
302 /// Stops a `MainLoop` from running. Any calls to `run` for the
303 /// loop will return.
304 ///
305 /// Note that sources that have already been dispatched when
306 /// `quit` is called will still be executed.
307 pub fn quit(&self) {
308 unsafe {
309 glib_sys::g_main_loop_quit(self.inner)
310 }
311 }
312
313 /// Checks to see if the main loop is currently being run via
314 /// `run`.
315 pub fn is_running(&self) -> bool {
316 unsafe {
317 glib_sys::g_main_loop_is_running(self.inner) != 0
318 }
319 }
320
321 /// Returns the context of this loop.
322 pub fn context(&self) -> MainContext {
323 unsafe {
324 let ptr = glib_sys::g_main_loop_get_context(self.inner);
325 glib_sys::g_main_context_ref(ptr);
326 MainContext { inner: ptr }
327 }
328 }
329}
330
331impl Clone for MainLoop {
332 fn clone(&self) -> MainLoop {
333 unsafe {
334 let ptr = glib_sys::g_main_loop_ref(self.inner);
335 assert!(!ptr.is_null());
336 MainLoop { inner: ptr }
337 }
338 }
339}
340
341impl Drop for MainLoop {
342 fn drop(&mut self) {
343 unsafe {
344 glib_sys::g_main_loop_unref(self.inner);
345 }
346 }
347}
348
349/// A binding to the `GSource` underlying type.
350pub struct Source<T> {
351 inner: *mut glib_sys::GSource, // TODO: send/sync?
352 _marker: marker::PhantomData<T>,
353}
354
355struct Inner<T> {
356 _gsource: glib_sys::GSource,
357 funcs: Box<glib_sys::GSourceFuncs>,
358 data: T,
359}
360
361fn source_new<T>(source: *mut glib_sys::GSource) -> Source<T> {
362 Source { inner: source, _marker: marker::PhantomData }
363}
364
365impl<T: SourceFuncs> Source<T> {
366 /// Creates a new `GSource` structure.
367 ///
368 /// The source will not initially be associated with any `MainContext` and
369 /// must be added to one with `attach` before it will be executed.
370 pub fn new(t: T) -> Source<T> {
371 unsafe {
372 let size = mem::size_of::<Inner<T>>();
373 assert!(size < <c_uint>::max_value() as usize);
374 let mut funcs: Box<glib_sys::GSourceFuncs> = Box::new(mem::zeroed());
375 funcs.prepare = Some(prepare::<T>);
376 funcs.check = Some(check::<T>);
377 funcs.dispatch = Some(dispatch::<T>);
378 funcs.finalize = Some(finalize::<T>);
379 let ptr = glib_sys::g_source_new(&mut *funcs, size as c_uint);
380 assert!(!ptr.is_null());
381 ptr::write(&mut (*(ptr as *mut Inner<T>)).data, t);
382 ptr::write(&mut (*(ptr as *mut Inner<T>)).funcs, funcs);
383 Source {
384 inner: ptr,
385 _marker: marker::PhantomData,
386 }
387 }
388 }
389
390 /// Acquires an underlying reference to the data contained within this
391 /// `Source`.
392 pub fn get_ref(&self) -> &T {
393 unsafe { &( *(self.inner as *const Inner<T>) ).data }
394 }
395
396 /// Adds a `Source` to a context so that it will be executed within that
397 /// context.
398 pub fn attach(&self, context: &MainContext) {
399 // NOTE: this is not thread-safe
400 unsafe { glib_sys::g_source_attach(self.inner, context.inner); }
401 }
402
403 /// Removes a source from its `MainContext`, if any, and mark it as
404 /// destroyed.
405 ///
406 /// The source cannot be subsequently added to another context. It is safe
407 /// to call this on sources which have already been removed from their
408 /// context.
409 pub fn destroy(&self) {
410 unsafe { glib_sys::g_source_destroy(self.inner) }
411 }
412
413 /// Sets the priority of a source.
414 ///
415 /// While the main loop is being run, a source will be dispatched if it is
416 /// ready to be dispatched and no sources at a higher (numerically smaller)
417 /// priority are ready to be dispatched.
418 ///
419 /// A child source always has the same priority as its parent. It is not
420 /// permitted to change the priority of a source once it has been added as a
421 /// child of another source.
422 pub fn set_priority(&self, priority: i32) {
423 // NOTE: this is not threadsafe if this isn't registered with a context
424 unsafe { glib_sys::g_source_set_priority(self.inner, priority) }
425 }
426
427 /// Gets the priority of a source.
428 pub fn priority(&self) -> i32 {
429 // NOTE: this is not threadsafe against concurrent writes
430 unsafe { glib_sys::g_source_get_priority(self.inner) }
431 }
432
433 /// Sets whether a source can be called recursively.
434 ///
435 /// If can_recurse is `true`, then while the source is being dispatched then
436 /// this source will be processed normally. Otherwise, all processing of
437 /// this source is blocked until the dispatch function returns.
438 pub fn set_can_recurse(&self, can_recurse: bool) {
439 // NOTE: this is not threadsafe if this isn't registered with a context
440 let can_recurse = if can_recurse { TRUE } else { FALSE };
441 unsafe { glib_sys::g_source_set_can_recurse(self.inner, can_recurse) }
442 }
443
444 /// Checks whether a source is allowed to be called recursively.
445 pub fn can_recurse(&self) -> bool {
446 // NOTE: this is not threadsafe against concurrent writes
447 unsafe { glib_sys::g_source_get_can_recurse(self.inner) != 0 }
448 }
449
450 /// Returns the numeric ID for a particular source.
451 ///
452 /// The ID of a source is a positive integer which is unique within a
453 /// particular main loop context.
454 pub fn get_id(&self) -> u32 {
455 unsafe { glib_sys::g_source_get_id(self.inner) }
456 }
457
458 /// Gets the `MainContext` with which the source is associated.
459 pub fn context(&self) -> Option<MainContext> {
460 unsafe {
461 let context = glib_sys::g_source_get_context(self.inner);
462 if context.is_null() {
463 None
464 }
465 else {
466 glib_sys::g_main_context_ref(context);
467 Some(MainContext {
468 inner: context,
469 })
470 }
471 }
472 }
473
474 /// Sets the callback function for a source. The callback for a source is
475 /// called from the source's dispatch function.
476 pub fn set_callback<F>(&self, f: F)
477 where F: FnMut(T::CallbackArg) -> bool + 'static,
478 {
479 let callback = Box::into_raw(Box::new(f));
480 unsafe {
481 glib_sys::g_source_set_callback(self.inner,
482 T::g_source_func::<F>(),
483 callback as *mut _,
484 Some(destroy::<F>));
485 }
486 //
487 // unsafe extern fn call<F>(user_data: glib_sys::gpointer) -> glib_sys::gboolean
488 // where F: FnMut() -> bool
489 // {
490 // // TODO: needs a bomb to abort on panic
491 // let f = user_data as *mut F;
492 // if (*f)() { 1 } else { 0 }
493 // }
494 //
495 unsafe extern fn destroy<F>(user_data: glib_sys::gpointer) {
496 // TODO: needs a bomb to abort on panic
497 drop(Box::from_raw(user_data as *mut F));
498 }
499 }
500
501 /// Sets a `Source` to be dispatched when the given monotonic time is
502 /// reached (or passed). If the monotonic time is in the past (as it always
503 /// will be if ready_time is the current time) then the source will be
504 /// dispatched immediately.
505 ///
506 /// If ready_time is `None` then the source is never woken up on the basis
507 /// of the passage of time.
508 ///
509 /// Dispatching the source does not reset the ready time. You should do so
510 /// yourself, from the source dispatch function.
511 ///
512 /// Note that if you have a pair of sources where the ready time of one
513 /// suggests that it will be delivered first but the priority for the other
514 /// suggests that it would be delivered first, and the ready time for both
515 /// sources is reached during the same main context iteration then the order
516 /// of dispatch is undefined.
517 ///
518 /// This API is only intended to be used by implementations of `Source`. Do
519 /// not call this API on a `Source` that you did not create.
520 pub fn set_ready_time(&self, ready_time: Option<Instant>) {
521 // NOTE: this is not threadsafe if this isn't registered with a context
522 let time = match ready_time {
523 Some(time) => {
524 let now = Instant::now();
525 if now < time {
526 let duration = time.duration_since(now);
527 let mono_time = unsafe { glib_sys::g_get_monotonic_time() };
528 (utils::millis(duration) * 1000) as i64 + mono_time
529 }
530 else {
531 0
532 }
533 },
534 None => -1,
535 };
536 unsafe { glib_sys::g_source_set_ready_time(self.inner, time) }
537 }
538
539 /// Monitors fd for the IO events in events.
540 ///
541 /// The token returned by this function can be used to remove or modify the
542 /// monitoring of the fd using `unix_remove_fd` or `unix_modify_fd`.
543 ///
544 /// It is not necessary to remove the fd before destroying the source; it
545 /// will be cleaned up automatically.
546 ///
547 /// This API is only intended to be used by implementations of `Source`. Do
548 /// not call this API on a `Source` that you did not create.
549 ///
550 /// As the name suggests, this function is not available on Windows.
551 #[cfg(unix)]
552 pub fn unix_add_fd(&self, fd: i32, events: &IoCondition) -> UnixToken {
553 unsafe {
554 let ptr = glib_sys::g_source_add_unix_fd(self.inner, fd, io::bits(events));
555 UnixToken(ptr)
556 }
557 }
558
559 /// Updates the event mask to watch for the fd identified by tag .
560 ///
561 /// `token` is the token returned from `unix_add_fd`
562 ///
563 /// If you want to remove a fd, don't set its event mask to zero. Instead,
564 /// call `remove_unix_fd`
565 ///
566 /// This API is only intended to be used by implementations of `Source`. Do
567 /// not call this API on a `Source` that you did not create.
568 ///
569 /// As the name suggests, this function is not available on Windows.
570 ///
571 /// # Unsafety
572 ///
573 /// This function can only be called with tokens that were returned from
574 /// this source's `unix_add_fd` implementation and haven't been removed yet.
575 #[cfg(unix)]
576 pub unsafe fn unix_modify_fd(&self,
577 token: &UnixToken,
578 events: &IoCondition) {
579 glib_sys::g_source_modify_unix_fd(self.inner, token.0, io::bits(events));
580 }
581
582 /// Reverses the effect of a previous call to `unix_add_fd`.
583 ///
584 /// You only need to call this if you want to remove an fd from being
585 /// watched while keeping the same source around. In the normal case you
586 /// will just want to destroy the source.
587 ///
588 /// This API is only intended to be used by implementations of `Source`. Do
589 /// not call this API on a `Source` that you did not create.
590 ///
591 /// As the name suggests, this function is not available on Windows.
592 ///
593 /// # Unsafety
594 ///
595 /// This function can only be called with tokens that were returned from
596 /// this source's `unix_add_fd` implementation and haven't been removed yet.
597 #[cfg(unix)]
598 pub unsafe fn unix_remove_fd(&self, token: &UnixToken) {
599 glib_sys::g_source_remove_unix_fd(self.inner, token.0)
600 }
601
602 /// Queries the events reported for the fd corresponding to token on source
603 /// during the last poll.
604 ///
605 /// The return value of this function is only defined when the function is
606 /// called from the check or dispatch functions for source.
607 ///
608 /// This API is only intended to be used by implementations of `Source`. Do
609 /// not call this API on a `Source` that you did not create.
610 ///
611 /// As the name suggests, this function is not available on Windows.
612 ///
613 /// # Unsafety
614 ///
615 /// This function can only be called with tokens that were returned from
616 /// this source's `unix_add_fd` implementation and haven't been removed yet.
617 #[cfg(unix)]
618 pub unsafe fn unix_query_fd(&self, token: &UnixToken) -> IoCondition {
619 io::bits_new(glib_sys::g_source_query_unix_fd(self.inner, token.0))
620 }
621}
622
623impl<T> Clone for Source<T> {
624 fn clone(&self) -> Source<T> {
625 unsafe {
626 let ptr = glib_sys::g_source_ref(self.inner);
627 assert!(!ptr.is_null());
628 Source {
629 inner: ptr,
630 _marker: marker::PhantomData,
631 }
632 }
633 }
634}
635
636impl<T> Drop for Source<T> {
637 fn drop(&mut self) {
638 unsafe {
639 glib_sys::g_source_unref(self.inner);
640 }
641 }
642}
643
644/// Tokens returns from `unix_add_fd` to later remove the fd.
645#[cfg(unix)]
646pub struct UnixToken(glib_sys::gpointer);
647
648/// Trait for the callbacks that will be invoked by the `Source` type.
649pub trait SourceFuncs: Sized {
650 /// Type passed to the callback in `dispatch`.
651 type CallbackArg;
652
653 /// Called before all the file descriptors are polled.
654 ///
655 /// If the source can determine that it is ready here (without waiting for
656 /// the results of the poll() call) it should return `true`. It can also
657 /// return a timeout value which should be the maximum timeout which should
658 /// be passed to the poll() call.
659 ///
660 /// The actual timeout used will be -1 if all sources returned `None` or it
661 /// will be the minimum of all the timeout_ values returned which were >= 0.
662 /// If prepare returns a timeout and the source also has a 'ready time' set
663 /// then the nearer of the two will be used.
664 fn prepare(&self, source: &Source<Self>) -> (bool, Option<Duration>);
665
666 /// Called after all the file descriptors are polled.
667 ///
668 /// The source should return `true` if it is ready to be dispatched. Note
669 /// that some time may have passed since the previous prepare function was
670 /// called, so the source should be checked again here.
671 fn check(&self, source: &Source<Self>) -> bool;
672
673 /// Called to dispatch the event source, after it has returned `true` in
674 /// either its `prepare` or its `check` function.
675 ///
676 /// The dispatch function is passed in a callback function. The dispatch
677 /// function should call the callback function. The return value of the
678 /// dispatch function should be `false` if the source should be removed or
679 /// `true` to keep it.
680 fn dispatch(&self,
681 source: &Source<Self>,
682 f: glib_sys::GSourceFunc,
683 data: glib_sys::gpointer) -> bool;
684
685 /// Returns an FFI function pointer to invoke the closure specified.
686 ///
687 /// This is used to implement the `set_callback` function.
688 fn g_source_func<F>() -> glib_sys::GSourceFunc
689 where F: FnMut(Self::CallbackArg) -> bool;
690}
691
692unsafe extern fn prepare<T: SourceFuncs>(source: *mut glib_sys::GSource,
693 timeout: *mut c_int)
694 -> glib_sys::gboolean {
695 // TODO: needs a bomb to abort on panic
696 let inner = source as *mut Inner<T>;
697 let source = ManuallyDrop::new(Source {
698 inner: source,
699 _marker: marker::PhantomData,
700 });
701 let (ret, duration) = (*inner).data.prepare(source.get_ref());
702 if !ret {
703 return FALSE
704 }
705 if let Some(dur) = duration {
706 *timeout = cmp::max(utils::millis(dur), <c_int>::max_value() as u64) as c_int;
707 }
708 return TRUE
709}
710
711unsafe extern fn check<T: SourceFuncs>(source: *mut glib_sys::GSource) -> glib_sys::gboolean {
712 // TODO: needs a bomb to abort on panic
713 let inner = source as *mut Inner<T>;
714 let source = ManuallyDrop::new(Source {
715 inner: source,
716 _marker: marker::PhantomData,
717 });
718 if (*inner).data.check(source.get_ref()) {
719 1
720 }
721 else {
722 0
723 }
724}
725
726unsafe extern fn dispatch<T: SourceFuncs>(source: *mut glib_sys::GSource,
727 source_func: glib_sys::GSourceFunc,
728 data: glib_sys::gpointer)
729 -> glib_sys::gboolean {
730 // TODO: needs a bomb to abort on panic
731 let inner = source as *mut Inner<T>;
732 let source = ManuallyDrop::new(Source {
733 inner: source,
734 _marker: marker::PhantomData,
735 });
736 if (*inner).data.dispatch(source.get_ref(), source_func, data) {
737 1
738 } else {
739 0
740 }
741}
742
743unsafe extern fn finalize<T: SourceFuncs>(source: *mut glib_sys::GSource) {
744 // TODO: needs a bomb to abort on panic
745 let source = source as *mut Inner<T>;
746 ptr::read(&(*source).funcs);
747 ptr::read(&(*source).data);
748}