<commit_before>//! High layer providing somewhat automatic marshalling of Rust closures
//! as C function pointers.
//!
//! The main facility here is given by the structs `Closure`*`N`* and
//! `ClosureMut`*`N`*, for natural numbers *`N`* from 0 to 12 (as of now).
//! These represent C closures, which can be used to turn Rust lambdas
//! (or in generally, anything that implements `Fn` or `FnMut`) into
//! ordinary C function pointers. For example, a Rust value of type
//! `Fn(u32, u32) -> u64` can be turned into a closure of type
//! `Closure2<u32, u32, u64>`. Then a C function pointer of type
//! `extern "C" fn(u32, u32) -> u64` can be borrowed from the closure
//! and passed to C.
//!
//! Here’s an example using [`ClosureMut1`](struct.ClosureMut1.html):
//!
//! ```
//! use libffi::high::ClosureMut1;
//!
//! let mut x = 0u64;
//! let mut f = |y: u32| { x += y as u64; x };
//!
//! let closure = ClosureMut1::new(&mut f);
//! let counter = closure.code_ptr();
//!
//! assert_eq!(5, counter(5));
//! assert_eq!(6, counter(1));
//! assert_eq!(8, counter(2));
//! ```
//!
//! Note that in the above example, `closure` is an ordinary C function
//! pointer of type `extern "C" fn(u64) -> u64`.
use std::marker::PhantomData;
use std::{mem, ptr};

use middle;

/// Representations of C types for the high layer.
pub mod types;
use self::types::*;

macro_rules! define_closure_types {
    (
        $cif:ident $callback:ident $callback_mut:ident
                   $closure:ident  $closure_mut:ident ;
                   $( $T:ident )*
    )
        =>
    {
        /// Typed CIF (“Call InterFace”), which statically tracks
        /// argument and result types.
        pub struct $cif<$( $T, )* R> {
            untyped: middle::Cif,
            _marker: PhantomData<fn($( $T, )*) -> R>,
        }

        impl<$( $T, )* R> $cif<$( $T, )* R> {
            /// Creates a new statically-typed CIF from the given argument
            /// and result types.
            #[allow(non_snake_case)]
            pub fn new($( $T: Type<$T>, )* result: Type<R>) -> Self {
                let cif = middle::Cif::new(vec![$( $T.into_untyped() ),*],
                                           result.into_untyped());
                $cif { untyped: cif, _marker: PhantomData }
            }
        }

        impl<$( $T: FfiType, )* R: FfiType> $cif<$( $T, )* R> {
            /// Creates a new statically-typed CIF by reifying the
            /// argument types as `Type<T>`s.
            pub fn reify() -> Self {
                Self::new($( $T::get_type(), )* R::get_type())
            }
        }

        // We use tuples of pointers to describe the arguments, and we
        // extract them by pattern matching. This assumes that a tuple
        // of pointers will be laid out packed and in order. This seems
        // to hold true right now, and I can’t think of a reason why it
        // wouldn’t be that way, but technically it may be undefined
        // behavior.

        /// The type of function that gets called from an immutable
        /// typed closure.
        pub type $callback<U, $( $T, )* R>
            = extern "C" fn(cif:      &::low::ffi_cif,
                            result:   &mut R,
                            args:     &($( &$T, )*),
                            userdata: &U);

        /// The type of function that gets called from a mutable
        /// typed closure.
        pub type $callback_mut<U, $( $T, )* R>
            = extern "C" fn(cif:      &::low::ffi_cif,
                            result:   &mut R,
                            args:     &($( &$T, )*),
                            userdata: &mut U);

        /// A mutable typed closure with the given argument and result
        /// types.
        pub struct $closure<'a, $( $T, )* R> {
            untyped: middle::Closure<'a>,
            _marker: PhantomData<fn($( $T, )*) -> R>,
        }

        impl<'a, $($T: Copy + FfiType,)* R: FfiType>
            $closure<'a, $($T,)* R>
        {
            /// Constructs a typed closure callable from C from a
            /// Rust closure.
            pub fn new<Callback>(callback: &'a Callback) -> Self
                where Callback: Fn($( $T, )*) -> R + 'a
            {
                Self::new_with_cif($cif::reify(), callback)
            }
        }

        impl<'a, $( $T, )* R> $closure<'a, $( $T, )* R> {
            /// Gets the C code pointer that is used to invoke the
            /// closure.
            pub fn code_ptr(&self) -> &extern "C" fn($( $T, )*) -> R {
                unsafe {
                    mem::transmute(self.untyped.code_ptr())
                }
            }

            /// Constructs a typed closure callable from C from a CIF
            /// describing the calling convention for the resulting
            /// function, a callback for the function to call, and
            /// userdata to pass to the callback.
            pub fn from_parts<U>(cif: $cif<$( $T, )* R>,
                                 callback: $callback<U, $( $T, )* R>,
                                 userdata: &'a U) -> Self
            {
                let callback: middle::Callback<U, R>
                    = unsafe { mem::transmute(callback) };
                let closure
                    = middle::Closure::new(cif.untyped,
                                           callback,
                                           userdata);
                $closure {
                    untyped: closure,
                    _marker: PhantomData,
                }
            }
        }

        impl<'a, $( $T: Copy, )* R> $closure<'a, $( $T, )* R> {
            /// Constructs a typed closure callable from C from a CIF
            /// describing the calling convention for the resulting
            /// function and the Rust closure to call.
            pub fn new_with_cif<Callback>(cif: $cif<$( $T, )* R>,
                                          callback: &'a Callback) -> Self
                where Callback: Fn($( $T, )*) -> R + 'a
            {
                Self::from_parts(cif,
                                 Self::static_callback,
                                 callback)
            }

            #[allow(non_snake_case)]
            extern "C" fn static_callback<Callback>
                (_cif:     &::low::ffi_cif,
                 result:   &mut R,
                 &($( &$T, )*):
                           &($( &$T, )*),
                 userdata: &Callback)
              where Callback: Fn($( $T, )*) -> R + 'a
            {
                unsafe {
                    ptr::write(result, userdata($( $T, )*));
                }
            }
        }

        /// An immutable typed closure with the given argument and
        /// result types.
        pub struct $closure_mut<'a, $( $T, )* R> {
            untyped: middle::Closure<'a>,
            _marker: PhantomData<fn($( $T, )*) -> R>,
        }

        impl<'a, $($T: Copy + FfiType,)* R: FfiType>
            $closure_mut<'a, $($T,)* R>
        {
            /// Constructs a typed closure callable from C from a
            /// Rust closure.
            pub fn new<Callback>(callback: &'a mut Callback) -> Self
                where Callback: FnMut($( $T, )*) -> R + 'a
            {
                Self::new_with_cif($cif::reify(), callback)
            }
        }

        impl<'a, $( $T, )* R> $closure_mut<'a, $( $T, )* R> {
            /// Gets the C code pointer that is used to invoke the
            /// closure.
            pub fn code_ptr(&self) -> &extern "C" fn($( $T, )*) -> R {
                unsafe {
                    mem::transmute(self.untyped.code_ptr())
                }
            }

            /// Constructs a typed closure callable from C from a CIF
            /// describing the calling convention for the resulting
            /// function, a callback for the function to call, and
            /// userdata to pass to the callback.
            pub fn from_parts<U>(cif:      $cif<$( $T, )* R>,
                                 callback: $callback_mut<U, $( $T, )* R>,
                                 userdata: &'a mut U) -> Self
            {
                let callback: middle::CallbackMut<U, R>
                    = unsafe { mem::transmute(callback) };
                let closure
                    = middle::Closure::new_mut(cif.untyped,
                                               callback,
                                               userdata);
                $closure_mut {
                    untyped: closure,
                    _marker: PhantomData,
                }
            }
        }

        impl<'a, $( $T: Copy, )* R> $closure_mut<'a, $( $T, )* R> {
            /// Constructs a typed closure callable from C from a CIF
            /// describing the calling convention for the resulting
            /// function and the Rust closure to call.
            pub fn new_with_cif<Callback>(cif: $cif<$( $T, )* R>,
                                          callback: &'a mut Callback) -> Self
                where Callback: FnMut($( $T, )*) -> R + 'a
            {
                Self::from_parts(cif,
                                 Self::static_callback,
                                 callback)
            }

            #[allow(non_snake_case)]
            extern "C" fn static_callback<Callback>
                (_cif:     &::low::ffi_cif,
                 result:   &mut R,
                 &($( &$T, )*):
                           &($( &$T, )*),
                 userdata: &mut Callback)
              where Callback: FnMut($( $T, )*) -> R + 'a
            {
                unsafe {
                    ptr::write(result, userdata($( $T, )*));
                }
            }
        }
    }
}

define_closure_types!(Cif0 Callback0 CallbackMut0 Closure0 ClosureMut0;
                      );
define_closure_types!(Cif1 Callback1 CallbackMut1 Closure1 ClosureMut1;
                      A);
define_closure_types!(Cif2 Callback2 CallbackMut2 Closure2 ClosureMut2;
                      A B);
define_closure_types!(Cif3 Callback3 CallbackMut3 Closure3 ClosureMut3;
                      A B C);
define_closure_types!(Cif4 Callback4 CallbackMut4 Closure4 ClosureMut4;
                      A B C D);
define_closure_types!(Cif5 Callback5 CallbackMut5 Closure5 ClosureMut5;
                      A B C D E);
define_closure_types!(Cif6 Callback6 CallbackMut6 Closure6 ClosureMut6;
                      A B C D E F);
define_closure_types!(Cif7 Callback7 CallbackMut7 Closure7 ClosureMut7;
                      A B C D E F G);
define_closure_types!(Cif8 Callback8 CallbackMut8 Closure8 ClosureMut8;
                      A B C D E F G H);
define_closure_types!(Cif9 Callback9 CallbackMut9 Closure9 ClosureMut9;
                      A B C D E F G H I);
define_closure_types!(Cif10 Callback10 CallbackMut10 Closure10 ClosureMut10;
                      A B C D E F G H I J);
define_closure_types!(Cif11 Callback11 CallbackMut11 Closure11 ClosureMut11;
                      A B C D E F G H I J K);
define_closure_types!(Cif12 Callback12 CallbackMut12 Closure12 ClosureMut12;
                      A B C D E F G H I J K L);

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

    #[test]
    fn new_with_cif() {
        let x: u64 = 1;
        let f = |y: u64, z: u64| x + y + z;

        let type_   = u64::get_type();
        let cif     = Cif2::new(type_.clone(), type_.clone(), type_.clone());
        let closure = Closure2::new_with_cif(cif, &f);

        assert_eq!(12, closure.code_ptr()(5, 6));
    }

    #[test]
    fn new_with_cif_mut() {
        let mut x: u64 = 0;
        let mut f = |y: u64| { x += y; x };

        let type_   = u64::get_type();
        let cif     = Cif1::new(type_.clone(), type_.clone());
        let closure = ClosureMut1::new_with_cif(cif, &mut f);

        let counter = closure.code_ptr();

        assert_eq!(5, counter(5));
        assert_eq!(6, counter(1));
        assert_eq!(8, counter(2));
    }

    #[test]
    fn new() {
        let x: u64 = 1;
        let f = |y: u64, z: u64| x + y + z;

        let closure = Closure2::new(&f);

        assert_eq!(12, closure.code_ptr()(5, 6));
    }

    #[test]
    fn new_mut() {
        let mut x: u64 = 0;
        let mut f = |y: u32| { x += y as u64; x };

        let closure = ClosureMut1::new(&mut f);
        let counter = closure.code_ptr();

        assert_eq!(5, counter(5));
        assert_eq!(6, counter(1));
        assert_eq!(8, counter(2));
    }
}
<commit_msg>Changed params for high-level closure API from Copy to Clone.<commit_after>//! High layer providing somewhat automatic marshalling of Rust closures
//! as C function pointers.
//!
//! The main facility here is given by the structs `Closure`*`N`* and
//! `ClosureMut`*`N`*, for natural numbers *`N`* from 0 to 12 (as of now).
//! These represent C closures, which can be used to turn Rust lambdas
//! (or in generally, anything that implements `Fn` or `FnMut`) into
//! ordinary C function pointers. For example, a Rust value of type
//! `Fn(u32, u32) -> u64` can be turned into a closure of type
//! `Closure2<u32, u32, u64>`. Then a C function pointer of type
//! `extern "C" fn(u32, u32) -> u64` can be borrowed from the closure
//! and passed to C.
//!
//! Here’s an example using [`ClosureMut1`](struct.ClosureMut1.html):
//!
//! ```
//! use libffi::high::ClosureMut1;
//!
//! let mut x = 0u64;
//! let mut f = |y: u32| { x += y as u64; x };
//!
//! let closure = ClosureMut1::new(&mut f);
//! let counter = closure.code_ptr();
//!
//! assert_eq!(5, counter(5));
//! assert_eq!(6, counter(1));
//! assert_eq!(8, counter(2));
//! ```
//!
//! Note that in the above example, `closure` is an ordinary C function
//! pointer of type `extern "C" fn(u64) -> u64`.
use std::marker::PhantomData;
use std::{mem, ptr};

use middle;

/// Representations of C types for the high layer.
pub mod types;
use self::types::*;

macro_rules! define_closure_types {
    (
        $cif:ident $callback:ident $callback_mut:ident
                   $closure:ident  $closure_mut:ident ;
                   $( $T:ident )*
    )
        =>
    {
        /// Typed CIF (“Call InterFace”), which statically tracks
        /// argument and result types.
        pub struct $cif<$( $T, )* R> {
            untyped: middle::Cif,
            _marker: PhantomData<fn($( $T, )*) -> R>,
        }

        impl<$( $T, )* R> $cif<$( $T, )* R> {
            /// Creates a new statically-typed CIF from the given argument
            /// and result types.
            #[allow(non_snake_case)]
            pub fn new($( $T: Type<$T>, )* result: Type<R>) -> Self {
                let cif = middle::Cif::new(vec![$( $T.into_untyped() ),*],
                                           result.into_untyped());
                $cif { untyped: cif, _marker: PhantomData }
            }
        }

        impl<$( $T: FfiType, )* R: FfiType> $cif<$( $T, )* R> {
            /// Creates a new statically-typed CIF by reifying the
            /// argument types as `Type<T>`s.
            pub fn reify() -> Self {
                Self::new($( $T::get_type(), )* R::get_type())
            }
        }

        // We use tuples of pointers to describe the arguments, and we
        // extract them by pattern matching. This assumes that a tuple
        // of pointers will be laid out packed and in order. This seems
        // to hold true right now, and I can’t think of a reason why it
        // wouldn’t be that way, but technically it may be undefined
        // behavior.

        /// The type of function that gets called from an immutable
        /// typed closure.
        pub type $callback<U, $( $T, )* R>
            = extern "C" fn(cif:      &::low::ffi_cif,
                            result:   &mut R,
                            args:     &($( &$T, )*),
                            userdata: &U);

        /// The type of function that gets called from a mutable
        /// typed closure.
        pub type $callback_mut<U, $( $T, )* R>
            = extern "C" fn(cif:      &::low::ffi_cif,
                            result:   &mut R,
                            args:     &($( &$T, )*),
                            userdata: &mut U);

        /// A mutable typed closure with the given argument and result
        /// types.
        pub struct $closure<'a, $( $T, )* R> {
            untyped: middle::Closure<'a>,
            _marker: PhantomData<fn($( $T, )*) -> R>,
        }

        impl<'a, $($T: Clone + FfiType,)* R: FfiType>
            $closure<'a, $($T,)* R>
        {
            /// Constructs a typed closure callable from C from a
            /// Rust closure.
            pub fn new<Callback>(callback: &'a Callback) -> Self
                where Callback: Fn($( $T, )*) -> R + 'a
            {
                Self::new_with_cif($cif::reify(), callback)
            }
        }

        impl<'a, $( $T, )* R> $closure<'a, $( $T, )* R> {
            /// Gets the C code pointer that is used to invoke the
            /// closure.
            pub fn code_ptr(&self) -> &extern "C" fn($( $T, )*) -> R {
                unsafe {
                    mem::transmute(self.untyped.code_ptr())
                }
            }

            /// Constructs a typed closure callable from C from a CIF
            /// describing the calling convention for the resulting
            /// function, a callback for the function to call, and
            /// userdata to pass to the callback.
            pub fn from_parts<U>(cif: $cif<$( $T, )* R>,
                                 callback: $callback<U, $( $T, )* R>,
                                 userdata: &'a U) -> Self
            {
                let callback: middle::Callback<U, R>
                    = unsafe { mem::transmute(callback) };
                let closure
                    = middle::Closure::new(cif.untyped,
                                           callback,
                                           userdata);
                $closure {
                    untyped: closure,
                    _marker: PhantomData,
                }
            }
        }

        impl<'a, $( $T: Clone, )* R> $closure<'a, $( $T, )* R> {
            /// Constructs a typed closure callable from C from a CIF
            /// describing the calling convention for the resulting
            /// function and the Rust closure to call.
            pub fn new_with_cif<Callback>(cif: $cif<$( $T, )* R>,
                                          callback: &'a Callback) -> Self
                where Callback: Fn($( $T, )*) -> R + 'a
            {
                Self::from_parts(cif,
                                 Self::static_callback,
                                 callback)
            }

            #[allow(non_snake_case)]
            extern "C" fn static_callback<Callback>
                (_cif:     &::low::ffi_cif,
                 result:   &mut R,
                 &($( $T, )*):
                           &($( &$T, )*),
                 userdata: &Callback)
              where Callback: Fn($( $T, )*) -> R + 'a
            {
                unsafe {
                    ptr::write(result, userdata($( $T.clone(), )*));
                }
            }
        }

        /// An immutable typed closure with the given argument and
        /// result types.
        pub struct $closure_mut<'a, $( $T, )* R> {
            untyped: middle::Closure<'a>,
            _marker: PhantomData<fn($( $T, )*) -> R>,
        }

        impl<'a, $($T: Clone + FfiType,)* R: FfiType>
            $closure_mut<'a, $($T,)* R>
        {
            /// Constructs a typed closure callable from C from a
            /// Rust closure.
            pub fn new<Callback>(callback: &'a mut Callback) -> Self
                where Callback: FnMut($( $T, )*) -> R + 'a
            {
                Self::new_with_cif($cif::reify(), callback)
            }
        }

        impl<'a, $( $T, )* R> $closure_mut<'a, $( $T, )* R> {
            /// Gets the C code pointer that is used to invoke the
            /// closure.
            pub fn code_ptr(&self) -> &extern "C" fn($( $T, )*) -> R {
                unsafe {
                    mem::transmute(self.untyped.code_ptr())
                }
            }

            /// Constructs a typed closure callable from C from a CIF
            /// describing the calling convention for the resulting
            /// function, a callback for the function to call, and
            /// userdata to pass to the callback.
            pub fn from_parts<U>(cif:      $cif<$( $T, )* R>,
                                 callback: $callback_mut<U, $( $T, )* R>,
                                 userdata: &'a mut U) -> Self
            {
                let callback: middle::CallbackMut<U, R>
                    = unsafe { mem::transmute(callback) };
                let closure
                    = middle::Closure::new_mut(cif.untyped,
                                               callback,
                                               userdata);
                $closure_mut {
                    untyped: closure,
                    _marker: PhantomData,
                }
            }
        }

        impl<'a, $( $T: Clone, )* R> $closure_mut<'a, $( $T, )* R> {
            /// Constructs a typed closure callable from C from a CIF
            /// describing the calling convention for the resulting
            /// function and the Rust closure to call.
            pub fn new_with_cif<Callback>(cif: $cif<$( $T, )* R>,
                                          callback: &'a mut Callback) -> Self
                where Callback: FnMut($( $T, )*) -> R + 'a
            {
                Self::from_parts(cif,
                                 Self::static_callback,
                                 callback)
            }

            #[allow(non_snake_case)]
            extern "C" fn static_callback<Callback>
                (_cif:     &::low::ffi_cif,
                 result:   &mut R,
                 &($( $T, )*):
                           &($( &$T, )*),
                 userdata: &mut Callback)
              where Callback: FnMut($( $T, )*) -> R + 'a
            {
                unsafe {
                    ptr::write(result, userdata($( $T.clone(), )*));
                }
            }
        }
    }
}

define_closure_types!(Cif0 Callback0 CallbackMut0 Closure0 ClosureMut0;
                      );
define_closure_types!(Cif1 Callback1 CallbackMut1 Closure1 ClosureMut1;
                      A);
define_closure_types!(Cif2 Callback2 CallbackMut2 Closure2 ClosureMut2;
                      A B);
define_closure_types!(Cif3 Callback3 CallbackMut3 Closure3 ClosureMut3;
                      A B C);
define_closure_types!(Cif4 Callback4 CallbackMut4 Closure4 ClosureMut4;
                      A B C D);
define_closure_types!(Cif5 Callback5 CallbackMut5 Closure5 ClosureMut5;
                      A B C D E);
define_closure_types!(Cif6 Callback6 CallbackMut6 Closure6 ClosureMut6;
                      A B C D E F);
define_closure_types!(Cif7 Callback7 CallbackMut7 Closure7 ClosureMut7;
                      A B C D E F G);
define_closure_types!(Cif8 Callback8 CallbackMut8 Closure8 ClosureMut8;
                      A B C D E F G H);
define_closure_types!(Cif9 Callback9 CallbackMut9 Closure9 ClosureMut9;
                      A B C D E F G H I);
define_closure_types!(Cif10 Callback10 CallbackMut10 Closure10 ClosureMut10;
                      A B C D E F G H I J);
define_closure_types!(Cif11 Callback11 CallbackMut11 Closure11 ClosureMut11;
                      A B C D E F G H I J K);
define_closure_types!(Cif12 Callback12 CallbackMut12 Closure12 ClosureMut12;
                      A B C D E F G H I J K L);

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

    #[test]
    fn new_with_cif() {
        let x: u64 = 1;
        let f = |y: u64, z: u64| x + y + z;

        let type_   = u64::get_type();
        let cif     = Cif2::new(type_.clone(), type_.clone(), type_.clone());
        let closure = Closure2::new_with_cif(cif, &f);

        assert_eq!(12, closure.code_ptr()(5, 6));
    }

    #[test]
    fn new_with_cif_mut() {
        let mut x: u64 = 0;
        let mut f = |y: u64| { x += y; x };

        let type_   = u64::get_type();
        let cif     = Cif1::new(type_.clone(), type_.clone());
        let closure = ClosureMut1::new_with_cif(cif, &mut f);

        let counter = closure.code_ptr();

        assert_eq!(5, counter(5));
        assert_eq!(6, counter(1));
        assert_eq!(8, counter(2));
    }

    #[test]
    fn new() {
        let x: u64 = 1;
        let f = |y: u64, z: u64| x + y + z;

        let closure = Closure2::new(&f);

        assert_eq!(12, closure.code_ptr()(5, 6));
    }

    #[test]
    fn new_mut() {
        let mut x: u64 = 0;
        let mut f = |y: u32| { x += y as u64; x };

        let closure = ClosureMut1::new(&mut f);
        let counter = closure.code_ptr();

        assert_eq!(5, counter(5));
        assert_eq!(6, counter(1));
        assert_eq!(8, counter(2));
    }
}
<|endoftext|>


<commit_before>use common::*;
use super::*;

use std::collections::HashMap;

use auth;
use cursor::{CursorIter, UserCursor, ListCursor};
use error::Error::TwitterError;
use links;
use user;
use tweet;

///Look up the lists the given user has been added to.
pub fn memberships<'a>(user: &'a user::UserID, token: &'a auth::Token) -> CursorIter<'a, ListCursor> {
    let mut params = HashMap::new();
    add_name_param(&mut params, user);
    CursorIter::new(links::lists::LISTS_MEMBERSHIPS, token, Some(params), Some(20))
}

///Return up to 100 lists the given user is subscribed to, including those the user made
///themselves.
///
///TODO: this is not strictly `subscriptions` and `ownerships` blended
pub fn list<'a>(user: &'a user::UserID, owned_first: bool, token: &'a auth::Token)
    -> WebResponse<Vec<List>>
{
    let mut params = HashMap::new();
    add_name_param(&mut params, user);
    add_param(&mut params, "reverse", owned_first.to_string());

    let mut resp = try!(auth::get(links::lists::LISTS_LIST, token, Some(&params)));
    parse_response(&mut resp)
}

///Look up the lists the given user is subscribed to, but not ones the user made themselves.
pub fn subscriptions<'a>(user: &'a user::UserID, token: &'a auth::Token) -> CursorIter<'a, ListCursor> {
    let mut params = HashMap::new();
    add_name_param(&mut params, user);
    CursorIter::new(links::lists::LISTS_SUBSCRIPTIONS, token, Some(params), Some(20))
}

///Look up the lists created by the given user.
pub fn ownerships<'a>(user: &'a user::UserID, token: &'a auth::Token) -> CursorIter<'a, ListCursor> {
    let mut params = HashMap::new();
    add_name_param(&mut params, user);
    CursorIter::new(links::lists::LISTS_OWNERSHIPS, token, Some(params), Some(20))
}

///Look up information for a single list.
pub fn show<'a>(list: ListID<'a>, token: &'a auth::Token) -> WebResponse<List> {
    let mut params = HashMap::new();

    add_list_param(&mut params, &list);

    let mut resp = try!(auth::get(links::lists::LISTS_SHOW, token, Some(&params)));

    parse_response(&mut resp)
}

///Look up the users that have been added to the given list.
pub fn members<'a>(list: ListID<'a>, token: &'a auth::Token) -> CursorIter<'a, UserCursor> {
    let mut params = HashMap::new();

    add_list_param(&mut params, &list);

    CursorIter::new(links::lists::LISTS_MEMBERS, token, Some(params), Some(20))
}

///Check whether the given user has been added to the given list.
pub fn is_member<'a, T: Into<user::UserID<'a>>>(user: T, list: ListID<'a>, token: &auth::Token) ->
    WebResponse<bool>
{
    let mut params = HashMap::new();

    add_list_param(&mut params, &list);
    add_name_param(&mut params, &user.into());

    let mut resp = try!(auth::get(links::lists::LISTS_MEMBERS_SHOW, token, Some(&params)));

    let out: WebResponse<user::TwitterUser> = parse_response(&mut resp);

    match out {
        Ok(user) => Ok(Response::map(user, |_| true)),
        Err(TwitterError(terrs)) => {
            if terrs.errors.iter().any(|e| e.code == 109) {
                //here's a fun conundrum: since "is not in this list" is returned as an error code,
                //the rate limit info that would otherwise be part of the response isn't there. the
                //rate_headers method was factored out specifically for this location, since it's
                //still there, just accompanying an error response instead of a user.
                Ok(Response::map(rate_headers(&resp), |_| false))
            }
            else {
                Err(TwitterError(terrs))
            }
        },
        Err(err) => Err(err),
    }
}

///Begin navigating the collection of tweets made by the users added to the given list.
pub fn statuses<'a>(list: ListID<'a>, with_rts: bool, token: &'a auth::Token)
    -> tweet::Timeline<'a>
{
    let mut params = HashMap::new();
    add_list_param(&mut params, &list);
    add_param(&mut params, "include_rts", with_rts.to_string());

    tweet::Timeline::new(links::lists::LISTS_STATUSES, Some(params), token)
}
<commit_msg>list::{subscribers, is_subscribed}<commit_after>use common::*;
use super::*;

use std::collections::HashMap;

use auth;
use cursor::{CursorIter, UserCursor, ListCursor};
use error::Error::TwitterError;
use links;
use user;
use tweet;

///Look up the lists the given user has been added to.
pub fn memberships<'a>(user: &'a user::UserID, token: &'a auth::Token) -> CursorIter<'a, ListCursor> {
    let mut params = HashMap::new();
    add_name_param(&mut params, user);
    CursorIter::new(links::lists::LISTS_MEMBERSHIPS, token, Some(params), Some(20))
}

///Return up to 100 lists the given user is subscribed to, including those the user made
///themselves.
///
///TODO: this is not strictly `subscriptions` and `ownerships` blended
pub fn list<'a>(user: &'a user::UserID, owned_first: bool, token: &'a auth::Token)
    -> WebResponse<Vec<List>>
{
    let mut params = HashMap::new();
    add_name_param(&mut params, user);
    add_param(&mut params, "reverse", owned_first.to_string());

    let mut resp = try!(auth::get(links::lists::LISTS_LIST, token, Some(&params)));
    parse_response(&mut resp)
}

///Look up the lists the given user is subscribed to, but not ones the user made themselves.
pub fn subscriptions<'a>(user: &'a user::UserID, token: &'a auth::Token) -> CursorIter<'a, ListCursor> {
    let mut params = HashMap::new();
    add_name_param(&mut params, user);
    CursorIter::new(links::lists::LISTS_SUBSCRIPTIONS, token, Some(params), Some(20))
}

///Look up the lists created by the given user.
pub fn ownerships<'a>(user: &'a user::UserID, token: &'a auth::Token) -> CursorIter<'a, ListCursor> {
    let mut params = HashMap::new();
    add_name_param(&mut params, user);
    CursorIter::new(links::lists::LISTS_OWNERSHIPS, token, Some(params), Some(20))
}

///Look up information for a single list.
pub fn show<'a>(list: ListID<'a>, token: &'a auth::Token) -> WebResponse<List> {
    let mut params = HashMap::new();

    add_list_param(&mut params, &list);

    let mut resp = try!(auth::get(links::lists::LISTS_SHOW, token, Some(&params)));

    parse_response(&mut resp)
}

///Look up the users that have been added to the given list.
pub fn members<'a>(list: ListID<'a>, token: &'a auth::Token) -> CursorIter<'a, UserCursor> {
    let mut params = HashMap::new();

    add_list_param(&mut params, &list);

    CursorIter::new(links::lists::LISTS_MEMBERS, token, Some(params), Some(20))
}

///Look up the users that have subscribed to the given list.
pub fn suscribers<'a>(list: ListID<'a>, token: &'a auth::Token) -> CursorIter<'a, UserCursor> {
    let mut params = HashMap::new();

    add_list_param(&mut params, &list);

    CursorIter::new(links::lists::LISTS_SUBSCRIBERS, token, Some(params), Some(20))
}

///Check whether the given user is subscribed to the given list.
pub fn is_subscribed<'a, T: Into<user::UserID<'a>>>(user: T, list: ListID<'a>, token: &auth::Token) ->
    WebResponse<bool>
{
    let mut params = HashMap::new();

    add_list_param(&mut params, &list);
    add_name_param(&mut params, &user.into());

    let mut resp = try!(auth::get(links::lists::LISTS_SUBSCRIBERS_SHOW, token, Some(&params)));

    let out: WebResponse<user::TwitterUser> = parse_response(&mut resp);

    match out {
        Ok(user) => Ok(Response::map(user, |_| true)),
        Err(TwitterError(terrs)) => {
            //TODO: this is currently a copy of is_member, is the error code different?
            if terrs.errors.iter().any(|e| e.code == 109) {
                //here's a fun conundrum: since "is not in this list" is returned as an error code,
                //the rate limit info that would otherwise be part of the response isn't there. the
                //rate_headers method was factored out specifically for this location, since it's
                //still there, just accompanying an error response instead of a user.
                Ok(Response::map(rate_headers(&resp), |_| false))
            }
            else {
                Err(TwitterError(terrs))
            }
        },
        Err(err) => Err(err),
    }
}

///Check whether the given user has been added to the given list.
pub fn is_member<'a, T: Into<user::UserID<'a>>>(user: T, list: ListID<'a>, token: &auth::Token) ->
    WebResponse<bool>
{
    let mut params = HashMap::new();

    add_list_param(&mut params, &list);
    add_name_param(&mut params, &user.into());

    let mut resp = try!(auth::get(links::lists::LISTS_MEMBERS_SHOW, token, Some(&params)));

    let out: WebResponse<user::TwitterUser> = parse_response(&mut resp);

    match out {
        Ok(user) => Ok(Response::map(user, |_| true)),
        Err(TwitterError(terrs)) => {
            if terrs.errors.iter().any(|e| e.code == 109) {
                //here's a fun conundrum: since "is not in this list" is returned as an error code,
                //the rate limit info that would otherwise be part of the response isn't there. the
                //rate_headers method was factored out specifically for this location, since it's
                //still there, just accompanying an error response instead of a user.
                Ok(Response::map(rate_headers(&resp), |_| false))
            }
            else {
                Err(TwitterError(terrs))
            }
        },
        Err(err) => Err(err),
    }
}

///Begin navigating the collection of tweets made by the users added to the given list.
pub fn statuses<'a>(list: ListID<'a>, with_rts: bool, token: &'a auth::Token)
    -> tweet::Timeline<'a>
{
    let mut params = HashMap::new();
    add_list_param(&mut params, &list);
    add_param(&mut params, "include_rts", with_rts.to_string());

    tweet::Timeline::new(links::lists::LISTS_STATUSES, Some(params), token)
}
<|endoftext|>


<commit_before>use std::collections::{BTreeMap, HashMap};
use std::io::{self, Read, Write};
use std::env;
use std::error::Error;
use std::fs::{self, File};
use std::path::Path;
use std::process;

use toml::{self, Table, Value};
use tempdir::TempDir;

use deps::RawDep;
use deps::Dep;
use error::{CliError, CliResult};
use config::Config;
use fmt::Format;

pub struct Lockfile {
    pub deps: HashMap<String, RawDep>,
    toml: Box<Table>,
}

impl Lockfile {
    pub fn from_config(cfg: &Config) -> CliResult<Self> {
        debugln!("Lockfile:from_config");
        Lockfile::from_file(&cfg.lockfile)
    }

    pub fn from_file<P: AsRef<Path>>(p: P) -> CliResult<Self> {
        debugln!("Lockfile:from_file:file={:?}", p.as_ref());
        let mut f = match File::open(p.as_ref()) {
            Ok(f) => f,
            Err(e) => return Err(CliError::FileOpen(e.description().to_owned())),
        };

        let mut s = String::new();
        if let Err(e) = f.read_to_string(&mut s) {
            return Err(CliError::Generic(format!("Couldn't read the contents of the lockfile with error: {}",
                                                 e.description())));
        }

        let mut parser = toml::Parser::new(&s);
        if let Some(toml) = parser.parse() {
            return Ok(Lockfile {
                deps: HashMap::new(),
                toml: Box::new(toml),
            });
        }

        // On err
        let mut error_str = String::from("could not parse input as TOML\n");
        for error in parser.errors.iter() {
            let (loline, locol) = parser.to_linecol(error.lo);
            let (hiline, hicol) = parser.to_linecol(error.hi);
            error_str.push_str(&format!("{:?}:{}:{}{} {}\n",
                                        f,
                                        loline + 1,
                                        locol + 1,
                                        if loline != hiline || locol != hicol {
                                            format!("-{}:{}", hiline + 1, hicol + 1)
                                        } else {
                                            "".to_owned()
                                        },
                                        error.desc));
        }
        Err(CliError::Generic(error_str))
    }

    #[cfg_attr(feature = "lints", allow(cyclomatic_complexity))]
    pub fn get_updates(&mut self, cfg: &Config) -> CliResult<Option<BTreeMap<String, Dep>>> {
        debugln!("Lockfile:get_updates");
        try!(self.parse_deps_to_depth(cfg.root, cfg.depth));

        // try!(self.get_non_root_deps(self.toml));
        let tmp = match TempDir::new("cargo-outdated") {
            Ok(t) => t,
            Err(e) => return Err(CliError::Generic(e.description().to_owned())),
        };

        verbose!(cfg, "Setting up temp space...");
        let tmp_manifest = tmp.path().join(&cfg.manifest.file_name().unwrap());
        let tmp_lockfile = tmp.path().join(&cfg.lockfile.file_name().unwrap());

        let mut mf = match File::create(&tmp_manifest) {
            Ok(f) => f,
            Err(e) => {
                debugln!("Lockfile:get_updates:creating temp manifest failed: {}", e);
                return Err(CliError::Generic(e.description().to_owned()));
            }
        };

        debugln!("Lockfile:get_updates:temp manifest created");
        try!(self.write_semver_manifest(&mut mf));
        verboseln!(cfg, "{}", Format::Good("Done"));

        match fs::copy(&cfg.lockfile, &tmp_lockfile) {
            Ok(..) => (),
            Err(e) => {
                debugln!("temp Cargo.lock failed with error: {}", e);
                return Err(CliError::Generic(e.description().to_owned()));
            }
        }

        debugln!("\n{}\n", {
            let mut f = File::open(&tmp_lockfile)
                .unwrap_or_else(|e| panic!("cannot open file: {}", e));

            let mut s = String::new();
            f.read_to_string(&mut s).ok();
            s
        });

        let cwd = env::current_dir()
            .unwrap_or_else(|e| panic!("current working dir opening error: {}", e));
        debugln!("executing; cargo update");
        env::set_current_dir(tmp.path())
            .unwrap_or_else(|e| panic!("cannot set current dir: {}", e));
        print!("Checking for SemVer compatible updates...");
        let mut out = io::stdout();
        out.flush().unwrap_or_else(|e| panic!("failed to flush stdout: {}", e));
        if let Err(e) = process::Command::new("cargo")
            .arg("update")
            .arg("--manifest-path")
            .arg(tmp_manifest.to_str()
                .expect("failed to convert temp Cargo.toml path to string"))
            .output()
            .and_then(|v| {
                if v.status.success() {
                    Ok(v)
                } else {
                    Err(io::Error::new(io::ErrorKind::Other, "did not exit successfully"))
                }
            }) {

            return Err(CliError::Generic(format!("Failed to run 'cargo update' with error '{}'",
                                                 e.description())));
        }
        println!("{}", Format::Good("Done"));

        verbose!(cfg, "Parsing the results...");
        debugln!("creating new lockfile from tmp results");
        let mut updated_lf = try!(Lockfile::from_file(&tmp_lockfile));
        try!(updated_lf.parse_deps_to_depth(None, 0));
        let mut res = BTreeMap::new();
        debugln!("parsing semver results");
        for (d_name, d) in self.deps.iter() {
            debugln!("iter; name={}; ver={}", d_name, d.ver);
            if let Some(semver_dep) = updated_lf.deps.get(&d.name) {
                if semver_dep.ver != d.ver {
                    res.insert(d_name.to_owned(),
                               Dep {
                                   name: d.label(),
                                   source: d.source.clone(),
                                   project_ver: d.ver.clone(),
                                   semver_ver: Some(semver_dep.ver.clone()),
                                   latest_ver: None,
                               });
                }
            }
        }
        verboseln!(cfg, "{}", Format::Good("Done"));

        verbose!(cfg, "Creating temp space for latest versions...");
        let mut mf = match File::create(&tmp_manifest) {
            Ok(f) => f,
            Err(e) => {
                debugln!("temp Cargo.toml failed with error: {}", e);
                return Err(CliError::Generic(e.description().to_owned()));
            }
        };

        try!(self.write_latest_manifest(&mut mf));

        match fs::copy(&cfg.lockfile, &tmp_lockfile) {
            Ok(..) => (),
            Err(e) => {
                debugln!("temp Cargo.lock failed with error: {}", e);
                return Err(CliError::Generic(e.description().to_owned()));
            }
        }
        verboseln!(cfg, "{}", Format::Good("Done"));

        print!("Checking for the latest updates...");
        out.flush().expect("failed to flush stdout");
        if let Err(e) = process::Command::new("cargo")
            .arg("update")
            .arg("--manifest-path")
            .arg(tmp_manifest.to_str()
                .expect("failed to convert temp Cargo.toml path to string"))
            .output()
            .and_then(|v| {
                if v.status.success() {
                    Ok(v)
                } else {
                    Err(io::Error::new(io::ErrorKind::Other, "did not exit successfully"))
                }
            }) {

            return Err(CliError::Generic(format!("Failed to run 'cargo update' with error '{}'",
                                                 e.description())));
        }
        println!("{}", Format::Good("Done"));

        verbose!(cfg, "Parsing the results...");
        let mut updated_lf = try!(Lockfile::from_file(&tmp_lockfile));
        try!(updated_lf.parse_deps_to_depth(None, 0));
        for (d_name, d) in self.deps.iter() {
            debugln!("iter; name={}", d_name);
            if let Some(latest_dep) = updated_lf.deps.get(&d.name) {
                if latest_dep.ver != d.ver {
                    let exists = if let Some(d) = res.get_mut(d_name) {
                        d.latest_ver = Some(latest_dep.ver.clone());
                        true
                    } else {
                        false
                    };

                    if !exists {
                        res.insert(d_name.to_owned(),
                                   Dep {
                                       name: d.label(),
                                       source: d.source.clone(),
                                       project_ver: d.ver.clone(),
                                       semver_ver: None,
                                       latest_ver: Some(latest_dep.ver.clone()),
                                   });
                    }
                }
            }
        }
        verboseln!(cfg, "{}", Format::Good("Done"));

        env::set_current_dir(&cwd).unwrap_or_else(|e| panic!("cannot set current dir: {}", e));

        if res.is_empty() {
            debugln!("returning; res=Ok(None)");
            Ok(None)
        } else {
            if let Some(ref dep_v) = cfg.to_update {
                let mut safe = vec![];
                for dep in dep_v {
                    if res.contains_key(dep.to_owned()) {
                        safe.push(dep);
                    }
                }
                let mut ret = BTreeMap::new();
                for dep in safe.into_iter() {
                    ret.insert((*dep).to_owned(),
                               res.remove(&**dep)
                                   .expect("failed to get dependency from results set"));
                }
                return Ok(Some(ret));
            }
            debugln!("returning; res={:#?}", res);
            Ok(Some(res))
        }
    }

    fn parse_deps_to_depth(&mut self, root: Option<&str>, mut depth: u32) -> CliResult<()> {
        debugln!("executing; parse_deps_to_depth; depth={}", depth);
        let mut all_deps = depth == 0;

        try!(self.parse_root_deps(root));

        while depth > 1 || all_deps {
            debugln!("iter; depth={};", depth);
            match self.toml.get("package") {
                Some(&Value::Array(ref tables)) => {
                    for table in tables {
                        let name = table.lookup("name")
                            .expect("no 'name' field in Cargo.lock [package] table")
                            .as_str()
                            .expect("'name' field of [package] table in Cargo.lock was \
                                             not a valid string");
                        if !self.deps.contains_key(name) {
                            continue;
                        }
                        let ver = table.lookup("version")
                            .expect("no 'version' field in Cargo.lock [package] table")
                            .as_str()
                            .expect("'version' field of [package] table in Cargo.lock \
                                                was not a valid string");
                        let mut next_level = vec![];
                        if let Some(existing_dep) = self.deps.get_mut(name) {
                            if existing_dep.ver != ver {
                                // probably a child of another dep...skip!
                                continue;
                            }
                            match table.lookup("dependencies") {
                                Some(&Value::Array(ref deps)) => {
                                    let mut children = vec![];
                                    for d in deps {
                                        let dep_str = d.as_str().unwrap_or("");
                                        let mut child: RawDep = match dep_str.parse() {
                                            Ok(val) => val,
                                            Err(e) => return Err(CliError::Generic(e)),
                                        };
                                        child.parent = Some(name.to_owned());
                                        children.push(child.name.clone());
                                        if all_deps || depth > 1 {
                                            debugln!("adding sub dep {}->{}", name, child.name);
                                            next_level.push(child);
                                        }
                                    }
                                    existing_dep.children = Some(children);
                                }
                                Some(..) => unreachable!(),
                                None => (),
                            }
                        }
                        for child in next_level.into_iter() {
                            self.deps.insert(child.name.clone(), child);
                        }
                    }
                    depth = if depth > 0 { depth - 1 } else { break; };
                    if depth == 1 {
                        all_deps = false;
                    }
                }
                Some(_) => unreachable!(),
                None => return Err(CliError::NoNonRootDeps),
            }
        }

        debugln!("All deps: {:#?}", self.deps);
        Ok(())
    }

    fn parse_root_deps(&mut self, root: Option<&str>) -> CliResult<()> {
        debugln!("executing; parse_root_deps;");
        let root_table = if let Some(name) = root {
            let tables = match self.toml.get("package") {
                Some(&Value::Array(ref tables)) => tables,
                _ => return Err(CliError::TomlTableRoot),
            };
            match tables.iter().find(|t| t.lookup("name").and_then(Value::as_str) == Some(name)) {
                Some(table) => table,
                _ => return Err(CliError::TomlTableRoot),
            }
        } else {
            match self.toml.get("root") {
                Some(table) => table,
                None => return Err(CliError::TomlTableRoot),
            }
        };
        match root_table.lookup("dependencies") {
            Some(&Value::Array(ref val)) => {
                debugln!("found root deps table");

                for v in val {
                    let val_str = v.as_str().unwrap_or("");
                    debugln!("adding root dep {}", val_str);
                    let raw_dep: RawDep = match val_str.parse() {
                        Ok(val) => val,
                        Err(e) => return Err(CliError::Generic(e)),
                    };
                    self.deps.insert(raw_dep.name.clone(), raw_dep);
                }
            }
            Some(_) => unreachable!(),
            None => return Err(CliError::NoRootDeps),
        }

        debugln!("Root deps: {:#?}", self.deps);
        Ok(())
    }

    fn write_manifest_pretext<W>(&self, w: &mut W) -> CliResult<()>
        where W: Write
    {
        write!(w,
               "[package]\n\
                      name = \"temp\"\n\
                      version = \"1.0.0\"\n\
                      [[bin]]\n\
                      name = \"test\"\n\
                      [dependencies]\n")
            .unwrap();

        Ok(())
    }

    fn unique_deps(&self) -> HashMap<String, RawDep> {
        self.deps.iter().map(|(_, ref dep)| (dep.name.clone(), (**dep).clone())).collect()
    }

    pub fn write_semver_manifest<W>(&self, w: &mut W) -> CliResult<()>
        where W: Write
    {
        debugln!("executing; write_semver_manifest;");
        try!(self.write_manifest_pretext(w));

        for dep in self.unique_deps().values() {
            if !dep.source.starts_with("(registry+") {
                continue;
            }
            debugln!("iter; name={}; ver={}", dep.name, dep.ver);
            if let Err(e) = write!(w, "{} = \"{}\"\n", dep.name, dep.ver) {
                return Err(CliError::Generic(format!("Failed to write Cargo.toml with error '{}'",
                                                     e.description())));
            }
        }

        Ok(())
    }
    pub fn write_latest_manifest<W>(&self, w: &mut W) -> CliResult<()>
        where W: Write
    {
        debugln!("write_latest_manifest;");
        try!(self.write_manifest_pretext(w));

        for dep in self.unique_deps().values() {
            if !dep.source.starts_with("(registry+") {
                continue;
            }
            debugln!("write_latest_manifest:iter:ver=*,name={}", dep.name);
            if let Err(e) = write!(w, "{} = \"*\"\n", dep.name) {
                return Err(CliError::Generic(format!("Failed to write manifest with error: '{}'",
                                                     e.description())));
            }
        }

        Ok(())
    }
}
<commit_msg>fix: Set bin.path in the temp manifest<commit_after>use std::collections::{BTreeMap, HashMap};
use std::io::{self, Read, Write};
use std::env;
use std::error::Error;
use std::fs::{self, File};
use std::path::Path;
use std::process;

use toml::{self, Table, Value};
use tempdir::TempDir;

use deps::RawDep;
use deps::Dep;
use error::{CliError, CliResult};
use config::Config;
use fmt::Format;

pub struct Lockfile {
    pub deps: HashMap<String, RawDep>,
    toml: Box<Table>,
}

impl Lockfile {
    pub fn from_config(cfg: &Config) -> CliResult<Self> {
        debugln!("Lockfile:from_config");
        Lockfile::from_file(&cfg.lockfile)
    }

    pub fn from_file<P: AsRef<Path>>(p: P) -> CliResult<Self> {
        debugln!("Lockfile:from_file:file={:?}", p.as_ref());
        let mut f = match File::open(p.as_ref()) {
            Ok(f) => f,
            Err(e) => return Err(CliError::FileOpen(e.description().to_owned())),
        };

        let mut s = String::new();
        if let Err(e) = f.read_to_string(&mut s) {
            return Err(CliError::Generic(format!("Couldn't read the contents of the lockfile with error: {}",
                                                 e.description())));
        }

        let mut parser = toml::Parser::new(&s);
        if let Some(toml) = parser.parse() {
            return Ok(Lockfile {
                deps: HashMap::new(),
                toml: Box::new(toml),
            });
        }

        // On err
        let mut error_str = String::from("could not parse input as TOML\n");
        for error in parser.errors.iter() {
            let (loline, locol) = parser.to_linecol(error.lo);
            let (hiline, hicol) = parser.to_linecol(error.hi);
            error_str.push_str(&format!("{:?}:{}:{}{} {}\n",
                                        f,
                                        loline + 1,
                                        locol + 1,
                                        if loline != hiline || locol != hicol {
                                            format!("-{}:{}", hiline + 1, hicol + 1)
                                        } else {
                                            "".to_owned()
                                        },
                                        error.desc));
        }
        Err(CliError::Generic(error_str))
    }

    #[cfg_attr(feature = "lints", allow(cyclomatic_complexity))]
    pub fn get_updates(&mut self, cfg: &Config) -> CliResult<Option<BTreeMap<String, Dep>>> {
        debugln!("Lockfile:get_updates");
        try!(self.parse_deps_to_depth(cfg.root, cfg.depth));

        // try!(self.get_non_root_deps(self.toml));
        let tmp = match TempDir::new("cargo-outdated") {
            Ok(t) => t,
            Err(e) => return Err(CliError::Generic(e.description().to_owned())),
        };

        verbose!(cfg, "Setting up temp space...");
        let tmp_manifest = tmp.path().join(&cfg.manifest.file_name().unwrap());
        let tmp_lockfile = tmp.path().join(&cfg.lockfile.file_name().unwrap());

        let mut mf = match File::create(&tmp_manifest) {
            Ok(f) => f,
            Err(e) => {
                debugln!("Lockfile:get_updates:creating temp manifest failed: {}", e);
                return Err(CliError::Generic(e.description().to_owned()));
            }
        };

        debugln!("Lockfile:get_updates:temp manifest created");
        try!(self.write_semver_manifest(&mut mf));
        verboseln!(cfg, "{}", Format::Good("Done"));

        match fs::copy(&cfg.lockfile, &tmp_lockfile) {
            Ok(..) => (),
            Err(e) => {
                debugln!("temp Cargo.lock failed with error: {}", e);
                return Err(CliError::Generic(e.description().to_owned()));
            }
        }

        debugln!("\n{}\n", {
            let mut f = File::open(&tmp_lockfile)
                .unwrap_or_else(|e| panic!("cannot open file: {}", e));

            let mut s = String::new();
            f.read_to_string(&mut s).ok();
            s
        });

        let cwd = env::current_dir()
            .unwrap_or_else(|e| panic!("current working dir opening error: {}", e));
        debugln!("executing; cargo update");
        env::set_current_dir(tmp.path())
            .unwrap_or_else(|e| panic!("cannot set current dir: {}", e));
        print!("Checking for SemVer compatible updates...");
        let mut out = io::stdout();
        out.flush().unwrap_or_else(|e| panic!("failed to flush stdout: {}", e));
        if let Err(e) = process::Command::new("cargo")
            .arg("update")
            .arg("--manifest-path")
            .arg(tmp_manifest.to_str()
                .expect("failed to convert temp Cargo.toml path to string"))
            .output()
            .and_then(|v| {
                if v.status.success() {
                    Ok(v)
                } else {
                    Err(io::Error::new(io::ErrorKind::Other, "did not exit successfully"))
                }
            }) {

            return Err(CliError::Generic(format!("Failed to run 'cargo update' with error '{}'",
                                                 e.description())));
        }
        println!("{}", Format::Good("Done"));

        verbose!(cfg, "Parsing the results...");
        debugln!("creating new lockfile from tmp results");
        let mut updated_lf = try!(Lockfile::from_file(&tmp_lockfile));
        try!(updated_lf.parse_deps_to_depth(None, 0));
        let mut res = BTreeMap::new();
        debugln!("parsing semver results");
        for (d_name, d) in self.deps.iter() {
            debugln!("iter; name={}; ver={}", d_name, d.ver);
            if let Some(semver_dep) = updated_lf.deps.get(&d.name) {
                if semver_dep.ver != d.ver {
                    res.insert(d_name.to_owned(),
                               Dep {
                                   name: d.label(),
                                   source: d.source.clone(),
                                   project_ver: d.ver.clone(),
                                   semver_ver: Some(semver_dep.ver.clone()),
                                   latest_ver: None,
                               });
                }
            }
        }
        verboseln!(cfg, "{}", Format::Good("Done"));

        verbose!(cfg, "Creating temp space for latest versions...");
        let mut mf = match File::create(&tmp_manifest) {
            Ok(f) => f,
            Err(e) => {
                debugln!("temp Cargo.toml failed with error: {}", e);
                return Err(CliError::Generic(e.description().to_owned()));
            }
        };

        try!(self.write_latest_manifest(&mut mf));

        match fs::copy(&cfg.lockfile, &tmp_lockfile) {
            Ok(..) => (),
            Err(e) => {
                debugln!("temp Cargo.lock failed with error: {}", e);
                return Err(CliError::Generic(e.description().to_owned()));
            }
        }
        verboseln!(cfg, "{}", Format::Good("Done"));

        print!("Checking for the latest updates...");
        out.flush().expect("failed to flush stdout");
        if let Err(e) = process::Command::new("cargo")
            .arg("update")
            .arg("--manifest-path")
            .arg(tmp_manifest.to_str()
                .expect("failed to convert temp Cargo.toml path to string"))
            .output()
            .and_then(|v| {
                if v.status.success() {
                    Ok(v)
                } else {
                    Err(io::Error::new(io::ErrorKind::Other, "did not exit successfully"))
                }
            }) {

            return Err(CliError::Generic(format!("Failed to run 'cargo update' with error '{}'",
                                                 e.description())));
        }
        println!("{}", Format::Good("Done"));

        verbose!(cfg, "Parsing the results...");
        let mut updated_lf = try!(Lockfile::from_file(&tmp_lockfile));
        try!(updated_lf.parse_deps_to_depth(None, 0));
        for (d_name, d) in self.deps.iter() {
            debugln!("iter; name={}", d_name);
            if let Some(latest_dep) = updated_lf.deps.get(&d.name) {
                if latest_dep.ver != d.ver {
                    let exists = if let Some(d) = res.get_mut(d_name) {
                        d.latest_ver = Some(latest_dep.ver.clone());
                        true
                    } else {
                        false
                    };

                    if !exists {
                        res.insert(d_name.to_owned(),
                                   Dep {
                                       name: d.label(),
                                       source: d.source.clone(),
                                       project_ver: d.ver.clone(),
                                       semver_ver: None,
                                       latest_ver: Some(latest_dep.ver.clone()),
                                   });
                    }
                }
            }
        }
        verboseln!(cfg, "{}", Format::Good("Done"));

        env::set_current_dir(&cwd).unwrap_or_else(|e| panic!("cannot set current dir: {}", e));

        if res.is_empty() {
            debugln!("returning; res=Ok(None)");
            Ok(None)
        } else {
            if let Some(ref dep_v) = cfg.to_update {
                let mut safe = vec![];
                for dep in dep_v {
                    if res.contains_key(dep.to_owned()) {
                        safe.push(dep);
                    }
                }
                let mut ret = BTreeMap::new();
                for dep in safe.into_iter() {
                    ret.insert((*dep).to_owned(),
                               res.remove(&**dep)
                                   .expect("failed to get dependency from results set"));
                }
                return Ok(Some(ret));
            }
            debugln!("returning; res={:#?}", res);
            Ok(Some(res))
        }
    }

    fn parse_deps_to_depth(&mut self, root: Option<&str>, mut depth: u32) -> CliResult<()> {
        debugln!("executing; parse_deps_to_depth; depth={}", depth);
        let mut all_deps = depth == 0;

        try!(self.parse_root_deps(root));

        while depth > 1 || all_deps {
            debugln!("iter; depth={};", depth);
            match self.toml.get("package") {
                Some(&Value::Array(ref tables)) => {
                    for table in tables {
                        let name = table.lookup("name")
                            .expect("no 'name' field in Cargo.lock [package] table")
                            .as_str()
                            .expect("'name' field of [package] table in Cargo.lock was \
                                             not a valid string");
                        if !self.deps.contains_key(name) {
                            continue;
                        }
                        let ver = table.lookup("version")
                            .expect("no 'version' field in Cargo.lock [package] table")
                            .as_str()
                            .expect("'version' field of [package] table in Cargo.lock \
                                                was not a valid string");
                        let mut next_level = vec![];
                        if let Some(existing_dep) = self.deps.get_mut(name) {
                            if existing_dep.ver != ver {
                                // probably a child of another dep...skip!
                                continue;
                            }
                            match table.lookup("dependencies") {
                                Some(&Value::Array(ref deps)) => {
                                    let mut children = vec![];
                                    for d in deps {
                                        let dep_str = d.as_str().unwrap_or("");
                                        let mut child: RawDep = match dep_str.parse() {
                                            Ok(val) => val,
                                            Err(e) => return Err(CliError::Generic(e)),
                                        };
                                        child.parent = Some(name.to_owned());
                                        children.push(child.name.clone());
                                        if all_deps || depth > 1 {
                                            debugln!("adding sub dep {}->{}", name, child.name);
                                            next_level.push(child);
                                        }
                                    }
                                    existing_dep.children = Some(children);
                                }
                                Some(..) => unreachable!(),
                                None => (),
                            }
                        }
                        for child in next_level.into_iter() {
                            self.deps.insert(child.name.clone(), child);
                        }
                    }
                    depth = if depth > 0 { depth - 1 } else { break; };
                    if depth == 1 {
                        all_deps = false;
                    }
                }
                Some(_) => unreachable!(),
                None => return Err(CliError::NoNonRootDeps),
            }
        }

        debugln!("All deps: {:#?}", self.deps);
        Ok(())
    }

    fn parse_root_deps(&mut self, root: Option<&str>) -> CliResult<()> {
        debugln!("executing; parse_root_deps;");
        let root_table = if let Some(name) = root {
            let tables = match self.toml.get("package") {
                Some(&Value::Array(ref tables)) => tables,
                _ => return Err(CliError::TomlTableRoot),
            };
            match tables.iter().find(|t| t.lookup("name").and_then(Value::as_str) == Some(name)) {
                Some(table) => table,
                _ => return Err(CliError::TomlTableRoot),
            }
        } else {
            match self.toml.get("root") {
                Some(table) => table,
                None => return Err(CliError::TomlTableRoot),
            }
        };
        match root_table.lookup("dependencies") {
            Some(&Value::Array(ref val)) => {
                debugln!("found root deps table");

                for v in val {
                    let val_str = v.as_str().unwrap_or("");
                    debugln!("adding root dep {}", val_str);
                    let raw_dep: RawDep = match val_str.parse() {
                        Ok(val) => val,
                        Err(e) => return Err(CliError::Generic(e)),
                    };
                    self.deps.insert(raw_dep.name.clone(), raw_dep);
                }
            }
            Some(_) => unreachable!(),
            None => return Err(CliError::NoRootDeps),
        }

        debugln!("Root deps: {:#?}", self.deps);
        Ok(())
    }

    fn write_manifest_pretext<W>(&self, w: &mut W) -> CliResult<()>
        where W: Write
    {
        write!(w,
               "[package]\n\
                      name = \"temp\"\n\
                      version = \"1.0.0\"\n\
                      [[bin]]\n\
                      name = \"test\"\n\
                      path = \"test.rs\"\n\
                      [dependencies]\n")
            .unwrap();

        Ok(())
    }

    fn unique_deps(&self) -> HashMap<String, RawDep> {
        self.deps.iter().map(|(_, ref dep)| (dep.name.clone(), (**dep).clone())).collect()
    }

    pub fn write_semver_manifest<W>(&self, w: &mut W) -> CliResult<()>
        where W: Write
    {
        debugln!("executing; write_semver_manifest;");
        try!(self.write_manifest_pretext(w));

        for dep in self.unique_deps().values() {
            if !dep.source.starts_with("(registry+") {
                continue;
            }
            debugln!("iter; name={}; ver={}", dep.name, dep.ver);
            if let Err(e) = write!(w, "{} = \"{}\"\n", dep.name, dep.ver) {
                return Err(CliError::Generic(format!("Failed to write Cargo.toml with error '{}'",
                                                     e.description())));
            }
        }

        Ok(())
    }
    pub fn write_latest_manifest<W>(&self, w: &mut W) -> CliResult<()>
        where W: Write
    {
        debugln!("write_latest_manifest;");
        try!(self.write_manifest_pretext(w));

        for dep in self.unique_deps().values() {
            if !dep.source.starts_with("(registry+") {
                continue;
            }
            debugln!("write_latest_manifest:iter:ver=*,name={}", dep.name);
            if let Err(e) = write!(w, "{} = \"*\"\n", dep.name) {
                return Err(CliError::Generic(format!("Failed to write manifest with error: '{}'",
                                                     e.description())));
            }
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::ascii::AsciiExt;
use std::cmp::min;

pub fn compute_matches<'a, 'b>(choices: &'a [&'b str], query: &str) -> Vec<&'b str> {
    struct ScoredChoice<'a> {
        score: f64,
        choice: &'a str,
    };
    let mut ret = Vec::new();
    for choice in choices.iter() {
        let score = score(&choice, query);
        if score > 0_f64 {
            ret.push(ScoredChoice{ score: score, choice: &choice });
        }
    }
    ret.sort_by(|x, y| y.score.partial_cmp(&x.score).unwrap());
    ret.iter().map(|s| s.choice).collect()
}

#[allow(dead_code)]
fn get_slice_indices(length: usize, workers: usize, idx: usize) -> (usize, usize) {
    let lb = (length as f64 / workers as f64) * idx as f64;
    let ub = (length as f64 / workers as f64) * (idx + 1) as f64;
    (lb as usize, ub as usize)
}

#[test]
fn get_slice_indices_test() {
    assert_eq!(get_slice_indices(100, 1, 0), (0, 100));

    assert_eq!(get_slice_indices(100, 2, 1), (50, 100));
    assert_eq!(get_slice_indices(100, 2, 0), (0, 50));

    assert_eq!(get_slice_indices(100, 3, 0), (0, 33));
    assert_eq!(get_slice_indices(100, 3, 1), (33, 66));
    assert_eq!(get_slice_indices(100, 3, 2), (66, 100));

    assert_eq!(get_slice_indices(100, 4, 0), (0, 25));
    assert_eq!(get_slice_indices(100, 4, 1), (25, 50));
    assert_eq!(get_slice_indices(100, 4, 2), (50, 75));
    assert_eq!(get_slice_indices(100, 4, 3), (75, 100));

    assert_eq!(get_slice_indices(12, 12, 11), (11, 12));
    assert_eq!(get_slice_indices(12, 12, 0), (0, 1));

    assert_eq!(get_slice_indices(1, 2, 0), (0, 0));
    assert_eq!(get_slice_indices(1, 2, 1), (0, 1));
}

fn score(choice: &str, query: &str) -> f64 {
    if query.len() == 0 {
        return 1.0;
    }
    if choice.len() == 0 {
        return 0.0;
    }

    let query = query.to_ascii_lowercase();
    let choice = choice.to_ascii_lowercase();

    match compute_match_length(&choice, &query) {
        None => return 0.0,
        Some(match_length) => {
            let score = query.len() as f64 / match_length as f64;
            return score as f64 / choice.len() as f64;
        }
    }
}

fn compute_match_length(string: &str, chars: &str) -> Option<usize> {
    let first_char = chars.char_at(0);
    let rest = &chars[1..chars.len()];
    let indices = find_char_in_string(string, first_char);

    let mut current_min = None;
    for i in indices.iter() {
        let last_index = find_end_of_match(string, rest, *i);
        if last_index.is_some() {
            let idx = last_index.unwrap() - *i + 1;
            if current_min.is_some() {
                let cm = min(current_min.unwrap(), idx);
                current_min = Some(cm);
            } else {
                current_min = Some(idx)
            }
        }
    }
    return current_min;
}

fn find_char_in_string(string: &str, char: char) -> Vec<usize> {
    let mut indices = Vec::new();
    let mut i = 0;
    for c in string.chars() {
        if c == char {
            indices.push(i);
        }
        i = i + 1;
    }
    return indices;
}

fn find_end_of_match(string: &str, rest_of_query: &str, first_index: usize) -> Option<usize> {
    let mut last_index = first_index + 1;
    let chars_in_string = string.chars().collect::<Vec<_>>().len();
    for c in rest_of_query.chars() {
        let current_substring = string.slice_chars(last_index, chars_in_string);
        match current_substring.find(c) {
            None => return None,
            Some(ref i) => {
                last_index += *i + 1;
            }
        }
    }
    return Some(last_index - 1);
}

#[test]
fn find_end_of_match_test() {
    assert_eq!(find_end_of_match("a", "a", 0), None);
    assert_eq!(find_end_of_match("ba", "a", 1), None);
    assert_eq!(find_end_of_match("aaa", "aa", 0), Some(2));
    assert_eq!(find_end_of_match("aaa", "b", 0), None);
    assert_eq!(find_end_of_match("this is a long match", "this is a match", 0), None);
    assert_eq!(find_end_of_match("this is a long match", "his is a match", 0), Some(19));
    assert_eq!(find_end_of_match("./rust/x86_64-apple-darwin/test/run-pass/process-spawn-with-unicode-params-πЯ音æ∞/child.stage2-x86_64-apple-darwin", "ust", 2), Some(5));
}

#[test]
fn basic_scoring() {
    assert_eq!(score("", "a"), 0.0);
    assert_eq!(score("a", ""), 1.0);
    assert_eq!(score("short", "longer"), 0.0);
    assert_eq!(score("a", "b"), 0.0);
    assert_eq!(score("ab", "ac"), 0.0);

    assert!(score("a", "a") > 0.0);
    assert!(score("ab", "a") > 0.0);
    assert!(score("ba", "a") > 0.0);
    assert!(score("bab", "a") > 0.0);
    assert!(score("babababab", "aaaa") > 0.0);

    assert_eq!(score("a", "a"), 1_f64 / "a".len() as f64);
    assert_eq!(score("ab", "ab"), 0.5);
    assert_eq!(score("a long string", "a long string"), 1_f64 / "a long string".len() as f64);
    assert_eq!(score("spec/search_spec.rb", "sear"), 1_f64 / "spec/search_spec.rb".len() as f64);
}

#[test]
fn character_matching() {
    assert!(score("/! symbols $^", "/!$^") > 0.0);

    assert_eq!(score("a", "A"), 1.0);
    assert_eq!(score("A", "a"), 1.0);

    assert_eq!(score("a", "aa"), 0.0);
}

#[test]
fn match_equality() {
    assert!(score("selecta.gemspec", "asp") > score("algorithm4_spec.rb", "asp"));
    assert!(score("README.md", "em") > score("benchmark.rb", "em"));
    assert!(score("search.rb", "sear") > score("spec/search_spec.rb", "sear"));

    assert!(score("fbb", "fbb") > score("foo bar baz", "fbb"));
    assert!(score("foo", "foo") > score("longer foo", "foo"));
    assert!(score("foo", "foo") > score("foo longer", "foo"));
    assert!(score("1/2/3/4", "1/2/3") > score("1/9/2/3/4", "1/2/3"));

    assert!(score("long 12 long", "12") > score("1 long 2", "12"));

    assert_eq!(score("121padding2", "12"), 1.0 / "121padding2".len() as f64);
    assert_eq!(score("1padding212", "12"), 1.0 / "1padding212".len() as f64);
}
<commit_msg>Remove unnecessary lifetime from compute_matches<commit_after>use std::ascii::AsciiExt;
use std::cmp::min;

pub fn compute_matches<'a>(choices: &[&'a str], query: &str) -> Vec<&'a str> {
    struct ScoredChoice<'a> {
        score: f64,
        choice: &'a str,
    };
    let mut ret = Vec::new();
    for choice in choices.iter() {
        let score = score(&choice, query);
        if score > 0_f64 {
            ret.push(ScoredChoice{ score: score, choice: &choice });
        }
    }
    ret.sort_by(|x, y| y.score.partial_cmp(&x.score).unwrap());
    ret.iter().map(|s| s.choice).collect()
}

#[allow(dead_code)]
fn get_slice_indices(length: usize, workers: usize, idx: usize) -> (usize, usize) {
    let lb = (length as f64 / workers as f64) * idx as f64;
    let ub = (length as f64 / workers as f64) * (idx + 1) as f64;
    (lb as usize, ub as usize)
}

#[test]
fn get_slice_indices_test() {
    assert_eq!(get_slice_indices(100, 1, 0), (0, 100));

    assert_eq!(get_slice_indices(100, 2, 1), (50, 100));
    assert_eq!(get_slice_indices(100, 2, 0), (0, 50));

    assert_eq!(get_slice_indices(100, 3, 0), (0, 33));
    assert_eq!(get_slice_indices(100, 3, 1), (33, 66));
    assert_eq!(get_slice_indices(100, 3, 2), (66, 100));

    assert_eq!(get_slice_indices(100, 4, 0), (0, 25));
    assert_eq!(get_slice_indices(100, 4, 1), (25, 50));
    assert_eq!(get_slice_indices(100, 4, 2), (50, 75));
    assert_eq!(get_slice_indices(100, 4, 3), (75, 100));

    assert_eq!(get_slice_indices(12, 12, 11), (11, 12));
    assert_eq!(get_slice_indices(12, 12, 0), (0, 1));

    assert_eq!(get_slice_indices(1, 2, 0), (0, 0));
    assert_eq!(get_slice_indices(1, 2, 1), (0, 1));
}

fn score(choice: &str, query: &str) -> f64 {
    if query.len() == 0 {
        return 1.0;
    }
    if choice.len() == 0 {
        return 0.0;
    }

    let query = query.to_ascii_lowercase();
    let choice = choice.to_ascii_lowercase();

    match compute_match_length(&choice, &query) {
        None => return 0.0,
        Some(match_length) => {
            let score = query.len() as f64 / match_length as f64;
            return score as f64 / choice.len() as f64;
        }
    }
}

fn compute_match_length(string: &str, chars: &str) -> Option<usize> {
    let first_char = chars.char_at(0);
    let rest = &chars[1..chars.len()];
    let indices = find_char_in_string(string, first_char);

    let mut current_min = None;
    for i in indices.iter() {
        let last_index = find_end_of_match(string, rest, *i);
        if last_index.is_some() {
            let idx = last_index.unwrap() - *i + 1;
            if current_min.is_some() {
                let cm = min(current_min.unwrap(), idx);
                current_min = Some(cm);
            } else {
                current_min = Some(idx)
            }
        }
    }
    return current_min;
}

fn find_char_in_string(string: &str, char: char) -> Vec<usize> {
    let mut indices = Vec::new();
    let mut i = 0;
    for c in string.chars() {
        if c == char {
            indices.push(i);
        }
        i = i + 1;
    }
    return indices;
}

fn find_end_of_match(string: &str, rest_of_query: &str, first_index: usize) -> Option<usize> {
    let mut last_index = first_index + 1;
    let chars_in_string = string.chars().collect::<Vec<_>>().len();
    for c in rest_of_query.chars() {
        let current_substring = string.slice_chars(last_index, chars_in_string);
        match current_substring.find(c) {
            None => return None,
            Some(ref i) => {
                last_index += *i + 1;
            }
        }
    }
    return Some(last_index - 1);
}

#[test]
fn find_end_of_match_test() {
    assert_eq!(find_end_of_match("a", "a", 0), None);
    assert_eq!(find_end_of_match("ba", "a", 1), None);
    assert_eq!(find_end_of_match("aaa", "aa", 0), Some(2));
    assert_eq!(find_end_of_match("aaa", "b", 0), None);
    assert_eq!(find_end_of_match("this is a long match", "this is a match", 0), None);
    assert_eq!(find_end_of_match("this is a long match", "his is a match", 0), Some(19));
    assert_eq!(find_end_of_match("./rust/x86_64-apple-darwin/test/run-pass/process-spawn-with-unicode-params-πЯ音æ∞/child.stage2-x86_64-apple-darwin", "ust", 2), Some(5));
}

#[test]
fn basic_scoring() {
    assert_eq!(score("", "a"), 0.0);
    assert_eq!(score("a", ""), 1.0);
    assert_eq!(score("short", "longer"), 0.0);
    assert_eq!(score("a", "b"), 0.0);
    assert_eq!(score("ab", "ac"), 0.0);

    assert!(score("a", "a") > 0.0);
    assert!(score("ab", "a") > 0.0);
    assert!(score("ba", "a") > 0.0);
    assert!(score("bab", "a") > 0.0);
    assert!(score("babababab", "aaaa") > 0.0);

    assert_eq!(score("a", "a"), 1_f64 / "a".len() as f64);
    assert_eq!(score("ab", "ab"), 0.5);
    assert_eq!(score("a long string", "a long string"), 1_f64 / "a long string".len() as f64);
    assert_eq!(score("spec/search_spec.rb", "sear"), 1_f64 / "spec/search_spec.rb".len() as f64);
}

#[test]
fn character_matching() {
    assert!(score("/! symbols $^", "/!$^") > 0.0);

    assert_eq!(score("a", "A"), 1.0);
    assert_eq!(score("A", "a"), 1.0);

    assert_eq!(score("a", "aa"), 0.0);
}

#[test]
fn match_equality() {
    assert!(score("selecta.gemspec", "asp") > score("algorithm4_spec.rb", "asp"));
    assert!(score("README.md", "em") > score("benchmark.rb", "em"));
    assert!(score("search.rb", "sear") > score("spec/search_spec.rb", "sear"));

    assert!(score("fbb", "fbb") > score("foo bar baz", "fbb"));
    assert!(score("foo", "foo") > score("longer foo", "foo"));
    assert!(score("foo", "foo") > score("foo longer", "foo"));
    assert!(score("1/2/3/4", "1/2/3") > score("1/9/2/3/4", "1/2/3"));

    assert!(score("long 12 long", "12") > score("1 long 2", "12"));

    assert_eq!(score("121padding2", "12"), 1.0 / "121padding2".len() as f64);
    assert_eq!(score("1padding212", "12"), 1.0 / "1padding212".len() as f64);
}
<|endoftext|>


<commit_before>use std::ascii::AsciiExt;
use std::cmp::*;
use std::os;
use std::thread;
use std::sync::mpsc::*;

macro_rules! chars {
    ($str:expr) => (
        &$str.chars().collect::<Vec<char>>()
    );
}

pub fn compute_matches<'a>(choices: &[&'a str], query: &str) -> Vec<&'a str> {
    #[derive(PartialEq)]
    struct ScoredChoice {
        idx: usize,
        score: f64,
    }
    impl PartialOrd for ScoredChoice {
        fn partial_cmp(&self, other: &ScoredChoice) -> Option<Ordering> {
            if other.score == self.score {
                // We fall back to an array index comparison in order to guarantee a stable sort;
                // otherwise the matches may be displayed in a nondeterministic order.
                Some(self.idx.cmp(&other.idx))
            } else {
                other.score.partial_cmp(&self.score)
            }
        }
    }
    let mut join_guards = Vec::new();
    let (tx, rx) = channel();
    let workers = os::num_cpus();
    for current_worker in 0..workers {
        let tx = tx.clone();
        join_guards.push(thread::scoped(move|| {
            let (lower_bound, upper_bound) = get_slice_indices(choices.len(), workers, current_worker);
            for i in lower_bound..upper_bound {
                let score = score(choices[i], query);
                tx.send(ScoredChoice{ idx: i, score: score }).unwrap();
            }
        }));
    }

    let mut ret = Vec::new();
    for _ in 0..choices.len() {
        let scored_choice = rx.recv().unwrap();
        if scored_choice.score > 0_f64 {
            ret.push(scored_choice);
        }
    }

    ret.sort_by(|x, y| x.partial_cmp(y).unwrap());
    ret.iter().map(|x| choices[x.idx]).collect()
}

fn get_slice_indices(length: usize, workers: usize, idx: usize) -> (usize, usize) {
    let lb = (length as f64 / workers as f64) * idx as f64;
    let ub = (length as f64 / workers as f64) * (idx + 1) as f64;
    (lb as usize, ub as usize)
}

#[test]
fn get_slice_indices_test() {
    assert_eq!(get_slice_indices(100, 1, 0), (0, 100));

    assert_eq!(get_slice_indices(100, 2, 1), (50, 100));
    assert_eq!(get_slice_indices(100, 2, 0), (0, 50));

    assert_eq!(get_slice_indices(100, 3, 0), (0, 33));
    assert_eq!(get_slice_indices(100, 3, 1), (33, 66));
    assert_eq!(get_slice_indices(100, 3, 2), (66, 100));

    assert_eq!(get_slice_indices(100, 4, 0), (0, 25));
    assert_eq!(get_slice_indices(100, 4, 1), (25, 50));
    assert_eq!(get_slice_indices(100, 4, 2), (50, 75));
    assert_eq!(get_slice_indices(100, 4, 3), (75, 100));

    assert_eq!(get_slice_indices(12, 12, 11), (11, 12));
    assert_eq!(get_slice_indices(12, 12, 0), (0, 1));

    assert_eq!(get_slice_indices(1, 2, 0), (0, 0));
    assert_eq!(get_slice_indices(1, 2, 1), (0, 1));
}

fn score(choice: &str, query: &str) -> f64 {
    if query.len() == 0 {
        return 1.0;
    }
    if choice.len() == 0 {
        return 0.0;
    }

    let query = chars!(query);
    let choice = chars!(choice);

    match compute_match_length(choice, query) {
        None => return 0.0,
        Some(match_length) => {
            let score = query.len() as f64 / match_length as f64;
            return score as f64 / choice.len() as f64;
        }
    }
}

// This function is for picking out the matching characters for a given (choice, query) pair for
// rendering purposes. It assumes that the given choice is in fact a match for the given query, and
// will panic if this is not the case.
pub fn visual_score(choice: &str, query: &str) -> Vec<usize> {
    if query.len() == 0 || choice.len() == 0 {
        return Vec::new();
    }
    let query = chars!(query);
    let choice = chars!(choice);

    let (first_idx, _) = get_longest_match(&choice, &query).unwrap();
    get_match_indices(&choice, &query[1..], first_idx).unwrap()
}

fn compute_match_length(string: &[char], query: &[char]) -> Option<usize> {
    get_match_length(get_longest_match(string, query))
}

fn get_longest_match(string: &[char], query: &[char]) -> Option<(usize, usize)> {
    let first_char = query[0];
    let rest = &query[1..];
    let indices = find_char_in_string(string, first_char);

    let mut current_bounds: Option<(usize, usize)> = None;
    let smallest_possible_match = query.len();
    for &i in &indices {
        if let Some(last_index) = find_end_of_match(string, rest, i) {
            let last_bounds = Some((i, last_index));
            let last_match_len = get_match_length(last_bounds).unwrap();
            if current_bounds.is_none() || last_match_len < get_match_length(current_bounds).unwrap() {
                current_bounds = last_bounds;
                if last_match_len == smallest_possible_match {
                    break;
                }
            }
        }
    }
    current_bounds
}

fn get_match_length(bounds: Option<(usize, usize)>) -> Option<usize> {
    if let Some((lb, ub)) = bounds {
        Some(ub - lb + 1)
    } else {
        None
    }
}

fn find_char_in_string(string: &[char], char: char) -> Vec<usize> {
    let mut indices = Vec::new();
    for (i, c) in string.iter().enumerate() {
        if chars_equal(&char, c) {
            indices.push(i);
        }
    }
    return indices;
}

fn find_end_of_match(string: &[char], rest_of_query: &[char], first_index: usize) -> Option<usize> {
    if let Some(indices) = get_match_indices(string, rest_of_query, first_index) {
        Some(indices[indices.len() - 1])
    } else {
        None
    }
}

fn get_match_indices(string: &[char], rest_of_query: &[char], first_index: usize) -> Option<Vec<usize>> {
    let mut ret = Vec::new();
    let mut last_index = first_index + 1;
    ret.push(first_index);
    for c in rest_of_query.iter() {
        let current_substring = &string[last_index..];
        let mut index = None;
        for (i, x) in current_substring.iter().enumerate() {
            if chars_equal(c, x) {
                index = Some(i);
                break;
            }
        }
        if index.is_some() {
            last_index += index.unwrap() + 1;
            ret.push(last_index - 1);
        } else {
            return None;
        }
    }
    Some(ret)
}

fn chars_equal(q: &char, c: &char) -> bool {
    *q == *c || *q == c.to_ascii_lowercase()
}

#[test]
fn chars_equal_test() {
    assert!(chars_equal(&'a', &'a'));
    assert!(!chars_equal(&'a', &'b'));
    assert!(chars_equal(&'A', &'A'));
    assert!(!chars_equal(&'A', &'a'));
    assert!(chars_equal(&'a', &'A'));
}

#[test]
fn get_match_indices_test() {
    assert_eq!(get_match_indices(chars!("asdf"), chars!("sdf"), 0).unwrap(), vec![0, 1, 2, 3]);
    assert_eq!(get_match_indices(chars!("aoeuasdf"), chars!("sdf"), 4).unwrap(), vec![4, 5, 6, 7]);
    assert_eq!(get_match_indices(chars!(" a s d f"), chars!("sdf"), 1).unwrap(), vec![1, 3, 5, 7]);
}

#[test]
fn find_end_of_match_test() {
    assert_eq!(find_end_of_match(chars!("a"), chars!("a"), 0), None);
    assert_eq!(find_end_of_match(chars!("ba"), chars!("a"), 1), None);
    assert_eq!(find_end_of_match(chars!("aaa"), chars!("aa"), 0), Some(2));
    assert_eq!(find_end_of_match(chars!("aaa"), chars!("b"), 0), None);
    assert_eq!(find_end_of_match(chars!("this is a long match"), chars!("this is a match"), 0), None);
    assert_eq!(find_end_of_match(chars!("this is a long match"), chars!("his is a match"), 0), Some(19));
    assert_eq!(find_end_of_match(chars!("./rust/x86_64-apple-darwin/test/run-pass/process-spawn-with-unicode-params-πЯ音æ∞/child.stage2-x86_64-apple-darwin"), chars!("ust"), 2), Some(5));
}

#[test]
fn unicode_boundary_handling_test() {
    score("./rust/x86_64-apple-darwin/test/run-pass/process-spawn-with-unicode-params-πЯ音æ∞/child.stage2-x86_64-apple-darwin", "he");
}

#[test]
fn basic_scoring() {
    assert_eq!(score("", "a"), 0.0);
    assert_eq!(score("a", ""), 1.0);
    assert_eq!(score("short", "longer"), 0.0);
    assert_eq!(score("a", "b"), 0.0);
    assert_eq!(score("ab", "ac"), 0.0);

    assert!(score("a", "a") > 0.0);
    assert!(score("ab", "a") > 0.0);
    assert!(score("ba", "a") > 0.0);
    assert!(score("bab", "a") > 0.0);
    assert!(score("babababab", "aaaa") > 0.0);

    assert_eq!(score("a", "a"), 1_f64 / "a".len() as f64);
    assert_eq!(score("ab", "ab"), 0.5);
    assert_eq!(score("a long string", "a long string"), 1_f64 / "a long string".len() as f64);
    assert_eq!(score("spec/search_spec.rb", "sear"), 1_f64 / "spec/search_spec.rb".len() as f64);
}

#[test]
fn character_matching() {
    assert!(score("/! symbols $^", "/!$^") > 0.0);

    assert_eq!(score("a", "A"), 0.0);
    assert_eq!(score("A", "a"), 1.0);
    assert_eq!(score("A", "A"), 1.0);

    assert_eq!(score("a", "aa"), 0.0);
}

#[test]
fn match_equality() {
    assert!(score("selecta.gemspec", "asp") > score("algorithm4_spec.rb", "asp"));
    assert!(score("README.md", "em") > score("benchmark.rb", "em"));
    assert!(score("search.rb", "sear") > score("spec/search_spec.rb", "sear"));

    assert!(score("fbb", "fbb") > score("foo bar baz", "fbb"));
    assert!(score("foo", "foo") > score("longer foo", "foo"));
    assert!(score("foo", "foo") > score("foo longer", "foo"));
    assert!(score("1/2/3/4", "1/2/3") > score("1/9/2/3/4", "1/2/3"));

    assert!(score("long 12 long", "12") > score("1 long 2", "12"));

    assert_eq!(score("121padding2", "12"), 1.0 / "121padding2".len() as f64);
    assert_eq!(score("1padding212", "12"), 1.0 / "1padding212".len() as f64);
}
<commit_msg>Remove unnecessary derefs<commit_after>use std::ascii::AsciiExt;
use std::cmp::*;
use std::os;
use std::thread;
use std::sync::mpsc::*;

macro_rules! chars {
    ($str:expr) => (
        &$str.chars().collect::<Vec<char>>()
    );
}

pub fn compute_matches<'a>(choices: &[&'a str], query: &str) -> Vec<&'a str> {
    #[derive(PartialEq)]
    struct ScoredChoice {
        idx: usize,
        score: f64,
    }
    impl PartialOrd for ScoredChoice {
        fn partial_cmp(&self, other: &ScoredChoice) -> Option<Ordering> {
            if other.score == self.score {
                // We fall back to an array index comparison in order to guarantee a stable sort;
                // otherwise the matches may be displayed in a nondeterministic order.
                Some(self.idx.cmp(&other.idx))
            } else {
                other.score.partial_cmp(&self.score)
            }
        }
    }
    let mut join_guards = Vec::new();
    let (tx, rx) = channel();
    let workers = os::num_cpus();
    for current_worker in 0..workers {
        let tx = tx.clone();
        join_guards.push(thread::scoped(move|| {
            let (lower_bound, upper_bound) = get_slice_indices(choices.len(), workers, current_worker);
            for i in lower_bound..upper_bound {
                let score = score(choices[i], query);
                tx.send(ScoredChoice{ idx: i, score: score }).unwrap();
            }
        }));
    }

    let mut ret = Vec::new();
    for _ in 0..choices.len() {
        let scored_choice = rx.recv().unwrap();
        if scored_choice.score > 0_f64 {
            ret.push(scored_choice);
        }
    }

    ret.sort_by(|x, y| x.partial_cmp(y).unwrap());
    ret.iter().map(|x| choices[x.idx]).collect()
}

fn get_slice_indices(length: usize, workers: usize, idx: usize) -> (usize, usize) {
    let lb = (length as f64 / workers as f64) * idx as f64;
    let ub = (length as f64 / workers as f64) * (idx + 1) as f64;
    (lb as usize, ub as usize)
}

#[test]
fn get_slice_indices_test() {
    assert_eq!(get_slice_indices(100, 1, 0), (0, 100));

    assert_eq!(get_slice_indices(100, 2, 1), (50, 100));
    assert_eq!(get_slice_indices(100, 2, 0), (0, 50));

    assert_eq!(get_slice_indices(100, 3, 0), (0, 33));
    assert_eq!(get_slice_indices(100, 3, 1), (33, 66));
    assert_eq!(get_slice_indices(100, 3, 2), (66, 100));

    assert_eq!(get_slice_indices(100, 4, 0), (0, 25));
    assert_eq!(get_slice_indices(100, 4, 1), (25, 50));
    assert_eq!(get_slice_indices(100, 4, 2), (50, 75));
    assert_eq!(get_slice_indices(100, 4, 3), (75, 100));

    assert_eq!(get_slice_indices(12, 12, 11), (11, 12));
    assert_eq!(get_slice_indices(12, 12, 0), (0, 1));

    assert_eq!(get_slice_indices(1, 2, 0), (0, 0));
    assert_eq!(get_slice_indices(1, 2, 1), (0, 1));
}

fn score(choice: &str, query: &str) -> f64 {
    if query.len() == 0 {
        return 1.0;
    }
    if choice.len() == 0 {
        return 0.0;
    }

    let query = chars!(query);
    let choice = chars!(choice);

    match compute_match_length(choice, query) {
        None => return 0.0,
        Some(match_length) => {
            let score = query.len() as f64 / match_length as f64;
            return score as f64 / choice.len() as f64;
        }
    }
}

// This function is for picking out the matching characters for a given (choice, query) pair for
// rendering purposes. It assumes that the given choice is in fact a match for the given query, and
// will panic if this is not the case.
pub fn visual_score(choice: &str, query: &str) -> Vec<usize> {
    if query.len() == 0 || choice.len() == 0 {
        return Vec::new();
    }
    let query = chars!(query);
    let choice = chars!(choice);

    let (first_idx, _) = get_longest_match(&choice, &query).unwrap();
    get_match_indices(&choice, &query[1..], first_idx).unwrap()
}

fn compute_match_length(string: &[char], query: &[char]) -> Option<usize> {
    get_match_length(get_longest_match(string, query))
}

fn get_longest_match(string: &[char], query: &[char]) -> Option<(usize, usize)> {
    let first_char = query[0];
    let rest = &query[1..];
    let indices = find_char_in_string(string, first_char);

    let mut current_bounds: Option<(usize, usize)> = None;
    let smallest_possible_match = query.len();
    for &i in &indices {
        if let Some(last_index) = find_end_of_match(string, rest, i) {
            let last_bounds = Some((i, last_index));
            let last_match_len = get_match_length(last_bounds).unwrap();
            if current_bounds.is_none() || last_match_len < get_match_length(current_bounds).unwrap() {
                current_bounds = last_bounds;
                if last_match_len == smallest_possible_match {
                    break;
                }
            }
        }
    }
    current_bounds
}

fn get_match_length(bounds: Option<(usize, usize)>) -> Option<usize> {
    if let Some((lb, ub)) = bounds {
        Some(ub - lb + 1)
    } else {
        None
    }
}

fn find_char_in_string(string: &[char], char: char) -> Vec<usize> {
    let mut indices = Vec::new();
    for (i, c) in string.iter().enumerate() {
        if chars_equal(&char, c) {
            indices.push(i);
        }
    }
    return indices;
}

fn find_end_of_match(string: &[char], rest_of_query: &[char], first_index: usize) -> Option<usize> {
    if let Some(indices) = get_match_indices(string, rest_of_query, first_index) {
        Some(indices[indices.len() - 1])
    } else {
        None
    }
}

fn get_match_indices(string: &[char], rest_of_query: &[char], first_index: usize) -> Option<Vec<usize>> {
    let mut ret = Vec::new();
    let mut last_index = first_index + 1;
    ret.push(first_index);
    for c in rest_of_query.iter() {
        let current_substring = &string[last_index..];
        let mut index = None;
        for (i, x) in current_substring.iter().enumerate() {
            if chars_equal(c, x) {
                index = Some(i);
                break;
            }
        }
        if index.is_some() {
            last_index += index.unwrap() + 1;
            ret.push(last_index - 1);
        } else {
            return None;
        }
    }
    Some(ret)
}

fn chars_equal(q: &char, c: &char) -> bool {
    q == c || *q == c.to_ascii_lowercase()
}

#[test]
fn chars_equal_test() {
    assert!(chars_equal(&'a', &'a'));
    assert!(!chars_equal(&'a', &'b'));
    assert!(chars_equal(&'A', &'A'));
    assert!(!chars_equal(&'A', &'a'));
    assert!(chars_equal(&'a', &'A'));
}

#[test]
fn get_match_indices_test() {
    assert_eq!(get_match_indices(chars!("asdf"), chars!("sdf"), 0).unwrap(), vec![0, 1, 2, 3]);
    assert_eq!(get_match_indices(chars!("aoeuasdf"), chars!("sdf"), 4).unwrap(), vec![4, 5, 6, 7]);
    assert_eq!(get_match_indices(chars!(" a s d f"), chars!("sdf"), 1).unwrap(), vec![1, 3, 5, 7]);
}

#[test]
fn find_end_of_match_test() {
    assert_eq!(find_end_of_match(chars!("a"), chars!("a"), 0), None);
    assert_eq!(find_end_of_match(chars!("ba"), chars!("a"), 1), None);
    assert_eq!(find_end_of_match(chars!("aaa"), chars!("aa"), 0), Some(2));
    assert_eq!(find_end_of_match(chars!("aaa"), chars!("b"), 0), None);
    assert_eq!(find_end_of_match(chars!("this is a long match"), chars!("this is a match"), 0), None);
    assert_eq!(find_end_of_match(chars!("this is a long match"), chars!("his is a match"), 0), Some(19));
    assert_eq!(find_end_of_match(chars!("./rust/x86_64-apple-darwin/test/run-pass/process-spawn-with-unicode-params-πЯ音æ∞/child.stage2-x86_64-apple-darwin"), chars!("ust"), 2), Some(5));
}

#[test]
fn unicode_boundary_handling_test() {
    score("./rust/x86_64-apple-darwin/test/run-pass/process-spawn-with-unicode-params-πЯ音æ∞/child.stage2-x86_64-apple-darwin", "he");
}

#[test]
fn basic_scoring() {
    assert_eq!(score("", "a"), 0.0);
    assert_eq!(score("a", ""), 1.0);
    assert_eq!(score("short", "longer"), 0.0);
    assert_eq!(score("a", "b"), 0.0);
    assert_eq!(score("ab", "ac"), 0.0);

    assert!(score("a", "a") > 0.0);
    assert!(score("ab", "a") > 0.0);
    assert!(score("ba", "a") > 0.0);
    assert!(score("bab", "a") > 0.0);
    assert!(score("babababab", "aaaa") > 0.0);

    assert_eq!(score("a", "a"), 1_f64 / "a".len() as f64);
    assert_eq!(score("ab", "ab"), 0.5);
    assert_eq!(score("a long string", "a long string"), 1_f64 / "a long string".len() as f64);
    assert_eq!(score("spec/search_spec.rb", "sear"), 1_f64 / "spec/search_spec.rb".len() as f64);
}

#[test]
fn character_matching() {
    assert!(score("/! symbols $^", "/!$^") > 0.0);

    assert_eq!(score("a", "A"), 0.0);
    assert_eq!(score("A", "a"), 1.0);
    assert_eq!(score("A", "A"), 1.0);

    assert_eq!(score("a", "aa"), 0.0);
}

#[test]
fn match_equality() {
    assert!(score("selecta.gemspec", "asp") > score("algorithm4_spec.rb", "asp"));
    assert!(score("README.md", "em") > score("benchmark.rb", "em"));
    assert!(score("search.rb", "sear") > score("spec/search_spec.rb", "sear"));

    assert!(score("fbb", "fbb") > score("foo bar baz", "fbb"));
    assert!(score("foo", "foo") > score("longer foo", "foo"));
    assert!(score("foo", "foo") > score("foo longer", "foo"));
    assert!(score("1/2/3/4", "1/2/3") > score("1/9/2/3/4", "1/2/3"));

    assert!(score("long 12 long", "12") > score("1 long 2", "12"));

    assert_eq!(score("121padding2", "12"), 1.0 / "121padding2".len() as f64);
    assert_eq!(score("1padding212", "12"), 1.0 / "1padding212".len() as f64);
}
<|endoftext|>