<commit_before>use context::*;
use ryba_kit::template::*;
use ryba_kit::form::*;
use ryba_kit::auth::*;
use rocket::request::{Form, FromFormValue};
use rocket::response::Redirect;
use rocket::http::{Cookie, Cookies};
use rocket::State;
use pages::*;
use Users;
use std::sync::Mutex;

#[derive(Serialize)]
pub struct Page {
    title: &'static str,
}

impl Default for Page {
    fn default() -> Page {
        Self { title: "Login" }
    }
}

#[get("/login")]
pub fn get(ctx: Context<Page>) -> Template {
    Template::render("login", &ctx)
}

#[post("/login", data="<data>")]
fn post<'a>(users: State<Mutex<Users>>,
            cookies: &Cookies,
            mut ctx: Context<Page>,
            data: Form<'a, Login<'a>>)
            -> Result<Redirect, Template>
{
/*    let mut form = data.into_inner();
    if let (&Ok(ref user_name), &Ok(ref password), &Ok(ref redirect)) =
        (&form.name.value, &form.password.value, &form.redirect.value) {
        match users.get(user_name) {
            Some(correct_password) if password == correct_password => {
                cookies.add(Cookie::new("user_name", user_name.clone()));
                cookies.add(Cookie::new("hash",
                                        Session::hash(user_name,
                                                      &ctx.session.extra_data,
                                                      password)
                                                .to_string()));
                return Ok(Redirect::to(redirect));
            }
            Some(_) => form.password.msg = Some("wrong password".to_string()),
            None => form.name.msg = Some("user not found".to_string()),
        }
    }*/
   // ctx.site.login = form;
    Err(Template::render("login", ctx))
}
<commit_msg>login works<commit_after>use context::*;
use ryba_kit::template::*;
use ryba_kit::form::*;
use ryba_kit::auth::*;
use rocket::request::{Form, FromFormValue};
use rocket::response::Redirect;
use rocket::http::{Cookie, Cookies};
use rocket::State;
use pages::*;
use Users;
use std::sync::Mutex;

#[derive(Serialize)]
pub struct Page {
    title: &'static str,
}

impl Default for Page {
    fn default() -> Page {
        Self { title: "Login" }
    }
}

#[get("/login")]
pub fn get(ctx: Context<Page>) -> Template {
    Template::render("login", &ctx)
}

#[post("/login", data="<data>")]
fn post<'a>(_users: State<Mutex<Users>>,
            cookies: &Cookies,
            mut ctx: Context<Page>,
            data: Form<'a, Login<'a>>)
            -> Result<Redirect, Template> {
    if let Ok(users) = _users.inner().lock() {
        let form = data.get();
        ctx.site.login = form.context();
        if let Some((name, password, redirect)) = form.values() {
            match users.get(name) {
                Some(correct_password) if password == correct_password => {
                    cookies.add(Cookie::new("user_name", name.clone()));
                    cookies.add(Cookie::new("hash",
                                            hash(name, &ctx.session.client_info, password)
                                                .to_string()));
                    return Ok(Redirect::to(redirect));
                }
                Some(_) => ctx.site.login.password.msg = Some("wrong password".to_string()),
                None => ctx.site.login.name.msg = Some("User not found".to_string()),
            }

        }
    }
    Err(Template::render("login", ctx))
}
<|endoftext|>


<commit_before>use std::sync::{Arc, Mutex};

use wayland_protocols_misc::zwp_input_method_v2::server::zwp_input_method_keyboard_grab_v2::{
    self, ZwpInputMethodKeyboardGrabV2,
};
use wayland_server::backend::{ClientId, ObjectId};
use wayland_server::Dispatch;

use crate::backend::input::KeyState;
use crate::input::{
    keyboard::{
        GrabStartData as KeyboardGrabStartData, KeyboardGrab, KeyboardHandle, KeyboardInnerHandle,
        KeymapFile, ModifiersState,
    },
    SeatHandler,
};
use crate::wayland::{seat::WaylandFocus, text_input::TextInputHandle};

use super::InputMethodManagerState;

#[derive(Default, Debug)]
pub(crate) struct InputMethodKeyboard {
    pub grab: Option<ZwpInputMethodKeyboardGrabV2>,
    pub repeat_delay: i32,
    pub repeat_rate: i32,
    pub keymap_file: Option<KeymapFile>,
    pub text_input_handle: Option<TextInputHandle>,
}

/// Handle to an input method instance
#[derive(Default, Debug, Clone)]
pub struct InputMethodKeyboardGrab {
    pub(crate) inner: Arc<Mutex<InputMethodKeyboard>>,
}

impl<D> KeyboardGrab<D> for InputMethodKeyboardGrab
where
    D: SeatHandler + 'static,
    <D as SeatHandler>::KeyboardFocus: WaylandFocus,
{
    fn input(
        &mut self,
        _data: &mut D,
        _handle: &mut KeyboardInnerHandle<'_, D>,
        keycode: u32,
        key_state: KeyState,
        modifiers: Option<ModifiersState>,
        _serial: crate::utils::Serial,
        time: u32,
    ) {
        let inner = self.inner.lock().unwrap();
        let keyboard = inner.grab.as_ref().unwrap();
        inner
            .text_input_handle
            .as_ref()
            .unwrap()
            .with_focused_text_input(|_, _, serial| {
                if let Some(serialized) = modifiers.map(|m| m.serialized) {
                    keyboard.modifiers(
                        *serial,
                        serialized.depressed,
                        serialized.latched,
                        serialized.locked,
                        serialized.layout_locked,
                    )
                }
                keyboard.key(*serial, time, keycode, key_state.into());
            });
    }

    fn set_focus(
        &mut self,
        data: &mut D,
        handle: &mut KeyboardInnerHandle<'_, D>,
        focus: Option<<D as SeatHandler>::KeyboardFocus>,
        serial: crate::utils::Serial,
    ) {
        let inner = self.inner.lock().unwrap();
        inner
            .text_input_handle
            .as_ref()
            .unwrap()
            .set_focus(focus.as_ref().and_then(|f| f.wl_surface().clone()));
        handle.set_focus(data, focus, serial)
    }

    fn start_data(&self) -> &KeyboardGrabStartData<D> {
        &KeyboardGrabStartData { focus: None }
    }
}

/// User data of ZwpInputKeyboardGrabV2 object
#[derive(Debug)]
pub struct InputMethodKeyboardUserData<D: SeatHandler> {
    pub(super) handle: InputMethodKeyboardGrab,
    pub(crate) keyboard_handle: KeyboardHandle<D>,
}

impl<D: SeatHandler + 'static> Dispatch<ZwpInputMethodKeyboardGrabV2, InputMethodKeyboardUserData<D>, D>
    for InputMethodManagerState
{
    fn destroyed(_state: &mut D, _client: ClientId, _id: ObjectId, data: &InputMethodKeyboardUserData<D>) {
        data.handle.inner.lock().unwrap().grab = None;
        data.keyboard_handle.unset_grab();
    }

    fn request(
        _state: &mut D,
        _client: &wayland_server::Client,
        _resource: &ZwpInputMethodKeyboardGrabV2,
        request: zwp_input_method_keyboard_grab_v2::Request,
        _data: &InputMethodKeyboardUserData<D>,
        _dhandle: &wayland_server::DisplayHandle,
        _data_init: &mut wayland_server::DataInit<'_, D>,
    ) {
        match request {
            zwp_input_method_keyboard_grab_v2::Request::Release => {
                // Nothing to do
            }
            _ => unreachable!(),
        }
    }
}
<commit_msg>clippy fixes<commit_after>use std::sync::{Arc, Mutex};

use wayland_protocols_misc::zwp_input_method_v2::server::zwp_input_method_keyboard_grab_v2::{
    self, ZwpInputMethodKeyboardGrabV2,
};
use wayland_server::backend::{ClientId, ObjectId};
use wayland_server::Dispatch;

use crate::backend::input::KeyState;
use crate::input::{
    keyboard::{
        GrabStartData as KeyboardGrabStartData, KeyboardGrab, KeyboardHandle, KeyboardInnerHandle,
        KeymapFile, ModifiersState,
    },
    SeatHandler,
};
use crate::wayland::{seat::WaylandFocus, text_input::TextInputHandle};

use super::InputMethodManagerState;

#[derive(Default, Debug)]
pub(crate) struct InputMethodKeyboard {
    pub grab: Option<ZwpInputMethodKeyboardGrabV2>,
    pub repeat_delay: i32,
    pub repeat_rate: i32,
    pub keymap_file: Option<KeymapFile>,
    pub text_input_handle: Option<TextInputHandle>,
}

/// Handle to an input method instance
#[derive(Default, Debug, Clone)]
pub struct InputMethodKeyboardGrab {
    pub(crate) inner: Arc<Mutex<InputMethodKeyboard>>,
}

impl<D> KeyboardGrab<D> for InputMethodKeyboardGrab
where
    D: SeatHandler + 'static,
    <D as SeatHandler>::KeyboardFocus: WaylandFocus,
{
    fn input(
        &mut self,
        _data: &mut D,
        _handle: &mut KeyboardInnerHandle<'_, D>,
        keycode: u32,
        key_state: KeyState,
        modifiers: Option<ModifiersState>,
        _serial: crate::utils::Serial,
        time: u32,
    ) {
        let inner = self.inner.lock().unwrap();
        let keyboard = inner.grab.as_ref().unwrap();
        inner
            .text_input_handle
            .as_ref()
            .unwrap()
            .with_focused_text_input(|_, _, serial| {
                if let Some(serialized) = modifiers.map(|m| m.serialized) {
                    keyboard.modifiers(
                        *serial,
                        serialized.depressed,
                        serialized.latched,
                        serialized.locked,
                        serialized.layout_locked,
                    )
                }
                keyboard.key(*serial, time, keycode, key_state.into());
            });
    }

    fn set_focus(
        &mut self,
        data: &mut D,
        handle: &mut KeyboardInnerHandle<'_, D>,
        focus: Option<<D as SeatHandler>::KeyboardFocus>,
        serial: crate::utils::Serial,
    ) {
        let inner = self.inner.lock().unwrap();
        inner
            .text_input_handle
            .as_ref()
            .unwrap()
            .set_focus(focus.as_ref().and_then(|f| f.wl_surface()));
        handle.set_focus(data, focus, serial)
    }

    fn start_data(&self) -> &KeyboardGrabStartData<D> {
        &KeyboardGrabStartData { focus: None }
    }
}

/// User data of ZwpInputKeyboardGrabV2 object
#[derive(Debug)]
pub struct InputMethodKeyboardUserData<D: SeatHandler> {
    pub(super) handle: InputMethodKeyboardGrab,
    pub(crate) keyboard_handle: KeyboardHandle<D>,
}

impl<D: SeatHandler + 'static> Dispatch<ZwpInputMethodKeyboardGrabV2, InputMethodKeyboardUserData<D>, D>
    for InputMethodManagerState
{
    fn destroyed(_state: &mut D, _client: ClientId, _id: ObjectId, data: &InputMethodKeyboardUserData<D>) {
        data.handle.inner.lock().unwrap().grab = None;
        data.keyboard_handle.unset_grab();
    }

    fn request(
        _state: &mut D,
        _client: &wayland_server::Client,
        _resource: &ZwpInputMethodKeyboardGrabV2,
        request: zwp_input_method_keyboard_grab_v2::Request,
        _data: &InputMethodKeyboardUserData<D>,
        _dhandle: &wayland_server::DisplayHandle,
        _data_init: &mut wayland_server::DataInit<'_, D>,
    ) {
        match request {
            zwp_input_method_keyboard_grab_v2::Request::Release => {
                // Nothing to do
            }
            _ => unreachable!(),
        }
    }
}
<|endoftext|>


<commit_before>#![feature(nll)]

extern crate postgres;
extern crate getopts;

use postgres::{Connection, TlsMode};

use std::env;
use getopts::Options;
use std::process;

extern crate pombase;

use pombase::db::*;
use pombase::web::config::*;
use pombase::web::data_build::*;
use pombase::interpro::parse_interpro;

const PKG_NAME: &str = env!("CARGO_PKG_NAME");
const VERSION: &str = env!("CARGO_PKG_VERSION");

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

fn main() -> Result<(), std::io::Error> {
    print!("{} v{}\n", PKG_NAME, VERSION);

    let args: Vec<String> = env::args().collect();
    let mut opts = Options::new();

    opts.optflag("h", "help", "print this help message");
    opts.optopt("c", "config-file", "Configuration file name", "CONFIG");
    opts.optopt("C", "doc-config-file",
                "Documentation configuration file name", "DOC_CONFIG");
    opts.optopt("p", "postgresql-connection-string",
                "PostgresSQL connection string like: postgres://user:pass@host/db_name",
                "CONN_STR");
    opts.optopt("i", "domain-data-file",
                "The name of the InterPro data file generated by 'pombase-domain-process'",
                "FILE");
    opts.optopt("", "go-eco-mapping",
                "GO evidence code to ECO ID mapping from http://purl.obolibrary.org/obo/eco/gaf-eco-mapping.txt", "FILE");
    opts.optopt("d", "output-directory",
                "Destination directory for the output", "DIR");
    opts.optflag("j", "store-json",
                 "optionally create a 'web_json' schema to store the generated JSON in the database");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => panic!("Invalid options\n{}", f)
    };

    let program = args[0].clone();

    if matches.opt_present("help") {
        print_usage(&program, opts);
        process::exit(0);
    }

    if !matches.opt_present("config-file") {
        print!("no -c|--config-file option\n");
        print_usage(&program, opts);
        process::exit(1);
    }
    if !matches.opt_present("doc-config-file") {
        print!("no --doc-config-file option\n");
        print_usage(&program, opts);
        process::exit(1);
    }
    if !matches.opt_present("postgresql-connection-string") {
        print!("no -p|--postgresql-connection-string option\n");
        print_usage(&program, opts);
        process::exit(1);
    }
    if !matches.opt_present("go-eco-mapping") {
        print!("no --go-eco-mapping option\n");
        print_usage(&program, opts);
        process::exit(1);
    }
    if !matches.opt_present("output-directory") {
        print!("no -d|--output-directory option\n");
        print_usage(&program, opts);
        process::exit(1);
    }

    let config = Config::read(&matches.opt_str("c").unwrap());
    let doc_config = DocConfig::read(&matches.opt_str("C").unwrap());
    let connection_string = matches.opt_str("p").unwrap();
    let interpro_json = matches.opt_str("i").unwrap();
    let go_eco_mapping = GoEcoMapping::read(&matches.opt_str("go-eco-mapping").unwrap())?;
    let output_dir = matches.opt_str("d").unwrap();

    let conn = match Connection::connect(connection_string.as_str(), TlsMode::None) {
        Ok(conn) => conn,
        Err(err) => panic!("failed to connect using: {}, err: {}", connection_string, err)
    };

    let raw = Raw::new(&conn);
    let interpro_data = parse_interpro(&config, &interpro_json);
    let web_data_build = WebDataBuild::new(&raw, &interpro_data, &config);
    let web_data = web_data_build.get_web_data();

    match web_data.write(&config, &go_eco_mapping, &doc_config, &output_dir) {
        Ok(_) => (),
        Err(e) => {
            panic!("error while writing: {}", e);
        },
    }

    if matches.opt_present("store-json") {
        conn.execute("DROP SCHEMA IF EXISTS web_json CASCADE", &[])?;
        conn.execute("CREATE SCHEMA web_json", &[])?;
        conn.execute("CREATE EXTENSION IF NOT EXISTS pg_trgm;", &[])?;
        conn.execute("CREATE TABLE web_json.gene (uniquename TEXT, data JSONB)", &[])?;
        conn.execute("CREATE INDEX gene_uniquename_idx ON web_json.gene(uniquename)", &[])?;
        conn.execute("CREATE TABLE web_json.term (termid TEXT, data JSONB)", &[])?;
        conn.execute("CREATE INDEX term_termid_idx ON web_json.term(termid)", &[])?;
        conn.execute("CREATE TABLE web_json.reference (uniquename TEXT, data JSONB)", &[])?;
        conn.execute("CREATE INDEX reference_uniquename_idx on web_json.reference(uniquename)", &[])?;

        web_data.store_jsonb(&conn);

        print!("stored results as JSONB using {}\n", &connection_string);
    }

    Ok(())
}
<commit_msg>Complain if --domain-data-file is missing<commit_after>#![feature(nll)]

extern crate postgres;
extern crate getopts;

use postgres::{Connection, TlsMode};

use std::env;
use getopts::Options;
use std::process;

extern crate pombase;

use pombase::db::*;
use pombase::web::config::*;
use pombase::web::data_build::*;
use pombase::interpro::parse_interpro;

const PKG_NAME: &str = env!("CARGO_PKG_NAME");
const VERSION: &str = env!("CARGO_PKG_VERSION");

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]", program);
    print!("{}", opts.usage(&brief));
}

fn main() -> Result<(), std::io::Error> {
    print!("{} v{}\n", PKG_NAME, VERSION);

    let args: Vec<String> = env::args().collect();
    let mut opts = Options::new();

    opts.optflag("h", "help", "print this help message");
    opts.optopt("c", "config-file", "Configuration file name", "CONFIG");
    opts.optopt("C", "doc-config-file",
                "Documentation configuration file name", "DOC_CONFIG");
    opts.optopt("p", "postgresql-connection-string",
                "PostgresSQL connection string like: postgres://user:pass@host/db_name",
                "CONN_STR");
    opts.optopt("i", "domain-data-file",
                "The name of the InterPro data file generated by 'pombase-domain-process'",
                "FILE");
    opts.optopt("", "go-eco-mapping",
                "GO evidence code to ECO ID mapping from http://purl.obolibrary.org/obo/eco/gaf-eco-mapping.txt", "FILE");
    opts.optopt("d", "output-directory",
                "Destination directory for the output", "DIR");
    opts.optflag("j", "store-json",
                 "optionally create a 'web_json' schema to store the generated JSON in the database");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => m,
        Err(f) => panic!("Invalid options\n{}", f)
    };

    let program = args[0].clone();

    if matches.opt_present("help") {
        print_usage(&program, opts);
        process::exit(0);
    }

    if !matches.opt_present("config-file") {
        print!("no -c|--config-file option\n");
        print_usage(&program, opts);
        process::exit(1);
    }
    if !matches.opt_present("doc-config-file") {
        print!("no --doc-config-file option\n");
        print_usage(&program, opts);
        process::exit(1);
    }
    if !matches.opt_present("postgresql-connection-string") {
        print!("no -p|--postgresql-connection-string option\n");
        print_usage(&program, opts);
        process::exit(1);
    }
    if !matches.opt_present("go-eco-mapping") {
        print!("no --go-eco-mapping option\n");
        print_usage(&program, opts);
        process::exit(1);
    }
    if !matches.opt_present("domain-data-file") {
        print!("no -i|--domain-data-file option\n");
        print_usage(&program, opts);
        process::exit(1);
    }
    if !matches.opt_present("output-directory") {
        print!("no -d|--output-directory option\n");
        print_usage(&program, opts);
        process::exit(1);
    }

    let config = Config::read(&matches.opt_str("c").unwrap());
    let doc_config = DocConfig::read(&matches.opt_str("C").unwrap());
    let connection_string = matches.opt_str("p").unwrap();
    let interpro_json = matches.opt_str("i").unwrap();
    let go_eco_mapping = GoEcoMapping::read(&matches.opt_str("go-eco-mapping").unwrap())?;
    let output_dir = matches.opt_str("d").unwrap();

    let conn = match Connection::connect(connection_string.as_str(), TlsMode::None) {
        Ok(conn) => conn,
        Err(err) => panic!("failed to connect using: {}, err: {}", connection_string, err)
    };

    let raw = Raw::new(&conn);
    let interpro_data = parse_interpro(&config, &interpro_json);
    let web_data_build = WebDataBuild::new(&raw, &interpro_data, &config);
    let web_data = web_data_build.get_web_data();

    match web_data.write(&config, &go_eco_mapping, &doc_config, &output_dir) {
        Ok(_) => (),
        Err(e) => {
            panic!("error while writing: {}", e);
        },
    }

    if matches.opt_present("store-json") {
        conn.execute("DROP SCHEMA IF EXISTS web_json CASCADE", &[])?;
        conn.execute("CREATE SCHEMA web_json", &[])?;
        conn.execute("CREATE EXTENSION IF NOT EXISTS pg_trgm;", &[])?;
        conn.execute("CREATE TABLE web_json.gene (uniquename TEXT, data JSONB)", &[])?;
        conn.execute("CREATE INDEX gene_uniquename_idx ON web_json.gene(uniquename)", &[])?;
        conn.execute("CREATE TABLE web_json.term (termid TEXT, data JSONB)", &[])?;
        conn.execute("CREATE INDEX term_termid_idx ON web_json.term(termid)", &[])?;
        conn.execute("CREATE TABLE web_json.reference (uniquename TEXT, data JSONB)", &[])?;
        conn.execute("CREATE INDEX reference_uniquename_idx on web_json.reference(uniquename)", &[])?;

        web_data.store_jsonb(&conn);

        print!("stored results as JSONB using {}\n", &connection_string);
    }

    Ok(())
}
<|endoftext|>


<commit_before>extern mod std;
extern mod extra;

struct ChildNode {
    pixel: Pixel;
    parent: ParentNode;
}

impl ChildNode {

}

struct Edge {
    source: &ChildNode;
    dest: &ChildNode;
}

struct ParentNode {
    edges: ~[Edge];
}

struct Pixel {
    r: int;
    g: int;
    b: int;
}

fn main() {
    let pixels: ~[Pixel] = processImage();

}
<commit_msg>a bit of work on edges.<commit_after>extern mod std;
extern mod extra;

struct ChildNode {
    pixel: Pixel;
    parent: ParentNode;
}

impl ChildNode {

}

struct Edge {
    source: &ChildNode;
    dest: &ChildNode;
    weight: int;
}

impl Edge {
    fn new(source: &ChildNode, dest: &ChildNode)-> Edge {
        Edge {
            source: source;
            dest: dest;
            weight: 0;
        }
    }
}

struct ParentNode {
    edges: ~[Edge];
}

struct Pixel {
    r: int;
    g: int;
    b: int;
}

fn main() {
    let pixels: ~[Pixel] = processImage();

}
<|endoftext|>


<commit_before>extern crate serde;
extern crate serde_json;

#[macro_use]
extern crate serde_derive;

use serde_json::Error;

#[derive(Serialize, Deserialize)]
struct Person {
    name: String,
    age: u8,
    phones: Vec<String>,
}

#[derive(Serialize, Deserialize)]
struct People {
    people: Vec<Person>
}

fn typed_example(data: &str) -> Result<(), Error> {
    // Some JSON input data as a &str. Maybe this comes from the user.

    // Parse the string of data into a Person object. This is exactly the
    // same function as the one that produced serde_json::Value above, but
    // now we are asking it for a Person as output.
    let p: Person = serde_json::from_str(data)?;

    // Do things just like with any other Rust data structure.
    println!("Please call {} at the number {}", p.name, p.phones[0]);

    Ok(())
}

#[test]
fn it_works_with_simple_data() {
    let data = r#"{
                    "name": "John Doe",
                    "age": 43,
                    "phones": [
                      "+44 1234567",
                      "+44 2345678"
                    ]
                  }"#;
    let result = typed_example(data);
    assert!(result.is_ok());
}

#[test]
fn it_errs_if_data_is_wrong() {
    let data = r#"{
                    "name": "John Doe",
                    "age": "43",
                    "phones": [
                      "+44 1234567",
                      "+44 2345678"
                    ]
                  }"#;
    let result = typed_example(data);
    assert!(result.is_err());
}

#[test]
fn it_nests_structures() {
    let data = r#"{
        "people": [
            {
                "name": "John Doe",
                "age": 43,
                "phones": [
                    "+44 1234567",
                    "+44 2345678"
                ]
            },
            {
                "name": "John Doe",
                "age": 43,
                "phones": [
                    "+44 1234567",
                    "+44 2345678"
                ]
            }
        ]
    }"#;
    let result: Result<People, Error> = serde_json::from_str(data);
    assert!(result.is_ok());
}

#[test]
fn it_expands_vectors() {
    let data = r#"[
        {
            "name": "John Doe",
            "age": 43,
            "phones": [
                "+44 1234567",
                "+44 2345678"
            ]
        },
        {
            "name": "John Doe",
            "age": 43,
            "phones": [
                "+44 1234567",
                "+44 2345678"
            ]
        }
    ]"#;
    let result: Result<Vec<Person>, Error> = serde_json::from_str(data);
    assert!(result.is_ok());
}<commit_msg>Understand serde with optionals<commit_after>extern crate serde;
extern crate serde_json;

#[macro_use]
extern crate serde_derive;

use serde_json::Error;

#[derive(Serialize, Deserialize)]
struct Person {
    name: String,
    age: u8,
    phones: Vec<String>,
}

#[derive(Serialize, Deserialize)]
struct People {
    people: Vec<Person>
}

#[derive(Serialize, Deserialize)]
struct Optionals {
    option: Option<i64>
}

fn typed_example(data: &str) -> Result<(), Error> {
    // Some JSON input data as a &str. Maybe this comes from the user.

    // Parse the string of data into a Person object. This is exactly the
    // same function as the one that produced serde_json::Value above, but
    // now we are asking it for a Person as output.
    let p: Person = serde_json::from_str(data)?;

    // Do things just like with any other Rust data structure.
    println!("Please call {} at the number {}", p.name, p.phones[0]);

    Ok(())
}

#[test]
fn it_works_with_simple_data() {
    let data = r#"{
                    "name": "John Doe",
                    "age": 43,
                    "phones": [
                      "+44 1234567",
                      "+44 2345678"
                    ]
                  }"#;
    let result = typed_example(data);
    assert!(result.is_ok());
}

#[test]
fn it_errs_if_data_is_wrong() {
    let data = r#"{
                    "name": "John Doe",
                    "age": "43",
                    "phones": [
                      "+44 1234567",
                      "+44 2345678"
                    ]
                  }"#;
    let result = typed_example(data);
    assert!(result.is_err());
}

#[test]
fn it_nests_structures() {
    let data = r#"{
        "people": [
            {
                "name": "John Doe",
                "age": 43,
                "phones": [
                    "+44 1234567",
                    "+44 2345678"
                ]
            },
            {
                "name": "John Doe",
                "age": 43,
                "phones": [
                    "+44 1234567",
                    "+44 2345678"
                ]
            }
        ]
    }"#;
    let result: Result<People, Error> = serde_json::from_str(data);
    assert!(result.is_ok());
}

#[test]
fn it_expands_vectors() {
    let data = r#"[
        {
            "name": "John Doe",
            "age": 43,
            "phones": [
                "+44 1234567",
                "+44 2345678"
            ]
        },
        {
            "name": "John Doe",
            "age": 43,
            "phones": [
                "+44 1234567",
                "+44 2345678"
            ]
        }
    ]"#;
    let result: Result<Vec<Person>, Error> = serde_json::from_str(data);
    assert!(result.is_ok());
}

#[test]
fn optional_values_can_be_left_out() {
    let data = r#"
        {
            "optional": 1
        }
    "#;
    let result: Result<Optionals, Error> = serde_json::from_str(data);
    assert!(result.is_ok());
    let data = r#"{}"#;
    let result: Result<Optionals, Error> = serde_json::from_str(data);
    assert!(result.is_ok());
    let structure = result.unwrap();
    assert!(structure.option.is_none());
}<|endoftext|>


<commit_before>//! Tests for --message-format flag.

use cargo_test_support::{basic_manifest, project};

#[cargo_test]
fn cannot_specify_two() {
    let p = project()
        .file("Cargo.toml", &basic_manifest("foo", "0.1.0"))
        .file("src/main.rs", "fn main() {}")
        .build();

    let formats = ["human", "json", "short"];

    let two_kinds = "error: cannot specify two kinds of `message-format` arguments\n";
    for a in formats.iter() {
        for b in formats.iter() {
            p.cargo(&format!("build --message-format {},{}", a, b))
                .with_status(101)
                .with_stderr(two_kinds)
                .run();
        }
    }
}

#[cargo_test]
fn double_json_works() {
    let p = project()
        .file("Cargo.toml", &basic_manifest("foo", "0.1.0"))
        .file("src/main.rs", "fn main() {}")
        .build();

    p.cargo("build --message-format json,json-render-diagnostics")
        .run();
    p.cargo("build --message-format json,json-diagnostic-short")
        .run();
    p.cargo("build --message-format json,json-diagnostic-rendered-ansi")
        .run();
    p.cargo("build --message-format json --message-format json-diagnostic-rendered-ansi")
        .run();
    p.cargo("build --message-format json-diagnostic-rendered-ansi")
        .run();
    p.cargo("build --message-format json-diagnostic-short,json-diagnostic-rendered-ansi")
        .run();
}

#[cargo_test]
fn cargo_renders() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = 'foo'
                version = '0.1.0'

                [dependencies]
                bar = { path = 'bar' }
            "#,
        )
        .file("src/main.rs", "")
        .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
        .file("bar/src/lib.rs", "")
        .build();

    p.cargo("build --message-format json-render-diagnostics")
        .with_status(101)
        .with_stdout(
            "{\"reason\":\"compiler-artifact\",[..]\n\
             {\"reason\":\"build-finished\",\"success\":false}",
        )
        .with_stderr_contains(
            "\
[COMPILING] bar [..]
[COMPILING] foo [..]
error[..]`main`[..]
",
        )
        .run();
}

#[cargo_test]
fn cargo_renders_short() {
    let p = project()
        .file("Cargo.toml", &basic_manifest("foo", "0.1.0"))
        .file("src/main.rs", "")
        .build();

    p.cargo("build --message-format json-render-diagnostics,json-diagnostic-short")
        .with_status(101)
        .with_stderr_contains(
            "\
[COMPILING] foo [..]
error[..]`main`[..]
",
        )
        .with_stderr_does_not_contain("note:")
        .run();
}

#[cargo_test]
fn cargo_renders_ansi() {
    let p = project()
        .file("Cargo.toml", &basic_manifest("foo", "0.1.0"))
        .file("src/main.rs", "")
        .build();

    p.cargo("build --message-format json-diagnostic-rendered-ansi")
        .with_status(101)
        .with_stdout_contains("[..]\\u001b[38;5;9merror[..]")
        .run();
}
<commit_msg>Test the passing of --error-format to rustdoc<commit_after>//! Tests for --message-format flag.

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

#[cargo_test]
fn cannot_specify_two() {
    let p = project()
        .file("Cargo.toml", &basic_manifest("foo", "0.1.0"))
        .file("src/main.rs", "fn main() {}")
        .build();

    let formats = ["human", "json", "short"];

    let two_kinds = "error: cannot specify two kinds of `message-format` arguments\n";
    for a in formats.iter() {
        for b in formats.iter() {
            p.cargo(&format!("build --message-format {},{}", a, b))
                .with_status(101)
                .with_stderr(two_kinds)
                .run();
        }
    }
}

#[cargo_test]
fn double_json_works() {
    let p = project()
        .file("Cargo.toml", &basic_manifest("foo", "0.1.0"))
        .file("src/main.rs", "fn main() {}")
        .build();

    p.cargo("build --message-format json,json-render-diagnostics")
        .run();
    p.cargo("build --message-format json,json-diagnostic-short")
        .run();
    p.cargo("build --message-format json,json-diagnostic-rendered-ansi")
        .run();
    p.cargo("build --message-format json --message-format json-diagnostic-rendered-ansi")
        .run();
    p.cargo("build --message-format json-diagnostic-rendered-ansi")
        .run();
    p.cargo("build --message-format json-diagnostic-short,json-diagnostic-rendered-ansi")
        .run();
}

#[cargo_test]
fn cargo_renders() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [package]
                name = 'foo'
                version = '0.1.0'

                [dependencies]
                bar = { path = 'bar' }
            "#,
        )
        .file("src/main.rs", "")
        .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
        .file("bar/src/lib.rs", "")
        .build();

    p.cargo("build --message-format json-render-diagnostics")
        .with_status(101)
        .with_stdout(
            "{\"reason\":\"compiler-artifact\",[..]\n\
             {\"reason\":\"build-finished\",\"success\":false}",
        )
        .with_stderr_contains(
            "\
[COMPILING] bar [..]
[COMPILING] foo [..]
error[..]`main`[..]
",
        )
        .run();
}

#[cargo_test]
fn cargo_renders_short() {
    let p = project()
        .file("Cargo.toml", &basic_manifest("foo", "0.1.0"))
        .file("src/main.rs", "")
        .build();

    p.cargo("build --message-format json-render-diagnostics,json-diagnostic-short")
        .with_status(101)
        .with_stderr_contains(
            "\
[COMPILING] foo [..]
error[..]`main`[..]
",
        )
        .with_stderr_does_not_contain("note:")
        .run();
}

#[cargo_test]
fn cargo_renders_ansi() {
    let p = project()
        .file("Cargo.toml", &basic_manifest("foo", "0.1.0"))
        .file("src/main.rs", "")
        .build();

    p.cargo("build --message-format json-diagnostic-rendered-ansi")
        .with_status(101)
        .with_stdout_contains("[..]\\u001b[38;5;9merror[..]")
        .run();
}

#[cargo_test]
fn cargo_renders_doctests() {
    if !is_nightly() {
        // --error-format=short support added in 1.51
        return;
    }

    let p = project()
        .file("Cargo.toml", &basic_lib_manifest("foo"))
        .file(
            "src/lib.rs",
            "\
            /// ```rust
            /// bar()
            /// ```
            pub fn bar() {}
            ",
        )
        .build();

    p.cargo("test --doc --message-format short")
        .with_status(101)
        .with_stdout_contains("src/lib.rs:2:1: error[E0425]:[..]")
        .with_stdout_contains("[..]src/lib.rs - bar (line 1)[..]")
        .run();
}
<|endoftext|>


<commit_before>#![feature(exclusive_range_pattern)]
#![feature(half_open_range_patterns)]
#![warn(clippy::match_overlapping_arm)]
#![allow(clippy::redundant_pattern_matching)]
#![allow(clippy::if_same_then_else, clippy::equatable_if_let)]

/// Tests for match_overlapping_arm

fn overlapping() {
    const FOO: u64 = 2;

    match 42 {
        0..=10 => println!("0..=10"),
        0..=11 => println!("0..=11"),
        _ => (),
    }

    match 42 {
        0..=5 => println!("0..=5"),
        6..=7 => println!("6..=7"),
        FOO..=11 => println!("FOO..=11"),
        _ => (),
    }

    match 42 {
        2 => println!("2"),
        0..=5 => println!("0..=5"),
        _ => (),
    }

    match 42 {
        2 => println!("2"),
        0..=2 => println!("0..=2"),
        _ => (),
    }

    match 42 {
        0..=10 => println!("0..=10"),
        11..=50 => println!("11..=50"),
        _ => (),
    }

    match 42 {
        2 => println!("2"),
        0..2 => println!("0..2"),
        _ => (),
    }

    match 42 {
        0..10 => println!("0..10"),
        10..50 => println!("10..50"),
        _ => (),
    }

    match 42 {
        0..11 => println!("0..11"),
        0..=11 => println!("0..=11"),
        _ => (),
    }

    match 42 {
        5..7 => println!("5..7"),
        0..10 => println!("0..10"),
        _ => (),
    }

    match 42 {
        5..10 => println!("5..10"),
        0..=10 => println!("0..=10"),
        _ => (),
    }

    match 42 {
        0..14 => println!("0..14"),
        5..10 => println!("5..10"),
        _ => (),
    }

    match 42 {
        5..14 => println!("5..14"),
        0..=10 => println!("0..=10"),
        _ => (),
    }

    match 42 {
        0..7 => println!("0..7"),
        0..=10 => println!("0..=10"),
        _ => (),
    }

    match 42 {
        3.. => println!("3.."),
        0.. => println!("0.."),
        _ => (),
    }

    match 42 {
        ..=23 => println!("..=23"),
        ..26 => println!("..26"),
        _ => (),
    }

    if let None = Some(42) {
        // nothing
    } else if let None = Some(42) {
        // another nothing :-)
    }
}

fn main() {}
<commit_msg>Add test for #7829<commit_after>#![feature(exclusive_range_pattern)]
#![feature(half_open_range_patterns)]
#![warn(clippy::match_overlapping_arm)]
#![allow(clippy::redundant_pattern_matching)]
#![allow(clippy::if_same_then_else, clippy::equatable_if_let)]

/// Tests for match_overlapping_arm

fn overlapping() {
    const FOO: u64 = 2;

    match 42 {
        0..=10 => println!("0..=10"),
        0..=11 => println!("0..=11"),
        _ => (),
    }

    match 42 {
        0..=5 => println!("0..=5"),
        6..=7 => println!("6..=7"),
        FOO..=11 => println!("FOO..=11"),
        _ => (),
    }

    match 42 {
        2 => println!("2"),
        0..=5 => println!("0..=5"),
        _ => (),
    }

    match 42 {
        2 => println!("2"),
        0..=2 => println!("0..=2"),
        _ => (),
    }

    match 42 {
        0..=10 => println!("0..=10"),
        11..=50 => println!("11..=50"),
        _ => (),
    }

    match 42 {
        2 => println!("2"),
        0..2 => println!("0..2"),
        _ => (),
    }

    match 42 {
        0..10 => println!("0..10"),
        10..50 => println!("10..50"),
        _ => (),
    }

    match 42 {
        0..11 => println!("0..11"),
        0..=11 => println!("0..=11"),
        _ => (),
    }

    match 42 {
        5..7 => println!("5..7"),
        0..10 => println!("0..10"),
        _ => (),
    }

    match 42 {
        5..10 => println!("5..10"),
        0..=10 => println!("0..=10"),
        _ => (),
    }

    match 42 {
        0..14 => println!("0..14"),
        5..10 => println!("5..10"),
        _ => (),
    }

    match 42 {
        5..14 => println!("5..14"),
        0..=10 => println!("0..=10"),
        _ => (),
    }

    match 42 {
        0..7 => println!("0..7"),
        0..=10 => println!("0..=10"),
        _ => (),
    }

    match 42 {
        3.. => println!("3.."),
        0.. => println!("0.."),
        _ => (),
    }

    match 42 {
        ..=23 => println!("..=23"),
        ..26 => println!("..26"),
        _ => (),
    }

    // Issue #7829
    match 0 {
        -1..=1 => (),
        -2..=2 => (),
        _ => (),
    }

    if let None = Some(42) {
        // nothing
    } else if let None = Some(42) {
        // another nothing :-)
    }
}

fn main() {}
<|endoftext|>


<commit_before>//! Abstractions for asynchronous programming.
//!
//! This crate provides a number of core abstractions for writing asynchronous
//! code:
//!
//! - [Futures](crate::future::Future) are single eventual values produced by
//!   asynchronous computations. Some programming languages (e.g. JavaScript)
//!   call this concept "promise".
//! - [Streams](crate::stream::Stream) represent a series of values
//!   produced asynchronously.
//! - [Sinks](crate::sink::Sink) provide support for asynchronous writing of
//!   data.
//! - [Executors](crate::executor) are responsible for running asynchronous
//!   tasks.
//!
//! The crate also contains abstractions for [asynchronous I/O](crate::io) and
//! [cross-task communication](crate::channel).
//!
//! Underlying all of this is the *task system*, which is a form of lightweight
//! threading. Large asynchronous computations are built up using futures,
//! streams and sinks, and then spawned as independent tasks that are run to
//! completion, but *do not block* the thread running them.
//!
//! The following example describes how the task system context is built and used
//! within macros and keywords such as async and await!.
//!
//! ```rust
//! # use futures::channel::mpsc;
//! # use futures::executor; ///standard executors to provide a context for futures and streams
//! # use futures::executor::ThreadPool;
//! # use futures::StreamExt;
//!
//! fn main() {
//!     let pool = ThreadPool::new().expect("Failed to build pool");
//!     let (tx, rx) = mpsc::unbounded::<i32>();
//!
//!     // Create a future by an async block, where async is responsible for an
//!     // implementation of Future. At this point no executor has been provided
//!     // to this future, so it will not be running.
//!     let fut_values = async {
//!         // Create another async block, again where the Future implementation
//!         // is generated by async. Since this is inside of a parent async block,
//!         // it will be provided with the executor of the parent block when the parent
//!         // block is executed.
//!         //
//!         // This executor chaining is done by Future::poll whose second argument
//!         // is a std::task::Context. This represents our executor, and the Future
//!         // implemented by this async block can be polled using the parent async
//!         // block's executor.
//!         let fut_tx_result = async move {
//!             (0..100).for_each(|v| {
//!                 tx.unbounded_send(v).expect("Failed to send");
//!             })
//!         };
//!
//!         // Use the provided thread pool to spawn the generated future
//!         // responsible for transmission
//!         pool.spawn_ok(fut_tx_result);
//!
//!         let fut_values = rx
//!             .map(|v| v * 2)
//!             .collect();
//!
//!         // Use the executor provided to this async block to wait for the
//!         // future to complete.
//!         fut_values.await
//!     };
//!
//!     // Actually execute the above future, which will invoke Future::poll and
//!     // subsequenty chain appropriate Future::poll and methods needing executors
//!     // to drive all futures. Eventually fut_values will be driven to completion.
//!     let values: Vec<i32> = executor::block_on(fut_values);
//!
//!     println!("Values={:?}", values);
//! }
//! ```
//!
//! The majority of examples and code snippets in this crate assume that they are
//! inside an async block as written above.

#![cfg_attr(feature = "cfg-target-has-atomic", feature(cfg_target_has_atomic))]
#![cfg_attr(feature = "read-initializer", feature(read_initializer))]

#![cfg_attr(not(feature = "std"), no_std)]

#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms, unreachable_pub)]
// It cannot be included in the published code because this lints have false positives in the minimum required version.
#![cfg_attr(test, warn(single_use_lifetimes))]
#![warn(clippy::all)]
#![doc(test(attr(deny(warnings), allow(dead_code, unused_assignments, unused_variables))))]

#![cfg_attr(docsrs, feature(doc_cfg))]

#[cfg(all(feature = "cfg-target-has-atomic", not(feature = "unstable")))]
compile_error!("The `cfg-target-has-atomic` feature requires the `unstable` feature as an explicit opt-in to unstable features");

#[cfg(all(feature = "bilock", not(feature = "unstable")))]
compile_error!("The `bilock` feature requires the `unstable` feature as an explicit opt-in to unstable features");

#[cfg(all(feature = "read-initializer", not(feature = "unstable")))]
compile_error!("The `read-initializer` feature requires the `unstable` feature as an explicit opt-in to unstable features");

#[doc(hidden)]
pub use futures_core::future::{Future, TryFuture};
#[doc(hidden)]
pub use futures_util::future::{FutureExt, TryFutureExt};

#[doc(hidden)]
pub use futures_core::stream::{Stream, TryStream};
#[doc(hidden)]
pub use futures_util::stream::{StreamExt, TryStreamExt};

#[doc(hidden)]
pub use futures_sink::Sink;
#[doc(hidden)]
pub use futures_util::sink::SinkExt;

#[cfg(feature = "std")]
#[doc(hidden)]
pub use futures_io::{AsyncBufRead, AsyncRead, AsyncSeek, AsyncWrite};
#[cfg(feature = "std")]
#[doc(hidden)]
pub use futures_util::{AsyncBufReadExt, AsyncReadExt, AsyncSeekExt, AsyncWriteExt};

// Macro reexports
pub use futures_core::ready; // Readiness propagation
pub use futures_util::pin_mut;
#[cfg(feature = "std")]
#[cfg(feature = "async-await")]
pub use futures_util::select;
#[cfg(feature = "async-await")]
pub use futures_util::{join, pending, poll, select_biased, try_join}; // Async-await

// Module reexports
#[doc(inline)]
pub use futures_util::{future, never, sink, stream, task};

#[cfg(feature = "alloc")]
#[doc(inline)]
pub use futures_channel as channel;
#[cfg(feature = "alloc")]
#[doc(inline)]
pub use futures_util::lock;

#[cfg(feature = "std")]
#[doc(inline)]
pub use futures_util::io;

#[cfg(feature = "executor")]
#[cfg_attr(docsrs, doc(cfg(feature = "executor")))]
#[doc(inline)]
pub use futures_executor as executor;

#[cfg(feature = "compat")]
#[cfg_attr(docsrs, doc(cfg(feature = "compat")))]
#[doc(inline)]
pub use futures_util::compat;

pub mod prelude {
    //! A "prelude" for crates using the `futures` crate.
    //!
    //! This prelude is similar to the standard library's prelude in that you'll
    //! almost always want to import its entire contents, but unlike the
    //! standard library's prelude you'll have to do so manually:
    //!
    //! ```
    //! # #[allow(unused_imports)]
    //! use futures::prelude::*;
    //! ```
    //!
    //! The prelude may grow over time as additional items see ubiquitous use.

    pub use crate::future::{self, Future, TryFuture};
    pub use crate::sink::{self, Sink};
    pub use crate::stream::{self, Stream, TryStream};

    #[doc(no_inline)]
    pub use crate::future::{FutureExt as _, TryFutureExt as _};
    #[doc(no_inline)]
    pub use crate::sink::SinkExt as _;
    #[doc(no_inline)]
    pub use crate::stream::{StreamExt as _, TryStreamExt as _};

    #[cfg(feature = "std")]
    pub use crate::io::{AsyncBufRead, AsyncRead, AsyncSeek, AsyncWrite};

    #[cfg(feature = "std")]
    #[doc(no_inline)]
    pub use crate::io::{
        AsyncBufReadExt as _, AsyncReadExt as _, AsyncSeekExt as _, AsyncWriteExt as _,
    };
}
<commit_msg>Remove empty line from futures example<commit_after>//! Abstractions for asynchronous programming.
//!
//! This crate provides a number of core abstractions for writing asynchronous
//! code:
//!
//! - [Futures](crate::future::Future) are single eventual values produced by
//!   asynchronous computations. Some programming languages (e.g. JavaScript)
//!   call this concept "promise".
//! - [Streams](crate::stream::Stream) represent a series of values
//!   produced asynchronously.
//! - [Sinks](crate::sink::Sink) provide support for asynchronous writing of
//!   data.
//! - [Executors](crate::executor) are responsible for running asynchronous
//!   tasks.
//!
//! The crate also contains abstractions for [asynchronous I/O](crate::io) and
//! [cross-task communication](crate::channel).
//!
//! Underlying all of this is the *task system*, which is a form of lightweight
//! threading. Large asynchronous computations are built up using futures,
//! streams and sinks, and then spawned as independent tasks that are run to
//! completion, but *do not block* the thread running them.
//!
//! The following example describes how the task system context is built and used
//! within macros and keywords such as async and await!.
//!
//! ```rust
//! # use futures::channel::mpsc;
//! # use futures::executor; ///standard executors to provide a context for futures and streams
//! # use futures::executor::ThreadPool;
//! # use futures::StreamExt;
//! #
//! fn main() {
//!     let pool = ThreadPool::new().expect("Failed to build pool");
//!     let (tx, rx) = mpsc::unbounded::<i32>();
//!
//!     // Create a future by an async block, where async is responsible for an
//!     // implementation of Future. At this point no executor has been provided
//!     // to this future, so it will not be running.
//!     let fut_values = async {
//!         // Create another async block, again where the Future implementation
//!         // is generated by async. Since this is inside of a parent async block,
//!         // it will be provided with the executor of the parent block when the parent
//!         // block is executed.
//!         //
//!         // This executor chaining is done by Future::poll whose second argument
//!         // is a std::task::Context. This represents our executor, and the Future
//!         // implemented by this async block can be polled using the parent async
//!         // block's executor.
//!         let fut_tx_result = async move {
//!             (0..100).for_each(|v| {
//!                 tx.unbounded_send(v).expect("Failed to send");
//!             })
//!         };
//!
//!         // Use the provided thread pool to spawn the generated future
//!         // responsible for transmission
//!         pool.spawn_ok(fut_tx_result);
//!
//!         let fut_values = rx
//!             .map(|v| v * 2)
//!             .collect();
//!
//!         // Use the executor provided to this async block to wait for the
//!         // future to complete.
//!         fut_values.await
//!     };
//!
//!     // Actually execute the above future, which will invoke Future::poll and
//!     // subsequenty chain appropriate Future::poll and methods needing executors
//!     // to drive all futures. Eventually fut_values will be driven to completion.
//!     let values: Vec<i32> = executor::block_on(fut_values);
//!
//!     println!("Values={:?}", values);
//! }
//! ```
//!
//! The majority of examples and code snippets in this crate assume that they are
//! inside an async block as written above.

#![cfg_attr(feature = "cfg-target-has-atomic", feature(cfg_target_has_atomic))]
#![cfg_attr(feature = "read-initializer", feature(read_initializer))]

#![cfg_attr(not(feature = "std"), no_std)]

#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms, unreachable_pub)]
// It cannot be included in the published code because this lints have false positives in the minimum required version.
#![cfg_attr(test, warn(single_use_lifetimes))]
#![warn(clippy::all)]
#![doc(test(attr(deny(warnings), allow(dead_code, unused_assignments, unused_variables))))]

#![cfg_attr(docsrs, feature(doc_cfg))]

#[cfg(all(feature = "cfg-target-has-atomic", not(feature = "unstable")))]
compile_error!("The `cfg-target-has-atomic` feature requires the `unstable` feature as an explicit opt-in to unstable features");

#[cfg(all(feature = "bilock", not(feature = "unstable")))]
compile_error!("The `bilock` feature requires the `unstable` feature as an explicit opt-in to unstable features");

#[cfg(all(feature = "read-initializer", not(feature = "unstable")))]
compile_error!("The `read-initializer` feature requires the `unstable` feature as an explicit opt-in to unstable features");

#[doc(hidden)]
pub use futures_core::future::{Future, TryFuture};
#[doc(hidden)]
pub use futures_util::future::{FutureExt, TryFutureExt};

#[doc(hidden)]
pub use futures_core::stream::{Stream, TryStream};
#[doc(hidden)]
pub use futures_util::stream::{StreamExt, TryStreamExt};

#[doc(hidden)]
pub use futures_sink::Sink;
#[doc(hidden)]
pub use futures_util::sink::SinkExt;

#[cfg(feature = "std")]
#[doc(hidden)]
pub use futures_io::{AsyncBufRead, AsyncRead, AsyncSeek, AsyncWrite};
#[cfg(feature = "std")]
#[doc(hidden)]
pub use futures_util::{AsyncBufReadExt, AsyncReadExt, AsyncSeekExt, AsyncWriteExt};

// Macro reexports
pub use futures_core::ready; // Readiness propagation
pub use futures_util::pin_mut;
#[cfg(feature = "std")]
#[cfg(feature = "async-await")]
pub use futures_util::select;
#[cfg(feature = "async-await")]
pub use futures_util::{join, pending, poll, select_biased, try_join}; // Async-await

// Module reexports
#[doc(inline)]
pub use futures_util::{future, never, sink, stream, task};

#[cfg(feature = "alloc")]
#[doc(inline)]
pub use futures_channel as channel;
#[cfg(feature = "alloc")]
#[doc(inline)]
pub use futures_util::lock;

#[cfg(feature = "std")]
#[doc(inline)]
pub use futures_util::io;

#[cfg(feature = "executor")]
#[cfg_attr(docsrs, doc(cfg(feature = "executor")))]
#[doc(inline)]
pub use futures_executor as executor;

#[cfg(feature = "compat")]
#[cfg_attr(docsrs, doc(cfg(feature = "compat")))]
#[doc(inline)]
pub use futures_util::compat;

pub mod prelude {
    //! A "prelude" for crates using the `futures` crate.
    //!
    //! This prelude is similar to the standard library's prelude in that you'll
    //! almost always want to import its entire contents, but unlike the
    //! standard library's prelude you'll have to do so manually:
    //!
    //! ```
    //! # #[allow(unused_imports)]
    //! use futures::prelude::*;
    //! ```
    //!
    //! The prelude may grow over time as additional items see ubiquitous use.

    pub use crate::future::{self, Future, TryFuture};
    pub use crate::sink::{self, Sink};
    pub use crate::stream::{self, Stream, TryStream};

    #[doc(no_inline)]
    pub use crate::future::{FutureExt as _, TryFutureExt as _};
    #[doc(no_inline)]
    pub use crate::sink::SinkExt as _;
    #[doc(no_inline)]
    pub use crate::stream::{StreamExt as _, TryStreamExt as _};

    #[cfg(feature = "std")]
    pub use crate::io::{AsyncBufRead, AsyncRead, AsyncSeek, AsyncWrite};

    #[cfg(feature = "std")]
    #[doc(no_inline)]
    pub use crate::io::{
        AsyncBufReadExt as _, AsyncReadExt as _, AsyncSeekExt as _, AsyncWriteExt as _,
    };
}
<|endoftext|>


<commit_before>//!
//!
//! https://tools.ietf.org/html/rfc2971
//!
//! The IMAP4 ID extension
//!

use std::{borrow::Cow, collections::HashMap};

use nom::{
    branch::alt,
    bytes::complete::tag_no_case,
    character::complete::{char, space1},
    combinator::map,
    multi::many0,
    sequence::{separated_pair, tuple},
    IResult,
};

use crate::{
    parser::core::{nil, nstring_utf8, string_utf8},
    Response,
};

// A single id parameter (field and value).
// Format: string SPACE nstring
// [RFC2971 - Formal Syntax](https://tools.ietf.org/html/rfc2971#section-4)
fn id_param(i: &[u8]) -> IResult<&[u8], (&str, Option<&str>)> {
    separated_pair(string_utf8, space1, nstring_utf8)(i)
}

// The non-nil case of id parameter list.
// Format: "(" #(string SPACE nstring) ")"
// [RFC2971 - Formal Syntax](https://tools.ietf.org/html/rfc2971#section-4)
fn id_param_list_not_nil(i: &[u8]) -> IResult<&[u8], HashMap<&str, &str>> {
    map(
        tuple((
            char('('),
            id_param,
            many0(tuple((space1, id_param))),
            char(')'),
        )),
        |(_, first_param, rest_params, _)| {
            let mut params = vec![first_param];
            for (_, p) in rest_params {
                params.push(p)
            }

            params
                .into_iter()
                .filter(|(_k, v)| v.is_some())
                .map(|(k, v)| (k, v.unwrap()))
                .collect()
        },
    )(i)
}

// The id parameter list of all cases
// id_params_list ::= "(" #(string SPACE nstring) ")" / nil
// [RFC2971 - Formal Syntax](https://tools.ietf.org/html/rfc2971#section-4)
fn id_param_list(i: &[u8]) -> IResult<&[u8], Option<HashMap<&str, &str>>> {
    alt((map(id_param_list_not_nil, Some), map(nil, |_| None)))(i)
}

// id_response ::= "ID" SPACE id_params_list
// [RFC2971 - Formal Syntax](https://tools.ietf.org/html/rfc2971#section-4)
pub(crate) fn resp_id(i: &[u8]) -> IResult<&[u8], Response> {
    let (rest, map) = map(
        tuple((tag_no_case("ID"), space1, id_param_list)),
        |(_id, _sp, p)| p,
    )(i)?;

    Ok((
        rest,
        Response::Id(map.map(|m| {
            m.into_iter()
                .map(|(k, v)| (Cow::Borrowed(k), Cow::Borrowed(v)))
                .collect()
        })),
    ))
}

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

    #[test]
    fn test_id_param() {
        assert_matches!(
            id_param(br##""name" "Cyrus""##),
            Ok((_, (name, value))) => {
                assert_eq!(name, "name");
                assert_eq!(value, Some("Cyrus"));
            }
        );

        assert_matches!(
            id_param(br##""name" NIL"##),
            Ok((_, (name, value))) => {
                assert_eq!(name, "name");
                assert_eq!(value, None);
            }
        );
    }

    #[test]
    fn test_id_param_list_not_nil() {
        assert_matches!(
            id_param_list_not_nil(br##"("name" "Cyrus" "version" "1.5" "os" "sunos" "os-version" "5.5" "support-url" "mailto:cyrus-bugs+@andrew.cmu.edu")"##),
            Ok((_, params)) => {
                assert_eq!(
                    params,
                    vec![
                        ("name", "Cyrus"),
                        ("version", "1.5"),
                        ("os", "sunos"),
                        ("os-version", "5.5"),
                        ("support-url", "mailto:cyrus-bugs+@andrew.cmu.edu"),
                    ].into_iter()
                    .collect()
                );
            }
        );
    }

    #[test]
    fn test_id_param_list() {
        assert_matches!(
            id_param_list(br##"("name" "Cyrus" "version" "1.5" "os" "sunos" "os-version" "5.5" "support-url" "mailto:cyrus-bugs+@andrew.cmu.edu")"##),
            Ok((_, Some(params))) => {
                assert_eq!(
                    params,
                    vec![
                        ("name", "Cyrus"),
                        ("version", "1.5"),
                        ("os", "sunos"),
                        ("os-version", "5.5"),
                        ("support-url", "mailto:cyrus-bugs+@andrew.cmu.edu"),
                    ].into_iter()
                    .collect()
                );
            }
        );

        assert_matches!(
            id_param_list(br##"NIL"##),
            Ok((_, params)) => {
                assert_eq!(params, None);
            }
        );
    }

    #[test]
    fn test_resp_id() {
        assert_matches!(
            resp_id(br##"ID ("name" "Cyrus" "version" "1.5" "os" "sunos" "os-version" "5.5" "support-url" "mailto:cyrus-bugs+@andrew.cmu.edu")"##),
            Ok((_, Response::Id(Some(id_info)))) => {
                assert_eq!(
                    id_info,
                    vec![
                        ("name", "Cyrus"),
                        ("version", "1.5"),
                        ("os", "sunos"),
                        ("os-version", "5.5"),
                        ("support-url", "mailto:cyrus-bugs+@andrew.cmu.edu"),
                    ].into_iter()
                    .map(|(k, v)| (Cow::Borrowed(k), Cow::Borrowed(v)))
                    .collect()
                );
            }
        );

        assert_matches!(
            resp_id(br##"ID NIL"##),
            Ok((_, Response::Id(id_info))) => {
                assert_eq!(id_info, None);
            }
        );
    }
}
<commit_msg>Test that RFC2971 parser can deal with NIL values<commit_after>//!
//!
//! https://tools.ietf.org/html/rfc2971
//!
//! The IMAP4 ID extension
//!

use std::{borrow::Cow, collections::HashMap};

use nom::{
    branch::alt,
    bytes::complete::tag_no_case,
    character::complete::{char, space1},
    combinator::map,
    multi::many0,
    sequence::{separated_pair, tuple},
    IResult,
};

use crate::{
    parser::core::{nil, nstring_utf8, string_utf8},
    Response,
};

// A single id parameter (field and value).
// Format: string SPACE nstring
// [RFC2971 - Formal Syntax](https://tools.ietf.org/html/rfc2971#section-4)
fn id_param(i: &[u8]) -> IResult<&[u8], (&str, Option<&str>)> {
    separated_pair(string_utf8, space1, nstring_utf8)(i)
}

// The non-nil case of id parameter list.
// Format: "(" #(string SPACE nstring) ")"
// [RFC2971 - Formal Syntax](https://tools.ietf.org/html/rfc2971#section-4)
fn id_param_list_not_nil(i: &[u8]) -> IResult<&[u8], HashMap<&str, &str>> {
    map(
        tuple((
            char('('),
            id_param,
            many0(tuple((space1, id_param))),
            char(')'),
        )),
        |(_, first_param, rest_params, _)| {
            let mut params = vec![first_param];
            for (_, p) in rest_params {
                params.push(p)
            }

            params
                .into_iter()
                .filter(|(_k, v)| v.is_some())
                .map(|(k, v)| (k, v.unwrap()))
                .collect()
        },
    )(i)
}

// The id parameter list of all cases
// id_params_list ::= "(" #(string SPACE nstring) ")" / nil
// [RFC2971 - Formal Syntax](https://tools.ietf.org/html/rfc2971#section-4)
fn id_param_list(i: &[u8]) -> IResult<&[u8], Option<HashMap<&str, &str>>> {
    alt((map(id_param_list_not_nil, Some), map(nil, |_| None)))(i)
}

// id_response ::= "ID" SPACE id_params_list
// [RFC2971 - Formal Syntax](https://tools.ietf.org/html/rfc2971#section-4)
pub(crate) fn resp_id(i: &[u8]) -> IResult<&[u8], Response> {
    let (rest, map) = map(
        tuple((tag_no_case("ID"), space1, id_param_list)),
        |(_id, _sp, p)| p,
    )(i)?;

    Ok((
        rest,
        Response::Id(map.map(|m| {
            m.into_iter()
                .map(|(k, v)| (Cow::Borrowed(k), Cow::Borrowed(v)))
                .collect()
        })),
    ))
}

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

    #[test]
    fn test_id_param() {
        assert_matches!(
            id_param(br##""name" "Cyrus""##),
            Ok((_, (name, value))) => {
                assert_eq!(name, "name");
                assert_eq!(value, Some("Cyrus"));
            }
        );

        assert_matches!(
            id_param(br##""name" NIL"##),
            Ok((_, (name, value))) => {
                assert_eq!(name, "name");
                assert_eq!(value, None);
            }
        );
    }

    #[test]
    fn test_id_param_list_not_nil() {
        assert_matches!(
            id_param_list_not_nil(br##"("name" "Cyrus" "version" "1.5" "os" "sunos" "os-version" "5.5" "support-url" "mailto:cyrus-bugs+@andrew.cmu.edu")"##),
            Ok((_, params)) => {
                assert_eq!(
                    params,
                    vec![
                        ("name", "Cyrus"),
                        ("version", "1.5"),
                        ("os", "sunos"),
                        ("os-version", "5.5"),
                        ("support-url", "mailto:cyrus-bugs+@andrew.cmu.edu"),
                    ].into_iter()
                    .collect()
                );
            }
        );
    }

    #[test]
    fn test_id_param_list() {
        assert_matches!(
            id_param_list(br##"("name" "Cyrus" "version" "1.5" "os" "sunos" "os-version" "5.5" "support-url" "mailto:cyrus-bugs+@andrew.cmu.edu")"##),
            Ok((_, Some(params))) => {
                assert_eq!(
                    params,
                    vec![
                        ("name", "Cyrus"),
                        ("version", "1.5"),
                        ("os", "sunos"),
                        ("os-version", "5.5"),
                        ("support-url", "mailto:cyrus-bugs+@andrew.cmu.edu"),
                    ].into_iter()
                    .collect()
                );
            }
        );

        assert_matches!(
            id_param_list(br##"NIL"##),
            Ok((_, params)) => {
                assert_eq!(params, None);
            }
        );
    }

    #[test]
    fn test_resp_id() {
        assert_matches!(
            resp_id(br##"ID ("name" "Cyrus" "version" "1.5" "os" "sunos" "os-version" "5.5" "support-url" "mailto:cyrus-bugs+@andrew.cmu.edu")"##),
            Ok((_, Response::Id(Some(id_info)))) => {
                assert_eq!(
                    id_info,
                    vec![
                        ("name", "Cyrus"),
                        ("version", "1.5"),
                        ("os", "sunos"),
                        ("os-version", "5.5"),
                        ("support-url", "mailto:cyrus-bugs+@andrew.cmu.edu"),
                    ].into_iter()
                    .map(|(k, v)| (Cow::Borrowed(k), Cow::Borrowed(v)))
                    .collect()
                );
            }
        );

        // Test that NILs inside parameter list don't crash the parser.
        // RFC2971 allows NILs as parameter values.
        assert_matches!(
            resp_id(br##"ID ("name" "Cyrus" "version" "1.5" "os" NIL "os-version" NIL "support-url" "mailto:cyrus-bugs+@andrew.cmu.edu")"##),
            Ok((_, Response::Id(Some(id_info)))) => {
                assert_eq!(
                    id_info,
                    vec![
                        ("name", "Cyrus"),
                        ("version", "1.5"),
                        ("support-url", "mailto:cyrus-bugs+@andrew.cmu.edu"),
                    ].into_iter()
                    .map(|(k, v)| (Cow::Borrowed(k), Cow::Borrowed(v)))
                    .collect()
                );
            }
        );

        assert_matches!(
            resp_id(br##"ID NIL"##),
            Ok((_, Response::Id(id_info))) => {
                assert_eq!(id_info, None);
            }
        );
    }
}
<|endoftext|>


<commit_before>use super::Gba;
use arm::Cycles;
use std::cell::RefCell;
use std::collections::VecDeque;
use std::rc::Rc;

pub type EventFn = fn(gba: &mut Gba, late: Cycles);

#[derive(Default, Clone)]
pub struct Scheduler {
    inner: Rc<RefCell<Inner>>,
}

impl Scheduler {
    #[inline(always)]
    pub fn schedule(&mut self, new_event: Event) {
        self.inner.borrow_mut().schedule(new_event);
    }

    #[inline(always)]
    pub fn advance(&mut self, cycles: Cycles) -> Option<(EventFn, Cycles)> {
        self.inner.borrow_mut().advance(cycles)
    }
}

pub struct Event {
    callback: EventFn,
    cycles_remaining: Cycles,
}

#[derive(Default)]
struct Inner {
    events: VecDeque<Event>,
}

impl Inner {
    fn schedule(&mut self, mut new_event: Event) {
        let mut insert_idx = self.events.len();
        for (idx, event) in self.events.iter_mut().enumerate() {
            if event.cycles_remaining > new_event.cycles_remaining {
                event.cycles_remaining -= new_event.cycles_remaining;
                insert_idx = idx + 1;
                break;
            }
            new_event.cycles_remaining -= event.cycles_remaining;
        }
        self.events.insert(insert_idx, new_event);
    }

    fn has_next_event(&self, cycles: Cycles) -> bool {
        if let Some(event) = self.events.front() {
            event.cycles_remaining <= cycles
        } else {
            false
        }
    }

    fn advance(&mut self, cycles: Cycles) -> Option<(EventFn, Cycles)> {
        if self.has_next_event(cycles) {
            let event = self.events.pop_front().unwrap();
            Some((event.callback, cycles - event.cycles_remaining))
        } else {
            None
        }
    }
}
<commit_msg>Fix GBA event scheduling code.<commit_after>use super::Gba;
use arm::Cycles;
use std::cell::RefCell;
use std::collections::VecDeque;
use std::rc::Rc;

pub type EventFn = fn(gba: &mut Gba, late: Cycles);

#[derive(Default, Clone)]
pub struct Scheduler {
    inner: Rc<RefCell<Inner>>,
}

impl Scheduler {
    #[inline(always)]
    pub fn schedule(&mut self, callback: EventFn, cycles: impl Into<Cycles>) {
        self.inner.borrow_mut().schedule(Event {
            callback,
            cycles_remaining: cycles.into(),
        });
    }

    #[inline(always)]
    pub fn advance(&mut self, cycles: Cycles) -> Option<(EventFn, Cycles)> {
        self.inner.borrow_mut().advance(cycles)
    }
}

pub struct Event {
    callback: EventFn,
    cycles_remaining: Cycles,
}

#[derive(Default)]
struct Inner {
    events: VecDeque<Event>,
}

impl Inner {
    fn schedule(&mut self, mut new_event: Event) {
        let mut insert_idx = self.events.len();
        for (idx, event) in self.events.iter_mut().enumerate() {
            if event.cycles_remaining > new_event.cycles_remaining {
                event.cycles_remaining -= new_event.cycles_remaining;
                insert_idx = idx + 1;
                break;
            }
            new_event.cycles_remaining -= event.cycles_remaining;
        }
        self.events.insert(insert_idx, new_event);
    }

    fn advance(&mut self, cycles: Cycles) -> Option<(EventFn, Cycles)> {
        if let Some(event) = self.events.front_mut() {
            if event.cycles_remaining > cycles {
                event.cycles_remaining -= cycles;
                return None;
            }
        } else {
            return None;
        }

        let event = self.events.pop_front().unwrap();
        Some((event.callback, cycles - event.cycles_remaining))
    }
}

    fn advance(&mut self, cycles: Cycles) -> Option<(EventFn, Cycles)> {
        if self.has_next_event(cycles) {
            let event = self.events.pop_front().unwrap();
            Some((event.callback, cycles - event.cycles_remaining))
        } else {
            None
        }
    }
}
<|endoftext|>


<commit_before>//! Hosts result from a configuration of `/etc/hosts`

use std::collections::HashMap;
use std::io;
use std::path::Path;
#[cfg(unix)]
use std::str::FromStr;
use std::sync::Arc;

use lookup::Lookup;
use proto::op::Query;
#[cfg(unix)]
use proto::rr::RData;
use proto::rr::{Name, RecordType};

#[derive(Debug, Default)]
struct LookupType {
    /// represents the A record type
    a: Option<Lookup>,
    /// represents the AAAA record type
    aaaa: Option<Lookup>,
}

/// Configuration for the local `/etc/hosts`
#[derive(Debug, Default)]
pub struct Hosts {
    /// Name -> RDatas map
    by_name: HashMap<Name, LookupType>,
}

impl Hosts {
    /// Creates a new configuration from /etc/hosts, only works for unix like OSes,
    /// others will return empty configuration
    pub fn new() -> Hosts {
        read_hosts_conf("/etc/hosts").unwrap_or_default()
    }

    /// lookup_static_host looks up the addresses for the given host from /etc/hosts.
    pub fn lookup_static_host(&self, query: &Query) -> Option<Lookup> {
        if !self.by_name.is_empty() {
            if let Some(val) = self.by_name.get(query.name()) {
                let result = match query.query_type() {
                    RecordType::A => val.a.clone(),
                    RecordType::AAAA => val.aaaa.clone(),
                    _ => None,
                };

                return result;
            }
        }
        None
    }

    /// Insert a new Lookup for the associated `Name` and `RecordType`
    pub fn insert(&mut self, name: Name, record_type: RecordType, lookup: Lookup) {
        assert!(record_type == RecordType::A || record_type == RecordType::AAAA);

        let lookup_type = self
            .by_name
            .entry(name.clone())
            .or_insert_with(LookupType::default);

        let new_lookup = {
            let mut old_lookup = match record_type {
                RecordType::A => lookup_type.a.get_or_insert_with(|| {
                    let query = Query::query(name.clone(), record_type);
                    Lookup::new_with_max_ttl(query, Arc::new(vec![]))
                }),
                RecordType::AAAA => lookup_type.aaaa.get_or_insert_with(|| {
                    let query = Query::query(name.clone(), record_type);
                    Lookup::new_with_max_ttl(query, Arc::new(vec![]))
                }),
                _ => {
                    warn!("unsupported IP type from Hosts file: {:#?}", record_type);
                    return;
                }
            };

            old_lookup.append(lookup)
        };

        // replace the appended version
        match record_type {
            RecordType::A => lookup_type.a = Some(new_lookup),
            RecordType::AAAA => lookup_type.aaaa = Some(new_lookup),
            _ => warn!("unsupported IP type from Hosts file"),
        }
    }
}

/// parse configuration from `/etc/hosts`
#[cfg(unix)]
pub fn read_hosts_conf<P: AsRef<Path>>(path: P) -> io::Result<Hosts> {
    use std::fs::File;
    use std::io::{BufRead, BufReader};

    use proto::rr::domain::TryParseIp;

    let mut hosts = Hosts {
        by_name: HashMap::new(),
    };

    // lines in the file should have the form `addr host1 host2 host3 ...`
    // line starts with `#` will be regarded with comments and ignored,
    // also empty line also will be ignored,
    // if line only include `addr` without `host` will be ignored,
    // file will parsed to map in the form `Name -> LookUp`.
    let file = File::open(path)?;

    for line in BufReader::new(file).lines() {
        let line = line.unwrap_or_default();
        let line = if let Some(pos) = line.find('#') {
            String::from(line.split_at(pos).0)
        } else {
            line
        };
        let line = line.trim();
        if line.is_empty() {
            continue;
        }

        let fields: Vec<String> = line.split_whitespace().map(|s| s.to_string()).collect();
        if fields.len() < 2 {
            continue;
        }
        let addr = if let Some(a) = fields[0].try_parse_ip() {
            a
        } else {
            warn!("could not parse an IP from hosts file");
            continue;
        };

        for domain in fields.iter().skip(1).map(|domain| domain.to_lowercase()) {
            if let Ok(name) = Name::from_str(&domain) {
                match addr {
                    RData::A(..) => {
                        let query = Query::query(name.clone(), RecordType::A);
                        let lookup = Lookup::new_with_max_ttl(query, Arc::new(vec![addr.clone()]));
                        hosts.insert(name.clone(), RecordType::A, lookup);
                    }
                    RData::AAAA(..) => {
                        let query = Query::query(name.clone(), RecordType::AAAA);
                        let lookup = Lookup::new_with_max_ttl(query, Arc::new(vec![addr.clone()]));
                        hosts.insert(name.clone(), RecordType::AAAA, lookup);
                    }
                    _ => {
                        warn!("unsupported IP type from Hosts file: {:#?}", addr);
                        continue;
                    }
                };

                // TODO: insert reverse lookup as well.
            };
        }
    }

    Ok(hosts)
}

#[cfg(not(unix))]
pub fn read_hosts_conf<P: AsRef<Path>>(_path: P) -> io::Result<Hosts> {
    Err(io::Error::new(
        io::ErrorKind::Other,
        "Non-Posix systems currently not supported".to_string(),
    ))
}

#[cfg(unix)]
#[cfg(test)]
mod tests {
    use super::*;
    use std::env;
    use std::net::{Ipv4Addr, Ipv6Addr};

    fn tests_dir() -> String {
        let server_path = env::var("TDNS_SERVER_SRC_ROOT").unwrap_or_else(|_| ".".to_owned());
        format!{"{}/../resolver/tests", server_path}
    }

    #[test]
    fn test_read_hosts_conf() {
        let path = format!("{}/hosts", tests_dir());
        let hosts = read_hosts_conf(&path).unwrap();

        let name = Name::from_str("localhost").unwrap();
        let rdatas = hosts
            .lookup_static_host(&Query::query(name.clone(), RecordType::A))
            .unwrap()
            .iter()
            .map(|r| r.to_owned())
            .collect::<Vec<RData>>();

        assert_eq!(rdatas, vec![RData::A(Ipv4Addr::new(127, 0, 0, 1))]);

        let rdatas = hosts
            .lookup_static_host(&Query::query(name.clone(), RecordType::AAAA))
            .unwrap()
            .iter()
            .map(|r| r.to_owned())
            .collect::<Vec<RData>>();

        assert_eq!(
            rdatas,
            vec![RData::AAAA(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1))]
        );

        let name = Name::from_str("broadcasthost").unwrap();
        let rdatas = hosts
            .lookup_static_host(&Query::query(name.clone(), RecordType::A))
            .unwrap()
            .iter()
            .map(|r| r.to_owned())
            .collect::<Vec<RData>>();
        assert_eq!(rdatas, vec![RData::A(Ipv4Addr::new(255, 255, 255, 255))]);

        let name = Name::from_str("example.com").unwrap();
        let rdatas = hosts
            .lookup_static_host(&Query::query(name.clone(), RecordType::A))
            .unwrap()
            .iter()
            .map(|r| r.to_owned())
            .collect::<Vec<RData>>();
        assert_eq!(rdatas, vec![RData::A(Ipv4Addr::new(10, 0, 1, 102))]);

        let name = Name::from_str("a.example.com").unwrap();
        let rdatas = hosts
            .lookup_static_host(&Query::query(name.clone(), RecordType::A))
            .unwrap()
            .iter()
            .map(|r| r.to_owned())
            .collect::<Vec<RData>>();
        assert_eq!(rdatas, vec![RData::A(Ipv4Addr::new(10, 0, 1, 111))]);

        let name = Name::from_str("b.example.com").unwrap();
        let rdatas = hosts
            .lookup_static_host(&Query::query(name.clone(), RecordType::A))
            .unwrap()
            .iter()
            .map(|r| r.to_owned())
            .collect::<Vec<RData>>();
        assert_eq!(rdatas, vec![RData::A(Ipv4Addr::new(10, 0, 1, 111))]);
    }
}
<commit_msg>Support Windows hosts file when system configuration is used (#623)<commit_after>//! Hosts result from a configuration of the system hosts file

use std::collections::HashMap;
use std::io;
use std::path::Path;
#[cfg(any(unix, windows))]
use std::str::FromStr;
use std::sync::Arc;

use lookup::Lookup;
use proto::op::Query;
#[cfg(any(unix, windows))]
use proto::rr::RData;
use proto::rr::{Name, RecordType};

#[derive(Debug, Default)]
struct LookupType {
    /// represents the A record type
    a: Option<Lookup>,
    /// represents the AAAA record type
    aaaa: Option<Lookup>,
}

/// Configuration for the local hosts file
#[derive(Debug, Default)]
pub struct Hosts {
    /// Name -> RDatas map
    by_name: HashMap<Name, LookupType>,
}

impl Hosts {
    /// Creates a new configuration from the system hosts file,
    /// only works for Windows and Unix-like OSes,
    /// will return empty configuration on others
    pub fn new() -> Hosts {
        read_hosts_conf(hosts_path()).unwrap_or_default()
    }

    /// lookup_static_host looks up the addresses
    /// for the given host from the system hosts file.
    pub fn lookup_static_host(&self, query: &Query) -> Option<Lookup> {
        if !self.by_name.is_empty() {
            if let Some(val) = self.by_name.get(query.name()) {
                let result = match query.query_type() {
                    RecordType::A => val.a.clone(),
                    RecordType::AAAA => val.aaaa.clone(),
                    _ => None,
                };

                return result;
            }
        }
        None
    }

    /// Insert a new Lookup for the associated `Name` and `RecordType`
    pub fn insert(&mut self, name: Name, record_type: RecordType, lookup: Lookup) {
        assert!(record_type == RecordType::A || record_type == RecordType::AAAA);

        let lookup_type = self
            .by_name
            .entry(name.clone())
            .or_insert_with(LookupType::default);

        let new_lookup = {
            let mut old_lookup = match record_type {
                RecordType::A => lookup_type.a.get_or_insert_with(|| {
                    let query = Query::query(name.clone(), record_type);
                    Lookup::new_with_max_ttl(query, Arc::new(vec![]))
                }),
                RecordType::AAAA => lookup_type.aaaa.get_or_insert_with(|| {
                    let query = Query::query(name.clone(), record_type);
                    Lookup::new_with_max_ttl(query, Arc::new(vec![]))
                }),
                _ => {
                    warn!("unsupported IP type from Hosts file: {:#?}", record_type);
                    return;
                }
            };

            old_lookup.append(lookup)
        };

        // replace the appended version
        match record_type {
            RecordType::A => lookup_type.a = Some(new_lookup),
            RecordType::AAAA => lookup_type.aaaa = Some(new_lookup),
            _ => warn!("unsupported IP type from Hosts file"),
        }
    }
}

#[cfg(unix)]
fn hosts_path() -> &'static str {
    "/etc/hosts"
}

#[cfg(windows)]
fn hosts_path() -> std::path::PathBuf {
    let system_root =
        std::env::var_os("SystemRoot").expect("Environtment variable SystemRoot not found");
    let system_root = Path::new(&system_root);
    system_root.join("System32\\drivers\\etc\\hosts")
}

/// parse configuration from `path`
#[cfg(any(unix, windows))]
pub fn read_hosts_conf<P: AsRef<Path>>(path: P) -> io::Result<Hosts> {
    use std::fs::File;
    use std::io::{BufRead, BufReader};

    use proto::rr::domain::TryParseIp;

    let mut hosts = Hosts {
        by_name: HashMap::new(),
    };

    // lines in the file should have the form `addr host1 host2 host3 ...`
    // line starts with `#` will be regarded with comments and ignored,
    // also empty line also will be ignored,
    // if line only include `addr` without `host` will be ignored,
    // file will parsed to map in the form `Name -> LookUp`.
    let file = File::open(path)?;

    for line in BufReader::new(file).lines() {
        // Remove comments from the line
        let line = line
            .as_ref()
            .map(|line| line.split('#').next().unwrap().trim())
            .unwrap_or_default();
        if line.is_empty() {
            continue;
        }

        let fields: Vec<_> = line.split_whitespace().collect();
        if fields.len() < 2 {
            continue;
        }
        let addr = if let Some(a) = fields[0].try_parse_ip() {
            a
        } else {
            warn!("could not parse an IP from hosts file");
            continue;
        };

        for domain in fields.iter().skip(1).map(|domain| domain.to_lowercase()) {
            if let Ok(name) = Name::from_str(&domain) {
                match addr {
                    RData::A(..) => {
                        let query = Query::query(name.clone(), RecordType::A);
                        let lookup = Lookup::new_with_max_ttl(query, Arc::new(vec![addr.clone()]));
                        hosts.insert(name.clone(), RecordType::A, lookup);
                    }
                    RData::AAAA(..) => {
                        let query = Query::query(name.clone(), RecordType::AAAA);
                        let lookup = Lookup::new_with_max_ttl(query, Arc::new(vec![addr.clone()]));
                        hosts.insert(name.clone(), RecordType::AAAA, lookup);
                    }
                    _ => {
                        warn!("unsupported IP type from Hosts file: {:#?}", addr);
                        continue;
                    }
                };

                // TODO: insert reverse lookup as well.
            };
        }
    }

    Ok(hosts)
}

#[cfg(not(any(unix, windows)))]
pub fn read_hosts_conf<P: AsRef<Path>>(_path: P) -> io::Result<Hosts> {
    Err(io::Error::new(
        io::ErrorKind::Other,
        "Only Windows or Unix-like hosts file is supported".to_string(),
    ))
}

#[cfg(any(unix, windows))]
#[cfg(test)]
mod tests {
    use super::*;
    use std::env;
    use std::net::{Ipv4Addr, Ipv6Addr};

    fn tests_dir() -> String {
        let server_path = env::var("TDNS_SERVER_SRC_ROOT").unwrap_or_else(|_| ".".to_owned());
        format!{"{}/../resolver/tests", server_path}
    }

    #[test]
    fn test_read_hosts_conf() {
        let path = format!("{}/hosts", tests_dir());
        let hosts = read_hosts_conf(&path).unwrap();

        let name = Name::from_str("localhost").unwrap();
        let rdatas = hosts
            .lookup_static_host(&Query::query(name.clone(), RecordType::A))
            .unwrap()
            .iter()
            .map(|r| r.to_owned())
            .collect::<Vec<RData>>();

        assert_eq!(rdatas, vec![RData::A(Ipv4Addr::new(127, 0, 0, 1))]);

        let rdatas = hosts
            .lookup_static_host(&Query::query(name.clone(), RecordType::AAAA))
            .unwrap()
            .iter()
            .map(|r| r.to_owned())
            .collect::<Vec<RData>>();

        assert_eq!(
            rdatas,
            vec![RData::AAAA(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1))]
        );

        let name = Name::from_str("broadcasthost").unwrap();
        let rdatas = hosts
            .lookup_static_host(&Query::query(name.clone(), RecordType::A))
            .unwrap()
            .iter()
            .map(|r| r.to_owned())
            .collect::<Vec<RData>>();
        assert_eq!(rdatas, vec![RData::A(Ipv4Addr::new(255, 255, 255, 255))]);

        let name = Name::from_str("example.com").unwrap();
        let rdatas = hosts
            .lookup_static_host(&Query::query(name.clone(), RecordType::A))
            .unwrap()
            .iter()
            .map(|r| r.to_owned())
            .collect::<Vec<RData>>();
        assert_eq!(rdatas, vec![RData::A(Ipv4Addr::new(10, 0, 1, 102))]);

        let name = Name::from_str("a.example.com").unwrap();
        let rdatas = hosts
            .lookup_static_host(&Query::query(name.clone(), RecordType::A))
            .unwrap()
            .iter()
            .map(|r| r.to_owned())
            .collect::<Vec<RData>>();
        assert_eq!(rdatas, vec![RData::A(Ipv4Addr::new(10, 0, 1, 111))]);

        let name = Name::from_str("b.example.com").unwrap();
        let rdatas = hosts
            .lookup_static_host(&Query::query(name.clone(), RecordType::A))
            .unwrap()
            .iter()
            .map(|r| r.to_owned())
            .collect::<Vec<RData>>();
        assert_eq!(rdatas, vec![RData::A(Ipv4Addr::new(10, 0, 1, 111))]);
    }
}
<|endoftext|>