<commit_before>import front.ast;
import front.ast.ident;
import front.ast.def;
import front.ast.ann;
import driver.session;
import util.common.span;
import std.map.hashmap;
import std.list.list;
import std.list.nil;
import std.list.cons;
import std.option;
import std.option.some;
import std.option.none;
import std._str;
import std._vec;

tag scope {
    scope_crate(@ast.crate);
    scope_item(@ast.item);
    scope_block(ast.block);
    scope_arm(ast.arm);
}

type env = rec(list[scope] scopes,
               session.session sess);

fn lookup_name(&env e, ast.ident i) -> option.t[def] {

    // log "resolving name " + i;

    fn found_def_item(@ast.item i) -> option.t[def] {
        alt (i.node) {
            case (ast.item_const(_, _, _, ?id, _)) {
                ret some[def](ast.def_const(id));
            }
            case (ast.item_fn(_, _, _, ?id, _)) {
                ret some[def](ast.def_fn(id));
            }
            case (ast.item_mod(_, _, ?id)) {
                ret some[def](ast.def_mod(id));
            }
            case (ast.item_ty(_, _, _, ?id, _)) {
                ret some[def](ast.def_ty(id));
            }
            case (ast.item_tag(_, _, _, ?id)) {
                ret some[def](ast.def_ty(id));
            }
            case (ast.item_obj(_, _, _, ?id, _)) {
                ret some[def](ast.def_obj(id));
            }
        }
    }

    fn found_decl_stmt(@ast.stmt s) -> option.t[def] {
        alt (s.node) {
            case (ast.stmt_decl(?d)) {
                alt (d.node) {
                    case (ast.decl_local(?loc)) {
                        ret some[def](ast.def_local(loc.id));
                    }
                    case (ast.decl_item(?it)) {
                        ret found_def_item(it);
                    }
                }
            }
        }
        ret none[def];
    }

    fn check_mod(ast.ident i, ast._mod m) -> option.t[def] {
        alt (m.index.find(i)) {
            case (some[ast.mod_index_entry](?ent)) {
                alt (ent) {
                    case (ast.mie_item(?ix)) {
                        ret found_def_item(m.items.(ix));
                    }
                    case (ast.mie_tag_variant(?item_idx, ?variant_idx)) {
                        alt (m.items.(item_idx).node) {
                            case (ast.item_tag(_, ?variants, _, ?tid)) {
                                auto vid = variants.(variant_idx).id;
                                ret some[def](ast.def_variant(tid, vid));
                            }
                            case (_) {
                                log "tag item not actually a tag";
                                fail;
                            }
                        }
                    }
                }
            }
            case (none[ast.mod_index_entry]) { /* fall through */ }
        }
        ret none[def];
    }

    fn in_scope(ast.ident i, &scope s) -> option.t[def] {
        alt (s) {

            case (scope_crate(?c)) {
                ret check_mod(i, c.node.module);
            }

            case (scope_item(?it)) {
                alt (it.node) {
                    case (ast.item_fn(_, ?f, ?ty_params, _, _)) {
                        for (ast.arg a in f.inputs) {
                            if (_str.eq(a.ident, i)) {
                                ret some[def](ast.def_arg(a.id));
                            }
                        }
                        for (ast.ty_param tp in ty_params) {
                            if (_str.eq(tp.ident, i)) {
                                ret some[def](ast.def_ty_arg(tp.id));
                            }
                        }
                    }
                    case (ast.item_obj(_, ?ob, ?ty_params, _, _)) {
                        for (ast.obj_field f in ob.fields) {
                            if (_str.eq(f.ident, i)) {
                                ret some[def](ast.def_obj_field(f.id));
                            }
                        }
                        for (ast.ty_param tp in ty_params) {
                            if (_str.eq(tp.ident, i)) {
                                ret some[def](ast.def_ty_arg(tp.id));
                            }
                        }
                    }
                    case (ast.item_mod(_, ?m, _)) {
                        ret check_mod(i, m);
                    }
                    case (_) { /* fall through */ }
                }
            }

            case (scope_block(?b)) {
                alt (b.node.index.find(i)) {
                    case (some[uint](?ix)) {
                        ret found_decl_stmt(b.node.stmts.(ix));
                    }
                    case (_) { /* fall through */  }
                }
            }

            case (scope_arm(?a)) {
                alt (a.index.find(i)) {
                    case (some[ast.def_id](?did)) {
                        ret some[def](ast.def_binding(did));
                    }
                    case (_) { /* fall through */  }
                }
            }
        }
        ret none[def];
    }

    ret std.list.find[scope,def](e.scopes, bind in_scope(i, _));
}

fn fold_pat_tag(&env e, &span sp, ident i, vec[@ast.pat] args,
                option.t[ast.variant_def] old_def, ann a) -> @ast.pat {
    auto new_def;
    alt (lookup_name(e, i)) {
        case (some[def](?d)) {
            alt (d) {
                case (ast.def_variant(?did, ?vid)) {
                    new_def = some[ast.variant_def](tup(did, vid));
                }
                case (_) {
                    e.sess.err("not a tag variant: " + i);
                    new_def = none[ast.variant_def];
                }
            }
        }
        case (none[def]) {
            new_def = none[ast.variant_def];
            e.sess.err("unresolved name: " + i);
        }
    }

    ret @fold.respan[ast.pat_](sp, ast.pat_tag(i, args, new_def, a));
}

fn fold_expr_name(&env e, &span sp, &ast.name n,
                  &option.t[def] d, ann a) -> @ast.expr {

    if (_vec.len[@ast.ty](n.node.types) > 0u) {
        e.sess.unimpl("resolving name expr with ty params");
    }

    auto d_ = lookup_name(e, n.node.ident);

    alt (d_) {
        case (some[def](_)) {
            // log "resolved name " + n.node.ident;
        }
        case (none[def]) {
            e.sess.err("unresolved name: " + n.node.ident);
        }
    }

    ret @fold.respan[ast.expr_](sp, ast.expr_name(n, d_, a));
}

fn fold_ty_path(&env e, &span sp, ast.path p,
                &option.t[def] d) -> @ast.ty {

    let uint len = _vec.len[ast.name](p);
    check (len != 0u);
    if (len > 1u) {
        e.sess.unimpl("resolving path ty with >1 component");
    }

    let ast.name n = p.(0);

    if (_vec.len[@ast.ty](n.node.types) > 0u) {
        e.sess.unimpl("resolving path ty with ty params");
    }

    auto d_ = lookup_name(e, n.node.ident);

    alt (d_) {
        case (some[def](_)) {
            // log "resolved name " + n.node.ident;
        }
        case (none[def]) {
            e.sess.err("unresolved name: " + n.node.ident);
        }
    }

    ret @fold.respan[ast.ty_](sp, ast.ty_path(p, d_));
}

fn update_env_for_crate(&env e, @ast.crate c) -> env {
    ret rec(scopes = cons[scope](scope_crate(c), @e.scopes) with e);
}

fn update_env_for_item(&env e, @ast.item i) -> env {
    ret rec(scopes = cons[scope](scope_item(i), @e.scopes) with e);
}

fn update_env_for_block(&env e, &ast.block b) -> env {
    ret rec(scopes = cons[scope](scope_block(b), @e.scopes) with e);
}

fn update_env_for_arm(&env e, &ast.arm p) -> env {
    ret rec(scopes = cons[scope](scope_arm(p), @e.scopes) with e);
}

fn resolve_crate(session.session sess, @ast.crate crate) -> @ast.crate {

    let fold.ast_fold[env] fld = fold.new_identity_fold[env]();

    fld = @rec( fold_pat_tag = bind fold_pat_tag(_,_,_,_,_,_),
                fold_expr_name = bind fold_expr_name(_,_,_,_,_),
                fold_ty_path = bind fold_ty_path(_,_,_,_),
                update_env_for_crate = bind update_env_for_crate(_,_),
                update_env_for_item = bind update_env_for_item(_,_),
                update_env_for_block = bind update_env_for_block(_,_),
                update_env_for_arm = bind update_env_for_arm(_,_)
                with *fld );

    auto e = rec(scopes = nil[scope],
                 sess = sess);

    ret fold.fold_crate[env](e, fld, crate);
}

// 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 ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Change resolve errs to span_errs.<commit_after>import front.ast;
import front.ast.ident;
import front.ast.def;
import front.ast.ann;
import driver.session;
import util.common.span;
import std.map.hashmap;
import std.list.list;
import std.list.nil;
import std.list.cons;
import std.option;
import std.option.some;
import std.option.none;
import std._str;
import std._vec;

tag scope {
    scope_crate(@ast.crate);
    scope_item(@ast.item);
    scope_block(ast.block);
    scope_arm(ast.arm);
}

type env = rec(list[scope] scopes,
               session.session sess);

fn lookup_name(&env e, ast.ident i) -> option.t[def] {

    // log "resolving name " + i;

    fn found_def_item(@ast.item i) -> option.t[def] {
        alt (i.node) {
            case (ast.item_const(_, _, _, ?id, _)) {
                ret some[def](ast.def_const(id));
            }
            case (ast.item_fn(_, _, _, ?id, _)) {
                ret some[def](ast.def_fn(id));
            }
            case (ast.item_mod(_, _, ?id)) {
                ret some[def](ast.def_mod(id));
            }
            case (ast.item_ty(_, _, _, ?id, _)) {
                ret some[def](ast.def_ty(id));
            }
            case (ast.item_tag(_, _, _, ?id)) {
                ret some[def](ast.def_ty(id));
            }
            case (ast.item_obj(_, _, _, ?id, _)) {
                ret some[def](ast.def_obj(id));
            }
        }
    }

    fn found_decl_stmt(@ast.stmt s) -> option.t[def] {
        alt (s.node) {
            case (ast.stmt_decl(?d)) {
                alt (d.node) {
                    case (ast.decl_local(?loc)) {
                        ret some[def](ast.def_local(loc.id));
                    }
                    case (ast.decl_item(?it)) {
                        ret found_def_item(it);
                    }
                }
            }
        }
        ret none[def];
    }

    fn check_mod(ast.ident i, ast._mod m) -> option.t[def] {
        alt (m.index.find(i)) {
            case (some[ast.mod_index_entry](?ent)) {
                alt (ent) {
                    case (ast.mie_item(?ix)) {
                        ret found_def_item(m.items.(ix));
                    }
                    case (ast.mie_tag_variant(?item_idx, ?variant_idx)) {
                        alt (m.items.(item_idx).node) {
                            case (ast.item_tag(_, ?variants, _, ?tid)) {
                                auto vid = variants.(variant_idx).id;
                                ret some[def](ast.def_variant(tid, vid));
                            }
                            case (_) {
                                log "tag item not actually a tag";
                                fail;
                            }
                        }
                    }
                }
            }
            case (none[ast.mod_index_entry]) { /* fall through */ }
        }
        ret none[def];
    }

    fn in_scope(ast.ident i, &scope s) -> option.t[def] {
        alt (s) {

            case (scope_crate(?c)) {
                ret check_mod(i, c.node.module);
            }

            case (scope_item(?it)) {
                alt (it.node) {
                    case (ast.item_fn(_, ?f, ?ty_params, _, _)) {
                        for (ast.arg a in f.inputs) {
                            if (_str.eq(a.ident, i)) {
                                ret some[def](ast.def_arg(a.id));
                            }
                        }
                        for (ast.ty_param tp in ty_params) {
                            if (_str.eq(tp.ident, i)) {
                                ret some[def](ast.def_ty_arg(tp.id));
                            }
                        }
                    }
                    case (ast.item_obj(_, ?ob, ?ty_params, _, _)) {
                        for (ast.obj_field f in ob.fields) {
                            if (_str.eq(f.ident, i)) {
                                ret some[def](ast.def_obj_field(f.id));
                            }
                        }
                        for (ast.ty_param tp in ty_params) {
                            if (_str.eq(tp.ident, i)) {
                                ret some[def](ast.def_ty_arg(tp.id));
                            }
                        }
                    }
                    case (ast.item_mod(_, ?m, _)) {
                        ret check_mod(i, m);
                    }
                    case (_) { /* fall through */ }
                }
            }

            case (scope_block(?b)) {
                alt (b.node.index.find(i)) {
                    case (some[uint](?ix)) {
                        ret found_decl_stmt(b.node.stmts.(ix));
                    }
                    case (_) { /* fall through */  }
                }
            }

            case (scope_arm(?a)) {
                alt (a.index.find(i)) {
                    case (some[ast.def_id](?did)) {
                        ret some[def](ast.def_binding(did));
                    }
                    case (_) { /* fall through */  }
                }
            }
        }
        ret none[def];
    }

    ret std.list.find[scope,def](e.scopes, bind in_scope(i, _));
}

fn fold_pat_tag(&env e, &span sp, ident i, vec[@ast.pat] args,
                option.t[ast.variant_def] old_def, ann a) -> @ast.pat {
    auto new_def;
    alt (lookup_name(e, i)) {
        case (some[def](?d)) {
            alt (d) {
                case (ast.def_variant(?did, ?vid)) {
                    new_def = some[ast.variant_def](tup(did, vid));
                }
                case (_) {
                    e.sess.span_err(sp, "not a tag variant: " + i);
                    new_def = none[ast.variant_def];
                }
            }
        }
        case (none[def]) {
            new_def = none[ast.variant_def];
            e.sess.span_err(sp, "unresolved name: " + i);
        }
    }

    ret @fold.respan[ast.pat_](sp, ast.pat_tag(i, args, new_def, a));
}

fn fold_expr_name(&env e, &span sp, &ast.name n,
                  &option.t[def] d, ann a) -> @ast.expr {

    if (_vec.len[@ast.ty](n.node.types) > 0u) {
        e.sess.unimpl("resolving name expr with ty params");
    }

    auto d_ = lookup_name(e, n.node.ident);

    alt (d_) {
        case (some[def](_)) {
            // log "resolved name " + n.node.ident;
        }
        case (none[def]) {
            e.sess.span_err(sp, "unresolved name: " + n.node.ident);
        }
    }

    ret @fold.respan[ast.expr_](sp, ast.expr_name(n, d_, a));
}

fn fold_ty_path(&env e, &span sp, ast.path p,
                &option.t[def] d) -> @ast.ty {

    let uint len = _vec.len[ast.name](p);
    check (len != 0u);
    if (len > 1u) {
        e.sess.unimpl("resolving path ty with >1 component");
    }

    let ast.name n = p.(0);

    if (_vec.len[@ast.ty](n.node.types) > 0u) {
        e.sess.unimpl("resolving path ty with ty params");
    }

    auto d_ = lookup_name(e, n.node.ident);

    alt (d_) {
        case (some[def](_)) {
            // log "resolved name " + n.node.ident;
        }
        case (none[def]) {
            e.sess.span_err(sp, "unresolved name: " + n.node.ident);
        }
    }

    ret @fold.respan[ast.ty_](sp, ast.ty_path(p, d_));
}

fn update_env_for_crate(&env e, @ast.crate c) -> env {
    ret rec(scopes = cons[scope](scope_crate(c), @e.scopes) with e);
}

fn update_env_for_item(&env e, @ast.item i) -> env {
    ret rec(scopes = cons[scope](scope_item(i), @e.scopes) with e);
}

fn update_env_for_block(&env e, &ast.block b) -> env {
    ret rec(scopes = cons[scope](scope_block(b), @e.scopes) with e);
}

fn update_env_for_arm(&env e, &ast.arm p) -> env {
    ret rec(scopes = cons[scope](scope_arm(p), @e.scopes) with e);
}

fn resolve_crate(session.session sess, @ast.crate crate) -> @ast.crate {

    let fold.ast_fold[env] fld = fold.new_identity_fold[env]();

    fld = @rec( fold_pat_tag = bind fold_pat_tag(_,_,_,_,_,_),
                fold_expr_name = bind fold_expr_name(_,_,_,_,_),
                fold_ty_path = bind fold_ty_path(_,_,_,_),
                update_env_for_crate = bind update_env_for_crate(_,_),
                update_env_for_item = bind update_env_for_item(_,_),
                update_env_for_block = bind update_env_for_block(_,_),
                update_env_for_arm = bind update_env_for_arm(_,_)
                with *fld );

    auto e = rec(scopes = nil[scope],
                 sess = sess);

    ret fold.fold_crate[env](e, fld, crate);
}

// 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 ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>extern crate pwx;
extern crate docopt;
extern crate rustc_serialize;
extern crate uuid;
extern crate rpassword;

use pwx::{Pwx,PwxIterator};
use std::io::{Write,stdout,stderr};
use std::process::exit;
use std::path::Path;
use docopt::Docopt;
use uuid::Uuid;

const USAGE: &'static str = "
Usage: pwx <file> list
       pwx <file> info
       pwx <file> get <uuid> <name>
       pwx <file> set <uuid <name> <val>
       pwx (--help | --version)

Options:
    -h, --help      Show this help message
    -v, --version   Show pwx version
";

// Get pkg version at compile time
const VERSION: &'static str = env!("CARGO_PKG_VERSION");

macro_rules! usage {
    ($code:expr, $err:expr) => {{
        let _ = writeln!(std::io::stderr(), "{}\n{}", $err, USAGE);
        return $code;
    }};
}

#[derive(RustcDecodable, Debug)]
struct Args {
    arg_file: String,
    arg_name: String,
    arg_val: String,
    arg_uuid: String,
    cmd_list: bool,
    cmd_set: bool,
    cmd_get: bool,
    cmd_info: bool,
    flag_version: bool,
}

/**
 * Get password
 * 1. If PWX_PASSWORD is set use it
 * 2. Otherwise read from console
 *
 * This function may panic on encoding issues
 */
fn get_password() -> String {
    let var = std::env::var("PWX_PASSWORD");
    if var.is_ok() {
        return var.unwrap()
    }

    // Get password from terminal
    print!("Password: ");
    stdout().flush().unwrap();
    rpassword::read_password().unwrap()
}

fn real_main() -> i32 {

    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());

    if args.flag_version {
        println!("pwx {}", VERSION);
        return 0;
    }

    let mut p = match Pwx::open(Path::new(&args.arg_file), get_password().as_bytes()) {
        Err(f) => {
            let _ = writeln!(stderr(), "Error: {}", f);
            exit(-1);
        },
        Ok(p) => p,
    };

    if !p.is_authentic() {
        return -1;
    }

    if args.cmd_list {
        let mut fields = PwxIterator::from_start(&mut p).unwrap();
        fields.skip_record();

        let mut uuid = String::new();
        let mut title = String::new();
        let mut username = String::new();

        for (typ,val) in fields {
            match typ {
                0x01 => uuid = Uuid::from_bytes(val.as_ref()).unwrap_or(Uuid::nil()).to_hyphenated_string(),
                0x03 => title = String::from_utf8_lossy(val.as_ref()).into_owned(),
                0x04 => username = String::from_utf8_lossy(val.as_ref()).into_owned(),
                0xff => {
                    println!("{} {}[{}]", uuid, title, username);
                    uuid = String::new();
                    title = String::new();
                    username = String::new();
                }
                _ => (),
            }
        }
    } else if args.cmd_info {

        let fields = PwxIterator::from_start(&mut p).unwrap();
        for (typ,val) in fields {
            match typ {
                0x01 => print!("{} ", Uuid::from_bytes(val.as_ref()).unwrap_or(Uuid::nil()).to_hyphenated_string()),
                0x07 => print!("{} ", String::from_utf8_lossy(val.as_ref())),
                0x08 => println!("@{} ", String::from_utf8_lossy(val.as_ref())),
                0x09 => println!("{} ", String::from_utf8_lossy(val.as_ref())),
                0x0a => println!("\"{}\" ", String::from_utf8_lossy(val.as_ref())),
                0xff => break,
                _ => (),
            }
        }
    }

    return 0
}

// Rust set_exit_status cannot be used yet, the only way to
// set an exit code to exit using exit(code) so we wrap the
// main function like this
fn main() {
    let exit_code = real_main();
    exit(exit_code);
}

<commit_msg>Add option --pass-interactive<commit_after>extern crate pwx;
extern crate docopt;
extern crate rustc_serialize;
extern crate uuid;
extern crate rpassword;

use pwx::{Pwx,PwxIterator};
use std::io::{Write,stdout,stderr};
use std::process::exit;
use std::path::Path;
use docopt::Docopt;
use uuid::Uuid;

const USAGE: &'static str = "
Usage: pwx [options] <file> list
       pwx [options] <file> info
       pwx [options] <file> get <uuid> <name>
       pwx [options] <file> set <uuid <name> <val>
       pwx (--help | --version)

Options:
    -h, --help          Show this help message
    -v, --version       Show pwx version
    --pass-interactive  Read password from console
";

// Get pkg version at compile time
const VERSION: &'static str = env!("CARGO_PKG_VERSION");

macro_rules! usage {
    ($code:expr, $err:expr) => {{
        let _ = writeln!(std::io::stderr(), "{}\n{}", $err, USAGE);
        return $code;
    }};
}

#[derive(RustcDecodable, Debug)]
struct Args {
    arg_file: String,
    arg_name: String,
    arg_val: String,
    arg_uuid: String,
    cmd_list: bool,
    cmd_set: bool,
    cmd_get: bool,
    cmd_info: bool,
    flag_version: bool,
    flag_pass_interactive: bool,
}

fn get_password_from_console() -> String {
    // Get password from terminal
    print!("Password: ");
    stdout().flush().unwrap();
    rpassword::read_password().unwrap()
}

/**
 * Get password
 * 1. If --pass-interactive read from console
 * 2. If PWX_PASSWORD is set use it
 * 3. Otherwise read from console
 *
 * This function may panic on encoding issues
 */
fn get_password(args: &Args) -> String {
    if args.flag_pass_interactive {
        return get_password_from_console();
    }

    let var = std::env::var("PWX_PASSWORD");
    if var.is_ok() {
        return var.unwrap()
    }

    get_password_from_console()
}

fn real_main() -> i32 {

    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());

    if args.flag_version {
        println!("pwx {}", VERSION);
        return 0;
    }

    let mut p = match Pwx::open(Path::new(&args.arg_file), get_password(&args).as_bytes()) {
        Err(f) => {
            let _ = writeln!(stderr(), "Error: {}", f);
            exit(-1);
        },
        Ok(p) => p,
    };

    if !p.is_authentic() {
        return -1;
    }

    if args.cmd_list {
        let mut fields = PwxIterator::from_start(&mut p).unwrap();
        fields.skip_record();

        let mut uuid = String::new();
        let mut title = String::new();
        let mut username = String::new();

        for (typ,val) in fields {
            match typ {
                0x01 => uuid = Uuid::from_bytes(val.as_ref()).unwrap_or(Uuid::nil()).to_hyphenated_string(),
                0x03 => title = String::from_utf8_lossy(val.as_ref()).into_owned(),
                0x04 => username = String::from_utf8_lossy(val.as_ref()).into_owned(),
                0xff => {
                    println!("{} {}[{}]", uuid, title, username);
                    uuid = String::new();
                    title = String::new();
                    username = String::new();
                }
                _ => (),
            }
        }
    } else if args.cmd_info {

        let fields = PwxIterator::from_start(&mut p).unwrap();
        for (typ,val) in fields {
            match typ {
                0x01 => print!("{} ", Uuid::from_bytes(val.as_ref()).unwrap_or(Uuid::nil()).to_hyphenated_string()),
                0x07 => print!("{} ", String::from_utf8_lossy(val.as_ref())),
                0x08 => println!("@{} ", String::from_utf8_lossy(val.as_ref())),
                0x09 => println!("{} ", String::from_utf8_lossy(val.as_ref())),
                0x0a => println!("\"{}\" ", String::from_utf8_lossy(val.as_ref())),
                0xff => break,
                _ => (),
            }
        }
    }

    return 0
}

// Rust set_exit_status cannot be used yet, the only way to
// set an exit code to exit using exit(code) so we wrap the
// main function like this
fn main() {
    let exit_code = real_main();
    exit(exit_code);
}

<|endoftext|>


<commit_before>use std::io;
use std::io::prelude::*;

use data::{ Value, DataMode, Shape };
use connection::Connection;
use process::{Process, PrimitiveDef};
use language::Item;

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use num_complex::Complex;

enum Format {
    F32LE,
    C32LE,
}

struct BinFileDown(Shape, Format);
impl Process for BinFileDown {
    fn run(&self, downwards: &mut Connection, upwards: &mut Connection) -> bool {
        let mut down = downwards.write_bytes();

        match self.1 {
            Format::F32LE => {
                for b in upwards.iter_number() {
                    if down.write_f32::<LittleEndian>(b as f32).is_err() { return false; }
                }
            }
            Format::C32LE => {
                for b in upwards.iter_complex() {
                    if down.write_f32::<LittleEndian>(b.re as f32).is_err() { return false; }
                    if down.write_f32::<LittleEndian>(b.im as f32).is_err() { return false; }
                }
            }
        }

        true
    }

    fn shape_up(&self) -> &Shape {
        &self.0
    }
}

struct BinFileUp(Shape, Format);
impl Process for BinFileUp {
    fn run(&self, downwards: &mut Connection, upwards: &mut Connection) -> bool {
        let mut down = io::BufReader::new(downwards.read_bytes());

        match self.1 {
            Format::F32LE => {
                loop {
                    match down.read_f32::<LittleEndian>() {
                        Ok(v) => {
                            if upwards.send((0, vec![Value::Number(v as f64)])).is_err() {
                                return false;
                            }
                        }
                        Err(e) => {
                            return e.kind() == ::std::io::ErrorKind::UnexpectedEof;
                        }
                    }
                }
            }
            Format::C32LE => {
                fn read_complex<R: Read>(r: &mut R) -> io::Result<Complex<f64>> {
                    let re = try!(r.read_f32::<LittleEndian>()) as f64;
                    let im = try!(r.read_f32::<LittleEndian>()) as f64;
                    Ok(Complex::new(re, im))
                }

                loop {
                    match read_complex(&mut down) {
                        Ok(v) => {
                            if upwards.send((0, vec![Value::Complex(v)])).is_err() {
                                return false;
                            }
                        }
                        Err(e) => {
                            return e.kind() == ::std::io::ErrorKind::UnexpectedEof;
                        }
                    }
                }
            }
        }

        true
    }

    fn shape_up(&self) -> &Shape {
        &self.0
    }
}

pub struct BinFileDef;
impl PrimitiveDef for BinFileDef {
    fn invoke_def(&self, downward_shape: &Shape, arg: Item) -> Box<Process + 'static> {
        let dir = downward_shape.match_bytes()
            .expect("Invalid shape below binfile");

        let arg_sym = match arg.as_constant() {
            Some(&Value::Symbol(ref s)) => s,
            _ => panic!("binfile expected a constant symbol argument")
        };

        let (shape, format) = match &arg_sym[..] {
            "f32le" => (Shape::number(dir, 0.0, 1.0), Format::F32LE),
            "c32le" => (Shape::complex(dir), Format::C32LE),
            other => panic!("Invalid binfile format `{}`", other),
        };

        match dir {
            DataMode { down: false, up: true } => box BinFileUp(shape, format),
            DataMode { down: true, up: false } => box BinFileDown (shape, format),
            _ => panic!("Invalid shape {:?} below binfile", downward_shape)
        }
    }
}
pub static BINFILE_DEF: BinFileDef = BinFileDef;
<commit_msg>Remove unreachable expression<commit_after>use std::io;
use std::io::prelude::*;

use data::{ Value, DataMode, Shape };
use connection::Connection;
use process::{Process, PrimitiveDef};
use language::Item;

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use num_complex::Complex;

enum Format {
    F32LE,
    C32LE,
}

struct BinFileDown(Shape, Format);
impl Process for BinFileDown {
    fn run(&self, downwards: &mut Connection, upwards: &mut Connection) -> bool {
        let mut down = downwards.write_bytes();

        match self.1 {
            Format::F32LE => {
                for b in upwards.iter_number() {
                    if down.write_f32::<LittleEndian>(b as f32).is_err() { return false; }
                }
            }
            Format::C32LE => {
                for b in upwards.iter_complex() {
                    if down.write_f32::<LittleEndian>(b.re as f32).is_err() { return false; }
                    if down.write_f32::<LittleEndian>(b.im as f32).is_err() { return false; }
                }
            }
        }

        true
    }

    fn shape_up(&self) -> &Shape {
        &self.0
    }
}

struct BinFileUp(Shape, Format);
impl Process for BinFileUp {
    fn run(&self, downwards: &mut Connection, upwards: &mut Connection) -> bool {
        let mut down = io::BufReader::new(downwards.read_bytes());

        match self.1 {
            Format::F32LE => {
                loop {
                    match down.read_f32::<LittleEndian>() {
                        Ok(v) => {
                            if upwards.send((0, vec![Value::Number(v as f64)])).is_err() {
                                return false;
                            }
                        }
                        Err(e) => {
                            return e.kind() == ::std::io::ErrorKind::UnexpectedEof;
                        }
                    }
                }
            }
            Format::C32LE => {
                fn read_complex<R: Read>(r: &mut R) -> io::Result<Complex<f64>> {
                    let re = try!(r.read_f32::<LittleEndian>()) as f64;
                    let im = try!(r.read_f32::<LittleEndian>()) as f64;
                    Ok(Complex::new(re, im))
                }

                loop {
                    match read_complex(&mut down) {
                        Ok(v) => {
                            if upwards.send((0, vec![Value::Complex(v)])).is_err() {
                                return false;
                            }
                        }
                        Err(e) => {
                            return e.kind() == ::std::io::ErrorKind::UnexpectedEof;
                        }
                    }
                }
            }
        }
    }

    fn shape_up(&self) -> &Shape {
        &self.0
    }
}

pub struct BinFileDef;
impl PrimitiveDef for BinFileDef {
    fn invoke_def(&self, downward_shape: &Shape, arg: Item) -> Box<Process + 'static> {
        let dir = downward_shape.match_bytes()
            .expect("Invalid shape below binfile");

        let arg_sym = match arg.as_constant() {
            Some(&Value::Symbol(ref s)) => s,
            _ => panic!("binfile expected a constant symbol argument")
        };

        let (shape, format) = match &arg_sym[..] {
            "f32le" => (Shape::number(dir, 0.0, 1.0), Format::F32LE),
            "c32le" => (Shape::complex(dir), Format::C32LE),
            other => panic!("Invalid binfile format `{}`", other),
        };

        match dir {
            DataMode { down: false, up: true } => box BinFileUp(shape, format),
            DataMode { down: true, up: false } => box BinFileDown (shape, format),
            _ => panic!("Invalid shape {:?} below binfile", downward_shape)
        }
    }
}
pub static BINFILE_DEF: BinFileDef = BinFileDef;
<|endoftext|>


<commit_before>use std::cell::Cell;
use std::collections::VecDeque;
use std::io;
use std::os::unix::io::AsRawFd;
use std::rc::Rc;
use std::sync::{Arc, Mutex};

use nix::poll::{poll, PollFd, PollFlags};

use wayland_commons::map::ObjectMap;
use wayland_commons::wire::{Argument, Message};

use super::connection::{Connection, Error as CError};
use super::proxy::{ObjectMeta, ProxyInner};
use super::Dispatched;

use crate::{AnonymousObject, DispatchData, Filter, Main, RawEvent};

pub(crate) type QueueBuffer = Arc<Mutex<VecDeque<Message>>>;

pub(crate) fn create_queue_buffer() -> QueueBuffer {
    Arc::new(Mutex::new(VecDeque::new()))
}

pub(crate) struct EventQueueInner {
    pub(crate) connection: Arc<Mutex<Connection>>,
    pub(crate) map: Arc<Mutex<ObjectMap<ObjectMeta>>>,
    pub(crate) buffer: QueueBuffer,
    display_buffer: QueueBuffer,
}

impl EventQueueInner {
    pub(crate) fn new(
        connection: Arc<Mutex<Connection>>,
        buffer: Option<QueueBuffer>,
    ) -> EventQueueInner {
        let (map, display_buffer) = {
            let cx = connection.lock().unwrap();
            (cx.map.clone(), cx.display_buffer.clone())
        };
        EventQueueInner {
            connection,
            map,
            buffer: buffer.unwrap_or_else(create_queue_buffer),
            display_buffer,
        }
    }

    pub(crate) fn dispatch<F>(&self, mut data: DispatchData, mut fallback: F) -> io::Result<u32>
    where
        F: FnMut(RawEvent, Main<AnonymousObject>, DispatchData<'_>),
    {
        // don't read events if there are some pending
        if let Err(()) = self.prepare_read() {
            return self.dispatch_pending(data.reborrow(), &mut fallback);
        }

        // temporarily retrieve the socket Fd, only using it for POLL-ing!
        let socket_fd;
        {
            // Flush the outgoing socket
            let mut conn_lock = self.connection.lock().unwrap();
            socket_fd = conn_lock.socket.get_socket().as_raw_fd();
            loop {
                match conn_lock.flush() {
                    Ok(_) => break,
                    Err(::nix::Error::Sys(::nix::errno::Errno::EAGAIN)) => {
                        // EAGAIN, we need to wait before writing, so we poll the socket
                        let poll_ret = poll(&mut [PollFd::new(socket_fd, PollFlags::POLLOUT)], -1);
                        match poll_ret {
                            Ok(_) => continue,
                            Err(::nix::Error::Sys(e)) => {
                                self.cancel_read();
                                return Err(e.into());
                            }
                            Err(_) => unreachable!(),
                        }
                    }
                    Err(::nix::Error::Sys(e)) => {
                        if e != ::nix::errno::Errno::EPIPE {
                            // don't abort on EPIPE, so we can continue reading
                            // to get the protocol error
                            self.cancel_read();
                            return Err(e.into());
                        }
                    }
                    Err(_) => unreachable!(),
                }
            }
        }

        // wait for incoming messages to arrive
        match poll(&mut [PollFd::new(socket_fd, PollFlags::POLLIN)], -1) {
            Ok(_) => (),
            Err(::nix::Error::Sys(e)) => {
                self.cancel_read();
                return Err(e.into());
            }
            Err(_) => unreachable!(),
        }
        let read_ret = self.read_events();

        // even if read_events returned an error, it may have queued messages the need dispatching
        // so we dispatch them
        let dispatch_ret = self.dispatch_pending(data.reborrow(), &mut fallback);

        match read_ret {
            Ok(()) => (),
            Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
                // we waited for read readiness be then received a WouldBlock error
                // this means that an other thread was also reading events and read them
                // under our nose
                // this is alright, continue
            }
            Err(e) => return Err(e),
        }

        dispatch_ret
    }

    fn dispatch_buffer<F>(
        &self,
        buffer: &Mutex<VecDeque<Message>>,
        mut data: DispatchData,
        mut fallback: F,
    ) -> io::Result<u32>
    where
        F: FnMut(RawEvent, Main<AnonymousObject>, DispatchData<'_>),
    {
        let mut count = 0;
        let mut proxymap = super::ProxyMap::make(self.map.clone(), self.connection.clone());
        loop {
            let msg = { buffer.lock().unwrap().pop_front() };
            let msg = match msg {
                Some(m) => m,
                None => break,
            };
            let id = msg.sender_id;
            if let Some(proxy) = ProxyInner::from_id(id, self.map.clone(), self.connection.clone())
            {
                let object = proxy.object.clone();
                if object.meta.client_destroyed {
                    // This is a potential race, if we reach here it means that the proxy was
                    // destroyed by the user between this message was queued and now. To handle it
                    // correctly, we must close any FDs it contains, mark any child object as
                    // destroyed (but the server will never know about it, so the ids will be
                    // leaked) and discard the event.
                    for arg in msg.args {
                        match arg {
                            Argument::Fd(fd) => {
                                let _ = ::nix::unistd::close(fd);
                            }
                            Argument::NewId(id) => {
                                let mut map = self.map.lock().unwrap();
                                map.with(id, |obj| {
                                    obj.meta.client_destroyed = true;
                                })
                                .unwrap();
                            }
                            _ => {}
                        }
                    }
                    continue;
                }
                let mut dispatcher = object.meta.dispatcher.lock().unwrap();
                match dispatcher.dispatch(msg, proxy, &mut proxymap, data.reborrow()) {
                    Dispatched::Yes => {
                        count += 1;
                    }
                    Dispatched::NoDispatch(msg, proxy) => {
                        let raw_event = message_to_rawevent(msg, &proxy, &mut proxymap);
                        fallback(raw_event, Main::wrap(proxy), data.reborrow());
                        count += 1;
                    }
                    Dispatched::BadMsg => {
                        return Err(io::Error::new(
                            io::ErrorKind::Other,
                            format!("Dispatch for object {}@{} errored.", object.interface, id),
                        ))
                    }
                }
            } else {
                return Err(io::Error::new(
                    io::ErrorKind::Other,
                    format!("Received an event for unknown object {}.", id),
                ));
            }
        }
        Ok(count)
    }

    pub(crate) fn dispatch_pending<F>(&self, mut data: DispatchData, fallback: F) -> io::Result<u32>
    where
        F: FnMut(RawEvent, Main<AnonymousObject>, DispatchData<'_>),
    {
        // First always dispatch the display buffer
        let display_dispatched =
            self.dispatch_buffer(&self.display_buffer, data.reborrow(), |_, _, _| unreachable!())?;

        // Then our actual buffer
        let self_dispatched = self.dispatch_buffer(&self.buffer, data.reborrow(), fallback)?;

        Ok(display_dispatched + self_dispatched)
    }

    pub(crate) fn sync_roundtrip<F>(
        &self,
        mut data: DispatchData,
        mut fallback: F,
    ) -> io::Result<u32>
    where
        F: FnMut(RawEvent, Main<AnonymousObject>, DispatchData<'_>),
    {
        use crate::protocol::wl_callback::{Event as CbEvent, WlCallback};
        use crate::protocol::wl_display::{Request as DRequest, WlDisplay};
        // first retrieve the display and make a wrapper for it in this event queue
        let mut display =
            ProxyInner::from_id(1, self.map.clone(), self.connection.clone()).unwrap();
        display.attach(&self);

        let done = Rc::new(Cell::new(false));
        let cb = display.send::<WlDisplay, WlCallback>(DRequest::Sync {}, Some(1)).unwrap();
        let done2 = done.clone();
        cb.assign::<WlCallback, _>(Filter::new(move |(_, CbEvent::Done { .. }), _, _| {
            done2.set(true);
        }));

        let mut dispatched = 0;

        loop {
            dispatched += self.dispatch(data.reborrow(), &mut fallback)?;
            if done.get() {
                return Ok(dispatched);
            }
        }
    }

    pub(crate) fn prepare_read(&self) -> Result<(), ()> {
        if !self.buffer.lock().unwrap().is_empty() {
            return Err(());
        }

        // TODO: un-mock
        Ok(())
    }

    pub(crate) fn read_events(&self) -> io::Result<()> {
        // TODO: integrate more properly with prepare read with a fence
        match self.connection.lock().unwrap().read_events() {
            Ok(_) => Ok(()),
            Err(CError::Protocol(e)) => {
                eprintln!("[wayland-client] Protocol error while reading events: {}", e);
                Err(::nix::errno::Errno::EPROTO.into())
            },
            Err(CError::Parse(e)) => {
                eprintln!("[wayland-client] Parse error while reading events: {}", e);
                Err(::nix::errno::Errno::EPROTO.into())
            },
            Err(CError::Nix(::nix::Error::Sys(errno))) => Err(errno.into()),
            Err(CError::Nix(_)) => unreachable!(),
        }
    }

    pub(crate) fn cancel_read(&self) {
        // TODO: un-mock
    }
}

fn message_to_rawevent(msg: Message, proxy: &ProxyInner, map: &mut super::ProxyMap) -> RawEvent {
    let Message { opcode, args, .. } = msg;

    let args = args
        .into_iter()
        .map(|a| match a {
            Argument::Int(i) => crate::Argument::Int(i),
            Argument::Uint(u) => crate::Argument::Uint(u),
            Argument::Array(v) => {
                crate::Argument::Array(if v.is_empty() { None } else { Some(*v) })
            }
            Argument::Fixed(f) => crate::Argument::Float((f as f32) / 256.),
            Argument::Fd(f) => crate::Argument::Fd(f),
            Argument::Str(cs) => crate::Argument::Str({
                let bytes = cs.into_bytes();
                if bytes.is_empty() {
                    None
                } else {
                    Some(
                        String::from_utf8(bytes)
                            .unwrap_or_else(|e| String::from_utf8_lossy(&e.into_bytes()).into()),
                    )
                }
            }),
            Argument::Object(id) => crate::Argument::Object(map.get(id)),
            Argument::NewId(id) => crate::Argument::NewId(map.get_new(id)),
        })
        .collect();

    RawEvent {
        interface: proxy.object.interface,
        opcode,
        name: proxy.object.events[opcode as usize].name,
        args,
    }
}
<commit_msg>Fix code formatting<commit_after>use std::cell::Cell;
use std::collections::VecDeque;
use std::io;
use std::os::unix::io::AsRawFd;
use std::rc::Rc;
use std::sync::{Arc, Mutex};

use nix::poll::{poll, PollFd, PollFlags};

use wayland_commons::map::ObjectMap;
use wayland_commons::wire::{Argument, Message};

use super::connection::{Connection, Error as CError};
use super::proxy::{ObjectMeta, ProxyInner};
use super::Dispatched;

use crate::{AnonymousObject, DispatchData, Filter, Main, RawEvent};

pub(crate) type QueueBuffer = Arc<Mutex<VecDeque<Message>>>;

pub(crate) fn create_queue_buffer() -> QueueBuffer {
    Arc::new(Mutex::new(VecDeque::new()))
}

pub(crate) struct EventQueueInner {
    pub(crate) connection: Arc<Mutex<Connection>>,
    pub(crate) map: Arc<Mutex<ObjectMap<ObjectMeta>>>,
    pub(crate) buffer: QueueBuffer,
    display_buffer: QueueBuffer,
}

impl EventQueueInner {
    pub(crate) fn new(
        connection: Arc<Mutex<Connection>>,
        buffer: Option<QueueBuffer>,
    ) -> EventQueueInner {
        let (map, display_buffer) = {
            let cx = connection.lock().unwrap();
            (cx.map.clone(), cx.display_buffer.clone())
        };
        EventQueueInner {
            connection,
            map,
            buffer: buffer.unwrap_or_else(create_queue_buffer),
            display_buffer,
        }
    }

    pub(crate) fn dispatch<F>(&self, mut data: DispatchData, mut fallback: F) -> io::Result<u32>
    where
        F: FnMut(RawEvent, Main<AnonymousObject>, DispatchData<'_>),
    {
        // don't read events if there are some pending
        if let Err(()) = self.prepare_read() {
            return self.dispatch_pending(data.reborrow(), &mut fallback);
        }

        // temporarily retrieve the socket Fd, only using it for POLL-ing!
        let socket_fd;
        {
            // Flush the outgoing socket
            let mut conn_lock = self.connection.lock().unwrap();
            socket_fd = conn_lock.socket.get_socket().as_raw_fd();
            loop {
                match conn_lock.flush() {
                    Ok(_) => break,
                    Err(::nix::Error::Sys(::nix::errno::Errno::EAGAIN)) => {
                        // EAGAIN, we need to wait before writing, so we poll the socket
                        let poll_ret = poll(&mut [PollFd::new(socket_fd, PollFlags::POLLOUT)], -1);
                        match poll_ret {
                            Ok(_) => continue,
                            Err(::nix::Error::Sys(e)) => {
                                self.cancel_read();
                                return Err(e.into());
                            }
                            Err(_) => unreachable!(),
                        }
                    }
                    Err(::nix::Error::Sys(e)) => {
                        if e != ::nix::errno::Errno::EPIPE {
                            // don't abort on EPIPE, so we can continue reading
                            // to get the protocol error
                            self.cancel_read();
                            return Err(e.into());
                        }
                    }
                    Err(_) => unreachable!(),
                }
            }
        }

        // wait for incoming messages to arrive
        match poll(&mut [PollFd::new(socket_fd, PollFlags::POLLIN)], -1) {
            Ok(_) => (),
            Err(::nix::Error::Sys(e)) => {
                self.cancel_read();
                return Err(e.into());
            }
            Err(_) => unreachable!(),
        }
        let read_ret = self.read_events();

        // even if read_events returned an error, it may have queued messages the need dispatching
        // so we dispatch them
        let dispatch_ret = self.dispatch_pending(data.reborrow(), &mut fallback);

        match read_ret {
            Ok(()) => (),
            Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
                // we waited for read readiness be then received a WouldBlock error
                // this means that an other thread was also reading events and read them
                // under our nose
                // this is alright, continue
            }
            Err(e) => return Err(e),
        }

        dispatch_ret
    }

    fn dispatch_buffer<F>(
        &self,
        buffer: &Mutex<VecDeque<Message>>,
        mut data: DispatchData,
        mut fallback: F,
    ) -> io::Result<u32>
    where
        F: FnMut(RawEvent, Main<AnonymousObject>, DispatchData<'_>),
    {
        let mut count = 0;
        let mut proxymap = super::ProxyMap::make(self.map.clone(), self.connection.clone());
        loop {
            let msg = { buffer.lock().unwrap().pop_front() };
            let msg = match msg {
                Some(m) => m,
                None => break,
            };
            let id = msg.sender_id;
            if let Some(proxy) = ProxyInner::from_id(id, self.map.clone(), self.connection.clone())
            {
                let object = proxy.object.clone();
                if object.meta.client_destroyed {
                    // This is a potential race, if we reach here it means that the proxy was
                    // destroyed by the user between this message was queued and now. To handle it
                    // correctly, we must close any FDs it contains, mark any child object as
                    // destroyed (but the server will never know about it, so the ids will be
                    // leaked) and discard the event.
                    for arg in msg.args {
                        match arg {
                            Argument::Fd(fd) => {
                                let _ = ::nix::unistd::close(fd);
                            }
                            Argument::NewId(id) => {
                                let mut map = self.map.lock().unwrap();
                                map.with(id, |obj| {
                                    obj.meta.client_destroyed = true;
                                })
                                .unwrap();
                            }
                            _ => {}
                        }
                    }
                    continue;
                }
                let mut dispatcher = object.meta.dispatcher.lock().unwrap();
                match dispatcher.dispatch(msg, proxy, &mut proxymap, data.reborrow()) {
                    Dispatched::Yes => {
                        count += 1;
                    }
                    Dispatched::NoDispatch(msg, proxy) => {
                        let raw_event = message_to_rawevent(msg, &proxy, &mut proxymap);
                        fallback(raw_event, Main::wrap(proxy), data.reborrow());
                        count += 1;
                    }
                    Dispatched::BadMsg => {
                        return Err(io::Error::new(
                            io::ErrorKind::Other,
                            format!("Dispatch for object {}@{} errored.", object.interface, id),
                        ))
                    }
                }
            } else {
                return Err(io::Error::new(
                    io::ErrorKind::Other,
                    format!("Received an event for unknown object {}.", id),
                ));
            }
        }
        Ok(count)
    }

    pub(crate) fn dispatch_pending<F>(&self, mut data: DispatchData, fallback: F) -> io::Result<u32>
    where
        F: FnMut(RawEvent, Main<AnonymousObject>, DispatchData<'_>),
    {
        // First always dispatch the display buffer
        let display_dispatched =
            self.dispatch_buffer(&self.display_buffer, data.reborrow(), |_, _, _| unreachable!())?;

        // Then our actual buffer
        let self_dispatched = self.dispatch_buffer(&self.buffer, data.reborrow(), fallback)?;

        Ok(display_dispatched + self_dispatched)
    }

    pub(crate) fn sync_roundtrip<F>(
        &self,
        mut data: DispatchData,
        mut fallback: F,
    ) -> io::Result<u32>
    where
        F: FnMut(RawEvent, Main<AnonymousObject>, DispatchData<'_>),
    {
        use crate::protocol::wl_callback::{Event as CbEvent, WlCallback};
        use crate::protocol::wl_display::{Request as DRequest, WlDisplay};
        // first retrieve the display and make a wrapper for it in this event queue
        let mut display =
            ProxyInner::from_id(1, self.map.clone(), self.connection.clone()).unwrap();
        display.attach(&self);

        let done = Rc::new(Cell::new(false));
        let cb = display.send::<WlDisplay, WlCallback>(DRequest::Sync {}, Some(1)).unwrap();
        let done2 = done.clone();
        cb.assign::<WlCallback, _>(Filter::new(move |(_, CbEvent::Done { .. }), _, _| {
            done2.set(true);
        }));

        let mut dispatched = 0;

        loop {
            dispatched += self.dispatch(data.reborrow(), &mut fallback)?;
            if done.get() {
                return Ok(dispatched);
            }
        }
    }

    pub(crate) fn prepare_read(&self) -> Result<(), ()> {
        if !self.buffer.lock().unwrap().is_empty() {
            return Err(());
        }

        // TODO: un-mock
        Ok(())
    }

    pub(crate) fn read_events(&self) -> io::Result<()> {
        // TODO: integrate more properly with prepare read with a fence
        match self.connection.lock().unwrap().read_events() {
            Ok(_) => Ok(()),
            Err(CError::Protocol(e)) => {
                eprintln!("[wayland-client] Protocol error while reading events: {}", e);
                Err(::nix::errno::Errno::EPROTO.into())
            }
            Err(CError::Parse(e)) => {
                eprintln!("[wayland-client] Parse error while reading events: {}", e);
                Err(::nix::errno::Errno::EPROTO.into())
            }
            Err(CError::Nix(::nix::Error::Sys(errno))) => Err(errno.into()),
            Err(CError::Nix(_)) => unreachable!(),
        }
    }

    pub(crate) fn cancel_read(&self) {
        // TODO: un-mock
    }
}

fn message_to_rawevent(msg: Message, proxy: &ProxyInner, map: &mut super::ProxyMap) -> RawEvent {
    let Message { opcode, args, .. } = msg;

    let args = args
        .into_iter()
        .map(|a| match a {
            Argument::Int(i) => crate::Argument::Int(i),
            Argument::Uint(u) => crate::Argument::Uint(u),
            Argument::Array(v) => {
                crate::Argument::Array(if v.is_empty() { None } else { Some(*v) })
            }
            Argument::Fixed(f) => crate::Argument::Float((f as f32) / 256.),
            Argument::Fd(f) => crate::Argument::Fd(f),
            Argument::Str(cs) => crate::Argument::Str({
                let bytes = cs.into_bytes();
                if bytes.is_empty() {
                    None
                } else {
                    Some(
                        String::from_utf8(bytes)
                            .unwrap_or_else(|e| String::from_utf8_lossy(&e.into_bytes()).into()),
                    )
                }
            }),
            Argument::Object(id) => crate::Argument::Object(map.get(id)),
            Argument::NewId(id) => crate::Argument::NewId(map.get_new(id)),
        })
        .collect();

    RawEvent {
        interface: proxy.object.interface,
        opcode,
        name: proxy.object.events[opcode as usize].name,
        args,
    }
}
<|endoftext|>


<commit_before>//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//

//! Error module, containing error types
error_chain!{
    errors {
        /// Error kind indicating that the JSON parser failed
        ParserError {}
        /// Error kind indicating that the Reader failed to read something
        ReaderError {}
        /// Error kind indicating that a call to the task warrior binary failed
        TaskCmdError {}
        /// Error kind indicating that a conversion to JSON failed
        SerializeError {}
    }
}
<commit_msg>Add error descriptions<commit_after>//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//

//! Error module, containing error types
error_chain!{
    errors {
        /// Error kind indicating that the JSON parser failed
        ParserError {
            description("Failed to create a Task from JSON")
        }
        /// Error kind indicating that the Reader failed to read something
        ReaderError {
            description("Failed to read tasks from a Reader")
        }
        /// Error kind indicating that a call to the task warrior binary failed
        TaskCmdError {
            description("There was a problem while calling the external 'task' binary")
        }
        /// Error kind indicating that a conversion to JSON failed
        SerializeError {
            description("A Task could not be converted to JSON")
        }
    }
}
<|endoftext|>


<commit_before>use backtrace::Backtrace;
use hyper::status::StatusCode;
use rustc_serialize::base64::FromBase64Error;
use rustc_serialize::json::{DecoderError, Json, ParserError, ToJson};
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::convert::From;
use std::error::Error;
use std::fmt;
use std::io::Error as IoError;

#[derive(PartialEq, Debug)]
pub enum ErrorStatus {
    ElementNotSelectable,
    ElementNotVisible,
    InsecureCertificate,
    InvalidArgument,
    InvalidCookieDomain,
    InvalidElementCoordinates,
    InvalidElementState,
    InvalidSelector,
    InvalidSessionId,
    JavascriptError,
    MoveTargetOutOfBounds,
    NoSuchAlert,
    NoSuchElement,
    NoSuchFrame,
    NoSuchWindow,
    ScriptTimeout,
    SessionNotCreated,
    StaleElementReference,
    Timeout,
    UnableToSetCookie,
    UnexpectedAlertOpen,
    UnknownError,
    UnknownMethod,
    UnknownPath,
    UnsupportedOperation,
}

impl ErrorStatus {
    pub fn status_code(&self) -> &'static str {
        match self {
            &ErrorStatus::ElementNotSelectable => "element not selectable",
            &ErrorStatus::ElementNotVisible => "element not visible",
            &ErrorStatus::InsecureCertificate => "insecure certificate",
            &ErrorStatus::InvalidArgument => "invalid argument",
            &ErrorStatus::InvalidCookieDomain => "invalid cookie domain",
            &ErrorStatus::InvalidElementCoordinates => "invalid element coordinates",
            &ErrorStatus::InvalidElementState => "invalid element state",
            &ErrorStatus::InvalidSelector => "invalid selector",
            &ErrorStatus::InvalidSessionId => "invalid session id",
            &ErrorStatus::JavascriptError => "javascript error",
            &ErrorStatus::MoveTargetOutOfBounds => "move target out of bounds",
            &ErrorStatus::NoSuchAlert => "no such alert",
            &ErrorStatus::NoSuchElement => "no such element",
            &ErrorStatus::NoSuchFrame => "no such frame",
            &ErrorStatus::NoSuchWindow => "no such window",
            &ErrorStatus::ScriptTimeout => "script timeout",
            &ErrorStatus::SessionNotCreated => "session not created",
            &ErrorStatus::StaleElementReference => "stale element reference",
            &ErrorStatus::Timeout => "timeout",
            &ErrorStatus::UnableToSetCookie => "unable to set cookie",
            &ErrorStatus::UnexpectedAlertOpen => "unexpected alert open",
            &ErrorStatus::UnknownError => "unknown error",
            &ErrorStatus::UnknownMethod => "unknown command",
            &ErrorStatus::UnknownPath => "unknown command",
            &ErrorStatus::UnsupportedOperation => "unsupported operation",
        }
    }

    pub fn http_status(&self) -> StatusCode {
        match self {
            &ErrorStatus::ElementNotSelectable => StatusCode::BadRequest,
            &ErrorStatus::ElementNotVisible => StatusCode::BadRequest,
            &ErrorStatus::InsecureCertificate => StatusCode::BadRequest,
            &ErrorStatus::InvalidArgument => StatusCode::BadRequest,
            &ErrorStatus::InvalidCookieDomain => StatusCode::BadRequest,
            &ErrorStatus::InvalidElementCoordinates => StatusCode::BadRequest,
            &ErrorStatus::InvalidElementState => StatusCode::BadRequest,
            &ErrorStatus::InvalidSelector => StatusCode::BadRequest,
            &ErrorStatus::InvalidSessionId => StatusCode::NotFound,
            &ErrorStatus::JavascriptError => StatusCode::InternalServerError,
            &ErrorStatus::MoveTargetOutOfBounds => StatusCode::InternalServerError,
            &ErrorStatus::NoSuchAlert => StatusCode::BadRequest,
            &ErrorStatus::NoSuchElement => StatusCode::NotFound,
            &ErrorStatus::NoSuchFrame => StatusCode::BadRequest,
            &ErrorStatus::NoSuchWindow => StatusCode::BadRequest,
            &ErrorStatus::ScriptTimeout => StatusCode::RequestTimeout,
            &ErrorStatus::SessionNotCreated => StatusCode::InternalServerError,
            &ErrorStatus::StaleElementReference => StatusCode::BadRequest,
            &ErrorStatus::Timeout => StatusCode::RequestTimeout,
            &ErrorStatus::UnableToSetCookie => StatusCode::InternalServerError,
            &ErrorStatus::UnexpectedAlertOpen => StatusCode::InternalServerError,
            &ErrorStatus::UnknownError => StatusCode::InternalServerError,
            &ErrorStatus::UnknownMethod => StatusCode::MethodNotAllowed,
            &ErrorStatus::UnknownPath => StatusCode::NotFound,
            &ErrorStatus::UnsupportedOperation => StatusCode::InternalServerError,
        }
    }
}

pub type WebDriverResult<T> = Result<T, WebDriverError>;

#[derive(Debug)]
pub struct WebDriverError {
    pub error: ErrorStatus,
    pub message: Cow<'static, str>,
    pub backtrace: Backtrace,
    pub delete_session: bool,
}

impl fmt::Display for WebDriverError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.message.fmt(f)
    }
}

impl WebDriverError {
    pub fn new<S>(error: ErrorStatus, message: S) -> WebDriverError
        where S: Into<Cow<'static, str>>
    {
        WebDriverError {
            error: error,
            message: message.into(),
            backtrace: Backtrace::new(),
            delete_session: false,
        }
    }

    pub fn status_code(&self) -> &'static str {
        self.error.status_code()
    }

    pub fn http_status(&self) -> StatusCode {
        self.error.http_status()
    }

    pub fn to_json_string(&self) -> String {
        self.to_json().to_string()
    }
}

impl ToJson for WebDriverError {
    fn to_json(&self) -> Json {
        let mut data = BTreeMap::new();
        data.insert("error".into(), self.status_code().to_json());
        data.insert("message".into(), self.message.to_json());
        data.insert("stacktrace".into(),
                    format!("{:?}", self.backtrace).to_json());
        Json::Object(data)
    }
}

impl Error for WebDriverError {
    fn description(&self) -> &str {
        self.status_code()
    }

    fn cause(&self) -> Option<&Error> {
        None
    }
}

impl From<ParserError> for WebDriverError {
    fn from(err: ParserError) -> WebDriverError {
        WebDriverError::new(ErrorStatus::UnknownError, err.description().to_string())
    }
}

impl From<IoError> for WebDriverError {
    fn from(err: IoError) -> WebDriverError {
        WebDriverError::new(ErrorStatus::UnknownError, err.description().to_string())
    }
}

impl From<DecoderError> for WebDriverError {
    fn from(err: DecoderError) -> WebDriverError {
        WebDriverError::new(ErrorStatus::UnknownError, err.description().to_string())
    }
}

impl From<FromBase64Error> for WebDriverError {
    fn from(err: FromBase64Error) -> WebDriverError {
        WebDriverError::new(ErrorStatus::UnknownError, err.description().to_string())
    }
}

impl From<Box<Error>> for WebDriverError {
    fn from(err: Box<Error>) -> WebDriverError {
        WebDriverError::new(ErrorStatus::UnknownError, err.description().to_string())
    }
}
<commit_msg>Wrap error responses in a 'value' object.<commit_after>use backtrace::Backtrace;
use hyper::status::StatusCode;
use rustc_serialize::base64::FromBase64Error;
use rustc_serialize::json::{DecoderError, Json, ParserError, ToJson};
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::convert::From;
use std::error::Error;
use std::fmt;
use std::io::Error as IoError;

#[derive(PartialEq, Debug)]
pub enum ErrorStatus {
    ElementNotSelectable,
    ElementNotVisible,
    InsecureCertificate,
    InvalidArgument,
    InvalidCookieDomain,
    InvalidElementCoordinates,
    InvalidElementState,
    InvalidSelector,
    InvalidSessionId,
    JavascriptError,
    MoveTargetOutOfBounds,
    NoSuchAlert,
    NoSuchElement,
    NoSuchFrame,
    NoSuchWindow,
    ScriptTimeout,
    SessionNotCreated,
    StaleElementReference,
    Timeout,
    UnableToSetCookie,
    UnexpectedAlertOpen,
    UnknownError,
    UnknownMethod,
    UnknownPath,
    UnsupportedOperation,
}

impl ErrorStatus {
    pub fn status_code(&self) -> &'static str {
        match self {
            &ErrorStatus::ElementNotSelectable => "element not selectable",
            &ErrorStatus::ElementNotVisible => "element not visible",
            &ErrorStatus::InsecureCertificate => "insecure certificate",
            &ErrorStatus::InvalidArgument => "invalid argument",
            &ErrorStatus::InvalidCookieDomain => "invalid cookie domain",
            &ErrorStatus::InvalidElementCoordinates => "invalid element coordinates",
            &ErrorStatus::InvalidElementState => "invalid element state",
            &ErrorStatus::InvalidSelector => "invalid selector",
            &ErrorStatus::InvalidSessionId => "invalid session id",
            &ErrorStatus::JavascriptError => "javascript error",
            &ErrorStatus::MoveTargetOutOfBounds => "move target out of bounds",
            &ErrorStatus::NoSuchAlert => "no such alert",
            &ErrorStatus::NoSuchElement => "no such element",
            &ErrorStatus::NoSuchFrame => "no such frame",
            &ErrorStatus::NoSuchWindow => "no such window",
            &ErrorStatus::ScriptTimeout => "script timeout",
            &ErrorStatus::SessionNotCreated => "session not created",
            &ErrorStatus::StaleElementReference => "stale element reference",
            &ErrorStatus::Timeout => "timeout",
            &ErrorStatus::UnableToSetCookie => "unable to set cookie",
            &ErrorStatus::UnexpectedAlertOpen => "unexpected alert open",
            &ErrorStatus::UnknownError => "unknown error",
            &ErrorStatus::UnknownMethod => "unknown command",
            &ErrorStatus::UnknownPath => "unknown command",
            &ErrorStatus::UnsupportedOperation => "unsupported operation",
        }
    }

    pub fn http_status(&self) -> StatusCode {
        match self {
            &ErrorStatus::ElementNotSelectable => StatusCode::BadRequest,
            &ErrorStatus::ElementNotVisible => StatusCode::BadRequest,
            &ErrorStatus::InsecureCertificate => StatusCode::BadRequest,
            &ErrorStatus::InvalidArgument => StatusCode::BadRequest,
            &ErrorStatus::InvalidCookieDomain => StatusCode::BadRequest,
            &ErrorStatus::InvalidElementCoordinates => StatusCode::BadRequest,
            &ErrorStatus::InvalidElementState => StatusCode::BadRequest,
            &ErrorStatus::InvalidSelector => StatusCode::BadRequest,
            &ErrorStatus::InvalidSessionId => StatusCode::NotFound,
            &ErrorStatus::JavascriptError => StatusCode::InternalServerError,
            &ErrorStatus::MoveTargetOutOfBounds => StatusCode::InternalServerError,
            &ErrorStatus::NoSuchAlert => StatusCode::BadRequest,
            &ErrorStatus::NoSuchElement => StatusCode::NotFound,
            &ErrorStatus::NoSuchFrame => StatusCode::BadRequest,
            &ErrorStatus::NoSuchWindow => StatusCode::BadRequest,
            &ErrorStatus::ScriptTimeout => StatusCode::RequestTimeout,
            &ErrorStatus::SessionNotCreated => StatusCode::InternalServerError,
            &ErrorStatus::StaleElementReference => StatusCode::BadRequest,
            &ErrorStatus::Timeout => StatusCode::RequestTimeout,
            &ErrorStatus::UnableToSetCookie => StatusCode::InternalServerError,
            &ErrorStatus::UnexpectedAlertOpen => StatusCode::InternalServerError,
            &ErrorStatus::UnknownError => StatusCode::InternalServerError,
            &ErrorStatus::UnknownMethod => StatusCode::MethodNotAllowed,
            &ErrorStatus::UnknownPath => StatusCode::NotFound,
            &ErrorStatus::UnsupportedOperation => StatusCode::InternalServerError,
        }
    }
}

pub type WebDriverResult<T> = Result<T, WebDriverError>;

#[derive(Debug)]
pub struct WebDriverError {
    pub error: ErrorStatus,
    pub message: Cow<'static, str>,
    pub backtrace: Backtrace,
    pub delete_session: bool,
}

impl fmt::Display for WebDriverError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.message.fmt(f)
    }
}

impl WebDriverError {
    pub fn new<S>(error: ErrorStatus, message: S) -> WebDriverError
        where S: Into<Cow<'static, str>>
    {
        WebDriverError {
            error: error,
            message: message.into(),
            backtrace: Backtrace::new(),
            delete_session: false,
        }
    }

    pub fn status_code(&self) -> &'static str {
        self.error.status_code()
    }

    pub fn http_status(&self) -> StatusCode {
        self.error.http_status()
    }

    pub fn to_json_string(&self) -> String {
        self.to_json().to_string()
    }
}

impl ToJson for WebDriverError {
    fn to_json(&self) -> Json {
        let mut data = BTreeMap::new();
        data.insert("error".into(), self.status_code().to_json());
        data.insert("message".into(), self.message.to_json());
        data.insert("stacktrace".into(),
                    format!("{:?}", self.backtrace).to_json());
        let mut wrapper = BTreeMap::new();
        wrapper.insert("value".into(), Json::Object(data));
        Json::Object(wrapper)
    }
}

impl Error for WebDriverError {
    fn description(&self) -> &str {
        self.status_code()
    }

    fn cause(&self) -> Option<&Error> {
        None
    }
}

impl From<ParserError> for WebDriverError {
    fn from(err: ParserError) -> WebDriverError {
        WebDriverError::new(ErrorStatus::UnknownError, err.description().to_string())
    }
}

impl From<IoError> for WebDriverError {
    fn from(err: IoError) -> WebDriverError {
        WebDriverError::new(ErrorStatus::UnknownError, err.description().to_string())
    }
}

impl From<DecoderError> for WebDriverError {
    fn from(err: DecoderError) -> WebDriverError {
        WebDriverError::new(ErrorStatus::UnknownError, err.description().to_string())
    }
}

impl From<FromBase64Error> for WebDriverError {
    fn from(err: FromBase64Error) -> WebDriverError {
        WebDriverError::new(ErrorStatus::UnknownError, err.description().to_string())
    }
}

impl From<Box<Error>> for WebDriverError {
    fn from(err: Box<Error>) -> WebDriverError {
        WebDriverError::new(ErrorStatus::UnknownError, err.description().to_string())
    }
}
<|endoftext|>


<commit_before>use std::iter::IntoIterator;
use std::str::FromStr;

use crate::error::Result;
use crate::map::Map;
use crate::source::AsyncSource;
use crate::{config::Config, path::Expression, source::Source, value::Value};

/// A configuration builder
///
/// It registers ordered sources of configuration to later build consistent [`Config`] from them.
/// Configuration sources it defines are defaults, [`Source`]s and overrides.
///
/// Defaults are alaways loaded first and can be overwritten by any of two other sources.
/// Overrides are always loaded last, thus cannot be overridden.
/// Both can be only set explicitly key by key in code
/// using [`set_default`](Self::set_default) or [`set_override`](Self::set_override).
///
/// An intermediate category, [`Source`], set groups of keys at once implicitly using data coming from external sources
/// like files, environment variables or others that one implements. Defining a [`Source`] is as simple as implementing
/// a trait for a struct.
///
/// Adding sources, setting defaults and overrides does not invoke any I/O nor builds a config.
/// It happens on demand when [`build`](Self::build) (or its alternative) is called.
/// Therefore all errors, related to any of the [`Source`] will only show up then.
///
/// # Sync and async builder
///
/// [`ConfigBuilder`] uses type parameter to keep track of builder state.
///
/// In [`DefaultState`] builder only supports [`Source`]s
///
/// In [`AsyncState`] it supports both [`Source`]s and [`AsyncSource`]s at the price of building using `async fn`.
///
/// # Examples
///
/// ```rust
/// # use config::*;
/// # use std::error::Error;
/// # fn main() -> Result<(), Box<dyn Error>> {
/// let mut builder = Config::builder()
///     .set_default("default", "1")?
///     .add_source(File::new("config/settings", FileFormat::Json))
/// //  .add_async_source(...)
///     .set_override("override", "1")?;
///
/// match builder.build() {
///     Ok(config) => {
///         // use your config
///     },
///     Err(e) => {
///         // something went wrong
///     }
/// }
/// # Ok(())
/// # }
/// ```
///
/// If any [`AsyncSource`] is used, the builder will transition to [`AsyncState`].
/// In such case, it is required to _await_ calls to [`build`](Self::build) and its non-consuming sibling.
///
/// Calls can be not chained as well
/// ```rust
/// # use std::error::Error;
/// # use config::*;
/// # fn main() -> Result<(), Box<dyn Error>> {
/// let mut builder = Config::builder();
/// builder = builder.set_default("default", "1")?;
/// builder = builder.add_source(File::new("config/settings", FileFormat::Json));
/// builder = builder.add_source(File::new("config/settings.prod", FileFormat::Json));
/// builder = builder.set_override("override", "1")?;
/// # Ok(())
/// # }
/// ```
///
/// Calling [`Config::builder`](Config::builder) yields builder in the default state.
/// If having an asynchronous state as the initial state is desired, _turbofish_ notation needs to be used.
/// ```rust
/// # use config::{*, builder::AsyncState};
/// let mut builder = ConfigBuilder::<AsyncState>::default();
/// ```
///
/// If for some reason acquiring builder in default state is required without calling [`Config::builder`](Config::builder)
/// it can also be achieved.
/// ```rust
/// # use config::{*, builder::DefaultState};
/// let mut builder = ConfigBuilder::<DefaultState>::default();
/// ```
#[derive(Debug, Clone, Default)]
pub struct ConfigBuilder<St: BuilderState> {
    defaults: Map<Expression, Value>,
    overrides: Map<Expression, Value>,
    state: St,
}

/// Represents [`ConfigBuilder`] state.
pub trait BuilderState {}

/// Represents data specific to builder in default, sychronous state, without support for async.
#[derive(Debug, Default)]
pub struct DefaultState {
    sources: Vec<Box<dyn Source + Send + Sync>>,
}

/// The asynchronous configuration builder.
///
/// Similar to a [`ConfigBuilder`] it maintains a set of defaults, a set of sources, and overrides.
///
/// Defaults do not override anything, sources override defaults, and overrides override anything else.
/// Within those three groups order of adding them at call site matters - entities added later take precedence.
///
/// For more detailed description and examples see [`ConfigBuilder`].
/// [`AsyncConfigBuilder`] is just an extension of it that takes async functions into account.
///
/// To obtain a [`Config`] call [`build`](AsyncConfigBuilder::build) or [`build_cloned`](AsyncConfigBuilder::build_cloned)
///
/// # Example
/// Since this library does not implement any [`AsyncSource`] an example in rustdocs cannot be given.
/// Detailed explanation about why such a source is not implemented is in [`AsyncSource`]'s documentation.
///
/// Refer to [`ConfigBuilder`] for similar API sample usage or to the examples folder of the crate, where such a source is implemented.
#[derive(Debug, Clone, Default)]
pub struct AsyncConfigBuilder {
    defaults: Map<Expression, Value>,
}

/// Represents data specific to builder in asychronous state, with support for async.
#[derive(Debug, Default)]
pub struct AsyncState {
    sources: Vec<SourceType>,
}

#[derive(Debug, Clone)]
enum SourceType {
    Sync(Box<dyn Source + Send + Sync>),
    Async(Box<dyn AsyncSource + Send + Sync>),
}

impl BuilderState for DefaultState {}
impl BuilderState for AsyncState {}

impl<St: BuilderState> ConfigBuilder<St> {
    // operations allowed in any state

    /// Set a default `value` at `key`
    ///
    /// This value can be overwritten by any [`Source`], [`AsyncSource`] or override.
    ///
    /// # Errors
    ///
    /// Fails if `Expression::from_str(key)` fails.
    pub fn set_default<S, T>(mut self, key: S, value: T) -> Result<ConfigBuilder<St>>
    where
        S: AsRef<str>,
        T: Into<Value>,
    {
        self.defaults
            .insert(Expression::from_str(key.as_ref())?, value.into());
        Ok(self)
    }

    /// Set an override
    ///
    /// This function sets an overwrite value. It will not be altered by any default, [`Source`] nor [`AsyncSource`]
    ///
    /// # Errors
    ///
    /// Fails if `Expression::from_str(key)` fails.
    pub fn set_override<S, T>(mut self, key: S, value: T) -> Result<ConfigBuilder<St>>
    where
        S: AsRef<str>,
        T: Into<Value>,
    {
        self.overrides
            .insert(Expression::from_str(key.as_ref())?, value.into());
        Ok(self)
    }
}

impl ConfigBuilder<DefaultState> {
    // operations allowed in sync state

    /// Registers new [`Source`] in this builder.
    ///
    /// Calling this method does not invoke any I/O. [`Source`] is only saved in internal register for later use.
    pub fn add_source<T>(mut self, source: T) -> Self
    where
        T: Source + Send + Sync + 'static,
    {
        self.state.sources.push(Box::new(source));
        self
    }

    /// Registers new [`AsyncSource`] in this builder and forces transition to [`AsyncState`].
    ///
    /// Calling this method does not invoke any I/O. [`AsyncSource`] is only saved in internal register for later use.
    pub fn add_async_source<T>(self, source: T) -> ConfigBuilder<AsyncState>
    where
        T: AsyncSource + Send + Sync + 'static,
    {
        let async_state = ConfigBuilder {
            state: AsyncState {
                sources: self
                    .state
                    .sources
                    .into_iter()
                    .map(|s| SourceType::Sync(s))
                    .collect(),
            },
            defaults: self.defaults,
            overrides: self.overrides,
        };

        async_state.add_async_source(source)
    }

    /// Reads all registered [`Source`]s.
    ///
    /// This is the method that invokes all I/O operations.
    /// For a non consuming alternative see [`build_cloned`](Self::build_cloned)
    ///
    /// # Errors
    /// If source collection fails, be it technical reasons or related to inability to read data as `Config` for different reasons,
    /// this method returns error.
    pub fn build(self) -> Result<Config> {
        Self::build_internal(self.defaults, self.overrides, &self.state.sources)
    }

    /// Reads all registered [`Source`]s.
    ///
    /// Similar to [`build`](Self::build), but it does not take ownership of `ConfigBuilder` to allow later reuse.
    /// Internally it clones data to achieve it.
    ///
    /// # Errors
    /// If source collection fails, be it technical reasons or related to inability to read data as `Config` for different reasons,
    /// this method returns error.
    pub fn build_cloned(&self) -> Result<Config> {
        Self::build_internal(
            self.defaults.clone(),
            self.overrides.clone(),
            &self.state.sources,
        )
    }

    fn build_internal(
        defaults: Map<Expression, Value>,
        overrides: Map<Expression, Value>,
        sources: &[Box<dyn Source + Send + Sync>],
    ) -> Result<Config> {
        let mut cache: Value = Map::<String, Value>::new().into();

        // Add defaults
        for (key, val) in defaults.into_iter() {
            key.set(&mut cache, val);
        }

        // Add sources
        sources.collect_to(&mut cache)?;

        // Add overrides
        for (key, val) in overrides.into_iter() {
            key.set(&mut cache, val);
        }

        Ok(Config::new(cache))
    }
}

impl ConfigBuilder<AsyncState> {
    // operations allowed in async state

    /// Registers new [`Source`] in this builder.
    ///
    /// Calling this method does not invoke any I/O. [`Source`] is only saved in internal register for later use.
    pub fn add_source<T>(mut self, source: T) -> ConfigBuilder<AsyncState>
    where
        T: Source + Send + Sync + 'static,
    {
        self.state.sources.push(SourceType::Sync(Box::new(source)));
        self
    }

    /// Registers new [`AsyncSource`] in this builder.
    ///
    /// Calling this method does not invoke any I/O. [`AsyncSource`] is only saved in internal register for later use.
    pub fn add_async_source<T>(mut self, source: T) -> ConfigBuilder<AsyncState>
    where
        T: AsyncSource + Send + Sync + 'static,
    {
        self.state.sources.push(SourceType::Async(Box::new(source)));
        self
    }

    /// Reads all registered defaults, [`Source`]s, [`AsyncSource`]s and overrides.
    ///
    /// This is the method that invokes all I/O operations.
    /// For a non consuming alternative see [`build_cloned`](Self::build_cloned)
    ///
    /// # Errors
    /// If source collection fails, be it technical reasons or related to inability to read data as `Config` for different reasons,
    /// this method returns error.
    pub async fn build(self) -> Result<Config> {
        Self::build_internal(self.defaults, self.overrides, &self.state.sources).await
    }

    /// Reads all registered defaults, [`Source`]s, [`AsyncSource`]s and overrides.
    ///
    /// Similar to [`build`](Self::build), but it does not take ownership of `ConfigBuilder` to allow later reuse.
    /// Internally it clones data to achieve it.
    ///
    /// # Errors
    /// If source collection fails, be it technical reasons or related to inability to read data as `Config` for different reasons,
    /// this method returns error.
    pub async fn build_cloned(&self) -> Result<Config> {
        Self::build_internal(
            self.defaults.clone(),
            self.overrides.clone(),
            &self.state.sources,
        )
        .await
    }

    async fn build_internal(
        defaults: Map<Expression, Value>,
        overrides: Map<Expression, Value>,
        sources: &[SourceType],
    ) -> Result<Config> {
        let mut cache: Value = Map::<String, Value>::new().into();

        // Add defaults
        for (key, val) in defaults.into_iter() {
            key.set(&mut cache, val);
        }

        for source in sources.iter() {
            match source {
                SourceType::Sync(source) => source.collect_to(&mut cache)?,
                SourceType::Async(source) => source.collect_to(&mut cache).await?,
            }
        }

        // Add overrides
        for (key, val) in overrides.into_iter() {
            key.set(&mut cache, val);
        }

        Ok(Config::new(cache))
    }
}
<commit_msg>Fix clippy: Remove unused field: AsyncConfigBuilder::defaults<commit_after>use std::iter::IntoIterator;
use std::str::FromStr;

use crate::error::Result;
use crate::map::Map;
use crate::source::AsyncSource;
use crate::{config::Config, path::Expression, source::Source, value::Value};

/// A configuration builder
///
/// It registers ordered sources of configuration to later build consistent [`Config`] from them.
/// Configuration sources it defines are defaults, [`Source`]s and overrides.
///
/// Defaults are alaways loaded first and can be overwritten by any of two other sources.
/// Overrides are always loaded last, thus cannot be overridden.
/// Both can be only set explicitly key by key in code
/// using [`set_default`](Self::set_default) or [`set_override`](Self::set_override).
///
/// An intermediate category, [`Source`], set groups of keys at once implicitly using data coming from external sources
/// like files, environment variables or others that one implements. Defining a [`Source`] is as simple as implementing
/// a trait for a struct.
///
/// Adding sources, setting defaults and overrides does not invoke any I/O nor builds a config.
/// It happens on demand when [`build`](Self::build) (or its alternative) is called.
/// Therefore all errors, related to any of the [`Source`] will only show up then.
///
/// # Sync and async builder
///
/// [`ConfigBuilder`] uses type parameter to keep track of builder state.
///
/// In [`DefaultState`] builder only supports [`Source`]s
///
/// In [`AsyncState`] it supports both [`Source`]s and [`AsyncSource`]s at the price of building using `async fn`.
///
/// # Examples
///
/// ```rust
/// # use config::*;
/// # use std::error::Error;
/// # fn main() -> Result<(), Box<dyn Error>> {
/// let mut builder = Config::builder()
///     .set_default("default", "1")?
///     .add_source(File::new("config/settings", FileFormat::Json))
/// //  .add_async_source(...)
///     .set_override("override", "1")?;
///
/// match builder.build() {
///     Ok(config) => {
///         // use your config
///     },
///     Err(e) => {
///         // something went wrong
///     }
/// }
/// # Ok(())
/// # }
/// ```
///
/// If any [`AsyncSource`] is used, the builder will transition to [`AsyncState`].
/// In such case, it is required to _await_ calls to [`build`](Self::build) and its non-consuming sibling.
///
/// Calls can be not chained as well
/// ```rust
/// # use std::error::Error;
/// # use config::*;
/// # fn main() -> Result<(), Box<dyn Error>> {
/// let mut builder = Config::builder();
/// builder = builder.set_default("default", "1")?;
/// builder = builder.add_source(File::new("config/settings", FileFormat::Json));
/// builder = builder.add_source(File::new("config/settings.prod", FileFormat::Json));
/// builder = builder.set_override("override", "1")?;
/// # Ok(())
/// # }
/// ```
///
/// Calling [`Config::builder`](Config::builder) yields builder in the default state.
/// If having an asynchronous state as the initial state is desired, _turbofish_ notation needs to be used.
/// ```rust
/// # use config::{*, builder::AsyncState};
/// let mut builder = ConfigBuilder::<AsyncState>::default();
/// ```
///
/// If for some reason acquiring builder in default state is required without calling [`Config::builder`](Config::builder)
/// it can also be achieved.
/// ```rust
/// # use config::{*, builder::DefaultState};
/// let mut builder = ConfigBuilder::<DefaultState>::default();
/// ```
#[derive(Debug, Clone, Default)]
pub struct ConfigBuilder<St: BuilderState> {
    defaults: Map<Expression, Value>,
    overrides: Map<Expression, Value>,
    state: St,
}

/// Represents [`ConfigBuilder`] state.
pub trait BuilderState {}

/// Represents data specific to builder in default, sychronous state, without support for async.
#[derive(Debug, Default)]
pub struct DefaultState {
    sources: Vec<Box<dyn Source + Send + Sync>>,
}

/// The asynchronous configuration builder.
///
/// Similar to a [`ConfigBuilder`] it maintains a set of defaults, a set of sources, and overrides.
///
/// Defaults do not override anything, sources override defaults, and overrides override anything else.
/// Within those three groups order of adding them at call site matters - entities added later take precedence.
///
/// For more detailed description and examples see [`ConfigBuilder`].
/// [`AsyncConfigBuilder`] is just an extension of it that takes async functions into account.
///
/// To obtain a [`Config`] call [`build`](AsyncConfigBuilder::build) or [`build_cloned`](AsyncConfigBuilder::build_cloned)
///
/// # Example
/// Since this library does not implement any [`AsyncSource`] an example in rustdocs cannot be given.
/// Detailed explanation about why such a source is not implemented is in [`AsyncSource`]'s documentation.
///
/// Refer to [`ConfigBuilder`] for similar API sample usage or to the examples folder of the crate, where such a source is implemented.
#[derive(Debug, Clone, Default)]
pub struct AsyncConfigBuilder {}

/// Represents data specific to builder in asychronous state, with support for async.
#[derive(Debug, Default)]
pub struct AsyncState {
    sources: Vec<SourceType>,
}

#[derive(Debug, Clone)]
enum SourceType {
    Sync(Box<dyn Source + Send + Sync>),
    Async(Box<dyn AsyncSource + Send + Sync>),
}

impl BuilderState for DefaultState {}
impl BuilderState for AsyncState {}

impl<St: BuilderState> ConfigBuilder<St> {
    // operations allowed in any state

    /// Set a default `value` at `key`
    ///
    /// This value can be overwritten by any [`Source`], [`AsyncSource`] or override.
    ///
    /// # Errors
    ///
    /// Fails if `Expression::from_str(key)` fails.
    pub fn set_default<S, T>(mut self, key: S, value: T) -> Result<ConfigBuilder<St>>
    where
        S: AsRef<str>,
        T: Into<Value>,
    {
        self.defaults
            .insert(Expression::from_str(key.as_ref())?, value.into());
        Ok(self)
    }

    /// Set an override
    ///
    /// This function sets an overwrite value. It will not be altered by any default, [`Source`] nor [`AsyncSource`]
    ///
    /// # Errors
    ///
    /// Fails if `Expression::from_str(key)` fails.
    pub fn set_override<S, T>(mut self, key: S, value: T) -> Result<ConfigBuilder<St>>
    where
        S: AsRef<str>,
        T: Into<Value>,
    {
        self.overrides
            .insert(Expression::from_str(key.as_ref())?, value.into());
        Ok(self)
    }
}

impl ConfigBuilder<DefaultState> {
    // operations allowed in sync state

    /// Registers new [`Source`] in this builder.
    ///
    /// Calling this method does not invoke any I/O. [`Source`] is only saved in internal register for later use.
    pub fn add_source<T>(mut self, source: T) -> Self
    where
        T: Source + Send + Sync + 'static,
    {
        self.state.sources.push(Box::new(source));
        self
    }

    /// Registers new [`AsyncSource`] in this builder and forces transition to [`AsyncState`].
    ///
    /// Calling this method does not invoke any I/O. [`AsyncSource`] is only saved in internal register for later use.
    pub fn add_async_source<T>(self, source: T) -> ConfigBuilder<AsyncState>
    where
        T: AsyncSource + Send + Sync + 'static,
    {
        let async_state = ConfigBuilder {
            state: AsyncState {
                sources: self
                    .state
                    .sources
                    .into_iter()
                    .map(|s| SourceType::Sync(s))
                    .collect(),
            },
            defaults: self.defaults,
            overrides: self.overrides,
        };

        async_state.add_async_source(source)
    }

    /// Reads all registered [`Source`]s.
    ///
    /// This is the method that invokes all I/O operations.
    /// For a non consuming alternative see [`build_cloned`](Self::build_cloned)
    ///
    /// # Errors
    /// If source collection fails, be it technical reasons or related to inability to read data as `Config` for different reasons,
    /// this method returns error.
    pub fn build(self) -> Result<Config> {
        Self::build_internal(self.defaults, self.overrides, &self.state.sources)
    }

    /// Reads all registered [`Source`]s.
    ///
    /// Similar to [`build`](Self::build), but it does not take ownership of `ConfigBuilder` to allow later reuse.
    /// Internally it clones data to achieve it.
    ///
    /// # Errors
    /// If source collection fails, be it technical reasons or related to inability to read data as `Config` for different reasons,
    /// this method returns error.
    pub fn build_cloned(&self) -> Result<Config> {
        Self::build_internal(
            self.defaults.clone(),
            self.overrides.clone(),
            &self.state.sources,
        )
    }

    fn build_internal(
        defaults: Map<Expression, Value>,
        overrides: Map<Expression, Value>,
        sources: &[Box<dyn Source + Send + Sync>],
    ) -> Result<Config> {
        let mut cache: Value = Map::<String, Value>::new().into();

        // Add defaults
        for (key, val) in defaults.into_iter() {
            key.set(&mut cache, val);
        }

        // Add sources
        sources.collect_to(&mut cache)?;

        // Add overrides
        for (key, val) in overrides.into_iter() {
            key.set(&mut cache, val);
        }

        Ok(Config::new(cache))
    }
}

impl ConfigBuilder<AsyncState> {
    // operations allowed in async state

    /// Registers new [`Source`] in this builder.
    ///
    /// Calling this method does not invoke any I/O. [`Source`] is only saved in internal register for later use.
    pub fn add_source<T>(mut self, source: T) -> ConfigBuilder<AsyncState>
    where
        T: Source + Send + Sync + 'static,
    {
        self.state.sources.push(SourceType::Sync(Box::new(source)));
        self
    }

    /// Registers new [`AsyncSource`] in this builder.
    ///
    /// Calling this method does not invoke any I/O. [`AsyncSource`] is only saved in internal register for later use.
    pub fn add_async_source<T>(mut self, source: T) -> ConfigBuilder<AsyncState>
    where
        T: AsyncSource + Send + Sync + 'static,
    {
        self.state.sources.push(SourceType::Async(Box::new(source)));
        self
    }

    /// Reads all registered defaults, [`Source`]s, [`AsyncSource`]s and overrides.
    ///
    /// This is the method that invokes all I/O operations.
    /// For a non consuming alternative see [`build_cloned`](Self::build_cloned)
    ///
    /// # Errors
    /// If source collection fails, be it technical reasons or related to inability to read data as `Config` for different reasons,
    /// this method returns error.
    pub async fn build(self) -> Result<Config> {
        Self::build_internal(self.defaults, self.overrides, &self.state.sources).await
    }

    /// Reads all registered defaults, [`Source`]s, [`AsyncSource`]s and overrides.
    ///
    /// Similar to [`build`](Self::build), but it does not take ownership of `ConfigBuilder` to allow later reuse.
    /// Internally it clones data to achieve it.
    ///
    /// # Errors
    /// If source collection fails, be it technical reasons or related to inability to read data as `Config` for different reasons,
    /// this method returns error.
    pub async fn build_cloned(&self) -> Result<Config> {
        Self::build_internal(
            self.defaults.clone(),
            self.overrides.clone(),
            &self.state.sources,
        )
        .await
    }

    async fn build_internal(
        defaults: Map<Expression, Value>,
        overrides: Map<Expression, Value>,
        sources: &[SourceType],
    ) -> Result<Config> {
        let mut cache: Value = Map::<String, Value>::new().into();

        // Add defaults
        for (key, val) in defaults.into_iter() {
            key.set(&mut cache, val);
        }

        for source in sources.iter() {
            match source {
                SourceType::Sync(source) => source.collect_to(&mut cache)?,
                SourceType::Async(source) => source.collect_to(&mut cache).await?,
            }
        }

        // Add overrides
        for (key, val) in overrides.into_iter() {
            key.set(&mut cache, val);
        }

        Ok(Config::new(cache))
    }
}
<|endoftext|>