<commit_before>import std::map::hashmap;
import middle::ty;
import middle::ty::*;
import metadata::encoder;
import syntax::codemap;
import syntax::print::pprust;
import syntax::print::pprust::{path_to_str, constr_args_to_str, proto_to_str,
                               mode_to_str};
import syntax::{ast, ast_util};
import middle::ast_map;
import driver::session::session;

fn region_to_str(cx: ctxt, region: region) -> str {
    alt region {
      re_named(_)   { "<name>" }    // TODO: include name
      re_caller(_)  { "<caller>" }
      re_block(node_id) {
        alt cx.items.get(node_id) {
            ast_map::node_block(blk) {
                #fmt("<block at %s>", codemap::span_to_str(blk.span,
                                                           cx.sess.codemap))
            }
            _ { cx.sess.bug("re_block refers to non-block") }
        }
      }
      re_self(_)    { "self" }
      re_inferred   { "" }
    }
}

fn ty_to_str(cx: ctxt, typ: t) -> str {
    fn fn_input_to_str(cx: ctxt, input: {mode: ast::mode, ty: t}) ->
       str {
        let {mode, ty} = input;
        let modestr = alt canon_mode(cx, mode) {
          ast::infer(_) { "" }
          ast::expl(m) {
            if !ty::type_has_vars(ty) &&
                m == ty::default_arg_mode_for_ty(ty) {
                ""
            } else {
                mode_to_str(ast::expl(m))
            }
          }
        };
        modestr + ty_to_str(cx, ty)
    }
    fn fn_to_str(cx: ctxt, proto: ast::proto, ident: option<ast::ident>,
                 inputs: [arg], output: t, cf: ast::ret_style,
                 constrs: [@constr]) -> str {
        let s = proto_to_str(proto);
        alt ident { some(i) { s += " "; s += i; } _ { } }
        s += "(";
        let strs = [];
        for a: arg in inputs { strs += [fn_input_to_str(cx, a)]; }
        s += str::connect(strs, ", ");
        s += ")";
        if ty::get(output).struct != ty_nil {
            s += " -> ";
            alt cf {
              ast::noreturn { s += "!"; }
              ast::return_val { s += ty_to_str(cx, output); }
            }
        }
        s += constrs_str(constrs);
        ret s;
    }
    fn method_to_str(cx: ctxt, m: method) -> str {
        ret fn_to_str(cx, m.fty.proto, some(m.ident), m.fty.inputs,
                      m.fty.output, m.fty.ret_style, m.fty.constraints) + ";";
    }
    fn field_to_str(cx: ctxt, f: field) -> str {
        ret f.ident + ": " + mt_to_str(cx, f.mt);
    }
    fn mt_to_str(cx: ctxt, m: mt) -> str {
        let mstr = alt m.mutbl {
          ast::m_mutbl { "mut " }
          ast::m_imm { "" }
          ast::m_const { "const " }
        };
        ret mstr + ty_to_str(cx, m.ty);
    }
    fn parameterized(cx: ctxt, base: str, tps: [ty::t]) -> str {
        if vec::len(tps) > 0u {
            let strs = vec::map(tps, {|t| ty_to_str(cx, t)});
            #fmt["%s<%s>", base, str::connect(strs, ",")]
        } else {
            base
        }
    }

    // if there is an id, print that instead of the structural type:
    alt ty::type_def_id(typ) {
      some(def_id) {
        let cs = ast_map::path_to_str(ty::item_path(cx, def_id));
        ret alt ty::get(typ).struct {
          ty_enum(_, tps) | ty_res(_, _, tps) | ty_iface(_, tps) |
          ty_class(_, tps) {
            parameterized(cx, cs, tps)
          }
          _ { cs }
        };
      }
      none { /* fallthrough */}
    }

    // pretty print the structural type representation:
    ret alt ty::get(typ).struct {
      ty_nil { "()" }
      ty_bot { "_|_" }
      ty_bool { "bool" }
      ty_int(ast::ty_i) { "int" }
      ty_int(ast::ty_char) { "char" }
      ty_int(t) { ast_util::int_ty_to_str(t) }
      ty_uint(ast::ty_u) { "uint" }
      ty_uint(t) { ast_util::uint_ty_to_str(t) }
      ty_float(ast::ty_f) { "float" }
      ty_float(t) { ast_util::float_ty_to_str(t) }
      ty_str { "str" }
      ty_self(ts) { parameterized(cx, "self", ts) }
      ty_box(tm) { "@" + mt_to_str(cx, tm) }
      ty_uniq(tm) { "~" + mt_to_str(cx, tm) }
      ty_ptr(tm) { "*" + mt_to_str(cx, tm) }
      ty_rptr(r, tm) { "&" + region_to_str(cx, r) + "." + mt_to_str(cx, tm) }
      ty_vec(tm) { "[" + mt_to_str(cx, tm) + "]" }
      ty_type { "type" }
      ty_rec(elems) {
        let strs: [str] = [];
        for fld: field in elems { strs += [field_to_str(cx, fld)]; }
        "{" + str::connect(strs, ",") + "}"
      }
      ty_tup(elems) {
        let strs = [];
        for elem in elems { strs += [ty_to_str(cx, elem)]; }
        "(" + str::connect(strs, ",") + ")"
      }
      ty_fn(f) {
        fn_to_str(cx, f.proto, none, f.inputs, f.output, f.ret_style,
                  f.constraints)
      }
      ty_var(v) { "<T" + int::str(v) + ">" }
      ty_param(id, _) {
        "'" + str::from_bytes([('a' as u8) + (id as u8)])
      }
      ty_enum(did, tps) | ty_res(did, _, tps) | ty_iface(did, tps) |
      ty_class(did, tps) {
        let path = ty::item_path(cx, did);
        let base = ast_map::path_to_str(path);
        parameterized(cx, base, tps)
      }
      _ { ty_to_short_str(cx, typ) }
    }
}

fn ty_to_short_str(cx: ctxt, typ: t) -> str {
    let s = encoder::encoded_ty(cx, typ);
    if str::len(s) >= 32u { s = str::slice(s, 0u, 32u); }
    ret s;
}

fn constr_to_str(c: @constr) -> str {
    ret path_to_str(c.node.path) +
            pprust::constr_args_to_str(pprust::uint_to_str, c.node.args);
}

fn constrs_str(constrs: [@constr]) -> str {
    let s = "";
    let colon = true;
    for c: @constr in constrs {
        if colon { s += " : "; colon = false; } else { s += ", "; }
        s += constr_to_str(c);
    }
    ret s;
}

fn ty_constr_to_str<Q>(c: @ast::spanned<ast::constr_general_<@ast::path, Q>>)
   -> str {
    ret path_to_str(c.node.path) +
            constr_args_to_str::<@ast::path>(path_to_str, c.node.args);
}

// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>rustc: Give a better error message when references involving the caller region fail to unify<commit_after>import std::map::hashmap;
import middle::ty;
import middle::ty::*;
import metadata::encoder;
import syntax::codemap;
import syntax::print::pprust;
import syntax::print::pprust::{path_to_str, constr_args_to_str, proto_to_str,
                               mode_to_str};
import syntax::{ast, ast_util};
import middle::ast_map;
import driver::session::session;

fn region_to_str(cx: ctxt, region: region) -> str {
    alt region {
      re_named(_)   { "<name>" }    // TODO: include name
      re_caller(def_id) {
        if def_id.crate == ast::local_crate {
            alt cx.items.get(def_id.node) {
              ast_map::node_item(item, path) {
                #fmt("<caller of %s::%s>", ast_map::path_to_str(*path),
                     item.ident)
              }
              _ { "<caller>" }
            }
        } else {
            "<caller>"
        }
      }
      re_block(node_id) {
        alt cx.items.get(node_id) {
            ast_map::node_block(blk) {
                #fmt("<block at %s>", codemap::span_to_str(blk.span,
                                                           cx.sess.codemap))
            }
            _ { cx.sess.bug("re_block refers to non-block") }
        }
      }
      re_self(_)    { "self" }
      re_inferred   { "" }
    }
}

fn ty_to_str(cx: ctxt, typ: t) -> str {
    fn fn_input_to_str(cx: ctxt, input: {mode: ast::mode, ty: t}) ->
       str {
        let {mode, ty} = input;
        let modestr = alt canon_mode(cx, mode) {
          ast::infer(_) { "" }
          ast::expl(m) {
            if !ty::type_has_vars(ty) &&
                m == ty::default_arg_mode_for_ty(ty) {
                ""
            } else {
                mode_to_str(ast::expl(m))
            }
          }
        };
        modestr + ty_to_str(cx, ty)
    }
    fn fn_to_str(cx: ctxt, proto: ast::proto, ident: option<ast::ident>,
                 inputs: [arg], output: t, cf: ast::ret_style,
                 constrs: [@constr]) -> str {
        let s = proto_to_str(proto);
        alt ident { some(i) { s += " "; s += i; } _ { } }
        s += "(";
        let strs = [];
        for a: arg in inputs { strs += [fn_input_to_str(cx, a)]; }
        s += str::connect(strs, ", ");
        s += ")";
        if ty::get(output).struct != ty_nil {
            s += " -> ";
            alt cf {
              ast::noreturn { s += "!"; }
              ast::return_val { s += ty_to_str(cx, output); }
            }
        }
        s += constrs_str(constrs);
        ret s;
    }
    fn method_to_str(cx: ctxt, m: method) -> str {
        ret fn_to_str(cx, m.fty.proto, some(m.ident), m.fty.inputs,
                      m.fty.output, m.fty.ret_style, m.fty.constraints) + ";";
    }
    fn field_to_str(cx: ctxt, f: field) -> str {
        ret f.ident + ": " + mt_to_str(cx, f.mt);
    }
    fn mt_to_str(cx: ctxt, m: mt) -> str {
        let mstr = alt m.mutbl {
          ast::m_mutbl { "mut " }
          ast::m_imm { "" }
          ast::m_const { "const " }
        };
        ret mstr + ty_to_str(cx, m.ty);
    }
    fn parameterized(cx: ctxt, base: str, tps: [ty::t]) -> str {
        if vec::len(tps) > 0u {
            let strs = vec::map(tps, {|t| ty_to_str(cx, t)});
            #fmt["%s<%s>", base, str::connect(strs, ",")]
        } else {
            base
        }
    }

    // if there is an id, print that instead of the structural type:
    alt ty::type_def_id(typ) {
      some(def_id) {
        let cs = ast_map::path_to_str(ty::item_path(cx, def_id));
        ret alt ty::get(typ).struct {
          ty_enum(_, tps) | ty_res(_, _, tps) | ty_iface(_, tps) |
          ty_class(_, tps) {
            parameterized(cx, cs, tps)
          }
          _ { cs }
        };
      }
      none { /* fallthrough */}
    }

    // pretty print the structural type representation:
    ret alt ty::get(typ).struct {
      ty_nil { "()" }
      ty_bot { "_|_" }
      ty_bool { "bool" }
      ty_int(ast::ty_i) { "int" }
      ty_int(ast::ty_char) { "char" }
      ty_int(t) { ast_util::int_ty_to_str(t) }
      ty_uint(ast::ty_u) { "uint" }
      ty_uint(t) { ast_util::uint_ty_to_str(t) }
      ty_float(ast::ty_f) { "float" }
      ty_float(t) { ast_util::float_ty_to_str(t) }
      ty_str { "str" }
      ty_self(ts) { parameterized(cx, "self", ts) }
      ty_box(tm) { "@" + mt_to_str(cx, tm) }
      ty_uniq(tm) { "~" + mt_to_str(cx, tm) }
      ty_ptr(tm) { "*" + mt_to_str(cx, tm) }
      ty_rptr(r, tm) { "&" + region_to_str(cx, r) + "." + mt_to_str(cx, tm) }
      ty_vec(tm) { "[" + mt_to_str(cx, tm) + "]" }
      ty_type { "type" }
      ty_rec(elems) {
        let strs: [str] = [];
        for fld: field in elems { strs += [field_to_str(cx, fld)]; }
        "{" + str::connect(strs, ",") + "}"
      }
      ty_tup(elems) {
        let strs = [];
        for elem in elems { strs += [ty_to_str(cx, elem)]; }
        "(" + str::connect(strs, ",") + ")"
      }
      ty_fn(f) {
        fn_to_str(cx, f.proto, none, f.inputs, f.output, f.ret_style,
                  f.constraints)
      }
      ty_var(v) { "<T" + int::str(v) + ">" }
      ty_param(id, _) {
        "'" + str::from_bytes([('a' as u8) + (id as u8)])
      }
      ty_enum(did, tps) | ty_res(did, _, tps) | ty_iface(did, tps) |
      ty_class(did, tps) {
        let path = ty::item_path(cx, did);
        let base = ast_map::path_to_str(path);
        parameterized(cx, base, tps)
      }
      _ { ty_to_short_str(cx, typ) }
    }
}

fn ty_to_short_str(cx: ctxt, typ: t) -> str {
    let s = encoder::encoded_ty(cx, typ);
    if str::len(s) >= 32u { s = str::slice(s, 0u, 32u); }
    ret s;
}

fn constr_to_str(c: @constr) -> str {
    ret path_to_str(c.node.path) +
            pprust::constr_args_to_str(pprust::uint_to_str, c.node.args);
}

fn constrs_str(constrs: [@constr]) -> str {
    let s = "";
    let colon = true;
    for c: @constr in constrs {
        if colon { s += " : "; colon = false; } else { s += ", "; }
        s += constr_to_str(c);
    }
    ret s;
}

fn ty_constr_to_str<Q>(c: @ast::spanned<ast::constr_general_<@ast::path, Q>>)
   -> str {
    ret path_to_str(c.node.path) +
            constr_args_to_str::<@ast::path>(path_to_str, c.node.args);
}

// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


<commit_before>//! `cargo upgrade`
#![warn(
    missing_docs,
    missing_debug_implementations,
    missing_copy_implementations,
    trivial_casts,
    trivial_numeric_casts,
    unsafe_code,
    unstable_features,
    unused_import_braces,
    unused_qualifications
)]

#[macro_use]
extern crate error_chain;

use crate::errors::*;
use cargo_edit::{find, get_latest_dependency, CrateName, Dependency, LocalManifest};
use failure::Fail;
use std::collections::HashMap;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process;
use structopt::StructOpt;
use termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, WriteColor};

mod errors {
    error_chain! {
        links {
            CargoEditLib(::cargo_edit::Error, ::cargo_edit::ErrorKind);
        }
        foreign_links {
            CargoMetadata(::failure::Compat<::cargo_metadata::Error>);
        }
    }
}

#[derive(Debug, StructOpt)]
#[structopt(bin_name = "cargo")]
enum Command {
    /// Upgrade dependencies as specified in the local manifest file (i.e. Cargo.toml).
    #[structopt(name = "upgrade", author = "")]
    #[structopt(
        after_help = "This command differs from `cargo update`, which updates the dependency versions recorded in the
local lock file (Cargo.lock).

If `<dependency>`(s) are provided, only the specified dependencies will be upgraded. The version to
upgrade to for each can be specified with e.g. `docopt@0.8.0` or `serde@>=0.9,<2.0`.

Dev, build, and all target dependencies will also be upgraded. Only dependencies from crates.io are
supported. Git/path dependencies will be ignored.

All packages in the workspace will be upgraded if the `--all` flag is supplied. The `--all` flag may
be supplied in the presence of a virtual manifest."
    )]
    Upgrade(Args),
}

#[derive(Debug, StructOpt)]
struct Args {
    /// Crates to be upgraded.
    dependency: Vec<String>,

    /// Path to the manifest to upgrade
    #[structopt(long = "manifest-path", value_name = "path")]
    manifest_path: Option<PathBuf>,

    /// Upgrade all packages in the workspace.
    #[structopt(long = "all")]
    all: bool,

    /// Include prerelease versions when fetching from crates.io (e.g. 0.6.0-alpha').
    #[structopt(long = "allow-prerelease")]
    allow_prerelease: bool,

    /// Print changes to be made without making them.
    #[structopt(long = "dry-run")]
    dry_run: bool,
}

/// A collection of manifests.
struct Manifests(Vec<(LocalManifest, cargo_metadata::Package)>);

impl Manifests {
    /// Get all manifests in the workspace.
    fn get_all(manifest_path: &Option<PathBuf>) -> Result<Self> {
        let mut cmd = cargo_metadata::MetadataCommand::new();
        cmd.no_deps();
        if let Some(path) = manifest_path {
            cmd.manifest_path(path);
        }
        let result = cmd.exec();
        if let Err(e) = result {
            return Err(Error::from(e.compat()).chain_err(|| "Failed to get workspace metadata"));
        }
        result
            .unwrap()
            .packages
            .into_iter()
            .map(|package| {
                Ok((
                    LocalManifest::try_new(Path::new(&package.manifest_path))?,
                    package,
                ))
            })
            .collect::<Result<Vec<_>>>()
            .map(Manifests)
    }

    /// Get the manifest specified by the manifest path. Try to make an educated guess if no path is
    /// provided.
    fn get_local_one(manifest_path: &Option<PathBuf>) -> Result<Self> {
        let resolved_manifest_path: String = find(&manifest_path)?.to_string_lossy().into();

        let manifest = LocalManifest::find(&manifest_path)?;

        let mut cmd = cargo_metadata::MetadataCommand::new();
        cmd.no_deps();
        if let Some(path) = manifest_path {
            cmd.manifest_path(path);
        }
        let result = cmd.exec();
        if let Err(e) = result {
            return Err(Error::from(e.compat()).chain_err(|| "Invalid manifest"));
        }
        let packages = result.unwrap().packages;
        let package = packages
            .iter()
            .find(|p| p.manifest_path.to_string_lossy() == resolved_manifest_path)
            // If we have successfully got metadata, but our manifest path does not correspond to a
            // package, we must have been called against a virtual manifest.
            .chain_err(|| {
                "Found virtual manifest, but this command requires running against an \
                 actual package in this workspace. Try adding `--all`."
            })?;

        Ok(Manifests(vec![(manifest, package.to_owned())]))
    }

    /// Get the the combined set of dependencies to upgrade. If the user has specified
    /// per-dependency desired versions, extract those here.
    fn get_dependencies(&self, only_update: Vec<String>) -> Result<DesiredUpgrades> {
        /// Helper function to check whether a `cargo_metadata::Dependency` is a version dependency.
        fn is_version_dep(dependency: &cargo_metadata::Dependency) -> bool {
            match dependency.source {
                // This is the criterion cargo uses (in `SourceId::from_url`) to decide whether a
                // dependency has the 'registry' kind.
                Some(ref s) => s.splitn(2, '+').next() == Some("registry"),
                _ => false,
            }
        }

        Ok(DesiredUpgrades(if only_update.is_empty() {
            // User hasn't asked for any specific dependencies to be upgraded, so upgrade all the
            // dependencies.
            self.0
                .iter()
                .flat_map(|&(_, ref package)| package.dependencies.clone())
                .filter(is_version_dep)
                .map(|dependency| (dependency.name, None))
                .collect()
        } else {
            only_update
                .into_iter()
                .map(|name| {
                    if let Some(dependency) = CrateName::new(&name.clone()).parse_as_version()? {
                        Ok((
                            dependency.name.clone(),
                            dependency.version().map(String::from),
                        ))
                    } else {
                        Ok((name, None))
                    }
                })
                .collect::<Result<_>>()?
        }))
    }

    /// Upgrade the manifests on disk following the previously-determined upgrade schema.
    fn upgrade(self, upgraded_deps: &ActualUpgrades, dry_run: bool) -> Result<()> {
        if dry_run {
            let bufwtr = BufferWriter::stdout(ColorChoice::Always);
            let mut buffer = bufwtr.buffer();
            buffer
                .set_color(ColorSpec::new().set_fg(Some(Color::Cyan)).set_bold(true))
                .chain_err(|| "Failed to set output colour")?;
            write!(&mut buffer, "Starting dry run. ")
                .chain_err(|| "Failed to write dry run message")?;
            buffer
                .set_color(&ColorSpec::new())
                .chain_err(|| "Failed to clear output colour")?;
            writeln!(&mut buffer, "Changes will not be saved.")
                .chain_err(|| "Failed to write dry run message")?;
            bufwtr
                .print(&buffer)
                .chain_err(|| "Failed to print dry run message")?;
        }

        for (mut manifest, package) in self.0 {
            println!("{}:", package.name);

            for (name, version) in &upgraded_deps.0 {
                manifest.upgrade(&Dependency::new(name).set_version(version), dry_run)?;
            }
        }

        Ok(())
    }
}

/// The set of dependencies to be upgraded, alongside desired versions, if specified by the user.
struct DesiredUpgrades(HashMap<String, Option<String>>);

/// The complete specification of the upgrades that will be performed. Map of the dependency names
/// to the new versions.
struct ActualUpgrades(HashMap<String, String>);

impl DesiredUpgrades {
    /// Transform the dependencies into their upgraded forms. If a version is specified, all
    /// dependencies will get that version.
    fn get_upgraded(self, allow_prerelease: bool) -> Result<ActualUpgrades> {
        self.0
            .into_iter()
            .map(|(name, version)| {
                if let Some(v) = version {
                    Ok((name, v))
                } else {
                    get_latest_dependency(&name, allow_prerelease)
                        .map(|new_dep| {
                            (
                                name,
                                new_dep
                                    .version()
                                    .expect("Invalid dependency type")
                                    .to_string(),
                            )
                        })
                        .chain_err(|| "Failed to get new version")
                }
            })
            .collect::<Result<_>>()
            .map(ActualUpgrades)
    }
}

/// Main processing function. Allows us to return a `Result` so that `main` can print pretty error
/// messages.
fn process(args: Args) -> Result<()> {
    let Args {
        dependency,
        manifest_path,
        all,
        allow_prerelease,
        dry_run,
        ..
    } = args;

    let manifests = if all {
        Manifests::get_all(&manifest_path)
    } else {
        Manifests::get_local_one(&manifest_path)
    }?;

    let existing_dependencies = manifests.get_dependencies(dependency)?;

    let upgraded_dependencies = existing_dependencies.get_upgraded(allow_prerelease)?;

    manifests.upgrade(&upgraded_dependencies, dry_run)
}

fn main() {
    let args: Command = Command::from_args();
    let Command::Upgrade(args) = args;

    if let Err(err) = process(args) {
        eprintln!("Command failed due to unhandled error: {}\n", err);

        for e in err.iter().skip(1) {
            eprintln!("Caused by: {}", e);
        }

        if let Some(backtrace) = err.backtrace() {
            eprintln!("Backtrace: {:?}", backtrace);
        }

        process::exit(1);
    }
}
<commit_msg>Simplify error conversion a bit<commit_after>//! `cargo upgrade`
#![warn(
    missing_docs,
    missing_debug_implementations,
    missing_copy_implementations,
    trivial_casts,
    trivial_numeric_casts,
    unsafe_code,
    unstable_features,
    unused_import_braces,
    unused_qualifications
)]

#[macro_use]
extern crate error_chain;

use crate::errors::*;
use cargo_edit::{find, get_latest_dependency, CrateName, Dependency, LocalManifest};
use failure::Fail;
use std::collections::HashMap;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process;
use structopt::StructOpt;
use termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, WriteColor};

mod errors {
    error_chain! {
        links {
            CargoEditLib(::cargo_edit::Error, ::cargo_edit::ErrorKind);
        }
        foreign_links {
            CargoMetadata(::failure::Compat<::cargo_metadata::Error>);
        }
    }
}

#[derive(Debug, StructOpt)]
#[structopt(bin_name = "cargo")]
enum Command {
    /// Upgrade dependencies as specified in the local manifest file (i.e. Cargo.toml).
    #[structopt(name = "upgrade", author = "")]
    #[structopt(
        after_help = "This command differs from `cargo update`, which updates the dependency versions recorded in the
local lock file (Cargo.lock).

If `<dependency>`(s) are provided, only the specified dependencies will be upgraded. The version to
upgrade to for each can be specified with e.g. `docopt@0.8.0` or `serde@>=0.9,<2.0`.

Dev, build, and all target dependencies will also be upgraded. Only dependencies from crates.io are
supported. Git/path dependencies will be ignored.

All packages in the workspace will be upgraded if the `--all` flag is supplied. The `--all` flag may
be supplied in the presence of a virtual manifest."
    )]
    Upgrade(Args),
}

#[derive(Debug, StructOpt)]
struct Args {
    /// Crates to be upgraded.
    dependency: Vec<String>,

    /// Path to the manifest to upgrade
    #[structopt(long = "manifest-path", value_name = "path")]
    manifest_path: Option<PathBuf>,

    /// Upgrade all packages in the workspace.
    #[structopt(long = "all")]
    all: bool,

    /// Include prerelease versions when fetching from crates.io (e.g. 0.6.0-alpha').
    #[structopt(long = "allow-prerelease")]
    allow_prerelease: bool,

    /// Print changes to be made without making them.
    #[structopt(long = "dry-run")]
    dry_run: bool,
}

/// A collection of manifests.
struct Manifests(Vec<(LocalManifest, cargo_metadata::Package)>);

impl Manifests {
    /// Get all manifests in the workspace.
    fn get_all(manifest_path: &Option<PathBuf>) -> Result<Self> {
        let mut cmd = cargo_metadata::MetadataCommand::new();
        cmd.no_deps();
        if let Some(path) = manifest_path {
            cmd.manifest_path(path);
        }
        let result = cmd
            .exec()
            .map_err(|e| Error::from(e.compat()).chain_err(|| "Invalid manifest"))?;
        result
            .packages
            .into_iter()
            .map(|package| {
                Ok((
                    LocalManifest::try_new(Path::new(&package.manifest_path))?,
                    package,
                ))
            })
            .collect::<Result<Vec<_>>>()
            .map(Manifests)
    }

    /// Get the manifest specified by the manifest path. Try to make an educated guess if no path is
    /// provided.
    fn get_local_one(manifest_path: &Option<PathBuf>) -> Result<Self> {
        let resolved_manifest_path: String = find(&manifest_path)?.to_string_lossy().into();

        let manifest = LocalManifest::find(&manifest_path)?;

        let mut cmd = cargo_metadata::MetadataCommand::new();
        cmd.no_deps();
        if let Some(path) = manifest_path {
            cmd.manifest_path(path);
        }
        let result = cmd
            .exec()
            .map_err(|e| Error::from(e.compat()).chain_err(|| "Invalid manifest"))?;
        let packages = result.packages;
        let package = packages
            .iter()
            .find(|p| p.manifest_path.to_string_lossy() == resolved_manifest_path)
            // If we have successfully got metadata, but our manifest path does not correspond to a
            // package, we must have been called against a virtual manifest.
            .chain_err(|| {
                "Found virtual manifest, but this command requires running against an \
                 actual package in this workspace. Try adding `--all`."
            })?;

        Ok(Manifests(vec![(manifest, package.to_owned())]))
    }

    /// Get the the combined set of dependencies to upgrade. If the user has specified
    /// per-dependency desired versions, extract those here.
    fn get_dependencies(&self, only_update: Vec<String>) -> Result<DesiredUpgrades> {
        /// Helper function to check whether a `cargo_metadata::Dependency` is a version dependency.
        fn is_version_dep(dependency: &cargo_metadata::Dependency) -> bool {
            match dependency.source {
                // This is the criterion cargo uses (in `SourceId::from_url`) to decide whether a
                // dependency has the 'registry' kind.
                Some(ref s) => s.splitn(2, '+').next() == Some("registry"),
                _ => false,
            }
        }

        Ok(DesiredUpgrades(if only_update.is_empty() {
            // User hasn't asked for any specific dependencies to be upgraded, so upgrade all the
            // dependencies.
            self.0
                .iter()
                .flat_map(|&(_, ref package)| package.dependencies.clone())
                .filter(is_version_dep)
                .map(|dependency| (dependency.name, None))
                .collect()
        } else {
            only_update
                .into_iter()
                .map(|name| {
                    if let Some(dependency) = CrateName::new(&name.clone()).parse_as_version()? {
                        Ok((
                            dependency.name.clone(),
                            dependency.version().map(String::from),
                        ))
                    } else {
                        Ok((name, None))
                    }
                })
                .collect::<Result<_>>()?
        }))
    }

    /// Upgrade the manifests on disk following the previously-determined upgrade schema.
    fn upgrade(self, upgraded_deps: &ActualUpgrades, dry_run: bool) -> Result<()> {
        if dry_run {
            let bufwtr = BufferWriter::stdout(ColorChoice::Always);
            let mut buffer = bufwtr.buffer();
            buffer
                .set_color(ColorSpec::new().set_fg(Some(Color::Cyan)).set_bold(true))
                .chain_err(|| "Failed to set output colour")?;
            write!(&mut buffer, "Starting dry run. ")
                .chain_err(|| "Failed to write dry run message")?;
            buffer
                .set_color(&ColorSpec::new())
                .chain_err(|| "Failed to clear output colour")?;
            writeln!(&mut buffer, "Changes will not be saved.")
                .chain_err(|| "Failed to write dry run message")?;
            bufwtr
                .print(&buffer)
                .chain_err(|| "Failed to print dry run message")?;
        }

        for (mut manifest, package) in self.0 {
            println!("{}:", package.name);

            for (name, version) in &upgraded_deps.0 {
                manifest.upgrade(&Dependency::new(name).set_version(version), dry_run)?;
            }
        }

        Ok(())
    }
}

/// The set of dependencies to be upgraded, alongside desired versions, if specified by the user.
struct DesiredUpgrades(HashMap<String, Option<String>>);

/// The complete specification of the upgrades that will be performed. Map of the dependency names
/// to the new versions.
struct ActualUpgrades(HashMap<String, String>);

impl DesiredUpgrades {
    /// Transform the dependencies into their upgraded forms. If a version is specified, all
    /// dependencies will get that version.
    fn get_upgraded(self, allow_prerelease: bool) -> Result<ActualUpgrades> {
        self.0
            .into_iter()
            .map(|(name, version)| {
                if let Some(v) = version {
                    Ok((name, v))
                } else {
                    get_latest_dependency(&name, allow_prerelease)
                        .map(|new_dep| {
                            (
                                name,
                                new_dep
                                    .version()
                                    .expect("Invalid dependency type")
                                    .to_string(),
                            )
                        })
                        .chain_err(|| "Failed to get new version")
                }
            })
            .collect::<Result<_>>()
            .map(ActualUpgrades)
    }
}

/// Main processing function. Allows us to return a `Result` so that `main` can print pretty error
/// messages.
fn process(args: Args) -> Result<()> {
    let Args {
        dependency,
        manifest_path,
        all,
        allow_prerelease,
        dry_run,
        ..
    } = args;

    let manifests = if all {
        Manifests::get_all(&manifest_path)
    } else {
        Manifests::get_local_one(&manifest_path)
    }?;

    let existing_dependencies = manifests.get_dependencies(dependency)?;

    let upgraded_dependencies = existing_dependencies.get_upgraded(allow_prerelease)?;

    manifests.upgrade(&upgraded_dependencies, dry_run)
}

fn main() {
    let args: Command = Command::from_args();
    let Command::Upgrade(args) = args;

    if let Err(err) = process(args) {
        eprintln!("Command failed due to unhandled error: {}\n", err);

        for e in err.iter().skip(1) {
            eprintln!("Caused by: {}", e);
        }

        if let Some(backtrace) = err.backtrace() {
            eprintln!("Backtrace: {:?}", backtrace);
        }

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


<commit_before>use super::ArgumentConvert;
use crate::{model::prelude::*, prelude::*};

/// Error that can be returned from [`User::convert`].
#[non_exhaustive]
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub enum UserParseError {
    /// The provided user string failed to parse, or the parsed result cannot be found in the
    /// guild cache data.
    NotFoundOrMalformed,
}

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

impl std::fmt::Display for UserParseError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::NotFoundOrMalformed => write!(f, "User not found or unknown format"),
        }
    }
}

/// Look up a user by a string case-insensitively.
///
/// Requires the cache feature to be enabled. If a user is not in cache, they will not be found!
///
/// The lookup strategy is as follows (in order):
/// 1. Lookup by ID.
/// 2. [Lookup by mention](`crate::utils::parse_username`).
/// 3. [Lookup by name#discrim](`crate::utils::parse_user_tag`).
/// 4. Lookup by name
#[cfg(feature = "cache")]
#[async_trait::async_trait]
impl ArgumentConvert for User {
    type Err = UserParseError;

    async fn convert(
        ctx: &Context,
        _guild_id: Option<GuildId>,
        _channel_id: Option<ChannelId>,
        s: &str,
    ) -> Result<Self, Self::Err> {
        let users = ctx.cache.users.read().await;

        let lookup_by_id = || users.get(&UserId(s.parse().ok()?));

        let lookup_by_mention = || users.get(&UserId(crate::utils::parse_username(s)?));

        let lookup_by_name_and_discrim = || {
            let (name, discrim) = crate::utils::parse_user_tag(s)?;
            users
                .values()
                .find(|user| user.discriminator == discrim && user.name.eq_ignore_ascii_case(name))
        };

        let lookup_by_name = || users.values().find(|user| user.name == s);

        lookup_by_id()
            .or_else(lookup_by_mention)
            .or_else(lookup_by_name_and_discrim)
            .or_else(lookup_by_name)
            .cloned()
            .ok_or(UserParseError::NotFoundOrMalformed)
    }
}
<commit_msg>Fall back to `Member` parsing if `User` is not in the cache in `ArgumentConvert` (#1489)<commit_after>use super::ArgumentConvert;
use crate::{model::prelude::*, prelude::*};

/// Error that can be returned from [`User::convert`].
#[non_exhaustive]
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub enum UserParseError {
    /// The provided user string failed to parse, or the parsed result cannot be found in the
    /// guild cache data.
    NotFoundOrMalformed,
}

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

impl std::fmt::Display for UserParseError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::NotFoundOrMalformed => write!(f, "User not found or unknown format"),
        }
    }
}

/// Look up a user by a string case-insensitively.
///
/// Requires the cache feature to be enabled. If a user is not in cache, they will not be found!
///
/// The lookup strategy is as follows (in order):
/// 1. Lookup by ID.
/// 2. [Lookup by mention](`crate::utils::parse_username`).
/// 3. [Lookup by name#discrim](`crate::utils::parse_user_tag`).
/// 4. Lookup by name
#[cfg(feature = "cache")]
#[async_trait::async_trait]
impl ArgumentConvert for User {
    type Err = UserParseError;

    async fn convert(
        ctx: &Context,
        guild_id: Option<GuildId>,
        channel_id: Option<ChannelId>,
        s: &str,
    ) -> Result<Self, Self::Err> {
        let users = ctx.cache.users.read().await;

        let lookup_by_id = || users.get(&UserId(s.parse().ok()?));

        let lookup_by_mention = || users.get(&UserId(crate::utils::parse_username(s)?));

        let lookup_by_name_and_discrim = || {
            let (name, discrim) = crate::utils::parse_user_tag(s)?;
            users
                .values()
                .find(|user| user.discriminator == discrim && user.name.eq_ignore_ascii_case(name))
        };

        let lookup_by_name = || users.values().find(|user| user.name == s);

        // Try to look up in global user cache via a variety of methods
        if let Some(user) = lookup_by_id()
            .or_else(lookup_by_mention)
            .or_else(lookup_by_name_and_discrim)
            .or_else(lookup_by_name)
        {
            return Ok(user.clone());
        }

        // If not successful, convert as a Member which uses HTTP endpoints instead of cache
        if let Ok(member) = Member::convert(ctx, guild_id, channel_id, s).await {
            return Ok(member.user);
        }

        Err(UserParseError::NotFoundOrMalformed)
    }
}
<|endoftext|>


<commit_before>use std::io;

#[derive(Copy, Clone, Debug)]
enum Player {
    YeonSeung,
    JunSeok,
}

impl Player {
    fn opponent(&self) -> Player {
        match *self {
            Player::YeonSeung => Player::JunSeok,
            Player::JunSeok => Player::YeonSeung,
        }
    }
}

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
struct Coordinate {
    row: usize,
    col: usize,
}

impl Coordinate {
    fn move_in(&self, dir: Direction, delta: usize) -> Coordinate {
        match dir {
            Direction::Up => Coordinate{row: self.row - delta, col: self.col},
            Direction::Down => Coordinate{row: self.row + delta, col: self.col},
            Direction::Left => Coordinate{row: self.row, col: self.col - delta},
            Direction::Right => Coordinate{row: self.row, col: self.col + delta},
        }
    }
    fn induces_board_type(&self) -> bool {
        *self == Coordinate{row: 1, col: 1} ||
        *self == Coordinate{row: 2, col: 1} ||
        *self == Coordinate{row: 2, col: 0} ||
        *self == Coordinate{row: 3, col: 0}
    }
}

#[derive(Copy, Clone)]
enum Direction {
    Up,
    Down,
    Left,
    Right,
}
const POSSIBLE_DIRECTIONS: [Direction; 4] = [
    Direction::Up,
    Direction::Down,
    Direction::Left,
    Direction::Right,
];

#[derive(Copy, Clone, Debug)]
enum MoveType {
    Single,
    OneUp,
    OneDown,
    OneLeft,
    OneRight,
    TwoUp,
    TwoDown,
    TwoLeft,
    TwoRight,
    UpAndDown,
    LeftAndRight,
}
const POSSIBLE_MOVE_TYPES: [MoveType; 11] = [
    MoveType::Single,
    MoveType::OneUp,
    MoveType::OneDown,
    MoveType::OneLeft,
    MoveType::OneRight,
    MoveType::TwoUp,
    MoveType::TwoDown,
    MoveType::TwoLeft,
    MoveType::TwoRight,
    MoveType::UpAndDown,
    MoveType::LeftAndRight,
];

#[derive(Copy, Clone, Debug)]
struct Move {
    coord: Coordinate,
    move_type: MoveType,
    board_type: Option<BoardType>,
}
impl Move {
    fn coords(&self) -> Vec<Coordinate> {
        match self.move_type {
            MoveType::Single => vec![],
            MoveType::OneUp => vec![self.coord.move_in(Direction::Up, 1)],
            MoveType::OneDown => vec![self.coord.move_in(Direction::Down, 1)],
            MoveType::OneLeft => vec![self.coord.move_in(Direction::Left, 1)],
            MoveType::OneRight => vec![self.coord.move_in(Direction::Right, 1)],
            MoveType::TwoUp => vec![self.coord.move_in(Direction::Up, 1), self.coord.move_in(Direction::Up, 2)],
            MoveType::TwoDown => vec![self.coord.move_in(Direction::Down, 1), self.coord.move_in(Direction::Down, 2)],
            MoveType::TwoLeft => vec![self.coord.move_in(Direction::Left, 1), self.coord.move_in(Direction::Left, 2)],
            MoveType::TwoRight => vec![self.coord.move_in(Direction::Right, 1), self.coord.move_in(Direction::Right, 2)],
            MoveType::UpAndDown => vec![self.coord.move_in(Direction::Up, 1), self.coord.move_in(Direction::Down, 1)],
            MoveType::LeftAndRight => vec![self.coord.move_in(Direction::Left, 1), self.coord.move_in(Direction::Right, 1)],
        }
    }
}

const NUM_COLS: usize = 5;
const NUM_ROWS: usize = 4;

// Hacks for the three states of the lower-left of the board in JunSeok vs YeonSeung game
#[derive(Copy, Clone, Debug)]
enum BoardType {
    Left,
    Middle,
    Right,
}
const POSSIBLE_BOARD_TYPES: [BoardType; 3] = [
    BoardType::Left,
    BoardType::Middle,
    BoardType::Right,
];

type BoardArray = [[bool; NUM_COLS]; NUM_ROWS];
struct Board {
    board: BoardArray,
    board_type: Option<BoardType>,
}

impl Board {
    fn make_move(&mut self, m: Move) {
        match m.board_type {
            Some(_) => self.board_type = m.board_type,
            None => (),
        }
        self.set_squares(m, true)
    }

    fn undo_move(&mut self, m: Move, bt: Option<BoardType>) {
        self.board_type = bt;
        self.set_squares(m, false)
    }

    fn set_squares(&mut self, m: Move, mode: bool) {
        self.board[m.coord.row][m.coord.col] = mode;
        for other_space in m.coords().iter() {
            self.board[other_space.row][other_space.col] = mode;
        }
    }

    fn occupied(&self, c: Coordinate) -> bool {
        self.in_bounds(c) && self.board[c.row][c.col]
    }

    fn in_bounds(&self, c: Coordinate) -> bool {
        // >= 0 is always true due to type limits.
        // c.row >= 0 && c.row < NUM_ROWS && c.col >= 0 && c.col < NUM_COLS
        c.row < NUM_ROWS && c.col < NUM_COLS
    }

    // Assuming that m is a move with an unoccupied coordinate!
    // This doesn't check whether the target squares are occupied.
    // Advantage: It's quicker. Disadvantage: It allows some illegal moves.
    fn move_in_bounds(&self, m: Move) -> bool {
        match m.move_type {
            MoveType::Single => true,
            MoveType::OneUp => m.coord.row >= 1,
            MoveType::OneDown => m.coord.row < NUM_ROWS - 1,
            MoveType::OneLeft => m.coord.col >= 1,
            MoveType::OneRight => m.coord.col < NUM_COLS - 1,
            MoveType::TwoUp => m.coord.row >= 2,
            MoveType::TwoDown => m.coord.row < NUM_ROWS - 2,
            MoveType::TwoLeft => m.coord.col >= 2,
            MoveType::TwoRight => m.coord.col < NUM_COLS - 2,
            MoveType::UpAndDown => m.coord.row >= 1 && m.coord.row < NUM_ROWS - 1,
            MoveType::LeftAndRight => m.coord.col >= 1 && m.coord.col < NUM_COLS - 1,
        }
    }

    // Unfortunately I kind of have to hard-code this.
    fn makes_unsolvable(c: Coordinate, b: Option<BoardType>) -> bool {
        match b {
            Some(BoardType::Left)   => c == Coordinate{row: 2, col: 1} || c == Coordinate{row: 1, col: 1},
            Some(BoardType::Middle) => c == Coordinate{row: 3, col: 0} || c == Coordinate{row: 1, col: 1},
            Some(BoardType::Right)  => c == Coordinate{row: 3, col: 0} || c == Coordinate{row: 2, col: 0},
            None => false,
        }
    }

    fn frontier(&self) -> Vec<Coordinate> {
        let mut results = Vec::new();
        for row in 0..NUM_ROWS {
            for col in 0..NUM_COLS {
                let coord = Coordinate{row: row, col: col};
                if self.occupied(coord) || Board::makes_unsolvable(coord, self.board_type) {
                    continue;
                }
                let mut have_neighbor = false;
                for dir in POSSIBLE_DIRECTIONS.iter() {
                    let new_coord = coord.move_in(*dir, 1);
                    if self.occupied(new_coord) {
                        have_neighbor = true;
                        break;
                    }
                }
                if have_neighbor {
                    results.push(coord);
                }
            }
        }
        results
    }

    fn legal_moves(&self) -> Vec<Move> {
        let mut results = Vec::new();
        for frontier_space in self.frontier().iter() {
            for move_type in POSSIBLE_MOVE_TYPES.iter() {
                let mov = Move{coord: *frontier_space, move_type: *move_type, board_type: None};
                if !self.move_in_bounds(mov) {
                    continue;
                }
                let mut other_space_taken = false;
                let mut induces_board_type = frontier_space.induces_board_type();
                for other_space in mov.coords().iter() {
                    if other_space.induces_board_type() {
                        induces_board_type = true;
                    }
                    if self.occupied(*other_space) || Board::makes_unsolvable(*other_space, self.board_type) {
                        other_space_taken = true;
                        break;
                    }
                }
                if !other_space_taken {
                    if induces_board_type && self.board_type.is_none() {
                        for board_type in POSSIBLE_BOARD_TYPES.iter() {
                            if Board::makes_unsolvable(*frontier_space, Some(*board_type)) {
                                continue;
                            }
                            let mut other_spaces_ok = true;
                            for other_space in mov.coords().iter() {
                                if Board::makes_unsolvable(*other_space, Some(*board_type)) {
                                    other_spaces_ok = false;
                                    break;
                                }
                            }
                            if other_spaces_ok {
                                results.push(Move{coord: mov.coord, move_type: mov.move_type, board_type: Some(*board_type)});
                            }
                        }

                    } else {
                        results.push(mov);
                    }
                }
            }
        }
        results
    }

    fn print(&self) {
        for row in self.board.iter() {
            for col in row.iter() {
                print!("{: >5} ", col);
            }
            println!("");
        }
        println!("{:?}", self.board_type);
    }
}

#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
enum GameResult {
    PlaceholderJunSeok,
    JunSeokWin,
    YeonSeungWin,
    PlaceholderYeonSeung,
}

fn minimax_alpha_beta(player: Player, board: &mut Board, initial_alpha: GameResult, initial_beta: GameResult) -> (GameResult, Option<Move>) {
    let moves = board.legal_moves();
    // There are no more moves, which means my opponent completed the railroad.
    // So I lose.
    if moves.is_empty() {
        return match player {
            Player::YeonSeung => (GameResult::JunSeokWin, None),
            Player::JunSeok => (GameResult::YeonSeungWin, None),
        }
    }
    let mut best = match player {
        Player::YeonSeung => initial_alpha,
        Player::JunSeok => initial_beta,
    };
    let mut alpha = initial_alpha;
    let mut beta = initial_beta;
    let mut best_move = None;

    for possible_move in moves.iter() {
        let bt = board.board_type;
        board.make_move(*possible_move);
        let (reply, _) = minimax_alpha_beta(player.opponent(), board, alpha, beta);
        board.undo_move(*possible_move, bt);

        match player {
            Player::YeonSeung => {
                if reply > best {
                    best = reply;
                    alpha = reply;
                    best_move = Some(*possible_move);
                }
                if best >= GameResult::YeonSeungWin {
                    return (best, best_move);
                }
            },
            Player::JunSeok => {
                if reply < best {
                    best = reply;
                    beta = reply;
                    best_move = Some(*possible_move);
                }
                if best <= GameResult::JunSeokWin {
                    return (best, best_move);
                }
            },
        }

        if alpha >= beta {
            return (best, best_move);
        }
    }

    (best, best_move)
}

fn print_all_responses(player: Player, starting_board: &mut Board) {
    for legal_move in starting_board.legal_moves().iter() {
        print!("If {:?} does: {:?}, ", player, legal_move);
        let bt = starting_board.board_type;
        starting_board.make_move(*legal_move);
        let (result, best_move) = minimax_alpha_beta(player.opponent(), starting_board, GameResult::PlaceholderJunSeok, GameResult::PlaceholderYeonSeung);
        match best_move {
            Some(x) => {
                println!("{:?} does: {:?}, {:?}", player.opponent(), x, result);
                starting_board.make_move(x);
                starting_board.print();
                starting_board.undo_move(x, bt);
            }
            None => (),
        }
        starting_board.undo_move(*legal_move, bt);
    }
}

fn main() {
    let mut starting_board = Board{
        board: [
            [false,  true,  true,  true, false],
            [false, false, false,  true, false],
            [false, false, false,  true, false],
            [false, false, false, false, false],
        ],
        board_type: None,
    };
    let starting_player = Player::YeonSeung;

    let all_responses = false;
    let best_move = false;
    let legal_moves = false;
    let interactive = true;

    if legal_moves {
        for legal_move in starting_board.legal_moves().iter() {
            println!("{:?}", legal_move);
        }
    }

    if best_move {
        let (result, best_move) = minimax_alpha_beta(starting_player, &mut starting_board, GameResult::PlaceholderJunSeok, GameResult::PlaceholderYeonSeung);
        println!("{:?}", result);
        println!("{:?}", best_move);
        match best_move {
            Some(x) => {
                starting_board.make_move(x);
                starting_board.print();
            },
            None => (),
        }
    }

    if all_responses {
        print_all_responses(starting_player, &mut starting_board);
    }

    if interactive {
        let mut player = starting_player;
        loop {
            let moves = starting_board.legal_moves();
            if moves.is_empty() {
                println!("No moves left, {:?} wins", player.opponent());
                break;
            }
            for (i, legal_move) in moves.iter().enumerate() {
                println!("{} {:?}", i, legal_move);
            }
            println!("It's {:?}'s turn. What move?", player);
            let mut input_move = String::new();
            io::stdin().read_line(&mut input_move).ok().expect("Failed to read line");
            let input_move: usize = input_move.trim().parse().ok().expect("Give me a number");
            let mut found = false;
            for (i, legal_move) in moves.iter().enumerate() {
                if i == input_move {
                    starting_board.make_move(*legal_move);
                    player = player.opponent();
                    found = true;
                }
            }
            if !found {
                println!("Not found. Auto-calculating a move.")
            }
        }
    }
}
<commit_msg>interactive: Add an analyze command<commit_after>use std::io;

#[derive(Copy, Clone, Debug)]
enum Player {
    YeonSeung,
    JunSeok,
}

impl Player {
    fn opponent(&self) -> Player {
        match *self {
            Player::YeonSeung => Player::JunSeok,
            Player::JunSeok => Player::YeonSeung,
        }
    }
}

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
struct Coordinate {
    row: usize,
    col: usize,
}

impl Coordinate {
    fn move_in(&self, dir: Direction, delta: usize) -> Coordinate {
        match dir {
            Direction::Up => Coordinate{row: self.row - delta, col: self.col},
            Direction::Down => Coordinate{row: self.row + delta, col: self.col},
            Direction::Left => Coordinate{row: self.row, col: self.col - delta},
            Direction::Right => Coordinate{row: self.row, col: self.col + delta},
        }
    }
    fn induces_board_type(&self) -> bool {
        *self == Coordinate{row: 1, col: 1} ||
        *self == Coordinate{row: 2, col: 1} ||
        *self == Coordinate{row: 2, col: 0} ||
        *self == Coordinate{row: 3, col: 0}
    }
}

#[derive(Copy, Clone)]
enum Direction {
    Up,
    Down,
    Left,
    Right,
}
const POSSIBLE_DIRECTIONS: [Direction; 4] = [
    Direction::Up,
    Direction::Down,
    Direction::Left,
    Direction::Right,
];

#[derive(Copy, Clone, Debug)]
enum MoveType {
    Single,
    OneUp,
    OneDown,
    OneLeft,
    OneRight,
    TwoUp,
    TwoDown,
    TwoLeft,
    TwoRight,
    UpAndDown,
    LeftAndRight,
}
const POSSIBLE_MOVE_TYPES: [MoveType; 11] = [
    MoveType::Single,
    MoveType::OneUp,
    MoveType::OneDown,
    MoveType::OneLeft,
    MoveType::OneRight,
    MoveType::TwoUp,
    MoveType::TwoDown,
    MoveType::TwoLeft,
    MoveType::TwoRight,
    MoveType::UpAndDown,
    MoveType::LeftAndRight,
];

#[derive(Copy, Clone, Debug)]
struct Move {
    coord: Coordinate,
    move_type: MoveType,
    board_type: Option<BoardType>,
}
impl Move {
    fn coords(&self) -> Vec<Coordinate> {
        match self.move_type {
            MoveType::Single => vec![],
            MoveType::OneUp => vec![self.coord.move_in(Direction::Up, 1)],
            MoveType::OneDown => vec![self.coord.move_in(Direction::Down, 1)],
            MoveType::OneLeft => vec![self.coord.move_in(Direction::Left, 1)],
            MoveType::OneRight => vec![self.coord.move_in(Direction::Right, 1)],
            MoveType::TwoUp => vec![self.coord.move_in(Direction::Up, 1), self.coord.move_in(Direction::Up, 2)],
            MoveType::TwoDown => vec![self.coord.move_in(Direction::Down, 1), self.coord.move_in(Direction::Down, 2)],
            MoveType::TwoLeft => vec![self.coord.move_in(Direction::Left, 1), self.coord.move_in(Direction::Left, 2)],
            MoveType::TwoRight => vec![self.coord.move_in(Direction::Right, 1), self.coord.move_in(Direction::Right, 2)],
            MoveType::UpAndDown => vec![self.coord.move_in(Direction::Up, 1), self.coord.move_in(Direction::Down, 1)],
            MoveType::LeftAndRight => vec![self.coord.move_in(Direction::Left, 1), self.coord.move_in(Direction::Right, 1)],
        }
    }
}

const NUM_COLS: usize = 5;
const NUM_ROWS: usize = 4;

// Hacks for the three states of the lower-left of the board in JunSeok vs YeonSeung game
#[derive(Copy, Clone, Debug)]
enum BoardType {
    Left,
    Middle,
    Right,
}
const POSSIBLE_BOARD_TYPES: [BoardType; 3] = [
    BoardType::Left,
    BoardType::Middle,
    BoardType::Right,
];

type BoardArray = [[bool; NUM_COLS]; NUM_ROWS];
struct Board {
    board: BoardArray,
    board_type: Option<BoardType>,
}

impl Board {
    fn make_move(&mut self, m: Move) {
        match m.board_type {
            Some(_) => self.board_type = m.board_type,
            None => (),
        }
        self.set_squares(m, true)
    }

    fn undo_move(&mut self, m: Move, bt: Option<BoardType>) {
        self.board_type = bt;
        self.set_squares(m, false)
    }

    fn set_squares(&mut self, m: Move, mode: bool) {
        self.board[m.coord.row][m.coord.col] = mode;
        for other_space in m.coords().iter() {
            self.board[other_space.row][other_space.col] = mode;
        }
    }

    fn occupied(&self, c: Coordinate) -> bool {
        self.in_bounds(c) && self.board[c.row][c.col]
    }

    fn in_bounds(&self, c: Coordinate) -> bool {
        // >= 0 is always true due to type limits.
        // c.row >= 0 && c.row < NUM_ROWS && c.col >= 0 && c.col < NUM_COLS
        c.row < NUM_ROWS && c.col < NUM_COLS
    }

    // Assuming that m is a move with an unoccupied coordinate!
    // This doesn't check whether the target squares are occupied.
    // Advantage: It's quicker. Disadvantage: It allows some illegal moves.
    fn move_in_bounds(&self, m: Move) -> bool {
        match m.move_type {
            MoveType::Single => true,
            MoveType::OneUp => m.coord.row >= 1,
            MoveType::OneDown => m.coord.row < NUM_ROWS - 1,
            MoveType::OneLeft => m.coord.col >= 1,
            MoveType::OneRight => m.coord.col < NUM_COLS - 1,
            MoveType::TwoUp => m.coord.row >= 2,
            MoveType::TwoDown => m.coord.row < NUM_ROWS - 2,
            MoveType::TwoLeft => m.coord.col >= 2,
            MoveType::TwoRight => m.coord.col < NUM_COLS - 2,
            MoveType::UpAndDown => m.coord.row >= 1 && m.coord.row < NUM_ROWS - 1,
            MoveType::LeftAndRight => m.coord.col >= 1 && m.coord.col < NUM_COLS - 1,
        }
    }

    // Unfortunately I kind of have to hard-code this.
    fn makes_unsolvable(c: Coordinate, b: Option<BoardType>) -> bool {
        match b {
            Some(BoardType::Left)   => c == Coordinate{row: 2, col: 1} || c == Coordinate{row: 1, col: 1},
            Some(BoardType::Middle) => c == Coordinate{row: 3, col: 0} || c == Coordinate{row: 1, col: 1},
            Some(BoardType::Right)  => c == Coordinate{row: 3, col: 0} || c == Coordinate{row: 2, col: 0},
            None => false,
        }
    }

    fn frontier(&self) -> Vec<Coordinate> {
        let mut results = Vec::new();
        for row in 0..NUM_ROWS {
            for col in 0..NUM_COLS {
                let coord = Coordinate{row: row, col: col};
                if self.occupied(coord) || Board::makes_unsolvable(coord, self.board_type) {
                    continue;
                }
                let mut have_neighbor = false;
                for dir in POSSIBLE_DIRECTIONS.iter() {
                    let new_coord = coord.move_in(*dir, 1);
                    if self.occupied(new_coord) {
                        have_neighbor = true;
                        break;
                    }
                }
                if have_neighbor {
                    results.push(coord);
                }
            }
        }
        results
    }

    fn legal_moves(&self) -> Vec<Move> {
        let mut results = Vec::new();
        for frontier_space in self.frontier().iter() {
            for move_type in POSSIBLE_MOVE_TYPES.iter() {
                let mov = Move{coord: *frontier_space, move_type: *move_type, board_type: None};
                if !self.move_in_bounds(mov) {
                    continue;
                }
                let mut other_space_taken = false;
                let mut induces_board_type = frontier_space.induces_board_type();
                for other_space in mov.coords().iter() {
                    if other_space.induces_board_type() {
                        induces_board_type = true;
                    }
                    if self.occupied(*other_space) || Board::makes_unsolvable(*other_space, self.board_type) {
                        other_space_taken = true;
                        break;
                    }
                }
                if !other_space_taken {
                    if induces_board_type && self.board_type.is_none() {
                        for board_type in POSSIBLE_BOARD_TYPES.iter() {
                            if Board::makes_unsolvable(*frontier_space, Some(*board_type)) {
                                continue;
                            }
                            let mut other_spaces_ok = true;
                            for other_space in mov.coords().iter() {
                                if Board::makes_unsolvable(*other_space, Some(*board_type)) {
                                    other_spaces_ok = false;
                                    break;
                                }
                            }
                            if other_spaces_ok {
                                results.push(Move{coord: mov.coord, move_type: mov.move_type, board_type: Some(*board_type)});
                            }
                        }

                    } else {
                        results.push(mov);
                    }
                }
            }
        }
        results
    }

    fn print(&self) {
        for row in self.board.iter() {
            for col in row.iter() {
                print!("{: >5} ", col);
            }
            println!("");
        }
        println!("{:?}", self.board_type);
    }
}

#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
enum GameResult {
    PlaceholderJunSeok,
    JunSeokWin,
    YeonSeungWin,
    PlaceholderYeonSeung,
}

fn minimax_alpha_beta(player: Player, board: &mut Board, initial_alpha: GameResult, initial_beta: GameResult) -> (GameResult, Option<Move>) {
    let moves = board.legal_moves();
    // There are no more moves, which means my opponent completed the railroad.
    // So I lose.
    if moves.is_empty() {
        return match player {
            Player::YeonSeung => (GameResult::JunSeokWin, None),
            Player::JunSeok => (GameResult::YeonSeungWin, None),
        }
    }
    let mut best = match player {
        Player::YeonSeung => initial_alpha,
        Player::JunSeok => initial_beta,
    };
    let mut alpha = initial_alpha;
    let mut beta = initial_beta;
    let mut best_move = None;

    for possible_move in moves.iter() {
        let bt = board.board_type;
        board.make_move(*possible_move);
        let (reply, _) = minimax_alpha_beta(player.opponent(), board, alpha, beta);
        board.undo_move(*possible_move, bt);

        match player {
            Player::YeonSeung => {
                if reply > best {
                    best = reply;
                    alpha = reply;
                    best_move = Some(*possible_move);
                }
                if best >= GameResult::YeonSeungWin {
                    return (best, best_move);
                }
            },
            Player::JunSeok => {
                if reply < best {
                    best = reply;
                    beta = reply;
                    best_move = Some(*possible_move);
                }
                if best <= GameResult::JunSeokWin {
                    return (best, best_move);
                }
            },
        }

        if alpha >= beta {
            return (best, best_move);
        }
    }

    (best, best_move)
}

fn print_all_responses(player: Player, starting_board: &mut Board) {
    for legal_move in starting_board.legal_moves().iter() {
        print!("If {:?} does: {:?}, ", player, legal_move);
        let bt = starting_board.board_type;
        starting_board.make_move(*legal_move);
        let (result, best_move) = minimax_alpha_beta(player.opponent(), starting_board, GameResult::PlaceholderJunSeok, GameResult::PlaceholderYeonSeung);
        match best_move {
            Some(x) => {
                println!("{:?} does: {:?}, {:?}", player.opponent(), x, result);
                starting_board.make_move(x);
                starting_board.print();
                starting_board.undo_move(x, bt);
            }
            None => (),
        }
        starting_board.undo_move(*legal_move, bt);
    }
}

fn main() {
    let mut starting_board = Board{
        board: [
            [false,  true,  true,  true, false],
            [false, false, false,  true, false],
            [false, false, false,  true, false],
            [false, false, false, false, false],
        ],
        board_type: None,
    };
    let starting_player = Player::YeonSeung;

    let all_responses = false;
    let best_move = false;
    let legal_moves = false;
    let interactive = true;

    if legal_moves {
        for legal_move in starting_board.legal_moves().iter() {
            println!("{:?}", legal_move);
        }
    }

    if best_move {
        let (result, best_move) = minimax_alpha_beta(starting_player, &mut starting_board, GameResult::PlaceholderJunSeok, GameResult::PlaceholderYeonSeung);
        println!("{:?}", result);
        println!("{:?}", best_move);
        match best_move {
            Some(x) => {
                starting_board.make_move(x);
                starting_board.print();
            },
            None => (),
        }
    }

    if all_responses {
        print_all_responses(starting_player, &mut starting_board);
    }

    if interactive {
        let mut player = starting_player;
        loop {
            let moves = starting_board.legal_moves();
            if moves.is_empty() {
                println!("No moves left, {:?} wins", player.opponent());
                break;
            }
            for (i, legal_move) in moves.iter().enumerate() {
                println!("{} {:?}", i, legal_move);
            }
            println!("It's {:?}'s turn. What move?", player);
            let mut input_move = String::new();
            io::stdin().read_line(&mut input_move).ok().expect("Failed to read line");
            if input_move.trim() == "analyze" {
                print_all_responses(player, &mut starting_board);
            } else {
                let input_move: usize = match input_move.trim().parse() {
                    Ok(num) => num,
                    Err(_) => { println!("Not a number."); continue },
                };
                let mut found = false;
                for (i, legal_move) in moves.iter().enumerate() {
                    if i == input_move {
                        starting_board.make_move(*legal_move);
                        player = player.opponent();
                        found = true;
                    }
                }
                if !found {
                    println!("Move not found.");
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::ptr;

use baseline::stub::ensure_stub;
use class::{self, ClassDef, ClassDefId, ClassSize};
use ctxt::SemContext;
use mem;
use object::Header;
use vtable::{DISPLAY_SIZE, VTableBox};
use ty::BuiltinType;

pub fn specialize_type<'ast>(ctxt: &SemContext<'ast>,
                             ty: BuiltinType,
                             specialize_for: SpecializeFor,
                             type_params: &[BuiltinType])
                             -> BuiltinType {
    match ty {
        BuiltinType::ClassTypeParam(_, id) => {
            if specialize_for == SpecializeFor::Class {
                type_params[id.idx()]
            } else {
                ty
            }
        }

        BuiltinType::FctTypeParam(_, id) => {
            if specialize_for == SpecializeFor::Fct {
                type_params[id.idx()]
            } else {
                ty
            }
        }

        BuiltinType::Generic(type_id) => {
            let ty = ctxt.types.borrow().get(type_id);

            let params: Vec<_> = ty.params
                .iter()
                .map(|&t| specialize_type(ctxt, t, specialize_for, type_params))
                .collect();

            let type_id = ctxt.types.borrow_mut().insert(ty.cls_id, params);

            BuiltinType::Generic(type_id)
        }

        _ => ty,
    }
}

#[derive(Copy, Clone, PartialEq, Eq)]
pub enum SpecializeFor {
    Fct,
    Class,
}

pub fn specialize_class_def(ctxt: &SemContext,
                            cls: &class::Class,
                            type_params: &[BuiltinType])
                            -> ClassDefId {
    if let Some(&id) = cls.specializations.borrow().get(type_params) {
        return id;
    }

    create_specialized_class_def(ctxt, cls, type_params)
}

fn create_specialized_class_def(ctxt: &SemContext,
                                cls: &class::Class,
                                type_params: &[BuiltinType])
                                -> ClassDefId {
    let id: ClassDefId = ctxt.class_defs.len().into();

    let old = cls.specializations.borrow_mut().insert(type_params.to_vec(), id);
    assert!(old.is_none());

    ctxt.class_defs
        .push(ClassDef {
                  id: id,
                  cls_id: cls.id,
                  type_params: type_params.to_vec(),
                  parent_id: None,
                  size: ClassSize::Fixed(0),
                  fields: Vec::new(),
                  ref_fields: Vec::new(),
                  vtable: None,
              });

    let mut fields;
    let mut ref_fields;
    let mut size;
    let mut vtable_entries = Vec::new();
    let parent_id;

    if cls.is_array || cls.is_str {
        fields = Vec::new();
        ref_fields = Vec::new();
        size = 0;

        let super_id = cls.parent_class.expect("Array & Str should have super class");
        let sup = ctxt.classes[super_id].borrow();
        let id = specialize_class_def(ctxt, &*sup, &[]);
        parent_id = Some(id);

    } else {
        if let Some(super_id) = cls.parent_class {
            let sup = ctxt.classes[super_id].borrow();
            let id = specialize_class_def(ctxt, &*sup, &[]);
            let cls_def = ctxt.class_defs[id].borrow();

            fields = cls_def.fields.clone();
            ref_fields = cls_def.ref_fields.clone();
            size = match cls_def.size {
                ClassSize::Fixed(size) => size,
                _ => unreachable!(),
            };
            parent_id = Some(id);

            let vtable = sup.vtable.as_ref().unwrap();
            vtable_entries.extend_from_slice(vtable.table());

        } else {
            fields = Vec::with_capacity(cls.fields.len());
            ref_fields = Vec::new();
            size = Header::size();
            parent_id = None;
        };

        for f in &cls.fields {
            let ty = specialize_type(ctxt, f.ty, SpecializeFor::Class, &type_params);
            debug_assert!(!ty.contains_type_param(ctxt));

            let field_size = f.ty.size(ctxt);
            let field_align = f.ty.align(ctxt);

            let offset = mem::align_i32(size, field_align);
            fields.push(offset);

            size = offset + field_size;

            if ty.reference_type() {
                ref_fields.push(offset);
            }
        }

        size = mem::align_i32(size, mem::ptr_width());
    }

    for &mid in &cls.methods {
        let mut fct = ctxt.fcts[mid].borrow_mut();

        if fct.vtable_index.is_some() {
            continue;
        }

        if fct.is_virtual() {
            let vtable_index = if let Some(overrides) = fct.overrides {
                ctxt.fcts[overrides].borrow().vtable_index.unwrap()

            } else {
                let vtable_index = vtable_entries.len();
                vtable_entries.push(ensure_stub(ctxt) as usize);

                vtable_index as u32
            };

            fct.vtable_index = Some(vtable_index);
        }
    }

    let mut cls_def = ctxt.class_defs[id].borrow_mut();
    cls_def.size = ClassSize::Fixed(size);
    cls_def.fields = fields;
    cls_def.ref_fields = ref_fields;
    cls_def.parent_id = parent_id;

    let clsptr = (&*cls_def) as *const class::ClassDef as *mut class::ClassDef;
    let vtable = VTableBox::new(clsptr, &vtable_entries);
    cls_def.vtable = Some(vtable);

    ensure_display(ctxt, &mut cls_def);

    id
}

fn ensure_display<'ast>(ctxt: &SemContext<'ast>, cls_def: &mut ClassDef) -> usize {
    let vtable = cls_def.vtable.as_mut().unwrap();

    // if subtype_display[0] is set, vtable was already initialized
    if !vtable.subtype_display[0].is_null() {
        return vtable.subtype_depth as usize;
    }

    if let Some(parent_id) = cls_def.parent_id {
        let mut parent = ctxt.class_defs[parent_id].borrow_mut();
        let depth = 1 + ensure_display(ctxt, &mut *parent);

        let parent_vtable = parent.vtable.as_ref().unwrap();
        let depth_fixed;

        if depth >= DISPLAY_SIZE {
            depth_fixed = DISPLAY_SIZE;

            vtable.allocate_overflow(depth as usize - DISPLAY_SIZE + 1);

            unsafe {
                if depth > DISPLAY_SIZE {
                    ptr::copy_nonoverlapping(parent_vtable.subtype_overflow,
                                             vtable.subtype_overflow as *mut _,
                                             depth as usize - DISPLAY_SIZE);
                }

                let ptr = vtable
                    .subtype_overflow
                    .offset(depth as isize - DISPLAY_SIZE as isize) as
                          *mut _;

                *ptr = &**vtable as *const _;
            }

        } else {
            depth_fixed = depth;

            vtable.subtype_display[depth] = &**vtable as *const _;
        }

        vtable.subtype_depth = depth as i32;
        vtable.subtype_display[0..depth_fixed].clone_from_slice(&parent_vtable.subtype_display
                                                                     [0..depth_fixed]);

        depth

    } else {
        vtable.subtype_depth = 0;
        vtable.subtype_display[0] = &**vtable as *const _;

        0
    }
}<commit_msg>store dynamic class size for Arrray and Str<commit_after>use std::ptr;

use baseline::stub::ensure_stub;
use class::{self, ClassDef, ClassDefId, ClassSize};
use ctxt::SemContext;
use mem;
use object::Header;
use vtable::{DISPLAY_SIZE, VTableBox};
use ty::BuiltinType;

pub fn specialize_type<'ast>(ctxt: &SemContext<'ast>,
                             ty: BuiltinType,
                             specialize_for: SpecializeFor,
                             type_params: &[BuiltinType])
                             -> BuiltinType {
    match ty {
        BuiltinType::ClassTypeParam(_, id) => {
            if specialize_for == SpecializeFor::Class {
                type_params[id.idx()]
            } else {
                ty
            }
        }

        BuiltinType::FctTypeParam(_, id) => {
            if specialize_for == SpecializeFor::Fct {
                type_params[id.idx()]
            } else {
                ty
            }
        }

        BuiltinType::Generic(type_id) => {
            let ty = ctxt.types.borrow().get(type_id);

            let params: Vec<_> = ty.params
                .iter()
                .map(|&t| specialize_type(ctxt, t, specialize_for, type_params))
                .collect();

            let type_id = ctxt.types.borrow_mut().insert(ty.cls_id, params);

            BuiltinType::Generic(type_id)
        }

        _ => ty,
    }
}

#[derive(Copy, Clone, PartialEq, Eq)]
pub enum SpecializeFor {
    Fct,
    Class,
}

pub fn specialize_class_def(ctxt: &SemContext,
                            cls: &class::Class,
                            type_params: &[BuiltinType])
                            -> ClassDefId {
    if let Some(&id) = cls.specializations.borrow().get(type_params) {
        return id;
    }

    create_specialized_class_def(ctxt, cls, type_params)
}

fn create_specialized_class_def(ctxt: &SemContext,
                                cls: &class::Class,
                                type_params: &[BuiltinType])
                                -> ClassDefId {
    let id: ClassDefId = ctxt.class_defs.len().into();

    let old = cls.specializations.borrow_mut().insert(type_params.to_vec(), id);
    assert!(old.is_none());

    ctxt.class_defs
        .push(ClassDef {
                  id: id,
                  cls_id: cls.id,
                  type_params: type_params.to_vec(),
                  parent_id: None,
                  size: ClassSize::Fixed(0),
                  fields: Vec::new(),
                  ref_fields: Vec::new(),
                  vtable: None,
              });

    let mut fields;
    let mut ref_fields;
    let size;
    let mut vtable_entries = Vec::new();
    let parent_id;

    if cls.is_array || cls.is_str {
        fields = Vec::new();
        ref_fields = Vec::new();

        size = if cls.is_array && type_params[0].reference_type() {
            ClassSize::ObjArray
        } else if cls.is_array {
            ClassSize::Array(type_params[0].size(ctxt))
        } else {
            ClassSize::Str
        };

        let super_id = cls.parent_class.expect("Array & Str should have super class");
        let sup = ctxt.classes[super_id].borrow();
        let id = specialize_class_def(ctxt, &*sup, &[]);
        parent_id = Some(id);

    } else {
        let mut csize;

        if let Some(super_id) = cls.parent_class {
            let sup = ctxt.classes[super_id].borrow();
            let id = specialize_class_def(ctxt, &*sup, &[]);
            let cls_def = ctxt.class_defs[id].borrow();

            fields = cls_def.fields.clone();
            ref_fields = cls_def.ref_fields.clone();
            csize = match cls_def.size {
                ClassSize::Fixed(size) => size,
                _ => unreachable!(),
            };
            parent_id = Some(id);

            let vtable = sup.vtable.as_ref().unwrap();
            vtable_entries.extend_from_slice(vtable.table());

        } else {
            fields = Vec::with_capacity(cls.fields.len());
            ref_fields = Vec::new();
            csize = Header::size();
            parent_id = None;
        };

        for f in &cls.fields {
            let ty = specialize_type(ctxt, f.ty, SpecializeFor::Class, &type_params);
            debug_assert!(!ty.contains_type_param(ctxt));

            let field_size = f.ty.size(ctxt);
            let field_align = f.ty.align(ctxt);

            let offset = mem::align_i32(csize, field_align);
            fields.push(offset);

            csize = offset + field_size;

            if ty.reference_type() {
                ref_fields.push(offset);
            }
        }

        size = ClassSize::Fixed(mem::align_i32(csize, mem::ptr_width()));
    }

    for &mid in &cls.methods {
        let mut fct = ctxt.fcts[mid].borrow_mut();

        if fct.vtable_index.is_some() {
            continue;
        }

        if fct.is_virtual() {
            let vtable_index = if let Some(overrides) = fct.overrides {
                ctxt.fcts[overrides].borrow().vtable_index.unwrap()

            } else {
                let vtable_index = vtable_entries.len();
                vtable_entries.push(ensure_stub(ctxt) as usize);

                vtable_index as u32
            };

            fct.vtable_index = Some(vtable_index);
        }
    }

    let mut cls_def = ctxt.class_defs[id].borrow_mut();
    cls_def.size = size;
    cls_def.fields = fields;
    cls_def.ref_fields = ref_fields;
    cls_def.parent_id = parent_id;

    let clsptr = (&*cls_def) as *const class::ClassDef as *mut class::ClassDef;
    let vtable = VTableBox::new(clsptr, &vtable_entries);
    cls_def.vtable = Some(vtable);

    ensure_display(ctxt, &mut cls_def);

    id
}

fn ensure_display<'ast>(ctxt: &SemContext<'ast>, cls_def: &mut ClassDef) -> usize {
    let vtable = cls_def.vtable.as_mut().unwrap();

    // if subtype_display[0] is set, vtable was already initialized
    if !vtable.subtype_display[0].is_null() {
        return vtable.subtype_depth as usize;
    }

    if let Some(parent_id) = cls_def.parent_id {
        let mut parent = ctxt.class_defs[parent_id].borrow_mut();
        let depth = 1 + ensure_display(ctxt, &mut *parent);

        let parent_vtable = parent.vtable.as_ref().unwrap();
        let depth_fixed;

        if depth >= DISPLAY_SIZE {
            depth_fixed = DISPLAY_SIZE;

            vtable.allocate_overflow(depth as usize - DISPLAY_SIZE + 1);

            unsafe {
                if depth > DISPLAY_SIZE {
                    ptr::copy_nonoverlapping(parent_vtable.subtype_overflow,
                                             vtable.subtype_overflow as *mut _,
                                             depth as usize - DISPLAY_SIZE);
                }

                let ptr = vtable
                    .subtype_overflow
                    .offset(depth as isize - DISPLAY_SIZE as isize) as
                          *mut _;

                *ptr = &**vtable as *const _;
            }

        } else {
            depth_fixed = depth;

            vtable.subtype_display[depth] = &**vtable as *const _;
        }

        vtable.subtype_depth = depth as i32;
        vtable.subtype_display[0..depth_fixed].clone_from_slice(&parent_vtable.subtype_display
                                                                     [0..depth_fixed]);

        depth

    } else {
        vtable.subtype_depth = 0;
        vtable.subtype_display[0] = &**vtable as *const _;

        0
    }
}<|endoftext|>


<commit_before>extern crate compiletest_rs as compiletest;

use std::path::{PathBuf, Path};
use std::io::Write;

fn compile_fail(sysroot: &str) {
    // Disable rustc's new error fomatting. It breaks these tests.
    std::env::remove_var("RUST_NEW_ERROR_FORMAT");
    let flags = format!("--sysroot {} -Dwarnings", sysroot);
    for_all_targets(sysroot, |target| {
        let mut config = compiletest::default_config();
        config.host_rustcflags = Some(flags.clone());
        config.mode = "compile-fail".parse().expect("Invalid mode");
        config.run_lib_path = Path::new(sysroot).join("lib").join("rustlib").join(&target).join("lib");
        config.rustc_path = "target/debug/miri".into();
        config.src_base = PathBuf::from("tests/compile-fail".to_string());
        config.target = target.to_owned();
        config.target_rustcflags = Some(flags.clone());
        compiletest::run_tests(&config);
    });
}

fn run_pass() {
    // Disable rustc's new error fomatting. It breaks these tests.
    std::env::remove_var("RUST_NEW_ERROR_FORMAT");
    let mut config = compiletest::default_config();
    config.mode = "run-pass".parse().expect("Invalid mode");
    config.src_base = PathBuf::from("tests/run-pass".to_string());
    compiletest::run_tests(&config);
}

fn for_all_targets<F: FnMut(String)>(sysroot: &str, mut f: F) {
    for target in std::fs::read_dir(format!("{}/lib/rustlib/", sysroot)).unwrap() {
        let target = target.unwrap();
        if !target.metadata().unwrap().is_dir() {
            continue;
        }
        let target = target.file_name().into_string().unwrap();
        if target == "etc" {
            continue;
        }
        let stderr = std::io::stderr();
        writeln!(stderr.lock(), "running tests for target {}", target).unwrap();
        f(target);
    }
}

#[test]
fn compile_test() {
    // Taken from https://github.com/Manishearth/rust-clippy/pull/911.
    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
    let sysroot = match (home, toolchain) {
        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
        _ => option_env!("RUST_SYSROOT")
            .expect("need to specify RUST_SYSROOT env var or use rustup or multirust")
            .to_owned(),
    };
    compile_fail(&sysroot);
    run_pass();
    for_all_targets(&sysroot, |target| {
        for file in std::fs::read_dir("tests/run-pass").unwrap() {
            let file = file.unwrap();
            if !file.metadata().unwrap().is_file() {
                continue;
            }
            let file = file.path();
            let stderr = std::io::stderr();
            write!(stderr.lock(), "test [miri-pass] {} ", file.to_str().unwrap()).unwrap();
            let mut cmd = std::process::Command::new("target/debug/miri");
            cmd.arg(file);
            cmd.arg("-Dwarnings");
            cmd.arg(format!("--target={}", target));
            let libs = Path::new(&sysroot).join("lib");
            let sysroot = libs.join("rustlib").join(&target).join("lib");
            let paths = std::env::join_paths(&[libs, sysroot]).unwrap();
            cmd.env(compiletest::procsrv::dylib_env_var(), paths);
            match cmd.output() {
                Ok(ref output) if output.status.success() => writeln!(stderr.lock(), "ok").unwrap(),
                Ok(output) => {
                    writeln!(stderr.lock(), "FAILED with exit code {}", output.status.code().unwrap_or(0)).unwrap();
                    writeln!(stderr.lock(), "stdout: \n {}", std::str::from_utf8(&output.stdout).unwrap()).unwrap();
                    writeln!(stderr.lock(), "stderr: \n {}", std::str::from_utf8(&output.stderr).unwrap()).unwrap();
                    panic!("some tests failed");
                }
                Err(e) => {
                    writeln!(stderr.lock(), "FAILED: {}", e).unwrap();
                    panic!("some tests failed");
                },
            }
        }
        let stderr = std::io::stderr();
        writeln!(stderr.lock(), "").unwrap();
    });
}
<commit_msg>compiletest 2.0 uses json errors and doesn't depend on the output format anymore<commit_after>extern crate compiletest_rs as compiletest;

use std::path::{PathBuf, Path};
use std::io::Write;

fn compile_fail(sysroot: &str) {
    let flags = format!("--sysroot {} -Dwarnings", sysroot);
    for_all_targets(sysroot, |target| {
        let mut config = compiletest::default_config();
        config.host_rustcflags = Some(flags.clone());
        config.mode = "compile-fail".parse().expect("Invalid mode");
        config.run_lib_path = Path::new(sysroot).join("lib").join("rustlib").join(&target).join("lib");
        config.rustc_path = "target/debug/miri".into();
        config.src_base = PathBuf::from("tests/compile-fail".to_string());
        config.target = target.to_owned();
        config.target_rustcflags = Some(flags.clone());
        compiletest::run_tests(&config);
    });
}

fn run_pass() {
    let mut config = compiletest::default_config();
    config.mode = "run-pass".parse().expect("Invalid mode");
    config.src_base = PathBuf::from("tests/run-pass".to_string());
    compiletest::run_tests(&config);
}

fn for_all_targets<F: FnMut(String)>(sysroot: &str, mut f: F) {
    for target in std::fs::read_dir(format!("{}/lib/rustlib/", sysroot)).unwrap() {
        let target = target.unwrap();
        if !target.metadata().unwrap().is_dir() {
            continue;
        }
        let target = target.file_name().into_string().unwrap();
        if target == "etc" {
            continue;
        }
        let stderr = std::io::stderr();
        writeln!(stderr.lock(), "running tests for target {}", target).unwrap();
        f(target);
    }
}

#[test]
fn compile_test() {
    // Taken from https://github.com/Manishearth/rust-clippy/pull/911.
    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
    let sysroot = match (home, toolchain) {
        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
        _ => option_env!("RUST_SYSROOT")
            .expect("need to specify RUST_SYSROOT env var or use rustup or multirust")
            .to_owned(),
    };
    compile_fail(&sysroot);
    run_pass();
    for_all_targets(&sysroot, |target| {
        for file in std::fs::read_dir("tests/run-pass").unwrap() {
            let file = file.unwrap();
            if !file.metadata().unwrap().is_file() {
                continue;
            }
            let file = file.path();
            let stderr = std::io::stderr();
            write!(stderr.lock(), "test [miri-pass] {} ", file.to_str().unwrap()).unwrap();
            let mut cmd = std::process::Command::new("target/debug/miri");
            cmd.arg(file);
            cmd.arg("-Dwarnings");
            cmd.arg(format!("--target={}", target));
            let libs = Path::new(&sysroot).join("lib");
            let sysroot = libs.join("rustlib").join(&target).join("lib");
            let paths = std::env::join_paths(&[libs, sysroot]).unwrap();
            cmd.env(compiletest::procsrv::dylib_env_var(), paths);
            match cmd.output() {
                Ok(ref output) if output.status.success() => writeln!(stderr.lock(), "ok").unwrap(),
                Ok(output) => {
                    writeln!(stderr.lock(), "FAILED with exit code {}", output.status.code().unwrap_or(0)).unwrap();
                    writeln!(stderr.lock(), "stdout: \n {}", std::str::from_utf8(&output.stdout).unwrap()).unwrap();
                    writeln!(stderr.lock(), "stderr: \n {}", std::str::from_utf8(&output.stderr).unwrap()).unwrap();
                    panic!("some tests failed");
                }
                Err(e) => {
                    writeln!(stderr.lock(), "FAILED: {}", e).unwrap();
                    panic!("some tests failed");
                },
            }
        }
        let stderr = std::io::stderr();
        writeln!(stderr.lock(), "").unwrap();
    });
}
<|endoftext|>


<commit_before>extern crate reql;
extern crate rayon;

use reql::r;
use reql::commands::Client;
use rayon::prelude::*;

#[test]
fn connection_pool_works() {
    // Setup the connection
    r.connection()
        .set_servers(vec!["localhost:28015", "localhost:28016", "localhost:28017"])
        .set_db("blog")
        .connect()
        .unwrap();

    // Try arbitrary expressions
    r.expr(200).run().unwrap();

    // Create our database if necessary
    r.db_create("blog").run().unwrap();

    // Drop table if nessary
    r.table_drop("users").run().unwrap();

    // Create our table if necessary
    r.table_create("users").run().unwrap();

    // Insert 1 user(s) into the table
    (0..1u32)
        .into_par_iter()
        .enumerate()
        .for_each(|(i, _)| {
            let user = r.object()
                .insert("name", format!("User {}", i))
                .insert("age", i*2)
                .build();
            r.table("users").insert(user).run().unwrap();
        });
}
<commit_msg>Update examples<commit_after>extern crate reql;
extern crate rayon;

use reql::r;
use rayon::prelude::*;

#[test]
fn connection_pool_works() {
    // Setup the connection
    r.connection()
        .set_servers(vec!["localhost:28015", "localhost:28016", "localhost:28017"])
        .set_db("blog")
        .connect()
        .unwrap();

    // Try arbitrary expressions
    r.expr(200).run().unwrap();

    // Create our database if necessary
    r.db_create("blog").run().unwrap();

    // Drop table if nessary
    r.table_drop("users").run().unwrap();

    // Create our table if necessary
    r.table_create("users").run().unwrap();

    // Insert 1 user(s) into the table
    (0..1u32)
        .into_par_iter()
        .enumerate()
        .for_each(|(i, _)| {
            let user = r.object()
                .insert("name", format!("User {}", i))
                .insert("age", i*2)
                .build();
            r.table("users").insert(user).run().unwrap();
        });
}
<|endoftext|>


<commit_before>// Using structs to represent 2D points
// and calculating the Euclidean distance between them

mod pointutils {

    pub struct Point {
        pub x: f64,
        pub y: f64,
    }

    pub fn euclidean(point_a: Point, point_b: Point) -> f64 {
        0.0

    }
}

fn main() {
    let point_a: pointutils::Point = pointutils::Point { x: 0.3, y: 20.0 };
    let point_b: pointutils::Point = pointutils::Point { x: 4.0, y: -0.03 };

    let euclidean_distance = pointutils::euclidean(point_a, point_b);
    // let euclidean_distance = euclidean(point_a, point_b);
    println!("Found distance: {}", euclidean_distance);

}
<commit_msg>Add pow and sqrt functions, return actual result<commit_after>// Using structs to represent 2D points
// and calculating the Euclidean distance between them

mod pointutils {
    use std::num::pow;

    pub struct Point {
        pub x: f64,
        pub y: f64,
    }

    pub fn euclidean(point_a: Point, point_b: Point) -> f64 {
        let value_sq = pow((point_a.x - point_b.x), 2) + pow((point_a.y - point_b.y), 2);
        value_sq.sqrt()
    }
}

fn main() {
    let point_a: pointutils::Point = pointutils::Point { x: 0.3, y: 20.0 };
    let point_b: pointutils::Point = pointutils::Point { x: 4.0, y: -0.03 };

    let euclidean_distance = pointutils::euclidean(point_a, point_b);
    println!("Found distance: {}", euclidean_distance);

}
<|endoftext|>