<commit_before>/*! Functions for changing world and entity state. */

use std::io::prelude::*;
use std::path::Path;
use std::fs::{self, File};
use rand::Rng;
use calx::{Dijkstra, Dir6, HexFov, HexGeom};
use calx_ecs::Entity;
use world::World;
use area;
use location::Location;
use item::Slot;
use components::{CompositeStats, BrainState};
use query::{self, ControlState};

/// Player input action.
#[derive(Copy, Eq, PartialEq, Clone, Debug, RustcEncodable, RustcDecodable)]
pub enum Input {
    /// Take a step in the given direction.
    Step(Dir6),
    /// Melee attack in the given direction.
    Melee(Dir6),
    /// Shoot in the given direction.
    Shoot(Dir6),
    /// Do nothing for a turn.
    Pass,
}

/// Top-level game state update function. Only valid to call if
/// control_state() returned ReadyToUpdate.
pub fn update(w: &mut World) {
    assert!(query::control_state(w) == ControlState::ReadyToUpdate);

    ai_main(w);

    w.flags.tick += 1;
    w.flags.player_acted = false;
}

/// Run AI for all autonomous mobs.
fn ai_main(w: &mut World) {
    let actives: Vec<Entity> = w.ecs.brain.iter().map(|(&e, _)| e).collect();
    for e in actives.into_iter() {
        update_entity(w, e);
    }
}

pub fn update_entity(w: &mut World, e: Entity) {
    if query::is_mob(w, e) && !query::is_player(w, e) && query::ticks_this_frame(w, e) {
        mob_ai(w, e);
    }
}

pub fn mob_ai(w: &mut World, e: Entity) {
    assert!(query::is_mob(w, e));
    assert!(!query::is_player(w, e));
    assert!(query::ticks_this_frame(w, e));

    if query::brain_state(w, e) == Some(BrainState::Asleep) {
        let self_loc = query::location(w, e).unwrap();
        // Mob is inactive, but may wake up if it spots the player.
        if let Some(player_loc) = query::player(w).and_then(|e| query::location(w, e)) {
            // TODO: Line-of-sight, stealth concerns, other enemies than
            // player etc.
            if let Some(d) = player_loc.distance_from(self_loc) {
                if d < 6 {
                    wake_up(w, e);
                }
            }
        }

        return;
    }

    if let Some(p) = query::player(w) {
        let loc = query::location(w, e).expect("no location");

        let vec_to_enemy = loc.v2_at(query::location(w, p).expect("no location"));
        if let Some(v) = vec_to_enemy {
            if v.hex_dist() == 1 {
                // Melee range, hit.
                melee(w, e, Dir6::from_v2(v));
            } else {
                // Walk towards.
                let pathing_depth = 16;
                let pathing = Dijkstra::new(vec![query::location(w, p).expect("no location")],
                                            |&loc| !query::blocks_walk(w, loc),
                                            pathing_depth);

                let steps = pathing.sorted_neighbors(&loc);
                if steps.len() > 0 {
                    step(w,
                         e,
                         loc.dir6_towards(steps[0]).expect("No loc pair orientation"));
                } else {
                    let dir = w.flags.rng.gen();
                    step(w, e, dir);
                    // TODO: Fall asleep if things get boring.
                }
            }
        }
    }
}

/// Give player input. Only valid to call if control_state() returned
/// AwaitingInput.
pub fn input(w: &mut World, input: Input) {
    assert!(query::control_state(w) == ControlState::AwaitingInput);
    let p = query::player(w).expect("No player to receive input");
    match input {
        Input::Step(d) => {
            step(w, p, d);
        }
        Input::Melee(d) => {
            melee(w, p, d);
        }
        Input::Shoot(d) => {
            shoot(w, p, d);
        }
        Input::Pass => {}
    }
    w.flags.player_acted = true;

    // Run one world update cycle right away, so that we don't get awkward
    // single frames rendered where the player has acted and the rest of the
    // world hasn't.
    if query::control_state(w) == ControlState::ReadyToUpdate {
        update(w);
    }
}

/// Try to move the entity in direction.
pub fn step(w: &mut World, e: Entity, dir: Dir6) {
    let target_loc = query::location(w, e).unwrap() + dir.to_v2();
    if query::can_enter(w, e, target_loc) {
        place_entity(w, e, target_loc);
    }
}

/// Fight in a direction.
pub fn melee(w: &mut World, e: Entity, dir: Dir6) {
    unimplemented!();
    /*
    let loc = self.location().expect("no location") + dir.to_v2();
    if let Some(e) = loc.mob_at() {
        let us = self.stats();
        e.damage(us.power + us.attack);
    }
    */
}

pub fn shoot(w: &mut World, e: Entity, dir: Dir6) {
    unimplemented!();
    /*
    let stats = self.stats();

    if stats.ranged_range > 0 {
        action::shoot(self.location().unwrap(), dir, stats.ranged_range, stats.ranged_power);
    }
    */
}

pub fn pick_up(w: &mut World, picker: Entity, item: Entity) -> bool {
    if !query::can_be_picked_up(w, item) {
        return false;
    }

    match query::free_bag_slot(w, picker) {
        Some(slot) => {
            equip(w, item, picker, slot);
            return true;
        }
        // Inventory full.
        None => {
            return false;
        }
    }
}

/// Equip an item to a slot. Slot must be empty.
pub fn equip(w: &mut World, item: Entity, e: Entity, slot: Slot) {
    w.spatial.equip(item, e, slot);
    recompose_stats(w, e)
}

/// Generate composed stats from base stats and the stats of equipped items.
/// This function must be called after any operation that changes the composed
/// stats affecting state of an entity.
pub fn recompose_stats(w: &mut World, e: Entity) {
    let mut stats = query::base_stats(w, e);
    for &slot in [Slot::Body,
                  Slot::Feet,
                  Slot::Head,
                  Slot::Melee,
                  Slot::Ranged,
                  Slot::TrinketF,
                  Slot::TrinketG,
                  Slot::TrinketH,
                  Slot::TrinketI]
                     .iter() {
        if let Some(item) = w.spatial.entity_equipped(e, slot) {
            stats = stats + query::stats(w, item);
        }
    }

    w.ecs.composite_stats.insert(e, CompositeStats(stats));
}

pub fn place_entity(w: &mut World, e: Entity, loc: Location) {
    w.spatial.insert_at(e, loc);
    after_entity_move(w, e);
}

/// Clear map memory of an entity.
pub fn forget_map(w: &mut World, e: Entity) {
    w.ecs.map_memory.get_mut(e).map(|mm| {
        mm.seen.clear();
        mm.remembered.clear();
    });
}

/// Callback when entity moves to a new location.
fn after_entity_move(w: &mut World, e: Entity) {
    let loc = query::location(w, e).expect("Entity must have location for callback");

    do_fov(w, e);

    for item in w.spatial.entities_at(loc).into_iter() {
        if item != e {
            on_step_on(w, e, item);
        }
    }

    if query::is_player(w, e) {
        w.flags.camera = loc;

        if query::terrain(w, loc).is_exit() {
            area::next_level(w);
        }
    }
}

pub fn do_fov(w: &mut World, e: Entity) {
    if !w.ecs.map_memory.contains(e) {
        return;
    }

    if let Some(loc) = query::location(w, e) {
        let sight_range = 12;
        let seen_locs: Vec<Location> = HexFov::new(|pt| query::blocks_sight(w, (loc + pt)),
                                                   sight_range)
                                           .fake_isometric()
                                           .map(|pt| loc + pt)
                                           .collect();
        let mut mm = &mut w.ecs.map_memory[e];
        mm.seen.clear();
        mm.seen.extend(seen_locs.clone().into_iter());
        mm.remembered.extend(seen_locs.into_iter());
    }
}

pub fn on_step_on(w: &mut World, stepper: Entity, item: Entity) {
    if query::is_instant_item(w, item) && query::is_player(w, stepper) {
        unimplemented!();
    }
}

pub fn set_brain_state(w: &mut World, e: Entity, state: BrainState) {
    w.ecs.brain.get_mut(e).map(|b| b.state = state);
}

pub fn wake_up(w: &mut World, e: Entity) {
    if query::brain_state(w, e) == Some(BrainState::Asleep) {
        set_brain_state(w, e, BrainState::Hunting);
    }
}

////////////////////////////////////////////////////////////////////////

static SAVE_FILENAME: &'static str = "magog_save.json";

pub fn save_game(w: &World) {
    // Only save if there's still a living player around.
    if query::game_over(w) {
        return;
    }

    let save_data = w.save();
    File::create(SAVE_FILENAME)
        .unwrap()
        .write_all(&save_data.into_bytes())
        .unwrap();
}

pub fn load_game() -> Result<World, ()> {
    if !save_exists() {
        return Err(());
    }
    let path = Path::new(SAVE_FILENAME);
    let mut save_data = String::new();
    File::open(&path).unwrap().read_to_string(&mut save_data).unwrap();
    // TODO: Informative error message if load fails.
    match World::load(&save_data[..]) {
        Ok(w) => Ok(w),
        _ => Err(()),
    }
}

pub fn _delete_save() {
    let _ = fs::remove_file(SAVE_FILENAME);
}

pub fn save_exists() -> bool {
    fs::metadata(SAVE_FILENAME).is_ok()
}
<commit_msg>Melee is back<commit_after>/*! Functions for changing world and entity state. */

use std::io::prelude::*;
use std::path::Path;
use std::fs::{self, File};
use rand::Rng;
use calx::{Dijkstra, Dir6, HexFov, HexGeom, RngExt};
use calx_ecs::Entity;
use world::World;
use area;
use location::Location;
use item::Slot;
use components::{CompositeStats, BrainState};
use query::{self, ControlState};
use msg;

/// Player input action.
#[derive(Copy, Eq, PartialEq, Clone, Debug, RustcEncodable, RustcDecodable)]
pub enum Input {
    /// Take a step in the given direction.
    Step(Dir6),
    /// Melee attack in the given direction.
    Melee(Dir6),
    /// Shoot in the given direction.
    Shoot(Dir6),
    /// Do nothing for a turn.
    Pass,
}

/// Top-level game state update function. Only valid to call if
/// control_state() returned ReadyToUpdate.
pub fn update(w: &mut World) {
    assert!(query::control_state(w) == ControlState::ReadyToUpdate);

    ai_main(w);

    w.flags.tick += 1;
    w.flags.player_acted = false;
}

/// Run AI for all autonomous mobs.
fn ai_main(w: &mut World) {
    let actives: Vec<Entity> = w.ecs.brain.iter().map(|(&e, _)| e).collect();
    for e in actives.into_iter() {
        update_entity(w, e);
    }
}

pub fn update_entity(w: &mut World, e: Entity) {
    if query::is_mob(w, e) && !query::is_player(w, e) && query::ticks_this_frame(w, e) {
        mob_ai(w, e);
    }
}

pub fn mob_ai(w: &mut World, e: Entity) {
    assert!(query::is_mob(w, e));
    assert!(!query::is_player(w, e));
    assert!(query::ticks_this_frame(w, e));

    if query::brain_state(w, e) == Some(BrainState::Asleep) {
        let self_loc = query::location(w, e).unwrap();
        // Mob is inactive, but may wake up if it spots the player.
        if let Some(player_loc) = query::player(w).and_then(|e| query::location(w, e)) {
            // TODO: Line-of-sight, stealth concerns, other enemies than
            // player etc.
            if let Some(d) = player_loc.distance_from(self_loc) {
                if d < 6 {
                    wake_up(w, e);
                }
            }
        }

        return;
    }

    if let Some(p) = query::player(w) {
        let loc = query::location(w, e).expect("no location");

        let vec_to_enemy = loc.v2_at(query::location(w, p).expect("no location"));
        if let Some(v) = vec_to_enemy {
            if v.hex_dist() == 1 {
                // Melee range, hit.
                melee(w, e, Dir6::from_v2(v));
            } else {
                // Walk towards.
                let pathing_depth = 16;
                let pathing = Dijkstra::new(vec![query::location(w, p).expect("no location")],
                                            |&loc| !query::blocks_walk(w, loc),
                                            pathing_depth);

                let steps = pathing.sorted_neighbors(&loc);
                if steps.len() > 0 {
                    step(w,
                         e,
                         loc.dir6_towards(steps[0]).expect("No loc pair orientation"));
                } else {
                    let dir = w.flags.rng.gen();
                    step(w, e, dir);
                    // TODO: Fall asleep if things get boring.
                }
            }
        }
    }
}

/// Give player input. Only valid to call if control_state() returned
/// AwaitingInput.
pub fn input(w: &mut World, input: Input) {
    assert!(query::control_state(w) == ControlState::AwaitingInput);
    let p = query::player(w).expect("No player to receive input");
    match input {
        Input::Step(d) => {
            step(w, p, d);
        }
        Input::Melee(d) => {
            melee(w, p, d);
        }
        Input::Shoot(d) => {
            shoot(w, p, d);
        }
        Input::Pass => {}
    }
    w.flags.player_acted = true;

    // Run one world update cycle right away, so that we don't get awkward
    // single frames rendered where the player has acted and the rest of the
    // world hasn't.
    if query::control_state(w) == ControlState::ReadyToUpdate {
        update(w);
    }
}

/// Try to move the entity in direction.
pub fn step(w: &mut World, e: Entity, dir: Dir6) {
    let target_loc = query::location(w, e).unwrap() + dir.to_v2();
    if query::can_enter(w, e, target_loc) {
        place_entity(w, e, target_loc);
    }
}

/// Fight in a direction.
pub fn melee(w: &mut World, e: Entity, dir: Dir6) {
    let loc = query::location(w, e).expect("no location") + dir.to_v2();
    if let Some(e) = query::mob_at(w, loc) {
        let us = query::stats(w, e);
        damage(w, e, us.power + us.attack);
    }
}

pub fn shoot(w: &mut World, e: Entity, dir: Dir6) {
    unimplemented!();
    /*
    let stats = self.stats();

    if stats.ranged_range > 0 {
        action::shoot(self.location().unwrap(), dir, stats.ranged_range, stats.ranged_power);
    }
    */
}

pub fn pick_up(w: &mut World, picker: Entity, item: Entity) -> bool {
    if !query::can_be_picked_up(w, item) {
        return false;
    }

    match query::free_bag_slot(w, picker) {
        Some(slot) => {
            equip(w, item, picker, slot);
            return true;
        }
        // Inventory full.
        None => {
            return false;
        }
    }
}

/// Equip an item to a slot. Slot must be empty.
pub fn equip(w: &mut World, item: Entity, e: Entity, slot: Slot) {
    w.spatial.equip(item, e, slot);
    recompose_stats(w, e)
}

/// Generate composed stats from base stats and the stats of equipped items.
/// This function must be called after any operation that changes the composed
/// stats affecting state of an entity.
pub fn recompose_stats(w: &mut World, e: Entity) {
    let mut stats = query::base_stats(w, e);
    for &slot in [Slot::Body,
                  Slot::Feet,
                  Slot::Head,
                  Slot::Melee,
                  Slot::Ranged,
                  Slot::TrinketF,
                  Slot::TrinketG,
                  Slot::TrinketH,
                  Slot::TrinketI]
                     .iter() {
        if let Some(item) = w.spatial.entity_equipped(e, slot) {
            stats = stats + query::stats(w, item);
        }
    }

    w.ecs.composite_stats.insert(e, CompositeStats(stats));
}

pub fn place_entity(w: &mut World, e: Entity, loc: Location) {
    w.spatial.insert_at(e, loc);
    after_entity_move(w, e);
}

/// Clear map memory of an entity.
pub fn forget_map(w: &mut World, e: Entity) {
    w.ecs.map_memory.get_mut(e).map(|mm| {
        mm.seen.clear();
        mm.remembered.clear();
    });
}

/// Callback when entity moves to a new location.
fn after_entity_move(w: &mut World, e: Entity) {
    let loc = query::location(w, e).expect("Entity must have location for callback");

    do_fov(w, e);

    for item in w.spatial.entities_at(loc).into_iter() {
        if item != e {
            on_step_on(w, e, item);
        }
    }

    if query::is_player(w, e) {
        w.flags.camera = loc;

        if query::terrain(w, loc).is_exit() {
            area::next_level(w);
        }
    }
}

pub fn do_fov(w: &mut World, e: Entity) {
    if !w.ecs.map_memory.contains(e) {
        return;
    }

    if let Some(loc) = query::location(w, e) {
        let sight_range = 12;
        let seen_locs: Vec<Location> = HexFov::new(|pt| query::blocks_sight(w, (loc + pt)),
                                                   sight_range)
                                           .fake_isometric()
                                           .map(|pt| loc + pt)
                                           .collect();
        let mut mm = &mut w.ecs.map_memory[e];
        mm.seen.clear();
        mm.seen.extend(seen_locs.clone().into_iter());
        mm.remembered.extend(seen_locs.into_iter());
    }
}

pub fn on_step_on(w: &mut World, stepper: Entity, item: Entity) {
    if query::is_instant_item(w, item) && query::is_player(w, stepper) {
        unimplemented!();
    }
}

pub fn set_brain_state(w: &mut World, e: Entity, state: BrainState) {
    w.ecs.brain.get_mut(e).map(|b| b.state = state);
}

pub fn wake_up(w: &mut World, e: Entity) {
    if query::brain_state(w, e) == Some(BrainState::Asleep) {
        set_brain_state(w, e, BrainState::Hunting);
    }
}

/// Apply damage to entity, subject to damage reduction.
pub fn damage(w: &mut World, e: Entity, mut power: i32) {
    let stats = query::stats(w, e);
    power -= stats.protection;

    if power < 1 {
        // Give damage a bit under the reduction an off-chance to hit.
        // Power that's too low can't do anything though.
        if power >= -5 {
            power = 1;
        } else {
            return;
        }
    }

    // Every five points of power is one certain hit.
    let full = power / 5;
    // The fractional points are one probabilistic hit.
    let partial = (power % 5) as f32 / 5.0;

    let damage = full +
                 if w.flags.rng.with_chance(partial) {
        1
    } else {
        0
    };
    apply_damage(w, e, damage);
}

/// Actually subtract points from the entity's hit points. Called from
/// damage method.
fn apply_damage(w: &mut World, e: Entity, amount: i32) {
    if amount <= 0 {
        return;
    }
    let max_hp = query::max_hp(w, e);

    let is_killed = w.ecs.health.get_mut(e).map_or(false,
                                                   |h| {
                                                       h.wounds += amount;
                                                       h.wounds >= max_hp
                                                   });

    msg::push(::Msg::Damage(e));

    if is_killed {
        kill(w, e);
    }
}

pub fn kill(w: &mut World, e: Entity) {
    unimplemented!();
}

////////////////////////////////////////////////////////////////////////

static SAVE_FILENAME: &'static str = "magog_save.json";

pub fn save_game(w: &World) {
    // Only save if there's still a living player around.
    if query::game_over(w) {
        return;
    }

    let save_data = w.save();
    File::create(SAVE_FILENAME)
        .unwrap()
        .write_all(&save_data.into_bytes())
        .unwrap();
}

pub fn load_game() -> Result<World, ()> {
    if !save_exists() {
        return Err(());
    }
    let path = Path::new(SAVE_FILENAME);
    let mut save_data = String::new();
    File::open(&path).unwrap().read_to_string(&mut save_data).unwrap();
    // TODO: Informative error message if load fails.
    match World::load(&save_data[..]) {
        Ok(w) => Ok(w),
        _ => Err(()),
    }
}

pub fn _delete_save() {
    let _ = fs::remove_file(SAVE_FILENAME);
}

pub fn save_exists() -> bool {
    fs::metadata(SAVE_FILENAME).is_ok()
}
<|endoftext|>


<commit_before>#[test]
fn bar() {
    assert_eq!(4, 4);
}

// Having more than 1 test does seem to make a difference
// (i.e., this calls ptr::swap which having just one test does not).
#[test]
fn baz() {
    assert_eq!(5, 5);
}
<commit_msg>add a test for excluding tests on miri<commit_after>#[test]
fn bar() {
    assert_eq!(4, 4);
}

// Having more than 1 test does seem to make a difference
// (i.e., this calls ptr::swap which having just one test does not).
#[test]
fn baz() {
    assert_eq!(5, 5);
}

// A test that won't work on miri
#[cfg(not(feature = "cargo-miri"))]
#[test]
fn does_not_work_on_miri() {
    let x = 0u8;
    assert!(&x as *const _ as usize % 4 < 4);
}
<|endoftext|>


<commit_before>use super::graph::OwnedGraph;
use super::{ScoreNorm, SimilarityMatrix, WeightedNodeColors};
use graph_io_gml::parse_gml;
use closed01::Closed01;
use asexp::sexp::Sexp;
use petgraph::Directed;
use petgraph::Graph as PetGraph;
use std::f32::{INFINITY, NEG_INFINITY};
use std::fs::File;
use std::io::Read;

fn convert_weight(w: Option<&Sexp>) -> Option<f32> {
    match w {
        Some(s) => s.get_float().map(|f| f as f32),
        None => {
            // use a default
            Some(0.0)
        }
    }
}

fn determine_edge_value_range<T>(g: &PetGraph<T, f32, Directed>) -> (f32, f32) {
    let mut w_min = INFINITY;
    let mut w_max = NEG_INFINITY;
    for i in g.raw_edges() {
        w_min = w_min.min(i.weight);
        w_max = w_max.max(i.weight);
    }
    (w_min, w_max)
}

fn normalize_to_closed01(w: f32, range: (f32, f32)) -> Closed01<f32> {
    assert!(range.1 >= range.0);
    let dist = range.1 - range.0;
    if dist == 0.0 {
        Closed01::zero()
    } else {
        Closed01::new((w - range.0) / dist)
    }
}

pub fn load_graph(graph_file: &str) -> OwnedGraph<f32> {
    let graph_str = {
        let mut graph_file = File::open(graph_file).unwrap();
        let mut graph_str = String::new();
        let _ = graph_file.read_to_string(&mut graph_str).unwrap();
        graph_str
    };

    let graph = parse_gml(
        &graph_str,
        &|node_sexp| -> Option<f32> {
            Some(
                node_sexp
                    .and_then(|se| se.get_float().map(|f| f as f32))
                    .unwrap(),
            )
        },
        &convert_weight,
    ).unwrap();

    let edge_range = determine_edge_value_range(&graph);
    let graph = graph.map(
        |_, nw| nw.clone(),
        |_, &ew| normalize_to_closed01(ew, edge_range),
    );

    OwnedGraph::from_petgraph(&graph)
}

pub fn score_graphs(
    a: &OwnedGraph<f32>,
    b: &OwnedGraph<f32>,
    iters: usize,
    eps: f32,
    edge_score: bool,
) -> f32 {
    let mut s = SimilarityMatrix::new(a, b, WeightedNodeColors);
    s.iterate(iters, eps);
    let assignment = s.optimal_node_assignment();
    if edge_score {
        s.score_outgoing_edge_weights_sum_norm(&assignment, ScoreNorm::MaxDegree)
            .get()
    } else {
        s.score_optimal_sum_norm(Some(&assignment), ScoreNorm::MaxDegree)
            .get()
    }
}
<commit_msg>Replace a tuple by struct MinMax<commit_after>use super::graph::OwnedGraph;
use super::{ScoreNorm, SimilarityMatrix, WeightedNodeColors};
use graph_io_gml::parse_gml;
use closed01::Closed01;
use asexp::sexp::Sexp;
use petgraph::Directed;
use petgraph::Graph as PetGraph;
use std::f32::{INFINITY, NEG_INFINITY};
use std::fs::File;
use std::io::Read;

fn convert_weight(w: Option<&Sexp>) -> Option<f32> {
    match w {
        Some(s) => s.get_float().map(|f| f as f32),
        None => {
            // use a default
            Some(0.0)
        }
    }
}

#[derive(Copy, Clone)]
struct MinMax {
    min: f32,
    max: f32,
}

fn determine_edge_value_range<T>(g: &PetGraph<T, f32, Directed>) -> MinMax {
    let mut min_max = MinMax {
        min: INFINITY,
        max: NEG_INFINITY,
    };
    for i in g.raw_edges() {
        min_max.min = min_max.min.min(i.weight);
        min_max.max = min_max.max.max(i.weight);
    }
    min_max
}

fn normalize_to_closed01(w: f32, range: MinMax) -> Closed01<f32> {
    assert!(range.max >= range.min);
    let dist = range.max - range.min;
    if dist == 0.0 {
        Closed01::zero()
    } else {
        Closed01::new((w - range.min) / dist)
    }
}

pub fn load_graph(graph_file: &str) -> OwnedGraph<f32> {
    let graph_str = {
        let mut graph_file = File::open(graph_file).unwrap();
        let mut graph_str = String::new();
        let _ = graph_file.read_to_string(&mut graph_str).unwrap();
        graph_str
    };

    let graph = parse_gml(
        &graph_str,
        &|node_sexp| -> Option<f32> {
            Some(
                node_sexp
                    .and_then(|se| se.get_float().map(|f| f as f32))
                    .unwrap(),
            )
        },
        &convert_weight,
    ).unwrap();

    let edge_range = determine_edge_value_range(&graph);
    let graph = graph.map(
        |_, nw| nw.clone(),
        |_, &ew| normalize_to_closed01(ew, edge_range),
    );

    OwnedGraph::from_petgraph(&graph)
}

pub fn score_graphs(
    a: &OwnedGraph<f32>,
    b: &OwnedGraph<f32>,
    iters: usize,
    eps: f32,
    edge_score: bool,
) -> f32 {
    let mut s = SimilarityMatrix::new(a, b, WeightedNodeColors);
    s.iterate(iters, eps);
    let assignment = s.optimal_node_assignment();
    if edge_score {
        s.score_outgoing_edge_weights_sum_norm(&assignment, ScoreNorm::MaxDegree)
            .get()
    } else {
        s.score_optimal_sum_norm(Some(&assignment), ScoreNorm::MaxDegree)
            .get()
    }
}
<|endoftext|>


<commit_before>extern mod actors;

use actors::actor::{Actor, ActorRef};
use std::comm::{stream};
use std::task;

#[test]
fn test_actor() {
    let (port, chan) = stream::<~str>();
    let actor_ref = ActorRef::new(chan);

    let actor = Actor::new(port, actor_ref.get_channel());

    do task::spawn {
        actor.start();
    }

    actor_ref.stop();
}
<commit_msg>Add should fail<commit_after>extern mod actors;

use actors::actor::{Actor, ActorRef};
use std::comm::{stream};
use std::task;

#[test]
#[should_fail]
fn test_actor() {
    let (port, chan) = stream::<~str>();
    let actor_ref = ActorRef::new(chan);

    let actor = Actor::new(port, actor_ref.get_channel());

    do task::spawn {
        actor.start();
    };

    actor_ref.stop();
}
<|endoftext|>


<commit_before>use regex::Regex;
use reqwest;
use serde_json;

use web::data::SolrTermSummary;

pub struct Search {
    solr_url: String,
}

#[derive(Deserialize, Debug)]
struct SolrResponse {
    pub docs: Vec<SolrTermSummary>,
}

#[derive(Deserialize, Debug)]
struct SolrResponseContainer {
    pub response: SolrResponse,
}

impl Search {
    pub fn new(solr_url: String) -> Search {
        Search {
            solr_url: solr_url,
        }
    }

    fn get_query_part(&self, words: &Vec<String>) -> String {
        let mut ret = String::new();

        let words_length = words.len();

        for (i, word) in words.iter().enumerate() {
            if i == words_length - 1 {
                ret += &format!("{} {}~0.8 {}*", word, word, word);
            } else {
                ret += &format!("{} {}~0.8 ", word, word);
            }
        }

        ret
    }

    pub fn term_complete(&self, cv_name: &str, q: &str)
                         -> Result<Vec<SolrTermSummary>, reqwest::Error>
    {
        let mut terms_url =
            self.solr_url.to_owned() + "/terms/select?wt=json&q=";

        let termid_re_string = r"(?P<prefix>[\w_]+):(?P<accession>\d+)";
        let termid_re = Regex::new(termid_re_string).unwrap();

        let parent_re_string = r"^\[".to_owned() + termid_re_string + r"\]$";
        let parent_re = Regex::new(&parent_re_string).unwrap();

        let maybe_captures = parent_re.captures(cv_name);

        if let Some(captures) = maybe_captures {
            let prefix = captures.name("prefix").unwrap();
            let accession = captures.name("accession").unwrap();
            terms_url += &format!("(interesting_parents:{}\\:{} OR id:{}\\:{})",
                                  prefix, accession, prefix, accession);
        } else {
            terms_url += "cv_name:";
            terms_url += cv_name;
        }

        if let Some(captures) = termid_re.captures(q) {
            let prefix = captures.name("prefix").unwrap();
            let accession = captures.name("accession").unwrap();
            terms_url += " AND id:";
            terms_url += prefix;
            terms_url += r"\:";
            terms_url += accession;
        } else {
            terms_url += " AND (name:(";

            let clean_words: Vec<String> =
                Regex::new(r"(\w+)").unwrap().captures_iter(q)
                .map(|cap| cap.at(1).unwrap().to_owned()).collect();

            if clean_words.len() == 0 {
                return Ok(vec![]);
            }

            let clean_words_length = clean_words.len();

            for (i, word) in clean_words.iter().enumerate() {
                if i == clean_words_length - 1 {
                    terms_url += &format!("{} {}~0.8 {}*", word, word, word);
                } else {
                    terms_url += &format!("{} {}~0.8 ", word, word);
                }
            }

            let query_part = self.get_query_part(&clean_words);

            terms_url += &format!(")^4 OR close_synonyms:({})^0.2 OR distant_synonyms:({})^0.1)",
                                 query_part, query_part);
        }
        print!("{:?}\n", terms_url);

        let res = reqwest::get(&terms_url)?;

        println!("Status: {}", res.status());
        println!("Headers:\n{}", res.headers());

        match serde_json::from_reader(res) {
            Ok(solr_response_container) => {
                let container: SolrResponseContainer = solr_response_container;
                Ok(container.response.docs)
            },
            Err(err) => {
                panic!(format!("{:?}", err));
            }
        }
    }
}
<commit_msg>Increase the weight of term synonyms<commit_after>use regex::Regex;
use reqwest;
use serde_json;

use web::data::SolrTermSummary;

pub struct Search {
    solr_url: String,
}

#[derive(Deserialize, Debug)]
struct SolrResponse {
    pub docs: Vec<SolrTermSummary>,
}

#[derive(Deserialize, Debug)]
struct SolrResponseContainer {
    pub response: SolrResponse,
}

impl Search {
    pub fn new(solr_url: String) -> Search {
        Search {
            solr_url: solr_url,
        }
    }

    fn get_query_part(&self, words: &Vec<String>) -> String {
        let mut ret = String::new();

        let words_length = words.len();

        for (i, word) in words.iter().enumerate() {
            if i == words_length - 1 {
                ret += &format!("{} {}~0.8 {}*", word, word, word);
            } else {
                ret += &format!("{} {}~0.8 ", word, word);
            }
        }

        ret
    }

    pub fn term_complete(&self, cv_name: &str, q: &str)
                         -> Result<Vec<SolrTermSummary>, reqwest::Error>
    {
        let mut terms_url =
            self.solr_url.to_owned() + "/terms/select?wt=json&q=";

        let termid_re_string = r"(?P<prefix>[\w_]+):(?P<accession>\d+)";
        let termid_re = Regex::new(termid_re_string).unwrap();

        let parent_re_string = r"^\[".to_owned() + termid_re_string + r"\]$";
        let parent_re = Regex::new(&parent_re_string).unwrap();

        let maybe_captures = parent_re.captures(cv_name);

        if let Some(captures) = maybe_captures {
            let prefix = captures.name("prefix").unwrap();
            let accession = captures.name("accession").unwrap();
            terms_url += &format!("(interesting_parents:{}\\:{} OR id:{}\\:{})",
                                  prefix, accession, prefix, accession);
        } else {
            terms_url += "cv_name:";
            terms_url += cv_name;
        }

        if let Some(captures) = termid_re.captures(q) {
            let prefix = captures.name("prefix").unwrap();
            let accession = captures.name("accession").unwrap();
            terms_url += " AND id:";
            terms_url += prefix;
            terms_url += r"\:";
            terms_url += accession;
        } else {
            terms_url += " AND (name:(";

            let clean_words: Vec<String> =
                Regex::new(r"(\w+)").unwrap().captures_iter(q)
                .map(|cap| cap.at(1).unwrap().to_owned()).collect();

            if clean_words.len() == 0 {
                return Ok(vec![]);
            }

            let clean_words_length = clean_words.len();

            for (i, word) in clean_words.iter().enumerate() {
                if i == clean_words_length - 1 {
                    terms_url += &format!("{} {}~0.8 {}*", word, word, word);
                } else {
                    terms_url += &format!("{} {}~0.8 ", word, word);
                }
            }

            let query_part = self.get_query_part(&clean_words);

            terms_url += &format!(") OR close_synonyms:({})^0.8 OR distant_synonyms:({})^0.6)",
                                 query_part, query_part);
        }
        print!("{:?}\n", terms_url);

        let res = reqwest::get(&terms_url)?;

        println!("Status: {}", res.status());
        println!("Headers:\n{}", res.headers());

        match serde_json::from_reader(res) {
            Ok(solr_response_container) => {
                let container: SolrResponseContainer = solr_response_container;
                Ok(container.response.docs)
            },
            Err(err) => {
                panic!(format!("{:?}", err));
            }
        }
    }
}
<|endoftext|>


<commit_before>use rustc_hir as hir;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::Node;
use rustc_middle::hir::map::Map;
use rustc_middle::middle::resolve_lifetime as rl;
use rustc_middle::ty::{self, Region, TyCtxt};

/// This function calls the `visit_ty` method for the parameters
/// corresponding to the anonymous regions. The `nested_visitor.found_type`
/// contains the anonymous type.
///
/// # Arguments
/// region - the anonymous region corresponding to the anon_anon conflict
/// br - the bound region corresponding to the above region which is of type `BrAnon(_)`
///
/// # Example
/// ```
/// fn foo(x: &mut Vec<&u8>, y: &u8)
///    { x.push(y); }
/// ```
/// The function returns the nested type corresponding to the anonymous region
/// for e.g., `&u8` and Vec<`&u8`.
pub(crate) fn find_anon_type(
    tcx: TyCtxt<'tcx>,
    region: Region<'tcx>,
    br: &ty::BoundRegionKind,
) -> Option<(&'tcx hir::Ty<'tcx>, &'tcx hir::FnDecl<'tcx>)> {
    if let Some(anon_reg) = tcx.is_suitable_region(region) {
        let hir_id = tcx.hir().local_def_id_to_hir_id(anon_reg.def_id);
        let fndecl = match tcx.hir().get(hir_id) {
            Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref m, ..), .. })
            | Node::TraitItem(&hir::TraitItem {
                kind: hir::TraitItemKind::Fn(ref m, ..), ..
            })
            | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(ref m, ..), .. }) => {
                &m.decl
            }
            _ => return None,
        };

        fndecl
            .inputs
            .iter()
            .find_map(|arg| find_component_for_bound_region(tcx, arg, br))
            .map(|ty| (ty, &**fndecl))
    } else {
        None
    }
}

// This method creates a FindNestedTypeVisitor which returns the type corresponding
// to the anonymous region.
fn find_component_for_bound_region(
    tcx: TyCtxt<'tcx>,
    arg: &'tcx hir::Ty<'tcx>,
    br: &ty::BoundRegionKind,
) -> Option<&'tcx hir::Ty<'tcx>> {
    let mut nested_visitor = FindNestedTypeVisitor {
        tcx,
        bound_region: *br,
        found_type: None,
        current_index: ty::INNERMOST,
    };
    nested_visitor.visit_ty(arg);
    nested_visitor.found_type
}

// The FindNestedTypeVisitor captures the corresponding `hir::Ty` of the
// anonymous region. The example above would lead to a conflict between
// the two anonymous lifetimes for &u8 in x and y respectively. This visitor
// would be invoked twice, once for each lifetime, and would
// walk the types like &mut Vec<&u8> and &u8 looking for the HIR
// where that lifetime appears. This allows us to highlight the
// specific part of the type in the error message.
struct FindNestedTypeVisitor<'tcx> {
    tcx: TyCtxt<'tcx>,
    // The bound_region corresponding to the Refree(freeregion)
    // associated with the anonymous region we are looking for.
    bound_region: ty::BoundRegionKind,
    // The type where the anonymous lifetime appears
    // for e.g., Vec<`&u8`> and <`&u8`>
    found_type: Option<&'tcx hir::Ty<'tcx>>,
    current_index: ty::DebruijnIndex,
}

impl Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
    type Map = Map<'tcx>;

    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
        NestedVisitorMap::OnlyBodies(self.tcx.hir())
    }

    fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
        match arg.kind {
            hir::TyKind::BareFn(_) => {
                self.current_index.shift_in(1);
                intravisit::walk_ty(self, arg);
                self.current_index.shift_out(1);
                return;
            }

            hir::TyKind::TraitObject(bounds, _) => {
                for bound in bounds {
                    self.current_index.shift_in(1);
                    self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
                    self.current_index.shift_out(1);
                }
            }

            hir::TyKind::Rptr(ref lifetime, _) => {
                // the lifetime of the TyRptr
                let hir_id = lifetime.hir_id;
                match (self.tcx.named_region(hir_id), self.bound_region) {
                    // Find the index of the anonymous region that was part of the
                    // error. We will then search the function parameters for a bound
                    // region at the right depth with the same index
                    (
                        Some(rl::Region::LateBoundAnon(debruijn_index, anon_index)),
                        ty::BrAnon(br_index),
                    ) => {
                        debug!(
                            "LateBoundAnon depth = {:?} anon_index = {:?} br_index={:?}",
                            debruijn_index, anon_index, br_index
                        );
                        if debruijn_index == self.current_index && anon_index == br_index {
                            self.found_type = Some(arg);
                            return; // we can stop visiting now
                        }
                    }

                    // Find the index of the named region that was part of the
                    // error. We will then search the function parameters for a bound
                    // region at the right depth with the same index
                    (Some(rl::Region::EarlyBound(_, id, _)), ty::BrNamed(def_id, _)) => {
                        debug!("EarlyBound id={:?} def_id={:?}", id, def_id);
                        if id == def_id {
                            self.found_type = Some(arg);
                            return; // we can stop visiting now
                        }
                    }

                    // Find the index of the named region that was part of the
                    // error. We will then search the function parameters for a bound
                    // region at the right depth with the same index
                    (
                        Some(rl::Region::LateBound(debruijn_index, id, _)),
                        ty::BrNamed(def_id, _),
                    ) => {
                        debug!(
                            "FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}",
                            debruijn_index
                        );
                        debug!("LateBound id={:?} def_id={:?}", id, def_id);
                        if debruijn_index == self.current_index && id == def_id {
                            self.found_type = Some(arg);
                            return; // we can stop visiting now
                        }
                    }

                    (
                        Some(
                            rl::Region::Static
                            | rl::Region::Free(_, _)
                            | rl::Region::EarlyBound(_, _, _)
                            | rl::Region::LateBound(_, _, _)
                            | rl::Region::LateBoundAnon(_, _),
                        )
                        | None,
                        _,
                    ) => {
                        debug!("no arg found");
                    }
                }
            }
            // Checks if it is of type `hir::TyKind::Path` which corresponds to a struct.
            hir::TyKind::Path(_) => {
                let subvisitor = &mut TyPathVisitor {
                    tcx: self.tcx,
                    found_it: false,
                    bound_region: self.bound_region,
                    current_index: self.current_index,
                };
                intravisit::walk_ty(subvisitor, arg); // call walk_ty; as visit_ty is empty,
                // this will visit only outermost type
                if subvisitor.found_it {
                    self.found_type = Some(arg);
                }
            }
            _ => {}
        }
        // walk the embedded contents: e.g., if we are visiting `Vec<&Foo>`,
        // go on to visit `&Foo`
        intravisit::walk_ty(self, arg);
    }
}

// The visitor captures the corresponding `hir::Ty` of the anonymous region
// in the case of structs ie. `hir::TyKind::Path`.
// This visitor would be invoked for each lifetime corresponding to a struct,
// and would walk the types like Vec<Ref> in the above example and Ref looking for the HIR
// where that lifetime appears. This allows us to highlight the
// specific part of the type in the error message.
struct TyPathVisitor<'tcx> {
    tcx: TyCtxt<'tcx>,
    found_it: bool,
    bound_region: ty::BoundRegionKind,
    current_index: ty::DebruijnIndex,
}

impl Visitor<'tcx> for TyPathVisitor<'tcx> {
    type Map = Map<'tcx>;

    fn nested_visit_map(&mut self) -> NestedVisitorMap<Map<'tcx>> {
        NestedVisitorMap::OnlyBodies(self.tcx.hir())
    }

    fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) {
        match (self.tcx.named_region(lifetime.hir_id), self.bound_region) {
            // the lifetime of the TyPath!
            (Some(rl::Region::LateBoundAnon(debruijn_index, anon_index)), ty::BrAnon(br_index)) => {
                if debruijn_index == self.current_index && anon_index == br_index {
                    self.found_it = true;
                    return;
                }
            }

            (Some(rl::Region::EarlyBound(_, id, _)), ty::BrNamed(def_id, _)) => {
                debug!("EarlyBound id={:?} def_id={:?}", id, def_id);
                if id == def_id {
                    self.found_it = true;
                    return; // we can stop visiting now
                }
            }

            (Some(rl::Region::LateBound(debruijn_index, id, _)), ty::BrNamed(def_id, _)) => {
                debug!("FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}", debruijn_index,);
                debug!("id={:?}", id);
                debug!("def_id={:?}", def_id);
                if debruijn_index == self.current_index && id == def_id {
                    self.found_it = true;
                    return; // we can stop visiting now
                }
            }

            (
                Some(
                    rl::Region::Static
                    | rl::Region::EarlyBound(_, _, _)
                    | rl::Region::LateBound(_, _, _)
                    | rl::Region::LateBoundAnon(_, _)
                    | rl::Region::Free(_, _),
                )
                | None,
                _,
            ) => {
                debug!("no arg found");
            }
        }
    }

    fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
        // ignore nested types
        //
        // If you have a type like `Foo<'a, &Ty>` we
        // are only interested in the immediate lifetimes ('a).
        //
        // Making `visit_ty` empty will ignore the `&Ty` embedded
        // inside, it will get reached by the outer visitor.
        debug!("`Ty` corresponding to a struct is {:?}", arg);
    }
}
<commit_msg>Fix a typo in the `find_anon_type` doc<commit_after>use rustc_hir as hir;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_hir::Node;
use rustc_middle::hir::map::Map;
use rustc_middle::middle::resolve_lifetime as rl;
use rustc_middle::ty::{self, Region, TyCtxt};

/// This function calls the `visit_ty` method for the parameters
/// corresponding to the anonymous regions. The `nested_visitor.found_type`
/// contains the anonymous type.
///
/// # Arguments
/// region - the anonymous region corresponding to the anon_anon conflict
/// br - the bound region corresponding to the above region which is of type `BrAnon(_)`
///
/// # Example
/// ```
/// fn foo(x: &mut Vec<&u8>, y: &u8)
///    { x.push(y); }
/// ```
/// The function returns the nested type corresponding to the anonymous region
/// for e.g., `&u8` and `Vec<&u8>`.
pub(crate) fn find_anon_type(
    tcx: TyCtxt<'tcx>,
    region: Region<'tcx>,
    br: &ty::BoundRegionKind,
) -> Option<(&'tcx hir::Ty<'tcx>, &'tcx hir::FnDecl<'tcx>)> {
    if let Some(anon_reg) = tcx.is_suitable_region(region) {
        let hir_id = tcx.hir().local_def_id_to_hir_id(anon_reg.def_id);
        let fndecl = match tcx.hir().get(hir_id) {
            Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref m, ..), .. })
            | Node::TraitItem(&hir::TraitItem {
                kind: hir::TraitItemKind::Fn(ref m, ..), ..
            })
            | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(ref m, ..), .. }) => {
                &m.decl
            }
            _ => return None,
        };

        fndecl
            .inputs
            .iter()
            .find_map(|arg| find_component_for_bound_region(tcx, arg, br))
            .map(|ty| (ty, &**fndecl))
    } else {
        None
    }
}

// This method creates a FindNestedTypeVisitor which returns the type corresponding
// to the anonymous region.
fn find_component_for_bound_region(
    tcx: TyCtxt<'tcx>,
    arg: &'tcx hir::Ty<'tcx>,
    br: &ty::BoundRegionKind,
) -> Option<&'tcx hir::Ty<'tcx>> {
    let mut nested_visitor = FindNestedTypeVisitor {
        tcx,
        bound_region: *br,
        found_type: None,
        current_index: ty::INNERMOST,
    };
    nested_visitor.visit_ty(arg);
    nested_visitor.found_type
}

// The FindNestedTypeVisitor captures the corresponding `hir::Ty` of the
// anonymous region. The example above would lead to a conflict between
// the two anonymous lifetimes for &u8 in x and y respectively. This visitor
// would be invoked twice, once for each lifetime, and would
// walk the types like &mut Vec<&u8> and &u8 looking for the HIR
// where that lifetime appears. This allows us to highlight the
// specific part of the type in the error message.
struct FindNestedTypeVisitor<'tcx> {
    tcx: TyCtxt<'tcx>,
    // The bound_region corresponding to the Refree(freeregion)
    // associated with the anonymous region we are looking for.
    bound_region: ty::BoundRegionKind,
    // The type where the anonymous lifetime appears
    // for e.g., Vec<`&u8`> and <`&u8`>
    found_type: Option<&'tcx hir::Ty<'tcx>>,
    current_index: ty::DebruijnIndex,
}

impl Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
    type Map = Map<'tcx>;

    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
        NestedVisitorMap::OnlyBodies(self.tcx.hir())
    }

    fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
        match arg.kind {
            hir::TyKind::BareFn(_) => {
                self.current_index.shift_in(1);
                intravisit::walk_ty(self, arg);
                self.current_index.shift_out(1);
                return;
            }

            hir::TyKind::TraitObject(bounds, _) => {
                for bound in bounds {
                    self.current_index.shift_in(1);
                    self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
                    self.current_index.shift_out(1);
                }
            }

            hir::TyKind::Rptr(ref lifetime, _) => {
                // the lifetime of the TyRptr
                let hir_id = lifetime.hir_id;
                match (self.tcx.named_region(hir_id), self.bound_region) {
                    // Find the index of the anonymous region that was part of the
                    // error. We will then search the function parameters for a bound
                    // region at the right depth with the same index
                    (
                        Some(rl::Region::LateBoundAnon(debruijn_index, anon_index)),
                        ty::BrAnon(br_index),
                    ) => {
                        debug!(
                            "LateBoundAnon depth = {:?} anon_index = {:?} br_index={:?}",
                            debruijn_index, anon_index, br_index
                        );
                        if debruijn_index == self.current_index && anon_index == br_index {
                            self.found_type = Some(arg);
                            return; // we can stop visiting now
                        }
                    }

                    // Find the index of the named region that was part of the
                    // error. We will then search the function parameters for a bound
                    // region at the right depth with the same index
                    (Some(rl::Region::EarlyBound(_, id, _)), ty::BrNamed(def_id, _)) => {
                        debug!("EarlyBound id={:?} def_id={:?}", id, def_id);
                        if id == def_id {
                            self.found_type = Some(arg);
                            return; // we can stop visiting now
                        }
                    }

                    // Find the index of the named region that was part of the
                    // error. We will then search the function parameters for a bound
                    // region at the right depth with the same index
                    (
                        Some(rl::Region::LateBound(debruijn_index, id, _)),
                        ty::BrNamed(def_id, _),
                    ) => {
                        debug!(
                            "FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}",
                            debruijn_index
                        );
                        debug!("LateBound id={:?} def_id={:?}", id, def_id);
                        if debruijn_index == self.current_index && id == def_id {
                            self.found_type = Some(arg);
                            return; // we can stop visiting now
                        }
                    }

                    (
                        Some(
                            rl::Region::Static
                            | rl::Region::Free(_, _)
                            | rl::Region::EarlyBound(_, _, _)
                            | rl::Region::LateBound(_, _, _)
                            | rl::Region::LateBoundAnon(_, _),
                        )
                        | None,
                        _,
                    ) => {
                        debug!("no arg found");
                    }
                }
            }
            // Checks if it is of type `hir::TyKind::Path` which corresponds to a struct.
            hir::TyKind::Path(_) => {
                let subvisitor = &mut TyPathVisitor {
                    tcx: self.tcx,
                    found_it: false,
                    bound_region: self.bound_region,
                    current_index: self.current_index,
                };
                intravisit::walk_ty(subvisitor, arg); // call walk_ty; as visit_ty is empty,
                // this will visit only outermost type
                if subvisitor.found_it {
                    self.found_type = Some(arg);
                }
            }
            _ => {}
        }
        // walk the embedded contents: e.g., if we are visiting `Vec<&Foo>`,
        // go on to visit `&Foo`
        intravisit::walk_ty(self, arg);
    }
}

// The visitor captures the corresponding `hir::Ty` of the anonymous region
// in the case of structs ie. `hir::TyKind::Path`.
// This visitor would be invoked for each lifetime corresponding to a struct,
// and would walk the types like Vec<Ref> in the above example and Ref looking for the HIR
// where that lifetime appears. This allows us to highlight the
// specific part of the type in the error message.
struct TyPathVisitor<'tcx> {
    tcx: TyCtxt<'tcx>,
    found_it: bool,
    bound_region: ty::BoundRegionKind,
    current_index: ty::DebruijnIndex,
}

impl Visitor<'tcx> for TyPathVisitor<'tcx> {
    type Map = Map<'tcx>;

    fn nested_visit_map(&mut self) -> NestedVisitorMap<Map<'tcx>> {
        NestedVisitorMap::OnlyBodies(self.tcx.hir())
    }

    fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) {
        match (self.tcx.named_region(lifetime.hir_id), self.bound_region) {
            // the lifetime of the TyPath!
            (Some(rl::Region::LateBoundAnon(debruijn_index, anon_index)), ty::BrAnon(br_index)) => {
                if debruijn_index == self.current_index && anon_index == br_index {
                    self.found_it = true;
                    return;
                }
            }

            (Some(rl::Region::EarlyBound(_, id, _)), ty::BrNamed(def_id, _)) => {
                debug!("EarlyBound id={:?} def_id={:?}", id, def_id);
                if id == def_id {
                    self.found_it = true;
                    return; // we can stop visiting now
                }
            }

            (Some(rl::Region::LateBound(debruijn_index, id, _)), ty::BrNamed(def_id, _)) => {
                debug!("FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}", debruijn_index,);
                debug!("id={:?}", id);
                debug!("def_id={:?}", def_id);
                if debruijn_index == self.current_index && id == def_id {
                    self.found_it = true;
                    return; // we can stop visiting now
                }
            }

            (
                Some(
                    rl::Region::Static
                    | rl::Region::EarlyBound(_, _, _)
                    | rl::Region::LateBound(_, _, _)
                    | rl::Region::LateBoundAnon(_, _)
                    | rl::Region::Free(_, _),
                )
                | None,
                _,
            ) => {
                debug!("no arg found");
            }
        }
    }

    fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
        // ignore nested types
        //
        // If you have a type like `Foo<'a, &Ty>` we
        // are only interested in the immediate lifetimes ('a).
        //
        // Making `visit_ty` empty will ignore the `&Ty` embedded
        // inside, it will get reached by the outer visitor.
        debug!("`Ty` corresponding to a struct is {:?}", arg);
    }
}
<|endoftext|>


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

//! Explicit endian types useful for embedding in structs or reinterpreting data.
//!
//! Each endian type is guarnteed to have the same size and alignment as a regular unsigned primiive
//! of the equal size.
//!
//! # Examples
//!
//! ```
//! # use  data_model::*;
//!   let b: Be32 = From::from(3);
//!   let l: Le32 = From::from(3);
//!
//!   assert_eq!(b.to_native(), 3);
//!   assert_eq!(l.to_native(), 3);
//!   assert!(b == 3);
//!   assert!(l == 3);
//!
//!   let b_trans: u32 = unsafe { std::mem::transmute(b) };
//!   let l_trans: u32 = unsafe { std::mem::transmute(l) };
//!
//!   #[cfg(target_endian = "little")]
//!   assert_eq!(l_trans, 3);
//!   #[cfg(target_endian = "big")]
//!   assert_eq!(b_trans, 3);
//!
//!   assert_ne!(b_trans, l_trans);
//! ```

use std::mem::{align_of, size_of};

use assertions::const_assert;
use serde::{Deserialize, Deserializer, Serialize, Serializer};

use crate::DataInit;

macro_rules! endian_type {
    ($old_type:ident, $new_type:ident, $to_new:ident, $from_new:ident) => {
        /// An integer type of with an explicit endianness.
        ///
        /// See module level documentation for examples.
        #[derive(Copy, Clone, Eq, PartialEq, Debug, Default)]
        pub struct $new_type($old_type);

        impl $new_type {
            fn _assert() {
                const_assert!(align_of::<$new_type>() == align_of::<$old_type>());
                const_assert!(size_of::<$new_type>() == size_of::<$old_type>());
            }

            /// Converts `self` to the native endianness.
            pub fn to_native(self) -> $old_type {
                $old_type::$from_new(self.0)
            }
        }

        unsafe impl DataInit for $new_type {}

        impl PartialEq<$old_type> for $new_type {
            fn eq(&self, other: &$old_type) -> bool {
                self.0 == $old_type::$to_new(*other)
            }
        }

        impl PartialEq<$new_type> for $old_type {
            fn eq(&self, other: &$new_type) -> bool {
                $old_type::$to_new(other.0) == *self
            }
        }

        impl Into<$old_type> for $new_type {
            fn into(self) -> $old_type {
                $old_type::$from_new(self.0)
            }
        }

        impl From<$old_type> for $new_type {
            fn from(v: $old_type) -> $new_type {
                $new_type($old_type::$to_new(v))
            }
        }

        impl Serialize for $new_type {
            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
            where
                S: Serializer,
            {
                self.to_native().serialize(serializer)
            }
        }

        impl<'de> Deserialize<'de> for $new_type {
            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
            where
                D: Deserializer<'de>,
            {
                Ok($old_type::deserialize(deserializer)?.into())
            }
        }
    };
}

endian_type!(u16, Le16, to_le, from_le);
endian_type!(i16, SLe16, to_le, from_le);
endian_type!(u32, Le32, to_le, from_le);
endian_type!(i32, SLe32, to_le, from_le);
endian_type!(u64, Le64, to_le, from_le);
endian_type!(i64, SLe64, to_le, from_le);
endian_type!(usize, LeSize, to_le, from_le);
endian_type!(isize, SLeSize, to_le, from_le);
endian_type!(u16, Be16, to_be, from_be);
endian_type!(i16, SBe16, to_be, from_be);
endian_type!(u32, Be32, to_be, from_be);
endian_type!(i32, SBe32, to_be, from_be);
endian_type!(u64, Be64, to_be, from_be);
endian_type!(i64, SBe64, to_be, from_be);
endian_type!(usize, BeSize, to_be, from_be);
endian_type!(isize, SBeSize, to_be, from_be);

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

    use std::convert::From;
    use std::mem::transmute;

    #[cfg(target_endian = "little")]
    const NATIVE_LITTLE: bool = true;
    #[cfg(target_endian = "big")]
    const NATIVE_LITTLE: bool = false;
    const NATIVE_BIG: bool = !NATIVE_LITTLE;

    macro_rules! endian_test {
        ($old_type:ty, $new_type:ty, $test_name:ident, $native:expr) => {
            mod $test_name {
                use super::*;

                #[allow(overflowing_literals)]
                #[test]
                fn equality() {
                    let v = 0x0123456789ABCDEF as $old_type;
                    let endian_v: $new_type = From::from(v);
                    let endian_into: $old_type = endian_v.into();
                    let endian_transmute: $old_type = unsafe { transmute(endian_v) };

                    if $native {
                        assert_eq!(endian_v, endian_transmute);
                    } else {
                        assert_eq!(endian_v, endian_transmute.swap_bytes());
                    }

                    assert_eq!(v, endian_into);
                    assert!(v == endian_v);
                    assert!(endian_v == v);
                }
            }
        };
    }

    endian_test!(u16, Le16, test_le16, NATIVE_LITTLE);
    endian_test!(i16, SLe16, test_sle16, NATIVE_LITTLE);
    endian_test!(u32, Le32, test_le32, NATIVE_LITTLE);
    endian_test!(i32, SLe32, test_sle32, NATIVE_LITTLE);
    endian_test!(u64, Le64, test_le64, NATIVE_LITTLE);
    endian_test!(i64, SLe64, test_sle64, NATIVE_LITTLE);
    endian_test!(usize, LeSize, test_le_size, NATIVE_LITTLE);
    endian_test!(isize, SLeSize, test_sle_size, NATIVE_LITTLE);
    endian_test!(u16, Be16, test_be16, NATIVE_BIG);
    endian_test!(i16, SBe16, test_sbe16, NATIVE_BIG);
    endian_test!(u32, Be32, test_be32, NATIVE_BIG);
    endian_test!(i32, SBe32, test_sbe32, NATIVE_BIG);
    endian_test!(u64, Be64, test_be64, NATIVE_BIG);
    endian_test!(i64, SBe64, test_sbe64, NATIVE_BIG);
    endian_test!(usize, BeSize, test_be_size, NATIVE_BIG);
    endian_test!(isize, SBeSize, test_sbe_size, NATIVE_BIG);
}
<commit_msg>data_model: Fix clippy error on 1.51.0 related to Into<>.<commit_after>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Explicit endian types useful for embedding in structs or reinterpreting data.
//!
//! Each endian type is guarnteed to have the same size and alignment as a regular unsigned primiive
//! of the equal size.
//!
//! # Examples
//!
//! ```
//! # use  data_model::*;
//!   let b: Be32 = From::from(3);
//!   let l: Le32 = From::from(3);
//!
//!   assert_eq!(b.to_native(), 3);
//!   assert_eq!(l.to_native(), 3);
//!   assert!(b == 3);
//!   assert!(l == 3);
//!
//!   let b_trans: u32 = unsafe { std::mem::transmute(b) };
//!   let l_trans: u32 = unsafe { std::mem::transmute(l) };
//!
//!   #[cfg(target_endian = "little")]
//!   assert_eq!(l_trans, 3);
//!   #[cfg(target_endian = "big")]
//!   assert_eq!(b_trans, 3);
//!
//!   assert_ne!(b_trans, l_trans);
//! ```

use std::mem::{align_of, size_of};

use assertions::const_assert;
use serde::{Deserialize, Deserializer, Serialize, Serializer};

use crate::DataInit;

macro_rules! endian_type {
    ($old_type:ident, $new_type:ident, $to_new:ident, $from_new:ident) => {
        /// An integer type of with an explicit endianness.
        ///
        /// See module level documentation for examples.
        #[derive(Copy, Clone, Eq, PartialEq, Debug, Default)]
        pub struct $new_type($old_type);

        impl $new_type {
            fn _assert() {
                const_assert!(align_of::<$new_type>() == align_of::<$old_type>());
                const_assert!(size_of::<$new_type>() == size_of::<$old_type>());
            }

            /// Converts `self` to the native endianness.
            pub fn to_native(self) -> $old_type {
                $old_type::$from_new(self.0)
            }
        }

        unsafe impl DataInit for $new_type {}

        impl PartialEq<$old_type> for $new_type {
            fn eq(&self, other: &$old_type) -> bool {
                self.0 == $old_type::$to_new(*other)
            }
        }

        impl PartialEq<$new_type> for $old_type {
            fn eq(&self, other: &$new_type) -> bool {
                $old_type::$to_new(other.0) == *self
            }
        }

        impl From<$new_type> for $old_type {
            fn from(v: $new_type) -> $old_type {
                $old_type::$from_new(v.0)
            }
        }

        impl From<$old_type> for $new_type {
            fn from(v: $old_type) -> $new_type {
                $new_type($old_type::$to_new(v))
            }
        }

        impl Serialize for $new_type {
            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
            where
                S: Serializer,
            {
                self.to_native().serialize(serializer)
            }
        }

        impl<'de> Deserialize<'de> for $new_type {
            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
            where
                D: Deserializer<'de>,
            {
                Ok($old_type::deserialize(deserializer)?.into())
            }
        }
    };
}

endian_type!(u16, Le16, to_le, from_le);
endian_type!(i16, SLe16, to_le, from_le);
endian_type!(u32, Le32, to_le, from_le);
endian_type!(i32, SLe32, to_le, from_le);
endian_type!(u64, Le64, to_le, from_le);
endian_type!(i64, SLe64, to_le, from_le);
endian_type!(usize, LeSize, to_le, from_le);
endian_type!(isize, SLeSize, to_le, from_le);
endian_type!(u16, Be16, to_be, from_be);
endian_type!(i16, SBe16, to_be, from_be);
endian_type!(u32, Be32, to_be, from_be);
endian_type!(i32, SBe32, to_be, from_be);
endian_type!(u64, Be64, to_be, from_be);
endian_type!(i64, SBe64, to_be, from_be);
endian_type!(usize, BeSize, to_be, from_be);
endian_type!(isize, SBeSize, to_be, from_be);

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

    use std::convert::From;
    use std::mem::transmute;

    #[cfg(target_endian = "little")]
    const NATIVE_LITTLE: bool = true;
    #[cfg(target_endian = "big")]
    const NATIVE_LITTLE: bool = false;
    const NATIVE_BIG: bool = !NATIVE_LITTLE;

    macro_rules! endian_test {
        ($old_type:ty, $new_type:ty, $test_name:ident, $native:expr) => {
            mod $test_name {
                use super::*;

                #[allow(overflowing_literals)]
                #[test]
                fn equality() {
                    let v = 0x0123456789ABCDEF as $old_type;
                    let endian_v: $new_type = From::from(v);
                    let endian_into: $old_type = endian_v.into();
                    let endian_transmute: $old_type = unsafe { transmute(endian_v) };

                    if $native {
                        assert_eq!(endian_v, endian_transmute);
                    } else {
                        assert_eq!(endian_v, endian_transmute.swap_bytes());
                    }

                    assert_eq!(v, endian_into);
                    assert!(v == endian_v);
                    assert!(endian_v == v);
                }
            }
        };
    }

    endian_test!(u16, Le16, test_le16, NATIVE_LITTLE);
    endian_test!(i16, SLe16, test_sle16, NATIVE_LITTLE);
    endian_test!(u32, Le32, test_le32, NATIVE_LITTLE);
    endian_test!(i32, SLe32, test_sle32, NATIVE_LITTLE);
    endian_test!(u64, Le64, test_le64, NATIVE_LITTLE);
    endian_test!(i64, SLe64, test_sle64, NATIVE_LITTLE);
    endian_test!(usize, LeSize, test_le_size, NATIVE_LITTLE);
    endian_test!(isize, SLeSize, test_sle_size, NATIVE_LITTLE);
    endian_test!(u16, Be16, test_be16, NATIVE_BIG);
    endian_test!(i16, SBe16, test_sbe16, NATIVE_BIG);
    endian_test!(u32, Be32, test_be32, NATIVE_BIG);
    endian_test!(i32, SBe32, test_sbe32, NATIVE_BIG);
    endian_test!(u64, Be64, test_be64, NATIVE_BIG);
    endian_test!(i64, SBe64, test_sbe64, NATIVE_BIG);
    endian_test!(usize, BeSize, test_be_size, NATIVE_BIG);
    endian_test!(isize, SBeSize, test_sbe_size, NATIVE_BIG);
}
<|endoftext|>


<commit_before>extern crate bazel_protos;
extern crate boxfuture;
extern crate bytes;
extern crate clap;
extern crate fs;
extern crate futures;
extern crate hashing;
extern crate protobuf;

use boxfuture::{Boxable, BoxFuture};
use bytes::Bytes;
use clap::{App, Arg, SubCommand};
use fs::{GetFileDigest, ResettablePool, Snapshot, Store, VFS};
use futures::future::{self, Future, join_all};
use hashing::{Digest, Fingerprint};
use protobuf::Message;
use std::error::Error;
use std::fs::File;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::process::exit;
use std::sync::Arc;
use std::time::Duration;

#[derive(Debug)]
enum ExitCode {
  UnknownError = 1,
  NotFound = 2,
}

#[derive(Debug)]
struct ExitError(pub String, pub ExitCode);

impl From<String> for ExitError {
  fn from(s: String) -> Self {
    ExitError(s, ExitCode::UnknownError)
  }
}

fn main() {
  match execute(
    App::new("fs_util")
      .subcommand(
        SubCommand::with_name("file")
          .subcommand(
            SubCommand::with_name("cat")
              .about("Output the contents of a file by fingerprint.")
              .arg(Arg::with_name("fingerprint").required(true).takes_value(
                true,
              ))
              .arg(Arg::with_name("size_bytes").required(true).takes_value(
                true,
              )),
          )
          .subcommand(
            SubCommand::with_name("save")
              .about(
                "Ingest a file by path, which allows it to be used in Directories/Snapshots. \
Outputs a fingerprint of its contents and its size in bytes, separated by a space.",
              )
              .arg(Arg::with_name("path").required(true).takes_value(true)),
          ),
      )
      .subcommand(
        SubCommand::with_name("directory")
          .subcommand(
            SubCommand::with_name("materialize")
              .about(
                "Materialize a directory by fingerprint to the filesystem. \
Destination must not exist before this command is run.",
              )
              .arg(Arg::with_name("fingerprint").required(true).takes_value(
                true,
              ))
              .arg(Arg::with_name("size_bytes").required(true).takes_value(
                true,
              ))
              .arg(Arg::with_name("destination").required(true).takes_value(
                true,
              )),
          )
          .subcommand(
            SubCommand::with_name("save")
              .about(
                "Ingest a directory recursively. Saves all files found therein and saves Directory \
protos for each directory found. Outputs a fingerprint of the canonical top-level Directory proto \
and the size of the serialized proto in bytes, separated by a space.",
              )
              .arg(
                Arg::with_name("globs")
                  .required(true)
                  .takes_value(true)
                  .multiple(true)
                  .help(
                    "globs matching the files and directories which should be included in the \
directory, relative to the root.",
                  ),
              )
                .arg(Arg::with_name("root").long("root").required(true).takes_value(true).help(
                  "Root under which the globs live. The Directory proto produced will be relative \
to this directory.",
                )),
          )
          .subcommand(
            SubCommand::with_name("cat-proto")
              .about(
                "Output the bytes of a serialized Directory proto addressed by fingerprint.",
              )
              .arg(
                Arg::with_name("output-format")
                  .long("output-format")
                  .takes_value(true)
                  .default_value("binary")
                  .possible_values(&["binary", "text"]),
              )
              .arg(Arg::with_name("fingerprint").required(true).takes_value(
                true,
              ))
              .arg(Arg::with_name("size_bytes").required(true).takes_value(
                true,
              )),
          ),
      )
      .subcommand(
        SubCommand::with_name("cat")
          .about(
            "Output the contents of a file or Directory proto addressed by fingerprint.",
          )
          .arg(Arg::with_name("fingerprint").required(true).takes_value(
            true,
          ))
          .arg(Arg::with_name("size_bytes").required(true).takes_value(
            true,
          )),
      )
      .arg(
        Arg::with_name("local-store-path")
          .takes_value(true)
          .long("local-store-path")
          .required(true),
      )
        .arg(
          Arg::with_name("server-address")
              .takes_value(true)
              .long("server-address")
              .required(false)
        )
      .get_matches(),
  ) {
    Ok(_) => {}
    Err(err) => {
      eprintln!("{}", err.0);
      exit(err.1 as i32)
    }
  };
}

fn execute(top_match: clap::ArgMatches) -> Result<(), ExitError> {
  let store_dir = top_match.value_of("local-store-path").unwrap();
  let pool = Arc::new(ResettablePool::new("fsutil-pool-".to_string()));
  let store = {
    let store_result = match top_match.value_of("server-address") {
      Some(cas_address) => {
        Store::with_remote(
          store_dir,
          pool.clone(),
          cas_address,
          1,
          10 * 1024 * 1024,
          Duration::from_secs(30),
        )
      }
      None => Store::local_only(store_dir, pool.clone()),
    };
    let store = store_result.map_err(|e| {
      format!(
        "Failed to open/create store for directory {}: {}",
        store_dir,
        e
      )
    })?;
    Arc::new(store)
  };

  match top_match.subcommand() {
    ("file", Some(sub_match)) => {
      match sub_match.subcommand() {
        ("cat", Some(args)) => {
          let fingerprint = Fingerprint::from_hex_string(args.value_of("fingerprint").unwrap())?;
          let size_bytes = args
            .value_of("size_bytes")
            .unwrap()
            .parse::<usize>()
            .expect("size_bytes must be a non-negative number");
          let digest = Digest(fingerprint, size_bytes);
          let write_result = store
            .load_file_bytes_with(digest, |bytes| io::stdout().write_all(&bytes).unwrap())
            .wait()?;
          write_result.ok_or_else(|| {
            ExitError(
              format!("File with digest {:?} not found", digest),
              ExitCode::NotFound,
            )
          })
        }
        ("save", Some(args)) => {
          let path = PathBuf::from(args.value_of("path").unwrap());
          // Canonicalize path to guarantee that a relative path has a parent.
          let posix_fs = make_posix_fs(
            path
              .canonicalize()
              .map_err(|e| {
                format!("Error canonicalizing path {:?}: {}", path, e.description())
              })?
              .parent()
              .ok_or_else(|| {
                format!("File being saved must have parent but {:?} did not", path)
              })?,
            pool,
          );
          let file = posix_fs
            .stat(PathBuf::from(path.file_name().unwrap()))
            .unwrap();
          match file {
            fs::Stat::File(f) => {
              let digest = FileSaver {
                store: store,
                posix_fs: Arc::new(posix_fs),
              }.digest(&f)
                .wait()
                .unwrap();
              Ok(println!("{} {}", digest.0, digest.1))
            }
            o => Err(
              format!(
                "Tried to save file {:?} but it was not a file, was a {:?}",
                path,
                o
              ).into(),
            ),
          }

        }
        (_, _) => unimplemented!(),
      }
    }
    ("directory", Some(sub_match)) => {
      match sub_match.subcommand() {
        ("materialize", Some(args)) => {
          let destination = PathBuf::from(args.value_of("destination").unwrap());
          let fingerprint = Fingerprint::from_hex_string(args.value_of("fingerprint").unwrap())?;
          let size_bytes = args
            .value_of("size_bytes")
            .unwrap()
            .parse::<usize>()
            .expect("size_bytes must be a non-negative number");
          let digest = Digest(fingerprint, size_bytes);
          materialize_directory(store, destination, digest).wait()
        }
        ("save", Some(args)) => {
          let posix_fs = Arc::new(make_posix_fs(args.value_of("root").unwrap(), pool));
          let digest = posix_fs
            .expand(fs::PathGlobs::create(
              &args
                .values_of("globs")
                .unwrap()
                .map(|s| s.to_string())
                .collect::<Vec<String>>(),
              &[],
            )?)
            .map_err(|e| format!("Error expanding globs: {}", e.description()))
            .and_then(move |paths| {
              Snapshot::from_path_stats(
                store.clone(),
                Arc::new(FileSaver {
                  store: store.clone(),
                  posix_fs: posix_fs,
                }),
                paths,
              )
            })
            .map(|snapshot| snapshot.digest.unwrap())
            .wait()?;
          Ok(println!("{} {}", digest.0, digest.1))
        }
        ("cat-proto", Some(args)) => {
          let fingerprint = Fingerprint::from_hex_string(args.value_of("fingerprint").unwrap())?;
          let size_bytes = args
            .value_of("size_bytes")
            .unwrap()
            .parse::<usize>()
            .expect("size_bytes must be a non-negative number");
          let digest = Digest(fingerprint, size_bytes);
          let proto_bytes = match args.value_of("output-format").unwrap() {
            "binary" => {
              store.load_directory(digest).wait().map(|maybe_d| {
                maybe_d.map(|d| d.write_to_bytes().unwrap())
              })
            }
            "text" => {
              store.load_directory(digest).wait().map(|maybe_p| {
                maybe_p.map(|p| format!("{:?}\n", p).as_bytes().to_vec())
              })
            }
            format => Err(format!(
              "Unexpected value of --output-format arg: {}",
              format
            )),
          }?;
          match proto_bytes {
            Some(bytes) => {
              io::stdout().write(&bytes).unwrap();
              Ok(())
            }
            None => Err(ExitError(
              format!("Directory with digest {:?} not found", digest),
              ExitCode::NotFound,
            )),
          }
        }
        (_, _) => unimplemented!(),
      }
    }
    ("cat", Some(args)) => {
      let fingerprint = Fingerprint::from_hex_string(args.value_of("fingerprint").unwrap())?;
      let size_bytes = args
        .value_of("size_bytes")
        .unwrap()
        .parse::<usize>()
        .expect("size_bytes must be a non-negative number");
      let digest = Digest(fingerprint, size_bytes);
      let v = match store.load_file_bytes_with(digest, |bytes| bytes).wait()? {
        None => {
          store
            .load_directory(digest)
            .map(|maybe_dir| {
              maybe_dir.map(|dir| {
                Bytes::from(dir.write_to_bytes().expect(
                  "Error serializing Directory proto",
                ))
              })
            })
            .wait()?
        }
        some => some,
      };
      match v {
        Some(bytes) => {
          io::stdout().write(&bytes).unwrap();
          Ok(())
        }
        None => Err(ExitError(
          format!("Digest {:?} not found", digest),
          ExitCode::NotFound,
        )),
      }
    }

    (_, _) => unimplemented!(),
  }
}

fn make_posix_fs<P: AsRef<Path>>(root: P, pool: Arc<ResettablePool>) -> fs::PosixFS {
  fs::PosixFS::new(&root, pool, vec![]).unwrap()
}

struct FileSaver {
  store: Arc<Store>,
  posix_fs: Arc<fs::PosixFS>,
}

impl GetFileDigest<String> for FileSaver {
  fn digest(&self, file: &fs::File) -> BoxFuture<Digest, String> {
    let file_copy = file.clone();
    let store = self.store.clone();
    self
      .posix_fs
      .read_file(&file)
      .map_err(move |err| {
        format!("Error reading file {:?}: {}", file_copy, err.description())
      })
      .and_then(move |content| store.store_file_bytes(content.content, true))
      .to_boxed()
  }
}

fn materialize_directory(
  store: Arc<Store>,
  destination: PathBuf,
  digest: Digest,
) -> BoxFuture<(), ExitError> {
  let mkdir = make_clean_dir(&destination).map_err(|e| {
    format!(
      "Error making directory {:?}: {:?}",
      destination,
      e,
    ).into()
  });
  match mkdir {
    Ok(()) => {}
    Err(e) => return future::err(e).to_boxed(),
  };
  store
    .load_directory(digest)
    .map_err(|e| e.into())
    .and_then(move |directory_opt| {
      directory_opt.ok_or_else(|| {
        ExitError(
          format!("Directory with digest {:?} not found", digest),
          ExitCode::NotFound,
        )
      })
    })
    .and_then(move |directory| {
      let file_futures = directory
        .get_files()
        .iter()
        .map(|file_node| {
          let store = store.clone();
          let path = destination.join(file_node.get_name());
          let digest: Digest = file_node.get_digest().into();
          materialize_file(store, path, digest)
        })
        .collect::<Vec<_>>();
      let directory_futures = directory
        .get_directories()
        .iter()
        .map(|directory_node| {
          let store = store.clone();
          let path = destination.join(directory_node.get_name());
          let digest: Digest = directory_node.get_digest().into();
          materialize_directory(store, path, digest)
        })
        .collect::<Vec<_>>();
      join_all(file_futures)
        .join(join_all(directory_futures))
        .map(|_| ())
    })
    .to_boxed()
}

fn materialize_file(
  store: Arc<Store>,
  destination: PathBuf,
  digest: Digest,
) -> BoxFuture<(), ExitError> {
  store
    .load_file_bytes_with(digest, move |bytes| {
      File::create(&destination)
        .and_then(|mut f| f.write_all(&bytes))
        .map_err(|e| {
          format!("Error writing file {:?}: {}", destination, e.description())
        })
    })
    .map_err(|e| e.into())
    .and_then(move |write_result| match write_result {
      Some(Ok(())) => Ok(()),
      Some(Err(e)) => Err(e.into()),
      None => {
        Err(ExitError(
          format!("File with digest {:?} not found", digest),
          ExitCode::NotFound,
        ))
      }
    })
    .to_boxed()
}

fn make_clean_dir(path: &Path) -> Result<(), io::Error> {
  let parent = path.parent().ok_or_else(|| {
    io::Error::new(io::ErrorKind::NotFound, format!("{:?} had no parent", path))
  })?;
  std::fs::create_dir_all(parent)?;
  std::fs::create_dir(path)
}
<commit_msg>fs_util writes to remote CAS if it's present (#5378)<commit_after>extern crate bazel_protos;
extern crate boxfuture;
extern crate bytes;
extern crate clap;
extern crate fs;
extern crate futures;
extern crate hashing;
extern crate protobuf;

use boxfuture::{Boxable, BoxFuture};
use bytes::Bytes;
use clap::{App, Arg, SubCommand};
use fs::{GetFileDigest, ResettablePool, Snapshot, Store, VFS};
use futures::future::{self, Future, join_all};
use hashing::{Digest, Fingerprint};
use protobuf::Message;
use std::error::Error;
use std::fs::File;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::process::exit;
use std::sync::Arc;
use std::time::Duration;

#[derive(Debug)]
enum ExitCode {
  UnknownError = 1,
  NotFound = 2,
}

#[derive(Debug)]
struct ExitError(pub String, pub ExitCode);

impl From<String> for ExitError {
  fn from(s: String) -> Self {
    ExitError(s, ExitCode::UnknownError)
  }
}

fn main() {
  match execute(
    App::new("fs_util")
      .subcommand(
        SubCommand::with_name("file")
          .subcommand(
            SubCommand::with_name("cat")
              .about("Output the contents of a file by fingerprint.")
              .arg(Arg::with_name("fingerprint").required(true).takes_value(
                true,
              ))
              .arg(Arg::with_name("size_bytes").required(true).takes_value(
                true,
              )),
          )
          .subcommand(
            SubCommand::with_name("save")
              .about(
                "Ingest a file by path, which allows it to be used in Directories/Snapshots. \
Outputs a fingerprint of its contents and its size in bytes, separated by a space.",
              )
              .arg(Arg::with_name("path").required(true).takes_value(true)),
          ),
      )
      .subcommand(
        SubCommand::with_name("directory")
          .subcommand(
            SubCommand::with_name("materialize")
              .about(
                "Materialize a directory by fingerprint to the filesystem. \
Destination must not exist before this command is run.",
              )
              .arg(Arg::with_name("fingerprint").required(true).takes_value(
                true,
              ))
              .arg(Arg::with_name("size_bytes").required(true).takes_value(
                true,
              ))
              .arg(Arg::with_name("destination").required(true).takes_value(
                true,
              )),
          )
          .subcommand(
            SubCommand::with_name("save")
              .about(
                "Ingest a directory recursively. Saves all files found therein and saves Directory \
protos for each directory found. Outputs a fingerprint of the canonical top-level Directory proto \
and the size of the serialized proto in bytes, separated by a space.",
              )
              .arg(
                Arg::with_name("globs")
                  .required(true)
                  .takes_value(true)
                  .multiple(true)
                  .help(
                    "globs matching the files and directories which should be included in the \
directory, relative to the root.",
                  ),
              )
                .arg(Arg::with_name("root").long("root").required(true).takes_value(true).help(
                  "Root under which the globs live. The Directory proto produced will be relative \
to this directory.",
                )),
          )
          .subcommand(
            SubCommand::with_name("cat-proto")
              .about(
                "Output the bytes of a serialized Directory proto addressed by fingerprint.",
              )
              .arg(
                Arg::with_name("output-format")
                  .long("output-format")
                  .takes_value(true)
                  .default_value("binary")
                  .possible_values(&["binary", "text"]),
              )
              .arg(Arg::with_name("fingerprint").required(true).takes_value(
                true,
              ))
              .arg(Arg::with_name("size_bytes").required(true).takes_value(
                true,
              )),
          ),
      )
      .subcommand(
        SubCommand::with_name("cat")
          .about(
            "Output the contents of a file or Directory proto addressed by fingerprint.",
          )
          .arg(Arg::with_name("fingerprint").required(true).takes_value(
            true,
          ))
          .arg(Arg::with_name("size_bytes").required(true).takes_value(
            true,
          )),
      )
      .arg(
        Arg::with_name("local-store-path")
          .takes_value(true)
          .long("local-store-path")
          .required(true),
      )
        .arg(
          Arg::with_name("server-address")
              .takes_value(true)
              .long("server-address")
              .required(false)
        )
      .get_matches(),
  ) {
    Ok(_) => {}
    Err(err) => {
      eprintln!("{}", err.0);
      exit(err.1 as i32)
    }
  };
}

fn execute(top_match: clap::ArgMatches) -> Result<(), ExitError> {
  let store_dir = top_match.value_of("local-store-path").unwrap();
  let pool = Arc::new(ResettablePool::new("fsutil-pool-".to_string()));
  let (store, store_has_remote) = {
    let (store_result, store_has_remote) = match top_match.value_of("server-address") {
      Some(cas_address) => {
        (
          Store::with_remote(
            store_dir,
            pool.clone(),
            cas_address,
            1,
            10 * 1024 * 1024,
            Duration::from_secs(30),
          ),
          true,
        )
      }
      None => (Store::local_only(store_dir, pool.clone()), false),
    };
    let store = store_result.map_err(|e| {
      format!(
        "Failed to open/create store for directory {}: {}",
        store_dir,
        e
      )
    })?;
    (Arc::new(store), store_has_remote)
  };

  match top_match.subcommand() {
    ("file", Some(sub_match)) => {
      match sub_match.subcommand() {
        ("cat", Some(args)) => {
          let fingerprint = Fingerprint::from_hex_string(args.value_of("fingerprint").unwrap())?;
          let size_bytes = args
            .value_of("size_bytes")
            .unwrap()
            .parse::<usize>()
            .expect("size_bytes must be a non-negative number");
          let digest = Digest(fingerprint, size_bytes);
          let write_result = store
            .load_file_bytes_with(digest, |bytes| io::stdout().write_all(&bytes).unwrap())
            .wait()?;
          write_result.ok_or_else(|| {
            ExitError(
              format!("File with digest {:?} not found", digest),
              ExitCode::NotFound,
            )
          })
        }
        ("save", Some(args)) => {
          let path = PathBuf::from(args.value_of("path").unwrap());
          // Canonicalize path to guarantee that a relative path has a parent.
          let posix_fs = make_posix_fs(
            path
              .canonicalize()
              .map_err(|e| {
                format!("Error canonicalizing path {:?}: {}", path, e.description())
              })?
              .parent()
              .ok_or_else(|| {
                format!("File being saved must have parent but {:?} did not", path)
              })?,
            pool,
          );
          let file = posix_fs
            .stat(PathBuf::from(path.file_name().unwrap()))
            .unwrap();
          match file {
            fs::Stat::File(f) => {
              let digest = FileSaver {
                store: store.clone(),
                posix_fs: Arc::new(posix_fs),
              }.digest(&f)
                .wait()
                .unwrap();
              if store_has_remote {
                store.ensure_remote_has_recursive(vec![digest]).wait()?;
              }
              Ok(println!("{} {}", digest.0, digest.1))
            }
            o => Err(
              format!(
                "Tried to save file {:?} but it was not a file, was a {:?}",
                path,
                o
              ).into(),
            ),
          }

        }
        (_, _) => unimplemented!(),
      }
    }
    ("directory", Some(sub_match)) => {
      match sub_match.subcommand() {
        ("materialize", Some(args)) => {
          let destination = PathBuf::from(args.value_of("destination").unwrap());
          let fingerprint = Fingerprint::from_hex_string(args.value_of("fingerprint").unwrap())?;
          let size_bytes = args
            .value_of("size_bytes")
            .unwrap()
            .parse::<usize>()
            .expect("size_bytes must be a non-negative number");
          let digest = Digest(fingerprint, size_bytes);
          materialize_directory(store, destination, digest).wait()
        }
        ("save", Some(args)) => {
          let posix_fs = Arc::new(make_posix_fs(args.value_of("root").unwrap(), pool));
          let store_copy = store.clone();
          let digest = posix_fs
            .expand(fs::PathGlobs::create(
              &args
                .values_of("globs")
                .unwrap()
                .map(|s| s.to_string())
                .collect::<Vec<String>>(),
              &[],
            )?)
            .map_err(|e| format!("Error expanding globs: {}", e.description()))
            .and_then(move |paths| {
              Snapshot::from_path_stats(
                store_copy.clone(),
                Arc::new(FileSaver {
                  store: store_copy,
                  posix_fs: posix_fs,
                }),
                paths,
              )
            })
            .map(|snapshot| snapshot.digest.unwrap())
            .wait()?;
          if store_has_remote {
            store.ensure_remote_has_recursive(vec![digest]).wait()?;
          }
          Ok(println!("{} {}", digest.0, digest.1))
        }
        ("cat-proto", Some(args)) => {
          let fingerprint = Fingerprint::from_hex_string(args.value_of("fingerprint").unwrap())?;
          let size_bytes = args
            .value_of("size_bytes")
            .unwrap()
            .parse::<usize>()
            .expect("size_bytes must be a non-negative number");
          let digest = Digest(fingerprint, size_bytes);
          let proto_bytes = match args.value_of("output-format").unwrap() {
            "binary" => {
              store.load_directory(digest).wait().map(|maybe_d| {
                maybe_d.map(|d| d.write_to_bytes().unwrap())
              })
            }
            "text" => {
              store.load_directory(digest).wait().map(|maybe_p| {
                maybe_p.map(|p| format!("{:?}\n", p).as_bytes().to_vec())
              })
            }
            format => Err(format!(
              "Unexpected value of --output-format arg: {}",
              format
            )),
          }?;
          match proto_bytes {
            Some(bytes) => {
              io::stdout().write(&bytes).unwrap();
              Ok(())
            }
            None => Err(ExitError(
              format!("Directory with digest {:?} not found", digest),
              ExitCode::NotFound,
            )),
          }
        }
        (_, _) => unimplemented!(),
      }
    }
    ("cat", Some(args)) => {
      let fingerprint = Fingerprint::from_hex_string(args.value_of("fingerprint").unwrap())?;
      let size_bytes = args
        .value_of("size_bytes")
        .unwrap()
        .parse::<usize>()
        .expect("size_bytes must be a non-negative number");
      let digest = Digest(fingerprint, size_bytes);
      let v = match store.load_file_bytes_with(digest, |bytes| bytes).wait()? {
        None => {
          store
            .load_directory(digest)
            .map(|maybe_dir| {
              maybe_dir.map(|dir| {
                Bytes::from(dir.write_to_bytes().expect(
                  "Error serializing Directory proto",
                ))
              })
            })
            .wait()?
        }
        some => some,
      };
      match v {
        Some(bytes) => {
          io::stdout().write(&bytes).unwrap();
          Ok(())
        }
        None => Err(ExitError(
          format!("Digest {:?} not found", digest),
          ExitCode::NotFound,
        )),
      }
    }

    (_, _) => unimplemented!(),
  }
}

fn make_posix_fs<P: AsRef<Path>>(root: P, pool: Arc<ResettablePool>) -> fs::PosixFS {
  fs::PosixFS::new(&root, pool, vec![]).unwrap()
}

struct FileSaver {
  store: Arc<Store>,
  posix_fs: Arc<fs::PosixFS>,
}

impl GetFileDigest<String> for FileSaver {
  fn digest(&self, file: &fs::File) -> BoxFuture<Digest, String> {
    let file_copy = file.clone();
    let store = self.store.clone();
    self
      .posix_fs
      .read_file(&file)
      .map_err(move |err| {
        format!("Error reading file {:?}: {}", file_copy, err.description())
      })
      .and_then(move |content| store.store_file_bytes(content.content, true))
      .to_boxed()
  }
}

fn materialize_directory(
  store: Arc<Store>,
  destination: PathBuf,
  digest: Digest,
) -> BoxFuture<(), ExitError> {
  let mkdir = make_clean_dir(&destination).map_err(|e| {
    format!(
      "Error making directory {:?}: {:?}",
      destination,
      e,
    ).into()
  });
  match mkdir {
    Ok(()) => {}
    Err(e) => return future::err(e).to_boxed(),
  };
  store
    .load_directory(digest)
    .map_err(|e| e.into())
    .and_then(move |directory_opt| {
      directory_opt.ok_or_else(|| {
        ExitError(
          format!("Directory with digest {:?} not found", digest),
          ExitCode::NotFound,
        )
      })
    })
    .and_then(move |directory| {
      let file_futures = directory
        .get_files()
        .iter()
        .map(|file_node| {
          let store = store.clone();
          let path = destination.join(file_node.get_name());
          let digest: Digest = file_node.get_digest().into();
          materialize_file(store, path, digest)
        })
        .collect::<Vec<_>>();
      let directory_futures = directory
        .get_directories()
        .iter()
        .map(|directory_node| {
          let store = store.clone();
          let path = destination.join(directory_node.get_name());
          let digest: Digest = directory_node.get_digest().into();
          materialize_directory(store, path, digest)
        })
        .collect::<Vec<_>>();
      join_all(file_futures)
        .join(join_all(directory_futures))
        .map(|_| ())
    })
    .to_boxed()
}

fn materialize_file(
  store: Arc<Store>,
  destination: PathBuf,
  digest: Digest,
) -> BoxFuture<(), ExitError> {
  store
    .load_file_bytes_with(digest, move |bytes| {
      File::create(&destination)
        .and_then(|mut f| f.write_all(&bytes))
        .map_err(|e| {
          format!("Error writing file {:?}: {}", destination, e.description())
        })
    })
    .map_err(|e| e.into())
    .and_then(move |write_result| match write_result {
      Some(Ok(())) => Ok(()),
      Some(Err(e)) => Err(e.into()),
      None => {
        Err(ExitError(
          format!("File with digest {:?} not found", digest),
          ExitCode::NotFound,
        ))
      }
    })
    .to_boxed()
}

fn make_clean_dir(path: &Path) -> Result<(), io::Error> {
  let parent = path.parent().ok_or_else(|| {
    io::Error::new(io::ErrorKind::NotFound, format!("{:?} had no parent", path))
  })?;
  std::fs::create_dir_all(parent)?;
  std::fs::create_dir(path)
}
<|endoftext|>


<commit_before>extern crate core;

use self::core::fmt::Show;
use matchers::matcher::Matcher;

pub struct Lt<T> {
    value: T,
    file_line: (&'static str, uint)
}

impl<T: PartialOrd + Show> Matcher<T> for Lt<T> {
    fn assert_check(&self, expected: T) -> bool {
        expected < self.value
    }

    fn msg(&self, expected: T) -> String {
        format!("Expected {} to be less than {} but it was not.", exptected, self.value)
    }

    fn negated_msg(&self, expected: T) -> String {
        format!("Expected {} NOT to be less than {} but it was.", expexted, self.value)
    }

    fn get_file_line(&self) -> (&'static str, uint) {
        self.file_line
    }
}

pub fn be_lt<T: PartialOrd + Show>(value: T, file_line: (&'static str, uint)) -> Box<Lt<T>> {
    box Lt { value: value, file_line: file_line }
}

#[macro_export]
pub macro_rules! be_lt(
    ($value:expr) => (
        be_lt($value, (file!(), expand_line!()))
    );
)
<commit_msg> fix typo<commit_after>extern crate core;

use self::core::fmt::Show;
use matchers::matcher::Matcher;

pub struct Lt<T> {
    value: T,
    file_line: (&'static str, uint)
}

impl<T: PartialOrd + Show> Matcher<T> for Lt<T> {
    fn assert_check(&self, expected: T) -> bool {
        expected < self.value
    }

    fn msg(&self, expected: T) -> String {
        format!("Expected {} to be less than {} but it was not.", expected, self.value)
    }

    fn negated_msg(&self, expected: T) -> String {
        format!("Expected {} NOT to be less than {} but it was.", expected, self.value)
    }

    fn get_file_line(&self) -> (&'static str, uint) {
        self.file_line
    }
}

pub fn be_lt<T: PartialOrd + Show>(value: T, file_line: (&'static str, uint)) -> Box<Lt<T>> {
    box Lt { value: value, file_line: file_line }
}

#[macro_export]
pub macro_rules! be_lt(
    ($value:expr) => (
        be_lt($value, (file!(), expand_line!()))
    );
)
<|endoftext|>