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
//! <a href="https://github.com/Nercury/android_looper-rs">
//! <img style="position: absolute; top: 0; left: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_left_orange_ff7600.png" alt="Fork me on GitHub">
//! </a>
//! <style>.sidebar { margin-top: 53px }</style>
//!
//! From [android docs](http://developer.android.com/reference/android/os/Looper.html):
//!
//! > Class used to run a message loop for a thread. Threads by default do not have a message loop
//! > associated with them; to create one, call prepare() in the thread that is to run the loop, and
//! > then loop() to have it process messages until the loop is stopped.
//!
//! # Library design conventions
//!
//! This library is a minimal safe wrapper for what otherwise be unsafe ffi bindings. There are
//! few conventions used here that are good to know to make the best use of it.
//!
//! ## Safety does not include the correct destruction order
//!
//! While this library may provide the `RAII` wrappers (see bellow), it will not keep
//! track of wrapper dependencies. Doing it at this level would require `Rc` machinery that
//! may cause several problems: force users to use `Rc` or `Arc`, complicate implementation,
//! no longer be zero-cost.
//!
//! Instead, the users are encouraged to build wrappers around these different type kinds (listed
//! bellow) that manage resources as needed for each use case.
//!
//! ### Not-copyable `struct Object` kind
//!
//! This is [RAII](https://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization) type
//! that wraps a low-level resource, provides methods to manipulate it and also destroys it when
//! it goes out of scope. It may also have convenience methods `from_handle` as constructor and method
//! `forget` to get back the handle and disable the `RAII`.
//!
//! ### Copyable `struct/enum Object` kind
//!
//! Used for tracking intermediate glue information, usually replaces or wraps cumbersome `C` unions,
//! types or enums.
//!
//! ### Copyable `struct ObjectRef` kind
//!
//! Wraps a low level handle(s) and provides methods to manipulate it/them. Used in situations
//! where the handle lifetime is controlled by another object or it is some kind of global singleton.
//! In such cases the method calls themselves may return errors when called on expired or invalid
//! handle.
//!

extern crate android_looper_sys as ffi;
extern crate libc;

use self::error::{Error, Result};
use std::ptr;
use libc::c_int;

pub use ffi::LooperPrepareOpts;

pub mod error;

pub type LooperHandle = *mut ffi::ALooper;

/**
Reference to a looper.

From [NDK docs](http://developer.android.com/ndk/reference/group___looper.html):

> A looper is the state tracking an event loop for a thread.
> Loopers do not define event structures or other such things;
> rather they are a lower-level facility to attach one or more discrete objects listening for an
> event. An "event" here is simply data available on a file descriptor: each attached object has
> an associated file descriptor, and waiting for "events" means (internally) polling on all of
> these file descriptors until one or more of them have data available.

> A thread can have only one Looper associated with it.
*/
#[derive(Copy, Clone, Debug)]
pub struct LooperRef {
    handle: LooperHandle,
}

impl LooperRef {
    /// Create `LooperRef` from native handle.
    pub fn from_handle(handle: LooperHandle) -> LooperRef {
        LooperRef { handle: handle }
    }

    /// Prepares a looper associated with the calling thread, and returns it.
    /// If the thread already has a looper, it is returned. Otherwise, a new one is created,
    /// associated with the thread, and returned.
    pub fn prepare(opts: LooperPrepareOpts) -> Result<LooperRef> {
        let looper_handle = unsafe { ffi::ALooper_prepare(opts as c_int) };
        if looper_handle.is_null() {
            return Err(Error::PrepareLooperFailed);
        }
        Ok(LooperRef { handle: looper_handle })
    }

    /// Acquire looper to prevent its deletion until `AcquiredLooper` object is dropped.
    pub fn acquire(&self) -> AcquiredLooper {
        AcquiredLooper::from_ref(*self)
    }

    /// Get native looper handle.
    pub fn handle(&self) -> LooperHandle {
        self.handle
    }

    /// Performs all pending callbacks until all data has been consumed.
    ///
    /// Calls `ALooper_pollAll(0, NULL, NULL, NULL)`.
    /// This method is unstable and may be removed in favor of better version.
    pub fn poll_all_blind(&self) {
        unsafe { ffi::ALooper_pollAll(0, ptr::null_mut(), ptr::null_mut(), ptr::null_mut()) };
    }
}

/// `RAII` acquired looper wrapper.
///
/// This prevents the object from being deleted until this wrapper is dropped.
/// This is only needed to safely hand an ALooper from one thread to another.
pub struct AcquiredLooper {
    handle: LooperHandle,
}

impl AcquiredLooper {
    /// Acquire looper to prevent its deletion until this object is dropped.
    pub fn from_ref(looper: LooperRef) -> AcquiredLooper {
        unsafe { ffi::ALooper_acquire(looper.handle()) }
        AcquiredLooper { handle: looper.handle() }
    }
}

impl Drop for AcquiredLooper {
    fn drop(&mut self) {
        unsafe { ffi::ALooper_acquire(self.handle) }
    }
}