<commit_before>// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::collections::HashSet;

use syn::{self, visit};
use syn::punctuated::Punctuated;

use internals::ast::{Data, Container};
use internals::attr;

use proc_macro2::Span;

// Remove the default from every type parameter because in the generated impls
// they look like associated types: "error: associated type bindings are not
// allowed here".
pub fn without_defaults(generics: &syn::Generics) -> syn::Generics {
    syn::Generics {
        params: generics
            .params
            .iter()
            .map(|param| match *param {
                syn::GenericParam::Type(ref param) => {
                    syn::GenericParam::Type(syn::TypeParam {
                        eq_token: None,
                        default: None,
                        ..param.clone()
                    })
                }
                _ => param.clone(),
            })
            .collect(),
        ..generics.clone()
    }
}

pub fn with_where_predicates(
    generics: &syn::Generics,
    predicates: &[syn::WherePredicate],
) -> syn::Generics {
    let mut generics = generics.clone();
    generics.make_where_clause()
        .predicates
        .extend(predicates.into_iter().cloned());
    generics
}

pub fn with_where_predicates_from_fields<F, W>(
    cont: &Container,
    generics: &syn::Generics,
    trait_bound: &syn::Path,
    from_field: F,
    gen_bound_where: W,
) -> syn::Generics
where
    F: Fn(&attr::Field) -> Option<&[syn::WherePredicate]>,
    W: Fn(&attr::Field) -> bool,
{
    let predicates = cont.data
        .all_fields()
        .flat_map(|field| {
            let field_ty = field.ty;
            let matching_generic = |t: &syn::PathSegment, g| match g {
                &syn::GenericParam::Type(ref generic_ty)
                    if generic_ty.ident == t.ident => true,
                _ => false
            };

            let mut field_bound: Option<syn::WherePredicate> = None;
            if let &syn::Type::Path(ref ty_path) = field_ty {
                field_bound = match (gen_bound_where(&field.attrs), ty_path.path.segments.first()) {
                    (true, Some(syn::punctuated::Pair::Punctuated(ref t, _)))
                        if generics.params.iter().fold(false, |b, g| b || matching_generic(t, g))
                        => Some(parse_quote!(#field_ty: #trait_bound)),
                    (_, _) => None
                };
            }
            field_bound.into_iter().chain(from_field(&field.attrs).into_iter().flat_map(|predicates| predicates.to_vec()))
        });

    let mut generics = generics.clone();
    generics.make_where_clause()
        .predicates
        .extend(predicates);
    generics
}

// Puts the given bound on any generic type parameters that are used in fields
// for which filter returns true.
//
// For example, the following struct needs the bound `A: Serialize, B: Serialize`.
//
//     struct S<'b, A, B: 'b, C> {
//         a: A,
//         b: Option<&'b B>
//         #[serde(skip_serializing)]
//         c: C,
//     }
pub fn with_bound<F>(
    cont: &Container,
    generics: &syn::Generics,
    filter: F,
    bound: &syn::Path,
) -> syn::Generics
where
    F: Fn(&attr::Field, Option<&attr::Variant>) -> bool,
{
    struct FindTyParams {
        // Set of all generic type parameters on the current struct (A, B, C in
        // the example). Initialized up front.
        all_ty_params: HashSet<syn::Ident>,
        // Set of generic type parameters used in fields for which filter
        // returns true (A and B in the example). Filled in as the visitor sees
        // them.
        relevant_ty_params: HashSet<syn::Ident>,
    }
    impl<'ast> visit::Visit<'ast> for FindTyParams {
        fn visit_path(&mut self, path: &syn::Path) {
            if let Some(seg) = path.segments.last() {
                if seg.into_value().ident == "PhantomData" {
                    // Hardcoded exception, because PhantomData<T> implements
                    // Serialize and Deserialize whether or not T implements it.
                    return;
                }
            }
            if path.leading_colon.is_none() && path.segments.len() == 1 {
                let id = path.segments[0].ident;
                if self.all_ty_params.contains(&id) {
                    self.relevant_ty_params.insert(id);
                }
            }
            visit::visit_path(self, path);
        }

        // Type parameter should not be considered used by a macro path.
        //
        //     struct TypeMacro<T> {
        //         mac: T!(),
        //         marker: PhantomData<T>,
        //     }
        fn visit_macro(&mut self, _mac: &syn::Macro) {}
    }

    let all_ty_params: HashSet<_> = generics
        .params
        .iter()
        .filter_map(|param| match *param {
            syn::GenericParam::Type(ref param) => Some(param.ident),
            _ => None,
        })
        .collect();

    let mut visitor = FindTyParams {
        all_ty_params: all_ty_params,
        relevant_ty_params: HashSet::new(),
    };
    match cont.data {
        Data::Enum(ref variants) => for variant in variants.iter() {
            let relevant_fields = variant
                .fields
                .iter()
                .filter(|field| filter(&field.attrs, Some(&variant.attrs)));
            for field in relevant_fields {
                visit::visit_type(&mut visitor, field.ty);
            }
        },
        Data::Struct(_, ref fields) => {
            for field in fields.iter().filter(|field| filter(&field.attrs, None)) {
                visit::visit_type(&mut visitor, field.ty);
            }
        }
    }

    let new_predicates = generics
        .params
        .iter()
        .filter_map(|param| match *param {
            syn::GenericParam::Type(ref param) => Some(param.ident),
            _ => None,
        })
        .filter(|id| visitor.relevant_ty_params.contains(id))
        .map(|id| {
            syn::WherePredicate::Type(syn::PredicateType {
                lifetimes: None,
                // the type parameter that is being bounded e.g. T
                bounded_ty: syn::Type::Path(syn::TypePath {
                    qself: None,
                    path: id.into(),
                }),
                colon_token: Default::default(),
                // the bound e.g. Serialize
                bounds: vec![
                    syn::TypeParamBound::Trait(syn::TraitBound {
                        paren_token: None,
                        modifier: syn::TraitBoundModifier::None,
                        lifetimes: None,
                        path: bound.clone(),
                    }),
                ].into_iter().collect(),
            })
        });

    let mut generics = generics.clone();
    generics.make_where_clause()
        .predicates
        .extend(new_predicates);
    generics
}

pub fn with_self_bound(
    cont: &Container,
    generics: &syn::Generics,
    bound: &syn::Path,
) -> syn::Generics {
    let mut generics = generics.clone();
    generics.make_where_clause()
        .predicates
        .push(syn::WherePredicate::Type(syn::PredicateType {
            lifetimes: None,
            // the type that is being bounded e.g. MyStruct<'a, T>
            bounded_ty: type_of_item(cont),
            colon_token: Default::default(),
            // the bound e.g. Default
            bounds: vec![
                syn::TypeParamBound::Trait(syn::TraitBound {
                    paren_token: None,
                    modifier: syn::TraitBoundModifier::None,
                    lifetimes: None,
                    path: bound.clone(),
                }),
            ].into_iter().collect(),
        }));
    generics
}

pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Generics {
    let bound = syn::Lifetime::new(lifetime, Span::call_site());
    let def = syn::LifetimeDef {
        attrs: Vec::new(),
        lifetime: bound,
        colon_token: None,
        bounds: Punctuated::new(),
    };

    let params = Some(syn::GenericParam::Lifetime(def))
        .into_iter()
        .chain(generics.params
            .iter()
            .cloned()
            .map(|mut param| {
                match param {
                    syn::GenericParam::Lifetime(ref mut param) => {
                        param.bounds.push(bound);
                    }
                    syn::GenericParam::Type(ref mut param) => {
                        param.bounds.push(syn::TypeParamBound::Lifetime(bound));
                    }
                    syn::GenericParam::Const(_) => {}
                }
                param
            }))
        .collect();

    syn::Generics {
        params: params,
        ..generics.clone()
    }
}

fn type_of_item(cont: &Container) -> syn::Type {
    syn::Type::Path(syn::TypePath {
        qself: None,
        path: syn::Path {
            leading_colon: None,
            segments: vec![
                syn::PathSegment {
                    ident: cont.ident,
                    arguments: syn::PathArguments::AngleBracketed(
                        syn::AngleBracketedGenericArguments {
                            colon2_token: None,
                            lt_token: Default::default(),
                            args: cont.generics
                                .params
                                .iter()
                                .map(|param| match *param {
                                    syn::GenericParam::Type(ref param) => {
                                        syn::GenericArgument::Type(syn::Type::Path(syn::TypePath {
                                            qself: None,
                                            path: param.ident.into(),
                                        }))
                                    }
                                    syn::GenericParam::Lifetime(ref param) => {
                                        syn::GenericArgument::Lifetime(param.lifetime)
                                    }
                                    syn::GenericParam::Const(_) => {
                                        panic!("Serde does not support const generics yet");
                                    }
                                })
                                .collect(),
                            gt_token: Default::default(),
                        },
                    ),
                },
            ].into_iter().collect(),
        },
    })
}
<commit_msg>Fix clippy warnings<commit_after>// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::collections::HashSet;

use syn::{self, visit};
use syn::punctuated::Punctuated;

use internals::ast::{Data, Container};
use internals::attr;

use proc_macro2::Span;

// Remove the default from every type parameter because in the generated impls
// they look like associated types: "error: associated type bindings are not
// allowed here".
pub fn without_defaults(generics: &syn::Generics) -> syn::Generics {
    syn::Generics {
        params: generics
            .params
            .iter()
            .map(|param| match *param {
                syn::GenericParam::Type(ref param) => {
                    syn::GenericParam::Type(syn::TypeParam {
                        eq_token: None,
                        default: None,
                        ..param.clone()
                    })
                }
                _ => param.clone(),
            })
            .collect(),
        ..generics.clone()
    }
}

pub fn with_where_predicates(
    generics: &syn::Generics,
    predicates: &[syn::WherePredicate],
) -> syn::Generics {
    let mut generics = generics.clone();
    generics.make_where_clause()
        .predicates
        .extend(predicates.into_iter().cloned());
    generics
}

pub fn with_where_predicates_from_fields<F, W>(
    cont: &Container,
    generics: &syn::Generics,
    trait_bound: &syn::Path,
    from_field: F,
    gen_bound_where: W,
) -> syn::Generics
where
    F: Fn(&attr::Field) -> Option<&[syn::WherePredicate]>,
    W: Fn(&attr::Field) -> bool,
{
    let predicates = cont.data
        .all_fields()
        .flat_map(|field| {
            let field_ty = field.ty;
            let matching_generic = |t: &syn::PathSegment, g: &syn::GenericParam| match *g {
                syn::GenericParam::Type(ref generic_ty)
                    if generic_ty.ident == t.ident => true,
                _ => false
            };

            let mut field_bound: Option<syn::WherePredicate> = None;
            if let syn::Type::Path(ref ty_path) = *field_ty {
                field_bound = match (gen_bound_where(&field.attrs), ty_path.path.segments.first()) {
                    (true, Some(syn::punctuated::Pair::Punctuated(ref t, _))) =>
                        if generics.params.iter().any(|g| matching_generic(t, g)) {
                            Some(parse_quote!(#field_ty: #trait_bound))
                        } else {None},
                    (_, _) => None
                };
            }
            field_bound.into_iter().chain(from_field(&field.attrs).into_iter().flat_map(|predicates| predicates.to_vec()))
        });

    let mut generics = generics.clone();
    generics.make_where_clause()
        .predicates
        .extend(predicates);
    generics
}

// Puts the given bound on any generic type parameters that are used in fields
// for which filter returns true.
//
// For example, the following struct needs the bound `A: Serialize, B: Serialize`.
//
//     struct S<'b, A, B: 'b, C> {
//         a: A,
//         b: Option<&'b B>
//         #[serde(skip_serializing)]
//         c: C,
//     }
pub fn with_bound<F>(
    cont: &Container,
    generics: &syn::Generics,
    filter: F,
    bound: &syn::Path,
) -> syn::Generics
where
    F: Fn(&attr::Field, Option<&attr::Variant>) -> bool,
{
    struct FindTyParams {
        // Set of all generic type parameters on the current struct (A, B, C in
        // the example). Initialized up front.
        all_ty_params: HashSet<syn::Ident>,
        // Set of generic type parameters used in fields for which filter
        // returns true (A and B in the example). Filled in as the visitor sees
        // them.
        relevant_ty_params: HashSet<syn::Ident>,
    }
    impl<'ast> visit::Visit<'ast> for FindTyParams {
        fn visit_path(&mut self, path: &syn::Path) {
            if let Some(seg) = path.segments.last() {
                if seg.into_value().ident == "PhantomData" {
                    // Hardcoded exception, because PhantomData<T> implements
                    // Serialize and Deserialize whether or not T implements it.
                    return;
                }
            }
            if path.leading_colon.is_none() && path.segments.len() == 1 {
                let id = path.segments[0].ident;
                if self.all_ty_params.contains(&id) {
                    self.relevant_ty_params.insert(id);
                }
            }
            visit::visit_path(self, path);
        }

        // Type parameter should not be considered used by a macro path.
        //
        //     struct TypeMacro<T> {
        //         mac: T!(),
        //         marker: PhantomData<T>,
        //     }
        fn visit_macro(&mut self, _mac: &syn::Macro) {}
    }

    let all_ty_params: HashSet<_> = generics
        .params
        .iter()
        .filter_map(|param| match *param {
            syn::GenericParam::Type(ref param) => Some(param.ident),
            _ => None,
        })
        .collect();

    let mut visitor = FindTyParams {
        all_ty_params: all_ty_params,
        relevant_ty_params: HashSet::new(),
    };
    match cont.data {
        Data::Enum(ref variants) => for variant in variants.iter() {
            let relevant_fields = variant
                .fields
                .iter()
                .filter(|field| filter(&field.attrs, Some(&variant.attrs)));
            for field in relevant_fields {
                visit::visit_type(&mut visitor, field.ty);
            }
        },
        Data::Struct(_, ref fields) => {
            for field in fields.iter().filter(|field| filter(&field.attrs, None)) {
                visit::visit_type(&mut visitor, field.ty);
            }
        }
    }

    let new_predicates = generics
        .params
        .iter()
        .filter_map(|param| match *param {
            syn::GenericParam::Type(ref param) => Some(param.ident),
            _ => None,
        })
        .filter(|id| visitor.relevant_ty_params.contains(id))
        .map(|id| {
            syn::WherePredicate::Type(syn::PredicateType {
                lifetimes: None,
                // the type parameter that is being bounded e.g. T
                bounded_ty: syn::Type::Path(syn::TypePath {
                    qself: None,
                    path: id.into(),
                }),
                colon_token: Default::default(),
                // the bound e.g. Serialize
                bounds: vec![
                    syn::TypeParamBound::Trait(syn::TraitBound {
                        paren_token: None,
                        modifier: syn::TraitBoundModifier::None,
                        lifetimes: None,
                        path: bound.clone(),
                    }),
                ].into_iter().collect(),
            })
        });

    let mut generics = generics.clone();
    generics.make_where_clause()
        .predicates
        .extend(new_predicates);
    generics
}

pub fn with_self_bound(
    cont: &Container,
    generics: &syn::Generics,
    bound: &syn::Path,
) -> syn::Generics {
    let mut generics = generics.clone();
    generics.make_where_clause()
        .predicates
        .push(syn::WherePredicate::Type(syn::PredicateType {
            lifetimes: None,
            // the type that is being bounded e.g. MyStruct<'a, T>
            bounded_ty: type_of_item(cont),
            colon_token: Default::default(),
            // the bound e.g. Default
            bounds: vec![
                syn::TypeParamBound::Trait(syn::TraitBound {
                    paren_token: None,
                    modifier: syn::TraitBoundModifier::None,
                    lifetimes: None,
                    path: bound.clone(),
                }),
            ].into_iter().collect(),
        }));
    generics
}

pub fn with_lifetime_bound(generics: &syn::Generics, lifetime: &str) -> syn::Generics {
    let bound = syn::Lifetime::new(lifetime, Span::call_site());
    let def = syn::LifetimeDef {
        attrs: Vec::new(),
        lifetime: bound,
        colon_token: None,
        bounds: Punctuated::new(),
    };

    let params = Some(syn::GenericParam::Lifetime(def))
        .into_iter()
        .chain(generics.params
            .iter()
            .cloned()
            .map(|mut param| {
                match param {
                    syn::GenericParam::Lifetime(ref mut param) => {
                        param.bounds.push(bound);
                    }
                    syn::GenericParam::Type(ref mut param) => {
                        param.bounds.push(syn::TypeParamBound::Lifetime(bound));
                    }
                    syn::GenericParam::Const(_) => {}
                }
                param
            }))
        .collect();

    syn::Generics {
        params: params,
        ..generics.clone()
    }
}

fn type_of_item(cont: &Container) -> syn::Type {
    syn::Type::Path(syn::TypePath {
        qself: None,
        path: syn::Path {
            leading_colon: None,
            segments: vec![
                syn::PathSegment {
                    ident: cont.ident,
                    arguments: syn::PathArguments::AngleBracketed(
                        syn::AngleBracketedGenericArguments {
                            colon2_token: None,
                            lt_token: Default::default(),
                            args: cont.generics
                                .params
                                .iter()
                                .map(|param| match *param {
                                    syn::GenericParam::Type(ref param) => {
                                        syn::GenericArgument::Type(syn::Type::Path(syn::TypePath {
                                            qself: None,
                                            path: param.ident.into(),
                                        }))
                                    }
                                    syn::GenericParam::Lifetime(ref param) => {
                                        syn::GenericArgument::Lifetime(param.lifetime)
                                    }
                                    syn::GenericParam::Const(_) => {
                                        panic!("Serde does not support const generics yet");
                                    }
                                })
                                .collect(),
                            gt_token: Default::default(),
                        },
                    ),
                },
            ].into_iter().collect(),
        },
    })
}
<|endoftext|>


<commit_before>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use infer::InferCtxt;
use syntax::ast;
use syntax::codemap::Span;
use rustc_data_structures::small_vec::SmallVec;
use traits::{FulfillmentContext, ObligationCause, TraitEngine, TraitEngineExt};
use traits::query::NoSolution;
use ty::{self, Ty, TyCtxt};

use ich::StableHashingContext;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
                                           StableHasherResult};
use std::mem;

/// Outlives bounds are relationships between generic parameters,
/// whether they both be regions (`'a: 'b`) or whether types are
/// involved (`T: 'a`).  These relationships can be extracted from the
/// full set of predicates we understand or also from types (in which
/// case they are called implied bounds). They are fed to the
/// `OutlivesEnv` which in turn is supplied to the region checker and
/// other parts of the inference system.
#[derive(Clone, Debug)]
pub enum OutlivesBound<'tcx> {
    RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
    RegionSubParam(ty::Region<'tcx>, ty::ParamTy),
    RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'tcx>),
}

EnumLiftImpl! {
    impl<'a, 'tcx> Lift<'tcx> for self::OutlivesBound<'a> {
        type Lifted = self::OutlivesBound<'tcx>;
        (self::OutlivesBound::RegionSubRegion)(a, b),
        (self::OutlivesBound::RegionSubParam)(a, b),
        (self::OutlivesBound::RegionSubProjection)(a, b),
    }
}

EnumTypeFoldableImpl! {
    impl<'tcx> TypeFoldable<'tcx> for self::OutlivesBound<'tcx> {
        (self::OutlivesBound::RegionSubRegion)(a, b),
        (self::OutlivesBound::RegionSubParam)(a, b),
        (self::OutlivesBound::RegionSubProjection)(a, b),
    }
}

impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for OutlivesBound<'tcx> {
    fn hash_stable<W: StableHasherResult>(&self,
                                          hcx: &mut StableHashingContext<'a>,
                                          hasher: &mut StableHasher<W>) {
        mem::discriminant(self).hash_stable(hcx, hasher);
        match *self {
            OutlivesBound::RegionSubRegion(ref a, ref b) => {
                a.hash_stable(hcx, hasher);
                b.hash_stable(hcx, hasher);
            }
            OutlivesBound::RegionSubParam(ref a, ref b) => {
                a.hash_stable(hcx, hasher);
                b.hash_stable(hcx, hasher);
            }
            OutlivesBound::RegionSubProjection(ref a, ref b) => {
                a.hash_stable(hcx, hasher);
                b.hash_stable(hcx, hasher);
            }
        }
    }
}

impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
    /// Implied bounds are region relationships that we deduce
    /// automatically.  The idea is that (e.g.) a caller must check that a
    /// function's argument types are well-formed immediately before
    /// calling that fn, and hence the *callee* can assume that its
    /// argument types are well-formed. This may imply certain relationships
    /// between generic parameters. For example:
    ///
    ///     fn foo<'a,T>(x: &'a T)
    ///
    /// can only be called with a `'a` and `T` such that `&'a T` is WF.
    /// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`.
    ///
    /// # Parameters
    ///
    /// - `param_env`, the where-clauses in scope
    /// - `body_id`, the body-id to use when normalizing assoc types.
    ///   Note that this may cause outlives obligations to be injected
    ///   into the inference context with this body-id.
    /// - `ty`, the type that we are supposed to assume is WF.
    /// - `span`, a span to use when normalizing, hopefully not important,
    ///   might be useful if a `bug!` occurs.
    pub fn implied_outlives_bounds(
        &self,
        param_env: ty::ParamEnv<'tcx>,
        _body_id: ast::NodeId,
        ty: Ty<'tcx>,
        span: Span,
    ) -> Vec<OutlivesBound<'tcx>> {
        debug!("implied_outlives_bounds(ty = {:?})", ty);

        let mut orig_values = SmallVec::new();
        let key = self.canonicalize_query(&param_env.and(ty), &mut orig_values);
        let result = match self.tcx.global_tcx().implied_outlives_bounds(key) {
            Ok(r) => r,
            Err(NoSolution) => {
                self.tcx.sess.delay_span_bug(
                    span,
                    "implied_outlives_bounds failed to solve all obligations"
                );
                return vec![];
            }
        };
        assert!(result.value.is_proven());

        let result = self.instantiate_query_result_and_region_obligations(
            &ObligationCause::dummy(), param_env, &orig_values, &result);
        debug!("implied_outlives_bounds for {:?}: {:#?}", ty, result);
        let result = match result {
            Ok(v) => v,
            Err(_) => {
                self.tcx.sess.delay_span_bug(
                    span,
                    "implied_outlives_bounds failed to instantiate"
                );
                return vec![];
            }
        };

        // Instantiation may have produced new inference variables and constraints on those
        // variables. Process these constraints.
        let mut fulfill_cx = FulfillmentContext::new();
        fulfill_cx.register_predicate_obligations(self, result.obligations);
        if let Err(_) = fulfill_cx.select_all_or_error(self) {
            self.tcx.sess.delay_span_bug(
                span,
                "implied_outlives_bounds failed to solve obligations from instantiation"
            );
        }

        result.value
    }
}

pub fn explicit_outlives_bounds<'tcx>(
    param_env: ty::ParamEnv<'tcx>,
) -> impl Iterator<Item = OutlivesBound<'tcx>> + 'tcx {
    debug!("explicit_outlives_bounds()");
    param_env
        .caller_bounds
        .into_iter()
        .filter_map(move |predicate| match predicate {
            ty::Predicate::Projection(..) |
            ty::Predicate::Trait(..) |
            ty::Predicate::Subtype(..) |
            ty::Predicate::WellFormed(..) |
            ty::Predicate::ObjectSafe(..) |
            ty::Predicate::ClosureKind(..) |
            ty::Predicate::TypeOutlives(..) |
            ty::Predicate::ConstEvaluatable(..) => None,
            ty::Predicate::RegionOutlives(ref data) => data.no_late_bound_regions().map(
                |ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a),
            ),
        })
}
<commit_msg>use proper body-id and span when solving obligations<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use infer::InferCtxt;
use syntax::ast;
use syntax::codemap::Span;
use rustc_data_structures::small_vec::SmallVec;
use traits::{FulfillmentContext, ObligationCause, TraitEngine, TraitEngineExt};
use traits::query::NoSolution;
use ty::{self, Ty, TyCtxt};

use ich::StableHashingContext;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
                                           StableHasherResult};
use std::mem;

/// Outlives bounds are relationships between generic parameters,
/// whether they both be regions (`'a: 'b`) or whether types are
/// involved (`T: 'a`).  These relationships can be extracted from the
/// full set of predicates we understand or also from types (in which
/// case they are called implied bounds). They are fed to the
/// `OutlivesEnv` which in turn is supplied to the region checker and
/// other parts of the inference system.
#[derive(Clone, Debug)]
pub enum OutlivesBound<'tcx> {
    RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
    RegionSubParam(ty::Region<'tcx>, ty::ParamTy),
    RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'tcx>),
}

EnumLiftImpl! {
    impl<'a, 'tcx> Lift<'tcx> for self::OutlivesBound<'a> {
        type Lifted = self::OutlivesBound<'tcx>;
        (self::OutlivesBound::RegionSubRegion)(a, b),
        (self::OutlivesBound::RegionSubParam)(a, b),
        (self::OutlivesBound::RegionSubProjection)(a, b),
    }
}

EnumTypeFoldableImpl! {
    impl<'tcx> TypeFoldable<'tcx> for self::OutlivesBound<'tcx> {
        (self::OutlivesBound::RegionSubRegion)(a, b),
        (self::OutlivesBound::RegionSubParam)(a, b),
        (self::OutlivesBound::RegionSubProjection)(a, b),
    }
}

impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for OutlivesBound<'tcx> {
    fn hash_stable<W: StableHasherResult>(&self,
                                          hcx: &mut StableHashingContext<'a>,
                                          hasher: &mut StableHasher<W>) {
        mem::discriminant(self).hash_stable(hcx, hasher);
        match *self {
            OutlivesBound::RegionSubRegion(ref a, ref b) => {
                a.hash_stable(hcx, hasher);
                b.hash_stable(hcx, hasher);
            }
            OutlivesBound::RegionSubParam(ref a, ref b) => {
                a.hash_stable(hcx, hasher);
                b.hash_stable(hcx, hasher);
            }
            OutlivesBound::RegionSubProjection(ref a, ref b) => {
                a.hash_stable(hcx, hasher);
                b.hash_stable(hcx, hasher);
            }
        }
    }
}

impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
    /// Implied bounds are region relationships that we deduce
    /// automatically.  The idea is that (e.g.) a caller must check that a
    /// function's argument types are well-formed immediately before
    /// calling that fn, and hence the *callee* can assume that its
    /// argument types are well-formed. This may imply certain relationships
    /// between generic parameters. For example:
    ///
    ///     fn foo<'a,T>(x: &'a T)
    ///
    /// can only be called with a `'a` and `T` such that `&'a T` is WF.
    /// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`.
    ///
    /// # Parameters
    ///
    /// - `param_env`, the where-clauses in scope
    /// - `body_id`, the body-id to use when normalizing assoc types.
    ///   Note that this may cause outlives obligations to be injected
    ///   into the inference context with this body-id.
    /// - `ty`, the type that we are supposed to assume is WF.
    /// - `span`, a span to use when normalizing, hopefully not important,
    ///   might be useful if a `bug!` occurs.
    pub fn implied_outlives_bounds(
        &self,
        param_env: ty::ParamEnv<'tcx>,
        body_id: ast::NodeId,
        ty: Ty<'tcx>,
        span: Span,
    ) -> Vec<OutlivesBound<'tcx>> {
        debug!("implied_outlives_bounds(ty = {:?})", ty);

        let mut orig_values = SmallVec::new();
        let key = self.canonicalize_query(&param_env.and(ty), &mut orig_values);
        let result = match self.tcx.global_tcx().implied_outlives_bounds(key) {
            Ok(r) => r,
            Err(NoSolution) => {
                self.tcx.sess.delay_span_bug(
                    span,
                    "implied_outlives_bounds failed to solve all obligations"
                );
                return vec![];
            }
        };
        assert!(result.value.is_proven());

        let result = self.instantiate_query_result_and_region_obligations(
            &ObligationCause::misc(span, body_id), param_env, &orig_values, &result);
        debug!("implied_outlives_bounds for {:?}: {:#?}", ty, result);
        let result = match result {
            Ok(v) => v,
            Err(_) => {
                self.tcx.sess.delay_span_bug(
                    span,
                    "implied_outlives_bounds failed to instantiate"
                );
                return vec![];
            }
        };

        // Instantiation may have produced new inference variables and constraints on those
        // variables. Process these constraints.
        let mut fulfill_cx = FulfillmentContext::new();
        fulfill_cx.register_predicate_obligations(self, result.obligations);
        if let Err(_) = fulfill_cx.select_all_or_error(self) {
            self.tcx.sess.delay_span_bug(
                span,
                "implied_outlives_bounds failed to solve obligations from instantiation"
            );
        }

        result.value
    }
}

pub fn explicit_outlives_bounds<'tcx>(
    param_env: ty::ParamEnv<'tcx>,
) -> impl Iterator<Item = OutlivesBound<'tcx>> + 'tcx {
    debug!("explicit_outlives_bounds()");
    param_env
        .caller_bounds
        .into_iter()
        .filter_map(move |predicate| match predicate {
            ty::Predicate::Projection(..) |
            ty::Predicate::Trait(..) |
            ty::Predicate::Subtype(..) |
            ty::Predicate::WellFormed(..) |
            ty::Predicate::ObjectSafe(..) |
            ty::Predicate::ClosureKind(..) |
            ty::Predicate::TypeOutlives(..) |
            ty::Predicate::ConstEvaluatable(..) => None,
            ty::Predicate::RegionOutlives(ref data) => data.no_late_bound_regions().map(
                |ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a),
            ),
        })
}
<|endoftext|>


<commit_before>use crate::spec::crt_objects::{self, CrtObjectsFallback};
use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions};

pub fn opts() -> TargetOptions {
    let mut pre_link_args = LinkArgs::new();
    pre_link_args.insert(
        LinkerFlavor::Gcc,
        vec![
            // Tell GCC to avoid linker plugins, because we are not bundling
            // them with Windows installer, and Rust does its own LTO anyways.
            "-fno-use-linker-plugin".to_string(),
            // Always enable DEP (NX bit) when it is available
            "-Wl,--nxcompat".to_string(),
        ],
    );

    let mut late_link_args = LinkArgs::new();
    let mut late_link_args_dynamic = LinkArgs::new();
    let mut late_link_args_static = LinkArgs::new();
    late_link_args.insert(
        LinkerFlavor::Gcc,
        vec![
            "-lmingwex".to_string(),
            "-lmingw32".to_string(),
            "-lmsvcrt".to_string(),
            // mingw's msvcrt is a weird hybrid import library and static library.
            // And it seems that the linker fails to use import symbols from msvcrt
            // that are required from functions in msvcrt in certain cases. For example
            // `_fmode` that is used by an implementation of `__p__fmode` in x86_64.
            // Listing the library twice seems to fix that, and seems to also be done
            // by mingw's gcc (Though not sure if it's done on purpose, or by mistake).
            //
            // See https://github.com/rust-lang/rust/pull/47483
            "-lmsvcrt".to_string(),
            "-luser32".to_string(),
            "-lkernel32".to_string(),
        ],
    );
    late_link_args_dynamic.insert(
        LinkerFlavor::Gcc,
        vec![
            // If any of our crates are dynamically linked then we need to use
            // the shared libgcc_s-dw2-1.dll. This is required to support
            // unwinding across DLL boundaries.
            "-lgcc_s".to_string(),
            "-lgcc".to_string(),
            "-lkernel32".to_string(),
        ],
    );
    late_link_args_static.insert(
        LinkerFlavor::Gcc,
        vec![
            // If all of our crates are statically linked then we can get away
            // with statically linking the libgcc unwinding code. This allows
            // binaries to be redistributed without the libgcc_s-dw2-1.dll
            // dependency, but unfortunately break unwinding across DLL
            // boundaries when unwinding across FFI boundaries.
            "-lgcc_eh".to_string(),
            "-l:libpthread.a".to_string(),
            "-lgcc".to_string(),
            // libpthread depends on libmsvcrt, so we need to link it *again*.
            "-lmsvcrt".to_string(),
            "-lkernel32".to_string(),
        ],
    );

    TargetOptions {
        // FIXME(#13846) this should be enabled for windows
        function_sections: false,
        linker: Some("gcc".to_string()),
        dynamic_linking: true,
        executables: true,
        dll_prefix: String::new(),
        dll_suffix: ".dll".to_string(),
        exe_suffix: ".exe".to_string(),
        staticlib_prefix: "lib".to_string(),
        staticlib_suffix: ".a".to_string(),
        target_family: Some("windows".to_string()),
        is_like_windows: true,
        allows_weak_linkage: false,
        pre_link_args,
        pre_link_objects: crt_objects::pre_mingw(),
        post_link_objects: crt_objects::post_mingw(),
        pre_link_objects_fallback: crt_objects::pre_mingw_fallback(),
        post_link_objects_fallback: crt_objects::post_mingw_fallback(),
        crt_objects_fallback: Some(CrtObjectsFallback::Mingw),
        late_link_args,
        late_link_args_dynamic,
        late_link_args_static,
        abi_return_struct_as_int: true,
        emit_debug_gdb_scripts: false,
        requires_uwtable: true,

        ..Default::default()
    }
}
<commit_msg>Reoder order in which MinGW libs are linked<commit_after>use crate::spec::crt_objects::{self, CrtObjectsFallback};
use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions};

pub fn opts() -> TargetOptions {
    let mut pre_link_args = LinkArgs::new();
    pre_link_args.insert(
        LinkerFlavor::Gcc,
        vec![
            // Tell GCC to avoid linker plugins, because we are not bundling
            // them with Windows installer, and Rust does its own LTO anyways.
            "-fno-use-linker-plugin".to_string(),
            // Always enable DEP (NX bit) when it is available
            "-Wl,--nxcompat".to_string(),
        ],
    );

    let mut late_link_args = LinkArgs::new();
    let mut late_link_args_dynamic = LinkArgs::new();
    let mut late_link_args_static = LinkArgs::new();
    late_link_args.insert(
        LinkerFlavor::Gcc,
        vec![
            "-lmsvcrt".to_string(),
            "-lmingwex".to_string(),
            "-lmingw32".to_string(),
            // mingw's msvcrt is a weird hybrid import library and static library.
            // And it seems that the linker fails to use import symbols from msvcrt
            // that are required from functions in msvcrt in certain cases. For example
            // `_fmode` that is used by an implementation of `__p__fmode` in x86_64.
            // Listing the library twice seems to fix that, and seems to also be done
            // by mingw's gcc (Though not sure if it's done on purpose, or by mistake).
            //
            // See https://github.com/rust-lang/rust/pull/47483
            "-lmsvcrt".to_string(),
            "-luser32".to_string(),
            "-lkernel32".to_string(),
        ],
    );
    late_link_args_dynamic.insert(
        LinkerFlavor::Gcc,
        vec![
            // If any of our crates are dynamically linked then we need to use
            // the shared libgcc_s-dw2-1.dll. This is required to support
            // unwinding across DLL boundaries.
            "-lgcc_s".to_string(),
            "-lgcc".to_string(),
            "-lkernel32".to_string(),
        ],
    );
    late_link_args_static.insert(
        LinkerFlavor::Gcc,
        vec![
            // If all of our crates are statically linked then we can get away
            // with statically linking the libgcc unwinding code. This allows
            // binaries to be redistributed without the libgcc_s-dw2-1.dll
            // dependency, but unfortunately break unwinding across DLL
            // boundaries when unwinding across FFI boundaries.
            "-lgcc_eh".to_string(),
            "-l:libpthread.a".to_string(),
            "-lgcc".to_string(),
            // libpthread depends on libmsvcrt, so we need to link it *again*.
            "-lmsvcrt".to_string(),
            "-lkernel32".to_string(),
        ],
    );

    TargetOptions {
        // FIXME(#13846) this should be enabled for windows
        function_sections: false,
        linker: Some("gcc".to_string()),
        dynamic_linking: true,
        executables: true,
        dll_prefix: String::new(),
        dll_suffix: ".dll".to_string(),
        exe_suffix: ".exe".to_string(),
        staticlib_prefix: "lib".to_string(),
        staticlib_suffix: ".a".to_string(),
        target_family: Some("windows".to_string()),
        is_like_windows: true,
        allows_weak_linkage: false,
        pre_link_args,
        pre_link_objects: crt_objects::pre_mingw(),
        post_link_objects: crt_objects::post_mingw(),
        pre_link_objects_fallback: crt_objects::pre_mingw_fallback(),
        post_link_objects_fallback: crt_objects::post_mingw_fallback(),
        crt_objects_fallback: Some(CrtObjectsFallback::Mingw),
        late_link_args,
        late_link_args_dynamic,
        late_link_args_static,
        abi_return_struct_as_int: true,
        emit_debug_gdb_scripts: false,
        requires_uwtable: true,

        ..Default::default()
    }
}
<|endoftext|>


<commit_before>//! Operations on manifest files.

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

use rawpath::RawPath;

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

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

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

struct PathBlock {
    path: RawPath,
    block: Option<usize>,
}

struct ManifestParser<R> {
    input: R,
    buf: Vec<u8>,
}

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

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

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

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

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

impl Volume {
    /// wip
    pub fn start_path(&self) -> Option<&Path> {
        self.start_path.path.as_path()
    }

    /// wip
    pub fn end_path(&self) -> Option<&Path> {
        self.end_path.path.as_path()
    }

    /// wip
    pub fn start_path_bytes(&self) -> &[u8] {
        self.start_path.path.as_bytes()
    }

    /// wip
    pub fn end_path_bytes(&self) -> &[u8] {
        self.end_path.path.as_bytes()
    }

    /// wip
    pub fn start_block(&self) -> Option<usize> {
        self.start_path.block
    }

    /// wip
    pub fn end_block(&self) -> Option<usize> {
        self.end_path.block
    }

    /// wip
    pub fn hash_type(&self) -> &str {
        &self.hash_type
    }

    /// wip
    pub fn hash(&self) -> &[u8] {
        &self.hash
    }
}

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

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

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

impl From<ParseIntError> for ParseError {
    fn from(err: ParseIntError) -> ParseError {
        ParseError::ParseInt(err)
    }
}

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

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

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

        let mut volumes = Vec::new();
        while let Some((vol, i)) = try!(self.read_volume()) {
            // resize volumes if necessary
            if i >= volumes.len() {
                volumes.reserve(i + 1);
                for _ in volumes.len()..i + 1 {
                    volumes.push(None);
                }
            }
            volumes[i] = Some(vol);
        }

        Ok(Manifest {
            hostname: hostname,
            local_dir: local_dir,
            volumes: volumes,
        })
    }

    fn read_volume(&mut self) -> Result<Option<(Volume, usize)>, ParseError> {
        // volume number
        let mut param = try!(self.read_param_str("Volume"));
        if param.ends_with(":") {
            param.pop();
        }
        let num = try!(usize::from_str(&param));
        let start_path = try!(self.read_path_block("StartingPath"));
        let end_path = try!(self.read_path_block("EndingPath"));

        // TODO: missing fields
        let vol = Volume {
            start_path: start_path,
            end_path: end_path,
            hash_type: String::new(),
            hash: vec![],
        };
        Ok(Some((vol, num)))
    }

    fn read_path_block(&mut self, key: &str) -> Result<PathBlock, ParseError> {
        try!(self.consume_whitespace());
        if !try!(self.consume_keyword(key)) {
            return Err(ParseError::MissingKeyword(key.to_owned()));
        }
        try!(self.consume_whitespace());
        let path = try!(self.read_param_value());
        try!(self.consume_whitespace());
        let block = if !try!(self.consume_byte(b'\n')) {
            let bytes = try!(self.read_param_value());
            let s = try!(String::from_utf8(bytes));
            let num = try!(usize::from_str(&s));
            Some(num)
        } else {
            None
        };
        Ok(PathBlock {
            path: RawPath::with_bytes(path),
            block: block,
        })
    }

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

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

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

    fn consume_newline(&mut self) -> io::Result<()> {
        self.consume_until(|b| {
            match b {
                b' ' | b'\t' | b'\r' | b'\n' => true,
                _ => false,
            }
        })
    }

    fn consume_whitespace(&mut self) -> io::Result<()> {
        self.consume_until(|b| {
            match b {
                b' ' | b'\t' => true,
                _ => false,
            }
        })
    }

    fn consume_until<F>(&mut self, mut f: F) -> io::Result<()>
        where F: FnMut(u8) -> bool
    {
        loop {
            let (pos, end) = {
                let buf = try!(self.input.fill_buf());
                match buf.iter().cloned().position(&mut f) {
                    Some(p) => (p, true),
                    None => (buf.len(), buf.is_empty()),
                }
            };
            self.input.consume(pos);
            if end {
                return Ok(());
            }
        }
    }

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

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

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

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

use rawpath::RawPath;

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

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

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

struct PathBlock {
    path: RawPath,
    block: Option<usize>,
}

struct ManifestParser<R> {
    input: R,
    buf: Vec<u8>,
}

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

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

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

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

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

impl Volume {
    /// wip
    pub fn start_path(&self) -> Option<&Path> {
        self.start_path.path.as_path()
    }

    /// wip
    pub fn end_path(&self) -> Option<&Path> {
        self.end_path.path.as_path()
    }

    /// wip
    pub fn start_path_bytes(&self) -> &[u8] {
        self.start_path.path.as_bytes()
    }

    /// wip
    pub fn end_path_bytes(&self) -> &[u8] {
        self.end_path.path.as_bytes()
    }

    /// wip
    pub fn start_block(&self) -> Option<usize> {
        self.start_path.block
    }

    /// wip
    pub fn end_block(&self) -> Option<usize> {
        self.end_path.block
    }

    /// wip
    pub fn hash_type(&self) -> &str {
        &self.hash_type
    }

    /// wip
    pub fn hash(&self) -> &[u8] {
        &self.hash
    }
}

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

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

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

impl From<ParseIntError> for ParseError {
    fn from(err: ParseIntError) -> ParseError {
        ParseError::ParseInt(err)
    }
}

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

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

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

        let mut volumes = Vec::new();
        while let Some((vol, i)) = try!(self.read_volume()) {
            // resize volumes if necessary
            if i >= volumes.len() {
                volumes.reserve(i + 1);
                for _ in volumes.len()..i + 1 {
                    volumes.push(None);
                }
            }
            volumes[i] = Some(vol);
        }

        Ok(Manifest {
            hostname: hostname,
            local_dir: local_dir,
            volumes: volumes,
        })
    }

    fn read_volume(&mut self) -> Result<Option<(Volume, usize)>, ParseError> {
        // volume number
        let mut param = try!(self.read_param_str("Volume"));
        if param.ends_with(":") {
            param.pop();
        }
        let num = try!(usize::from_str(&param));
        let start_path = try!(self.read_path_block("StartingPath"));
        let end_path = try!(self.read_path_block("EndingPath"));
        let (htype, h) = try!(self.read_hash_param());

        let vol = Volume {
            start_path: start_path,
            end_path: end_path,
            hash_type: htype,
            hash: h,
        };
        Ok(Some((vol, num)))
    }

    fn read_path_block(&mut self, key: &str) -> Result<PathBlock, ParseError> {
        try!(self.consume_whitespace());
        if !try!(self.consume_keyword(key)) {
            return Err(ParseError::MissingKeyword(key.to_owned()));
        }
        try!(self.consume_whitespace());
        let path = try!(self.read_param_value());
        try!(self.consume_whitespace());
        let block = if !try!(self.consume_byte(b'\n')) {
            let bytes = try!(self.read_param_value());
            let s = try!(String::from_utf8(bytes));
            let num = try!(usize::from_str(&s));
            Some(num)
        } else {
            None
        };
        Ok(PathBlock {
            path: RawPath::with_bytes(path),
            block: block,
        })
    }

    fn read_hash_param(&mut self) -> Result<(String, Vec<u8>), ParseError> {
        try!(self.consume_whitespace());
        if !try!(self.consume_keyword("Hash")) {
            return Err(ParseError::MissingKeyword("Hash".to_owned()));
        }
        try!(self.consume_whitespace());
        let bytes = try!(self.read_param_value());
        let path = try!(String::from_utf8(bytes));
        try!(self.consume_whitespace());

        unimplemented!()
    }

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

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

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

    fn consume_newline(&mut self) -> io::Result<()> {
        self.consume_until(|b| {
            match b {
                b' ' | b'\t' | b'\r' | b'\n' => true,
                _ => false,
            }
        })
    }

    fn consume_whitespace(&mut self) -> io::Result<()> {
        self.consume_until(|b| {
            match b {
                b' ' | b'\t' => true,
                _ => false,
            }
        })
    }

    fn consume_until<F>(&mut self, mut f: F) -> io::Result<()>
        where F: FnMut(u8) -> bool
    {
        loop {
            let (pos, end) = {
                let buf = try!(self.input.fill_buf());
                match buf.iter().cloned().position(&mut f) {
                    Some(p) => (p, true),
                    None => (buf.len(), buf.is_empty()),
                }
            };
            self.input.consume(pos);
            if end {
                return Ok(());
            }
        }
    }

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

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

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


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

//!
//! A tokenizer is a pattern matcher that is intended to turn a stream of symbols into another stream of symbols based on the patterns
//! that are matched. Every pattern can produce a different output symbol. If two input strings can ndfa in two different output
//! symbols, then the output symbol that is ordered lower is the one that's produced (ie, if the output symbols are numbers, then '0' will
//! be produced instead of '1' in the event of a clash)
//!

use super::countable::*;
use super::symbol_range::*;
use super::regular_pattern::*;
use super::state_machine::*;
use super::ndfa::*;
use super::prepare::*;
use super::symbol_range_dfa::*;

///
/// Used for generating tokenizing pattern matchers
///
pub struct Tokenizer<InputSymbol: Clone+Ord+Countable, OutputSymbol: Clone+Ord> {
    patterns: Vec<(Pattern<InputSymbol>, OutputSymbol)>
}

impl<InputSymbol: Clone+Ord+Countable+'static, OutputSymbol: Clone+Ord+'static> Tokenizer<InputSymbol, OutputSymbol> {
    ///
    /// Creates a new tokenizer
    ///
    pub fn new() -> Tokenizer<InputSymbol, OutputSymbol> {
        Tokenizer { patterns: vec![] }
    }

    ///
    /// Adds a new pattern that will generate the specified output symbol
    ///
    pub fn add_pattern<TPattern: ToPattern<InputSymbol>>(&mut self, pattern: TPattern, output: OutputSymbol) {
        self.patterns.push((pattern.to_pattern(), output));
    }

    ///
    /// Compiles an NDFA from this tokenizer
    ///
    pub fn to_ndfa(&self) -> Box<StateMachine<SymbolRange<InputSymbol>, OutputSymbol>> {
        let mut ndfa = Ndfa::new();

        for &(ref pattern, ref output) in &self.patterns {
            // Compile each pattern starting at state 0
            let end_state = pattern.compile(&mut ndfa, 0);

            // Set the output for this pattern
            ndfa.set_output_symbol(end_state, output.clone());
        }

        // Clear out any overlapping ranges so we can build a valid DFA
        ndfa.fix_overlapping_ranges();

        Box::new(ndfa)
    }
}

impl<'a, InputSymbol: Clone+Ord+Countable+'static, OutputSymbol: Clone+Ord+'static> PrepareToMatch<SymbolRangeDfa<InputSymbol, OutputSymbol>>
for &'a Tokenizer<InputSymbol, OutputSymbol> {
    #[inline]
    fn prepare_to_match(self) -> SymbolRangeDfa<InputSymbol, OutputSymbol> {
        let ndfa = self.to_ndfa();

        ndfa.prepare_to_match()
    }
}

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

    #[test]
    fn can_match_tokenizer_like_any_other_pattern() {
        #[derive(Ord, PartialOrd, Eq, PartialEq, Clone)]
        enum TestToken {
            AllAs,
            AllBs
        }

        let mut tokenizer = Tokenizer::new();
        tokenizer.add_pattern("a".repeat_forever(1), TestToken::AllAs);
        tokenizer.add_pattern("b".repeat_forever(1), TestToken::AllBs);

        assert!(matches("aaaa", &tokenizer) == Some(4));
        assert!(matches("bbbbb", &tokenizer) == Some(5));
        assert!(matches("abbb", &tokenizer) == Some(1));
        assert!(matches("bbaaa", &tokenizer) == Some(2));
    }

    #[test]
    fn can_distinguish_simple_tokens() {
        #[derive(Ord, PartialOrd, Eq, PartialEq, Clone)]
        enum TestToken {
            AllAs,
            AllBs
        }

        let mut tokenizer = Tokenizer::new();
        tokenizer.add_pattern("a".repeat_forever(1), TestToken::AllAs);
        tokenizer.add_pattern("b".repeat_forever(1), TestToken::AllBs);

        let matcher = tokenizer.prepare_to_match();

        assert!(match_pattern(matcher.start(), &mut "aaaaa".read_symbols()).is_accepted(&TestToken::AllAs));
        assert!(match_pattern(matcher.start(), &mut "bbbb".read_symbols()).is_accepted(&TestToken::AllBs));
    }

    #[test]
    fn clashes_producer_lower_tokens() {
        #[derive(Ord, PartialOrd, Eq, PartialEq, Clone)]
        enum TestToken {
            Abbb,
            Aaab
        }

        let mut tokenizer = Tokenizer::new();
        tokenizer.add_pattern("a".repeat_forever(1).append("b"), TestToken::Aaab);
        tokenizer.add_pattern("a".append("b".repeat_forever(1)), TestToken::Abbb);

        let matcher = tokenizer.prepare_to_match();

        assert!(match_pattern(matcher.start(), &mut "aaab".read_symbols()).is_accepted(&TestToken::Aaab));
        assert!(match_pattern(matcher.start(), &mut "ab".read_symbols()).is_accepted(&TestToken::Abbb));
        assert!(match_pattern(matcher.start(), &mut "abbbb".read_symbols()).is_accepted(&TestToken::Abbb));
    }
}
<commit_msg>Rename Tokenizer to TokenMatcher<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! A TokenMatcher is a pattern matcher that is intended to turn a stream of symbols into another stream of symbols based on the patterns
//! that are matched. Every pattern can produce a different output symbol. If two input strings can ndfa in two different output
//! symbols, then the output symbol that is ordered lower is the one that's produced (ie, if the output symbols are numbers, then '0' will
//! be produced instead of '1' in the event of a clash)
//!

use super::countable::*;
use super::symbol_range::*;
use super::regular_pattern::*;
use super::state_machine::*;
use super::ndfa::*;
use super::prepare::*;
use super::symbol_range_dfa::*;

///
/// Used for generating tokenizing pattern matchers
///
pub struct TokenMatcher<InputSymbol: Clone+Ord+Countable, OutputSymbol: Clone+Ord> {
    patterns: Vec<(Pattern<InputSymbol>, OutputSymbol)>
}

impl<InputSymbol: Clone+Ord+Countable+'static, OutputSymbol: Clone+Ord+'static> TokenMatcher<InputSymbol, OutputSymbol> {
    ///
    /// Creates a new TokenMatcher
    ///
    pub fn new() -> TokenMatcher<InputSymbol, OutputSymbol> {
        TokenMatcher { patterns: vec![] }
    }

    ///
    /// Adds a new pattern that will generate the specified output symbol
    ///
    pub fn add_pattern<TPattern: ToPattern<InputSymbol>>(&mut self, pattern: TPattern, output: OutputSymbol) {
        self.patterns.push((pattern.to_pattern(), output));
    }

    ///
    /// Compiles an NDFA from this TokenMatcher
    ///
    pub fn to_ndfa(&self) -> Box<StateMachine<SymbolRange<InputSymbol>, OutputSymbol>> {
        let mut ndfa = Ndfa::new();

        for &(ref pattern, ref output) in &self.patterns {
            // Compile each pattern starting at state 0
            let end_state = pattern.compile(&mut ndfa, 0);

            // Set the output for this pattern
            ndfa.set_output_symbol(end_state, output.clone());
        }

        // Clear out any overlapping ranges so we can build a valid DFA
        ndfa.fix_overlapping_ranges();

        Box::new(ndfa)
    }
}

impl<'a, InputSymbol: Clone+Ord+Countable+'static, OutputSymbol: Clone+Ord+'static> PrepareToMatch<SymbolRangeDfa<InputSymbol, OutputSymbol>>
for &'a TokenMatcher<InputSymbol, OutputSymbol> {
    #[inline]
    fn prepare_to_match(self) -> SymbolRangeDfa<InputSymbol, OutputSymbol> {
        let ndfa = self.to_ndfa();

        ndfa.prepare_to_match()
    }
}

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

    #[test]
    fn can_match_TokenMatcher_like_any_other_pattern() {
        #[derive(Ord, PartialOrd, Eq, PartialEq, Clone)]
        enum TestToken {
            AllAs,
            AllBs
        }

        let mut TokenMatcher = TokenMatcher::new();
        TokenMatcher.add_pattern("a".repeat_forever(1), TestToken::AllAs);
        TokenMatcher.add_pattern("b".repeat_forever(1), TestToken::AllBs);

        assert!(matches("aaaa", &TokenMatcher) == Some(4));
        assert!(matches("bbbbb", &TokenMatcher) == Some(5));
        assert!(matches("abbb", &TokenMatcher) == Some(1));
        assert!(matches("bbaaa", &TokenMatcher) == Some(2));
    }

    #[test]
    fn can_distinguish_simple_tokens() {
        #[derive(Ord, PartialOrd, Eq, PartialEq, Clone)]
        enum TestToken {
            AllAs,
            AllBs
        }

        let mut TokenMatcher = TokenMatcher::new();
        TokenMatcher.add_pattern("a".repeat_forever(1), TestToken::AllAs);
        TokenMatcher.add_pattern("b".repeat_forever(1), TestToken::AllBs);

        let matcher = TokenMatcher.prepare_to_match();

        assert!(match_pattern(matcher.start(), &mut "aaaaa".read_symbols()).is_accepted(&TestToken::AllAs));
        assert!(match_pattern(matcher.start(), &mut "bbbb".read_symbols()).is_accepted(&TestToken::AllBs));
    }

    #[test]
    fn clashes_producer_lower_tokens() {
        #[derive(Ord, PartialOrd, Eq, PartialEq, Clone)]
        enum TestToken {
            Abbb,
            Aaab
        }

        let mut TokenMatcher = TokenMatcher::new();
        TokenMatcher.add_pattern("a".repeat_forever(1).append("b"), TestToken::Aaab);
        TokenMatcher.add_pattern("a".append("b".repeat_forever(1)), TestToken::Abbb);

        let matcher = TokenMatcher.prepare_to_match();

        assert!(match_pattern(matcher.start(), &mut "aaab".read_symbols()).is_accepted(&TestToken::Aaab));
        assert!(match_pattern(matcher.start(), &mut "ab".read_symbols()).is_accepted(&TestToken::Abbb));
        assert!(match_pattern(matcher.start(), &mut "abbbb".read_symbols()).is_accepted(&TestToken::Abbb));
    }
}
<|endoftext|>


<commit_before>//! Codec for chunk type 18 = FLI_PSTAMP.

use ::{Raster,RasterMut};
use super::linscale;

/// Magic for a FLI_PSTAMP chunk - Postage Stamp Image.
///
/// This chunk type holds a postage stamp -- a reduced-size image --
/// of the frame.  It generally appears only in the first frame chunk
/// within a FLIC file.
///
/// When creating a postage stamp, Animator Pro considers the ideal
/// size to be 100x63 pixels.  The actual size will vary as needed to
/// maintain the same aspect ratio as the original.
///
/// The pixels in a postage stamp image are mapped into a six-cube
/// color space, regardless of the color palette settings for the full
/// frame image.  A six-cube color space is formed as follows:
///
/// ```text
///   start at palette entry 0
///   for red = 0 through 5
///       for green = 0 through 5
///           for blue = 0 through 5
///               palette_red   = (red   * 256) / 6
///               palette_green = (green * 256) / 6
///               palette_blue  = (blue  * 256) / 6
///               move to next palette entry
///           end for blue
///       end for green
///   end for red
/// ```
///
/// Any arbitrary RGB value (where each component is in the range of
/// 0-255) can be mapped into the six-cube space using the formula:
///
/// ```text
///   ((6 * red) / 256) * 36 + ((6 * green) / 256) * 6 + ((6 * blue) / 256)
/// ```
///
/// When a frame data chunk has been identified as a postage stamp,
/// the header for the chunk contains more fields than just size and
/// type.  The full postage stamp chunk header is defined as follows:
///
///   Offset | Length |  Name  | Description
///   ------:| ------:|:------:| -------------------------------------
///        0 |      4 |  size  | The size of the postage stamp chunk, including this header.
///        4 |      2 |  type  | Postage stamp identifier; always 18.
///        6 |      2 | height | Height of the postage stamp image, in pixels.
///        8 |      2 |  width | Width of the postage stamp image, in pixels.
///       10 |      2 |  xlate | Color translation type; always 1, indicating six-cube color space.
///
/// Immediately following this header is the postage stamp data.  The
/// data is formatted as a chunk with standard size/type header.  The
/// type will be one of:
///
///   Value | Name        | Description
///   -----:| ----------- | ------------------------------------------
///      15 | FPS_BRUN    | Byte run length compression.
///      16 | FPS_COPY    | No compression.
///      18 | FPS_XLAT256 | Six-cube color xlate table.
///
/// The FPS_BRUN and FPS_COPY types are identical to the FLI_BRUN and
/// FLI_COPY encoding methods described above.
///
/// The FPS_XLAT256 type indicates that the chunk contains a 256-byte
/// color translation table instead of pixel data.  To process this
/// type of postage stamp, read the pixel data for the full-sized
/// frame image, and translate its pixels into six-cube space using a
/// lookup in the 256-byte color translation table.  This type of
/// postage stamp appears when the size of the animation frames is
/// smaller than the standard 100x63 postage stamp size.
pub const FLI_PSTAMP: u16 = 18;

/// Magic for a FPS_XLAT256 chunk - Postage Stamp, Six-Cube Color Translation Table.
pub const FPS_XLAT256: u16 = FLI_PSTAMP;

/// Magic for the six-cube color translation type.
pub const PSTAMP_SIXCUBE: u16 = 1;

/// Stardard postage stamp width.
pub const STANDARD_PSTAMP_W: u16 = 100;

/// Stardard postage stamp height.
pub const STANDARD_PSTAMP_H: u16 = 63;

/// Create the postage stamp's six-cube palette.
pub fn make_pstamp_pal(dst: &mut RasterMut) {
    assert!(dst.pal.len() >= 6 * 6 * 6);

    let mut c = 0;
    for r in 0..6 {
        for g in 0..6 {
            for b in 0..6 {
                dst.pal[3 * c + 0] = ((r * 256) / 6) as u8;
                dst.pal[3 * c + 1] = ((g * 256) / 6) as u8;
                dst.pal[3 * c + 2] = ((b * 256) / 6) as u8;
                c = c + 1;
            }
        }
    }
}

/// Create a translation table to map the palette into the postage
/// stamp's six-cube palette.
pub fn make_pstamp_xlat256(pal: &[u8], xlat256: &mut [u8]) {
    assert_eq!(pal.len(), 3 * xlat256.len());

    for c in 0..xlat256.len() {
        let r = pal[3 * c + 0] as u32;
        let g = pal[3 * c + 1] as u32;
        let b = pal[3 * c + 2] as u32;

        xlat256[c]
            = (((6 * r) / 256) * 36
            +  ((6 * g) / 256) * 6
            +  ((6 * b) / 256)) as u8;
    }
}

/// Apply the translation table to the pixels in the raster, mapping
/// the pixels to the postage stamp's six-cube palette.
pub fn apply_pstamp_xlat256(xlat256: &[u8], dst: &mut RasterMut) {
    assert!(xlat256.len() >= ::std::u8::MAX as usize);

    let start = dst.stride * dst.y;
    let end = dst.stride * (dst.y + dst.h);
    for row in dst.buf[start..end].chunks_mut(dst.stride) {
        let start = dst.x;
        let end = start + dst.w;
        for e in &mut row[start..end] {
            *e = xlat256[*e as usize];
        }
    }
}

/// Create a new scaled down image, remapped into the six-color
/// palette.  The image may be encoded as part of a postage stamp
/// chunk using the FLI_BRUN and FLI_COPY encoders.
pub fn prepare_pstamp(
        src: &Raster, xlat256: &[u8], dst_w: usize, dst_h: usize)
        -> Vec<u8> {
    assert!(xlat256.len() >= ::std::u8::MAX as usize);

    let mut pstamp = Vec::with_capacity(dst_w * dst_h);

    for dy in 0..dst_h {
        let sy = linscale(src.h, dst_h, dy);
        let src_start = src.stride * (src.y + sy) + src.x;
        let src_end = src_start + src.w;
        let dst_start = dst_w * dy;
        let dst_end = dst_start + dst_w;
        let src_row = &src.buf[src_start..src_end];
        let dst_row = &mut pstamp[dst_start..dst_end];

        for dx in 0..dst_w {
            let sx = linscale(src.w, dst_w, dx);
            dst_row[dx] = xlat256[src_row[sx] as usize];
        }
    }

    pstamp
}

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

    #[test]
    fn test_make_pstamp_xlat256() {
        let src = [
            0x00, 0x00, 0x00,
            0x00, 0x00, 0xFF,
            0x00, 0xFF, 0x00,
            0x00, 0xFF, 0xFF,
            0xFF, 0x00, 0x00,
            0xFF, 0x00, 0xFF,
            0xFF, 0xFF, 0x00,
            0xFF, 0xFF, 0xFF ];

        let expected = [
            0, 5, 30, 35, 180, 185, 210, 215 ];

        let mut xlat256 = [0; 8];

        make_pstamp_xlat256(&src, &mut xlat256);
        assert_eq!(&xlat256[..], &expected[..]);
    }

    #[test]
    fn test_apply_pstamp_xlat256() {
        let src = [
            0, 5, 30, 35, 180, 185, 210, 215 ];

        let mut buf = [
            7, 6, 5, 4, 3, 2, 1, 0 ];

        let expected = [
            215, 210, 185, 180, 35, 30, 5, 0 ];

        const SCREEN_W: usize = 8;
        const SCREEN_H: usize = 1;
        let mut pal = [0; 3 * 256];

        let mut xlat256 = [0; 256];
        xlat256[0..8].copy_from_slice(&src[..]);

        apply_pstamp_xlat256(&xlat256,
                &mut RasterMut::new(SCREEN_W, SCREEN_H, &mut buf, &mut pal));
        assert_eq!(&buf[..], &expected[..]);
    }
}
<commit_msg>Fix #5: FlicWriter panics during to postage stamp creation.<commit_after>//! Codec for chunk type 18 = FLI_PSTAMP.

use ::{Raster,RasterMut};
use super::linscale;

/// Magic for a FLI_PSTAMP chunk - Postage Stamp Image.
///
/// This chunk type holds a postage stamp -- a reduced-size image --
/// of the frame.  It generally appears only in the first frame chunk
/// within a FLIC file.
///
/// When creating a postage stamp, Animator Pro considers the ideal
/// size to be 100x63 pixels.  The actual size will vary as needed to
/// maintain the same aspect ratio as the original.
///
/// The pixels in a postage stamp image are mapped into a six-cube
/// color space, regardless of the color palette settings for the full
/// frame image.  A six-cube color space is formed as follows:
///
/// ```text
///   start at palette entry 0
///   for red = 0 through 5
///       for green = 0 through 5
///           for blue = 0 through 5
///               palette_red   = (red   * 256) / 6
///               palette_green = (green * 256) / 6
///               palette_blue  = (blue  * 256) / 6
///               move to next palette entry
///           end for blue
///       end for green
///   end for red
/// ```
///
/// Any arbitrary RGB value (where each component is in the range of
/// 0-255) can be mapped into the six-cube space using the formula:
///
/// ```text
///   ((6 * red) / 256) * 36 + ((6 * green) / 256) * 6 + ((6 * blue) / 256)
/// ```
///
/// When a frame data chunk has been identified as a postage stamp,
/// the header for the chunk contains more fields than just size and
/// type.  The full postage stamp chunk header is defined as follows:
///
///   Offset | Length |  Name  | Description
///   ------:| ------:|:------:| -------------------------------------
///        0 |      4 |  size  | The size of the postage stamp chunk, including this header.
///        4 |      2 |  type  | Postage stamp identifier; always 18.
///        6 |      2 | height | Height of the postage stamp image, in pixels.
///        8 |      2 |  width | Width of the postage stamp image, in pixels.
///       10 |      2 |  xlate | Color translation type; always 1, indicating six-cube color space.
///
/// Immediately following this header is the postage stamp data.  The
/// data is formatted as a chunk with standard size/type header.  The
/// type will be one of:
///
///   Value | Name        | Description
///   -----:| ----------- | ------------------------------------------
///      15 | FPS_BRUN    | Byte run length compression.
///      16 | FPS_COPY    | No compression.
///      18 | FPS_XLAT256 | Six-cube color xlate table.
///
/// The FPS_BRUN and FPS_COPY types are identical to the FLI_BRUN and
/// FLI_COPY encoding methods described above.
///
/// The FPS_XLAT256 type indicates that the chunk contains a 256-byte
/// color translation table instead of pixel data.  To process this
/// type of postage stamp, read the pixel data for the full-sized
/// frame image, and translate its pixels into six-cube space using a
/// lookup in the 256-byte color translation table.  This type of
/// postage stamp appears when the size of the animation frames is
/// smaller than the standard 100x63 postage stamp size.
pub const FLI_PSTAMP: u16 = 18;

/// Magic for a FPS_XLAT256 chunk - Postage Stamp, Six-Cube Color Translation Table.
pub const FPS_XLAT256: u16 = FLI_PSTAMP;

/// Magic for the six-cube color translation type.
pub const PSTAMP_SIXCUBE: u16 = 1;

/// Stardard postage stamp width.
pub const STANDARD_PSTAMP_W: u16 = 100;

/// Stardard postage stamp height.
pub const STANDARD_PSTAMP_H: u16 = 63;

/// Create the postage stamp's six-cube palette.
pub fn make_pstamp_pal(dst: &mut RasterMut) {
    assert!(dst.pal.len() >= 6 * 6 * 6);

    let mut c = 0;
    for r in 0..6 {
        for g in 0..6 {
            for b in 0..6 {
                dst.pal[3 * c + 0] = ((r * 256) / 6) as u8;
                dst.pal[3 * c + 1] = ((g * 256) / 6) as u8;
                dst.pal[3 * c + 2] = ((b * 256) / 6) as u8;
                c = c + 1;
            }
        }
    }
}

/// Create a translation table to map the palette into the postage
/// stamp's six-cube palette.
pub fn make_pstamp_xlat256(pal: &[u8], xlat256: &mut [u8]) {
    assert_eq!(pal.len(), 3 * xlat256.len());

    for c in 0..xlat256.len() {
        let r = pal[3 * c + 0] as u32;
        let g = pal[3 * c + 1] as u32;
        let b = pal[3 * c + 2] as u32;

        xlat256[c]
            = (((6 * r) / 256) * 36
            +  ((6 * g) / 256) * 6
            +  ((6 * b) / 256)) as u8;
    }
}

/// Apply the translation table to the pixels in the raster, mapping
/// the pixels to the postage stamp's six-cube palette.
pub fn apply_pstamp_xlat256(xlat256: &[u8], dst: &mut RasterMut) {
    assert!(xlat256.len() >= ::std::u8::MAX as usize);

    let start = dst.stride * dst.y;
    let end = dst.stride * (dst.y + dst.h);
    for row in dst.buf[start..end].chunks_mut(dst.stride) {
        let start = dst.x;
        let end = start + dst.w;
        for e in &mut row[start..end] {
            *e = xlat256[*e as usize];
        }
    }
}

/// Create a new scaled down image, remapped into the six-color
/// palette.  The image may be encoded as part of a postage stamp
/// chunk using the FLI_BRUN and FLI_COPY encoders.
pub fn prepare_pstamp(
        src: &Raster, xlat256: &[u8], dst_w: usize, dst_h: usize)
        -> Vec<u8> {
    assert!(xlat256.len() >= ::std::u8::MAX as usize);

    let mut pstamp = vec![0; dst_w * dst_h];

    for dy in 0..dst_h {
        let sy = linscale(src.h, dst_h, dy);
        let src_start = src.stride * (src.y + sy) + src.x;
        let src_end = src_start + src.w;
        let dst_start = dst_w * dy;
        let dst_end = dst_start + dst_w;
        let src_row = &src.buf[src_start..src_end];
        let dst_row = &mut pstamp[dst_start..dst_end];

        for dx in 0..dst_w {
            let sx = linscale(src.w, dst_w, dx);
            dst_row[dx] = xlat256[src_row[sx] as usize];
        }
    }

    pstamp
}

#[cfg(test)]
mod tests {
    use ::{Raster,RasterMut};
    use super::*;

    #[test]
    fn test_make_pstamp_xlat256() {
        let src = [
            0x00, 0x00, 0x00,
            0x00, 0x00, 0xFF,
            0x00, 0xFF, 0x00,
            0x00, 0xFF, 0xFF,
            0xFF, 0x00, 0x00,
            0xFF, 0x00, 0xFF,
            0xFF, 0xFF, 0x00,
            0xFF, 0xFF, 0xFF ];

        let expected = [
            0, 5, 30, 35, 180, 185, 210, 215 ];

        let mut xlat256 = [0; 8];

        make_pstamp_xlat256(&src, &mut xlat256);
        assert_eq!(&xlat256[..], &expected[..]);
    }

    #[test]
    fn test_apply_pstamp_xlat256() {
        let src = [
            0, 5, 30, 35, 180, 185, 210, 215 ];

        let mut buf = [
            7, 6, 5, 4, 3, 2, 1, 0 ];

        let expected = [
            215, 210, 185, 180, 35, 30, 5, 0 ];

        const SCREEN_W: usize = 8;
        const SCREEN_H: usize = 1;
        let mut pal = [0; 3 * 256];

        let mut xlat256 = [0; 256];
        xlat256[0..8].copy_from_slice(&src[..]);

        apply_pstamp_xlat256(&xlat256,
                &mut RasterMut::new(SCREEN_W, SCREEN_H, &mut buf, &mut pal));
        assert_eq!(&buf[..], &expected[..]);
    }

    #[test]
    fn test_prepare_pstamp() {
        let src = [
            11, 11, 12, 12, 13, 13, 14, 14,
            11, 11, 12, 12, 13, 13, 14, 14,
            21, 21, 22, 22, 23, 23, 24, 24,
            21, 21, 22, 22, 23, 23, 24, 24,
            31, 31, 32, 32, 33, 33, 34, 34,
            31, 31, 32, 32, 33, 33, 34, 34,
            41, 41, 42, 42, 43, 43, 44, 44,
            41, 41, 42, 42, 43, 43, 44, 44 ];

        let expected = [
            11, 12, 13, 14,
            21, 22, 23, 24,
            31, 32, 33, 34,
            41, 42, 43, 44 ];

        const SCREEN_W: usize = 8;
        const SCREEN_H: usize = 8;
        let mut xlat256 = [0; 256];
        let pal = [0; 3 * 256];

        for i in 0..256 {
            xlat256[i] = i as u8;
        }

        let raster = Raster::new(SCREEN_W, SCREEN_H, &src, &pal);
        let pstamp = prepare_pstamp(
                &raster, &xlat256, 4, 4);
        assert_eq!(&pstamp[..], &expected[..]);
    }
}
<|endoftext|>