<commit_before>use std::ptr;
use std::from_str::FromStr;

use device;
use libudev_c;
use util;

use udev::Udev;
use device::Device;

pub struct Monitor<'u> {
    pub udev: &'u Udev,
    monitor: libudev_c::udev_monitor
}

#[deriving(Show)]
pub enum Action {
    Add,
    Remove,
    Change,
    Move,
    Online,
    Offline
}

#[deriving(Show)]
pub struct Event {
    action: Action,
    seqnum: u64
}

pub struct MonitorIterator<'m, 'u: 'm> {
    monitor: &'m Monitor<'u>
}

pub unsafe fn monitor<'u>(udev: &'u Udev, monitor: libudev_c::udev_monitor) -> Monitor<'u> {
    Monitor {
        udev: udev,
        monitor: monitor
    }
}

#[allow(unused_mut)]
impl<'u> Monitor<'u> {
    pub fn filter_subsystem(mut self, subsystem: &str) -> Monitor<'u> {
        subsystem.with_c_str(|subsystem| util::handle_error(unsafe {
            libudev_c::udev_monitor_filter_add_match_subsystem_devtype(self.monitor, subsystem, ptr::null())
        }));
        self
    }
    pub fn filter_subsystem_devtype(mut self, subsystem: &str, devtype: &str) -> Monitor<'u> {
        subsystem.with_c_str(|subsystem| devtype.with_c_str(|devtype| util::handle_error(unsafe {
            libudev_c::udev_monitor_filter_add_match_subsystem_devtype(self.monitor, subsystem, devtype)
        })));
        self
    }
    pub fn filter_tag(mut self, tag: &str) -> Monitor<'u> {
        tag.with_c_str(|tag| util::handle_error(unsafe {
            libudev_c::udev_monitor_filter_add_match_tag(self.monitor, tag)
        }));
        self
    }
    pub fn unfilter(mut self) -> Monitor<'u> {
        util::handle_error(unsafe {
            libudev_c::udev_monitor_filter_remove(self.monitor)
        });
        self
    }
    pub fn iter<'m>(&'m self) -> MonitorIterator<'m, 'u> {
        util::handle_error(unsafe {
            // Technically this mutates but we're single threaded anyways. Basically, having two
            // iterators existing at the same time won't cause any problems because next() can't be
            // called at the same time (single threaded).
            libudev_c::udev_monitor_enable_receiving(self.monitor)
        });
        MonitorIterator::<'m, 'u> {
            monitor: self
        }
    }
}

#[unsafe_destructor]
impl<'u> Drop for Monitor<'u> {
    fn drop(&mut self) {
        unsafe {
            libudev_c::udev_monitor_unref(self.monitor);
        }
    }
}

impl FromStr for Action {
    fn from_str(s: &str) -> Option<Action> {
        match s {
            "add"       => Some(Add),
            "remove"    => Some(Remove),
            "change"    => Some(Change),
            "move"      => Some(Move),
            "online"    => Some(Online),
            "offline"   => Some(Offline),
            _           => None
        }
    }
}

impl<'m, 'u> Iterator<(Event, Device<'u>)> for MonitorIterator<'m, 'u> {
    fn next(&mut self) -> Option<(Event, Device<'u>)> {
        loop {
            if let Ok(Some(dev)) = util::check_errno(|| unsafe {
                libudev_c::udev_monitor_receive_device(self.monitor.monitor)
            }) {
                return Some((
                    Event {
                        action: from_str(unsafe {
                                    util::c_to_str(libudev_c::udev_device_get_action(dev))
                                }.unwrap()).unwrap(),
                        seqnum: unsafe {
                                    libudev_c::udev_device_get_seqnum(dev)
                                }
                    },
                    unsafe { device::device(self.monitor.udev, dev) }
                ));
            }
        }
    }
}

<commit_msg>remove uncessesary mut.<commit_after>use std::ptr;
use std::from_str::FromStr;

use device;
use libudev_c;
use util;

use udev::Udev;
use device::Device;

pub struct Monitor<'u> {
    pub udev: &'u Udev,
    monitor: libudev_c::udev_monitor
}

#[deriving(Show)]
pub enum Action {
    Add,
    Remove,
    Change,
    Move,
    Online,
    Offline
}

#[deriving(Show)]
pub struct Event {
    action: Action,
    seqnum: u64
}

pub struct MonitorIterator<'m, 'u: 'm> {
    monitor: &'m Monitor<'u>
}

pub unsafe fn monitor(udev: &Udev, monitor: libudev_c::udev_monitor) -> Monitor {
    Monitor {
        udev: udev,
        monitor: monitor
    }
}

impl<'u> Monitor<'u> {
    pub fn filter_subsystem(self, subsystem: &str) -> Monitor<'u> {
        subsystem.with_c_str(|subsystem| util::handle_error(unsafe {
            libudev_c::udev_monitor_filter_add_match_subsystem_devtype(self.monitor, subsystem, ptr::null())
        }));
        self
    }
    pub fn filter_subsystem_devtype(self, subsystem: &str, devtype: &str) -> Monitor<'u> {
        subsystem.with_c_str(|subsystem| devtype.with_c_str(|devtype| util::handle_error(unsafe {
            libudev_c::udev_monitor_filter_add_match_subsystem_devtype(self.monitor, subsystem, devtype)
        })));
        self
    }
    pub fn filter_tag(self, tag: &str) -> Monitor<'u> {
        tag.with_c_str(|tag| util::handle_error(unsafe {
            libudev_c::udev_monitor_filter_add_match_tag(self.monitor, tag)
        }));
        self
    }
    pub fn unfilter(self) -> Monitor<'u> {
        util::handle_error(unsafe {
            libudev_c::udev_monitor_filter_remove(self.monitor)
        });
        self
    }
    pub fn iter<'m>(&'m self) -> MonitorIterator<'m, 'u> {
        util::handle_error(unsafe {
            // Technically this mutates but we're single threaded anyways. Basically, having two
            // iterators existing at the same time won't cause any problems because next() can't be
            // called at the same time (single threaded).
            libudev_c::udev_monitor_enable_receiving(self.monitor)
        });
        MonitorIterator::<'m, 'u> {
            monitor: self
        }
    }
}

#[unsafe_destructor]
impl<'u> Drop for Monitor<'u> {
    fn drop(&mut self) {
        unsafe {
            libudev_c::udev_monitor_unref(self.monitor);
        }
    }
}

impl FromStr for Action {
    fn from_str(s: &str) -> Option<Action> {
        match s {
            "add"       => Some(Add),
            "remove"    => Some(Remove),
            "change"    => Some(Change),
            "move"      => Some(Move),
            "online"    => Some(Online),
            "offline"   => Some(Offline),
            _           => None
        }
    }
}

impl<'m, 'u> Iterator<(Event, Device<'u>)> for MonitorIterator<'m, 'u> {
    fn next(&mut self) -> Option<(Event, Device<'u>)> {
        loop {
            if let Ok(Some(dev)) = util::check_errno(|| unsafe {
                libudev_c::udev_monitor_receive_device(self.monitor.monitor)
            }) {
                return Some((
                    Event {
                        action: from_str(unsafe {
                                    util::c_to_str(libudev_c::udev_device_get_action(dev))
                                }.unwrap()).unwrap(),
                        seqnum: unsafe {
                                    libudev_c::udev_device_get_seqnum(dev)
                                }
                    },
                    unsafe { device::device(self.monitor.udev, dev) }
                ));
            }
        }
    }
}

<|endoftext|>


<commit_before>
//! Trying to module physics using state research.

use UpdateDelta = state::UpdateDelta;

/// The difference in time from one frame to the next.
pub struct DeltaTime(f64);

pub type Position = [f64, ..3];
pub type Velocity = [f64, ..3];

/// Object in motion under no force.
pub struct NoForce {
    /// The position of object.
    pub pos: Position,
    /// The velocity of object.
    pub vel: Velocity,
}

impl UpdateDelta<DeltaTime> for NoForce {
    #[inline(always)]
    fn update(&mut self, &DeltaTime(dt): &DeltaTime) {
        for i in range(0u, 3) {
            self.pos[i] += self.vel[i] * dt;
        }
    }
}

<commit_msg>Added WithAcceleration<commit_after>
//! Trying to module physics using state research.

use UpdateDelta = state::UpdateDelta;

/// The difference in time from one frame to the next.
pub struct DeltaTime(f64);

pub type Position = [f64, ..3];
pub type Velocity = [f64, ..3];
pub type Acceleration = [f64, ..3];

/// Object in motion under no force.
pub struct NoForce {
    /// The position of object.
    pub pos: Position,
    /// The velocity of object.
    pub vel: Velocity,
}

impl UpdateDelta<DeltaTime> for NoForce {
    #[inline(always)]
    fn update(&mut self, &DeltaTime(dt): &DeltaTime) {
        for i in range(0u, 3) {
            self.pos[i] += self.vel[i] * dt;
        }
    }
}

/// Moves point with acceleration.
pub struct WithAcceleration {
    /// The position of object.
    pub pos: Position,
    /// The velocity of object.
    pub vel: Velocity,
    /// The acceleration on object.
    pub acc: Acceleration,
}

impl UpdateDelta<DeltaTime> for WithAcceleration {
    #[inline(always)]
    fn update(&mut self, &DeltaTime(dt): &DeltaTime) {
        for i in range(0u, 3) {
            let vel_next = self.vel[i] + self.acc[i] * dt;
            self.pos[i] += 0.5 * dt * (self.vel[i] + vel_next);
        }
    }
}

<|endoftext|>


<commit_before>use std::fmt;

use self::Resolver::Function;

pub enum Resolver {
    Function(Box<Fn(u64) -> usize>),
}

impl Resolver {
    /// Returns the number of the correct plural form
    /// for `n` objects, as defined by the rule contained in this resolver.
    pub fn resolve(&self, n: u64) -> usize {
        match *self {
            Function(ref func) => func(n),
        }
    }
}

impl fmt::Debug for Resolver {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Function(..) => fmt.write_str("Function(..)"),
        }
    }
}
<commit_msg>Add a little comment<commit_after>use std::fmt;

use self::Resolver::Function;

pub enum Resolver {
    /// A function/closure manually supplied by the user.
    Function(Box<Fn(u64) -> usize>),
}

impl Resolver {
    /// Returns the number of the correct plural form
    /// for `n` objects, as defined by the rule contained in this resolver.
    pub fn resolve(&self, n: u64) -> usize {
        match *self {
            Function(ref func) => func(n),
        }
    }
}

impl fmt::Debug for Resolver {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Function(..) => fmt.write_str("Function(..)"),
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Amanieu d'Antras
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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.

use std::cell::UnsafeCell;
use std::ops::Deref;
use std::time::{Duration, Instant};
use std::fmt;
use std::mem;
use std::marker::PhantomData;
use raw_remutex::RawReentrantMutex;

#[cfg(feature = "owning_ref")]
use owning_ref::StableAddress;

/// A mutex which can be recursively locked by a single thread.
///
/// This type is identical to `Mutex` except for the following points:
///
/// - Locking multiple times from the same thread will work correctly instead of
///   deadlocking.
/// - `ReentrantMutexGuard` does not give mutable references to the locked data.
///   Use a `RefCell` if you need this.
/// - `ReentrantMutexGuard` is not `Send`.
///
/// See [`Mutex`](struct.Mutex.html) for more details about the underlying mutex
/// primitive.
pub struct ReentrantMutex<T: ?Sized> {
    raw: RawReentrantMutex,
    data: UnsafeCell<T>,
}

unsafe impl<T: Send> Send for ReentrantMutex<T> {}
unsafe impl<T: Send> Sync for ReentrantMutex<T> {}

/// An RAII implementation of a "scoped lock" of a reentrant mutex. When this structure
/// is dropped (falls out of scope), the lock will be unlocked.
///
/// The data protected by the mutex can be accessed through this guard via its
/// `Deref` implementation.
#[must_use]
pub struct ReentrantMutexGuard<'a, T: ?Sized + 'a> {
    mutex: &'a ReentrantMutex<T>,

    // The raw pointer here ensures that ReentrantMutexGuard is !Send
    marker: PhantomData<(&'a T, *mut ())>,
}

unsafe impl<'a, T: ?Sized + 'a + Sync> Sync for ReentrantMutexGuard<'a, T> {}

impl<T> ReentrantMutex<T> {
    /// Creates a new reentrant mutex in an unlocked state ready for use.
    #[cfg(feature = "nightly")]
    #[inline]
    pub const fn new(val: T) -> ReentrantMutex<T> {
        ReentrantMutex {
            data: UnsafeCell::new(val),
            raw: RawReentrantMutex::new(),
        }
    }

    /// Creates a new reentrant mutex in an unlocked state ready for use.
    #[cfg(not(feature = "nightly"))]
    #[inline]
    pub fn new(val: T) -> ReentrantMutex<T> {
        ReentrantMutex {
            data: UnsafeCell::new(val),
            raw: RawReentrantMutex::new(),
        }
    }

    /// Consumes this reentrant mutex, returning the underlying data.
    #[inline]
    pub fn into_inner(self) -> T {
        unsafe { self.data.into_inner() }
    }
}

impl<T: ?Sized> ReentrantMutex<T> {
    /// Acquires a reentrant mutex, blocking the current thread until it is able
    /// to do so.
    ///
    /// If the mutex is held by another thread then this function will block the
    /// local thread until it is available to acquire the mutex. If the mutex is
    /// already held by the current thread then this function will increment the
    /// lock reference count and return immediately. Upon returning,
    /// the thread is the only thread with the mutex held. An RAII guard is
    /// returned to allow scoped unlock of the lock. When the guard goes out of
    /// scope, the mutex will be unlocked.
    #[inline]
    pub fn lock(&self) -> ReentrantMutexGuard<T> {
        self.raw.lock();
        ReentrantMutexGuard::new(self)
    }

    /// Attempts to acquire this lock.
    ///
    /// If the lock could not be acquired at this time, then `None` is returned.
    /// Otherwise, an RAII guard is returned. The lock will be unlocked when the
    /// guard is dropped.
    ///
    /// This function does not block.
    #[inline]
    pub fn try_lock(&self) -> Option<ReentrantMutexGuard<T>> {
        if self.raw.try_lock() {
            Some(ReentrantMutexGuard::new(self))
        } else {
            None
        }
    }

    /// Attempts to acquire this lock until a timeout is reached.
    ///
    /// If the lock could not be acquired before the timeout expired, then
    /// `None` is returned. Otherwise, an RAII guard is returned. The lock will
    /// be unlocked when the guard is dropped.
    #[inline]
    pub fn try_lock_for(&self, timeout: Duration) -> Option<ReentrantMutexGuard<T>> {
        if self.raw.try_lock_for(timeout) {
            Some(ReentrantMutexGuard::new(self))
        } else {
            None
        }
    }

    /// Attempts to acquire this lock until a timeout is reached.
    ///
    /// If the lock could not be acquired before the timeout expired, then
    /// `None` is returned. Otherwise, an RAII guard is returned. The lock will
    /// be unlocked when the guard is dropped.
    #[inline]
    pub fn try_lock_until(&self, timeout: Instant) -> Option<ReentrantMutexGuard<T>> {
        if self.raw.try_lock_until(timeout) {
            Some(ReentrantMutexGuard::new(self))
        } else {
            None
        }
    }

    /// Returns a mutable reference to the underlying data.
    ///
    /// Since this call borrows the `ReentrantMutex` mutably, no actual locking needs to
    /// take place---the mutable borrow statically guarantees no locks exist.
    #[inline]
    pub fn get_mut(&mut self) -> &mut T {
        unsafe { &mut *self.data.get() }
    }

    /// Releases the mutex.
    ///
    /// # Safety
    ///
    /// This function must only be called if the mutex was locked using
    /// `raw_lock` or `raw_try_lock`, or if a `ReentrantMutexGuard` from this mutex was
    /// leaked (e.g. with `mem::forget`). The mutex must be locked.
    #[inline]
    pub unsafe fn raw_unlock(&self) {
        self.raw.unlock(false);
    }

    /// Releases the mutex using a fair unlock protocol.
    ///
    /// See `ReentrantMutexGuard::unlock_fair`.
    ///
    /// # Safety
    ///
    /// This function must only be called if the mutex was locked using
    /// `raw_lock` or `raw_try_lock`, or if a `ReentrantMutexGuard` from this mutex was
    /// leaked (e.g. with `mem::forget`). The mutex must be locked.
    #[inline]
    pub unsafe fn raw_unlock_fair(&self) {
        self.raw.unlock(true);
    }
}
impl ReentrantMutex<()> {
    /// Acquires a mutex, blocking the current thread until it is able to do so.
    ///
    /// This is similar to `lock`, except that a `ReentrantMutexGuard` is not returned.
    /// Instead you will need to call `raw_unlock` to release the mutex.
    #[inline]
    pub fn raw_lock(&self) {
        self.raw.lock();
    }

    /// Attempts to acquire this lock.
    ///
    /// This is similar to `try_lock`, except that a `ReentrantMutexGuard` is not
    /// returned. Instead you will need to call `raw_unlock` to release the
    /// mutex.
    #[inline]
    pub fn raw_try_lock(&self) -> bool {
        self.raw.try_lock()
    }
}

impl<T: ?Sized + Default> Default for ReentrantMutex<T> {
    #[inline]
    fn default() -> ReentrantMutex<T> {
        ReentrantMutex::new(Default::default())
    }
}

impl<T: ?Sized + fmt::Debug> fmt::Debug for ReentrantMutex<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.try_lock() {
            Some(guard) => write!(f, "ReentrantMutex {{ data: {:?} }}", &*guard),
            None => write!(f, "ReentrantMutex {{ <locked> }}"),
        }
    }
}

impl<'a, T: ?Sized + 'a> ReentrantMutexGuard<'a, T> {
    fn new(mutex: &'a ReentrantMutex<T>) -> Self {
        ReentrantMutexGuard {
            mutex: mutex,
            marker: PhantomData,
        }
    }
    /// Unlocks the mutex using a fair unlock protocol.
    ///
    /// By default, mutexes are unfair and allow the current thread to re-lock
    /// the mutex before another has the chance to acquire the lock, even if
    /// that thread has been blocked on the mutex for a long time. This is the
    /// default because it allows much higher throughput as it avoids forcing a
    /// context switch on every mutex unlock. This can result in one thread
    /// acquiring a mutex many more times than other threads.
    ///
    /// However in some cases it can be beneficial to ensure fairness by forcing
    /// the lock to pass on to a waiting thread if there is one. This is done by
    /// using this method instead of dropping the `ReentrantMutexGuard` normally.
    #[inline]
    pub fn unlock_fair(self) {
        self.mutex.raw.unlock(true);
        mem::forget(self);
    }
}

impl<'a, T: ?Sized + 'a> Deref for ReentrantMutexGuard<'a, T> {
    type Target = T;
    #[inline]
    fn deref(&self) -> &T {
        unsafe { &*self.mutex.data.get() }
    }
}

impl<'a, T: ?Sized + 'a> Drop for ReentrantMutexGuard<'a, T> {
    #[inline]
    fn drop(&mut self) {
        self.mutex.raw.unlock(false);
    }
}

#[cfg(feature = "owning_ref")]
unsafe impl<'a, T: ?Sized> StableAddress for ReentrantMutexGuard<'a, T> {}

#[cfg(test)]
mod tests {
    use std::cell::RefCell;
    use std::sync::Arc;
    use std::thread;
    use ReentrantMutex;

    #[test]
    fn smoke() {
        let m = ReentrantMutex::new(());
        {
            let a = m.lock();
            {
                let b = m.lock();
                {
                    let c = m.lock();
                    assert_eq!(*c, ());
                }
                assert_eq!(*b, ());
            }
            assert_eq!(*a, ());
        }
    }

    #[test]
    fn is_mutex() {
        let m = Arc::new(ReentrantMutex::new(RefCell::new(0)));
        let m2 = m.clone();
        let lock = m.lock();
        let child = thread::spawn(move || {
            let lock = m2.lock();
            assert_eq!(*lock.borrow(), 4950);
        });
        for i in 0..100 {
            let lock = m.lock();
            *lock.borrow_mut() += i;
        }
        drop(lock);
        child.join().unwrap();
    }

    #[test]
    fn trylock_works() {
        let m = Arc::new(ReentrantMutex::new(()));
        let m2 = m.clone();
        let _lock = m.try_lock();
        let _lock2 = m.try_lock();
        thread::spawn(move || {
            let lock = m2.try_lock();
            assert!(lock.is_none());
        }).join()
            .unwrap();
        let _lock3 = m.try_lock();
    }
}
<commit_msg>Add map() to ReentrantMutexGuard<commit_after>// Copyright 2016 Amanieu d'Antras
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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.

use std::cell::UnsafeCell;
use std::ops::Deref;
use std::time::{Duration, Instant};
use std::fmt;
use std::mem;
use std::marker::PhantomData;
use raw_remutex::RawReentrantMutex;

#[cfg(feature = "owning_ref")]
use owning_ref::StableAddress;

/// A mutex which can be recursively locked by a single thread.
///
/// This type is identical to `Mutex` except for the following points:
///
/// - Locking multiple times from the same thread will work correctly instead of
///   deadlocking.
/// - `ReentrantMutexGuard` does not give mutable references to the locked data.
///   Use a `RefCell` if you need this.
/// - `ReentrantMutexGuard` is not `Send`.
///
/// See [`Mutex`](struct.Mutex.html) for more details about the underlying mutex
/// primitive.
pub struct ReentrantMutex<T: ?Sized> {
    raw: RawReentrantMutex,
    data: UnsafeCell<T>,
}

unsafe impl<T: Send> Send for ReentrantMutex<T> {}
unsafe impl<T: Send> Sync for ReentrantMutex<T> {}

/// An RAII implementation of a "scoped lock" of a reentrant mutex. When this structure
/// is dropped (falls out of scope), the lock will be unlocked.
///
/// The data protected by the mutex can be accessed through this guard via its
/// `Deref` implementation.
#[must_use]
pub struct ReentrantMutexGuard<'a, T: ?Sized + 'a> {
    raw: &'a RawReentrantMutex,
    data: *const T,
    marker: PhantomData<&'a T>,
}

unsafe impl<'a, T: ?Sized + Sync + 'a> Sync for ReentrantMutexGuard<'a, T> {}

impl<T> ReentrantMutex<T> {
    /// Creates a new reentrant mutex in an unlocked state ready for use.
    #[cfg(feature = "nightly")]
    #[inline]
    pub const fn new(val: T) -> ReentrantMutex<T> {
        ReentrantMutex {
            data: UnsafeCell::new(val),
            raw: RawReentrantMutex::new(),
        }
    }

    /// Creates a new reentrant mutex in an unlocked state ready for use.
    #[cfg(not(feature = "nightly"))]
    #[inline]
    pub fn new(val: T) -> ReentrantMutex<T> {
        ReentrantMutex {
            data: UnsafeCell::new(val),
            raw: RawReentrantMutex::new(),
        }
    }

    /// Consumes this reentrant mutex, returning the underlying data.
    #[inline]
    pub fn into_inner(self) -> T {
        unsafe { self.data.into_inner() }
    }
}

impl<T: ?Sized> ReentrantMutex<T> {
    #[inline]
    fn guard(&self) -> ReentrantMutexGuard<T> {
        ReentrantMutexGuard {
            raw: &self.raw,
            data: self.data.get(),
            marker: PhantomData,
        }
    }

    /// Acquires a reentrant mutex, blocking the current thread until it is able
    /// to do so.
    ///
    /// If the mutex is held by another thread then this function will block the
    /// local thread until it is available to acquire the mutex. If the mutex is
    /// already held by the current thread then this function will increment the
    /// lock reference count and return immediately. Upon returning,
    /// the thread is the only thread with the mutex held. An RAII guard is
    /// returned to allow scoped unlock of the lock. When the guard goes out of
    /// scope, the mutex will be unlocked.
    #[inline]
    pub fn lock(&self) -> ReentrantMutexGuard<T> {
        self.raw.lock();
        self.guard()
    }

    /// Attempts to acquire this lock.
    ///
    /// If the lock could not be acquired at this time, then `None` is returned.
    /// Otherwise, an RAII guard is returned. The lock will be unlocked when the
    /// guard is dropped.
    ///
    /// This function does not block.
    #[inline]
    pub fn try_lock(&self) -> Option<ReentrantMutexGuard<T>> {
        if self.raw.try_lock() {
            Some(self.guard())
        } else {
            None
        }
    }

    /// Attempts to acquire this lock until a timeout is reached.
    ///
    /// If the lock could not be acquired before the timeout expired, then
    /// `None` is returned. Otherwise, an RAII guard is returned. The lock will
    /// be unlocked when the guard is dropped.
    #[inline]
    pub fn try_lock_for(&self, timeout: Duration) -> Option<ReentrantMutexGuard<T>> {
        if self.raw.try_lock_for(timeout) {
            Some(self.guard())
        } else {
            None
        }
    }

    /// Attempts to acquire this lock until a timeout is reached.
    ///
    /// If the lock could not be acquired before the timeout expired, then
    /// `None` is returned. Otherwise, an RAII guard is returned. The lock will
    /// be unlocked when the guard is dropped.
    #[inline]
    pub fn try_lock_until(&self, timeout: Instant) -> Option<ReentrantMutexGuard<T>> {
        if self.raw.try_lock_until(timeout) {
            Some(self.guard())
        } else {
            None
        }
    }

    /// Returns a mutable reference to the underlying data.
    ///
    /// Since this call borrows the `ReentrantMutex` mutably, no actual locking needs to
    /// take place---the mutable borrow statically guarantees no locks exist.
    #[inline]
    pub fn get_mut(&mut self) -> &mut T {
        unsafe { &mut *self.data.get() }
    }

    /// Releases the mutex.
    ///
    /// # Safety
    ///
    /// This function must only be called if the mutex was locked using
    /// `raw_lock` or `raw_try_lock`, or if a `ReentrantMutexGuard` from this mutex was
    /// leaked (e.g. with `mem::forget`). The mutex must be locked.
    #[inline]
    pub unsafe fn raw_unlock(&self) {
        self.raw.unlock(false);
    }

    /// Releases the mutex using a fair unlock protocol.
    ///
    /// See `ReentrantMutexGuard::unlock_fair`.
    ///
    /// # Safety
    ///
    /// This function must only be called if the mutex was locked using
    /// `raw_lock` or `raw_try_lock`, or if a `ReentrantMutexGuard` from this mutex was
    /// leaked (e.g. with `mem::forget`). The mutex must be locked.
    #[inline]
    pub unsafe fn raw_unlock_fair(&self) {
        self.raw.unlock(true);
    }
}
impl ReentrantMutex<()> {
    /// Acquires a mutex, blocking the current thread until it is able to do so.
    ///
    /// This is similar to `lock`, except that a `ReentrantMutexGuard` is not returned.
    /// Instead you will need to call `raw_unlock` to release the mutex.
    #[inline]
    pub fn raw_lock(&self) {
        self.raw.lock();
    }

    /// Attempts to acquire this lock.
    ///
    /// This is similar to `try_lock`, except that a `ReentrantMutexGuard` is not
    /// returned. Instead you will need to call `raw_unlock` to release the
    /// mutex.
    #[inline]
    pub fn raw_try_lock(&self) -> bool {
        self.raw.try_lock()
    }
}

impl<T: ?Sized + Default> Default for ReentrantMutex<T> {
    #[inline]
    fn default() -> ReentrantMutex<T> {
        ReentrantMutex::new(Default::default())
    }
}

impl<T: ?Sized + fmt::Debug> fmt::Debug for ReentrantMutex<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.try_lock() {
            Some(guard) => write!(f, "ReentrantMutex {{ data: {:?} }}", &*guard),
            None => write!(f, "ReentrantMutex {{ <locked> }}"),
        }
    }
}

impl<'a, T: ?Sized + 'a> ReentrantMutexGuard<'a, T> {
    /// Unlocks the mutex using a fair unlock protocol.
    ///
    /// By default, mutexes are unfair and allow the current thread to re-lock
    /// the mutex before another has the chance to acquire the lock, even if
    /// that thread has been blocked on the mutex for a long time. This is the
    /// default because it allows much higher throughput as it avoids forcing a
    /// context switch on every mutex unlock. This can result in one thread
    /// acquiring a mutex many more times than other threads.
    ///
    /// However in some cases it can be beneficial to ensure fairness by forcing
    /// the lock to pass on to a waiting thread if there is one. This is done by
    /// using this method instead of dropping the `ReentrantMutexGuard` normally.
    #[inline]
    pub fn unlock_fair(self) {
        self.raw.unlock(true);
        mem::forget(self);
    }

    /// Make a new `ReentrantMutexGuard` for a component of the locked data.
    ///
    /// This operation cannot fail as the `ReentrantMutexGuard` passed
    /// in already locked the mutex.
    ///
    /// This is an associated function that needs to be
    /// used as `ReentrantMutexGuard::map(...)`. A method would interfere with
    /// methods of the same name on the contents of the locked data.
    #[inline]
    pub fn map<U: ?Sized, F>(orig: Self, f: F) -> ReentrantMutexGuard<'a, U>
        where F: FnOnce(&T) -> &U
    {
        let raw = orig.raw;
        let data = f(unsafe { &*orig.data });
        mem::forget(orig);
        ReentrantMutexGuard {
            raw,
            data,
            marker: PhantomData,
        }
    }
}

impl<'a, T: ?Sized + 'a> Deref for ReentrantMutexGuard<'a, T> {
    type Target = T;
    #[inline]
    fn deref(&self) -> &T {
        unsafe { &*self.data }
    }
}

impl<'a, T: ?Sized + 'a> Drop for ReentrantMutexGuard<'a, T> {
    #[inline]
    fn drop(&mut self) {
        self.raw.unlock(false);
    }
}

#[cfg(feature = "owning_ref")]
unsafe impl<'a, T: ?Sized> StableAddress for ReentrantMutexGuard<'a, T> {}

#[cfg(test)]
mod tests {
    use std::cell::RefCell;
    use std::sync::Arc;
    use std::thread;
    use ReentrantMutex;

    #[test]
    fn smoke() {
        let m = ReentrantMutex::new(());
        {
            let a = m.lock();
            {
                let b = m.lock();
                {
                    let c = m.lock();
                    assert_eq!(*c, ());
                }
                assert_eq!(*b, ());
            }
            assert_eq!(*a, ());
        }
    }

    #[test]
    fn is_mutex() {
        let m = Arc::new(ReentrantMutex::new(RefCell::new(0)));
        let m2 = m.clone();
        let lock = m.lock();
        let child = thread::spawn(move || {
            let lock = m2.lock();
            assert_eq!(*lock.borrow(), 4950);
        });
        for i in 0..100 {
            let lock = m.lock();
            *lock.borrow_mut() += i;
        }
        drop(lock);
        child.join().unwrap();
    }

    #[test]
    fn trylock_works() {
        let m = Arc::new(ReentrantMutex::new(()));
        let m2 = m.clone();
        let _lock = m.try_lock();
        let _lock2 = m.try_lock();
        thread::spawn(move || {
            let lock = m2.try_lock();
            assert!(lock.is_none());
        }).join()
            .unwrap();
        let _lock3 = m.try_lock();
    }
}
<|endoftext|>


<commit_before>//! common functions for all parsers

/// Interface of all Rusticata parsers.
///
/// A object implementing the RParser trait is an instance of a parser,
/// including the state (and all associated variables).
pub trait RParser {
    // XXX static functions seem to cause problems with hashmaps
    // fn probe(&[u8]) -> bool;

    /// Parsing function
    ///
    /// This function is called for every packet of a connection.
    ///
    /// Arguments:
    ///
    /// - `self`: the state (parser instance)
    /// - a slice on the packet data
    /// - the direction of this packet (0: to server, 1: to client)
    ///
    /// Return value:
    ///
    /// `R_STATUS_OK` or `R_STATUS_FAIL`, possibly or'ed with
    /// `R_STATUS_EVENTS` if parsing events were raised.
    fn parse(&mut self, &[u8], u8) -> u32;
}

// status: return code, events

pub static R_STATUS_EVENTS : u32  = 0x0100;

pub static R_STATUS_OK : u32      = 0x0000;
pub static R_STATUS_FAIL : u32    = 0x0001;

pub static R_STATUS_EV_MASK : u32 = 0x0f00;
pub static R_STATUS_MASK : u32    = 0x00ff;

macro_rules! r_status_is_ok {
    ($status:expr) => { ($status & $crate::R_STATUS_MASK) == $crate::R_STATUS_MASK }
}

macro_rules! r_status_has_events {
    ($status:expr) => { ($status & $crate::R_STATUS_EV_MASK) == $crate::R_STATUS_EVENTS }
}

// Helper macros
// We can't define them (can we ?) in the trait, partly because of the 'no_mangle' and 'extern'
// stuff.
// This forces to use macros in addition to the trait, but at least provides a proper way of
// encapsulating the translation of C variables to rust.

macro_rules! r_declare_state_new {
    ($f:ident, $ty:ident, $args:expr) => {
        #[no_mangle]
        pub extern "C" fn $f() -> *mut libc::c_char {
            let b = Box::new($ty::new($args));
            unsafe { mem::transmute(b) }
        }
    }
}

macro_rules! r_declare_state_free {
    ($f:ident, $ty:ident, $expr:expr) => {
        impl<'a> Drop for $ty<'a> {
            fn drop(&mut self) {
                $expr
            }
        }

        #[no_mangle]
        pub extern fn $f(ptr: *mut libc::c_char)
        {
            let b: Box<$ty> = unsafe { mem::transmute(ptr) };
            // reference will be dropped automatically, and allocated memory
            // will be freed
            // but let's do it explicitly
            drop(b);
        }
    }
}

macro_rules! r_implement_probe {
    ($f:ident, $g:ident) => {
        #[no_mangle]
        pub extern "C" fn $f(input: *const c_char, input_len: u32, _offset: *const c_char) -> u32 {
            let data_len = input_len as usize;
            let data : &[u8] = unsafe { std::slice::from_raw_parts(input as *mut u8, data_len) };
            match $g(data) {
                true  => 1,
                false => 0,
            }
        }
    }
}

macro_rules! r_implement_parse {
    ($f:ident, $g:ident) => {
        #[no_mangle]
        pub extern "C" fn $f(direction: u8, input: *const c_char, input_len: u32, ptr: *mut $g) -> u32 {
            let data_len = input_len as usize;
            let data : &[u8] = unsafe { std::slice::from_raw_parts(input as *mut u8, data_len) };
            if ptr.is_null() { return 0xffff; };
            let parser = unsafe { &mut *ptr };
            parser.parse(data, direction)
        }
    }
}

<commit_msg>Catch unwinding exceptions in parse and probe calls<commit_after>//! common functions for all parsers

/// Interface of all Rusticata parsers.
///
/// A object implementing the RParser trait is an instance of a parser,
/// including the state (and all associated variables).
pub trait RParser {
    // XXX static functions seem to cause problems with hashmaps
    // fn probe(&[u8]) -> bool;

    /// Parsing function
    ///
    /// This function is called for every packet of a connection.
    ///
    /// Arguments:
    ///
    /// - `self`: the state (parser instance)
    /// - a slice on the packet data
    /// - the direction of this packet (0: to server, 1: to client)
    ///
    /// Return value:
    ///
    /// `R_STATUS_OK` or `R_STATUS_FAIL`, possibly or'ed with
    /// `R_STATUS_EVENTS` if parsing events were raised.
    fn parse(&mut self, &[u8], u8) -> u32;
}

// status: return code, events

pub static R_STATUS_EVENTS : u32  = 0x0100;

pub static R_STATUS_OK : u32      = 0x0000;
pub static R_STATUS_FAIL : u32    = 0x0001;

pub static R_STATUS_EV_MASK : u32 = 0x0f00;
pub static R_STATUS_MASK : u32    = 0x00ff;

#[macro_export]
macro_rules! r_status_is_ok {
    ($status:expr) => { ($status & $crate::R_STATUS_MASK) == $crate::R_STATUS_MASK }
}

#[macro_export]
macro_rules! r_status_has_events {
    ($status:expr) => { ($status & $crate::R_STATUS_EV_MASK) == $crate::R_STATUS_EVENTS }
}

// Helper macros
// We can't define them (can we ?) in the trait, partly because of the 'no_mangle' and 'extern'
// stuff.
// This forces to use macros in addition to the trait, but at least provides a proper way of
// encapsulating the translation of C variables to rust.

#[macro_export]
macro_rules! r_declare_state_new {
    ($f:ident, $ty:ident, $args:expr) => {
        #[no_mangle]
        pub extern "C" fn $f() -> *mut libc::c_char {
            let b = Box::new($ty::new($args));
            unsafe { mem::transmute(b) }
        }
    }
}

#[macro_export]
macro_rules! r_declare_state_free {
    ($f:ident, $ty:ident, $expr:expr) => {
        impl<'a> Drop for $ty<'a> {
            fn drop(&mut self) {
                $expr
            }
        }

        #[no_mangle]
        pub extern fn $f(ptr: *mut libc::c_char)
        {
            let b: Box<$ty> = unsafe { mem::transmute(ptr) };
            // reference will be dropped automatically, and allocated memory
            // will be freed
            // but let's do it explicitly
            drop(b);
        }
    }
}

#[macro_export]
macro_rules! r_implement_probe {
    ($f:ident, $g:ident) => {
        #[no_mangle]
        pub extern "C" fn $f(input: *const c_char, input_len: u32, _offset: *const c_char) -> u32 {
            let data_len = input_len as usize;
            let data : &[u8] = unsafe { std::slice::from_raw_parts(input as *mut u8, data_len) };
            let res = ::std::panic::catch_unwind(|| {
                match $g(data) {
                    true  => 1,
                    false => 0,
                }
            });
            match res {
                Ok(v)  => v,
                Err(_) => 0xffffffff,
            }
        }
    }
}

#[macro_export]
macro_rules! r_implement_parse {
    ($f:ident, $g:ident) => {
        #[no_mangle]
        pub extern "C" fn $f(direction: u8, input: *const c_char, input_len: u32, ptr: *mut $g) -> u32 {
            let data_len = input_len as usize;
            let data : &[u8] = unsafe { std::slice::from_raw_parts(input as *mut u8, data_len) };
            if ptr.is_null() { return 0xffffffff; };
            let res = ::std::panic::catch_unwind(|| {
                let parser = unsafe { &mut *ptr };
                parser.parse(data, direction)
            });
            match res {
                Ok(v)  => v,
                Err(_) => 0xffffffff,
            }
        }
    }
}

<|endoftext|>


<commit_before>use core::prelude::*;

use core::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
use core::cell::UnsafeCell;
use core::ops::{Deref, DerefMut};

/// A reader-writer lock
///
/// This type of lock allows a number of readers or at most one writer at any
/// point in time. The write portion of this lock typically allows modification
/// of the underlying data (exclusive access) and the read portion of this lock
/// typically allows for read-only access (shared access).
///
/// The type parameter `T` represents the data that this lock protects. It is
/// required that `T` satisfies `Send` to be shared across tasks and `Sync` to
/// allow concurrent access through readers. The RAII guards returned from the
/// locking methods implement `Deref` (and `DerefMut` for the `write` methods)
/// to allow access to the contained of the lock.
///
/// Based on
/// https://jfdube.wordpress.com/2014/01/03/implementing-a-recursive-read-write-spinlock/
///
pub struct RwLock<T>
{
    lock: AtomicUsize,
    data: UnsafeCell<T>,
}

/// A guard to which the protected data can be read
///
/// When the guard falls out of scope it will decrement the read count,
/// potentially releasing the lock.
pub struct RwLockReadGuard<'a, T:'a>
{
    lock: &'a AtomicUsize,
    data: &'a T,
}

/// A guard to which the protected data can be written
///
/// When the guard falls out of scope it will release the lock.
pub struct RwLockWriteGuard<'a, T:'a>
{
    lock: &'a AtomicUsize,
    data: &'a mut T,
}

unsafe impl<T> Sync for RwLock<T> {}
unsafe impl<T:'static+Send> Send for RwLock<T> {}

/// A RwLock which may be used statically.
///
/// ```
/// use spin::{StaticRwLock, STATIC_RWLOCK_INIT};
///
/// static SPRWLCK: StaticRwLock = STATIC_RWLOCK_INIT;
///
/// fn demo() {
///     let lock = SPRWLCK.read();
///     // do something with lock
///     drop(lock);
/// }
/// ```
pub type StaticRwLock = RwLock<()>;

/// A initializer for StaticRwLock, containing no data.
pub const STATIC_RWLOCK_INIT: StaticRwLock = RwLock {
    lock: ATOMIC_USIZE_INIT,
    data: UnsafeCell { value: () },
};

const USIZE_MSB: usize = ::core::isize::MIN as usize;

impl<T> RwLock<T>
{
    /// Creates a new spinlock wrapping the supplied data.
    #[inline]
    pub fn new(user_data: T) -> RwLock<T>
    {
        RwLock
        {
            lock: ATOMIC_USIZE_INIT,
            data: UnsafeCell::new(user_data),
        }
    }

    /// Locks this rwlock with shared read access, blocking the current thread
    /// until it can be acquired.
    ///
    /// The calling thread will be blocked until there are no more writers which
    /// hold the lock. There may be other readers currently inside the lock when
    /// this method returns. This method does not provide any guarantees with
    /// respect to the ordering of whether contentious readers or writers will
    /// acquire the lock first.
    ///
    /// Returns an RAII guard which will release this thread's shared access
    /// once it is dropped.
    ///
    /// ```
    /// let mylock = spin::RwLock::new(0us);
    /// {
    ///     let mut data = mylock.read();
    ///     // The lock is now locked and the data can be read
    ///     println!("{}", *data);
    ///     // The lock is dropped
    /// }
    /// ```
    #[inline]
    pub fn read<'a>(&'a self) -> RwLockReadGuard<'a, T>
    {
        // (funny do-while loop)
        while {
            // Old value, with write bit unset
            let mut old;

            // Wait for for writer to go away before doing expensive atomic ops
            // (funny do-while loop)
            while {
                old = self.lock.load(Ordering::Relaxed);
                old & USIZE_MSB != 0
            } {}

            // unset write bit
            old &= !USIZE_MSB;

            let new = old + 1;
            debug_assert!(new != (!USIZE_MSB) & (-1));

            self.lock.compare_and_swap(old, new, Ordering::SeqCst) != old
        } {}
        RwLockReadGuard {
            lock: &self.lock,
            data: unsafe { & *self.data.get() },
        }
    }

    /// Attempt to acquire this lock with shared read access.
    ///
    /// This function will never block and will return immediately if `read`
    /// would otherwise succeed. Returns `Some` of an RAII guard which will
    /// release the shared access of this thread when dropped, or `None` if the
    /// access could not be granted. This method does not provide any
    /// guarantees with respect to the ordering of whether contentious readers
    /// or writers will acquire the lock first.
    ///
    /// ```
    /// let mylock = spin::RwLock::new(0us);
    /// {
    ///     match mylock.try_read() {
    ///         Some(data) => {
    ///             // The lock is now locked and the data can be read
    ///             println!("{}", *data);
    ///             // The lock is dropped
    ///         },
    ///         None => (), // no cigar
    ///     }
    /// }
    /// ```
    #[inline]
    pub fn try_read(&self) -> Option<RwLockReadGuard<T>>
    {
        // Old value, with write bit unset
        let old = (!USIZE_MSB) & self.lock.load(Ordering::Relaxed);

        let new = old + 1;
        debug_assert!(new != (!USIZE_MSB) & (-1));
        if self.lock.compare_and_swap(old,
                                      new,
                                      Ordering::SeqCst) == old
        {
            Some(RwLockReadGuard {
                lock: &self.lock,
                data: unsafe { & *self.data.get() },
            })
        } else {
            None
        }
    }

    /// Lock this rwlock with exclusive write access, blocking the current
    /// thread until it can be acquired.
    ///
    /// This function will not return while other writers or other readers
    /// currently have access to the lock.
    ///
    /// Returns an RAII guard which will drop the write access of this rwlock
    /// when dropped.
    ///
    /// ```
    /// let mylock = spin::RwLock::new(0us);
    /// {
    ///     let mut data = mylock.write();
    ///     // The lock is now locked and the data can be written
    ///     *data += 1;
    ///     // The lock is dropped
    /// }
    /// ```
    #[inline]
    pub fn write<'a>(&'a self) -> RwLockWriteGuard<'a, T>
    {
        loop
        {
            // Old value, with write bit unset.
            let old = (!USIZE_MSB) & self.lock.load(Ordering::Relaxed);
            // Old value, with write bit set.
            let new = USIZE_MSB | old;
            if self.lock.compare_and_swap(old,
                                          new,
                                          Ordering::SeqCst) == old
            {
                // Wait for readers to go away, then lock is ours.
                while self.lock.load(Ordering::Relaxed) != USIZE_MSB { }
                break
            }
        }
        RwLockWriteGuard {
            lock: &self.lock,
            data: unsafe { &mut *self.data.get() },
        }
    }

    /// Attempt to lock this rwlock with exclusive write access.
    ///
    /// This function does not ever block, and it will return `None` if a call
    /// to `write` would otherwise block. If successful, an RAII guard is
    /// returned.
    ///
    /// ```
    /// let mylock = spin::RwLock::new(0us);
    /// {
    ///     match mylock.try_write() {
    ///         Some(mut data) => {
    ///             // The lock is now locked and the data can be written
    ///             *data += 1;
    ///             // The lock is implicitly dropped
    ///         },
    ///         None => (), // no cigar
    ///     }
    /// }
    /// ```
    #[inline]
    pub fn try_write(&self) -> Option<RwLockWriteGuard<T>>
    {
        if self.lock.compare_and_swap(0,
                                      USIZE_MSB,
                                      Ordering::SeqCst) == 0
        {
            Some(RwLockWriteGuard {
                lock: &self.lock,
                data: unsafe { &mut *self.data.get() },
            })
        } else {
            None
        }
    }
}

impl<'rwlock, T> Deref for RwLockReadGuard<'rwlock, T> {
    type Target = T;

    fn deref(&self) -> &T { self.data }
}

impl<'rwlock, T> Deref for RwLockWriteGuard<'rwlock, T> {
    type Target = T;

    fn deref(&self) -> &T { self.data }
}

impl<'rwlock, T> DerefMut for RwLockWriteGuard<'rwlock, T> {
    fn deref_mut(&mut self) -> &mut T { self.data }
}

#[unsafe_destructor]
impl<'rwlock, T> Drop for RwLockReadGuard<'rwlock, T> {
    fn drop(&mut self) {
        debug_assert!(self.lock.load(Ordering::Relaxed) & (!USIZE_MSB) > 0);
        self.lock.fetch_sub(1, Ordering::SeqCst);
    }
}

#[unsafe_destructor]
impl<'rwlock, T> Drop for RwLockWriteGuard<'rwlock, T> {
    fn drop(&mut self) {
        debug_assert_eq!(self.lock.load(Ordering::Relaxed), USIZE_MSB);
        self.lock.store(0, Ordering::Relaxed);
    }
}
<commit_msg>Change `match` to `if let` to satisfy dropck<commit_after>use core::prelude::*;

use core::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
use core::cell::UnsafeCell;
use core::ops::{Deref, DerefMut};

/// A reader-writer lock
///
/// This type of lock allows a number of readers or at most one writer at any
/// point in time. The write portion of this lock typically allows modification
/// of the underlying data (exclusive access) and the read portion of this lock
/// typically allows for read-only access (shared access).
///
/// The type parameter `T` represents the data that this lock protects. It is
/// required that `T` satisfies `Send` to be shared across tasks and `Sync` to
/// allow concurrent access through readers. The RAII guards returned from the
/// locking methods implement `Deref` (and `DerefMut` for the `write` methods)
/// to allow access to the contained of the lock.
///
/// Based on
/// https://jfdube.wordpress.com/2014/01/03/implementing-a-recursive-read-write-spinlock/
///
pub struct RwLock<T>
{
    lock: AtomicUsize,
    data: UnsafeCell<T>,
}

/// A guard to which the protected data can be read
///
/// When the guard falls out of scope it will decrement the read count,
/// potentially releasing the lock.
pub struct RwLockReadGuard<'a, T:'a>
{
    lock: &'a AtomicUsize,
    data: &'a T,
}

/// A guard to which the protected data can be written
///
/// When the guard falls out of scope it will release the lock.
pub struct RwLockWriteGuard<'a, T:'a>
{
    lock: &'a AtomicUsize,
    data: &'a mut T,
}

unsafe impl<T> Sync for RwLock<T> {}
unsafe impl<T:'static+Send> Send for RwLock<T> {}

/// A RwLock which may be used statically.
///
/// ```
/// use spin::{StaticRwLock, STATIC_RWLOCK_INIT};
///
/// static SPRWLCK: StaticRwLock = STATIC_RWLOCK_INIT;
///
/// fn demo() {
///     let lock = SPRWLCK.read();
///     // do something with lock
///     drop(lock);
/// }
/// ```
pub type StaticRwLock = RwLock<()>;

/// A initializer for StaticRwLock, containing no data.
pub const STATIC_RWLOCK_INIT: StaticRwLock = RwLock {
    lock: ATOMIC_USIZE_INIT,
    data: UnsafeCell { value: () },
};

const USIZE_MSB: usize = ::core::isize::MIN as usize;

impl<T> RwLock<T>
{
    /// Creates a new spinlock wrapping the supplied data.
    #[inline]
    pub fn new(user_data: T) -> RwLock<T>
    {
        RwLock
        {
            lock: ATOMIC_USIZE_INIT,
            data: UnsafeCell::new(user_data),
        }
    }

    /// Locks this rwlock with shared read access, blocking the current thread
    /// until it can be acquired.
    ///
    /// The calling thread will be blocked until there are no more writers which
    /// hold the lock. There may be other readers currently inside the lock when
    /// this method returns. This method does not provide any guarantees with
    /// respect to the ordering of whether contentious readers or writers will
    /// acquire the lock first.
    ///
    /// Returns an RAII guard which will release this thread's shared access
    /// once it is dropped.
    ///
    /// ```
    /// let mylock = spin::RwLock::new(0us);
    /// {
    ///     let mut data = mylock.read();
    ///     // The lock is now locked and the data can be read
    ///     println!("{}", *data);
    ///     // The lock is dropped
    /// }
    /// ```
    #[inline]
    pub fn read<'a>(&'a self) -> RwLockReadGuard<'a, T>
    {
        // (funny do-while loop)
        while {
            // Old value, with write bit unset
            let mut old;

            // Wait for for writer to go away before doing expensive atomic ops
            // (funny do-while loop)
            while {
                old = self.lock.load(Ordering::Relaxed);
                old & USIZE_MSB != 0
            } {}

            // unset write bit
            old &= !USIZE_MSB;

            let new = old + 1;
            debug_assert!(new != (!USIZE_MSB) & (-1));

            self.lock.compare_and_swap(old, new, Ordering::SeqCst) != old
        } {}
        RwLockReadGuard {
            lock: &self.lock,
            data: unsafe { & *self.data.get() },
        }
    }

    /// Attempt to acquire this lock with shared read access.
    ///
    /// This function will never block and will return immediately if `read`
    /// would otherwise succeed. Returns `Some` of an RAII guard which will
    /// release the shared access of this thread when dropped, or `None` if the
    /// access could not be granted. This method does not provide any
    /// guarantees with respect to the ordering of whether contentious readers
    /// or writers will acquire the lock first.
    ///
    /// ```
    /// let mylock = spin::RwLock::new(0us);
    /// {
    ///     if let Some(data) = mylock.try_read() {
    ///         // The lock is now locked and the data can be read
    ///         println!("{}", *data);
    ///         // The lock is dropped
    ///     };
    /// }
    /// ```
    #[inline]
    pub fn try_read(&self) -> Option<RwLockReadGuard<T>>
    {
        // Old value, with write bit unset
        let old = (!USIZE_MSB) & self.lock.load(Ordering::Relaxed);

        let new = old + 1;
        debug_assert!(new != (!USIZE_MSB) & (-1));
        if self.lock.compare_and_swap(old,
                                      new,
                                      Ordering::SeqCst) == old
        {
            Some(RwLockReadGuard {
                lock: &self.lock,
                data: unsafe { & *self.data.get() },
            })
        } else {
            None
        }
    }

    /// Lock this rwlock with exclusive write access, blocking the current
    /// thread until it can be acquired.
    ///
    /// This function will not return while other writers or other readers
    /// currently have access to the lock.
    ///
    /// Returns an RAII guard which will drop the write access of this rwlock
    /// when dropped.
    ///
    /// ```
    /// let mylock = spin::RwLock::new(0us);
    /// {
    ///     let mut data = mylock.write();
    ///     // The lock is now locked and the data can be written
    ///     *data += 1;
    ///     // The lock is dropped
    /// }
    /// ```
    #[inline]
    pub fn write<'a>(&'a self) -> RwLockWriteGuard<'a, T>
    {
        loop
        {
            // Old value, with write bit unset.
            let old = (!USIZE_MSB) & self.lock.load(Ordering::Relaxed);
            // Old value, with write bit set.
            let new = USIZE_MSB | old;
            if self.lock.compare_and_swap(old,
                                          new,
                                          Ordering::SeqCst) == old
            {
                // Wait for readers to go away, then lock is ours.
                while self.lock.load(Ordering::Relaxed) != USIZE_MSB { }
                break
            }
        }
        RwLockWriteGuard {
            lock: &self.lock,
            data: unsafe { &mut *self.data.get() },
        }
    }

    /// Attempt to lock this rwlock with exclusive write access.
    ///
    /// This function does not ever block, and it will return `None` if a call
    /// to `write` would otherwise block. If successful, an RAII guard is
    /// returned.
    ///
    /// ```
    /// let mylock = spin::RwLock::new(0us);
    /// {
    ///     if let Some(mut data) = mylock.try_write() {
    ///         // The lock is now locked and the data can be written
    ///         *data += 1;
    ///         // The lock is implicitly dropped
    ///     };
    /// }
    /// ```
    #[inline]
    pub fn try_write(&self) -> Option<RwLockWriteGuard<T>>
    {
        if self.lock.compare_and_swap(0,
                                      USIZE_MSB,
                                      Ordering::SeqCst) == 0
        {
            Some(RwLockWriteGuard {
                lock: &self.lock,
                data: unsafe { &mut *self.data.get() },
            })
        } else {
            None
        }
    }
}

impl<'rwlock, T> Deref for RwLockReadGuard<'rwlock, T> {
    type Target = T;

    fn deref(&self) -> &T { self.data }
}

impl<'rwlock, T> Deref for RwLockWriteGuard<'rwlock, T> {
    type Target = T;

    fn deref(&self) -> &T { self.data }
}

impl<'rwlock, T> DerefMut for RwLockWriteGuard<'rwlock, T> {
    fn deref_mut(&mut self) -> &mut T { self.data }
}

#[unsafe_destructor]
impl<'rwlock, T> Drop for RwLockReadGuard<'rwlock, T> {
    fn drop(&mut self) {
        debug_assert!(self.lock.load(Ordering::Relaxed) & (!USIZE_MSB) > 0);
        self.lock.fetch_sub(1, Ordering::SeqCst);
    }
}

#[unsafe_destructor]
impl<'rwlock, T> Drop for RwLockWriteGuard<'rwlock, T> {
    fn drop(&mut self) {
        debug_assert_eq!(self.lock.load(Ordering::Relaxed), USIZE_MSB);
        self.lock.store(0, Ordering::Relaxed);
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The SAX-RS Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![comment = "Wrapper for libxml2's SAX parser."]
#![crate_id = "github.com/bjz/sax-rs#sax:0.1"]

#![crate_type = "lib"]

#![feature(globs)]

extern crate libc;
extern crate sync;

use libc::{c_char, c_int};
use std::cast;
use std::comm::{Receiver, channel};
use std::str;
use std::io::{File, IoResult};
use std::fmt;

use error::ErrorData;

pub mod error;
pub mod ffi;
mod extfn;

/// Events to be sent by the parser.
#[deriving(Eq, Clone)]
pub enum ParseEvent {
    /// The document has begun to be processed.
    StartDocument,
    /// The document processing has finished.
    EndDocument,
    /// An opening tag has was parsed.
    StartElement(~str, Attributes),
    /// A closing tag was parsed.
    EndElement(~str),
    /// Some characters between tags have been recived.
    Characters(~str),
    /// A comment tag was parsed.
    Comment(~str),
    /// A `CDATA` block was parsed.
    CdataBlock(~str),
}

impl fmt::Show for ParseEvent {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            StartDocument => write!(fmt.buf, "START DOCUMENT"),
            EndDocument => write!(fmt.buf, "END DOCUMENT"),
            StartElement(ref name, ref atts) => write!(fmt.buf, "<{}{}>", *name, atts),
            EndElement(ref name) => write!(fmt.buf, "</{}>", *name),
            Characters(ref ch) => write!(fmt.buf, "{}", ch.clone()),
            Comment(ref value) => write!(fmt.buf, "", *value),
            CdataBlock(ref value) => write!(fmt.buf, "<![CDATA[{}]]>", *value),
        }
    }
}

#[deriving(Eq, Clone)]
pub struct Attribute {
    name: ~str,
    value: ~str,
}

/// A list of attributes
#[deriving(Eq, Clone)]
pub struct Attributes(Vec<Attribute>);

impl Attributes {
    unsafe fn from_buf(atts: **ffi::xmlChar) -> Attributes {
        let mut ret = Vec::new();
        let mut ptr = atts as **c_char;
        while !ptr.is_null() && !(*ptr).is_null() {
            ret.push(
                Attribute {
                    name: str::raw::from_c_str(*ptr),
                    value: str::raw::from_c_str(*ptr.offset(1)),
                }
            );
            ptr = ptr.offset(2);
        }
        Attributes(ret)
    }

    pub fn find<'a>(&'a self, name: &str) -> Option<&'a str> {
        let Attributes(ref s) = *self;
        s.iter()
         .find(|att| name == att.name)
         .map(|att| att.value.as_slice())
    }

    pub fn get<'a>(&'a self, name: &str) -> &'a str {
        self.find(name).expect(format!("Could not find an attribute with the name \"{}\"", name))
    }

    pub fn find_clone(&self, name: &str) -> Option<~str> {
        self.find(name).map(|v| v.to_owned())
    }

    pub fn get_clone(&self, name: &str) -> ~str {
        self.get(name).to_owned()
    }
}

impl fmt::Show for Attributes {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let Attributes(ref s) = *self;
        for att in s.iter() {
            try!(write!(fmt.buf, " {}=\"{}\"", att.name, att.value));
        }
        Ok(())
    }
}

/// Either a parse event wrapped in `Ok` or some Error data wrapped in `Err`.
pub type ParseResult = Result<ParseEvent, ErrorData>;

/// Parses the entire XML string.
///
/// # Returns
///
/// A receiver that recieves parse results.
///
/// # Example
///
/// ~~~rust
/// let parser = parse_str("<yo>hullo!</yo>");
/// for result in parser.iter() {
///     match result {
///         Ok(StartDocument) => (),
///         Ok(EndDocument) => break,
///         Ok(event) => println!("{}", event.to_str()),
///         Err(err) => println!("{}", err.to_str()),
///     }
/// }
/// ~~~
#[inline(never)]
pub fn parse_str(src: &str) -> Receiver<ParseResult> {
    // ensure that the xml library is ready for use
    use sync::one::{Once, ONCE_INIT};
    static mut INIT: Once = ONCE_INIT;
    unsafe {
        INIT.doit(|| {
            ffi::xmlInitParser();
            std::rt::at_exit(proc() ffi::xmlCleanupParser());
        })
    }

    let len = src.len() as c_int;
    src.to_c_str().with_ref(|c_str| {
        let (sender, receiver) = channel();
        unsafe {
            ffi::xmlSAXUserParseMemory(&extfn::new_handler(),
                                       cast::transmute(&sender),
                                       c_str, len);
        }
        receiver
    })
}

pub fn parse_file(path: &Path) -> IoResult<Receiver<ParseResult> > {
  File::open(path)
    .and_then( |mut file| {
      file.read_to_str()
    })
    .and_then( |contents| {
      Ok(parse_str(contents))
    })
}

#[cfg(test)]
mod tests {
    use super::*;

    fn get_mock_atts() -> Attributes {
        Attributes(Vec::from_slice([
            Attribute { name: ~"foo", value: ~"0" },
            Attribute { name: ~"bar", value: ~"1" },
            Attribute { name: ~"baz", value: ~"2" }
        ]))
    }

    #[test]
    fn test_att_get() {
        let atts = get_mock_atts();
        assert_eq!(atts.get("foo"), "0");
        assert_eq!(atts.get("bar"), "1");
        assert_eq!(atts.get("baz"), "2");
    }

    #[test]
    fn test_att_find() {
        let atts = get_mock_atts();
        assert_eq!(atts.find("foo"), Some("0"));
        assert_eq!(atts.find("bar"), Some("1"));
        assert_eq!(atts.find("baz"), Some("2"));
    }

    #[test]
    fn test() {
        let sax = parse_str(
            "<hello><this />test</hello>"
        );
        loop {
            match sax.recv() {
                Ok(StartDocument) => (),
                Ok(EndDocument) => break,
                Ok(event) => println!("{}", event.to_str()),
                Err(err) => println!("{}", err.to_str()),
            }
        }
    }
}
<commit_msg>Clean up formatting<commit_after>// Copyright 2013 The SAX-RS Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![comment = "Wrapper for libxml2's SAX parser."]
#![crate_id = "github.com/bjz/sax-rs#sax:0.1"]

#![crate_type = "lib"]

#![feature(globs)]

extern crate libc;
extern crate sync;

use libc::{c_char, c_int};
use std::cast;
use std::comm::{Receiver, channel};
use std::str;
use std::io::{File, IoResult};
use std::fmt;

use error::ErrorData;

pub mod error;
pub mod ffi;
mod extfn;

/// Events to be sent by the parser.
#[deriving(Eq, Clone)]
pub enum ParseEvent {
    /// The document has begun to be processed.
    StartDocument,
    /// The document processing has finished.
    EndDocument,
    /// An opening tag has was parsed.
    StartElement(~str, Attributes),
    /// A closing tag was parsed.
    EndElement(~str),
    /// Some characters between tags have been recived.
    Characters(~str),
    /// A comment tag was parsed.
    Comment(~str),
    /// A `CDATA` block was parsed.
    CdataBlock(~str),
}

impl fmt::Show for ParseEvent {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            StartDocument => write!(fmt.buf, "START DOCUMENT"),
            EndDocument => write!(fmt.buf, "END DOCUMENT"),
            StartElement(ref name, ref atts) => write!(fmt.buf, "<{}{}>", *name, atts),
            EndElement(ref name) => write!(fmt.buf, "</{}>", *name),
            Characters(ref ch) => write!(fmt.buf, "{}", ch.clone()),
            Comment(ref value) => write!(fmt.buf, "", *value),
            CdataBlock(ref value) => write!(fmt.buf, "<![CDATA[{}]]>", *value),
        }
    }
}

#[deriving(Eq, Clone)]
pub struct Attribute {
    name: ~str,
    value: ~str,
}

/// A list of attributes
#[deriving(Eq, Clone)]
pub struct Attributes(Vec<Attribute>);

impl Attributes {
    unsafe fn from_buf(atts: **ffi::xmlChar) -> Attributes {
        let mut ret = Vec::new();
        let mut ptr = atts as **c_char;
        while !ptr.is_null() && !(*ptr).is_null() {
            ret.push(
                Attribute {
                    name: str::raw::from_c_str(*ptr),
                    value: str::raw::from_c_str(*ptr.offset(1)),
                }
            );
            ptr = ptr.offset(2);
        }
        Attributes(ret)
    }

    pub fn find<'a>(&'a self, name: &str) -> Option<&'a str> {
        let Attributes(ref s) = *self;
        s.iter().find(|att| name == att.name)
                .map(|att| att.value.as_slice())
    }

    pub fn get<'a>(&'a self, name: &str) -> &'a str {
        self.find(name).expect(format!("Could not find an attribute with the name \"{}\"", name))
    }

    pub fn find_clone(&self, name: &str) -> Option<~str> {
        self.find(name).map(|v| v.to_owned())
    }

    pub fn get_clone(&self, name: &str) -> ~str {
        self.get(name).to_owned()
    }
}

impl fmt::Show for Attributes {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let Attributes(ref s) = *self;
        for att in s.iter() {
            try!(write!(fmt.buf, " {}=\"{}\"", att.name, att.value));
        }
        Ok(())
    }
}

/// Either a parse event wrapped in `Ok` or some Error data wrapped in `Err`.
pub type ParseResult = Result<ParseEvent, ErrorData>;

/// Parses the entire XML string.
///
/// # Returns
///
/// A receiver that recieves parse results.
///
/// # Example
///
/// ~~~rust
/// let parser = parse_str("<yo>hullo!</yo>");
/// for result in parser.iter() {
///     match result {
///         Ok(StartDocument) => (),
///         Ok(EndDocument) => break,
///         Ok(event) => println!("{}", event.to_str()),
///         Err(err) => println!("{}", err.to_str()),
///     }
/// }
/// ~~~
#[inline(never)]
pub fn parse_str(src: &str) -> Receiver<ParseResult> {
    // ensure that the xml library is ready for use
    use sync::one::{Once, ONCE_INIT};
    static mut INIT: Once = ONCE_INIT;
    unsafe {
        INIT.doit(|| {
            ffi::xmlInitParser();
            std::rt::at_exit(proc() ffi::xmlCleanupParser());
        })
    }

    let len = src.len() as c_int;
    src.to_c_str().with_ref(|c_str| {
        let (sender, receiver) = channel();
        unsafe {
            ffi::xmlSAXUserParseMemory(&extfn::new_handler(),
                                       cast::transmute(&sender),
                                       c_str, len);
        }
        receiver
    })
}

pub fn parse_file(path: &Path) -> IoResult<Receiver<ParseResult>> {
    File::open(path).and_then(|mut file| file.read_to_str())
                    .and_then(|contents| Ok(parse_str(contents)))
}

#[cfg(test)]
mod tests {
    use super::*;

    fn get_mock_atts() -> Attributes {
        Attributes(Vec::from_slice([
            Attribute { name: ~"foo", value: ~"0" },
            Attribute { name: ~"bar", value: ~"1" },
            Attribute { name: ~"baz", value: ~"2" }
        ]))
    }

    #[test]
    fn test_att_get() {
        let atts = get_mock_atts();
        assert_eq!(atts.get("foo"), "0");
        assert_eq!(atts.get("bar"), "1");
        assert_eq!(atts.get("baz"), "2");
    }

    #[test]
    fn test_att_find() {
        let atts = get_mock_atts();
        assert_eq!(atts.find("foo"), Some("0"));
        assert_eq!(atts.find("bar"), Some("1"));
        assert_eq!(atts.find("baz"), Some("2"));
    }

    #[test]
    fn test() {
        let sax = parse_str(
            "<hello><this />test</hello>"
        );
        loop {
            match sax.recv() {
                Ok(StartDocument) => (),
                Ok(EndDocument) => break,
                Ok(event) => println!("{}", event.to_str()),
                Err(err) => println!("{}", err.to_str()),
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate html5ever;
extern crate tendril;
extern crate regex;
extern crate hyper;
extern crate string_cache;
extern crate url;

use html5ever::rcdom::{Document, Doctype, Text, Comment, Element};
use html5ever::rcdom::{RcDom, Handle};
use html5ever::{parse_document, Attribute};
use tendril::stream::TendrilSink;
use std::default::Default;

use regex::Regex;
use hyper::Client;
use hyper::header::Connection;
use hyper::header::ConnectionOption;

use Provider;
use Track;
use open_graph;
use youtube;
use soundcloud;
use spotify;
use error::Error;

use url::percent_encoding::{percent_decode};

static YOUTUBE_EMBED:       &'static str = r"www.youtube.com/embed/([a-zA-Z0-9_-].+)";
static YOUTUBE_LIST:        &'static str = r"www.youtube.com/embed/videoseries\?list=([a-zA-Z0-9_-]+)";
static YOUTUBE_WATCH:       &'static str = r"www.youtube.com/watch\?v=([a-zA-Z0-9_-]+)";
static SOUNDCLOUD_TRACK:    &'static str = r"api.soundcloud.com/tracks/([a-zA-Z0-9_-]+)";
static SOUNDCLOUD_PLAYLIST: &'static str = r"api.soundcloud.com/playlists/([a-zA-Z0-9_-]+)";
static SOUNDCLOUD_USER:     &'static str = r"api.soundcloud.com/users/([a-zA-Z0-9_-]+)";
static SPOTIFY_TRACK:       &'static str = r"open.spotify.com/track/([a-zA-Z0-9_-]+)";
static SPOTIFY_TRACK_OPEN:  &'static str = r"spotify:track:([a-zA-Z0-9_-]+)";
static SPOTIFY_PLAYLIST:    &'static str = r"(spotify:user:[a-zA-Z0-9_-]+:playlist:[a-zA-Z0-9_-]+)";

#[derive(Debug)]
pub struct ScraperProduct {
    pub tracks: Vec<Track>,
    pub og_obj: Option<open_graph::Object>,
}

pub fn extract(url: &str) -> Result<ScraperProduct, Error> {
    let client = Client::new();
    let mut res = client.get(url)
        .header(Connection(vec![ConnectionOption::Close]))
        .send()
        .unwrap();
    if res.status.is_success() {
        let dom = parse_document(RcDom::default(), Default::default())
            .from_utf8()
            .read_from(&mut res)
            .unwrap();
        let mut tracks   = Vec::new();
        let mut og_props = Vec::new();
        walk(0, dom.document, &mut tracks, &mut og_props);
        let og_obj = if og_props.len() > 0 {
            Some(open_graph::Object::new(&og_props))
        } else {
            None
        };
        Ok(ScraperProduct {
            tracks: tracks,
            og_obj: og_obj
        })
    } else {
        println!("Failed to get entry html {}: {}", res.status, url);
        Err(Error::NotFound)
    }
}

// This is not proper HTML serialization, of course.
fn walk(indent: usize,
        handle: Handle,
        tracks: &mut Vec<Track>,
        og_props: &mut Vec<(String, String)>) {
    let node = handle.borrow();
    match node.node {
        Document         => (),
        Doctype(_, _, _) => (),
        Text(_)          => (),
        Comment(_)       => (),
        Element(ref name, _, ref attrs) => {
            let tag_name = name.local.as_ref();
            let mut ps = extract_open_graph_metadata_from_tag(tag_name, attrs);
            og_props.append(&mut ps);
            let ts = extract_tracks_from_tag(tag_name, attrs);
            for track in ts.iter().cloned() {
                if !(tracks).iter().any(|t| track == *t) {
                    (*tracks).push(track)
                }
            }
        }
    }
    for child in node.children.iter() {
        walk(indent+4, child.clone(), tracks, og_props);
    }
}

fn attr(attr_name: &str, attrs: &Vec<Attribute>) -> Option<String> {
    for attr in attrs.iter() {
        if attr.name.local.as_ref() == attr_name {
            return Some(attr.value.to_string())
        }
    }
    None
}

pub fn extract_tracks_from_tag(tag_name: &str,
                               attrs: &Vec<Attribute>) -> Vec<Track> {
    if tag_name == "iframe" {
        match attr("src", attrs) {
            Some(ref src) => extract_tracks_from_url(src.to_string()),
            None => vec![]
        }
    } else if tag_name == "a" || tag_name == "link" {
        match attr("href", attrs) {
            Some(ref href) => extract_tracks_from_url(href.to_string()),
            None => vec![]
        }
    } else {
        vec![]
    }
}

pub fn extract_open_graph_metadata_from_tag(tag_name: &str,
                                            attrs: &Vec<Attribute>) -> Vec<(String, String)> {

    let mut og_props = vec!();
    if tag_name == "meta" {
        match extract_open_graph_prop("property", attrs) {
            Some((key, content)) => og_props.push((key, content)),
            None                 => (),
        }
        match extract_open_graph_prop("name", attrs) {
            Some((key, content)) => og_props.push((key, content)),
            None                 => (),
        }
    }
    og_props
}

fn extract_open_graph_prop<'a>(attr_name: &str, attrs: &Vec<Attribute>) -> Option<(String, String)> {
    attr(attr_name, attrs)
        .and_then(|property|
                  if property.starts_with("og:") {
                      let end = property.chars().count();
                      let key = unsafe {
                          property.slice_unchecked(3, end)
                      }.to_string();
                      attr("content", attrs).map(|content| (key, content))
                  } else {
                      None
                  })
}

fn extract_identifier(value: &str, regex_str: &str) -> Option<String> {
    match Regex::new(regex_str) {
        Ok(re) => match re.captures(value) {
            Some(cap) => {
                let strs: Vec<&str> = cap[1].split('?').collect();
                return Some(strs[0].to_string())
            },
            None => None
        },
        Err(_) => None
    }
}

fn fetch_spotify_playlist(uri: &str) -> Vec<Track> {
    match Regex::new(r"spotify:user:([a-zA-Z0-9_-]+):playlist:([a-zA-Z0-9_-]+)") {
        Ok(re) => match re.captures(uri) {
            Some(cap) => {
                let strs: Vec<&str> = cap[1].split('?').collect();
                let user_id         = strs[0].to_string();
                let strs: Vec<&str> = cap[2].split('?').collect();
                let playlist_id     = strs[0].to_string();
                return match spotify::fetch_playlist(&user_id, &playlist_id) {
                    Ok(playlist) => playlist.tracks.items.iter()
                                                   .map(|ref i| Track::from_sp_track(&i.track))
                                                   .collect::<Vec<_>>(),
                    Err(_)       => vec![]
                }
            },
            None => vec![]
        },
        Err(_) => vec![]
    }
}

fn fetch_spotify_track(identifier: String) -> Vec<Track> {
    match spotify::fetch_track(&identifier) {
        Ok(t) => {
            let ref mut track = Track::new(Provider::Spotify, identifier);
            track.update_with_sp_track(&t);
            vec![track.clone()]
        },
        Err(_) => vec![Track::new(Provider::Spotify, identifier)],
    }
}

fn extract_tracks_from_url(url: String) -> Vec<Track> {
    let decoded = percent_decode(url.as_bytes()).decode_utf8_lossy().into_owned();
    match extract_identifier(&decoded, YOUTUBE_WATCH) {
        Some(identifier) => {
            return vec![Track::new(Provider::YouTube, identifier)]
        },
        None => ()
    }
    match extract_identifier(&decoded, YOUTUBE_LIST) {
        Some(identifier) => {
            return match youtube::fetch_playlist(&identifier) {
                Ok(res) => res.items.iter()
                                    .map(|ref i| Track::from_yt_playlist_item(i))
                                    .collect::<Vec<_>>(),
                Err(_)       => vec![]
            }
        },
        None => ()
    }
    match extract_identifier(&decoded, YOUTUBE_EMBED) {
        Some(identifier) => {
            return vec![Track::new(Provider::YouTube, identifier)]
        },
        None => ()
    }
    match extract_identifier(&decoded, SOUNDCLOUD_TRACK) {
        Some(identifier) => {
            return vec![Track::new(Provider::SoundCloud, identifier)]
        },
        None => ()
    }
    match extract_identifier(&decoded, SOUNDCLOUD_PLAYLIST) {
        Some(identifier) => {
            return match soundcloud::fetch_playlist(&identifier) {
                Ok(playlist) => playlist.tracks
                                        .iter()
                                        .map(|ref t| Track::from_sc_track(t))
                                        .collect::<Vec<_>>(),
                Err(_)       => vec![]
            }
        },
        None => ()
    }
    match extract_identifier(&decoded, SOUNDCLOUD_USER) {
        Some(identifier) => {
            return match soundcloud::fetch_user_tracks(&identifier) {
                Ok(tracks) => tracks.iter()
                                    .map(|ref t| Track::from_sc_track(t))
                                    .collect::<Vec<_>>(),
                Err(_)     => vec![]
            }
        },
        None => ()
    }
    match extract_identifier(&decoded, SPOTIFY_TRACK) {
        Some(identifier) => {
            return fetch_spotify_track(identifier)
        },
        None => ()
    }
    match extract_identifier(&decoded, SPOTIFY_TRACK_OPEN) {
        Some(identifier) => {
            return fetch_spotify_track(identifier)
        },
        None => ()
    }
    match extract_identifier(&decoded, SPOTIFY_PLAYLIST) {
        Some(uri) => {
            return fetch_spotify_playlist(&uri)
        },
        None => ()
    }
    return vec![]
}

#[cfg(test)]
mod test {
    use super::extract;
    use super::extract_identifier;
    use Provider;
    use Track;

    #[test]
    fn test_extract_identifier() {
        let soundcloud_src = "https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/195425494/stream&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&visual=true";
        match extract_identifier(soundcloud_src, super::SOUNDCLOUD_TRACK) {
            Some(identifier) => assert_eq!(identifier, "195425494".to_string()),
            None             => assert!(false)
        }
        let youtube_embed = "https://www.youtube.com/embed/X8tOngmlES0?rel=0";
        match extract_identifier(youtube_embed, super::YOUTUBE_EMBED) {
            Some(identifier) => assert_eq!(identifier, "X8tOngmlES0".to_string()),
            None             => assert!(false)
        }

        let youtube_watch = "https://www.youtube.com/watch?v=oDuif301F-8";
        match extract_identifier(youtube_watch, super::YOUTUBE_WATCH) {
            Some(identifier) => assert_eq!(identifier, "oDuif301F-8".to_string()),
            None             => assert!(false)
        }

        let youtube_list = "https://www.youtube.com/embed/videoseries?list=PLy8LZ8FM-o0ViuGAF68RAaXkQ8V-3dbTX";
        match extract_identifier(youtube_list, super::YOUTUBE_LIST) {
            Some(identifier) => assert_eq!(identifier, "PLy8LZ8FM-o0ViuGAF68RAaXkQ8V-3dbTX".to_string()),
            None             => assert!(false)
        }
    }
    #[test]
    fn test_extract() {
        let url = "http://spincoaster.com/spincoaster-breakout-2017";
        let tracks = extract(url).unwrap().tracks;
        let youtube_tracks: Vec<&Track> = tracks.iter().filter(|&x| x.provider == Provider::YouTube).collect();
        let spotify_tracks: Vec<&Track> = tracks.iter().filter(|&x| x.provider == Provider::Spotify).collect();
        assert_eq!(youtube_tracks.len(), 15);
        assert_eq!(spotify_tracks.len(), 30);
    }
}
<commit_msg>Extract apple music resource from link and iframe url<commit_after>extern crate html5ever;
extern crate tendril;
extern crate regex;
extern crate hyper;
extern crate string_cache;
extern crate url;

use html5ever::rcdom::{Document, Doctype, Text, Comment, Element};
use html5ever::rcdom::{RcDom, Handle};
use html5ever::{parse_document, Attribute};
use tendril::stream::TendrilSink;
use std::default::Default;

use regex::Regex;
use hyper::Client;
use hyper::header::Connection;
use hyper::header::ConnectionOption;

use Provider;
use Track;
use open_graph;
use youtube;
use soundcloud;
use spotify;
use error::Error;

use url::percent_encoding::{percent_decode};

static APPLE_MUSIC_SONG:     &'static str = r"tools.applemusic.com/embed/v1/song/([a-zA-Z0-9_-]+)";
static APPLE_MUSIC_ALBUM:    &'static str = r"tools.applemusic.com/embed/v1/album/([a-zA-Z0-9_-]+)";
static APPLE_MUSIC_PLAYLIST: &'static str = r"tools.applemusic.com/embed/v1/playlist/pl.([a-zA-Z0-9_-]+)";
static YOUTUBE_EMBED:        &'static str = r"www.youtube.com/embed/([a-zA-Z0-9_-].+)";
static YOUTUBE_LIST:         &'static str = r"www.youtube.com/embed/videoseries\?list=([a-zA-Z0-9_-]+)";
static YOUTUBE_WATCH:        &'static str = r"www.youtube.com/watch\?v=([a-zA-Z0-9_-]+)";
static SOUNDCLOUD_TRACK:     &'static str = r"api.soundcloud.com/tracks/([a-zA-Z0-9_-]+)";
static SOUNDCLOUD_PLAYLIST:  &'static str = r"api.soundcloud.com/playlists/([a-zA-Z0-9_-]+)";
static SOUNDCLOUD_USER:      &'static str = r"api.soundcloud.com/users/([a-zA-Z0-9_-]+)";
static SPOTIFY_TRACK:        &'static str = r"open.spotify.com/track/([a-zA-Z0-9_-]+)";
static SPOTIFY_TRACK_OPEN:   &'static str = r"spotify:track:([a-zA-Z0-9_-]+)";
static SPOTIFY_PLAYLIST:     &'static str = r"(spotify:user:[a-zA-Z0-9_-]+:playlist:[a-zA-Z0-9_-]+)";

#[derive(Debug)]
pub struct ScraperProduct {
    pub tracks: Vec<Track>,
    pub og_obj: Option<open_graph::Object>,
}

pub fn extract(url: &str) -> Result<ScraperProduct, Error> {
    let client = Client::new();
    let mut res = client.get(url)
        .header(Connection(vec![ConnectionOption::Close]))
        .send()
        .unwrap();
    if res.status.is_success() {
        let dom = parse_document(RcDom::default(), Default::default())
            .from_utf8()
            .read_from(&mut res)
            .unwrap();
        let mut tracks   = Vec::new();
        let mut og_props = Vec::new();
        walk(0, dom.document, &mut tracks, &mut og_props);
        let og_obj = if og_props.len() > 0 {
            Some(open_graph::Object::new(&og_props))
        } else {
            None
        };
        Ok(ScraperProduct {
            tracks: tracks,
            og_obj: og_obj
        })
    } else {
        println!("Failed to get entry html {}: {}", res.status, url);
        Err(Error::NotFound)
    }
}

// This is not proper HTML serialization, of course.
fn walk(indent: usize,
        handle: Handle,
        tracks: &mut Vec<Track>,
        og_props: &mut Vec<(String, String)>) {
    let node = handle.borrow();
    match node.node {
        Document         => (),
        Doctype(_, _, _) => (),
        Text(_)          => (),
        Comment(_)       => (),
        Element(ref name, _, ref attrs) => {
            let tag_name = name.local.as_ref();
            let mut ps = extract_open_graph_metadata_from_tag(tag_name, attrs);
            og_props.append(&mut ps);
            let ts = extract_tracks_from_tag(tag_name, attrs);
            for track in ts.iter().cloned() {
                if !(tracks).iter().any(|t| track == *t) {
                    (*tracks).push(track)
                }
            }
        }
    }
    for child in node.children.iter() {
        walk(indent+4, child.clone(), tracks, og_props);
    }
}

fn attr(attr_name: &str, attrs: &Vec<Attribute>) -> Option<String> {
    for attr in attrs.iter() {
        if attr.name.local.as_ref() == attr_name {
            return Some(attr.value.to_string())
        }
    }
    None
}

pub fn extract_tracks_from_tag(tag_name: &str,
                               attrs: &Vec<Attribute>) -> Vec<Track> {
    if tag_name == "iframe" {
        match attr("src", attrs) {
            Some(ref src) => extract_tracks_from_url(src.to_string()),
            None => vec![]
        }
    } else if tag_name == "a" || tag_name == "link" {
        match attr("href", attrs) {
            Some(ref href) => extract_tracks_from_url(href.to_string()),
            None => vec![]
        }
    } else {
        vec![]
    }
}

pub fn extract_open_graph_metadata_from_tag(tag_name: &str,
                                            attrs: &Vec<Attribute>) -> Vec<(String, String)> {

    let mut og_props = vec!();
    if tag_name == "meta" {
        match extract_open_graph_prop("property", attrs) {
            Some((key, content)) => og_props.push((key, content)),
            None                 => (),
        }
        match extract_open_graph_prop("name", attrs) {
            Some((key, content)) => og_props.push((key, content)),
            None                 => (),
        }
    }
    og_props
}

fn extract_open_graph_prop<'a>(attr_name: &str, attrs: &Vec<Attribute>) -> Option<(String, String)> {
    attr(attr_name, attrs)
        .and_then(|property|
                  if property.starts_with("og:") {
                      let end = property.chars().count();
                      let key = unsafe {
                          property.slice_unchecked(3, end)
                      }.to_string();
                      attr("content", attrs).map(|content| (key, content))
                  } else {
                      None
                  })
}

fn extract_identifier(value: &str, regex_str: &str) -> Option<String> {
    match Regex::new(regex_str) {
        Ok(re) => match re.captures(value) {
            Some(cap) => {
                let strs: Vec<&str> = cap[1].split('?').collect();
                return Some(strs[0].to_string())
            },
            None => None
        },
        Err(_) => None
    }
}

fn fetch_spotify_playlist(uri: &str) -> Vec<Track> {
    match Regex::new(r"spotify:user:([a-zA-Z0-9_-]+):playlist:([a-zA-Z0-9_-]+)") {
        Ok(re) => match re.captures(uri) {
            Some(cap) => {
                let strs: Vec<&str> = cap[1].split('?').collect();
                let user_id         = strs[0].to_string();
                let strs: Vec<&str> = cap[2].split('?').collect();
                let playlist_id     = strs[0].to_string();
                return match spotify::fetch_playlist(&user_id, &playlist_id) {
                    Ok(playlist) => playlist.tracks.items.iter()
                                                   .map(|ref i| Track::from_sp_track(&i.track))
                                                   .collect::<Vec<_>>(),
                    Err(_)       => vec![]
                }
            },
            None => vec![]
        },
        Err(_) => vec![]
    }
}

fn fetch_spotify_track(identifier: String) -> Vec<Track> {
    match spotify::fetch_track(&identifier) {
        Ok(t) => {
            let ref mut track = Track::new(Provider::Spotify, identifier);
            track.update_with_sp_track(&t);
            vec![track.clone()]
        },
        Err(_) => vec![Track::new(Provider::Spotify, identifier)],
    }
}

fn extract_tracks_from_url(url: String) -> Vec<Track> {
    let decoded = percent_decode(url.as_bytes()).decode_utf8_lossy().into_owned();

    match extract_identifier(&decoded, APPLE_MUSIC_SONG) {
        Some(identifier) => {
            return vec![Track::new(Provider::AppleMusic, identifier)]
        },
        None => ()
    }
    match extract_identifier(&decoded, APPLE_MUSIC_ALBUM) {
        Some(identifier) => {
            // todo: fetch songs
            return vec![]
        },
        None => ()
    }
    match extract_identifier(&decoded, APPLE_MUSIC_PLAYLIST) {
        Some(identifier) => {
            // todo: fetch songs
            return vec![]
        },
        None => ()
    }
    match extract_identifier(&decoded, YOUTUBE_WATCH) {
        Some(identifier) => {
            return vec![Track::new(Provider::YouTube, identifier)]
        },
        None => ()
    }
    match extract_identifier(&decoded, YOUTUBE_LIST) {
        Some(identifier) => {
            return match youtube::fetch_playlist(&identifier) {
                Ok(res) => res.items.iter()
                                    .map(|ref i| Track::from_yt_playlist_item(i))
                                    .collect::<Vec<_>>(),
                Err(_)       => vec![]
            }
        },
        None => ()
    }
    match extract_identifier(&decoded, YOUTUBE_EMBED) {
        Some(identifier) => {
            return vec![Track::new(Provider::YouTube, identifier)]
        },
        None => ()
    }
    match extract_identifier(&decoded, SOUNDCLOUD_TRACK) {
        Some(identifier) => {
            return vec![Track::new(Provider::SoundCloud, identifier)]
        },
        None => ()
    }
    match extract_identifier(&decoded, SOUNDCLOUD_PLAYLIST) {
        Some(identifier) => {
            return match soundcloud::fetch_playlist(&identifier) {
                Ok(playlist) => playlist.tracks
                                        .iter()
                                        .map(|ref t| Track::from_sc_track(t))
                                        .collect::<Vec<_>>(),
                Err(_)       => vec![]
            }
        },
        None => ()
    }
    match extract_identifier(&decoded, SOUNDCLOUD_USER) {
        Some(identifier) => {
            return match soundcloud::fetch_user_tracks(&identifier) {
                Ok(tracks) => tracks.iter()
                                    .map(|ref t| Track::from_sc_track(t))
                                    .collect::<Vec<_>>(),
                Err(_)     => vec![]
            }
        },
        None => ()
    }
    match extract_identifier(&decoded, SPOTIFY_TRACK) {
        Some(identifier) => {
            return fetch_spotify_track(identifier)
        },
        None => ()
    }
    match extract_identifier(&decoded, SPOTIFY_TRACK_OPEN) {
        Some(identifier) => {
            return fetch_spotify_track(identifier)
        },
        None => ()
    }
    match extract_identifier(&decoded, SPOTIFY_PLAYLIST) {
        Some(uri) => {
            return fetch_spotify_playlist(&uri)
        },
        None => ()
    }
    return vec![]
}

#[cfg(test)]
mod test {
    use super::extract;
    use super::extract_identifier;
    use Provider;
    use Track;

    #[test]
    fn test_extract_identifier() {
        let soundcloud_src = "https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/195425494/stream&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&visual=true";
        match extract_identifier(soundcloud_src, super::SOUNDCLOUD_TRACK) {
            Some(identifier) => assert_eq!(identifier, "195425494".to_string()),
            None             => assert!(false)
        }
        let youtube_embed = "https://www.youtube.com/embed/X8tOngmlES0?rel=0";
        match extract_identifier(youtube_embed, super::YOUTUBE_EMBED) {
            Some(identifier) => assert_eq!(identifier, "X8tOngmlES0".to_string()),
            None             => assert!(false)
        }

        let youtube_watch = "https://www.youtube.com/watch?v=oDuif301F-8";
        match extract_identifier(youtube_watch, super::YOUTUBE_WATCH) {
            Some(identifier) => assert_eq!(identifier, "oDuif301F-8".to_string()),
            None             => assert!(false)
        }

        let youtube_list = "https://www.youtube.com/embed/videoseries?list=PLy8LZ8FM-o0ViuGAF68RAaXkQ8V-3dbTX";
        match extract_identifier(youtube_list, super::YOUTUBE_LIST) {
            Some(identifier) => assert_eq!(identifier, "PLy8LZ8FM-o0ViuGAF68RAaXkQ8V-3dbTX".to_string()),
            None             => assert!(false)
        }
    }
    #[test]
    fn test_extract() {
        let url = "http://spincoaster.com/spincoaster-breakout-2017";
        let tracks = extract(url).unwrap().tracks;
        let youtube_tracks: Vec<&Track> = tracks.iter().filter(|&x| x.provider == Provider::YouTube).collect();
        let spotify_tracks: Vec<&Track> = tracks.iter().filter(|&x| x.provider == Provider::Spotify).collect();
        assert_eq!(youtube_tracks.len(), 15);
        assert_eq!(spotify_tracks.len(), 30);
    }
}
<|endoftext|>