<commit_before>use time::get_time;
use player::Player;
use player::PlayerType;
use arena::Arena;
use super::enums;
use super::moves;
use super::resolve;
use super::pokemon_token::PokemonToken;
use super::movedex::Movedex;
use super::moves::Technique;
use self::rand::{Rng, thread_rng};
use self::regex::Regex;

extern crate rand;
extern crate regex;

#[derive(Debug)]
enum MoveName {
    disable,
    teleport
}

pub fn test(){
    println!("Unique");
    for entry in Movedex::new().get_entries() {
         if entry.get_category() == enums::MoveCategory::Unique {
             println!("{:?}: {:?} - {:?}", entry.get_id(), entry.get_name(), entry.get_type());
         }
    }
}

pub fn test2(){
    println!("Unique");
    for entry in Movedex::new().get_entries() {
         if entry.get_category() == enums::MoveCategory::Unique {
             println!("{:?}", entry.get_name());
         }
    }
}

pub fn unique(attack: &Technique, name: &str, move_type: enums::Types, mut user: PokemonToken, target: PokemonToken, attacker: &mut Player, defender: &mut Player, arena: &mut Arena) {
    let movedex = Movedex::new();
    let mut rng = thread_rng();

    // target.get_moves(dex.move_by_id());
    // match dex.get_entries() {
    match name {
        "disable" => {
            println!("disable" );
        },
        "teleport" => {
            println!("teleport");
        },
        "mimic" => {
            let attack = movedex.move_by_id(defender.get_last_move().unwrap().0.get_id()).unwrap();
            attack.resolve(arena, 1);
        },
        "focus-energy" => {
        },
        "metronome" => {
            let random = rng.gen_range(1, 616);
            let attack = movedex.move_by_id(random).unwrap();
            attack.resolve(arena, 1);
        },
        "mirror-move" => {
            let attack = movedex.move_by_id(defender.get_last_move().unwrap().0.get_id()).unwrap();
            attack.resolve(arena, 1);
        },
        "nature-power" => {
            match arena.get_current_effect().0 {
                enums::Types::Normal => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "tri-attack" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                enums::Types::Flying => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "air-slash" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                enums::Types::Ground => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "earth_power" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                enums::Types::Rock => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "power_gem" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                enums::Types::Fire => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "lava_plume" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                enums::Types::Water => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "hydro_pump" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                enums::Types::Grass => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "energy-ball" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                enums::Types::Electric => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "thunderbolt" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                enums::Types::Ice => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "ice_beam" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                _ => {},
            }
        },
        // "transform" => {
        // },
        "splash" => {
            if arena.get_current_effect().0 == enums::Types::Flying{
                println!("The attack can not be used because {:?} is activated.", enums::Types::Flying);
            }else{
                println!("Nothing happens...");
            }
        },
        "rest" => {
            for entry in Movedex::new().get_entries() {
                if entry.get_name() == "rest" {
                    ////Fehler muss noch behofen werden
                    //let mut user_clone = moves::get_user(1, arena).clone();
                    // resolve::ailment("rest",
                    //                  entry.get_type(),
                    //                  entry.get_ailment(),
                    //                  100,
                    //                  user,
                    //                  target,
                    //                  defender);
                }
            }

        },
        "conversion" => {
            user.set_type(0, attack.get_type());
        },
        "spite" => {
            // defender.get_last_move().unwrap().0.get_power_points();
            // target.decrement_ap();
        },
        "sleep-talk" => {
            if attacker.is_asleep(){
                attacker.get_attack(0);
            }
        },
        // "conversion-2" => {
        // },
        // "substitute" => {
        // },
        // "sketch" => {
        // },
        // "spider-web" => {
        // },
        // "mind-reader" => {
        // },
        // "curse" => {
        // },
        // "protect" => {
        // },
        // "belly-drum" => {
        // },
        // "destiny-bond" => {
        // },
        // "detect" => {
        // },
        // "lock-on" => {
        // },
        // "endure" => {
        // },
        // "mean-look" => {
        // },
        // "heal-bell" => {
        // },
        // "pain-split" => {
        // },
        // "baton-pass" => {
        // },
        // "encore" => {
        // },
        // "psych-up" => {
        // },
        // "future-sight" => {
        // },
        // "stockpile" => {
        // },
        // "memento" => {
        // },
        // "follow-me" => {
        // },
        // "taunt" => {
        // },
        // "helping-hand" => {
        // },
        // "trick" => {
        // },
        // "role-play" => {
        // },
        // "wish" => {
        // },
        // "assist" => {
        // },
        // "magic-coat" => {
        // },
        // "recycle" => {
        // },
        // "skill-swap" => {
        // },
        // "imprison" => {
        // },
        // "refresh" => {
        // },
        // "grudge" => {
        // },
        // "snatch" => {
        // },
        // "camouflage" => {
        // },
        // "aromatherapy" => {
        // },
        // "block" => {
        // },
        // "doom-desire" => {
        // },
        // "healing-wish" => {
        // },
        // "acupressure" => {
        // },
        // "psycho-shift" => {
        // },
        // "power-trick" => {
        // },
        // "gastro-acid" => {
        // },
        // "copycat" => {
        // },
        // "power-swap" => {
        // },
        // "guard-swap" => {
        // },
        // "worry-seed" => {
        // },
        // "heart-swap" => {
        // },
        // "aqua-ring" => {
        // },
        // "magnet-rise" => {
        // },
        // "switcheroo" => {
        // },
        // "defog" => {
        // },
        // "lunar-dance" => {
        // },
        // "guard-split" => {
        // },
        // "power-split" => {
        // },
        // "rage-powder" => {
        // },
        // "soak" => {
        // },
        // "simple-beam" => {
        // },
        // "entrainment" => {
        // },
        // "after-you" => {
        // },
        // "ally-switch" => {
        // },
        // "shell-smash" => {
        // },
        // "quash" => {
        // },
        // "reflect-type" => {
        // },
        // "bestow" => {
        // },
        // "trick-or-treat" => {
        // },
        // "forests-curse" => {
        // },
        // "topsy-turvy" => {
        // },
        // "flower-shield" => {
        // },
        // "electrify" => {
        // },
        // "kings-shield" => {
        // },
        // "spiky-shield" => {
        // },
        // "powder" => {
        // },
        // "happy-hour" => {
        // },
        // "celebrate" => {
        // },
        // "hold-hands" => {
        // },
        _ => {},
    };
}
<commit_msg>fix error, add attack<commit_after>use time::get_time;
use player::Player;
use player::PlayerType;
use player;
use arena::Arena;
use super::enums;
use super::moves;
use super::resolve;
use super::pokemon_token::PokemonToken;
use super::movedex::Movedex;
use super::moves::Technique;
use self::rand::{Rng, thread_rng};
use self::regex::Regex;

extern crate rand;
extern crate regex;

#[derive(Debug)]
enum MoveName {
    disable,
    teleport
}

pub fn test(){
    println!("Unique");
    for entry in Movedex::new().get_entries() {
         if entry.get_category() == enums::MoveCategory::Unique {
             println!("{:?}: {:?} - {:?}", entry.get_id(), entry.get_name(), entry.get_type());
         }
    }
}

pub fn test2(){
    println!("Unique");
    for entry in Movedex::new().get_entries() {
         if entry.get_category() == enums::MoveCategory::Unique {
             println!("{:?}", entry.get_name());
         }
    }
}

pub fn unique(attack: &Technique, name: &str, move_type: enums::Types, mut user: PokemonToken, mut target: PokemonToken, attacker: &mut Player, defender: &mut Player, arena: &mut Arena) {
    let movedex = Movedex::new();
    let mut rng = thread_rng();

    // target.get_moves(dex.move_by_id());
    // match dex.get_entries() {
    match name {
        "disable" => {
            println!("disable" );
        },
        "teleport" => {
            println!("teleport");
        },
        "mimic" => {
            let attack = movedex.move_by_id(defender.get_last_move().unwrap().0.get_id()).unwrap();
            attack.resolve(arena, 1);
        },
        "focus-energy" => {
        },
        "metronome" => {
            let random = rng.gen_range(1, 616);
            let attack = movedex.move_by_id(random).unwrap();
            attack.resolve(arena, 1);
        },
        "mirror-move" => {
            let attack = movedex.move_by_id(defender.get_last_move().unwrap().0.get_id()).unwrap();
            attack.resolve(arena, 1);
        },
        "nature-power" => {
            match arena.get_current_effect().0 {
                enums::Types::Normal => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "tri-attack" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                enums::Types::Flying => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "air-slash" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                enums::Types::Ground => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "earth_power" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                enums::Types::Rock => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "power_gem" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                enums::Types::Fire => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "lava_plume" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                enums::Types::Water => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "hydro_pump" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                enums::Types::Grass => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "energy-ball" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                enums::Types::Electric => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "thunderbolt" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                enums::Types::Ice => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "ice_beam" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                _ => {},
            }
        },
        // "transform" => {
        // },
        "splash" => {
            if arena.get_current_effect().0 == enums::Types::Flying{
                println!("The attack can not be used because {:?} is activated.", enums::Types::Flying);
            }else{
                println!("Nothing happens...");
            }
        },
        "rest" => {
            for entry in Movedex::new().get_entries() {
                if entry.get_name() == "rest" {
                    ////Fehler muss noch behofen werden
                    //let mut user_clone = moves::get_user(1, arena).clone();
                    // resolve::ailment("rest",
                    //                  entry.get_type(),
                    //                  entry.get_ailment(),
                    //                  100,
                    //                  user,
                    //                  &mut target,
                    //                  defender);
                }
            }

        },
        "conversion" => {
            user.set_type(0, attack.get_type());
        },
        "spite" => {
            // defender.get_last_move().unwrap().0.get_power_points();
            // target.decrement_ap();
        },
        "sleep-talk" => {
            struct AllMoves {
                one: String,
                two: String,
                three: String,
                four: String,
            }
            // let one: String;;
            let mut moves = AllMoves {one: "".to_string(), two: "".to_string(), three: "".to_string(), four: "".to_string(), };
            if user.is_asleep(){
                if attacker.get_attack(&player::AttackSlot::One).get_name() != "sleep-talk"{
                    // moves.one = attacker.get_attack(&player::AttackSlot::One).get_name();
                    moves.one = attacker.get_attack(&player::AttackSlot::One).get_name().to_string();
                }
                if attacker.get_attack(&player::AttackSlot::Two).get_name() != "sleep-talk"{
                    moves.two = attacker.get_attack(&player::AttackSlot::Two).get_name().to_string();
                }
                if attacker.get_attack(&player::AttackSlot::Three).get_name() != "sleep-talk"{
                    moves.three = attacker.get_attack(&player::AttackSlot::Three).get_name().to_string();
                }
                if attacker.get_attack(&player::AttackSlot::Four).get_name() != "sleep-talk"{
                    moves.four = attacker.get_attack(&player::AttackSlot::Four).get_name().to_string();
                }

                let mut random = rng.gen_range(1, 4);
                loop {
                    match random {
                        1 => {
                            if moves.one == "".to_string(){
                                random = rng.gen_range(2, 4);
                            }else{
                                let attack = movedex.move_by_id(attacker.get_attack(&player::AttackSlot::One).get_id()).unwrap();
                                attack.resolve(arena, 1);
                                break
                            }
                        },
                        2 => {
                            if moves.two == "".to_string(){
                                random = rng.gen_range(1, 4);
                            }else{
                                let attack = movedex.move_by_id(attacker.get_attack(&player::AttackSlot::Two).get_id()).unwrap();
                                attack.resolve(arena, 1);
                                break
                            }
                        },
                        3 => {
                            if moves.three == "".to_string(){
                                random = rng.gen_range(1, 4);
                            }else{
                                let attack = movedex.move_by_id(attacker.get_attack(&player::AttackSlot::Three).get_id()).unwrap();
                                attack.resolve(arena, 1);
                                break
                            }
                        },
                        4 => {
                            if moves.four == "".to_string(){
                                random = rng.gen_range(1, 3);
                            }else{
                                let attack = movedex.move_by_id(attacker.get_attack(&player::AttackSlot::Four).get_id()).unwrap();
                                attack.resolve(arena, 1);
                                break
                            }
                        },
                        _=> { random = rng.gen_range(1, 4); }
                    }
                }
            }
        },
        "celebrate" => {
            println!("{:?} disappears and then rises out of a birthday present that falls into the picture from above.", user.get_name());
        },
        "powder" => {
            if target.get_types().0 == enums::Types::Grass || target.get_types().1 == enums::Types::Grass{
                println!("{:?} has no effect on  Pokemon type plants", name);
            }
        },
        "reflect-type" => {
            user.set_type(0, target.get_types().0);
            user.set_type(1, target.get_types().1);
        },
        "soak" => {
            target.set_type(0, enums::Types::Water);
            target.set_type(1, enums::Types::Water);
        },
        // "conversion-2" => {
        // },
        // "substitute" => {
        // },
        // "sketch" => {
        // },
        // "spider-web" => {
        // },
        // "mind-reader" => {
        // },
        // "curse" => {
        // },
        // "protect" => {
        // },
        // "belly-drum" => {
        // },
        // "destiny-bond" => {
        // },
        // "detect" => {
        // },
        // "lock-on" => {
        // },
        // "endure" => {
        // },
        // "mean-look" => {
        // },
        // "heal-bell" => {
        // },
        // "pain-split" => {
        // },
        // "baton-pass" => {
        // },
        // "encore" => {
        // },
        // "psych-up" => {
        // },
        // "future-sight" => {
        // },
        // "stockpile" => {
        // },
        // "memento" => {
        // },
        // "follow-me" => {
        // },
        // "taunt" => {
        // },
        // "helping-hand" => {
        // },
        // "trick" => {
        // },
        // "role-play" => {
        // },
        // "wish" => {
        // },
        // "assist" => {
        // },
        // "magic-coat" => {
        // },
        // "recycle" => {
        // },
        // "skill-swap" => {
        // },
        // "imprison" => {
        // },
        // "refresh" => {
        // },
        // "grudge" => {
        // },
        // "snatch" => {
        // },
        // "camouflage" => {
        // },
        // "aromatherapy" => {
        // },
        // "block" => {
        // },
        // "doom-desire" => {
        // },
        // "healing-wish" => {
        // },
        // "acupressure" => {
        // },
        // "psycho-shift" => {
        // },
        // "power-trick" => {
        // },
        // "gastro-acid" => {
        // },
        // "copycat" => {
        // },
        // "power-swap" => {
        // },
        // "guard-swap" => {
        // },
        // "worry-seed" => {
        // },
        // "heart-swap" => {
        // },
        // "aqua-ring" => {
        // },
        // "magnet-rise" => {
        // },
        // "switcheroo" => {
        // },
        // "defog" => {
        // },
        // "lunar-dance" => {
        // },
        // "guard-split" => {
        // },
        // "power-split" => {
        // },
        // "rage-powder" => {
        // },
        // "simple-beam" => {
        // },
        // "entrainment" => {
        // },
        // "after-you" => {
        // },
        // "ally-switch" => {
        // },
        // "shell-smash" => {
        // },
        // "quash" => {
        // },
        // "bestow" => {
        // },
        // "trick-or-treat" => {
        // },
        // "forests-curse" => {
        // },
        // "topsy-turvy" => {
        // },
        // "flower-shield" => {
        // },
        // "electrify" => {
        // },
        // "kings-shield" => {
        // },
        // "spiky-shield" => {
        // },
        // "happy-hour" => {
        // },
        // "hold-hands" => {
        // },
        _ => {},
    };
}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/// Supervise a service.
///
/// The supervisor is responsible for running any services we are asked to start. It handles
/// spawning the new process, watching for failure, and ensuring the service is either up or down.
/// If the process dies, the supervisor will restart it.

use std;
use std::fmt;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
use std::path::PathBuf;
use std::process::Child;
use std::result;
use std::sync::{Arc, RwLock};
use std::thread;

use hcore::os::process::{HabChild, ExitStatusExt};
use hcore::package::PackageInstall;
use hcore::service::ServiceGroup;
use serde::{Serialize, Serializer};
use serde::ser::SerializeStruct;
use time::SteadyTime;

use error::{Result, Error};
use fs;
use util;

const PIDFILE_NAME: &'static str = "PID";
static LOGKEY: &'static str = "SV";

#[derive(Debug, Deserialize, Serialize)]
pub enum ProcessState {
    Down,
    Up,
    Start,
    Restart,
}

impl fmt::Display for ProcessState {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let state = match self {
            &ProcessState::Down => "down",
            &ProcessState::Up => "up",
            &ProcessState::Start => "start",
            &ProcessState::Restart => "restart",
        };
        write!(f, "{}", state)
    }
}

/// Additional params used to start the Supervisor.
/// These params are outside the scope of what is in
/// Supervisor.package.ident, and aren't runtime params that are stored
/// in the top-level Supervisor struct (such as PID etc)
#[derive(Debug, Deserialize, Serialize)]
pub struct RuntimeConfig {
    pub svc_user: String,
    pub svc_group: String,
}

impl RuntimeConfig {
    pub fn new(svc_user: String, svc_group: String) -> RuntimeConfig {
        RuntimeConfig {
            svc_user: svc_user,
            svc_group: svc_group,
        }
    }
}

impl Default for RuntimeConfig {
    fn default() -> RuntimeConfig {
        RuntimeConfig {
            svc_user: util::users::DEFAULT_USER.to_string(),
            svc_group: util::users::DEFAULT_GROUP.to_string(),
        }
    }
}

#[derive(Debug)]
pub struct Supervisor {
    pub child: Option<HabChild>,
    pub package: Arc<RwLock<PackageInstall>>,
    pub preamble: String,
    pub state: ProcessState,
    pub state_entered: SteadyTime,
    pub has_started: bool,
    pub runtime_config: RuntimeConfig,
}

impl Supervisor {
    pub fn new(package: Arc<RwLock<PackageInstall>>,
               service_group: &ServiceGroup,
               runtime_config: RuntimeConfig)
               -> Supervisor {
        Supervisor {
            child: None,
            package: package,
            preamble: format!("{}", service_group),
            state: ProcessState::Down,
            state_entered: SteadyTime::now(),
            has_started: false,
            runtime_config: runtime_config,
        }
    }

    fn enter_state(&mut self, state: ProcessState) {
        self.state = state;
        self.state_entered = SteadyTime::now();
    }

    pub fn status(&self) -> (bool, String) {
        let status = format!("{}: {} for {}",
                             self.preamble,
                             self.state,
                             SteadyTime::now() - self.state_entered);
        let healthy = match self.state {
            ProcessState::Up | ProcessState::Start | ProcessState::Restart => true,
            ProcessState::Down => false,
        };
        (healthy, status)
    }

    pub fn start(&mut self) -> Result<()> {
        if self.child.is_none() {
            outputln!(preamble self.preamble,
                      "Starting process as user={}, group={}",
                      &self.runtime_config.svc_user,
                      &self.runtime_config.svc_group);
            self.enter_state(ProcessState::Start);
            let mut child = try!(util::create_command(self.run_cmd(),
                                                      &self.runtime_config.svc_user,
                                                      &self.runtime_config.svc_group)
                .spawn());

            let hab_child = try!(HabChild::from(&mut child));
            self.child = Some(hab_child);
            try!(self.create_pidfile());
            let package_name = self.preamble.clone();
            try!(thread::Builder::new()
                .name(String::from("sup-service-read"))
                .spawn(move || -> Result<()> { child_reader(&mut child, package_name) }));
            self.enter_state(ProcessState::Up);
            self.has_started = true;
        } else {
            outputln!(preamble & self.preamble, "Already started");
        }
        Ok(())
    }

    /// Send a SIGTERM to a process, wait 8 seconds, then send SIGKILL
    pub fn stop(&mut self) -> Result<()> {
        match self.child {
            Some(ref mut child) => {
                outputln!(preamble & self.preamble, "Stopping...");
                let shutdown = try!(child.kill());
                outputln!("{} - Shutdown method: {}", self.preamble, shutdown);
            }
            None => {}
        };
        self.check_process();
        Ok(())
    }

    pub fn is_up(&self) -> bool {
        if let ProcessState::Up = self.state {
            true
        } else {
            false
        }
    }

    pub fn is_down(&self) -> bool {
        if let ProcessState::Down = self.state {
            true
        } else {
            false
        }
    }

    pub fn down(&mut self) -> Result<()> {
        self.enter_state(ProcessState::Down);
        try!(self.stop());
        self.cleanup_pidfile();
        Ok(())
    }

    pub fn restart(&mut self) -> Result<()> {
        self.enter_state(ProcessState::Restart);
        try!(self.stop());
        try!(self.start());
        Ok(())
    }

    /// if the child process exists, check it's status via waitpid().
    pub fn check_process(&mut self) {
        let changed = match self.child {
            None => false,
            Some(ref mut child) => {
                match child.status() {
                    Ok(ref status) if status.no_status() => false,
                    Ok(ref status) => {
                        if status.code().is_some() {
                            outputln!("{} - process {} died with exit code {}",
                                      self.preamble,
                                      child.id(),
                                      status.code().unwrap());
                        } else if status.signal().is_some() {
                            outputln!("{} - process {} died with signal {}",
                                      self.preamble,
                                      child.id(),
                                      status.signal().unwrap());
                        }
                        true
                    }
                    Err(e) => {
                        debug!("Error checking process status: {}, continuing", e);
                        false
                    }
                }
            }
        };
        if changed {
            match self.state {
                ProcessState::Up | ProcessState::Start | ProcessState::Restart => {
                    outputln!("{} - Service exited", self.preamble);
                    self.child = None;
                }
                ProcessState::Down => {
                    self.enter_state(ProcessState::Down);
                    self.child = None;
                }
            }
        }
    }

    pub fn run_cmd(&self) -> PathBuf {
        self.service_dir().join("run")
    }

    pub fn service_dir(&self) -> PathBuf {
        fs::svc_path(&self.package.read().expect("Package lock poisoned").ident().name)
    }

    pub fn pid_file(&self) -> PathBuf {
        self.service_dir().join(PIDFILE_NAME)
    }

    /// Create a pid file for a package
    /// The existence of this file does not guarantee that a
    /// process exists at the PID contained within.
    pub fn create_pidfile(&self) -> Result<()> {
        match self.child {
            Some(ref child) => {
                let pid_file = self.pid_file();
                let ref pid = child.id();
                debug!("Creating PID file for child {} -> {:?}",
                       pid_file.display(),
                       pid);
                let mut f = try!(File::create(pid_file));
                try!(write!(f, "{}", pid));
                Ok(())
            }
            None => Ok(()),
        }
    }

    /// Remove a pidfile for this package if it exists.
    /// Do NOT fail if there is an error removing the PIDFILE
    pub fn cleanup_pidfile(&self) {
        let pid_file = self.pid_file();
        debug!("Attempting to clean up pid file {}", &pid_file.display());
        match std::fs::remove_file(pid_file) {
            Ok(_) => {
                debug!("Removed pid file");
            }
            Err(e) => {
                debug!("Error removing pidfile: {}, continuing", e);
            }
        };
    }

    /// attempt to read the pidfile for this package.
    /// If the pidfile does not exist, then return None,
    /// otherwise, return Some(pid, uptime_seconds).
    pub fn read_pidfile(&self) -> Result<Option<u32>> {
        let pid_file = self.pid_file();
        debug!("Reading pidfile {}", &pid_file.display());

        let mut f = try!(File::open(pid_file));
        let mut contents = String::new();
        try!(f.read_to_string(&mut contents));
        debug!("pidfile contents = {}", contents);
        let pid = match contents.parse::<u32>() {
            Ok(pid) => pid,
            Err(e) => {
                debug!("Error reading pidfile: {}", e);
                return Err(sup_error!(Error::InvalidPidFile));
            }
        };
        Ok(Some(pid))
    }
}

impl Serialize for Supervisor {
    fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error>
        where S: Serializer
    {
        let pid = match self.child {
            Some(ref child) => Some(child.id()),
            None => None,
        };
        let mut strukt = try!(serializer.serialize_struct("supervisor", 7));
        try!(strukt.serialize_field("pid", &pid));
        try!(strukt.serialize_field("package",
                                    &self.package
                                        .read()
                                        .expect("Package lock poisoned")
                                        .to_string()));
        try!(strukt.serialize_field("preamble", &self.preamble));
        try!(strukt.serialize_field("state", &self.state));
        try!(strukt.serialize_field("state_entered", &self.state_entered.to_string()));
        try!(strukt.serialize_field("started", &self.has_started));
        try!(strukt.serialize_field("runtime_config", &self.runtime_config));
        strukt.end()
    }
}

impl Drop for Supervisor {
    fn drop(&mut self) {
        let _ = self.cleanup_pidfile();
    }
}

/// Consume output from a child process until EOF, then finish
fn child_reader(child: &mut Child, package_name: String) -> Result<()> {
    let c_stdout = match child.stdout {
        Some(ref mut s) => s,
        None => return Err(sup_error!(Error::UnpackFailed)),
    };

    let mut reader = BufReader::new(c_stdout);
    let mut buffer = String::new();

    while reader.read_line(&mut buffer).unwrap() > 0 {
        let mut line = output_format!(preamble &package_name, logkey "O");
        line.push_str(&buffer);
        print!("{}", line);
        buffer.clear();
    }
    debug!("child_reader exiting");
    Ok(())
}
<commit_msg>[sup] Use set pkg user and group as owner of PID file<commit_after>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/// Supervise a service.
///
/// The supervisor is responsible for running any services we are asked to start. It handles
/// spawning the new process, watching for failure, and ensuring the service is either up or down.
/// If the process dies, the supervisor will restart it.

use std;
use std::fmt;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
use std::path::PathBuf;
use std::process::Child;
use std::result;
use std::sync::{Arc, RwLock};
use std::thread;

use hcore::os::process::{HabChild, ExitStatusExt};
use hcore::util::perm::set_owner;
use hcore::package::PackageInstall;
use hcore::service::ServiceGroup;
use serde::{Serialize, Serializer};
use serde::ser::SerializeStruct;
use time::SteadyTime;

use error::{Result, Error};
use fs;
use util;

const PIDFILE_NAME: &'static str = "PID";
static LOGKEY: &'static str = "SV";

#[derive(Debug, Deserialize, Serialize)]
pub enum ProcessState {
    Down,
    Up,
    Start,
    Restart,
}

impl fmt::Display for ProcessState {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let state = match self {
            &ProcessState::Down => "down",
            &ProcessState::Up => "up",
            &ProcessState::Start => "start",
            &ProcessState::Restart => "restart",
        };
        write!(f, "{}", state)
    }
}

/// Additional params used to start the Supervisor.
/// These params are outside the scope of what is in
/// Supervisor.package.ident, and aren't runtime params that are stored
/// in the top-level Supervisor struct (such as PID etc)
#[derive(Debug, Deserialize, Serialize)]
pub struct RuntimeConfig {
    pub svc_user: String,
    pub svc_group: String,
}

impl RuntimeConfig {
    pub fn new(svc_user: String, svc_group: String) -> RuntimeConfig {
        RuntimeConfig {
            svc_user: svc_user,
            svc_group: svc_group,
        }
    }
}

impl Default for RuntimeConfig {
    fn default() -> RuntimeConfig {
        RuntimeConfig {
            svc_user: util::users::DEFAULT_USER.to_string(),
            svc_group: util::users::DEFAULT_GROUP.to_string(),
        }
    }
}

#[derive(Debug)]
pub struct Supervisor {
    pub child: Option<HabChild>,
    pub package: Arc<RwLock<PackageInstall>>,
    pub preamble: String,
    pub state: ProcessState,
    pub state_entered: SteadyTime,
    pub has_started: bool,
    pub runtime_config: RuntimeConfig,
}

impl Supervisor {
    pub fn new(package: Arc<RwLock<PackageInstall>>,
               service_group: &ServiceGroup,
               runtime_config: RuntimeConfig)
               -> Supervisor {
        Supervisor {
            child: None,
            package: package,
            preamble: format!("{}", service_group),
            state: ProcessState::Down,
            state_entered: SteadyTime::now(),
            has_started: false,
            runtime_config: runtime_config,
        }
    }

    fn enter_state(&mut self, state: ProcessState) {
        self.state = state;
        self.state_entered = SteadyTime::now();
    }

    pub fn status(&self) -> (bool, String) {
        let status = format!("{}: {} for {}",
                             self.preamble,
                             self.state,
                             SteadyTime::now() - self.state_entered);
        let healthy = match self.state {
            ProcessState::Up | ProcessState::Start | ProcessState::Restart => true,
            ProcessState::Down => false,
        };
        (healthy, status)
    }

    pub fn start(&mut self) -> Result<()> {
        if self.child.is_none() {
            outputln!(preamble self.preamble,
                      "Starting process as user={}, group={}",
                      &self.runtime_config.svc_user,
                      &self.runtime_config.svc_group);
            self.enter_state(ProcessState::Start);
            let mut child = try!(util::create_command(self.run_cmd(),
                                                      &self.runtime_config.svc_user,
                                                      &self.runtime_config.svc_group)
                .spawn());

            let hab_child = try!(HabChild::from(&mut child));
            self.child = Some(hab_child);
            try!(self.create_pidfile());
            let package_name = self.preamble.clone();
            try!(thread::Builder::new()
                .name(String::from("sup-service-read"))
                .spawn(move || -> Result<()> { child_reader(&mut child, package_name) }));
            self.enter_state(ProcessState::Up);
            self.has_started = true;
        } else {
            outputln!(preamble & self.preamble, "Already started");
        }
        Ok(())
    }

    /// Send a SIGTERM to a process, wait 8 seconds, then send SIGKILL
    pub fn stop(&mut self) -> Result<()> {
        match self.child {
            Some(ref mut child) => {
                outputln!(preamble & self.preamble, "Stopping...");
                let shutdown = try!(child.kill());
                outputln!("{} - Shutdown method: {}", self.preamble, shutdown);
            }
            None => {}
        };
        self.check_process();
        Ok(())
    }

    pub fn is_up(&self) -> bool {
        if let ProcessState::Up = self.state {
            true
        } else {
            false
        }
    }

    pub fn is_down(&self) -> bool {
        if let ProcessState::Down = self.state {
            true
        } else {
            false
        }
    }

    pub fn down(&mut self) -> Result<()> {
        self.enter_state(ProcessState::Down);
        try!(self.stop());
        self.cleanup_pidfile();
        Ok(())
    }

    pub fn restart(&mut self) -> Result<()> {
        self.enter_state(ProcessState::Restart);
        try!(self.stop());
        try!(self.start());
        Ok(())
    }

    /// if the child process exists, check it's status via waitpid().
    pub fn check_process(&mut self) {
        let changed = match self.child {
            None => false,
            Some(ref mut child) => {
                match child.status() {
                    Ok(ref status) if status.no_status() => false,
                    Ok(ref status) => {
                        if status.code().is_some() {
                            outputln!("{} - process {} died with exit code {}",
                                      self.preamble,
                                      child.id(),
                                      status.code().unwrap());
                        } else if status.signal().is_some() {
                            outputln!("{} - process {} died with signal {}",
                                      self.preamble,
                                      child.id(),
                                      status.signal().unwrap());
                        }
                        true
                    }
                    Err(e) => {
                        debug!("Error checking process status: {}, continuing", e);
                        false
                    }
                }
            }
        };
        if changed {
            match self.state {
                ProcessState::Up | ProcessState::Start | ProcessState::Restart => {
                    outputln!("{} - Service exited", self.preamble);
                    self.child = None;
                }
                ProcessState::Down => {
                    self.enter_state(ProcessState::Down);
                    self.child = None;
                }
            }
        }
    }

    pub fn run_cmd(&self) -> PathBuf {
        self.service_dir().join("run")
    }

    pub fn service_dir(&self) -> PathBuf {
        fs::svc_path(&self.package.read().expect("Package lock poisoned").ident().name)
    }

    pub fn pid_file(&self) -> PathBuf {
        self.service_dir().join(PIDFILE_NAME)
    }

    /// Create a pid file for a package
    /// The existence of this file does not guarantee that a
    /// process exists at the PID contained within.
    pub fn create_pidfile(&self) -> Result<()> {
        match self.child {
            Some(ref child) => {
                let pid_file = self.pid_file();
                let ref pid = child.id();
                debug!("Creating PID file for child {} -> {:?}",
                       pid_file.display(),
                       pid);
                let mut f = try!(File::create(&pid_file));
                try!(set_owner(pid_file,
                               &self.runtime_config.svc_user,
                               &self.runtime_config.svc_group));
                try!(write!(f, "{}", pid));
                Ok(())
            }
            None => Ok(()),
        }
    }

    /// Remove a pidfile for this package if it exists.
    /// Do NOT fail if there is an error removing the PIDFILE
    pub fn cleanup_pidfile(&self) {
        let pid_file = self.pid_file();
        debug!("Attempting to clean up pid file {}", &pid_file.display());
        match std::fs::remove_file(pid_file) {
            Ok(_) => {
                debug!("Removed pid file");
            }
            Err(e) => {
                debug!("Error removing pidfile: {}, continuing", e);
            }
        };
    }

    /// attempt to read the pidfile for this package.
    /// If the pidfile does not exist, then return None,
    /// otherwise, return Some(pid, uptime_seconds).
    pub fn read_pidfile(&self) -> Result<Option<u32>> {
        let pid_file = self.pid_file();
        debug!("Reading pidfile {}", &pid_file.display());

        let mut f = try!(File::open(pid_file));
        let mut contents = String::new();
        try!(f.read_to_string(&mut contents));
        debug!("pidfile contents = {}", contents);
        let pid = match contents.parse::<u32>() {
            Ok(pid) => pid,
            Err(e) => {
                debug!("Error reading pidfile: {}", e);
                return Err(sup_error!(Error::InvalidPidFile));
            }
        };
        Ok(Some(pid))
    }
}

impl Serialize for Supervisor {
    fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error>
        where S: Serializer
    {
        let pid = match self.child {
            Some(ref child) => Some(child.id()),
            None => None,
        };
        let mut strukt = try!(serializer.serialize_struct("supervisor", 7));
        try!(strukt.serialize_field("pid", &pid));
        try!(strukt.serialize_field("package",
                                    &self.package
                                        .read()
                                        .expect("Package lock poisoned")
                                        .to_string()));
        try!(strukt.serialize_field("preamble", &self.preamble));
        try!(strukt.serialize_field("state", &self.state));
        try!(strukt.serialize_field("state_entered", &self.state_entered.to_string()));
        try!(strukt.serialize_field("started", &self.has_started));
        try!(strukt.serialize_field("runtime_config", &self.runtime_config));
        strukt.end()
    }
}

impl Drop for Supervisor {
    fn drop(&mut self) {
        let _ = self.cleanup_pidfile();
    }
}

/// Consume output from a child process until EOF, then finish
fn child_reader(child: &mut Child, package_name: String) -> Result<()> {
    let c_stdout = match child.stdout {
        Some(ref mut s) => s,
        None => return Err(sup_error!(Error::UnpackFailed)),
    };

    let mut reader = BufReader::new(c_stdout);
    let mut buffer = String::new();

    while reader.read_line(&mut buffer).unwrap() > 0 {
        let mut line = output_format!(preamble &package_name, logkey "O");
        line.push_str(&buffer);
        print!("{}", line);
        buffer.clear();
    }
    debug!("child_reader exiting");
    Ok(())
}
<|endoftext|>


<commit_before>#[cfg(feature = "aead-cipher-2022")]
use std::time::Duration;

use cfg_if::cfg_if;
#[cfg(feature = "aead-cipher-2022")]
use lru_time_cache::LruCache;
#[allow(dead_code)]
use spin::Mutex as SpinMutex;

#[cfg(feature = "aead-cipher-2022")]
use crate::relay::tcprelay::proxy_stream::protocol::v2::SERVER_STREAM_TIMESTAMP_MAX_DIFF;
use crate::{config::ServerType, crypto::CipherKind};

#[cfg(feature = "security-replay-attack-detect")]
use self::ppbloom::PingPongBloom;

#[cfg(feature = "security-replay-attack-detect")]
mod ppbloom;

/// A Bloom Filter based protector against replay attach
pub struct ReplayProtector {
    // Check for duplicated IV/Nonce, for prevent replay attack
    // https://github.com/shadowsocks/shadowsocks-org/issues/44
    #[cfg(feature = "security-replay-attack-detect")]
    nonce_ppbloom: SpinMutex<PingPongBloom>,

    // AEAD 2022 specific filter.
    // AEAD 2022 TCP protocol has a timestamp, which can already reject most of the replay requests,
    // so we only need to remember nonce that are in the valid time range
    #[cfg(feature = "aead-cipher-2022")]
    nonce_set: SpinMutex<LruCache<Vec<u8>, ()>>,
}

impl ReplayProtector {
    /// Create a new ReplayProtector
    #[allow(unused_variables)]
    pub fn new(config_type: ServerType) -> ReplayProtector {
        ReplayProtector {
            #[cfg(feature = "security-replay-attack-detect")]
            nonce_ppbloom: SpinMutex::new(PingPongBloom::new(config_type)),
            #[cfg(feature = "aead-cipher-2022")]
            nonce_set: SpinMutex::new(LruCache::with_expiry_duration(Duration::from_secs(
                SERVER_STREAM_TIMESTAMP_MAX_DIFF * 2,
            ))),
        }
    }

    /// Check if nonce exist or not
    #[inline(always)]
    pub fn check_nonce_and_set(&self, method: CipherKind, nonce: &[u8]) -> bool {
        // Plain cipher doesn't have a nonce
        // Always treated as non-duplicated
        if nonce.is_empty() {
            return false;
        }

        #[cfg(feature = "aead-cipher-2022")]
        if method.is_aead_2022() {
            let mut set = self.nonce_set.lock();
            if set.get(nonce).is_some() {
                return true;
            }
            set.insert(nonce.to_vec(), ());
            return false;
        }

        cfg_if! {
            if #[cfg(feature = "security-replay-attack-detect")] {
                let mut ppbloom = self.nonce_ppbloom.lock();
                ppbloom.check_and_set(nonce)
            } else {
                false
            }
        }
    }
}
<commit_msg>make clippy happy<commit_after>#[cfg(feature = "aead-cipher-2022")]
use std::time::Duration;

use cfg_if::cfg_if;
#[cfg(feature = "aead-cipher-2022")]
use lru_time_cache::LruCache;
#[allow(unused_imports)]
use spin::Mutex as SpinMutex;

#[cfg(feature = "aead-cipher-2022")]
use crate::relay::tcprelay::proxy_stream::protocol::v2::SERVER_STREAM_TIMESTAMP_MAX_DIFF;
use crate::{config::ServerType, crypto::CipherKind};

#[cfg(feature = "security-replay-attack-detect")]
use self::ppbloom::PingPongBloom;

#[cfg(feature = "security-replay-attack-detect")]
mod ppbloom;

/// A Bloom Filter based protector against replay attach
pub struct ReplayProtector {
    // Check for duplicated IV/Nonce, for prevent replay attack
    // https://github.com/shadowsocks/shadowsocks-org/issues/44
    #[cfg(feature = "security-replay-attack-detect")]
    nonce_ppbloom: SpinMutex<PingPongBloom>,

    // AEAD 2022 specific filter.
    // AEAD 2022 TCP protocol has a timestamp, which can already reject most of the replay requests,
    // so we only need to remember nonce that are in the valid time range
    #[cfg(feature = "aead-cipher-2022")]
    nonce_set: SpinMutex<LruCache<Vec<u8>, ()>>,
}

impl ReplayProtector {
    /// Create a new ReplayProtector
    #[allow(unused_variables)]
    pub fn new(config_type: ServerType) -> ReplayProtector {
        ReplayProtector {
            #[cfg(feature = "security-replay-attack-detect")]
            nonce_ppbloom: SpinMutex::new(PingPongBloom::new(config_type)),
            #[cfg(feature = "aead-cipher-2022")]
            nonce_set: SpinMutex::new(LruCache::with_expiry_duration(Duration::from_secs(
                SERVER_STREAM_TIMESTAMP_MAX_DIFF * 2,
            ))),
        }
    }

    /// Check if nonce exist or not
    #[inline(always)]
    pub fn check_nonce_and_set(&self, method: CipherKind, nonce: &[u8]) -> bool {
        // Plain cipher doesn't have a nonce
        // Always treated as non-duplicated
        if nonce.is_empty() {
            return false;
        }

        #[cfg(feature = "aead-cipher-2022")]
        if method.is_aead_2022() {
            let mut set = self.nonce_set.lock();
            if set.get(nonce).is_some() {
                return true;
            }
            set.insert(nonce.to_vec(), ());
            return false;
        }

        cfg_if! {
            if #[cfg(feature = "security-replay-attack-detect")] {
                let mut ppbloom = self.nonce_ppbloom.lock();
                ppbloom.check_and_set(nonce)
            } else {
                false
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::ops;
use std::mem;

use self::Node::*;

/// A `Node` in the `Rope`'s tree.
///
/// A `Node` is either a `Leaf` holding a `String`, or a
/// a `Branch` concatenating together two `Node`s.
#[derive(Debug, Clone)]
pub enum Node {
    /// A leaf node
    Leaf(String)
  , /// A branch concatenating together `l`eft and `r`ight nodes.
    Branch(BranchNode)
}

#[derive(Debug, Clone)]
pub struct BranchNode {
    /// The length of this node
    len: usize
  , /// The weight of a node is the summed weight of its left subtree
    weight: usize
  , /// The left branch node
    pub left: Box<Node>
  , /// The right branch node
    pub right: Box<Node>
}

impl Default for Node {
    fn default() -> Self { Node::empty() }
}

/// Returns the _n_th fibonacci number.
// TODO: replace with an iterative implementation and/or lookup table?
fn fibonacci(n: usize) -> usize {
    match n { 0 => 1
            , 1 => 1
            , _ => fibonacci(n - 1) + fibonacci(n - 2)
            }
}

impl BranchNode {

    #[inline]
    fn new(left: Node, right: Node) -> Self {
        BranchNode { len: left.len() + right.len()
                   , weight: left.subtree_weight()
                   , left: box left
                   , right: box right
                   }
    }

    #[inline]
    fn take_left(&mut self) -> Node {
        mem::replace(self.left.as_mut(), Node::empty())
    }

    #[inline]
    fn take_right(&mut self) -> Node {
        mem::replace(self.right.as_mut(), Node::empty())
    }

    fn split(&mut self, index: usize) -> &mut Node {
        if index < self.weight {
            // split the left node
            let mut left = self.take_left();
            left.split(index);
            // replacing *self with a new BranchNode will update the
            // node's weight automagically
            *self = BranchNode::new(left, self.take_right());
            self.left.as_mut()
        } else {
            // split the right node
            let mut right = self.take_right();
            right.split(index);
            // replacing *self with a new BranchNode will update the
            // node's weight automagically
            *self = BranchNode::new(self.take_left(), right);
            self.left.as_mut()
        }
    }

}

impl Node {
    fn split_leaf(&mut self, index: usize) -> bool {
        // we mutably borrow `self` here. This precludes us from changing it
        // directly as in `*self = ...`, because the borrow checker won't allow
        // it. Therefore, the assignment to `self` must be outside the `if let`
        // clause.
        *self = if let Leaf(ref mut s) = *self {

            // if this node is a Leaf, take the String out of it
            // (note that empty strings don't allocate).
            let string = mem::replace(s, String::new());
            // split the string into left and right parts...
            let left = Leaf(string[index..].to_string());
            let right = Leaf(string[..index].to_string());
            // construct the new Branch node that will be reassigned to `self`
            Node::new_branch(left, right)
        } else {
            // if this node is not a Leaf, we return immediately, thus skipping
            // the assignment
            return false
        };
        return true
    }

    pub fn split(&mut self, index: usize) -> &mut Node {
        if self.split_leaf(index) == true {
            self
        } else {
            if let &mut Branch(ref mut node) = self {
                node.split(index)
            } else {
                unreachable!("A node that was neither a leaf nor a branch \
                              happened?")
            }
        }
    }

    pub fn empty() -> Self {
        Leaf(String::new())
    }

    /// Concatenate two `Node`s to return a new `Branch` node.
    #[inline]
    pub fn new_branch(left: Self, right: Self) -> Self {
        Branch(BranchNode::new(left, right))
    }

    #[inline]
    pub fn concat(&mut self, right: Self) {
        *self = Node::new_branch(mem::replace(self, Node::empty()), right)
    }

    #[inline]
    pub const fn new_leaf(string: String) -> Self {
        Leaf(string)
    }

    /// Returns true if this node is balanced
    ///
    /// "We define the depth of a leaf to be 0, and the depth of a
    /// concatenation to be one plus the maximum depth of its children. Let
    /// _Fn_ be the _n_th Fibonacci number. A rope of depth _n_ is balanced if
    /// its length is at least _Fn_+2, e.g. a balanced rope of depth 1 must
    /// have length at least 2. Note that balanced ropes may contain unbalanced
    /// subropes."
    /// – from "Ropes: An Alternative to Strings"
    #[inline]
    pub fn is_balanced(&self) -> bool {
        self.len() >= fibonacci(self.depth() + 2)
    }

    /// Returns the depth in the tree of a node
    #[inline]
    fn depth(&self) -> usize {
        use std::cmp::max;

        match self {
            &Node::Leaf(_) => 0
          , &Node::Branch(BranchNode { ref left, ref right, .. }) =>
                max(left.depth(), right.depth()) + 1
            }
    }

    /// Returns the length of a node
    //  TODO: do we want to cache this?
    pub fn len(&self) -> usize {
        match self { &Leaf(ref s) => s.len()
                   , &Branch(BranchNode { ref left, ref right, .. }) =>
                        left.len() + right.len()
                    }
    }

    /// Calculates the weight of a node
    #[inline]
    fn subtree_weight (&self) -> usize {
        match self { &Leaf(ref s) => s.len()
                   , &Branch(BranchNode { ref left, .. }) =>
                        left.subtree_weight()
                    }
    }

    /// Rebalance the subrope starting at this `Node`, returning a new `Node`
    ///
    /// From "Ropes: An Alternative to Strings":
    /// > "The rebalancing operation maintains an ordered sequence of (empty
    /// > or) balanced ropes, one for each length interval [_Fn_, _Fn_+1), for
    /// > _n_ >= 2. We traverse the rope from left to right, inserting each
    /// > leaf into the appropriate sequence position, depending on its length.
    ///
    /// > The concatenation of the sequence of ropes in order of decreasing
    /// > length is equivalent to the prefix of the rope we have traversed so
    /// > far. Each new leaf _x_ is with_insert_ropeed into the appropriate entry of the
    /// > sequence. Assume that _x_’s length is in the interval [_Fn_, _Fn_+1),
    /// > and thus it should be put in slot _n_ (which also corresponds to
    /// > maximum depth _n_ − 2). If all lower and equal numbered levels are
    /// > empty, then this can be done directly. If not, then we concatenate
    /// > ropes in slots 2, ... ,(_n_ − 1) (concatenating onto the left), and
    /// > concatenate _x_ to the right of the result. We then continue to
    /// > concatenate ropes from the sequence in increasing order to the left
    /// > of this result, until the result fits into an empty slot in the
    /// > sequence."
    pub fn rebalance(self) -> Self {
        // TODO: this is a huge mess, I based it on the IBM Java implementation
        //       please refactor until it stops being ugly!
        //        - eliza, 12/17/2016

        if self.is_balanced() {
            // the subrope is already balanced, do nothing
            self
        } else {
            let mut leaves: Vec<Option<Node>> =
                self.into_leaves().map(Option::Some).collect();
            let len = leaves.len();
            fn _rebalance(l: &mut Vec<Option<Node>>, start: usize, end: usize)
                          -> Node {
                match end - start {
                    1 => l[start].take().unwrap()
                  , 2 => l[start].take().unwrap() + l[start + 1].take().unwrap()
                  , n => {
                        let mid = start + (n / 2);
                        _rebalance(l, start, mid) + _rebalance(l, mid, end)

                    }
                }
            };
            _rebalance(&mut leaves, 0, len)
        }
    }

    /// Returns an iterator over all leaf nodes in this `Node`'s subrope
    fn leaves<'a>(&'a self) -> Leaves<'a> {
        Leaves(vec![self])
    }

    /// Returns a move iterator over all leaf nodes in this `Node`'s subrope
    fn into_leaves(self) -> IntoLeaves {
        IntoLeaves(vec![self])
    }

    /// Returns an iterator over all the strings in this `Node`s subrope'
    #[inline]
    pub fn strings<'a>(&'a self) -> impl Iterator<Item=&'a str> {
        box self.leaves().map(|n| match n {
            &Leaf(ref s) => s.as_ref()
          , _ => unreachable!("Node.leaves() iterator contained something \
                               that wasn't a leaf. Barring _force majeure_, \
                               this should be impossible. Something's broken.")
        })
    }

    /// Returns a move iterator over all the strings in this `Node`s subrope'
    ///
    /// Consumes `self`.
    #[inline]
    pub fn into_strings(self) -> impl Iterator<Item=String> {
        box self.into_leaves().map(|n| match n {
            Leaf(s) => s
            , _ => unreachable!("Node.into_leaves() iterator contained \
                                 something  that wasn't a leaf. Barring _force \
                                 majeure_, this should be impossible. \
                                 Something's broken.")
        })
    }

    str_iters! {
        #[doc="Returns an iterator over all the bytes in this `Node`'s \
               subrope \n\

               \nAs a Rope consists of a sequence of bytes, we can iterate \
               through a rope by byte. This method returns such an iterator."]
        #[inline]
        impl bytes<u8> for Node {}
        #[doc="Returns an iterator over all the characters in this `Node`'s \
               subrope \n\

               \nAs a `Rope` consists of valid UTF-8, we can iterate through a \
               `Rope` by `char`. This method returns such an iterator. \n\

               \nIt's important to remember that `char` represents a Unicode \
               Scalar Value, and may not match your idea of what a \
               'character' is. Iteration over grapheme clusters may be what \
               you actually want."]
        #[inline]
        impl chars<char> for Node {}
        // TODO: this is actually Wrong, the indices will wrap around once we
        //       iterate into the next leaf node. we'll need to write our own
        //       char_indices iterator that tracks the character's index in the
        //       global Rope. shouldn't be too hard, just a fold...
        //          - eliza, 12/18/2016
        // #[inline]
        // impl char_indices<(usize, char)> for Node {}
        #[inline]
        impl split_whitespace<&'a str> for Node {}
        #[inline]
        impl lines<&'a str> for Node {}
    }

    // /// Returns n iterator over the bytes of this `Node`'s subrope
    // ///
    // ///
    // #[inline]
    // pub fn bytes<'a>(&'a self) -> impl Iterator<Item=u8> + 'a {
    //     self.strings().flat_map(str::bytes)
    // }

    /// Returns an iterator over the grapheme clusters of this `Node`'s subrope'
    ///
    /// This is the iterator returned by `Node::into_iter`.
    #[inline]
    pub fn graphemes<'a>(&'a self) -> impl Iterator<Item=&'a str> {
        // the compiler won't let me mark this as unimplemented using the
        // unimplemented!() macro, due to Reasons (i suspect relating to
        // returning `impl Trait`)
        //  - eliza, 12/18/2016
        panic!("Unimplemented!");
        self.strings()
    }

}

/// An iterator over a series of leaf `Node`s
struct Leaves<'a>(Vec<&'a Node>);

impl<'a> Iterator for Leaves<'a> {
    type Item = &'a Node;
    fn next(&mut self) -> Option<Self::Item> {
        match self.0.pop() {
            None => None
          , Some(leaf @ &Leaf(_)) => Some(leaf)
          , Some(&Branch(BranchNode { ref left, ref right, .. })) => {
                self.0.push(right);
                self.0.push(left);
                self.next()
            }
        }
    }
}

/// A move iterator over a series of leaf `Node`s
struct IntoLeaves(Vec<Node>);

impl Iterator for IntoLeaves {
    type Item = Node;
    fn next(&mut self) -> Option<Self::Item> {
        match self.0.pop() {
            None => None
          , Some(leaf @ Leaf(_)) => Some(leaf)
          , Some(Branch(BranchNode { box left, box right, .. })) => {
                self.0.push(right);
                self.0.push(left);
                self.next()
            }
        }
    }
}

impl ops::Add for Node {
    type Output = Self;
    /// Concatenate two `Node`s, returning a `Branch` node.
    fn add(self, right: Self) -> Self { Node::new_branch(self, right) }
}
<commit_msg>rope: add assertions in Node::split_leaf()<commit_after>use std::ops;
use std::mem;

use self::Node::*;

/// A `Node` in the `Rope`'s tree.
///
/// A `Node` is either a `Leaf` holding a `String`, or a
/// a `Branch` concatenating together two `Node`s.
#[derive(Debug, Clone)]
pub enum Node {
    /// A leaf node
    Leaf(String)
  , /// A branch concatenating together `l`eft and `r`ight nodes.
    Branch(BranchNode)
}

#[derive(Debug, Clone)]
pub struct BranchNode {
    /// The length of this node
    len: usize
  , /// The weight of a node is the summed weight of its left subtree
    weight: usize
  , /// The left branch node
    pub left: Box<Node>
  , /// The right branch node
    pub right: Box<Node>
}

impl Default for Node {
    fn default() -> Self { Node::empty() }
}

/// Returns the _n_th fibonacci number.
// TODO: replace with an iterative implementation and/or lookup table?
fn fibonacci(n: usize) -> usize {
    match n { 0 => 1
            , 1 => 1
            , _ => fibonacci(n - 1) + fibonacci(n - 2)
            }
}

impl BranchNode {

    #[inline]
    fn new(left: Node, right: Node) -> Self {
        BranchNode { len: left.len() + right.len()
                   , weight: left.subtree_weight()
                   , left: box left
                   , right: box right
                   }
    }

    #[inline]
    fn take_left(&mut self) -> Node {
        mem::replace(self.left.as_mut(), Node::empty())
    }

    #[inline]
    fn take_right(&mut self) -> Node {
        mem::replace(self.right.as_mut(), Node::empty())
    }

    fn split(&mut self, index: usize) -> &mut Node {
        if index < self.weight {
            // split the left node
            let mut left = self.take_left();
            left.split(index);
            // replacing *self with a new BranchNode will update the
            // node's weight automagically
            *self = BranchNode::new(left, self.take_right());
            self.left.as_mut()
        } else {
            // split the right node
            let mut right = self.take_right();
            right.split(index);
            // replacing *self with a new BranchNode will update the
            // node's weight automagically
            *self = BranchNode::new(self.take_left(), right);
            self.left.as_mut()
        }
    }

}

impl Node {
    fn split_leaf(&mut self, index: usize) -> bool {
        // we mutably borrow `self` here. This precludes us from changing it
        // directly as in `*self = ...`, because the borrow checker won't allow
        // it. Therefore, the assignment to `self` must be outside the `if let`
        // clause.
        *self = if let Leaf(ref mut s) = *self {
            assert!( s.len() >= 1
                   , "Node::split_leaf: String {} had only {} characters and \
                      thus could not be split at index {}."
                   , s, s.len(), index);

            // if this node is a Leaf, take the String out of it
            // (note that empty strings don't allocate).
            let string = mem::replace(s, String::new());
            // split the string into left and right parts...
            let left = Leaf(string[index..].to_string());
            let right = Leaf(string[..index].to_string());
            // construct the new Branch node that will be reassigned to `self`
            Node::new_branch(left, right)
        } else {
            // if this node is not a Leaf, we return immediately, thus skipping
            // the assignment
            return false
        };
        return true
    }

    pub fn split(&mut self, index: usize) -> &mut Node {
        if self.split_leaf(index) == true {
            self
        } else {
            if let &mut Branch(ref mut node) = self {
                node.split(index)
            } else {
                unreachable!("A node that was neither a leaf nor a branch \
                              happened?")
            }
        }
    }

    pub fn empty() -> Self {
        Leaf(String::new())
    }

    /// Concatenate two `Node`s to return a new `Branch` node.
    #[inline]
    pub fn new_branch(left: Self, right: Self) -> Self {
        Branch(BranchNode::new(left, right))
    }

    #[inline]
    pub fn concat(&mut self, right: Self) {
        *self = Node::new_branch(mem::replace(self, Node::empty()), right)
    }

    #[inline]
    pub const fn new_leaf(string: String) -> Self {
        Leaf(string)
    }

    /// Returns true if this node is balanced
    ///
    /// "We define the depth of a leaf to be 0, and the depth of a
    /// concatenation to be one plus the maximum depth of its children. Let
    /// _Fn_ be the _n_th Fibonacci number. A rope of depth _n_ is balanced if
    /// its length is at least _Fn_+2, e.g. a balanced rope of depth 1 must
    /// have length at least 2. Note that balanced ropes may contain unbalanced
    /// subropes."
    /// – from "Ropes: An Alternative to Strings"
    #[inline]
    pub fn is_balanced(&self) -> bool {
        self.len() >= fibonacci(self.depth() + 2)
    }

    /// Returns the depth in the tree of a node
    #[inline]
    fn depth(&self) -> usize {
        use std::cmp::max;

        match self {
            &Node::Leaf(_) => 0
          , &Node::Branch(BranchNode { ref left, ref right, .. }) =>
                max(left.depth(), right.depth()) + 1
            }
    }

    /// Returns the length of a node
    //  TODO: do we want to cache this?
    pub fn len(&self) -> usize {
        match self { &Leaf(ref s) => s.len()
                   , &Branch(BranchNode { ref left, ref right, .. }) =>
                        left.len() + right.len()
                    }
    }

    /// Calculates the weight of a node
    #[inline]
    fn subtree_weight (&self) -> usize {
        match self { &Leaf(ref s) => s.len()
                   , &Branch(BranchNode { ref left, .. }) =>
                        left.subtree_weight()
                    }
    }

    /// Rebalance the subrope starting at this `Node`, returning a new `Node`
    ///
    /// From "Ropes: An Alternative to Strings":
    /// > "The rebalancing operation maintains an ordered sequence of (empty
    /// > or) balanced ropes, one for each length interval [_Fn_, _Fn_+1), for
    /// > _n_ >= 2. We traverse the rope from left to right, inserting each
    /// > leaf into the appropriate sequence position, depending on its length.
    ///
    /// > The concatenation of the sequence of ropes in order of decreasing
    /// > length is equivalent to the prefix of the rope we have traversed so
    /// > far. Each new leaf _x_ is with_insert_ropeed into the appropriate entry of the
    /// > sequence. Assume that _x_’s length is in the interval [_Fn_, _Fn_+1),
    /// > and thus it should be put in slot _n_ (which also corresponds to
    /// > maximum depth _n_ − 2). If all lower and equal numbered levels are
    /// > empty, then this can be done directly. If not, then we concatenate
    /// > ropes in slots 2, ... ,(_n_ − 1) (concatenating onto the left), and
    /// > concatenate _x_ to the right of the result. We then continue to
    /// > concatenate ropes from the sequence in increasing order to the left
    /// > of this result, until the result fits into an empty slot in the
    /// > sequence."
    pub fn rebalance(self) -> Self {
        // TODO: this is a huge mess, I based it on the IBM Java implementation
        //       please refactor until it stops being ugly!
        //        - eliza, 12/17/2016

        if self.is_balanced() {
            // the subrope is already balanced, do nothing
            self
        } else {
            let mut leaves: Vec<Option<Node>> =
                self.into_leaves().map(Option::Some).collect();
            let len = leaves.len();
            fn _rebalance(l: &mut Vec<Option<Node>>, start: usize, end: usize)
                          -> Node {
                match end - start {
                    1 => l[start].take().unwrap()
                  , 2 => l[start].take().unwrap() + l[start + 1].take().unwrap()
                  , n => {
                        let mid = start + (n / 2);
                        _rebalance(l, start, mid) + _rebalance(l, mid, end)

                    }
                }
            };
            _rebalance(&mut leaves, 0, len)
        }
    }

    /// Returns an iterator over all leaf nodes in this `Node`'s subrope
    fn leaves<'a>(&'a self) -> Leaves<'a> {
        Leaves(vec![self])
    }

    /// Returns a move iterator over all leaf nodes in this `Node`'s subrope
    fn into_leaves(self) -> IntoLeaves {
        IntoLeaves(vec![self])
    }

    /// Returns an iterator over all the strings in this `Node`s subrope'
    #[inline]
    pub fn strings<'a>(&'a self) -> impl Iterator<Item=&'a str> {
        box self.leaves().map(|n| match n {
            &Leaf(ref s) => s.as_ref()
          , _ => unreachable!("Node.leaves() iterator contained something \
                               that wasn't a leaf. Barring _force majeure_, \
                               this should be impossible. Something's broken.")
        })
    }

    /// Returns a move iterator over all the strings in this `Node`s subrope'
    ///
    /// Consumes `self`.
    #[inline]
    pub fn into_strings(self) -> impl Iterator<Item=String> {
        box self.into_leaves().map(|n| match n {
            Leaf(s) => s
            , _ => unreachable!("Node.into_leaves() iterator contained \
                                 something  that wasn't a leaf. Barring _force \
                                 majeure_, this should be impossible. \
                                 Something's broken.")
        })
    }

    str_iters! {
        #[doc="Returns an iterator over all the bytes in this `Node`'s \
               subrope \n\

               \nAs a Rope consists of a sequence of bytes, we can iterate \
               through a rope by byte. This method returns such an iterator."]
        #[inline]
        impl bytes<u8> for Node {}
        #[doc="Returns an iterator over all the characters in this `Node`'s \
               subrope \n\

               \nAs a `Rope` consists of valid UTF-8, we can iterate through a \
               `Rope` by `char`. This method returns such an iterator. \n\

               \nIt's important to remember that `char` represents a Unicode \
               Scalar Value, and may not match your idea of what a \
               'character' is. Iteration over grapheme clusters may be what \
               you actually want."]
        #[inline]
        impl chars<char> for Node {}
        // TODO: this is actually Wrong, the indices will wrap around once we
        //       iterate into the next leaf node. we'll need to write our own
        //       char_indices iterator that tracks the character's index in the
        //       global Rope. shouldn't be too hard, just a fold...
        //          - eliza, 12/18/2016
        // #[inline]
        // impl char_indices<(usize, char)> for Node {}
        #[inline]
        impl split_whitespace<&'a str> for Node {}
        #[inline]
        impl lines<&'a str> for Node {}
    }

    // /// Returns n iterator over the bytes of this `Node`'s subrope
    // ///
    // ///
    // #[inline]
    // pub fn bytes<'a>(&'a self) -> impl Iterator<Item=u8> + 'a {
    //     self.strings().flat_map(str::bytes)
    // }

    /// Returns an iterator over the grapheme clusters of this `Node`'s subrope'
    ///
    /// This is the iterator returned by `Node::into_iter`.
    #[inline]
    pub fn graphemes<'a>(&'a self) -> impl Iterator<Item=&'a str> {
        // the compiler won't let me mark this as unimplemented using the
        // unimplemented!() macro, due to Reasons (i suspect relating to
        // returning `impl Trait`)
        //  - eliza, 12/18/2016
        panic!("Unimplemented!");
        self.strings()
    }

}

/// An iterator over a series of leaf `Node`s
struct Leaves<'a>(Vec<&'a Node>);

impl<'a> Iterator for Leaves<'a> {
    type Item = &'a Node;
    fn next(&mut self) -> Option<Self::Item> {
        match self.0.pop() {
            None => None
          , Some(leaf @ &Leaf(_)) => Some(leaf)
          , Some(&Branch(BranchNode { ref left, ref right, .. })) => {
                self.0.push(right);
                self.0.push(left);
                self.next()
            }
        }
    }
}

/// A move iterator over a series of leaf `Node`s
struct IntoLeaves(Vec<Node>);

impl Iterator for IntoLeaves {
    type Item = Node;
    fn next(&mut self) -> Option<Self::Item> {
        match self.0.pop() {
            None => None
          , Some(leaf @ Leaf(_)) => Some(leaf)
          , Some(Branch(BranchNode { box left, box right, .. })) => {
                self.0.push(right);
                self.0.push(left);
                self.next()
            }
        }
    }
}

impl ops::Add for Node {
    type Output = Self;
    /// Concatenate two `Node`s, returning a `Branch` node.
    fn add(self, right: Self) -> Self { Node::new_branch(self, right) }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use codespan::Span;
use hex;
use std::{
    cmp::Ordering,
    convert::TryFrom,
    fmt,
    hash::{Hash, Hasher},
    sync::atomic::{AtomicUsize, Ordering as AtomicOrdering},
};

pub mod ast_debug;
pub mod fake_natives;
pub mod remembering_unique_map;
pub mod unique_map;

//**************************************************************************************************
// Address
//**************************************************************************************************

pub const ADDRESS_LENGTH: usize = 32;

#[derive(Ord, PartialOrd, Eq, PartialEq, Hash, Default, Clone, Copy)]
pub struct Address([u8; ADDRESS_LENGTH]);

impl Address {
    pub const LIBRA_CORE: Address = Address::new([
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0,
    ]);

    pub const fn new(address: [u8; ADDRESS_LENGTH]) -> Self {
        Address(address)
    }

    pub fn to_u8(self) -> [u8; ADDRESS_LENGTH] {
        self.0
    }

    pub fn parse_str(s: &str) -> Result<Address, String> {
        let mut hex_string = String::from(&s[2..]);
        if hex_string.len() % 2 != 0 {
            hex_string.insert(0, '0');
        }

        let mut result = hex::decode(hex_string.as_str()).unwrap();
        let len = result.len();
        if len < 32 {
            result.reverse();
            for _ in len..32 {
                result.push(0);
            }
            result.reverse();
        }

        assert!(result.len() >= 32);
        Self::try_from(&result[..]).map_err(|_| {
            format!(
                "Address is {} bytes long. The maximum size is {} bytes",
                result.len(),
                ADDRESS_LENGTH
            )
        })
    }
}

impl AsRef<[u8]> for Address {
    fn as_ref(&self) -> &[u8] {
        &self.0
    }
}

impl fmt::Display for Address {
    fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
        write!(f, "0x{:#x}", self)
    }
}

impl fmt::Debug for Address {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "0x{:#x}", self)
    }
}

impl fmt::LowerHex for Address {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let encoded = hex::encode(&self.0);
        let dropped = encoded
            .chars()
            .skip_while(|c| c == &'0')
            .collect::<String>();
        if dropped.is_empty() {
            write!(f, "0")
        } else {
            write!(f, "{}", dropped)
        }
    }
}

impl TryFrom<&[u8]> for Address {
    type Error = String;

    fn try_from(bytes: &[u8]) -> Result<Address, String> {
        if bytes.len() != ADDRESS_LENGTH {
            Err(format!("The Address {:?} is of invalid length", bytes))
        } else {
            let mut addr = [0u8; ADDRESS_LENGTH];
            addr.copy_from_slice(bytes);
            Ok(Address(addr))
        }
    }
}

//**************************************************************************************************
// Loc
//**************************************************************************************************

#[derive(Debug, Copy, Clone, Default, Eq, PartialEq)]
pub struct Loc {
    file: &'static str,
    span: Span,
}
impl Loc {
    pub fn new(file: &'static str, span: Span) -> Loc {
        Loc { file, span }
    }

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

    pub fn span(self) -> Span {
        self.span
    }
}

impl PartialOrd for Loc {
    fn partial_cmp(&self, other: &Loc) -> Option<Ordering> {
        let file_ord = self.file.partial_cmp(other.file)?;
        if file_ord != Ordering::Equal {
            return Some(file_ord);
        }

        let start_ord = self.span.start().partial_cmp(&other.span.start())?;
        if start_ord != Ordering::Equal {
            return Some(start_ord);
        }

        self.span.end().partial_cmp(&other.span.end())
    }
}

impl Ord for Loc {
    fn cmp(&self, other: &Loc) -> Ordering {
        self.file.cmp(other.file).then_with(|| {
            self.span
                .start()
                .cmp(&other.span.start())
                .then_with(|| self.span.end().cmp(&other.span.end()))
        })
    }
}

pub trait TName: Eq + Ord + Clone {
    type Key: Ord + Clone;
    type Loc: Copy;
    fn drop_loc(self) -> (Self::Loc, Self::Key);
    fn clone_drop_loc(&self) -> (Self::Loc, Self::Key);
    fn add_loc(loc: Self::Loc, key: Self::Key) -> Self;
}

pub trait Identifier {
    fn value(&self) -> &str;
    fn loc(&self) -> Loc;
}

//**************************************************************************************************
// Spanned
//**************************************************************************************************

#[derive(Copy, Clone, Default)]
pub struct Spanned<T> {
    pub loc: Loc,
    pub value: T,
}

impl<T> Spanned<T> {
    pub fn new(loc: Loc, value: T) -> Spanned<T> {
        Spanned { loc, value }
    }
}

impl<T: PartialEq> PartialEq for Spanned<T> {
    fn eq(&self, other: &Spanned<T>) -> bool {
        self.value == other.value
    }
}

impl<T: Eq> Eq for Spanned<T> {}

impl<T: Hash> Hash for Spanned<T> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.value.hash(state);
    }
}

impl<T: PartialOrd> PartialOrd for Spanned<T> {
    fn partial_cmp(&self, other: &Spanned<T>) -> Option<Ordering> {
        self.value.partial_cmp(&other.value)
    }
}

impl<T: Ord> Ord for Spanned<T> {
    fn cmp(&self, other: &Spanned<T>) -> Ordering {
        self.value.cmp(&other.value)
    }
}

impl<T: fmt::Display> fmt::Display for Spanned<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}", &self.value)
    }
}

impl<T: fmt::Debug> fmt::Debug for Spanned<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}", &self.value)
    }
}

impl<T: ast_debug::AstDebug> ast_debug::AstDebug for Spanned<T> {
    fn ast_debug(&self, w: &mut ast_debug::AstWriter) {
        self.value.ast_debug(w)
    }
}

/// Function used to have nearly tuple-like syntax for creating a Spanned
pub const fn sp<T>(loc: Loc, value: T) -> Spanned<T> {
    Spanned { loc, value }
}

/// Macro used to create a tuple-like pattern match for Spanned
macro_rules! sp {
    (_, $value:pat) => {
        Spanned { value: $value, .. }
    };
    ($loc:pat, _) => {
        Spanned { loc: $loc, .. }
    };
    ($loc:pat, $value:pat) => {
        Spanned {
            loc: $loc,
            value: $value,
        }
    };
}

//**************************************************************************************************
// Name
//**************************************************************************************************

// TODO maybe we should intern these strings somehow
pub type Name = Spanned<String>;

impl TName for Name {
    type Key = String;
    type Loc = Loc;

    fn drop_loc(self) -> (Loc, String) {
        (self.loc, self.value)
    }

    fn clone_drop_loc(&self) -> (Loc, String) {
        (self.loc, self.value.clone())
    }

    fn add_loc(loc: Loc, key: String) -> Self {
        sp(loc, key)
    }
}

//**************************************************************************************************
// Name
//**************************************************************************************************

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Counter(usize);

impl Counter {
    pub fn next() -> u64 {
        static COUNTER_NEXT: AtomicUsize = AtomicUsize::new(0);

        COUNTER_NEXT.fetch_add(1, AtomicOrdering::AcqRel) as u64
    }
}

//**************************************************************************************************
// Display
//**************************************************************************************************

pub fn format_delim<T: fmt::Display, I: IntoIterator<Item = T>>(items: I, delim: &str) -> String {
    items
        .into_iter()
        .map(|item| format!("{}", item))
        .collect::<Vec<_>>()
        .join(delim)
}

pub fn format_comma<T: fmt::Display, I: IntoIterator<Item = T>>(items: I) -> String {
    format_delim(items, ",")
}
<commit_msg>[language][move] Avoid hardcoded 32 byte address length in a few more places<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use codespan::Span;
use hex;
use std::{
    cmp::Ordering,
    convert::TryFrom,
    fmt,
    hash::{Hash, Hasher},
    sync::atomic::{AtomicUsize, Ordering as AtomicOrdering},
};

pub mod ast_debug;
pub mod fake_natives;
pub mod remembering_unique_map;
pub mod unique_map;

//**************************************************************************************************
// Address
//**************************************************************************************************

pub const ADDRESS_LENGTH: usize = 32;

#[derive(Ord, PartialOrd, Eq, PartialEq, Hash, Default, Clone, Copy)]
pub struct Address([u8; ADDRESS_LENGTH]);

impl Address {
    pub const LIBRA_CORE: Address = Address::new([
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0,
    ]);

    pub const fn new(address: [u8; ADDRESS_LENGTH]) -> Self {
        Address(address)
    }

    pub fn to_u8(self) -> [u8; ADDRESS_LENGTH] {
        self.0
    }

    pub fn parse_str(s: &str) -> Result<Address, String> {
        let mut hex_string = String::from(&s[2..]);
        if hex_string.len() % 2 != 0 {
            hex_string.insert(0, '0');
        }

        let mut result = hex::decode(hex_string.as_str()).unwrap();
        let len = result.len();
        if len < ADDRESS_LENGTH {
            result.reverse();
            for _ in len..ADDRESS_LENGTH {
                result.push(0);
            }
            result.reverse();
        }

        assert!(result.len() >= ADDRESS_LENGTH);
        Self::try_from(&result[..]).map_err(|_| {
            format!(
                "Address is {} bytes long. The maximum size is {} bytes",
                result.len(),
                ADDRESS_LENGTH
            )
        })
    }
}

impl AsRef<[u8]> for Address {
    fn as_ref(&self) -> &[u8] {
        &self.0
    }
}

impl fmt::Display for Address {
    fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
        write!(f, "0x{:#x}", self)
    }
}

impl fmt::Debug for Address {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "0x{:#x}", self)
    }
}

impl fmt::LowerHex for Address {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let encoded = hex::encode(&self.0);
        let dropped = encoded
            .chars()
            .skip_while(|c| c == &'0')
            .collect::<String>();
        if dropped.is_empty() {
            write!(f, "0")
        } else {
            write!(f, "{}", dropped)
        }
    }
}

impl TryFrom<&[u8]> for Address {
    type Error = String;

    fn try_from(bytes: &[u8]) -> Result<Address, String> {
        if bytes.len() != ADDRESS_LENGTH {
            Err(format!("The Address {:?} is of invalid length", bytes))
        } else {
            let mut addr = [0u8; ADDRESS_LENGTH];
            addr.copy_from_slice(bytes);
            Ok(Address(addr))
        }
    }
}

//**************************************************************************************************
// Loc
//**************************************************************************************************

#[derive(Debug, Copy, Clone, Default, Eq, PartialEq)]
pub struct Loc {
    file: &'static str,
    span: Span,
}
impl Loc {
    pub fn new(file: &'static str, span: Span) -> Loc {
        Loc { file, span }
    }

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

    pub fn span(self) -> Span {
        self.span
    }
}

impl PartialOrd for Loc {
    fn partial_cmp(&self, other: &Loc) -> Option<Ordering> {
        let file_ord = self.file.partial_cmp(other.file)?;
        if file_ord != Ordering::Equal {
            return Some(file_ord);
        }

        let start_ord = self.span.start().partial_cmp(&other.span.start())?;
        if start_ord != Ordering::Equal {
            return Some(start_ord);
        }

        self.span.end().partial_cmp(&other.span.end())
    }
}

impl Ord for Loc {
    fn cmp(&self, other: &Loc) -> Ordering {
        self.file.cmp(other.file).then_with(|| {
            self.span
                .start()
                .cmp(&other.span.start())
                .then_with(|| self.span.end().cmp(&other.span.end()))
        })
    }
}

pub trait TName: Eq + Ord + Clone {
    type Key: Ord + Clone;
    type Loc: Copy;
    fn drop_loc(self) -> (Self::Loc, Self::Key);
    fn clone_drop_loc(&self) -> (Self::Loc, Self::Key);
    fn add_loc(loc: Self::Loc, key: Self::Key) -> Self;
}

pub trait Identifier {
    fn value(&self) -> &str;
    fn loc(&self) -> Loc;
}

//**************************************************************************************************
// Spanned
//**************************************************************************************************

#[derive(Copy, Clone, Default)]
pub struct Spanned<T> {
    pub loc: Loc,
    pub value: T,
}

impl<T> Spanned<T> {
    pub fn new(loc: Loc, value: T) -> Spanned<T> {
        Spanned { loc, value }
    }
}

impl<T: PartialEq> PartialEq for Spanned<T> {
    fn eq(&self, other: &Spanned<T>) -> bool {
        self.value == other.value
    }
}

impl<T: Eq> Eq for Spanned<T> {}

impl<T: Hash> Hash for Spanned<T> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.value.hash(state);
    }
}

impl<T: PartialOrd> PartialOrd for Spanned<T> {
    fn partial_cmp(&self, other: &Spanned<T>) -> Option<Ordering> {
        self.value.partial_cmp(&other.value)
    }
}

impl<T: Ord> Ord for Spanned<T> {
    fn cmp(&self, other: &Spanned<T>) -> Ordering {
        self.value.cmp(&other.value)
    }
}

impl<T: fmt::Display> fmt::Display for Spanned<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
        write!(f, "{}", &self.value)
    }
}

impl<T: fmt::Debug> fmt::Debug for Spanned<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}", &self.value)
    }
}

impl<T: ast_debug::AstDebug> ast_debug::AstDebug for Spanned<T> {
    fn ast_debug(&self, w: &mut ast_debug::AstWriter) {
        self.value.ast_debug(w)
    }
}

/// Function used to have nearly tuple-like syntax for creating a Spanned
pub const fn sp<T>(loc: Loc, value: T) -> Spanned<T> {
    Spanned { loc, value }
}

/// Macro used to create a tuple-like pattern match for Spanned
macro_rules! sp {
    (_, $value:pat) => {
        Spanned { value: $value, .. }
    };
    ($loc:pat, _) => {
        Spanned { loc: $loc, .. }
    };
    ($loc:pat, $value:pat) => {
        Spanned {
            loc: $loc,
            value: $value,
        }
    };
}

//**************************************************************************************************
// Name
//**************************************************************************************************

// TODO maybe we should intern these strings somehow
pub type Name = Spanned<String>;

impl TName for Name {
    type Key = String;
    type Loc = Loc;

    fn drop_loc(self) -> (Loc, String) {
        (self.loc, self.value)
    }

    fn clone_drop_loc(&self) -> (Loc, String) {
        (self.loc, self.value.clone())
    }

    fn add_loc(loc: Loc, key: String) -> Self {
        sp(loc, key)
    }
}

//**************************************************************************************************
// Name
//**************************************************************************************************

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Counter(usize);

impl Counter {
    pub fn next() -> u64 {
        static COUNTER_NEXT: AtomicUsize = AtomicUsize::new(0);

        COUNTER_NEXT.fetch_add(1, AtomicOrdering::AcqRel) as u64
    }
}

//**************************************************************************************************
// Display
//**************************************************************************************************

pub fn format_delim<T: fmt::Display, I: IntoIterator<Item = T>>(items: I, delim: &str) -> String {
    items
        .into_iter()
        .map(|item| format!("{}", item))
        .collect::<Vec<_>>()
        .join(delim)
}

pub fn format_comma<T: fmt::Display, I: IntoIterator<Item = T>>(items: I) -> String {
    format_delim(items, ",")
}
<|endoftext|>