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}