<commit_before>//! Less used details of `CxxVector` are exposed in this module. `CxxVector`
//! itself is exposed at the crate root.

use crate::extern_type::ExternType;
use crate::kind::Trivial;
use crate::string::CxxString;
use core::ffi::c_void;
use core::fmt::{self, Debug, Display};
use core::iter::FusedIterator;
use core::marker::{PhantomData, PhantomPinned};
use core::mem;
use core::pin::Pin;
use core::ptr;
use core::slice;

#[doc(inline)]
pub use crate::Vector;

/// Binding to C++ `std::vector<T, std::allocator<T>>`.
///
/// # Invariants
///
/// As an invariant of this API and the static analysis of the cxx::bridge
/// macro, in Rust code we can never obtain a `CxxVector` by value. Instead in
/// Rust code we will only ever look at a vector behind a reference or smart
/// pointer, as in `&CxxVector<T>` or `UniquePtr<CxxVector<T>>`.
#[repr(C, packed)]
pub struct CxxVector<T> {
    _private: [T; 0],
    _pinned: PhantomData<PhantomPinned>,
}

impl<T> CxxVector<T>
where
    T: VectorElement,
{
    /// Returns the number of elements in the vector.
    ///
    /// Matches the behavior of C++ [std::vector\<T\>::size][size].
    ///
    /// [size]: https://en.cppreference.com/w/cpp/container/vector/size
    pub fn len(&self) -> usize {
        T::__vector_size(self)
    }

    /// Returns true if the vector contains no elements.
    ///
    /// Matches the behavior of C++ [std::vector\<T\>::empty][empty].
    ///
    /// [empty]: https://en.cppreference.com/w/cpp/container/vector/empty
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns a reference to an element at the given position, or `None` if
    /// out of bounds.
    pub fn get(&self, pos: usize) -> Option<&T> {
        if pos < self.len() {
            Some(unsafe { self.get_unchecked(pos) })
        } else {
            None
        }
    }

    /// Returns a pinned mutable reference to an element at the given position,
    /// or `None` if out of bounds.
    pub fn get_mut(self: Pin<&mut Self>, pos: usize) -> Option<Pin<&mut T>> {
        if pos < self.len() {
            Some(unsafe { CxxVector::get_unchecked_mut(self, pos) })
        } else {
            None
        }
    }

    /// Returns a reference to an element without doing bounds checking.
    ///
    /// This is generally not recommended, use with caution! Calling this method
    /// with an out-of-bounds index is undefined behavior even if the resulting
    /// reference is not used.
    ///
    /// Matches the behavior of C++
    /// [std::vector\<T\>::operator\[\] const][operator_at].
    ///
    /// [operator_at]: https://en.cppreference.com/w/cpp/container/vector/operator_at
    pub unsafe fn get_unchecked(&self, pos: usize) -> &T {
        let this = self as *const CxxVector<T> as *mut CxxVector<T>;
        let ptr = T::__get_unchecked(this, pos) as *const T;
        &*ptr
    }

    /// Returns a pinned mutable reference to an element without doing bounds
    /// checking.
    ///
    /// This is generally not recommended, use with caution! Calling this method
    /// with an out-of-bounds index is undefined behavior even if the resulting
    /// reference is not used.
    ///
    /// Matches the behavior of C++
    /// [std::vector\<T\>::operator\[\]][operator_at].
    ///
    /// [operator_at]: https://en.cppreference.com/w/cpp/container/vector/operator_at
    pub unsafe fn get_unchecked_mut(self: Pin<&mut Self>, pos: usize) -> Pin<&mut T> {
        let ptr = T::__get_unchecked(Pin::get_unchecked_mut(self), pos);
        Pin::new_unchecked(&mut *ptr)
    }

    /// Returns a slice to the underlying contiguous array of elements.
    pub fn as_slice(&self) -> &[T]
    where
        T: ExternType<Kind = Trivial>,
    {
        let len = self.len();
        if len == 0 {
            // The slice::from_raw_parts in the other branch requires a nonnull
            // and properly aligned data ptr. C++ standard does not guarantee
            // that data() on a vector with size 0 would return a nonnull
            // pointer or sufficiently aligned pointer, so using it would be
            // undefined behavior. Create our own empty slice in Rust instead
            // which upholds the invariants.
            &[]
        } else {
            let this = self as *const CxxVector<T> as *mut CxxVector<T>;
            let ptr = unsafe { T::__get_unchecked(this, 0) };
            unsafe { slice::from_raw_parts(ptr, len) }
        }
    }

    /// Returns an iterator over elements of type `&T`.
    pub fn iter(&self) -> Iter<T> {
        Iter { v: self, index: 0 }
    }

    /// Returns an iterator over elements of type `Pin<&mut T>`.
    pub fn iter_mut(self: Pin<&mut Self>) -> IterMut<T> {
        IterMut { v: self, index: 0 }
    }
}

/// Iterator over elements of a `CxxVector` by shared reference.
///
/// The iterator element type is `&'a T`.
pub struct Iter<'a, T> {
    v: &'a CxxVector<T>,
    index: usize,
}

impl<'a, T> IntoIterator for &'a CxxVector<T>
where
    T: VectorElement,
{
    type Item = &'a T;
    type IntoIter = Iter<'a, T>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}

impl<'a, T> Iterator for Iter<'a, T>
where
    T: VectorElement,
{
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item> {
        let next = self.v.get(self.index)?;
        self.index += 1;
        Some(next)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.len();
        (len, Some(len))
    }
}

impl<'a, T> ExactSizeIterator for Iter<'a, T>
where
    T: VectorElement,
{
    fn len(&self) -> usize {
        self.v.len() - self.index
    }
}

impl<'a, T> FusedIterator for Iter<'a, T> where T: VectorElement {}

/// Iterator over elements of a `CxxVector` by pinned mutable reference.
///
/// The iterator element type is `Pin<&'a mut T>`.
pub struct IterMut<'a, T> {
    v: Pin<&'a mut CxxVector<T>>,
    index: usize,
}

impl<'a, T> IntoIterator for Pin<&'a mut CxxVector<T>>
where
    T: VectorElement,
{
    type Item = Pin<&'a mut T>;
    type IntoIter = IterMut<'a, T>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter_mut()
    }
}

impl<'a, T> Iterator for IterMut<'a, T>
where
    T: VectorElement,
{
    type Item = Pin<&'a mut T>;

    fn next(&mut self) -> Option<Self::Item> {
        let next = CxxVector::get_mut(self.v.as_mut(), self.index)?;
        self.index += 1;
        // Extend lifetime to allow simultaneous holding of nonoverlapping
        // elements, analogous to slice::split_first_mut.
        unsafe {
            let ptr = Pin::into_inner_unchecked(next) as *mut T;
            Some(Pin::new_unchecked(&mut *ptr))
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.len();
        (len, Some(len))
    }
}

impl<'a, T> ExactSizeIterator for IterMut<'a, T>
where
    T: VectorElement,
{
    fn len(&self) -> usize {
        self.v.len() - self.index
    }
}

impl<'a, T> FusedIterator for IterMut<'a, T> where T: VectorElement {}

impl<T> Debug for CxxVector<T>
where
    T: VectorElement + Debug,
{
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.debug_list().entries(self).finish()
    }
}

pub(crate) struct TypeName<T> {
    element: PhantomData<T>,
}

impl<T> TypeName<T> {
    pub const fn new() -> Self {
        TypeName {
            element: PhantomData,
        }
    }
}

impl<T> Display for TypeName<T>
where
    T: VectorElement,
{
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "CxxVector<{}>", T::__NAME)
    }
}

// Methods are private; not intended to be implemented outside of cxxbridge
// codebase.
#[doc(hidden)]
pub unsafe trait VectorElement: Sized {
    const __NAME: &'static dyn Display;
    fn __vector_size(v: &CxxVector<Self>) -> usize;
    unsafe fn __get_unchecked(v: *mut CxxVector<Self>, pos: usize) -> *mut Self;
    fn __unique_ptr_null() -> *mut c_void;
    unsafe fn __unique_ptr_raw(raw: *mut CxxVector<Self>) -> *mut c_void;
    unsafe fn __unique_ptr_get(repr: *mut c_void) -> *const CxxVector<Self>;
    unsafe fn __unique_ptr_release(repr: *mut c_void) -> *mut CxxVector<Self>;
    unsafe fn __unique_ptr_drop(repr: *mut c_void);
}

macro_rules! impl_vector_element {
    ($segment:expr, $name:expr, $ty:ty) => {
        const_assert_eq!(1, mem::align_of::<CxxVector<$ty>>());

        unsafe impl VectorElement for $ty {
            const __NAME: &'static dyn Display = &$name;
            fn __vector_size(v: &CxxVector<$ty>) -> usize {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$std$vector$", $segment, "$size")]
                        fn __vector_size(_: &CxxVector<$ty>) -> usize;
                    }
                }
                unsafe { __vector_size(v) }
            }
            unsafe fn __get_unchecked(v: *mut CxxVector<$ty>, pos: usize) -> *mut $ty {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$std$vector$", $segment, "$get_unchecked")]
                        fn __get_unchecked(_: *mut CxxVector<$ty>, _: usize) -> *mut $ty;
                    }
                }
                __get_unchecked(v, pos)
            }
            fn __unique_ptr_null() -> *mut c_void {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$null")]
                        fn __unique_ptr_null(this: *mut *mut c_void);
                    }
                }
                let mut repr = ptr::null_mut::<c_void>();
                unsafe { __unique_ptr_null(&mut repr) }
                repr
            }
            unsafe fn __unique_ptr_raw(raw: *mut CxxVector<Self>) -> *mut c_void {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$raw")]
                        fn __unique_ptr_raw(this: *mut *mut c_void, raw: *mut CxxVector<$ty>);
                    }
                }
                let mut repr = ptr::null_mut::<c_void>();
                __unique_ptr_raw(&mut repr, raw);
                repr
            }
            unsafe fn __unique_ptr_get(repr: *mut c_void) -> *const CxxVector<Self> {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$get")]
                        fn __unique_ptr_get(this: *const *mut c_void) -> *const CxxVector<$ty>;
                    }
                }
                __unique_ptr_get(&repr)
            }
            unsafe fn __unique_ptr_release(mut repr: *mut c_void) -> *mut CxxVector<Self> {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$release")]
                        fn __unique_ptr_release(this: *mut *mut c_void) -> *mut CxxVector<$ty>;
                    }
                }
                __unique_ptr_release(&mut repr)
            }
            unsafe fn __unique_ptr_drop(mut repr: *mut c_void) {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$drop")]
                        fn __unique_ptr_drop(this: *mut *mut c_void);
                    }
                }
                __unique_ptr_drop(&mut repr);
            }
        }
    };
}

macro_rules! impl_vector_element_for_primitive {
    ($ty:ident) => {
        impl_vector_element!(stringify!($ty), stringify!($ty), $ty);
    };
}

impl_vector_element_for_primitive!(u8);
impl_vector_element_for_primitive!(u16);
impl_vector_element_for_primitive!(u32);
impl_vector_element_for_primitive!(u64);
impl_vector_element_for_primitive!(usize);
impl_vector_element_for_primitive!(i8);
impl_vector_element_for_primitive!(i16);
impl_vector_element_for_primitive!(i32);
impl_vector_element_for_primitive!(i64);
impl_vector_element_for_primitive!(isize);
impl_vector_element_for_primitive!(f32);
impl_vector_element_for_primitive!(f64);

impl_vector_element!("string", "CxxString", CxxString);
<commit_msg>Work around conflict between CxxVector::get_mut and Pin::get_mut<commit_after>//! Less used details of `CxxVector` are exposed in this module. `CxxVector`
//! itself is exposed at the crate root.

use crate::extern_type::ExternType;
use crate::kind::Trivial;
use crate::string::CxxString;
use core::ffi::c_void;
use core::fmt::{self, Debug, Display};
use core::iter::FusedIterator;
use core::marker::{PhantomData, PhantomPinned};
use core::mem;
use core::pin::Pin;
use core::ptr;
use core::slice;

#[doc(inline)]
pub use crate::Vector;

/// Binding to C++ `std::vector<T, std::allocator<T>>`.
///
/// # Invariants
///
/// As an invariant of this API and the static analysis of the cxx::bridge
/// macro, in Rust code we can never obtain a `CxxVector` by value. Instead in
/// Rust code we will only ever look at a vector behind a reference or smart
/// pointer, as in `&CxxVector<T>` or `UniquePtr<CxxVector<T>>`.
#[repr(C, packed)]
pub struct CxxVector<T> {
    _private: [T; 0],
    _pinned: PhantomData<PhantomPinned>,
}

impl<T> CxxVector<T>
where
    T: VectorElement,
{
    /// Returns the number of elements in the vector.
    ///
    /// Matches the behavior of C++ [std::vector\<T\>::size][size].
    ///
    /// [size]: https://en.cppreference.com/w/cpp/container/vector/size
    pub fn len(&self) -> usize {
        T::__vector_size(self)
    }

    /// Returns true if the vector contains no elements.
    ///
    /// Matches the behavior of C++ [std::vector\<T\>::empty][empty].
    ///
    /// [empty]: https://en.cppreference.com/w/cpp/container/vector/empty
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns a reference to an element at the given position, or `None` if
    /// out of bounds.
    pub fn get(&self, pos: usize) -> Option<&T> {
        if pos < self.len() {
            Some(unsafe { self.get_unchecked(pos) })
        } else {
            None
        }
    }

    /// Returns a pinned mutable reference to an element at the given position,
    /// or `None` if out of bounds.
    pub fn index_mut(self: Pin<&mut Self>, pos: usize) -> Option<Pin<&mut T>> {
        if pos < self.len() {
            Some(unsafe { self.index_unchecked_mut(pos) })
        } else {
            None
        }
    }

    /// Returns a reference to an element without doing bounds checking.
    ///
    /// This is generally not recommended, use with caution! Calling this method
    /// with an out-of-bounds index is undefined behavior even if the resulting
    /// reference is not used.
    ///
    /// Matches the behavior of C++
    /// [std::vector\<T\>::operator\[\] const][operator_at].
    ///
    /// [operator_at]: https://en.cppreference.com/w/cpp/container/vector/operator_at
    pub unsafe fn get_unchecked(&self, pos: usize) -> &T {
        let this = self as *const CxxVector<T> as *mut CxxVector<T>;
        let ptr = T::__get_unchecked(this, pos) as *const T;
        &*ptr
    }

    /// Returns a pinned mutable reference to an element without doing bounds
    /// checking.
    ///
    /// This is generally not recommended, use with caution! Calling this method
    /// with an out-of-bounds index is undefined behavior even if the resulting
    /// reference is not used.
    ///
    /// Matches the behavior of C++
    /// [std::vector\<T\>::operator\[\]][operator_at].
    ///
    /// [operator_at]: https://en.cppreference.com/w/cpp/container/vector/operator_at
    pub unsafe fn index_unchecked_mut(self: Pin<&mut Self>, pos: usize) -> Pin<&mut T> {
        let ptr = T::__get_unchecked(self.get_unchecked_mut(), pos);
        Pin::new_unchecked(&mut *ptr)
    }

    /// Returns a slice to the underlying contiguous array of elements.
    pub fn as_slice(&self) -> &[T]
    where
        T: ExternType<Kind = Trivial>,
    {
        let len = self.len();
        if len == 0 {
            // The slice::from_raw_parts in the other branch requires a nonnull
            // and properly aligned data ptr. C++ standard does not guarantee
            // that data() on a vector with size 0 would return a nonnull
            // pointer or sufficiently aligned pointer, so using it would be
            // undefined behavior. Create our own empty slice in Rust instead
            // which upholds the invariants.
            &[]
        } else {
            let this = self as *const CxxVector<T> as *mut CxxVector<T>;
            let ptr = unsafe { T::__get_unchecked(this, 0) };
            unsafe { slice::from_raw_parts(ptr, len) }
        }
    }

    /// Returns an iterator over elements of type `&T`.
    pub fn iter(&self) -> Iter<T> {
        Iter { v: self, index: 0 }
    }

    /// Returns an iterator over elements of type `Pin<&mut T>`.
    pub fn iter_mut(self: Pin<&mut Self>) -> IterMut<T> {
        IterMut { v: self, index: 0 }
    }
}

/// Iterator over elements of a `CxxVector` by shared reference.
///
/// The iterator element type is `&'a T`.
pub struct Iter<'a, T> {
    v: &'a CxxVector<T>,
    index: usize,
}

impl<'a, T> IntoIterator for &'a CxxVector<T>
where
    T: VectorElement,
{
    type Item = &'a T;
    type IntoIter = Iter<'a, T>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}

impl<'a, T> Iterator for Iter<'a, T>
where
    T: VectorElement,
{
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item> {
        let next = self.v.get(self.index)?;
        self.index += 1;
        Some(next)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.len();
        (len, Some(len))
    }
}

impl<'a, T> ExactSizeIterator for Iter<'a, T>
where
    T: VectorElement,
{
    fn len(&self) -> usize {
        self.v.len() - self.index
    }
}

impl<'a, T> FusedIterator for Iter<'a, T> where T: VectorElement {}

/// Iterator over elements of a `CxxVector` by pinned mutable reference.
///
/// The iterator element type is `Pin<&'a mut T>`.
pub struct IterMut<'a, T> {
    v: Pin<&'a mut CxxVector<T>>,
    index: usize,
}

impl<'a, T> IntoIterator for Pin<&'a mut CxxVector<T>>
where
    T: VectorElement,
{
    type Item = Pin<&'a mut T>;
    type IntoIter = IterMut<'a, T>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter_mut()
    }
}

impl<'a, T> Iterator for IterMut<'a, T>
where
    T: VectorElement,
{
    type Item = Pin<&'a mut T>;

    fn next(&mut self) -> Option<Self::Item> {
        let next = self.v.as_mut().index_mut(self.index)?;
        self.index += 1;
        // Extend lifetime to allow simultaneous holding of nonoverlapping
        // elements, analogous to slice::split_first_mut.
        unsafe {
            let ptr = Pin::into_inner_unchecked(next) as *mut T;
            Some(Pin::new_unchecked(&mut *ptr))
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.len();
        (len, Some(len))
    }
}

impl<'a, T> ExactSizeIterator for IterMut<'a, T>
where
    T: VectorElement,
{
    fn len(&self) -> usize {
        self.v.len() - self.index
    }
}

impl<'a, T> FusedIterator for IterMut<'a, T> where T: VectorElement {}

impl<T> Debug for CxxVector<T>
where
    T: VectorElement + Debug,
{
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.debug_list().entries(self).finish()
    }
}

pub(crate) struct TypeName<T> {
    element: PhantomData<T>,
}

impl<T> TypeName<T> {
    pub const fn new() -> Self {
        TypeName {
            element: PhantomData,
        }
    }
}

impl<T> Display for TypeName<T>
where
    T: VectorElement,
{
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "CxxVector<{}>", T::__NAME)
    }
}

// Methods are private; not intended to be implemented outside of cxxbridge
// codebase.
#[doc(hidden)]
pub unsafe trait VectorElement: Sized {
    const __NAME: &'static dyn Display;
    fn __vector_size(v: &CxxVector<Self>) -> usize;
    unsafe fn __get_unchecked(v: *mut CxxVector<Self>, pos: usize) -> *mut Self;
    fn __unique_ptr_null() -> *mut c_void;
    unsafe fn __unique_ptr_raw(raw: *mut CxxVector<Self>) -> *mut c_void;
    unsafe fn __unique_ptr_get(repr: *mut c_void) -> *const CxxVector<Self>;
    unsafe fn __unique_ptr_release(repr: *mut c_void) -> *mut CxxVector<Self>;
    unsafe fn __unique_ptr_drop(repr: *mut c_void);
}

macro_rules! impl_vector_element {
    ($segment:expr, $name:expr, $ty:ty) => {
        const_assert_eq!(1, mem::align_of::<CxxVector<$ty>>());

        unsafe impl VectorElement for $ty {
            const __NAME: &'static dyn Display = &$name;
            fn __vector_size(v: &CxxVector<$ty>) -> usize {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$std$vector$", $segment, "$size")]
                        fn __vector_size(_: &CxxVector<$ty>) -> usize;
                    }
                }
                unsafe { __vector_size(v) }
            }
            unsafe fn __get_unchecked(v: *mut CxxVector<$ty>, pos: usize) -> *mut $ty {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$std$vector$", $segment, "$get_unchecked")]
                        fn __get_unchecked(_: *mut CxxVector<$ty>, _: usize) -> *mut $ty;
                    }
                }
                __get_unchecked(v, pos)
            }
            fn __unique_ptr_null() -> *mut c_void {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$null")]
                        fn __unique_ptr_null(this: *mut *mut c_void);
                    }
                }
                let mut repr = ptr::null_mut::<c_void>();
                unsafe { __unique_ptr_null(&mut repr) }
                repr
            }
            unsafe fn __unique_ptr_raw(raw: *mut CxxVector<Self>) -> *mut c_void {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$raw")]
                        fn __unique_ptr_raw(this: *mut *mut c_void, raw: *mut CxxVector<$ty>);
                    }
                }
                let mut repr = ptr::null_mut::<c_void>();
                __unique_ptr_raw(&mut repr, raw);
                repr
            }
            unsafe fn __unique_ptr_get(repr: *mut c_void) -> *const CxxVector<Self> {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$get")]
                        fn __unique_ptr_get(this: *const *mut c_void) -> *const CxxVector<$ty>;
                    }
                }
                __unique_ptr_get(&repr)
            }
            unsafe fn __unique_ptr_release(mut repr: *mut c_void) -> *mut CxxVector<Self> {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$release")]
                        fn __unique_ptr_release(this: *mut *mut c_void) -> *mut CxxVector<$ty>;
                    }
                }
                __unique_ptr_release(&mut repr)
            }
            unsafe fn __unique_ptr_drop(mut repr: *mut c_void) {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$drop")]
                        fn __unique_ptr_drop(this: *mut *mut c_void);
                    }
                }
                __unique_ptr_drop(&mut repr);
            }
        }
    };
}

macro_rules! impl_vector_element_for_primitive {
    ($ty:ident) => {
        impl_vector_element!(stringify!($ty), stringify!($ty), $ty);
    };
}

impl_vector_element_for_primitive!(u8);
impl_vector_element_for_primitive!(u16);
impl_vector_element_for_primitive!(u32);
impl_vector_element_for_primitive!(u64);
impl_vector_element_for_primitive!(usize);
impl_vector_element_for_primitive!(i8);
impl_vector_element_for_primitive!(i16);
impl_vector_element_for_primitive!(i32);
impl_vector_element_for_primitive!(i64);
impl_vector_element_for_primitive!(isize);
impl_vector_element_for_primitive!(f32);
impl_vector_element_for_primitive!(f64);

impl_vector_element!("string", "CxxString", CxxString);
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::cmp::Ord;
use std::sync::{RwLock, Arc};
use transaction::Transaction;
use error::{Error, ErrorKind, Result};

#[derive(Debug)]
pub struct Database<K, V>
    where K: Ord
{
    store: Arc<BTreeMap<K, V>>,
    txn_mut: RwLock<Transaction<K, V>>,
    closed: bool,
}

impl<K, V> Database<K, V>
    where K: Ord
{
    pub fn new() -> Result<Database<K, V>> {
        let store = Arc::new(BTreeMap::new());
        Ok(Database {
            store: store.clone(),
            txn_mut: RwLock::new(Transaction { store: store.clone() }),
            closed: false,
        })
    }

    pub fn read<F>(&self, f: F) -> Result<()>
        where F: Fn(&Transaction<K, V>) -> Result<()>
    {
        match self.txn_mut.read() {
            Ok(store) => f(&store),
            Err(_) => unreachable!(),
        }
    }

    pub fn update<F>(&self, f: F) -> Result<()>
        where F: Fn(&Transaction<K, V>) -> Result<()>
    {
        match self.txn_mut.write() {
            Ok(store) => f(&store),
            Err(_) => unreachable!(),
        }
    }

    pub fn close(&mut self) -> Result<()> {
        if self.closed {
            return Err(Error::new(ErrorKind::DataBaseClosed));
        }
        self.closed = true;
        Ok(())
    }
}

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

    #[test]
    fn test_new() {
        let db = Database::<String, String>::new().unwrap();
        assert_eq!(false, db.closed);
    }

    #[test]
    fn test_close() {
        let db = &mut Database::<String, String>::new().unwrap();
        assert!(db.close().is_ok());
        assert!(db.close().is_err());
        assert!(db.close().is_err());
    }

    #[test]
    fn test_read() {
        let db = &Database::<String, String>::new().unwrap();
        assert!(db.read(|txn| -> Result<()> {
            txn.get()
            Ok(())
        }).is_ok())
    }
}
<commit_msg>feat: read && update definition<commit_after>use std::collections::BTreeMap;
use std::cmp::Ord;
use std::sync::{RwLock, Arc};
use transaction::{Transaction, ReadTransaction, WriteTransaction};
use error::{Error, ErrorKind, Result};

#[derive(Debug)]
pub struct Database<K, V>
    where K: Ord
{
    store: Arc<BTreeMap<K, V>>,
    txn_mut: RwLock<Transaction<K, V>>,
    closed: bool,
}

impl<K, V> Database<K, V>
    where K: Ord
{
    pub fn new() -> Result<Database<K, V>> {
        let store = Arc::new(BTreeMap::new());
        Ok(Database {
            store: store.clone(),
            txn_mut: RwLock::new(Transaction { store: store.clone() }),
            closed: false,
        })
    }

    pub fn read<F>(&self, f: F) -> Result<()>
        where F: Fn(&Transaction<K, V>) -> Result<()>
    {
        match self.txn_mut.read() {
            Ok(store) => f(&*store),
            Err(_) => unreachable!(),
        }
    }

    pub fn update<F>(&self, f: F) -> Result<()>
        where F: Fn(&Transaction<K, V>) -> Result<()>
    {
        match self.txn_mut.write() {
            Ok(store) => f(&*store),
            Err(_) => unreachable!(),
        }
    }

    pub fn close(&mut self) -> Result<()> {
        if self.closed {
            return Err(Error::new(ErrorKind::DataBaseClosed));
        }
        self.closed = true;
        Ok(())
    }
}

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

    #[test]
    fn test_new() {
        let db = Database::<String, String>::new().unwrap();
        assert_eq!(false, db.closed);
    }

    #[test]
    fn test_close() {
        let db = &mut Database::<String, String>::new().unwrap();
        assert!(db.close().is_ok());
        assert!(db.close().is_err());
        assert!(db.close().is_err());
    }

    #[test]
    fn test_read() {
        let db = &Database::<&str, &str>::new().unwrap();
        assert!(db.read(&|txn: &Transaction<&str, &str>| -> Result<()> {
                assert!(txn.get("not exist").is_none());
                Ok(())
            })
            .is_ok())
    }
}
<|endoftext|>


<commit_before>use authorization::AuthorizationHeaderFactory;
use Bytes;
use client::GetResponse;
use hyper::client::Client;
use hyper::error::Error;
use hyper::header::{ByteRangeSpec, Headers, Range};
use pbr::{MultiBar, Pipe, ProgressBar, Units};
use response::CheckResponseStatus;
use std::cmp::min;
use std::io::Read;
use std::thread;
use std::time::{Instant, Duration};
use write::{OutputFileWriter, OutputChunkWriter};

/// Constant to represent the length of the buffer to download
/// the remote content
const DOWNLOAD_BUFFER_BYTES: usize = 1024 * 64;

/// Constant to represent the refresh interval (in milliseconds)
/// for the CLI
const PROGRESS_UPDATE_INTERVAL_MILLIS: u64 = 500;

/// Represents a range between two Bytes types
#[derive(Debug, PartialEq)]
struct RangeBytes(Bytes, Bytes);

/// Function to get the current chunk length, based on the chunk index.
fn get_chunk_length(chunk_index: u64,
                    content_length: Bytes,
                    global_chunk_length: Bytes)
                    -> Option<RangeBytes> {

    if content_length == 0 || global_chunk_length == 0 {
        return None;
    }

    let b_range: Bytes = chunk_index * global_chunk_length;

    if b_range >= (content_length - 1) {
        return None;
    }

    let e_range: Bytes = min(content_length - 1,
                             ((chunk_index + 1) * global_chunk_length) - 1);

    Some(RangeBytes(b_range, e_range))

}

/// Function to get the HTTP header to send to the file server, for a chunk (specified by its index)
fn get_header_from_index(chunk_index: u64,
                         content_length: Bytes,
                         global_chunk_length: Bytes)
                         -> Option<(Headers, RangeBytes)> {

    get_chunk_length(chunk_index, content_length, global_chunk_length).map(|range| {
        let mut header = Headers::new();
        header.set(Range::Bytes(vec![ByteRangeSpec::FromTo(range.0, range.1)]));
        (header, RangeBytes(range.0, range.1 - range.0))
    })
}

/// Function to get from the server the content of a chunk.
/// This function returns a Result type - Bytes if the content of the header is accessible, an Error type otherwise.
fn download_a_chunk(http_client: &Client,
                    http_header: Headers,
                    mut chunk_writer: OutputChunkWriter,
                    url: &str,
                    mpb: &mut ProgressBar<Pipe>)
                    -> Result<Bytes, Error> {

    let mut body = http_client.get_http_response_using_headers(url, http_header).unwrap();
    if !body.check_partialcontent_status() {
        return Err(Error::Status);
    }
    let mut bytes_buffer = [0; DOWNLOAD_BUFFER_BYTES];
    let mut sum_bytes = 0;

    let progress_update_interval = Duration::from_millis(PROGRESS_UPDATE_INTERVAL_MILLIS);
    let mut last_progress_bytes = 0;
    let mut last_progress_time = Instant::now() - progress_update_interval;

    while let Ok(n) = body.read(&mut bytes_buffer) {
        if n == 0 {
            return Ok(sum_bytes);
        }

        chunk_writer.write(sum_bytes, &bytes_buffer[0..n]);

        sum_bytes += n as u64;

        // Update the CLI
        if Instant::now().duration_since(last_progress_time) > progress_update_interval {
            last_progress_time = Instant::now();
            let progress_bytes_delta = sum_bytes - last_progress_bytes;
            last_progress_bytes = sum_bytes;
            mpb.add(progress_bytes_delta);
        }
    }
    mpb.add(sum_bytes - last_progress_bytes);
    return Ok(0u64);
}

/// Function to download each chunk of a remote content (given by its URL).
/// This function takes as parameters:
/// * the remote content length,
/// * a mutable reference to share between threads, which contains each chunk,
/// * the number of chunks that contains the remote content,
/// * the URL of the remote content server,
/// * a custom authorization to access and download the remote content.
pub fn download_chunks(content_length: Bytes,
                       mut out_file: OutputFileWriter,
                       nb_chunks: u64,
                       url: &str,
                       authorization_header_factory: Option<AuthorizationHeaderFactory>) {

    // let mut downloaded_chunks: Arc<Mutex<Chunks>> =
    //     Arc::new(Mutex::new(Chunks::with_capacity(nb_chunks as usize)));
    let global_chunk_length: u64 = (content_length / nb_chunks) + 1;
    let mut jobs = vec![];

    let mut mpb = MultiBar::new();
    mpb.println(&format!("Downloading {} chunks: ", nb_chunks));

    for chunk_index in 0..nb_chunks {

        let (mut http_header, RangeBytes(chunk_offset, chunk_length)) =
            get_header_from_index(chunk_index, content_length, global_chunk_length).unwrap();
        let hyper_client = Client::new();
        let url_clone = String::from(url);
        if let Some(auth_header_factory) = authorization_header_factory.clone() {
            http_header.set(auth_header_factory.build_header());
        }

        // Progress bar customization
        let mut mp = mpb.create_bar(chunk_length);
        mp.tick_format("▏▎▍▌▋▊▉██▉▊▋▌▍▎▏");
        mp.format("|#--|");
        mp.show_tick = true;
        mp.show_speed = true;
        mp.show_percent = true;
        mp.show_counter = false;
        mp.show_time_left = true;
        mp.set_units(Units::Bytes);
        mp.message(&format!("Chunk {} ", chunk_index));

        let chunk_writer = out_file.get_chunk_writer(chunk_offset);
        jobs.push(thread::spawn(move || match download_a_chunk(&hyper_client,
                                                                    http_header,
                                                                    chunk_writer,
                                                                    &url_clone,
                                                                    &mut mp) {
            Ok(bytes_written) => {
                mp.finish();
                if bytes_written == 0 {
                    panic!("The downloaded chunk {} is empty", chunk_index);
                }
            }
            Err(error) => {
                mp.finish();
                panic!("Cannot download the chunk {}, due to error {}",
                       chunk_index,
                       error);
            }
        }));
    }

    mpb.listen();

    for child in jobs {
        let _ = child.join();
    }

}

#[cfg(test)]
mod test_chunk_length {

    use super::get_chunk_length;
    use super::RangeBytes;

    #[test]
    fn wrong_content_length_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 15, 0));
    }

    #[test]
    fn wrong_global_chunk_length_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 0, 15));
    }

    #[test]
    fn wrong_length_parameters_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 0, 0));
    }

    #[test]
    fn get_the_first_range_in_chunk() {
        assert_eq!(Some(RangeBytes(0, 249)), get_chunk_length(0, 1000, 250));
    }

    #[test]
    fn get_the_last_range_in_chunk() {
        assert_eq!(Some(RangeBytes(750, 999)), get_chunk_length(3, 1000, 250));
    }

    #[test]
    fn get_the_last_range_in_shorten_chunk() {
        assert_eq!(Some(RangeBytes(750, 997)), get_chunk_length(3, 998, 250));
    }

    #[test]
    fn wrong_index_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(4, 1000, 250));
    }

}

#[cfg(test)]
mod test_header {

    use super::{get_header_from_index, RangeBytes};
    use hyper::header::{ByteRangeSpec, Headers, Range};

    #[test]
    fn wrong_chunk_length_should_return_none() {
        assert_eq!(None, get_header_from_index(0, 0, 0));
    }

    #[test]
    fn good_chunk_length_should_return_a_good_header() {
        let mut test_header = Headers::new();
        test_header.set(Range::Bytes(vec![ByteRangeSpec::FromTo(750, 997)]));
        assert_eq!(Some((test_header, RangeBytes(750, 247))),
                   get_header_from_index(3, 998, 250));
    }

}
<commit_msg>Extern. MultiBar object initialization<commit_after>use authorization::AuthorizationHeaderFactory;
use Bytes;
use client::GetResponse;
use hyper::client::Client;
use hyper::error::Error;
use hyper::header::{ByteRangeSpec, Headers, Range};
use pbr::{MultiBar, Pipe, ProgressBar, Units};
use response::CheckResponseStatus;
use std::cmp::min;
use std::io::Read;
use std::thread;
use std::time::{Instant, Duration};
use write::{OutputFileWriter, OutputChunkWriter};

/// Constant to represent the length of the buffer to download
/// the remote content
const DOWNLOAD_BUFFER_BYTES: usize = 1024 * 64;

/// Constant to represent the refresh interval (in milliseconds)
/// for the CLI
const PROGRESS_UPDATE_INTERVAL_MILLIS: u64 = 500;

/// Represents a range between two Bytes types
#[derive(Debug, PartialEq)]
struct RangeBytes(Bytes, Bytes);

macro_rules! initbar {
    ($mp:ident,$mpb:ident,$length:expr,$index:expr) => {
        let mut $mp = $mpb.create_bar($length);
        $mp.tick_format("▏▎▍▌▋▊▉██▉▊▋▌▍▎▏");
        $mp.format("|#--|");
        $mp.show_tick = true;
        $mp.show_speed = true;
        $mp.show_percent = true;
        $mp.show_counter = false;
        $mp.show_time_left = true;
        $mp.set_units(Units::Bytes);
        $mp.message(&format!("Chunk {} ", $index));
    }
}

/// Function to get the current chunk length, based on the chunk index.
fn get_chunk_length(chunk_index: u64,
                    content_length: Bytes,
                    global_chunk_length: Bytes)
                    -> Option<RangeBytes> {

    if content_length == 0 || global_chunk_length == 0 {
        return None;
    }

    let b_range: Bytes = chunk_index * global_chunk_length;

    if b_range >= (content_length - 1) {
        return None;
    }

    let e_range: Bytes = min(content_length - 1,
                             ((chunk_index + 1) * global_chunk_length) - 1);

    Some(RangeBytes(b_range, e_range))

}

/// Function to get the HTTP header to send to the file server, for a chunk (specified by its index)
fn get_header_from_index(chunk_index: u64,
                         content_length: Bytes,
                         global_chunk_length: Bytes)
                         -> Option<(Headers, RangeBytes)> {

    get_chunk_length(chunk_index, content_length, global_chunk_length).map(|range| {
        let mut header = Headers::new();
        header.set(Range::Bytes(vec![ByteRangeSpec::FromTo(range.0, range.1)]));
        (header, RangeBytes(range.0, range.1 - range.0))
    })
}

/// Function to get from the server the content of a chunk.
/// This function returns a Result type - Bytes if the content of the header is accessible, an Error type otherwise.
fn download_a_chunk(http_client: &Client,
                    http_header: Headers,
                    mut chunk_writer: OutputChunkWriter,
                    url: &str,
                    mpb: &mut ProgressBar<Pipe>)
                    -> Result<Bytes, Error> {

    let mut body = http_client.get_http_response_using_headers(url, http_header).unwrap();
    if !body.check_partialcontent_status() {
        return Err(Error::Status);
    }
    let mut bytes_buffer = [0; DOWNLOAD_BUFFER_BYTES];
    let mut sum_bytes = 0;

    let progress_update_interval = Duration::from_millis(PROGRESS_UPDATE_INTERVAL_MILLIS);
    let mut last_progress_bytes = 0;
    let mut last_progress_time = Instant::now() - progress_update_interval;

    while let Ok(n) = body.read(&mut bytes_buffer) {
        if n == 0 {
            return Ok(sum_bytes);
        }

        chunk_writer.write(sum_bytes, &bytes_buffer[0..n]);

        sum_bytes += n as u64;

        // Update the CLI
        if Instant::now().duration_since(last_progress_time) > progress_update_interval {
            last_progress_time = Instant::now();
            let progress_bytes_delta = sum_bytes - last_progress_bytes;
            last_progress_bytes = sum_bytes;
            mpb.add(progress_bytes_delta);
        }
    }
    mpb.add(sum_bytes - last_progress_bytes);
    return Ok(0u64);
}

/// Function to download each chunk of a remote content (given by its URL).
/// This function takes as parameters:
/// * the remote content length,
/// * a mutable reference to share between threads, which contains each chunk,
/// * the number of chunks that contains the remote content,
/// * the URL of the remote content server,
/// * a custom authorization to access and download the remote content.
pub fn download_chunks(content_length: Bytes,
                       mut out_file: OutputFileWriter,
                       nb_chunks: u64,
                       url: &str,
                       authorization_header_factory: Option<AuthorizationHeaderFactory>) {

    // let mut downloaded_chunks: Arc<Mutex<Chunks>> =
    //     Arc::new(Mutex::new(Chunks::with_capacity(nb_chunks as usize)));
    let global_chunk_length: u64 = (content_length / nb_chunks) + 1;
    let mut jobs = vec![];

    let mut mpb = MultiBar::new();
    mpb.println(&format!("Downloading {} chunks: ", nb_chunks));

    for chunk_index in 0..nb_chunks {

        let (mut http_header, RangeBytes(chunk_offset, chunk_length)) =
            get_header_from_index(chunk_index, content_length, global_chunk_length).unwrap();
        let hyper_client = Client::new();
        let url_clone = String::from(url);
        if let Some(auth_header_factory) = authorization_header_factory.clone() {
            http_header.set(auth_header_factory.build_header());
        }

        // Initialize the progress bar for that chunk
        initbar!(mp, mpb, chunk_length, chunk_index);

        let chunk_writer = out_file.get_chunk_writer(chunk_offset);
        jobs.push(thread::spawn(move || match download_a_chunk(&hyper_client,
                                                                    http_header,
                                                                    chunk_writer,
                                                                    &url_clone,
                                                                    &mut mp) {
            Ok(bytes_written) => {
                mp.finish();
                if bytes_written == 0 {
                    panic!("The downloaded chunk {} is empty", chunk_index);
                }
            }
            Err(error) => {
                mp.finish();
                panic!("Cannot download the chunk {}, due to error {}",
                       chunk_index,
                       error);
            }
        }));
    }

    mpb.listen();

    for child in jobs {
        let _ = child.join();
    }

}

#[cfg(test)]
mod test_chunk_length {

    use super::get_chunk_length;
    use super::RangeBytes;

    #[test]
    fn wrong_content_length_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 15, 0));
    }

    #[test]
    fn wrong_global_chunk_length_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 0, 15));
    }

    #[test]
    fn wrong_length_parameters_should_return_none() {
        assert_eq!(None, get_chunk_length(0, 0, 0));
    }

    #[test]
    fn get_the_first_range_in_chunk() {
        assert_eq!(Some(RangeBytes(0, 249)), get_chunk_length(0, 1000, 250));
    }

    #[test]
    fn get_the_last_range_in_chunk() {
        assert_eq!(Some(RangeBytes(750, 999)), get_chunk_length(3, 1000, 250));
    }

    #[test]
    fn get_the_last_range_in_shorten_chunk() {
        assert_eq!(Some(RangeBytes(750, 997)), get_chunk_length(3, 998, 250));
    }

    #[test]
    fn wrong_index_parameter_should_return_none() {
        assert_eq!(None, get_chunk_length(4, 1000, 250));
    }

}

#[cfg(test)]
mod test_header {

    use super::{get_header_from_index, RangeBytes};
    use hyper::header::{ByteRangeSpec, Headers, Range};

    #[test]
    fn wrong_chunk_length_should_return_none() {
        assert_eq!(None, get_header_from_index(0, 0, 0));
    }

    #[test]
    fn good_chunk_length_should_return_a_good_header() {
        let mut test_header = Headers::new();
        test_header.set(Range::Bytes(vec![ByteRangeSpec::FromTo(750, 997)]));
        assert_eq!(Some((test_header, RangeBytes(750, 247))),
                   get_header_from_index(3, 998, 250));
    }

}
<|endoftext|>


<commit_before>use std::iter;
use super::stacks_and_queues::bag::{Bag, Iter};
use super::stacks_and_queues::Stack;
use super::stacks_and_queues::linked_stack;

#[derive(Clone, Debug)]
pub struct Graph {
    v: usize,
    e: usize,
    adj: Vec<Bag<usize>>
}

impl Graph {
    pub fn new(v: usize) -> Graph {
        Graph {
            v: v,
            e: 0,
            adj: iter::repeat(Bag::<usize>::new()).take(v).collect()
        }
    }

    fn validate_vertex(&self, v: usize) {
        assert!(v < self.v, "vertex is not between 0 and {}", self.v - 1)
    }

    pub fn vertices(&self) -> usize {
        self.v
    }

    pub fn edges(&self) -> usize {
        self.e
    }

    pub fn add_edge(&mut self, v: usize, w: usize) {
        self.validate_vertex(v);
        self.validate_vertex(w);

        self.e += 1;
        self.adj[v].add(w);
        self.adj[w].add(v);
    }

    // FIXME: should this be a global function
    pub fn degree(&self, v: usize) -> usize {
        self.validate_vertex(v);
        self.adj[v].len()
    }

    pub fn max_degree(&self) -> usize {
        (0 .. self.vertices()).map(|v| self.degree(v)).max().unwrap_or(0)
    }

    pub fn average_degree(&self) -> f64 {
        // (0 .. self.vertices()) .map(|v| self.degree(v)).sum::<usize>() as f64 / self.vertices() as f64
        2.0 * self.edges() as f64 / self.vertices() as f64
    }

    pub fn number_of_self_loops(&self) -> usize {
        let mut count = 0;
        for v in 0 .. self.vertices() {
            for w in self.adj(v) {
                if v == *w {
                    count += 1;
                }
            }
        }
        count / 2
    }

    pub fn to_dot(&self) -> String {
        let mut dot = String::new();

        dot.push_str("graph G {\n");
        for i in 0 .. self.v {
            dot.push_str(&format!("  {};\n", i));
        }

        for (v, adj) in self.adj.iter().enumerate() {
            for w in adj.iter() {
                dot.push_str(&format!("  {} -- {};\n", v, w));
            }
        }
        dot.push_str("}\n");
        dot
    }

    pub fn adj(&self, v: usize) -> Iter<usize> {
        self.adj[v].iter()
    }

    pub fn dfs<'a>(&'a self, s: usize) -> DepthFirstPaths<'a> {
        let marked = iter::repeat(false).take(self.vertices()).collect();
        let edge_to = iter::repeat(None).take(self.vertices()).collect();
        let mut path = DepthFirstPaths {
            graph: self,
            marked: marked,
            edge_to: edge_to,
            s: s
        };
        let s = path.s.clone();

        path.dfs(s);
        path
    }
}

pub struct DepthFirstPaths<'a> {
    graph: &'a Graph,
    marked: Vec<bool>,
    edge_to: Vec<Option<usize>>,
    s: usize
}

impl<'a> DepthFirstPaths<'a> {
    pub fn dfs(&mut self, v: usize) {
        self.marked[v] = true;
        for w in self.graph.adj(v) {
            if !self.marked[*w] {
                self.dfs(*w);
                self.edge_to[*w] = Some(v);
            }
        }
    }

    pub fn has_path_to(&self, v: usize) -> bool {
        self.marked[v]
    }

    pub fn path_to(&self, v: usize) -> Option<Vec<usize>> {
        if !self.has_path_to(v) {
            None
        } else {
            let mut path = linked_stack::LinkedStack::new();
            let mut x = v;
            while x != self.s {
                path.push(x);
                x = self.edge_to[x].unwrap();
            }
            path.push(self.s);
            Some(path.into_iter().collect())
        }
    }
}

#[test]
fn test_graph_visit() {
    let mut g = Graph::new(13);
    g.add_edge(0, 1);
    g.add_edge(0, 2);
    g.add_edge(0, 6);
    g.add_edge(0, 5);
    g.add_edge(5, 3);
    g.add_edge(5, 4);
    g.add_edge(3, 4);
    g.add_edge(4, 6);

    g.add_edge(7, 8);

    g.add_edge(9, 10);
    g.add_edge(9, 11);
    g.add_edge(9, 12);
    g.add_edge(11, 12);

    println!("dot => \n {}", g.to_dot());
    let path = g.dfs(0);
    assert!(path.path_to(3).is_some());

}

#[test]
fn test_graph() {
    let mut g = Graph::new(10);
    g.add_edge(0, 3);
    g.add_edge(0, 5);
    g.add_edge(4, 5);
    g.add_edge(2, 9);
    g.add_edge(2, 8);
    g.add_edge(3, 7);

    g.add_edge(1, 6);
    g.add_edge(6, 9);
    g.add_edge(5, 8);

    // println!("got => \n{}", g.to_dot());

    assert_eq!(10, g.vertices());
    assert_eq!(9, g.edges());
    assert_eq!(3, g.degree(5));

    for w in g.adj(5) {
        assert!(vec![8, 4, 0].contains(w));
    }

    assert_eq!(g.max_degree(), 3);
    assert!(g.average_degree() < 2.0);
    assert_eq!(g.number_of_self_loops(), 0);
}

#[test]
fn test_graph_functions() {
    let mut g = Graph::new(5);
    for i in 0 .. 5 {
        for j in 0 .. 5 {
            g.add_edge(i, j);
        }
    }

    assert_eq!(10, g.max_degree());
    assert_eq!(5, g.number_of_self_loops());
}
<commit_msg>undirected_graphs: add bfs search for Graph, refactor search path<commit_after>use std::iter;
use super::stacks_and_queues::bag::{Bag, Iter};
use super::stacks_and_queues::{Stack, Queue};
use super::stacks_and_queues::linked_stack;
use super::stacks_and_queues::resizing_array_queue::ResizingArrayQueue;

#[derive(Clone, Debug)]
pub struct Graph {
    v: usize,
    e: usize,
    adj: Vec<Bag<usize>>
}

impl Graph {
    pub fn new(v: usize) -> Graph {
        Graph {
            v: v,
            e: 0,
            adj: iter::repeat(Bag::<usize>::new()).take(v).collect()
        }
    }

    fn validate_vertex(&self, v: usize) {
        assert!(v < self.v, "vertex is not between 0 and {}", self.v - 1)
    }

    pub fn vertices(&self) -> usize {
        self.v
    }

    pub fn edges(&self) -> usize {
        self.e
    }

    pub fn add_edge(&mut self, v: usize, w: usize) {
        self.validate_vertex(v);
        self.validate_vertex(w);

        self.e += 1;
        self.adj[v].add(w);
        self.adj[w].add(v);
    }

    // FIXME: should this be a global function
    pub fn degree(&self, v: usize) -> usize {
        self.validate_vertex(v);
        self.adj[v].len()
    }

    pub fn max_degree(&self) -> usize {
        (0 .. self.vertices()).map(|v| self.degree(v)).max().unwrap_or(0)
    }

    pub fn average_degree(&self) -> f64 {
        // (0 .. self.vertices()) .map(|v| self.degree(v)).sum::<usize>() as f64 / self.vertices() as f64
        2.0 * self.edges() as f64 / self.vertices() as f64
    }

    pub fn number_of_self_loops(&self) -> usize {
        let mut count = 0;
        for v in 0 .. self.vertices() {
            for w in self.adj(v) {
                if v == *w {
                    count += 1;
                }
            }
        }
        count / 2
    }

    pub fn to_dot(&self) -> String {
        let mut dot = String::new();

        dot.push_str("graph G {\n");
        for i in 0 .. self.v {
            dot.push_str(&format!("  {};\n", i));
        }

        for (v, adj) in self.adj.iter().enumerate() {
            for w in adj.iter() {
                dot.push_str(&format!("  {} -- {};\n", v, w));
            }
        }
        dot.push_str("}\n");
        dot
    }

    pub fn adj(&self, v: usize) -> Iter<usize> {
        self.adj[v].iter()
    }

    pub fn dfs<'a>(&'a self, s: usize) -> SearchPaths<'a> {
        let mut path = SearchPaths::new(self, s);
        path.dfs(s);
        path
    }

    pub fn bfs<'a>(&'a self, s: usize) -> SearchPaths<'a> {
        let mut path = SearchPaths::new(self, s);
        path.bfs(s);
        path
    }
}

pub struct SearchPaths<'a> {
    graph: &'a Graph,
    marked: Vec<bool>,
    edge_to: Vec<Option<usize>>,
    s: usize
}

impl<'a> SearchPaths<'a> {
    fn new<'b>(graph: &'b Graph, s: usize) -> SearchPaths<'b> {
        let marked = iter::repeat(false).take(graph.vertices()).collect();
        let edge_to = iter::repeat(None).take(graph.vertices()).collect();
        SearchPaths {
            graph: graph,
            marked: marked,
            edge_to: edge_to,
            s: s
        }
    }

    fn dfs(&mut self, v: usize) {
        self.marked[v] = true;
        for w in self.graph.adj(v) {
            if !self.marked[*w] {
                self.dfs(*w);
                self.edge_to[*w] = Some(v);
            }
        }
    }

    fn bfs(&mut self, s: usize) {
        let mut q = ResizingArrayQueue::new();
        q.enqueue(s);
        self.marked[s] = true;
        while !q.is_empty() {
            let v = q.dequeue().unwrap();
            for w in self.graph.adj(v) {
                if !self.marked[*w] {
                    self.edge_to[*w] = Some(v);
                    q.enqueue(*w);
                    self.marked[*w] = true;
                }
            }
        }
    }

    pub fn has_path_to(&self, v: usize) -> bool {
        self.marked[v]
    }

    pub fn path_to(&self, v: usize) -> Option<Vec<usize>> {
        if !self.has_path_to(v) {
            None
        } else {
            let mut path = linked_stack::LinkedStack::new();
            let mut x = v;
            while x != self.s {
                path.push(x);
                x = self.edge_to[x].unwrap();
            }
            path.push(self.s);
            Some(path.into_iter().collect())
        }
    }
}

#[test]
fn test_graph_visit() {
    let mut g = Graph::new(13);
    g.add_edge(0, 1);
    g.add_edge(0, 2);
    g.add_edge(0, 6);
    g.add_edge(0, 5);
    g.add_edge(5, 3);
    g.add_edge(5, 4);
    g.add_edge(3, 4);
    g.add_edge(4, 6);

    g.add_edge(7, 8);

    g.add_edge(9, 10);
    g.add_edge(9, 11);
    g.add_edge(9, 12);
    g.add_edge(11, 12);

    println!("dot => \n {}", g.to_dot());
    assert_eq!(format!("{:?}", g.dfs(0).path_to(3).unwrap()), "[0, 5, 4, 3]");
    assert_eq!(format!("{:?}", g.bfs(0).path_to(3).unwrap()), "[0, 5, 3]");
}

#[test]
fn test_graph() {
    let mut g = Graph::new(10);
    g.add_edge(0, 3);
    g.add_edge(0, 5);
    g.add_edge(4, 5);
    g.add_edge(2, 9);
    g.add_edge(2, 8);
    g.add_edge(3, 7);

    g.add_edge(1, 6);
    g.add_edge(6, 9);
    g.add_edge(5, 8);

    // println!("got => \n{}", g.to_dot());

    assert_eq!(10, g.vertices());
    assert_eq!(9, g.edges());
    assert_eq!(3, g.degree(5));

    for w in g.adj(5) {
        assert!(vec![8, 4, 0].contains(w));
    }

    assert_eq!(g.max_degree(), 3);
    assert!(g.average_degree() < 2.0);
    assert_eq!(g.number_of_self_loops(), 0);
}

#[test]
fn test_graph_functions() {
    let mut g = Graph::new(5);
    for i in 0 .. 5 {
        for j in 0 .. 5 {
            g.add_edge(i, j);
        }
    }

    assert_eq!(10, g.max_degree());
    assert_eq!(5, g.number_of_self_loops());
}
<|endoftext|>


<commit_before>/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Alex Lyon <arcterus@mail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

// #[macro_export]
// macro_rules! main { ($($arg:tt)+) => ({
//     extern crate uu_arch;
//     use std::io::Write;
//     use uu_arch::uumain;

//     fn main() {
//         uucore::panic::install_sigpipe_hook();

//         let code = uumain(uucore::args().collect());
//         // Since stdout is line-buffered by default, we need to ensure any pending
//         // writes are flushed before exiting. Ideally, this should be enforced by
//         // each utility.
//         //
//         // See: https://github.com/rust-lang/rust/issues/23818
//         //
//         std::io::stdout().flush().expect("could not flush stdout");
//         std::process::exit(code);
//     }
// })}

// extern crate proc_macro;
// use proc_macro::TokenStream;
// #[proc_macro_attribute]
// pub fn hello(attr: TokenStream, item: TokenStream) -> TokenStream {
//     let result = quote! {
//         fn main() {
//             uucore::panic::install_sigpipe_hook();
//             std::io::stdout().flush().expect("could not flush stdout");
//             std::process::exit(code);
//         }
//     };
// }

#[macro_export]
macro_rules! executable(
    () => ({
        let module = module_path!();
        let module = module.split("::").next().unwrap_or(module);
        if &module[0..3] == "uu_" {
            &module[3..]
        } else {
            module
        }
    })
);

#[macro_export]
macro_rules! show_error(
    ($($args:tt)+) => ({
        eprint!("{}: error: ", executable!());
        eprintln!($($args)+);
    })
);

#[macro_export]
macro_rules! show_warning(
    ($($args:tt)+) => ({
        eprint!("{}: warning: ", executable!());
        eprintln!($($args)+);
    })
);

#[macro_export]
macro_rules! show_info(
    ($($args:tt)+) => ({
        eprint!("{}: ", executable!());
        eprintln!($($args)+);
    })
);

#[macro_export]
macro_rules! disp_err(
    ($($args:tt)+) => ({
        eprint!("{}: ", executable!());
        eprintln!($($args)+);
        eprintln!("Try '{} --help' for more information.", executable!());
    })
);

#[macro_export]
macro_rules! crash(
    ($exitcode:expr, $($args:tt)+) => ({
        show_error!($($args)+);
        ::std::process::exit($exitcode)
    })
);

#[macro_export]
macro_rules! exit(
    ($exitcode:expr) => ({
        ::std::process::exit($exitcode)
    })
);

#[macro_export]
macro_rules! crash_if_err(
    ($exitcode:expr, $exp:expr) => (
        match $exp {
            Ok(m) => m,
            Err(f) => crash!($exitcode, "{}", f),
        }
    )
);

#[macro_export]
macro_rules! return_if_err(
    ($exitcode:expr, $exp:expr) => (
        match $exp {
            Ok(m) => m,
            Err(f) => {
                show_error!("{}", f);
                return $exitcode;
            }
        }
    )
);

#[macro_export]
macro_rules! safe_write(
    ($fd:expr, $($args:tt)+) => (
        match write!($fd, $($args)+) {
            Ok(_) => {}
            Err(f) => panic!(f.to_string())
        }
    )
);

#[macro_export]
macro_rules! safe_writeln(
    ($fd:expr, $($args:tt)+) => (
        match writeln!($fd, $($args)+) {
            Ok(_) => {}
            Err(f) => panic!(f.to_string())
        }
    )
);

#[macro_export]
macro_rules! safe_unwrap(
    ($exp:expr) => (
        match $exp {
            Ok(m) => m,
            Err(f) => crash!(1, "{}", f.to_string())
        }
    )
);

//-- message templates

//-- message templates : general

#[macro_export]
macro_rules! snippet_list_join_oxford {
    ($conjunction:expr, $valOne:expr, $valTwo:expr) => (
        format!("{}, {} {}", $valOne, $conjunction, $valTwo)
    );
    ($conjunction:expr, $valOne:expr, $valTwo:expr $(, $remainingVals:expr)*) => (
        format!("{}, {}", $valOne, snippet_list_join_inner!($conjunction, $valTwo $(, $remainingVals)*))
    );
}

#[macro_export]
macro_rules! snippet_list_join_or {
    ($valOne:expr, $valTwo:expr) => (
        format!("{} or {}", $valOne, $valTwo)
    );
    ($valOne:expr, $valTwo:expr $(, $remainingVals:expr)*) => (
        format!("{}, {}", $valOne, snippet_list_join_oxford!("or", $valTwo $(, $remainingVals)*))
    );
}

//-- message templates : invalid input

#[macro_export]
macro_rules! msg_invalid_input {
    ($reason: expr) => {
        format!("invalid input: {}", $reason)
    };
}

#[macro_export]
macro_rules! snippet_no_file_at_path {
    ($path:expr) => {
        format!("nonexistent path {}", $path)
    };
}

// -- message templates : invalid input : flag

#[macro_export]
macro_rules! msg_invalid_opt_use {
    ($about:expr, $flag:expr) => {
        msg_invalid_input!(format!("The '{}' option {}", $flag, $about))
    };
    ($about:expr, $longflag:expr, $shortflag:expr) => {
        msg_invalid_input!(format!(
            "The '{}' ('{}') option {}",
            $longflag, $shortflag, $about
        ))
    };
}

#[macro_export]
macro_rules! msg_opt_only_usable_if {
    ($clause:expr, $flag:expr) => {
        msg_invalid_opt_use!(format!("only usable if {}", $clause), $flag)
    };
    ($clause:expr, $longflag:expr, $shortflag:expr) => {
        msg_invalid_opt_use!(format!("only usable if {}", $clause), $longflag, $shortflag)
    };
}

#[macro_export]
macro_rules! msg_opt_invalid_should_be {
    ($expects:expr, $received:expr, $flag:expr) => {
        msg_invalid_opt_use!(
            format!("expects {}, but was provided {}", $expects, $received),
            $flag
        )
    };
    ($expects:expr, $received:expr, $longflag:expr, $shortflag:expr) => {
        msg_invalid_opt_use!(
            format!("expects {}, but was provided {}", $expects, $received),
            $longflag,
            $shortflag
        )
    };
}

// -- message templates : invalid input : args

#[macro_export]
macro_rules! msg_arg_invalid_value {
    ($expects:expr, $received:expr) => {
        msg_invalid_input!(format!(
            "expects its argument to be {}, but was provided {}",
            $expects, $received
        ))
    };
}

#[macro_export]
macro_rules! msg_args_invalid_value {
    ($expects:expr, $received:expr) => {
        msg_invalid_input!(format!(
            "expects its arguments to be {}, but was provided {}",
            $expects, $received
        ))
    };
    ($msg:expr) => {
        msg_invalid_input!($msg)
    };
}

#[macro_export]
macro_rules! msg_args_nonexistent_file {
    ($received:expr) => {
        msg_args_invalid_value!("paths to files", snippet_no_file_at_path!($received))
    };
}

#[macro_export]
macro_rules! msg_wrong_number_of_arguments {
    () => {
        msg_args_invalid_value!("wrong number of arguments")
    };
    ($min:expr, $max:expr) => {
        msg_args_invalid_value!(format!("expects {}-{} arguments", $min, $max))
    };
    ($exact:expr) => {
        if $exact == 1 {
            msg_args_invalid_value!("expects 1 argument")
        } else {
            msg_args_invalid_value!(format!("expects {} arguments", $exact))
        }
    };
}

// -- message templates : invalid input : input combinations

#[macro_export]
macro_rules! msg_expects_one_of {
    ($valOne:expr $(, $remainingVals:expr)*) => (
        msg_invalid_input!(format!("expects one of {}", snippet_list_join_or!($valOne $(, $remainingVals)*)))
    );
}

#[macro_export]
macro_rules! msg_expects_no_more_than_one_of {
    ($valOne:expr $(, $remainingVals:expr)*) => (
        msg_invalid_input!(format!("expects no more than one of {}", snippet_list_join_or!($valOne $(, $remainingVals)*))) ;
    );
}
<commit_msg>change/API! ~ `disp_err!()` => `show_usage_error!()`<commit_after>/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Alex Lyon <arcterus@mail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

// #[macro_export]
// macro_rules! main { ($($arg:tt)+) => ({
//     extern crate uu_arch;
//     use std::io::Write;
//     use uu_arch::uumain;

//     fn main() {
//         uucore::panic::install_sigpipe_hook();

//         let code = uumain(uucore::args().collect());
//         // Since stdout is line-buffered by default, we need to ensure any pending
//         // writes are flushed before exiting. Ideally, this should be enforced by
//         // each utility.
//         //
//         // See: https://github.com/rust-lang/rust/issues/23818
//         //
//         std::io::stdout().flush().expect("could not flush stdout");
//         std::process::exit(code);
//     }
// })}

// extern crate proc_macro;
// use proc_macro::TokenStream;
// #[proc_macro_attribute]
// pub fn hello(attr: TokenStream, item: TokenStream) -> TokenStream {
//     let result = quote! {
//         fn main() {
//             uucore::panic::install_sigpipe_hook();
//             std::io::stdout().flush().expect("could not flush stdout");
//             std::process::exit(code);
//         }
//     };
// }

#[macro_export]
macro_rules! executable(
    () => ({
        let module = module_path!();
        let module = module.split("::").next().unwrap_or(module);
        if &module[0..3] == "uu_" {
            &module[3..]
        } else {
            module
        }
    })
);

#[macro_export]
macro_rules! show_error(
    ($($args:tt)+) => ({
        eprint!("{}: error: ", executable!());
        eprintln!($($args)+);
    })
);

#[macro_export]
macro_rules! show_warning(
    ($($args:tt)+) => ({
        eprint!("{}: warning: ", executable!());
        eprintln!($($args)+);
    })
);

#[macro_export]
macro_rules! show_info(
    ($($args:tt)+) => ({
        eprint!("{}: ", executable!());
        eprintln!($($args)+);
    })
);

#[macro_export]
macro_rules! show_usage_error(
    ($($args:tt)+) => ({
        eprint!("{}: ", executable!());
        eprintln!($($args)+);
        eprintln!("Try '{} --help' for more information.", executable!());
    })
);

#[macro_export]
macro_rules! crash(
    ($exitcode:expr, $($args:tt)+) => ({
        show_error!($($args)+);
        ::std::process::exit($exitcode)
    })
);

#[macro_export]
macro_rules! exit(
    ($exitcode:expr) => ({
        ::std::process::exit($exitcode)
    })
);

#[macro_export]
macro_rules! crash_if_err(
    ($exitcode:expr, $exp:expr) => (
        match $exp {
            Ok(m) => m,
            Err(f) => crash!($exitcode, "{}", f),
        }
    )
);

#[macro_export]
macro_rules! return_if_err(
    ($exitcode:expr, $exp:expr) => (
        match $exp {
            Ok(m) => m,
            Err(f) => {
                show_error!("{}", f);
                return $exitcode;
            }
        }
    )
);

#[macro_export]
macro_rules! safe_write(
    ($fd:expr, $($args:tt)+) => (
        match write!($fd, $($args)+) {
            Ok(_) => {}
            Err(f) => panic!(f.to_string())
        }
    )
);

#[macro_export]
macro_rules! safe_writeln(
    ($fd:expr, $($args:tt)+) => (
        match writeln!($fd, $($args)+) {
            Ok(_) => {}
            Err(f) => panic!(f.to_string())
        }
    )
);

#[macro_export]
macro_rules! safe_unwrap(
    ($exp:expr) => (
        match $exp {
            Ok(m) => m,
            Err(f) => crash!(1, "{}", f.to_string())
        }
    )
);

//-- message templates

//-- message templates : general

#[macro_export]
macro_rules! snippet_list_join_oxford {
    ($conjunction:expr, $valOne:expr, $valTwo:expr) => (
        format!("{}, {} {}", $valOne, $conjunction, $valTwo)
    );
    ($conjunction:expr, $valOne:expr, $valTwo:expr $(, $remainingVals:expr)*) => (
        format!("{}, {}", $valOne, snippet_list_join_inner!($conjunction, $valTwo $(, $remainingVals)*))
    );
}

#[macro_export]
macro_rules! snippet_list_join_or {
    ($valOne:expr, $valTwo:expr) => (
        format!("{} or {}", $valOne, $valTwo)
    );
    ($valOne:expr, $valTwo:expr $(, $remainingVals:expr)*) => (
        format!("{}, {}", $valOne, snippet_list_join_oxford!("or", $valTwo $(, $remainingVals)*))
    );
}

//-- message templates : invalid input

#[macro_export]
macro_rules! msg_invalid_input {
    ($reason: expr) => {
        format!("invalid input: {}", $reason)
    };
}

#[macro_export]
macro_rules! snippet_no_file_at_path {
    ($path:expr) => {
        format!("nonexistent path {}", $path)
    };
}

// -- message templates : invalid input : flag

#[macro_export]
macro_rules! msg_invalid_opt_use {
    ($about:expr, $flag:expr) => {
        msg_invalid_input!(format!("The '{}' option {}", $flag, $about))
    };
    ($about:expr, $longflag:expr, $shortflag:expr) => {
        msg_invalid_input!(format!(
            "The '{}' ('{}') option {}",
            $longflag, $shortflag, $about
        ))
    };
}

#[macro_export]
macro_rules! msg_opt_only_usable_if {
    ($clause:expr, $flag:expr) => {
        msg_invalid_opt_use!(format!("only usable if {}", $clause), $flag)
    };
    ($clause:expr, $longflag:expr, $shortflag:expr) => {
        msg_invalid_opt_use!(format!("only usable if {}", $clause), $longflag, $shortflag)
    };
}

#[macro_export]
macro_rules! msg_opt_invalid_should_be {
    ($expects:expr, $received:expr, $flag:expr) => {
        msg_invalid_opt_use!(
            format!("expects {}, but was provided {}", $expects, $received),
            $flag
        )
    };
    ($expects:expr, $received:expr, $longflag:expr, $shortflag:expr) => {
        msg_invalid_opt_use!(
            format!("expects {}, but was provided {}", $expects, $received),
            $longflag,
            $shortflag
        )
    };
}

// -- message templates : invalid input : args

#[macro_export]
macro_rules! msg_arg_invalid_value {
    ($expects:expr, $received:expr) => {
        msg_invalid_input!(format!(
            "expects its argument to be {}, but was provided {}",
            $expects, $received
        ))
    };
}

#[macro_export]
macro_rules! msg_args_invalid_value {
    ($expects:expr, $received:expr) => {
        msg_invalid_input!(format!(
            "expects its arguments to be {}, but was provided {}",
            $expects, $received
        ))
    };
    ($msg:expr) => {
        msg_invalid_input!($msg)
    };
}

#[macro_export]
macro_rules! msg_args_nonexistent_file {
    ($received:expr) => {
        msg_args_invalid_value!("paths to files", snippet_no_file_at_path!($received))
    };
}

#[macro_export]
macro_rules! msg_wrong_number_of_arguments {
    () => {
        msg_args_invalid_value!("wrong number of arguments")
    };
    ($min:expr, $max:expr) => {
        msg_args_invalid_value!(format!("expects {}-{} arguments", $min, $max))
    };
    ($exact:expr) => {
        if $exact == 1 {
            msg_args_invalid_value!("expects 1 argument")
        } else {
            msg_args_invalid_value!(format!("expects {} arguments", $exact))
        }
    };
}

// -- message templates : invalid input : input combinations

#[macro_export]
macro_rules! msg_expects_one_of {
    ($valOne:expr $(, $remainingVals:expr)*) => (
        msg_invalid_input!(format!("expects one of {}", snippet_list_join_or!($valOne $(, $remainingVals)*)))
    );
}

#[macro_export]
macro_rules! msg_expects_no_more_than_one_of {
    ($valOne:expr $(, $remainingVals:expr)*) => (
        msg_invalid_input!(format!("expects no more than one of {}", snippet_list_join_or!($valOne $(, $remainingVals)*))) ;
    );
}
<|endoftext|>


<commit_before>use std::{error,fmt};

use super::{EvaluationContext,Functions,Value};

pub trait Function {
    fn evaluate<'a, 'd>(&self,
                        context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>;
}

#[derive(Copy,Clone,Debug,PartialEq,Hash)]
pub enum ArgumentType {
    Nodeset,
    Boolean,
    Number,
    String,
}

#[derive(Copy,Clone,Debug,PartialEq,Hash)]
pub enum Error {
    TooManyArguments{ expected: usize, actual: usize },
    NotEnoughArguments{ expected: usize, actual: usize },
    WrongType{ expected: ArgumentType, actual: ArgumentType },
}

impl Error {
    fn wrong_type(actual: &Value, expected: ArgumentType) -> Error {
        let actual = match *actual {
            Value::Nodes(..)   => ArgumentType::Nodeset,
            Value::String(..)  => ArgumentType::String,
            Value::Number(..)  => ArgumentType::Number,
            Value::Boolean(..) => ArgumentType::Boolean,
        };

        Error::WrongType {
            expected: expected,
            actual: actual
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        use self::Error::*;
        match *self {
            TooManyArguments{..}   => "too many arguments",
            NotEnoughArguments{..} => "not enough arguments",
            WrongType{..}          => "argument of wrong type",
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        use self::Error::*;
        match *self {
            TooManyArguments{expected, actual} => {
                write!(fmt, "too many arguments, expected {} but had {}", expected, actual)
            },
            NotEnoughArguments{expected, actual} => {
                write!(fmt, "not enough arguments, expected {} but had {}", expected, actual)
            },
            WrongType{expected, actual} => {
                write!(fmt, "argument was the wrong type, expected {:?} but had {:?}", expected, actual)
            },
        }
    }
}

fn minimum_arg_count<T>(args: &Vec<T>, minimum: usize) -> Result<(), Error> {
    let actual = args.len();
    if actual < minimum {
        Err(Error::NotEnoughArguments{expected: minimum, actual: actual})
    } else {
        Ok(())
    }
}

fn exact_arg_count<T>(args: &Vec<T>, expected: usize) -> Result<(), Error> {
    let actual = args.len();
    if actual < expected {
        Err(Error::NotEnoughArguments{ expected: expected, actual: actual })
    } else if actual > expected {
        Err(Error::TooManyArguments{ expected: expected, actual: actual })
    } else {
        Ok(())
    }
}

fn string_args(args: Vec<Value>) -> Result<Vec<String>, Error> {
    fn string_arg(v: Value) -> Result<String, Error> {
        match v {
            Value::String(s) => Ok(s),
            _ => Err(Error::wrong_type(&v, ArgumentType::String)),
        }
    }

    args.into_iter().map(string_arg).collect()
}

struct Last;

impl Function for Last {
    fn evaluate<'a, 'd>(&self,
                        context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 0));
        Ok(Value::Number(context.size() as f64))
    }
}

struct Position;

impl Function for Position {
    fn evaluate<'a, 'd>(&self,
                        context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 0));
        Ok(Value::Number(context.position() as f64))
    }
}

struct Count;

impl Function for Count {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 1));
        let arg = &args[0];
        match arg {
            &Value::Nodes(ref nodeset) => Ok(Value::Number(nodeset.size() as f64)),
            _ => Err(Error::wrong_type(arg, ArgumentType::Nodeset)),
        }
    }
}

struct Concat;

impl Function for Concat {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(minimum_arg_count(&args, 2));
        let args = try!(string_args(args));
        Ok(Value::String(args.concat()))
    }
}

struct StartsWith;

impl Function for StartsWith {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 2));
        let args = try!(string_args(args));
        let v = args[0].starts_with(&*args[1]);
        Ok(Value::Boolean(v))
    }
}

struct Contains;

impl Function for Contains {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 2));
        let args = try!(string_args(args));
        let v = args[0].contains(&*args[1]);
        Ok(Value::Boolean(v))
    }
}

struct SubstringBefore;

impl Function for SubstringBefore {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 2));
        let args = try!(string_args(args));
        let haystack = &args[0];

        let s = match haystack.find_str(&*args[1]) {
            Some(pos) => &haystack[..pos],
            None => "",
        };

        Ok(Value::String(s.to_string()))
    }
}

struct SubstringAfter;

impl Function for SubstringAfter {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 2));
        let args = try!(string_args(args));
        let haystack = &args[0];
        let needle = &*args[1];

        let s = match haystack.find_str(needle) {
            Some(pos) => &haystack[pos + needle.len()..],
            None => "",
        };

        Ok(Value::String(s.to_string()))
    }
}

struct Not;

impl Function for Not {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 1));
        let arg = &args[0];
        match arg {
            &Value::Boolean(v) => Ok(Value::Boolean(!v)),
            _ => Err(Error::wrong_type(arg, ArgumentType::Boolean)),
        }
    }
}

struct True;

impl Function for True {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 0));
        Ok(Value::Boolean(true))
    }
}

struct False;

impl Function for False {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 0));
        Ok(Value::Boolean(false))
    }
}

pub fn register_core_functions(functions: &mut Functions) {
    functions.insert("last".to_string(), box Last);
    functions.insert("position".to_string(), box Position);
    functions.insert("count".to_string(), box Count);
    functions.insert("concat".to_string(), box Concat);
    functions.insert("starts-with".to_string(), box StartsWith);
    functions.insert("contains".to_string(), box Contains);
    functions.insert("substring-before".to_string(), box SubstringBefore);
    functions.insert("substring-after".to_string(), box SubstringAfter);
    functions.insert("not".to_string(), box Not);
    functions.insert("true".to_string(), box True);
    functions.insert("false".to_string(), box False);
}

#[cfg(test)]
mod test {
    use std::collections::HashMap;
    use document::Package;
    use super::super::{EvaluationContext,LiteralValue,Value,Functions,Variables,Namespaces};
    use super::super::nodeset::ToNode;
    use super::{
        Function,
        Error,
        Last,
        Position,
        Count,
        Concat,
        StartsWith,
        Contains,
        SubstringBefore,
        SubstringAfter,
    };

    struct Setup<'d> {
        functions: Functions,
        variables: Variables<'d>,
        namespaces: Namespaces,
    }

    impl<'d> Setup<'d> {
        fn new() -> Setup<'d> {
            Setup {
                functions: HashMap::new(),
                variables: HashMap::new(),
                namespaces: HashMap::new(),
            }
        }

        fn evaluate<N, F>(&self, node: N, f: F, args: Vec<Value<'d>>)
            -> Result<Value<'d>, Error>
            where N: ToNode<'d>,
                  F: Function
        {
            let context = EvaluationContext::new(
                node, &self.functions, &self.variables, &self.namespaces
            );
            f.evaluate(&context, args)
        }
    }

    fn evaluate_literal<F>(f: F, args: Vec<LiteralValue>) -> Result<LiteralValue, Error>
        where F: Function
    {
        let package = Package::new();
        let doc = package.as_document();
        let setup = Setup::new();

        let args = args.into_iter().map(|a| a.into_value()).collect();

        let r = setup.evaluate(doc.root(), f, args);

        r.map(|r| r.into_literal_value())
    }

    #[test]
    fn last_returns_context_size() {
        let r = evaluate_literal(Last, vec![]);
        assert_eq!(Ok(LiteralValue::Number(1.0)), r);
    }

    #[test]
    fn position_returns_context_position() {
        let r = evaluate_literal(Position, vec![]);

        assert_eq!(Ok(LiteralValue::Number(1.0)), r);
    }

    #[test]
    fn count_counts_nodes_in_nodeset() {
        let package = Package::new();
        let doc = package.as_document();
        let setup = Setup::new();

        let nodeset = nodeset![doc.root()];
        let r = setup.evaluate(doc.root(), Count, vec![Value::Nodes(nodeset)]);

        assert_eq!(Ok(Value::Number(1.0)), r);
    }

    #[test]
    fn concat_combines_strings() {
        let args = vec![LiteralValue::String("hello".to_string()),
                        LiteralValue::String(" ".to_string()),
                        LiteralValue::String("world".to_string())];
        let r = evaluate_literal(Concat, args);

        assert_eq!(Ok(LiteralValue::String("hello world".to_string())), r);
    }

    #[test]
    fn starts_with_checks_prefixes() {
        let args = vec![LiteralValue::String("hello".to_string()),
                        LiteralValue::String("he".to_string())];
        let r = evaluate_literal(StartsWith, args);

        assert_eq!(Ok(LiteralValue::Boolean(true)), r);
    }

    #[test]
    fn contains_looks_for_a_needle() {
        let args = vec![LiteralValue::String("astronomer".to_string()),
                        LiteralValue::String("ono".to_string())];
        let r = evaluate_literal(Contains, args);

        assert_eq!(Ok(LiteralValue::Boolean(true)), r);
    }

    #[test]
    fn substring_before_slices_before() {
        let args = vec![LiteralValue::String("1999/04/01".to_string()),
                        LiteralValue::String("/".to_string())];
        let r = evaluate_literal(SubstringBefore, args);

        assert_eq!(Ok(LiteralValue::String("1999".to_string())), r);
    }

    #[test]
    fn substring_after_slices_after() {
        let args = vec![LiteralValue::String("1999/04/01".to_string()),
                        LiteralValue::String("/".to_string())];
        let r = evaluate_literal(SubstringAfter, args);

        assert_eq!(Ok(LiteralValue::String("04/01".to_string())), r);
    }
}
<commit_msg>Add XPath core function floor()<commit_after>use std::{error,fmt};
use std::num::Float;

use super::{EvaluationContext,Functions,Value};

pub trait Function {
    fn evaluate<'a, 'd>(&self,
                        context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>;
}

#[derive(Copy,Clone,Debug,PartialEq,Hash)]
pub enum ArgumentType {
    Nodeset,
    Boolean,
    Number,
    String,
}

#[derive(Copy,Clone,Debug,PartialEq,Hash)]
pub enum Error {
    TooManyArguments{ expected: usize, actual: usize },
    NotEnoughArguments{ expected: usize, actual: usize },
    WrongType{ expected: ArgumentType, actual: ArgumentType },
}

impl Error {
    fn wrong_type(actual: &Value, expected: ArgumentType) -> Error {
        let actual = match *actual {
            Value::Nodes(..)   => ArgumentType::Nodeset,
            Value::String(..)  => ArgumentType::String,
            Value::Number(..)  => ArgumentType::Number,
            Value::Boolean(..) => ArgumentType::Boolean,
        };

        Error::WrongType {
            expected: expected,
            actual: actual
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        use self::Error::*;
        match *self {
            TooManyArguments{..}   => "too many arguments",
            NotEnoughArguments{..} => "not enough arguments",
            WrongType{..}          => "argument of wrong type",
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        use self::Error::*;
        match *self {
            TooManyArguments{expected, actual} => {
                write!(fmt, "too many arguments, expected {} but had {}", expected, actual)
            },
            NotEnoughArguments{expected, actual} => {
                write!(fmt, "not enough arguments, expected {} but had {}", expected, actual)
            },
            WrongType{expected, actual} => {
                write!(fmt, "argument was the wrong type, expected {:?} but had {:?}", expected, actual)
            },
        }
    }
}

fn minimum_arg_count<T>(args: &Vec<T>, minimum: usize) -> Result<(), Error> {
    let actual = args.len();
    if actual < minimum {
        Err(Error::NotEnoughArguments{expected: minimum, actual: actual})
    } else {
        Ok(())
    }
}

fn exact_arg_count<T>(args: &Vec<T>, expected: usize) -> Result<(), Error> {
    let actual = args.len();
    if actual < expected {
        Err(Error::NotEnoughArguments{ expected: expected, actual: actual })
    } else if actual > expected {
        Err(Error::TooManyArguments{ expected: expected, actual: actual })
    } else {
        Ok(())
    }
}

fn string_args(args: Vec<Value>) -> Result<Vec<String>, Error> {
    fn string_arg(v: Value) -> Result<String, Error> {
        match v {
            Value::String(s) => Ok(s),
            _ => Err(Error::wrong_type(&v, ArgumentType::String)),
        }
    }

    args.into_iter().map(string_arg).collect()
}

fn one_number(args: Vec<Value>) -> Result<f64, Error> {
    match &args[0] {
        &Value::Number(v) => Ok(v),
        a => Err(Error::wrong_type(a, ArgumentType::Number)),
    }
}

struct Last;

impl Function for Last {
    fn evaluate<'a, 'd>(&self,
                        context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 0));
        Ok(Value::Number(context.size() as f64))
    }
}

struct Position;

impl Function for Position {
    fn evaluate<'a, 'd>(&self,
                        context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 0));
        Ok(Value::Number(context.position() as f64))
    }
}

struct Count;

impl Function for Count {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 1));
        let arg = &args[0];
        match arg {
            &Value::Nodes(ref nodeset) => Ok(Value::Number(nodeset.size() as f64)),
            _ => Err(Error::wrong_type(arg, ArgumentType::Nodeset)),
        }
    }
}

struct Concat;

impl Function for Concat {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(minimum_arg_count(&args, 2));
        let args = try!(string_args(args));
        Ok(Value::String(args.concat()))
    }
}

struct StartsWith;

impl Function for StartsWith {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 2));
        let args = try!(string_args(args));
        let v = args[0].starts_with(&*args[1]);
        Ok(Value::Boolean(v))
    }
}

struct Contains;

impl Function for Contains {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 2));
        let args = try!(string_args(args));
        let v = args[0].contains(&*args[1]);
        Ok(Value::Boolean(v))
    }
}

struct SubstringBefore;

impl Function for SubstringBefore {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 2));
        let args = try!(string_args(args));
        let haystack = &args[0];

        let s = match haystack.find_str(&*args[1]) {
            Some(pos) => &haystack[..pos],
            None => "",
        };

        Ok(Value::String(s.to_string()))
    }
}

struct SubstringAfter;

impl Function for SubstringAfter {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 2));
        let args = try!(string_args(args));
        let haystack = &args[0];
        let needle = &*args[1];

        let s = match haystack.find_str(needle) {
            Some(pos) => &haystack[pos + needle.len()..],
            None => "",
        };

        Ok(Value::String(s.to_string()))
    }
}

struct Not;

impl Function for Not {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 1));
        let arg = &args[0];
        match arg {
            &Value::Boolean(v) => Ok(Value::Boolean(!v)),
            _ => Err(Error::wrong_type(arg, ArgumentType::Boolean)),
        }
    }
}

struct True;

impl Function for True {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 0));
        Ok(Value::Boolean(true))
    }
}

struct False;

impl Function for False {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 0));
        Ok(Value::Boolean(false))
    }
}

struct Floor;

impl Function for Floor {
    fn evaluate<'a, 'd>(&self,
                        _context: &EvaluationContext<'a, 'd>,
                        args: Vec<Value<'d>>) -> Result<Value<'d>, Error>
    {
        try!(exact_arg_count(&args, 1));
        let arg = try!(one_number(args));
        Ok(Value::Number(arg.floor()))
    }
}

pub fn register_core_functions(functions: &mut Functions) {
    functions.insert("last".to_string(), box Last);
    functions.insert("position".to_string(), box Position);
    functions.insert("count".to_string(), box Count);
    functions.insert("concat".to_string(), box Concat);
    functions.insert("starts-with".to_string(), box StartsWith);
    functions.insert("contains".to_string(), box Contains);
    functions.insert("substring-before".to_string(), box SubstringBefore);
    functions.insert("substring-after".to_string(), box SubstringAfter);
    functions.insert("not".to_string(), box Not);
    functions.insert("true".to_string(), box True);
    functions.insert("false".to_string(), box False);
    functions.insert("floor".to_string(), box Floor);
}

#[cfg(test)]
mod test {
    use std::collections::HashMap;
    use document::Package;
    use super::super::{EvaluationContext,LiteralValue,Value,Functions,Variables,Namespaces};
    use super::super::nodeset::ToNode;
    use super::{
        Function,
        Error,
        Last,
        Position,
        Count,
        Concat,
        StartsWith,
        Contains,
        SubstringBefore,
        SubstringAfter,
        Floor,
    };

    struct Setup<'d> {
        functions: Functions,
        variables: Variables<'d>,
        namespaces: Namespaces,
    }

    impl<'d> Setup<'d> {
        fn new() -> Setup<'d> {
            Setup {
                functions: HashMap::new(),
                variables: HashMap::new(),
                namespaces: HashMap::new(),
            }
        }

        fn evaluate<N, F>(&self, node: N, f: F, args: Vec<Value<'d>>)
            -> Result<Value<'d>, Error>
            where N: ToNode<'d>,
                  F: Function
        {
            let context = EvaluationContext::new(
                node, &self.functions, &self.variables, &self.namespaces
            );
            f.evaluate(&context, args)
        }
    }

    fn evaluate_literal<F>(f: F, args: Vec<LiteralValue>) -> Result<LiteralValue, Error>
        where F: Function
    {
        let package = Package::new();
        let doc = package.as_document();
        let setup = Setup::new();

        let args = args.into_iter().map(|a| a.into_value()).collect();

        let r = setup.evaluate(doc.root(), f, args);

        r.map(|r| r.into_literal_value())
    }

    #[test]
    fn last_returns_context_size() {
        let r = evaluate_literal(Last, vec![]);
        assert_eq!(Ok(LiteralValue::Number(1.0)), r);
    }

    #[test]
    fn position_returns_context_position() {
        let r = evaluate_literal(Position, vec![]);

        assert_eq!(Ok(LiteralValue::Number(1.0)), r);
    }

    #[test]
    fn count_counts_nodes_in_nodeset() {
        let package = Package::new();
        let doc = package.as_document();
        let setup = Setup::new();

        let nodeset = nodeset![doc.root()];
        let r = setup.evaluate(doc.root(), Count, vec![Value::Nodes(nodeset)]);

        assert_eq!(Ok(Value::Number(1.0)), r);
    }

    #[test]
    fn concat_combines_strings() {
        let args = vec![LiteralValue::String("hello".to_string()),
                        LiteralValue::String(" ".to_string()),
                        LiteralValue::String("world".to_string())];
        let r = evaluate_literal(Concat, args);

        assert_eq!(Ok(LiteralValue::String("hello world".to_string())), r);
    }

    #[test]
    fn starts_with_checks_prefixes() {
        let args = vec![LiteralValue::String("hello".to_string()),
                        LiteralValue::String("he".to_string())];
        let r = evaluate_literal(StartsWith, args);

        assert_eq!(Ok(LiteralValue::Boolean(true)), r);
    }

    #[test]
    fn contains_looks_for_a_needle() {
        let args = vec![LiteralValue::String("astronomer".to_string()),
                        LiteralValue::String("ono".to_string())];
        let r = evaluate_literal(Contains, args);

        assert_eq!(Ok(LiteralValue::Boolean(true)), r);
    }

    #[test]
    fn substring_before_slices_before() {
        let args = vec![LiteralValue::String("1999/04/01".to_string()),
                        LiteralValue::String("/".to_string())];
        let r = evaluate_literal(SubstringBefore, args);

        assert_eq!(Ok(LiteralValue::String("1999".to_string())), r);
    }

    #[test]
    fn substring_after_slices_after() {
        let args = vec![LiteralValue::String("1999/04/01".to_string()),
                        LiteralValue::String("/".to_string())];
        let r = evaluate_literal(SubstringAfter, args);

        assert_eq!(Ok(LiteralValue::String("04/01".to_string())), r);
    }

    #[test]
    fn floor_rounds_down() {
        let r = evaluate_literal(Floor, vec![LiteralValue::Number(199.99)]);

        assert_eq!(Ok(LiteralValue::Number(199.0)), r);
    }
}
<|endoftext|>