<commit_before>use rustc_front::hir::*;
use reexport::*;
use rustc::lint::*;
use syntax::codemap::Span;
use rustc_front::visit::{Visitor, walk_ty, walk_ty_param_bound};
use std::collections::HashSet;

use utils::{in_external_macro, span_lint};

declare_lint!(pub NEEDLESS_LIFETIMES, Warn,
              "using explicit lifetimes for references in function arguments when elision rules \
               would allow omitting them");

#[derive(Copy,Clone)]
pub struct LifetimePass;

impl LintPass for LifetimePass {
    fn get_lints(&self) -> LintArray {
        lint_array!(NEEDLESS_LIFETIMES)
    }
}

impl LateLintPass for LifetimePass {
    fn check_item(&mut self, cx: &LateContext, item: &Item) {
        if let ItemFn(ref decl, _, _, _, ref generics, _) = item.node {
            check_fn_inner(cx, decl, None, &generics, item.span);
        }
    }

    fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) {
        if let MethodImplItem(ref sig, _) = item.node {
            check_fn_inner(cx, &sig.decl, Some(&sig.explicit_self),
                           &sig.generics, item.span);
        }
    }

    fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) {
        if let MethodTraitItem(ref sig, _) = item.node {
            check_fn_inner(cx, &sig.decl, Some(&sig.explicit_self),
                           &sig.generics, item.span);
        }
    }
}

/// The lifetime of a &-reference.
#[derive(PartialEq, Eq, Hash, Debug)]
enum RefLt {
    Unnamed,
    Static,
    Named(Name),
}
use self::RefLt::*;

fn check_fn_inner(cx: &LateContext, decl: &FnDecl, slf: Option<&ExplicitSelf>,
                  generics: &Generics, span: Span) {
    if in_external_macro(cx, span) || has_where_lifetimes(&generics.where_clause) {
        return;
    }
    if could_use_elision(decl, slf, &generics.lifetimes) {
        span_lint(cx, NEEDLESS_LIFETIMES, span,
                  "explicit lifetimes given in parameter types where they could be elided");
    }
}

fn could_use_elision(func: &FnDecl, slf: Option<&ExplicitSelf>,
                     named_lts: &[LifetimeDef]) -> bool {
    // There are two scenarios where elision works:
    // * no output references, all input references have different LT
    // * output references, exactly one input reference with same LT
    // All lifetimes must be unnamed, 'static or defined without bounds on the
    // level of the current item.

    // check named LTs
    let allowed_lts = allowed_lts_from(named_lts);

    // these will collect all the lifetimes for references in arg/return types
    let mut input_visitor = RefVisitor(Vec::new());
    let mut output_visitor = RefVisitor(Vec::new());

    // extract lifetime in "self" argument for methods (there is a "self" argument
    // in func.inputs, but its type is TyInfer)
    if let Some(slf) = slf {
        match slf.node {
            SelfRegion(ref opt_lt, _, _) => input_visitor.record(opt_lt),
            SelfExplicit(ref ty, _) => walk_ty(&mut input_visitor, ty),
            _ => { }
        }
    }
    // extract lifetimes in input argument types
    for arg in &func.inputs {
        walk_ty(&mut input_visitor, &arg.ty);
    }
    // extract lifetimes in output type
    if let Return(ref ty) = func.output {
        walk_ty(&mut output_visitor, ty);
    }

    let input_lts = input_visitor.into_vec();
    let output_lts = output_visitor.into_vec();

    // check for lifetimes from higher scopes
    for lt in input_lts.iter().chain(output_lts.iter()) {
        if !allowed_lts.contains(lt) {
            return false;
        }
    }

    // no input lifetimes? easy case!
    if input_lts.is_empty() {
        return false;
    } else if output_lts.is_empty() {
        // no output lifetimes, check distinctness of input lifetimes

        // only unnamed and static, ok
        if input_lts.iter().all(|lt| *lt == Unnamed || *lt == Static) {
            return false;
        }
        // we have no output reference, so we only need all distinct lifetimes
        if input_lts.len() == unique_lifetimes(&input_lts) {
            return true;
        }
    } else {
        // we have output references, so we need one input reference,
        // and all output lifetimes must be the same
        if unique_lifetimes(&output_lts) > 1 {
            return false;
        }
        if input_lts.len() == 1 {
            match (&input_lts[0], &output_lts[0]) {
                (&Named(n1), &Named(n2)) if n1 == n2 => { return true; }
                (&Named(_), &Unnamed) => { return true; }
                (&Unnamed, &Named(_)) => { return true; }
                _ => { } // already elided, different named lifetimes
                         // or something static going on
            }
        }
    }
    false
}

fn allowed_lts_from(named_lts: &[LifetimeDef]) -> HashSet<RefLt> {
    let mut allowed_lts = HashSet::new();
    for lt in named_lts {
        if lt.bounds.is_empty() {
            allowed_lts.insert(Named(lt.lifetime.name));
        }
    }
    allowed_lts.insert(Unnamed);
    allowed_lts.insert(Static);
    allowed_lts
}

/// Number of unique lifetimes in the given vector.
fn unique_lifetimes(lts: &[RefLt]) -> usize {
    lts.iter().collect::<HashSet<_>>().len()
}

/// A visitor usable for rustc_front::visit::walk_ty().
struct RefVisitor(Vec<RefLt>);

impl RefVisitor {
    fn record(&mut self, lifetime: &Option<Lifetime>) {
        if let &Some(ref lt) = lifetime {
            if lt.name.as_str() == "'static" {
                self.0.push(Static);
            } else {
                self.0.push(Named(lt.name));
            }
        } else {
            self.0.push(Unnamed);
        }
    }

    fn into_vec(self) -> Vec<RefLt> {
        self.0
    }
}

impl<'v> Visitor<'v> for RefVisitor {
    // for lifetimes of references
    fn visit_opt_lifetime_ref(&mut self, _: Span, lifetime: &'v Option<Lifetime>) {
        self.record(lifetime);
    }

    // for lifetimes as parameters of generics
    fn visit_lifetime_ref(&mut self, lifetime: &'v Lifetime) {
        self.record(&Some(*lifetime));
    }

    // for lifetime bounds; the default impl calls visit_lifetime_ref
    fn visit_lifetime_bound(&mut self, _: &'v Lifetime) { }
}

/// Are any lifetimes mentioned in the `where` clause? If yes, we don't try to
/// reason about elision.
fn has_where_lifetimes(where_clause: &WhereClause) -> bool {
    for predicate in &where_clause.predicates {
        match *predicate {
            WherePredicate::RegionPredicate(..) => return true,
            WherePredicate::BoundPredicate(ref pred) => {
                // a predicate like F: Trait or F: for<'a> Trait<'a>
                let mut visitor = RefVisitor(Vec::new());
                // walk the type F, it may not contain LT refs
                walk_ty(&mut visitor, &pred.bounded_ty);
                if !visitor.0.is_empty() { return true; }
                // if the bounds define new lifetimes, they are fine to occur
                let allowed_lts = allowed_lts_from(&pred.bound_lifetimes);
                // now walk the bounds
                for bound in pred.bounds.iter() {
                    walk_ty_param_bound(&mut visitor, bound);
                }
                // and check that all lifetimes are allowed
                for lt in visitor.into_vec() {
                    if !allowed_lts.contains(&lt) {
                        return true;
                    }
                }
            }
            WherePredicate::EqPredicate(ref pred) => {
                let mut visitor = RefVisitor(Vec::new());
                walk_ty(&mut visitor, &pred.ty);
                if !visitor.0.is_empty() { return true; }
            }
        }
    }
    false
}
<commit_msg>rustup to rustc 1.5.0-nightly (65d5c0833 2015-09-29)<commit_after>use rustc_front::hir::*;
use reexport::*;
use rustc::lint::*;
use syntax::codemap::Span;
use rustc_front::visit::{Visitor, walk_ty, walk_ty_param_bound};
use std::collections::HashSet;

use utils::{in_external_macro, span_lint};

declare_lint!(pub NEEDLESS_LIFETIMES, Warn,
              "using explicit lifetimes for references in function arguments when elision rules \
               would allow omitting them");

#[derive(Copy,Clone)]
pub struct LifetimePass;

impl LintPass for LifetimePass {
    fn get_lints(&self) -> LintArray {
        lint_array!(NEEDLESS_LIFETIMES)
    }
}

impl LateLintPass for LifetimePass {
    fn check_item(&mut self, cx: &LateContext, item: &Item) {
        if let ItemFn(ref decl, _, _, _, ref generics, _) = item.node {
            check_fn_inner(cx, decl, None, &generics, item.span);
        }
    }

    fn check_impl_item(&mut self, cx: &LateContext, item: &ImplItem) {
        if let MethodImplItem(ref sig, _) = item.node {
            check_fn_inner(cx, &sig.decl, Some(&sig.explicit_self),
                           &sig.generics, item.span);
        }
    }

    fn check_trait_item(&mut self, cx: &LateContext, item: &TraitItem) {
        if let MethodTraitItem(ref sig, _) = item.node {
            check_fn_inner(cx, &sig.decl, Some(&sig.explicit_self),
                           &sig.generics, item.span);
        }
    }
}

/// The lifetime of a &-reference.
#[derive(PartialEq, Eq, Hash, Debug)]
enum RefLt {
    Unnamed,
    Static,
    Named(Name),
}
use self::RefLt::*;

fn check_fn_inner(cx: &LateContext, decl: &FnDecl, slf: Option<&ExplicitSelf>,
                  generics: &Generics, span: Span) {
    if in_external_macro(cx, span) || has_where_lifetimes(&generics.where_clause) {
        return;
    }
    if could_use_elision(decl, slf, &generics.lifetimes) {
        span_lint(cx, NEEDLESS_LIFETIMES, span,
                  "explicit lifetimes given in parameter types where they could be elided");
    }
}

fn could_use_elision(func: &FnDecl, slf: Option<&ExplicitSelf>,
                     named_lts: &[LifetimeDef]) -> bool {
    // There are two scenarios where elision works:
    // * no output references, all input references have different LT
    // * output references, exactly one input reference with same LT
    // All lifetimes must be unnamed, 'static or defined without bounds on the
    // level of the current item.

    // check named LTs
    let allowed_lts = allowed_lts_from(named_lts);

    // these will collect all the lifetimes for references in arg/return types
    let mut input_visitor = RefVisitor(Vec::new());
    let mut output_visitor = RefVisitor(Vec::new());

    // extract lifetime in "self" argument for methods (there is a "self" argument
    // in func.inputs, but its type is TyInfer)
    if let Some(slf) = slf {
        match slf.node {
            SelfRegion(ref opt_lt, _, _) => input_visitor.record(opt_lt),
            SelfExplicit(ref ty, _) => walk_ty(&mut input_visitor, ty),
            _ => { }
        }
    }
    // extract lifetimes in input argument types
    for arg in &func.inputs {
        walk_ty(&mut input_visitor, &arg.ty);
    }
    // extract lifetimes in output type
    if let Return(ref ty) = func.output {
        walk_ty(&mut output_visitor, ty);
    }

    let input_lts = input_visitor.into_vec();
    let output_lts = output_visitor.into_vec();

    // check for lifetimes from higher scopes
    for lt in input_lts.iter().chain(output_lts.iter()) {
        if !allowed_lts.contains(lt) {
            return false;
        }
    }

    // no input lifetimes? easy case!
    if input_lts.is_empty() {
        return false;
    } else if output_lts.is_empty() {
        // no output lifetimes, check distinctness of input lifetimes

        // only unnamed and static, ok
        if input_lts.iter().all(|lt| *lt == Unnamed || *lt == Static) {
            return false;
        }
        // we have no output reference, so we only need all distinct lifetimes
        if input_lts.len() == unique_lifetimes(&input_lts) {
            return true;
        }
    } else {
        // we have output references, so we need one input reference,
        // and all output lifetimes must be the same
        if unique_lifetimes(&output_lts) > 1 {
            return false;
        }
        if input_lts.len() == 1 {
            match (&input_lts[0], &output_lts[0]) {
                (&Named(n1), &Named(n2)) if n1 == n2 => { return true; }
                (&Named(_), &Unnamed) => { return true; }
                (&Unnamed, &Named(_)) => { return true; }
                _ => { } // already elided, different named lifetimes
                         // or something static going on
            }
        }
    }
    false
}

fn allowed_lts_from(named_lts: &[LifetimeDef]) -> HashSet<RefLt> {
    let mut allowed_lts = HashSet::new();
    for lt in named_lts {
        if lt.bounds.is_empty() {
            allowed_lts.insert(Named(lt.lifetime.name));
        }
    }
    allowed_lts.insert(Unnamed);
    allowed_lts.insert(Static);
    allowed_lts
}

/// Number of unique lifetimes in the given vector.
fn unique_lifetimes(lts: &[RefLt]) -> usize {
    lts.iter().collect::<HashSet<_>>().len()
}

/// A visitor usable for rustc_front::visit::walk_ty().
struct RefVisitor(Vec<RefLt>);

impl RefVisitor {
    fn record(&mut self, lifetime: &Option<Lifetime>) {
        if let &Some(ref lt) = lifetime {
            if lt.name.as_str() == "'static" {
                self.0.push(Static);
            } else {
                self.0.push(Named(lt.name));
            }
        } else {
            self.0.push(Unnamed);
        }
    }

    fn into_vec(self) -> Vec<RefLt> {
        self.0
    }
}

impl<'v> Visitor<'v> for RefVisitor {
    // for lifetimes as parameters of generics
    fn visit_lifetime(&mut self, lifetime: &'v Lifetime) {
        self.record(&Some(*lifetime));
    }
}

/// Are any lifetimes mentioned in the `where` clause? If yes, we don't try to
/// reason about elision.
fn has_where_lifetimes(where_clause: &WhereClause) -> bool {
    for predicate in &where_clause.predicates {
        match *predicate {
            WherePredicate::RegionPredicate(..) => return true,
            WherePredicate::BoundPredicate(ref pred) => {
                // a predicate like F: Trait or F: for<'a> Trait<'a>
                let mut visitor = RefVisitor(Vec::new());
                // walk the type F, it may not contain LT refs
                walk_ty(&mut visitor, &pred.bounded_ty);
                if !visitor.0.is_empty() { return true; }
                // if the bounds define new lifetimes, they are fine to occur
                let allowed_lts = allowed_lts_from(&pred.bound_lifetimes);
                // now walk the bounds
                for bound in pred.bounds.iter() {
                    walk_ty_param_bound(&mut visitor, bound);
                }
                // and check that all lifetimes are allowed
                for lt in visitor.into_vec() {
                    if !allowed_lts.contains(&lt) {
                        return true;
                    }
                }
            }
            WherePredicate::EqPredicate(ref pred) => {
                let mut visitor = RefVisitor(Vec::new());
                walk_ty(&mut visitor, &pred.ty);
                if !visitor.0.is_empty() { return true; }
            }
        }
    }
    false
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use cg::{self, WhereClause};
use darling::util::Override;
use quote::Tokens;
use syn::{self, Ident};
use synstructure::{Structure, VariantInfo};

pub fn derive(input: syn::DeriveInput) -> Tokens {
    let name = &input.ident;
    let trait_path = parse_quote!(::style_traits::ToCss);
    let (impl_generics, ty_generics, mut where_clause) =
        cg::trait_parts(&input, &trait_path);

    let input_attrs = cg::parse_input_attrs::<CssInputAttrs>(&input);
    let s = Structure::new(&input);

    let match_body = s.each_variant(|variant| {
        derive_variant_arm(variant, &mut where_clause)
    });

    let mut impls = quote! {
        impl #impl_generics ::style_traits::ToCss for #name #ty_generics #where_clause {
            #[allow(unused_variables)]
            #[inline]
            fn to_css<W>(
                &self,
                dest: &mut ::style_traits::CssWriter<W>,
            ) -> ::std::fmt::Result
            where
                W: ::std::fmt::Write
            {
                match *self {
                    #match_body
                }
            }
        }
    };

    if input_attrs.derive_debug {
        impls.append_all(quote! {
            impl #impl_generics ::std::fmt::Debug for #name #ty_generics #where_clause {
                fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                    ::style_traits::ToCss::to_css(
                        self,
                        &mut ::style_traits::CssWriter::new(f),
                    )
                }
            }
        });
    }

    impls
}

fn derive_variant_arm(
    variant: &VariantInfo,
    where_clause: &mut WhereClause,
) -> Tokens {
    let bindings = variant.bindings();
    let identifier = cg::to_css_identifier(variant.ast().ident.as_ref());
    let ast = variant.ast();
    let variant_attrs = cg::parse_variant_attrs::<CssVariantAttrs>(&ast);
    let separator = if variant_attrs.comma { ", " } else { " " };

    if variant_attrs.dimension {
        assert_eq!(bindings.len(), 1);
        assert!(
            variant_attrs.function.is_none() && variant_attrs.keyword.is_none(),
            "That makes no sense"
        );
    }

    let mut expr = if let Some(keyword) = variant_attrs.keyword {
        assert!(bindings.is_empty());
        let keyword = keyword.to_string();
        quote! {
            ::std::fmt::Write::write_str(dest, #keyword)
        }
    } else if !bindings.is_empty() {
        let mut expr = quote! {};
        if variant_attrs.iterable {
            assert_eq!(bindings.len(), 1);
            let binding = &bindings[0];
            expr = quote! {
                #expr

                for item in #binding.iter() {
                    writer.item(&item)?;
                }
            };
        } else {
            for binding in bindings {
                let attrs = cg::parse_field_attrs::<CssFieldAttrs>(&binding.ast());
                if attrs.skip {
                    continue;
                }
                if !attrs.ignore_bound {
                    where_clause.add_trait_bound(&binding.ast().ty);
                }
                expr = quote! {
                    #expr
                    writer.item(#binding)?;
                };
            }
        }

        quote! {{
            let mut writer = ::style_traits::values::SequenceWriter::new(dest, #separator);
            #expr
            Ok(())
        }}
    } else {
        quote! {
            ::std::fmt::Write::write_str(dest, #identifier)
        }
    };

    if variant_attrs.dimension {
        expr = quote! {
            #expr?;
            ::std::fmt::Write::write_str(dest, #identifier)
        }
    } else if let Some(function) = variant_attrs.function {
        let mut identifier = function.explicit().map_or(identifier, |name| name.to_string());
        identifier.push_str("(");
        expr = quote! {
            ::std::fmt::Write::write_str(dest, #identifier)?;
            #expr?;
            ::std::fmt::Write::write_str(dest, ")")
        }
    }
    expr
}

#[darling(attributes(css), default)]
#[derive(Default, FromDeriveInput)]
struct CssInputAttrs {
    derive_debug: bool,
    // Here because structs variants are also their whole type definition.
    function: Option<Override<Ident>>,
    // Here because structs variants are also their whole type definition.
    comma: bool,
    // Here because structs variants are also their whole type definition.
    iterable: bool,
}

#[darling(attributes(css), default)]
#[derive(Default, FromVariant)]
pub struct CssVariantAttrs {
    pub function: Option<Override<Ident>>,
    pub iterable: bool,
    pub comma: bool,
    pub dimension: bool,
    pub keyword: Option<String>,
    pub aliases: Option<String>,
}

#[darling(attributes(css), default)]
#[derive(Default, FromField)]
struct CssFieldAttrs {
    ignore_bound: bool,
    skip: bool,
}
<commit_msg>Don't use Ident for #[css(function)]<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use cg::{self, WhereClause};
use darling::util::Override;
use quote::Tokens;
use syn::{self, Data};
use synstructure::{Structure, VariantInfo};

pub fn derive(input: syn::DeriveInput) -> Tokens {
    let name = &input.ident;
    let trait_path = parse_quote!(::style_traits::ToCss);
    let (impl_generics, ty_generics, mut where_clause) =
        cg::trait_parts(&input, &trait_path);

    let input_attrs = cg::parse_input_attrs::<CssInputAttrs>(&input);
    let s = Structure::new(&input);

    let match_body = s.each_variant(|variant| {
        derive_variant_arm(variant, &mut where_clause)
    });

    let mut impls = quote! {
        impl #impl_generics ::style_traits::ToCss for #name #ty_generics #where_clause {
            #[allow(unused_variables)]
            #[inline]
            fn to_css<W>(
                &self,
                dest: &mut ::style_traits::CssWriter<W>,
            ) -> ::std::fmt::Result
            where
                W: ::std::fmt::Write
            {
                match *self {
                    #match_body
                }
            }
        }
    };

    if input_attrs.derive_debug {
        impls.append_all(quote! {
            impl #impl_generics ::std::fmt::Debug for #name #ty_generics #where_clause {
                fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                    ::style_traits::ToCss::to_css(
                        self,
                        &mut ::style_traits::CssWriter::new(f),
                    )
                }
            }
        });
    }

    impls
}

fn derive_variant_arm(
    variant: &VariantInfo,
    where_clause: &mut WhereClause,
) -> Tokens {
    let bindings = variant.bindings();
    let identifier = cg::to_css_identifier(variant.ast().ident.as_ref());
    let ast = variant.ast();
    let variant_attrs = cg::parse_variant_attrs::<CssVariantAttrs>(&ast);
    let separator = if variant_attrs.comma { ", " } else { " " };

    if variant_attrs.dimension {
        assert_eq!(bindings.len(), 1);
        assert!(
            variant_attrs.function.is_none() && variant_attrs.keyword.is_none(),
            "That makes no sense"
        );
    }

    let mut expr = if let Some(keyword) = variant_attrs.keyword {
        assert!(bindings.is_empty());
        let keyword = keyword.to_string();
        quote! {
            ::std::fmt::Write::write_str(dest, #keyword)
        }
    } else if !bindings.is_empty() {
        let mut expr = quote! {};
        if variant_attrs.iterable {
            assert_eq!(bindings.len(), 1);
            let binding = &bindings[0];
            expr = quote! {
                #expr

                for item in #binding.iter() {
                    writer.item(&item)?;
                }
            };
        } else {
            for binding in bindings {
                let attrs = cg::parse_field_attrs::<CssFieldAttrs>(&binding.ast());
                if attrs.skip {
                    continue;
                }
                if !attrs.ignore_bound {
                    where_clause.add_trait_bound(&binding.ast().ty);
                }
                expr = quote! {
                    #expr
                    writer.item(#binding)?;
                };
            }
        }

        quote! {{
            let mut writer = ::style_traits::values::SequenceWriter::new(dest, #separator);
            #expr
            Ok(())
        }}
    } else {
        quote! {
            ::std::fmt::Write::write_str(dest, #identifier)
        }
    };

    if variant_attrs.dimension {
        expr = quote! {
            #expr?;
            ::std::fmt::Write::write_str(dest, #identifier)
        }
    } else if let Some(function) = variant_attrs.function {
        let mut identifier = function.explicit().map_or(identifier, |name| name);
        identifier.push_str("(");
        expr = quote! {
            ::std::fmt::Write::write_str(dest, #identifier)?;
            #expr?;
            ::std::fmt::Write::write_str(dest, ")")
        }
    }
    expr
}

#[darling(attributes(css), default)]
#[derive(Default, FromDeriveInput)]
struct CssInputAttrs {
    derive_debug: bool,
    // Here because structs variants are also their whole type definition.
    function: Option<Override<String>>,
    // Here because structs variants are also their whole type definition.
    comma: bool,
    // Here because structs variants are also their whole type definition.
    iterable: bool,
}

#[darling(attributes(css), default)]
#[derive(Default, FromVariant)]
pub struct CssVariantAttrs {
    pub function: Option<Override<String>>,
    pub iterable: bool,
    pub comma: bool,
    pub dimension: bool,
    pub keyword: Option<String>,
    pub aliases: Option<String>,
}

#[darling(attributes(css), default)]
#[derive(Default, FromField)]
struct CssFieldAttrs {
    ignore_bound: bool,
    skip: bool,
}
<|endoftext|>


<commit_before>//! Defines the light interface implemented by all lights in tray_rust and
//! the OcclusionTester which provides a convenient interface for doing
//! shadow tests for lights

use std::f32;

use linalg;
use film::Colorf;
use scene::Scene;

pub use self::point::Point;

pub mod point;

/// The OcclusionTester provides a simple interface for setting up and executing
/// occlusion queries in the scene
#[derive(Clone, Copy, Debug)]
pub struct OcclusionTester {
    /// The ray (or ray segment) that the occlusion test is performed on
    pub ray: linalg::Ray,
}

impl OcclusionTester {
    /// Create an occlusion tester to perform the test between two points
    pub fn test_points(a: &linalg::Point, b: &linalg::Point) -> OcclusionTester {
        OcclusionTester { ray: linalg::Ray::segment(a, &(*b - *a), 0.001, 0.999) }
    }
    /// Create an occlusion tester to perform the test along the ray starting at `p`
    /// and in direction `d`
    pub fn test_ray(p: &linalg::Point, d: &linalg::Vector) -> OcclusionTester {
        OcclusionTester { ray: linalg::Ray::segment(p, d, 0.001, f32::INFINITY) }
    }
    /// Perform the occlusion test in the scene
    pub fn occluded(&self, scene: &Scene) -> bool {
        let mut r = self.ray;
        if let Some(_) = scene.intersect(&mut r) {
            true
        } else {
            false
        }
    }
}

/// Trait implemented by all lights in tray_rust. Provides methods for sampling
/// the light and in the future ones for checking if it's a delta light, computing
/// its power and so on.
pub trait Light {
    /// Sample the illumination from the light arriving at the point `p`
    /// Returns the color, incident light direction, pdf and occlusion tester object
    /// `samples` will be used to randomly sample the light and should contain 3 f32s
    /// TODO: how to require that it's at least this size?
    fn sample_incident(&self, p: &linalg::Point, samples: &(f32, f32)) -> (Colorf, linalg::Vector, f32, OcclusionTester);
    /// Determine if the light is described by a delta distribution
    fn delta_light(&self) -> bool;
}

<commit_msg>Clean up overly long line<commit_after>//! Defines the light interface implemented by all lights in tray_rust and
//! the OcclusionTester which provides a convenient interface for doing
//! shadow tests for lights

use std::f32;

use linalg;
use film::Colorf;
use scene::Scene;

pub use self::point::Point;

pub mod point;

/// The OcclusionTester provides a simple interface for setting up and executing
/// occlusion queries in the scene
#[derive(Clone, Copy, Debug)]
pub struct OcclusionTester {
    /// The ray (or ray segment) that the occlusion test is performed on
    pub ray: linalg::Ray,
}

impl OcclusionTester {
    /// Create an occlusion tester to perform the test between two points
    pub fn test_points(a: &linalg::Point, b: &linalg::Point) -> OcclusionTester {
        OcclusionTester { ray: linalg::Ray::segment(a, &(*b - *a), 0.001, 0.999) }
    }
    /// Create an occlusion tester to perform the test along the ray starting at `p`
    /// and in direction `d`
    pub fn test_ray(p: &linalg::Point, d: &linalg::Vector) -> OcclusionTester {
        OcclusionTester { ray: linalg::Ray::segment(p, d, 0.001, f32::INFINITY) }
    }
    /// Perform the occlusion test in the scene
    pub fn occluded(&self, scene: &Scene) -> bool {
        let mut r = self.ray;
        if let Some(_) = scene.intersect(&mut r) {
            true
        } else {
            false
        }
    }
}

/// Trait implemented by all lights in tray_rust. Provides methods for sampling
/// the light and in the future ones for checking if it's a delta light, computing
/// its power and so on.
pub trait Light {
    /// Sample the illumination from the light arriving at the point `p`
    /// Returns the color, incident light direction, pdf and occlusion tester object
    /// `samples` will be used to randomly sample the light and should contain 3 f32s
    /// TODO: how to require that it's at least this size?
    fn sample_incident(&self, p: &linalg::Point, samples: &(f32, f32))
        -> (Colorf, linalg::Vector, f32, OcclusionTester);
    /// Determine if the light is described by a delta distribution
    fn delta_light(&self) -> bool;
}

<|endoftext|>


<commit_before>use std::collections::HashMap;
use itertools::Itertools;

fn is_seq(triplet: &Vec<&u32>) -> bool {
    triplet[1] - triplet[0] == triplet[2] - triplet[1]
}

pub fn main() {
    let primes_from1000 = (1000..)
                              .filter(|&n| (2..(n as f32).sqrt() as u32 + 1).all(|i| n % i != 0));
    let mut permutations = HashMap::<String, Vec<u32>>::new();

    for p in primes_from1000.take_while(|&n| n < 10_000) {
        let mut numbers = p.to_string().chars().collect::<Vec<char>>();
        numbers.sort();
        let key = numbers.into_iter().collect::<String>();
        let mut v = permutations.entry(key).or_insert(Vec::new());
        v.push(p)
    }

    let mut res = Vec::new();
    for v in permutations.values().filter(|&v| v.len() > 2) {
        let r = v.iter()
                 .combinations_n(3)
                 .filter(|c| is_seq(c))
                 .flatten()
                 .collect::<Vec<_>>();
        if !r.is_empty() {
            res.push(r);
        }
    }
    println!("{:?}", res);
}
<commit_msg>use proper Entry API<commit_after>use std::collections::HashMap;
use itertools::Itertools;

fn is_seq(triplet: &Vec<&u32>) -> bool {
    triplet[1] - triplet[0] == triplet[2] - triplet[1]
}

pub fn main() {
    let primes_from1000 = (1000..)
                              .filter(|&n| (2..(n as f32).sqrt() as u32 + 1).all(|i| n % i != 0));
    let mut permutations = HashMap::<String, Vec<u32>>::new();

    for p in primes_from1000.take_while(|&n| n < 10_000) {
        let mut numbers = p.to_string().chars().collect::<Vec<char>>();
        numbers.sort();
        let key = numbers.into_iter().collect::<String>();
        let mut v = permutations.entry(key).or_insert_with(Vec::new);
        v.push(p)
    }

    let mut res = Vec::new();
    for v in permutations.values().filter(|&v| v.len() > 2) {
        let r = v.iter()
                 .combinations_n(3)
                 .filter(|c| is_seq(c))
                 .flatten()
                 .collect::<Vec<_>>();
        if !r.is_empty() {
            res.push(r);
        }
    }
    println!("{:?}", res);
}
<|endoftext|>


<commit_before>use std;
use std::io;

use read_le16;
use read_le32;

use errors::Result;
use errors::ErrorKind::*;

#[derive(Debug)]
struct Extent {
    /// The docs call this 'block' (like everything else). I've invented a different name.
    part: u32,
    start: u64,
    len: u16,
}

pub struct TreeReader<R> {
    inner: R,
    pos: u64,
    len: u64,
    block_size: u32,
    extents: Vec<Extent>,
}

impl<R> TreeReader<R>
where
    R: io::Read + io::Seek,
{
    pub fn new(
        mut inner: R,
        block_size: u32,
        size: u64,
        core: [u8; ::INODE_CORE_SIZE],
        checksum_prefix: Option<u32>,
    ) -> Result<TreeReader<R>> {
        let extents = load_extent_tree(
            &mut |block| ::load_disc_bytes(&mut inner, block_size, block),
            core,
            checksum_prefix,
        )?;
        TreeReader::create(inner, block_size, size, extents)
    }

    fn create(inner: R, block_size: u32, size: u64, extents: Vec<Extent>) -> Result<TreeReader<R>> {
        Ok(TreeReader {
            pos: 0,
            len: size,
            inner,
            extents,
            block_size,
        })
    }

    pub fn into_inner(self) -> R {
        self.inner
    }
}

enum FoundPart<'a> {
    Actual(&'a Extent),
    Sparse(u32),
}

fn find_part(part: u32, extents: &[Extent]) -> FoundPart {
    for extent in extents {
        if part < extent.part {
            // we've gone past it
            return FoundPart::Sparse(extent.part - part);
        }

        if part >= extent.part && part < extent.part + extent.len as u32 {
            // we're inside it
            return FoundPart::Actual(extent);
        }
    }

    FoundPart::Sparse(std::u32::MAX)
}

impl<R> io::Read for TreeReader<R>
where
    R: io::Read + io::Seek,
{
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        if buf.is_empty() {
            return Ok(0);
        }

        let block_size = self.block_size as u64;

        let wanted_block = (self.pos / block_size) as u32;
        let read_of_this_block = self.pos % block_size;

        match find_part(wanted_block, &self.extents) {
            FoundPart::Actual(extent) => {
                let bytes_through_extent =
                    (block_size * (wanted_block - extent.part) as u64) + read_of_this_block;
                let remaining_bytes_in_extent =
                    (extent.len as u64 * block_size) - bytes_through_extent;
                let to_read = std::cmp::min(remaining_bytes_in_extent, buf.len() as u64) as usize;
                let to_read = std::cmp::min(to_read as u64, self.len - self.pos) as usize;
                self.inner.seek(io::SeekFrom::Start(
                    extent.start as u64 * block_size + bytes_through_extent,
                ))?;
                let read = self.inner.read(&mut buf[0..to_read])?;
                self.pos += read as u64;
                Ok(read)
            }
            FoundPart::Sparse(max) => {
                let max_bytes = max as u64 * block_size;
                let read = std::cmp::min(max_bytes, buf.len() as u64) as usize;
                let read = std::cmp::min(read as u64, self.len - self.pos) as usize;
                zero(&mut buf[0..read]);
                self.pos += read as u64;
                Ok(read)
            }
        }
    }
}

impl<R> io::Seek for TreeReader<R>
where
    R: io::Read + io::Seek,
{
    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
        match pos {
            io::SeekFrom::Start(set) => self.pos = set,
            io::SeekFrom::Current(diff) => self.pos = (self.pos as i64 + diff) as u64,
            io::SeekFrom::End(set) => {
                assert!(set >= 0);
                self.pos = self.len - set as u64
            }
        }

        assert!(self.pos <= self.len);

        Ok(self.pos)
    }
}

fn add_found_extents<F>(
    load_block: &mut F,
    data: &[u8],
    expected_depth: u16,
    extents: &mut Vec<Extent>,
    checksum_prefix: Option<u32>,
    first_level: bool,
) -> Result<()>
where
    F: FnMut(u64) -> Result<Vec<u8>>,
{
    ensure!(
        0x0a == data[0] && 0xf3 == data[1],
        AssumptionFailed("invalid extent magic".to_string())
    );

    let extent_entries = read_le16(&data[2..]);
    // 4..: max; doesn't seem to be useful during read
    let depth = read_le16(&data[6..]);
    // 8..: generation, not used in standard ext4

    ensure!(
        expected_depth == depth,
        AssumptionFailed(format!("depth incorrect: {} != {}", expected_depth, depth))
    );

    if !first_level && checksum_prefix.is_some() {
        let end_of_entries = data.len() - 4;
        let on_disc = read_le32(&data[end_of_entries..(end_of_entries + 4)]);
        let computed =
            ::parse::ext4_style_crc32c_le(checksum_prefix.unwrap(), &data[..end_of_entries]);

        ensure!(
            computed == on_disc,
            AssumptionFailed(format!(
                "extent checksum mismatch: {:08x} != {:08x} @ {}",
                on_disc,
                computed,
                data.len()
            ))
        );
    }

    if 0 == depth {
        for en in 0..extent_entries {
            let raw_extent = &data[12 + en as usize * 12..];
            let ee_block = read_le32(raw_extent);
            let ee_len = read_le16(&raw_extent[4..]);
            let ee_start_hi = read_le16(&raw_extent[6..]);
            let ee_start_lo = read_le32(&raw_extent[8..]);
            let ee_start = ee_start_lo as u64 + 0x1000 * ee_start_hi as u64;

            extents.push(Extent {
                part: ee_block,
                start: ee_start,
                len: ee_len,
            });
        }

        return Ok(());
    }

    for en in 0..extent_entries {
        let extent_idx = &data[12 + en as usize * 12..];
        //            let ei_block = as_u32(extent_idx);
        let ei_leaf_lo = read_le32(&extent_idx[4..]);
        let ei_leaf_hi = read_le16(&extent_idx[8..]);
        let ee_leaf: u64 = ei_leaf_lo as u64 + ((ei_leaf_hi as u64) << 32);
        let data = load_block(ee_leaf)?;
        add_found_extents(
            load_block,
            &data,
            depth - 1,
            extents,
            checksum_prefix,
            false,
        )?;
    }

    Ok(())
}

fn load_extent_tree<F>(
    load_block: &mut F,
    core: [u8; ::INODE_CORE_SIZE],
    checksum_prefix: Option<u32>,
) -> Result<Vec<Extent>>
where
    F: FnMut(u64) -> Result<Vec<u8>>,
{
    ensure!(
        0x0a == core[0] && 0xf3 == core[1],
        AssumptionFailed("invalid extent magic".to_string())
    );

    let extent_entries = read_le16(&core[2..]);
    // 4..: max; doesn't seem to be useful during read
    let depth = read_le16(&core[6..]);

    ensure!(
        depth <= 5,
        AssumptionFailed(format!("initial depth too high: {}", depth))
    );

    let mut extents = Vec::with_capacity(extent_entries as usize + depth as usize * 200);

    add_found_extents(
        load_block,
        &core,
        depth,
        &mut extents,
        checksum_prefix,
        true,
    )?;

    extents.sort_by_key(|e| e.part);

    Ok(extents)
}

fn zero(mut buf: &mut [u8]) {
    unsafe { std::ptr::write_bytes(buf.as_mut_ptr(), 0u8, buf.len()) }
}

#[cfg(test)]
mod tests {
    use std::io;
    use std::io::Read;
    use extents::TreeReader;
    use extents::Extent;

    #[test]
    fn simple_tree() {
        let data = (0..255u8).collect::<Vec<u8>>();
        let size = 4 + 4 * 2;
        let all_bytes = io::Cursor::new(data);
        let mut reader = TreeReader::create(
            all_bytes,
            4,
            size as u64,
            vec![
                Extent {
                    part: 0,
                    start: 10,
                    len: 1,
                },
                Extent {
                    part: 1,
                    start: 20,
                    len: 2,
                },
            ],
        ).unwrap();

        let mut res = Vec::new();
        assert_eq!(size, reader.read_to_end(&mut res).unwrap());

        assert_eq!(vec![40, 41, 42, 43, 80, 81, 82, 83, 84, 85, 86, 87], res);
    }

    #[test]
    fn zero_buf() {
        let mut buf = [7u8; 5];
        assert_eq!(7, buf[0]);
        ::extents::zero(&mut buf);
        for i in &buf {
            assert_eq!(0, *i);
        }
    }
}
<commit_msg>warning<commit_after>use std;
use std::io;

use read_le16;
use read_le32;

use errors::Result;
use errors::ErrorKind::*;

#[derive(Debug)]
struct Extent {
    /// The docs call this 'block' (like everything else). I've invented a different name.
    part: u32,
    start: u64,
    len: u16,
}

pub struct TreeReader<R> {
    inner: R,
    pos: u64,
    len: u64,
    block_size: u32,
    extents: Vec<Extent>,
}

impl<R> TreeReader<R>
where
    R: io::Read + io::Seek,
{
    pub fn new(
        mut inner: R,
        block_size: u32,
        size: u64,
        core: [u8; ::INODE_CORE_SIZE],
        checksum_prefix: Option<u32>,
    ) -> Result<TreeReader<R>> {
        let extents = load_extent_tree(
            &mut |block| ::load_disc_bytes(&mut inner, block_size, block),
            core,
            checksum_prefix,
        )?;
        TreeReader::create(inner, block_size, size, extents)
    }

    fn create(inner: R, block_size: u32, size: u64, extents: Vec<Extent>) -> Result<TreeReader<R>> {
        Ok(TreeReader {
            pos: 0,
            len: size,
            inner,
            extents,
            block_size,
        })
    }

    pub fn into_inner(self) -> R {
        self.inner
    }
}

enum FoundPart<'a> {
    Actual(&'a Extent),
    Sparse(u32),
}

fn find_part(part: u32, extents: &[Extent]) -> FoundPart {
    for extent in extents {
        if part < extent.part {
            // we've gone past it
            return FoundPart::Sparse(extent.part - part);
        }

        if part >= extent.part && part < extent.part + extent.len as u32 {
            // we're inside it
            return FoundPart::Actual(extent);
        }
    }

    FoundPart::Sparse(std::u32::MAX)
}

impl<R> io::Read for TreeReader<R>
where
    R: io::Read + io::Seek,
{
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        if buf.is_empty() {
            return Ok(0);
        }

        let block_size = self.block_size as u64;

        let wanted_block = (self.pos / block_size) as u32;
        let read_of_this_block = self.pos % block_size;

        match find_part(wanted_block, &self.extents) {
            FoundPart::Actual(extent) => {
                let bytes_through_extent =
                    (block_size * (wanted_block - extent.part) as u64) + read_of_this_block;
                let remaining_bytes_in_extent =
                    (extent.len as u64 * block_size) - bytes_through_extent;
                let to_read = std::cmp::min(remaining_bytes_in_extent, buf.len() as u64) as usize;
                let to_read = std::cmp::min(to_read as u64, self.len - self.pos) as usize;
                self.inner.seek(io::SeekFrom::Start(
                    extent.start as u64 * block_size + bytes_through_extent,
                ))?;
                let read = self.inner.read(&mut buf[0..to_read])?;
                self.pos += read as u64;
                Ok(read)
            }
            FoundPart::Sparse(max) => {
                let max_bytes = max as u64 * block_size;
                let read = std::cmp::min(max_bytes, buf.len() as u64) as usize;
                let read = std::cmp::min(read as u64, self.len - self.pos) as usize;
                zero(&mut buf[0..read]);
                self.pos += read as u64;
                Ok(read)
            }
        }
    }
}

impl<R> io::Seek for TreeReader<R>
where
    R: io::Read + io::Seek,
{
    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
        match pos {
            io::SeekFrom::Start(set) => self.pos = set,
            io::SeekFrom::Current(diff) => self.pos = (self.pos as i64 + diff) as u64,
            io::SeekFrom::End(set) => {
                assert!(set >= 0);
                self.pos = self.len - set as u64
            }
        }

        assert!(self.pos <= self.len);

        Ok(self.pos)
    }
}

fn add_found_extents<F>(
    load_block: &mut F,
    data: &[u8],
    expected_depth: u16,
    extents: &mut Vec<Extent>,
    checksum_prefix: Option<u32>,
    first_level: bool,
) -> Result<()>
where
    F: FnMut(u64) -> Result<Vec<u8>>,
{
    ensure!(
        0x0a == data[0] && 0xf3 == data[1],
        AssumptionFailed("invalid extent magic".to_string())
    );

    let extent_entries = read_le16(&data[2..]);
    // 4..: max; doesn't seem to be useful during read
    let depth = read_le16(&data[6..]);
    // 8..: generation, not used in standard ext4

    ensure!(
        expected_depth == depth,
        AssumptionFailed(format!("depth incorrect: {} != {}", expected_depth, depth))
    );

    if !first_level && checksum_prefix.is_some() {
        let end_of_entries = data.len() - 4;
        let on_disc = read_le32(&data[end_of_entries..(end_of_entries + 4)]);
        let computed =
            ::parse::ext4_style_crc32c_le(checksum_prefix.unwrap(), &data[..end_of_entries]);

        ensure!(
            computed == on_disc,
            AssumptionFailed(format!(
                "extent checksum mismatch: {:08x} != {:08x} @ {}",
                on_disc,
                computed,
                data.len()
            ))
        );
    }

    if 0 == depth {
        for en in 0..extent_entries {
            let raw_extent = &data[12 + en as usize * 12..];
            let ee_block = read_le32(raw_extent);
            let ee_len = read_le16(&raw_extent[4..]);
            let ee_start_hi = read_le16(&raw_extent[6..]);
            let ee_start_lo = read_le32(&raw_extent[8..]);
            let ee_start = ee_start_lo as u64 + 0x1000 * ee_start_hi as u64;

            extents.push(Extent {
                part: ee_block,
                start: ee_start,
                len: ee_len,
            });
        }

        return Ok(());
    }

    for en in 0..extent_entries {
        let extent_idx = &data[12 + en as usize * 12..];
        //            let ei_block = as_u32(extent_idx);
        let ei_leaf_lo = read_le32(&extent_idx[4..]);
        let ei_leaf_hi = read_le16(&extent_idx[8..]);
        let ee_leaf: u64 = ei_leaf_lo as u64 + ((ei_leaf_hi as u64) << 32);
        let data = load_block(ee_leaf)?;
        add_found_extents(
            load_block,
            &data,
            depth - 1,
            extents,
            checksum_prefix,
            false,
        )?;
    }

    Ok(())
}

fn load_extent_tree<F>(
    load_block: &mut F,
    core: [u8; ::INODE_CORE_SIZE],
    checksum_prefix: Option<u32>,
) -> Result<Vec<Extent>>
where
    F: FnMut(u64) -> Result<Vec<u8>>,
{
    ensure!(
        0x0a == core[0] && 0xf3 == core[1],
        AssumptionFailed("invalid extent magic".to_string())
    );

    let extent_entries = read_le16(&core[2..]);
    // 4..: max; doesn't seem to be useful during read
    let depth = read_le16(&core[6..]);

    ensure!(
        depth <= 5,
        AssumptionFailed(format!("initial depth too high: {}", depth))
    );

    let mut extents = Vec::with_capacity(extent_entries as usize + depth as usize * 200);

    add_found_extents(
        load_block,
        &core,
        depth,
        &mut extents,
        checksum_prefix,
        true,
    )?;

    extents.sort_by_key(|e| e.part);

    Ok(extents)
}

fn zero(buf: &mut [u8]) {
    unsafe { std::ptr::write_bytes(buf.as_mut_ptr(), 0u8, buf.len()) }
}

#[cfg(test)]
mod tests {
    use std::io;
    use std::io::Read;
    use extents::TreeReader;
    use extents::Extent;

    #[test]
    fn simple_tree() {
        let data = (0..255u8).collect::<Vec<u8>>();
        let size = 4 + 4 * 2;
        let all_bytes = io::Cursor::new(data);
        let mut reader = TreeReader::create(
            all_bytes,
            4,
            size as u64,
            vec![
                Extent {
                    part: 0,
                    start: 10,
                    len: 1,
                },
                Extent {
                    part: 1,
                    start: 20,
                    len: 2,
                },
            ],
        ).unwrap();

        let mut res = Vec::new();
        assert_eq!(size, reader.read_to_end(&mut res).unwrap());

        assert_eq!(vec![40, 41, 42, 43, 80, 81, 82, 83, 84, 85, 86, 87], res);
    }

    #[test]
    fn zero_buf() {
        let mut buf = [7u8; 5];
        assert_eq!(7, buf[0]);
        ::extents::zero(&mut buf);
        for i in &buf {
            assert_eq!(0, *i);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright © 2015, Peter Atashian
// Licensed under the MIT License <LICENSE.md>
//! ApiSet Contract for api-ms-win-core-file-l1
pub const CREATE_NEW: ::DWORD = 1;
pub const CREATE_ALWAYS: ::DWORD = 2;
pub const OPEN_EXISTING: ::DWORD = 3;
pub const OPEN_ALWAYS: ::DWORD = 4;
pub const TRUNCATE_EXISTING: ::DWORD = 5;
pub const INVALID_FILE_SIZE: ::DWORD = 0xFFFFFFFF;
pub const INVALID_SET_FILE_POINTER: ::DWORD = 0xFFFFFFFF;
pub const INVALID_FILE_ATTRIBUTES: ::DWORD = 0xFFFFFFFF;
#[repr(C)] #[derive(Clone, Copy, Debug)]
pub struct WIN32_FILE_ATTRIBUTE_DATA {
    pub dwFileAttributes: ::DWORD,
    pub ftCreationTime: ::FILETIME,
    pub ftLastAccessTime: ::FILETIME,
    pub ftLastWriteTime: ::FILETIME,
    pub nFileSizeHigh: ::DWORD,
    pub nFileSizeLow: ::DWORD,
}
pub type LPWIN32_FILE_ATTRIBUTE_DATA = *mut WIN32_FILE_ATTRIBUTE_DATA;
#[repr(C)] #[derive(Clone, Copy, Debug)]
pub struct BY_HANDLE_FILE_INFORMATION {
    pub dwFileAttributes: ::DWORD,
    pub ftCreationTime: ::FILETIME,
    pub ftLastAccessTime: ::FILETIME,
    pub ftLastWriteTime: ::FILETIME,
    pub dwVolumeSerialNumber: ::DWORD,
    pub nFileSizeHigh: ::DWORD,
    pub nFileSizeLow: ::DWORD,
    pub nNumberOfLinks: ::DWORD,
    pub nFileIndexHigh: ::DWORD,
    pub nFileIndexLow: ::DWORD,
}
pub type PBY_HANDLE_FILE_INFORMATION = *mut BY_HANDLE_FILE_INFORMATION;
pub type LPBY_HANDLE_FILE_INFORMATION = *mut BY_HANDLE_FILE_INFORMATION;
#[repr(C)] #[derive(Clone, Copy, Debug)]
pub struct CREATEFILE2_EXTENDED_PARAMETERS {
    pub dwSize: ::DWORD,
    pub dwFileAttributes: ::DWORD,
    pub dwFileFlags: ::DWORD,
    pub dwSecurityQosFlags: ::DWORD,
    pub lpSecurityAttributes: ::LPSECURITY_ATTRIBUTES,
    pub hTemplateFile: ::HANDLE,
}
pub type PCREATEFILE2_EXTENDED_PARAMETERS = *mut CREATEFILE2_EXTENDED_PARAMETERS;
pub type LPCREATEFILE2_EXTENDED_PARAMETERS = *mut CREATEFILE2_EXTENDED_PARAMETERS;
<commit_msg>Bindings for file info types<commit_after>// Copyright © 2015, Peter Atashian
// Licensed under the MIT License <LICENSE.md>
//! ApiSet Contract for api-ms-win-core-file-l1
pub const CREATE_NEW: ::DWORD = 1;
pub const CREATE_ALWAYS: ::DWORD = 2;
pub const OPEN_EXISTING: ::DWORD = 3;
pub const OPEN_ALWAYS: ::DWORD = 4;
pub const TRUNCATE_EXISTING: ::DWORD = 5;
pub const INVALID_FILE_SIZE: ::DWORD = 0xFFFFFFFF;
pub const INVALID_SET_FILE_POINTER: ::DWORD = 0xFFFFFFFF;
pub const INVALID_FILE_ATTRIBUTES: ::DWORD = 0xFFFFFFFF;
#[repr(C)] #[derive(Clone, Copy, Debug)]
pub struct WIN32_FILE_ATTRIBUTE_DATA {
    pub dwFileAttributes: ::DWORD,
    pub ftCreationTime: ::FILETIME,
    pub ftLastAccessTime: ::FILETIME,
    pub ftLastWriteTime: ::FILETIME,
    pub nFileSizeHigh: ::DWORD,
    pub nFileSizeLow: ::DWORD,
}
pub type LPWIN32_FILE_ATTRIBUTE_DATA = *mut WIN32_FILE_ATTRIBUTE_DATA;
#[repr(C)] #[derive(Clone, Copy, Debug)]
pub struct BY_HANDLE_FILE_INFORMATION {
    pub dwFileAttributes: ::DWORD,
    pub ftCreationTime: ::FILETIME,
    pub ftLastAccessTime: ::FILETIME,
    pub ftLastWriteTime: ::FILETIME,
    pub dwVolumeSerialNumber: ::DWORD,
    pub nFileSizeHigh: ::DWORD,
    pub nFileSizeLow: ::DWORD,
    pub nNumberOfLinks: ::DWORD,
    pub nFileIndexHigh: ::DWORD,
    pub nFileIndexLow: ::DWORD,
}
pub type PBY_HANDLE_FILE_INFORMATION = *mut BY_HANDLE_FILE_INFORMATION;
pub type LPBY_HANDLE_FILE_INFORMATION = *mut BY_HANDLE_FILE_INFORMATION;
#[repr(C)] #[derive(Clone, Copy, Debug)]
pub struct CREATEFILE2_EXTENDED_PARAMETERS {
    pub dwSize: ::DWORD,
    pub dwFileAttributes: ::DWORD,
    pub dwFileFlags: ::DWORD,
    pub dwSecurityQosFlags: ::DWORD,
    pub lpSecurityAttributes: ::LPSECURITY_ATTRIBUTES,
    pub hTemplateFile: ::HANDLE,
}
pub type PCREATEFILE2_EXTENDED_PARAMETERS = *mut CREATEFILE2_EXTENDED_PARAMETERS;
pub type LPCREATEFILE2_EXTENDED_PARAMETERS = *mut CREATEFILE2_EXTENDED_PARAMETERS;
ENUM!{enum PRIORITY_HINT {
    IoPriorityHintVeryLow = 0,
    IoPriorityHintLow = 1,
    IoPriorityHintNormal = 2,
    MaximumIoPriorityHintType = 3,
}}
#[repr(C)] #[derive(Clone, Copy, Debug)]
pub struct FILE_BASIC_INFO {
    pub CreationTime: ::LARGE_INTEGER,
    pub LastAccessTime: ::LARGE_INTEGER,
    pub LastWriteTime: ::LARGE_INTEGER,
    pub ChangeTime: ::LARGE_INTEGER,
    pub FileAttributes: ::DWORD,
}
#[repr(C)] #[derive(Clone, Copy, Debug)]
pub struct FILE_STANDARD_INFO {
    pub AllocationSize: ::LARGE_INTEGER,
    pub EndOfFile: ::LARGE_INTEGER,
    pub NumberOfLinks: ::DWORD,
    pub DeletePending: ::BOOLEAN,
    pub Directory: ::BOOLEAN,
}
#[repr(C)] #[derive(Clone, Copy, Debug)]
pub struct FILE_NAME_INFO {
    pub FileNameLength: ::DWORD,
    pub FileName: [::WCHAR; 0],
}
#[repr(C)] #[derive(Clone, Copy, Debug)]
pub struct FILE_RENAME_INFO {
    pub ReplaceIfExists: ::BOOL,
    pub RootDirectory: ::HANDLE,
    pub FileNameLength: ::DWORD,
    pub FileName: [::WCHAR; 0],
}
#[repr(C)] #[derive(Clone, Copy, Debug)]
pub struct FILE_DISPOSITION_INFO {
    pub DeleteFile: ::BOOL,
}
#[repr(C)] #[derive(Clone, Copy, Debug)]
pub struct FILE_ALLOCATION_INFO {
    pub AllocationSize: ::LARGE_INTEGER,
}
#[repr(C)] #[derive(Clone, Copy, Debug)]
pub struct FILE_END_OF_FILE_INFO {
    pub EndOfFile: ::LARGE_INTEGER,
}
#[repr(C)] #[derive(Clone, Copy, Debug)]
pub struct FILE_STREAM_INFO {
    pub NextEntryOffset: ::DWORD,
    pub StreamNameLength: ::DWORD,
    pub StreamSize: ::DWORD,
    pub StreamAllocationSize: ::DWORD,
    pub StreamName: [::WCHAR; 0],
}
#[repr(C)] #[derive(Clone, Copy, Debug)]
pub struct FILE_COMPRESSION_INFO {
    pub CompressedFileSize: ::LARGE_INTEGER,
    pub CompressionFormat: ::WORD,
    pub CompressionUnitShift: ::UCHAR,
    pub ChunkShift: ::UCHAR,
    pub ClusterShift: ::UCHAR,
    pub Reserved: [::UCHAR; 3],
}
#[repr(C)] #[derive(Clone, Copy, Debug)]
pub struct FILE_ATTRIBUTE_TAG_INFO {
    pub NextEntryOffset: ::DWORD,
    pub ReparseTag: ::DWORD,
}
#[repr(C)] #[derive(Clone, Copy, Debug)]
pub struct FILE_ID_BOTH_DIR_INFO {
    pub NextEntryOffset: ::DWORD,
    pub FileIndex: ::DWORD,
    pub CreationTime: ::LARGE_INTEGER,
    pub LastAccessTime: ::LARGE_INTEGER,
    pub LastWriteTime: ::LARGE_INTEGER,
    pub ChangeTime: ::LARGE_INTEGER,
    pub EndOfFile: ::LARGE_INTEGER,
    pub AllocationSize: ::LARGE_INTEGER,
    pub FileAttributes: ::DWORD,
    pub FileNameLength: ::DWORD,
    pub EaSize: ::DWORD,
    pub ShortNameLength: ::CCHAR,
    pub ShortName: [::WCHAR; 12],
    pub FileId: ::LARGE_INTEGER,
    pub FileName: [::WCHAR; 0],
}
#[repr(C)] #[derive(Clone, Copy, Debug)]
pub struct FILE_IO_PRIORITY_HINT_INFO {
    pub PriorityHint: ::PRIORITY_HINT,
}
#[repr(C)] #[derive(Clone, Copy, Debug)]
pub struct FILE_FULL_DIR_INFO {
    pub NextEntryOffset: ::ULONG,
    pub FileIndex: ::ULONG,
    pub CreationTime: ::LARGE_INTEGER,
    pub LastAccessTime: ::LARGE_INTEGER,
    pub LastWriteTime: ::LARGE_INTEGER,
    pub ChangeTime: ::LARGE_INTEGER,
    pub EndOfFile: ::LARGE_INTEGER,
    pub AllocationSize: ::LARGE_INTEGER,
    pub FileAttributes: ::ULONG,
    pub FileNameLength: ::ULONG,
    pub EaSize: ::ULONG,
    pub FileName: [::WCHAR; 0],
}
#[repr(C)] #[derive(Clone, Copy, Debug)]
pub struct FILE_STORAGE_INFO {
    pub LogicalBytesPerSector: ::ULONG,
    pub PhysicalBytesPerSectorForAtomicity: ::ULONG,
    pub PhysicalBytesPerSectorForPerformance: ::ULONG,
    pub FileSystemEffectivePhysicalBytesPerSectorForAtomicity: ::ULONG,
    pub Flags: ::ULONG,
    pub ByteOffsetForSectorAlignment: ::ULONG,
    pub ByteOffsetForPartitionAlignment: ::ULONG,
}
#[repr(C)] #[derive(Clone, Copy, Debug)]
pub struct FILE_ALIGNMENT_INFO {
    pub AlignmentRequirement: ::ULONG,
}
#[repr(C)] #[derive(Clone, Copy, Debug)]
pub struct FILE_ID_INFO {
    pub VolumeSerialNumber: ::ULONGLONG,
    pub FileId: ::FILE_ID_128,
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! Unix-specific utilities for working with the filesystem.

use std::ffi::{OsStr, OsString};
use std::path::Path;

use log::warn;

/// An extended attribute of a file.
///
/// On Linux, extended attributes can be obtained using `getfattr` and set with
/// `setfattr` utilities. On macOS, they can be manipulated through `getxattr`
/// and `setxattr` utilities.
///
/// See the [Wikipedia] article for more details.
///
/// [Wikipedia]: https://en.wikipedia.org/wiki/Extended_file_attributes
pub struct ExtAttr {
    /// A name of the extended attribute.
    pub name: OsString,
    /// A value of the extended attribute.
    pub value: Option<OsString>,
}

/// Returns an iterator over extended attributes of the specified file.
///
/// # Errors
///
/// The function will fail if a list of extended attributes of the file cannot
/// be obtained (e.g. when the file doesn't exist). However, all errors when
/// that can occur when inspecting values for particular attribute are logged
/// and forgotten.
///
/// # Examples
///
/// ```no_run
/// let attrs = rrg::fs::unix::ext_attrs(&"/tmp/foo")
///     .expect("failed to collect extended attributes");
///
/// for attr in attrs {
///     let name = attr.name.to_string_lossy();
///     match attr.value {
///         Some(value) => println!("{}: {}", name, value.to_string_lossy()),
///         None => println!("{}", name),
///     }
/// }
/// ```
pub fn ext_attrs<'p, P>(path: &'p P) -> std::io::Result<ExtAttrs<'p>>
where
    P: AsRef<Path>,
{
    let iter = xattr::list(&path)?;

    Ok(ExtAttrs {
        path: path.as_ref(),
        iter: iter,
    })
}

/// Iterator over extended attributes of a file.
///
/// Note that this iterator always returns an attribute. All errors that can
/// occur when obtaining values for particular attributes are swallowed.
///
/// The iterator can be constructed with the [`ext_attrs`] function.
///
/// [`ext_attrs`]: fn.ext_attrs.html
pub struct ExtAttrs<'p> {
    path: &'p Path,
    iter: xattr::XAttrs,
}

impl<'p> Iterator for ExtAttrs<'p> {

    type Item = ExtAttr;

    fn next(&mut self) -> Option<ExtAttr> {
        for name in &mut self.iter {
            let value = match ext_attr_value(self.path, &name) {
                Ok(value) => value,
                Err(()) => continue,
            };

            return Some(ExtAttr {
                name: name,
                value: value,
            });
        }

        None
    }
}

/// Collects value of an extended attribute with the specified name.
///
/// This is a tiny wrapper around `xattr::get`, but logs and forgets the error
/// (if occurs).
fn ext_attr_value<P>(path: P, name: &OsStr) -> Result<Option<OsString>, ()>
where
    P: AsRef<Path>,
{
    match xattr::get(&path, name) {
        Ok(value) => Ok(value.map(std::os::unix::ffi::OsStringExt::from_vec)),
        Err(error) => Err(warn! {
            "failed to collect attribute '{:?}' of '{path}': {cause}",
            name = name,
            path = path.as_ref().display(),
            cause = error,
        }),
    }
}
<commit_msg>Simplify example of extended attribute collection.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! Unix-specific utilities for working with the filesystem.

use std::ffi::{OsStr, OsString};
use std::path::Path;

use log::warn;

/// An extended attribute of a file.
///
/// On Linux, extended attributes can be obtained using `getfattr` and set with
/// `setfattr` utilities. On macOS, they can be manipulated through `getxattr`
/// and `setxattr` utilities.
///
/// See the [Wikipedia] article for more details.
///
/// [Wikipedia]: https://en.wikipedia.org/wiki/Extended_file_attributes
pub struct ExtAttr {
    /// A name of the extended attribute.
    pub name: OsString,
    /// A value of the extended attribute.
    pub value: Option<OsString>,
}

/// Returns an iterator over extended attributes of the specified file.
///
/// # Errors
///
/// The function will fail if a list of extended attributes of the file cannot
/// be obtained (e.g. when the file doesn't exist). However, all errors when
/// that can occur when inspecting values for particular attribute are logged
/// and forgotten.
///
/// # Examples
///
/// ```no_run
/// for attr in rrg::fs::unix::ext_attrs(&"/tmp/foo").unwrap() {
///     let name = attr.name.to_string_lossy();
///     match attr.value {
///         Some(value) => println!("{}: {}", name, value.to_string_lossy()),
///         None => println!("{}", name),
///     }
/// }
/// ```
pub fn ext_attrs<'p, P>(path: &'p P) -> std::io::Result<ExtAttrs<'p>>
where
    P: AsRef<Path>,
{
    let iter = xattr::list(&path)?;

    Ok(ExtAttrs {
        path: path.as_ref(),
        iter: iter,
    })
}

/// Iterator over extended attributes of a file.
///
/// Note that this iterator always returns an attribute. All errors that can
/// occur when obtaining values for particular attributes are swallowed.
///
/// The iterator can be constructed with the [`ext_attrs`] function.
///
/// [`ext_attrs`]: fn.ext_attrs.html
pub struct ExtAttrs<'p> {
    path: &'p Path,
    iter: xattr::XAttrs,
}

impl<'p> Iterator for ExtAttrs<'p> {

    type Item = ExtAttr;

    fn next(&mut self) -> Option<ExtAttr> {
        for name in &mut self.iter {
            let value = match ext_attr_value(self.path, &name) {
                Ok(value) => value,
                Err(()) => continue,
            };

            return Some(ExtAttr {
                name: name,
                value: value,
            });
        }

        None
    }
}

/// Collects value of an extended attribute with the specified name.
///
/// This is a tiny wrapper around `xattr::get`, but logs and forgets the error
/// (if occurs).
fn ext_attr_value<P>(path: P, name: &OsStr) -> Result<Option<OsString>, ()>
where
    P: AsRef<Path>,
{
    match xattr::get(&path, name) {
        Ok(value) => Ok(value.map(std::os::unix::ffi::OsStringExt::from_vec)),
        Err(error) => Err(warn! {
            "failed to collect attribute '{:?}' of '{path}': {cause}",
            name = name,
            path = path.as_ref().display(),
            cause = error,
        }),
    }
}
<|endoftext|>


<commit_before>//! History API

#[cfg(unix)]
use libc;
use std::collections::vec_deque;
use std::collections::VecDeque;
use std::fs::File;
use std::iter::DoubleEndedIterator;
use std::ops::Index;
use std::path::Path;

use super::Result;
use config::{Config, HistoryDuplicates};

/// Search direction
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Direction {
    Forward,
    Reverse,
}

/// Current state of the history.
#[derive(Default)]
pub struct History {
    entries: VecDeque<String>,
    max_len: usize,
    ignore_space: bool,
    ignore_dups: bool,
}

impl History {
    pub fn new() -> History {
        Self::with_config(Config::default())
    }
    pub fn with_config(config: Config) -> History {
        History {
            entries: VecDeque::new(),
            max_len: config.max_history_size(),
            ignore_space: config.history_duplicates() == HistoryDuplicates::IgnoreConsecutive,
            ignore_dups: config.history_ignore_space(),
        }
    }

    /// Return the history entry at position `index`, starting from 0.
    pub fn get(&self, index: usize) -> Option<&String> {
        self.entries.get(index)
    }

    /// Return the last history entry (i.e. previous command)
    pub fn last(&self) -> Option<&String> {
        self.entries.back()
    }

    /// Add a new entry in the history.
    pub fn add<S: AsRef<str> + Into<String>>(&mut self, line: S) -> bool {
        if self.max_len == 0 {
            return false;
        }
        if line.as_ref().is_empty()
            || (self.ignore_space
                && line.as_ref()
                    .chars()
                    .next()
                    .map_or(true, |c| c.is_whitespace()))
        {
            return false;
        }
        if self.ignore_dups {
            if let Some(s) = self.entries.back() {
                if s == line.as_ref() {
                    return false;
                }
            }
        }
        if self.entries.len() == self.max_len {
            self.entries.pop_front();
        }
        self.entries.push_back(line.into());
        true
    }

    /// Return the number of entries in the history.
    pub fn len(&self) -> usize {
        self.entries.len()
    }
    /// Return true if the history has no entry.
    pub fn is_empty(&self) -> bool {
        self.entries.is_empty()
    }

    /// Set the maximum length for the history. This function can be called even
    /// if there is already some history, the function will make sure to retain
    /// just the latest `len` elements if the new history length value is
    /// smaller than the amount of items already inside the history.
    ///
    /// Like [stifle_history](http://cnswww.cns.cwru.
    /// edu/php/chet/readline/history.html#IDX11).
    pub fn set_max_len(&mut self, len: usize) {
        self.max_len = len;
        if len == 0 {
            self.entries.clear();
            return;
        }
        loop {
            if self.entries.len() <= len {
                break;
            }
            self.entries.pop_front();
        }
    }

    /// Save the history in the specified file.
    // TODO append_history
    // http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX30
    // TODO history_truncate_file
    // http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX31
    pub fn save<P: AsRef<Path> + ?Sized>(&self, path: &P) -> Result<()> {
        use std::io::{BufWriter, Write};

        if self.is_empty() {
            return Ok(());
        }
        let old_umask = umask();
        let f = File::create(path);
        restore_umask(old_umask);
        let file = try!(f);
        fix_perm(&file);
        let mut wtr = BufWriter::new(file);
        for entry in &self.entries {
            try!(wtr.write_all(entry.as_bytes()));
            try!(wtr.write_all(b"\n"));
        }
        Ok(())
    }

    /// Load the history from the specified file.
    ///
    /// # Errors
    /// Will return `Err` if path does not already exist or could not be read.
    pub fn load<P: AsRef<Path> + ?Sized>(&mut self, path: &P) -> Result<()> {
        use std::io::{BufRead, BufReader};

        let file = try!(File::open(&path));
        let rdr = BufReader::new(file);
        for line in rdr.lines() {
            self.add(try!(line).as_ref()); // TODO truncate to MAX_LINE
        }
        Ok(())
    }

    /// Clear history
    pub fn clear(&mut self) {
        self.entries.clear()
    }

    /// Search history (start position inclusive [0, len-1]).
    ///
    /// Return the absolute index of the nearest history entry that matches
    /// `term`.
    ///
    /// Return None if no entry contains `term` between [start, len -1] for
    /// forward search
    /// or between [0, start] for reverse search.
    pub fn search(&self, term: &str, start: usize, dir: Direction) -> Option<usize> {
        let test = |entry: &String| entry.contains(term);
        self.search_match(term, start, dir, test)
    }

    /// Anchored search
    pub fn starts_with(&self, term: &str, start: usize, dir: Direction) -> Option<usize> {
        let test = |entry: &String| entry.starts_with(term);
        self.search_match(term, start, dir, test)
    }

    fn search_match<F>(&self, term: &str, start: usize, dir: Direction, test: F) -> Option<usize>
    where
        F: Fn(&String) -> bool,
    {
        if term.is_empty() || start >= self.len() {
            return None;
        }
        match dir {
            Direction::Reverse => {
                let index = self.entries
                    .iter()
                    .rev()
                    .skip(self.entries.len() - 1 - start)
                    .position(test);
                index.and_then(|index| Some(start - index))
            }
            Direction::Forward => {
                let index = self.entries.iter().skip(start).position(test);
                index.and_then(|index| Some(index + start))
            }
        }
    }

    /// Return a forward iterator.
    pub fn iter(&self) -> Iter {
        Iter(self.entries.iter())
    }
}

impl Index<usize> for History {
    type Output = String;

    fn index(&self, index: usize) -> &String {
        &self.entries[index]
    }
}

impl<'a> IntoIterator for &'a History {
    type Item = &'a String;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Iter<'a> {
        self.iter()
    }
}

/// History iterator.
pub struct Iter<'a>(vec_deque::Iter<'a, String>);

impl<'a> Iterator for Iter<'a> {
    type Item = &'a String;

    fn next(&mut self) -> Option<&'a String> {
        self.0.next()
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }
}

impl<'a> DoubleEndedIterator for Iter<'a> {
    fn next_back(&mut self) -> Option<&'a String> {
        self.0.next_back()
    }
}

#[cfg(windows)]
fn umask() -> u16 {
    0
}
#[cfg(unix)]
fn umask() -> libc::mode_t {
    unsafe { libc::umask(libc::S_IXUSR | libc::S_IRWXG | libc::S_IRWXO) }
}
#[cfg(windows)]
fn restore_umask(_: u16) {}
#[cfg(unix)]
fn restore_umask(old_umask: libc::mode_t) {
    unsafe {
        libc::umask(old_umask);
    }
}

#[cfg(windows)]
fn fix_perm(_: &File) {}
#[cfg(unix)]
fn fix_perm(file: &File) {
    use std::os::unix::io::AsRawFd;
    unsafe {
        libc::fchmod(file.as_raw_fd(), libc::S_IRUSR | libc::S_IWUSR);
    }
}

#[cfg(test)]
mod tests {
    extern crate tempdir;
    use super::{Direction, History};
    use config::Config;
    use std::path::Path;

    fn init() -> History {
        let mut history = History::new();
        assert!(history.add("line1"));
        assert!(history.add("line2"));
        assert!(history.add("line3"));
        history
    }

    #[test]
    fn new() {
        let history = History::new();
        assert_eq!(0, history.entries.len());
    }

    #[test]
    fn add() {
        let config = Config::builder().history_ignore_space(true).build();
        let mut history = History::with_config(config);
        assert_eq!(config.max_history_size(), history.max_len);
        assert!(history.add("line1"));
        assert!(history.add("line2"));
        assert!(!history.add("line2"));
        assert!(!history.add(""));
        assert!(!history.add(" line3"));
    }

    #[test]
    fn set_max_len() {
        let mut history = init();
        history.set_max_len(1);
        assert_eq!(1, history.entries.len());
        assert_eq!(Some(&"line3".to_owned()), history.last());
    }

    #[test]
    fn save() {
        let mut history = init();
        let td = tempdir::TempDir::new_in(&Path::new("."), "histo").unwrap();
        let history_path = td.path().join(".history");

        history.save(&history_path).unwrap();
        history.load(&history_path).unwrap();
        td.close().unwrap();
    }

    #[test]
    fn search() {
        let history = init();
        assert_eq!(None, history.search("", 0, Direction::Forward));
        assert_eq!(None, history.search("none", 0, Direction::Forward));
        assert_eq!(None, history.search("line", 3, Direction::Forward));

        assert_eq!(Some(0), history.search("line", 0, Direction::Forward));
        assert_eq!(Some(1), history.search("line", 1, Direction::Forward));
        assert_eq!(Some(2), history.search("line3", 1, Direction::Forward));
    }

    #[test]
    fn reverse_search() {
        let history = init();
        assert_eq!(None, history.search("", 2, Direction::Reverse));
        assert_eq!(None, history.search("none", 2, Direction::Reverse));
        assert_eq!(None, history.search("line", 3, Direction::Reverse));

        assert_eq!(Some(2), history.search("line", 2, Direction::Reverse));
        assert_eq!(Some(1), history.search("line", 1, Direction::Reverse));
        assert_eq!(Some(0), history.search("line1", 1, Direction::Reverse));
    }
}
<commit_msg>Ensure history is correctly flushed<commit_after>//! History API

#[cfg(unix)]
use libc;
use std::collections::vec_deque;
use std::collections::VecDeque;
use std::fs::File;
use std::iter::DoubleEndedIterator;
use std::ops::Index;
use std::path::Path;

use super::Result;
use config::{Config, HistoryDuplicates};

/// Search direction
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Direction {
    Forward,
    Reverse,
}

/// Current state of the history.
#[derive(Default)]
pub struct History {
    entries: VecDeque<String>,
    max_len: usize,
    ignore_space: bool,
    ignore_dups: bool,
}

impl History {
    pub fn new() -> History {
        Self::with_config(Config::default())
    }
    pub fn with_config(config: Config) -> History {
        History {
            entries: VecDeque::new(),
            max_len: config.max_history_size(),
            ignore_space: config.history_duplicates() == HistoryDuplicates::IgnoreConsecutive,
            ignore_dups: config.history_ignore_space(),
        }
    }

    /// Return the history entry at position `index`, starting from 0.
    pub fn get(&self, index: usize) -> Option<&String> {
        self.entries.get(index)
    }

    /// Return the last history entry (i.e. previous command)
    pub fn last(&self) -> Option<&String> {
        self.entries.back()
    }

    /// Add a new entry in the history.
    pub fn add<S: AsRef<str> + Into<String>>(&mut self, line: S) -> bool {
        if self.max_len == 0 {
            return false;
        }
        if line.as_ref().is_empty()
            || (self.ignore_space
                && line.as_ref()
                    .chars()
                    .next()
                    .map_or(true, |c| c.is_whitespace()))
        {
            return false;
        }
        if self.ignore_dups {
            if let Some(s) = self.entries.back() {
                if s == line.as_ref() {
                    return false;
                }
            }
        }
        if self.entries.len() == self.max_len {
            self.entries.pop_front();
        }
        self.entries.push_back(line.into());
        true
    }

    /// Return the number of entries in the history.
    pub fn len(&self) -> usize {
        self.entries.len()
    }
    /// Return true if the history has no entry.
    pub fn is_empty(&self) -> bool {
        self.entries.is_empty()
    }

    /// Set the maximum length for the history. This function can be called even
    /// if there is already some history, the function will make sure to retain
    /// just the latest `len` elements if the new history length value is
    /// smaller than the amount of items already inside the history.
    ///
    /// Like [stifle_history](http://cnswww.cns.cwru.
    /// edu/php/chet/readline/history.html#IDX11).
    pub fn set_max_len(&mut self, len: usize) {
        self.max_len = len;
        if len == 0 {
            self.entries.clear();
            return;
        }
        loop {
            if self.entries.len() <= len {
                break;
            }
            self.entries.pop_front();
        }
    }

    /// Save the history in the specified file.
    // TODO append_history
    // http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX30
    // TODO history_truncate_file
    // http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX31
    pub fn save<P: AsRef<Path> + ?Sized>(&self, path: &P) -> Result<()> {
        use std::io::{BufWriter, Write};

        if self.is_empty() {
            return Ok(());
        }
        let old_umask = umask();
        let f = File::create(path);
        restore_umask(old_umask);
        let file = try!(f);
        fix_perm(&file);
        let mut wtr = BufWriter::new(file);
        for entry in &self.entries {
            try!(wtr.write_all(entry.as_bytes()));
            try!(wtr.write_all(b"\n"));
        }
        // https://github.com/rust-lang/rust/issues/32677#issuecomment-204833485
        try!(wtr.flush());
        Ok(())
    }

    /// Load the history from the specified file.
    ///
    /// # Errors
    /// Will return `Err` if path does not already exist or could not be read.
    pub fn load<P: AsRef<Path> + ?Sized>(&mut self, path: &P) -> Result<()> {
        use std::io::{BufRead, BufReader};

        let file = try!(File::open(&path));
        let rdr = BufReader::new(file);
        for line in rdr.lines() {
            self.add(try!(line).as_ref()); // TODO truncate to MAX_LINE
        }
        Ok(())
    }

    /// Clear history
    pub fn clear(&mut self) {
        self.entries.clear()
    }

    /// Search history (start position inclusive [0, len-1]).
    ///
    /// Return the absolute index of the nearest history entry that matches
    /// `term`.
    ///
    /// Return None if no entry contains `term` between [start, len -1] for
    /// forward search
    /// or between [0, start] for reverse search.
    pub fn search(&self, term: &str, start: usize, dir: Direction) -> Option<usize> {
        let test = |entry: &String| entry.contains(term);
        self.search_match(term, start, dir, test)
    }

    /// Anchored search
    pub fn starts_with(&self, term: &str, start: usize, dir: Direction) -> Option<usize> {
        let test = |entry: &String| entry.starts_with(term);
        self.search_match(term, start, dir, test)
    }

    fn search_match<F>(&self, term: &str, start: usize, dir: Direction, test: F) -> Option<usize>
    where
        F: Fn(&String) -> bool,
    {
        if term.is_empty() || start >= self.len() {
            return None;
        }
        match dir {
            Direction::Reverse => {
                let index = self.entries
                    .iter()
                    .rev()
                    .skip(self.entries.len() - 1 - start)
                    .position(test);
                index.and_then(|index| Some(start - index))
            }
            Direction::Forward => {
                let index = self.entries.iter().skip(start).position(test);
                index.and_then(|index| Some(index + start))
            }
        }
    }

    /// Return a forward iterator.
    pub fn iter(&self) -> Iter {
        Iter(self.entries.iter())
    }
}

impl Index<usize> for History {
    type Output = String;

    fn index(&self, index: usize) -> &String {
        &self.entries[index]
    }
}

impl<'a> IntoIterator for &'a History {
    type Item = &'a String;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Iter<'a> {
        self.iter()
    }
}

/// History iterator.
pub struct Iter<'a>(vec_deque::Iter<'a, String>);

impl<'a> Iterator for Iter<'a> {
    type Item = &'a String;

    fn next(&mut self) -> Option<&'a String> {
        self.0.next()
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }
}

impl<'a> DoubleEndedIterator for Iter<'a> {
    fn next_back(&mut self) -> Option<&'a String> {
        self.0.next_back()
    }
}

#[cfg(windows)]
fn umask() -> u16 {
    0
}
#[cfg(unix)]
fn umask() -> libc::mode_t {
    unsafe { libc::umask(libc::S_IXUSR | libc::S_IRWXG | libc::S_IRWXO) }
}
#[cfg(windows)]
fn restore_umask(_: u16) {}
#[cfg(unix)]
fn restore_umask(old_umask: libc::mode_t) {
    unsafe {
        libc::umask(old_umask);
    }
}

#[cfg(windows)]
fn fix_perm(_: &File) {}
#[cfg(unix)]
fn fix_perm(file: &File) {
    use std::os::unix::io::AsRawFd;
    unsafe {
        libc::fchmod(file.as_raw_fd(), libc::S_IRUSR | libc::S_IWUSR);
    }
}

#[cfg(test)]
mod tests {
    extern crate tempdir;
    use super::{Direction, History};
    use config::Config;
    use std::path::Path;

    fn init() -> History {
        let mut history = History::new();
        assert!(history.add("line1"));
        assert!(history.add("line2"));
        assert!(history.add("line3"));
        history
    }

    #[test]
    fn new() {
        let history = History::new();
        assert_eq!(0, history.entries.len());
    }

    #[test]
    fn add() {
        let config = Config::builder().history_ignore_space(true).build();
        let mut history = History::with_config(config);
        assert_eq!(config.max_history_size(), history.max_len);
        assert!(history.add("line1"));
        assert!(history.add("line2"));
        assert!(!history.add("line2"));
        assert!(!history.add(""));
        assert!(!history.add(" line3"));
    }

    #[test]
    fn set_max_len() {
        let mut history = init();
        history.set_max_len(1);
        assert_eq!(1, history.entries.len());
        assert_eq!(Some(&"line3".to_owned()), history.last());
    }

    #[test]
    fn save() {
        let mut history = init();
        let td = tempdir::TempDir::new_in(&Path::new("."), "histo").unwrap();
        let history_path = td.path().join(".history");

        history.save(&history_path).unwrap();
        history.load(&history_path).unwrap();
        td.close().unwrap();
    }

    #[test]
    fn search() {
        let history = init();
        assert_eq!(None, history.search("", 0, Direction::Forward));
        assert_eq!(None, history.search("none", 0, Direction::Forward));
        assert_eq!(None, history.search("line", 3, Direction::Forward));

        assert_eq!(Some(0), history.search("line", 0, Direction::Forward));
        assert_eq!(Some(1), history.search("line", 1, Direction::Forward));
        assert_eq!(Some(2), history.search("line3", 1, Direction::Forward));
    }

    #[test]
    fn reverse_search() {
        let history = init();
        assert_eq!(None, history.search("", 2, Direction::Reverse));
        assert_eq!(None, history.search("none", 2, Direction::Reverse));
        assert_eq!(None, history.search("line", 3, Direction::Reverse));

        assert_eq!(Some(2), history.search("line", 2, Direction::Reverse));
        assert_eq!(Some(1), history.search("line", 1, Direction::Reverse));
        assert_eq!(Some(0), history.search("line1", 1, Direction::Reverse));
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-2013 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.

// Issue #7526: lowercase static constants in patterns look like bindings

// This is similar to compile-fail/match-static-const-lc, except it
// shows the expected usual workaround (choosing a different name for
// the static definition) and also demonstrates that one can work
// around this problem locally by reanming the constant in the `use`
// form to an uppercase identifier that placates the lint.

#[deny(non_uppercase_pattern_statics)];

pub static A : int = 97;

fn f() {
    let r = match (0,0) {
        (0, A) => 0,
        (x, y) => 1 + x + y,
    };
    assert!(r == 1);
}

mod m {
    pub static aha : int = 7;
}

fn g() {
    use AHA = m::aha;
    let r = match (0,0) {
        (0, AHA) => 0,
        (x, y)   => 1 + x + y,
    };
    assert!(r == 1);
}

fn main () {
    f();
    g();
}
<commit_msg>Throwing in another interesting test case: There is no need to warn about constants that are (non-trivial) paths rather than just identifiers, regardless of what case their characters are.<commit_after>// Copyright 2012-2013 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.

// Issue #7526: lowercase static constants in patterns look like bindings

// This is similar to compile-fail/match-static-const-lc, except it
// shows the expected usual workaround (choosing a different name for
// the static definition) and also demonstrates that one can work
// around this problem locally by reanming the constant in the `use`
// form to an uppercase identifier that placates the lint.

#[deny(non_uppercase_pattern_statics)];

pub static A : int = 97;

fn f() {
    let r = match (0,0) {
        (0, A) => 0,
        (x, y) => 1 + x + y,
    };
    assert!(r == 1);
}

mod m {
    pub static aha : int = 7;
}

fn g() {
    use AHA = m::aha;
    let r = match (0,0) {
        (0, AHA) => 0,
        (x, y)   => 1 + x + y,
    };
    assert!(r == 1);
}

fn h() {
    let r = match (0,0) {
        (0, m::aha) => 0,
        (x, y)      => 1 + x + y,
    };
    assert!(r == 1);
}

fn main () {
    f();
    g();
    h();
}
<|endoftext|>