<commit_before>#![allow(missing_docs)]

//! Traits and tags for identifying the dimension of all algebraic entities.

use std::any::{Any, TypeId};
use std::cmp;
use std::fmt::Debug;
use std::ops::{Add, Div, Mul, Sub};
use typenum::{
    self, Bit, Diff, Max, Maximum, Min, Minimum, Prod, Quot, Sum, UInt, UTerm, Unsigned, B1,
};

#[cfg(feature = "serde-serialize")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};

/// Dim of dynamically-sized algebraic entities.
#[derive(Clone, Copy, Eq, Debug)]
pub struct Dynamic {
    value: usize,
}

impl Dynamic {
    /// A dynamic size equal to `value`.
    #[inline]
    pub fn new(value: usize) -> Self {
        Self { value: value }
    }
}

#[cfg(feature = "serde-serialize")]
impl Serialize for Dynamic {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where S: Serializer {
        self.value.serialize(serializer)
    }
}

#[cfg(feature = "serde-serialize")]
impl<'de> Deserialize<'de> for Dynamic {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where D: Deserializer<'de> {
        usize::deserialize(deserializer).map(|x| Dynamic { value: x })
    }
}

/// Trait implemented by `Dynamic`.
pub trait IsDynamic {}
/// Trait implemented by `Dynamic` and type-level integers different from `U1`.
pub trait IsNotStaticOne {}

impl IsDynamic for Dynamic {}
impl IsNotStaticOne for Dynamic {}

/// Trait implemented by any type that can be used as a dimension. This includes type-level
/// integers and `Dynamic` (for dimensions not known at compile-time).
pub trait Dim: Any + Debug + Copy + PartialEq + Send + Sync {
    #[inline(always)]
    fn is<D: Dim>() -> bool {
        TypeId::of::<Self>() == TypeId::of::<D>()
    }

    /// Gets the compile-time value of `Self`. Returns `None` if it is not known, i.e., if `Self =
    /// Dynamic`.
    fn try_to_usize() -> Option<usize>;

    /// Gets the run-time value of `self`. For type-level integers, this is the same as
    /// `Self::try_to_usize().unwrap()`.
    fn value(&self) -> usize;

    /// Builds an instance of `Self` from a run-time value. Panics if `Self` is a type-level
    /// integer and `dim != Self::try_to_usize().unwrap()`.
    fn from_usize(dim: usize) -> Self;
}

impl Dim for Dynamic {
    #[inline]
    fn try_to_usize() -> Option<usize> {
        None
    }

    #[inline]
    fn from_usize(dim: usize) -> Self {
        Self::new(dim)
    }

    #[inline]
    fn value(&self) -> usize {
        self.value
    }
}

impl Add<usize> for Dynamic {
    type Output = Dynamic;

    #[inline]
    fn add(self, rhs: usize) -> Self {
        Self::new(self.value + rhs)
    }
}

impl Sub<usize> for Dynamic {
    type Output = Dynamic;

    #[inline]
    fn sub(self, rhs: usize) -> Self {
        Self::new(self.value - rhs)
    }
}

impl<T: Dim> PartialEq<T> for Dynamic {
    fn eq(&self, other: &T) -> bool {
        self.value() == other.value()
    }
}

/*
 *
 * Operations.
 *
 */

macro_rules! dim_ops(
    ($($DimOp:    ident, $DimNameOp: ident,
       $Op:       ident, $op: ident, $op_path: path,
       $DimResOp: ident, $DimNameResOp: ident,
       $ResOp: ident);* $(;)*) => {$(
        pub type $DimResOp<D1, D2> = <D1 as $DimOp<D2>>::Output;

        pub trait $DimOp<D: Dim>: Dim {
            type Output: Dim;

            fn $op(self, other: D) -> Self::Output;
        }

        impl<D1: DimName, D2: DimName> $DimOp<D2> for D1
            where D1::Value: $Op<D2::Value>,
                  $ResOp<D1::Value, D2::Value>: NamedDim {
            type Output = <$ResOp<D1::Value, D2::Value> as NamedDim>::Name;

            #[inline]
            fn $op(self, _: D2) -> Self::Output {
                Self::Output::name()
            }
        }

        impl<D: Dim> $DimOp<D> for Dynamic {
            type Output = Dynamic;

            #[inline]
            fn $op(self, other: D) -> Dynamic {
                Dynamic::new($op_path(self.value, other.value()))
            }
        }

        impl<D: DimName> $DimOp<Dynamic> for D {
            type Output = Dynamic;

            #[inline]
            fn $op(self, other: Dynamic) -> Dynamic {
                Dynamic::new($op_path(self.value(), other.value))
            }
        }

        pub type $DimNameResOp<D1, D2> = <D1 as $DimNameOp<D2>>::Output;

        pub trait $DimNameOp<D: DimName>: DimName {
            type Output: DimName;

            fn $op(self, other: D) -> Self::Output;
        }

        impl<D1: DimName, D2: DimName> $DimNameOp<D2> for D1
            where D1::Value: $Op<D2::Value>,
                  $ResOp<D1::Value, D2::Value>: NamedDim {
            type Output = <$ResOp<D1::Value, D2::Value> as NamedDim>::Name;

            #[inline]
            fn $op(self, _: D2) -> Self::Output {
                Self::Output::name()
            }
        }
   )*}
);

dim_ops!(
    DimAdd, DimNameAdd, Add, add, Add::add, DimSum,     DimNameSum,     Sum;
    DimMul, DimNameMul, Mul, mul, Mul::mul, DimProd,    DimNameProd,    Prod;
    DimSub, DimNameSub, Sub, sub, Sub::sub, DimDiff,    DimNameDiff,    Diff;
    DimDiv, DimNameDiv, Div, div, Div::div, DimQuot,    DimNameQuot,    Quot;
    DimMin, DimNameMin, Min, min, cmp::min, DimMinimum, DimNameMinimum, Minimum;
    DimMax, DimNameMax, Max, max, cmp::max, DimMaximum, DimNameMaximum, Maximum;
);

/// Trait implemented exclusively by type-level integers.
pub trait DimName: Dim {
    type Value: NamedDim<Name = Self>;

    /// The name of this dimension, i.e., the singleton `Self`.
    #[inline]
    fn name() -> Self;

    // FIXME: this is not a very idiomatic name.
    /// The value of this dimension.
    #[inline]
    fn dim() -> usize {
        Self::Value::to_usize()
    }
}

pub trait NamedDim: Sized + Any + Unsigned {
    type Name: DimName<Value = Self>;
}

/// A type level dimension with a value of `1`.
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
pub struct U1;

impl Dim for U1 {
    #[inline]
    fn try_to_usize() -> Option<usize> {
        Some(1)
    }

    #[inline]
    fn from_usize(dim: usize) -> Self {
        assert!(dim == 1, "Mismatched dimension.");
        U1
    }

    #[inline]
    fn value(&self) -> usize {
        1
    }
}

impl DimName for U1 {
    type Value = typenum::U1;

    #[inline]
    fn name() -> Self {
        U1
    }
}

impl NamedDim for typenum::U1 {
    type Name = U1;
}

// For values greater than U1023, just use the typenum binary representation directly.
impl<
        A: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        B: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        C: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        D: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        E: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        F: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        G: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
    > NamedDim for UInt<UInt<UInt<UInt<UInt<UInt<UInt<UInt<UTerm, B1>, A>, B>, C>, D>, E>, F>, G>
{
    type Name = Self;
}

impl<
        A: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        B: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        C: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        D: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        E: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        F: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        G: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
    > Dim for UInt<UInt<UInt<UInt<UInt<UInt<UInt<UInt<UTerm, B1>, A>, B>, C>, D>, E>, F>, G>
{
    #[inline]
    fn try_to_usize() -> Option<usize> {
        Some(Self::to_usize())
    }

    #[inline]
    fn from_usize(dim: usize) -> Self {
        assert!(dim == Self::to_usize(), "Mismatched dimension.");
        Self::new()
    }

    #[inline]
    fn value(&self) -> usize {
        Self::to_usize()
    }
}

impl<
        A: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        B: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        C: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        D: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        E: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        F: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        G: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
    > DimName for UInt<UInt<UInt<UInt<UInt<UInt<UInt<UInt<UTerm, B1>, A>, B>, C>, D>, E>, F>, G>
{
    type Value = Self;

    #[inline]
    fn name() -> Self {
        Self::new()
    }
}

impl<
        A: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        B: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        C: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        D: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        E: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        F: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        G: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
    > IsNotStaticOne
    for UInt<UInt<UInt<UInt<UInt<UInt<UInt<UInt<UTerm, B1>, A>, B>, C>, D>, E>, F>, G>
{
}

impl<U: Unsigned + DimName, B: Bit + Any + Debug + Copy + PartialEq + Send + Sync> NamedDim
    for UInt<U, B>
{
    type Name = UInt<U, B>;
}

impl<U: Unsigned + DimName, B: Bit + Any + Debug + Copy + PartialEq + Send + Sync> Dim
    for UInt<U, B>
{
    #[inline]
    fn try_to_usize() -> Option<usize> {
        Some(Self::to_usize())
    }

    #[inline]
    fn from_usize(dim: usize) -> Self {
        assert!(dim == Self::to_usize(), "Mismatched dimension.");
        Self::new()
    }

    #[inline]
    fn value(&self) -> usize {
        Self::to_usize()
    }
}

impl<U: Unsigned + DimName, B: Bit + Any + Debug + Copy + PartialEq + Send + Sync> DimName
    for UInt<U, B>
{
    type Value = UInt<U, B>;

    #[inline]
    fn name() -> Self {
        Self::new()
    }
}

impl<U: Unsigned + DimName, B: Bit + Any + Debug + Copy + PartialEq + Send + Sync> IsNotStaticOne
    for UInt<U, B>
{
}

macro_rules! named_dimension(
    ($($D: ident),* $(,)*) => {$(
        /// A type level dimension.
        #[derive(Debug, Copy, Clone, Hash, Eq)]
        #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
        pub struct $D;

        impl Dim for $D {
            #[inline]
            fn try_to_usize() -> Option<usize> {
                Some(typenum::$D::to_usize())
            }

            #[inline]
            fn from_usize(dim: usize) -> Self {
                assert!(dim == typenum::$D::to_usize(), "Mismatched dimension.");
                $D
            }

            #[inline]
            fn value(&self) -> usize {
                typenum::$D::to_usize()
            }
        }

        impl DimName for $D {
            type Value = typenum::$D;

            #[inline]
            fn name() -> Self {
                $D
            }
        }

        impl NamedDim for typenum::$D {
            type Name = $D;
        }

        impl IsNotStaticOne for $D { }

        impl<T: Dim> PartialEq<T> for $D {
            fn eq(&self, other: &T) -> bool {
                self.value() == other.value()
            }
        }
    )*}
);

// We give explicit names to all Unsigned in [0, 128[
named_dimension!(
    U0, /*U1,*/ U2, U3, U4, U5, U6, U7, U8, U9, U10, U11, U12, U13, U14, U15, U16, U17, U18,
    U19, U20, U21, U22, U23, U24, U25, U26, U27, U28, U29, U30, U31, U32, U33, U34, U35, U36, U37,
    U38, U39, U40, U41, U42, U43, U44, U45, U46, U47, U48, U49, U50, U51, U52, U53, U54, U55, U56,
    U57, U58, U59, U60, U61, U62, U63, U64, U65, U66, U67, U68, U69, U70, U71, U72, U73, U74, U75,
    U76, U77, U78, U79, U80, U81, U82, U83, U84, U85, U86, U87, U88, U89, U90, U91, U92, U93, U94,
    U95, U96, U97, U98, U99, U100, U101, U102, U103, U104, U105, U106, U107, U108, U109, U110,
    U111, U112, U113, U114, U115, U116, U117, U118, U119, U120, U121, U122, U123, U124, U125, U126,
    U127,
);
<commit_msg>Revert "Broader PartialEq implementation for types implementing Dim trait"<commit_after>#![allow(missing_docs)]

//! Traits and tags for identifying the dimension of all algebraic entities.

use std::any::{Any, TypeId};
use std::cmp;
use std::fmt::Debug;
use std::ops::{Add, Div, Mul, Sub};
use typenum::{
    self, Bit, Diff, Max, Maximum, Min, Minimum, Prod, Quot, Sum, UInt, UTerm, Unsigned, B1,
};

#[cfg(feature = "serde-serialize")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};

/// Dim of dynamically-sized algebraic entities.
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub struct Dynamic {
    value: usize,
}

impl Dynamic {
    /// A dynamic size equal to `value`.
    #[inline]
    pub fn new(value: usize) -> Self {
        Self { value: value }
    }
}

#[cfg(feature = "serde-serialize")]
impl Serialize for Dynamic {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where S: Serializer {
        self.value.serialize(serializer)
    }
}

#[cfg(feature = "serde-serialize")]
impl<'de> Deserialize<'de> for Dynamic {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where D: Deserializer<'de> {
        usize::deserialize(deserializer).map(|x| Dynamic { value: x })
    }
}

/// Trait implemented by `Dynamic`.
pub trait IsDynamic {}
/// Trait implemented by `Dynamic` and type-level integers different from `U1`.
pub trait IsNotStaticOne {}

impl IsDynamic for Dynamic {}
impl IsNotStaticOne for Dynamic {}

/// Trait implemented by any type that can be used as a dimension. This includes type-level
/// integers and `Dynamic` (for dimensions not known at compile-time).
pub trait Dim: Any + Debug + Copy + PartialEq + Send + Sync {
    #[inline(always)]
    fn is<D: Dim>() -> bool {
        TypeId::of::<Self>() == TypeId::of::<D>()
    }

    /// Gets the compile-time value of `Self`. Returns `None` if it is not known, i.e., if `Self =
    /// Dynamic`.
    fn try_to_usize() -> Option<usize>;

    /// Gets the run-time value of `self`. For type-level integers, this is the same as
    /// `Self::try_to_usize().unwrap()`.
    fn value(&self) -> usize;

    /// Builds an instance of `Self` from a run-time value. Panics if `Self` is a type-level
    /// integer and `dim != Self::try_to_usize().unwrap()`.
    fn from_usize(dim: usize) -> Self;
}

impl Dim for Dynamic {
    #[inline]
    fn try_to_usize() -> Option<usize> {
        None
    }

    #[inline]
    fn from_usize(dim: usize) -> Self {
        Self::new(dim)
    }

    #[inline]
    fn value(&self) -> usize {
        self.value
    }
}

impl Add<usize> for Dynamic {
    type Output = Dynamic;

    #[inline]
    fn add(self, rhs: usize) -> Self {
        Self::new(self.value + rhs)
    }
}

impl Sub<usize> for Dynamic {
    type Output = Dynamic;

    #[inline]
    fn sub(self, rhs: usize) -> Self {
        Self::new(self.value - rhs)
    }
}

/*
 *
 * Operations.
 *
 */

macro_rules! dim_ops(
    ($($DimOp:    ident, $DimNameOp: ident,
       $Op:       ident, $op: ident, $op_path: path,
       $DimResOp: ident, $DimNameResOp: ident,
       $ResOp: ident);* $(;)*) => {$(
        pub type $DimResOp<D1, D2> = <D1 as $DimOp<D2>>::Output;

        pub trait $DimOp<D: Dim>: Dim {
            type Output: Dim;

            fn $op(self, other: D) -> Self::Output;
        }

        impl<D1: DimName, D2: DimName> $DimOp<D2> for D1
            where D1::Value: $Op<D2::Value>,
                  $ResOp<D1::Value, D2::Value>: NamedDim {
            type Output = <$ResOp<D1::Value, D2::Value> as NamedDim>::Name;

            #[inline]
            fn $op(self, _: D2) -> Self::Output {
                Self::Output::name()
            }
        }

        impl<D: Dim> $DimOp<D> for Dynamic {
            type Output = Dynamic;

            #[inline]
            fn $op(self, other: D) -> Dynamic {
                Dynamic::new($op_path(self.value, other.value()))
            }
        }

        impl<D: DimName> $DimOp<Dynamic> for D {
            type Output = Dynamic;

            #[inline]
            fn $op(self, other: Dynamic) -> Dynamic {
                Dynamic::new($op_path(self.value(), other.value))
            }
        }

        pub type $DimNameResOp<D1, D2> = <D1 as $DimNameOp<D2>>::Output;

        pub trait $DimNameOp<D: DimName>: DimName {
            type Output: DimName;

            fn $op(self, other: D) -> Self::Output;
        }

        impl<D1: DimName, D2: DimName> $DimNameOp<D2> for D1
            where D1::Value: $Op<D2::Value>,
                  $ResOp<D1::Value, D2::Value>: NamedDim {
            type Output = <$ResOp<D1::Value, D2::Value> as NamedDim>::Name;

            #[inline]
            fn $op(self, _: D2) -> Self::Output {
                Self::Output::name()
            }
        }
   )*}
);

dim_ops!(
    DimAdd, DimNameAdd, Add, add, Add::add, DimSum,     DimNameSum,     Sum;
    DimMul, DimNameMul, Mul, mul, Mul::mul, DimProd,    DimNameProd,    Prod;
    DimSub, DimNameSub, Sub, sub, Sub::sub, DimDiff,    DimNameDiff,    Diff;
    DimDiv, DimNameDiv, Div, div, Div::div, DimQuot,    DimNameQuot,    Quot;
    DimMin, DimNameMin, Min, min, cmp::min, DimMinimum, DimNameMinimum, Minimum;
    DimMax, DimNameMax, Max, max, cmp::max, DimMaximum, DimNameMaximum, Maximum;
);

/// Trait implemented exclusively by type-level integers.
pub trait DimName: Dim {
    type Value: NamedDim<Name = Self>;

    /// The name of this dimension, i.e., the singleton `Self`.
    #[inline]
    fn name() -> Self;

    // FIXME: this is not a very idiomatic name.
    /// The value of this dimension.
    #[inline]
    fn dim() -> usize {
        Self::Value::to_usize()
    }
}

pub trait NamedDim: Sized + Any + Unsigned {
    type Name: DimName<Value = Self>;
}

/// A type level dimension with a value of `1`.
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
pub struct U1;

impl Dim for U1 {
    #[inline]
    fn try_to_usize() -> Option<usize> {
        Some(1)
    }

    #[inline]
    fn from_usize(dim: usize) -> Self {
        assert!(dim == 1, "Mismatched dimension.");
        U1
    }

    #[inline]
    fn value(&self) -> usize {
        1
    }
}

impl DimName for U1 {
    type Value = typenum::U1;

    #[inline]
    fn name() -> Self {
        U1
    }
}

impl NamedDim for typenum::U1 {
    type Name = U1;
}

macro_rules! named_dimension (
    ($($D: ident),* $(,)*) => {$(
        /// A type level dimension.
        #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
        #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
        pub struct $D;

        impl Dim for $D {
            #[inline]
            fn try_to_usize() -> Option<usize> {
                Some(typenum::$D::to_usize())
            }

            #[inline]
            fn from_usize(dim: usize) -> Self {
                assert!(dim == typenum::$D::to_usize(), "Mismatched dimension.");
                $D
            }

            #[inline]
            fn value(&self) -> usize {
                typenum::$D::to_usize()
            }
        }

        impl DimName for $D {
            type Value = typenum::$D;

            #[inline]
            fn name() -> Self {
                $D
            }
        }

        impl NamedDim for typenum::$D {
            type Name = $D;
        }

        impl IsNotStaticOne for $D { }
    )*}
);

// We give explicit names to all Unsigned in [0, 128[
named_dimension!(
    U0, /*U1,*/ U2, U3, U4, U5, U6, U7, U8, U9, U10, U11, U12, U13, U14, U15, U16, U17, U18,
    U19, U20, U21, U22, U23, U24, U25, U26, U27, U28, U29, U30, U31, U32, U33, U34, U35, U36, U37,
    U38, U39, U40, U41, U42, U43, U44, U45, U46, U47, U48, U49, U50, U51, U52, U53, U54, U55, U56,
    U57, U58, U59, U60, U61, U62, U63, U64, U65, U66, U67, U68, U69, U70, U71, U72, U73, U74, U75,
    U76, U77, U78, U79, U80, U81, U82, U83, U84, U85, U86, U87, U88, U89, U90, U91, U92, U93, U94,
    U95, U96, U97, U98, U99, U100, U101, U102, U103, U104, U105, U106, U107, U108, U109, U110,
    U111, U112, U113, U114, U115, U116, U117, U118, U119, U120, U121, U122, U123, U124, U125, U126,
    U127
);

// For values greater than U1023, just use the typenum binary representation directly.
impl<
        A: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        B: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        C: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        D: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        E: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        F: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        G: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
    > NamedDim for UInt<UInt<UInt<UInt<UInt<UInt<UInt<UInt<UTerm, B1>, A>, B>, C>, D>, E>, F>, G>
{
    type Name = Self;
}

impl<
        A: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        B: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        C: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        D: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        E: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        F: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        G: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
    > Dim for UInt<UInt<UInt<UInt<UInt<UInt<UInt<UInt<UTerm, B1>, A>, B>, C>, D>, E>, F>, G>
{
    #[inline]
    fn try_to_usize() -> Option<usize> {
        Some(Self::to_usize())
    }

    #[inline]
    fn from_usize(dim: usize) -> Self {
        assert!(dim == Self::to_usize(), "Mismatched dimension.");
        Self::new()
    }

    #[inline]
    fn value(&self) -> usize {
        Self::to_usize()
    }
}

impl<
        A: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        B: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        C: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        D: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        E: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        F: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        G: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
    > DimName for UInt<UInt<UInt<UInt<UInt<UInt<UInt<UInt<UTerm, B1>, A>, B>, C>, D>, E>, F>, G>
{
    type Value = Self;

    #[inline]
    fn name() -> Self {
        Self::new()
    }
}

impl<
        A: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        B: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        C: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        D: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        E: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        F: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
        G: Bit + Any + Debug + Copy + PartialEq + Send + Sync,
    > IsNotStaticOne
    for UInt<UInt<UInt<UInt<UInt<UInt<UInt<UInt<UTerm, B1>, A>, B>, C>, D>, E>, F>, G>
{
}

impl<U: Unsigned + DimName, B: Bit + Any + Debug + Copy + PartialEq + Send + Sync> NamedDim
    for UInt<U, B>
{
    type Name = UInt<U, B>;
}

impl<U: Unsigned + DimName, B: Bit + Any + Debug + Copy + PartialEq + Send + Sync> Dim
    for UInt<U, B>
{
    #[inline]
    fn try_to_usize() -> Option<usize> {
        Some(Self::to_usize())
    }

    #[inline]
    fn from_usize(dim: usize) -> Self {
        assert!(dim == Self::to_usize(), "Mismatched dimension.");
        Self::new()
    }

    #[inline]
    fn value(&self) -> usize {
        Self::to_usize()
    }
}

impl<U: Unsigned + DimName, B: Bit + Any + Debug + Copy + PartialEq + Send + Sync> DimName
    for UInt<U, B>
{
    type Value = UInt<U, B>;

    #[inline]
    fn name() -> Self {
        Self::new()
    }
}

impl<U: Unsigned + DimName, B: Bit + Any + Debug + Copy + PartialEq + Send + Sync> IsNotStaticOne
    for UInt<U, B>
{
}
<|endoftext|>


<commit_before>//! Module providing the TermLogger Implementation

use log::{
    set_boxed_logger, set_max_level, Level, LevelFilter, Log, Metadata, Record, SetLoggerError,
};
use std::io::{Error, Write};
use std::sync::Mutex;
use termcolor::{ColorChoice, ColorSpec, StandardStream, WriteColor};

use super::logging::*;

use crate::{Config, SharedLogger};

enum StdTerminal {
    Stderr(Box<dyn WriteColor + Send>),
    Stdout(Box<dyn WriteColor + Send>),
}

impl StdTerminal {
    fn flush(&mut self) -> Result<(), Error> {
        match self {
            StdTerminal::Stderr(term) => term.flush(),
            StdTerminal::Stdout(term) => term.flush(),
        }
    }
}

struct OutputStreams {
    err: StdTerminal,
    out: StdTerminal,
}

/// Specifies which streams should be used when logging
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub enum TerminalMode {
    /// Only use Stdout
    Stdout,
    /// Only use Stderr
    Stderr,
    /// Use Stderr for Errors and Stdout otherwise
    Mixed,
}

impl Default for TerminalMode {
    fn default() -> TerminalMode {
        TerminalMode::Mixed
    }
}

/// The TermLogger struct. Provides a stderr/out based Logger implementation
///
/// Supports colored output
pub struct TermLogger {
    level: LevelFilter,
    config: Config,
    streams: Mutex<OutputStreams>,
}

impl TermLogger {
    /// init function. Globally initializes the TermLogger as the one and only used log facility.
    ///
    /// Takes the desired `Level` and `Config` as arguments. They cannot be changed later on.
    /// Fails if another Logger was already initialized
    ///
    /// # Examples
    /// ```
    /// # extern crate simplelog;
    /// # use simplelog::*;
    /// # fn main() {
    ///     TermLogger::init(
    ///         LevelFilter::Info,
    ///         Config::default(),
    ///         TerminalMode::Mixed,
    ///         ColorChoice::Auto
    ///     );
    /// # }
    /// ```
    pub fn init(
        log_level: LevelFilter,
        config: Config,
        mode: TerminalMode,
        color_choice: ColorChoice,
    ) -> Result<(), SetLoggerError> {
        let logger = TermLogger::new(log_level, config, mode, color_choice);
        set_max_level(log_level);
        set_boxed_logger(logger)?;
        Ok(())
    }

    /// allows to create a new logger, that can be independently used, no matter whats globally set.
    ///
    /// no macros are provided for this case and you probably
    /// dont want to use this function, but `init()`, if you dont want to build a `CombinedLogger`.
    ///
    /// Takes the desired `Level` and `Config` as arguments. They cannot be changed later on.
    ///
    /// Returns a `Box`ed TermLogger
    ///
    /// # Examples
    /// ```
    /// # extern crate simplelog;
    /// # use simplelog::*;
    /// # fn main() {
    /// let term_logger = TermLogger::new(
    ///     LevelFilter::Info,
    ///     Config::default(),
    ///     TerminalMode::Mixed,
    ///     ColorChoice::Auto
    /// );
    /// # }
    /// ```
    pub fn new(
        log_level: LevelFilter,
        config: Config,
        mode: TerminalMode,
        color_choice: ColorChoice,
    ) -> Box<TermLogger> {
        let streams = match mode {
            TerminalMode::Stdout => OutputStreams {
                err: StdTerminal::Stdout(Box::new(StandardStream::stdout(color_choice))),
                out: StdTerminal::Stdout(Box::new(StandardStream::stdout(color_choice))),
            },
            TerminalMode::Stderr => OutputStreams {
                err: StdTerminal::Stderr(Box::new(StandardStream::stderr(color_choice))),
                out: StdTerminal::Stderr(Box::new(StandardStream::stderr(color_choice))),
            },
            TerminalMode::Mixed => OutputStreams {
                err: StdTerminal::Stderr(Box::new(StandardStream::stderr(color_choice))),
                out: StdTerminal::Stdout(Box::new(StandardStream::stdout(color_choice))),
            },
        };

        Box::new(TermLogger {
            level: log_level,
            config,
            streams: Mutex::new(streams),
        })
    }

    fn try_log_term(
        &self,
        record: &Record<'_>,
        term_lock: &mut Box<dyn WriteColor + Send>,
    ) -> Result<(), Error> {
        let color = self.config.level_color[record.level() as usize];

        if self.config.time <= record.level() && self.config.time != LevelFilter::Off {
            write_time(&mut *term_lock, &self.config)?;
        }

        if self.config.level <= record.level() && self.config.level != LevelFilter::Off {
            term_lock.set_color(ColorSpec::new().set_fg(color))?;
            write_level(record, &mut *term_lock, &self.config)?;
            term_lock.reset()?;
        }

        if self.config.thread <= record.level() && self.config.thread != LevelFilter::Off {
            write_thread_id(&mut *term_lock, &self.config)?;
        }

        if self.config.target <= record.level() && self.config.target != LevelFilter::Off {
            write_target(record, &mut *term_lock)?;
        }

        if self.config.location <= record.level() && self.config.location != LevelFilter::Off {
            write_location(record, &mut *term_lock)?;
        }

        write_args(record, &mut *term_lock)
    }

    fn try_log(&self, record: &Record<'_>) -> Result<(), Error> {
        if self.enabled(record.metadata()) {
            if should_skip(&self.config, record) {
                return Ok(());
            }

            let mut streams = self.streams.lock().unwrap();

            if record.level() == Level::Error {
                match streams.err {
                    StdTerminal::Stderr(ref mut term) => self.try_log_term(record, term),
                    StdTerminal::Stdout(ref mut term) => self.try_log_term(record, term),
                }
            } else {
                match streams.out {
                    StdTerminal::Stderr(ref mut term) => self.try_log_term(record, term),
                    StdTerminal::Stdout(ref mut term) => self.try_log_term(record, term),
                }
            }
        } else {
            Ok(())
        }
    }
}

impl Log for TermLogger {
    fn enabled(&self, metadata: &Metadata<'_>) -> bool {
        metadata.level() <= self.level
    }

    fn log(&self, record: &Record<'_>) {
        let _ = self.try_log(record);
    }

    fn flush(&self) {
        let mut streams = self.streams.lock().unwrap();
        let _ = streams.out.flush();
        let _ = streams.err.flush();
    }
}

impl SharedLogger for TermLogger {
    fn level(&self) -> LevelFilter {
        self.level
    }

    fn config(&self) -> Option<&Config> {
        Some(&self.config)
    }

    fn as_log(self: Box<Self>) -> Box<dyn Log> {
        Box::new(*self)
    }
}
<commit_msg>add write thread name support for termlog<commit_after>//! Module providing the TermLogger Implementation

use log::{
    set_boxed_logger, set_max_level, Level, LevelFilter, Log, Metadata, Record, SetLoggerError,
};
use std::io::{Error, Write};
use std::sync::Mutex;
use termcolor::{ColorChoice, ColorSpec, StandardStream, WriteColor};

use super::logging::*;

use crate::{Config, SharedLogger, ThreadLogMode};

enum StdTerminal {
    Stderr(Box<dyn WriteColor + Send>),
    Stdout(Box<dyn WriteColor + Send>),
}

impl StdTerminal {
    fn flush(&mut self) -> Result<(), Error> {
        match self {
            StdTerminal::Stderr(term) => term.flush(),
            StdTerminal::Stdout(term) => term.flush(),
        }
    }
}

struct OutputStreams {
    err: StdTerminal,
    out: StdTerminal,
}

/// Specifies which streams should be used when logging
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub enum TerminalMode {
    /// Only use Stdout
    Stdout,
    /// Only use Stderr
    Stderr,
    /// Use Stderr for Errors and Stdout otherwise
    Mixed,
}

impl Default for TerminalMode {
    fn default() -> TerminalMode {
        TerminalMode::Mixed
    }
}

/// The TermLogger struct. Provides a stderr/out based Logger implementation
///
/// Supports colored output
pub struct TermLogger {
    level: LevelFilter,
    config: Config,
    streams: Mutex<OutputStreams>,
}

impl TermLogger {
    /// init function. Globally initializes the TermLogger as the one and only used log facility.
    ///
    /// Takes the desired `Level` and `Config` as arguments. They cannot be changed later on.
    /// Fails if another Logger was already initialized
    ///
    /// # Examples
    /// ```
    /// # extern crate simplelog;
    /// # use simplelog::*;
    /// # fn main() {
    ///     TermLogger::init(
    ///         LevelFilter::Info,
    ///         Config::default(),
    ///         TerminalMode::Mixed,
    ///         ColorChoice::Auto
    ///     );
    /// # }
    /// ```
    pub fn init(
        log_level: LevelFilter,
        config: Config,
        mode: TerminalMode,
        color_choice: ColorChoice,
    ) -> Result<(), SetLoggerError> {
        let logger = TermLogger::new(log_level, config, mode, color_choice);
        set_max_level(log_level);
        set_boxed_logger(logger)?;
        Ok(())
    }

    /// allows to create a new logger, that can be independently used, no matter whats globally set.
    ///
    /// no macros are provided for this case and you probably
    /// dont want to use this function, but `init()`, if you dont want to build a `CombinedLogger`.
    ///
    /// Takes the desired `Level` and `Config` as arguments. They cannot be changed later on.
    ///
    /// Returns a `Box`ed TermLogger
    ///
    /// # Examples
    /// ```
    /// # extern crate simplelog;
    /// # use simplelog::*;
    /// # fn main() {
    /// let term_logger = TermLogger::new(
    ///     LevelFilter::Info,
    ///     Config::default(),
    ///     TerminalMode::Mixed,
    ///     ColorChoice::Auto
    /// );
    /// # }
    /// ```
    pub fn new(
        log_level: LevelFilter,
        config: Config,
        mode: TerminalMode,
        color_choice: ColorChoice,
    ) -> Box<TermLogger> {
        let streams = match mode {
            TerminalMode::Stdout => OutputStreams {
                err: StdTerminal::Stdout(Box::new(StandardStream::stdout(color_choice))),
                out: StdTerminal::Stdout(Box::new(StandardStream::stdout(color_choice))),
            },
            TerminalMode::Stderr => OutputStreams {
                err: StdTerminal::Stderr(Box::new(StandardStream::stderr(color_choice))),
                out: StdTerminal::Stderr(Box::new(StandardStream::stderr(color_choice))),
            },
            TerminalMode::Mixed => OutputStreams {
                err: StdTerminal::Stderr(Box::new(StandardStream::stderr(color_choice))),
                out: StdTerminal::Stdout(Box::new(StandardStream::stdout(color_choice))),
            },
        };

        Box::new(TermLogger {
            level: log_level,
            config,
            streams: Mutex::new(streams),
        })
    }

    fn try_log_term(
        &self,
        record: &Record<'_>,
        term_lock: &mut Box<dyn WriteColor + Send>,
    ) -> Result<(), Error> {
        let color = self.config.level_color[record.level() as usize];

        if self.config.time <= record.level() && self.config.time != LevelFilter::Off {
            write_time(&mut *term_lock, &self.config)?;
        }

        if self.config.level <= record.level() && self.config.level != LevelFilter::Off {
            term_lock.set_color(ColorSpec::new().set_fg(color))?;
            write_level(record, &mut *term_lock, &self.config)?;
            term_lock.reset()?;
        }

        if self.config.thread <= record.level() && self.config.thread != LevelFilter::Off {
            match self.config.thread_log_mode {
                ThreadLogMode::IDs => {
                    write_thread_id(&mut *term_lock, &self.config)?;
                }
                ThreadLogMode::Names | ThreadLogMode::Both => {
                    write_thread_name(&mut *term_lock, &self.config)?;
                }
            }
        }

        if self.config.target <= record.level() && self.config.target != LevelFilter::Off {
            write_target(record, &mut *term_lock)?;
        }

        if self.config.location <= record.level() && self.config.location != LevelFilter::Off {
            write_location(record, &mut *term_lock)?;
        }

        write_args(record, &mut *term_lock)
    }

    fn try_log(&self, record: &Record<'_>) -> Result<(), Error> {
        if self.enabled(record.metadata()) {
            if should_skip(&self.config, record) {
                return Ok(());
            }

            let mut streams = self.streams.lock().unwrap();

            if record.level() == Level::Error {
                match streams.err {
                    StdTerminal::Stderr(ref mut term) => self.try_log_term(record, term),
                    StdTerminal::Stdout(ref mut term) => self.try_log_term(record, term),
                }
            } else {
                match streams.out {
                    StdTerminal::Stderr(ref mut term) => self.try_log_term(record, term),
                    StdTerminal::Stdout(ref mut term) => self.try_log_term(record, term),
                }
            }
        } else {
            Ok(())
        }
    }
}

impl Log for TermLogger {
    fn enabled(&self, metadata: &Metadata<'_>) -> bool {
        metadata.level() <= self.level
    }

    fn log(&self, record: &Record<'_>) {
        let _ = self.try_log(record);
    }

    fn flush(&self) {
        let mut streams = self.streams.lock().unwrap();
        let _ = streams.out.flush();
        let _ = streams.err.flush();
    }
}

impl SharedLogger for TermLogger {
    fn level(&self) -> LevelFilter {
        self.level
    }

    fn config(&self) -> Option<&Config> {
        Some(&self.config)
    }

    fn as_log(self: Box<Self>) -> Box<dyn Log> {
        Box::new(*self)
    }
}
<|endoftext|>


<commit_before>extern crate cargotest;
extern crate hamcrest;

use cargotest::support::{project, execs, main_file, basic_bin_manifest};
use hamcrest::{assert_that};

static MANIFEST_OUTPUT: &'static str = r#"
{
    "name":"foo",
    "version":"0.5.0",
    "id":"foo[..]0.5.0[..](path+file://[..]/foo)",
    "license": null,
    "license_file": null,
    "source":null,
    "dependencies":[],
    "targets":[{
        "kind":["bin"],
        "name":"foo",
        "src_path":"[..][/]foo[/]src[/]foo.rs"
    }],
    "features":{},
    "manifest_path":"[..]Cargo.toml"
}"#;

#[test]
fn cargo_read_manifest_path_to_cargo_toml_relative() {
    let p = project("foo")
        .file("Cargo.toml", &basic_bin_manifest("foo"))
        .file("src/foo.rs", &main_file(r#""i am foo""#, &[]));

    assert_that(p.cargo_process("read-manifest")
                 .arg("--manifest-path").arg("foo/Cargo.toml")
                 .cwd(p.root().parent().unwrap()),
                execs().with_status(0)
                       .with_json(MANIFEST_OUTPUT));
}

#[test]
fn cargo_read_manifest_path_to_cargo_toml_absolute() {
    let p = project("foo")
        .file("Cargo.toml", &basic_bin_manifest("foo"))
        .file("src/foo.rs", &main_file(r#""i am foo""#, &[]));

    assert_that(p.cargo_process("read-manifest")
                 .arg("--manifest-path").arg(p.root().join("Cargo.toml"))
                 .cwd(p.root().parent().unwrap()),
                execs().with_status(0)
                       .with_json(MANIFEST_OUTPUT));
}

#[test]
fn cargo_read_manifest_path_to_cargo_toml_parent_relative() {
    let p = project("foo")
        .file("Cargo.toml", &basic_bin_manifest("foo"))
        .file("src/foo.rs", &main_file(r#""i am foo""#, &[]));

    assert_that(p.cargo_process("read-manifest")
                 .arg("--manifest-path").arg("foo")
                 .cwd(p.root().parent().unwrap()),
                execs().with_status(101)
                       .with_stderr("[ERROR] the manifest-path must be \
                                             a path to a Cargo.toml file"));
}

#[test]
fn cargo_read_manifest_path_to_cargo_toml_parent_absolute() {
    let p = project("foo")
        .file("Cargo.toml", &basic_bin_manifest("foo"))
        .file("src/foo.rs", &main_file(r#""i am foo""#, &[]));

    assert_that(p.cargo_process("read-manifest")
                 .arg("--manifest-path").arg(p.root())
                 .cwd(p.root().parent().unwrap()),
                execs().with_status(101)
                       .with_stderr("[ERROR] the manifest-path must be \
                                             a path to a Cargo.toml file"));
}

#[test]
fn cargo_read_manifest_cwd() {
    let p = project("foo")
        .file("Cargo.toml", &basic_bin_manifest("foo"))
        .file("src/foo.rs", &main_file(r#""i am foo""#, &[]));

    assert_that(p.cargo_process("read-manifest")
                 .cwd(p.root()),
                execs().with_status(0)
                       .with_json(MANIFEST_OUTPUT));
}
<commit_msg>Fixed failing read-metadata test due to addition of description.<commit_after>extern crate cargotest;
extern crate hamcrest;

use cargotest::support::{project, execs, main_file, basic_bin_manifest};
use hamcrest::{assert_that};

static MANIFEST_OUTPUT: &'static str = r#"
{
    "name":"foo",
    "version":"0.5.0",
    "id":"foo[..]0.5.0[..](path+file://[..]/foo)",
    "license": null,
    "license_file": null,
    "description": null,
    "source":null,
    "dependencies":[],
    "targets":[{
        "kind":["bin"],
        "name":"foo",
        "src_path":"[..][/]foo[/]src[/]foo.rs"
    }],
    "features":{},
    "manifest_path":"[..]Cargo.toml"
}"#;

#[test]
fn cargo_read_manifest_path_to_cargo_toml_relative() {
    let p = project("foo")
        .file("Cargo.toml", &basic_bin_manifest("foo"))
        .file("src/foo.rs", &main_file(r#""i am foo""#, &[]));

    assert_that(p.cargo_process("read-manifest")
                 .arg("--manifest-path").arg("foo/Cargo.toml")
                 .cwd(p.root().parent().unwrap()),
                execs().with_status(0)
                       .with_json(MANIFEST_OUTPUT));
}

#[test]
fn cargo_read_manifest_path_to_cargo_toml_absolute() {
    let p = project("foo")
        .file("Cargo.toml", &basic_bin_manifest("foo"))
        .file("src/foo.rs", &main_file(r#""i am foo""#, &[]));

    assert_that(p.cargo_process("read-manifest")
                 .arg("--manifest-path").arg(p.root().join("Cargo.toml"))
                 .cwd(p.root().parent().unwrap()),
                execs().with_status(0)
                       .with_json(MANIFEST_OUTPUT));
}

#[test]
fn cargo_read_manifest_path_to_cargo_toml_parent_relative() {
    let p = project("foo")
        .file("Cargo.toml", &basic_bin_manifest("foo"))
        .file("src/foo.rs", &main_file(r#""i am foo""#, &[]));

    assert_that(p.cargo_process("read-manifest")
                 .arg("--manifest-path").arg("foo")
                 .cwd(p.root().parent().unwrap()),
                execs().with_status(101)
                       .with_stderr("[ERROR] the manifest-path must be \
                                             a path to a Cargo.toml file"));
}

#[test]
fn cargo_read_manifest_path_to_cargo_toml_parent_absolute() {
    let p = project("foo")
        .file("Cargo.toml", &basic_bin_manifest("foo"))
        .file("src/foo.rs", &main_file(r#""i am foo""#, &[]));

    assert_that(p.cargo_process("read-manifest")
                 .arg("--manifest-path").arg(p.root())
                 .cwd(p.root().parent().unwrap()),
                execs().with_status(101)
                       .with_stderr("[ERROR] the manifest-path must be \
                                             a path to a Cargo.toml file"));
}

#[test]
fn cargo_read_manifest_cwd() {
    let p = project("foo")
        .file("Cargo.toml", &basic_bin_manifest("foo"))
        .file("src/foo.rs", &main_file(r#""i am foo""#, &[]));

    assert_that(p.cargo_process("read-manifest")
                 .cwd(p.root()),
                execs().with_status(0)
                       .with_json(MANIFEST_OUTPUT));
}
<|endoftext|>


<commit_before>use std::kinds::marker::ContravariantLifetime;
use std::mem;
use std::ptr;

use runtime::Object;
use {class, Id, IdVector};
use super::{INSCopying, INSObject};

pub struct NSRange {
	pub location: uint,
	pub length: uint,
}

pub struct NSEnumerator<'a, T> {
	id: Id<Object>,
	marker: ContravariantLifetime<'a>,
}

impl<'a, T> NSEnumerator<'a, T> {
	unsafe fn from_ptr(ptr: *Object) -> NSEnumerator<'a, T> {
		NSEnumerator { id: Id::from_ptr(ptr), marker: ContravariantLifetime }
	}
}

impl<'a, T> Iterator<&'a T> for NSEnumerator<'a, T> {
	fn next(&mut self) -> Option<&'a T> {
		unsafe {
			let obj = msg_send![self.id nextObject] as *T;
			obj.to_option()
		}
	}
}

pub trait INSArray<T: INSObject> : INSObject {
	fn count(&self) -> uint {
		let result = unsafe {
			msg_send![self count]
		};
		result as uint
	}

	fn object_at<'a>(&'a self, index: uint) -> &'a T {
		unsafe {
			let result = msg_send![self objectAtIndex:index] as *T;
			&*result
		}
	}

	fn object_enumerator<'a>(&'a self) -> NSEnumerator<'a, T> {
		unsafe {
			let result = msg_send![self objectEnumerator];
			NSEnumerator::from_ptr(result)
		}
	}

	unsafe fn from_refs(refs: &[&T]) -> Id<Self> {
		let cls = class::<Self>();
		let obj = msg_send![cls alloc];
		let obj = msg_send![obj initWithObjects:refs.as_ptr() count:refs.len()];
		Id::from_retained_ptr(obj as *Self)
	}

	fn from_vec(vec: Vec<Id<T>>) -> Id<Self> {
		let refs = vec.as_refs_slice();
		unsafe {
			INSArray::from_refs(refs)
		}
	}

	fn objects_in_range<'a>(&'a self, start: uint, len: uint) -> Vec<&'a T> {
		let vec: Vec<*T> = Vec::from_elem(len, ptr::null());
		let range = NSRange { location: start, length: len };
		unsafe {
			msg_send![self getObjects:vec.as_ptr() range:range];
			mem::transmute(vec)
		}
	}

	fn to_vec<'a>(&'a self) -> Vec<&'a T> {
		self.objects_in_range(0, self.count())
	}
}

object_struct!(NSArray<T>)

impl<T: INSObject> INSArray<T> for NSArray<T> { }

impl<T> INSCopying<NSArray<T>> for NSArray<T> { }

impl<T: INSObject> Collection for NSArray<T> {
	fn len(&self) -> uint {
		self.count()
	}
}

#[cfg(test)]
mod tests {
	use {Id};
	use foundation::{INSObject, NSObject};
	use super::{INSArray, NSArray};

	#[test]
	fn test_count() {
		let empty_array: Id<NSArray<NSObject>> = INSObject::new();
		assert!(empty_array.count() == 0);

		let vec: Vec<Id<NSObject>> = Vec::from_fn(4, |_| INSObject::new());
		let array: Id<NSArray<NSObject>> = INSArray::from_vec(vec);
		assert!(array.count() == 4);
	}

	#[test]
	fn test_object_at() {
		let vec: Vec<Id<NSObject>> = Vec::from_fn(4, |_| INSObject::new());
		let array: Id<NSArray<NSObject>> = INSArray::from_vec(vec);
		assert!(array.object_at(0) != array.object_at(3));
	}

	#[test]
	fn test_object_enumerator() {
		let vec: Vec<Id<NSObject>> = Vec::from_fn(4, |_| INSObject::new());
		let array: Id<NSArray<NSObject>> = INSArray::from_vec(vec);

		assert!(array.object_enumerator().count() == 4);
		assert!(array.object_enumerator()
		             .enumerate()
		             .all(|(i, obj)| obj == array.object_at(i)));
	}

	#[test]
	fn test_objects_in_range() {
		let vec: Vec<Id<NSObject>> = Vec::from_fn(4, |_| INSObject::new());
		let array: Id<NSArray<NSObject>> = INSArray::from_vec(vec);

		let middle_objs = array.objects_in_range(1, 2);
		assert!(middle_objs.len() == 2);
		assert!(*middle_objs.get(0) == array.object_at(1));
		assert!(*middle_objs.get(1) == array.object_at(2));

		let empty_objs = array.objects_in_range(1, 0);
		assert!(empty_objs.len() == 0);

		let all_objs = array.objects_in_range(0, 4);
		assert!(all_objs.len() == 4);
	}
}
<commit_msg>Added into_vec to NSArray.<commit_after>use std::kinds::marker::ContravariantLifetime;
use std::mem;
use std::ptr;

use runtime::Object;
use {class, Id, IdVector, IntoIdVector};
use super::{INSCopying, INSObject};

pub struct NSRange {
	pub location: uint,
	pub length: uint,
}

pub struct NSEnumerator<'a, T> {
	id: Id<Object>,
	marker: ContravariantLifetime<'a>,
}

impl<'a, T> NSEnumerator<'a, T> {
	unsafe fn from_ptr(ptr: *Object) -> NSEnumerator<'a, T> {
		NSEnumerator { id: Id::from_ptr(ptr), marker: ContravariantLifetime }
	}
}

impl<'a, T> Iterator<&'a T> for NSEnumerator<'a, T> {
	fn next(&mut self) -> Option<&'a T> {
		unsafe {
			let obj = msg_send![self.id nextObject] as *T;
			obj.to_option()
		}
	}
}

pub trait INSArray<T: INSObject> : INSObject {
	fn count(&self) -> uint {
		let result = unsafe {
			msg_send![self count]
		};
		result as uint
	}

	fn object_at<'a>(&'a self, index: uint) -> &'a T {
		unsafe {
			let result = msg_send![self objectAtIndex:index] as *T;
			&*result
		}
	}

	fn object_enumerator<'a>(&'a self) -> NSEnumerator<'a, T> {
		unsafe {
			let result = msg_send![self objectEnumerator];
			NSEnumerator::from_ptr(result)
		}
	}

	unsafe fn from_refs(refs: &[&T]) -> Id<Self> {
		let cls = class::<Self>();
		let obj = msg_send![cls alloc];
		let obj = msg_send![obj initWithObjects:refs.as_ptr() count:refs.len()];
		Id::from_retained_ptr(obj as *Self)
	}

	fn from_vec(vec: Vec<Id<T>>) -> Id<Self> {
		let refs = vec.as_refs_slice();
		unsafe {
			INSArray::from_refs(refs)
		}
	}

	fn objects_in_range<'a>(&'a self, start: uint, len: uint) -> Vec<&'a T> {
		let vec: Vec<*T> = Vec::from_elem(len, ptr::null());
		let range = NSRange { location: start, length: len };
		unsafe {
			msg_send![self getObjects:vec.as_ptr() range:range];
			mem::transmute(vec)
		}
	}

	fn to_vec<'a>(&'a self) -> Vec<&'a T> {
		self.objects_in_range(0, self.count())
	}

	fn into_vec(array: Id<Self>) -> Vec<Id<T>> {
		let vec = array.to_vec();
		unsafe {
			vec.into_id_vec()
		}
	}
}

object_struct!(NSArray<T>)

impl<T: INSObject> INSArray<T> for NSArray<T> { }

impl<T> INSCopying<NSArray<T>> for NSArray<T> { }

impl<T: INSObject> Collection for NSArray<T> {
	fn len(&self) -> uint {
		self.count()
	}
}

#[cfg(test)]
mod tests {
	use {Id};
	use foundation::{INSObject, NSObject};
	use super::{INSArray, NSArray};

	#[test]
	fn test_count() {
		let empty_array: Id<NSArray<NSObject>> = INSObject::new();
		assert!(empty_array.count() == 0);

		let vec: Vec<Id<NSObject>> = Vec::from_fn(4, |_| INSObject::new());
		let array: Id<NSArray<NSObject>> = INSArray::from_vec(vec);
		assert!(array.count() == 4);
	}

	#[test]
	fn test_object_at() {
		let vec: Vec<Id<NSObject>> = Vec::from_fn(4, |_| INSObject::new());
		let array: Id<NSArray<NSObject>> = INSArray::from_vec(vec);
		assert!(array.object_at(0) != array.object_at(3));
	}

	#[test]
	fn test_object_enumerator() {
		let vec: Vec<Id<NSObject>> = Vec::from_fn(4, |_| INSObject::new());
		let array: Id<NSArray<NSObject>> = INSArray::from_vec(vec);

		assert!(array.object_enumerator().count() == 4);
		assert!(array.object_enumerator()
		             .enumerate()
		             .all(|(i, obj)| obj == array.object_at(i)));
	}

	#[test]
	fn test_objects_in_range() {
		let vec: Vec<Id<NSObject>> = Vec::from_fn(4, |_| INSObject::new());
		let array: Id<NSArray<NSObject>> = INSArray::from_vec(vec);

		let middle_objs = array.objects_in_range(1, 2);
		assert!(middle_objs.len() == 2);
		assert!(*middle_objs.get(0) == array.object_at(1));
		assert!(*middle_objs.get(1) == array.object_at(2));

		let empty_objs = array.objects_in_range(1, 0);
		assert!(empty_objs.len() == 0);

		let all_objs = array.objects_in_range(0, 4);
		assert!(all_objs.len() == 4);
	}

	#[test]
	fn test_into_vec() {
		let vec: Vec<Id<NSObject>> = Vec::from_fn(4, |_| INSObject::new());
		let array: Id<NSArray<NSObject>> = INSArray::from_vec(vec);

		let vec = INSArray::into_vec(array);
		assert!(vec.len() == 4);
	}
}
<|endoftext|>


<commit_before>#![deny(clippy::all, clippy::pedantic)]

use std::fmt::{self, Debug, Display};
use thiserror::Error;

pub struct NoFormat;

#[derive(Debug)]
pub struct DebugOnly;

pub struct DisplayOnly;

impl Display for DisplayOnly {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("display only")
    }
}

#[derive(Debug)]
pub struct DebugAndDisplay;

impl Display for DebugAndDisplay {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("debug and display")
    }
}

// Should expand to:
//
//     impl<E> Display for EnumDebugField<E>
//     where
//         E: Debug;
//
//     impl<E> Error for EnumDebugField<E>
//     where
//         Self: Debug + Display;
//
#[derive(Error, Debug)]
pub enum EnumDebugGeneric<E> {
    #[error("{0:?}")]
    FatalError(E),
}

// Should expand to:
//
//     impl<E> Display for EnumFromGeneric<E>;
//
//     impl<E> Error for EnumFromGeneric<E>
//     where
//         EnumDebugGeneric<E>: Error + 'static,
//         Self: Debug + Display;
//
#[derive(Error, Debug)]
pub enum EnumFromGeneric<E> {
    #[error("enum from generic")]
    Source(#[from] EnumDebugGeneric<E>),
}

// Should expand to:
//
//     impl<HasDisplay, HasDebug, HasNeither> Display
//         for EnumCompound<HasDisplay, HasDebug, HasNeither>
//     where
//         HasDisplay: Display,
//         HasDebug: Debug;
//
//     impl<HasDisplay, HasDebug, HasNeither> Error
//         for EnumCompound<HasDisplay, HasDebug, HasNeither>
//     where
//         Self: Debug + Display;
//
#[derive(Error)]
pub enum EnumCompound<HasDisplay, HasDebug, HasNeither> {
    #[error("{0} {1:?}")]
    DisplayDebug(HasDisplay, HasDebug),
    #[error("{0}")]
    Display(HasDisplay, HasNeither),
    #[error("{1:?}")]
    Debug(HasNeither, HasDebug),
}

impl<HasDisplay, HasDebug, HasNeither> Debug for EnumCompound<HasDisplay, HasDebug, HasNeither> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("EnumCompound")
    }
}

#[test]
fn test_display_enum_compound() {
    let mut instance: EnumCompound<DisplayOnly, DebugOnly, NoFormat>;

    instance = EnumCompound::DisplayDebug(DisplayOnly, DebugOnly);
    assert_eq!(format!("{}", instance), "display only DebugOnly");

    instance = EnumCompound::Display(DisplayOnly, NoFormat);
    assert_eq!(format!("{}", instance), "display only");

    instance = EnumCompound::Debug(NoFormat, DebugOnly);
    assert_eq!(format!("{}", instance), "DebugOnly");
}

// Should expand to:
//
//     impl<E> Display for EnumTransparentGeneric<E>
//     where
//         E: Display;
//
//     impl<E> Error for EnumTransparentGeneric<E>
//     where
//         E: Error,
//         Self: Debug + Display;
//
#[derive(Error, Debug)]
pub enum EnumTransparentGeneric<E> {
    #[error(transparent)]
    Other(E),
}

// Should expand to:
//
//     impl<E> Display for StructDebugGeneric<E>
//     where
//         E: Debug;
//
//     impl<E> Error for StructDebugGeneric<E>
//     where
//         Self: Debug + Display;
//
#[derive(Error, Debug)]
#[error("{underlying:?}")]
pub struct StructDebugGeneric<E> {
    pub underlying: E,
}

// Should expand to:
//
//     impl<E> Error for StructFromGeneric<E>
//     where
//         StructDebugGeneric<E>: Error + 'static,
//         Self: Debug + Display;
//
#[derive(Error, Debug)]
pub struct StructFromGeneric<E> {
    #[from]
    pub source: StructDebugGeneric<E>,
}

// Should expand to:
//
//     impl<E> Display for StructTransparentGeneric<E>
//     where
//         E: Display;
//
//     impl<E> Error for StructTransparentGeneric<E>
//     where
//         E: Error,
//         Self: Debug + Display;
//
#[derive(Error, Debug)]
#[error(transparent)]
pub struct StructTransparentGeneric<E>(E);
<commit_msg>Ignore needless_late_init Clippy lint in test<commit_after>#![deny(clippy::all, clippy::pedantic)]
#![allow(clippy::needless_late_init)]

use std::fmt::{self, Debug, Display};
use thiserror::Error;

pub struct NoFormat;

#[derive(Debug)]
pub struct DebugOnly;

pub struct DisplayOnly;

impl Display for DisplayOnly {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("display only")
    }
}

#[derive(Debug)]
pub struct DebugAndDisplay;

impl Display for DebugAndDisplay {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("debug and display")
    }
}

// Should expand to:
//
//     impl<E> Display for EnumDebugField<E>
//     where
//         E: Debug;
//
//     impl<E> Error for EnumDebugField<E>
//     where
//         Self: Debug + Display;
//
#[derive(Error, Debug)]
pub enum EnumDebugGeneric<E> {
    #[error("{0:?}")]
    FatalError(E),
}

// Should expand to:
//
//     impl<E> Display for EnumFromGeneric<E>;
//
//     impl<E> Error for EnumFromGeneric<E>
//     where
//         EnumDebugGeneric<E>: Error + 'static,
//         Self: Debug + Display;
//
#[derive(Error, Debug)]
pub enum EnumFromGeneric<E> {
    #[error("enum from generic")]
    Source(#[from] EnumDebugGeneric<E>),
}

// Should expand to:
//
//     impl<HasDisplay, HasDebug, HasNeither> Display
//         for EnumCompound<HasDisplay, HasDebug, HasNeither>
//     where
//         HasDisplay: Display,
//         HasDebug: Debug;
//
//     impl<HasDisplay, HasDebug, HasNeither> Error
//         for EnumCompound<HasDisplay, HasDebug, HasNeither>
//     where
//         Self: Debug + Display;
//
#[derive(Error)]
pub enum EnumCompound<HasDisplay, HasDebug, HasNeither> {
    #[error("{0} {1:?}")]
    DisplayDebug(HasDisplay, HasDebug),
    #[error("{0}")]
    Display(HasDisplay, HasNeither),
    #[error("{1:?}")]
    Debug(HasNeither, HasDebug),
}

impl<HasDisplay, HasDebug, HasNeither> Debug for EnumCompound<HasDisplay, HasDebug, HasNeither> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("EnumCompound")
    }
}

#[test]
fn test_display_enum_compound() {
    let mut instance: EnumCompound<DisplayOnly, DebugOnly, NoFormat>;

    instance = EnumCompound::DisplayDebug(DisplayOnly, DebugOnly);
    assert_eq!(format!("{}", instance), "display only DebugOnly");

    instance = EnumCompound::Display(DisplayOnly, NoFormat);
    assert_eq!(format!("{}", instance), "display only");

    instance = EnumCompound::Debug(NoFormat, DebugOnly);
    assert_eq!(format!("{}", instance), "DebugOnly");
}

// Should expand to:
//
//     impl<E> Display for EnumTransparentGeneric<E>
//     where
//         E: Display;
//
//     impl<E> Error for EnumTransparentGeneric<E>
//     where
//         E: Error,
//         Self: Debug + Display;
//
#[derive(Error, Debug)]
pub enum EnumTransparentGeneric<E> {
    #[error(transparent)]
    Other(E),
}

// Should expand to:
//
//     impl<E> Display for StructDebugGeneric<E>
//     where
//         E: Debug;
//
//     impl<E> Error for StructDebugGeneric<E>
//     where
//         Self: Debug + Display;
//
#[derive(Error, Debug)]
#[error("{underlying:?}")]
pub struct StructDebugGeneric<E> {
    pub underlying: E,
}

// Should expand to:
//
//     impl<E> Error for StructFromGeneric<E>
//     where
//         StructDebugGeneric<E>: Error + 'static,
//         Self: Debug + Display;
//
#[derive(Error, Debug)]
pub struct StructFromGeneric<E> {
    #[from]
    pub source: StructDebugGeneric<E>,
}

// Should expand to:
//
//     impl<E> Display for StructTransparentGeneric<E>
//     where
//         E: Display;
//
//     impl<E> Error for StructTransparentGeneric<E>
//     where
//         E: Error,
//         Self: Debug + Display;
//
#[derive(Error, Debug)]
#[error(transparent)]
pub struct StructTransparentGeneric<E>(E);
<|endoftext|>


<commit_before>//! Operations on manifest files.

use std::error::Error;
use std::fmt::{self, Display, Formatter};
use std::io::{self, BufRead};
use std::path::{Path, PathBuf};
use std::str;

/// Manifest file info.
pub struct Manifest {
    hostname: String,
    local_dir: PathBuf,
    volumes: Vec<Option<Volume>>,
}

/// Volume info.
pub struct Volume {
    start_path: PathBuf,
    end_path: PathBuf,
    hash_type: String,
    hash: Vec<u8>,
}

/// wip
#[derive(Debug)]
pub enum ParseError {
    /// wip
    Io(io::Error),
    /// wip
    MissingHostname,
    /// wip
    MissingLocaldir,
}

struct ManifestParser<R> {
    input: R,
    buf: Vec<u8>,
    hostname: String,
    local_dir: Option<PathBuf>,
    volumes: Vec<Option<Volume>>,
}

impl Manifest {
    /// Parses a stream to get a manifest.
    pub fn parse<R: BufRead>(m: &mut R) -> Result<Self, ParseError> {
        let parser = ManifestParser::new(m);
        parser.parse()
    }

    /// wip
    pub fn hostname(&self) -> Option<&str> {
        Some(&self.hostname)
    }

    /// wip
    pub fn local_dir(&self) -> Option<&Path> {
        Some(&self.local_dir)
    }

    /// wip
    pub fn max_vol_num(&self) -> usize {
        self.volumes.len()
    }

    /// wip
    pub fn volume(&self, num: usize) -> Option<&Volume> {
        self.volumes.get(num).and_then(|v| v.as_ref())
    }
}

impl Error for ParseError {
    fn description(&self) -> &str {
        match *self {
            ParseError::Io(ref err) => err.description(),
            ParseError::MissingHostname => "missing 'Hostname' keyword",
            ParseError::MissingLocaldir => "missing 'Localdir' keyword",
        }
    }
}

impl Display for ParseError {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match *self {
            ParseError::Io(ref e) => write!(fmt, "{}", e),
            _ => write!(fmt, "{}", self.description()),
        }
    }
}

impl From<io::Error> for ParseError {
    fn from(err: io::Error) -> ParseError {
        ParseError::Io(err)
    }
}

impl<R: BufRead> ManifestParser<R> {
    pub fn new(input: R) -> Self {
        ManifestParser {
            input: input,
            buf: vec![],
            hostname: String::new(),
            local_dir: None,
            volumes: vec![],
        }
    }

    pub fn parse(mut self) -> Result<Manifest, ParseError> {
        // parse hostname
        if !try!(self.consume_keyword("Hostname")) {
            return Err(ParseError::MissingHostname);
        }
        try!(self.consume_whitespace());
        try!(self.input.read_line(&mut self.hostname));

        // parse localdir
        if !try!(self.consume_keyword("Localdir")) {
            return Err(ParseError::MissingLocaldir);
        }
        try!(self.consume_whitespace());

        // make result
        Ok(Manifest {
            hostname: self.hostname,
            local_dir: self.local_dir.unwrap(),
            volumes: self.volumes,
        })
    }

    fn consume_keyword(&mut self, key: &str) -> io::Result<bool> {
        try!(self.input.read_until(b' ', &mut self.buf));
        Ok(match_keyword(&self.buf, key))
    }

    fn consume_whitespace(&mut self) -> io::Result<()> {
        loop {
            let (pos, end) = {
                let buf = try!(self.input.fill_buf());
                match buf.iter().cloned().position(|b| b != b' ') {
                    Some(p) => (p, false),
                    None => (buf.len(), true),
                }
            };
            self.input.consume(pos);
            if end {
                return Ok(());
            }
        }
    }
}

#[inline]
fn match_keyword(buf: &[u8], key: &str) -> bool {
    str::from_utf8(&buf).ok().map_or(false, |s| s == key)
}
<commit_msg>Before manifest parser refactor<commit_after>//! Operations on manifest files.

use std::error::Error;
use std::fmt::{self, Display, Formatter};
use std::io::{self, BufRead};
use std::path::{Path, PathBuf};
use std::str;

/// Manifest file info.
pub struct Manifest {
    hostname: String,
    local_dir: PathBuf,
    volumes: Vec<Option<Volume>>,
}

/// Volume info.
pub struct Volume {
    start_path: PathBuf,
    end_path: PathBuf,
    hash_type: String,
    hash: Vec<u8>,
}

/// wip
#[derive(Debug)]
pub enum ParseError {
    /// wip
    Io(io::Error),
    /// wip
    MissingHostname,
    /// wip
    MissingLocaldir,
}

struct ManifestParser<R> {
    input: R,
    buf: Vec<u8>,
    hostname: String,
    local_dir: Option<PathBuf>,
    volumes: Vec<Option<Volume>>,
}

impl Manifest {
    /// Parses a stream to get a manifest.
    pub fn parse<R: BufRead>(m: &mut R) -> Result<Self, ParseError> {
        let parser = ManifestParser::new(m);
        parser.parse()
    }

    /// wip
    pub fn hostname(&self) -> Option<&str> {
        Some(&self.hostname)
    }

    /// wip
    pub fn local_dir(&self) -> Option<&Path> {
        Some(&self.local_dir)
    }

    /// wip
    pub fn max_vol_num(&self) -> usize {
        self.volumes.len()
    }

    /// wip
    pub fn volume(&self, num: usize) -> Option<&Volume> {
        self.volumes.get(num).and_then(|v| v.as_ref())
    }
}

impl Error for ParseError {
    fn description(&self) -> &str {
        match *self {
            ParseError::Io(ref err) => err.description(),
            ParseError::MissingHostname => "missing 'Hostname' keyword",
            ParseError::MissingLocaldir => "missing 'Localdir' keyword",
        }
    }
}

impl Display for ParseError {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match *self {
            ParseError::Io(ref e) => write!(fmt, "{}", e),
            _ => write!(fmt, "{}", self.description()),
        }
    }
}

impl From<io::Error> for ParseError {
    fn from(err: io::Error) -> ParseError {
        ParseError::Io(err)
    }
}

impl<R: BufRead> ManifestParser<R> {
    pub fn new(input: R) -> Self {
        ManifestParser {
            input: input,
            buf: vec![],
            hostname: String::new(),
            local_dir: None,
            volumes: vec![],
        }
    }

    pub fn parse(mut self) -> Result<Manifest, ParseError> {
        // parse hostname
        if !try!(self.consume_keyword("Hostname")) {
            return Err(ParseError::MissingHostname);
        }
        try!(self.consume_whitespace());
        try!(self.input.read_line(&mut self.hostname));

        // parse localdir
        if !try!(self.consume_keyword("Localdir")) {
            return Err(ParseError::MissingLocaldir);
        }
        try!(self.consume_whitespace());

        // make result
        Ok(Manifest {
            hostname: self.hostname,
            local_dir: self.local_dir.unwrap(),
            volumes: self.volumes,
        })
    }

    fn consume_keyword(&mut self, key: &str) -> io::Result<bool> {
        try!(self.input.read_until(b' ', &mut self.buf));
        Ok(match_keyword(&self.buf, key))
    }

    fn consume_whitespace(&mut self) -> io::Result<()> {
        loop {
            let (pos, end) = {
                let buf = try!(self.input.fill_buf());
                match buf.iter().cloned().position(|b| b != b' ') {
                    Some(p) => (p, true),
                    None => (buf.len(), buf.is_empty()),
                }
            };
            self.input.consume(pos);
            if end {
                return Ok(());
            }
        }
    }

    fn read_param(&mut self) -> io::Result<Vec<u8>> {
        if try!(self.consume_byte(b'"')) {
            try!(self.input.read_until(b'"', &mut self.buf));
        } else {
            try!(self.input.read_until(b'\n', &mut self.buf));
        }
        let mut result = Vec::with_capacity(self.buf.len());
        // unescape
        for (i, b) in self.buf.iter().cloned().enumerate() {
            if b != b'\\' {
                result.push(b);
            } else {
                let rest = self.buf.split_at(i).1;
                if rest.starts_with(b"\\") {
                    result.push(b'\\');
                } else if rest.starts_with(b"%20") {
                    result.push(b' ');
                } else if rest.starts_with(b"\"") {
                    result.push(b'"');
                }
            }
        }
        Ok(result)
    }

    fn consume_byte(&mut self, expected: u8) -> io::Result<bool> {
        let found = {
            let buf = try!(self.input.fill_buf());
            buf.first().map_or(false, |b| *b == expected)
        };
        if found {
            self.input.consume(1);
        }
        Ok(found)
    }
}

#[inline]
fn match_keyword(buf: &[u8], key: &str) -> bool {
    str::from_utf8(&buf).ok().map_or(false, |s| s == key)
}
<|endoftext|>


<commit_before>use crate::UNICODE_DIRECTORY;
use std::path::Path;
use std::process::Command;

static URL_PREFIX: &str = "https://www.unicode.org/Public/UCD/latest/ucd/";

static README: &str = "ReadMe.txt";

static RESOURCES: &[&str] =
    &["DerivedCoreProperties.txt", "PropList.txt", "UnicodeData.txt", "SpecialCasing.txt"];

pub fn fetch_latest() {
    let directory = Path::new(UNICODE_DIRECTORY);
    if let Err(e) = std::fs::create_dir_all(directory) {
        if e.kind() != std::io::ErrorKind::AlreadyExists {
            panic!("Failed to create {:?}: {}", UNICODE_DIRECTORY, e);
        }
    }
    let output = Command::new("curl").arg(URL_PREFIX.to_owned() + README).output().unwrap();
    if !output.status.success() {
        panic!(
            "Failed to run curl to fetch readme: stderr: {}",
            String::from_utf8_lossy(&output.stderr)
        );
    }
    let current = std::fs::read_to_string(directory.join(README)).unwrap_or_default();
    if current.as_bytes() != &output.stdout[..] {
        std::fs::write(directory.join(README), output.stdout).unwrap();
    }

    for resource in RESOURCES {
        let output = Command::new("curl").arg(URL_PREFIX.to_owned() + resource).output().unwrap();
        if !output.status.success() {
            panic!(
                "Failed to run curl to fetch {}: stderr: {}",
                resource,
                String::from_utf8_lossy(&output.stderr)
            );
        }
        std::fs::write(directory.join(resource), output.stdout).unwrap();
    }
}
<commit_msg>Avoid re-fetching Unicode data<commit_after>use crate::UNICODE_DIRECTORY;
use std::path::Path;
use std::process::Command;

static URL_PREFIX: &str = "https://www.unicode.org/Public/UCD/latest/ucd/";

static README: &str = "ReadMe.txt";

static RESOURCES: &[&str] =
    &["DerivedCoreProperties.txt", "PropList.txt", "UnicodeData.txt", "SpecialCasing.txt"];

pub fn fetch_latest() {
    let directory = Path::new(UNICODE_DIRECTORY);
    if directory.exists() {
        eprintln!(
            "Not refetching unicode data, already exists, please delete {:?} to regenerate",
            directory
        );
        return;
    }
    if let Err(e) = std::fs::create_dir_all(directory) {
        panic!("Failed to create {:?}: {}", UNICODE_DIRECTORY, e);
    }
    let output = Command::new("curl").arg(URL_PREFIX.to_owned() + README).output().unwrap();
    if !output.status.success() {
        panic!(
            "Failed to run curl to fetch readme: stderr: {}",
            String::from_utf8_lossy(&output.stderr)
        );
    }
    let current = std::fs::read_to_string(directory.join(README)).unwrap_or_default();
    if current.as_bytes() != &output.stdout[..] {
        std::fs::write(directory.join(README), output.stdout).unwrap();
    }

    for resource in RESOURCES {
        let output = Command::new("curl").arg(URL_PREFIX.to_owned() + resource).output().unwrap();
        if !output.status.success() {
            panic!(
                "Failed to run curl to fetch {}: stderr: {}",
                resource,
                String::from_utf8_lossy(&output.stderr)
            );
        }
        std::fs::write(directory.join(resource), output.stdout).unwrap();
    }
}
<|endoftext|>


<commit_before>//! Operations on manifest files.

use std::error::Error;
use std::fmt::{self, Display, Formatter};
use std::io::{self, BufRead};
use std::path::{Path, PathBuf};
use std::str;

/// Manifest file info.
pub struct Manifest {
    hostname: String,
    local_dir: PathBuf,
    volumes: Vec<Option<Volume>>,
}

/// Volume info.
pub struct Volume {
    start_path: PathBuf,
    end_path: PathBuf,
    hash_type: String,
    hash: Vec<u8>,
}

/// wip
#[derive(Debug)]
pub enum ParseError {
    /// wip
    Io(io::Error),
    /// wip
    MissingHostname,
    /// wip
    MissingLocaldir,
}

struct ManifestParser<R> {
    input: R,
    buf: Vec<u8>,
    hostname: String,
    local_dir: Option<PathBuf>,
    volumes: Vec<Option<Volume>>,
}

impl Manifest {
    /// Parses a stream to get a manifest.
    pub fn parse<R: BufRead>(m: &mut R) -> Result<Self, ParseError> {
        let parser = ManifestParser::new(m);
        parser.parse()
    }

    /// wip
    pub fn hostname(&self) -> Option<&str> {
        Some(&self.hostname)
    }

    /// wip
    pub fn local_dir(&self) -> Option<&Path> {
        Some(&self.local_dir)
    }

    /// wip
    pub fn max_vol_num(&self) -> usize {
        self.volumes.len()
    }

    /// wip
    pub fn volume(&self, num: usize) -> Option<&Volume> {
        self.volumes.get(num).and_then(|v| v.as_ref())
    }
}

impl Error for ParseError {
    fn description(&self) -> &str {
        match *self {
            ParseError::Io(ref err) => err.description(),
            ParseError::MissingHostname => "missing 'Hostname' keyword",
            ParseError::MissingLocaldir => "missing 'Localdir' keyword",
        }
    }
}

impl Display for ParseError {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match *self {
            ParseError::Io(ref e) => write!(fmt, "{}", e),
            _ => write!(fmt, "{}", self.description()),
        }
    }
}

impl From<io::Error> for ParseError {
    fn from(err: io::Error) -> ParseError {
        ParseError::Io(err)
    }
}

impl<R: BufRead> ManifestParser<R> {
    pub fn new(input: R) -> Self {
        ManifestParser {
            input: input,
            buf: vec![],
            hostname: String::new(),
            local_dir: None,
            volumes: vec![],
        }
    }

    pub fn parse(mut self) -> Result<Manifest, ParseError> {
        // parse hostname
        if !try!(self.consume_keyword("Hostname")) {
            return Err(ParseError::MissingHostname);
        }
        try!(self.consume_whitespace());
        try!(self.input.read_line(&mut self.hostname));

        // parse localdir
        if !try!(self.consume_keyword("Localdir")) {
            return Err(ParseError::MissingLocaldir);
        }
        try!(self.consume_whitespace());

        // make result
        Ok(Manifest {
            hostname: self.hostname,
            local_dir: self.local_dir.unwrap(),
            volumes: self.volumes,
        })
    }

    fn consume_keyword(&mut self, key: &str) -> io::Result<bool> {
        try!(self.input.read_until(b' ', &mut self.buf));
        Ok(match_keyword(&self.buf, key))
    }

    fn consume_whitespace(&mut self) -> io::Result<()> {
        loop {
            let (pos, end) = {
                let buf = try!(self.input.fill_buf());
                match buf.iter().cloned().position(|b| b != b' ') {
                    Some(p) => (p, true),
                    None => (buf.len(), buf.is_empty()),
                }
            };
            self.input.consume(pos);
            if end {
                return Ok(());
            }
        }
    }

    fn read_param(&mut self) -> io::Result<Vec<u8>> {
        if try!(self.consume_byte(b'"')) {
            try!(self.input.read_until(b'"', &mut self.buf));
        } else {
            try!(self.input.read_until(b'\n', &mut self.buf));
        }
        let mut result = Vec::with_capacity(self.buf.len());
        // unescape
        for (i, b) in self.buf.iter().cloned().enumerate() {
            if b != b'\\' {
                result.push(b);
            } else {
                // expects a \xNN where NN is a number string representing the escaped char
                // e.g. \x20 is the space ' '
                if self.buf.len() - i >= 4 && self.buf[i + 1] == b'x' {
                    let num = (self.buf[i + 2] - b'0') << 4 + self.buf[i + 3] - b'0';
                    result.push(b);
                }
            }
        }
        Ok(result)
    }

    fn consume_byte(&mut self, expected: u8) -> io::Result<bool> {
        let found = {
            let buf = try!(self.input.fill_buf());
            buf.first().map_or(false, |b| *b == expected)
        };
        if found {
            self.input.consume(1);
        }
        Ok(found)
    }
}

#[inline]
fn match_keyword(buf: &[u8], key: &str) -> bool {
    str::from_utf8(&buf).ok().map_or(false, |s| s == key)
}
<commit_msg>Refactor of params parsing<commit_after>//! Operations on manifest files.

use std::error::Error;
use std::fmt::{self, Display, Formatter};
use std::io::{self, BufRead};
use std::path::{Path, PathBuf};
use std::str;
use std::string::FromUtf8Error;

/// Manifest file info.
pub struct Manifest {
    hostname: String,
    local_dir: PathBuf,
    volumes: Vec<Option<Volume>>,
}

/// Volume info.
pub struct Volume {
    start_path: PathBuf,
    end_path: PathBuf,
    hash_type: String,
    hash: Vec<u8>,
}

/// wip
#[derive(Debug)]
pub enum ParseError {
    /// wip
    Io(io::Error),
    /// wip
    MissingKeyword(String),
    /// wip
    Utf8Error(FromUtf8Error),
}

struct ManifestParser<R> {
    input: R,
    buf: Vec<u8>,
    hostname: String,
    local_dir: Vec<u8>,
    volumes: Vec<Option<Volume>>,
}

impl Manifest {
    /// Parses a stream to get a manifest.
    pub fn parse<R: BufRead>(m: &mut R) -> Result<Self, ParseError> {
        let parser = ManifestParser::new(m);
        parser.parse()
    }

    /// wip
    pub fn hostname(&self) -> Option<&str> {
        Some(&self.hostname)
    }

    /// wip
    pub fn local_dir(&self) -> Option<&Path> {
        Some(&self.local_dir)
    }

    /// wip
    pub fn max_vol_num(&self) -> usize {
        self.volumes.len()
    }

    /// wip
    pub fn volume(&self, num: usize) -> Option<&Volume> {
        self.volumes.get(num).and_then(|v| v.as_ref())
    }
}

impl Error for ParseError {
    fn description(&self) -> &str {
        match *self {
            ParseError::Io(ref err) => err.description(),
            ParseError::MissingKeyword(_) => "missing keyword in manifest",
            ParseError::Utf8Error(ref err) => err.description(),
        }
    }
}

impl Display for ParseError {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match *self {
            ParseError::Io(ref e) => write!(fmt, "{}", e),
            ParseError::MissingKeyword(ref e) => write!(fmt, "missing keyword '{}' in manifest", e),
            ParseError::Utf8Error(ref e) => write!(fmt, "{}", e),
        }
    }
}

impl From<io::Error> for ParseError {
    fn from(err: io::Error) -> ParseError {
        ParseError::Io(err)
    }
}

impl From<FromUtf8Error> for ParseError {
    fn from(err: FromUtf8Error) -> ParseError {
        ParseError::Utf8Error(err)
    }
}

impl<R: BufRead> ManifestParser<R> {
    pub fn new(input: R) -> Self {
        ManifestParser {
            input: input,
            buf: vec![],
            hostname: String::new(),
            local_dir: vec![],
            volumes: vec![],
        }
    }

    pub fn parse(mut self) -> Result<Manifest, ParseError> {
        self.hostname = try!(self.read_param_str("Hostname"));
        self.local_dir = try!(self.read_param_bytes("Localdir"));

        // make result
        unimplemented!()
    }

    fn read_param_bytes(&mut self, key: &str) -> Result<Vec<u8>, ParseError> {
        try!(self.consume_whitespace());
        if !try!(self.consume_keyword(key)) {
            return Err(ParseError::MissingKeyword(key.to_owned()));
        }
        try!(self.consume_whitespace());
        self.read_param_value().map_err(From::from)
    }

    fn read_param_str(&mut self, key: &str) -> Result<String, ParseError> {
        let bytes = try!(self.read_param_bytes(key));
        String::from_utf8(bytes).map_err(From::from)
    }

    fn consume_keyword(&mut self, key: &str) -> io::Result<bool> {
        try!(self.input.read_until(b' ', &mut self.buf));
        Ok(match_keyword(&self.buf, key))
    }

    fn consume_whitespace(&mut self) -> io::Result<()> {
        loop {
            let (pos, end) = {
                let buf = try!(self.input.fill_buf());
                match buf.iter().cloned().position(|b| !is_whitespace(b)) {
                    Some(p) => (p, true),
                    None => (buf.len(), buf.is_empty()),
                }
            };
            self.input.consume(pos);
            if end {
                return Ok(());
            }
        }

        fn is_whitespace(b: u8) -> bool {
            match b {
                b' ' | b'\r' | b'\n' | b'\t' => true,
                _ => false,
            }
        };
    }

    fn read_param_value(&mut self) -> io::Result<Vec<u8>> {
        if try!(self.consume_byte(b'"')) {
            try!(self.input.read_until(b'"', &mut self.buf));
        } else {
            try!(self.input.read_until(b'\n', &mut self.buf));
        }
        let mut result = Vec::with_capacity(self.buf.len());
        // unescape
        for (i, b) in self.buf.iter().cloned().enumerate() {
            if b != b'\\' {
                result.push(b);
            } else {
                // expects a \xNN where NN is a number string representing the escaped char in hex
                // e.g. \x20 is the space ' '
                if self.buf.len() - i >= 4 && self.buf[i + 1] == b'x' {
                    let num = (self.buf[i + 2] - b'0') << 4 + self.buf[i + 3] - b'0';
                    result.push(num);
                }
            }
        }
        Ok(result)
    }

    fn consume_byte(&mut self, expected: u8) -> io::Result<bool> {
        let found = {
            let buf = try!(self.input.fill_buf());
            buf.first().map_or(false, |b| *b == expected)
        };
        if found {
            self.input.consume(1);
        }
        Ok(found)
    }
}

#[inline]
fn match_keyword(buf: &[u8], key: &str) -> bool {
    str::from_utf8(&buf).ok().map_or(false, |s| s == key)
}
<|endoftext|>