<commit_before>use super::*;

/// Represents lifetimes and type parameters attached to a declaration
/// of a function, enum, trait, etc.
#[derive(Debug, Clone, Eq, PartialEq, Default, Hash)]
pub struct Generics {
    pub lifetimes: Vec<LifetimeDef>,
    pub ty_params: Vec<TyParam>,
    pub where_clause: WhereClause,
}

#[cfg(feature = "printing")]
/// Returned by `Generics::split_for_impl`.
#[derive(Debug)]
pub struct ImplGenerics<'a>(&'a Generics);

#[cfg(feature = "printing")]
/// Returned by `Generics::split_for_impl`.
#[derive(Debug)]
pub struct TyGenerics<'a>(&'a Generics);

impl Generics {
    #[cfg(feature = "printing")]
    /// Split a type's generics into the pieces required for impl'ing a trait
    /// for that type.
    ///
    /// ```
    /// # extern crate syn;
    /// # #[macro_use]
    /// # extern crate quote;
    /// # fn main() {
    /// # let generics: syn::Generics = Default::default();
    /// # let name = syn::Ident::new("MyType");
    /// let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
    /// quote! {
    ///     impl #impl_generics MyTrait for #name #ty_generics #where_clause {
    ///         // ...
    ///     }
    /// }
    /// # ;
    /// # }
    /// ```
    pub fn split_for_impl(&self) -> (ImplGenerics, TyGenerics, &WhereClause) {
        (ImplGenerics(self), TyGenerics(self), &self.where_clause)
    }
}

#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Lifetime {
    pub ident: Ident,
}

impl Lifetime {
    pub fn new<T: Into<Ident>>(t: T) -> Self {
        let id = Ident::new(t);
        if !id.as_ref().starts_with('\'') {
            panic!("lifetime name must start with apostrophe as in \"'a\", \
                   got {:?}",
                   id.as_ref());
        }
        Lifetime { ident: id }
    }
}

/// A lifetime definition, e.g. `'a: 'b+'c+'d`
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct LifetimeDef {
    pub attrs: Vec<Attribute>,
    pub lifetime: Lifetime,
    pub bounds: Vec<Lifetime>,
}

impl LifetimeDef {
    pub fn new<T: Into<Ident>>(t: T) -> Self {
        LifetimeDef {
            attrs: Vec::new(),
            lifetime: Lifetime::new(t),
            bounds: Vec::new(),
        }
    }
}

#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct TyParam {
    pub attrs: Vec<Attribute>,
    pub ident: Ident,
    pub bounds: Vec<TyParamBound>,
    pub default: Option<Ty>,
}

/// The AST represents all type param bounds as types.
/// `typeck::collect::compute_bounds` matches these against
/// the "special" built-in traits (see `middle::lang_items`) and
/// detects Copy, Send and Sync.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum TyParamBound {
    Trait(PolyTraitRef, TraitBoundModifier),
    Region(Lifetime),
}

/// A modifier on a bound, currently this is only used for `?Sized`, where the
/// modifier is `Maybe`. Negative bounds should also be handled here.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum TraitBoundModifier {
    None,
    Maybe,
}

/// A `where` clause in a definition
#[derive(Debug, Clone, Eq, PartialEq, Default, Hash)]
pub struct WhereClause {
    pub predicates: Vec<WherePredicate>,
}

impl WhereClause {
    pub fn none() -> Self {
        WhereClause { predicates: Vec::new() }
    }
}

/// A single predicate in a `where` clause
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum WherePredicate {
    /// A type binding, e.g. `for<'c> Foo: Send+Clone+'c`
    BoundPredicate(WhereBoundPredicate),
    /// A lifetime predicate, e.g. `'a: 'b+'c`
    RegionPredicate(WhereRegionPredicate),
}

/// A type bound.
///
/// E.g. `for<'c> Foo: Send+Clone+'c`
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct WhereBoundPredicate {
    /// Any lifetimes from a `for` binding
    pub bound_lifetimes: Vec<LifetimeDef>,
    /// The type being bounded
    pub bounded_ty: Ty,
    /// Trait and lifetime bounds (`Clone+Send+'static`)
    pub bounds: Vec<TyParamBound>,
}

/// A lifetime predicate.
///
/// E.g. `'a: 'b+'c`
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct WhereRegionPredicate {
    pub lifetime: Lifetime,
    pub bounds: Vec<Lifetime>,
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;
    use attr::parsing::outer_attr;
    use ident::parsing::ident;
    use ty::parsing::{ty, poly_trait_ref};

    named!(pub generics -> Generics, map!(
        alt!(
            do_parse!(
                punct!("<") >>
                lifetimes: separated_list!(punct!(","), lifetime_def) >>
                ty_params: opt_vec!(preceded!(
                    cond!(!lifetimes.is_empty(), punct!(",")),
                    separated_nonempty_list!(punct!(","), ty_param)
                )) >>
                cond!(!lifetimes.is_empty() || !ty_params.is_empty(), option!(punct!(","))) >>
                punct!(">") >>
                (lifetimes, ty_params)
            )
            |
            epsilon!() => { |_| (Vec::new(), Vec::new()) }
        ),
        |(lifetimes, ty_params)| Generics {
            lifetimes: lifetimes,
            ty_params: ty_params,
            where_clause: Default::default(),
        }
    ));

    named!(pub lifetime -> Lifetime, preceded!(
        punct!("'"),
        alt!(
            map!(ident, |id| Lifetime {
                ident: format!("'{}", id).into(),
            })
            |
            map!(keyword!("static"), |_| Lifetime {
                ident: "'static".into(),
            })
        )
    ));

    named!(pub lifetime_def -> LifetimeDef, do_parse!(
        attrs: many0!(outer_attr) >>
        life: lifetime >>
        bounds: opt_vec!(preceded!(
            punct!(":"),
            separated_list!(punct!("+"), lifetime)
        )) >>
        (LifetimeDef {
            attrs: attrs,
            lifetime: life,
            bounds: bounds,
        })
    ));

    named!(pub bound_lifetimes -> Vec<LifetimeDef>, opt_vec!(do_parse!(
        keyword!("for") >>
        punct!("<") >>
        lifetimes: terminated_list!(punct!(","), lifetime_def) >>
        punct!(">") >>
        (lifetimes)
    )));

    named!(ty_param -> TyParam, do_parse!(
        attrs: many0!(outer_attr) >>
        id: ident >>
        bounds: opt_vec!(preceded!(
            punct!(":"),
            separated_nonempty_list!(punct!("+"), ty_param_bound)
        )) >>
        default: option!(preceded!(
            punct!("="),
            ty
        )) >>
        (TyParam {
            attrs: attrs,
            ident: id,
            bounds: bounds,
            default: default,
        })
    ));

    named!(pub ty_param_bound -> TyParamBound, alt!(
        preceded!(punct!("?"), poly_trait_ref) => {
            |poly| TyParamBound::Trait(poly, TraitBoundModifier::Maybe)
        }
        |
        lifetime => { TyParamBound::Region }
        |
        poly_trait_ref => {
            |poly| TyParamBound::Trait(poly, TraitBoundModifier::None)
        }
    ));

    named!(pub where_clause -> WhereClause, alt!(
        do_parse!(
            keyword!("where") >>
            predicates: separated_nonempty_list!(punct!(","), where_predicate) >>
            option!(punct!(",")) >>
            (WhereClause { predicates: predicates })
        )
        |
        epsilon!() => { |_| Default::default() }
    ));

    named!(where_predicate -> WherePredicate, alt!(
        do_parse!(
            ident: lifetime >>
            bounds: opt_vec!(preceded!(
                punct!(":"),
                separated_list!(punct!("+"), lifetime)
            )) >>
            (WherePredicate::RegionPredicate(WhereRegionPredicate {
                lifetime: ident,
                bounds: bounds,
            }))
        )
        |
        do_parse!(
            bound_lifetimes: bound_lifetimes >>
            bounded_ty: ty >>
            punct!(":") >>
            bounds: separated_nonempty_list!(punct!("+"), ty_param_bound) >>
            (WherePredicate::BoundPredicate(WhereBoundPredicate {
                bound_lifetimes: bound_lifetimes,
                bounded_ty: bounded_ty,
                bounds: bounds,
            }))
        )
    ));
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;
    use attr::FilterAttrs;
    use quote::{Tokens, ToTokens};

    impl ToTokens for Generics {
        fn to_tokens(&self, tokens: &mut Tokens) {
            let has_lifetimes = !self.lifetimes.is_empty();
            let has_ty_params = !self.ty_params.is_empty();
            if has_lifetimes || has_ty_params {
                tokens.append("<");
                tokens.append_separated(&self.lifetimes, ",");
                if has_lifetimes && has_ty_params {
                    tokens.append(",");
                }
                tokens.append_separated(&self.ty_params, ",");
                tokens.append(">");
            }
        }
    }

    impl<'a> ToTokens for ImplGenerics<'a> {
        fn to_tokens(&self, tokens: &mut Tokens) {
            let has_lifetimes = !self.0.lifetimes.is_empty();
            let has_ty_params = !self.0.ty_params.is_empty();
            if has_lifetimes || has_ty_params {
                tokens.append("<");
                tokens.append_separated(&self.0.lifetimes, ",");
                // Leave off the type parameter defaults
                for (i, ty_param) in self.0.ty_params.iter().enumerate() {
                    if i > 0 || has_lifetimes {
                        tokens.append(",");
                    }
                    tokens.append_all(ty_param.attrs.outer());
                    ty_param.ident.to_tokens(tokens);
                    if !ty_param.bounds.is_empty() {
                        tokens.append(":");
                        tokens.append_separated(&ty_param.bounds, "+");
                    }
                }
                tokens.append(">");
            }
        }
    }

    impl<'a> ToTokens for TyGenerics<'a> {
        fn to_tokens(&self, tokens: &mut Tokens) {
            let has_lifetimes = !self.0.lifetimes.is_empty();
            let has_ty_params = !self.0.ty_params.is_empty();
            if has_lifetimes || has_ty_params {
                tokens.append("<");
                // Leave off the lifetime bounds and attributes
                let lifetimes = self.0.lifetimes.iter().map(|ld| &ld.lifetime);
                tokens.append_separated(lifetimes, ",");
                if has_lifetimes && has_ty_params {
                    tokens.append(",");
                }
                // Leave off the type parameter bounds, defaults, and attributes
                let ty_params = self.0.ty_params.iter().map(|tp| &tp.ident);
                tokens.append_separated(ty_params, ",");
                tokens.append(">");
            }
        }
    }

    impl ToTokens for Lifetime {
        fn to_tokens(&self, tokens: &mut Tokens) {
            self.ident.to_tokens(tokens);
        }
    }

    impl ToTokens for LifetimeDef {
        fn to_tokens(&self, tokens: &mut Tokens) {
            tokens.append_all(self.attrs.outer());
            self.lifetime.to_tokens(tokens);
            if !self.bounds.is_empty() {
                tokens.append(":");
                tokens.append_separated(&self.bounds, "+");
            }
        }
    }

    impl ToTokens for TyParam {
        fn to_tokens(&self, tokens: &mut Tokens) {
            tokens.append_all(self.attrs.outer());
            self.ident.to_tokens(tokens);
            if !self.bounds.is_empty() {
                tokens.append(":");
                tokens.append_separated(&self.bounds, "+");
            }
            if let Some(ref default) = self.default {
                tokens.append("=");
                default.to_tokens(tokens);
            }
        }
    }

    impl ToTokens for TyParamBound {
        fn to_tokens(&self, tokens: &mut Tokens) {
            match *self {
                TyParamBound::Region(ref lifetime) => lifetime.to_tokens(tokens),
                TyParamBound::Trait(ref trait_ref, modifier) => {
                    match modifier {
                        TraitBoundModifier::None => {}
                        TraitBoundModifier::Maybe => tokens.append("?"),
                    }
                    trait_ref.to_tokens(tokens);
                }
            }
        }
    }

    impl ToTokens for WhereClause {
        fn to_tokens(&self, tokens: &mut Tokens) {
            if !self.predicates.is_empty() {
                tokens.append("where");
                tokens.append_separated(&self.predicates, ",");
            }
        }
    }

    impl ToTokens for WherePredicate {
        fn to_tokens(&self, tokens: &mut Tokens) {
            match *self {
                WherePredicate::BoundPredicate(ref predicate) => {
                    predicate.to_tokens(tokens);
                }
                WherePredicate::RegionPredicate(ref predicate) => {
                    predicate.to_tokens(tokens);
                }
            }
        }
    }

    impl ToTokens for WhereBoundPredicate {
        fn to_tokens(&self, tokens: &mut Tokens) {
            if !self.bound_lifetimes.is_empty() {
                tokens.append("for");
                tokens.append("<");
                tokens.append_separated(&self.bound_lifetimes, ",");
                tokens.append(">");
            }
            self.bounded_ty.to_tokens(tokens);
            if !self.bounds.is_empty() {
                tokens.append(":");
                tokens.append_separated(&self.bounds, "+");
            }
        }
    }

    impl ToTokens for WhereRegionPredicate {
        fn to_tokens(&self, tokens: &mut Tokens) {
            self.lifetime.to_tokens(tokens);
            if !self.bounds.is_empty() {
                tokens.append(":");
                tokens.append_separated(&self.bounds, "+");
            }
        }
    }
}
<commit_msg>Equality predicate<commit_after>use super::*;

/// Represents lifetimes and type parameters attached to a declaration
/// of a function, enum, trait, etc.
#[derive(Debug, Clone, Eq, PartialEq, Default, Hash)]
pub struct Generics {
    pub lifetimes: Vec<LifetimeDef>,
    pub ty_params: Vec<TyParam>,
    pub where_clause: WhereClause,
}

#[cfg(feature = "printing")]
/// Returned by `Generics::split_for_impl`.
#[derive(Debug)]
pub struct ImplGenerics<'a>(&'a Generics);

#[cfg(feature = "printing")]
/// Returned by `Generics::split_for_impl`.
#[derive(Debug)]
pub struct TyGenerics<'a>(&'a Generics);

impl Generics {
    #[cfg(feature = "printing")]
    /// Split a type's generics into the pieces required for impl'ing a trait
    /// for that type.
    ///
    /// ```
    /// # extern crate syn;
    /// # #[macro_use]
    /// # extern crate quote;
    /// # fn main() {
    /// # let generics: syn::Generics = Default::default();
    /// # let name = syn::Ident::new("MyType");
    /// let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
    /// quote! {
    ///     impl #impl_generics MyTrait for #name #ty_generics #where_clause {
    ///         // ...
    ///     }
    /// }
    /// # ;
    /// # }
    /// ```
    pub fn split_for_impl(&self) -> (ImplGenerics, TyGenerics, &WhereClause) {
        (ImplGenerics(self), TyGenerics(self), &self.where_clause)
    }
}

#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct Lifetime {
    pub ident: Ident,
}

impl Lifetime {
    pub fn new<T: Into<Ident>>(t: T) -> Self {
        let id = Ident::new(t);
        if !id.as_ref().starts_with('\'') {
            panic!("lifetime name must start with apostrophe as in \"'a\", \
                   got {:?}",
                   id.as_ref());
        }
        Lifetime { ident: id }
    }
}

/// A lifetime definition, e.g. `'a: 'b+'c+'d`
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct LifetimeDef {
    pub attrs: Vec<Attribute>,
    pub lifetime: Lifetime,
    pub bounds: Vec<Lifetime>,
}

impl LifetimeDef {
    pub fn new<T: Into<Ident>>(t: T) -> Self {
        LifetimeDef {
            attrs: Vec::new(),
            lifetime: Lifetime::new(t),
            bounds: Vec::new(),
        }
    }
}

#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct TyParam {
    pub attrs: Vec<Attribute>,
    pub ident: Ident,
    pub bounds: Vec<TyParamBound>,
    pub default: Option<Ty>,
}

/// The AST represents all type param bounds as types.
/// `typeck::collect::compute_bounds` matches these against
/// the "special" built-in traits (see `middle::lang_items`) and
/// detects Copy, Send and Sync.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum TyParamBound {
    Trait(PolyTraitRef, TraitBoundModifier),
    Region(Lifetime),
}

/// A modifier on a bound, currently this is only used for `?Sized`, where the
/// modifier is `Maybe`. Negative bounds should also be handled here.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum TraitBoundModifier {
    None,
    Maybe,
}

/// A `where` clause in a definition
#[derive(Debug, Clone, Eq, PartialEq, Default, Hash)]
pub struct WhereClause {
    pub predicates: Vec<WherePredicate>,
}

impl WhereClause {
    pub fn none() -> Self {
        WhereClause { predicates: Vec::new() }
    }
}

/// A single predicate in a `where` clause
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum WherePredicate {
    /// A type binding, e.g. `for<'c> Foo: Send+Clone+'c`
    BoundPredicate(WhereBoundPredicate),
    /// A lifetime predicate, e.g. `'a: 'b+'c`
    RegionPredicate(WhereRegionPredicate),
    /// An equality predicate (unsupported)
    EqPredicate(WhereEqPredicate),
}

/// A type bound.
///
/// E.g. `for<'c> Foo: Send+Clone+'c`
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct WhereBoundPredicate {
    /// Any lifetimes from a `for` binding
    pub bound_lifetimes: Vec<LifetimeDef>,
    /// The type being bounded
    pub bounded_ty: Ty,
    /// Trait and lifetime bounds (`Clone+Send+'static`)
    pub bounds: Vec<TyParamBound>,
}

/// A lifetime predicate.
///
/// E.g. `'a: 'b+'c`
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct WhereRegionPredicate {
    pub lifetime: Lifetime,
    pub bounds: Vec<Lifetime>,
}

/// An equality predicate (unsupported).
///
/// E.g. `T=int`
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct WhereEqPredicate {
    pub lhs_ty: Ty,
    pub rhs_ty: Ty,
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;
    use attr::parsing::outer_attr;
    use ident::parsing::ident;
    use ty::parsing::{ty, poly_trait_ref};

    named!(pub generics -> Generics, map!(
        alt!(
            do_parse!(
                punct!("<") >>
                lifetimes: separated_list!(punct!(","), lifetime_def) >>
                ty_params: opt_vec!(preceded!(
                    cond!(!lifetimes.is_empty(), punct!(",")),
                    separated_nonempty_list!(punct!(","), ty_param)
                )) >>
                cond!(!lifetimes.is_empty() || !ty_params.is_empty(), option!(punct!(","))) >>
                punct!(">") >>
                (lifetimes, ty_params)
            )
            |
            epsilon!() => { |_| (Vec::new(), Vec::new()) }
        ),
        |(lifetimes, ty_params)| Generics {
            lifetimes: lifetimes,
            ty_params: ty_params,
            where_clause: Default::default(),
        }
    ));

    named!(pub lifetime -> Lifetime, preceded!(
        punct!("'"),
        alt!(
            map!(ident, |id| Lifetime {
                ident: format!("'{}", id).into(),
            })
            |
            map!(keyword!("static"), |_| Lifetime {
                ident: "'static".into(),
            })
        )
    ));

    named!(pub lifetime_def -> LifetimeDef, do_parse!(
        attrs: many0!(outer_attr) >>
        life: lifetime >>
        bounds: opt_vec!(preceded!(
            punct!(":"),
            separated_list!(punct!("+"), lifetime)
        )) >>
        (LifetimeDef {
            attrs: attrs,
            lifetime: life,
            bounds: bounds,
        })
    ));

    named!(pub bound_lifetimes -> Vec<LifetimeDef>, opt_vec!(do_parse!(
        keyword!("for") >>
        punct!("<") >>
        lifetimes: terminated_list!(punct!(","), lifetime_def) >>
        punct!(">") >>
        (lifetimes)
    )));

    named!(ty_param -> TyParam, do_parse!(
        attrs: many0!(outer_attr) >>
        id: ident >>
        bounds: opt_vec!(preceded!(
            punct!(":"),
            separated_nonempty_list!(punct!("+"), ty_param_bound)
        )) >>
        default: option!(preceded!(
            punct!("="),
            ty
        )) >>
        (TyParam {
            attrs: attrs,
            ident: id,
            bounds: bounds,
            default: default,
        })
    ));

    named!(pub ty_param_bound -> TyParamBound, alt!(
        preceded!(punct!("?"), poly_trait_ref) => {
            |poly| TyParamBound::Trait(poly, TraitBoundModifier::Maybe)
        }
        |
        lifetime => { TyParamBound::Region }
        |
        poly_trait_ref => {
            |poly| TyParamBound::Trait(poly, TraitBoundModifier::None)
        }
    ));

    named!(pub where_clause -> WhereClause, alt!(
        do_parse!(
            keyword!("where") >>
            predicates: separated_nonempty_list!(punct!(","), where_predicate) >>
            option!(punct!(",")) >>
            (WhereClause { predicates: predicates })
        )
        |
        epsilon!() => { |_| Default::default() }
    ));

    named!(where_predicate -> WherePredicate, alt!(
        do_parse!(
            ident: lifetime >>
            bounds: opt_vec!(preceded!(
                punct!(":"),
                separated_list!(punct!("+"), lifetime)
            )) >>
            (WherePredicate::RegionPredicate(WhereRegionPredicate {
                lifetime: ident,
                bounds: bounds,
            }))
        )
        |
        do_parse!(
            bound_lifetimes: bound_lifetimes >>
            bounded_ty: ty >>
            punct!(":") >>
            bounds: separated_nonempty_list!(punct!("+"), ty_param_bound) >>
            (WherePredicate::BoundPredicate(WhereBoundPredicate {
                bound_lifetimes: bound_lifetimes,
                bounded_ty: bounded_ty,
                bounds: bounds,
            }))
        )
    ));
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;
    use attr::FilterAttrs;
    use quote::{Tokens, ToTokens};

    impl ToTokens for Generics {
        fn to_tokens(&self, tokens: &mut Tokens) {
            let has_lifetimes = !self.lifetimes.is_empty();
            let has_ty_params = !self.ty_params.is_empty();
            if has_lifetimes || has_ty_params {
                tokens.append("<");
                tokens.append_separated(&self.lifetimes, ",");
                if has_lifetimes && has_ty_params {
                    tokens.append(",");
                }
                tokens.append_separated(&self.ty_params, ",");
                tokens.append(">");
            }
        }
    }

    impl<'a> ToTokens for ImplGenerics<'a> {
        fn to_tokens(&self, tokens: &mut Tokens) {
            let has_lifetimes = !self.0.lifetimes.is_empty();
            let has_ty_params = !self.0.ty_params.is_empty();
            if has_lifetimes || has_ty_params {
                tokens.append("<");
                tokens.append_separated(&self.0.lifetimes, ",");
                // Leave off the type parameter defaults
                for (i, ty_param) in self.0.ty_params.iter().enumerate() {
                    if i > 0 || has_lifetimes {
                        tokens.append(",");
                    }
                    tokens.append_all(ty_param.attrs.outer());
                    ty_param.ident.to_tokens(tokens);
                    if !ty_param.bounds.is_empty() {
                        tokens.append(":");
                        tokens.append_separated(&ty_param.bounds, "+");
                    }
                }
                tokens.append(">");
            }
        }
    }

    impl<'a> ToTokens for TyGenerics<'a> {
        fn to_tokens(&self, tokens: &mut Tokens) {
            let has_lifetimes = !self.0.lifetimes.is_empty();
            let has_ty_params = !self.0.ty_params.is_empty();
            if has_lifetimes || has_ty_params {
                tokens.append("<");
                // Leave off the lifetime bounds and attributes
                let lifetimes = self.0.lifetimes.iter().map(|ld| &ld.lifetime);
                tokens.append_separated(lifetimes, ",");
                if has_lifetimes && has_ty_params {
                    tokens.append(",");
                }
                // Leave off the type parameter bounds, defaults, and attributes
                let ty_params = self.0.ty_params.iter().map(|tp| &tp.ident);
                tokens.append_separated(ty_params, ",");
                tokens.append(">");
            }
        }
    }

    impl ToTokens for Lifetime {
        fn to_tokens(&self, tokens: &mut Tokens) {
            self.ident.to_tokens(tokens);
        }
    }

    impl ToTokens for LifetimeDef {
        fn to_tokens(&self, tokens: &mut Tokens) {
            tokens.append_all(self.attrs.outer());
            self.lifetime.to_tokens(tokens);
            if !self.bounds.is_empty() {
                tokens.append(":");
                tokens.append_separated(&self.bounds, "+");
            }
        }
    }

    impl ToTokens for TyParam {
        fn to_tokens(&self, tokens: &mut Tokens) {
            tokens.append_all(self.attrs.outer());
            self.ident.to_tokens(tokens);
            if !self.bounds.is_empty() {
                tokens.append(":");
                tokens.append_separated(&self.bounds, "+");
            }
            if let Some(ref default) = self.default {
                tokens.append("=");
                default.to_tokens(tokens);
            }
        }
    }

    impl ToTokens for TyParamBound {
        fn to_tokens(&self, tokens: &mut Tokens) {
            match *self {
                TyParamBound::Region(ref lifetime) => lifetime.to_tokens(tokens),
                TyParamBound::Trait(ref trait_ref, modifier) => {
                    match modifier {
                        TraitBoundModifier::None => {}
                        TraitBoundModifier::Maybe => tokens.append("?"),
                    }
                    trait_ref.to_tokens(tokens);
                }
            }
        }
    }

    impl ToTokens for WhereClause {
        fn to_tokens(&self, tokens: &mut Tokens) {
            if !self.predicates.is_empty() {
                tokens.append("where");
                tokens.append_separated(&self.predicates, ",");
            }
        }
    }

    impl ToTokens for WherePredicate {
        fn to_tokens(&self, tokens: &mut Tokens) {
            match *self {
                WherePredicate::BoundPredicate(ref predicate) => {
                    predicate.to_tokens(tokens);
                }
                WherePredicate::RegionPredicate(ref predicate) => {
                    predicate.to_tokens(tokens);
                }
                WherePredicate::EqPredicate(ref predicate) => {
                    predicate.to_tokens(tokens);
                }
            }
        }
    }

    impl ToTokens for WhereBoundPredicate {
        fn to_tokens(&self, tokens: &mut Tokens) {
            if !self.bound_lifetimes.is_empty() {
                tokens.append("for");
                tokens.append("<");
                tokens.append_separated(&self.bound_lifetimes, ",");
                tokens.append(">");
            }
            self.bounded_ty.to_tokens(tokens);
            if !self.bounds.is_empty() {
                tokens.append(":");
                tokens.append_separated(&self.bounds, "+");
            }
        }
    }

    impl ToTokens for WhereRegionPredicate {
        fn to_tokens(&self, tokens: &mut Tokens) {
            self.lifetime.to_tokens(tokens);
            if !self.bounds.is_empty() {
                tokens.append(":");
                tokens.append_separated(&self.bounds, "+");
            }
        }
    }

    impl ToTokens for WhereEqPredicate {
        fn to_tokens(&self, tokens: &mut Tokens) {
            self.lhs_ty.to_tokens(tokens);
            tokens.append("=");
            self.rhs_ty.to_tokens(tokens);
        }
    }
}
<|endoftext|>


<commit_before>use glob::glob;
use serde_json;
use std;
use std::collections::HashMap;
use std::fs::File;
use std::io::prelude::*;
use structs::{CliError, Config, Member, PublicKey, Repo, Sector, SectorGroup, Team};

use futures::future::Future;
use futures::stream::Stream;
use hyper::{header, Client, Method, Request};
use hyper_rustls::HttpsConnector;
use tokio_core::reactor;

pub struct GithubClient {
    conf: Config,
}

impl GithubClient {
    pub fn new(config: &Config) -> GithubClient {
        if std::env::var("SSL_CERT_FILE").is_err() {
            std::env::set_var("SSL_CERT_FILE", &config.cert_path);
        }
        GithubClient { conf: config.clone() }
    }

    fn get_cache_path(url: &str) -> std::path::PathBuf {
        let mut path = std::env::temp_dir();
        path.push("sectora-cache");
        path.push(url);
        path
    }

    fn load_content_from_cache(&self, url: &str) -> Result<(std::fs::Metadata, String), CliError> {
        let path = Self::get_cache_path(url);
        let metadata = std::fs::metadata(path.to_str().unwrap())?;
        let mut f = File::open(path.to_str().unwrap())?;
        let mut content = String::new();
        f.read_to_string(&mut content)?;
        Ok((metadata, content))
    }

    fn store_content_to_cache(&self, url: &str, content: &str) -> Result<(), CliError> {
        let path = Self::get_cache_path(url);
        std::fs::create_dir_all(path.parent().unwrap())?;
        let mut f = File::create(path.to_str().unwrap())?;
        f.write(content.as_bytes())?;
        Ok(())
    }

    fn get_content_from_url(&self, url: &str) -> Result<String, CliError> {
        let mut all_contents: Vec<serde_json::value::Value> = Vec::new();
        let mut page = 1;
        loop {
            let mut new_array = self.get_content_from_url_page(url, page)?;
            if new_array.is_empty() {
                break;
            }
            all_contents.append(&mut new_array);
            page += 1;
        }
        let content = serde_json::ser::to_string(&all_contents)?;
        self.store_content_to_cache(url, &content)?;
        Ok(content)
    }

    fn get_content_from_url_page(&self, url: &str, page: u64) -> Result<Vec<serde_json::value::Value>, CliError> {
        let token = String::from("token ") + &self.conf.token;
        let sep = if url.contains("?") { "&" } else { "?" };
        let url_p = format!("{}{}page={}", url, sep, page);
        let mut req: Request = Request::new(Method::Get, url_p.parse().unwrap());
        req.headers_mut().set(header::Authorization(token));
        req.headers_mut().set(header::UserAgent::new("sectora"));
        let mut core = reactor::Core::new()?;
        let client = Client::configure().connector(HttpsConnector::new(4, &core.handle()))
                                        .build(&core.handle());
        let work = client.request(req).and_then(|res| {
            res.body().concat2().and_then(move |body| {
                let v =
                    serde_json::from_slice::<Vec<serde_json::value::Value>>(&body).map_err(|_| std::io::Error::new(std::io::ErrorKind::Other, format!("output:{:?}", body)))?;
                Ok(v)
            })
        });
        Ok(core.run(work)?)
    }

    fn get_content(&self, url: &str) -> Result<String, CliError> {
        match self.load_content_from_cache(url) {
            Ok((metadata, cache_content)) => match std::time::SystemTime::now().duration_since(metadata.modified()?) {
                Ok(caching_duration) => {
                    if caching_duration.as_secs() > self.conf.cache_duration {
                        match self.get_content_from_url(url) {
                            Ok(content_from_url) => Ok(content_from_url),
                            Err(_) => Ok(cache_content),
                        }
                    } else {
                        Ok(cache_content)
                    }
                }
                Err(_) => Ok(cache_content),
            },
            Err(_) => self.get_content_from_url(url),
        }
    }

    #[allow(dead_code)]
    pub fn print_user_public_key(&self, user: &str) -> Result<(), CliError> {
        let keys = self.get_user_public_key(user)?;
        println!("{}", keys);
        Ok(())
    }

    fn get_user_public_key(&self, user: &str) -> Result<String, CliError> {
        let url = format!("{}/users/{}/keys", self.conf.endpoint, user);
        let content = self.get_content(&url)?;
        let keys = serde_json::from_str::<Vec<PublicKey>>(&content)?;
        Ok(keys.iter().map(|k| k.key.clone()).collect::<Vec<String>>().join("\n"))
    }

    #[allow(dead_code)]
    pub fn check_pam(&self, user: &str) -> Result<bool, CliError> {
        let sectors = self.get_sectors()?;
        Ok(sectors.iter().any(|team| team.members.contains_key(user)))
    }

    pub fn get_sectors(&self) -> Result<Vec<SectorGroup>, CliError> {
        let mut sectors: Vec<SectorGroup> = self.get_teams_result()?;
        sectors.append(&mut self.get_repos_result()?);
        Ok(sectors)
    }

    fn get_teams_result(&self) -> Result<Vec<SectorGroup>, CliError> {
        let gh_teams = self.get_team_map()?;
        let mut teams = Vec::new();
        for team_conf in &self.conf.team {
            if let &Some(gh_team) = &gh_teams.get(&team_conf.name) {
                teams.push(SectorGroup { sector: Sector::from(gh_team.clone()),
                                         gid: team_conf.gid.clone(),
                                         group: team_conf.group.clone(),
                                         members: self.get_team_members(gh_team.id)?, });
            }
        }
        Ok(teams)
    }

    fn get_team_map(&self) -> Result<HashMap<String, Team>, CliError> {
        let url = format!("{}/orgs/{}/teams", self.conf.endpoint, self.conf.org);
        let content = self.get_content(&url)?;
        let teams = serde_json::from_str::<Vec<Team>>(&content)?;
        Ok(teams.iter().map(|t| (t.name.clone(), t.clone())).collect())
    }

    fn get_team_members(&self, mid: u64) -> Result<HashMap<String, Member>, CliError> {
        let url = format!("{}/teams/{}/members", self.conf.endpoint, mid);
        let content = self.get_content(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(&content)?;
        Ok(members.iter().map(|m| (m.login.clone(), m.clone())).collect())
    }

    fn get_repos_result(&self) -> Result<Vec<SectorGroup>, CliError> {
        let gh_repos = self.get_repo_map()?;
        let mut repos = Vec::new();
        for repo_conf in &self.conf.repo {
            if let &Some(gh_repo) = &gh_repos.get(&repo_conf.name) {
                repos.push(SectorGroup { sector: Sector::from(gh_repo.clone()),
                                         gid: repo_conf.gid.clone(),
                                         group: repo_conf.group.clone(),
                                         members: self.get_repo_collaborators(&gh_repo.name)?, });
            }
        }
        Ok(repos)
    }

    fn get_repo_map(&self) -> Result<HashMap<String, Repo>, CliError> {
        let url = format!("{}/orgs/{}/repos", self.conf.endpoint, self.conf.org);
        let content = self.get_content(&url)?;
        let repos = serde_json::from_str::<Vec<Repo>>(&content)?;
        Ok(repos.iter().map(|t| (t.name.clone(), t.clone())).collect())
    }

    fn get_repo_collaborators(&self, repo_name: &str) -> Result<HashMap<String, Member>, CliError> {
        let url = format!("{}/repos/{}/{}/collaborators?affiliation=outside",
                          self.conf.endpoint, self.conf.org, repo_name);
        let content = self.get_content(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(&content)?;
        Ok(members.iter().map(|m| (m.login.clone(), m.clone())).collect())
    }

    #[allow(dead_code)]
    pub fn clear_all_caches(&self) -> Result<(), CliError> {
        let mut path = std::env::temp_dir();
        path.push("sectora-cache/**/*");
        for entry in glob(&path.to_str().unwrap()).unwrap() {
            match entry {
                Ok(path) => {
                    if path.is_file() {
                        std::fs::remove_file(path)?
                    }
                }
                Err(e) => println!("{:?}", e),
            }
        }
        Ok(())
    }
}
<commit_msg>Refactor<commit_after>use glob::glob;
use serde_json;
use std;
use std::collections::HashMap;
use std::fs::File;
use std::io::prelude::*;
use structs::{CliError, Config, Member, PublicKey, Repo, Sector, SectorGroup, Team};

use futures::future::Future;
use futures::stream::Stream;
use hyper::{header, Client, Method, Request};
use hyper_rustls::HttpsConnector;
use tokio_core::reactor;

pub struct GithubClient {
    conf: Config,
}

impl GithubClient {
    pub fn new(config: &Config) -> GithubClient {
        if std::env::var("SSL_CERT_FILE").is_err() {
            std::env::set_var("SSL_CERT_FILE", &config.cert_path);
        }
        GithubClient { conf: config.clone() }
    }

    fn get_cache_path(url: &str) -> std::path::PathBuf {
        let mut path = std::env::temp_dir();
        path.push("sectora-cache");
        path.push(url);
        path
    }

    fn load_content_from_cache(&self, url: &str) -> Result<(std::fs::Metadata, String), CliError> {
        let path = Self::get_cache_path(url);
        let metadata = std::fs::metadata(path.to_str().unwrap())?;
        let mut f = File::open(path.to_str().unwrap())?;
        let mut content = String::new();
        f.read_to_string(&mut content)?;
        Ok((metadata, content))
    }

    fn store_content_to_cache(&self, url: &str, content: &str) -> Result<(), CliError> {
        let path = Self::get_cache_path(url);
        std::fs::create_dir_all(path.parent().unwrap())?;
        let mut f = File::create(path.to_str().unwrap())?;
        f.write(content.as_bytes())?;
        Ok(())
    }

    fn get_content_from_url(&self, url: &str) -> Result<String, CliError> {
        let mut all_contents: Vec<serde_json::value::Value> = Vec::new();
        let mut page = 1;
        loop {
            let mut new_array = self.get_content_from_url_page(url, page)?;
            if new_array.is_empty() {
                break;
            }
            all_contents.append(&mut new_array);
            page += 1;
        }
        let content = serde_json::ser::to_string(&all_contents)?;
        self.store_content_to_cache(url, &content)?;
        Ok(content)
    }

    fn build_page_request(&self, url: &str, page: u64) -> Request {
        let token = String::from("token ") + &self.conf.token;
        let sep = if url.contains("?") { "&" } else { "?" };
        let url_p = format!("{}{}page={}", url, sep, page);
        let mut req: Request = Request::new(Method::Get, url_p.parse().unwrap());
        req.headers_mut().set(header::Authorization(token));
        req.headers_mut().set(header::UserAgent::new("sectora"));
        req
    }

    fn get_content_from_url_page(&self, url: &str, page: u64) -> Result<Vec<serde_json::value::Value>, CliError> {
        let req = self.build_page_request(url, page);
        let mut core = reactor::Core::new()?;
        let client = Client::configure().connector(HttpsConnector::new(4, &core.handle()))
                                        .build(&core.handle());
        let work = client.request(req).and_then(|res| {
            res.body().concat2().and_then(move |body| {
                let v =
                    serde_json::from_slice::<Vec<serde_json::value::Value>>(&body).map_err(|_| std::io::Error::new(std::io::ErrorKind::Other, format!("output:{:?}", body)))?;
                Ok(v)
            })
        });
        Ok(core.run(work)?)
    }

    fn get_content(&self, url: &str) -> Result<String, CliError> {
        match self.load_content_from_cache(url) {
            Ok((metadata, cache_content)) => match std::time::SystemTime::now().duration_since(metadata.modified()?) {
                Ok(caching_duration) => {
                    if caching_duration.as_secs() > self.conf.cache_duration {
                        match self.get_content_from_url(url) {
                            Ok(content_from_url) => Ok(content_from_url),
                            Err(_) => Ok(cache_content),
                        }
                    } else {
                        Ok(cache_content)
                    }
                }
                Err(_) => Ok(cache_content),
            },
            Err(_) => self.get_content_from_url(url),
        }
    }

    #[allow(dead_code)]
    pub fn print_user_public_key(&self, user: &str) -> Result<(), CliError> {
        let keys = self.get_user_public_key(user)?;
        println!("{}", keys);
        Ok(())
    }

    fn get_user_public_key(&self, user: &str) -> Result<String, CliError> {
        let url = format!("{}/users/{}/keys", self.conf.endpoint, user);
        let content = self.get_content(&url)?;
        let keys = serde_json::from_str::<Vec<PublicKey>>(&content)?;
        Ok(keys.iter().map(|k| k.key.clone()).collect::<Vec<String>>().join("\n"))
    }

    #[allow(dead_code)]
    pub fn check_pam(&self, user: &str) -> Result<bool, CliError> {
        let sectors = self.get_sectors()?;
        Ok(sectors.iter().any(|team| team.members.contains_key(user)))
    }

    pub fn get_sectors(&self) -> Result<Vec<SectorGroup>, CliError> {
        let mut sectors: Vec<SectorGroup> = self.get_teams_result()?;
        sectors.append(&mut self.get_repos_result()?);
        Ok(sectors)
    }

    fn get_teams_result(&self) -> Result<Vec<SectorGroup>, CliError> {
        let gh_teams = self.get_team_map()?;
        let mut teams = Vec::new();
        for team_conf in &self.conf.team {
            if let &Some(gh_team) = &gh_teams.get(&team_conf.name) {
                teams.push(SectorGroup { sector: Sector::from(gh_team.clone()),
                                         gid: team_conf.gid.clone(),
                                         group: team_conf.group.clone(),
                                         members: self.get_team_members(gh_team.id)?, });
            }
        }
        Ok(teams)
    }

    fn get_team_map(&self) -> Result<HashMap<String, Team>, CliError> {
        let url = format!("{}/orgs/{}/teams", self.conf.endpoint, self.conf.org);
        let content = self.get_content(&url)?;
        let teams = serde_json::from_str::<Vec<Team>>(&content)?;
        Ok(teams.iter().map(|t| (t.name.clone(), t.clone())).collect())
    }

    fn get_team_members(&self, mid: u64) -> Result<HashMap<String, Member>, CliError> {
        let url = format!("{}/teams/{}/members", self.conf.endpoint, mid);
        let content = self.get_content(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(&content)?;
        Ok(members.iter().map(|m| (m.login.clone(), m.clone())).collect())
    }

    fn get_repos_result(&self) -> Result<Vec<SectorGroup>, CliError> {
        let gh_repos = self.get_repo_map()?;
        let mut repos = Vec::new();
        for repo_conf in &self.conf.repo {
            if let &Some(gh_repo) = &gh_repos.get(&repo_conf.name) {
                repos.push(SectorGroup { sector: Sector::from(gh_repo.clone()),
                                         gid: repo_conf.gid.clone(),
                                         group: repo_conf.group.clone(),
                                         members: self.get_repo_collaborators(&gh_repo.name)?, });
            }
        }
        Ok(repos)
    }

    fn get_repo_map(&self) -> Result<HashMap<String, Repo>, CliError> {
        let url = format!("{}/orgs/{}/repos", self.conf.endpoint, self.conf.org);
        let content = self.get_content(&url)?;
        let repos = serde_json::from_str::<Vec<Repo>>(&content)?;
        Ok(repos.iter().map(|t| (t.name.clone(), t.clone())).collect())
    }

    fn get_repo_collaborators(&self, repo_name: &str) -> Result<HashMap<String, Member>, CliError> {
        let url = format!("{}/repos/{}/{}/collaborators?affiliation=outside",
                          self.conf.endpoint, self.conf.org, repo_name);
        let content = self.get_content(&url)?;
        let members = serde_json::from_str::<Vec<Member>>(&content)?;
        Ok(members.iter().map(|m| (m.login.clone(), m.clone())).collect())
    }

    #[allow(dead_code)]
    pub fn clear_all_caches(&self) -> Result<(), CliError> {
        let mut path = std::env::temp_dir();
        path.push("sectora-cache/**/*");
        for entry in glob(&path.to_str().unwrap()).unwrap() {
            match entry {
                Ok(path) => {
                    if path.is_file() {
                        std::fs::remove_file(path)?
                    }
                }
                Err(e) => println!("{:?}", e),
            }
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::ascii::AsciiExt;
use std::collections::BTreeMap;
use std::str::FromStr;
use toml::Value;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum GStatus {
    Manual,     //already generated
    Generate,
    Comment,
    Ignore,
}

impl GStatus {
    pub fn ignored(&self) -> bool {
        self == &GStatus::Ignore
    }
    pub fn need_generate(&self) -> bool {
        self == &GStatus::Generate
    }
    pub fn normal(&self) -> bool {
        self == &GStatus::Generate || self == &GStatus::Manual
    }
}

impl Default for GStatus {
    fn default() -> GStatus { GStatus::Ignore }
}

impl FromStr for GStatus {
    type Err = String;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "manual" => Ok(GStatus::Manual),
            "generate" => Ok(GStatus::Generate),
            "comment" => Ok(GStatus::Comment),
            "ignore" => Ok(GStatus::Ignore),
            _ => Err("Wrong object status".into())
        }
    }
}

/// Info about GObject descendant
#[derive(Clone, Debug)]
pub struct GObject {
    pub name: String,
    pub non_nullable_overrides: Vec<String>, // sorted
    pub status: GStatus,
}

impl Default for GObject {
    fn default() -> GObject {
        GObject {
            name: "Default".into(),
            non_nullable_overrides: Vec::new(),
            status: Default::default(),
        }
    }
}

//TODO: ?change to HashMap<String, GStatus>
pub type GObjects =  BTreeMap<String, GObject>;

pub fn parse_toml(toml_objects: &Value) -> GObjects {
    let mut objects = GObjects::new();
    for toml_object in toml_objects.as_slice().unwrap() {
        let gobject = parse_object(toml_object);
        objects.insert(gobject.name.clone(), gobject);
    }
    objects
}

fn parse_object(toml_object: &Value) -> GObject {
    let name = toml_object.lookup("name").expect("Object name not defined")
        .as_str().unwrap().into();

    let status = match toml_object.lookup("status") {
        Some(value) => GStatus::from_str(value.as_str().unwrap()).unwrap_or(Default::default()),
        None => Default::default(),
    };

    let mut non_nullable_overrides = Vec::new();
    if let Some(fn_names) = toml_object.lookup("non_nullable").and_then(|o| o.as_slice()) {
        non_nullable_overrides = fn_names.iter()
            .filter_map(|fn_name| fn_name.as_str().map(String::from))
            .collect();
        non_nullable_overrides.sort();
    }

    GObject { name: name, non_nullable_overrides: non_nullable_overrides, status: status }
}

pub fn parse_status_shorthands(objects: &mut GObjects, toml: &Value) {
    use self::GStatus::*;
    for &status in [Manual, Generate, Comment, Ignore].iter() {
        parse_status_shorthand(objects, status, toml);
    }
}

fn parse_status_shorthand(objects: &mut GObjects, status: GStatus, toml: &Value) {
    let name = format!("options.{:?}", status).to_ascii_lowercase();
    toml.lookup(&name).map(|a| a.as_slice().unwrap())
        .map(|a| for name_ in a.iter().map(|s| s.as_str().unwrap()) {
        match objects.get(name_) {
            None => {
                objects.insert(name_.into(), GObject {
                    name: name_.into(),
                    .. Default::default()
                });
            },
            Some(_) => panic!("Bad name in {}: {} already defined", name, name_),
        }
    });
}
<commit_msg>Fix shorthand parsing<commit_after>use std::ascii::AsciiExt;
use std::collections::BTreeMap;
use std::str::FromStr;
use toml::Value;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum GStatus {
    Manual,     //already generated
    Generate,
    Comment,
    Ignore,
}

impl GStatus {
    pub fn ignored(&self) -> bool {
        self == &GStatus::Ignore
    }
    pub fn need_generate(&self) -> bool {
        self == &GStatus::Generate
    }
    pub fn normal(&self) -> bool {
        self == &GStatus::Generate || self == &GStatus::Manual
    }
}

impl Default for GStatus {
    fn default() -> GStatus { GStatus::Ignore }
}

impl FromStr for GStatus {
    type Err = String;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "manual" => Ok(GStatus::Manual),
            "generate" => Ok(GStatus::Generate),
            "comment" => Ok(GStatus::Comment),
            "ignore" => Ok(GStatus::Ignore),
            _ => Err("Wrong object status".into())
        }
    }
}

/// Info about GObject descendant
#[derive(Clone, Debug)]
pub struct GObject {
    pub name: String,
    pub non_nullable_overrides: Vec<String>, // sorted
    pub status: GStatus,
}

impl Default for GObject {
    fn default() -> GObject {
        GObject {
            name: "Default".into(),
            non_nullable_overrides: Vec::new(),
            status: Default::default(),
        }
    }
}

//TODO: ?change to HashMap<String, GStatus>
pub type GObjects =  BTreeMap<String, GObject>;

pub fn parse_toml(toml_objects: &Value) -> GObjects {
    let mut objects = GObjects::new();
    for toml_object in toml_objects.as_slice().unwrap() {
        let gobject = parse_object(toml_object);
        objects.insert(gobject.name.clone(), gobject);
    }
    objects
}

fn parse_object(toml_object: &Value) -> GObject {
    let name = toml_object.lookup("name").expect("Object name not defined")
        .as_str().unwrap().into();

    let status = match toml_object.lookup("status") {
        Some(value) => GStatus::from_str(value.as_str().unwrap()).unwrap_or(Default::default()),
        None => Default::default(),
    };

    let mut non_nullable_overrides = Vec::new();
    if let Some(fn_names) = toml_object.lookup("non_nullable").and_then(|o| o.as_slice()) {
        non_nullable_overrides = fn_names.iter()
            .filter_map(|fn_name| fn_name.as_str().map(String::from))
            .collect();
        non_nullable_overrides.sort();
    }

    GObject { name: name, non_nullable_overrides: non_nullable_overrides, status: status }
}

pub fn parse_status_shorthands(objects: &mut GObjects, toml: &Value) {
    use self::GStatus::*;
    for &status in [Manual, Generate, Comment, Ignore].iter() {
        parse_status_shorthand(objects, status, toml);
    }
}

fn parse_status_shorthand(objects: &mut GObjects, status: GStatus, toml: &Value) {
    let name = format!("options.{:?}", status).to_ascii_lowercase();
    toml.lookup(&name).map(|a| a.as_slice().unwrap())
        .map(|a| for name_ in a.iter().map(|s| s.as_str().unwrap()) {
        match objects.get(name_) {
            None => {
                objects.insert(name_.into(), GObject {
                    name: name_.into(),
                    status: status,
                    .. Default::default()
                });
            },
            Some(_) => panic!("Bad name in {}: {} already defined", name, name_),
        }
    });
}
<|endoftext|>


<commit_before>use nom::branch::alt;
use nom::bytes::complete::take_while;
use nom::character::complete::{char, one_of};
use nom::combinator::{map, recognize};
use nom::multi::{many0, separated_list1};
use nom::sequence::tuple;
use nom::IResult;

const WHITESPACE_CHARS: [u8; 3] = [b' ', b'_', b'.'];
const SEPARATOR_CHAR: u8 = b'-';
const INVALID_TITLE_CHARS: [u8; 5] = [b'[', b']', b'(', b')', SEPARATOR_CHAR];

/// Variant of the default parser that looks for episodes fitting a `<title> - <episode>` format.
///
/// ### Implementation Note
///
/// Internally, this variant reverses the supplied string before and after parsing, as it makes it much easier to parse titles correctly.
pub mod title_and_episode {
    use super::{replace_whitespace, separator_opt, title, whitespace};
    use nom::branch::alt;
    use nom::bytes::complete::{is_not, tag_no_case};
    use nom::character::complete::{char, digit1, one_of};
    use nom::combinator::{map, map_res, opt};
    use nom::multi::many0;
    use nom::sequence::{delimited, separated_pair, tuple};
    use nom::IResult;

    pub fn parse<S>(input: S) -> Option<(String, u32)>
    where
        S: AsRef<str>,
    {
        let input = input.as_ref().chars().rev().collect::<String>();

        let (_, (_, _, (title, episode))) =
            tuple((opt(tags), whitespace, title_and_episode))(&input).ok()?;

        let title = title.chars().rev().collect::<String>();
        let cleaned = replace_whitespace(title);

        Some((cleaned, episode))
    }

    fn title_and_episode(input: &str) -> IResult<&str, (&str, u32)> {
        let result = separated_pair(episode, separator_opt, title);
        map(result, |(ep, title)| (title, ep))(input)
    }

    fn episode(input: &str) -> IResult<&str, u32> {
        let ep = map_res(digit1, |s: &str| {
            let rev = s.chars().rev().collect::<String>();
            rev.parse::<u32>()
        });

        // These look for one of the following formats:
        // S<season>E<episode>
        // Ep <episode>
        // Episode <episode>
        let season_marker = map(tuple((one_of("Ee"), digit1, one_of("Ss"))), |_| ());
        let ep_prefix = map(
            tuple((
                whitespace,
                // Reverse of "isode"
                opt(tag_no_case("edosi")),
                // Reverse of "ep"
                tag_no_case("pe"),
            )),
            |_| (),
        );
        let e_prefix = map(one_of("Ee"), |_| ());
        let prefix = alt((season_marker, ep_prefix, e_prefix));

        map(tuple((ep, opt(prefix))), |(ep, _)| ep)(input)
    }

    fn tags(input: &str) -> IResult<&str, ()> {
        map(many0(tag), |_| ())(input)
    }

    fn tag(input: &str) -> IResult<&str, ()> {
        let surrounding = tuple((whitespace, metadata_block, whitespace));
        map(surrounding, |_| ())(input)
    }

    fn metadata_block(input: &str) -> IResult<&str, &str> {
        alt((brackets, parens))(input)
    }

    fn parens(input: &str) -> IResult<&str, &str> {
        delimited(char(')'), is_not("("), char('('))(input)
    }

    fn brackets(input: &str) -> IResult<&str, &str> {
        delimited(char(']'), is_not("["), char('['))(input)
    }
}

/// Variant of the default parser that looks for episodes fitting a `<episode> - <title>` format.
pub mod episode_and_title {
    use super::{replace_whitespace, separator_opt, title, whitespace};
    use nom::branch::alt;
    use nom::bytes::complete::is_not;
    use nom::character::complete::{char, digit1};
    use nom::combinator::{map, map_res, opt};
    use nom::multi::many0;
    use nom::sequence::{delimited, separated_pair, tuple};
    use nom::IResult;

    pub fn parse<S>(input: S) -> Option<(String, u32)>
    where
        S: AsRef<str>,
    {
        let input = input.as_ref();

        let (_, (_, _, (episode, title))) =
            tuple((opt(tags), whitespace, episode_and_title))(input).ok()?;

        let title = replace_whitespace(title);

        Some((title, episode))
    }

    fn tags(input: &str) -> IResult<&str, ()> {
        map(many0(tag), |_| ())(input)
    }

    fn tag(input: &str) -> IResult<&str, ()> {
        let surrounding = tuple((whitespace, metadata_block, whitespace));
        map(surrounding, |_| ())(input)
    }

    fn metadata_block(input: &str) -> IResult<&str, &str> {
        alt((brackets, parens))(input)
    }

    fn parens(input: &str) -> IResult<&str, &str> {
        delimited(char('('), is_not(")"), char(')'))(input)
    }

    fn brackets(input: &str) -> IResult<&str, &str> {
        delimited(char('['), is_not("]"), char(']'))(input)
    }

    fn episode_and_title(input: &str) -> IResult<&str, (u32, &str)> {
        separated_pair(episode, separator_opt, title)(input)
    }

    fn episode(input: &str) -> IResult<&str, u32> {
        let ep = map_res(digit1, |s: &str| s.parse::<u32>());

        let season_marker = tuple((char('S'), digit1));
        let ep_marker = tuple((opt(season_marker), char('E')));

        map(tuple((opt(ep_marker), ep)), |(_, ep)| ep)(input)
    }
}

fn title(input: &str) -> IResult<&str, &str> {
    use nom::{error::ErrorKind, Err};

    let title = take_while(|ch| !INVALID_TITLE_CHARS.contains(&(ch as u8)));
    let mut result = separated_list1(separator, title);

    let (slice, fragments) = result(input)?;

    let has_digit_fragment = fragments
        .into_iter()
        .any(|frag| !frag.chars().any(|ch| ch.is_alphabetic()));

    if has_digit_fragment {
        return Err(Err::Error((slice, ErrorKind::SeparatedList)));
    }

    recognize(result)(input)
}

fn separator(input: &str) -> IResult<&str, ()> {
    let dash_char = map(char(SEPARATOR_CHAR as char), |_| ());
    map(tuple((whitespace, dash_char, whitespace)), |_| ())(input)
}

fn separator_opt(input: &str) -> IResult<&str, ()> {
    alt((separator, whitespace))(input)
}

fn whitespace(input: &str) -> IResult<&str, ()> {
    let whitespace_char = one_of(WHITESPACE_CHARS.as_ref());
    map(many0(whitespace_char), |_| ())(input)
}

fn replace_whitespace<S>(string: S) -> String
where
    S: Into<String>,
{
    let mut string = string.into();

    for ch in WHITESPACE_CHARS.iter().filter(|&&ch| ch != b' ') {
        string = string.replace(*ch as char, " ");
    }

    string.trim().to_string()
}
<commit_msg>anime: Remove unnecessary opt() around tag parsers<commit_after>use nom::branch::alt;
use nom::bytes::complete::take_while;
use nom::character::complete::{char, one_of};
use nom::combinator::{map, recognize};
use nom::multi::{many0, separated_list1};
use nom::sequence::tuple;
use nom::IResult;

const WHITESPACE_CHARS: [u8; 3] = [b' ', b'_', b'.'];
const SEPARATOR_CHAR: u8 = b'-';
const INVALID_TITLE_CHARS: [u8; 5] = [b'[', b']', b'(', b')', SEPARATOR_CHAR];

/// Variant of the default parser that looks for episodes fitting a `<title> - <episode>` format.
///
/// ### Implementation Note
///
/// Internally, this variant reverses the supplied string before and after parsing, as it makes it much easier to parse titles correctly.
pub mod title_and_episode {
    use super::{replace_whitespace, separator_opt, title, whitespace};
    use nom::branch::alt;
    use nom::bytes::complete::{is_not, tag_no_case};
    use nom::character::complete::{char, digit1, one_of};
    use nom::combinator::{map, map_res, opt};
    use nom::multi::many0;
    use nom::sequence::{delimited, separated_pair, tuple};
    use nom::IResult;

    pub fn parse<S>(input: S) -> Option<(String, u32)>
    where
        S: AsRef<str>,
    {
        let input = input.as_ref().chars().rev().collect::<String>();

        let (_, (_, _, (title, episode))) =
            tuple((tags, whitespace, title_and_episode))(&input).ok()?;

        let title = title.chars().rev().collect::<String>();
        let cleaned = replace_whitespace(title);

        Some((cleaned, episode))
    }

    fn title_and_episode(input: &str) -> IResult<&str, (&str, u32)> {
        let result = separated_pair(episode, separator_opt, title);
        map(result, |(ep, title)| (title, ep))(input)
    }

    fn episode(input: &str) -> IResult<&str, u32> {
        let ep = map_res(digit1, |s: &str| {
            let rev = s.chars().rev().collect::<String>();
            rev.parse::<u32>()
        });

        // These look for one of the following formats:
        // S<season>E<episode>
        // Ep <episode>
        // Episode <episode>
        let season_marker = map(tuple((one_of("Ee"), digit1, one_of("Ss"))), |_| ());
        let ep_prefix = map(
            tuple((
                whitespace,
                // Reverse of "isode"
                opt(tag_no_case("edosi")),
                // Reverse of "ep"
                tag_no_case("pe"),
            )),
            |_| (),
        );
        let e_prefix = map(one_of("Ee"), |_| ());
        let prefix = alt((season_marker, ep_prefix, e_prefix));

        map(tuple((ep, opt(prefix))), |(ep, _)| ep)(input)
    }

    fn tags(input: &str) -> IResult<&str, ()> {
        map(many0(tag), |_| ())(input)
    }

    fn tag(input: &str) -> IResult<&str, ()> {
        let surrounding = tuple((whitespace, metadata_block, whitespace));
        map(surrounding, |_| ())(input)
    }

    fn metadata_block(input: &str) -> IResult<&str, &str> {
        alt((brackets, parens))(input)
    }

    fn parens(input: &str) -> IResult<&str, &str> {
        delimited(char(')'), is_not("("), char('('))(input)
    }

    fn brackets(input: &str) -> IResult<&str, &str> {
        delimited(char(']'), is_not("["), char('['))(input)
    }
}

/// Variant of the default parser that looks for episodes fitting a `<episode> - <title>` format.
pub mod episode_and_title {
    use super::{replace_whitespace, separator_opt, title, whitespace};
    use nom::branch::alt;
    use nom::bytes::complete::is_not;
    use nom::character::complete::{char, digit1};
    use nom::combinator::{map, map_res, opt};
    use nom::multi::many0;
    use nom::sequence::{delimited, separated_pair, tuple};
    use nom::IResult;

    pub fn parse<S>(input: S) -> Option<(String, u32)>
    where
        S: AsRef<str>,
    {
        let input = input.as_ref();

        let (_, (_, _, (episode, title))) =
            tuple((tags, whitespace, episode_and_title))(input).ok()?;

        let title = replace_whitespace(title);

        Some((title, episode))
    }

    fn tags(input: &str) -> IResult<&str, ()> {
        map(many0(tag), |_| ())(input)
    }

    fn tag(input: &str) -> IResult<&str, ()> {
        let surrounding = tuple((whitespace, metadata_block, whitespace));
        map(surrounding, |_| ())(input)
    }

    fn metadata_block(input: &str) -> IResult<&str, &str> {
        alt((brackets, parens))(input)
    }

    fn parens(input: &str) -> IResult<&str, &str> {
        delimited(char('('), is_not(")"), char(')'))(input)
    }

    fn brackets(input: &str) -> IResult<&str, &str> {
        delimited(char('['), is_not("]"), char(']'))(input)
    }

    fn episode_and_title(input: &str) -> IResult<&str, (u32, &str)> {
        separated_pair(episode, separator_opt, title)(input)
    }

    fn episode(input: &str) -> IResult<&str, u32> {
        let ep = map_res(digit1, |s: &str| s.parse::<u32>());

        let season_marker = tuple((char('S'), digit1));
        let ep_marker = tuple((opt(season_marker), char('E')));

        map(tuple((opt(ep_marker), ep)), |(_, ep)| ep)(input)
    }
}

fn title(input: &str) -> IResult<&str, &str> {
    use nom::{error::ErrorKind, Err};

    let title = take_while(|ch| !INVALID_TITLE_CHARS.contains(&(ch as u8)));
    let mut result = separated_list1(separator, title);

    let (slice, fragments) = result(input)?;

    let has_digit_fragment = fragments
        .into_iter()
        .any(|frag| !frag.chars().any(|ch| ch.is_alphabetic()));

    if has_digit_fragment {
        return Err(Err::Error((slice, ErrorKind::SeparatedList)));
    }

    recognize(result)(input)
}

fn separator(input: &str) -> IResult<&str, ()> {
    let dash_char = map(char(SEPARATOR_CHAR as char), |_| ());
    map(tuple((whitespace, dash_char, whitespace)), |_| ())(input)
}

fn separator_opt(input: &str) -> IResult<&str, ()> {
    alt((separator, whitespace))(input)
}

fn whitespace(input: &str) -> IResult<&str, ()> {
    let whitespace_char = one_of(WHITESPACE_CHARS.as_ref());
    map(many0(whitespace_char), |_| ())(input)
}

fn replace_whitespace<S>(string: S) -> String
where
    S: Into<String>,
{
    let mut string = string.into();

    for ch in WHITESPACE_CHARS.iter().filter(|&&ch| ch != b' ') {
        string = string.replace(*ch as char, " ");
    }

    string.trim().to_string()
}
<|endoftext|>


<commit_before>// The MIT License (MIT)

// Copyright (c) 2015 Y. T. Chung

// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

use std::io::{self, Read, BufRead, Write};
use std::cmp;

use crypto::cipher::{Cipher, CipherVariant};

pub struct DecryptedReader<R: Read> {
    reader: R,
    buffer: Vec<u8>,
    cipher: CipherVariant,
    pos: usize,
    sent_final: bool,
}

const BUFFER_SIZE: usize = 2048;

impl<R: Read> DecryptedReader<R> {
    pub fn new(r: R, cipher: CipherVariant) -> DecryptedReader<R> {
        DecryptedReader {
            reader: r,
            buffer: Vec::new(),
            cipher: cipher,
            pos: 0,
            sent_final: false,
        }
    }

    pub fn get_ref(&self) -> &R {
        &self.reader
    }

    /// Gets a mutable reference to the underlying reader.
    ///
    /// # Warning
    ///
    /// It is inadvisable to read directly from or write directly to the
    /// underlying reader.
    pub fn get_mut(&mut self) -> &mut R {
        &mut self.reader
    }

    // /// Unwraps this `DecryptedReader`, returning the underlying reader.
    // ///
    // /// The internal buffer is flushed before returning the reader. Any leftover
    // /// data in the read buffer is lost.
    // pub fn into_inner(self) -> R {
    //     self.reader
    // }
}

impl<R: Read> BufRead for DecryptedReader<R> {
    fn fill_buf<'b>(&'b mut self) -> io::Result<&'b [u8]> {
        while self.pos == self.buffer.len() {
            if self.sent_final {
                return Ok(&[]);
            }

            let mut incoming = [0u8; BUFFER_SIZE];
            self.buffer.clear();
            match self.reader.read(&mut incoming) {
                Ok(0) => {
                    // EOF
                    try!(self.cipher
                             .finalize(&mut self.buffer)
                             .map_err(|err| io::Error::new(io::ErrorKind::Other,
                                                           err.desc)));
                    self.sent_final = true;
                },
                Ok(l) => {
                    try!(self.cipher
                             .update(&incoming[..l], &mut self.buffer)
                             .map_err(|err| io::Error::new(io::ErrorKind::Other,
                                                           err.desc)));
                },
                Err(err) => {
                    return Err(err);
                }
            };

            self.pos = 0;
        }

        Ok(&self.buffer[self.pos..])
    }

    fn consume(&mut self, amt: usize) {
        self.pos = cmp::min(self.pos + amt, self.buffer.len());
    }
}

impl<R: Read> Read for DecryptedReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let nread = {
            let mut available = try!(self.fill_buf());
            try!(available.read(buf))
        };
        self.consume(nread);
        Ok(nread)
    }
}

pub struct EncryptedWriter<W: Write> {
    writer: W,
    cipher: CipherVariant,
    buffer: Vec<u8>,
}

impl<W: Write> EncryptedWriter<W> {
    pub fn new(w: W, cipher: CipherVariant) -> EncryptedWriter<W> {
        EncryptedWriter {
            writer: w,
            cipher: cipher,
            buffer: Vec::new(),
        }
    }

    pub fn finalize(&mut self) -> io::Result<()> {
        self.buffer.clear();
        match self.cipher.finalize(&mut self.buffer) {
            Ok(..) => {
                self.writer.write_all(&self.buffer[..])
                    .and(self.writer.flush())
            },
            Err(err) => {
                Err(io::Error::new(
                        io::ErrorKind::Other,
                        err.desc))
            }
        }
    }

    pub fn get_ref(&self) -> &W {
        &self.writer
    }

    /// Gets a mutable reference to the underlying writer.
    ///
    /// # Warning
    ///
    /// It is inadvisable to read directly from or write directly to the
    /// underlying writer.
    pub fn get_mut(&mut self) -> &mut W {
        &mut self.writer
    }
}

impl<W: Write> Write for EncryptedWriter<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.buffer.clear();
        match self.cipher.update(buf, &mut self.buffer) {
            Ok(..) => {
                match self.writer.write_all(&self.buffer[..]) {
                    Ok(..) => {
                        Ok(buf.len())
                    },
                    Err(err) => Err(err),
                }
            },
            Err(err) => {
                Err(io::Error::new(
                        io::ErrorKind::Other,
                        err.desc))
            }
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        self.writer.flush()
    }
}

impl<W: Write> Drop for EncryptedWriter<W> {
    fn drop(&mut self) {
        let _ = self.finalize();
    }
}
<commit_msg>use and_then instead of and<commit_after>// The MIT License (MIT)

// Copyright (c) 2015 Y. T. Chung

// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

use std::io::{self, Read, BufRead, Write};
use std::cmp;

use crypto::cipher::{Cipher, CipherVariant};

pub struct DecryptedReader<R: Read> {
    reader: R,
    buffer: Vec<u8>,
    cipher: CipherVariant,
    pos: usize,
    sent_final: bool,
}

const BUFFER_SIZE: usize = 2048;

impl<R: Read> DecryptedReader<R> {
    pub fn new(r: R, cipher: CipherVariant) -> DecryptedReader<R> {
        DecryptedReader {
            reader: r,
            buffer: Vec::new(),
            cipher: cipher,
            pos: 0,
            sent_final: false,
        }
    }

    pub fn get_ref(&self) -> &R {
        &self.reader
    }

    /// Gets a mutable reference to the underlying reader.
    ///
    /// # Warning
    ///
    /// It is inadvisable to read directly from or write directly to the
    /// underlying reader.
    pub fn get_mut(&mut self) -> &mut R {
        &mut self.reader
    }

    // /// Unwraps this `DecryptedReader`, returning the underlying reader.
    // ///
    // /// The internal buffer is flushed before returning the reader. Any leftover
    // /// data in the read buffer is lost.
    // pub fn into_inner(self) -> R {
    //     self.reader
    // }
}

impl<R: Read> BufRead for DecryptedReader<R> {
    fn fill_buf<'b>(&'b mut self) -> io::Result<&'b [u8]> {
        while self.pos == self.buffer.len() {
            if self.sent_final {
                return Ok(&[]);
            }

            let mut incoming = [0u8; BUFFER_SIZE];
            self.buffer.clear();
            match self.reader.read(&mut incoming) {
                Ok(0) => {
                    // EOF
                    try!(self.cipher
                             .finalize(&mut self.buffer)
                             .map_err(|err| io::Error::new(io::ErrorKind::Other,
                                                           err.desc)));
                    self.sent_final = true;
                },
                Ok(l) => {
                    try!(self.cipher
                             .update(&incoming[..l], &mut self.buffer)
                             .map_err(|err| io::Error::new(io::ErrorKind::Other,
                                                           err.desc)));
                },
                Err(err) => {
                    return Err(err);
                }
            };

            self.pos = 0;
        }

        Ok(&self.buffer[self.pos..])
    }

    fn consume(&mut self, amt: usize) {
        self.pos = cmp::min(self.pos + amt, self.buffer.len());
    }
}

impl<R: Read> Read for DecryptedReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let nread = {
            let mut available = try!(self.fill_buf());
            try!(available.read(buf))
        };
        self.consume(nread);
        Ok(nread)
    }
}

pub struct EncryptedWriter<W: Write> {
    writer: W,
    cipher: CipherVariant,
    buffer: Vec<u8>,
}

impl<W: Write> EncryptedWriter<W> {
    pub fn new(w: W, cipher: CipherVariant) -> EncryptedWriter<W> {
        EncryptedWriter {
            writer: w,
            cipher: cipher,
            buffer: Vec::new(),
        }
    }

    pub fn finalize(&mut self) -> io::Result<()> {
        self.buffer.clear();
        match self.cipher.finalize(&mut self.buffer) {
            Ok(..) => {
                self.writer.write_all(&self.buffer[..])
                    .and_then(|_| self.writer.flush())
            },
            Err(err) => {
                Err(io::Error::new(
                        io::ErrorKind::Other,
                        err.desc))
            }
        }
    }

    pub fn get_ref(&self) -> &W {
        &self.writer
    }

    /// Gets a mutable reference to the underlying writer.
    ///
    /// # Warning
    ///
    /// It is inadvisable to read directly from or write directly to the
    /// underlying writer.
    pub fn get_mut(&mut self) -> &mut W {
        &mut self.writer
    }
}

impl<W: Write> Write for EncryptedWriter<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.buffer.clear();
        match self.cipher.update(buf, &mut self.buffer) {
            Ok(..) => {
                match self.writer.write_all(&self.buffer[..]) {
                    Ok(..) => {
                        Ok(buf.len())
                    },
                    Err(err) => Err(err),
                }
            },
            Err(err) => {
                Err(io::Error::new(
                        io::ErrorKind::Other,
                        err.desc))
            }
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        self.writer.flush()
    }
}

impl<W: Write> Drop for EncryptedWriter<W> {
    fn drop(&mut self) {
        let _ = self.finalize();
    }
}
<|endoftext|>


<commit_before>use DrawState;
use types::{self, Matrix2d, Scalar};
use {CircleArc, Ellipse, Image, ImageSize, Line, Polygon, Rectangle};

/// Implemented by all graphics back-ends.
///
/// [An example back-end using raw OpenGL](https://github.com/PistonDevelopers/opengl_graphics)
///
/// By default, this design uses triangles as graphics primitives.
/// This is supported by all GPUs and easy to implement in shader languages.
///
/// Default trait methods can be overridden for better performance or higher
/// quality.
///
/// When drawing, use this trait as generic constraint:
///
/// ```
/// use graphics::{Graphics, Context};
///
/// fn draw<G: Graphics>(c: &Context, g: &mut G) {
///     //...
/// }
/// ```
///
/// Color space is sRGB.
///
/// ### Notice for back-end authors
///
/// When sRGB is enabled for a back-end shader, the gamma must be converted
/// to linear space when used as vertex color or uniform parameter.
/// To convert gamma, use `color::gamma_srgb_to_linear`.
///
/// For more information, see
/// https://github.com/PistonDevelopers/piston/issues/1014.
pub trait Graphics: Sized {
    /// The texture type associated with the back-end.
    ///
    /// In generic code, this type is often unknown.
    /// This might lead to more boilerplate code:
    ///
    /// ```
    /// use graphics::{Graphics, Context, ImageSize};
    ///
    /// fn draw_texture<G, T>(c: &Context, g: &mut G)
    ///     where G: Graphics<Texture = T>, T: ImageSize {
    ///     //...
    /// }
    /// ```
    ///
    /// Code written specifically for one back-end can be easier to write.
    /// Later, when the code is done, it can be refactored into generic code.
    type Texture: ImageSize;

    /// Clears background with a color.
    ///
    /// The color should replace the values in the buffer.
    ///
    /// Color space is sRGB.
    fn clear_color(&mut self, color: types::Color);

    /// Clears stencil buffer with a value, usually 0.
    ///
    /// A stencil buffer contains values that are not visible on the screen.
    /// These values are used to test against the pixel to paint.
    ///
    /// If you are drawing a shape for clipping and forgot to clear the
    /// stencil buffer, then the clipping shape will carry over in next frame
    /// and cause artifacts.
    fn clear_stencil(&mut self, value: u8);

    /// Renders list of 2d triangles using a solid color.
    ///
    /// All vertices share the same color.
    ///
    /// The back-end calls the closure with a closure to receive vertices.
    /// First, the back-end sets up shaders and such to prepare.
    /// Then it calls the closure, which calls back with chunks of vertices.
    /// The number of vertices per chunk never exceeds
    /// `BACK_END_MAX_VERTEX_COUNT`.
    /// Vertex positions are encoded `[[x0, y0], [x1, y1], ...]`.
    ///
    /// Color space is sRGB.
    fn tri_list<F>(&mut self, draw_state: &DrawState, color: &[f32; 4], f: F)
        where F: FnMut(&mut dyn FnMut(&[[f32; 2]]));

    /// Renders list of 2d triangles using a color and a texture.
    ///
    /// All vertices share the same color.
    ///
    /// Tip: For objects of different colors, use grayscale textures.
    /// The texture color gets multiplied with the color.
    ///
    /// A texture coordinate is assigned per vertex (from [0, 0] to [1, 1]).
    ///
    /// The back-end calls the closure with a closure to receive vertices.
    /// First, the back-end sets up shaders and such to prepare.
    /// Then it calls the closure, which calls back with chunks of vertices.
    /// The number of vertices per chunk never exceeds
    /// `BACK_END_MAX_VERTEX_COUNT`.
    /// Vertex positions are encoded `[[x0, y0], [x1, y1], ...]`.
    /// Texture coordinates are encoded `[[u0, v0], [u1, v1], ...]`.
    ///
    /// Chunks uses separate buffer for vertex positions and texture coordinates.
    /// Arguments are `|vertices: &[f32], texture_coords: &[f32]`.
    ///
    /// Color space is sRGB.
    fn tri_list_uv<F>(&mut self,
                      draw_state: &DrawState,
                      color: &[f32; 4],
                      texture: &<Self as Graphics>::Texture,
                      f: F)
        where F: FnMut(&mut dyn FnMut(&[[f32; 2]], &[[f32; 2]]));

    /// Draws a rectangle.
    ///
    /// Can be overriden in the back-end for higher performance.
    ///
    /// Instead of calling this directly, use `Rectangle::draw`.
    #[inline(always)]
    fn rectangle<R: Into<types::Rectangle>>(&mut self,
                                            r: &Rectangle,
                                            rectangle: R,
                                            draw_state: &DrawState,
                                            transform: Matrix2d) {
        r.draw_tri(rectangle, draw_state, transform, self);
    }

    /// Draws a polygon.
    ///
    /// Can be overridden in the back-end for higher performance.
    ///
    /// Instead of calling this directly, use `Polygon::draw`.
    #[inline(always)]
    fn polygon(&mut self,
               p: &Polygon,
               polygon: types::Polygon,
               draw_state: &DrawState,
               transform: Matrix2d) {
        p.draw_tri(polygon, draw_state, transform, self);
    }

    /// Draws a tweened polygon using linear interpolation.
    ///
    /// Can be overridden in the back-end for higher performance.
    ///
    /// Instead of calling this directly, use `Polygon::draw_tween_lerp`.
    #[inline(always)]
    fn polygon_tween_lerp(&mut self,
                          p: &Polygon,
                          polygons: types::Polygons,
                          tween_factor: Scalar,
                          draw_state: &DrawState,
                          transform: Matrix2d) {
        p.draw_tween_lerp_tri(polygons, tween_factor, draw_state, transform, self);
    }

    /// Draws image.
    ///
    /// Can be overridden in the back-end for higher performance.
    ///
    /// Instead of calling this directly, use `Image::draw`.
    #[inline(always)]
    fn image(&mut self,
             image: &Image,
             texture: &Self::Texture,
             draw_state: &DrawState,
             transform: Matrix2d) {
        image.draw_tri(texture, draw_state, transform, self);
    }

    /// Draws ellipse.
    ///
    /// Can be overridden in the back-end for higher performance.
    ///
    /// Instead of calling this directly, use `Ellipse::draw`.
    #[inline(always)]
    fn ellipse<R: Into<types::Rectangle>>(&mut self,
                                          e: &Ellipse,
                                          rectangle: R,
                                          draw_state: &DrawState,
                                          transform: Matrix2d) {
        e.draw_tri(rectangle, draw_state, transform, self);
    }

    /// Draws line.
    ///
    /// Can be overridden in the back-end for higher performance.
    ///
    /// Instead of calling this directly, use `Line::draw`.
    #[inline(always)]
    fn line<L: Into<types::Line>>(&mut self,
                                  l: &Line,
                                  line: L,
                                  draw_state: &DrawState,
                                  transform: Matrix2d) {
        l.draw_tri(line, draw_state, transform, self);
    }

    /// Draws circle arc.
    ///
    /// Can be overriden in the back-end for higher performance.
    ///
    /// Instead of calling this directly, use `CircleArc::draw`.
    #[inline(always)]
    fn circle_arc<R: Into<types::Rectangle>>(&mut self,
                                             c: &CircleArc,
                                             rectangle: R,
                                             draw_state: &DrawState,
                                             transform: Matrix2d) {
        c.draw_tri(rectangle, draw_state, transform, self);
    }
}
<commit_msg>Added support for individual vertex colors<commit_after>use DrawState;
use types::{self, Matrix2d, Scalar};
use {CircleArc, Ellipse, Image, ImageSize, Line, Polygon, Rectangle};

/// Implemented by all graphics back-ends.
///
/// [An example back-end using raw OpenGL](https://github.com/PistonDevelopers/opengl_graphics)
///
/// By default, this design uses triangles as graphics primitives.
/// This is supported by all GPUs and easy to implement in shader languages.
///
/// Default trait methods can be overridden for better performance or higher
/// quality.
///
/// When drawing, use this trait as generic constraint:
///
/// ```
/// use graphics::{Graphics, Context};
///
/// fn draw<G: Graphics>(c: &Context, g: &mut G) {
///     //...
/// }
/// ```
///
/// Color space is sRGB.
///
/// ### Notice for back-end authors
///
/// When sRGB is enabled for a back-end shader, the gamma must be converted
/// to linear space when used as vertex color or uniform parameter.
/// To convert gamma, use `color::gamma_srgb_to_linear`.
///
/// For more information, see
/// https://github.com/PistonDevelopers/piston/issues/1014.
pub trait Graphics: Sized {
    /// The texture type associated with the back-end.
    ///
    /// In generic code, this type is often unknown.
    /// This might lead to more boilerplate code:
    ///
    /// ```
    /// use graphics::{Graphics, Context, ImageSize};
    ///
    /// fn draw_texture<G, T>(c: &Context, g: &mut G)
    ///     where G: Graphics<Texture = T>, T: ImageSize {
    ///     //...
    /// }
    /// ```
    ///
    /// Code written specifically for one back-end can be easier to write.
    /// Later, when the code is done, it can be refactored into generic code.
    type Texture: ImageSize;

    /// Clears background with a color.
    ///
    /// The color should replace the values in the buffer.
    ///
    /// Color space is sRGB.
    fn clear_color(&mut self, color: types::Color);

    /// Clears stencil buffer with a value, usually 0.
    ///
    /// A stencil buffer contains values that are not visible on the screen.
    /// These values are used to test against the pixel to paint.
    ///
    /// If you are drawing a shape for clipping and forgot to clear the
    /// stencil buffer, then the clipping shape will carry over in next frame
    /// and cause artifacts.
    fn clear_stencil(&mut self, value: u8);

    /// Renders list of 2d triangles using a solid color.
    ///
    /// All vertices share the same color.
    ///
    /// The back-end calls the closure with a closure to receive vertices.
    /// First, the back-end sets up shaders and such to prepare.
    /// Then it calls the closure, which calls back with chunks of vertices.
    /// The number of vertices per chunk never exceeds
    /// `BACK_END_MAX_VERTEX_COUNT`.
    /// Vertex positions are encoded `[[x0, y0], [x1, y1], ...]`.
    ///
    /// Color space is sRGB.
    fn tri_list<F>(&mut self, draw_state: &DrawState, color: &[f32; 4], f: F)
        where F: FnMut(&mut dyn FnMut(&[[f32; 2]]));

    /// Same as `tri_list`, but with individual vertex colors.
    ///
    /// Argument are `|vertices: &[[f32; 2], colors: &[[f32; 4]]]|`.
    fn tri_list_c<F>(&mut self, draw_state: &DrawState, f: F)
        where F: FnMut(&mut dyn FnMut(&[[f32; 2]], &[[f32; 4]]));

    /// Renders list of 2d triangles using a color and a texture.
    ///
    /// All vertices share the same color.
    ///
    /// Tip: For objects of different colors, use grayscale textures.
    /// The texture color gets multiplied with the color.
    ///
    /// A texture coordinate is assigned per vertex (from [0, 0] to [1, 1]).
    ///
    /// The back-end calls the closure with a closure to receive vertices.
    /// First, the back-end sets up shaders and such to prepare.
    /// Then it calls the closure, which calls back with chunks of vertices.
    /// The number of vertices per chunk never exceeds
    /// `BACK_END_MAX_VERTEX_COUNT`.
    /// Vertex positions are encoded `[[x0, y0], [x1, y1], ...]`.
    /// Texture coordinates are encoded `[[u0, v0], [u1, v1], ...]`.
    ///
    /// Chunks uses separate buffer for vertex positions and texture coordinates.
    /// Arguments are `|vertices: &[[f32; 2]], texture_coords: &[[f32; 2]]|`.
    ///
    /// Color space is sRGB.
    fn tri_list_uv<F>(&mut self,
                      draw_state: &DrawState,
                      color: &[f32; 4],
                      texture: &<Self as Graphics>::Texture,
                      f: F)
        where F: FnMut(&mut dyn FnMut(&[[f32; 2]], &[[f32; 2]]));

    /// Same as `tri_list_uv`, but with individual vertex colors.
    ///
    /// Argument are `|vertices: &[[f32; 2], texture_coors: &[[f32; 2]], colors: &[[f32; 4]]]|`.
    fn tri_list_uv_c<F>(&mut self,
                      draw_state: &DrawState,
                      texture: &<Self as Graphics>::Texture,
                      f: F)
        where F: FnMut(&mut dyn FnMut(&[[f32; 2]], &[[f32; 2]], &[[f32; 4]]));

    /// Draws a rectangle.
    ///
    /// Can be overriden in the back-end for higher performance.
    ///
    /// Instead of calling this directly, use `Rectangle::draw`.
    #[inline(always)]
    fn rectangle<R: Into<types::Rectangle>>(&mut self,
                                            r: &Rectangle,
                                            rectangle: R,
                                            draw_state: &DrawState,
                                            transform: Matrix2d) {
        r.draw_tri(rectangle, draw_state, transform, self);
    }

    /// Draws a polygon.
    ///
    /// Can be overridden in the back-end for higher performance.
    ///
    /// Instead of calling this directly, use `Polygon::draw`.
    #[inline(always)]
    fn polygon(&mut self,
               p: &Polygon,
               polygon: types::Polygon,
               draw_state: &DrawState,
               transform: Matrix2d) {
        p.draw_tri(polygon, draw_state, transform, self);
    }

    /// Draws a tweened polygon using linear interpolation.
    ///
    /// Can be overridden in the back-end for higher performance.
    ///
    /// Instead of calling this directly, use `Polygon::draw_tween_lerp`.
    #[inline(always)]
    fn polygon_tween_lerp(&mut self,
                          p: &Polygon,
                          polygons: types::Polygons,
                          tween_factor: Scalar,
                          draw_state: &DrawState,
                          transform: Matrix2d) {
        p.draw_tween_lerp_tri(polygons, tween_factor, draw_state, transform, self);
    }

    /// Draws image.
    ///
    /// Can be overridden in the back-end for higher performance.
    ///
    /// Instead of calling this directly, use `Image::draw`.
    #[inline(always)]
    fn image(&mut self,
             image: &Image,
             texture: &Self::Texture,
             draw_state: &DrawState,
             transform: Matrix2d) {
        image.draw_tri(texture, draw_state, transform, self);
    }

    /// Draws ellipse.
    ///
    /// Can be overridden in the back-end for higher performance.
    ///
    /// Instead of calling this directly, use `Ellipse::draw`.
    #[inline(always)]
    fn ellipse<R: Into<types::Rectangle>>(&mut self,
                                          e: &Ellipse,
                                          rectangle: R,
                                          draw_state: &DrawState,
                                          transform: Matrix2d) {
        e.draw_tri(rectangle, draw_state, transform, self);
    }

    /// Draws line.
    ///
    /// Can be overridden in the back-end for higher performance.
    ///
    /// Instead of calling this directly, use `Line::draw`.
    #[inline(always)]
    fn line<L: Into<types::Line>>(&mut self,
                                  l: &Line,
                                  line: L,
                                  draw_state: &DrawState,
                                  transform: Matrix2d) {
        l.draw_tri(line, draw_state, transform, self);
    }

    /// Draws circle arc.
    ///
    /// Can be overriden in the back-end for higher performance.
    ///
    /// Instead of calling this directly, use `CircleArc::draw`.
    #[inline(always)]
    fn circle_arc<R: Into<types::Rectangle>>(&mut self,
                                             c: &CircleArc,
                                             rectangle: R,
                                             draw_state: &DrawState,
                                             transform: Matrix2d) {
        c.draw_tri(rectangle, draw_state, transform, self);
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate serde;
extern crate test;

include!(concat!(env!("OUT_DIR"), "/test.rs"));
<commit_msg>serde_tests tests doesn't need the test crate<commit_after>extern crate serde;

include!(concat!(env!("OUT_DIR"), "/test.rs"));
<|endoftext|>


<commit_before>use card;
use std::fmt;

mod tests;

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Hand {
    pub cards: Vec<card::Card>,
    //pub ranking: PokerRanking
}

impl Hand {
    pub fn new(mut cards: Vec<card::Card>) -> Hand {
        cards.sort();
        Hand {
            cards: cards,

        }
    }

    fn has_flush(&self) -> bool {
        let mut suits = 0b0000;
        for card in &self.cards {
            suits = suits | (0b0001 << card.suit as u32);
        }
        match suits {
            0b0001 => true,
            0b0010 => true,
            0b0100 => true,
            0b1000 => true,
            _ => false
        }
    }

    fn has_straight(&self) -> bool {
        let mut ranks = 0b0;
        for card in &self.cards {
            ranks = ranks | (0b1 << card.rank as u32);
        }

        let straight_matcher = 0b11111;
        let ace_low_matcher = 0b1000000001111;
        if ranks ^ ace_low_matcher == 0 {
            return true;
        }
        for i in 0..8 {
            if ranks ^ (straight_matcher << i) == 0 {
                return true;
            }
        }
        false
    }
}

impl fmt::Display for Hand {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} {} {} {} {}", self.cards.get(0).unwrap(),
                                    self.cards.get(1).unwrap(),
                                    self.cards.get(2).unwrap(),
                                    self.cards.get(3).unwrap(),
                                    self.cards.get(4).unwrap())
    }
}

#[derive(Debug, PartialEq, PartialOrd, Eq, Ord)]
pub enum PokerRanking {
    HighCard,
    OnePair,
    TwoPair,
    Trips,
    Straight,
    Flush,
    FullHouse,
    Quads,
    StraightFlush,
}
<commit_msg>Removed unnecessary usage of binary literals<commit_after>use card;
use std::fmt;

mod tests;

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Hand {
    pub cards: Vec<card::Card>,
    //pub ranking: PokerRanking
}

impl Hand {
    pub fn new(mut cards: Vec<card::Card>) -> Hand {
        cards.sort();
        Hand {
            cards: cards,

        }
    }

    fn has_flush(&self) -> bool {
        let mut suits = 0;
        for card in &self.cards {
            suits = suits | (1 << card.suit as u32);
        }
        match suits {
            0b0001 => true,
            0b0010 => true,
            0b0100 => true,
            0b1000 => true,
            _ => false
        }
    }

    fn has_straight(&self) -> bool {
        let mut ranks = 0;
        for card in &self.cards {
            ranks = ranks | (1 << card.rank as u32);
        }

        let straight_matcher = 0b11111;
        let ace_low_matcher = 0b1000000001111;
        if ranks ^ ace_low_matcher == 0 {
            return true;
        }
        for i in 0..8 {
            if ranks ^ (straight_matcher << i) == 0 {
                return true;
            }
        }
        false
    }
}

impl fmt::Display for Hand {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{} {} {} {} {}", self.cards.get(0).unwrap(),
                                    self.cards.get(1).unwrap(),
                                    self.cards.get(2).unwrap(),
                                    self.cards.get(3).unwrap(),
                                    self.cards.get(4).unwrap())
    }
}

#[derive(Debug, PartialEq, PartialOrd, Eq, Ord)]
pub enum PokerRanking {
    HighCard,
    OnePair,
    TwoPair,
    Trips,
    Straight,
    Flush,
    FullHouse,
    Quads,
    StraightFlush,
}
<|endoftext|>