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

use attr::{AttrMetaMethods, HasAttrs};
use errors::Handler;
use feature_gate::GatedCfgAttr;
use fold::Folder;
use {ast, fold, attr};
use visit;
use codemap::{Spanned, respan};
use ptr::P;

use util::small_vector::SmallVector;

pub trait CfgFolder: fold::Folder {
    fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T>;
    fn visit_unconfigurable_expr(&mut self, _expr: &ast::Expr) {}
}

/// A folder that strips out items that do not belong in the current
/// configuration.
pub struct StripUnconfigured<'a> {
    diag: CfgDiagReal<'a, 'a>,
    config: &'a ast::CrateConfig,
}

impl<'a> CfgFolder for StripUnconfigured<'a> {
    fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
        if in_cfg(self.config, node.attrs(), &mut self.diag) {
            Some(node)
        } else {
            None
        }
    }

    fn visit_unconfigurable_expr(&mut self, expr: &ast::Expr) {
        if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a)) {
            let msg = "removing an expression is not supported in this position";
            self.diag.diag.span_err(attr.span, msg);
        }
    }
}

// Support conditional compilation by transforming the AST, stripping out
// any items that do not belong in the current configuration
pub fn strip_unconfigured_items(diagnostic: &Handler, krate: ast::Crate,
                                feature_gated_cfgs: &mut Vec<GatedCfgAttr>)
                                -> ast::Crate
{
    // Need to do this check here because cfg runs before feature_gates
    check_for_gated_stmt_expr_attributes(&krate, feature_gated_cfgs);

    let krate = process_cfg_attr(diagnostic, krate, feature_gated_cfgs);

    StripUnconfigured {
        config: &krate.config.clone(),
        diag: CfgDiagReal {
            diag: diagnostic,
            feature_gated_cfgs: feature_gated_cfgs,
        },
    }.fold_crate(krate)
}

impl<T: CfgFolder> fold::Folder for T {
    fn fold_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod {
        ast::ForeignMod {
            abi: foreign_mod.abi,
            items: foreign_mod.items.into_iter().filter_map(|item| self.configure(item)).collect(),
        }
    }

    fn fold_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind {
        let fold_struct = |this: &mut Self, vdata| match vdata {
            ast::VariantData::Struct(fields, id) => {
                let fields = fields.into_iter().filter_map(|field| this.configure(field));
                ast::VariantData::Struct(fields.collect(), id)
            }
            ast::VariantData::Tuple(fields, id) => {
                let fields = fields.into_iter().filter_map(|field| this.configure(field));
                ast::VariantData::Tuple(fields.collect(), id)
            }
            ast::VariantData::Unit(id) => ast::VariantData::Unit(id)
        };

        let item = match item {
            ast::ItemKind::Impl(u, o, a, b, c, items) => {
                let items = items.into_iter().filter_map(|item| self.configure(item)).collect();
                ast::ItemKind::Impl(u, o, a, b, c, items)
            }
            ast::ItemKind::Trait(u, a, b, items) => {
                let items = items.into_iter().filter_map(|item| self.configure(item)).collect();
                ast::ItemKind::Trait(u, a, b, items)
            }
            ast::ItemKind::Struct(def, generics) => {
                ast::ItemKind::Struct(fold_struct(self, def), generics)
            }
            ast::ItemKind::Enum(def, generics) => {
                let variants = def.variants.into_iter().filter_map(|v| {
                    self.configure(v).map(|v| {
                        Spanned {
                            node: ast::Variant_ {
                                name: v.node.name,
                                attrs: v.node.attrs,
                                data: fold_struct(self, v.node.data),
                                disr_expr: v.node.disr_expr,
                            },
                            span: v.span
                        }
                    })
                });
                ast::ItemKind::Enum(ast::EnumDef {
                    variants: variants.collect(),
                }, generics)
            }
            item => item,
        };

        fold::noop_fold_item_kind(item, self)
    }

    fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
        // If an expr is valid to cfg away it will have been removed by the
        // outer stmt or expression folder before descending in here.
        // Anything else is always required, and thus has to error out
        // in case of a cfg attr.
        //
        // NB: This is intentionally not part of the fold_expr() function
        //     in order for fold_opt_expr() to be able to avoid this check
        self.visit_unconfigurable_expr(&expr);
        fold_expr(self, expr)
    }

    fn fold_opt_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
        self.configure(expr).map(|expr| fold_expr(self, expr))
    }

    fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector<ast::Stmt> {
        self.configure(stmt).map(|stmt| fold::noop_fold_stmt(stmt, self))
                            .unwrap_or(SmallVector::zero())
    }

    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
        fold::noop_fold_mac(mac, self)
    }

    fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
        self.configure(item).map(|item| SmallVector::one(item.map(|i| self.fold_item_simple(i))))
                            .unwrap_or(SmallVector::zero())
    }
}

fn fold_expr<F: CfgFolder>(folder: &mut F, expr: P<ast::Expr>) -> P<ast::Expr> {
    expr.map(|ast::Expr {id, span, node, attrs}| {
        fold::noop_fold_expr(ast::Expr {
            id: id,
            node: match node {
                ast::ExprKind::Match(m, arms) => {
                    ast::ExprKind::Match(m, arms.into_iter()
                                        .filter_map(|a| folder.configure(a))
                                        .collect())
                }
                _ => node
            },
            span: span,
            attrs: attrs,
        }, folder)
    })
}

fn is_cfg(attr: &ast::Attribute) -> bool {
    attr.check_name("cfg")
}

// Determine if an item should be translated in the current crate
// configuration based on the item's attributes
fn in_cfg<T: CfgDiag>(cfg: &[P<ast::MetaItem>],
                      attrs: &[ast::Attribute],
                      diag: &mut T) -> bool {
    attrs.iter().all(|attr| {
        let mis = match attr.node.value.node {
            ast::MetaItemKind::List(_, ref mis) if is_cfg(&attr) => mis,
            _ => return true
        };

        if mis.len() != 1 {
            diag.emit_error(|diagnostic| {
                diagnostic.span_err(attr.span, "expected 1 cfg-pattern");
            });
            return true;
        }

        attr::cfg_matches(cfg, &mis[0], diag)
    })
}

struct CfgAttrFolder<'a, T> {
    diag: T,
    config: &'a ast::CrateConfig,
}

// Process `#[cfg_attr]`.
fn process_cfg_attr(diagnostic: &Handler, krate: ast::Crate,
                    feature_gated_cfgs: &mut Vec<GatedCfgAttr>) -> ast::Crate {
    let mut fld = CfgAttrFolder {
        diag: CfgDiagReal {
            diag: diagnostic,
            feature_gated_cfgs: feature_gated_cfgs,
        },
        config: &krate.config.clone(),
    };
    fld.fold_crate(krate)
}

impl<'a, T: CfgDiag> fold::Folder for CfgAttrFolder<'a, T> {
    fn fold_attribute(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
        if !attr.check_name("cfg_attr") {
            return fold::noop_fold_attribute(attr, self);
        }

        let attr_list = match attr.meta_item_list() {
            Some(attr_list) => attr_list,
            None => {
                self.diag.emit_error(|diag| {
                    diag.span_err(attr.span,
                        "expected `#[cfg_attr(<cfg pattern>, <attr>)]`");
                });
                return None;
            }
        };
        let (cfg, mi) = match (attr_list.len(), attr_list.get(0), attr_list.get(1)) {
            (2, Some(cfg), Some(mi)) => (cfg, mi),
            _ => {
                self.diag.emit_error(|diag| {
                    diag.span_err(attr.span,
                        "expected `#[cfg_attr(<cfg pattern>, <attr>)]`");
                });
                return None;
            }
        };

        if attr::cfg_matches(&self.config[..], &cfg, &mut self.diag) {
            Some(respan(mi.span, ast::Attribute_ {
                id: attr::mk_attr_id(),
                style: attr.node.style,
                value: mi.clone(),
                is_sugared_doc: false,
            }))
        } else {
            None
        }
    }

    // Need the ability to run pre-expansion.
    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
        fold::noop_fold_mac(mac, self)
    }
}

fn check_for_gated_stmt_expr_attributes(krate: &ast::Crate,
                                        discovered: &mut Vec<GatedCfgAttr>) {
    let mut v = StmtExprAttrFeatureVisitor {
        config: &krate.config,
        discovered: discovered,
    };
    visit::walk_crate(&mut v, krate);
}

/// To cover this feature, we need to discover all attributes
/// so we need to run before cfg.
struct StmtExprAttrFeatureVisitor<'a, 'b> {
    config: &'a ast::CrateConfig,
    discovered: &'b mut Vec<GatedCfgAttr>,
}

// Runs the cfg_attr and cfg folders locally in "silent" mode
// to discover attribute use on stmts or expressions ahead of time
impl<'v, 'a, 'b> visit::Visitor<'v> for StmtExprAttrFeatureVisitor<'a, 'b> {
    fn visit_stmt(&mut self, s: &'v ast::Stmt) {
        // check if there even are any attributes on this node
        let stmt_attrs = s.node.attrs();
        if stmt_attrs.len() > 0 {
            // attributes on items are fine
            if let ast::StmtKind::Decl(ref decl, _) = s.node {
                if let ast::DeclKind::Item(_) = decl.node {
                    visit::walk_stmt(self, s);
                    return;
                }
            }

            // flag the offending attributes
            for attr in stmt_attrs {
                self.discovered.push(GatedCfgAttr::GatedAttr(attr.span));
            }

            // if the node does not end up being cfg-d away, walk down
            if node_survives_cfg(stmt_attrs, self.config) {
                visit::walk_stmt(self, s);
            }
        } else {
            visit::walk_stmt(self, s);
        }
    }

    fn visit_expr(&mut self, ex: &'v ast::Expr) {
        // check if there even are any attributes on this node
        let expr_attrs = ex.attrs();
        if expr_attrs.len() > 0 {

            // flag the offending attributes
            for attr in expr_attrs {
                self.discovered.push(GatedCfgAttr::GatedAttr(attr.span));
            }

            // if the node does not end up being cfg-d away, walk down
            if node_survives_cfg(expr_attrs, self.config) {
                visit::walk_expr(self, ex);
            }
        } else {
            visit::walk_expr(self, ex);
        }
    }

    fn visit_foreign_item(&mut self, i: &'v ast::ForeignItem) {
        if node_survives_cfg(&i.attrs, self.config) {
            visit::walk_foreign_item(self, i);
        }
    }

    fn visit_item(&mut self, i: &'v ast::Item) {
        if node_survives_cfg(&i.attrs, self.config) {
            visit::walk_item(self, i);
        }
    }

    fn visit_impl_item(&mut self, ii: &'v ast::ImplItem) {
        if node_survives_cfg(&ii.attrs, self.config) {
            visit::walk_impl_item(self, ii);
        }
    }

    fn visit_trait_item(&mut self, ti: &'v ast::TraitItem) {
        if node_survives_cfg(&ti.attrs, self.config) {
            visit::walk_trait_item(self, ti);
        }
    }

    fn visit_struct_field(&mut self, s: &'v ast::StructField) {
        if node_survives_cfg(&s.attrs, self.config) {
            visit::walk_struct_field(self, s);
        }
    }

    fn visit_variant(&mut self, v: &'v ast::Variant,
                     g: &'v ast::Generics, item_id: ast::NodeId) {
        if node_survives_cfg(&v.node.attrs, self.config) {
            visit::walk_variant(self, v, g, item_id);
        }
    }

    fn visit_arm(&mut self, a: &'v ast::Arm) {
        if node_survives_cfg(&a.attrs, self.config) {
            visit::walk_arm(self, a);
        }
    }

    // This visitor runs pre expansion, so we need to prevent
    // the default panic here
    fn visit_mac(&mut self, mac: &'v ast::Mac) {
        visit::walk_mac(self, mac)
    }
}

pub trait CfgDiag {
    fn emit_error<F>(&mut self, f: F) where F: FnMut(&Handler);
    fn flag_gated<F>(&mut self, f: F) where F: FnMut(&mut Vec<GatedCfgAttr>);
}

pub struct CfgDiagReal<'a, 'b> {
    pub diag: &'a Handler,
    pub feature_gated_cfgs: &'b mut Vec<GatedCfgAttr>,
}

impl<'a, 'b> CfgDiag for CfgDiagReal<'a, 'b> {
    fn emit_error<F>(&mut self, mut f: F) where F: FnMut(&Handler) {
        f(self.diag)
    }
    fn flag_gated<F>(&mut self, mut f: F) where F: FnMut(&mut Vec<GatedCfgAttr>) {
        f(self.feature_gated_cfgs)
    }
}

struct CfgDiagSilent {
    error: bool,
}

impl CfgDiag for CfgDiagSilent {
    fn emit_error<F>(&mut self, _: F) where F: FnMut(&Handler) {
        self.error = true;
    }
    fn flag_gated<F>(&mut self, _: F) where F: FnMut(&mut Vec<GatedCfgAttr>) {}
}

fn node_survives_cfg(attrs: &[ast::Attribute],
                     config: &ast::CrateConfig) -> bool {
    let mut survives_cfg = true;

    for attr in attrs {
        let mut fld = CfgAttrFolder {
            diag: CfgDiagSilent { error: false },
            config: config,
        };
        let attr = fld.fold_attribute(attr.clone());

        // In case of error we can just return true,
        // since the actual cfg folders will end compilation anyway.

        if fld.diag.error { return true; }

        survives_cfg &= attr.map(|attr| {
            let mut diag = CfgDiagSilent { error: false };
            let r = in_cfg(config, &[attr], &mut diag);
            if diag.error { return true; }
            r
        }).unwrap_or(true)
    }

    survives_cfg
}
<commit_msg>Move cfg_attr processing and stmt/expr attribute gated feature checking into `StripUnconfigured`<commit_after>// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use attr::{AttrMetaMethods, HasAttrs};
use errors::Handler;
use feature_gate::GatedCfgAttr;
use fold::Folder;
use {ast, fold, attr};
use codemap::{Spanned, respan};
use ptr::P;

use util::small_vector::SmallVector;

pub trait CfgFolder: fold::Folder {
    fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T>;
    fn visit_stmt_or_expr_attrs(&mut self, _attrs: &[ast::Attribute]) {}
    fn visit_unconfigurable_expr(&mut self, _expr: &ast::Expr) {}
}

/// A folder that strips out items that do not belong in the current
/// configuration.
pub struct StripUnconfigured<'a> {
    diag: CfgDiagReal<'a, 'a>,
    config: &'a ast::CrateConfig,
}

impl<'a> StripUnconfigured<'a> {
    // Determine if an item should be translated in the current crate
    // configuration based on the item's attributes
    fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool {
        attrs.iter().all(|attr| {
            let mis = match attr.node.value.node {
                ast::MetaItemKind::List(_, ref mis) if is_cfg(&attr) => mis,
                _ => return true
            };

            if mis.len() != 1 {
                self.diag.emit_error(|diagnostic| {
                    diagnostic.span_err(attr.span, "expected 1 cfg-pattern");
                });
                return true;
            }

            attr::cfg_matches(self.config, &mis[0], &mut self.diag)
        })
    }

    fn process_cfg_attrs(&mut self, attrs: Vec<ast::Attribute>) -> Vec<ast::Attribute> {
        attrs.into_iter().filter_map(|attr| self.process_cfg_attr(attr)).collect()
    }

    fn process_cfg_attr(&mut self, attr: ast::Attribute) -> Option<ast::Attribute> {
        if !attr.check_name("cfg_attr") {
            return Some(attr);
        }

        let attr_list = match attr.meta_item_list() {
            Some(attr_list) => attr_list,
            None => {
                let msg = "expected `#[cfg_attr(<cfg pattern>, <attr>)]`";
                self.diag.diag.span_err(attr.span, msg);
                return None;
            }
        };
        let (cfg, mi) = match (attr_list.len(), attr_list.get(0), attr_list.get(1)) {
            (2, Some(cfg), Some(mi)) => (cfg, mi),
            _ => {
                let msg = "expected `#[cfg_attr(<cfg pattern>, <attr>)]`";
                self.diag.diag.span_err(attr.span, msg);
                return None;
            }
        };

        if attr::cfg_matches(self.config, &cfg, &mut self.diag) {
            Some(respan(mi.span, ast::Attribute_ {
                id: attr::mk_attr_id(),
                style: attr.node.style,
                value: mi.clone(),
                is_sugared_doc: false,
            }))
        } else {
            None
        }
    }
}

impl<'a> CfgFolder for StripUnconfigured<'a> {
    fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
        let node = node.map_attrs(|attrs| self.process_cfg_attrs(attrs));
        if self.in_cfg(node.attrs()) { Some(node) } else { None }
    }

    fn visit_stmt_or_expr_attrs(&mut self, attrs: &[ast::Attribute]) {
        // flag the offending attributes
        for attr in attrs.iter() {
            self.diag.feature_gated_cfgs.push(GatedCfgAttr::GatedAttr(attr.span));
        }
    }

    fn visit_unconfigurable_expr(&mut self, expr: &ast::Expr) {
        if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a)) {
            let msg = "removing an expression is not supported in this position";
            self.diag.diag.span_err(attr.span, msg);
        }
    }
}

// Support conditional compilation by transforming the AST, stripping out
// any items that do not belong in the current configuration
pub fn strip_unconfigured_items(diagnostic: &Handler, krate: ast::Crate,
                                feature_gated_cfgs: &mut Vec<GatedCfgAttr>)
                                -> ast::Crate
{
    StripUnconfigured {
        config: &krate.config.clone(),
        diag: CfgDiagReal {
            diag: diagnostic,
            feature_gated_cfgs: feature_gated_cfgs,
        },
    }.fold_crate(krate)
}

impl<T: CfgFolder> fold::Folder for T {
    fn fold_foreign_mod(&mut self, foreign_mod: ast::ForeignMod) -> ast::ForeignMod {
        ast::ForeignMod {
            abi: foreign_mod.abi,
            items: foreign_mod.items.into_iter().filter_map(|item| {
                self.configure(item).map(|item| fold::noop_fold_foreign_item(item, self))
            }).collect(),
        }
    }

    fn fold_item_kind(&mut self, item: ast::ItemKind) -> ast::ItemKind {
        let fold_struct = |this: &mut Self, vdata| match vdata {
            ast::VariantData::Struct(fields, id) => {
                let fields = fields.into_iter().filter_map(|field| this.configure(field));
                ast::VariantData::Struct(fields.collect(), id)
            }
            ast::VariantData::Tuple(fields, id) => {
                let fields = fields.into_iter().filter_map(|field| this.configure(field));
                ast::VariantData::Tuple(fields.collect(), id)
            }
            ast::VariantData::Unit(id) => ast::VariantData::Unit(id)
        };

        let item = match item {
            ast::ItemKind::Impl(u, o, a, b, c, items) => {
                let items = items.into_iter().filter_map(|item| self.configure(item)).collect();
                ast::ItemKind::Impl(u, o, a, b, c, items)
            }
            ast::ItemKind::Trait(u, a, b, items) => {
                let items = items.into_iter().filter_map(|item| self.configure(item)).collect();
                ast::ItemKind::Trait(u, a, b, items)
            }
            ast::ItemKind::Struct(def, generics) => {
                ast::ItemKind::Struct(fold_struct(self, def), generics)
            }
            ast::ItemKind::Enum(def, generics) => {
                let variants = def.variants.into_iter().filter_map(|v| {
                    self.configure(v).map(|v| {
                        Spanned {
                            node: ast::Variant_ {
                                name: v.node.name,
                                attrs: v.node.attrs,
                                data: fold_struct(self, v.node.data),
                                disr_expr: v.node.disr_expr,
                            },
                            span: v.span
                        }
                    })
                });
                ast::ItemKind::Enum(ast::EnumDef {
                    variants: variants.collect(),
                }, generics)
            }
            item => item,
        };

        fold::noop_fold_item_kind(item, self)
    }

    fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
        self.visit_stmt_or_expr_attrs(expr.attrs());
        // If an expr is valid to cfg away it will have been removed by the
        // outer stmt or expression folder before descending in here.
        // Anything else is always required, and thus has to error out
        // in case of a cfg attr.
        //
        // NB: This is intentionally not part of the fold_expr() function
        //     in order for fold_opt_expr() to be able to avoid this check
        self.visit_unconfigurable_expr(&expr);
        fold_expr(self, expr)
    }

    fn fold_opt_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
        self.configure(expr).map(|expr| fold_expr(self, expr))
    }

    fn fold_stmt(&mut self, stmt: ast::Stmt) -> SmallVector<ast::Stmt> {
        let is_item = match stmt.node {
            ast::StmtKind::Decl(ref decl, _) => match decl.node {
                ast::DeclKind::Item(_) => true,
                _ => false,
            },
            _ => false,
        };

        // avoid calling `visit_stmt_or_expr_attrs` on items
        if !is_item {
            self.visit_stmt_or_expr_attrs(stmt.attrs());
        }

        self.configure(stmt).map(|stmt| fold::noop_fold_stmt(stmt, self))
                            .unwrap_or(SmallVector::zero())
    }

    fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
        fold::noop_fold_mac(mac, self)
    }

    fn fold_item(&mut self, item: P<ast::Item>) -> SmallVector<P<ast::Item>> {
        self.configure(item).map(|item| SmallVector::one(item.map(|i| self.fold_item_simple(i))))
                            .unwrap_or(SmallVector::zero())
    }
}

fn fold_expr<F: CfgFolder>(folder: &mut F, expr: P<ast::Expr>) -> P<ast::Expr> {
    expr.map(|ast::Expr {id, span, node, attrs}| {
        fold::noop_fold_expr(ast::Expr {
            id: id,
            node: match node {
                ast::ExprKind::Match(m, arms) => {
                    ast::ExprKind::Match(m, arms.into_iter()
                                        .filter_map(|a| folder.configure(a))
                                        .collect())
                }
                _ => node
            },
            span: span,
            attrs: attrs,
        }, folder)
    })
}

fn is_cfg(attr: &ast::Attribute) -> bool {
    attr.check_name("cfg")
}

pub trait CfgDiag {
    fn emit_error<F>(&mut self, f: F) where F: FnMut(&Handler);
    fn flag_gated<F>(&mut self, f: F) where F: FnMut(&mut Vec<GatedCfgAttr>);
}

pub struct CfgDiagReal<'a, 'b> {
    pub diag: &'a Handler,
    pub feature_gated_cfgs: &'b mut Vec<GatedCfgAttr>,
}

impl<'a, 'b> CfgDiag for CfgDiagReal<'a, 'b> {
    fn emit_error<F>(&mut self, mut f: F) where F: FnMut(&Handler) {
        f(self.diag)
    }
    fn flag_gated<F>(&mut self, mut f: F) where F: FnMut(&mut Vec<GatedCfgAttr>) {
        f(self.feature_gated_cfgs)
    }
}
<|endoftext|>


<commit_before><commit_msg>k20::uart: Port to ioregs!<commit_after><|endoftext|>


<commit_before><commit_msg>Add idempotency test for issue 5399<commit_after>// rustfmt-max_width: 140

impl NotificationRepository {
    fn set_status_changed(
        &self,
        repo_tx_conn: &RepoTxConn,
        rid: &RoutableId,
        changed_at: NaiveDateTime,
    ) -> NukeResult<Option<NotificationStatus>> {
        repo_tx_conn.run(move |conn| {
            let res = diesel::update(client_notification::table)
                .filter(
                    client_notification::routable_id.eq(DieselRoutableId(rid.clone())).and(
                        client_notification::changed_at
                            .lt(changed_at)
                            .or(client_notification::changed_at.is_null()),
                    ),
                )
                .set(client_notification::changed_at.eq(changed_at))
                .returning((
                    client_notification::id,
                    client_notification::changed_at,
                    client_notification::polled_at,
                    client_notification::notified_at,
                ))
                .get_result::<(Uuid, Option<NaiveDateTime>, Option<NaiveDateTime>, Option<NaiveDateTime>)>(conn)
                .optional()?;

            match res {
                Some(row) => {
                    let client_id = client_contract::table
                        .inner_join(client_notification::table)
                        .filter(client_notification::id.eq(row.0))
                        .select(client_contract::client_id)
                        .get_result::<Uuid>(conn)?;

                    Ok(Some(NotificationStatus {
                        client_id: client_id.into(),
                        changed_at: row.1,
                        polled_at: row.2,
                        notified_at: row.3,
                    }))
                }
                None => Ok(None),
            }
        })
    }
}
<|endoftext|>


<commit_before><commit_msg>Make ToLua require a sized type.<commit_after><|endoftext|>


<commit_before>//! Event handling (mouse, keyboard, controller, touch screen, etc.)
//!
//! See [`Event`](enum.Event.html) for more information.
//!
//! # Unstable
//!
//! There are still many unanswered questions about the design of the events API in the turtle
//! crate. This module may change or be completely removed in the future. There will definitely
//! be *some* events API in the future, but it may end up looking different than it does today.

use serde::{Serialize, Deserialize};
use glutin::{
    dpi::{LogicalSize, PhysicalPosition},
    event::{self as glutin_event, WindowEvent, KeyboardInput},
};

use crate::Point;

/// Possible events returned from [`Drawing::poll_event()`](../struct.Drawing.html#method.poll_event).
///
/// Events are used to make programs more interactive. See that method's documentation for more
/// information about how to use events.
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Event {
    /// Sent when a keyboard key is pressed or released
    Key(Key, PressedState),

    /// Sent when a mouse button is pressed or released
    MouseButton(MouseButton, PressedState),

    /// Sent when the mouse is moving. Only sent when the mouse is over the window.
    /// `x` and `y` represent the new coordinates of where the mouse is currently.
    ///
    /// Coordinates are relative to the center of the window.
    MouseMove(Point),

    /// Sent when the mouse is scrolled. Only sent when the mouse is over the window.
    /// `x` and `y` are in scroll ticks.
    MouseScroll { x: f64, y: f64 },

    /// Sent when the window gets resized
    WindowResized { width: u32, height: u32 },

    /// Sent when the window focus changes
    ///
    /// The boolean value is true if the window is in focus.
    WindowFocused(bool),
    /// Sent when the cursor enters or leaves the window
    ///
    /// The boolean value is true if the cursor entered the window, and false if it left.
    WindowCursor(bool),

    /// Sent when the window is closed
    WindowClosed,
}

impl Event {
    /// Returns `None` if the input event is not a supported variant of `Event`
    #[cfg_attr(any(feature = "test", test), allow(dead_code))]
    pub(crate) fn from_window_event(
        event: WindowEvent,
        scale_factor: f64,
        to_logical: impl FnOnce(PhysicalPosition<f64>) -> Point,
    ) -> Option<Self> {
        match event {
            WindowEvent::Resized(size) => {
                let LogicalSize {width, height} = size.to_logical(scale_factor);
                Some(Event::WindowResized {width, height})
            },

            WindowEvent::KeyboardInput {input: KeyboardInput {state, virtual_keycode, ..}, ..} => {
                Some(Event::Key(
                    Key::from_keycode(virtual_keycode?)?,
                    PressedState::from_state(state),
                ))
            },
            WindowEvent::CursorEntered {..} => Some(Event::WindowCursor(true)),
            WindowEvent::CursorLeft {..} => Some(Event::WindowCursor(false)),
            WindowEvent::CursorMoved {position, ..} => {
                Some(Event::MouseMove(to_logical(position)))
            },
            WindowEvent::MouseInput {state, button, ..} => Some(Event::MouseButton(
                MouseButton::from_button(button)?,
                PressedState::from_state(state),
            )),
            WindowEvent::Focused(focused) => Some(Event::WindowFocused(focused)),
            WindowEvent::Destroyed => Some(Event::WindowClosed),

            WindowEvent::Moved(_) |
            WindowEvent::CloseRequested |
            WindowEvent::DroppedFile(_) |
            WindowEvent::HoveredFile(_) |
            WindowEvent::HoveredFileCancelled |
            WindowEvent::ReceivedCharacter(_) |
            WindowEvent::ModifiersChanged(_) |
            WindowEvent::MouseWheel {..} |
            WindowEvent::TouchpadPressure {..} |
            WindowEvent::AxisMotion {..} |
            WindowEvent::Touch(_) |
            WindowEvent::ScaleFactorChanged {..} |
            WindowEvent::ThemeChanged(_) => None, // Not supported
        }
    }
}

//TODO: Documentation
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum PressedState {
    Pressed,
    Released,
}

impl PressedState {
    #[cfg_attr(any(feature = "test", test), allow(dead_code))]
    fn from_state(state: glutin_event::ElementState) -> PressedState {
        match state {
            glutin_event::ElementState::Pressed => PressedState::Pressed,
            glutin_event::ElementState::Released => PressedState::Released,
        }
    }
}

//TODO: Documentation
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum Key {
    /// The '1' key over the letters.
    Num1,
    /// The '2' key over the letters.
    Num2,
    /// The '3' key over the letters.
    Num3,
    /// The '4' key over the letters.
    Num4,
    /// The '5' key over the letters.
    Num5,
    /// The '6' key over the letters.
    Num6,
    /// The '7' key over the letters.
    Num7,
    /// The '8' key over the letters.
    Num8,
    /// The '9' key over the letters.
    Num9,
    /// The '0' key over the letters.
    Num0,

    A,
    B,
    C,
    D,
    E,
    F,
    G,
    H,
    I,
    J,
    K,
    L,
    M,
    N,
    O,
    P,
    Q,
    R,
    S,
    T,
    U,
    V,
    W,
    X,
    Y,
    Z,

    /// The Escape key, next to F1
    Esc,

    F1,
    F2,
    F3,
    F4,
    F5,
    F6,
    F7,
    F8,
    F9,
    F10,
    F11,
    F12,
    F13,
    F14,
    F15,
    F16,
    F17,
    F18,
    F19,
    F20,
    F21,
    F22,
    F23,
    F24,

    Home,
    Delete,
    End,
    /// The PageDown (PgDn) key
    PageDown,
    /// The PageUp (PgUp) key
    PageUp,
    /// The backspace key, right over Enter/Return
    Backspace,
    /// The Enter/Return key, under Backspace
    Return,
    /// The spacebar key
    Space,

    /// The up arrow key
    UpArrow,
    /// The left arrow key
    LeftArrow,
    /// The right arrow key
    RightArrow,
    /// The down arrow key
    DownArrow,

    Numpad0,
    Numpad1,
    Numpad2,
    Numpad3,
    Numpad4,
    Numpad5,
    Numpad6,
    Numpad7,
    Numpad8,
    Numpad9,
    NumpadComma,
    NumpadEnter,
    NumpadEquals,

    Apostrophe,
    At,
    Backslash,
    Backtick,
    Colon,
    Comma,
    Decimal,
    Divide,
    Equals,
    Minus,
    Multiply,
    Period,
    Plus,
    /// The left bracket `[` key
    LeftBracket,
    /// The left bracket `]` key
    RightBracket,
    Semicolon,
    Slash,
    Tab,
}

impl Key {
    #[cfg_attr(any(feature = "test", test), allow(dead_code))]
    fn from_keycode(key: glutin_event::VirtualKeyCode) -> Option<Self> {
        use glutin_event::VirtualKeyCode::*;
        #[deny(unreachable_patterns, unused_variables)]
        Some(match key {
            Key1 => Key::Num1,
            Key2 => Key::Num2,
            Key3 => Key::Num3,
            Key4 => Key::Num4,
            Key5 => Key::Num5,
            Key6 => Key::Num6,
            Key7 => Key::Num7,
            Key8 => Key::Num8,
            Key9 => Key::Num9,
            Key0 => Key::Num0,

            A => Key::A,
            B => Key::B,
            C => Key::C,
            D => Key::D,
            E => Key::E,
            F => Key::F,
            G => Key::G,
            H => Key::H,
            I => Key::I,
            J => Key::J,
            K => Key::K,
            L => Key::L,
            M => Key::M,
            N => Key::N,
            O => Key::O,
            P => Key::P,
            Q => Key::Q,
            R => Key::R,
            S => Key::S,
            T => Key::T,
            U => Key::U,
            V => Key::V,
            W => Key::W,
            X => Key::X,
            Y => Key::Y,
            Z => Key::Z,

            Escape => Key::Esc,

            F1 => Key::F1,
            F2 => Key::F2,
            F3 => Key::F3,
            F4 => Key::F4,
            F5 => Key::F5,
            F6 => Key::F6,
            F7 => Key::F7,
            F8 => Key::F8,
            F9 => Key::F9,
            F10 => Key::F10,
            F11 => Key::F11,
            F12 => Key::F12,
            F13 => Key::F13,
            F14 => Key::F14,
            F15 => Key::F15,
            F16 => Key::F16,
            F17 => Key::F17,
            F18 => Key::F18,
            F19 => Key::F19,
            F20 => Key::F20,
            F21 => Key::F21,
            F22 => Key::F22,
            F23 => Key::F23,
            F24 => Key::F24,

            Home => Key::Home,
            Delete => Key::Delete,
            End => Key::End,
            PageDown => Key::PageDown,
            PageUp => Key::PageUp,
            Back => Key::Backspace,
            Return => Key::Return,
            Space => Key::Space,

            Left => Key::LeftArrow,
            Up => Key::UpArrow,
            Right => Key::RightArrow,
            Down => Key::DownArrow,

            Numpad0 => Key::Numpad0,
            Numpad1 => Key::Numpad1,
            Numpad2 => Key::Numpad2,
            Numpad3 => Key::Numpad3,
            Numpad4 => Key::Numpad4,
            Numpad5 => Key::Numpad5,
            Numpad6 => Key::Numpad6,
            Numpad7 => Key::Numpad7,
            Numpad8 => Key::Numpad8,
            Numpad9 => Key::Numpad9,

            Apostrophe => Key::Apostrophe,
            At => Key::At,
            Backslash => Key::Backslash,
            Colon => Key::Colon,
            Comma => Key::Comma,
            Equals => Key::Equals,
            Grave => Key::Backtick,
            LBracket => Key::LeftBracket,
            NumpadAdd | Plus => Key::Plus,
            NumpadComma => Key::NumpadComma,
            NumpadDecimal => Key::Decimal,
            NumpadDivide => Key::Divide,
            NumpadEnter => Key::NumpadEnter,
            NumpadEquals => Key::NumpadEquals,
            NumpadMultiply | Asterisk => Key::Multiply,
            NumpadSubtract | Minus => Key::Minus,
            Period => Key::Period,
            RBracket => Key::RightBracket,
            Semicolon => Key::Semicolon,
            Slash => Key::Slash,
            Tab => Key::Tab,

            // Unsupported keys (could be changed in the future)
            Snapshot |
            Scroll |
            Pause |
            Insert |
            Compose |
            Caret |
            Numlock |
            AbntC1 |
            AbntC2 |
            Apps |
            Ax |
            Calculator |
            Capital |
            Convert |
            Kana |
            Kanji |
            LAlt |
            LControl |
            LShift |
            LWin |
            Mail |
            MediaSelect |
            MediaStop |
            Mute |
            MyComputer |
            NavigateForward |
            NavigateBackward |
            NextTrack |
            NoConvert |
            OEM102 |
            PlayPause |
            Power |
            PrevTrack |
            RAlt |
            RControl |
            RShift |
            RWin |
            Sleep |
            Stop |
            Sysrq |
            Underline |
            Unlabeled |
            VolumeDown |
            VolumeUp |
            Wake |
            WebBack |
            WebFavorites |
            WebForward |
            WebHome |
            WebRefresh |
            WebSearch |
            WebStop |
            Yen |
            Copy |
            Paste |
            Cut => return None,
        })
    }
}

//TODO: Documentation
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum MouseButton {
    /// The left mouse button
    LeftButton,
    /// The middle mouse button
    MiddleButton,
    /// The right mouse button
    RightButton,
}

impl MouseButton {
    #[cfg_attr(any(feature = "test", test), allow(dead_code))]
    fn from_button(button: glutin_event::MouseButton) -> Option<Self> {
        use glutin_event::MouseButton::*;
        #[deny(unreachable_patterns, unused_variables)]
        match button {
            Left => Some(MouseButton::LeftButton),
            Middle => Some(MouseButton::MiddleButton),
            Right => Some(MouseButton::RightButton),
            Other(_) => None,
        }
    }
}
<commit_msg>Fix over->above, under->below in doc comments<commit_after>//! Event handling (mouse, keyboard, controller, touch screen, etc.)
//!
//! See [`Event`](enum.Event.html) for more information.
//!
//! # Unstable
//!
//! There are still many unanswered questions about the design of the events API in the turtle
//! crate. This module may change or be completely removed in the future. There will definitely
//! be *some* events API in the future, but it may end up looking different than it does today.

use serde::{Serialize, Deserialize};
use glutin::{
    dpi::{LogicalSize, PhysicalPosition},
    event::{self as glutin_event, WindowEvent, KeyboardInput},
};

use crate::Point;

/// Possible events returned from [`Drawing::poll_event()`](../struct.Drawing.html#method.poll_event).
///
/// Events are used to make programs more interactive. See that method's documentation for more
/// information about how to use events.
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Event {
    /// Sent when a keyboard key is pressed or released
    Key(Key, PressedState),

    /// Sent when a mouse button is pressed or released
    MouseButton(MouseButton, PressedState),

    /// Sent when the mouse is moving. Only sent when the mouse is over the window.
    /// `x` and `y` represent the new coordinates of where the mouse is currently.
    ///
    /// Coordinates are relative to the center of the window.
    MouseMove(Point),

    /// Sent when the mouse is scrolled. Only sent when the mouse is over the window.
    /// `x` and `y` are in scroll ticks.
    MouseScroll { x: f64, y: f64 },

    /// Sent when the window gets resized
    WindowResized { width: u32, height: u32 },

    /// Sent when the window focus changes
    ///
    /// The boolean value is true if the window is in focus.
    WindowFocused(bool),
    /// Sent when the cursor enters or leaves the window
    ///
    /// The boolean value is true if the cursor entered the window, and false if it left.
    WindowCursor(bool),

    /// Sent when the window is closed
    WindowClosed,
}

impl Event {
    /// Returns `None` if the input event is not a supported variant of `Event`
    #[cfg_attr(any(feature = "test", test), allow(dead_code))]
    pub(crate) fn from_window_event(
        event: WindowEvent,
        scale_factor: f64,
        to_logical: impl FnOnce(PhysicalPosition<f64>) -> Point,
    ) -> Option<Self> {
        match event {
            WindowEvent::Resized(size) => {
                let LogicalSize {width, height} = size.to_logical(scale_factor);
                Some(Event::WindowResized {width, height})
            },

            WindowEvent::KeyboardInput {input: KeyboardInput {state, virtual_keycode, ..}, ..} => {
                Some(Event::Key(
                    Key::from_keycode(virtual_keycode?)?,
                    PressedState::from_state(state),
                ))
            },
            WindowEvent::CursorEntered {..} => Some(Event::WindowCursor(true)),
            WindowEvent::CursorLeft {..} => Some(Event::WindowCursor(false)),
            WindowEvent::CursorMoved {position, ..} => {
                Some(Event::MouseMove(to_logical(position)))
            },
            WindowEvent::MouseInput {state, button, ..} => Some(Event::MouseButton(
                MouseButton::from_button(button)?,
                PressedState::from_state(state),
            )),
            WindowEvent::Focused(focused) => Some(Event::WindowFocused(focused)),
            WindowEvent::Destroyed => Some(Event::WindowClosed),

            WindowEvent::Moved(_) |
            WindowEvent::CloseRequested |
            WindowEvent::DroppedFile(_) |
            WindowEvent::HoveredFile(_) |
            WindowEvent::HoveredFileCancelled |
            WindowEvent::ReceivedCharacter(_) |
            WindowEvent::ModifiersChanged(_) |
            WindowEvent::MouseWheel {..} |
            WindowEvent::TouchpadPressure {..} |
            WindowEvent::AxisMotion {..} |
            WindowEvent::Touch(_) |
            WindowEvent::ScaleFactorChanged {..} |
            WindowEvent::ThemeChanged(_) => None, // Not supported
        }
    }
}

//TODO: Documentation
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum PressedState {
    Pressed,
    Released,
}

impl PressedState {
    #[cfg_attr(any(feature = "test", test), allow(dead_code))]
    fn from_state(state: glutin_event::ElementState) -> PressedState {
        match state {
            glutin_event::ElementState::Pressed => PressedState::Pressed,
            glutin_event::ElementState::Released => PressedState::Released,
        }
    }
}

//TODO: Documentation
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum Key {
    /// The '1' key above the letters.
    Num1,
    /// The '2' key above the letters.
    Num2,
    /// The '3' key above the letters.
    Num3,
    /// The '4' key above the letters.
    Num4,
    /// The '5' key above the letters.
    Num5,
    /// The '6' key above the letters.
    Num6,
    /// The '7' key above the letters.
    Num7,
    /// The '8' key above the letters.
    Num8,
    /// The '9' key above the letters.
    Num9,
    /// The '0' key above the letters.
    Num0,

    A,
    B,
    C,
    D,
    E,
    F,
    G,
    H,
    I,
    J,
    K,
    L,
    M,
    N,
    O,
    P,
    Q,
    R,
    S,
    T,
    U,
    V,
    W,
    X,
    Y,
    Z,

    /// The Escape key, next to F1
    Esc,

    F1,
    F2,
    F3,
    F4,
    F5,
    F6,
    F7,
    F8,
    F9,
    F10,
    F11,
    F12,
    F13,
    F14,
    F15,
    F16,
    F17,
    F18,
    F19,
    F20,
    F21,
    F22,
    F23,
    F24,

    Home,
    Delete,
    End,
    /// The PageDown (PgDn) key
    PageDown,
    /// The PageUp (PgUp) key
    PageUp,
    /// The backspace key, right above Enter/Return
    Backspace,
    /// The Enter/Return key, below Backspace
    Return,
    /// The spacebar key
    Space,

    /// The up arrow key
    UpArrow,
    /// The left arrow key
    LeftArrow,
    /// The right arrow key
    RightArrow,
    /// The down arrow key
    DownArrow,

    Numpad0,
    Numpad1,
    Numpad2,
    Numpad3,
    Numpad4,
    Numpad5,
    Numpad6,
    Numpad7,
    Numpad8,
    Numpad9,
    NumpadComma,
    NumpadEnter,
    NumpadEquals,

    Apostrophe,
    At,
    Backslash,
    Backtick,
    Colon,
    Comma,
    Decimal,
    Divide,
    Equals,
    Minus,
    Multiply,
    Period,
    Plus,
    /// The left bracket `[` key
    LeftBracket,
    /// The left bracket `]` key
    RightBracket,
    Semicolon,
    Slash,
    Tab,
}

impl Key {
    #[cfg_attr(any(feature = "test", test), allow(dead_code))]
    fn from_keycode(key: glutin_event::VirtualKeyCode) -> Option<Self> {
        use glutin_event::VirtualKeyCode::*;
        #[deny(unreachable_patterns, unused_variables)]
        Some(match key {
            Key1 => Key::Num1,
            Key2 => Key::Num2,
            Key3 => Key::Num3,
            Key4 => Key::Num4,
            Key5 => Key::Num5,
            Key6 => Key::Num6,
            Key7 => Key::Num7,
            Key8 => Key::Num8,
            Key9 => Key::Num9,
            Key0 => Key::Num0,

            A => Key::A,
            B => Key::B,
            C => Key::C,
            D => Key::D,
            E => Key::E,
            F => Key::F,
            G => Key::G,
            H => Key::H,
            I => Key::I,
            J => Key::J,
            K => Key::K,
            L => Key::L,
            M => Key::M,
            N => Key::N,
            O => Key::O,
            P => Key::P,
            Q => Key::Q,
            R => Key::R,
            S => Key::S,
            T => Key::T,
            U => Key::U,
            V => Key::V,
            W => Key::W,
            X => Key::X,
            Y => Key::Y,
            Z => Key::Z,

            Escape => Key::Esc,

            F1 => Key::F1,
            F2 => Key::F2,
            F3 => Key::F3,
            F4 => Key::F4,
            F5 => Key::F5,
            F6 => Key::F6,
            F7 => Key::F7,
            F8 => Key::F8,
            F9 => Key::F9,
            F10 => Key::F10,
            F11 => Key::F11,
            F12 => Key::F12,
            F13 => Key::F13,
            F14 => Key::F14,
            F15 => Key::F15,
            F16 => Key::F16,
            F17 => Key::F17,
            F18 => Key::F18,
            F19 => Key::F19,
            F20 => Key::F20,
            F21 => Key::F21,
            F22 => Key::F22,
            F23 => Key::F23,
            F24 => Key::F24,

            Home => Key::Home,
            Delete => Key::Delete,
            End => Key::End,
            PageDown => Key::PageDown,
            PageUp => Key::PageUp,
            Back => Key::Backspace,
            Return => Key::Return,
            Space => Key::Space,

            Left => Key::LeftArrow,
            Up => Key::UpArrow,
            Right => Key::RightArrow,
            Down => Key::DownArrow,

            Numpad0 => Key::Numpad0,
            Numpad1 => Key::Numpad1,
            Numpad2 => Key::Numpad2,
            Numpad3 => Key::Numpad3,
            Numpad4 => Key::Numpad4,
            Numpad5 => Key::Numpad5,
            Numpad6 => Key::Numpad6,
            Numpad7 => Key::Numpad7,
            Numpad8 => Key::Numpad8,
            Numpad9 => Key::Numpad9,

            Apostrophe => Key::Apostrophe,
            At => Key::At,
            Backslash => Key::Backslash,
            Colon => Key::Colon,
            Comma => Key::Comma,
            Equals => Key::Equals,
            Grave => Key::Backtick,
            LBracket => Key::LeftBracket,
            NumpadAdd | Plus => Key::Plus,
            NumpadComma => Key::NumpadComma,
            NumpadDecimal => Key::Decimal,
            NumpadDivide => Key::Divide,
            NumpadEnter => Key::NumpadEnter,
            NumpadEquals => Key::NumpadEquals,
            NumpadMultiply | Asterisk => Key::Multiply,
            NumpadSubtract | Minus => Key::Minus,
            Period => Key::Period,
            RBracket => Key::RightBracket,
            Semicolon => Key::Semicolon,
            Slash => Key::Slash,
            Tab => Key::Tab,

            // Unsupported keys (could be changed in the future)
            Snapshot |
            Scroll |
            Pause |
            Insert |
            Compose |
            Caret |
            Numlock |
            AbntC1 |
            AbntC2 |
            Apps |
            Ax |
            Calculator |
            Capital |
            Convert |
            Kana |
            Kanji |
            LAlt |
            LControl |
            LShift |
            LWin |
            Mail |
            MediaSelect |
            MediaStop |
            Mute |
            MyComputer |
            NavigateForward |
            NavigateBackward |
            NextTrack |
            NoConvert |
            OEM102 |
            PlayPause |
            Power |
            PrevTrack |
            RAlt |
            RControl |
            RShift |
            RWin |
            Sleep |
            Stop |
            Sysrq |
            Underline |
            Unlabeled |
            VolumeDown |
            VolumeUp |
            Wake |
            WebBack |
            WebFavorites |
            WebForward |
            WebHome |
            WebRefresh |
            WebSearch |
            WebStop |
            Yen |
            Copy |
            Paste |
            Cut => return None,
        })
    }
}

//TODO: Documentation
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum MouseButton {
    /// The left mouse button
    LeftButton,
    /// The middle mouse button
    MiddleButton,
    /// The right mouse button
    RightButton,
}

impl MouseButton {
    #[cfg_attr(any(feature = "test", test), allow(dead_code))]
    fn from_button(button: glutin_event::MouseButton) -> Option<Self> {
        use glutin_event::MouseButton::*;
        #[deny(unreachable_patterns, unused_variables)]
        match button {
            Left => Some(MouseButton::LeftButton),
            Middle => Some(MouseButton::MiddleButton),
            Right => Some(MouseButton::RightButton),
            Other(_) => None,
        }
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;

use regex::Regex;

pub mod id;
pub mod id_type;
pub mod header;
pub mod hash;

use module::Module;
use storage::file::id::*;
use storage::file::id_type::FileIDType;
use storage::file::hash::FileHash;
use super::parser::{FileHeaderParser, Parser, ParserError};

use self::header::spec::*;
use self::header::data::*;

/*
 * Internal abstract view on a file. Does not exist on the FS and is just kept
 * internally until it is written to disk.
 */
pub struct File {
    pub owning_module_name  : &'static str,
    pub header              : FileHeaderData,
    pub data                : String,
    pub id                  : FileID,
}

impl File {

    pub fn owner_name(&self) -> &'static str {
        self.owning_module_name
    }

    pub fn header(&self) -> &FileHeaderData {
        &self.header
    }

    pub fn data(&self) -> &String {
        &self.data
    }

    pub fn contents(&self) -> (&FileHeaderData, &String) {
        (self.header(), self.data())
    }

    pub fn id(&self) -> &FileID {
        &self.id
    }

    pub fn matches_with(&self, r: &Regex) -> bool {
        r.is_match(&self.data[..]) || self.header.matches_with(r)
    }

}

impl Display for File {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt,
"[File] Owner : '{:?}'
        FileID: '{:?}'
        Header: '{:?}'
        Data  : '{:?}'",
               self.owning_module_name,
               self.header,
               self.data,
               self.id);
        Ok(())
    }

}

impl Debug for File {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt,
"[File] Owner : '{:?}'
        FileID: '{:?}'
        Header: '{:?}'
        Data  : '{:?}'",
               self.owning_module_name,
               self.header,
               self.data,
               self.id);
        Ok(())
    }

}

#[cfg(test)]
mod test {
    // we use the JSON parser here, so we can generate FileHeaderData
    use storage::json::parser::JsonHeaderParser;
    use super::match_header_spec;
    use storage::parser::{FileHeaderParser, ParserError};
    use storage::file::FileHeaderData as FHD;
    use storage::file::FileHeaderSpec as FHS;

    #[test]
    fn test_spec_matching() {
        let text = String::from("{\"a\": 1, \"b\": -2}");
        let spec = FHS::Map {
            keys: vec![
                FHS::Key {
                    name: String::from("a"),
                    value_type: Box::new(FHS::UInteger)
                },
                FHS::Key {
                    name: String::from("b"),
                    value_type: Box::new(FHS::Integer)
                }
            ]
        };

        let parser  = JsonHeaderParser::new(Some(spec.clone()));
        let datares = parser.read(Some(text.clone()));
        assert!(datares.is_ok(), "Text could not be parsed: '{}'", text);
        let data = datares.unwrap();

        let matchres = match_header_spec(&spec, &data);
        assert!(matchres.is_none(), "Matching returns error: {:?}", matchres);
    }
}

<commit_msg>Fix: Debug for File implementation<commit_after>use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;

use regex::Regex;

pub mod id;
pub mod id_type;
pub mod header;
pub mod hash;

use module::Module;
use storage::file::id::*;
use storage::file::id_type::FileIDType;
use storage::file::hash::FileHash;
use super::parser::{FileHeaderParser, Parser, ParserError};

use self::header::spec::*;
use self::header::data::*;

/*
 * Internal abstract view on a file. Does not exist on the FS and is just kept
 * internally until it is written to disk.
 */
pub struct File {
    pub owning_module_name  : &'static str,
    pub header              : FileHeaderData,
    pub data                : String,
    pub id                  : FileID,
}

impl File {

    pub fn owner_name(&self) -> &'static str {
        self.owning_module_name
    }

    pub fn header(&self) -> &FileHeaderData {
        &self.header
    }

    pub fn data(&self) -> &String {
        &self.data
    }

    pub fn contents(&self) -> (&FileHeaderData, &String) {
        (self.header(), self.data())
    }

    pub fn id(&self) -> &FileID {
        &self.id
    }

    pub fn matches_with(&self, r: &Regex) -> bool {
        r.is_match(&self.data[..]) || self.header.matches_with(r)
    }

}

impl Display for File {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt,
"[File] Owner : '{:?}'
        FileID: '{:?}'
        Header: '{:?}'
        Data  : '{:?}'",
               self.owning_module_name,
               self.header,
               self.data,
               self.id);
        Ok(())
    }

}

impl Debug for File {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt,
"[File] Owner : '{:?}'
        FileID: '{:?}'
        Header: '{:?}'
        Data  : '{:?}'",
               self.owning_module_name,
               self.id,
               self.header,
               self.data);
        Ok(())
    }

}

#[cfg(test)]
mod test {
    // we use the JSON parser here, so we can generate FileHeaderData
    use storage::json::parser::JsonHeaderParser;
    use super::match_header_spec;
    use storage::parser::{FileHeaderParser, ParserError};
    use storage::file::FileHeaderData as FHD;
    use storage::file::FileHeaderSpec as FHS;

    #[test]
    fn test_spec_matching() {
        let text = String::from("{\"a\": 1, \"b\": -2}");
        let spec = FHS::Map {
            keys: vec![
                FHS::Key {
                    name: String::from("a"),
                    value_type: Box::new(FHS::UInteger)
                },
                FHS::Key {
                    name: String::from("b"),
                    value_type: Box::new(FHS::Integer)
                }
            ]
        };

        let parser  = JsonHeaderParser::new(Some(spec.clone()));
        let datares = parser.read(Some(text.clone()));
        assert!(datares.is_ok(), "Text could not be parsed: '{}'", text);
        let data = datares.unwrap();

        let matchres = match_header_spec(&spec, &data);
        assert!(matchres.is_none(), "Matching returns error: {:?}", matchres);
    }
}

<|endoftext|>


<commit_before>use redox::*;
use redox::time::*;

pub struct FileManager {
    folder_icon: BMPFile,
    audio_icon: BMPFile,
    bin_icon: BMPFile,
    image_icon: BMPFile,
    source_icon: BMPFile,
    script_icon: BMPFile,
    text_icon: BMPFile,
    file_icon: BMPFile,
    files: Vec<String>,
    selected: isize,
    last_mouse_event: MouseEvent,
    click_time: Duration,
}

fn load_icon(path: &str) -> BMPFile {
    let mut resource = File::open(&("file:///ui/mimetypes/".to_string() + path + ".bmp"));

    let mut vec: Vec<u8> = Vec::new();
    resource.read_to_end(&mut vec);

    BMPFile::from_data(&vec)
}

impl FileManager {
    pub fn new() -> Self {
        FileManager {
            folder_icon: load_icon("inode-directory"),
            audio_icon: load_icon("audio-x-wav"),
            bin_icon: load_icon("application-x-executable"),
            image_icon: load_icon("image-x-generic"),
            source_icon: load_icon("text-x-makefile"),
            script_icon: load_icon("text-x-script"),
            text_icon: load_icon("text-x-generic"),
            file_icon: load_icon("unknown"),
            files: Vec::new(),
            selected: -1,
            last_mouse_event: MouseEvent {
                x: 0,
                y: 0,
                left_button: false,
                middle_button: false,
                right_button: false,
            }
            click_time: Duration::new(0, 0),
        }
    }

    fn draw_content(&mut self, window: &mut Window) {
        window.set([255, 255, 255, 255]);

        let mut i = 0;
        let mut row = 0;
        for string in self.files.iter() {
            if i == self.selected {
                let width = window.width();
                window.rect(0, 32 * row as isize, width, 32, [224, 224, 224, 255]);
            }

            if string.ends_with('/') {
                window.image(0,
                             32 * row as isize,
                             self.folder_icon.width(),
                             self.folder_icon.height(),
                             self.folder_icon.as_slice());
            } else if string.ends_with(".wav") {
                window.image(0,
                             32 * row as isize,
                             self.audio_icon.width(),
                             self.audio_icon.height(),
                             self.audio_icon.as_slice());
            } else if string.ends_with(".bin") {
                window.image(0,
                             32 * row as isize,
                             self.bin_icon.width(),
                             self.bin_icon.height(),
                             self.bin_icon.as_slice());
            } else if string.ends_with(".bmp") {
                window.image(0,
                             32 * row as isize,
                             self.image_icon.width(),
                             self.image_icon.height(),
                             self.image_icon.as_slice());
            } else if string.ends_with(".rs") || string.ends_with(".asm") || string.ends_with(".list") {
                window.image(0,
                             32 * row as isize,
                             self.source_icon.width(),
                             self.source_icon.height(),
                             self.source_icon.as_slice());
            } else if string.ends_with(".sh") || string.ends_with(".lua") {
                window.image(0,
                             32 * row as isize,
                             self.script_icon.width(),
                             self.script_icon.height(),
                             self.script_icon.as_slice());
            } else if string.ends_with(".md") || string.ends_with(".txt") {
                window.image(0,
                             32 * row as isize,
                             self.text_icon.width(),
                             self.text_icon.height(),
                             self.text_icon.as_slice());
            } else {
                window.image(0,
                             32 * row as isize,
                             self.file_icon.width(),
                             self.file_icon.height(),
                             self.file_icon.as_slice());
            }

            let mut col = 0;
            for c in string.chars() {
                if c == '\n' {
                    col = 0;
                    row += 1;
                } else if c == '\t' {
                    col += 8 - col % 8;
                } else {
                    if col < window.width() / 8 && row < window.height() / 32 {
                        window.char(8 * col as isize + 40,
                                    32 * row as isize + 8,
                                    c,
                                    [0, 0, 0, 255]);
                        col += 1;
                    }
                }
                if col >= window.width() / 8 {
                    col = 0;
                    row += 1;
                }
            }
            row += 1;
            i += 1;
        }

        window.sync();
    }

    fn main(&mut self, path: &str) {
        let mut width = 160;
        let mut height = 0;
        {
            let mut resource = File::open(path);

            let mut vec: Vec<u8> = Vec::new();
            resource.read_to_end(&mut vec);

            for file in unsafe { String::from_utf8_unchecked(vec) }.split('\n') {
                if width < 40 + (file.len() + 1) * 8 {
                    width = 40 + (file.len() + 1) * 8;
                }
                self.files.push(file.to_string());
            }

            if height < self.files.len() * 32 {
                height = self.files.len() * 32;
            }
        }

        let mut window = Window::new((rand() % 400 + 50) as isize,
                                     (rand() % 300 + 50) as isize,
                                     width,
                                     height,
                                     &path);

        self.draw_content(&mut window);

        while let Option::Some(event) = window.poll() {
            match event.to_option() {
                EventOption::Key(key_event) => {
                    if key_event.pressed {
                        match key_event.scancode {
                            K_ESC => break,
                            K_HOME => self.selected = 0,
                            K_UP => if self.selected > 0 {
                                self.selected -= 1;
                            },
                            K_END => self.selected = self.files.len() as isize - 1,
                            K_DOWN => if self.selected < self.files.len() as isize - 1 {
                                self.selected += 1;
                            },
                            _ => match key_event.character {
                                '\0' => (),
                                '\n' => {
                                    if self.selected >= 0 &&
                                       self.selected < self.files.len() as isize {
                                        match self.files.get(self.selected as usize) {
                                            Option::Some(file) => OpenEvent {
                                                url_string: path.to_string() + &file,
                                            }.trigger(),
                                            Option::None => (),
                                        }
                                    }
                                }
                                _ => {
                                    let mut i = 0;
                                    for file in self.files.iter() {
                                        if file.starts_with(key_event.character) {
                                            self.selected = i;
                                            break;
                                        }
                                        i += 1;
                                    }
                                }
                            },
                        }

                        self.draw_content(&mut window);
                    }
                }
                EventOption::Mouse(mouse_event) => {
                    let mut redraw = false;
                    let mut i = 0;
                    let mut row = 0;
                    for file in self.files.iter() {
                        let mut col = 0;
                        for c in file.chars() {
                            if mouse_event.y >= 32 * row as isize &&
                               mouse_event.y < 32 * row as isize + 32 {
                                let click_time = Duration::realtime();
                                if self.selected == i {
                                    if click_time - self.click_time < Duration::new(0, 500 * NANOS_PER_MILLI) {
                                        match self.files.get(self.selected as usize) {
                                            Option::Some(file) => OpenEvent {
                                                url_string: path.to_string() + &file,
                                            }.trigger(),
                                            Option::None => (),
                                        }
                                        self.click_time = Duration::new(0, 0);
                                    }
                                } else {
                                    self.selected = i;
                                    self.click_time = click_time;
                                }
                                redraw = true;
                            }

                            if c == '\n' {
                                col = 0;
                                row += 1;
                            } else if c == '\t' {
                                col += 8 - col % 8;
                            } else {
                                if col < window.width() / 8 && row < window.height() / 32 {
                                    col += 1;
                                }
                            }
                            if col >= window.width() / 8 {
                                col = 0;
                                row += 1;
                            }
                        }
                        row += 1;
                        i += 1;
                    }

                    if redraw {
                        self.draw_content(&mut window);
                    }

                    if mouse_event.left_button
                    self.last_mouse_event = mouse_event;
                }
                _ => (),
            }
        }
    }
}

pub fn main() {
    match args().get(1) {
        Option::Some(arg) => FileManager::new().main(arg),
        Option::None => FileManager::new().main("file:///"),
    }
}
<commit_msg>Double click<commit_after>use redox::*;
use redox::time::*;

pub struct FileManager {
    folder_icon: BMPFile,
    audio_icon: BMPFile,
    bin_icon: BMPFile,
    image_icon: BMPFile,
    source_icon: BMPFile,
    script_icon: BMPFile,
    text_icon: BMPFile,
    file_icon: BMPFile,
    files: Vec<String>,
    selected: isize,
    last_mouse_event: MouseEvent,
    click_time: Duration,
}

fn load_icon(path: &str) -> BMPFile {
    let mut resource = File::open(&("file:///ui/mimetypes/".to_string() + path + ".bmp"));

    let mut vec: Vec<u8> = Vec::new();
    resource.read_to_end(&mut vec);

    BMPFile::from_data(&vec)
}

impl FileManager {
    pub fn new() -> Self {
        FileManager {
            folder_icon: load_icon("inode-directory"),
            audio_icon: load_icon("audio-x-wav"),
            bin_icon: load_icon("application-x-executable"),
            image_icon: load_icon("image-x-generic"),
            source_icon: load_icon("text-x-makefile"),
            script_icon: load_icon("text-x-script"),
            text_icon: load_icon("text-x-generic"),
            file_icon: load_icon("unknown"),
            files: Vec::new(),
            selected: -1,
            last_mouse_event: MouseEvent {
                x: 0,
                y: 0,
                left_button: false,
                middle_button: false,
                right_button: false,
            },
            click_time: Duration::new(0, 0),
        }
    }

    fn draw_content(&mut self, window: &mut Window) {
        window.set([255, 255, 255, 255]);

        let mut i = 0;
        let mut row = 0;
        for string in self.files.iter() {
            if i == self.selected {
                let width = window.width();
                window.rect(0, 32 * row as isize, width, 32, [224, 224, 224, 255]);
            }

            if string.ends_with('/') {
                window.image(0,
                             32 * row as isize,
                             self.folder_icon.width(),
                             self.folder_icon.height(),
                             self.folder_icon.as_slice());
            } else if string.ends_with(".wav") {
                window.image(0,
                             32 * row as isize,
                             self.audio_icon.width(),
                             self.audio_icon.height(),
                             self.audio_icon.as_slice());
            } else if string.ends_with(".bin") {
                window.image(0,
                             32 * row as isize,
                             self.bin_icon.width(),
                             self.bin_icon.height(),
                             self.bin_icon.as_slice());
            } else if string.ends_with(".bmp") {
                window.image(0,
                             32 * row as isize,
                             self.image_icon.width(),
                             self.image_icon.height(),
                             self.image_icon.as_slice());
            } else if string.ends_with(".rs") || string.ends_with(".asm") || string.ends_with(".list") {
                window.image(0,
                             32 * row as isize,
                             self.source_icon.width(),
                             self.source_icon.height(),
                             self.source_icon.as_slice());
            } else if string.ends_with(".sh") || string.ends_with(".lua") {
                window.image(0,
                             32 * row as isize,
                             self.script_icon.width(),
                             self.script_icon.height(),
                             self.script_icon.as_slice());
            } else if string.ends_with(".md") || string.ends_with(".txt") {
                window.image(0,
                             32 * row as isize,
                             self.text_icon.width(),
                             self.text_icon.height(),
                             self.text_icon.as_slice());
            } else {
                window.image(0,
                             32 * row as isize,
                             self.file_icon.width(),
                             self.file_icon.height(),
                             self.file_icon.as_slice());
            }

            let mut col = 0;
            for c in string.chars() {
                if c == '\n' {
                    col = 0;
                    row += 1;
                } else if c == '\t' {
                    col += 8 - col % 8;
                } else {
                    if col < window.width() / 8 && row < window.height() / 32 {
                        window.char(8 * col as isize + 40,
                                    32 * row as isize + 8,
                                    c,
                                    [0, 0, 0, 255]);
                        col += 1;
                    }
                }
                if col >= window.width() / 8 {
                    col = 0;
                    row += 1;
                }
            }
            row += 1;
            i += 1;
        }

        window.sync();
    }

    fn main(&mut self, path: &str) {
        let mut width = 160;
        let mut height = 0;
        {
            let mut resource = File::open(path);

            let mut vec: Vec<u8> = Vec::new();
            resource.read_to_end(&mut vec);

            for file in unsafe { String::from_utf8_unchecked(vec) }.split('\n') {
                if width < 40 + (file.len() + 1) * 8 {
                    width = 40 + (file.len() + 1) * 8;
                }
                self.files.push(file.to_string());
            }

            if height < self.files.len() * 32 {
                height = self.files.len() * 32;
            }
        }

        let mut window = Window::new((rand() % 400 + 50) as isize,
                                     (rand() % 300 + 50) as isize,
                                     width,
                                     height,
                                     &path);

        self.draw_content(&mut window);

        while let Option::Some(event) = window.poll() {
            match event.to_option() {
                EventOption::Key(key_event) => {
                    if key_event.pressed {
                        match key_event.scancode {
                            K_ESC => break,
                            K_HOME => self.selected = 0,
                            K_UP => if self.selected > 0 {
                                self.selected -= 1;
                            },
                            K_END => self.selected = self.files.len() as isize - 1,
                            K_DOWN => if self.selected < self.files.len() as isize - 1 {
                                self.selected += 1;
                            },
                            _ => match key_event.character {
                                '\0' => (),
                                '\n' => {
                                    if self.selected >= 0 &&
                                       self.selected < self.files.len() as isize {
                                        match self.files.get(self.selected as usize) {
                                            Option::Some(file) => OpenEvent {
                                                url_string: path.to_string() + &file,
                                            }.trigger(),
                                            Option::None => (),
                                        }
                                    }
                                }
                                _ => {
                                    let mut i = 0;
                                    for file in self.files.iter() {
                                        if file.starts_with(key_event.character) {
                                            self.selected = i;
                                            break;
                                        }
                                        i += 1;
                                    }
                                }
                            },
                        }

                        self.draw_content(&mut window);
                    }
                }
                EventOption::Mouse(mouse_event) => {
                    let mut redraw = false;
                    let mut i = 0;
                    let mut row = 0;
                    for file in self.files.iter() {
                        let mut col = 0;
                        for c in file.chars() {
                            if mouse_event.y >= 32 * row as isize &&
                               mouse_event.y < 32 * row as isize + 32 {
                                self.selected = i;
                                redraw = true;
                            }

                            if c == '\n' {
                                col = 0;
                                row += 1;
                            } else if c == '\t' {
                                col += 8 - col % 8;
                            } else {
                                if col < window.width() / 8 && row < window.height() / 32 {
                                    col += 1;
                                }
                            }
                            if col >= window.width() / 8 {
                                col = 0;
                                row += 1;
                            }
                        }
                        row += 1;
                        i += 1;
                    }

                    if redraw {
                        self.draw_content(&mut window);
                    }

                    //Check for double click
                    if mouse_event.left_button {
                        let click_time = Duration::realtime();

                        if click_time - self.click_time < Duration::new(0, 500 * NANOS_PER_MILLI)
                            && (self.last_mouse_event.x - mouse_event.x).abs() <= 4
                            && (self.last_mouse_event.y - mouse_event.y).abs() <= 4 {
                            if self.selected >= 0 && self.selected < self.files.len() as isize {
                                match self.files.get(self.selected as usize) {
                                    Option::Some(file) => OpenEvent {
                                        url_string: path.to_string() + &file,
                                    }.trigger(),
                                    Option::None => (),
                                }
                            }
                            self.click_time = Duration::new(0, 0);
                        } else {
                            self.click_time = click_time;
                        }
                    }
                    self.last_mouse_event = mouse_event;
                }
                _ => (),
            }
        }
    }
}

pub fn main() {
    match args().get(1) {
        Option::Some(arg) => FileManager::new().main(arg),
        Option::None => FileManager::new().main("file:///"),
    }
}
<|endoftext|>


<commit_before><commit_msg>version work<commit_after><|endoftext|>


<commit_before><commit_msg>Fixing buffer issues.<commit_after><|endoftext|>


<commit_before><commit_msg>Add straggling code sample.<commit_after><|endoftext|>


<commit_before><commit_msg>add card struct<commit_after><|endoftext|>


<commit_before><commit_msg>Fix(sync): if a native file already exists, but there is no syncdb, check to see if syncdb needs update<commit_after><|endoftext|>


<commit_before><commit_msg>Add ! NEGATE<commit_after><|endoftext|>


<commit_before><commit_msg> #23 Added error checking to window creation<commit_after><|endoftext|>


<commit_before><commit_msg>Feat(command): add option to use custom config file<commit_after><|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.

#![allow(non_snake_case)]

register_long_diagnostics! {

E0373: r##"
This error occurs when an attempt is made to use data captured by a closure,
when that data may no longer exist. It's most commonly seen when attempting to
return a closure:

```
fn foo() -> Box<Fn(u32) -> u32> {
    let x = 0u32;
    Box::new(|y| x + y)
}
```

Notice that `x` is stack-allocated by `foo()`. By default, Rust captures
closed-over data by reference. This means that once `foo()` returns, `x` no
longer exists. An attempt to access `x` within the closure would thus be unsafe.

Another situation where this might be encountered is when spawning threads:

```
fn foo() {
    let x = 0u32;
    let y = 1u32;

    let thr = std::thread::spawn(|| {
        x + y
    });
}
```

Since our new thread runs in parallel, the stack frame containing `x` and `y`
may well have disappeared by the time we try to use them. Even if we call
`thr.join()` within foo (which blocks until `thr` has completed, ensuring the
stack frame won't disappear), we will not succeed: the compiler cannot prove
that this behaviour is safe, and so won't let us do it.

The solution to this problem is usually to switch to using a `move` closure.
This approach moves (or copies, where possible) data into the closure, rather
than taking references to it. For example:

```
fn foo() -> Box<Fn(u32) -> u32> {
    let x = 0u32;
    Box::new(move |y| x + y)
}
```

Now that the closure has its own copy of the data, there's no need to worry
about safety.
"##,

E0381: r##"
It is not allowed to use or capture an uninitialized variable. For example:

```
fn main() {
    let x: i32;
    let y = x; // error, use of possibly uninitialized variable
```

To fix this, ensure that any declared variables are initialized before being
used.
"##,

E0382: r##"
This error occurs when an attempt is made to use a variable after its contents
have been moved elsewhere. For example:

```
struct MyStruct { s: u32 }

fn main() {
    let mut x = MyStruct{ s: 5u32 };
    let y = x;
    x.s = 6;
    println!("{}", x.s);
}
```

Since `MyStruct` is a type that is not marked `Copy`, the data gets moved out
of `x` when we set `y`. This is fundamental to Rust's ownership system: outside
of workarounds like `Rc`, a value cannot be owned by more than one variable.

If we own the type, the easiest way to address this problem is to implement
`Copy` and `Clone` on it, as shown below. This allows `y` to copy the
information in `x`, while leaving the original version owned by `x`. Subsequent
changes to `x` will not be reflected when accessing `y`.

```
#[derive(Copy, Clone)]
struct MyStruct { s: u32 }

fn main() {
    let mut x = MyStruct{ s: 5u32 };
    let y = x;
    x.s = 6;
    println!("{}", x.s);
}
```

Alternatively, if we don't control the struct's definition, or mutable shared
ownership is truly required, we can use `Rc` and `RefCell`:

```
use std::cell::RefCell;
use std::rc::Rc;

struct MyStruct { s: u32 }

fn main() {
    let mut x = Rc::new(RefCell::new(MyStruct{ s: 5u32 }));
    let y = x.clone();
    x.borrow_mut().s = 6;
    println!("{}", x.borrow.s);
}
```

With this approach, x and y share ownership of the data via the `Rc` (reference
count type). `RefCell` essentially performs runtime borrow checking: ensuring
that at most one writer or multiple readers can access the data at any one time.

If you wish to learn more about ownership in Rust, start with the chapter in the
Book:

https://doc.rust-lang.org/book/ownership.html
"##,

E0384: r##"
This error occurs when an attempt is made to reassign an immutable variable.
For example:

```
fn main(){
    let x = 3;
    x = 5; // error, reassignment of immutable variable
}
```

By default, variables in Rust are immutable. To fix this error, add the keyword
`mut` after the keyword `let` when declaring the variable. For example:

```
fn main(){
    let mut x = 3;
    x = 5;
}
```
"##

}

register_diagnostics! {
    E0383, // partial reinitialization of uninitialized structure
    E0385, // {} in an aliasable location
    E0386, // {} in an immutable container
    E0387, // {} in a captured outer variable in an `Fn` closure
    E0388, // {} in a static location
    E0389  // {} in a `&` reference
}
<commit_msg>rollup merge of #27605: AlisdairO/diagnostics387<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.

#![allow(non_snake_case)]

register_long_diagnostics! {

E0373: r##"
This error occurs when an attempt is made to use data captured by a closure,
when that data may no longer exist. It's most commonly seen when attempting to
return a closure:

```
fn foo() -> Box<Fn(u32) -> u32> {
    let x = 0u32;
    Box::new(|y| x + y)
}
```

Notice that `x` is stack-allocated by `foo()`. By default, Rust captures
closed-over data by reference. This means that once `foo()` returns, `x` no
longer exists. An attempt to access `x` within the closure would thus be unsafe.

Another situation where this might be encountered is when spawning threads:

```
fn foo() {
    let x = 0u32;
    let y = 1u32;

    let thr = std::thread::spawn(|| {
        x + y
    });
}
```

Since our new thread runs in parallel, the stack frame containing `x` and `y`
may well have disappeared by the time we try to use them. Even if we call
`thr.join()` within foo (which blocks until `thr` has completed, ensuring the
stack frame won't disappear), we will not succeed: the compiler cannot prove
that this behaviour is safe, and so won't let us do it.

The solution to this problem is usually to switch to using a `move` closure.
This approach moves (or copies, where possible) data into the closure, rather
than taking references to it. For example:

```
fn foo() -> Box<Fn(u32) -> u32> {
    let x = 0u32;
    Box::new(move |y| x + y)
}
```

Now that the closure has its own copy of the data, there's no need to worry
about safety.
"##,

E0381: r##"
It is not allowed to use or capture an uninitialized variable. For example:

```
fn main() {
    let x: i32;
    let y = x; // error, use of possibly uninitialized variable
```

To fix this, ensure that any declared variables are initialized before being
used.
"##,

E0382: r##"
This error occurs when an attempt is made to use a variable after its contents
have been moved elsewhere. For example:

```
struct MyStruct { s: u32 }

fn main() {
    let mut x = MyStruct{ s: 5u32 };
    let y = x;
    x.s = 6;
    println!("{}", x.s);
}
```

Since `MyStruct` is a type that is not marked `Copy`, the data gets moved out
of `x` when we set `y`. This is fundamental to Rust's ownership system: outside
of workarounds like `Rc`, a value cannot be owned by more than one variable.

If we own the type, the easiest way to address this problem is to implement
`Copy` and `Clone` on it, as shown below. This allows `y` to copy the
information in `x`, while leaving the original version owned by `x`. Subsequent
changes to `x` will not be reflected when accessing `y`.

```
#[derive(Copy, Clone)]
struct MyStruct { s: u32 }

fn main() {
    let mut x = MyStruct{ s: 5u32 };
    let y = x;
    x.s = 6;
    println!("{}", x.s);
}
```

Alternatively, if we don't control the struct's definition, or mutable shared
ownership is truly required, we can use `Rc` and `RefCell`:

```
use std::cell::RefCell;
use std::rc::Rc;

struct MyStruct { s: u32 }

fn main() {
    let mut x = Rc::new(RefCell::new(MyStruct{ s: 5u32 }));
    let y = x.clone();
    x.borrow_mut().s = 6;
    println!("{}", x.borrow.s);
}
```

With this approach, x and y share ownership of the data via the `Rc` (reference
count type). `RefCell` essentially performs runtime borrow checking: ensuring
that at most one writer or multiple readers can access the data at any one time.

If you wish to learn more about ownership in Rust, start with the chapter in the
Book:

https://doc.rust-lang.org/book/ownership.html
"##,

E0384: r##"
This error occurs when an attempt is made to reassign an immutable variable.
For example:

```
fn main(){
    let x = 3;
    x = 5; // error, reassignment of immutable variable
}
```

By default, variables in Rust are immutable. To fix this error, add the keyword
`mut` after the keyword `let` when declaring the variable. For example:

```
fn main(){
    let mut x = 3;
    x = 5;
}
```
"##,

E0387: r##"
This error occurs when an attempt is made to mutate or mutably reference data
that a closure has captured immutably. Examples of this error are shown below:

```
// Accepts a function or a closure that captures its environment immutably.
// Closures passed to foo will not be able to mutate their closed-over state.
fn foo<F: Fn()>(f: F) { }

// Attempts to mutate closed-over data.  Error message reads:
// `cannot assign to data in a captured outer variable...`
fn mutable() {
    let mut x = 0u32;
    foo(|| x = 2);
}

// Attempts to take a mutable reference to closed-over data.  Error message
// reads: `cannot borrow data mutably in a captured outer variable...`
fn mut_addr() {
    let mut x = 0u32;
    foo(|| { let y = &mut x; });
}
```

The problem here is that foo is defined as accepting a parameter of type `Fn`.
Closures passed into foo will thus be inferred to be of type `Fn`, meaning that
they capture their context immutably.

If the definition of `foo` is under your control, the simplest solution is to
capture the data mutably. This can be done by defining `foo` to take FnMut
rather than Fn:

```
fn foo<F: FnMut()>(f: F) { }
```

Alternatively, we can consider using the `Cell` and `RefCell` types to achieve
interior mutability through a shared reference. Our example's `mutable` function
could be redefined as below:

```
use std::cell::Cell;

fn mutable() {
    let x = Cell::new(0u32);
    foo(|| x.set(2));
}
```

You can read more about cell types in the API documentation:

https://doc.rust-lang.org/std/cell/
"##

}

register_diagnostics! {
    E0383, // partial reinitialization of uninitialized structure
    E0385, // {} in an aliasable location
    E0386, // {} in an immutable container
    E0388, // {} in a static location
    E0389  // {} in a `&` reference
}
<|endoftext|>


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

#![allow(dead_code)] // not used on all platforms

use collections::BTreeMap;
use ptr;
use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};

pub type Key = usize;

type Dtor = unsafe extern fn(*mut u8);

static NEXT_KEY: AtomicUsize = ATOMIC_USIZE_INIT;

static mut KEYS: *mut BTreeMap<Key, Option<Dtor>> = ptr::null_mut();

#[thread_local]
static mut LOCALS: *mut BTreeMap<Key, *mut u8> = ptr::null_mut();

unsafe fn keys() -> &'static mut BTreeMap<Key, Option<Dtor>> {
    if KEYS == ptr::null_mut() {
        KEYS = Box::into_raw(Box::new(BTreeMap::new()));
    }
    &mut *KEYS
}

unsafe fn locals() -> &'static mut BTreeMap<Key, *mut u8> {
    if LOCALS == ptr::null_mut() {
        LOCALS = Box::into_raw(Box::new(BTreeMap::new()));
    }
    &mut *LOCALS
}

#[inline]
pub unsafe fn create(dtor: Option<Dtor>) -> Key {
    let key = NEXT_KEY.fetch_add(1, Ordering::SeqCst);
    keys().insert(key, dtor);
    key
}

#[inline]
pub unsafe fn get(key: Key) -> *mut u8 {
    if let Some(&entry) = locals().get(&key) {
        entry
    } else {
        ptr::null_mut()
    }
}

#[inline]
pub unsafe fn set(key: Key, value: *mut u8) {
    locals().insert(key, value);
}

#[inline]
pub unsafe fn destroy(key: Key) {
    keys().remove(&key);
}
<commit_msg>Implement requires_synchronized_create() for Redox<commit_after>// Copyright 2016 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.

#![allow(dead_code)] // not used on all platforms

use collections::BTreeMap;
use ptr;
use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};

pub type Key = usize;

type Dtor = unsafe extern fn(*mut u8);

static NEXT_KEY: AtomicUsize = ATOMIC_USIZE_INIT;

static mut KEYS: *mut BTreeMap<Key, Option<Dtor>> = ptr::null_mut();

#[thread_local]
static mut LOCALS: *mut BTreeMap<Key, *mut u8> = ptr::null_mut();

unsafe fn keys() -> &'static mut BTreeMap<Key, Option<Dtor>> {
    if KEYS == ptr::null_mut() {
        KEYS = Box::into_raw(Box::new(BTreeMap::new()));
    }
    &mut *KEYS
}

unsafe fn locals() -> &'static mut BTreeMap<Key, *mut u8> {
    if LOCALS == ptr::null_mut() {
        LOCALS = Box::into_raw(Box::new(BTreeMap::new()));
    }
    &mut *LOCALS
}

#[inline]
pub unsafe fn create(dtor: Option<Dtor>) -> Key {
    let key = NEXT_KEY.fetch_add(1, Ordering::SeqCst);
    keys().insert(key, dtor);
    key
}

#[inline]
pub unsafe fn get(key: Key) -> *mut u8 {
    if let Some(&entry) = locals().get(&key) {
        entry
    } else {
        ptr::null_mut()
    }
}

#[inline]
pub unsafe fn set(key: Key, value: *mut u8) {
    locals().insert(key, value);
}

#[inline]
pub unsafe fn destroy(key: Key) {
    keys().remove(&key);
}

#[inline]
pub fn requires_synchronized_create() -> bool {
    false
}
<|endoftext|>


<commit_before><commit_msg>adding more cmds to docopt parsing<commit_after><|endoftext|>


<commit_before><commit_msg>Update main.rs<commit_after><|endoftext|>


<commit_before><commit_msg>testing: add missing mock file<commit_after><|endoftext|>


<commit_before><commit_msg>Match prefix free decoding result<commit_after><|endoftext|>


<commit_before><commit_msg>on hover effect for tile<commit_after><|endoftext|>


<commit_before><commit_msg>window lying about width/height is a piston problem<commit_after><|endoftext|>


<commit_before>// Copyright 2018 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.
//
// Checks that we correctly codegen extern "C" functions returning structs.
// See issue #52638.

// compile-flags: -O --target=sparc64-unknown-linux-gnu --crate-type=rlib
#![feature(no_core, lang_items)]
#![no_core]

#[lang="sized"]
trait Sized { }
#[lang="freeze"]
trait Freeze { }
#[lang="copy"]
trait Copy { }

#[repr(C)]
pub struct Bool {
    b: bool,
}

// CHECK: define i64 @structbool()
// CHECK-NEXT: start:
// CHECK-NEXT: ret i64 72057594037927936
#[no_mangle]
pub extern "C" fn structbool() -> Bool {
    Bool { b: true }
}
<commit_msg>Only run the sparc-abi test on sparc<commit_after>// Copyright 2018 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.
//
// Checks that we correctly codegen extern "C" functions returning structs.
// See issue #52638.

// only-sparc64
// compile-flags: -O --target=sparc64-unknown-linux-gnu --crate-type=rlib
#![feature(no_core, lang_items)]
#![no_core]

#[lang="sized"]
trait Sized { }
#[lang="freeze"]
trait Freeze { }
#[lang="copy"]
trait Copy { }

#[repr(C)]
pub struct Bool {
    b: bool,
}

// CHECK: define i64 @structbool()
// CHECK-NEXT: start:
// CHECK-NEXT: ret i64 72057594037927936
#[no_mangle]
pub extern "C" fn structbool() -> Bool {
    Bool { b: true }
}
<|endoftext|>