<commit_before>extern crate serde_yaml;
extern crate serde;
#[macro_use]
extern crate serde_derive;

#[macro_use]
extern crate slog;
extern crate slog_scope;
extern crate slog_html;
extern crate slog_journald;
extern crate slog_stdlog;
extern crate slog_stream;
extern crate slog_term;

extern crate wlc;
#[macro_use]
extern crate fireplace_lib;

use fireplace_lib::callback::IntoCallback;
use fireplace_lib::handlers::*;
use fireplace_lib::handlers::keyboard::KeyHandler;

use std::env;
use std::fs::OpenOptions;
use std::path::PathBuf;
use std::process::Command;

use wlc::{Callback, View};

mod logger;
mod config;
pub use self::config::Config;

fn try_config_locations(paths: &[PathBuf]) -> Config {
    for path in paths {
        if path.exists() {
            return serde_yaml::from_reader(OpenOptions::new()
                    .read(true)
                    .open(path)
                    .unwrap())
                .expect("Malformed config file");
        }
    }
    serde_yaml::from_str("").unwrap()
}

fn main() {

    // Parse configuration
    let mut locations = Vec::new();
    if let Ok(xdg_dir) = env::var("XDG_CONFIG_DIR") {
        locations.push(PathBuf::from(&xdg_dir).join("fireplace").join(".fireplace.yaml"));
        locations.push(PathBuf::from(&xdg_dir).join("fireplace").join("fireplace.yaml"));
        locations.push(PathBuf::from(&xdg_dir).join(".fireplace.yaml"));
        locations.push(PathBuf::from(&xdg_dir).join("fireplace.yaml"));
    }
    if let Some(home_dir) = env::home_dir() {
        locations.push(PathBuf::from(&home_dir).join(".config").join("fireplace").join(".fireplace.yaml"));
        locations.push(PathBuf::from(&home_dir).join(".config").join("fireplace").join("fireplace.yaml"));
        locations.push(PathBuf::from(&home_dir).join(".config").join(".fireplace.yaml"));
        locations.push(PathBuf::from(&home_dir).join(".config").join("fireplace.yaml"));
        locations.push(PathBuf::from(&home_dir).join(".fireplace.yaml"));
    }
    locations.push(PathBuf::from("/etc/fireplace/fireplace.yaml"));
    locations.push(PathBuf::from("/etc/fireplace.yaml"));
    let mut config = try_config_locations(&locations);

    // Initialize logger
    logger::init(config.logging);

    // Initialize the key combinations
    let mut keyboard_handler = KeyboardHandler::new();

    for (command, pattern) in config.keys.drain() {
        keyboard_handler.register(pattern, {
            struct GlobalKeyHandler {
                command: String,
            }
            impl KeyHandler for GlobalKeyHandler {
                fn handle_key(&mut self, _time: u32, _view: Option<&View>) {
                    match &*self.command {
                        "terminate" => wlc::terminate(),
                        x => {
                            warn!(slog_scope::logger(),
                                  "Unknown command {}. Ignoring KeyBinding",
                                  x)
                        }
                    };
                }
            }

            GlobalKeyHandler { command: command }
        });
    }

    for (command, pattern) in config.view.keys.drain() {
        keyboard_handler.register(pattern, {
            struct ViewKeyHandler {
                command: String,
            }
            impl KeyHandler for ViewKeyHandler {
                fn handle_key(&mut self, _time: u32, view: Option<&View>) {
                    if let Some(view) = view {
                        match &*self.command {
                            "close" => view.close(),
                            x => {
                                warn!(slog_scope::logger(),
                                      "Unknown command {}. Ignoring KeyBinding",
                                      x)
                            }
                        };
                    }
                }
            }

            ViewKeyHandler { command: command }
        });
    }

    for (command, pattern) in config.exec.keys.drain() {
        keyboard_handler.register(pattern, {
            struct ExecKeyHandler {
                command: String,
            }
            impl KeyHandler for ExecKeyHandler {
                fn handle_key(&mut self, _time: u32, _view: Option<&View>) {
                    use std::process;

                    match Command::new(env::var("SHELL").unwrap_or_else(|_| String::from("sh")))
                              .arg("-c")
                              .arg(self.command.clone())
                              .stdin(process::Stdio::null())
                              .stdout(process::Stdio::null())
                              .stderr(process::Stdio::null())
                              .spawn() {
                        Ok(_) => {}
                        Err(x) => {
                            warn!(slog_scope::logger(),
                                  "Command {} failed with {}",
                                  self.command,
                                  x)
                        }
                    };
                }
            }

            ExecKeyHandler { command: command }
        });
    }

    // load the other handlers are start the compositor

    let mut handlers: Vec<Box<Callback>> = Vec::new();

    handlers.push(Box::new(StoreHandler::new().into_callback()));
    handlers.push(Box::new(OutputConfigHandler::new(config.outputs)));
    handlers.push(Box::new(geometry::GeometryHandler::new().into_callback()));
    handlers.push(Box::new(geometry::GapsHandler::new().into_callback()));

    #[cfg(feature = "ui")]
    {
        handlers.push(Box::new(render::conrod::ConrodHandler::new().into_callback()));

        handlers.push(Box::new(render::conrod::provider::background::BackgroundHandler::new()
                                   .into_callback()));
        handlers.push(Box::new(render::conrod::provider::statusbar::StatusbarHandler::new().into_callback()));

        handlers.push(Box::new(render::ScreenshotHandler::new(config.screenshot)));
    }

    handlers.push(Box::new(workspaces::WorkspaceHandler::new(config.workspace).into_callback()));
    handlers.push(Box::new(FocusHandler::new(config.focus).into_callback()));
    handlers.push(Box::new(PointerHandler::new()));
    handlers.push(Box::new(keyboard_handler.into_callback()));

    wlc::init(handlers.into_callback()).unwrap();
}
<commit_msg>Fix default config<commit_after>extern crate serde_yaml;
extern crate serde;
#[macro_use]
extern crate serde_derive;

#[macro_use]
extern crate slog;
extern crate slog_scope;
extern crate slog_html;
extern crate slog_journald;
extern crate slog_stdlog;
extern crate slog_stream;
extern crate slog_term;

extern crate wlc;
#[macro_use]
extern crate fireplace_lib;

use fireplace_lib::callback::IntoCallback;
use fireplace_lib::handlers::*;
use fireplace_lib::handlers::keyboard::KeyHandler;

use std::env;
use std::fs::OpenOptions;
use std::path::PathBuf;
use std::process::Command;

use wlc::{Callback, View};

mod logger;
mod config;
pub use self::config::Config;

fn try_config_locations(paths: &[PathBuf]) -> Config {
    for path in paths {
        if path.exists() {
            return serde_yaml::from_reader(OpenOptions::new()
                    .read(true)
                    .open(path)
                    .unwrap())
                .expect("Malformed config file");
        }
    }
    Config::default()
}

fn main() {

    // Parse configuration
    let mut locations = Vec::new();
    if let Ok(xdg_dir) = env::var("XDG_CONFIG_DIR") {
        locations.push(PathBuf::from(&xdg_dir).join("fireplace").join(".fireplace.yaml"));
        locations.push(PathBuf::from(&xdg_dir).join("fireplace").join("fireplace.yaml"));
        locations.push(PathBuf::from(&xdg_dir).join(".fireplace.yaml"));
        locations.push(PathBuf::from(&xdg_dir).join("fireplace.yaml"));
    }
    if let Some(home_dir) = env::home_dir() {
        locations.push(PathBuf::from(&home_dir).join(".config").join("fireplace").join(".fireplace.yaml"));
        locations.push(PathBuf::from(&home_dir).join(".config").join("fireplace").join("fireplace.yaml"));
        locations.push(PathBuf::from(&home_dir).join(".config").join(".fireplace.yaml"));
        locations.push(PathBuf::from(&home_dir).join(".config").join("fireplace.yaml"));
        locations.push(PathBuf::from(&home_dir).join(".fireplace.yaml"));
    }
    locations.push(PathBuf::from("/etc/fireplace/fireplace.yaml"));
    locations.push(PathBuf::from("/etc/fireplace.yaml"));
    let mut config = try_config_locations(&locations);

    // Initialize logger
    logger::init(config.logging);

    // Initialize the key combinations
    let mut keyboard_handler = KeyboardHandler::new();

    for (command, pattern) in config.keys.drain() {
        keyboard_handler.register(pattern, {
            struct GlobalKeyHandler {
                command: String,
            }
            impl KeyHandler for GlobalKeyHandler {
                fn handle_key(&mut self, _time: u32, _view: Option<&View>) {
                    match &*self.command {
                        "terminate" => wlc::terminate(),
                        x => {
                            warn!(slog_scope::logger(),
                                  "Unknown command {}. Ignoring KeyBinding",
                                  x)
                        }
                    };
                }
            }

            GlobalKeyHandler { command: command }
        });
    }

    for (command, pattern) in config.view.keys.drain() {
        keyboard_handler.register(pattern, {
            struct ViewKeyHandler {
                command: String,
            }
            impl KeyHandler for ViewKeyHandler {
                fn handle_key(&mut self, _time: u32, view: Option<&View>) {
                    if let Some(view) = view {
                        match &*self.command {
                            "close" => view.close(),
                            x => {
                                warn!(slog_scope::logger(),
                                      "Unknown command {}. Ignoring KeyBinding",
                                      x)
                            }
                        };
                    }
                }
            }

            ViewKeyHandler { command: command }
        });
    }

    for (command, pattern) in config.exec.keys.drain() {
        keyboard_handler.register(pattern, {
            struct ExecKeyHandler {
                command: String,
            }
            impl KeyHandler for ExecKeyHandler {
                fn handle_key(&mut self, _time: u32, _view: Option<&View>) {
                    use std::process;

                    match Command::new(env::var("SHELL").unwrap_or_else(|_| String::from("sh")))
                              .arg("-c")
                              .arg(self.command.clone())
                              .stdin(process::Stdio::null())
                              .stdout(process::Stdio::null())
                              .stderr(process::Stdio::null())
                              .spawn() {
                        Ok(_) => {}
                        Err(x) => {
                            warn!(slog_scope::logger(),
                                  "Command {} failed with {}",
                                  self.command,
                                  x)
                        }
                    };
                }
            }

            ExecKeyHandler { command: command }
        });
    }

    // load the other handlers are start the compositor

    let mut handlers: Vec<Box<Callback>> = Vec::new();

    handlers.push(Box::new(StoreHandler::new().into_callback()));
    handlers.push(Box::new(OutputConfigHandler::new(config.outputs)));
    handlers.push(Box::new(geometry::GeometryHandler::new().into_callback()));
    handlers.push(Box::new(geometry::GapsHandler::new().into_callback()));

    #[cfg(feature = "ui")]
    {
        handlers.push(Box::new(render::conrod::ConrodHandler::new().into_callback()));

        handlers.push(Box::new(render::conrod::provider::background::BackgroundHandler::new()
                                   .into_callback()));
        handlers.push(Box::new(render::conrod::provider::statusbar::StatusbarHandler::new().into_callback()));

        handlers.push(Box::new(render::ScreenshotHandler::new(config.screenshot)));
    }

    handlers.push(Box::new(workspaces::WorkspaceHandler::new(config.workspace).into_callback()));
    handlers.push(Box::new(FocusHandler::new(config.focus).into_callback()));
    handlers.push(Box::new(PointerHandler::new()));
    handlers.push(Box::new(keyboard_handler.into_callback()));

    wlc::init(handlers.into_callback()).unwrap();
}
<|endoftext|>


<commit_before>#![deny(warnings)]

#[macro_use]
extern crate diesel;
extern crate dotenv;

use diesel::*;
use diesel::migrations::setup_database;
use diesel::pg::PgConnection;
use dotenv::dotenv;
use std::env;

table! {
    information_schema.tables (table_name) {
        table_name -> Text,
    }
}

fn main() {
    let _ = dotenv();
    // This code will eventually break, as it relies on internal details of Diesel.
    // If this function stops working, it's probably better to just delete it.
    let conn = PgConnection::establish(&env::var("DATABASE_URL").unwrap()).unwrap();

    if !table_exists("__diesel_schema_migrations", &conn) {
        setup_database(&conn).unwrap();
    }

    if table_exists("schema_migrations", &conn) {
        conn.transaction(|| {
            conn.execute("INSERT INTO __diesel_schema_migrations (
                SELECT version::text AS version, CURRENT_TIMESTAMP as run_on
                    FROM schema_migrations
            ) ON CONFLICT DO NOTHING")?;
        }).unwrap();
    }

    println!("The `migrate` binary is no longer used. Use `diesel migration run` \
              and `diesel migration revert` instead.");
}

fn table_exists(target: &str, conn: &PgConnection) -> bool {
    use self::tables::dsl::*;
    use diesel::expression::dsl::exists;

    let table_query = tables.filter(table_name.eq(target));
    select(exists(table_query)).get_result(conn).unwrap()
}
<commit_msg>One query = no transaction needed<commit_after>#![deny(warnings)]

#[macro_use]
extern crate diesel;
extern crate dotenv;

use diesel::*;
use diesel::migrations::setup_database;
use diesel::pg::PgConnection;
use dotenv::dotenv;
use std::env;

table! {
    information_schema.tables (table_name) {
        table_name -> Text,
    }
}

fn main() {
    let _ = dotenv();
    // This code will eventually break, as it relies on internal details of Diesel.
    // If this function stops working, it's probably better to just delete it.
    let conn = PgConnection::establish(&env::var("DATABASE_URL").unwrap()).unwrap();

    if !table_exists("__diesel_schema_migrations", &conn) {
        setup_database(&conn).unwrap();
    }

    if table_exists("schema_migrations", &conn) {
        conn.execute("INSERT INTO __diesel_schema_migrations (
            SELECT version::text AS version, CURRENT_TIMESTAMP as run_on
                FROM schema_migrations
        ) ON CONFLICT DO NOTHING").unwrap();
    }

    println!("The `migrate` binary is no longer used. Use `diesel migration run` \
              and `diesel migration revert` instead.");
}

fn table_exists(target: &str, conn: &PgConnection) -> bool {
    use self::tables::dsl::*;
    use diesel::expression::dsl::exists;

    let table_query = tables.filter(table_name.eq(target));
    select(exists(table_query)).get_result(conn).unwrap()
}
<|endoftext|>


<commit_before>//! Edo is a VERY simple templating language. It allows you to register handlers that are executed when their matching names are found in the template.
//!
//! For example, with the template `"Hello {name}"`, the `name` handler would be executed and the string it returns would be substituted in place of the original `{name}`.
#![deny(missing_docs)]

#[macro_use]
extern crate nom;

mod error;
mod parse;

use std::str;
use std::collections::HashMap;

use error::EdoError;
use parse::Expression;

/// A single template. Allows registering of handlers and rendering
pub struct Edo<'a> {
    #[doc(hidden)]
    handlers: HashMap<&'a str, Box<Fn() -> &'a str>>,
    template: Vec<Expression<'a>>,
}

impl<'a> Edo<'a> {
    /// Creates a new template instance.
    ///
    /// # Examples
    /// ```no_run
    /// # #![allow(unused_variables)]
    /// # use edo::Edo;
    /// let template = Edo::new("Hello {name}");
    /// ```
    pub fn new(template_string: &'a str) -> Result<Edo<'a>, EdoError> {
        Ok(Edo {
            handlers: HashMap::new(),
            template: try!(parse::parse(template_string)),
        })
    }

    /// Register a new function handler
    ///
    /// # Examples
    /// ```no_run
    /// # #![allow(unused_variables)]
    /// # use edo::Edo;
    /// let mut template = Edo::new("Hello {name}").unwrap();
    /// template.register_handler("name", || "World!");
    /// ```
    pub fn register_handler<F>(&mut self, name: &'a str, handler: F) where
        F: 'static + Fn() -> &'a str {
        self.handlers.insert(name, Box::new(handler));
    }

    /// Render template into a string
    ///
    /// # Examples
    /// ```
    /// # use edo::Edo;
    /// let mut template = Edo::new("Hello {name}").unwrap();
    /// template.register_handler("name", || "World!");
    /// let output = template.render();
    /// assert_eq!(output, "Hello World!");
    /// ```
    // TODO: add a strict mode that errors when there is no handler
    pub fn render(self) -> String {
        // Iterate over the template and
        // 1. Leave literals untouched
        // 2. Call the handlers for each function call and replace within the output
        self.template.iter()
            .map(|expression| match *expression {
                Expression::Literal(text) => text,
                Expression::Function { name, ref arguments } => {
                    match self.handlers.get(name) {
                        None => "",
                        Some(handler) => handler(),
                    }
                }
            })
            .collect::<Vec<&str>>()
            .concat()
    }
}

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

    #[test]
    fn create_new_edo() {
        let edo = Edo::new("Hello {name}");
        assert!(edo.is_ok());
    }

    #[test]
    fn register_handler() {
        let mut edo = match Edo::new("Hello {name}") {
            Ok(edo) => edo,
            Err(err) => panic!(err),
        };
        edo.register_handler("name", || "World!");
        assert!(edo.handlers.get("name").is_some());
    }

    #[test]
    fn render_template() {
        let mut edo = match Edo::new("Hello {name}") {
            Ok(edo) => edo,
            Err(err) => panic!(err),
        };
        edo.register_handler("name", || "World!");
        assert_eq!(
            edo.render(),
            "Hello World!"
        );
    }

    #[test]
    fn render_template_with_missing_handler() {
        let mut edo = match Edo::new("Hello {name}") {
            Ok(edo) => edo,
            Err(err) => panic!(err),
        };
        assert_eq!(
            edo.render(),
            "Hello "
        );
    }
}
<commit_msg>Allow handling of arguments<commit_after>//! Edo is a VERY simple templating language. It allows you to register handlers that are executed when their matching names are found in the template.
//!
//! For example, with the template `"Hello {name}"`, the `name` handler would be executed and the string it returns would be substituted in place of the original `{name}`.
#![deny(missing_docs)]

#[macro_use]
extern crate nom;

mod error;
mod parse;

use std::str;
use std::collections::HashMap;

use error::EdoError;
use parse::Expression;

/// A single template. Allows registering of handlers and rendering
pub struct Edo<'a> {
    #[doc(hidden)]
    handlers: HashMap<&'a str, Box<Fn(Vec<&'a str>) -> String>>,
    template: Vec<Expression<'a>>,
}

impl<'a> Edo<'a> {
    /// Creates a new template instance.
    ///
    /// # Examples
    /// ```no_run
    /// # #![allow(unused_variables)]
    /// # use edo::Edo;
    /// let template = Edo::new("Hello {name}");
    /// ```
    pub fn new(template_string: &'a str) -> Result<Edo<'a>, EdoError> {
        Ok(Edo {
            handlers: HashMap::new(),
            template: try!(parse::parse(template_string)),
        })
    }

    /// Register a new function handler
    ///
    /// # Examples
    /// ```no_run
    /// # #![allow(unused_variables)]
    /// # use edo::Edo;
    /// let mut template = Edo::new("Hello {name}").unwrap();
    /// template.register_handler("name", |_| String::from("World!"));
    /// ```
    pub fn register_handler<F>(&mut self, name: &'a str, handler: F) where
        F: 'static + Fn(Vec<&'a str>) -> String {
        self.handlers.insert(name, Box::new(handler));
    }

    /// Render template into a string
    ///
    /// # Examples
    /// ```
    /// # use edo::Edo;
    /// let mut template = Edo::new("Hello {name}").unwrap();
    /// template.register_handler("name", |_| String::from("World!"));
    /// let output = template.render();
    /// assert_eq!(output, "Hello World!");
    /// ```
    // TODO: add a strict mode that errors when there is no handler
    pub fn render(self) -> String {
        // Iterate over the template and
        // 1. Leave literals untouched
        // 2. Call the handlers for each function call and replace within the output
        self.template.iter()
            .map(|expression| match *expression {
                Expression::Literal(text) => String::from(text),
                Expression::Function { name, ref arguments } => {
                    match self.handlers.get(name) {
                        None => String::from(""),
                        Some(handler) => handler(arguments.clone()),
                    }
                }
            })
            .collect::<Vec<String>>()
            .concat()
    }
}

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

    #[test]
    fn create_new_edo() {
        let edo = Edo::new("Hello {name}");
        assert!(edo.is_ok());
    }

    #[test]
    fn register_handler() {
        let mut edo = match Edo::new("Hello {name}") {
            Ok(edo) => edo,
            Err(err) => panic!(err),
        };
        edo.register_handler("name", |_| String::from("World!"));
        assert!(edo.handlers.get("name").is_some());
    }

    #[test]
    fn render_template() {
        let mut edo = match Edo::new("Hello {name}") {
            Ok(edo) => edo,
            Err(err) => panic!(err),
        };
        edo.register_handler("name", |_| String::from("World!"));
        assert_eq!(
            edo.render(),
            "Hello World!"
        );
    }

    #[test]
    fn render_template_with_missing_handler() {
        let edo = match Edo::new("Hello {name}") {
            Ok(edo) => edo,
            Err(err) => panic!(err),
        };
        assert_eq!(
            edo.render(),
            "Hello "
        );
    }

    #[test]
    fn render_template_with_arguments() {
        let mut edo = match Edo::new("Hello {name(Gio, yes)}") {
            Ok(edo) => edo,
            Err(err) => panic!(err),
        };
        edo.register_handler("name", |args|
            format!("{}{}", args[0], if args[1] == "yes" { "!" } else { "" })
        );
        assert_eq!(
            edo.render(),
            "Hello Gio!"
        );
    }
}
<|endoftext|>


<commit_before>#![feature(macro_rules, plugin_registrar, quote, phase)]

#[phase(plugin, link)]
extern crate syntax;
#[phase(plugin, link)]
extern crate rustc;

use syntax::ast;
use rustc::lint::LintPassObject;
use rustc::plugin::Registry;
use rustc::lint::{Context, LintPass, LintArray};
use rustc::middle::def;
use syntax::codemap::Span;
use syntax::parse::token;
use syntax::visit::FnKind;

declare_lint!(EXCESSIVE_BOOL_USAGE_STRUCTS, Warn,
              "Warn about exessive use of boolean members in structs.")
declare_lint!(EXCESSIVE_BOOL_USAGE_FUNCS, Warn,
              "Warn about exessive use of boolean arguments in functions.")

struct Pass;

fn node_is_bool(cx: &Context, ty: &ast::Ty) -> bool {
    match ty.node {
        ast::TyPath(_, _, id) => {
            match cx.tcx.def_map.borrow().get_copy(&id) {
                def::DefPrimTy(ast::TyBool) => true,
                _ => false,
            }
        },
        _ => false,
    }
}

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(EXCESSIVE_BOOL_USAGE_STRUCTS, EXCESSIVE_BOOL_USAGE_FUNCS)
    }

    fn check_struct_def(&mut self, cx: &Context, def: &ast::StructDef,
            _i: ast::Ident, _gen: &ast::Generics, id: ast::NodeId) {
        let mut bools = vec![];
        let mut spans = vec![];

        for field in def.fields.iter() {
            if node_is_bool(cx, &*field.node.ty) {
                match field.node {
                    ast::StructField_ { kind: ast::NamedField(ident, _), .. } => {
                        spans.push(field.span);
                        bools.push(token::get_ident(ident).get().to_string())
                    },
                    _ => {},
                }
            }
        }

        if bools.len() >= 3 {
            cx.span_lint(EXCESSIVE_BOOL_USAGE_STRUCTS, cx.tcx.map.span(id),
                format!("Struct contains an excessive number ({}) of bools ({}).  \
                    Did you want to create a state machine?",
                    bools.len(),
                    bools.connect(", ")).as_slice());
            for span in spans.iter() {
                cx.tcx.sess.span_note(*span, "boolean field defined here");
            }
        }
    }

    fn check_fn(&mut self, cx: &Context, _: FnKind, decl: &ast::FnDecl, _: &ast::Block, sp: Span, _: ast::NodeId) {
        let mut spans = vec![];
        for arg in decl.inputs.iter() {
            if node_is_bool(cx, &*arg.ty) {
                spans.push(cx.tcx.map.span(arg.id));
            }
        }

        if spans.len() >= 3 {
            cx.span_lint(EXCESSIVE_BOOL_USAGE_FUNCS, sp,
                format!("Funtion contains an excessive number ({}) of bools.  \
                    Perhaps you should use enumerated arguments?",
                    spans.len()).as_slice());
            for span in spans.iter() {
                cx.tcx.sess.span_note(*span, "boolean argument defined here");
            }
        }
    }
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_lint_pass(box Pass as LintPassObject);
}
<commit_msg>For functions, one bool is the limit.<commit_after>#![feature(macro_rules, plugin_registrar, quote, phase)]

#[phase(plugin, link)]
extern crate syntax;
#[phase(plugin, link)]
extern crate rustc;

use syntax::ast;
use rustc::lint::LintPassObject;
use rustc::plugin::Registry;
use rustc::lint::{Context, LintPass, LintArray};
use rustc::middle::def;
use syntax::codemap::Span;
use syntax::parse::token;
use syntax::visit::FnKind;

declare_lint!(EXCESSIVE_BOOL_USAGE_STRUCTS, Warn,
              "Warn about exessive use of boolean members in structs.")
declare_lint!(EXCESSIVE_BOOL_USAGE_FUNCS, Warn,
              "Warn about exessive use of boolean arguments in functions.")

struct Pass;

fn node_is_bool(cx: &Context, ty: &ast::Ty) -> bool {
    match ty.node {
        ast::TyPath(_, _, id) => {
            match cx.tcx.def_map.borrow().get_copy(&id) {
                def::DefPrimTy(ast::TyBool) => true,
                _ => false,
            }
        },
        _ => false,
    }
}

impl LintPass for Pass {
    fn get_lints(&self) -> LintArray {
        lint_array!(EXCESSIVE_BOOL_USAGE_STRUCTS, EXCESSIVE_BOOL_USAGE_FUNCS)
    }

    fn check_struct_def(&mut self, cx: &Context, def: &ast::StructDef,
            _: ast::Ident, _: &ast::Generics, id: ast::NodeId) {
        let mut bools = vec![];
        let mut spans = vec![];

        for field in def.fields.iter() {
            if node_is_bool(cx, &*field.node.ty) {
                match field.node {
                    ast::StructField_ { kind: ast::NamedField(ident, _), .. } => {
                        spans.push(field.span);
                        bools.push(token::get_ident(ident).get().to_string())
                    },
                    _ => {},
                }
            }
        }

        if bools.len() >= 3 {
            cx.span_lint(EXCESSIVE_BOOL_USAGE_STRUCTS, cx.tcx.map.span(id),
                format!("Struct contains an excessive number ({}) of bools ({}).  \
                    Did you want to create a state machine?",
                    bools.len(),
                    bools.connect(", ")).as_slice());
            for span in spans.iter() {
                cx.tcx.sess.span_note(*span, "boolean field defined here");
            }
        }
    }

    fn check_fn(&mut self, cx: &Context, _: FnKind, decl: &ast::FnDecl,
            _: &ast::Block, sp: Span, _: ast::NodeId) {
        let mut spans = vec![];
        for arg in decl.inputs.iter() {
            if node_is_bool(cx, &*arg.ty) {
                spans.push(cx.tcx.map.span(arg.id));
            }
        }

        if spans.len() > 1 {
            cx.span_lint(EXCESSIVE_BOOL_USAGE_FUNCS, sp,
                format!("Funtion contains an excessive number ({}) of bools.  \
                    Perhaps you should use enumerated arguments?",
                    spans.len()).as_slice());
            for span in spans.iter() {
                cx.tcx.sess.span_note(*span, "boolean argument defined here");
            }
        }
    }
}

#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
    reg.register_lint_pass(box Pass as LintPassObject);
}
<|endoftext|>


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

//! Provides Cidr and Inet support for
//! [`postgres`](https://crates.io/crates/postgres).
//!
//! Unlike several other names of this pattern, this is not affiliated
//! with or supported by the [author](https://github.com/sfackler) of
//! `postgres`.
//!
//! Please see the `examples/` folder in the crate root for a simple example.
#![doc(html_root_url="https://docs.rs/postgres-inet/0.1.0")]
#![warn(missing_docs)]

#[macro_use]
extern crate postgres;

extern crate byteorder;
extern crate libc;

mod tests;

use postgres::types::{Type, ToSql, FromSql, IsNull};
use std::error::Error;
use std::fmt;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};

const IPV4_NETMASK_FULL: u8 = 32;
const IPV4_ADDRESS_FAMILY: u8 = ::libc::AF_INET as u8;
const IPV4_ADDRESS_SIZE: u8 = 4;

const IPV6_NETMASK_FULL: u8 = 128;
const IPV6_ADDRESS_FAMILY: u8 = (::libc::AF_INET + 1) as u8;
const IPV6_ADDRESS_SIZE: u8 = 16;

#[derive(Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
/// An IP address with a netmask.
pub struct MaskedIpAddr {
    addr: IpAddr,
    mask: u8,
}

impl MaskedIpAddr {
    /// Creates a new `MaskedIpAddr` from components.
    ///
    /// # Panics
    ///
    /// Panics if the netmask is greater than 32 for an IPv4 address, or is
    /// greater than 128 for an IPv6 address.
    ///
    /// # Examples
    ///
    /// To represent an address:
    ///
    /// ```
    /// # use postgres_inet::MaskedIpAddr;
    /// # use std::net::Ipv4Addr;
    /// let ip = Ipv4Addr::new(192, 0, 2, 142);
    /// MaskedIpAddr::new(ip, 32);
    /// ```
    ///
    /// To represent a network:
    ///
    /// ```
    /// # use postgres_inet::MaskedIpAddr;
    /// # use std::net::Ipv6Addr;
    /// let network = Ipv6Addr::new(0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0);
    /// MaskedIpAddr::new(network, 32);
    /// ```
    pub fn new<I: Into<IpAddr>>(addr: I, mask: u8) -> MaskedIpAddr {
        let addr = addr.into();

        if match addr {
            IpAddr::V4(_) => mask > IPV4_NETMASK_FULL,
            IpAddr::V6(_) => mask > IPV6_NETMASK_FULL,
        } {
            panic!("Mask too big for IP type!");
        }

        MaskedIpAddr {
            addr: addr,
            mask: mask,
        }
    }

    /// Returns true for the special 'unspecified' address.
    ///
    /// # Examples
    ///
    /// ```
    /// # use postgres_inet::MaskedIpAddr;
    /// # use std::net::{Ipv4Addr, Ipv6Addr};
    /// assert!(MaskedIpAddr::new(Ipv4Addr::new(0, 0, 0, 0), 32).is_unspecified());
    /// assert!(MaskedIpAddr::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0), 128).is_unspecified());
    /// ```
    pub fn is_unspecified(&self) -> bool {
        self.addr.is_unspecified()
    }

    /// Returns true if this is a loopback address.
    ///
    /// # Examples
    ///
    /// ```
    /// # use postgres_inet::MaskedIpAddr;
    /// # use std::net::{Ipv4Addr, Ipv6Addr};
    /// assert!(MaskedIpAddr::new(Ipv4Addr::new(127, 0, 0, 1), 32).is_loopback());
    /// assert!(MaskedIpAddr::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 128).is_loopback());
    /// ```
    pub fn is_loopback(&self) -> bool {
        self.addr.is_loopback()
    }

    /// Returns true if this is a multicast address.
    ///
    /// # Examples
    ///
    /// ```
    /// # use postgres_inet::MaskedIpAddr;
    /// # use std::net::{Ipv4Addr, Ipv6Addr};
    /// assert!(MaskedIpAddr::new(Ipv4Addr::new(224, 254, 0, 0), 32).is_multicast());
    /// assert!(MaskedIpAddr::new(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0), 128).is_multicast());
    /// ```
    pub fn is_multicast(&self) -> bool {
        self.addr.is_multicast()
    }

    /// Consumes the `MaskedIpAddr`, returning the IP address and netmask.
    ///
    /// # Examples
    ///
    /// ```
    /// # use postgres_inet::MaskedIpAddr;
    /// # use std::net::Ipv4Addr;
    /// let network = Ipv4Addr::new(198, 51, 100, 0);
    /// let (network_b, netmask) = MaskedIpAddr::new(network.clone(), 24).into_inner();
    /// assert_eq!(network, network_b);
    /// assert_eq!(netmask, 24);
    /// ```
    pub fn into_inner(self) -> (IpAddr, u8) {
        (self.addr, self.mask)
    }
}

impl From<Ipv4Addr> for MaskedIpAddr {
    fn from(ipv4: Ipv4Addr) -> MaskedIpAddr {
        MaskedIpAddr {
            addr: IpAddr::V4(ipv4),
            mask: IPV4_NETMASK_FULL,
        }
    }
}

impl From<Ipv6Addr> for MaskedIpAddr {
    fn from(ipv6: Ipv6Addr) -> MaskedIpAddr {
        MaskedIpAddr {
            addr: IpAddr::V6(ipv6),
            mask: IPV6_NETMASK_FULL,
        }
    }
}

impl From<IpAddr> for MaskedIpAddr {
    fn from(ip: IpAddr) -> MaskedIpAddr {
        MaskedIpAddr {
            mask: match ip {
                IpAddr::V4(_) => IPV4_NETMASK_FULL,
                IpAddr::V6(_) => IPV6_NETMASK_FULL,
            },
            addr: ip,
        }
    }
}

impl From<MaskedIpAddr> for IpAddr {
    fn from(mip: MaskedIpAddr) -> IpAddr {
        mip.addr
    }
}

impl fmt::Display for MaskedIpAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.addr {
            IpAddr::V4(ipv4) => {
                match self.mask {
                    IPV4_NETMASK_FULL => ipv4.fmt(f),
                    _ => write!(f, "{}/{}", ipv4, self.mask),
                }
            }
            IpAddr::V6(ipv6) => {
                match self.mask {
                    IPV6_NETMASK_FULL => ipv6.fmt(f),
                    _ => write!(f, "{}/{}", ipv6, self.mask),
                }
            }
        }

    }
}

impl fmt::Debug for MaskedIpAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}/{}", self.addr, self.mask)
    }
}

impl FromSql for MaskedIpAddr {
    fn from_sql(_: &Type, raw: &[u8]) -> Result<Self, Box<Error + 'static + Sync + Send>> {
        // The address family is at raw[0], as AF_INET for ipv4 or (AF_INET + 1)
        // for ipv6.  It's unneeded, as `nb` at raw[3] tells us the version just as
        // well. A bool of the `cidr`ness is at raw[2]. It's also unneeded, as it
        // doesn't affect our codepath in any way whatsoever.

        Ok(MaskedIpAddr {
            addr: match raw[3] {
                IPV4_ADDRESS_SIZE => IpAddr::V4(Ipv4Addr::new(raw[4], raw[5], raw[6], raw[7])),
                IPV6_ADDRESS_SIZE => {
                    // The IPv6 is sent in network byte order, so we need to convert it to the host
                    // order.
                    use byteorder::{NetworkEndian, ReadBytesExt};
                    use std::io::Read;

                    let mut raw = raw;
                    raw.read_exact(&mut [0u8; 4])?; // throw away the first four bytes
                    IpAddr::V6(Ipv6Addr::new(raw.read_u16::<NetworkEndian>()?,
                                             raw.read_u16::<NetworkEndian>()?,
                                             raw.read_u16::<NetworkEndian>()?,
                                             raw.read_u16::<NetworkEndian>()?,
                                             raw.read_u16::<NetworkEndian>()?,
                                             raw.read_u16::<NetworkEndian>()?,
                                             raw.read_u16::<NetworkEndian>()?,
                                             raw.read_u16::<NetworkEndian>()?))
                }
                _ => panic!("Unknown Internet Protocol Version!"),
            },
            mask: raw[1],
        })
    }

    fn accepts(ty: &Type) -> bool {
        match *ty {
            Type::Cidr | Type::Inet => true,
            _ => false,
        }
    }
}

impl ToSql for MaskedIpAddr {
    fn to_sql(&self, ty: &Type, w: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>> {
        // We're relying on the optimizer to clean this up.

        w.push(match self.addr { // Address Family
            IpAddr::V4(_) => IPV4_ADDRESS_FAMILY,
            IpAddr::V6(_) => IPV6_ADDRESS_FAMILY,
        });
        w.push(self.mask); // Subnet mask
        w.push(match *ty { // cidr
            Type::Cidr => true as u8,
            Type::Inet => false as u8,
            _ => unreachable!(),
        });
        w.push(match self.addr {
            IpAddr::V4(_) => IPV4_ADDRESS_SIZE,
            IpAddr::V6(_) => IPV6_ADDRESS_SIZE,
        });
        match self.addr { // Luckily, ipv6.octets() outputs in Network Byte Order.
            IpAddr::V4(ipv4) => w.append(&mut ipv4.octets().to_vec()),
            IpAddr::V6(ipv6) => w.append(&mut ipv6.octets().to_vec()),
        };

        Ok(IsNull::No)
    }

    accepts!(Type::Cidr, Type::Inet);
    to_sql_checked!();
}
<commit_msg>Improve documentation compliance with RFC 505.<commit_after>// Copyright 2017 Ethan Welker
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Provides Cidr and Inet support for [`postgres`][1].
//!
//! Unlike several other names of this pattern, this is not affiliated
//! with or supported by the [author][2] of [`postgres`][1].
//!
//! Please see the `examples/` folder in the crate root for a simple example.
//!
//! [1]: https://crates.io/crates/postgres
//! [2]: https://github.com/sfackler
#![doc(html_root_url="https://docs.rs/postgres-inet/0.1.0")]
#![warn(missing_docs)]

#[macro_use]
extern crate postgres;

extern crate byteorder;
extern crate libc;

mod tests;

use postgres::types::{Type, ToSql, FromSql, IsNull};
use std::error::Error;
use std::fmt;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};

const IPV4_NETMASK_FULL: u8 = 32;
const IPV4_ADDRESS_FAMILY: u8 = ::libc::AF_INET as u8;
const IPV4_ADDRESS_SIZE: u8 = 4;

const IPV6_NETMASK_FULL: u8 = 128;
const IPV6_ADDRESS_FAMILY: u8 = (::libc::AF_INET + 1) as u8;
const IPV6_ADDRESS_SIZE: u8 = 16;

#[derive(Clone, Eq, PartialEq, Hash, PartialOrd, Ord)]
/// An IP address with a netmask.
pub struct MaskedIpAddr {
    addr: IpAddr,
    mask: u8,
}

impl MaskedIpAddr {
    /// Creates a new `MaskedIpAddr` from components.
    ///
    /// # Panics
    ///
    /// Panics if the netmask is greater than 32 for an IPv4 address, or is
    /// greater than 128 for an IPv6 address.
    ///
    /// # Examples
    ///
    /// To represent an address:
    ///
    /// ```rust
    /// # use postgres_inet::MaskedIpAddr;
    /// # use std::net::Ipv4Addr;
    /// let ip = Ipv4Addr::new(192, 0, 2, 142);
    /// MaskedIpAddr::new(ip, 32);
    /// ```
    ///
    /// To represent a network:
    ///
    /// ```rust
    /// # use postgres_inet::MaskedIpAddr;
    /// # use std::net::Ipv6Addr;
    /// let network = Ipv6Addr::new(0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0);
    /// MaskedIpAddr::new(network, 32);
    /// ```
    pub fn new<I: Into<IpAddr>>(addr: I, mask: u8) -> MaskedIpAddr {
        let addr = addr.into();

        if match addr {
            IpAddr::V4(_) => mask > IPV4_NETMASK_FULL,
            IpAddr::V6(_) => mask > IPV6_NETMASK_FULL,
        } {
            panic!("Mask too big for IP type!");
        }

        MaskedIpAddr {
            addr: addr,
            mask: mask,
        }
    }

    /// Returns true for the special 'unspecified' address.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use postgres_inet::MaskedIpAddr;
    /// # use std::net::{Ipv4Addr, Ipv6Addr};
    /// assert!(MaskedIpAddr::new(Ipv4Addr::new(0, 0, 0, 0), 32).is_unspecified());
    /// assert!(MaskedIpAddr::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0), 128).is_unspecified());
    /// ```
    pub fn is_unspecified(&self) -> bool {
        self.addr.is_unspecified()
    }

    /// Returns true if this is a loopback address.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use postgres_inet::MaskedIpAddr;
    /// # use std::net::{Ipv4Addr, Ipv6Addr};
    /// assert!(MaskedIpAddr::new(Ipv4Addr::new(127, 0, 0, 1), 32).is_loopback());
    /// assert!(MaskedIpAddr::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 128).is_loopback());
    /// ```
    pub fn is_loopback(&self) -> bool {
        self.addr.is_loopback()
    }

    /// Returns true if this is a multicast address.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use postgres_inet::MaskedIpAddr;
    /// # use std::net::{Ipv4Addr, Ipv6Addr};
    /// assert!(MaskedIpAddr::new(Ipv4Addr::new(224, 254, 0, 0), 32).is_multicast());
    /// assert!(MaskedIpAddr::new(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0), 128).is_multicast());
    /// ```
    pub fn is_multicast(&self) -> bool {
        self.addr.is_multicast()
    }

    /// Consumes the `MaskedIpAddr`, returning the IP address and netmask.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use postgres_inet::MaskedIpAddr;
    /// # use std::net::Ipv4Addr;
    /// let network = Ipv4Addr::new(198, 51, 100, 0);
    /// let (network_b, netmask) = MaskedIpAddr::new(network.clone(), 24).into_inner();
    /// assert_eq!(network, network_b);
    /// assert_eq!(netmask, 24);
    /// ```
    pub fn into_inner(self) -> (IpAddr, u8) {
        (self.addr, self.mask)
    }
}

impl From<Ipv4Addr> for MaskedIpAddr {
    fn from(ipv4: Ipv4Addr) -> MaskedIpAddr {
        MaskedIpAddr {
            addr: IpAddr::V4(ipv4),
            mask: IPV4_NETMASK_FULL,
        }
    }
}

impl From<Ipv6Addr> for MaskedIpAddr {
    fn from(ipv6: Ipv6Addr) -> MaskedIpAddr {
        MaskedIpAddr {
            addr: IpAddr::V6(ipv6),
            mask: IPV6_NETMASK_FULL,
        }
    }
}

impl From<IpAddr> for MaskedIpAddr {
    fn from(ip: IpAddr) -> MaskedIpAddr {
        MaskedIpAddr {
            mask: match ip {
                IpAddr::V4(_) => IPV4_NETMASK_FULL,
                IpAddr::V6(_) => IPV6_NETMASK_FULL,
            },
            addr: ip,
        }
    }
}

impl From<MaskedIpAddr> for IpAddr {
    fn from(mip: MaskedIpAddr) -> IpAddr {
        mip.addr
    }
}

impl fmt::Display for MaskedIpAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.addr {
            IpAddr::V4(ipv4) => {
                match self.mask {
                    IPV4_NETMASK_FULL => ipv4.fmt(f),
                    _ => write!(f, "{}/{}", ipv4, self.mask),
                }
            }
            IpAddr::V6(ipv6) => {
                match self.mask {
                    IPV6_NETMASK_FULL => ipv6.fmt(f),
                    _ => write!(f, "{}/{}", ipv6, self.mask),
                }
            }
        }

    }
}

impl fmt::Debug for MaskedIpAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}/{}", self.addr, self.mask)
    }
}

impl FromSql for MaskedIpAddr {
    fn from_sql(_: &Type, raw: &[u8]) -> Result<Self, Box<Error + 'static + Sync + Send>> {
        // The address family is at raw[0], as AF_INET for ipv4 or (AF_INET + 1)
        // for ipv6.  It's unneeded, as `nb` at raw[3] tells us the version just as
        // well. A bool of the `cidr`ness is at raw[2]. It's also unneeded, as it
        // doesn't affect our codepath in any way whatsoever.

        Ok(MaskedIpAddr {
            addr: match raw[3] {
                IPV4_ADDRESS_SIZE => IpAddr::V4(Ipv4Addr::new(raw[4], raw[5], raw[6], raw[7])),
                IPV6_ADDRESS_SIZE => {
                    // The IPv6 is sent in network byte order, so we need to convert it to the host
                    // order.
                    use byteorder::{NetworkEndian, ReadBytesExt};
                    use std::io::Read;

                    let mut raw = raw;
                    raw.read_exact(&mut [0u8; 4])?; // throw away the first four bytes
                    IpAddr::V6(Ipv6Addr::new(raw.read_u16::<NetworkEndian>()?,
                                             raw.read_u16::<NetworkEndian>()?,
                                             raw.read_u16::<NetworkEndian>()?,
                                             raw.read_u16::<NetworkEndian>()?,
                                             raw.read_u16::<NetworkEndian>()?,
                                             raw.read_u16::<NetworkEndian>()?,
                                             raw.read_u16::<NetworkEndian>()?,
                                             raw.read_u16::<NetworkEndian>()?))
                }
                _ => panic!("Unknown Internet Protocol Version!"),
            },
            mask: raw[1],
        })
    }

    fn accepts(ty: &Type) -> bool {
        match *ty {
            Type::Cidr | Type::Inet => true,
            _ => false,
        }
    }
}

impl ToSql for MaskedIpAddr {
    fn to_sql(&self, ty: &Type, w: &mut Vec<u8>) -> Result<IsNull, Box<Error + Sync + Send>> {
        // We're relying on the optimizer to clean this up.

        w.push(match self.addr { // Address Family
            IpAddr::V4(_) => IPV4_ADDRESS_FAMILY,
            IpAddr::V6(_) => IPV6_ADDRESS_FAMILY,
        });
        w.push(self.mask); // Subnet mask
        w.push(match *ty { // cidr
            Type::Cidr => true as u8,
            Type::Inet => false as u8,
            _ => unreachable!(),
        });
        w.push(match self.addr {
            IpAddr::V4(_) => IPV4_ADDRESS_SIZE,
            IpAddr::V6(_) => IPV6_ADDRESS_SIZE,
        });
        match self.addr { // Luckily, ipv6.octets() outputs in Network Byte Order.
            IpAddr::V4(ipv4) => w.append(&mut ipv4.octets().to_vec()),
            IpAddr::V6(ipv6) => w.append(&mut ipv6.octets().to_vec()),
        };

        Ok(IsNull::No)
    }

    accepts!(Type::Cidr, Type::Inet);
    to_sql_checked!();
}
<|endoftext|>


<commit_before>use std::env;
use std::str::FromStr;
use std::error::Error;
use std::fmt;
use std::fmt::Debug;

/// The behavior if the environment variable is not set.
pub enum OptionType<T> where T: FromStr + Debug, T::Err: Error {
    /// Return `None`
    Optional,
    /// Return an error
    Required,
    /// Use the default value
    Default(T),
}

#[derive(Debug)]
pub enum EnvOptionError<T> where T: Error {
    /// An error occurred while parsing the environment variable.
    /// This error contains the T::Err type from the `parse` function.
    ParseError(T),
    /// The environment variable was missing.
    Missing,
}

impl<T> fmt::Display for EnvOptionError<T> where T: Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.description())
    }
}

impl<T> Error for EnvOptionError<T> where T: Error {
    fn description(&self) -> &str {
        match *self {
            EnvOptionError::ParseError(_) => "parse error",
            EnvOptionError::Missing => "variable is required"
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            EnvOptionError::ParseError(ref e) => Some(e),
            EnvOptionError::Missing => None
        }
    }
}

/// Get an environment variable, using the given mode to determine behavior when it is not set.
pub fn get<T>(var_name: &str, mode: OptionType<T>) -> Result<Option<T>, EnvOptionError<T::Err>>  where T : FromStr + Debug, T::Err: Error {
    match env::var(var_name) {
        Err(_) => match mode {
            OptionType::Optional => Ok(None),
            OptionType::Required => Err(EnvOptionError::Missing),
            OptionType::Default(d) => Ok(Some(d)),
        },
        Ok(value) => value.parse::<T>().map(|value| Some(value)).map_err(|e| EnvOptionError::ParseError(e)),
    }
}

/// Sugar around get to avoid the extra `Option` when it will never be `None` anyway.
pub fn require<T>(var_name: &str, default: Option<T>) -> Result<T, EnvOptionError<T::Err>> where T : FromStr + Debug, T::Err: Error {
    let mode = match default {
        None => OptionType::Required,
        Some(v) => OptionType::Default(v)
    };

    get(var_name, mode).map(|o| o.unwrap())
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<commit_msg>Include variable name in errors<commit_after>use std::env;
use std::str::FromStr;
use std::error::Error;
use std::fmt;
use std::fmt::Debug;

/// The behavior if the environment variable is not set.
pub enum OptionType<T> where T: FromStr + Debug, T::Err: Error {
    /// Return `None`
    Optional,
    /// Return an error
    Required,
    /// Use the default value
    Default(T),
}

#[derive(Debug)]
pub enum EnvOptionError<T> where T: Error {
    /// An error occurred while parsing the environment variable.
    /// This error contains the T::Err type from the `parse` function.
    ParseError(String, T),
    /// The environment variable was missing.
    Missing(String),
}

impl<T> fmt::Display for EnvOptionError<T> where T: Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            EnvOptionError::ParseError(ref s, ref err) => write!(f, "parsing {}: {}", s, err),
            EnvOptionError::Missing(ref s) => write!(f, "{} not found", s),
        }
    }
}

impl<T> Error for EnvOptionError<T> where T: Error {
    fn description(&self) -> &str {
        match *self {
            EnvOptionError::ParseError(_, _) => "parse error",
            EnvOptionError::Missing(_) => "variable is required"
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            EnvOptionError::ParseError(_, ref e) => Some(e),
            EnvOptionError::Missing(_) => None
        }
    }
}

/// Get an environment variable, using the given mode to determine behavior when it is not set.
pub fn get<T>(var_name: &str, mode: OptionType<T>) -> Result<Option<T>, EnvOptionError<T::Err>>  where T : FromStr + Debug, T::Err: Error {
    match env::var(var_name) {
        Err(_) => match mode {
            OptionType::Optional => Ok(None),
            OptionType::Required => Err(EnvOptionError::Missing(var_name.to_string())),
            OptionType::Default(d) => Ok(Some(d)),
        },
        Ok(value) => value.parse::<T>().map(|value| Some(value)).map_err(|e| EnvOptionError::ParseError(var_name.to_string(), e)),
    }
}

/// Sugar around get to avoid the extra `Option` when it will never be `None` anyway.
pub fn require<T>(var_name: &str, default: Option<T>) -> Result<T, EnvOptionError<T::Err>> where T : FromStr + Debug, T::Err: Error {
    let mode = match default {
        None => OptionType::Required,
        Some(v) => OptionType::Default(v)
    };

    get(var_name, mode).map(|o| o.unwrap())
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<|endoftext|>


<commit_before>use data::packet::Packet;
use data::rational::Rational64;
use stream::Stream;
use error::*;

use buffer::Buffered;
use std::io::SeekFrom;

#[derive(Clone, Debug, PartialEq)]
pub struct GlobalInfo {
    pub duration: Option<u64>,
    pub timebase: Option<Rational64>,
    pub streams: Vec<Stream>,
}

#[derive(Clone, Debug, PartialEq)]
pub enum Event {
    NewPacket(Packet),
    NewStream(Stream),
    MoreDataNeeded(usize),
}

pub trait Demuxer : Send {
    fn read_headers(&mut self, buf: &Box<Buffered>, info: &mut GlobalInfo) -> Result<SeekFrom>;
    fn read_event(&mut self, buf: &Box<Buffered>) -> Result<(SeekFrom, Event)>;
}

#[derive(Clone, Debug, PartialEq)]
pub struct Descr {
    pub name: &'static str,
    pub demuxer: &'static str,
    pub description: &'static str,
    pub extensions: &'static [&'static str],
    pub mime: &'static [&'static str],
}

pub trait Descriptor {
    fn create(&self) -> Box<Demuxer>;
    fn describe<'a>(&'a self) -> &'a Descr;

    fn probe(&self, data: &[u8]) -> u8;
}

pub struct Context {
    demuxer: Box<Demuxer>,
    reader: Box<Buffered>,
    pub info: GlobalInfo,
}

impl Context {
    pub fn new<R: Buffered + 'static>(demuxer: Box<Demuxer>, reader: Box<R>) -> Self {
        Context {
            demuxer: demuxer,
            reader: reader,
            info: GlobalInfo {
                duration: None,
                timebase: None,
                streams: Vec::with_capacity(2),
            },
        }
    }

    fn read_headers_internal(&mut self) -> Result<()> {
        let ref mut demux = self.demuxer;
        let res = demux.read_headers(&self.reader, &mut self.info);
        match res {
            Err(e) => Err(e),
            Ok(seek) => {
                //TODO: handle seeking here
                let res = self.reader.seek(seek);
                println!("stream now at index: {:?}", res);
                Ok(())
            }
        }
    }

    pub fn read_headers(&mut self) -> Result<()> {
        loop {
            println!("Filling");
            try!(self.reader.fill_buf());
            match self.read_headers_internal() {
                Err(e) => match e {
                    Error(ErrorKind::MoreDataNeeded(needed), _) => {
                        self.reader.grow(needed);
                    },
                    _ => return Err(e)
                },
                Ok(_) => return Ok(()),
            }
        }
    }

    fn read_event_internal(&mut self) -> Result<Event> {
        let ref mut demux = self.demuxer;

        let res = demux.read_event(&self.reader);
        match res {
            Err(e) => Err(e),
            Ok((seek, mut event)) => {
                //TODO: handle seeking here
                let res = self.reader.seek(seek);
                if let Event::NewStream(ref st) = event {
                    self.info.streams.push(st.clone());
                }
                if let Event::MoreDataNeeded(size) = event {
                    return Err(ErrorKind::MoreDataNeeded(size).into());
                }
                if let Event::NewPacket(ref mut pkt) = event {
                    if pkt.t.timebase.is_none() {
                        if let Some(ref st) = self.info.streams.iter().find(|s| {
                            s.index as isize == pkt.stream_index
                        }) {
                            pkt.t.timebase = Some(st.timebase);
                        }
                    }
                }
                Ok(event)
            }
        }
    }

    pub fn read_event(&mut self) -> Result<Event> {
        use std::io::ErrorKind as Eio;
        // TODO: guard against infiniloops and maybe factor the loop.
        loop {
            match self.read_event_internal() {
                Err(e) => match e {
                    Error(ErrorKind::MoreDataNeeded(needed), _) => {
                        let len = self.reader.data().len();
                        self.reader.grow(needed);
                        try!(self.reader.fill_buf());
                        if self.reader.data().len() <= len {
                            return Err(ErrorKind::Io(Eio::UnexpectedEof.into()).into());
                        }
                    },
                    _ => return Err(e)
                },
                Ok(ev) => return Ok(ev),
            }
        }
    }
}

pub const PROBE_DATA: usize = 4 * 1024;
pub const PROBE_SCORE_EXTENSION: u8 = 50;

// TODO:
// IntoIterator<Item = &'static Descriptor> is confusing

pub trait Probe {
    fn probe(&self, data: &[u8]) -> Option<&'static Descriptor>;
}

impl<'a> Probe for [&'static Descriptor] {
    fn probe(&self, data: &[u8]) -> Option<&'static Descriptor> {
        let mut max = u8::min_value();
        let mut candidate: Option<&'static Descriptor> = None;
        for desc in self {
            let score = desc.probe(data);

            if score > max {
                max = score;
                candidate = Some(*desc);
            }
        }

        if max > PROBE_SCORE_EXTENSION {
            candidate
        } else {
            None
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::io::SeekFrom;
    use data::packet::Packet;

    struct DummyDes {
        d: Descr,
    }

    struct DummyDemuxer {}

    impl Demuxer for DummyDemuxer {
        fn read_headers(&mut self, buf: &Box<Buffered>, _info: &mut GlobalInfo) -> Result<SeekFrom> {
            let len = buf.data().len();
            if 9 > len {
                let needed = 9 - len;
                Err(ErrorKind::MoreDataNeeded(needed).into())
            } else {
                Ok(SeekFrom::Current(9))
            }
        }
        fn read_event(&mut self, buf: &Box<Buffered>) -> Result<(SeekFrom, Event)> {
            let size = 2;
            let len = buf.data().len();
            if size > len {
                Err(ErrorKind::MoreDataNeeded(size - len).into())
            } else {
                println!("{:?}", buf.data());
                match &buf.data()[..2] {
                    b"p1" => {
                        Ok((SeekFrom::Current(3), Event::NewPacket(Packet::new())))
                    },
                    b"e1" => {
                        Ok((SeekFrom::Current(3), Event::MoreDataNeeded(0)))
                    }
                    _ => Err(ErrorKind::InvalidData.into())
                }
            }
        }
    }

    impl Descriptor for DummyDes {
        fn create(&self) -> Box<Demuxer> {
            Box::new(DummyDemuxer {})
        }
        fn describe<'a>(&'a self) -> &'a Descr {
            &self.d
        }
        fn probe(&self, data: &[u8]) -> u8 {
            match data {
                b"dummy" => 100,
                _ => 0,
            }
        }
    }

    const DUMMY_DES: &Descriptor = &DummyDes {
        d: Descr {
            name: "dummy",
            demuxer: "dummy",
            description: "Dummy dem",
            extensions: &["dm", "dum"],
            mime: &["application/dummy"],
        },
    };

    #[test]
    fn probe() {
        let demuxers: &[&'static Descriptor] = &[DUMMY_DES];

        demuxers.probe(b"dummy").unwrap();
    }

    use std::io::Cursor;
    use buffer::*;

    #[test]
    fn read_headers() {
        let buf = b"dummy header";
        let r = AccReader::with_capacity(4, Cursor::new(buf));
        let d = DUMMY_DES.create();
        let mut c = Context::new(d, Box::new(r));

        c.read_headers().unwrap();
    }

    #[test]
    fn read_event() {
        let buf = b"dummy header p1 e1 p1 ";

        let r = AccReader::with_capacity(4, Cursor::new(buf));
        let d = DUMMY_DES.create();
        let mut c = Context::new(d, Box::new(r));

        c.read_headers().unwrap();

        println!("{:?}", c.read_event());
        println!("{:?}", c.read_event());
        println!("{:?}", c.read_event());
        println!("{:?}", c.read_event());
    }
}
<commit_msg>format: Do not print the seek return value<commit_after>use data::packet::Packet;
use data::rational::Rational64;
use stream::Stream;
use error::*;

use buffer::Buffered;
use std::io::SeekFrom;

#[derive(Clone, Debug, PartialEq)]
pub struct GlobalInfo {
    pub duration: Option<u64>,
    pub timebase: Option<Rational64>,
    pub streams: Vec<Stream>,
}

#[derive(Clone, Debug, PartialEq)]
pub enum Event {
    NewPacket(Packet),
    NewStream(Stream),
    MoreDataNeeded(usize),
}

pub trait Demuxer : Send {
    fn read_headers(&mut self, buf: &Box<Buffered>, info: &mut GlobalInfo) -> Result<SeekFrom>;
    fn read_event(&mut self, buf: &Box<Buffered>) -> Result<(SeekFrom, Event)>;
}

#[derive(Clone, Debug, PartialEq)]
pub struct Descr {
    pub name: &'static str,
    pub demuxer: &'static str,
    pub description: &'static str,
    pub extensions: &'static [&'static str],
    pub mime: &'static [&'static str],
}

pub trait Descriptor {
    fn create(&self) -> Box<Demuxer>;
    fn describe<'a>(&'a self) -> &'a Descr;

    fn probe(&self, data: &[u8]) -> u8;
}

pub struct Context {
    demuxer: Box<Demuxer>,
    reader: Box<Buffered>,
    pub info: GlobalInfo,
}

impl Context {
    pub fn new<R: Buffered + 'static>(demuxer: Box<Demuxer>, reader: Box<R>) -> Self {
        Context {
            demuxer: demuxer,
            reader: reader,
            info: GlobalInfo {
                duration: None,
                timebase: None,
                streams: Vec::with_capacity(2),
            },
        }
    }

    fn read_headers_internal(&mut self) -> Result<()> {
        let ref mut demux = self.demuxer;
        let res = demux.read_headers(&self.reader, &mut self.info);
        match res {
            Err(e) => Err(e),
            Ok(seek) => {
                //TODO: handle seeking here
                let res = self.reader.seek(seek);
                println!("stream now at index: {:?}", res);
                Ok(())
            }
        }
    }

    pub fn read_headers(&mut self) -> Result<()> {
        loop {
            println!("Filling");
            try!(self.reader.fill_buf());
            match self.read_headers_internal() {
                Err(e) => match e {
                    Error(ErrorKind::MoreDataNeeded(needed), _) => {
                        self.reader.grow(needed);
                    },
                    _ => return Err(e)
                },
                Ok(_) => return Ok(()),
            }
        }
    }

    fn read_event_internal(&mut self) -> Result<Event> {
        let ref mut demux = self.demuxer;

        let res = demux.read_event(&self.reader);
        match res {
            Err(e) => Err(e),
            Ok((seek, mut event)) => {
                //TODO: handle seeking here
                let _ = self.reader.seek(seek)?;
                if let Event::NewStream(ref st) = event {
                    self.info.streams.push(st.clone());
                }
                if let Event::MoreDataNeeded(size) = event {
                    return Err(ErrorKind::MoreDataNeeded(size).into());
                }
                if let Event::NewPacket(ref mut pkt) = event {
                    if pkt.t.timebase.is_none() {
                        if let Some(ref st) = self.info.streams.iter().find(|s| {
                            s.index as isize == pkt.stream_index
                        }) {
                            pkt.t.timebase = Some(st.timebase);
                        }
                    }
                }
                Ok(event)
            }
        }
    }

    pub fn read_event(&mut self) -> Result<Event> {
        use std::io::ErrorKind as Eio;
        // TODO: guard against infiniloops and maybe factor the loop.
        loop {
            match self.read_event_internal() {
                Err(e) => match e {
                    Error(ErrorKind::MoreDataNeeded(needed), _) => {
                        let len = self.reader.data().len();
                        self.reader.grow(needed);
                        try!(self.reader.fill_buf());
                        if self.reader.data().len() <= len {
                            return Err(ErrorKind::Io(Eio::UnexpectedEof.into()).into());
                        }
                    },
                    _ => return Err(e)
                },
                Ok(ev) => return Ok(ev),
            }
        }
    }
}

pub const PROBE_DATA: usize = 4 * 1024;
pub const PROBE_SCORE_EXTENSION: u8 = 50;

// TODO:
// IntoIterator<Item = &'static Descriptor> is confusing

pub trait Probe {
    fn probe(&self, data: &[u8]) -> Option<&'static Descriptor>;
}

impl<'a> Probe for [&'static Descriptor] {
    fn probe(&self, data: &[u8]) -> Option<&'static Descriptor> {
        let mut max = u8::min_value();
        let mut candidate: Option<&'static Descriptor> = None;
        for desc in self {
            let score = desc.probe(data);

            if score > max {
                max = score;
                candidate = Some(*desc);
            }
        }

        if max > PROBE_SCORE_EXTENSION {
            candidate
        } else {
            None
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::io::SeekFrom;
    use data::packet::Packet;

    struct DummyDes {
        d: Descr,
    }

    struct DummyDemuxer {}

    impl Demuxer for DummyDemuxer {
        fn read_headers(&mut self, buf: &Box<Buffered>, _info: &mut GlobalInfo) -> Result<SeekFrom> {
            let len = buf.data().len();
            if 9 > len {
                let needed = 9 - len;
                Err(ErrorKind::MoreDataNeeded(needed).into())
            } else {
                Ok(SeekFrom::Current(9))
            }
        }
        fn read_event(&mut self, buf: &Box<Buffered>) -> Result<(SeekFrom, Event)> {
            let size = 2;
            let len = buf.data().len();
            if size > len {
                Err(ErrorKind::MoreDataNeeded(size - len).into())
            } else {
                println!("{:?}", buf.data());
                match &buf.data()[..2] {
                    b"p1" => {
                        Ok((SeekFrom::Current(3), Event::NewPacket(Packet::new())))
                    },
                    b"e1" => {
                        Ok((SeekFrom::Current(3), Event::MoreDataNeeded(0)))
                    }
                    _ => Err(ErrorKind::InvalidData.into())
                }
            }
        }
    }

    impl Descriptor for DummyDes {
        fn create(&self) -> Box<Demuxer> {
            Box::new(DummyDemuxer {})
        }
        fn describe<'a>(&'a self) -> &'a Descr {
            &self.d
        }
        fn probe(&self, data: &[u8]) -> u8 {
            match data {
                b"dummy" => 100,
                _ => 0,
            }
        }
    }

    const DUMMY_DES: &Descriptor = &DummyDes {
        d: Descr {
            name: "dummy",
            demuxer: "dummy",
            description: "Dummy dem",
            extensions: &["dm", "dum"],
            mime: &["application/dummy"],
        },
    };

    #[test]
    fn probe() {
        let demuxers: &[&'static Descriptor] = &[DUMMY_DES];

        demuxers.probe(b"dummy").unwrap();
    }

    use std::io::Cursor;
    use buffer::*;

    #[test]
    fn read_headers() {
        let buf = b"dummy header";
        let r = AccReader::with_capacity(4, Cursor::new(buf));
        let d = DUMMY_DES.create();
        let mut c = Context::new(d, Box::new(r));

        c.read_headers().unwrap();
    }

    #[test]
    fn read_event() {
        let buf = b"dummy header p1 e1 p1 ";

        let r = AccReader::with_capacity(4, Cursor::new(buf));
        let d = DUMMY_DES.create();
        let mut c = Context::new(d, Box::new(r));

        c.read_headers().unwrap();

        println!("{:?}", c.read_event());
        println!("{:?}", c.read_event());
        println!("{:?}", c.read_event());
        println!("{:?}", c.read_event());
    }
}
<|endoftext|>


<commit_before>#![deny(missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unstable_features,
        unused_import_braces, unused_qualifications)]

#![cfg_attr(feature = "nightly", allow(unstable_features))]
#![cfg_attr(feature = "lints", feature(plugin))]
#![cfg_attr(feature = "lints", plugin(clippy))]

extern crate librsync_sys as raw;
extern crate libc;

mod macros;
mod job;

use job::{Job, JobDriver};

use std::error;
use std::fmt::{self, Display, Formatter};
use std::io::{self, Read, Seek};
use std::ops::Deref;
use std::mem;
use std::ptr;
use std::slice;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum SignatureType {
    MD4,
    Blake2,
}

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Syntax,
    Mem,
    BadMagic,
    Unimplemented,
    Internal,
    Unknown(i32),
}

pub type Result<T> = std::result::Result<T, Error>;

pub struct Signature<R> {
    driver: JobDriver<R>,
}

pub struct Delta<R> {
    driver: JobDriver<R>,
    _sumset: Sumset,
}

pub struct Patch<'a, R> {
    driver: JobDriver<R>,
    _base: Box<StreamHolder<'a>>,
}

struct Sumset(*mut raw::rs_signature_t);

struct StreamHolder<'a>(Box<ReadAndSeek + 'a>);

// workaround for E0225
trait ReadAndSeek: Read + Seek {}
impl<T: Read + Seek> ReadAndSeek for T {}

impl<R: Read> Signature<R> {
    pub fn new(old: R,
               new_block_len: usize,
               strong_len: usize,
               sig_magic: SignatureType)
               -> Result<Self> {
        let job = unsafe { raw::rs_sig_begin(new_block_len, strong_len, sig_magic.as_raw()) };
        if job.is_null() {
            return Err(Error::BadMagic);
        }
        Ok(Signature { driver: JobDriver::new(old, Job(job)) })
    }

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

impl<R: Read> Read for Signature<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.driver.read(buf)
    }
}

impl<R: Read> Delta<R> {
    pub fn new<S: Read>(input: R, signature: S) -> Result<Self> {
        // load the signature
        let sumset = unsafe {
            let mut sumset = ptr::null_mut();
            let job = raw::rs_loadsig_begin(&mut sumset);
            assert!(!job.is_null());
            let mut job = JobDriver::new(signature, Job(job));
            try!(job.consume_input());
            let sumset = Sumset(sumset);
            let res = raw::rs_build_hash_table(*sumset);
            if res != raw::RS_DONE {
                return Err(Error::from(res));
            }
            sumset
        };
        let job = unsafe { raw::rs_delta_begin(*sumset) };
        assert!(!job.is_null());
        Ok(Delta {
            driver: JobDriver::new(input, Job(job)),
            _sumset: sumset,
        })
    }
}

impl<R: Read> Read for Delta<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.driver.read(buf)
    }
}

impl<'a, R: Read> Patch<'a, R> {
    pub fn new<B: Read + Seek + 'a>(base: B, delta: R) -> Result<Self> {
        let mut baseh = Box::new(StreamHolder(Box::new(base)));
        let job = unsafe { raw::rs_patch_begin(patch_copy_cb, baseh.as_raw()) };
        assert!(!job.is_null());
        Ok(Patch {
            driver: JobDriver::new(delta, Job(job)),
            _base: baseh,
        })
    }

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

impl<'a, R: Read> Read for Patch<'a, R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.driver.read(buf)
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Io(ref err) => err.description(),
            Error::Syntax => "syntax error",
            Error::Mem => "out of memory",
            Error::BadMagic => "bad magic number given",
            Error::Unimplemented => "unimplemented feature",
            Error::Internal => "internal error",
            Error::Unknown(_) => "unknown error from librsync",
        }
    }
}

impl Display for Error {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match *self {
            Error::Io(ref e) => write!(fmt, "{}", e),
            Error::Unknown(n) => write!(fmt, "unknown error {} from native library", n),
            _ => write!(fmt, "{}", std::error::Error::description(self)),
        }
    }
}

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

impl From<raw::rs_result> for Error {
    fn from(err: raw::rs_result) -> Error {
        match err {
            raw::RS_BLOCKED => io_err(io::ErrorKind::WouldBlock, "blocked waiting for more data"),
            raw::RS_IO_ERROR => io_err(io::ErrorKind::Other, "unknown IO error from librsync"),
            raw::RS_SYNTAX_ERROR => Error::Syntax,
            raw::RS_MEM_ERROR => Error::Mem,
            raw::RS_INPUT_ENDED => {
                io_err(io::ErrorKind::UnexpectedEof, "unexpected end of input file")
            }
            raw::RS_BAD_MAGIC => Error::BadMagic,
            raw::RS_UNIMPLEMENTED => Error::Unimplemented,
            raw::RS_CORRUPT => io_err(io::ErrorKind::InvalidData, "unbelievable value in stream"),
            raw::RS_INTERNAL_ERROR => Error::Internal,
            raw::RS_PARAM_ERROR => io_err(io::ErrorKind::InvalidInput, "bad parameter"),
            n => Error::Unknown(n),
        }
    }
}

impl SignatureType {
    pub fn from_raw(raw: raw::rs_magic_number) -> Option<Self> {
        match raw {
            raw::RS_MD4_SIG_MAGIC => Some(SignatureType::MD4),
            raw::RS_BLAKE2_SIG_MAGIC => Some(SignatureType::Blake2),
            _ => None,
        }
    }

    fn as_raw(&self) -> raw::rs_magic_number {
        match *self {
            SignatureType::MD4 => raw::RS_MD4_SIG_MAGIC,
            SignatureType::Blake2 => raw::RS_BLAKE2_SIG_MAGIC,
        }
    }
}

impl Drop for Sumset {
    fn drop(&mut self) {
        unsafe {
            if !self.0.is_null() {
                raw::rs_free_sumset(self.0);
            }
        }
    }
}

impl Deref for Sumset {
    type Target = *mut raw::rs_signature_t;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<'a> StreamHolder<'a> {
    fn as_stream(&mut self) -> &mut ReadAndSeek {
        &mut *self.0
    }

    unsafe fn as_raw(&mut self) -> *mut libc::c_void {
        mem::transmute(self)
    }
}

extern "C" fn patch_copy_cb(opaque: *mut libc::c_void,
                            pos: raw::rs_long_t,
                            len: *mut libc::size_t,
                            buf: *mut *mut libc::c_void)
                            -> raw::rs_result {
    let input = unsafe {
        let h: *mut StreamHolder = mem::transmute(opaque);
        (*h).as_stream()
    };
    let output = unsafe {
        let buf: *mut u8 = mem::transmute(*buf);
        slice::from_raw_parts_mut(buf, *len)
    };
    try_or_rs_error!(input.seek(io::SeekFrom::Start(pos as u64)));
    let n = try_or_rs_error!(input.read(output));
    unsafe { *len += n };
    raw::RS_DONE
}

fn io_err<E>(kind: io::ErrorKind, e: E) -> Error
    where E: Into<Box<error::Error + Send + Sync>>
{
    Error::Io(io::Error::new(kind, e))
}

#[cfg(test)]
mod test {
    use super::*;
    use std::io::{Cursor, Read};

    const DATA: &'static str = "this is a string to be tested";
    const DATA2: &'static str = "this is another string to be tested";

    fn data_signature() -> Vec<u8> {
        vec![0x72, 0x73, 0x01, 0x36, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x05, 0x1b, 0x21,
             0x04, 0x8b, 0xad, 0x3c, 0xbd, 0x19, 0x09, 0x1d, 0x1b, 0x04, 0xf0, 0x9d, 0x1f, 0x64,
             0x31, 0xde, 0x15, 0xf4, 0x04, 0x87, 0x60, 0x96, 0x19, 0x50, 0x39]
    }

    #[test]
    fn signature() {
        let cursor = Cursor::new(DATA);
        let mut sig = Signature::new(cursor, 10, 5, SignatureType::MD4).unwrap();
        let mut signature = Vec::new();
        let read = sig.read_to_end(&mut signature).unwrap();
        assert_eq!(read, signature.len());
        assert_eq!(signature, data_signature());
    }

    #[test]
    fn delta() {
        let sig = data_signature();
        let sig = Cursor::new(sig);
        let input = Cursor::new(DATA2);
        let mut job = Delta::new(input, sig).unwrap();
        let mut delta = Vec::new();
        let read = job.read_to_end(&mut delta).unwrap();
        assert_eq!(read, delta.len());
    }

    #[test]
    fn patch() {
        let base = Cursor::new(DATA);
        let new = Cursor::new(DATA2);
        let sig = Signature::new(base, 10, 5, SignatureType::MD4).unwrap();
        let delta = Delta::new(new, sig).unwrap();
        let base = Cursor::new(DATA);
        let mut patch = Patch::new(base, delta).unwrap();
        let mut computed_new = String::new();
        patch.read_to_string(&mut computed_new).unwrap();
        assert_eq!(computed_new, DATA2);
    }
}
<commit_msg>Tests refactor<commit_after>#![deny(missing_copy_implementations,
        trivial_casts, trivial_numeric_casts,
        unstable_features,
        unused_import_braces, unused_qualifications)]

#![cfg_attr(feature = "nightly", allow(unstable_features))]
#![cfg_attr(feature = "lints", feature(plugin))]
#![cfg_attr(feature = "lints", plugin(clippy))]

extern crate librsync_sys as raw;
extern crate libc;

mod macros;
mod job;

use job::{Job, JobDriver};

use std::error;
use std::fmt::{self, Display, Formatter};
use std::io::{self, Read, Seek};
use std::ops::Deref;
use std::mem;
use std::ptr;
use std::slice;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum SignatureType {
    MD4,
    Blake2,
}

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Syntax,
    Mem,
    BadMagic,
    Unimplemented,
    Internal,
    Unknown(i32),
}

pub type Result<T> = std::result::Result<T, Error>;

pub struct Signature<R> {
    driver: JobDriver<R>,
}

pub struct Delta<R> {
    driver: JobDriver<R>,
    _sumset: Sumset,
}

pub struct Patch<'a, R> {
    driver: JobDriver<R>,
    _base: Box<StreamHolder<'a>>,
}

struct Sumset(*mut raw::rs_signature_t);

struct StreamHolder<'a>(Box<ReadAndSeek + 'a>);

// workaround for E0225
trait ReadAndSeek: Read + Seek {}
impl<T: Read + Seek> ReadAndSeek for T {}

impl<R: Read> Signature<R> {
    pub fn new(old: R,
               new_block_len: usize,
               strong_len: usize,
               sig_magic: SignatureType)
               -> Result<Self> {
        let job = unsafe { raw::rs_sig_begin(new_block_len, strong_len, sig_magic.as_raw()) };
        if job.is_null() {
            return Err(Error::BadMagic);
        }
        Ok(Signature { driver: JobDriver::new(old, Job(job)) })
    }

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

impl<R: Read> Read for Signature<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.driver.read(buf)
    }
}

impl<R: Read> Delta<R> {
    pub fn new<S: Read>(input: R, signature: S) -> Result<Self> {
        // load the signature
        let sumset = unsafe {
            let mut sumset = ptr::null_mut();
            let job = raw::rs_loadsig_begin(&mut sumset);
            assert!(!job.is_null());
            let mut job = JobDriver::new(signature, Job(job));
            try!(job.consume_input());
            let sumset = Sumset(sumset);
            let res = raw::rs_build_hash_table(*sumset);
            if res != raw::RS_DONE {
                return Err(Error::from(res));
            }
            sumset
        };
        let job = unsafe { raw::rs_delta_begin(*sumset) };
        assert!(!job.is_null());
        Ok(Delta {
            driver: JobDriver::new(input, Job(job)),
            _sumset: sumset,
        })
    }
}

impl<R: Read> Read for Delta<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.driver.read(buf)
    }
}

impl<'a, R: Read> Patch<'a, R> {
    pub fn new<B: Read + Seek + 'a>(base: B, delta: R) -> Result<Self> {
        let mut baseh = Box::new(StreamHolder(Box::new(base)));
        let job = unsafe { raw::rs_patch_begin(patch_copy_cb, baseh.as_raw()) };
        assert!(!job.is_null());
        Ok(Patch {
            driver: JobDriver::new(delta, Job(job)),
            _base: baseh,
        })
    }

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

impl<'a, R: Read> Read for Patch<'a, R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.driver.read(buf)
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Io(ref err) => err.description(),
            Error::Syntax => "syntax error",
            Error::Mem => "out of memory",
            Error::BadMagic => "bad magic number given",
            Error::Unimplemented => "unimplemented feature",
            Error::Internal => "internal error",
            Error::Unknown(_) => "unknown error from librsync",
        }
    }
}

impl Display for Error {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        match *self {
            Error::Io(ref e) => write!(fmt, "{}", e),
            Error::Unknown(n) => write!(fmt, "unknown error {} from native library", n),
            _ => write!(fmt, "{}", std::error::Error::description(self)),
        }
    }
}

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

impl From<raw::rs_result> for Error {
    fn from(err: raw::rs_result) -> Error {
        match err {
            raw::RS_BLOCKED => io_err(io::ErrorKind::WouldBlock, "blocked waiting for more data"),
            raw::RS_IO_ERROR => io_err(io::ErrorKind::Other, "unknown IO error from librsync"),
            raw::RS_SYNTAX_ERROR => Error::Syntax,
            raw::RS_MEM_ERROR => Error::Mem,
            raw::RS_INPUT_ENDED => {
                io_err(io::ErrorKind::UnexpectedEof, "unexpected end of input file")
            }
            raw::RS_BAD_MAGIC => Error::BadMagic,
            raw::RS_UNIMPLEMENTED => Error::Unimplemented,
            raw::RS_CORRUPT => io_err(io::ErrorKind::InvalidData, "unbelievable value in stream"),
            raw::RS_INTERNAL_ERROR => Error::Internal,
            raw::RS_PARAM_ERROR => io_err(io::ErrorKind::InvalidInput, "bad parameter"),
            n => Error::Unknown(n),
        }
    }
}

impl SignatureType {
    pub fn from_raw(raw: raw::rs_magic_number) -> Option<Self> {
        match raw {
            raw::RS_MD4_SIG_MAGIC => Some(SignatureType::MD4),
            raw::RS_BLAKE2_SIG_MAGIC => Some(SignatureType::Blake2),
            _ => None,
        }
    }

    fn as_raw(&self) -> raw::rs_magic_number {
        match *self {
            SignatureType::MD4 => raw::RS_MD4_SIG_MAGIC,
            SignatureType::Blake2 => raw::RS_BLAKE2_SIG_MAGIC,
        }
    }
}

impl Drop for Sumset {
    fn drop(&mut self) {
        unsafe {
            if !self.0.is_null() {
                raw::rs_free_sumset(self.0);
            }
        }
    }
}

impl Deref for Sumset {
    type Target = *mut raw::rs_signature_t;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<'a> StreamHolder<'a> {
    fn as_stream(&mut self) -> &mut ReadAndSeek {
        &mut *self.0
    }

    unsafe fn as_raw(&mut self) -> *mut libc::c_void {
        mem::transmute(self)
    }
}

extern "C" fn patch_copy_cb(opaque: *mut libc::c_void,
                            pos: raw::rs_long_t,
                            len: *mut libc::size_t,
                            buf: *mut *mut libc::c_void)
                            -> raw::rs_result {
    let input = unsafe {
        let h: *mut StreamHolder = mem::transmute(opaque);
        (*h).as_stream()
    };
    let output = unsafe {
        let buf: *mut u8 = mem::transmute(*buf);
        slice::from_raw_parts_mut(buf, *len)
    };
    try_or_rs_error!(input.seek(io::SeekFrom::Start(pos as u64)));
    let n = try_or_rs_error!(input.read(output));
    unsafe { *len += n };
    raw::RS_DONE
}

fn io_err<E>(kind: io::ErrorKind, e: E) -> Error
    where E: Into<Box<error::Error + Send + Sync>>
{
    Error::Io(io::Error::new(kind, e))
}

#[cfg(test)]
mod test {
    use super::*;
    use std::io::{Cursor, Read};

    const DATA: &'static str = "this is a string to be tested";
    const DATA2: &'static str = "this is another string to be tested";

    // generated with `rdiff signature -b 10 -S 5 data data.sig`
    fn data_signature() -> Vec<u8> {
        vec![0x72, 0x73, 0x01, 0x36, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x05, 0x1b, 0x21,
             0x04, 0x8b, 0xad, 0x3c, 0xbd, 0x19, 0x09, 0x1d, 0x1b, 0x04, 0xf0, 0x9d, 0x1f, 0x64,
             0x31, 0xde, 0x15, 0xf4, 0x04, 0x87, 0x60, 0x96, 0x19, 0x50, 0x39]
    }

    // generated with `rdiff delta data.sig data2 data2.delta`
    fn data2_delta() -> Vec<u8> {
        vec![0x72, 0x73, 0x02, 0x36, 0x41, 0x10, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
             0x61, 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x45, 0x0a, 0x13, 0x00]
    }

    #[test]
    fn signature() {
        let cursor = Cursor::new(DATA);
        let mut sig = Signature::new(cursor, 10, 5, SignatureType::MD4).unwrap();
        let mut signature = Vec::new();
        let read = sig.read_to_end(&mut signature).unwrap();
        assert_eq!(read, signature.len());
        assert_eq!(signature, data_signature());
    }

    #[test]
    fn delta() {
        let sig = data_signature();
        let sig = Cursor::new(sig);
        let input = Cursor::new(DATA2);
        let mut job = Delta::new(input, sig).unwrap();
        let mut delta = Vec::new();
        let read = job.read_to_end(&mut delta).unwrap();
        assert_eq!(read, delta.len());
        assert_eq!(delta, data2_delta());
    }

    #[test]
    fn patch() {
        let base = Cursor::new(DATA);
        let delta = data2_delta();
        let delta = Cursor::new(delta);
        let mut patch = Patch::new(base, delta).unwrap();
        let mut computed_new = String::new();
        patch.read_to_string(&mut computed_new).unwrap();
        assert_eq!(computed_new, DATA2);
    }

    #[test]
    fn integration() {
        let base = Cursor::new(DATA);
        let new = Cursor::new(DATA2);
        let sig = Signature::new(base, 10, 5, SignatureType::MD4).unwrap();
        let delta = Delta::new(new, sig).unwrap();
        let base = Cursor::new(DATA);
        let mut patch = Patch::new(base, delta).unwrap();
        let mut computed_new = String::new();
        patch.read_to_string(&mut computed_new).unwrap();
        assert_eq!(computed_new, DATA2);
    }
}
<|endoftext|>


<commit_before>#![crate_type = "lib"]
#![crate_name = "rs_es"]

#![feature(convert)]

#[macro_use] extern crate log;
extern crate hyper;
extern crate rustc_serialize;

use std::error::Error;
use std::io;
use std::io::Read;
use std::fmt;

use hyper::client::response;

use rustc_serialize::json;
use rustc_serialize::json::Json;

#[derive(Debug)]
enum EsError {
    EsError(String),
    HttpError(hyper::error::HttpError),
    IoError(io::Error),
    JsonError(json::BuilderError)
}

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

impl From<hyper::error::HttpError> for EsError {
    fn from(err: hyper::error::HttpError) -> EsError {
        EsError::HttpError(err)
    }
}

impl From<json::BuilderError> for EsError {
    fn from(err: json::BuilderError) -> EsError {
        EsError::JsonError(err)
    }
}

impl Error for EsError {
    fn description(&self) -> &str {
        match *self {
            EsError::EsError(ref err) => err.as_str(),
            EsError::HttpError(ref err) => err.description(),
            EsError::IoError(ref err) => err.description(),
            EsError::JsonError(ref err) => err.description()
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            EsError::EsError(_)         => None,
            EsError::HttpError(ref err) => Some(err as &Error),
            EsError::IoError(ref err)   => Some(err as &Error),
            EsError::JsonError(ref err) => Some(err as &Error)
        }
    }
}

impl fmt::Display for EsError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            EsError::EsError(ref s) => fmt::Display::fmt(s, f),
            EsError::HttpError(ref err) => fmt::Display::fmt(err, f),
            EsError::IoError(ref err) => fmt::Display::fmt(err, f),
            EsError::JsonError(ref err) => fmt::Display::fmt(err, f)
        }
    }
}

struct Client {
    host:        String,
    port:        u32,
    http_client: hyper::Client
}

impl Client {
    fn new(host: String, port: u32) -> Client {
        Client {
            host:        host,
            port:        port,
            http_client: hyper::Client::new()
        }
    }

    fn get_base_url(&self) -> String {
        format!("http://{}:{}/", self.host, self.port)
    }

    fn version(&mut self) -> Result<String, EsError> {
        let url = format!("{}", self.get_base_url());
        let mut result = try!(self.http_client.get(url.as_str()).send());
        let json = try!(Json::from_reader(&mut result));
        match json.find_path(&["version", "number"]) {
            Some(version) => match version.as_string() {
                Some(string) => Ok(string.to_string()),
                None         => Err(EsError::EsError(format!("Cannot find version number in: {:?}",
                                                             json)))
            },
            None          => Err(EsError::EsError(format!("Cannot find version number in {:?}",
                                                          json)))
        }
    }
}

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

    #[test]
    fn it_works() {
        let mut client = Client::new("localhost".to_string(), 9200);
        assert_eq!(client.version().unwrap(), "1.3.2");
    }
}
<commit_msg>Tidy-up<commit_after>#![crate_type = "lib"]
#![crate_name = "rs_es"]

#![feature(convert)]

#[macro_use] extern crate log;
extern crate hyper;
extern crate rustc_serialize;

use std::error::Error;
use std::io;
use std::fmt;

use rustc_serialize::json;
use rustc_serialize::json::Json;

// Error handling

#[derive(Debug)]
pub enum EsError {
    EsError(String),
    HttpError(hyper::error::HttpError),
    IoError(io::Error),
    JsonError(json::BuilderError)
}

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

impl From<hyper::error::HttpError> for EsError {
    fn from(err: hyper::error::HttpError) -> EsError {
        EsError::HttpError(err)
    }
}

impl From<json::BuilderError> for EsError {
    fn from(err: json::BuilderError) -> EsError {
        EsError::JsonError(err)
    }
}

impl Error for EsError {
    fn description(&self) -> &str {
        match *self {
            EsError::EsError(ref err) => err.as_str(),
            EsError::HttpError(ref err) => err.description(),
            EsError::IoError(ref err) => err.description(),
            EsError::JsonError(ref err) => err.description()
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            EsError::EsError(_)         => None,
            EsError::HttpError(ref err) => Some(err as &Error),
            EsError::IoError(ref err)   => Some(err as &Error),
            EsError::JsonError(ref err) => Some(err as &Error)
        }
    }
}

impl fmt::Display for EsError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            EsError::EsError(ref s) => fmt::Display::fmt(s, f),
            EsError::HttpError(ref err) => fmt::Display::fmt(err, f),
            EsError::IoError(ref err) => fmt::Display::fmt(err, f),
            EsError::JsonError(ref err) => fmt::Display::fmt(err, f)
        }
    }
}

// The client

pub struct Client {
    host:        String,
    port:        u32,
    http_client: hyper::Client
}

impl Client {
    pub fn new(host: String, port: u32) -> Client {
        Client {
            host:        host,
            port:        port,
            http_client: hyper::Client::new()
        }
    }

    fn get_base_url(&self) -> String {
        format!("http://{}:{}/", self.host, self.port)
    }

    fn get(&mut self, url: &str, body: Option<&Json>) -> Result<Json, EsError> {
        let rb = self.http_client.get(url);
        let mut result = try!(match body {
            Some(json) => rb.body(json.as_string().unwrap()),
            None       => rb
        }.send());
        Ok(try!(Json::from_reader(&mut result)))
    }

    pub fn version(&mut self) -> Result<String, EsError> {
        let url = self.get_base_url();
        let json = try!(self.get(url.as_str(), None));
        match json.find_path(&["version", "number"]) {
            Some(version) => match version.as_string() {
                Some(string) => Ok(string.to_string()),
                None         => Err(EsError::EsError(format!("Cannot find version number in: {:?}",
                                                             json)))
            },
            None          => Err(EsError::EsError(format!("Cannot find version number in {:?}",
                                                          json)))
        }
    }
}

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

    #[test]
    fn it_works() {
        let mut client = Client::new("localhost".to_string(), 9200);
        assert_eq!(client.version().unwrap(), "1.3.2");
    }
}
<|endoftext|>