<commit_before>// Copyright 2017 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 rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::hir;
use rustc::middle::cstore::{self, NativeLibrary};
use rustc::session::Session;
use rustc::ty::TyCtxt;
use rustc::util::nodemap::FxHashSet;
use rustc_target::spec::abi::Abi;
use syntax::attr;
use syntax::source_map::Span;
use syntax::feature_gate::{self, GateIssue};
use syntax::symbol::Symbol;

pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Vec<NativeLibrary> {
    let mut collector = Collector {
        tcx,
        libs: Vec::new(),
    };
    tcx.hir().krate().visit_all_item_likes(&mut collector);
    collector.process_command_line();
    return collector.libs
}

pub fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool {
    match lib.cfg {
        Some(ref cfg) => attr::cfg_matches(cfg, &sess.parse_sess, None),
        None => true,
    }
}

struct Collector<'a, 'tcx: 'a> {
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    libs: Vec<NativeLibrary>,
}

impl<'a, 'tcx> ItemLikeVisitor<'tcx> for Collector<'a, 'tcx> {
    fn visit_item(&mut self, it: &'tcx hir::Item) {
        let fm = match it.node {
            hir::ItemKind::ForeignMod(ref fm) => fm,
            _ => return,
        };

        if fm.abi == Abi::Rust ||
            fm.abi == Abi::RustIntrinsic ||
            fm.abi == Abi::PlatformIntrinsic {
            return
        }

        // Process all of the #[link(..)]-style arguments
        for m in it.attrs.iter().filter(|a| a.check_name("link")) {
            let items = match m.meta_item_list() {
                Some(item) => item,
                None => continue,
            };
            let mut lib = NativeLibrary {
                name: None,
                kind: cstore::NativeUnknown,
                cfg: None,
                foreign_module: Some(self.tcx.hir().local_def_id(it.id)),
                wasm_import_module: None,
            };
            let mut kind_specified = false;

            for item in items.iter() {
                if item.check_name("kind") {
                    kind_specified = true;
                    let kind = match item.value_str() {
                        Some(name) => name,
                        None => continue, // skip like historical compilers
                    };
                    lib.kind = match &kind.as_str()[..] {
                        "static" => cstore::NativeStatic,
                        "static-nobundle" => cstore::NativeStaticNobundle,
                        "dylib" => cstore::NativeUnknown,
                        "framework" => cstore::NativeFramework,
                        k => {
                            struct_span_err!(self.tcx.sess, m.span, E0458,
                                      "unknown kind: `{}`", k)
                                .span_label(item.span, "unknown kind").emit();
                            cstore::NativeUnknown
                        }
                    };
                } else if item.check_name("name") {
                    lib.name = item.value_str();
                } else if item.check_name("cfg") {
                    let cfg = match item.meta_item_list() {
                        Some(list) => list,
                        None => continue, // skip like historical compilers
                    };
                    if cfg.is_empty() {
                        self.tcx.sess.span_err(
                            item.span(),
                            "`cfg()` must have an argument",
                        );
                    } else if let cfg @ Some(..) = cfg[0].meta_item() {
                        lib.cfg = cfg.cloned();
                    } else {
                        self.tcx.sess.span_err(cfg[0].span(), "invalid argument for `cfg(..)`");
                    }
                } else if item.check_name("wasm_import_module") {
                    match item.value_str() {
                        Some(s) => lib.wasm_import_module = Some(s),
                        None => {
                            let msg = "must be of the form #[link(wasm_import_module = \"...\")]";
                            self.tcx.sess.span_err(item.span(), msg);
                        }
                    }
                } else {
                    // currently, like past compilers, ignore unknown
                    // directives here.
                }
            }

            // In general we require #[link(name = "...")] but we allow
            // #[link(wasm_import_module = "...")] without the `name`.
            let requires_name = kind_specified || lib.wasm_import_module.is_none();
            if lib.name.is_none() && requires_name {
                struct_span_err!(self.tcx.sess, m.span, E0459,
                                 "#[link(...)] specified without \
                                  `name = \"foo\"`")
                    .span_label(m.span, "missing `name` argument")
                    .emit();
            }
            self.register_native_lib(Some(m.span), lib);
        }
    }

    fn visit_trait_item(&mut self, _it: &'tcx hir::TraitItem) {}
    fn visit_impl_item(&mut self, _it: &'tcx hir::ImplItem) {}
}

impl<'a, 'tcx> Collector<'a, 'tcx> {
    fn register_native_lib(&mut self, span: Option<Span>, lib: NativeLibrary) {
        if lib.name.as_ref().map(|s| s.as_str().is_empty()).unwrap_or(false) {
            match span {
                Some(span) => {
                    struct_span_err!(self.tcx.sess, span, E0454,
                                     "#[link(name = \"\")] given with empty name")
                        .span_label(span, "empty name given")
                        .emit();
                }
                None => {
                    self.tcx.sess.err("empty library name given via `-l`");
                }
            }
            return
        }
        let is_osx = self.tcx.sess.target.target.options.is_like_osx;
        if lib.kind == cstore::NativeFramework && !is_osx {
            let msg = "native frameworks are only available on macOS targets";
            match span {
                Some(span) => span_err!(self.tcx.sess, span, E0455, "{}", msg),
                None => self.tcx.sess.err(msg),
            }
        }
        if lib.cfg.is_some() && !self.tcx.features().link_cfg {
            feature_gate::emit_feature_err(&self.tcx.sess.parse_sess,
                                           "link_cfg",
                                           span.unwrap(),
                                           GateIssue::Language,
                                           "is feature gated");
        }
        if lib.kind == cstore::NativeStaticNobundle &&
           !self.tcx.features().static_nobundle {
            feature_gate::emit_feature_err(&self.tcx.sess.parse_sess,
                                           "static_nobundle",
                                           span.unwrap(),
                                           GateIssue::Language,
                                           "kind=\"static-nobundle\" is feature gated");
        }
        self.libs.push(lib);
    }

    // Process libs passed on the command line
    fn process_command_line(&mut self) {
        // First, check for errors
        let mut renames = FxHashSet::default();
        for &(ref name, ref new_name, _) in &self.tcx.sess.opts.libs {
            if let &Some(ref new_name) = new_name {
                let any_duplicate = self.libs
                    .iter()
                    .filter_map(|lib| lib.name.as_ref())
                    .any(|n| n == name);
                if new_name.is_empty() {
                    self.tcx.sess.err(
                        &format!("an empty renaming target was specified for library `{}`",name));
                } else if !any_duplicate {
                    self.tcx.sess.err(&format!("renaming of the library `{}` was specified, \
                                                however this crate contains no #[link(...)] \
                                                attributes referencing this library.", name));
                } else if renames.contains(name) {
                    self.tcx.sess.err(&format!("multiple renamings were \
                                                specified for library `{}` .",
                                               name));
                } else {
                    renames.insert(name);
                }
            }
        }

        // Update kind and, optionally, the name of all native libraries
        // (there may be more than one) with the specified name.  If any
        // library is mentioned more than once, keep the latest mention
        // of it, so that any possible dependent libraries appear before
        // it.  (This ensures that the linker is able to see symbols from
        // all possible dependent libraries before linking in the library
        // in question.)
        for &(ref name, ref new_name, kind) in &self.tcx.sess.opts.libs {
            // If we've already added any native libraries with the same
            // name, they will be pulled out into `moved`, so that we can
            // move them to the end of the list below.
            let mut existing = self.libs.drain_filter(|lib| {
                if let Some(lib_name) = lib.name {
                    if lib_name == name as &str {
                        if let Some(k) = kind {
                            lib.kind = k;
                        }
                        if let &Some(ref new_name) = new_name {
                            lib.name = Some(Symbol::intern(new_name));
                        }
                        return true;
                    }
                }
                false
            }).collect::<Vec<_>>();
            if existing.is_empty() {
                // Add if not found
                let new_name = new_name.as_ref().map(|s| &**s); // &Option<String> -> Option<&str>
                let lib = NativeLibrary {
                    name: Some(Symbol::intern(new_name.unwrap_or(name))),
                    kind: if let Some(k) = kind { k } else { cstore::NativeUnknown },
                    cfg: None,
                    foreign_module: None,
                    wasm_import_module: None,
                };
                self.register_native_lib(None, lib);
            } else {
                // Move all existing libraries with the same name to the
                // end of the command line.
                self.libs.append(&mut existing);
            }
        }
    }
}
<commit_msg>Fix typo in comment<commit_after>// Copyright 2017 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 rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::hir;
use rustc::middle::cstore::{self, NativeLibrary};
use rustc::session::Session;
use rustc::ty::TyCtxt;
use rustc::util::nodemap::FxHashSet;
use rustc_target::spec::abi::Abi;
use syntax::attr;
use syntax::source_map::Span;
use syntax::feature_gate::{self, GateIssue};
use syntax::symbol::Symbol;

pub fn collect<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Vec<NativeLibrary> {
    let mut collector = Collector {
        tcx,
        libs: Vec::new(),
    };
    tcx.hir().krate().visit_all_item_likes(&mut collector);
    collector.process_command_line();
    return collector.libs
}

pub fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool {
    match lib.cfg {
        Some(ref cfg) => attr::cfg_matches(cfg, &sess.parse_sess, None),
        None => true,
    }
}

struct Collector<'a, 'tcx: 'a> {
    tcx: TyCtxt<'a, 'tcx, 'tcx>,
    libs: Vec<NativeLibrary>,
}

impl<'a, 'tcx> ItemLikeVisitor<'tcx> for Collector<'a, 'tcx> {
    fn visit_item(&mut self, it: &'tcx hir::Item) {
        let fm = match it.node {
            hir::ItemKind::ForeignMod(ref fm) => fm,
            _ => return,
        };

        if fm.abi == Abi::Rust ||
            fm.abi == Abi::RustIntrinsic ||
            fm.abi == Abi::PlatformIntrinsic {
            return
        }

        // Process all of the #[link(..)]-style arguments
        for m in it.attrs.iter().filter(|a| a.check_name("link")) {
            let items = match m.meta_item_list() {
                Some(item) => item,
                None => continue,
            };
            let mut lib = NativeLibrary {
                name: None,
                kind: cstore::NativeUnknown,
                cfg: None,
                foreign_module: Some(self.tcx.hir().local_def_id(it.id)),
                wasm_import_module: None,
            };
            let mut kind_specified = false;

            for item in items.iter() {
                if item.check_name("kind") {
                    kind_specified = true;
                    let kind = match item.value_str() {
                        Some(name) => name,
                        None => continue, // skip like historical compilers
                    };
                    lib.kind = match &kind.as_str()[..] {
                        "static" => cstore::NativeStatic,
                        "static-nobundle" => cstore::NativeStaticNobundle,
                        "dylib" => cstore::NativeUnknown,
                        "framework" => cstore::NativeFramework,
                        k => {
                            struct_span_err!(self.tcx.sess, m.span, E0458,
                                      "unknown kind: `{}`", k)
                                .span_label(item.span, "unknown kind").emit();
                            cstore::NativeUnknown
                        }
                    };
                } else if item.check_name("name") {
                    lib.name = item.value_str();
                } else if item.check_name("cfg") {
                    let cfg = match item.meta_item_list() {
                        Some(list) => list,
                        None => continue, // skip like historical compilers
                    };
                    if cfg.is_empty() {
                        self.tcx.sess.span_err(
                            item.span(),
                            "`cfg()` must have an argument",
                        );
                    } else if let cfg @ Some(..) = cfg[0].meta_item() {
                        lib.cfg = cfg.cloned();
                    } else {
                        self.tcx.sess.span_err(cfg[0].span(), "invalid argument for `cfg(..)`");
                    }
                } else if item.check_name("wasm_import_module") {
                    match item.value_str() {
                        Some(s) => lib.wasm_import_module = Some(s),
                        None => {
                            let msg = "must be of the form #[link(wasm_import_module = \"...\")]";
                            self.tcx.sess.span_err(item.span(), msg);
                        }
                    }
                } else {
                    // currently, like past compilers, ignore unknown
                    // directives here.
                }
            }

            // In general we require #[link(name = "...")] but we allow
            // #[link(wasm_import_module = "...")] without the `name`.
            let requires_name = kind_specified || lib.wasm_import_module.is_none();
            if lib.name.is_none() && requires_name {
                struct_span_err!(self.tcx.sess, m.span, E0459,
                                 "#[link(...)] specified without \
                                  `name = \"foo\"`")
                    .span_label(m.span, "missing `name` argument")
                    .emit();
            }
            self.register_native_lib(Some(m.span), lib);
        }
    }

    fn visit_trait_item(&mut self, _it: &'tcx hir::TraitItem) {}
    fn visit_impl_item(&mut self, _it: &'tcx hir::ImplItem) {}
}

impl<'a, 'tcx> Collector<'a, 'tcx> {
    fn register_native_lib(&mut self, span: Option<Span>, lib: NativeLibrary) {
        if lib.name.as_ref().map(|s| s.as_str().is_empty()).unwrap_or(false) {
            match span {
                Some(span) => {
                    struct_span_err!(self.tcx.sess, span, E0454,
                                     "#[link(name = \"\")] given with empty name")
                        .span_label(span, "empty name given")
                        .emit();
                }
                None => {
                    self.tcx.sess.err("empty library name given via `-l`");
                }
            }
            return
        }
        let is_osx = self.tcx.sess.target.target.options.is_like_osx;
        if lib.kind == cstore::NativeFramework && !is_osx {
            let msg = "native frameworks are only available on macOS targets";
            match span {
                Some(span) => span_err!(self.tcx.sess, span, E0455, "{}", msg),
                None => self.tcx.sess.err(msg),
            }
        }
        if lib.cfg.is_some() && !self.tcx.features().link_cfg {
            feature_gate::emit_feature_err(&self.tcx.sess.parse_sess,
                                           "link_cfg",
                                           span.unwrap(),
                                           GateIssue::Language,
                                           "is feature gated");
        }
        if lib.kind == cstore::NativeStaticNobundle &&
           !self.tcx.features().static_nobundle {
            feature_gate::emit_feature_err(&self.tcx.sess.parse_sess,
                                           "static_nobundle",
                                           span.unwrap(),
                                           GateIssue::Language,
                                           "kind=\"static-nobundle\" is feature gated");
        }
        self.libs.push(lib);
    }

    // Process libs passed on the command line
    fn process_command_line(&mut self) {
        // First, check for errors
        let mut renames = FxHashSet::default();
        for &(ref name, ref new_name, _) in &self.tcx.sess.opts.libs {
            if let &Some(ref new_name) = new_name {
                let any_duplicate = self.libs
                    .iter()
                    .filter_map(|lib| lib.name.as_ref())
                    .any(|n| n == name);
                if new_name.is_empty() {
                    self.tcx.sess.err(
                        &format!("an empty renaming target was specified for library `{}`",name));
                } else if !any_duplicate {
                    self.tcx.sess.err(&format!("renaming of the library `{}` was specified, \
                                                however this crate contains no #[link(...)] \
                                                attributes referencing this library.", name));
                } else if renames.contains(name) {
                    self.tcx.sess.err(&format!("multiple renamings were \
                                                specified for library `{}` .",
                                               name));
                } else {
                    renames.insert(name);
                }
            }
        }

        // Update kind and, optionally, the name of all native libraries
        // (there may be more than one) with the specified name.  If any
        // library is mentioned more than once, keep the latest mention
        // of it, so that any possible dependent libraries appear before
        // it.  (This ensures that the linker is able to see symbols from
        // all possible dependent libraries before linking in the library
        // in question.)
        for &(ref name, ref new_name, kind) in &self.tcx.sess.opts.libs {
            // If we've already added any native libraries with the same
            // name, they will be pulled out into `existing`, so that we
            // can move them to the end of the list below.
            let mut existing = self.libs.drain_filter(|lib| {
                if let Some(lib_name) = lib.name {
                    if lib_name == name as &str {
                        if let Some(k) = kind {
                            lib.kind = k;
                        }
                        if let &Some(ref new_name) = new_name {
                            lib.name = Some(Symbol::intern(new_name));
                        }
                        return true;
                    }
                }
                false
            }).collect::<Vec<_>>();
            if existing.is_empty() {
                // Add if not found
                let new_name = new_name.as_ref().map(|s| &**s); // &Option<String> -> Option<&str>
                let lib = NativeLibrary {
                    name: Some(Symbol::intern(new_name.unwrap_or(name))),
                    kind: if let Some(k) = kind { k } else { cstore::NativeUnknown },
                    cfg: None,
                    foreign_module: None,
                    wasm_import_module: None,
                };
                self.register_native_lib(None, lib);
            } else {
                // Move all existing libraries with the same name to the
                // end of the command line.
                self.libs.append(&mut existing);
            }
        }
    }
}
<|endoftext|>


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

//! Code for type-checking closure expressions.

use super::{check_fn, Expectation, FnCtxt};

use astconv::AstConv;
use rustc::infer::type_variable::TypeVariableOrigin;
use rustc::ty::{self, ToPolyTraitRef, Ty};
use rustc::ty::subst::Substs;
use std::cmp;
use std::iter;
use syntax::abi::Abi;
use rustc::hir;

impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
    pub fn check_expr_closure(&self,
                              expr: &hir::Expr,
                              _capture: hir::CaptureClause,
                              decl: &'gcx hir::FnDecl,
                              body_id: hir::BodyId,
                              expected: Expectation<'tcx>)
                              -> Ty<'tcx> {
        debug!("check_expr_closure(expr={:?},expected={:?})",
               expr,
               expected);
        // FIXME: Should we adapt deduce_expectations_from_expected_type to work with
        // generator traits? It looks like it's conservative to add support for this later.

        // It's always helpful for inference if we know the kind of
        // closure sooner rather than later, so first examine the expected
        // type, and see if can glean a closure kind from there.
        let (expected_sig, expected_kind) = match expected.to_option(self) {
            Some(ty) => self.deduce_expectations_from_expected_type(ty),
            None => (None, None),
        };
        let body = self.tcx.hir.body(body_id);
        self.check_closure(expr, expected_kind, decl, body, expected_sig)
    }

    fn check_closure(&self,
                     expr: &hir::Expr,
                     opt_kind: Option<ty::ClosureKind>,
                     decl: &'gcx hir::FnDecl,
                     body: &'gcx hir::Body,
                     expected_sig: Option<ty::FnSig<'tcx>>)
                     -> Ty<'tcx> {
        debug!("check_closure opt_kind={:?} expected_sig={:?}",
               opt_kind,
               expected_sig);

        let expr_def_id = self.tcx.hir.local_def_id(expr.id);
        let sig = AstConv::ty_of_closure(self,
                                         hir::Unsafety::Normal,
                                         decl,
                                         Abi::RustCall,
                                         expected_sig);
        // `deduce_expectations_from_expected_type` introduces late-bound
        // lifetimes defined elsewhere, which we need to anonymize away.
        let sig = self.tcx.anonymize_late_bound_regions(&sig);

        // Create type variables (for now) to represent the transformed
        // types of upvars. These will be unified during the upvar
        // inference phase (`upvar.rs`).
        let base_substs = Substs::identity_for_item(self.tcx,
            self.tcx.closure_base_def_id(expr_def_id));
        let substs = base_substs.extend_to(self.tcx, expr_def_id,
                |_, _| span_bug!(expr.span, "closure has region param"),
                |_, _| self.infcx.next_ty_var(TypeVariableOrigin::TransformedUpvar(expr.span))
        );

        let fn_sig = self.liberate_late_bound_regions(expr_def_id, &sig);
        let fn_sig = self.inh.normalize_associated_types_in(body.value.span,
                                                            body.value.id,
                                                            self.param_env,
                                                            &fn_sig);

        let interior = check_fn(self, self.param_env, fn_sig, decl, expr.id, body, true).1;

        if let Some(interior) = interior {
            let closure_substs = ty::ClosureSubsts {
                substs: substs,
            };
            return self.tcx.mk_generator(expr_def_id, closure_substs, interior);
        }

        let closure_type = self.tcx.mk_closure(expr_def_id, substs);

        debug!("check_closure: expr.id={:?} closure_type={:?}", expr.id, closure_type);

        // Tuple up the arguments and insert the resulting function type into
        // the `closures` table.
        let sig = sig.map_bound(|sig| self.tcx.mk_fn_sig(
            iter::once(self.tcx.intern_tup(sig.inputs(), false)),
            sig.output(),
            sig.variadic,
            sig.unsafety,
            sig.abi
        ));

        debug!("closure for {:?} --> sig={:?} opt_kind={:?}",
               expr_def_id,
               sig,
               opt_kind);

        {
            let mut tables = self.tables.borrow_mut();
            tables.closure_tys_mut().insert(expr.hir_id, sig);
            match opt_kind {
                Some(kind) => {
                    tables.closure_kinds_mut().insert(expr.hir_id, (kind, None));
                }
                None => {}
            }
        }

        closure_type
    }

    fn deduce_expectations_from_expected_type
        (&self,
         expected_ty: Ty<'tcx>)
         -> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>) {
        debug!("deduce_expectations_from_expected_type(expected_ty={:?})",
               expected_ty);

        match expected_ty.sty {
            ty::TyDynamic(ref object_type, ..) => {
                let sig = object_type.projection_bounds()
                    .filter_map(|pb| {
                        let pb = pb.with_self_ty(self.tcx, self.tcx.types.err);
                        self.deduce_sig_from_projection(&pb)
                    })
                    .next();
                let kind = object_type.principal()
                    .and_then(|p| self.tcx.lang_items.fn_trait_kind(p.def_id()));
                (sig, kind)
            }
            ty::TyInfer(ty::TyVar(vid)) => self.deduce_expectations_from_obligations(vid),
            ty::TyFnPtr(sig) => (Some(sig.skip_binder().clone()), Some(ty::ClosureKind::Fn)),
            _ => (None, None),
        }
    }

    fn deduce_expectations_from_obligations
        (&self,
         expected_vid: ty::TyVid)
         -> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>) {
        let fulfillment_cx = self.fulfillment_cx.borrow();
        // Here `expected_ty` is known to be a type inference variable.

        let expected_sig = fulfillment_cx.pending_obligations()
            .iter()
            .map(|obligation| &obligation.obligation)
            .filter_map(|obligation| {
                debug!("deduce_expectations_from_obligations: obligation.predicate={:?}",
                       obligation.predicate);

                match obligation.predicate {
                    // Given a Projection predicate, we can potentially infer
                    // the complete signature.
                    ty::Predicate::Projection(ref proj_predicate) => {
                        let trait_ref = proj_predicate.to_poly_trait_ref(self.tcx);
                        self.self_type_matches_expected_vid(trait_ref, expected_vid)
                            .and_then(|_| self.deduce_sig_from_projection(proj_predicate))
                    }
                    _ => None,
                }
            })
            .next();

        // Even if we can't infer the full signature, we may be able to
        // infer the kind. This can occur if there is a trait-reference
        // like `F : Fn<A>`. Note that due to subtyping we could encounter
        // many viable options, so pick the most restrictive.
        let expected_kind = fulfillment_cx.pending_obligations()
            .iter()
            .map(|obligation| &obligation.obligation)
            .filter_map(|obligation| {
                let opt_trait_ref = match obligation.predicate {
                    ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref(self.tcx)),
                    ty::Predicate::Trait(ref data) => Some(data.to_poly_trait_ref()),
                    ty::Predicate::Equate(..) => None,
                    ty::Predicate::Subtype(..) => None,
                    ty::Predicate::RegionOutlives(..) => None,
                    ty::Predicate::TypeOutlives(..) => None,
                    ty::Predicate::WellFormed(..) => None,
                    ty::Predicate::ObjectSafe(..) => None,

                    // NB: This predicate is created by breaking down a
                    // `ClosureType: FnFoo()` predicate, where
                    // `ClosureType` represents some `TyClosure`. It can't
                    // possibly be referring to the current closure,
                    // because we haven't produced the `TyClosure` for
                    // this closure yet; this is exactly why the other
                    // code is looking for a self type of a unresolved
                    // inference variable.
                    ty::Predicate::ClosureKind(..) => None,
                };
                opt_trait_ref.and_then(|tr| self.self_type_matches_expected_vid(tr, expected_vid))
                    .and_then(|tr| self.tcx.lang_items.fn_trait_kind(tr.def_id()))
            })
            .fold(None,
                  |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur))));

        (expected_sig, expected_kind)
    }

    /// Given a projection like "<F as Fn(X)>::Result == Y", we can deduce
    /// everything we need to know about a closure.
    fn deduce_sig_from_projection(&self,
                                  projection: &ty::PolyProjectionPredicate<'tcx>)
                                  -> Option<ty::FnSig<'tcx>> {
        let tcx = self.tcx;

        debug!("deduce_sig_from_projection({:?})", projection);

        let trait_ref = projection.to_poly_trait_ref(tcx);

        if tcx.lang_items.fn_trait_kind(trait_ref.def_id()).is_none() {
            return None;
        }

        let arg_param_ty = trait_ref.substs().type_at(1);
        let arg_param_ty = self.resolve_type_vars_if_possible(&arg_param_ty);
        debug!("deduce_sig_from_projection: arg_param_ty {:?}",
               arg_param_ty);

        let input_tys = match arg_param_ty.sty {
            ty::TyTuple(tys, _) => tys.into_iter(),
            _ => {
                return None;
            }
        };

        let ret_param_ty = projection.0.ty;
        let ret_param_ty = self.resolve_type_vars_if_possible(&ret_param_ty);
        debug!("deduce_sig_from_projection: ret_param_ty {:?}", ret_param_ty);

        let fn_sig = self.tcx.mk_fn_sig(
            input_tys.cloned(),
            ret_param_ty,
            false,
            hir::Unsafety::Normal,
            Abi::Rust
        );
        debug!("deduce_sig_from_projection: fn_sig {:?}", fn_sig);

        Some(fn_sig)
    }

    fn self_type_matches_expected_vid(&self,
                                      trait_ref: ty::PolyTraitRef<'tcx>,
                                      expected_vid: ty::TyVid)
                                      -> Option<ty::PolyTraitRef<'tcx>> {
        let self_ty = self.shallow_resolve(trait_ref.self_ty());
        debug!("self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?})",
               trait_ref,
               self_ty);
        match self_ty.sty {
            ty::TyInfer(ty::TyVar(v)) if expected_vid == v => Some(trait_ref),
            _ => None,
        }
    }
}
<commit_msg>Remove unneeded FIXME for now<commit_after>// Copyright 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.

//! Code for type-checking closure expressions.

use super::{check_fn, Expectation, FnCtxt};

use astconv::AstConv;
use rustc::infer::type_variable::TypeVariableOrigin;
use rustc::ty::{self, ToPolyTraitRef, Ty};
use rustc::ty::subst::Substs;
use std::cmp;
use std::iter;
use syntax::abi::Abi;
use rustc::hir;

impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
    pub fn check_expr_closure(&self,
                              expr: &hir::Expr,
                              _capture: hir::CaptureClause,
                              decl: &'gcx hir::FnDecl,
                              body_id: hir::BodyId,
                              expected: Expectation<'tcx>)
                              -> Ty<'tcx> {
        debug!("check_expr_closure(expr={:?},expected={:?})",
               expr,
               expected);

        // It's always helpful for inference if we know the kind of
        // closure sooner rather than later, so first examine the expected
        // type, and see if can glean a closure kind from there.
        let (expected_sig, expected_kind) = match expected.to_option(self) {
            Some(ty) => self.deduce_expectations_from_expected_type(ty),
            None => (None, None),
        };
        let body = self.tcx.hir.body(body_id);
        self.check_closure(expr, expected_kind, decl, body, expected_sig)
    }

    fn check_closure(&self,
                     expr: &hir::Expr,
                     opt_kind: Option<ty::ClosureKind>,
                     decl: &'gcx hir::FnDecl,
                     body: &'gcx hir::Body,
                     expected_sig: Option<ty::FnSig<'tcx>>)
                     -> Ty<'tcx> {
        debug!("check_closure opt_kind={:?} expected_sig={:?}",
               opt_kind,
               expected_sig);

        let expr_def_id = self.tcx.hir.local_def_id(expr.id);
        let sig = AstConv::ty_of_closure(self,
                                         hir::Unsafety::Normal,
                                         decl,
                                         Abi::RustCall,
                                         expected_sig);
        // `deduce_expectations_from_expected_type` introduces late-bound
        // lifetimes defined elsewhere, which we need to anonymize away.
        let sig = self.tcx.anonymize_late_bound_regions(&sig);

        // Create type variables (for now) to represent the transformed
        // types of upvars. These will be unified during the upvar
        // inference phase (`upvar.rs`).
        let base_substs = Substs::identity_for_item(self.tcx,
            self.tcx.closure_base_def_id(expr_def_id));
        let substs = base_substs.extend_to(self.tcx, expr_def_id,
                |_, _| span_bug!(expr.span, "closure has region param"),
                |_, _| self.infcx.next_ty_var(TypeVariableOrigin::TransformedUpvar(expr.span))
        );

        let fn_sig = self.liberate_late_bound_regions(expr_def_id, &sig);
        let fn_sig = self.inh.normalize_associated_types_in(body.value.span,
                                                            body.value.id,
                                                            self.param_env,
                                                            &fn_sig);

        let interior = check_fn(self, self.param_env, fn_sig, decl, expr.id, body, true).1;

        if let Some(interior) = interior {
            let closure_substs = ty::ClosureSubsts {
                substs: substs,
            };
            return self.tcx.mk_generator(expr_def_id, closure_substs, interior);
        }

        let closure_type = self.tcx.mk_closure(expr_def_id, substs);

        debug!("check_closure: expr.id={:?} closure_type={:?}", expr.id, closure_type);

        // Tuple up the arguments and insert the resulting function type into
        // the `closures` table.
        let sig = sig.map_bound(|sig| self.tcx.mk_fn_sig(
            iter::once(self.tcx.intern_tup(sig.inputs(), false)),
            sig.output(),
            sig.variadic,
            sig.unsafety,
            sig.abi
        ));

        debug!("closure for {:?} --> sig={:?} opt_kind={:?}",
               expr_def_id,
               sig,
               opt_kind);

        {
            let mut tables = self.tables.borrow_mut();
            tables.closure_tys_mut().insert(expr.hir_id, sig);
            match opt_kind {
                Some(kind) => {
                    tables.closure_kinds_mut().insert(expr.hir_id, (kind, None));
                }
                None => {}
            }
        }

        closure_type
    }

    fn deduce_expectations_from_expected_type
        (&self,
         expected_ty: Ty<'tcx>)
         -> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>) {
        debug!("deduce_expectations_from_expected_type(expected_ty={:?})",
               expected_ty);

        match expected_ty.sty {
            ty::TyDynamic(ref object_type, ..) => {
                let sig = object_type.projection_bounds()
                    .filter_map(|pb| {
                        let pb = pb.with_self_ty(self.tcx, self.tcx.types.err);
                        self.deduce_sig_from_projection(&pb)
                    })
                    .next();
                let kind = object_type.principal()
                    .and_then(|p| self.tcx.lang_items.fn_trait_kind(p.def_id()));
                (sig, kind)
            }
            ty::TyInfer(ty::TyVar(vid)) => self.deduce_expectations_from_obligations(vid),
            ty::TyFnPtr(sig) => (Some(sig.skip_binder().clone()), Some(ty::ClosureKind::Fn)),
            _ => (None, None),
        }
    }

    fn deduce_expectations_from_obligations
        (&self,
         expected_vid: ty::TyVid)
         -> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>) {
        let fulfillment_cx = self.fulfillment_cx.borrow();
        // Here `expected_ty` is known to be a type inference variable.

        let expected_sig = fulfillment_cx.pending_obligations()
            .iter()
            .map(|obligation| &obligation.obligation)
            .filter_map(|obligation| {
                debug!("deduce_expectations_from_obligations: obligation.predicate={:?}",
                       obligation.predicate);

                match obligation.predicate {
                    // Given a Projection predicate, we can potentially infer
                    // the complete signature.
                    ty::Predicate::Projection(ref proj_predicate) => {
                        let trait_ref = proj_predicate.to_poly_trait_ref(self.tcx);
                        self.self_type_matches_expected_vid(trait_ref, expected_vid)
                            .and_then(|_| self.deduce_sig_from_projection(proj_predicate))
                    }
                    _ => None,
                }
            })
            .next();

        // Even if we can't infer the full signature, we may be able to
        // infer the kind. This can occur if there is a trait-reference
        // like `F : Fn<A>`. Note that due to subtyping we could encounter
        // many viable options, so pick the most restrictive.
        let expected_kind = fulfillment_cx.pending_obligations()
            .iter()
            .map(|obligation| &obligation.obligation)
            .filter_map(|obligation| {
                let opt_trait_ref = match obligation.predicate {
                    ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref(self.tcx)),
                    ty::Predicate::Trait(ref data) => Some(data.to_poly_trait_ref()),
                    ty::Predicate::Equate(..) => None,
                    ty::Predicate::Subtype(..) => None,
                    ty::Predicate::RegionOutlives(..) => None,
                    ty::Predicate::TypeOutlives(..) => None,
                    ty::Predicate::WellFormed(..) => None,
                    ty::Predicate::ObjectSafe(..) => None,

                    // NB: This predicate is created by breaking down a
                    // `ClosureType: FnFoo()` predicate, where
                    // `ClosureType` represents some `TyClosure`. It can't
                    // possibly be referring to the current closure,
                    // because we haven't produced the `TyClosure` for
                    // this closure yet; this is exactly why the other
                    // code is looking for a self type of a unresolved
                    // inference variable.
                    ty::Predicate::ClosureKind(..) => None,
                };
                opt_trait_ref.and_then(|tr| self.self_type_matches_expected_vid(tr, expected_vid))
                    .and_then(|tr| self.tcx.lang_items.fn_trait_kind(tr.def_id()))
            })
            .fold(None,
                  |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur))));

        (expected_sig, expected_kind)
    }

    /// Given a projection like "<F as Fn(X)>::Result == Y", we can deduce
    /// everything we need to know about a closure.
    fn deduce_sig_from_projection(&self,
                                  projection: &ty::PolyProjectionPredicate<'tcx>)
                                  -> Option<ty::FnSig<'tcx>> {
        let tcx = self.tcx;

        debug!("deduce_sig_from_projection({:?})", projection);

        let trait_ref = projection.to_poly_trait_ref(tcx);

        if tcx.lang_items.fn_trait_kind(trait_ref.def_id()).is_none() {
            return None;
        }

        let arg_param_ty = trait_ref.substs().type_at(1);
        let arg_param_ty = self.resolve_type_vars_if_possible(&arg_param_ty);
        debug!("deduce_sig_from_projection: arg_param_ty {:?}",
               arg_param_ty);

        let input_tys = match arg_param_ty.sty {
            ty::TyTuple(tys, _) => tys.into_iter(),
            _ => {
                return None;
            }
        };

        let ret_param_ty = projection.0.ty;
        let ret_param_ty = self.resolve_type_vars_if_possible(&ret_param_ty);
        debug!("deduce_sig_from_projection: ret_param_ty {:?}", ret_param_ty);

        let fn_sig = self.tcx.mk_fn_sig(
            input_tys.cloned(),
            ret_param_ty,
            false,
            hir::Unsafety::Normal,
            Abi::Rust
        );
        debug!("deduce_sig_from_projection: fn_sig {:?}", fn_sig);

        Some(fn_sig)
    }

    fn self_type_matches_expected_vid(&self,
                                      trait_ref: ty::PolyTraitRef<'tcx>,
                                      expected_vid: ty::TyVid)
                                      -> Option<ty::PolyTraitRef<'tcx>> {
        let self_ty = self.shallow_resolve(trait_ref.self_ty());
        debug!("self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?})",
               trait_ref,
               self_ty);
        match self_ty.sty {
            ty::TyInfer(ty::TyVar(v)) if expected_vid == v => Some(trait_ref),
            _ => None,
        }
    }
}
<|endoftext|>


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

// https://leetcode.com/problems/operations-on-tree/
struct LockingTree {
    tree: HashMap<i32, Vec<i32>>,
    locks: HashMap<i32, i32>,
}

/**
 * `&self` means the method takes an immutable reference
 * If you need a mutable reference, change it to `&mut self` instead.
 */
impl LockingTree {
    fn new(parent: Vec<i32>) -> Self {
        let mut tree = HashMap::new();
        for (num, parent) in parent.into_iter().enumerate() {
            let children = tree.entry(parent).or_insert(vec![]);
            (*children).push(num as i32);
        }
        LockingTree {
            tree,
            locks: HashMap::new(),
        }
    }

    fn lock(&mut self, num: i32, user: i32) -> bool {
        match self.locks.get(&num) {
            Some(_) => false,
            None => {
                self.locks.insert(num, user);
                true
            }
        }
    }

    fn unlock(&mut self, num: i32, user: i32) -> bool {
        match self.locks.get(&num) {
            Some(u) => {
                if user != *u {
                    return false;
                }
                self.locks.insert(num, user);
                true
            }
            None => false,
        }
    }

    fn upgrade(&mut self, num: i32, user: i32) -> bool {
        match self.locks.get(&num) {
            Some(_) => false,
            None => {
                todo!()
            }
        }
    }
}

fn main() {
    let mut tree = LockingTree::new(vec![-1, 0, 0, 1, 1, 2, 2]);
    println!("{}", tree.lock(2, 2)); // true
    println!("{}", tree.unlock(2, 3)); // false
    println!("{}", tree.unlock(2, 2)); // true
    println!("{}", tree.lock(4, 5)); // true
    println!("{}", tree.upgrade(0, 1)); // true
    println!("{}", tree.lock(0, 1)); // false
    println!("{}", tree.upgrade(3, 1)); // false
}
<commit_msg>Update problem 1993<commit_after>use std::collections::HashMap;

// https://leetcode.com/problems/operations-on-tree/
struct LockingTree {
    tree: HashMap<i32, Vec<i32>>,
    locks: HashMap<i32, i32>,
}

/**
 * `&self` means the method takes an immutable reference
 * If you need a mutable reference, change it to `&mut self` instead.
 */
impl LockingTree {
    fn new(parent: Vec<i32>) -> Self {
        let mut tree = HashMap::new();
        for (num, parent) in parent.into_iter().enumerate() {
            let children = tree.entry(parent).or_insert(vec![]);
            (*children).push(num as i32);
        }
        LockingTree {
            tree,
            locks: HashMap::new(),
        }
    }

    fn lock(&mut self, num: i32, user: i32) -> bool {
        match self.locks.get(&num) {
            Some(_) => false,
            None => {
                self.locks.insert(num, user);
                true
            }
        }
    }

    fn unlock(&mut self, num: i32, user: i32) -> bool {
        match self.locks.get(&num) {
            Some(u) => {
                if user != *u {
                    return false;
                }
                self.locks.insert(num, user);
                true
            }
            None => false,
        }
    }

    fn upgrade(&mut self, num: i32, user: i32) -> bool {
        fn has_locked_ancestor(
            tree: &HashMap<i32, Vec<i32>>,
            locks: &HashMap<i32, i32>,
            num_target: i32,
            num: i32,
            locked: bool,
        ) -> bool {
            if num == num_target {
                return locked;
            }
            let mut has_locked = match locks.get(&num) {
                Some(_) => true,
                None => false,
            };
            for child in tree.get(&num).unwrap_or(&vec![]).iter() {
                has_locked |= has_locked_ancestor(tree, locks, num_target, *child, has_locked);
            }
            has_locked
        }

        fn has_locked_descendent(
            tree: &HashMap<i32, Vec<i32>>,
            locks: &mut HashMap<i32, i32>,
            num: i32,
        ) -> bool {
            let mut has_locked = match locks.get(&num) {
                Some(_) => {
                    locks.remove(&num);
                    true
                }
                None => false,
            };
            for child in tree.get(&num).unwrap_or(&vec![]).iter() {
                has_locked |= has_locked_descendent(tree, locks, *child);
            }
            has_locked
        }

        match self.locks.get(&num) {
            Some(_) => false,
            None => {
                if has_locked_ancestor(&self.tree, &self.locks, num, 0, false) {
                    return false;
                }
                if !has_locked_descendent(&self.tree, &mut self.locks, num) {
                    return false;
                }
                self.locks.insert(num, user);
                true
            }
        }
    }
}

fn main() {
    let mut tree = LockingTree::new(vec![-1, 0, 0, 1, 1, 2, 2]);
    println!("{}", tree.lock(2, 2)); // true
    println!("{}", tree.unlock(2, 3)); // false
    println!("{}", tree.unlock(2, 2)); // true
    println!("{}", tree.lock(4, 5)); // true
    println!("{}", tree.upgrade(0, 1)); // true
    println!("{}", tree.lock(0, 1)); // false
    println!("{}", tree.upgrade(3, 1)); // false
}
<|endoftext|>


<commit_before>// Copyright 2016 The Grin Developers
//
// 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.

//! Synchronization of the local blockchain with the rest of the network. Used
//! either on a brand new node or when a node is late based on others' heads.
//! Always starts by downloading the header chain before asking either for full
//! blocks or a full UTXO set with related information.

/// How many block bodies to download in parallel
const MAX_BODY_DOWNLOADS: usize = 8;

use std::ops::{Deref, DerefMut};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::{Duration, Instant};

use core::core::hash::{Hash, Hashed};
use chain;
use p2p;
use types::Error;
use util::LOGGER;

#[derive(Debug)]
struct BlockDownload {
	hash: Hash,
	start_time: Instant,
	retries: u8,
}

/// Manages syncing the local chain with other peers. Needs both a head chain
/// and a full block chain to operate. First tries to advance the header
/// chain as much as possible, then downloads the full blocks by batches.
pub struct Syncer {
	chain: Arc<chain::Chain>,
	p2p: Arc<p2p::Server>,

	sync: Mutex<bool>,
	last_header_req: Mutex<Instant>,
	blocks_to_download: Mutex<Vec<Hash>>,
	blocks_downloading: Mutex<Vec<BlockDownload>>,
}

impl Syncer {
	pub fn new(chain_ref: Arc<chain::Chain>, p2p: Arc<p2p::Server>) -> Syncer {
		Syncer {
			chain: chain_ref,
			p2p: p2p,
			sync: Mutex::new(true),
			last_header_req: Mutex::new(Instant::now() - Duration::from_secs(2)),
			blocks_to_download: Mutex::new(vec![]),
			blocks_downloading: Mutex::new(vec![]),
		}
	}

	pub fn syncing(&self) -> bool {
		*self.sync.lock().unwrap()
	}

	/// Checks the local chain state, comparing it with our peers and triggers
	/// syncing if required.
	pub fn run(&self) -> Result<(), Error> {
		debug!(LOGGER, "Starting syncer.");
		let start = Instant::now();
		loop {
			let pc = self.p2p.peer_count();
			if pc > 3 {
				break;
			}
			if pc > 0 && (Instant::now() - start > Duration::from_secs(10)) {
				break;
			}
			thread::sleep(Duration::from_millis(200));
		}

		// check if we have missing full blocks for which we already have a header
		self.init_download()?;

		// main syncing loop, requests more headers and bodies periodically as long
  // as a peer with higher difficulty exists and we're not fully caught up
		info!(LOGGER, "Starting sync loop.");
		loop {
			let tip = self.chain.get_header_head()?;
			// TODO do something better (like trying to get more) if we lose peers
			let peer = self.p2p.most_work_peer().unwrap();
			debug!(
				LOGGER,
				"Sync: peer {} vs us {}",
				peer.info.total_difficulty,
				tip.total_difficulty
			);

			let more_headers = peer.info.total_difficulty > tip.total_difficulty;
			let more_bodies = {
				let blocks_to_download = self.blocks_to_download.lock().unwrap();
				let blocks_downloading = self.blocks_downloading.lock().unwrap();
				blocks_to_download.len() > 0 || blocks_downloading.len() > 0
			};

			{
				let last_header_req = self.last_header_req.lock().unwrap().clone();
				if more_headers || (Instant::now() - Duration::from_secs(30) > last_header_req) {
					self.request_headers()?;
				}
			}
			if more_bodies {
				self.request_bodies();
			}
			if !more_headers && !more_bodies {
				// TODO check we haven't been lied to on the total work
				let mut sync = self.sync.lock().unwrap();
				*sync = false;
				break;
			}

			thread::sleep(Duration::from_secs(2));
		}
		info!(LOGGER, "Sync done.");
		Ok(())
	}

	/// Checks the gap between the header chain and the full block chain and
	/// initializes the blocks_to_download structure with the missing full
	/// blocks
	fn init_download(&self) -> Result<(), Error> {
		// compare the header's head to the full one to see what we're missing
		let header_head = self.chain.get_header_head()?;
		let full_head = self.chain.head()?;
		let mut blocks_to_download = self.blocks_to_download.lock().unwrap();

		// go back the chain and insert for download all blocks we only have the
  // head for
		let mut prev_h = header_head.last_block_h;
		while prev_h != full_head.last_block_h {
			let header = self.chain.get_block_header(&prev_h)?;
			if header.height < full_head.height {
				break;
			}
			blocks_to_download.push(header.hash());
			prev_h = header.previous;
		}

		debug!(
			LOGGER,
			"Added {} full block hashes to download.",
			blocks_to_download.len()
		);
		Ok(())
	}

	/// Asks for the blocks we haven't downloaded yet and place them in the
	/// downloading structure.
	fn request_bodies(&self) {
		let mut blocks_to_download = self.blocks_to_download.lock().unwrap();
		let mut blocks_downloading = self.blocks_downloading.lock().unwrap();

		// retry blocks not downloading
		let now = Instant::now();
		for download in blocks_downloading.deref_mut() {
			let elapsed = (now - download.start_time).as_secs();
			if download.retries >= 8 {
				panic!("Failed to download required block {}", download.hash);
			}
			if download.retries < (elapsed / 5) as u8 {
				debug!(
					LOGGER,
					"Retry {} on block {}",
					download.retries,
					download.hash
				);
				self.request_block(download.hash);
				download.retries += 1;
			}
		}

		// consume hashes from blocks to download, place them in downloading and
  // request them from the network
		let mut count = 0;
		while blocks_to_download.len() > 0 && blocks_downloading.len() < MAX_BODY_DOWNLOADS {
			let h = blocks_to_download.pop().unwrap();
			self.request_block(h);
			count += 1;
			blocks_downloading.push(BlockDownload {
				hash: h,
				start_time: Instant::now(),
				retries: 0,
			});
		}
		debug!(
			LOGGER,
			"Requested {} full blocks to download, total left: {}. Current list: {:?}.",
			count,
			blocks_to_download.len(),
			blocks_downloading.deref(),
		);
	}

	/// We added a block, clean up the downloading structure
	pub fn block_received(&self, bh: Hash) {
		// just clean up the downloading list
		let mut bds = self.blocks_downloading.lock().unwrap();
		bds.iter()
			.position(|ref h| h.hash == bh)
			.map(|n| bds.remove(n));
	}

	/// Request some block headers from a peer to advance us
	fn request_headers(&self) -> Result<(), Error> {
		{
			let mut last_header_req = self.last_header_req.lock().unwrap();
			*last_header_req = Instant::now();
		}

		let tip = self.chain.get_header_head()?;
		let peer = self.p2p.most_work_peer();
		let locator = self.get_locator(&tip)?;
		if let Some(p) = peer {
			debug!(
				LOGGER,
				"Asking peer {} for more block headers starting from {} at {}.",
				p.info.addr,
				tip.last_block_h,
				tip.height
			);
			p.send_header_request(locator)?;
		} else {
			warn!(LOGGER, "Could not get most worked peer to request headers.");
		}
		Ok(())
	}

	/// We added a header, add it to the full block download list
	pub fn headers_received(&self, bhs: Vec<Hash>) {
		let mut blocks_to_download = self.blocks_to_download.lock().unwrap();
		let hs_len = bhs.len();
		for h in bhs {
			// enlist for full block download
			blocks_to_download.insert(0, h);
		}
		// ask for more headers if we got as many as required
		if hs_len == (p2p::MAX_BLOCK_HEADERS as usize) {
			self.request_headers().unwrap();
		}
	}

	/// Builds a vector of block hashes that should help the remote peer sending
	/// us the right block headers.
	fn get_locator(&self, tip: &chain::Tip) -> Result<Vec<Hash>, Error> {
		// Prepare the heights we want as the latests height minus increasing powers
  // of 2 up to max.
		let mut heights = vec![tip.height];
		let mut tail = (1..p2p::MAX_LOCATORS)
			.map(|n| 2u64.pow(n))
			.filter_map(|n| if n > tip.height {
				None
			} else {
				Some(tip.height - n)
			})
			.collect::<Vec<_>>();
		heights.append(&mut tail);
		debug!(LOGGER, "Loc heights: {:?}", heights);

		// Iteratively travel the header chain back from our head and retain the
  // headers at the wanted heights.
		let mut header = self.chain.get_block_header(&tip.last_block_h)?;
		let mut locator = vec![];
		while heights.len() > 0 {
			if header.height == heights[0] {
				heights = heights[1..].to_vec();
				locator.push(header.hash());
			}
			if header.height > 0 {
				header = self.chain.get_block_header(&header.previous)?;
			}
		}
		Ok(locator)
	}

	/// Pick a random peer and ask for a block by hash
	fn request_block(&self, h: Hash) {
		let peer = self.p2p.random_peer().unwrap();
		let send_result = peer.send_block_request(h);
		if let Err(e) = send_result {
			debug!(LOGGER, "Error requesting block: {:?}", e);
		}
	}
}
<commit_msg>Slight increase of retry on block download before give up<commit_after>// Copyright 2016 The Grin Developers
//
// 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.

//! Synchronization of the local blockchain with the rest of the network. Used
//! either on a brand new node or when a node is late based on others' heads.
//! Always starts by downloading the header chain before asking either for full
//! blocks or a full UTXO set with related information.

/// How many block bodies to download in parallel
const MAX_BODY_DOWNLOADS: usize = 8;

use std::ops::{Deref, DerefMut};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::{Duration, Instant};

use core::core::hash::{Hash, Hashed};
use chain;
use p2p;
use types::Error;
use util::LOGGER;

#[derive(Debug)]
struct BlockDownload {
	hash: Hash,
	start_time: Instant,
	retries: u8,
}

/// Manages syncing the local chain with other peers. Needs both a head chain
/// and a full block chain to operate. First tries to advance the header
/// chain as much as possible, then downloads the full blocks by batches.
pub struct Syncer {
	chain: Arc<chain::Chain>,
	p2p: Arc<p2p::Server>,

	sync: Mutex<bool>,
	last_header_req: Mutex<Instant>,
	blocks_to_download: Mutex<Vec<Hash>>,
	blocks_downloading: Mutex<Vec<BlockDownload>>,
}

impl Syncer {
	pub fn new(chain_ref: Arc<chain::Chain>, p2p: Arc<p2p::Server>) -> Syncer {
		Syncer {
			chain: chain_ref,
			p2p: p2p,
			sync: Mutex::new(true),
			last_header_req: Mutex::new(Instant::now() - Duration::from_secs(2)),
			blocks_to_download: Mutex::new(vec![]),
			blocks_downloading: Mutex::new(vec![]),
		}
	}

	pub fn syncing(&self) -> bool {
		*self.sync.lock().unwrap()
	}

	/// Checks the local chain state, comparing it with our peers and triggers
	/// syncing if required.
	pub fn run(&self) -> Result<(), Error> {
		debug!(LOGGER, "Starting syncer.");
		let start = Instant::now();
		loop {
			let pc = self.p2p.peer_count();
			if pc > 3 {
				break;
			}
			if pc > 0 && (Instant::now() - start > Duration::from_secs(10)) {
				break;
			}
			thread::sleep(Duration::from_millis(200));
		}

		// check if we have missing full blocks for which we already have a header
		self.init_download()?;

		// main syncing loop, requests more headers and bodies periodically as long
  // as a peer with higher difficulty exists and we're not fully caught up
		info!(LOGGER, "Starting sync loop.");
		loop {
			let tip = self.chain.get_header_head()?;
			// TODO do something better (like trying to get more) if we lose peers
			let peer = self.p2p.most_work_peer().unwrap();
			debug!(
				LOGGER,
				"Sync: peer {} vs us {}",
				peer.info.total_difficulty,
				tip.total_difficulty
			);

			let more_headers = peer.info.total_difficulty > tip.total_difficulty;
			let more_bodies = {
				let blocks_to_download = self.blocks_to_download.lock().unwrap();
				let blocks_downloading = self.blocks_downloading.lock().unwrap();
				blocks_to_download.len() > 0 || blocks_downloading.len() > 0
			};

			{
				let last_header_req = self.last_header_req.lock().unwrap().clone();
				if more_headers || (Instant::now() - Duration::from_secs(30) > last_header_req) {
					self.request_headers()?;
				}
			}
			if more_bodies {
				self.request_bodies();
			}
			if !more_headers && !more_bodies {
				// TODO check we haven't been lied to on the total work
				let mut sync = self.sync.lock().unwrap();
				*sync = false;
				break;
			}

			thread::sleep(Duration::from_secs(2));
		}
		info!(LOGGER, "Sync done.");
		Ok(())
	}

	/// Checks the gap between the header chain and the full block chain and
	/// initializes the blocks_to_download structure with the missing full
	/// blocks
	fn init_download(&self) -> Result<(), Error> {
		// compare the header's head to the full one to see what we're missing
		let header_head = self.chain.get_header_head()?;
		let full_head = self.chain.head()?;
		let mut blocks_to_download = self.blocks_to_download.lock().unwrap();

		// go back the chain and insert for download all blocks we only have the
  // head for
		let mut prev_h = header_head.last_block_h;
		while prev_h != full_head.last_block_h {
			let header = self.chain.get_block_header(&prev_h)?;
			if header.height < full_head.height {
				break;
			}
			blocks_to_download.push(header.hash());
			prev_h = header.previous;
		}

		debug!(
			LOGGER,
			"Added {} full block hashes to download.",
			blocks_to_download.len()
		);
		Ok(())
	}

	/// Asks for the blocks we haven't downloaded yet and place them in the
	/// downloading structure.
	fn request_bodies(&self) {
		let mut blocks_to_download = self.blocks_to_download.lock().unwrap();
		let mut blocks_downloading = self.blocks_downloading.lock().unwrap();

		// retry blocks not downloading
		let now = Instant::now();
		for download in blocks_downloading.deref_mut() {
			let elapsed = (now - download.start_time).as_secs();
			if download.retries >= 12 {
				panic!("Failed to download required block {}", download.hash);
			}
			if download.retries < (elapsed / 5) as u8 {
				debug!(
					LOGGER,
					"Retry {} on block {}",
					download.retries,
					download.hash
				);
				self.request_block(download.hash);
				download.retries += 1;
			}
		}

		// consume hashes from blocks to download, place them in downloading and
  // request them from the network
		let mut count = 0;
		while blocks_to_download.len() > 0 && blocks_downloading.len() < MAX_BODY_DOWNLOADS {
			let h = blocks_to_download.pop().unwrap();
			self.request_block(h);
			count += 1;
			blocks_downloading.push(BlockDownload {
				hash: h,
				start_time: Instant::now(),
				retries: 0,
			});
		}
		debug!(
			LOGGER,
			"Requested {} full blocks to download, total left: {}. Current list: {:?}.",
			count,
			blocks_to_download.len(),
			blocks_downloading.deref(),
		);
	}

	/// We added a block, clean up the downloading structure
	pub fn block_received(&self, bh: Hash) {
		// just clean up the downloading list
		let mut bds = self.blocks_downloading.lock().unwrap();
		bds.iter()
			.position(|ref h| h.hash == bh)
			.map(|n| bds.remove(n));
	}

	/// Request some block headers from a peer to advance us
	fn request_headers(&self) -> Result<(), Error> {
		{
			let mut last_header_req = self.last_header_req.lock().unwrap();
			*last_header_req = Instant::now();
		}

		let tip = self.chain.get_header_head()?;
		let peer = self.p2p.most_work_peer();
		let locator = self.get_locator(&tip)?;
		if let Some(p) = peer {
			debug!(
				LOGGER,
				"Asking peer {} for more block headers starting from {} at {}.",
				p.info.addr,
				tip.last_block_h,
				tip.height
			);
			p.send_header_request(locator)?;
		} else {
			warn!(LOGGER, "Could not get most worked peer to request headers.");
		}
		Ok(())
	}

	/// We added a header, add it to the full block download list
	pub fn headers_received(&self, bhs: Vec<Hash>) {
		let mut blocks_to_download = self.blocks_to_download.lock().unwrap();
		let hs_len = bhs.len();
		for h in bhs {
			// enlist for full block download
			blocks_to_download.insert(0, h);
		}
		// ask for more headers if we got as many as required
		if hs_len == (p2p::MAX_BLOCK_HEADERS as usize) {
			self.request_headers().unwrap();
		}
	}

	/// Builds a vector of block hashes that should help the remote peer sending
	/// us the right block headers.
	fn get_locator(&self, tip: &chain::Tip) -> Result<Vec<Hash>, Error> {
		// Prepare the heights we want as the latests height minus increasing powers
  // of 2 up to max.
		let mut heights = vec![tip.height];
		let mut tail = (1..p2p::MAX_LOCATORS)
			.map(|n| 2u64.pow(n))
			.filter_map(|n| if n > tip.height {
				None
			} else {
				Some(tip.height - n)
			})
			.collect::<Vec<_>>();
		heights.append(&mut tail);
		debug!(LOGGER, "Loc heights: {:?}", heights);

		// Iteratively travel the header chain back from our head and retain the
  // headers at the wanted heights.
		let mut header = self.chain.get_block_header(&tip.last_block_h)?;
		let mut locator = vec![];
		while heights.len() > 0 {
			if header.height == heights[0] {
				heights = heights[1..].to_vec();
				locator.push(header.hash());
			}
			if header.height > 0 {
				header = self.chain.get_block_header(&header.previous)?;
			}
		}
		Ok(locator)
	}

	/// Pick a random peer and ask for a block by hash
	fn request_block(&self, h: Hash) {
		let peer = self.p2p.random_peer().unwrap();
		let send_result = peer.send_block_request(h);
		if let Err(e) = send_result {
			debug!(LOGGER, "Error requesting block: {:?}", e);
		}
	}
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;

use clap::{App, Arg, SubCommand, AppSettings};
use rusqlite as rs;
use std::path::Path;

use std::error::Error;
use std::vec::Vec;
use std::ffi::OsString;
use std::collections::HashSet;

use chrono::Local;
use chrono::DateTime;
use chrono::Datelike;
use glob::glob;

use count_write::CountWrite;
use zstd::stream::copy_decode;
use zstd::stream::write::Encoder;
use zstd::stream::read::Decoder;
use tar::Builder;
use tar::Header;
use std::io::{SeekFrom, Seek};
use std::fs::File;

fn main() {
    let matches = App::new("Karmator maintance batch")
        .version(crate_version!())
        .author(crate_authors!("\n"))
        .about("Handles the maintance work for karmator")
        .setting(AppSettings::ColoredHelp)
        .subcommand(
            SubCommand::with_name("runs")
                .about("Detect runs of votes")
                .arg(
                    Arg::with_name("min")
                        .short("m")
                        .help("Min count of runs before outputting")
                        .takes_value(true),
                )
                .arg(
                    Arg::with_name("delete")
                        .long("delete")
                        .help("Delete the runs detected"),
                )
                .arg(
                    Arg::with_name("FILE")
                        .help("Database file to operate on")
                        .required(true),
                ),
        )
        .subcommand(
            SubCommand::with_name("prune")
                .about("Prune and pack up old backups")
                .arg(
                    Arg::with_name("delete")
                        .long("delete")
                        .help("Delete the old files"),
                )
                .arg(
                    Arg::with_name("BACKUPS")
                        .help("Backup directory to prune")
                        .required(true),
                ),
        )
        .get_matches();

    match matches.subcommand() {
        ("runs", Some(m))  => {
            let filename = m.value_of("FILE").unwrap();
            let min = value_t!(m, "min", u32).unwrap_or(20);
            let delete = m.is_present("delete");

            run(filename, min, delete)
        },
        ("prune", Some(m)) => {
            let directory = m.value_of("BACKUPS").unwrap();
            let delete = m.is_present("delete");

            prune(directory, delete)
        }
        _ => {
            println!("{}", matches.usage());
            Ok(())
        },
    }.unwrap();
}

#[derive(Debug, Clone)]
struct Vote {
    id: i32,
    by_whom_name: String,
    for_what_name: String,
    amount: i8,
}
impl PartialEq for Vote {
    fn eq(&self, other: &Self) -> bool {
        (self.by_whom_name == other.by_whom_name)
            && (self.for_what_name == other.for_what_name)
            && (self.amount == other.amount)
    }
}

#[derive(Debug)]
struct RunVal {
    oldest_id: i32,
    newest_id: i32,
    by_whom_name: String,
    for_what_name: String,
    amount: i8,
    count: u32,
}

fn get_run_val(srv: &Vote, pv: &Vote, count: u32) -> RunVal {
    RunVal {
        oldest_id: srv.id,
        newest_id: pv.id,
        by_whom_name: srv.by_whom_name.clone(),
        for_what_name: srv.for_what_name.clone(),
        amount: srv.amount,
        count: count,
    }
}

fn str_amount(amount: i8) -> &'static str {
    match amount {
        -1 => "Down",
        0 => "Side",
        1 => "Up",
        _ => panic!("invalid amount"),
    }
}

fn run(filename: &str, min: u32, delete: bool) -> Result<(), Box<dyn Error>> {
    let conn =
        rs::Connection::open_with_flags(Path::new(filename), rs::OpenFlags::SQLITE_OPEN_READ_WRITE)
            .expect(&format!("Connection error: {}", filename));

    let mut stmt = conn.prepare("SELECT id, by_whom_name, for_what_name, amount FROM votes")?;
    let vote_iter = stmt.query_map(rs::params![], |row| {
        Ok(Vote {
            id: row.get(0)?,
            by_whom_name: row.get(1)?,
            for_what_name: row.get(2)?,
            amount: row.get(3)?,
        })
    })?;

    // Time to compute the run
    let mut runs = Vec::new();

    let mut start_run_vote = None;
    let mut prev_vote = None;
    let mut count = 0;

    for rvote in vote_iter {
        let vote = rvote?;

        match (&start_run_vote, &prev_vote) {
            (None, None) => {
                start_run_vote = Some(vote.clone());
                prev_vote = Some(vote);
                count = 1; // Run of 1
            }
            (Some(srv), Some(pv)) => {
                if pv == &vote {
                    // Current vote + prev vote are the same, inc prev vote
                    prev_vote = Some(vote);
                    count += 1;
                } else {
                    // Current vote != prev vote, record the run, and reset
                    runs.push(get_run_val(srv, pv, count));

                    start_run_vote = Some(vote.clone());
                    prev_vote = Some(vote);
                    count = 1; // Run of 1
                }
            }
            (_, _) => panic!("Shouldn't happen"),
        };
    }

    // Record the last run
    runs.push(get_run_val(
        &start_run_vote.unwrap(),
        &prev_vote.unwrap(),
        count,
    ));

    if delete {
        // Scan and delete the offenders
        let mut stmt = conn.prepare("DELETE FROM votes WHERE id >= ? and id <= ?")?;
        for r in &runs {
            if r.count > min {
                let deleted = stmt.execute(rs::params![r.oldest_id, r.newest_id])?;

                if (r.count as usize) != deleted {
                    panic!("Expected: {} to be deleted, got {}", r.count, deleted);
                }
            }
        }
    } else {
        // Now we can scan for anything that > min and print them
        println!(
            "{: >8}, {: >8}, {: >14.14}, {: >14.14}, {: >6}, {: >5}",
            "start_id", "end_id", "by_whom_name", "for_what_name", "amount", "count"
        );
        for r in &runs {
            if r.count > min {
                println!(
                    "{: >8}, {: >8}, {: >14.14}, {: >14.14}, {: >6}, {: >5}",
                    r.oldest_id,
                    r.newest_id,
                    r.by_whom_name,
                    r.for_what_name,
                    str_amount(r.amount),
                    r.count
                );
            }
        }
    }

    Ok(())
}

fn prune(directory: &str, delete: bool) -> Result<(), Box<dyn Error>> {
    let now: DateTime<Local> = Local::now();
    let year = now.year();
    let month = now.month();

    // Fetch a set of all of the files
    let all_files = collect_glob(directory, "/db-backup-????-??-??.sqlite.zst");

    // Fetch a set of all of the file in the current month+year
    let current_month_year = collect_glob(directory, &format!("/db-backup-{}-{:02}-??.sqlite.zst", year, month));

    // Fetch a set of all of the file that is in previous year + first of the month
    let previous_first_month = collect_glob(directory, &format!("/db-backup-{}-??-01.sqlite.zst", year - 1));

    // Fetch a set of all of the file that is in current year + first of the month
    let current_first_month = collect_glob(directory, &format!("/db-backup-{}-??-01.sqlite.zst", year));

    // Calculate the initial set of files to prune
    let delete = delete_set(&all_files, vec![&current_month_year, &previous_first_month, &current_first_month]);

    println!("cmy: {:?}", current_month_year.len());
    println!("pfm: {:?}", previous_first_month.len());
    println!("cfm: {:?}", current_first_month.len());
    println!("keeping: {:?}\n", current_month_year.len() + previous_first_month.len() + current_first_month.len());

    println!("All: {:?}", all_files.len());
    println!("DELETE: {:?}", delete.len());
    println!("keeping: {:?}", all_files.len() - delete.len());
    println!("Difference is cos of double counting the current_first_month + current_month_year's first day file");

    // Compact pfm + cfm into their years
    let mut count = CountWrite::from(std::io::sink());
    {
        let mut tar = Builder::new(Encoder::new(&mut count, 21)?.auto_finish());

        for f in current_first_month.iter() {
            let mut file = File::open(f)?;
            let filename = Path::new(f).file_name().unwrap();
            let filesize = {
                let mut count = CountWrite::from(std::io::sink());
                copy_decode(&file, &mut count)?;
                count.count()
            };

            let mut header = Header::new_gnu();
            header.set_path(filename)?;
            header.set_size(filesize);
            header.set_cksum();

            file.seek(SeekFrom::Start(0))?;
            tar.append(
                &header,
                Decoder::new(std::fs::File::open(f)?)?
            )?;
        }

        tar.finish()?;
    }
    println!("tarball: {:?}", &count.count());

    // Rules:
    //  - Keep current month of daily snapshot
    //  - Keep first of each month in a year
    //  - When there is 12 first month snapshot of a year, compact it into a tarfile

    Ok(())
}

fn collect_glob(directory: &str, glob_str: &str) -> HashSet<OsString> {
    glob(&(directory.to_string() + glob_str)).unwrap()
        .flatten()
        .map(|e| e.into_os_string())
        .collect::<HashSet<OsString>>()
}

fn delete_set(all: &HashSet<OsString>, keep: Vec<&HashSet<OsString>>) -> HashSet<OsString> {
    let mut delete = all.clone();

    for hs in keep {
        let out = delete.difference(&hs).map(|e| e.clone()).collect();
        delete = out;
    }

    delete
}
<commit_msg>Finished the backup pruner<commit_after>#[macro_use]
extern crate clap;

use clap::{App, Arg, SubCommand, AppSettings};
use rusqlite as rs;
use std::path::Path;

use std::error::Error;
use std::vec::Vec;
use std::ffi::OsString;
use std::collections::HashSet;

use chrono::Local;
use chrono::DateTime;
use chrono::Datelike;
use glob::glob;

use count_write::CountWrite;
use zstd::stream::copy_decode;
use zstd::stream::write::Encoder;
use zstd::stream::read::Decoder;
use tar::Builder;
use tar::Header;
use std::io::{SeekFrom, Seek};
use std::fs::File;
use std::fs::OpenOptions;
use std::ffi::OsStr;

fn main() {
    let matches = App::new("Karmator maintance batch")
        .version(crate_version!())
        .author(crate_authors!("\n"))
        .about("Handles the maintance work for karmator")
        .setting(AppSettings::ColoredHelp)
        .subcommand(
            SubCommand::with_name("runs")
                .about("Detect runs of votes")
                .arg(
                    Arg::with_name("min")
                        .short("m")
                        .help("Min count of runs before outputting")
                        .takes_value(true),
                )
                .arg(
                    Arg::with_name("delete")
                        .long("delete")
                        .help("Delete the runs detected"),
                )
                .arg(
                    Arg::with_name("FILE")
                        .help("Database file to operate on")
                        .required(true),
                ),
        )
        .subcommand(
            SubCommand::with_name("prune")
                .about("Prune and pack up old backups")
                .arg(
                    Arg::with_name("delete")
                        .long("delete")
                        .help("Delete the old files"),
                )
                .arg(
                    Arg::with_name("skip")
                        .long("skip")
                        .help("Skip compacting old files"),
                )
                .arg(
                    Arg::with_name("BACKUPS")
                        .help("Backup directory to prune")
                        .required(true),
                ),
        )
        .get_matches();

    match matches.subcommand() {
        ("runs", Some(m))  => {
            let filename = m.value_of("FILE").unwrap();
            let min = value_t!(m, "min", u32).unwrap_or(20);
            let delete = m.is_present("delete");

            run(filename, min, delete)
        },
        ("prune", Some(m)) => {
            let directory = m.value_of("BACKUPS").unwrap();
            let delete = m.is_present("delete");
            let skip = m.is_present("skip");

            prune(directory, delete, skip)
        }
        _ => {
            println!("{}", matches.usage());
            Ok(())
        },
    }.unwrap();
}

#[derive(Debug, Clone)]
struct Vote {
    id: i32,
    by_whom_name: String,
    for_what_name: String,
    amount: i8,
}
impl PartialEq for Vote {
    fn eq(&self, other: &Self) -> bool {
        (self.by_whom_name == other.by_whom_name)
            && (self.for_what_name == other.for_what_name)
            && (self.amount == other.amount)
    }
}

#[derive(Debug)]
struct RunVal {
    oldest_id: i32,
    newest_id: i32,
    by_whom_name: String,
    for_what_name: String,
    amount: i8,
    count: u32,
}

fn get_run_val(srv: &Vote, pv: &Vote, count: u32) -> RunVal {
    RunVal {
        oldest_id: srv.id,
        newest_id: pv.id,
        by_whom_name: srv.by_whom_name.clone(),
        for_what_name: srv.for_what_name.clone(),
        amount: srv.amount,
        count: count,
    }
}

fn str_amount(amount: i8) -> &'static str {
    match amount {
        -1 => "Down",
        0 => "Side",
        1 => "Up",
        _ => panic!("invalid amount"),
    }
}

fn run(filename: &str, min: u32, delete: bool) -> Result<(), Box<dyn Error>> {
    let conn =
        rs::Connection::open_with_flags(Path::new(filename), rs::OpenFlags::SQLITE_OPEN_READ_WRITE)
            .expect(&format!("Connection error: {}", filename));

    let mut stmt = conn.prepare("SELECT id, by_whom_name, for_what_name, amount FROM votes")?;
    let vote_iter = stmt.query_map(rs::params![], |row| {
        Ok(Vote {
            id: row.get(0)?,
            by_whom_name: row.get(1)?,
            for_what_name: row.get(2)?,
            amount: row.get(3)?,
        })
    })?;

    // Time to compute the run
    let mut runs = Vec::new();

    let mut start_run_vote = None;
    let mut prev_vote = None;
    let mut count = 0;

    for rvote in vote_iter {
        let vote = rvote?;

        match (&start_run_vote, &prev_vote) {
            (None, None) => {
                start_run_vote = Some(vote.clone());
                prev_vote = Some(vote);
                count = 1; // Run of 1
            }
            (Some(srv), Some(pv)) => {
                if pv == &vote {
                    // Current vote + prev vote are the same, inc prev vote
                    prev_vote = Some(vote);
                    count += 1;
                } else {
                    // Current vote != prev vote, record the run, and reset
                    runs.push(get_run_val(srv, pv, count));

                    start_run_vote = Some(vote.clone());
                    prev_vote = Some(vote);
                    count = 1; // Run of 1
                }
            }
            (_, _) => panic!("Shouldn't happen"),
        };
    }

    // Record the last run
    runs.push(get_run_val(
        &start_run_vote.unwrap(),
        &prev_vote.unwrap(),
        count,
    ));

    if delete {
        // Scan and delete the offenders
        let mut stmt = conn.prepare("DELETE FROM votes WHERE id >= ? and id <= ?")?;
        for r in &runs {
            if r.count > min {
                let deleted = stmt.execute(rs::params![r.oldest_id, r.newest_id])?;

                if (r.count as usize) != deleted {
                    panic!("Expected: {} to be deleted, got {}", r.count, deleted);
                }
            }
        }
    } else {
        // Now we can scan for anything that > min and print them
        println!(
            "{: >8}, {: >8}, {: >14.14}, {: >14.14}, {: >6}, {: >5}",
            "start_id", "end_id", "by_whom_name", "for_what_name", "amount", "count"
        );
        for r in &runs {
            if r.count > min {
                println!(
                    "{: >8}, {: >8}, {: >14.14}, {: >14.14}, {: >6}, {: >5}",
                    r.oldest_id,
                    r.newest_id,
                    r.by_whom_name,
                    r.for_what_name,
                    str_amount(r.amount),
                    r.count
                );
            }
        }
    }

    Ok(())
}

fn prune(directory: &str, delete: bool, skip: bool) -> Result<(), Box<dyn Error>> {
    let now: DateTime<Local> = Local::now();
    let year = now.year();
    let month = now.month();

    // Fetch a set of all of the files
    let all_files = collect_glob(directory, "/db-backup-????-??-??.sqlite.zst");

    // Fetch a set of all of the file in the current month+year
    let current_month_year = collect_glob(directory, &format!("/db-backup-{}-{:02}-??.sqlite.zst", year, month));

    // Fetch a set of all of the file that is in previous year + first of the month
    let previous_first_month = collect_glob(directory, &format!("/db-backup-{}-??-01.sqlite.zst", year - 1));

    // Fetch a set of all of the file that is in current year + first of the month
    let current_first_month = collect_glob(directory, &format!("/db-backup-{}-??-01.sqlite.zst", year));

    // Calculate the initial set of files to prune
    let mut delete_files = delete_set(&all_files, vec![&current_month_year, &previous_first_month, &current_first_month]);

    // Compact pfm + cfm into their years
    if skip {
        println!("Compacting: Skipped");
    } else {
        if previous_first_month.len() == 12 {
            let tarfile = format!("{}/db-backup-{}.tar.zst", directory, year-1);
            print_compact(&previous_first_month, &tarfile)?;
            delete_files.extend(previous_first_month.iter().map(|e| e.clone()));
        }

        if current_first_month.len() == 12 {
            let tarfile = format!("{}/db-backup-{}.tar.zst", directory, year);
            print_compact(&current_first_month, &tarfile)?;
            delete_files.extend(current_first_month.iter().map(|e| e.clone()));
        }
    }

    // List the files we are going to delete
    print_delete(&delete_files, delete)?;
    Ok(())
}

fn collect_glob(directory: &str, glob_str: &str) -> HashSet<OsString> {
    glob(&(directory.to_string() + glob_str)).unwrap()
        .flatten()
        .map(|e| e.into_os_string())
        .collect::<HashSet<OsString>>()
}

fn delete_set(all: &HashSet<OsString>, keep: Vec<&HashSet<OsString>>) -> HashSet<OsString> {
    let mut delete = all.clone();

    for hs in keep {
        let out = delete.difference(&hs).map(|e| e.clone()).collect();
        delete = out;
    }

    delete
}

fn compact(compact: &HashSet<OsString>, filename: &str) -> Result<(), Box<dyn Error>> {
    let tarfile = OpenOptions::new()
        .write(true)
        .create_new(true)
        .open(filename);

    let mut tar = Builder::new(Encoder::new(tarfile?, 21)?.auto_finish());

    for f in compact.iter() {
        let mut file = File::open(f)?;
        let filename = Path::new(f).file_name().unwrap();
        let filesize = {
            let mut count = CountWrite::from(std::io::sink());
            copy_decode(&file, &mut count)?;
            count.count()
        };

        let mut header = Header::new_gnu();
        header.set_path(filename)?;
        header.set_size(filesize);
        header.set_cksum();

        file.seek(SeekFrom::Start(0))?;
        tar.append(
            &header,
            Decoder::new(std::fs::File::open(f)?)?
        )?;
    }

    tar.finish()?;

    Ok(())
}

fn print_compact(to_compact: &HashSet<OsString>, tarfile: &str) -> Result<(), Box<dyn Error>> {
    println!("Compacting: {}", tarfile);

    let mut print = to_compact.iter()
        .map(|e| Path::new(e).file_name().unwrap())
        .collect::<Vec<&OsStr>>();
    print.sort();

    for i in print.iter() {
        println!("\t{:?}", i);
    }

    compact(&to_compact, &tarfile)?;
    Ok(())
}

fn print_delete(to_delete: &HashSet<OsString>, delete: bool) -> Result<(), Box<dyn Error>> {
    println!("Deleting:");

    let mut print = to_delete.iter().collect::<Vec<&OsString>>();
    print.sort();

    for i in print.iter() {
        let path = Path::new(i);
        println!("\t{:?}", path.file_name().unwrap());

        if delete {
            std::fs::remove_file(path)?;
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>//! Implementation of the SPECK block cipher.
//!
//! SPECK is a really simple block cipher designed by the NSA. It is famous for its simple
//! structure and code size, which can fit in just a couple of lines, while still preserving
//! security.

#![feature(i128_type)]

/// The number of rounds.
const ROUNDS: u64 = 32;

/// A single round of SPECK.
///
/// This is a keyed ARX transformation.
macro_rules! round {
    ($x:ident, $y:ident, $k:ident) => {
        $x = $x.rotate_right(8);
        $x = $x.wrapping_add($y);
        $x ^= $k;
        $y = $y.rotate_left(3);
        $y ^= $x;
    }
}

/// Revert a SPECK round given some subkey.
macro_rules! inv_round {
    ($x:ident, $y:ident, $k:ident) => {
        $y ^= $x;
        $y = $y.rotate_right(3);
        $x ^= $k;
        $x = $x.wrapping_sub($y);
        $x = $x.rotate_left(8);
    }
}

/// Encrypt a block with key schedule generated on-the-go.
///
/// This works great for one-time use of a key (such as usages other than encryption), because it
/// should never read from memory (both the message and the keys are stored in the registers). As
/// such, this should be really fast for such usage.
///
/// If you want to reuse the key, however, it is recommended that you use the precomputed schedule
/// provided by the `Key` struct.
pub fn encrypt_block(m: u128, k: u128) -> u128 {
    let mut m1 = (m >> 64) as u64;
    let mut m2 = m as u64;
    let mut k1 = (k >> 64) as u64;
    let mut k2 = k as u64;

    // Run the initial round (similar to the loop below, but doesn't update the key schedule).
    round!(m1, m2, k2);

    for i in 0..ROUNDS - 1 {
        // Progress the key schedule.
        round!(k1, k2, i);
        // Run a round over the message.
        round!(m1, m2, k2);
    }

    m2 as u128 | (m1 as u128) << 64
}

/// A precomputed key.
///
/// This precomputes a key schedule, which can then be used for both encrypting and decrypting messages.
pub struct Key {
    /// The computed schedule.
    ///
    /// Each of these subkeys are used in a round of the cipher. The first subkey is used in the
    /// first round of the cipher and so on.
    schedule: [u64; ROUNDS as usize],
}

impl Key {
    /// Generate a new key from some seed.
    pub fn new(k: u128) -> Key {
        let mut k1 = (k >> 64) as u64;
        let mut k2 = k as u64;

        let mut ret = Key {
            schedule: [0; ROUNDS as usize],
        };

        // Run `ROUNDS - 1` rounds to generate the key's endpoint (the last key in the schedule).
        for i in 0..ROUNDS {
            // Insert the key into the schedule.
            ret.schedule[i as usize] = k2;

            // The beautiful thing about SPECK is that it reuses its round function to generate the
            // key schedule.
            round!(k1, k2, i);
        }

        ret
    }

    /// Encrypt a 128-bit block with this key.
    pub fn encrypt_block(&self, m: u128) -> u128 {
        let mut m1 = (m >> 64) as u64;
        let mut m2 = m as u64;

        // We run a round for every subkey in the generated key schedule.
        for &k in &self.schedule {
            // Run a round on the message.
            round!(m1, m2, k);
        }

        m2 as u128 | (m1 as u128) << 64
    }

    /// Decrypt a 128-bit block with this key.
    pub fn decrypt_block(&self, c: u128) -> u128 {
        let mut c1 = (c >> 64) as u64;
        let mut c2 = c as u64;

        // We run a round for every subkey in the generated key schedule.
        for &k in self.schedule.iter().rev() {
            // Run a round on the message.
            inv_round!(c1, c2, k);
        }

        c2 as u128 | (c1 as u128) << 64
    }
}

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

    #[test]
    fn encrypt_decrypt() {
        for mut x in 0u128..90000 {
            // <3
            x = x.wrapping_mul(0x6eed0e9da4d94a4f6eed0e9da4d94a4f);
            x ^= (x >> 6) >> (x >> 122);
            x = x.wrapping_mul(0x6eed0e9da4d94a4f6eed0e9da4d94a4f);

            let key = Key::new(!x);

            assert_eq!(key.decrypt_block(key.encrypt_block(x)), x);
            assert_eq!(key.encrypt_block(x), encrypt_block(x, !x));
        }
    }

    #[test]
    fn test_vectors() {
        // These test vectors are taken from the SPECK paper.
        assert_eq!(encrypt_block(0x6c617669757165207469206564616d20, 0x0f0e0d0c0b0a09080706050403020100), 0xa65d9851797832657860fedf5c570d18);
    }
}
<commit_msg>Removed dependency on `std`.<commit_after>//! Implementation of the SPECK block cipher.
//!
//! SPECK is a really simple block cipher designed by the NSA. It is famous for its simple
//! structure and code size, which can fit in just a couple of lines, while still preserving
//! security.

#![feature(i128_type)]

#![no_std]

/// The number of rounds.
const ROUNDS: u64 = 32;

/// A single round of SPECK.
///
/// This is a keyed ARX transformation.
macro_rules! round {
    ($x:ident, $y:ident, $k:ident) => {
        $x = $x.rotate_right(8);
        $x = $x.wrapping_add($y);
        $x ^= $k;
        $y = $y.rotate_left(3);
        $y ^= $x;
    }
}

/// Revert a SPECK round given some subkey.
macro_rules! inv_round {
    ($x:ident, $y:ident, $k:ident) => {
        $y ^= $x;
        $y = $y.rotate_right(3);
        $x ^= $k;
        $x = $x.wrapping_sub($y);
        $x = $x.rotate_left(8);
    }
}

/// Encrypt a block with key schedule generated on-the-go.
///
/// This works great for one-time use of a key (such as usages other than encryption), because it
/// should never read from memory (both the message and the keys are stored in the registers). As
/// such, this should be really fast for such usage.
///
/// If you want to reuse the key, however, it is recommended that you use the precomputed schedule
/// provided by the `Key` struct.
pub fn encrypt_block(m: u128, k: u128) -> u128 {
    let mut m1 = (m >> 64) as u64;
    let mut m2 = m as u64;
    let mut k1 = (k >> 64) as u64;
    let mut k2 = k as u64;

    // Run the initial round (similar to the loop below, but doesn't update the key schedule).
    round!(m1, m2, k2);

    for i in 0..ROUNDS - 1 {
        // Progress the key schedule.
        round!(k1, k2, i);
        // Run a round over the message.
        round!(m1, m2, k2);
    }

    m2 as u128 | (m1 as u128) << 64
}

/// A precomputed key.
///
/// This precomputes a key schedule, which can then be used for both encrypting and decrypting
/// messages.
pub struct Key {
    /// The computed schedule.
    ///
    /// Each of these subkeys are used in a round of the cipher. The first subkey is used in the
    /// first round of the cipher and so on.
    schedule: [u64; ROUNDS as usize],
}

impl Key {
    /// Generate a new key from some seed.
    pub fn new(k: u128) -> Key {
        let mut k1 = (k >> 64) as u64;
        let mut k2 = k as u64;

        let mut ret = Key {
            schedule: [0; ROUNDS as usize],
        };

        // Run `ROUNDS - 1` rounds to generate the key's endpoint (the last key in the schedule).
        for i in 0..ROUNDS {
            // Insert the key into the schedule.
            ret.schedule[i as usize] = k2;

            // The beautiful thing about SPECK is that it reuses its round function to generate the
            // key schedule.
            round!(k1, k2, i);
        }

        ret
    }

    /// Encrypt a 128-bit block with this key.
    pub fn encrypt_block(&self, m: u128) -> u128 {
        let mut m1 = (m >> 64) as u64;
        let mut m2 = m as u64;

        // We run a round for every subkey in the generated key schedule.
        for &k in &self.schedule {
            // Run a round on the message.
            round!(m1, m2, k);
        }

        m2 as u128 | (m1 as u128) << 64
    }

    /// Decrypt a 128-bit block with this key.
    pub fn decrypt_block(&self, c: u128) -> u128 {
        let mut c1 = (c >> 64) as u64;
        let mut c2 = c as u64;

        // We run a round for every subkey in the generated key schedule.
        for &k in self.schedule.iter().rev() {
            // Run a round on the message.
            inv_round!(c1, c2, k);
        }

        c2 as u128 | (c1 as u128) << 64
    }
}

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

    #[test]
    fn encrypt_decrypt() {
        for mut x in 0u128..90000 {
            // <3
            x = x.wrapping_mul(0x6eed0e9da4d94a4f6eed0e9da4d94a4f);
            x ^= (x >> 6) >> (x >> 122);
            x = x.wrapping_mul(0x6eed0e9da4d94a4f6eed0e9da4d94a4f);

            let key = Key::new(!x);

            assert_eq!(key.decrypt_block(key.encrypt_block(x)), x);
            assert_eq!(key.encrypt_block(x), encrypt_block(x, !x));
        }
    }

    #[test]
    fn test_vectors() {
        // These test vectors are taken from the SPECK paper.
        assert_eq!(
            encrypt_block(
                0x6c617669757165207469206564616d20,
                0x0f0e0d0c0b0a09080706050403020100
            ),
            0xa65d9851797832657860fedf5c570d18
        );
    }
}
<|endoftext|>