<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 codemap::{Spanned, respan};
use ptr::P;

use util::small_vector::SmallVector;

pub trait CfgFolder: fold::Folder {
    // Check if a node with the given attributes is in this configuration.
    fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool;

    // Update a node before checking if it is in this configuration (used to implement `cfg_attr`).
    fn process_attrs<T: HasAttrs>(&mut self, node: T) -> T { node }

    // Visit attributes on expression and statements (but not attributes on items in blocks).
    fn visit_stmt_or_expr_attrs(&mut self, _attrs: &[ast::Attribute]) {}

    // Visit unremovable (non-optional) expressions -- c.f. `fold_expr` vs `fold_opt_expr`.
    fn visit_unremovable_expr(&mut self, _expr: &ast::Expr) {}

    fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
        let node = self.process_attrs(node);
        if self.in_cfg(node.attrs()) { Some(node) } else { None }
    }
}

/// 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> {
    pub fn new(config: &'a ast::CrateConfig,
               diagnostic: &'a Handler,
               feature_gated_cfgs: &'a mut Vec<GatedCfgAttr>)
               -> Self {
        StripUnconfigured {
            config: config,
            diag: CfgDiagReal { diag: diagnostic, feature_gated_cfgs: feature_gated_cfgs },
        }
    }

    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> {
    // 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_attrs<T: HasAttrs>(&mut self, node: T) -> T {
        node.map_attrs(|attrs| {
            attrs.into_iter().filter_map(|attr| self.process_cfg_attr(attr)).collect()
        })
    }

    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_unremovable_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
{
    let config = &krate.config.clone();
    StripUnconfigured::new(config, diagnostic, 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::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_unremovable_expr(&expr);
        let expr = self.process_attrs(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| fold::noop_fold_item(item, self))
                            .unwrap_or(SmallVector::zero())
    }

    fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVector<ast::ImplItem> {
        self.configure(item).map(|item| fold::noop_fold_impl_item(item, self))
                            .unwrap_or(SmallVector::zero())
    }

    fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVector<ast::TraitItem> {
        self.configure(item).map(|item| fold::noop_fold_trait_item(item, self))
                            .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)
    }
}
<commit_msg>Avoid configuring interpolated items.<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 parse::token;
use ptr::P;

use util::small_vector::SmallVector;

pub trait CfgFolder: fold::Folder {
    // Check if a node with the given attributes is in this configuration.
    fn in_cfg(&mut self, attrs: &[ast::Attribute]) -> bool;

    // Update a node before checking if it is in this configuration (used to implement `cfg_attr`).
    fn process_attrs<T: HasAttrs>(&mut self, node: T) -> T { node }

    // Visit attributes on expression and statements (but not attributes on items in blocks).
    fn visit_stmt_or_expr_attrs(&mut self, _attrs: &[ast::Attribute]) {}

    // Visit unremovable (non-optional) expressions -- c.f. `fold_expr` vs `fold_opt_expr`.
    fn visit_unremovable_expr(&mut self, _expr: &ast::Expr) {}

    fn configure<T: HasAttrs>(&mut self, node: T) -> Option<T> {
        let node = self.process_attrs(node);
        if self.in_cfg(node.attrs()) { Some(node) } else { None }
    }
}

/// 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> {
    pub fn new(config: &'a ast::CrateConfig,
               diagnostic: &'a Handler,
               feature_gated_cfgs: &'a mut Vec<GatedCfgAttr>)
               -> Self {
        StripUnconfigured {
            config: config,
            diag: CfgDiagReal { diag: diagnostic, feature_gated_cfgs: feature_gated_cfgs },
        }
    }

    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> {
    // 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_attrs<T: HasAttrs>(&mut self, node: T) -> T {
        node.map_attrs(|attrs| {
            attrs.into_iter().filter_map(|attr| self.process_cfg_attr(attr)).collect()
        })
    }

    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_unremovable_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
{
    let config = &krate.config.clone();
    StripUnconfigured::new(config, diagnostic, 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::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_unremovable_expr(&expr);
        let expr = self.process_attrs(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| fold::noop_fold_item(item, self))
                            .unwrap_or(SmallVector::zero())
    }

    fn fold_impl_item(&mut self, item: ast::ImplItem) -> SmallVector<ast::ImplItem> {
        self.configure(item).map(|item| fold::noop_fold_impl_item(item, self))
                            .unwrap_or(SmallVector::zero())
    }

    fn fold_trait_item(&mut self, item: ast::TraitItem) -> SmallVector<ast::TraitItem> {
        self.configure(item).map(|item| fold::noop_fold_trait_item(item, self))
                            .unwrap_or(SmallVector::zero())
    }

    fn fold_interpolated(&mut self, nt: token::Nonterminal) -> token::Nonterminal {
        // Don't configure interpolated AST (c.f. #34171).
        // Interpolated AST will get configured once the surrounding tokens are parsed.
        nt
    }
}

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>use std::collections::BTreeMap;
use rustc_serialize::json::{ToJson, Json};

#[derive(Debug, Default, Clone)]
pub struct Object {
    pub title:            String,
    pub obj_type:         ObjectType,
    pub url:              String,

    pub images:           Vec<Image>,
    pub audios:           Vec<Audio>,
    pub videos:           Vec<Video>,

    pub description:      Option<String>,
    pub determiner:       Option<Determiner>,
    pub locale:           Option<String>,
    pub locale_alternate: Vec<String>,
    pub site_name:        Option<String>,
}

impl Object {
    pub fn new<'a>(props: &'a Vec<(String, String)>) -> Object {
        let mut obj = Object::default();
        for prop in props.iter() {
            let key: &str = &(prop.0);
            let v         = prop.1.clone();
            match key {
                "title"       => { obj.title       = v; },
                "type"        => { obj.obj_type    = ObjectType::new(v); },
                "url"         => { obj.url         = v; },
                "description" => { obj.description = Some(v); },
                "determiner"  => { obj.determiner  = Some(Determiner::new(v)); },
                "locale"      => { obj.locale      = Some(v); },
                "site_name"   => { obj.site_name   = Some(v); },

                "image"            => { obj.images.push(Image::new(v)); },
                "video"            => { obj.videos.push(Video::new(v)); },
                "audio"            => { obj.audios.push(Audio::new(v)); },
                "locale:alternate" => {
                    obj.locale_alternate.push(v)
                },
                v if v.starts_with("image") => {
                },
                v if v.starts_with("music") => {
                },

                v if v.starts_with("video") => {
                },
                v if v.starts_with("article") => {
                },
                v if v.starts_with("book") => {
                },
                v if v.starts_with("profile") => {
                },
                _ => {},
            }
        }
        obj
    }
}

impl ToJson for Object {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("title".to_string()           , self.title.to_json());
        d.insert("type".to_string()            , self.obj_type.to_json());
        d.insert("url".to_string()             , self.url.to_json());

        d.insert("images".to_string(),
                 Json::Array(self.images.iter().map(|x| x.to_json()).collect()));
        d.insert("audios".to_string(),
                 Json::Array(self.audios.iter().map(|x| x.to_json()).collect()));
        d.insert("videos".to_string(),
                 Json::Array(self.videos.iter().map(|x| x.to_json()).collect()));

        d.insert("description".to_string()     , self.description.to_json());
        d.insert("determiner".to_string()      , self.determiner.to_json());
        d.insert("locale".to_string()          , self.locale.to_json());
        d.insert("locale_alternate".to_string(), self.locale.to_json());
        d.insert("site_name".to_string()       , self.locale.to_json());

        Json::Object(d)
    }
}

#[derive(Debug, Clone)]
pub enum ObjectType {
    // No Vetical
    Article,
    Book,
    Profile,
    Website,
    // Music
    Song,
    Album,
    Playlist,
    RadioStation,
    // Video
    Movie,
    Episode,
    TVShow,
    VideoOther,
}

impl ObjectType {
    fn to_string(&self) -> String {
        match *self {
            ObjectType::Article      => "article",
            ObjectType::Book         => "book",
            ObjectType::Profile      => "profile",
            ObjectType::Website      => "website",
            ObjectType::Song         => "music.song",
            ObjectType::Album        => "music.album",
            ObjectType::Playlist     => "music.playlist",
            ObjectType::RadioStation => "music.radio_station",
            ObjectType::Movie        => "video.movie",
            ObjectType::Episode      => "video.episode",
            ObjectType::TVShow       => "video.tv_show",
            ObjectType::VideoOther   => "video.other"
        }.to_string()
    }
    pub fn new(str: String) -> ObjectType {
        match str.as_ref() {
            "article"             => ObjectType::Article,
            "book"                => ObjectType::Book,
            "profile"             => ObjectType::Profile,
            "website"             => ObjectType::Website,
            "music.song"          => ObjectType::Song,
            "music.album"         => ObjectType::Album,
            "music.playlist"      => ObjectType::Playlist,
            "music.radio_station" => ObjectType::RadioStation,
            "video.movie"         => ObjectType::Movie,
            "video.episode"       => ObjectType::Episode,
            "video.tv_show"       => ObjectType::TVShow,
            "video.other"         => ObjectType::VideoOther,
            _                     => ObjectType::Website,
        }
    }
}

impl Default for ObjectType {
    fn default() -> ObjectType  { ObjectType::Website }
}

impl ToJson for ObjectType {
    fn to_json(&self) -> Json {
        self.to_string().to_json()
    }
}

#[derive(Debug, Clone)]
pub enum Determiner {
    A,
    An,
    The,
    Blank,
    Auto,
}

impl Determiner {
    fn to_string(&self) -> String {
        match *self {
            Determiner::A     => "a",
            Determiner::An    => "an",
            Determiner::The   => "the",
            Determiner::Blank => "",
            Determiner::Auto  => "auto",
        }.to_string()
    }
    pub fn new(str: String) -> Determiner {
        match str.as_ref() {
            "a"     => Determiner::A,
            "an"    => Determiner::An,
            "the"   => Determiner::The,
            "auto"  => Determiner::Auto,
            _       => Determiner::Blank,
        }
    }
}

impl Default for Determiner {
    fn default() -> Determiner  { Determiner::Blank }
}

impl ToJson for Determiner {
    fn to_json(&self) -> Json {
        self.to_string().to_json()
    }
}

#[derive(Debug, Default, Clone)]
pub struct Image {
    pub url:        String,
    pub secure_url: Option<String>,
    pub obj_type:   Option<String>,
    pub width:      Option<i32>,
    pub height:     Option<i32>
}

impl Image {
    pub fn new(url: String) -> Image {
        Image {
            url:        url,
            secure_url: None,
            obj_type:   None,
            width:      None,
            height:     None,
        }
    }
}

impl ToJson for Image {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("url".to_string()       , self.url.to_json());
        d.insert("secure_url".to_string(), self.secure_url.to_json());
        d.insert("type".to_string()      , self.obj_type.to_json());
        d.insert("width".to_string()     , self.width.to_json());
        d.insert("height".to_string()    , self.height.to_json());
        Json::Object(d)
    }
}

#[derive(Debug, Default, Clone)]
pub struct Video {
    pub url:        String,
    pub secure_url: Option<String>,
    pub obj_type:   Option<String>,
    pub width:      Option<i32>,
    pub height:     Option<i32>
}

impl Video {
    pub fn new(url: String) -> Video {
        Video {
            url:        url,
            secure_url: None,
            obj_type:   None,
            width:      None,
            height:     None,
        }
    }
}

impl ToJson for Video {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("url".to_string()       , self.url.to_json());
        d.insert("secure_url".to_string(), self.secure_url.to_json());
        d.insert("type".to_string()      , self.obj_type.to_json());
        d.insert("width".to_string()     , self.width.to_json());
        d.insert("height".to_string()    , self.height.to_json());
        Json::Object(d)
    }
}

#[derive(Debug, Default, Clone)]
pub struct Audio {
    pub url:        String,
    pub secure_url: Option<String>,
    pub obj_type:   Option<String>,
}

impl Audio {
    pub fn new(url: String) -> Audio {
        Audio { url: url, secure_url: None, obj_type: None }
    }
}

impl ToJson for Audio {
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("url".to_string()       , self.url.to_json());
        d.insert("secure_url".to_string(), self.secure_url.to_json());
        d.insert("type".to_string()      , self.obj_type.to_json());
        Json::Object(d)
    }
}
<commit_msg>Refactor open_graph with serde<commit_after>#[derive(Serialize, Deserialize, Debug, Default, Clone)]
pub struct Object {
    pub title:            String,
    pub obj_type:         ObjectType,
    pub url:              String,

    pub images:           Vec<Image>,
    pub audios:           Vec<Audio>,
    pub videos:           Vec<Video>,

    pub description:      Option<String>,
    pub determiner:       Option<Determiner>,
    pub locale:           Option<String>,
    pub locale_alternate: Vec<String>,
    pub site_name:        Option<String>,
}

impl Object {
    pub fn new<'a>(props: &'a Vec<(String, String)>) -> Object {
        let mut obj = Object::default();
        for prop in props.iter() {
            let key: &str = &(prop.0);
            let v         = prop.1.clone();
            match key {
                "title"       => { obj.title       = v; },
                "type"        => { obj.obj_type    = ObjectType::new(v); },
                "url"         => { obj.url         = v; },
                "description" => { obj.description = Some(v); },
                "determiner"  => { obj.determiner  = Some(Determiner::new(v)); },
                "locale"      => { obj.locale      = Some(v); },
                "site_name"   => { obj.site_name   = Some(v); },

                "image"            => { obj.images.push(Image::new(v)); },
                "video"            => { obj.videos.push(Video::new(v)); },
                "audio"            => { obj.audios.push(Audio::new(v)); },
                "locale:alternate" => {
                    obj.locale_alternate.push(v)
                },
                v if v.starts_with("image") => {
                },
                v if v.starts_with("music") => {
                },

                v if v.starts_with("video") => {
                },
                v if v.starts_with("article") => {
                },
                v if v.starts_with("book") => {
                },
                v if v.starts_with("profile") => {
                },
                _ => {},
            }
        }
        obj
    }
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum ObjectType {
    // No Vetical
    #[serde(rename = "article")]
    Article,
    #[serde(rename = "book")]
    Book,
    #[serde(rename = "profile")]
    Profile,
    #[serde(rename = "website")]
    Website,
    // Music
    #[serde(rename = "music.song")]
    Song,
    #[serde(rename = "music.album")]
    Album,
    #[serde(rename = "music.playlist")]
    Playlist,
    #[serde(rename = "music.radio_station")]
    RadioStation,
    // Video
    #[serde(rename = "video.movie")]
    Movie,
    #[serde(rename = "video.episode")]
    Episode,
    #[serde(rename = "video.tv_show")]
    TVShow,
    #[serde(rename = "video.other")]
    VideoOther,
}

impl ObjectType {
    pub fn new(str: String) -> ObjectType {
        match str.as_ref() {
            "article"             => ObjectType::Article,
            "book"                => ObjectType::Book,
            "profile"             => ObjectType::Profile,
            "website"             => ObjectType::Website,
            "music.song"          => ObjectType::Song,
            "music.album"         => ObjectType::Album,
            "music.playlist"      => ObjectType::Playlist,
            "music.radio_station" => ObjectType::RadioStation,
            "video.movie"         => ObjectType::Movie,
            "video.episode"       => ObjectType::Episode,
            "video.tv_show"       => ObjectType::TVShow,
            "video.other"         => ObjectType::VideoOther,
            _                     => ObjectType::Website,
        }
    }
}

impl Default for ObjectType {
    fn default() -> ObjectType  { ObjectType::Website }
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum Determiner {
    #[serde(rename = "a")]
    A,
    #[serde(rename = "an")]
    An,
    #[serde(rename = "the")]
    The,
    #[serde(rename = "")]
    Blank,
    #[serde(rename = "auto")]
    Auto,
}

impl Determiner {
    pub fn new(str: String) -> Determiner {
        match str.as_ref() {
            "a"     => Determiner::A,
            "an"    => Determiner::An,
            "the"   => Determiner::The,
            "auto"  => Determiner::Auto,
            _       => Determiner::Blank,
        }
    }
}

impl Default for Determiner {
    fn default() -> Determiner  { Determiner::Blank }
}

#[derive(Serialize, Deserialize, Debug, Default, Clone)]
pub struct Image {
    pub url:        String,
    pub secure_url: Option<String>,
    pub obj_type:   Option<String>,
    pub width:      Option<i32>,
    pub height:     Option<i32>
}

impl Image {
    pub fn new(url: String) -> Image {
        Image {
            url:        url,
            secure_url: None,
            obj_type:   None,
            width:      None,
            height:     None,
        }
    }
}

#[derive(Serialize, Deserialize, Debug, Default, Clone)]
pub struct Video {
    pub url:        String,
    pub secure_url: Option<String>,
    pub obj_type:   Option<String>,
    pub width:      Option<i32>,
    pub height:     Option<i32>
}

impl Video {
    pub fn new(url: String) -> Video {
        Video {
            url:        url,
            secure_url: None,
            obj_type:   None,
            width:      None,
            height:     None,
        }
    }
}

#[derive(Serialize, Deserialize, Debug, Default, Clone)]
pub struct Audio {
    pub url:        String,
    pub secure_url: Option<String>,
    pub obj_type:   Option<String>,
}

impl Audio {
    pub fn new(url: String) -> Audio {
        Audio { url: url, secure_url: None, obj_type: None }
    }
}
<|endoftext|>


<commit_before>use storage::file::FileHeaderSpec as FHS;
use storage::file::FileHeaderData as FHD;

pub fn get_spec() -> FHS {
    FHS::Map { keys: vec![ url_key(), tags_key() ] }
}

fn url_key() -> FHS {
    FHS::Key { name: String::from("URL"), value_type: Box::new(FHS::Text) }
}

fn tags_key() -> FHS {
    FHS::Key { name: String::from("TAGS"), value_type: Box::new(text_array()) }
}

fn text_array() -> FHS {
    FHS::Array { allowed_types: vec![FHS::Text] }
}

pub fn build_header(url: &String, tags: &Vec<String>) -> FHD {
    FHD::Map {
        keys: vec![
            FHD::Key {
                name: String::from("URL"),
                value: Box::new(FHD::Text(url.clone()))
            },
            FHD::Key {
                name: String::from("TAGS"),
                value: Box::new(build_tag_array(tags))
            }
        ]
    }
}

fn build_tag_array(tags: &Vec<String>) -> FHD {
    let texttags = tags.into_iter().map(|t| FHD::Text(t.clone())).collect();
    FHD::Array { values: Box::new(texttags) }
}

<commit_msg>Add tags_of_file() to extract tags from a File<commit_after>use storage::file::FileHeaderSpec as FHS;
use storage::file::FileHeaderData as FHD;
use std::ops::Deref;

pub fn get_spec() -> FHS {
    FHS::Map { keys: vec![ url_key(), tags_key() ] }
}

fn url_key() -> FHS {
    FHS::Key { name: String::from("URL"), value_type: Box::new(FHS::Text) }
}

fn tags_key() -> FHS {
    FHS::Key { name: String::from("TAGS"), value_type: Box::new(text_array()) }
}

fn text_array() -> FHS {
    FHS::Array { allowed_types: vec![FHS::Text] }
}

pub fn build_header(url: &String, tags: &Vec<String>) -> FHD {
    FHD::Map {
        keys: vec![
            FHD::Key {
                name: String::from("URL"),
                value: Box::new(FHD::Text(url.clone()))
            },
            FHD::Key {
                name: String::from("TAGS"),
                value: Box::new(build_tag_array(tags))
            }
        ]
    }
}

fn build_tag_array(tags: &Vec<String>) -> FHD {
    let texttags = tags.into_iter().map(|t| FHD::Text(t.clone())).collect();
    FHD::Array { values: Box::new(texttags) }
}

pub fn get_tags_from_header(header: &FHD) -> Vec<String> {
    let mut tags : Vec<String> = vec![];

    fn match_array(a: &Box<FHD>) -> Vec<String> {
        let mut tags : Vec<String> = vec![];

        match a.deref() {
            &FHD::Array{values: ref vs} => {
                let values : Vec<FHD> = vs.deref().clone();
                for value in values {
                    match value {
                        FHD::Text(t) => tags.push(t),
                        _ => warn!("Malformed Header Data: Expected Text, found non-Text"),
                    }
                }
            }
            _ => warn!("Malformed Header Data: Expected Array, found non-Array"),
        }

        tags
    }

    match header {
        &FHD::Map{keys: ref ks} => {
            let keys : Vec<FHD> = ks.clone();
            for key in keys {
                match key {
                    FHD::Key{name: _, value: ref v} => return match_array(v),
                    _ => warn!("Malformed Header Data: Expected Key, found non-Key"),
                }
            }
        },
        _ => warn!("Malformed Header Data: Expected Map, found non-Map"),
    }

    tags
}

<|endoftext|>


<commit_before>extern crate num;
extern crate rand;

extern crate tcod;
use tcod::RootConsole;
use tcod::{Console};
use tcod::console::{FontLayout, FontType, Offscreen};
use tcod::input::{Key, KeyCode};

mod traits;
use traits::{Renderable, Movable, Position};

mod point;
use point::Point;

mod rectangle;

mod units;
mod map;

const SCREEN_WIDTH: i8 = 80;
const SCREEN_HEIGHT: i8 = 50;
const PANEL_HEIGHT: i8 = 5;

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Direction {
    Up,
    Down,
    Left,
    Right
}

impl Direction {
    fn to_rel_point(self) -> Point<i8> {
        match self {
            Direction::Up       => Point::new(0, -1),
            Direction::Down     => Point::new(0, 1),
            Direction::Left     => Point::new(-1, 0),
            Direction::Right    => Point::new(1, 0),
        }
    }
}

#[derive(Debug)]
enum KeyType {
    Movement(Direction),
    Exit,
    Other,
}

fn key_type(key: &Key) -> KeyType {
    match key.code {
        KeyCode::Right  =>  KeyType::Movement(Direction::Right),
        KeyCode::Left   =>  KeyType::Movement(Direction::Left),
        KeyCode::Up     =>  KeyType::Movement(Direction::Up),
        KeyCode::Down   =>  KeyType::Movement(Direction::Down),
        KeyCode::Escape =>  KeyType::Exit,
        _ => KeyType::Other,
    }
}

fn main() {
    let mut root = RootConsole::initializer()
                    .size(SCREEN_WIDTH as i32, SCREEN_HEIGHT as i32)
                    .title("Roguelike Tutorial")
                    .fullscreen(false)
                    .font("arial10x10.png", FontLayout::Tcod)
                    .font_type(FontType::Greyscale)
                    .init();

    let mut buffer_console = Offscreen::new(SCREEN_WIDTH as i32, SCREEN_HEIGHT as i32);

    root.set_default_foreground(tcod::colors::WHITE);

    let (map, start_coord) = map::Map::init();

    let mut player = units::Unit::new(start_coord, '@', tcod::colors::WHITE);

    while !root.window_closed() {
        buffer_console.clear();

        map.render_map(&mut buffer_console);
        map.render_npcs(&mut buffer_console);

        player.render(&mut buffer_console);

        tcod::console::blit(&buffer_console, (0,0), (0,0), &mut root, (0,0), 1.0, 1.0);
        root.flush();

        let key = root.wait_for_keypress(true);

        match key_type(&key) {
            KeyType::Movement(dir)  => {
                let pos = player.get_position();
                let new_pos = pos + dir.to_rel_point();

                if let Ok(tile) = map.get_tile_type(new_pos) {
                    if !tile.blocks_move() {
                        player.move_to(new_pos);
                    }
                }
            },
            KeyType::Exit           => break,
            KeyType::Other          => println!("{:?}", key),
        }
    }
}
<commit_msg>Added button to generate new map.<commit_after>extern crate num;
extern crate rand;

extern crate tcod;
use tcod::RootConsole;
use tcod::{Console};
use tcod::console::{FontLayout, FontType, Offscreen};
use tcod::input::{Key, KeyCode};

mod traits;
use traits::{Renderable, Movable, Position};

mod point;
use point::Point;

mod rectangle;

mod units;
mod map;

const SCREEN_WIDTH: i8 = 80;
const SCREEN_HEIGHT: i8 = 50;
const PANEL_HEIGHT: i8 = 5;

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Direction {
    Up,
    Down,
    Left,
    Right
}

impl Direction {
    fn to_rel_point(self) -> Point<i8> {
        match self {
            Direction::Up       => Point::new(0, -1),
            Direction::Down     => Point::new(0, 1),
            Direction::Left     => Point::new(-1, 0),
            Direction::Right    => Point::new(1, 0),
        }
    }
}

#[derive(Debug)]
enum KeyType {
    Movement(Direction),
    Exit,
    NewGame,
    Other,
}

fn key_type(key: &Key) -> KeyType {
    match key.code {
        KeyCode::Right  =>  KeyType::Movement(Direction::Right),
        KeyCode::Left   =>  KeyType::Movement(Direction::Left),
        KeyCode::Up     =>  KeyType::Movement(Direction::Up),
        KeyCode::Down   =>  KeyType::Movement(Direction::Down),
        KeyCode::Escape =>  KeyType::Exit,
        KeyCode::F1     =>  KeyType::NewGame,
        _ => KeyType::Other,
    }
}

fn main() {
    let mut root = RootConsole::initializer()
                    .size(SCREEN_WIDTH as i32, SCREEN_HEIGHT as i32)
                    .title("Roguelike Tutorial")
                    .fullscreen(false)
                    .font("arial10x10.png", FontLayout::Tcod)
                    .font_type(FontType::Greyscale)
                    .init();

    let mut buffer_console = Offscreen::new(SCREEN_WIDTH as i32, SCREEN_HEIGHT as i32);

    root.set_default_foreground(tcod::colors::WHITE);

    let (mut map, start_coord) = map::Map::init();

    let mut player = units::Unit::new(start_coord, '@', tcod::colors::WHITE);

    while !root.window_closed() {
        buffer_console.clear();

        map.render_map(&mut buffer_console);
        map.render_npcs(&mut buffer_console);

        player.render(&mut buffer_console);

        tcod::console::blit(&buffer_console, (0,0), (0,0), &mut root, (0,0), 1.0, 1.0);
        root.flush();

        let key = root.wait_for_keypress(true);

        match key_type(&key) {
            KeyType::Movement(dir)  => {
                let pos = player.get_position();
                let new_pos = pos + dir.to_rel_point();

                if let Ok(tile) = map.get_tile_type(new_pos) {
                    if !tile.blocks_move() {
                        player.move_to(new_pos);
                    }
                }
            },
            KeyType::Exit           => break,
            KeyType::NewGame        => {
                let (new_map, start_coord) = map::Map::init();
                map = new_map;
                player.move_to(start_coord);
            }
            KeyType::Other          => println!("{:?}", key),
        }
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate gol;
extern crate test;

use gol::map;
use test::Bencher;

#[bench]
fn benchmark_with_acorn(b: &mut Bencher) {
    let mut map = map::Map::acorn();
    for _ in 0..4408 {
        map.next_generation();
    }
    b.iter(|| map.clone().next_generation());
}
<commit_msg>bench<commit_after>#![feature(test)]

extern crate test;

use test::Bencher;

#[bench]
fn benchmark_with_acorn(b: &mut Bencher) {
    let mut map = gol::Map::acorn();
    for _ in 0..4408 {
        map.next_generation();
    }
    b.iter(|| map.clone().next_generation());
}
<|endoftext|>


<commit_before>//! Tests for rustc plugins.

use cargo_test_support::{basic_manifest, project};
use cargo_test_support::{is_nightly, rustc_host};

#[cargo_test]
fn plugin_to_the_max() {
    if !is_nightly() {
        // plugins are unstable
        return;
    }

    let foo = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [lib]
            name = "foo_lib"

            [dependencies.bar]
            path = "../bar"
        "#,
        )
        .file(
            "src/main.rs",
            r#"
            #![feature(plugin)]
            #![plugin(bar)]
            extern crate foo_lib;

            fn main() { foo_lib::foo(); }
        "#,
        )
        .file(
            "src/foo_lib.rs",
            r#"
            #![feature(plugin)]
            #![plugin(bar)]

            pub fn foo() {}
        "#,
        )
        .build();
    let _bar = project()
        .at("bar")
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "bar"
            version = "0.0.1"
            authors = []

            [lib]
            name = "bar"
            plugin = true

            [dependencies.baz]
            path = "../baz"
        "#,
        )
        .file(
            "src/lib.rs",
            r#"
            #![feature(plugin_registrar, rustc_private)]

            extern crate baz;
            extern crate rustc_driver;

            use rustc_driver::plugin::Registry;

            #[plugin_registrar]
            pub fn foo(_reg: &mut Registry) {
                println!("{}", baz::baz());
            }
        "#,
        )
        .build();
    let _baz = project()
        .at("baz")
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "baz"
            version = "0.0.1"
            authors = []

            [lib]
            name = "baz"
            crate_type = ["dylib"]
        "#,
        )
        .file("src/lib.rs", "pub fn baz() -> i32 { 1 }")
        .build();

    foo.cargo("build").run();
    foo.cargo("doc").run();
}

#[cargo_test]
fn plugin_with_dynamic_native_dependency() {
    if !is_nightly() {
        // plugins are unstable
        return;
    }

    let build = project()
        .at("builder")
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "builder"
            version = "0.0.1"
            authors = []

            [lib]
            name = "builder"
            crate-type = ["dylib"]
        "#,
        )
        .file("src/lib.rs", "#[no_mangle] pub extern fn foo() {}")
        .build();

    let foo = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies.bar]
            path = "bar"
        "#,
        )
        .file(
            "src/main.rs",
            r#"
            #![feature(plugin)]
            #![plugin(bar)]

            fn main() {}
        "#,
        )
        .file(
            "bar/Cargo.toml",
            r#"
            [package]
            name = "bar"
            version = "0.0.1"
            authors = []
            build = 'build.rs'

            [lib]
            name = "bar"
            plugin = true
        "#,
        )
        .file(
            "bar/build.rs",
            r#"
            use std::env;
            use std::fs;
            use std::path::PathBuf;

            fn main() {
                let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
                let root = PathBuf::from(env::var("BUILDER_ROOT").unwrap());
                let file = format!("{}builder{}",
                    env::consts::DLL_PREFIX,
                    env::consts::DLL_SUFFIX);
                let src = root.join(&file);
                let dst = out_dir.join(&file);
                fs::copy(src, dst).unwrap();
                if cfg!(windows) {
                    fs::copy(root.join("builder.dll.lib"),
                             out_dir.join("builder.dll.lib")).unwrap();
                }
                println!("cargo:rustc-flags=-L {}", out_dir.display());
            }
        "#,
        )
        .file(
            "bar/src/lib.rs",
            r#"
            #![feature(plugin_registrar, rustc_private)]

            extern crate rustc_driver;
            use rustc_driver::plugin::Registry;

            #[cfg_attr(not(target_env = "msvc"), link(name = "builder"))]
            #[cfg_attr(target_env = "msvc", link(name = "builder.dll"))]
            extern { fn foo(); }

            #[plugin_registrar]
            pub fn bar(_reg: &mut Registry) {
                unsafe { foo() }
            }
        "#,
        )
        .build();

    build.cargo("build").run();

    let root = build.root().join("target").join("debug");
    foo.cargo("build -v").env("BUILDER_ROOT", root).run();
}

#[cargo_test]
fn plugin_integration() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []
            build = "build.rs"

            [lib]
            name = "foo"
            plugin = true
            doctest = false
        "#,
        )
        .file("build.rs", "fn main() {}")
        .file("src/lib.rs", "")
        .file("tests/it_works.rs", "")
        .build();

    p.cargo("test -v").run();
}

#[cargo_test]
fn doctest_a_plugin() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies]
            bar = { path = "bar" }
        "#,
        )
        .file("src/lib.rs", "#[macro_use] extern crate bar;")
        .file(
            "bar/Cargo.toml",
            r#"
            [package]
            name = "bar"
            version = "0.0.1"
            authors = []

            [lib]
            name = "bar"
            plugin = true
        "#,
        )
        .file("bar/src/lib.rs", "pub fn bar() {}")
        .build();

    p.cargo("test -v").run();
}

// See #1515
#[cargo_test]
fn native_plugin_dependency_with_custom_linker() {
    let target = rustc_host();

    let _foo = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [lib]
            plugin = true
        "#,
        )
        .file("src/lib.rs", "")
        .build();

    let bar = project()
        .at("bar")
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "bar"
            version = "0.0.1"
            authors = []

            [dependencies.foo]
            path = "../foo"
        "#,
        )
        .file("src/lib.rs", "")
        .file(
            ".cargo/config",
            &format!(
                r#"
            [target.{}]
            linker = "nonexistent-linker"
        "#,
                target
            ),
        )
        .build();

    bar.cargo("build --verbose")
        .with_status(101)
        .with_stderr_contains(
            "\
[COMPILING] foo v0.0.1 ([..])
[RUNNING] `rustc [..] -C linker=nonexistent-linker [..]`
[ERROR] [..]linker[..]
",
        )
        .run();
}

#[cargo_test]
fn panic_abort_plugins() {
    if !is_nightly() {
        // requires rustc_private
        return;
    }

    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [profile.dev]
            panic = 'abort'

            [dependencies]
            bar = { path = "bar" }
        "#,
        )
        .file("src/lib.rs", "")
        .file(
            "bar/Cargo.toml",
            r#"
            [package]
            name = "bar"
            version = "0.0.1"
            authors = []

            [lib]
            plugin = true
        "#,
        )
        .file(
            "bar/src/lib.rs",
            r#"
            #![feature(rustc_private)]
            extern crate syntax;
        "#,
        )
        .build();

    p.cargo("build").run();
}

#[cargo_test]
fn shared_panic_abort_plugins() {
    if !is_nightly() {
        // requires rustc_private
        return;
    }

    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [profile.dev]
            panic = 'abort'

            [dependencies]
            bar = { path = "bar" }
            baz = { path = "baz" }
        "#,
        )
        .file("src/lib.rs", "extern crate baz;")
        .file(
            "bar/Cargo.toml",
            r#"
            [package]
            name = "bar"
            version = "0.0.1"
            authors = []

            [lib]
            plugin = true

            [dependencies]
            baz = { path = "../baz" }
        "#,
        )
        .file(
            "bar/src/lib.rs",
            r#"
            #![feature(rustc_private)]
            extern crate syntax;
            extern crate baz;
        "#,
        )
        .file("baz/Cargo.toml", &basic_manifest("baz", "0.0.1"))
        .file("baz/src/lib.rs", "")
        .build();

    p.cargo("build").run();
}
<commit_msg>Auto merge of #7955 - ehuss:fix-plugin-syntax-rename, r=alexcrichton<commit_after>//! Tests for rustc plugins.

use cargo_test_support::{basic_manifest, project};
use cargo_test_support::{is_nightly, rustc_host};

#[cargo_test]
fn plugin_to_the_max() {
    if !is_nightly() {
        // plugins are unstable
        return;
    }

    let foo = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [lib]
            name = "foo_lib"

            [dependencies.bar]
            path = "../bar"
        "#,
        )
        .file(
            "src/main.rs",
            r#"
            #![feature(plugin)]
            #![plugin(bar)]
            extern crate foo_lib;

            fn main() { foo_lib::foo(); }
        "#,
        )
        .file(
            "src/foo_lib.rs",
            r#"
            #![feature(plugin)]
            #![plugin(bar)]

            pub fn foo() {}
        "#,
        )
        .build();
    let _bar = project()
        .at("bar")
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "bar"
            version = "0.0.1"
            authors = []

            [lib]
            name = "bar"
            plugin = true

            [dependencies.baz]
            path = "../baz"
        "#,
        )
        .file(
            "src/lib.rs",
            r#"
            #![feature(plugin_registrar, rustc_private)]

            extern crate baz;
            extern crate rustc_driver;

            use rustc_driver::plugin::Registry;

            #[plugin_registrar]
            pub fn foo(_reg: &mut Registry) {
                println!("{}", baz::baz());
            }
        "#,
        )
        .build();
    let _baz = project()
        .at("baz")
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "baz"
            version = "0.0.1"
            authors = []

            [lib]
            name = "baz"
            crate_type = ["dylib"]
        "#,
        )
        .file("src/lib.rs", "pub fn baz() -> i32 { 1 }")
        .build();

    foo.cargo("build").run();
    foo.cargo("doc").run();
}

#[cargo_test]
fn plugin_with_dynamic_native_dependency() {
    if !is_nightly() {
        // plugins are unstable
        return;
    }

    let build = project()
        .at("builder")
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "builder"
            version = "0.0.1"
            authors = []

            [lib]
            name = "builder"
            crate-type = ["dylib"]
        "#,
        )
        .file("src/lib.rs", "#[no_mangle] pub extern fn foo() {}")
        .build();

    let foo = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies.bar]
            path = "bar"
        "#,
        )
        .file(
            "src/main.rs",
            r#"
            #![feature(plugin)]
            #![plugin(bar)]

            fn main() {}
        "#,
        )
        .file(
            "bar/Cargo.toml",
            r#"
            [package]
            name = "bar"
            version = "0.0.1"
            authors = []
            build = 'build.rs'

            [lib]
            name = "bar"
            plugin = true
        "#,
        )
        .file(
            "bar/build.rs",
            r#"
            use std::env;
            use std::fs;
            use std::path::PathBuf;

            fn main() {
                let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
                let root = PathBuf::from(env::var("BUILDER_ROOT").unwrap());
                let file = format!("{}builder{}",
                    env::consts::DLL_PREFIX,
                    env::consts::DLL_SUFFIX);
                let src = root.join(&file);
                let dst = out_dir.join(&file);
                fs::copy(src, dst).unwrap();
                if cfg!(windows) {
                    fs::copy(root.join("builder.dll.lib"),
                             out_dir.join("builder.dll.lib")).unwrap();
                }
                println!("cargo:rustc-flags=-L {}", out_dir.display());
            }
        "#,
        )
        .file(
            "bar/src/lib.rs",
            r#"
            #![feature(plugin_registrar, rustc_private)]

            extern crate rustc_driver;
            use rustc_driver::plugin::Registry;

            #[cfg_attr(not(target_env = "msvc"), link(name = "builder"))]
            #[cfg_attr(target_env = "msvc", link(name = "builder.dll"))]
            extern { fn foo(); }

            #[plugin_registrar]
            pub fn bar(_reg: &mut Registry) {
                unsafe { foo() }
            }
        "#,
        )
        .build();

    build.cargo("build").run();

    let root = build.root().join("target").join("debug");
    foo.cargo("build -v").env("BUILDER_ROOT", root).run();
}

#[cargo_test]
fn plugin_integration() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []
            build = "build.rs"

            [lib]
            name = "foo"
            plugin = true
            doctest = false
        "#,
        )
        .file("build.rs", "fn main() {}")
        .file("src/lib.rs", "")
        .file("tests/it_works.rs", "")
        .build();

    p.cargo("test -v").run();
}

#[cargo_test]
fn doctest_a_plugin() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies]
            bar = { path = "bar" }
        "#,
        )
        .file("src/lib.rs", "#[macro_use] extern crate bar;")
        .file(
            "bar/Cargo.toml",
            r#"
            [package]
            name = "bar"
            version = "0.0.1"
            authors = []

            [lib]
            name = "bar"
            plugin = true
        "#,
        )
        .file("bar/src/lib.rs", "pub fn bar() {}")
        .build();

    p.cargo("test -v").run();
}

// See #1515
#[cargo_test]
fn native_plugin_dependency_with_custom_linker() {
    let target = rustc_host();

    let _foo = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [lib]
            plugin = true
        "#,
        )
        .file("src/lib.rs", "")
        .build();

    let bar = project()
        .at("bar")
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "bar"
            version = "0.0.1"
            authors = []

            [dependencies.foo]
            path = "../foo"
        "#,
        )
        .file("src/lib.rs", "")
        .file(
            ".cargo/config",
            &format!(
                r#"
            [target.{}]
            linker = "nonexistent-linker"
        "#,
                target
            ),
        )
        .build();

    bar.cargo("build --verbose")
        .with_status(101)
        .with_stderr_contains(
            "\
[COMPILING] foo v0.0.1 ([..])
[RUNNING] `rustc [..] -C linker=nonexistent-linker [..]`
[ERROR] [..]linker[..]
",
        )
        .run();
}

#[cargo_test]
fn panic_abort_plugins() {
    if !is_nightly() {
        // requires rustc_private
        return;
    }

    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [profile.dev]
            panic = 'abort'

            [dependencies]
            bar = { path = "bar" }
        "#,
        )
        .file("src/lib.rs", "")
        .file(
            "bar/Cargo.toml",
            r#"
            [package]
            name = "bar"
            version = "0.0.1"
            authors = []

            [lib]
            plugin = true
        "#,
        )
        .file(
            "bar/src/lib.rs",
            r#"
            #![feature(rustc_private)]
            extern crate rustc_ast;
        "#,
        )
        .build();

    p.cargo("build").run();
}

#[cargo_test]
fn shared_panic_abort_plugins() {
    if !is_nightly() {
        // requires rustc_private
        return;
    }

    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [profile.dev]
            panic = 'abort'

            [dependencies]
            bar = { path = "bar" }
            baz = { path = "baz" }
        "#,
        )
        .file("src/lib.rs", "extern crate baz;")
        .file(
            "bar/Cargo.toml",
            r#"
            [package]
            name = "bar"
            version = "0.0.1"
            authors = []

            [lib]
            plugin = true

            [dependencies]
            baz = { path = "../baz" }
        "#,
        )
        .file(
            "bar/src/lib.rs",
            r#"
            #![feature(rustc_private)]
            extern crate rustc_ast;
            extern crate baz;
        "#,
        )
        .file("baz/Cargo.toml", &basic_manifest("baz", "0.0.1"))
        .file("baz/src/lib.rs", "")
        .build();

    p.cargo("build").run();
}
<|endoftext|>


<commit_before>use std::{env, fs};
use std::process;
use std::process::Command;

fn main() {
    let usage = r#"tutorial-maker <username> <program-name> <language> <program-type>

    <language> can only be the following:

    - rust

    <program-type> can only be the following:

    - library
"#;
    let args: Vec<String> = env::args().collect();

    if args.len() < 5 {
        println!("{usage}");

        process::exit(1);
    }

    println!("{:?}", args);

    let username = args[1].to_lowercase();
    let program_name = args[2].to_lowercase();
    let args3 = args[3].to_lowercase();
    let language = if args3 == "rust" {
        "rust"
    } else {
        println!("{usage}");

        process::exit(1);
    };

    let args4 = args[4].to_lowercase();
    let program_type = if args4 == "library" {
        "library"
    } else {
        println!("{usage}");

        process::exit(1);
    };

    let path_name = format!("repos/github/{username}");

    println!("making path name: {path_name}");

    fs::create_dir_all(&path_name).expect("unable to create path name");
    env::set_current_dir(&path_name).expect("changing directory failed");

    let folder_name = format!("{program_name}-{language}-{program_type}");
    let repo_name = format!("{username}/{folder_name}");

    println!("rm -rf {folder_name}");

    let removing_folder_output = Command::new("rm")
        .arg("-rf")
        .arg(&folder_name)
        .output()
        .expect("removing folder failed");

    if removing_folder_output.status.success() {
        println!(
            "cloning stdout: {}",
            String::from_utf8_lossy(&removing_folder_output.stdout)
        );
    } else {
        println!(
            "cloning stderr: {}",
            String::from_utf8_lossy(&removing_folder_output.stderr)
        );

        process::exit(1);
    }

    println!("gh repo clone {repo_name}");

    let cloning_output = Command::new("gh")
        .arg("repo")
        .arg("clone")
        .arg(&repo_name)
        .output()
        .expect("cloning failed");

    if cloning_output.status.success() {
        println!(
            "cloning stdout: {}",
            String::from_utf8_lossy(&cloning_output.stdout)
        );
    } else {
        println!(
            "cloning stderr: {}",
            String::from_utf8_lossy(&cloning_output.stderr)
        );

        process::exit(1);
    }

    env::set_current_dir(&folder_name).expect("changing directory failed");
}
<commit_msg>getting a list of commits<commit_after>use std::process;
use std::process::Command;
use std::{env, fs};

fn main() {
    let usage = r#"tutorial-maker <username> <program-name> <language> <program-type>

    <language> can only be the following:

    - rust

    <program-type> can only be the following:

    - library
"#;
    let args: Vec<String> = env::args().collect();

    if args.len() < 5 {
        println!("{usage}");

        process::exit(1);
    }

    println!("{:?}", args);

    let username = args[1].to_lowercase();
    let program_name = args[2].to_lowercase();
    let args3 = args[3].to_lowercase();
    let language = if args3 == "rust" {
        "rust"
    } else {
        println!("{usage}");

        process::exit(1);
    };

    let args4 = args[4].to_lowercase();
    let program_type = if args4 == "library" {
        "library"
    } else {
        println!("{usage}");

        process::exit(1);
    };

    let path_name = format!("repos/github/{username}");

    println!("making path name: {path_name}");

    fs::create_dir_all(&path_name).expect("unable to create path name");
    env::set_current_dir(&path_name).expect("changing directory failed");

    let folder_name = format!("{program_name}-{language}-{program_type}");
    let repo_name = format!("{username}/{folder_name}");

    println!("rm -rf {folder_name}");

    let removing_folder_output = Command::new("rm")
        .arg("-rf")
        .arg(&folder_name)
        .output()
        .expect("removing folder failed");

    if removing_folder_output.status.success() {
        println!(
            "cloning stdout: {}",
            String::from_utf8_lossy(&removing_folder_output.stdout)
        );
    } else {
        println!(
            "cloning stderr: {}",
            String::from_utf8_lossy(&removing_folder_output.stderr)
        );

        process::exit(1);
    }

    println!("gh repo clone {repo_name}");

    let cloning_output = Command::new("gh")
        .arg("repo")
        .arg("clone")
        .arg(&repo_name)
        .output()
        .expect("cloning failed");

    if cloning_output.status.success() {
        println!(
            "cloning stdout: {}",
            String::from_utf8_lossy(&cloning_output.stdout)
        );
    } else {
        println!(
            "cloning stderr: {}",
            String::from_utf8_lossy(&cloning_output.stderr)
        );

        process::exit(1);
    }

    env::set_current_dir(&folder_name).expect("changing directory failed");

    println!("git rev-list --all --reverse");

    let rev_list_output = Command::new("git")
        .arg("rev-list")
        .arg("--all")
        .arg("--reverse")
        .output()
        .expect("rev-list failed");

    if rev_list_output.status.success() {
        println!(
            "rev-list stdout: {}",
            String::from_utf8_lossy(&rev_list_output.stdout)
        );
    } else {
        println!(
            "rev-list stderr: {}",
            String::from_utf8_lossy(&rev_list_output.stderr)
        );

        process::exit(1);
    }
}
<|endoftext|>


<commit_before>use bifrost::raft::state_machine::StateMachineCtl;
use bifrost::utils::bincode::serialize;
use bifrost_plugins::hash_ident;
use bincode::deserialize;
use dovahkiin::types::Id;
use index::EntryKey;
use parking_lot::RwLock;
use ram::types::RandValue;
use serde::de::DeserializeOwned;
use serde::Deserialize;
use serde::Serialize;
use serde_json::ser::CharEscape::Quote;
use smallvec::SmallVec;
use std::collections::btree_map::BTreeMap;
use std::collections::btree_set::BTreeSet;
use std::collections::HashMap;
use std::collections::HashSet;

pub static SM_ID: u64 = hash_ident!(LSM_TREE_PLACEMENT_SM) as u64;

#[derive(Serialize, Deserialize)]
pub enum CmdError {
    AnotherSplitInProgress(InSplitStatus),
    CannotFindSplitMeta,
    SplitUnmatchSource,
    NoSplitInProgress,
    MidOutOfRange,
    PlacementNotFound,
}

#[derive(Serialize, Deserialize)]
pub enum QueryError {
    OutOfRange,
}

#[derive(Serialize, Deserialize)]
pub struct QueryResult {
    id: Id,
    split: Option<Id>,
    epoch: u64,
}

#[derive(Serialize, Deserialize, Clone)]
pub struct InSplitStatus {
    dest: Id,
    mid: Vec<u8>,
}

pub struct Placement {
    starts: EntryKey,
    ends: EntryKey,
    in_split: Option<InSplitStatus>,
    epoch: u64,
    id: Id,
}

pub struct PlacementSM {
    placements: HashMap<Id, Placement>,
    starts: BTreeMap<EntryKey, Id>,
    pending_new_ids: BTreeMap<Id, Id>,
}

raft_state_machine! {
    def cmd prepare_split(source: Id)  -> Id | CmdError;
    def cmd start_split(source: Id, dest: Id, mid: Vec<u8>, src_epoch: u64) -> u64 | CmdError;
    def cmd complete_split(source: Id, dest: Id, src_epoch: u64) -> u64 | CmdError;
    def cmd update_epoch(source: Id, epoch: u64) -> u64 | CmdError;
    def qry locate(id: Vec<u8>) -> QueryResult | QueryError;
}

impl StateMachineCmds for PlacementSM {
    fn prepare_split(&mut self, source: Id) -> Result<Id, CmdError> {
        if !self.placements.contains_key(&source) {
            return Err(CmdError::PlacementNotFound);
        }
        let new_id = Id::rand();
        self.pending_new_ids.insert(new_id, source);
        Ok(new_id)
    }

    fn start_split(&mut self, source: Id, dest: Id, mid: Vec<u8>, src_epoch: u64) -> Result<u64, CmdError> {
        if let Some(mut source_placement) = self.placements.get_mut(&source) {
            if let &Some(ref in_progress) = &source_placement.in_split {
                return Err(CmdError::AnotherSplitInProgress(in_progress.clone()));
            }

            let mid_key: EntryKey = SmallVec::from(mid);
            if mid_key < source_placement.starts || mid_key >= source_placement.ends {
                return Err(CmdError::MidOutOfRange);
            }

            source_placement.in_split = Some(InSplitStatus {
                dest,
                mid: mid_key.into_iter().collect(),
            });
            source_placement.epoch = src_epoch;
            Ok(source_placement.epoch)
        } else {
            Err(CmdError::PlacementNotFound)
        }
    }

    fn complete_split(&mut self, source: Id, dest: Id, src_epoch: u64) -> Result<u64, CmdError> {
        let (dest_placement, src_epoch) =
            if let Some(mut source_placement) = self.placements.get_mut(&source) {
                if let Some(pending_src) = self.pending_new_ids.get(&dest) {
                    if pending_src != &source {
                        return Err(CmdError::SplitUnmatchSource);
                    }
                } else {
                    return Err(CmdError::CannotFindSplitMeta);
                }
                let dest_placement = if let &Some(ref in_progress) = &source_placement.in_split {
                    if in_progress.dest != dest {
                        return Err(CmdError::AnotherSplitInProgress(in_progress.clone()));
                    }
                    let dest_ends = source_placement.ends.clone();
                    let source_ends = SmallVec::from(in_progress.mid.clone());
                    source_placement.ends = source_ends.clone();
                    Placement {
                        starts: source_ends,
                        ends: dest_ends,
                        in_split: None,
                        epoch: 0,
                        id: dest,
                    }
                } else {
                    return Err(CmdError::NoSplitInProgress);
                };
                source_placement.in_split = None;
                source_placement.epoch = src_epoch;
                (dest_placement, source_placement.epoch)
            } else {
                return Err(CmdError::PlacementNotFound);
            };
        self.starts.insert(dest_placement.starts.clone(), dest);
        self.placements.insert(dest, dest_placement);
        self.pending_new_ids.remove(&dest);
        Ok(src_epoch)
    }

    fn update_epoch(&mut self, source: Id, epoch: u64) -> Result<u64, CmdError> {
        // unconditionally update placement epoch in state machine and return its original value
        if let Some(mut source_placement) = self.placements.get_mut(&source) {
            let original = source_placement.epoch;
            source_placement.epoch = epoch;
            Ok(original)
        } else {
            Err(CmdError::PlacementNotFound)
        }
    }

    fn locate(&self, entry: Vec<u8>) -> Result<QueryResult, QueryError> {
        let search_key = SmallVec::from(entry);
        if let Some((_, placement_id)) = self.starts.range(..=search_key).last() {
            let placement = self.placements.get(placement_id).unwrap();
            let split = placement.in_split.as_ref().map(|s| s.dest);
            return Ok(QueryResult {
                id: placement.id,
                split,
                epoch: placement.epoch,
            });
        } else {
            return Err(QueryError::OutOfRange);
        }
    }
}

impl StateMachineCtl for PlacementSM {
    raft_sm_complete!();
    fn id(&self) -> u64 {
        SM_ID
    }
    fn snapshot(&self) -> Option<Vec<u8>> {
        unimplemented!()
    }
    fn recover(&mut self, data: Vec<u8>) {
        unimplemented!()
    }
}
<commit_msg>sinplify<commit_after>use bifrost::raft::state_machine::StateMachineCtl;
use bifrost::utils::bincode::serialize;
use bifrost_plugins::hash_ident;
use bincode::deserialize;
use dovahkiin::types::Id;
use index::EntryKey;
use parking_lot::RwLock;
use ram::types::RandValue;
use serde::de::DeserializeOwned;
use serde::Deserialize;
use serde::Serialize;
use serde_json::ser::CharEscape::Quote;
use smallvec::SmallVec;
use std::collections::btree_map::BTreeMap;
use std::collections::btree_set::BTreeSet;
use std::collections::HashMap;
use std::collections::HashSet;

pub static SM_ID: u64 = hash_ident!(LSM_TREE_PLACEMENT_SM) as u64;

#[derive(Serialize, Deserialize)]
pub enum CmdError {
    AnotherSplitInProgress(InSplitStatus),
    CannotFindSplitMeta,
    SplitUnmatchSource(Id),
    NoSplitInProgress,
    MidOutOfRange,
    PlacementNotFound,
}

#[derive(Serialize, Deserialize)]
pub enum QueryError {
    OutOfRange,
}

#[derive(Serialize, Deserialize)]
pub struct QueryResult {
    id: Id,
    split: Option<Id>,
    epoch: u64,
}

#[derive(Serialize, Deserialize, Clone)]
pub struct InSplitStatus {
    dest: Id,
    mid: Vec<u8>,
}

pub struct Placement {
    starts: EntryKey,
    ends: EntryKey,
    in_split: Option<InSplitStatus>,
    epoch: u64,
    id: Id,
}

pub struct PlacementSM {
    placements: HashMap<Id, Placement>,
    starts: BTreeMap<EntryKey, Id>
}

raft_state_machine! {
    def cmd prepare_split(source: Id, dest: Id)  -> () | CmdError;
    def cmd start_split(source: Id, dest: Id, mid: Vec<u8>, src_epoch: u64) -> u64 | CmdError;
    def cmd complete_split(source: Id, dest: Id, src_epoch: u64) -> u64 | CmdError;
    def cmd update_epoch(source: Id, epoch: u64) -> u64 | CmdError;
    def qry locate(id: Vec<u8>) -> QueryResult | QueryError;
}

impl StateMachineCmds for PlacementSM {
    fn prepare_split(&mut self, source: Id, dest: Id) -> Result<(), CmdError> {
        if let Some(src_placement) = self.placements.get(&source) {
            if let &Some(ref split) = &src_placement.in_split {
                return Err(CmdError::AnotherSplitInProgress(split.clone()))
            } else {
                return Ok(())
            }
        } else {
            return Err(CmdError::PlacementNotFound);
        }
    }

    fn start_split(&mut self, source: Id, dest: Id, mid: Vec<u8>, src_epoch: u64) -> Result<u64, CmdError> {
        if let Some(mut source_placement) = self.placements.get_mut(&source) {
            if let &Some(ref in_progress) = &source_placement.in_split {
                return Err(CmdError::AnotherSplitInProgress(in_progress.clone()));
            }

            let mid_key: EntryKey = SmallVec::from(mid);
            if mid_key < source_placement.starts || mid_key >= source_placement.ends {
                return Err(CmdError::MidOutOfRange);
            }

            source_placement.in_split = Some(InSplitStatus {
                dest,
                mid: mid_key.into_iter().collect(),
            });
            source_placement.epoch = src_epoch;
            Ok(source_placement.epoch)
        } else {
            Err(CmdError::PlacementNotFound)
        }
    }

    fn complete_split(&mut self, source: Id, dest: Id, src_epoch: u64) -> Result<u64, CmdError> {
        let (dest_placement, src_epoch) =
            if let Some(mut source_placement) = self.placements.get_mut(&source) {
                let dest_placement = if let &Some(ref in_progress) = &source_placement.in_split {
                    if in_progress.dest != dest {
                        return Err(CmdError::AnotherSplitInProgress(in_progress.clone()));
                    }
                    let dest_ends = source_placement.ends.clone();
                    let source_ends = SmallVec::from(in_progress.mid.clone());
                    source_placement.ends = source_ends.clone();
                    Placement {
                        starts: source_ends,
                        ends: dest_ends,
                        in_split: None,
                        epoch: 0,
                        id: dest,
                    }
                } else {
                    return Err(CmdError::NoSplitInProgress);
                };
                source_placement.in_split = None;
                source_placement.epoch = src_epoch;
                (dest_placement, source_placement.epoch)
            } else {
                return Err(CmdError::PlacementNotFound);
            };
        self.starts.insert(dest_placement.starts.clone(), dest);
        self.placements.insert(dest, dest_placement);
        Ok(src_epoch)
    }

    fn update_epoch(&mut self, source: Id, epoch: u64) -> Result<u64, CmdError> {
        // unconditionally update placement epoch in state machine and return its original value
        if let Some(mut source_placement) = self.placements.get_mut(&source) {
            let original = source_placement.epoch;
            source_placement.epoch = epoch;
            Ok(original)
        } else {
            Err(CmdError::PlacementNotFound)
        }
    }

    fn locate(&self, entry: Vec<u8>) -> Result<QueryResult, QueryError> {
        let search_key = SmallVec::from(entry);
        if let Some((_, placement_id)) = self.starts.range(..=search_key).last() {
            let placement = self.placements.get(placement_id).unwrap();
            let split = placement.in_split.as_ref().map(|s| s.dest);
            return Ok(QueryResult {
                id: placement.id,
                split,
                epoch: placement.epoch,
            });
        } else {
            return Err(QueryError::OutOfRange);
        }
    }
}

impl StateMachineCtl for PlacementSM {
    raft_sm_complete!();
    fn id(&self) -> u64 {
        SM_ID
    }
    fn snapshot(&self) -> Option<Vec<u8>> {
        unimplemented!()
    }
    fn recover(&mut self, data: Vec<u8>) {
        unimplemented!()
    }
}
<|endoftext|>


<commit_before>//! Utilities to do with connections between a Minecraft or Forge client and Netherrack

extern crate chrono;
use self::chrono::duration::Duration;

use super::packet::PacketHeader;

use std::collections::VecDeque;

use std::net::{Shutdown, TcpStream};

use std::io::Read;

use super::deque_buffer::DequeBuffer;

/// An enum describing the current connection's state
pub enum ConnectionState {

    /// Connection is in handshake mode
    HANDSHAKE,

    /// Connection is in login mode
    LOGIN,

    /// Connection is in status mode
    STATUS,

    /// Connection is in play mode
    PLAY

}

/// A struct defining a game connection
pub struct GameConnection {

    /// The TCP stream bound to this GameConnection
    pub stream: TcpStream,

    /// The state of this GameConnection
    pub state: ConnectionState

}

impl GameConnection {

    /// Creates a new GameConnection
    pub fn new(stream: TcpStream) -> GameConnection {
        GameConnection {
            stream: stream,
            state: ConnectionState::HANDSHAKE
        }
    }

    pub fn disconnect(&mut self) {
        //TODO: Check to see if in ConnectionState::PLAY, otherwise
        let result = self.stream.shutdown(Shutdown::Both);

        if result.is_ok() == false {
            error!("Error disconnecting: {:?}", result);
        }

    }

    /// Starts listening on the connection
    pub fn start_listening(&mut self) {

        info!("Got a new client from {}! Oh my!", self.stream.peer_addr().unwrap());

        let mut timeout_duration = Duration::zero();

        loop {

            if timeout_duration.num_seconds() >= 10 {
                info!("Client timed out");
                self.disconnect();
                break;
            }

            let mut raw_buffer = vec![0u8; 512];

            match self.stream.read(&mut raw_buffer) {

                Err(error) => {
                    // Connection dropped out or something broke
                    // In the future, we use the customized NetherrackStream to see if we're in GAME mode, and if so, get the attached player and start saving their information and get rid of them
                    // For now, we just exit the loop
                    error!("Got an error! {}", error);

                    self.disconnect();
                    break;
                }
                Ok(count) => {
                    if count == 0 {
                        //Nothing in stream, let's sleep for a few milliseconds and try again
                        timeout_duration = timeout_duration + Duration::milliseconds(2);
                        ::std::thread::sleep_ms(2);
                    } else {

                        timeout_duration = Duration::zero();

                        // Now truncate the raw buffer - Don't worry, it will reallocate to 512 on the next networking loop
                        raw_buffer.truncate(count);

                        let mut backing: VecDeque<u8> = VecDeque::<u8>::with_capacity(count);

                        for b in raw_buffer {

                            backing.push_back(b);
                        }

                        let mut buffer = DequeBuffer::from(backing);

                        //drop(raw_buffer);

                        let length_result = buffer.read_unsigned_varint_32();
                        let id_result = buffer.read_unsigned_varint_32();

                        if length_result.is_err() || id_result.is_err() {
                            error!("Error while reading packet ID or length! Oh no, dropping connection");

                            self.disconnect();
                            break;
                        }

                        let packet_header = PacketHeader { length: length_result.unwrap(), id: id_result.unwrap() };

                        info!("Read {} bytes, length is {}, id is {}", count, packet_header.length, packet_header.id);

                        info!("Remaining buffer size is {}", buffer.remaining());

                        //TODO: Move to a MinecraftClientConnection, determine if the client is Forge or Vanilla, and set the GameState to HANDSHAKE

                        if packet_header.id == 0 {
                            if packet_header.length == 1 {

                                //This is a request packet
                                debug!("Received a Server Status Request packet");

                            } else {

                                //This is a handshake packet
                                debug!("Received a Handshake packet");

                                let protocol_result = buffer.read_unsigned_varint_32();

                                if protocol_result.is_err() {
                                    error!("Error reading protocol version");
                                    self.disconnect();
                                    break;
                                }

                                let hostname: String = buffer.read_utf8_string();

                                let port: u16 = buffer.read_unsigned_short();

                                debug!("Protocol version {}, hostname: {}, port: {}", protocol_result.unwrap(), hostname, port);

                            }
                        }

                        // This is a memory leak. We need to get the time of last packet and check to see if it's more than 20 seconds ago
                    }
                }

            }

        }

        info!("Connection closed");

    }

}<commit_msg>Add some missing derived traits in game_connection.rs<commit_after>//! Utilities to do with connections between a Minecraft or Forge client and Netherrack

extern crate chrono;
use self::chrono::duration::Duration;

use super::packet::PacketHeader;

use std::collections::VecDeque;

use std::net::{Shutdown, TcpStream};

use std::io::Read;

use super::deque_buffer::DequeBuffer;

/// An enum describing the current connection's state
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum ConnectionState {

    /// Connection is in handshake mode
    HANDSHAKE,

    /// Connection is in login mode
    LOGIN,

    /// Connection is in status mode
    STATUS,

    /// Connection is in play mode
    PLAY

}

/// A struct defining a game connection
#[derive(Debug)]
pub struct GameConnection {

    /// The TCP stream bound to this GameConnection
    pub stream: TcpStream,

    /// The state of this GameConnection
    pub state: ConnectionState

}

impl GameConnection {

    /// Creates a new GameConnection
    pub fn new(stream: TcpStream) -> GameConnection {
        GameConnection {
            stream: stream,
            state: ConnectionState::HANDSHAKE
        }
    }

    pub fn disconnect(&mut self) {
        //TODO: Check to see if in ConnectionState::PLAY, otherwise
        let result = self.stream.shutdown(Shutdown::Both);

        if result.is_ok() == false {
            error!("Error disconnecting: {:?}", result);
        }

    }

    /// Starts listening on the connection
    pub fn start_listening(&mut self) {

        info!("Got a new client from {}! Oh my!", self.stream.peer_addr().unwrap());

        let mut timeout_duration = Duration::zero();

        loop {

            if timeout_duration.num_seconds() >= 10 {
                info!("Client timed out");
                self.disconnect();
                break;
            }

            let mut raw_buffer = vec![0u8; 512];

            match self.stream.read(&mut raw_buffer) {

                Err(error) => {
                    // Connection dropped out or something broke
                    // In the future, we use the customized NetherrackStream to see if we're in GAME mode, and if so, get the attached player and start saving their information and get rid of them
                    // For now, we just exit the loop
                    error!("Got an error! {}", error);

                    self.disconnect();
                    break;
                }
                Ok(count) => {
                    if count == 0 {
                        //Nothing in stream, let's sleep for a few milliseconds and try again
                        timeout_duration = timeout_duration + Duration::milliseconds(2);
                        ::std::thread::sleep_ms(2);
                    } else {

                        timeout_duration = Duration::zero();

                        // Now truncate the raw buffer - Don't worry, it will reallocate to 512 on the next networking loop
                        raw_buffer.truncate(count);

                        let mut backing: VecDeque<u8> = VecDeque::<u8>::with_capacity(count);

                        for b in raw_buffer {

                            backing.push_back(b);
                        }

                        let mut buffer = DequeBuffer::from(backing);

                        //drop(raw_buffer);

                        let length_result = buffer.read_unsigned_varint_32();
                        let id_result = buffer.read_unsigned_varint_32();

                        if length_result.is_err() || id_result.is_err() {
                            error!("Error while reading packet ID or length! Oh no, dropping connection");

                            self.disconnect();
                            break;
                        }

                        let packet_header = PacketHeader { length: length_result.unwrap(), id: id_result.unwrap() };

                        info!("Read {} bytes, length is {}, id is {}", count, packet_header.length, packet_header.id);

                        info!("Remaining buffer size is {}", buffer.remaining());

                        //TODO: Move to a MinecraftClientConnection, determine if the client is Forge or Vanilla, and set the GameState to HANDSHAKE

                        if packet_header.id == 0 {
                            if packet_header.length == 1 {

                                //This is a request packet
                                debug!("Received a Server Status Request packet");

                            } else {

                                //This is a handshake packet
                                debug!("Received a Handshake packet");

                                let protocol_result = buffer.read_unsigned_varint_32();

                                if protocol_result.is_err() {
                                    error!("Error reading protocol version");
                                    self.disconnect();
                                    break;
                                }

                                let hostname: String = buffer.read_utf8_string();

                                let port: u16 = buffer.read_unsigned_short();

                                debug!("Protocol version {}, hostname: {}, port: {}", protocol_result.unwrap(), hostname, port);

                            }
                        }

                        // This is a memory leak. We need to get the time of last packet and check to see if it's more than 20 seconds ago
                    }
                }

            }

        }

        info!("Connection closed");

    }

}<|endoftext|>