<commit_before>// Deny warnings, except in `dev` mode

// To update this list
// 1. Run `rustc -W help`
// 2. Grab all `default=warn` warnings
// 3. Paste them here, deleting `warnings`, and any with `deprecated` in the name
#![deny(const_err,
        dead_code,
        illegal_floating_point_literal_pattern,
        improper_ctypes,
        non_camel_case_types,
        non_shorthand_field_patterns,
        non_snake_case,
        non_upper_case_globals,
        no_mangle_generic_items,
        overflowing_literals,
        path_statements,
        patterns_in_fns_without_body,
        plugin_as_library,
        private_in_public,
        private_no_mangle_fns,
        private_no_mangle_statics,
        renamed_and_removed_lints,
        stable_features,
        unconditional_recursion,
        unions_with_drop_fields,
        unknown_lints,
        unreachable_code,
        unreachable_patterns,
        unused_allocation,
        unused_assignments,
        unused_attributes,
        unused_comparisons,
        unused_features,
        unused_imports,
        unused_macros,
        unused_must_use,
        unused_mut,
        unused_parens,
        unused_unsafe,
        unused_variables,
        while_true)]
// This list is select `allow` warnings
#![deny(trivial_casts,
       trivial_numeric_casts,
       unused_extern_crates,
       unused_import_braces)]
#![cfg_attr(feature="cargo-clippy", allow(
        cyclomatic_complexity,
        needless_pass_by_value))]
#![cfg_attr(feature="dev", warn(warnings))]

extern crate cobalt;
extern crate env_logger;
extern crate notify;
extern crate ghp;

extern crate hyper;

#[macro_use]
extern crate error_chain;

#[macro_use]
extern crate clap;

#[macro_use]
extern crate log;

mod build;
mod error;
mod serve;
mod new;

use std::fs;

use clap::{Arg, App, SubCommand, AppSettings};
use cobalt::{Config, Dump, jekyll};
use cobalt::{list_syntaxes, list_syntax_themes};
use env_logger::LogBuilder;
use log::{LogRecord, LogLevelFilter};

use error::*;

quick_main!(run);

fn run() -> Result<()> {
    let app_cli = App::new("Cobalt")
        .version(crate_version!())
        .author("Benny Klotz <r3qnbenni@gmail.com>, Johann Hofmann")
        .about("A static site generator written in Rust.")
        .setting(AppSettings::SubcommandRequired)
        .setting(AppSettings::GlobalVersion)
        .arg(Arg::with_name("config")
                 .short("c")
                 .long("config")
                 .value_name("FILE")
                 .help("Config file to use [default: .cobalt.yml]")
                 .global(true)
                 .takes_value(true))
        .arg(Arg::with_name("source")
                 .short("s")
                 .long("source")
                 .value_name("DIR")
                 .help("Source folder [default: ./]")
                 .global(true)
                 .takes_value(true))
        .arg(Arg::with_name("destination")
                 .short("d")
                 .long("destination")
                 .value_name("DIR")
                 .help("Destination folder [default: ./]")
                 .global(true)
                 .takes_value(true))
        .arg(Arg::with_name("layouts")
                 .short("l")
                 .long("layouts")
                 .value_name("DIR")
                 .help("Layout templates folder [default: ./_layouts]")
                 .global(true)
                 .takes_value(true))
        .arg(Arg::with_name("posts")
                 .short("p")
                 .long("posts")
                 .value_name("DIR")
                 .help("Posts folder [default: ./posts]")
                 .global(true)
                 .takes_value(true))
        .arg(Arg::with_name("drafts")
                 .long("drafts")
                 .help("Include drafts.")
                 .global(true)
                 .takes_value(false))
        .arg(Arg::with_name("log-level")
                 .short("L")
                 .long("log-level")
                 .possible_values(&["error", "warn", "info", "debug", "trace", "off"])
                 .help("Log level [default: info]")
                 .global(true)
                 .takes_value(true))
        .arg(Arg::with_name("trace")
                 .long("trace")
                 .help("Log ultra-verbose (trace level) information")
                 .global(true)
                 .takes_value(false))
        .arg(Arg::with_name("silent")
                 .long("silent")
                 .help("Suppress all output")
                 .global(true)
                 .takes_value(false))
        .arg(Arg::with_name("dump")
                 .long("dump")
                 .possible_values(&Dump::variants())
                 .help("Dump the specified internal state")
                 .global(true)
                 .multiple(true)
                 .takes_value(true))
        .subcommand(SubCommand::with_name("init")
                        .about("create a new cobalt project")
                        .arg(Arg::with_name("DIRECTORY")
                                 .help("Suppress all output")
                                 .default_value("./")
                                 .index(1)))
        .subcommand(SubCommand::with_name("new")
                        .about("Create a new post or page")
                        .arg(Arg::with_name("FILETYPE")
                                 .help("Type of file to create eg post or page")
                                 .default_value("post")
                                 .takes_value(true))
                        .arg(Arg::with_name("FILENAME")
                                 .help("File to create")
                                 .default_value_if("FILETYPE", Some("page"), "new_page.md")
                                 .default_value("new_post.md")
                                 .takes_value(true)))
        .subcommand(SubCommand::with_name("build")
                        .about("build the cobalt project at the source dir")
                        .arg(Arg::with_name("import")
                                 .short("i")
                                 .long("import")
                                 .help("Import after build to gh-pages branch")
                                 .takes_value(false))
                        .arg(Arg::with_name("branch")
                                 .short("b")
                                 .long("branch")
                                 .value_name("BRANCH")
                                 .help("Branch that will be used to import the site to")
                                 .default_value("gh-pages")
                                 .takes_value(true))
                        .arg(Arg::with_name("message")
                                 .short("m")
                                 .long("message")
                                 .value_name("COMMIT-MESSAGE")
                                 .help("Commit message that will be used on import")
                                 .default_value("cobalt site import")
                                 .takes_value(true)))
        .subcommand(SubCommand::with_name("clean").about("cleans directory set as destination"))
        .subcommand(SubCommand::with_name("serve")
                        .about("build and serve the cobalt project at the source dir")
                        .arg(Arg::with_name("port")
                                 .short("P")
                                 .long("port")
                                 .value_name("INT")
                                 .help("Port to serve from")
                                 .default_value("3000")
                                 .takes_value(true)))
        .subcommand(SubCommand::with_name("watch")
                        .about("build, serve, and watch the project at the source dir")
                        .arg(Arg::with_name("port")
                                 .short("P")
                                 .long("port")
                                 .value_name("INT")
                                 .help("Port to serve from")
                                 .default_value("3000")
                                 .takes_value(true)))
        .subcommand(SubCommand::with_name("import")
                        .about("moves the contents of the dest folder to the gh-pages branch")
                        .arg(Arg::with_name("branch")
                                 .short("b")
                                 .long("branch")
                                 .value_name("BRANCH")
                                 .help("Branch that will be used to import the site to")
                                 .default_value("gh-pages")
                                 .takes_value(true))
                        .arg(Arg::with_name("message")
                                 .short("m")
                                 .long("message")
                                 .value_name("COMMIT-MESSAGE")
                                 .help("Commit message that will be used on import")
                                 .default_value("cobalt site import")
                                 .takes_value(true)))
        .subcommand(SubCommand::with_name("list-syntax-themes").about("list available themes"))
        .subcommand(SubCommand::with_name("list-syntaxes").about("list supported syntaxes"))
        .subcommand(SubCommand::with_name("convert-jekyll")
                        .about("convert jekyll website to cobalt")
                        .arg(Arg::with_name("jksource")
                                 .long("jksrc")
                                 .value_name("JEKYLL-FILE-OR-DIR")
                                 .help("Jekyll posts' directory")
                                 .required(true)
                                 .takes_value(true))
                        .arg(Arg::with_name("jkdestination")
                                 .long("jkdst")
                                 .value_name("DIR")
                                 .help("Output dir of converted posts")
                                 .takes_value(true)
                                 .default_value("./posts")));

    let global_matches = app_cli.get_matches();

    let (command, matches) = match global_matches.subcommand() {
        (command, Some(matches)) => (command, matches),
        (_, None) => unreachable!(),
    };

    let format = |record: &LogRecord| {
        let level = format!("[{}]", record.level()).to_lowercase();
        format!("{:8} {}", level, record.args())
    };

    let mut builder = LogBuilder::new();
    builder.format(format);

    match matches
              .value_of("log-level")
              .or_else(|| global_matches.value_of("log-level")) {
        Some("error") => builder.filter(None, LogLevelFilter::Error),
        Some("warn") => builder.filter(None, LogLevelFilter::Warn),
        Some("debug") => builder.filter(None, LogLevelFilter::Debug),
        Some("trace") => builder.filter(None, LogLevelFilter::Trace),
        Some("off") => builder.filter(None, LogLevelFilter::Off),
        Some("info") | _ => builder.filter(None, LogLevelFilter::Info),
    };

    if matches.is_present("trace") {
        builder.filter(None, LogLevelFilter::Trace);
    }

    if matches.is_present("silent") {
        builder.filter(None, LogLevelFilter::Off);
    }

    builder.init().unwrap();

    let config_path = matches
        .value_of("config")
        .or_else(|| global_matches.value_of("config"))
        .unwrap_or(".cobalt.yml")
        .to_string();

    // Fetch config information if available
    let mut config: Config = if fs::metadata(&config_path).is_ok() {
        info!("Using config file {}", &config_path);

        match Config::from_file(&config_path) {
            Ok(config) => config,
            Err(e) => {
                error!("Error reading config file:");
                error!("{}", e);
                std::process::exit(1);
            }
        }
    } else {
        warn!("No .cobalt.yml file found in current directory, using default config.");
        Default::default()
    };

    config.source = matches
        .value_of("source")
        .or_else(|| global_matches.value_of("source"))
        .map(str::to_string)
        .unwrap_or(config.source);

    config.dest = matches
        .value_of("destination")
        .or_else(|| global_matches.value_of("destination"))
        .map(str::to_string)
        .unwrap_or(config.dest);

    config.layouts = matches
        .value_of("layouts")
        .or_else(|| global_matches.value_of("layouts"))
        .map(str::to_string)
        .unwrap_or(config.layouts);

    config.posts = matches
        .value_of("posts")
        .or_else(|| global_matches.value_of("posts"))
        .map(str::to_string)
        .unwrap_or(config.posts);

    config.include_drafts = matches.is_present("drafts");

    if global_matches.is_present("dump") {
        let mut dump = values_t!(global_matches, "dump", Dump)?;
        config.dump.append(&mut dump);
        info!("Setting: {:?}", config.dump);
    }
    if matches.is_present("dump") {
        let mut dump = values_t!(matches, "dump", Dump)?;
        config.dump.append(&mut dump);
        info!("Setting: {:?}", config.dump);
    }

    match command {
        "init" => new::init_command(config, matches),
        "new" => new::new_command(config, matches),
        "build" => build::build_command(config, matches),
        "clean" => build::clean_command(config, matches),
        "serve" => serve::serve_command(config, matches),
        "watch" => serve::watch_command(config, matches),
        "import" => build::import_command(config, matches),
        "list-syntax-themes" => {
            for name in list_syntax_themes() {
                println!("{}", name);
            }
            Ok(())
        }
        "list-syntaxes" => {
            for name in list_syntaxes() {
                println!("{}", name);
            }
            Ok(())
        }
        "convert-jekyll" => {
            let source = matches.value_of("source").unwrap().to_string();
            let dest = matches.value_of("destination").unwrap().to_string();
            jekyll::jk_document::convert_from_jk(std::path::Path::new(&source),
                                                 std::path::Path::new(&dest))
                .chain_err(|| "Jekyll conversion failed.")
        }
        _ => {
            bail!(global_matches.usage());
        }
    }.chain_err(|| format!("{} command failed", command))?;

    Ok(())
}
<commit_msg>fix(jekyll): Remove crash<commit_after>// Deny warnings, except in `dev` mode

// To update this list
// 1. Run `rustc -W help`
// 2. Grab all `default=warn` warnings
// 3. Paste them here, deleting `warnings`, and any with `deprecated` in the name
#![deny(const_err,
        dead_code,
        illegal_floating_point_literal_pattern,
        improper_ctypes,
        non_camel_case_types,
        non_shorthand_field_patterns,
        non_snake_case,
        non_upper_case_globals,
        no_mangle_generic_items,
        overflowing_literals,
        path_statements,
        patterns_in_fns_without_body,
        plugin_as_library,
        private_in_public,
        private_no_mangle_fns,
        private_no_mangle_statics,
        renamed_and_removed_lints,
        stable_features,
        unconditional_recursion,
        unions_with_drop_fields,
        unknown_lints,
        unreachable_code,
        unreachable_patterns,
        unused_allocation,
        unused_assignments,
        unused_attributes,
        unused_comparisons,
        unused_features,
        unused_imports,
        unused_macros,
        unused_must_use,
        unused_mut,
        unused_parens,
        unused_unsafe,
        unused_variables,
        while_true)]
// This list is select `allow` warnings
#![deny(trivial_casts,
       trivial_numeric_casts,
       unused_extern_crates,
       unused_import_braces)]
#![cfg_attr(feature="cargo-clippy", allow(
        cyclomatic_complexity,
        needless_pass_by_value))]
#![cfg_attr(feature="dev", warn(warnings))]

extern crate cobalt;
extern crate env_logger;
extern crate notify;
extern crate ghp;

extern crate hyper;

#[macro_use]
extern crate error_chain;

#[macro_use]
extern crate clap;

#[macro_use]
extern crate log;

mod build;
mod error;
mod serve;
mod new;

use std::fs;

use clap::{Arg, App, SubCommand, AppSettings};
use cobalt::{Config, Dump, jekyll};
use cobalt::{list_syntaxes, list_syntax_themes};
use env_logger::LogBuilder;
use log::{LogRecord, LogLevelFilter};

use error::*;

quick_main!(run);

fn run() -> Result<()> {
    let app_cli = App::new("Cobalt")
        .version(crate_version!())
        .author("Benny Klotz <r3qnbenni@gmail.com>, Johann Hofmann")
        .about("A static site generator written in Rust.")
        .setting(AppSettings::SubcommandRequired)
        .setting(AppSettings::GlobalVersion)
        .arg(Arg::with_name("config")
                 .short("c")
                 .long("config")
                 .value_name("FILE")
                 .help("Config file to use [default: .cobalt.yml]")
                 .global(true)
                 .takes_value(true))
        .arg(Arg::with_name("source")
                 .short("s")
                 .long("source")
                 .value_name("DIR")
                 .help("Source folder [default: ./]")
                 .global(true)
                 .takes_value(true))
        .arg(Arg::with_name("destination")
                 .short("d")
                 .long("destination")
                 .value_name("DIR")
                 .help("Destination folder [default: ./]")
                 .global(true)
                 .takes_value(true))
        .arg(Arg::with_name("layouts")
                 .short("l")
                 .long("layouts")
                 .value_name("DIR")
                 .help("Layout templates folder [default: ./_layouts]")
                 .global(true)
                 .takes_value(true))
        .arg(Arg::with_name("posts")
                 .short("p")
                 .long("posts")
                 .value_name("DIR")
                 .help("Posts folder [default: ./posts]")
                 .global(true)
                 .takes_value(true))
        .arg(Arg::with_name("drafts")
                 .long("drafts")
                 .help("Include drafts.")
                 .global(true)
                 .takes_value(false))
        .arg(Arg::with_name("log-level")
                 .short("L")
                 .long("log-level")
                 .possible_values(&["error", "warn", "info", "debug", "trace", "off"])
                 .help("Log level [default: info]")
                 .global(true)
                 .takes_value(true))
        .arg(Arg::with_name("trace")
                 .long("trace")
                 .help("Log ultra-verbose (trace level) information")
                 .global(true)
                 .takes_value(false))
        .arg(Arg::with_name("silent")
                 .long("silent")
                 .help("Suppress all output")
                 .global(true)
                 .takes_value(false))
        .arg(Arg::with_name("dump")
                 .long("dump")
                 .possible_values(&Dump::variants())
                 .help("Dump the specified internal state")
                 .global(true)
                 .multiple(true)
                 .takes_value(true))
        .subcommand(SubCommand::with_name("init")
                        .about("create a new cobalt project")
                        .arg(Arg::with_name("DIRECTORY")
                                 .help("Suppress all output")
                                 .default_value("./")
                                 .index(1)))
        .subcommand(SubCommand::with_name("new")
                        .about("Create a new post or page")
                        .arg(Arg::with_name("FILETYPE")
                                 .help("Type of file to create eg post or page")
                                 .default_value("post")
                                 .takes_value(true))
                        .arg(Arg::with_name("FILENAME")
                                 .help("File to create")
                                 .default_value_if("FILETYPE", Some("page"), "new_page.md")
                                 .default_value("new_post.md")
                                 .takes_value(true)))
        .subcommand(SubCommand::with_name("build")
                        .about("build the cobalt project at the source dir")
                        .arg(Arg::with_name("import")
                                 .short("i")
                                 .long("import")
                                 .help("Import after build to gh-pages branch")
                                 .takes_value(false))
                        .arg(Arg::with_name("branch")
                                 .short("b")
                                 .long("branch")
                                 .value_name("BRANCH")
                                 .help("Branch that will be used to import the site to")
                                 .default_value("gh-pages")
                                 .takes_value(true))
                        .arg(Arg::with_name("message")
                                 .short("m")
                                 .long("message")
                                 .value_name("COMMIT-MESSAGE")
                                 .help("Commit message that will be used on import")
                                 .default_value("cobalt site import")
                                 .takes_value(true)))
        .subcommand(SubCommand::with_name("clean").about("cleans directory set as destination"))
        .subcommand(SubCommand::with_name("serve")
                        .about("build and serve the cobalt project at the source dir")
                        .arg(Arg::with_name("port")
                                 .short("P")
                                 .long("port")
                                 .value_name("INT")
                                 .help("Port to serve from")
                                 .default_value("3000")
                                 .takes_value(true)))
        .subcommand(SubCommand::with_name("watch")
                        .about("build, serve, and watch the project at the source dir")
                        .arg(Arg::with_name("port")
                                 .short("P")
                                 .long("port")
                                 .value_name("INT")
                                 .help("Port to serve from")
                                 .default_value("3000")
                                 .takes_value(true)))
        .subcommand(SubCommand::with_name("import")
                        .about("moves the contents of the dest folder to the gh-pages branch")
                        .arg(Arg::with_name("branch")
                                 .short("b")
                                 .long("branch")
                                 .value_name("BRANCH")
                                 .help("Branch that will be used to import the site to")
                                 .default_value("gh-pages")
                                 .takes_value(true))
                        .arg(Arg::with_name("message")
                                 .short("m")
                                 .long("message")
                                 .value_name("COMMIT-MESSAGE")
                                 .help("Commit message that will be used on import")
                                 .default_value("cobalt site import")
                                 .takes_value(true)))
        .subcommand(SubCommand::with_name("list-syntax-themes").about("list available themes"))
        .subcommand(SubCommand::with_name("list-syntaxes").about("list supported syntaxes"))
        .subcommand(SubCommand::with_name("convert-jekyll")
                        .about("convert jekyll website to cobalt")
                        .arg(Arg::with_name("jksrc")
                                 .long("jksrc")
                                 .value_name("JEKYLL-FILE-OR-DIR")
                                 .help("Jekyll posts' directory")
                                 .required(true)
                                 .takes_value(true))
                        .arg(Arg::with_name("jkdst")
                                 .long("jkdst")
                                 .value_name("DIR")
                                 .help("Output dir of converted posts")
                                 .takes_value(true)
                                 .default_value("./posts")));

    let global_matches = app_cli.get_matches();

    let (command, matches) = match global_matches.subcommand() {
        (command, Some(matches)) => (command, matches),
        (_, None) => unreachable!(),
    };

    let format = |record: &LogRecord| {
        let level = format!("[{}]", record.level()).to_lowercase();
        format!("{:8} {}", level, record.args())
    };

    let mut builder = LogBuilder::new();
    builder.format(format);

    match matches
              .value_of("log-level")
              .or_else(|| global_matches.value_of("log-level")) {
        Some("error") => builder.filter(None, LogLevelFilter::Error),
        Some("warn") => builder.filter(None, LogLevelFilter::Warn),
        Some("debug") => builder.filter(None, LogLevelFilter::Debug),
        Some("trace") => builder.filter(None, LogLevelFilter::Trace),
        Some("off") => builder.filter(None, LogLevelFilter::Off),
        Some("info") | _ => builder.filter(None, LogLevelFilter::Info),
    };

    if matches.is_present("trace") {
        builder.filter(None, LogLevelFilter::Trace);
    }

    if matches.is_present("silent") {
        builder.filter(None, LogLevelFilter::Off);
    }

    builder.init().unwrap();

    let config_path = matches
        .value_of("config")
        .or_else(|| global_matches.value_of("config"))
        .unwrap_or(".cobalt.yml")
        .to_string();

    // Fetch config information if available
    let mut config: Config = if fs::metadata(&config_path).is_ok() {
        info!("Using config file {}", &config_path);

        match Config::from_file(&config_path) {
            Ok(config) => config,
            Err(e) => {
                error!("Error reading config file:");
                error!("{}", e);
                std::process::exit(1);
            }
        }
    } else {
        warn!("No .cobalt.yml file found in current directory, using default config.");
        Default::default()
    };

    config.source = matches
        .value_of("source")
        .or_else(|| global_matches.value_of("source"))
        .map(str::to_string)
        .unwrap_or(config.source);

    config.dest = matches
        .value_of("destination")
        .or_else(|| global_matches.value_of("destination"))
        .map(str::to_string)
        .unwrap_or(config.dest);

    config.layouts = matches
        .value_of("layouts")
        .or_else(|| global_matches.value_of("layouts"))
        .map(str::to_string)
        .unwrap_or(config.layouts);

    config.posts = matches
        .value_of("posts")
        .or_else(|| global_matches.value_of("posts"))
        .map(str::to_string)
        .unwrap_or(config.posts);

    config.include_drafts = matches.is_present("drafts");

    if global_matches.is_present("dump") {
        let mut dump = values_t!(global_matches, "dump", Dump)?;
        config.dump.append(&mut dump);
        info!("Setting: {:?}", config.dump);
    }
    if matches.is_present("dump") {
        let mut dump = values_t!(matches, "dump", Dump)?;
        config.dump.append(&mut dump);
        info!("Setting: {:?}", config.dump);
    }

    match command {
        "init" => new::init_command(config, matches),
        "new" => new::new_command(config, matches),
        "build" => build::build_command(config, matches),
        "clean" => build::clean_command(config, matches),
        "serve" => serve::serve_command(config, matches),
        "watch" => serve::watch_command(config, matches),
        "import" => build::import_command(config, matches),
        "list-syntax-themes" => {
            for name in list_syntax_themes() {
                println!("{}", name);
            }
            Ok(())
        }
        "list-syntaxes" => {
            for name in list_syntaxes() {
                println!("{}", name);
            }
            Ok(())
        }
        "convert-jekyll" => {
            let source = matches.value_of("jksrc").unwrap().to_string();
            let dest = matches.value_of("jkdst").unwrap().to_string();
            jekyll::jk_document::convert_from_jk(std::path::Path::new(&source),
                                                 std::path::Path::new(&dest))
                .chain_err(|| "Jekyll conversion failed.")
        }
        _ => {
            bail!(global_matches.usage());
        }
    }.chain_err(|| format!("{} command failed", command))?;

    Ok(())
}
<|endoftext|>


<commit_before>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Errors that can happen while encoding or decoding.

use std::fmt;

use crate::virtio::resource_bridge::ResourceBridgeError;
use crate::virtio::video::control::CtrlType;

/// An error indicating something went wrong while encoding or decoding.
/// Unlike `virtio::video::Error`, `VideoError` is not fatal for `Worker`.
#[derive(Debug)]
pub enum VideoError {
    /// Invalid argument.
    InvalidArgument,
    /// Invalid operation
    InvalidOperation,
    /// Invalid stream ID is specified.
    InvalidStreamId(u32),
    /// Invalid resource ID is specified.
    InvalidResourceId {
        stream_id: u32,
        resource_id: u32,
    },
    /// Invalid parameters are specified.
    InvalidParameter,
    /// No suitable format is supported.
    InvalidFormat,
    /// Failed to get a resource FD via resource_bridge.
    ResourceBridgeFailure(ResourceBridgeError),
    /// Unsupported control type is specified.
    UnsupportedControl(CtrlType),
    // Backend-specific error.
    BackendFailure(Box<dyn std::error::Error + Send>),
}

impl fmt::Display for VideoError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::VideoError::*;
        match self {
            InvalidArgument => write!(f, "invalid argument"),
            InvalidOperation => write!(f, "invalid operation"),
            InvalidStreamId(id) => write!(f, "invalid stream ID {}", id),
            InvalidResourceId {
                stream_id,
                resource_id,
            } => write!(
                f,
                "invalid resource ID {} for stream {}",
                resource_id, stream_id
            ),
            InvalidParameter => write!(f, "invalid parameter"),
            InvalidFormat => write!(f, "invalid format"),
            ResourceBridgeFailure(id) => write!(f, "failed to get resource FD for id {}", id),
            UnsupportedControl(ctrl_type) => write!(f, "unsupported control: {:?}", ctrl_type),
            BackendFailure(e) => write!(f, "backend failure: {}", e),
        }
    }
}

impl From<libvda::Error> for VideoError {
    fn from(error: libvda::Error) -> Self {
        VideoError::BackendFailure(Box::new(error))
    }
}

impl std::error::Error for VideoError {}

pub type VideoResult<T> = Result<T, VideoError>;
<commit_msg>virtio: video: use the thiserror crate with VideoError<commit_after>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Errors that can happen while encoding or decoding.

use thiserror::Error as ThisError;

use crate::virtio::resource_bridge::ResourceBridgeError;
use crate::virtio::video::control::CtrlType;

/// An error indicating something went wrong while encoding or decoding.
/// Unlike `virtio::video::Error`, `VideoError` is not fatal for `Worker`.
#[derive(Debug, ThisError)]
pub enum VideoError {
    /// Invalid argument.
    #[error("invalid argument")]
    InvalidArgument,
    /// Invalid operation.
    #[error("invalid operation")]
    InvalidOperation,
    /// Invalid stream ID is specified.
    #[error("invalid stream ID {0}")]
    InvalidStreamId(u32),
    /// Invalid resource ID is specified.
    #[error("invalid resource ID {resource_id} for stream {stream_id}")]
    InvalidResourceId { stream_id: u32, resource_id: u32 },
    /// Invalid parameters are specified.
    #[error("invalid parameter")]
    InvalidParameter,
    /// No suitable format is supported.
    #[error("invalid format")]
    InvalidFormat,
    /// Failed to get a resource FD via resource_bridge.
    #[error("failed to get resource FD for id {0}")]
    ResourceBridgeFailure(ResourceBridgeError),
    /// Unsupported control type is specified.
    #[error("unsupported control: {0:?}")]
    UnsupportedControl(CtrlType),
    /// Backend-specific error.
    #[error("backend failure: {0}")]
    BackendFailure(Box<dyn std::error::Error + Send>),
}

impl From<libvda::Error> for VideoError {
    fn from(error: libvda::Error) -> Self {
        VideoError::BackendFailure(Box::new(error))
    }
}

pub type VideoResult<T> = Result<T, VideoError>;
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::io::{Error, ErrorKind, Read};
use std::io::{BufReader, BufRead};
use std::io::prelude::*;
use std::iter::Iterator;
use std::fs::File;
use std::path::Path;
use std::string::String;
use std::convert::*;

extern crate csv; // TODO:why do I need to this here as well as top level lib.rs ??

use super::csv::StringRecord;

use super::rel::*;

#[derive(Debug)]
pub enum ExecutionError {
    IoError(Error),
    Custom(String)
}

impl From<Error> for ExecutionError {
    fn from(e: Error) -> Self {
        ExecutionError::IoError(e)
    }
}

//#[derive(Debug)]
//struct InMemoryRelation<'a> {
//    tuples: &'a Vec<Tuple>,
//    schema: &'a TupleType
//}

/// Represents a csv file with a known schema
#[derive(Debug)]
pub struct CsvRelation {
    file: File,
    schema: TupleType
}

pub struct FilterRelation {
    schema: TupleType,
    input: Box<SimpleRelation>,
    expr: Rex
}

pub struct ProjectRelation {
    schema: TupleType,
    input: Box<SimpleRelation>,
    expr: Vec<Rex>
}

impl<'a> CsvRelation {

    pub fn open(file: File, schema: TupleType) -> Result<Self,ExecutionError> {
        Ok(CsvRelation { file, schema })
    }

    /// Convert StringRecord into our internal tuple type based on the known schema
    fn create_tuple(&self, r: &StringRecord) -> Result<Tuple,ExecutionError> {
        assert_eq!(self.schema.columns.len(), r.len());
        let values = self.schema.columns.iter().zip(r.into_iter()).map(|(c,s)| match c.data_type {
            //TODO: remove unwrap use here
            DataType::UnsignedLong => Value::UnsignedLong(s.parse::<u64>().unwrap()),
            DataType::String => Value::String(s.to_string()),
            DataType::Double => Value::Double(s.parse::<f64>().unwrap()),
        }).collect();
        Ok(Tuple::new(values))
    }
}

/// trait for all relations (a relation is essentially just an iterator over tuples with
/// a known schema)
pub trait SimpleRelation {
    /// scan all records in this relation
    fn scan<'a>(&'a self) -> Box<Iterator<Item=Result<Tuple,ExecutionError>> + 'a>;
    /// get the schema for this relation
    fn schema<'a>(&'a self) -> &'a TupleType;
}

impl SimpleRelation for CsvRelation {

    fn scan<'a>(&'a self) -> Box<Iterator<Item=Result<Tuple,ExecutionError>> + 'a> {

        let buf_reader = BufReader::new(&self.file);
        let csv_reader = csv::Reader::from_reader(buf_reader);
        let record_iter = csv_reader.into_records();

        let tuple_iter = record_iter.map(move|r| match r {
            Ok(record) => self.create_tuple(&record),
            Err(_) => Err(ExecutionError::Custom("TODO".to_string()))
        });

        Box::new(tuple_iter)
    }

    fn schema<'a>(&'a self) -> &'a TupleType {
        &self.schema
    }

}

//impl<'a> SimpleRelation<'a> for InMemoryRelation<'a> {
//
//    fn scan<'a>(&'a self) -> Box<Iterator<Item=Result<Tuple,ExecutionError>> + 'a> {
//        let tuple_iter = self.tuples.iter().map(move |t| Ok(t.clone()));
//        Box::new(tuple_iter)
//    }
//
////    fn schema(&'a self) -> &'a TupleType {
////        &self.schema
////    }
//
//}

impl SimpleRelation for FilterRelation {

    fn scan<'a>(&'a self) -> Box<Iterator<Item=Result<Tuple, ExecutionError>> + 'a> {
        Box::new(self.input.scan().filter(move|t|
            match t {
                &Ok(ref tuple) => {
                    let predicate_eval = evaluate(tuple, &self.schema, &self.expr);

                    //println!("FilterRelation considering tuple: {:?} .. evals to {:?}", tuple, predicate_eval);

                    match predicate_eval {
                        Ok(Value::Boolean(b)) => b,
                        _ => false //TODO: error handling
                    }
                },
                _ => false //TODO: error handling
            }
        ))
    }

    fn schema<'a>(&'a self) -> &'a TupleType {
        &self.schema
    }

}

impl SimpleRelation for ProjectRelation {

    fn scan<'a>(&'a self) -> Box<Iterator<Item=Result<Tuple, ExecutionError>> + 'a> {
        let foo = self.input.scan().map(move|r| match r {
            Ok(tuple) => {
                let x = self.expr.iter().map(|e| match e {
                    &Rex::TupleValue(i) => tuple.values[i].clone(),
                    _ => unimplemented!()
                }).collect();
                Ok(Tuple { values: x })
            },
            Err(e) => panic!() // TODO
        });

        Box::new(foo)
    }

    fn schema<'a>(&'a self) -> &'a TupleType {
        &self.schema
    }
}

pub struct ExecutionContext {
    pub schemas: HashMap<String, TupleType>
}

impl ExecutionContext {

    pub fn new() -> Self {
        ExecutionContext { schemas: HashMap::new() }
    }

    pub fn register_table(&mut self, name: String, schema: TupleType) {
        self.schemas.insert(name, schema);
    }

    pub fn create_execution_plan(&self, plan: &Rel) -> Result<Box<SimpleRelation>,ExecutionError> {
        match *plan {

            Rel::TableScan { ref schema_name, ref table_name, ref schema} => {
                // for now, tables are csv files
                let file = File::open(format!("test/{}.csv", table_name))?;
                let rel = CsvRelation::open(file, schema.clone())?;
                Ok(Box::new(rel))
            },

            Rel::CsvFile { ref filename, ref schema } => {
                let file = File::open(filename)?;
                let rel = CsvRelation::open(file, schema.clone())?;
                Ok(Box::new(rel))
            },

            Rel::Selection { ref expr, ref input, ref schema } => {
                let input_rel = self.create_execution_plan(input)?;
                let rel = FilterRelation {
                    input: input_rel,
                    expr: expr.clone(),
                    schema: schema.clone()
                };
                Ok(Box::new(rel))
            },

            Rel::Projection { ref expr, ref input, ref schema } => {
                match input {
                    &Some(ref r) => {
                        let input_rel = self.create_execution_plan(&r)?;
                        let input_schema = input_rel.schema().clone();

                        let project_columns: Vec<ColumnMeta> = expr.iter().map(|e| {
                            match e {
                                &Rex::TupleValue(i) => input_schema.columns[i].clone(),
                                _ => unimplemented!()
                            }
                        }).collect();

                        let project_schema = TupleType { columns: project_columns };

                        let rel = ProjectRelation {
                            input: input_rel,
                            expr: expr.clone(),
                            schema: project_schema,

                        };

                        Ok(Box::new(rel))
                    },
                    _ => unimplemented!("Projection currently requires an input relation")
                }
            },

            _ => {
                println!("Not implemented: {:?}", plan);
                Err(ExecutionError::Custom("not implemented".to_string()))
            }
        }
    }

}

/// Evaluate a relational expression against a tuple
pub fn evaluate(tuple: &Tuple, tt: &TupleType, rex: &Rex) -> Result<Value, Box<Error>> {

    match rex {
        &Rex::BinaryExpr { box ref left, ref op, box ref right } => {
            let left_value = evaluate(tuple, tt, left)?;
            let right_value = evaluate(tuple, tt, right)?;
            match op {
                &Operator::Eq => Ok(Value::Boolean(left_value == right_value)),
                &Operator::NotEq => Ok(Value::Boolean(left_value != right_value)),
                &Operator::Lt => Ok(Value::Boolean(left_value < right_value)),
                &Operator::LtEq => Ok(Value::Boolean(left_value <= right_value)),
                &Operator::Gt => Ok(Value::Boolean(left_value > right_value)),
                &Operator::GtEq => Ok(Value::Boolean(left_value >= right_value)),
            }
        },
        &Rex::TupleValue(index) => Ok(tuple.values[index].clone()),
        &Rex::Literal(ref value) => Ok(value.clone()),
    }

}

<commit_msg>cleaning up error handling<commit_after>use std::collections::HashMap;
use std::io::{Error, ErrorKind, Read};
use std::io::{BufReader, BufRead};
use std::io::prelude::*;
use std::iter::Iterator;
use std::fs::File;
use std::path::Path;
use std::string::String;
use std::convert::*;

extern crate csv;

use super::csv::StringRecord;

use super::rel::*;

#[derive(Debug)]
pub enum ExecutionError {
    IoError(Error),
    CsvError(csv::Error),
    Custom(String)
}

impl From<Error> for ExecutionError {
    fn from(e: Error) -> Self {
        ExecutionError::IoError(e)
    }
}

/// Represents a csv file with a known schema
#[derive(Debug)]
pub struct CsvRelation {
    file: File,
    schema: TupleType
}

pub struct FilterRelation {
    schema: TupleType,
    input: Box<SimpleRelation>,
    expr: Rex
}

pub struct ProjectRelation {
    schema: TupleType,
    input: Box<SimpleRelation>,
    expr: Vec<Rex>
}

impl<'a> CsvRelation {

    pub fn open(file: File, schema: TupleType) -> Result<Self,ExecutionError> {
        Ok(CsvRelation { file, schema })
    }

    /// Convert StringRecord into our internal tuple type based on the known schema
    fn create_tuple(&self, r: &StringRecord) -> Result<Tuple,ExecutionError> {
        assert_eq!(self.schema.columns.len(), r.len());
        let values = self.schema.columns.iter().zip(r.into_iter()).map(|(c,s)| match c.data_type {
            //TODO: remove unwrap use here
            DataType::UnsignedLong => Value::UnsignedLong(s.parse::<u64>().unwrap()),
            DataType::String => Value::String(s.to_string()),
            DataType::Double => Value::Double(s.parse::<f64>().unwrap()),
        }).collect();
        Ok(Tuple::new(values))
    }
}

/// trait for all relations (a relation is essentially just an iterator over tuples with
/// a known schema)
pub trait SimpleRelation {
    /// scan all records in this relation
    fn scan<'a>(&'a self) -> Box<Iterator<Item=Result<Tuple,ExecutionError>> + 'a>;
    /// get the schema for this relation
    fn schema<'a>(&'a self) -> &'a TupleType;
}

impl SimpleRelation for CsvRelation {

    fn scan<'a>(&'a self) -> Box<Iterator<Item=Result<Tuple,ExecutionError>> + 'a> {

        let buf_reader = BufReader::new(&self.file);
        let csv_reader = csv::Reader::from_reader(buf_reader);
        let record_iter = csv_reader.into_records();

        let tuple_iter = record_iter.map(move|r| match r {
            Ok(record) => self.create_tuple(&record),
            Err(e) => Err(ExecutionError::CsvError(e))
        });

        Box::new(tuple_iter)
    }

    fn schema<'a>(&'a self) -> &'a TupleType {
        &self.schema
    }

}

impl SimpleRelation for FilterRelation {

    fn scan<'a>(&'a self) -> Box<Iterator<Item=Result<Tuple, ExecutionError>> + 'a> {
        Box::new(self.input.scan().filter(move|t|
            match t {
                &Ok(ref tuple) => match evaluate(tuple, &self.schema, &self.expr) {
                    Ok(Value::Boolean(b)) => b,
                    _ => panic!("Predicate expression evaluated to non-boolean value")
                },
                _ => true // let errors through the filter so they can be handled later
            }
        ))
    }

    fn schema<'a>(&'a self) -> &'a TupleType {
        &self.schema
    }
}

impl SimpleRelation for ProjectRelation {

    fn scan<'a>(&'a self) -> Box<Iterator<Item=Result<Tuple, ExecutionError>> + 'a> {
        let foo = self.input.scan().map(move|r| match r {
            Ok(tuple) => {
                let x = self.expr.iter().map(|e| match e {
                    &Rex::TupleValue(i) => tuple.values[i].clone(),
                    _ => unimplemented!()
                }).collect();
                Ok(Tuple { values: x })
            },
            Err(e) => panic!() // TODO
        });

        Box::new(foo)
    }

    fn schema<'a>(&'a self) -> &'a TupleType {
        &self.schema
    }
}

pub struct ExecutionContext {
    pub schemas: HashMap<String, TupleType>
}

impl ExecutionContext {

    pub fn new() -> Self {
        ExecutionContext { schemas: HashMap::new() }
    }

    pub fn register_table(&mut self, name: String, schema: TupleType) {
        self.schemas.insert(name, schema);
    }

    pub fn create_execution_plan(&self, plan: &Rel) -> Result<Box<SimpleRelation>,ExecutionError> {
        match *plan {

            Rel::TableScan { ref schema_name, ref table_name, ref schema} => {
                // for now, tables are csv files
                let file = File::open(format!("test/{}.csv", table_name))?;
                let rel = CsvRelation::open(file, schema.clone())?;
                Ok(Box::new(rel))
            },

            Rel::CsvFile { ref filename, ref schema } => {
                let file = File::open(filename)?;
                let rel = CsvRelation::open(file, schema.clone())?;
                Ok(Box::new(rel))
            },

            Rel::Selection { ref expr, ref input, ref schema } => {
                let input_rel = self.create_execution_plan(input)?;
                let rel = FilterRelation {
                    input: input_rel,
                    expr: expr.clone(),
                    schema: schema.clone()
                };
                Ok(Box::new(rel))
            },

            Rel::Projection { ref expr, ref input, ref schema } => {
                match input {
                    &Some(ref r) => {
                        let input_rel = self.create_execution_plan(&r)?;
                        let input_schema = input_rel.schema().clone();

                        let project_columns: Vec<ColumnMeta> = expr.iter().map(|e| {
                            match e {
                                &Rex::TupleValue(i) => input_schema.columns[i].clone(),
                                _ => unimplemented!()
                            }
                        }).collect();

                        let project_schema = TupleType { columns: project_columns };

                        let rel = ProjectRelation {
                            input: input_rel,
                            expr: expr.clone(),
                            schema: project_schema,

                        };

                        Ok(Box::new(rel))
                    },
                    _ => unimplemented!("Projection currently requires an input relation")
                }
            },

            _ => {
                println!("Not implemented: {:?}", plan);
                Err(ExecutionError::Custom("not implemented".to_string()))
            }
        }
    }

}

/// Evaluate a relational expression against a tuple
pub fn evaluate(tuple: &Tuple, tt: &TupleType, rex: &Rex) -> Result<Value, Box<ExecutionError>> {

    match rex {
        &Rex::BinaryExpr { box ref left, ref op, box ref right } => {
            let left_value = evaluate(tuple, tt, left)?;
            let right_value = evaluate(tuple, tt, right)?;
            match op {
                &Operator::Eq => Ok(Value::Boolean(left_value == right_value)),
                &Operator::NotEq => Ok(Value::Boolean(left_value != right_value)),
                &Operator::Lt => Ok(Value::Boolean(left_value < right_value)),
                &Operator::LtEq => Ok(Value::Boolean(left_value <= right_value)),
                &Operator::Gt => Ok(Value::Boolean(left_value > right_value)),
                &Operator::GtEq => Ok(Value::Boolean(left_value >= right_value)),
            }
        },
        &Rex::TupleValue(index) => Ok(tuple.values[index].clone()),
        &Rex::Literal(ref value) => Ok(value.clone()),
    }

}

<|endoftext|>


<commit_before>extern crate roboime_next;
#[macro_use] extern crate glium;
extern crate clap;
extern crate clock_ticks;
//extern crate image;
extern crate env_logger;
#[macro_use] extern crate log;

use std::error::Error;

pub mod models;
pub mod colors;
mod utils;
mod draw;

fn main_loop() -> Result<(), Box<Error>> {
    use std::env;
    use std::thread;
    //use std::io::Cursor;
    use std::time::Duration;
    use std::process::Command;
    use roboime_next::prelude::*;
    use roboime_next::{game, sim, ai};
    use roboime_next::base::{TeamSide, Side, Color, Vec2d};
    use clap::{Arg, App, AppSettings};
    use glium::{glutin, DisplayBuild, Surface};
    use log::LogLevelFilter;
    use env_logger::LogBuilder;
    //use image::image::GenericImage;
    use ::utils::*;

    let matches = App::new("robime-next-cli")
        .setting(AppSettings::ColoredHelp)
        .setting(AppSettings::DeriveDisplayOrder)
        .setting(AppSettings::TrailingVarArg)
        .about("Connect an AI to a Robocup SSL game through an stdio interface (like codingame).")
        .arg(Arg::with_name("blue")
             .short("b")
             .long("blue")
             .help("Play as the blue team."))
        .arg(Arg::with_name("yellow")
             .conflicts_with("blue")
             .short("y")
             .long("yellow")
             .help("Play as the yellow team. (default)"))
        .arg(Arg::with_name("right")
             .short("r")
             .long("right")
             .help("Play on the right side."))
        .arg(Arg::with_name("left")
             .conflicts_with("right")
             .short("l")
             .long("left")
             .help("Play on the left side. (default)"))
        .arg(Arg::with_name("pause")
             .short("p")
             .long("pause")
             .help("Start the simulator paused."))
        .arg(Arg::with_name("v")
             .short("v")
             .multiple(true)
             .help("Sets the level of verbosity."))
        .arg(Arg::with_name("q")
             .conflicts_with("v")
             .long("quiet")
             .short("q")
             .help("Don't log warnings or errors."))
        //.arg(Arg::with_name("d")
        //     .long("debug")
        //     .short("d")
        //     .help("Enable debug logs."))
        .arg(Arg::with_name("AI")
             .required(true)
             .multiple(true)
             .value_name("COMMAND")
             .help("Command to start the AI, accepts arguments."))
        .get_matches();

    {
        let mut builder = LogBuilder::new();
        builder.format(|record| {
            format!("{} [{}] {}", record.level(), record.location().module_path(), record.args())
        });
        let verbosity = matches.occurrences_of("v");
        builder.filter(Some("roboime"), match verbosity {
            0 => LogLevelFilter::Warn,
            1 => LogLevelFilter::Info,
            2 => LogLevelFilter::Debug,
            _ => LogLevelFilter::Trace,
        });
        if matches.is_present("q") {
            builder.filter(Some("roboime"), LogLevelFilter::Off);
        }
        if let Ok(ref log) = env::var("RUST_LOG") {
           builder.parse(log);
        }
        try!(builder.init());
    }

    // building the display, ie. the main object
    let display = try!(glutin::WindowBuilder::new()
        .with_title(format!("RoboIME Next"))
        // 1 extra pixel to align the middle lines to the screen
        .with_dimensions(1041, 741)
        .with_depth_buffer(24)
        .with_gl(glutin::GlRequest::Latest)
        .with_multisampling(2)
        .with_vsync()
        .build_glium());

    let perspective = {
        let (width, height) = display.get_window().unwrap().get_inner_size_points().unwrap();
        perspective_matrix(width as f32, height as f32)
    };

    let is_yellow = {
        let mut yellow = true;
        if matches.is_present("blue")   { yellow = false; };
        if matches.is_present("yellow") { yellow = true; };
        yellow
    };

    let is_left = {
        let mut left = true;
        if matches.is_present("right") { left = false; };
        if matches.is_present("left")  { left = true; };
        left
    };

    let mut is_paused = {
        let mut pause = false;
        if matches.is_present("pause") { pause = true; };
        pause
    };

    let mut ai_cfg = {
        let ai_cmd: Vec<&str> = matches.values_of("AI").unwrap().collect();
        let (ai_program, ai_args) = (ai_cmd[0], &ai_cmd[1..]);
        let mut ai_command = Command::new(ai_program);
        ai_command.args(ai_args);
        let mut ai_cfg = ai::Interface::new(ai_command);
        ai_cfg.is_yellow(is_yellow);
        ai_cfg
    };

    let team_side = {
        use ::models::TeamSide::*;
        match (is_yellow, is_left) {
            (true,  true)  => YellowIsLeft,
            (true,  false) => BlueIsLeft,
            (false, false) => YellowIsLeft,
            (false, true)  => BlueIsLeft,
        }
    };

    let mut sim_state = sim::State::new(TeamSide(Color::yellow(is_yellow), Side::left(is_left)));
    let mut draw_game = try!(draw::Game::new(&display)); draw_game.team_side(&display, team_side);
    let mut game_state = game::State::new();
    let mut ai = try!(ai_cfg.spawn());

    let mut accumulator = 0;
    let mut previous_clock = clock_ticks::precise_time_ns();
    let mut step_clock = previous_clock;
    let mut step_counter = 0;

    // init the AI
    debug!("Wait for AI to start...");
    sim_state.update_game(&mut game_state);
    try!(ai.push_init(&game_state));

    //drop(try!(rx.recv()));
    debug!("AI started, going on...");

    // debugger thread
    let debug = ai.debug.take().unwrap();
    let debugger = thread::spawn(move || {
        for line in debug {
            println!("AI> {}", line.unwrap());
        }
    });

    // the main loop
    'main: loop {
        #[derive(Copy, Clone, PartialEq, Eq)] enum Shot { No, Fwd, Bkw, }
        let mut single_shot = Shot::No;

        // render the game state
        let view = view_matrix(&[0.0, 0.0, 10.0], &[0.0, 0.0, -1.0], &[0.0, 1.0, 0.0]);
        //let view = view_matrix(&[-4.0, -4.0, 4.0], &[1.0, 1.0, -1.0], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[4.0, -4.0, 4.0], &[-1.0, 1.0, -1.0], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[-0.2, -0.2, 0.6], &[0.2, 0.2, -0.6], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[1.0, 2.0, 3.0], &[1.0, 1.0, -3.0], &[0.0, 1.0, 0.0]);
        //let view = view_matrix(&[-4.0, 0.7, 1.6], &[-0.2, -0.2, -0.6], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[-5.0, -0.7, 1.6], &[0.2, 0.2, -0.6], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[4.0, 0.7, 1.6], &[0.2, -0.2, -0.6], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[5.0, -0.7, 1.6], &[-0.2, 0.2, -0.6], &[0.0, 0.0, 1.0]);
        let mut target = display.draw();
        {
            //let state = try!(game_state.read());
            let state = &game_state;
            try!(draw_game.draw_to(&mut target, &state, perspective, view));
        }
        try!(target.finish());

        // polling and handling the events received by the window
        for event in display.poll_events() {
            use glium::glutin::Event::*;
            use glium::glutin::ElementState::*;
            use glium::glutin::VirtualKeyCode;

            match event {
                KeyboardInput(_, _, Some(VirtualKeyCode::Escape)) |
                Closed => {
                    break 'main;
                }
                KeyboardInput(Pressed, _, Some(VirtualKeyCode::P)) => {
                    is_paused = !is_paused;
                }
                KeyboardInput(Pressed, _, Some(VirtualKeyCode::RBracket)) => {
                    single_shot = Shot::Fwd;
                }
                KeyboardInput(Pressed, _, Some(VirtualKeyCode::LBracket)) => {
                    single_shot = Shot::Bkw;
                }
                KeyboardInput(Pressed, _, Some(VirtualKeyCode::R)) => {
                    // reset ball position and speed
                    sim_state.ball.pos = Vec2d(0.0, 0.0);
                    sim_state.ball.vel = Vec2d(0.0, 0.0);
                    sim_state.update_game(&mut game_state);
                }
                _ => ()
            }
        }

        const FIXED_TIME_STEP: u64 = 16666667;

        let now = clock_ticks::precise_time_ns();
        if !is_paused {
            accumulator += now - previous_clock;

            while accumulator >= FIXED_TIME_STEP {
                accumulator -= FIXED_TIME_STEP;
                let now = clock_ticks::precise_time_ns();
                let delta = now - step_clock;
                if delta >= 1_000_000_000 {
                    // expect ~60 steps per second
                    info!("{:2} steps in {:.03} seconds", step_counter, delta as f32 * 1.0e-9);
                    step_counter = 0;
                    step_clock = now;
                }

                // game step
                try!(ai.push_state(&game_state));
                let cmd = try!(ai.read_command(&game_state));
                sim_state.step(cmd, FIXED_TIME_STEP as f32 * 1.0e-9);
                sim_state.update_game(&mut game_state);
                step_counter += 1;
            }
        }
        previous_clock = now;

        if single_shot != Shot::No {
            // XXX: is there a simple way to no duplicade this?
            // game step
            try!(ai.push_state(&game_state));
            let cmd = try!(ai.read_command(&game_state));
            let mut timestep = FIXED_TIME_STEP as f32 * 1.0e-9;
            if single_shot == Shot::Bkw { timestep = -timestep; }
            sim_state.step(cmd, timestep);
            sim_state.update_game(&mut game_state);
        }

        thread::sleep(Duration::from_millis(((FIXED_TIME_STEP - accumulator) / 1_000_000) as u64));
    }

    try!(ai.quit());
    debug!("Waiting for AI to exit");
    // FIXME: error after a quit is a bug, silence it for now
    let _ = ai.join();
    let _ = debugger.join();
    info!("Bye!");

    Ok(())
}

fn main() {
    use std::process::exit;

    if let Err(err) = main_loop() {
        println!("Error: {}.", err.description());

        let mut err: &Error = &*err;
        while let Some(cause) = err.cause() {
            println!("- caused by: {}", cause.description());
            err = cause;
        }

        exit(1);
    }
}
<commit_msg>Improve key shortcuts: exit on Ctrl+Q, Cmd+Q, Win+Q.<commit_after>extern crate roboime_next;
#[macro_use] extern crate glium;
extern crate clap;
extern crate clock_ticks;
//extern crate image;
extern crate env_logger;
#[macro_use] extern crate log;

use std::error::Error;

pub mod models;
pub mod colors;
mod utils;
mod draw;

fn main_loop() -> Result<(), Box<Error>> {
    use std::env;
    use std::thread;
    //use std::io::Cursor;
    use std::time::Duration;
    use std::process::Command;
    use roboime_next::prelude::*;
    use roboime_next::{game, sim, ai};
    use roboime_next::base::{TeamSide, Side, Color, Vec2d};
    use clap::{Arg, App, AppSettings};
    use glium::{glutin, DisplayBuild, Surface};
    use log::LogLevelFilter;
    use env_logger::LogBuilder;
    //use image::image::GenericImage;
    use ::utils::*;

    let matches = App::new("robime-next-cli")
        .setting(AppSettings::ColoredHelp)
        .setting(AppSettings::DeriveDisplayOrder)
        .setting(AppSettings::TrailingVarArg)
        .about("Connect an AI to a Robocup SSL game through an stdio interface (like codingame).")
        .arg(Arg::with_name("blue")
             .short("b")
             .long("blue")
             .help("Play as the blue team."))
        .arg(Arg::with_name("yellow")
             .conflicts_with("blue")
             .short("y")
             .long("yellow")
             .help("Play as the yellow team. (default)"))
        .arg(Arg::with_name("right")
             .short("r")
             .long("right")
             .help("Play on the right side."))
        .arg(Arg::with_name("left")
             .conflicts_with("right")
             .short("l")
             .long("left")
             .help("Play on the left side. (default)"))
        .arg(Arg::with_name("pause")
             .short("p")
             .long("pause")
             .help("Start the simulator paused."))
        .arg(Arg::with_name("v")
             .short("v")
             .multiple(true)
             .help("Sets the level of verbosity."))
        .arg(Arg::with_name("q")
             .conflicts_with("v")
             .long("quiet")
             .short("q")
             .help("Don't log warnings or errors."))
        //.arg(Arg::with_name("d")
        //     .long("debug")
        //     .short("d")
        //     .help("Enable debug logs."))
        .arg(Arg::with_name("AI")
             .required(true)
             .multiple(true)
             .value_name("COMMAND")
             .help("Command to start the AI, accepts arguments."))
        .get_matches();

    {
        let mut builder = LogBuilder::new();
        builder.format(|record| {
            format!("{} [{}] {}", record.level(), record.location().module_path(), record.args())
        });
        let verbosity = matches.occurrences_of("v");
        builder.filter(Some("roboime"), match verbosity {
            0 => LogLevelFilter::Warn,
            1 => LogLevelFilter::Info,
            2 => LogLevelFilter::Debug,
            _ => LogLevelFilter::Trace,
        });
        if matches.is_present("q") {
            builder.filter(Some("roboime"), LogLevelFilter::Off);
        }
        if let Ok(ref log) = env::var("RUST_LOG") {
           builder.parse(log);
        }
        try!(builder.init());
    }

    // building the display, ie. the main object
    let display = try!(glutin::WindowBuilder::new()
        .with_title(format!("RoboIME Next"))
        // 1 extra pixel to align the middle lines to the screen
        .with_dimensions(1041, 741)
        .with_depth_buffer(24)
        .with_gl(glutin::GlRequest::Latest)
        .with_multisampling(2)
        .with_vsync()
        .build_glium());

    let perspective = {
        let (width, height) = display.get_window().unwrap().get_inner_size_points().unwrap();
        perspective_matrix(width as f32, height as f32)
    };

    let is_yellow = {
        let mut yellow = true;
        if matches.is_present("blue")   { yellow = false; };
        if matches.is_present("yellow") { yellow = true; };
        yellow
    };

    let is_left = {
        let mut left = true;
        if matches.is_present("right") { left = false; };
        if matches.is_present("left")  { left = true; };
        left
    };

    let mut is_paused = {
        let mut pause = false;
        if matches.is_present("pause") { pause = true; };
        pause
    };

    let mut ai_cfg = {
        let ai_cmd: Vec<&str> = matches.values_of("AI").unwrap().collect();
        let (ai_program, ai_args) = (ai_cmd[0], &ai_cmd[1..]);
        let mut ai_command = Command::new(ai_program);
        ai_command.args(ai_args);
        let mut ai_cfg = ai::Interface::new(ai_command);
        ai_cfg.is_yellow(is_yellow);
        ai_cfg
    };

    let team_side = {
        use ::models::TeamSide::*;
        match (is_yellow, is_left) {
            (true,  true)  => YellowIsLeft,
            (true,  false) => BlueIsLeft,
            (false, false) => YellowIsLeft,
            (false, true)  => BlueIsLeft,
        }
    };

    let mut sim_state = sim::State::new(TeamSide(Color::yellow(is_yellow), Side::left(is_left)));
    let mut draw_game = try!(draw::Game::new(&display)); draw_game.team_side(&display, team_side);
    let mut game_state = game::State::new();
    let mut ai = try!(ai_cfg.spawn());

    let mut accumulator = 0;
    let mut previous_clock = clock_ticks::precise_time_ns();
    let mut step_clock = previous_clock;
    let mut step_counter = 0;

    let mut key_meta = false;
    let mut key_ctrl = false;

    // init the AI
    debug!("Wait for AI to start...");
    sim_state.update_game(&mut game_state);
    try!(ai.push_init(&game_state));

    //drop(try!(rx.recv()));
    debug!("AI started, going on...");

    // debugger thread
    let debug = ai.debug.take().unwrap();
    let debugger = thread::spawn(move || {
        for line in debug {
            println!("AI> {}", line.unwrap());
        }
    });

    // the main loop
    'main: loop {
        #[derive(Copy, Clone, PartialEq, Eq)] enum Shot { No, Fwd, Bkw, }
        let mut single_shot = Shot::No;

        // render the game state
        let view = view_matrix(&[0.0, 0.0, 10.0], &[0.0, 0.0, -1.0], &[0.0, 1.0, 0.0]);
        //let view = view_matrix(&[-4.0, -4.0, 4.0], &[1.0, 1.0, -1.0], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[4.0, -4.0, 4.0], &[-1.0, 1.0, -1.0], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[-0.2, -0.2, 0.6], &[0.2, 0.2, -0.6], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[1.0, 2.0, 3.0], &[1.0, 1.0, -3.0], &[0.0, 1.0, 0.0]);
        //let view = view_matrix(&[-4.0, 0.7, 1.6], &[-0.2, -0.2, -0.6], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[-5.0, -0.7, 1.6], &[0.2, 0.2, -0.6], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[4.0, 0.7, 1.6], &[0.2, -0.2, -0.6], &[0.0, 0.0, 1.0]);
        //let view = view_matrix(&[5.0, -0.7, 1.6], &[-0.2, 0.2, -0.6], &[0.0, 0.0, 1.0]);
        let mut target = display.draw();
        {
            //let state = try!(game_state.read());
            let state = &game_state;
            try!(draw_game.draw_to(&mut target, &state, perspective, view));
        }
        try!(target.finish());

        // polling and handling the events received by the window
        for event in display.poll_events() {
            use glium::glutin::Event::*;
            use glium::glutin::ElementState::*;
            use glium::glutin::VirtualKeyCode::*;

            match event {

                // close on Ctrl+Q, Cmd+Q, Win+Q, Esc, window X button
                KeyboardInput(Pressed, _, Some(Q)) if key_meta || key_ctrl => break 'main,
                KeyboardInput(Pressed, _, Some(Escape)) | Closed => break 'main,

                // modifier keys
                KeyboardInput(Pressed,  _, Some(LWin)) |
                KeyboardInput(Pressed,  _, Some(RWin)) => { key_meta = true; }
                KeyboardInput(Released, _, Some(LWin)) |
                KeyboardInput(Released, _, Some(RWin)) => { key_meta = false; }
                KeyboardInput(Pressed,  _, Some(LControl)) |
                KeyboardInput(Pressed,  _, Some(RControl)) => { key_ctrl = true; }
                KeyboardInput(Released, _, Some(LControl)) |
                KeyboardInput(Released, _, Some(RControl)) => { key_ctrl = false; }

                // some actions
                KeyboardInput(Pressed, _, Some(P)) => {
                    is_paused = !is_paused;
                }
                KeyboardInput(Pressed, _, Some(RBracket)) => {
                    single_shot = Shot::Fwd;
                }
                KeyboardInput(Pressed, _, Some(LBracket)) => {
                    single_shot = Shot::Bkw;
                }
                KeyboardInput(Pressed, _, Some(R)) => {
                    // reset ball position and speed
                    sim_state.ball.pos = Vec2d(0.0, 0.0);
                    sim_state.ball.vel = Vec2d(0.0, 0.0);
                    sim_state.update_game(&mut game_state);
                }
                KeyboardInput(..) => {
                    debug!("{:?}", event);
                }
                _ => ()
            }
        }

        const FIXED_TIME_STEP: u64 = 16666667;

        let now = clock_ticks::precise_time_ns();
        if !is_paused {
            accumulator += now - previous_clock;

            while accumulator >= FIXED_TIME_STEP {
                accumulator -= FIXED_TIME_STEP;
                let now = clock_ticks::precise_time_ns();
                let delta = now - step_clock;
                if delta >= 1_000_000_000 {
                    // expect ~60 steps per second
                    info!("{:2} steps in {:.03} seconds", step_counter, delta as f32 * 1.0e-9);
                    step_counter = 0;
                    step_clock = now;
                }

                // game step
                try!(ai.push_state(&game_state));
                let cmd = try!(ai.read_command(&game_state));
                sim_state.step(cmd, FIXED_TIME_STEP as f32 * 1.0e-9);
                sim_state.update_game(&mut game_state);
                step_counter += 1;
            }
        }
        previous_clock = now;

        if single_shot != Shot::No {
            // XXX: is there a simple way to no duplicade this?
            // game step
            try!(ai.push_state(&game_state));
            let cmd = try!(ai.read_command(&game_state));
            let mut timestep = FIXED_TIME_STEP as f32 * 1.0e-9;
            if single_shot == Shot::Bkw { timestep = -timestep; }
            sim_state.step(cmd, timestep);
            sim_state.update_game(&mut game_state);
        }

        thread::sleep(Duration::from_millis(((FIXED_TIME_STEP - accumulator) / 1_000_000) as u64));
    }

    try!(ai.quit());
    debug!("Waiting for AI to exit");
    // FIXME: error after a quit is a bug, silence it for now
    let _ = ai.join();
    let _ = debugger.join();
    info!("Bye!");

    Ok(())
}

fn main() {
    use std::process::exit;

    if let Err(err) = main_loop() {
        println!("Error: {}.", err.description());

        let mut err: &Error = &*err;
        while let Some(cause) = err.cause() {
            println!("- caused by: {}", cause.description());
            err = cause;
        }

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


<commit_before>import std._uint;
import std._int;
import front.ast;

type filename = str;
type pos = rec(uint line, uint col);
type span = rec(filename filename, pos lo, pos hi);
type spanned[T] = rec(T node, span span);

tag ty_mach {
    ty_i8;
    ty_i16;
    ty_i32;
    ty_i64;

    ty_u8;
    ty_u16;
    ty_u32;
    ty_u64;

    ty_f32;
    ty_f64;
}

fn ty_mach_to_str(ty_mach tm) -> str {
    alt (tm) {
        case (ty_u8) { ret "u8"; }
        case (ty_u16) { ret "u16"; }
        case (ty_u32) { ret "u32"; }
        case (ty_u64) { ret "u64"; }

        case (ty_i8) { ret "i8"; }
        case (ty_i16) { ret "i16"; }
        case (ty_i32) { ret "i32"; }
        case (ty_i64) { ret "i64"; }

        case (ty_f32) { ret "f32"; }
        case (ty_f64) { ret "f64"; }
    }
}

fn new_str_hash[V]() -> std.map.hashmap[str,V] {
    let std.map.hashfn[str] hasher = std._str.hash;
    let std.map.eqfn[str] eqer = std._str.eq;
    ret std.map.mk_hashmap[str,V](hasher, eqer);
}

fn def_eq(&ast.def_id a, &ast.def_id b) -> bool {
    ret a._0 == b._0 && a._1 == b._1;
}

fn new_def_hash[V]() -> std.map.hashmap[ast.def_id,V] {

    fn hash(&ast.def_id d) -> uint {
        let uint u = d._0 as uint;
        u <<= 16u;
        u |= d._1 as uint;
        ret u;
    }

    let std.map.hashfn[ast.def_id] hasher = hash;
    let std.map.eqfn[ast.def_id] eqer = def_eq;
    ret std.map.mk_hashmap[ast.def_id,V](hasher, eqer);
}

fn new_int_hash[V]() -> std.map.hashmap[int,V] {
    fn hash_int(&int x) -> uint { ret x as uint; }
    fn eq_int(&int a, &int b) -> bool { ret a == b; }
    auto hasher = hash_int;
    auto eqer = eq_int;
    ret std.map.mk_hashmap[int,V](hasher, eqer);
}

fn istr(int i) -> str {
    ret _int.to_str(i, 10u);
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<commit_msg>rustc: Mix the bits more when hashing def ids<commit_after>import std._uint;
import std._int;
import front.ast;

type filename = str;
type pos = rec(uint line, uint col);
type span = rec(filename filename, pos lo, pos hi);
type spanned[T] = rec(T node, span span);

tag ty_mach {
    ty_i8;
    ty_i16;
    ty_i32;
    ty_i64;

    ty_u8;
    ty_u16;
    ty_u32;
    ty_u64;

    ty_f32;
    ty_f64;
}

fn ty_mach_to_str(ty_mach tm) -> str {
    alt (tm) {
        case (ty_u8) { ret "u8"; }
        case (ty_u16) { ret "u16"; }
        case (ty_u32) { ret "u32"; }
        case (ty_u64) { ret "u64"; }

        case (ty_i8) { ret "i8"; }
        case (ty_i16) { ret "i16"; }
        case (ty_i32) { ret "i32"; }
        case (ty_i64) { ret "i64"; }

        case (ty_f32) { ret "f32"; }
        case (ty_f64) { ret "f64"; }
    }
}

fn new_str_hash[V]() -> std.map.hashmap[str,V] {
    let std.map.hashfn[str] hasher = std._str.hash;
    let std.map.eqfn[str] eqer = std._str.eq;
    ret std.map.mk_hashmap[str,V](hasher, eqer);
}

fn def_eq(&ast.def_id a, &ast.def_id b) -> bool {
    ret a._0 == b._0 && a._1 == b._1;
}

fn hash_def(&ast.def_id d) -> uint {
    auto h = 5381u;
    h = ((h << 5u) + h) ^ (d._0 as uint);
    h = ((h << 5u) + h) ^ (d._1 as uint);
    ret h;
}

fn new_def_hash[V]() -> std.map.hashmap[ast.def_id,V] {
    let std.map.hashfn[ast.def_id] hasher = hash_def;
    let std.map.eqfn[ast.def_id] eqer = def_eq;
    ret std.map.mk_hashmap[ast.def_id,V](hasher, eqer);
}

fn new_int_hash[V]() -> std.map.hashmap[int,V] {
    fn hash_int(&int x) -> uint { ret x as uint; }
    fn eq_int(&int a, &int b) -> bool { ret a == b; }
    auto hasher = hash_int;
    auto eqer = eq_int;
    ret std.map.mk_hashmap[int,V](hasher, eqer);
}

fn istr(int i) -> str {
    ret _int.to_str(i, 10u);
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<|endoftext|>


<commit_before>//! Rust bindings for [libressl](http://libressl.org)'s libtls
//! For the authoritative source on the inner workings of libtls check
//! the [manpage](http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man3/tls_accept_fds.3?query=tls_init&sec=3).
//!
//! ## Client
//!
//! ```no_run
//! use std::io::Write;
//! use std::net::TcpStream;
//! tls::init();
//! let tcp = TcpStream::connect("google.com:443").unwrap();
//! let mut client = tls::new_client()
//!     .from_socket(&tcp, "google.com")
//!     .unwrap();
//! client.write("GET / HTTP/1.1\n\n".as_bytes()).unwrap();
//! ```
//!
//! ## Server
//!
//! The library does not handle TCP listening and binding, you need to handle the
//! TCP server accept() and then call `TlsServer::accept`
//!
//! ```no_run
//! use std::net::TcpListener;
//! tls::init();
//! let srv = TcpListener::bind("127.0.0.1:0").unwrap();
//! let addr = srv.local_addr().unwrap();
//! let mut tls_srv = tls::new_server()
//!     .key_file("tests/private_key.key")
//!     .cert_file("tests/certificate.crt")
//!     .bind().unwrap();
//! // Accept TCP connection, and then start TLS over it
//! let tcp_conn = srv.incoming().next().unwrap().unwrap();
//! let mut tls_conn = tls_srv.accept(&tcp_conn).unwrap();
//! ```
//!
//! ## Certificate Verification
//!
//! By default libtls will verify certificates using the system certificate store (usually defined
//! as /etc/ssl/cert.pem). In some Linux flavours and in Windows this file does not exist and you
//! will need to use one of the appropriate methods to load the correct certificates for your
//! system - check the Builder classes for the ca methods.

extern crate libc;

/// TODO: Remove this from the public API
use libc::time_t;
use std::error::Error;
use std::io;
use std::io::{Read, Write};
#[cfg(unix)]
use std::os::unix::io::AsRawFd;
#[cfg(windows)]
use std::os::windows::io::AsRawSocket;

mod util;
mod raw;
use raw::{TlsConfig, TlsContext};

pub use raw::{TlsResult, TlsError, init};

pub struct ClientBuilder {
    cfg: Option<TlsConfig>,
    error: Option<TlsError>,
}

impl ClientBuilder {
    /// Load CA certificates from PEM file
    pub fn ca_file(mut self, path: &str) -> Self {
        if self.error.is_some() {
            return self;
        }
        if let Some(cfg) = self.cfg.as_mut() {
            self.error = cfg.set_ca_file(path).err();
        }
        self
    }
    /// Load CA certificates from folder
    pub fn ca_path(mut self, path: &str) -> Self {
        if self.error.is_some() {
            return self;
        }
        if let Some(cfg) = self.cfg.as_mut() {
            self.error = cfg.set_ca_path(path).err();
        }
        self
    }
    /// Use CA certificates from PEM string
    pub fn ca(mut self, ca: &str) -> Self {
        if self.error.is_some() {
            return self;
        }
        if let Some(cfg) = self.cfg.as_mut() {
            self.error = cfg.set_ca_mem(ca).err();
        }
        self
    }
    pub fn verify_depth(mut self, depth: i32) -> Self {
        if self.error.is_some() {
            return self;
        }
        if let Some(cfg) = self.cfg.as_mut() {
            cfg.set_verify_depth(depth);
        }
        self
    }
    pub fn protocols(mut self, protocols: &str) -> Self {
        if self.error.is_some() {
            return self;
        }
        if let Some(cfg) = self.cfg.as_mut() {
            self.error = cfg.set_protocols(protocols).err();
        }
        self
    }
    pub fn ciphers(mut self, ciphers: &str) -> Self {
        if self.error.is_some() {
            return self;
        }
        if let Some(cfg) = self.cfg.as_mut() {
            self.error = cfg.set_ciphers(ciphers).err();
        }
        self
    }
    /// Disable certificate verification
    pub fn insecure_noverifycert(mut self) -> Self {
        if self.error.is_some() {
            return self;
        }
        if let Some(cfg) = self.cfg.as_mut() {
            cfg.insecure_noverifycert();
        }
        self
    }
    /// Disable hostname verification
    pub fn insecure_noverifyname(mut self) -> Self {
        if self.error.is_some() {
            return self;
        }
        if let Some(cfg) = self.cfg.as_mut() {
            cfg.insecure_noverifyname();
        }
        self
    }

    /// Create client context from settings
    fn new_ctx(self) -> TlsResult<TlsContext> {
        if let Some(err) = self.error {
            Err(err)
        } else {
            let mut cli = try!(TlsContext::new_client());
            // This unwrap should be safe, we can't have a cfg without an error
            try!(cli.configure(self.cfg.unwrap()));
            Ok(cli)
        }
    }

    #[cfg(unix)]
    /// Establish a TLS connection over the given socket
    pub fn from_socket<F: AsRawFd>(self, ifd: &F, servername: &str) -> TlsResult<TlsStream> {
        let mut ctx = try!(self.new_ctx());
        let fd = ifd.as_raw_fd();
        try!(ctx.connect_socket(fd, servername));
        Ok(TlsStream {
            ctx: ctx,
        })
    }

    #[cfg(windows)]
    /// Establish a TLS connection over the given socket
    pub fn from_socket<F: AsRawSocket>(self, isock: &F, servername: &str) -> TlsResult<TlsStream> {
        let mut ctx = try!(self.new_ctx());
        let sock = isock.as_raw_socket();
        try!(ctx.connect_socket(sock, servername));
        Ok(TlsStream { ctx: ctx })
    }
}

/// Create a new TLS client
pub fn new_client() -> ClientBuilder {
    match TlsConfig::new() {
        Ok(cfg) => {
            ClientBuilder {
                cfg: Some(cfg),
                error: None,
            }
        }
        Err(err) => {
            ClientBuilder {
                cfg: None,
                error: Some(err),
            }
        }
    }
}

pub struct TlsStream {
    ctx: TlsContext,
}

impl TlsStream {
    /// Executes the TLS handshake. This function is automatically called when reading or writing,
    /// you usually don't need to call it unless you want to force the handshake to finish sooner.
    ///
    /// Calling handshake multiple times, if the other end of the connection is not expecting it
    /// will usually result in an error.
    pub fn handshake(&mut self) -> TlsResult<()> {
        self.ctx.handshake()
    }

    /// Close the connection
    pub fn shutdown(&mut self) -> io::Result<()> {
        if let Err(err) = self.ctx.close() {
            if err.wants_more() {
                try!(self.ctx.close());
            } else {
                return Err(io::Error::from(err));
            }
        }
        Ok(())
    }

    pub fn certificate_issuer(&self) -> String {
        self.ctx.peer_cert_issuer()
    }
    pub fn certificate_hash(&self) -> String {
        self.ctx.peer_cert_hash()
    }
    pub fn certificate_subject(&self) -> String {
        self.ctx.peer_cert_subject()
    }
    pub fn peer_cert_provided(&self) -> bool {
        self.ctx.peer_cert_provided()
    }
    pub fn peer_cert_notbefore(&self) -> TlsResult<time_t> {
        self.ctx.peer_cert_notbefore()
    }
    pub fn peer_cert_notafter(&self) -> TlsResult<time_t> {
        self.ctx.peer_cert_notafter()
    }
    pub fn peer_cert_contains_name(&self, name: &str) -> bool {
        self.ctx.peer_cert_contains_name(name)
    }
    pub fn version(&self) -> String {
        self.ctx.conn_version()
    }
    pub fn cipher(&self) -> String {
        self.ctx.conn_cipher()
    }
}

impl Read for TlsStream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.ctx
            .read(buf)
            .map_err(|err| io::Error::from(err))
    }
}

impl Write for TlsStream {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.ctx
            .write(buf)
            .map_err(|err| io::Error::from(err))
    }
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl Drop for TlsStream {
    fn drop(&mut self) {
        let _ = self.ctx.close();
    }
}

pub struct ServerBuilder {
    cfg: Option<TlsConfig>,
    error: Option<TlsError>,
}

impl ServerBuilder {
    pub fn key_file(mut self, path: &str) -> Self {
        if self.error.is_some() {
            return self;
        }
        if let Some(cfg) = self.cfg.as_mut() {
            self.error = cfg.set_key_file(path).err();
        }
        self
    }
    pub fn cert_file(mut self, path: &str) -> Self {
        if self.error.is_some() {
            return self;
        }
        if let Some(cfg) = self.cfg.as_mut() {
            self.error = cfg.set_cert_file(path).err();
        }
        self
    }

    /// Create server context from settings
    fn new_ctx(self) -> TlsResult<TlsContext> {
        if let Some(err) = self.error {
            Err(err)
        } else {
            let mut cli = try!(TlsContext::new_server());
            // This unwrap should be safe, we can't have a cfg without an error
            try!(cli.configure(self.cfg.unwrap()));
            Ok(cli)
        }
    }
    pub fn bind(self) -> TlsResult<TlsServer> {
        let ctx = try!(self.new_ctx());
        Ok(TlsServer { ctx: ctx })
    }
}

/// Create a new TLS server
pub fn new_server() -> ServerBuilder {
    match TlsConfig::new() {
        Ok(cfg) => {
            ServerBuilder {
                cfg: Some(cfg),
                error: None,
            }
        }
        Err(err) => {
            ServerBuilder {
                cfg: None,
                error: Some(err),
            }
        }
    }
}

/// TLS Server, used to start TLS session over existing sockets.
pub struct TlsServer {
    ctx: TlsContext,
}

impl TlsServer {
    #[cfg(unix)]
    /// Start a new TLS connection over an existing socket (server-side)
    pub fn accept<F: AsRawFd>(&mut self, ifd: &F) -> io::Result<TlsStream> {
        let fd = ifd.as_raw_fd();
        let c = try!(self.ctx.accept_socket(fd));
        Ok(TlsStream {
            ctx: c,
        })
    }

    #[cfg(windows)]
    /// Start a new TLS connection over an existing socket (server-side)
    pub fn accept<F: AsRawSocket>(&mut self, isock: &F) -> TlsResult<TlsStream> {
        let sock = isock.as_raw_socket();
        let c = try!(self.ctx.accept_socket(sock));
        Ok(TlsStream { ctx: c })
    }
}

#[test]
fn test_protocols() {
    let mut cfg = TlsConfig::new().unwrap();

    // The following are all supported
    cfg.set_protocols("all").unwrap();
    cfg.set_protocols("legacy").unwrap();
    cfg.set_protocols("default").unwrap();
    cfg.set_protocols("secure").unwrap();
    cfg.set_protocols("tlsv1").unwrap();
    cfg.set_protocols("tlsv1.0").unwrap();
    cfg.set_protocols("tlsv1.1").unwrap();
    cfg.set_protocols("tlsv1.2").unwrap();

    // This is not valid
    assert!(cfg.set_protocols("unknown-proto").is_err());
}

#[test]
fn client_ctx_defs() {
    assert!(init());

    let c = TlsContext::new_client().unwrap();

    // These are the defaults before the connection is set
    assert_eq!(c.conn_version(), "");
    assert_eq!(c.conn_cipher(), "");
    assert!(c.peer_cert_notbefore().is_err());
    assert!(c.peer_cert_notafter().is_err());
    assert_eq!(c.peer_cert_issuer(), "");
    assert_eq!(c.peer_cert_subject(), "");
    assert_eq!(c.peer_cert_hash(), "");
    assert_eq!(c.peer_cert_contains_name("some.name"), false);
    assert_eq!(c.peer_cert_provided(), false);
}
<commit_msg>Add doc strings<commit_after>//! Rust bindings for [libressl](http://libressl.org)'s libtls
//! For the authoritative source on the inner workings of libtls check
//! the [manpage](http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man3/tls_accept_fds.3?query=tls_init&sec=3).
//!
//! ## Client
//!
//! ```no_run
//! use std::io::Write;
//! use std::net::TcpStream;
//! tls::init();
//! let tcp = TcpStream::connect("google.com:443").unwrap();
//! let mut client = tls::new_client()
//!     .from_socket(&tcp, "google.com")
//!     .unwrap();
//! client.write("GET / HTTP/1.1\n\n".as_bytes()).unwrap();
//! ```
//!
//! ## Server
//!
//! The library does not handle TCP listening and binding, you need to handle the
//! TCP server accept() and then call `TlsServer::accept`
//!
//! ```no_run
//! use std::net::TcpListener;
//! tls::init();
//! let srv = TcpListener::bind("127.0.0.1:0").unwrap();
//! let addr = srv.local_addr().unwrap();
//! let mut tls_srv = tls::new_server()
//!     .key_file("tests/private_key.key")
//!     .cert_file("tests/certificate.crt")
//!     .bind().unwrap();
//! // Accept TCP connection, and then start TLS over it
//! let tcp_conn = srv.incoming().next().unwrap().unwrap();
//! let mut tls_conn = tls_srv.accept(&tcp_conn).unwrap();
//! ```
//!
//! ## Certificate Verification
//!
//! By default libtls will verify certificates using the system certificate store (usually defined
//! as /etc/ssl/cert.pem). In some Linux flavours and in Windows this file does not exist and you
//! will need to use one of the appropriate methods to load the correct certificates for your
//! system - check the Builder classes for the ca methods.
//!
//! ## Connection Lifetime
//!
//! The `from_socket()` and `accept()` methods build new connections on top of
//! `RawFd`/`RawSocket`. Destroying the TlsStream object WILL NOT cause the underlying
//! sockets to be closed, you need to close them yourself.

extern crate libc;

/// TODO: Remove this from the public API
use libc::time_t;
use std::error::Error;
use std::io;
use std::io::{Read, Write};
#[cfg(unix)]
use std::os::unix::io::AsRawFd;
#[cfg(windows)]
use std::os::windows::io::AsRawSocket;

mod util;
mod raw;
use raw::{TlsConfig, TlsContext};

pub use raw::{TlsResult, TlsError, init};

pub struct ClientBuilder {
    cfg: Option<TlsConfig>,
    error: Option<TlsError>,
}

impl ClientBuilder {
    /// Load CA certificates from PEM file
    pub fn ca_file(mut self, path: &str) -> Self {
        if self.error.is_some() {
            return self;
        }
        if let Some(cfg) = self.cfg.as_mut() {
            self.error = cfg.set_ca_file(path).err();
        }
        self
    }
    /// Load CA certificates from folder
    pub fn ca_path(mut self, path: &str) -> Self {
        if self.error.is_some() {
            return self;
        }
        if let Some(cfg) = self.cfg.as_mut() {
            self.error = cfg.set_ca_path(path).err();
        }
        self
    }
    /// Use CA certificates from PEM string
    pub fn ca(mut self, ca: &str) -> Self {
        if self.error.is_some() {
            return self;
        }
        if let Some(cfg) = self.cfg.as_mut() {
            self.error = cfg.set_ca_mem(ca).err();
        }
        self
    }
    pub fn verify_depth(mut self, depth: i32) -> Self {
        if self.error.is_some() {
            return self;
        }
        if let Some(cfg) = self.cfg.as_mut() {
            cfg.set_verify_depth(depth);
        }
        self
    }
    pub fn protocols(mut self, protocols: &str) -> Self {
        if self.error.is_some() {
            return self;
        }
        if let Some(cfg) = self.cfg.as_mut() {
            self.error = cfg.set_protocols(protocols).err();
        }
        self
    }
    pub fn ciphers(mut self, ciphers: &str) -> Self {
        if self.error.is_some() {
            return self;
        }
        if let Some(cfg) = self.cfg.as_mut() {
            self.error = cfg.set_ciphers(ciphers).err();
        }
        self
    }
    /// Disable certificate verification
    pub fn insecure_noverifycert(mut self) -> Self {
        if self.error.is_some() {
            return self;
        }
        if let Some(cfg) = self.cfg.as_mut() {
            cfg.insecure_noverifycert();
        }
        self
    }
    /// Disable hostname verification
    pub fn insecure_noverifyname(mut self) -> Self {
        if self.error.is_some() {
            return self;
        }
        if let Some(cfg) = self.cfg.as_mut() {
            cfg.insecure_noverifyname();
        }
        self
    }

    /// Create client context from settings
    fn new_ctx(self) -> TlsResult<TlsContext> {
        if let Some(err) = self.error {
            Err(err)
        } else {
            let mut cli = try!(TlsContext::new_client());
            // This unwrap should be safe, we can't have a cfg without an error
            try!(cli.configure(self.cfg.unwrap()));
            Ok(cli)
        }
    }

    #[cfg(unix)]
    /// Establish a TLS connection over the given socket
    pub fn from_socket<F: AsRawFd>(self, ifd: &F, servername: &str) -> TlsResult<TlsStream> {
        let mut ctx = try!(self.new_ctx());
        let fd = ifd.as_raw_fd();
        try!(ctx.connect_socket(fd, servername));
        Ok(TlsStream {
            ctx: ctx,
        })
    }

    #[cfg(windows)]
    /// Establish a TLS connection over the given socket
    pub fn from_socket<F: AsRawSocket>(self, isock: &F, servername: &str) -> TlsResult<TlsStream> {
        let mut ctx = try!(self.new_ctx());
        let sock = isock.as_raw_socket();
        try!(ctx.connect_socket(sock, servername));
        Ok(TlsStream { ctx: ctx })
    }
}

/// Create a new TLS client
pub fn new_client() -> ClientBuilder {
    match TlsConfig::new() {
        Ok(cfg) => {
            ClientBuilder {
                cfg: Some(cfg),
                error: None,
            }
        }
        Err(err) => {
            ClientBuilder {
                cfg: None,
                error: Some(err),
            }
        }
    }
}

pub struct TlsStream {
    ctx: TlsContext,
}

impl TlsStream {
    /// Executes the TLS handshake. This function is automatically called when reading or writing,
    /// you usually don't need to call it unless you want to force the handshake to finish sooner.
    ///
    /// Calling handshake multiple times, if the other end of the connection is not expecting it
    /// will usually result in an error.
    pub fn handshake(&mut self) -> TlsResult<()> {
        self.ctx.handshake()
    }

    /// Close TLS connection. This will not close the underlying transport.
    pub fn shutdown(&mut self) -> io::Result<()> {
        if let Err(err) = self.ctx.close() {
            if err.wants_more() {
                try!(self.ctx.close());
            } else {
                return Err(io::Error::from(err));
            }
        }
        Ok(())
    }

    /// Calling this method before the handshake is complete causes this method
    /// to return an empty string. See [handshake()](#method.handshake).
    pub fn certificate_issuer(&self) -> String {
        self.ctx.peer_cert_issuer()
    }
    /// Calling this method before the handshake is complete causes this method
    /// to return an empty string. See [handshake()](#method.handshake).
    pub fn certificate_hash(&self) -> String {
        self.ctx.peer_cert_hash()
    }
    /// Calling this method before the handshake is complete causes this method
    /// to return an empty string. See [handshake()](#method.handshake).
    pub fn certificate_subject(&self) -> String {
        self.ctx.peer_cert_subject()
    }
    pub fn peer_cert_provided(&self) -> bool {
        self.ctx.peer_cert_provided()
    }
    pub fn peer_cert_notbefore(&self) -> TlsResult<time_t> {
        self.ctx.peer_cert_notbefore()
    }
    pub fn peer_cert_notafter(&self) -> TlsResult<time_t> {
        self.ctx.peer_cert_notafter()
    }
    pub fn peer_cert_contains_name(&self, name: &str) -> bool {
        self.ctx.peer_cert_contains_name(name)
    }
    /// Calling this method before the handshake is complete causes this method
    /// to return an empty string. See [handshake()](#method.handshake).
    pub fn version(&self) -> String {
        self.ctx.conn_version()
    }
    /// Calling this method before the handshake is complete causes this method
    /// to return an empty string. See [handshake()](#method.handshake).
    pub fn cipher(&self) -> String {
        self.ctx.conn_cipher()
    }
}

impl Read for TlsStream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.ctx
            .read(buf)
            .map_err(|err| io::Error::from(err))
    }
}

impl Write for TlsStream {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.ctx
            .write(buf)
            .map_err(|err| io::Error::from(err))
    }
    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl Drop for TlsStream {
    fn drop(&mut self) {
        let _ = self.ctx.close();
    }
}

pub struct ServerBuilder {
    cfg: Option<TlsConfig>,
    error: Option<TlsError>,
}

impl ServerBuilder {
    pub fn key_file(mut self, path: &str) -> Self {
        if self.error.is_some() {
            return self;
        }
        if let Some(cfg) = self.cfg.as_mut() {
            self.error = cfg.set_key_file(path).err();
        }
        self
    }
    pub fn cert_file(mut self, path: &str) -> Self {
        if self.error.is_some() {
            return self;
        }
        if let Some(cfg) = self.cfg.as_mut() {
            self.error = cfg.set_cert_file(path).err();
        }
        self
    }

    /// Create server context from settings
    fn new_ctx(self) -> TlsResult<TlsContext> {
        if let Some(err) = self.error {
            Err(err)
        } else {
            let mut cli = try!(TlsContext::new_server());
            // This unwrap should be safe, we can't have a cfg without an error
            try!(cli.configure(self.cfg.unwrap()));
            Ok(cli)
        }
    }
    pub fn bind(self) -> TlsResult<TlsServer> {
        let ctx = try!(self.new_ctx());
        Ok(TlsServer { ctx: ctx })
    }
}

/// Create a new TLS server
pub fn new_server() -> ServerBuilder {
    match TlsConfig::new() {
        Ok(cfg) => {
            ServerBuilder {
                cfg: Some(cfg),
                error: None,
            }
        }
        Err(err) => {
            ServerBuilder {
                cfg: None,
                error: Some(err),
            }
        }
    }
}

/// TLS Server, used to start TLS session over existing sockets.
pub struct TlsServer {
    ctx: TlsContext,
}

impl TlsServer {
    #[cfg(unix)]
    /// Start a new TLS connection over an existing socket (server-side)
    pub fn accept<F: AsRawFd>(&mut self, ifd: &F) -> io::Result<TlsStream> {
        let fd = ifd.as_raw_fd();
        let c = try!(self.ctx.accept_socket(fd));
        Ok(TlsStream {
            ctx: c,
        })
    }

    #[cfg(windows)]
    /// Start a new TLS connection over an existing socket (server-side)
    pub fn accept<F: AsRawSocket>(&mut self, isock: &F) -> TlsResult<TlsStream> {
        let sock = isock.as_raw_socket();
        let c = try!(self.ctx.accept_socket(sock));
        Ok(TlsStream { ctx: c })
    }
}

#[test]
fn test_protocols() {
    let mut cfg = TlsConfig::new().unwrap();

    // The following are all supported
    cfg.set_protocols("all").unwrap();
    cfg.set_protocols("legacy").unwrap();
    cfg.set_protocols("default").unwrap();
    cfg.set_protocols("secure").unwrap();
    cfg.set_protocols("tlsv1").unwrap();
    cfg.set_protocols("tlsv1.0").unwrap();
    cfg.set_protocols("tlsv1.1").unwrap();
    cfg.set_protocols("tlsv1.2").unwrap();

    // This is not valid
    assert!(cfg.set_protocols("unknown-proto").is_err());
}

#[test]
fn client_ctx_defs() {
    assert!(init());

    let c = TlsContext::new_client().unwrap();

    // These are the defaults before the connection is set
    assert_eq!(c.conn_version(), "");
    assert_eq!(c.conn_cipher(), "");
    assert!(c.peer_cert_notbefore().is_err());
    assert!(c.peer_cert_notafter().is_err());
    assert_eq!(c.peer_cert_issuer(), "");
    assert_eq!(c.peer_cert_subject(), "");
    assert_eq!(c.peer_cert_hash(), "");
    assert_eq!(c.peer_cert_contains_name("some.name"), false);
    assert_eq!(c.peer_cert_provided(), false);
}
<|endoftext|>