<commit_before>//! The Tessellated Intelligence System is a
//!
//! > massively parallel computer architecture comprised of non-uniformly
//! > interconnected heterogeneous nodes.
//!
//! The manual can be found [online](https://www.vidarholen.net/contents/junk/files/TIS-100%20Reference%20Manual.pdf).
//! Another useful resource is the unofficial [TIS-100 Hackers Guide](https://alandesmet.github.io/TIS-100-Hackers-Guide/).
//!
//! # Examples
//! Here we take a node and execute some instructions and check if double 1 has
//! the expected result.
//!
//! ```rust
//! extern crate tis_100_superoptimizer;
//!
//! use tis_100_superoptimizer::TIS_100::{Node,Instruction,Source,Destination,Register};
//!
//! fn main() {
//!     let node: Node = Node::new();
//!     let last: Node = node
//!         .execute(Instruction::MOV(Source::Literal(1), Destination::Register(Register::ACC)))
//!         .execute(Instruction::ADD(Source::Register(Register::ACC)));
//!
//!     assert_eq!(2, last.acc);
//! }
//! ```

use std::fmt::{Debug,Formatter,Error};

/// A `Node` models the basic execution node in TIS-100. You change a node state
/// by executing an `Instruction` on it.
#[derive(Debug,PartialEq,Eq)]
pub struct Node {
    /// The accumulator for the basic execution node.
    pub acc: i32,
    bac: i32,
    pc: isize,
    program: Program,
}

/// A `Program` is a sequence of `Instruction`s
pub struct Program(Vec<Instruction>);

impl PartialEq for Program {
    fn eq(&self, other: &Program) -> bool {
        let Program(ref self_instructions) = *self;
        let Program(ref other_instructions) = *other;
        if self_instructions.len() == other_instructions.len() {
            for index in 0..(self_instructions.len()) {
                let ref self_instruction = self_instructions[index];
                let ref other_instruction = other_instructions[index];
                if self_instruction != other_instruction {
                    return false
                }
            }
            true
        } else {
            false
        }
    }
}

impl Eq for Program {}

impl Debug for Program {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        let Program(ref instructions) = *self;
        write!(f, "[{}:", instructions.len()).unwrap();
        for instruction in instructions {
            write!(f, " {:?}", instruction).unwrap();
        }
        write!(f, "]")
    }
}

impl Clone for Program {
    fn clone(&self) -> Program {
        let mut clone_instructions: Vec<Instruction> = vec![];
        let Program(ref self_instructions) = *self;
        for ref mut instruction in self_instructions {
            clone_instructions.push(instruction.clone());
        }
        Program(clone_instructions)
    }
}

/// `Instruction`s are executed by a `Node`.
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Instruction {
    /// Does nothing
    NOP,
    /// Moves value from `Source` to `Destination`
    MOV(Source, Destination),
    /// Swaps the value of the accumulator (acc) and the backup (bac) register
    SWP,
    /// Saves the value of the accumulator (acc) to the backup register
    SAV,
    /// Add value from `Source` to accumulator (acc), storing result in acc
    ADD(Source),
    /// Subtracts value from `Source` from accumulator (acc), storing result in acc
    SUB(Source),
}

/// `Source` are either ports, registers or literals
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Source {
    /// A register
    Register(Register),
    /// A literal value
    Literal(i32)
}

/// Different types of Registers known in TIS-100
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Register {
    /// the NIL register, reading from it provides with zero
    NIL,
    /// The accumulator
    ACC,
}

/// `Destination` are either ports or registers
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Destination {
    /// A register
    Register(Register),
}

impl Node {
    /// Create a `Node` with defaults for accumulator and backup registers
    pub fn new() -> Node {
        Node { acc: 0, bac: 0, pc: 0, program: Program(vec![]) }
    }

    /// Create a `Node` from self with the program counter incremented
    pub fn increment_pc(&self) -> Node {
        Node { pc: self.pc + 1, program: self.program.clone(), .. *self }
    }

    /// Create a `Node` from self with a prescribed program counter value
    pub fn set_pc(&self, pc: isize) -> Node {
        Node { pc: pc, program: self.program.clone(), .. *self }
    }

    /// Create a `Node` from self with a prescribed accumulator register value
    pub fn set_acc(&self, acc: i32) -> Node {
        Node { acc: acc, program: self.program.clone(), .. *self }
    }

    /// Create a `Node` from self with a prescribed backup register value
    pub fn set_bac(&self, bac: i32) -> Node {
        Node { bac: bac, program: self.program.clone(), .. *self }
    }

    /// Execute the `instruction` on this `Node`. Returns a `Node` that reflects
    /// the changes the `instruction` would have on this `Node`.
    pub fn execute(&self, instruction: Instruction) -> Node {
        match instruction {
            Instruction::NOP => self.nop(),
            Instruction::MOV(source, destination) => self.mov(source, destination) ,
            Instruction::SWP => self.swap(),
            Instruction::SAV => self.save(),
            Instruction::ADD(source) => self.add(source),
            Instruction::SUB(source) => self.subtract(source),
        }
    }

    fn nop(&self) -> Node {
        self.increment_pc()
    }

    fn mov(&self, source: Source, destination: Destination) -> Node {
        let value: i32 = self.value_from(source);

        self.move_value(value, destination)
    }

    fn value_from(&self, source: Source) -> i32 {
        match source {
            Source::Register(Register::NIL) => 0,
            Source::Register(Register::ACC) => self.acc,
            Source::Literal(value) => value,
        }
    }

    fn move_value(&self, value: i32, destination: Destination) -> Node {
        match destination {
            Destination::Register(Register::ACC) => self.increment_pc().set_acc(value),
            _ => self.nop(),
        }
    }

    fn swap(&self) -> Node {
        let acc: i32 = self.acc;
        let bac: i32 = self.bac;

        self.increment_pc().set_acc(bac).set_bac(acc)
    }

    fn save(&self) -> Node {
        self.increment_pc().set_bac(self.acc)
    }

    fn add(&self, source: Source) -> Node{
        let value: i32 = self.value_from(source);

        self.add_value(value)
    }

    fn add_value(&self, value: i32) -> Node {
        self.increment_pc().set_acc(self.acc + value)
    }

    fn subtract(&self, source: Source) -> Node {
        let value: i32 = self.value_from(source);

        self.subtract_value(value)
    }

    fn subtract_value(&self, value: i32) -> Node {
        self.increment_pc().set_acc(self.acc - value)
    }
}

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

    fn node_with(acc: i32, bac: i32, pc: isize) -> Node {
        Node::new().set_acc(acc).set_bac(bac).set_pc(pc)
    }

    #[test]
    fn node_should_start_with_accumulator_zero() {
        let node: Node = Node::new();

        assert_eq!(0, node.acc);
    }

    #[test]
    fn node_should_start_with_backup_zero() {
        let node: Node = Node::new();
        let instruction: Instruction = Instruction::SWP;

        let next: Node = node.execute(instruction);

        assert_eq!(0, next.acc);
    }

    #[test]
    fn node_should_execute_NOP_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::NOP;

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn node_should_execute_MOV_from_NIL_to_NIL_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::MOV(Source::Register(Register::NIL),
                                                        Destination::Register(Register::NIL));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn node_should_execute_MOV_from_ACC_to_ACC_correctly() {
        let node: Node = Node::new().set_acc(2).set_bac(1);
        let instruction: Instruction = Instruction::MOV(Source::Register(Register::ACC),
                                                        Destination::Register(Register::ACC));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(2, 1, 1), next);
    }

    #[test]
    fn node_should_execute_MOV_from_Literal_to_ACC_correctly() {
        let node: Node = Node::new();
        let instruction: Instruction = Instruction::MOV(Source::Literal(1),
                                                        Destination::Register(Register::ACC));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn node_should_execute_SWP_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::SWP;

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(0, 1, 1), next);
    }

    #[test]
    fn node_should_execute_SAV_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::SAV;

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 1, 1), next);
    }

    #[test]
    fn node_should_execute_ADD_from_Literal_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::ADD(Source::Literal(1));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(2, 0, 1), next);
    }

    #[test]
    fn node_should_execute_SUB_from_Literal_correctly() {
        let node: Node = Node::new().set_acc(2);
        let instruction: Instruction = Instruction::SUB(Source::Literal(1));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn programs_should_differ_when_different_size() {
        assert_eq!(false, Program(vec![]) == Program(vec![Instruction::SAV]));
    }

    #[test]
    fn programs_should_differ_when_different_instructions() {
        assert_eq!(false, Program(vec![Instruction::SWP]) == Program(vec![Instruction::SAV]));
    }

    #[test]
    fn programs_should_equal_with_same_instructions() {
        assert_eq!(Program(vec![Instruction::SAV]), Program(vec![Instruction::SAV]));
    }
}

<commit_msg>Run a program<commit_after>//! The Tessellated Intelligence System is a
//!
//! > massively parallel computer architecture comprised of non-uniformly
//! > interconnected heterogeneous nodes.
//!
//! The manual can be found [online](https://www.vidarholen.net/contents/junk/files/TIS-100%20Reference%20Manual.pdf).
//! Another useful resource is the unofficial [TIS-100 Hackers Guide](https://alandesmet.github.io/TIS-100-Hackers-Guide/).
//!
//! # Examples
//! Here we take a node and execute some instructions and check if double 1 has
//! the expected result.
//!
//! ```rust
//! extern crate tis_100_superoptimizer;
//!
//! use tis_100_superoptimizer::TIS_100::{Node,Instruction,Source,Destination,Register};
//!
//! fn main() {
//!     let node: Node = Node::new();
//!     let last: Node = node
//!         .execute(Instruction::MOV(Source::Literal(1), Destination::Register(Register::ACC)))
//!         .execute(Instruction::ADD(Source::Register(Register::ACC)));
//!
//!     assert_eq!(2, last.acc);
//! }
//! ```

use std::fmt::{Debug,Formatter,Error};

/// A `Node` models the basic execution node in TIS-100. You change a node state
/// by executing an `Instruction` on it.
#[derive(Debug,PartialEq,Eq)]
pub struct Node {
    /// The accumulator for the basic execution node.
    pub acc: i32,
    bac: i32,
    pc: usize,
    program: Program,
}

/// A `Program` is a sequence of `Instruction`s
pub struct Program(Vec<Instruction>);

impl PartialEq for Program {
    fn eq(&self, other: &Program) -> bool {
        let Program(ref self_instructions) = *self;
        let Program(ref other_instructions) = *other;
        if self_instructions.len() == other_instructions.len() {
            for index in 0..(self_instructions.len()) {
                let ref self_instruction = self_instructions[index];
                let ref other_instruction = other_instructions[index];
                if self_instruction != other_instruction {
                    return false
                }
            }
            true
        } else {
            false
        }
    }
}

impl Eq for Program {}

impl Debug for Program {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        let Program(ref instructions) = *self;
        write!(f, "[{}:", instructions.len()).unwrap();
        for instruction in instructions {
            write!(f, " {:?}", instruction).unwrap();
        }
        write!(f, "]")
    }
}

impl Clone for Program {
    fn clone(&self) -> Program {
        let mut clone_instructions: Vec<Instruction> = vec![];
        let Program(ref self_instructions) = *self;
        for ref mut instruction in self_instructions {
            clone_instructions.push(instruction.clone());
        }
        Program(clone_instructions)
    }
}

/// `Instruction`s are executed by a `Node`.
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Instruction {
    /// Does nothing
    NOP,
    /// Moves value from `Source` to `Destination`
    MOV(Source, Destination),
    /// Swaps the value of the accumulator (acc) and the backup (bac) register
    SWP,
    /// Saves the value of the accumulator (acc) to the backup register
    SAV,
    /// Add value from `Source` to accumulator (acc), storing result in acc
    ADD(Source),
    /// Subtracts value from `Source` from accumulator (acc), storing result in acc
    SUB(Source),
}

/// `Source` are either ports, registers or literals
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Source {
    /// A register
    Register(Register),
    /// A literal value
    Literal(i32)
}

/// Different types of Registers known in TIS-100
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Register {
    /// the NIL register, reading from it provides with zero
    NIL,
    /// The accumulator
    ACC,
}

/// `Destination` are either ports or registers
#[derive(Debug,PartialEq,Eq,Clone)]
pub enum Destination {
    /// A register
    Register(Register),
}

/// The `Status` a `Program` run on a certain `Node`.
pub enum Status {
    /// a successful run of the program
    Successful(Node),
    /// an unsuccessful run of the program, because of a deadlock. I.e.
    Deadlock(Node),
}

impl Node {
    /// Create a `Node` with defaults for accumulator and backup registers
    pub fn new() -> Node {
        Node { acc: 0, bac: 0, pc: 0, program: Program(vec![]) }
    }

    /// Loads a program in this `Node`
    pub fn load(&self, program: Program) -> Node {
        Node { program: program.clone(), .. *self }
    }

    /// Run the loaded program, returning an calculation state
    pub fn run(&self) -> Status {
        let mut node = Node { program: self.program.clone(), .. *self };

        loop {
            match node.fetch_instruction() {
                Some(instruction) => {
                    node = node.execute(instruction);
                }
                None => {
                    break
                }
            }
        }

        Status::Successful(Node { program: node.program.clone(), .. node })
    }

    fn fetch_instruction(&self) -> Option<Instruction> {
        let Program(ref instructions) = self.program;
        if self.pc < instructions.len() {
            Some(instructions[self.pc].clone())
        } else {
            None
        }
    }

    /// Create a `Node` from self with the program counter incremented
    pub fn increment_pc(&self) -> Node {
        Node { pc: self.pc + 1, program: self.program.clone(), .. *self }
    }

    /// Create a `Node` from self with a prescribed program counter value
    pub fn set_pc(&self, pc: usize) -> Node {
        Node { pc: pc, program: self.program.clone(), .. *self }
    }

    /// Create a `Node` from self with a prescribed accumulator register value
    pub fn set_acc(&self, acc: i32) -> Node {
        Node { acc: acc, program: self.program.clone(), .. *self }
    }

    /// Create a `Node` from self with a prescribed backup register value
    pub fn set_bac(&self, bac: i32) -> Node {
        Node { bac: bac, program: self.program.clone(), .. *self }
    }

    /// Execute the `instruction` on this `Node`. Returns a `Node` that reflects
    /// the changes the `instruction` would have on this `Node`.
    pub fn execute(&self, instruction: Instruction) -> Node {
        match instruction {
            Instruction::NOP => self.nop(),
            Instruction::MOV(source, destination) => self.mov(source, destination) ,
            Instruction::SWP => self.swap(),
            Instruction::SAV => self.save(),
            Instruction::ADD(source) => self.add(source),
            Instruction::SUB(source) => self.subtract(source),
        }
    }

    fn nop(&self) -> Node {
        self.increment_pc()
    }

    fn mov(&self, source: Source, destination: Destination) -> Node {
        let value: i32 = self.value_from(source);

        self.move_value(value, destination)
    }

    fn value_from(&self, source: Source) -> i32 {
        match source {
            Source::Register(Register::NIL) => 0,
            Source::Register(Register::ACC) => self.acc,
            Source::Literal(value) => value,
        }
    }

    fn move_value(&self, value: i32, destination: Destination) -> Node {
        match destination {
            Destination::Register(Register::ACC) => self.increment_pc().set_acc(value),
            _ => self.nop(),
        }
    }

    fn swap(&self) -> Node {
        let acc: i32 = self.acc;
        let bac: i32 = self.bac;

        self.increment_pc().set_acc(bac).set_bac(acc)
    }

    fn save(&self) -> Node {
        self.increment_pc().set_bac(self.acc)
    }

    fn add(&self, source: Source) -> Node{
        let value: i32 = self.value_from(source);

        self.add_value(value)
    }

    fn add_value(&self, value: i32) -> Node {
        self.increment_pc().set_acc(self.acc + value)
    }

    fn subtract(&self, source: Source) -> Node {
        let value: i32 = self.value_from(source);

        self.subtract_value(value)
    }

    fn subtract_value(&self, value: i32) -> Node {
        self.increment_pc().set_acc(self.acc - value)
    }
}

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

    fn node_with(acc: i32, bac: i32, pc: usize) -> Node {
        Node::new().set_acc(acc).set_bac(bac).set_pc(pc)
    }

    #[test]
    fn node_should_start_with_accumulator_zero() {
        let node: Node = Node::new();

        assert_eq!(0, node.acc);
    }

    #[test]
    fn node_should_start_with_backup_zero() {
        let node: Node = Node::new();
        let instruction: Instruction = Instruction::SWP;

        let next: Node = node.execute(instruction);

        assert_eq!(0, next.acc);
    }

    #[test]
    fn node_should_execute_NOP_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::NOP;

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn node_should_execute_MOV_from_NIL_to_NIL_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::MOV(Source::Register(Register::NIL),
                                                        Destination::Register(Register::NIL));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn node_should_execute_MOV_from_ACC_to_ACC_correctly() {
        let node: Node = Node::new().set_acc(2).set_bac(1);
        let instruction: Instruction = Instruction::MOV(Source::Register(Register::ACC),
                                                        Destination::Register(Register::ACC));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(2, 1, 1), next);
    }

    #[test]
    fn node_should_execute_MOV_from_Literal_to_ACC_correctly() {
        let node: Node = Node::new();
        let instruction: Instruction = Instruction::MOV(Source::Literal(1),
                                                        Destination::Register(Register::ACC));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn node_should_execute_SWP_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::SWP;

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(0, 1, 1), next);
    }

    #[test]
    fn node_should_execute_SAV_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::SAV;

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 1, 1), next);
    }

    #[test]
    fn node_should_execute_ADD_from_Literal_correctly() {
        let node: Node = Node::new().set_acc(1);
        let instruction: Instruction = Instruction::ADD(Source::Literal(1));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(2, 0, 1), next);
    }

    #[test]
    fn node_should_execute_SUB_from_Literal_correctly() {
        let node: Node = Node::new().set_acc(2);
        let instruction: Instruction = Instruction::SUB(Source::Literal(1));

        let next: Node = node.execute(instruction);

        assert_eq!(node_with(1, 0, 1), next);
    }

    #[test]
    fn programs_should_differ_when_different_size() {
        assert_eq!(false, Program(vec![]) == Program(vec![Instruction::SAV]));
    }

    #[test]
    fn programs_should_differ_when_different_instructions() {
        assert_eq!(false, Program(vec![Instruction::SWP]) == Program(vec![Instruction::SAV]));
    }

    #[test]
    fn programs_should_equal_with_same_instructions() {
        assert_eq!(Program(vec![Instruction::SAV]), Program(vec![Instruction::SAV]));
    }

    #[test]
    fn node_should_execute_program_correctly() {
        let program: Program = Program(vec![// calculate 4 * source - 1
            Instruction::MOV(Source::Literal(1), Destination::Register(Register::ACC)),
            Instruction::ADD(Source::Register(Register::ACC)),
            Instruction::ADD(Source::Register(Register::ACC)),
            Instruction::SUB(Source::Literal(1))
        ]);
        let node: Node = Node::new().load(program);

        match node.run() {
            Status::Successful(_) => assert!(true),
            Status::Deadlock(_) => assert!(false),
        }
    }
}

<|endoftext|>


<commit_before>use af;
use af::{Array};
use num::Complex;

use utils;
use error::HALError;

/// Returns the tanh activated value
pub fn tanh(x: &Array) -> Array {
  af::tanh(x)
}

/// Returns the sigmoid activated value
/// 1.0/(1.0 + exp(-1.0 * e))
pub fn sigmoid(x: &Array) -> Array {
  let neg_one = utils::constant(x.dims(), x.get_type(), -1.0f32);
  let one = utils::constant(x.dims(), x.get_type(), 1.0f32);
  let exp_m_e = af::exp(&af::mul(&neg_one, x, false));
  let denominator = af::add(&one, &exp_m_e, false);
  let a = af::div(&one, &denominator, false);
  utils::assert_types(vec![x, &a]);
  a
}

/// Return the softmax activated value [numerical stable]
/// exp(x_i) / sum(exp(x))
pub fn softmax(x: &Array) -> Array {
  // page 185 of http://www.deeplearningbook.org/contents/mlp.html
  let z = x - af::max_all(x).0 as f32;
  let exponentiated = af::exp(&z);
  let sum_epx_x = af::sum_all(&exponentiated).0 as f32;
  let sum_exp_x_vec = utils::constant(x.dims(), x.get_type(), sum_epx_x);
  let a = af::div(&exponentiated, &sum_exp_x_vec, false);
  utils::assert_types(vec![x, &a]);
  a
}

/// Return the lrelu activated value
/// max(0.01*x, x)
pub fn lrelu(x: &Array) -> Array {
  let zero_one = utils::constant(x.dims(), x.get_type(), 0.01f32);
  let scaled = af::mul(x, &zero_one, false);
  let a = af::select(&scaled                               // return 0.01x
                     , &af::lt(x, &0.0f32, false) // if x > 0.0
                     , x);                        // else x
  utils::assert_types(vec![x, &a]);
  a
}

/// Return the derivative of relu [assumes that relu has already been applied]
/// 0.01     for x <= 0
/// 1        otherwise
pub fn lrelu_derivative(x: &Array) -> Array {
  let x_lt_zero = utils::constant(x.dims(), x.get_type(), 0.01f32);
  let one = utils::constant(x.dims(), x.get_type(), 1.0f32);
  let grad = af::select(&one, &af::gt(x, &0.0f32, false), &x_lt_zero);
  utils::assert_types(vec![x, &grad]);
  grad
}

/// Return the relu activated value
/// max(0, x)
pub fn relu(x: &Array) -> Array {
  let zero = utils::constant(x.dims(), x.get_type(), 0.0f32);
  let a = af::select(&zero, &af::lt(x, &0.0, false), x);
  utils::assert_types(vec![x, &a]);
  a
}

/// Return the derivative of relu [assumes that relu has already been applied]
/// 0 for x <= 0
/// 1 otherwise
pub fn relu_derivative(x: &Array) -> Array {
  let zero = utils::constant(x.dims(), x.get_type(), 0.0f32);
  let one = utils::constant(x.dims(), x.get_type(), 1.0f32);
  let grad = af::select(&one, &af::gt(x, &0.0f32, false), &zero);
  utils::assert_types(vec![x, &grad]);
  grad
}

/// Return the derivative of tanh [assumes that tanh has already been applied]
/// 1 - tanh(x)*tanh(x)
pub fn tanh_derivative(x: &Array) -> Array {
  let one = utils::constant(x.dims(), x.get_type(), 1.0f32);
  let grad = af::sub(&one, &af::mul(x, x, false), false);
  utils::assert_types(vec![x, &grad]);
  grad
}

/// Returns the derivative of sigmoid [assumes that sigmoid is already applied]
/// x * (1 - x)
pub fn sigmoid_derivative(x: &Array) -> Array {
  let one = utils::constant(x.dims(), x.get_type(), 1.0f32);
  let grad = af::mul(x, &af::sub(&one, x, false), false);
  utils::assert_types(vec![x, &grad]);
  grad
}

/// Returns the derivative of softmax [assumes that it was already applied]
/// x * (1 - x)
pub fn softmax_derivative(x: &Array) -> Array {
  // let orig_dims = x.dims();
  // let slide_dims = orig_dims;
  // slide_dims[2] = slide_dims[1];
  // slide_dims[1] = 1;
  // let j = af::mul(x, &af::moddims(x, slide_dims));
  // let diag = sigmoid_derivative(x);
  // af::print(&af::diag_extract(&j, 1))
  sigmoid_derivative(x)
}

/// Returns a linear activation [no non-linearity]
pub fn ones(x: &Array) -> Array {
  x.clone()
}

/// Returns a derivative of a linear activation (1's)
pub fn ones_derivative(x: &Array) -> Array {
  let grad = utils::constant(x.dims(), x.get_type(), 1.0f32);
  utils::assert_types(vec![x, &grad]);
  grad
}

/// Helper to determine whether function is smooth or non-smooth
pub fn is_smooth(name: &str) -> bool {
  match name {
    "softmax" => true,
    "sigmoid" => true,
    "relu"    => false,
    "lrelu"   => false,
    "tanh"    => true,
    "ones"    => true,
    "linear"  => true,
    _         => panic!("unknown function name provided"),
  }
}

/// Helper to get the correct activation using a string
pub fn get_activation(name: &str, x: &Array) -> Result<Array, HALError> {
  match name {
    "softmax" => Ok(softmax(x)),
    "sigmoid" => Ok(sigmoid(x)),
    "relu"    => Ok(relu(x)),
    "lrelu"   => Ok(lrelu(x)),
    "tanh"    => Ok(tanh(x)),
    "ones"    => Ok(ones(x)),
    "linear"  => Ok(ones(x)),
    _         => Err(HALError::UNKNOWN),
  }
}

/// Helper to get the correct activation derivative using a string
pub fn get_derivative(name: &str, x: &Array) -> Result<Array, HALError> {
  match name {
    "softmax" => Ok(softmax_derivative(x)),
    "sigmoid" => Ok(sigmoid_derivative(x)),
    "relu"    => Ok(relu_derivative(x)),
    "lrelu"   => Ok(lrelu_derivative(x)),
    "tanh"    => Ok(tanh_derivative(x)),
    "ones"    => Ok(ones_derivative(x)),
    "linear"  => Ok(ones_derivative(x)),
    _         => Err(HALError::UNKNOWN),
  }
}
<commit_msg>softmax difference row wise<commit_after>use af;
use af::{Array};
use num::Complex;

use utils;
use error::HALError;

/// Returns the tanh activated value
pub fn tanh(x: &Array) -> Array {
  af::tanh(x)
}

/// Returns the sigmoid activated value
/// 1.0/(1.0 + exp(-1.0 * e))
pub fn sigmoid(x: &Array) -> Array {
  let neg_one = utils::constant(x.dims(), x.get_type(), -1.0f32);
  let one = utils::constant(x.dims(), x.get_type(), 1.0f32);
  let exp_m_e = af::exp(&af::mul(&neg_one, x, false));
  let denominator = af::add(&one, &exp_m_e, false);
  let a = af::div(&one, &denominator, false);
  utils::assert_types(vec![x, &a]);
  a
}

/// Return the softmax activated value [numerical stable]
/// exp(x_i) / sum(exp(x))
pub fn softmax(x: &Array) -> Array {
  // page 185 of http://www.deeplearningbook.org/contents/mlp.html
  let z = af::sub(x, &af::max(x, 0), true);
  let exponentiated = af::exp(&z);
  let sum_epx_x = af::sum_all(&exponentiated).0 as f32;
  let sum_exp_x_vec = utils::constant(x.dims(), x.get_type(), sum_epx_x);
  let a = af::div(&exponentiated, &sum_exp_x_vec, false);
  utils::assert_types(vec![x, &a]);
  a
}

/// Return the lrelu activated value
/// max(0.01*x, x)
pub fn lrelu(x: &Array) -> Array {
  let zero_one = utils::constant(x.dims(), x.get_type(), 0.01f32);
  let scaled = af::mul(x, &zero_one, false);
  let a = af::select(&scaled                               // return 0.01x
                     , &af::lt(x, &0.0f32, false) // if x > 0.0
                     , x);                        // else x
  utils::assert_types(vec![x, &a]);
  a
}

/// Return the derivative of relu [assumes that relu has already been applied]
/// 0.01     for x <= 0
/// 1        otherwise
pub fn lrelu_derivative(x: &Array) -> Array {
  let x_lt_zero = utils::constant(x.dims(), x.get_type(), 0.01f32);
  let one = utils::constant(x.dims(), x.get_type(), 1.0f32);
  let grad = af::select(&one, &af::gt(x, &0.0f32, false), &x_lt_zero);
  utils::assert_types(vec![x, &grad]);
  grad
}

/// Return the relu activated value
/// max(0, x)
pub fn relu(x: &Array) -> Array {
  let zero = utils::constant(x.dims(), x.get_type(), 0.0f32);
  let a = af::select(&zero, &af::lt(x, &0.0, false), x);
  utils::assert_types(vec![x, &a]);
  a
}

/// Return the derivative of relu [assumes that relu has already been applied]
/// 0 for x <= 0
/// 1 otherwise
pub fn relu_derivative(x: &Array) -> Array {
  let zero = utils::constant(x.dims(), x.get_type(), 0.0f32);
  let one = utils::constant(x.dims(), x.get_type(), 1.0f32);
  let grad = af::select(&one, &af::gt(x, &0.0f32, false), &zero);
  utils::assert_types(vec![x, &grad]);
  grad
}

/// Return the derivative of tanh [assumes that tanh has already been applied]
/// 1 - tanh(x)*tanh(x)
pub fn tanh_derivative(x: &Array) -> Array {
  let one = utils::constant(x.dims(), x.get_type(), 1.0f32);
  let grad = af::sub(&one, &af::mul(x, x, false), false);
  utils::assert_types(vec![x, &grad]);
  grad
}

/// Returns the derivative of sigmoid [assumes that sigmoid is already applied]
/// x * (1 - x)
pub fn sigmoid_derivative(x: &Array) -> Array {
  let one = utils::constant(x.dims(), x.get_type(), 1.0f32);
  let grad = af::mul(x, &af::sub(&one, x, false), false);
  utils::assert_types(vec![x, &grad]);
  grad
}

/// Returns the derivative of softmax [assumes that it was already applied]
/// x * (1 - x)
pub fn softmax_derivative(x: &Array) -> Array {
  // let orig_dims = x.dims();
  // let slide_dims = orig_dims;
  // slide_dims[2] = slide_dims[1];
  // slide_dims[1] = 1;
  // let j = af::mul(x, &af::moddims(x, slide_dims));
  // let diag = sigmoid_derivative(x);
  // af::print(&af::diag_extract(&j, 1))
  sigmoid_derivative(x)
}

/// Returns a linear activation [no non-linearity]
pub fn ones(x: &Array) -> Array {
  x.clone()
}

/// Returns a derivative of a linear activation (1's)
pub fn ones_derivative(x: &Array) -> Array {
  let grad = utils::constant(x.dims(), x.get_type(), 1.0f32);
  utils::assert_types(vec![x, &grad]);
  grad
}

/// Helper to determine whether function is smooth or non-smooth
pub fn is_smooth(name: &str) -> bool {
  match name {
    "softmax" => true,
    "sigmoid" => true,
    "relu"    => false,
    "lrelu"   => false,
    "tanh"    => true,
    "ones"    => true,
    "linear"  => true,
    _         => panic!("unknown function name provided"),
  }
}

/// Helper to get the correct activation using a string
pub fn get_activation(name: &str, x: &Array) -> Result<Array, HALError> {
  match name {
    "softmax" => Ok(softmax(x)),
    "sigmoid" => Ok(sigmoid(x)),
    "relu"    => Ok(relu(x)),
    "lrelu"   => Ok(lrelu(x)),
    "tanh"    => Ok(tanh(x)),
    "ones"    => Ok(ones(x)),
    "linear"  => Ok(ones(x)),
    _         => Err(HALError::UNKNOWN),
  }
}

/// Helper to get the correct activation derivative using a string
pub fn get_derivative(name: &str, x: &Array) -> Result<Array, HALError> {
  match name {
    "softmax" => Ok(softmax_derivative(x)),
    "sigmoid" => Ok(sigmoid_derivative(x)),
    "relu"    => Ok(relu_derivative(x)),
    "lrelu"   => Ok(lrelu_derivative(x)),
    "tanh"    => Ok(tanh_derivative(x)),
    "ones"    => Ok(ones_derivative(x)),
    "linear"  => Ok(ones_derivative(x)),
    _         => Err(HALError::UNKNOWN),
  }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::collections::hash_map::{Entry, HashMap};
use std::collections::hash_set::HashSet;
use std::rc::Rc;
use std::cmp;
use std::mem;

use js_types::js_type::{JsVar, JsType, JsPtrEnum};
use uuid::Uuid;

// Initial Arena size in bytes
const INITIAL_SIZE: usize = 1024;
// Minimum Arena capacity is at least 1 byte
const MIN_CAP: usize = 1;

pub type Alloc<T> = Rc<RefCell<T>>;

pub struct Scope {
    parent: Option<Rc<Scope>>,
    children: Vec<Box<Scope>>,
    black_set: HashMap<Uuid, Alloc<JsVar>>,
    grey_set: HashMap<Uuid, Alloc<JsVar>>,
    white_set: HashMap<Uuid, Alloc<JsVar>>,
    get_roots: Box<Fn() -> HashSet<Uuid>>,
}

impl Scope {
    pub fn new<F>(get_roots: F) -> Scope
        where F: Fn() -> HashSet<Uuid> + 'static {
        Scope {
            parent: None,
            children: Vec::new(),
            black_set: HashMap::new(),
            grey_set: HashMap::new(),
            white_set: HashMap::new(),
            get_roots: Box::new(get_roots),
        }
    }

    pub fn as_child<F>(parent: Rc<Scope>, get_roots: F) -> Scope
        where F: Fn() -> HashSet<Uuid> + 'static {
        Scope {
            parent: Some(parent),
            children: Vec::new(),
            black_set: HashMap::new(),
            grey_set: HashMap::new(),
            white_set: HashMap::new(),
            get_roots: Box::new(get_roots),
        }
    }

    pub fn set_parent(&mut self, parent: Rc<Scope>) {
        self.parent = Some(parent);
    }

    pub fn add_child(&mut self, child: Scope) {
        self.children.push(Box::new(child));
    }

    pub fn alloc(&mut self, var: JsVar) -> Uuid {
        let uuid = var.uuid;
        self.white_set.insert(uuid, Rc::new(RefCell::new(var)));
        uuid
    }

    pub fn dealloc(&mut self, uuid: &Uuid) -> bool {
        if let Some(_) = self.white_set.remove(uuid) { true } else { false }
    }

    pub fn get_var_copy(&self, uuid: &Uuid) -> Option<JsVar> {
        self.find_id(uuid).map(|var| var.borrow().clone())
    }

    pub fn update_var(&mut self, var: JsVar) -> bool {
        if let Entry::Occupied(mut view) = self.find_id_mut(&var.uuid) {
            let inner = view.get_mut();
            *inner.borrow_mut() = var;
            true
        } else { false }
    }

    /// TODO Compute the roots of the current scope-- any variable that is
    /// directly referenced or declared within the scope. This might just be the
    /// key set of the uuid map(?) Not necessarily, I think. What if you do
    /// something like this:
    /// var x = {}
    /// var y = { 1: x }
    /// y = x
    /// y would be a root by the definition above, but is no longer reachable at
    /// the end of the scope because it now aliases x. A better definition would
    /// be "Any variable that is declared or referenced directly, but a direct
    /// reference (variable usage) supercedes a declaration." The above example
    /// demonstrates why this is necessary.
    /// This should come from the interpreter, so I shouldn't actually have to
    /// care about getting the root set myself.

    /// Roots always get marked as Black, since they're always reachable from
    /// the current scope. NB that this assumes all root references are actually
    /// valid reference types, i.e. they're not numbers, etc.
    pub fn mark_roots(&mut self) {
        let marks = (self.get_roots)();
        for mark in marks.iter() {
            if let Some(var) = self.white_set.remove(mark) {
                let uuid = var.borrow().uuid;
                // Get all child references
                let child_ids = Scope::get_var_children(&var);
                // Mark current ref as black
                self.black_set.insert(uuid, var);
                // Mark child references as grey
                self.grey_children(child_ids);
            }
        }
    }

    pub fn mark_phase(&mut self) {
        // Mark any grey object as black, and mark all white objs it refs as grey
        let mut new_grey_set = HashMap::new();
        for (uuid, var) in self.grey_set.drain() {
            let child_ids = Scope::get_var_children(&var);
            self.black_set.insert(uuid, var);
            for child_id in child_ids {
                if let Some(var) = self.white_set.remove(&child_id) {
                    new_grey_set.insert(child_id, var);
                }
            }
        }
        self.grey_set = new_grey_set;
    }

    pub fn sweep_phase(&mut self) {
        self.white_set = HashMap::new();
    }

    pub fn find_id(&self, uuid: &Uuid) -> Option<&Alloc<JsVar>> {
        self.white_set.get(uuid).or_else(||
            self.grey_set.get(uuid).or_else(||
                self.black_set.get(uuid)))
    }

    fn find_id_mut(&mut self, uuid: &Uuid) -> Entry<Uuid, Alloc<JsVar>> {
        if let e @ Entry::Occupied(_) = self.white_set.entry(*uuid) {
            e
        } else if let e @ Entry::Occupied(_) = self.grey_set.entry(*uuid) {
            e
        } else { self.black_set.entry(*uuid) }
    }

    fn grey_children(&mut self, child_ids: HashSet<Uuid>) {
        for child_id in child_ids.iter() {
            if let Some(var) = self.white_set.remove(child_id) {
                self.grey_set.insert(*child_id, var);
            }
        }
    }

    fn get_var_children(var: &Alloc<JsVar>) -> HashSet<Uuid> {
        if let JsType::JsPtr(ref ptr) = (*var.borrow()).t {
            match ptr {
                &JsPtrEnum::JsObj(ref obj) => obj.get_children(),
                _ => HashSet::new(),
            }
        } else { HashSet::new() }
    }

}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::hash_set::HashSet;
    use std::rc::Rc;
    use js_types::js_type::{JsVar, JsType, JsPtrEnum, JsKey, JsKeyEnum};
    use js_types::js_obj::{JsObjStruct};
    use uuid::Uuid;

    fn dummy_get_roots() -> HashSet<Uuid> {
        HashSet::new()
    }

    fn make_num(i: f64) -> JsVar {
        JsVar::new(JsType::JsNum(i))
    }

    fn make_obj(kvs: Vec<(JsKey, Alloc<JsVar>)>) -> JsVar {
        JsVar::new(JsType::JsPtr(JsPtrEnum::JsObj(JsObjStruct::new(None, "test", kvs))))
    }

    #[test]
    fn test_new_scope() {
        let mut test_scope = Scope::new(dummy_get_roots);
        assert!(test_scope.parent.is_none());
        assert!(test_scope.black_set.is_empty());
        assert!(test_scope.grey_set.is_empty());
        assert!(test_scope.white_set.is_empty());
        assert_eq!(test_scope.children.len(), 0);
    }

    #[test]
    fn test_as_child_scope() {
        let parent_scope = Scope::new(dummy_get_roots);
        let mut test_scope = Scope::as_child(Rc::new(parent_scope), dummy_get_roots);

        assert!(test_scope.parent.is_some());
        assert!(test_scope.black_set.is_empty());
        assert!(test_scope.grey_set.is_empty());
        assert!(test_scope.white_set.is_empty());
        assert_eq!(test_scope.children.len(), 0);
    }

    #[test]
    fn test_set_parent() {
        let parent_scope = Scope::new(dummy_get_roots);
        let mut test_scope = Scope::new(dummy_get_roots);
        assert!(test_scope.parent.is_none());
        test_scope.set_parent(Rc::new(parent_scope));
        assert!(test_scope.parent.is_some());
    }

    #[test]
    fn test_add_child() {
        let mut test_scope = Scope::new(dummy_get_roots);
        let child_scope1 = Scope::new(dummy_get_roots);
        let child_scope2 = Scope::new(dummy_get_roots);
        assert_eq!(test_scope.children.len(), 0);
        test_scope.add_child(child_scope1);
        assert_eq!(test_scope.children.len(), 1);
        test_scope.add_child(child_scope2);
        assert_eq!(test_scope.children.len(), 2);
    }

    #[test]
    fn test_alloc() {
        let mut test_scope = Scope::new(dummy_get_roots);
        let test_var = make_num(1.0);
        let test_uuid = test_var.uuid.clone();
        let uuid = test_scope.alloc(test_var);
        assert_eq!(test_uuid, uuid);
        assert!(test_scope.white_set.contains_key(&uuid));
        assert_eq!(test_scope.white_set.len(), 1);
        assert_eq!(test_scope.grey_set.len(), 0);
        assert_eq!(test_scope.black_set.len(), 0);
        let test_var2 = make_num(2.0);
        let uuid = test_scope.alloc(test_var2);
        assert!(test_scope.white_set.contains_key(&uuid));
        assert_eq!(test_scope.white_set.len(), 2);
        assert_eq!(test_scope.grey_set.len(), 0);
        assert_eq!(test_scope.black_set.len(), 0);
    }

    #[test]
    fn test_dealloc() {
        let mut test_scope = Scope::new(dummy_get_roots);
        let test_var = make_num(1.0);
        let uuid = test_scope.alloc(test_var);
        let bad_uuid = Uuid::new_v4();
        assert!(test_scope.dealloc(&uuid));
        assert_eq!(test_scope.white_set.len(), 0);
        assert_eq!(test_scope.grey_set.len(), 0);
        assert_eq!(test_scope.black_set.len(), 0);
        assert!(!test_scope.dealloc(&bad_uuid));
    }

    #[test]
    fn test_get_var_copy() {
        let mut test_scope = Scope::new(dummy_get_roots);
        let test_var = make_num(1.0);
        let uuid = test_scope.alloc(test_var);
        let bad_uuid = Uuid::new_v4();
        let var_copy = test_scope.get_var_copy(&uuid);
        assert!(var_copy.is_some());
        let var = var_copy.unwrap();
        assert_eq!(var.uuid, uuid);
        let bad_copy = test_scope.get_var_copy(&bad_uuid);
        assert!(bad_copy.is_none());
    }

    #[test]
    fn test_update_var() {
        let mut test_scope = Scope::new(dummy_get_roots);
        let test_var = make_num(1.0);
        let uuid = test_scope.alloc(test_var);
        let mut update = test_scope.get_var_copy(&uuid).unwrap();
        update = make_num(2.0);
        update.uuid = uuid;
        assert!(test_scope.update_var(update));
        let update = test_scope.get_var_copy(&uuid).unwrap();
        match update {
            JsVar{ t: JsType::JsNum(i), ..} => assert_eq!(i, 2.0),
            _ => ()
        }
        test_scope.dealloc(&uuid);
        assert!(!test_scope.update_var(update));
    }

    #[test]
    fn test_mark_roots() {
        let test_uuid = Uuid::new_v4();
        let mut test_var = make_num(1.0);
        let mut test_var2 = make_num(2.0);
        test_var.uuid = test_uuid;
        let simple_get_roots = move || { let mut set = HashSet::new();
                                    set.insert(test_uuid);
                                    set };
        let mut test_scope = Scope::new(simple_get_roots);
        let test_uuid = test_scope.alloc(test_var);
        let test_uuid2 = test_scope.alloc(test_var2);
        test_scope.mark_roots();
        assert_eq!(test_scope.black_set.len(), 1);
        assert!(test_scope.black_set.get(&test_uuid).is_some());
        assert!(test_scope.black_set.get(&test_uuid2).is_none());
    }

    #[test]
    fn test_mark_phase() {
        let test_uuid = Uuid::new_v4();
        let simple_get_roots = move || { let mut set = HashSet::new();
                                    set.insert(test_uuid);
                                    set };
        let mut test_scope = Scope::new(simple_get_roots);

        let mut test_var2 = make_num(2.0);
        let test_uuid2 = test_scope.alloc(test_var2);
        let test_var2_alloc = test_scope.find_id(&test_uuid2).unwrap().clone();

        let test_key = JsKey::new(JsKeyEnum::JsNum(1.0));
        let mut test_var = make_obj(vec![(test_key, test_var2_alloc)]);
        test_var.uuid = test_uuid;
        let test_uuid = test_scope.alloc(test_var);

        // Mark roots first...
        test_scope.mark_roots();
        assert!(test_scope.black_set.get(&test_uuid).is_some());
        assert_eq!(test_scope.black_set.len(), 1);
        assert_eq!(test_scope.grey_set.len(), 1);

        // ...then mark everything else
        test_scope.mark_phase();

        assert_eq!(test_scope.grey_set.len(), 0);
        assert!(test_scope.black_set.get(&test_uuid).is_some());
        assert!(test_scope.black_set.get(&test_uuid2).is_some());
    }
}
<commit_msg>Change Scopes to have Weak<T> parents and Rc<T> children<commit_after>use std::cell::RefCell;
use std::collections::hash_map::{Entry, HashMap};
use std::collections::hash_set::HashSet;
use std::rc::{Rc, Weak};
use std::cmp;
use std::mem;

use js_types::js_type::{JsVar, JsType, JsPtrEnum};
use uuid::Uuid;

// Initial Arena size in bytes
const INITIAL_SIZE: usize = 1024;
// Minimum Arena capacity is at least 1 byte
const MIN_CAP: usize = 1;

pub type Alloc<T> = Rc<RefCell<T>>;

pub struct Scope {
    pub parent: Option<Weak<Scope>>,
    children: Vec<Rc<Scope>>,
    black_set: HashMap<Uuid, Alloc<JsVar>>,
    grey_set: HashMap<Uuid, Alloc<JsVar>>,
    white_set: HashMap<Uuid, Alloc<JsVar>>,
    get_roots: Box<Fn() -> HashSet<Uuid>>,
}

impl Scope {
    pub fn new<F>(get_roots: F) -> Scope
        where F: Fn() -> HashSet<Uuid> + 'static {
        Scope {
            parent: None,
            children: Vec::new(),
            black_set: HashMap::new(),
            grey_set: HashMap::new(),
            white_set: HashMap::new(),
            get_roots: Box::new(get_roots),
        }
    }

    pub fn as_child<F>(parent: Weak<Scope>, get_roots: F) -> Scope
        where F: Fn() -> HashSet<Uuid> + 'static {
        Scope {
            parent: Some(parent),
            children: Vec::new(),
            black_set: HashMap::new(),
            grey_set: HashMap::new(),
            white_set: HashMap::new(),
            get_roots: Box::new(get_roots),
        }
    }

    pub fn set_parent(&mut self, parent: &Rc<Scope>) {
        self.parent = Some(Rc::downgrade(&parent.clone()));
    }

    pub fn add_child(&mut self, child: Scope) -> &mut Rc<Scope> {
        self.children.push(Rc::new(child));
        let num_children = self.children.len();
        &mut self.children[num_children - 1]
    }

    pub fn alloc(&mut self, var: JsVar) -> Uuid {
        let uuid = var.uuid;
        self.white_set.insert(uuid, Rc::new(RefCell::new(var)));
        uuid
    }

    pub fn dealloc(&mut self, uuid: &Uuid) -> bool {
        if let Some(_) = self.white_set.remove(uuid) { true } else { false }
    }

    pub fn get_var_copy(&self, uuid: &Uuid) -> Option<JsVar> {
        self.find_id(uuid).map(|var| var.borrow().clone())
    }

    pub fn update_var(&mut self, var: JsVar) -> bool {
        if let Entry::Occupied(mut view) = self.find_id_mut(&var.uuid) {
            let inner = view.get_mut();
            *inner.borrow_mut() = var;
            true
        } else { false }
    }

    /// TODO Compute the roots of the current scope-- any variable that is
    /// directly referenced or declared within the scope. This might just be the
    /// key set of the uuid map(?) Not necessarily, I think. What if you do
    /// something like this:
    /// var x = {}
    /// var y = { 1: x }
    /// y = x
    /// y would be a root by the definition above, but is no longer reachable at
    /// the end of the scope because it now aliases x. A better definition would
    /// be "Any variable that is declared or referenced directly, but a direct
    /// reference (variable usage) supercedes a declaration." The above example
    /// demonstrates why this is necessary.
    /// This should come from the interpreter, so I shouldn't actually have to
    /// care about getting the root set myself.

    /// Roots always get marked as Black, since they're always reachable from
    /// the current scope. NB that this assumes all root references are actually
    /// valid reference types, i.e. they're not numbers, etc.
    pub fn mark_roots(&mut self) {
        let marks = (self.get_roots)();
        for mark in marks.iter() {
            if let Some(var) = self.white_set.remove(mark) {
                let uuid = var.borrow().uuid;
                // Get all child references
                let child_ids = Scope::get_var_children(&var);
                // Mark current ref as black
                self.black_set.insert(uuid, var);
                // Mark child references as grey
                self.grey_children(child_ids);
            }
        }
    }

    pub fn mark_phase(&mut self) {
        // Mark any grey object as black, and mark all white objs it refs as grey
        let mut new_grey_set = HashMap::new();
        for (uuid, var) in self.grey_set.drain() {
            let child_ids = Scope::get_var_children(&var);
            self.black_set.insert(uuid, var);
            for child_id in child_ids {
                if let Some(var) = self.white_set.remove(&child_id) {
                    new_grey_set.insert(child_id, var);
                }
            }
        }
        self.grey_set = new_grey_set;
    }

    pub fn sweep_phase(&mut self) {
        self.white_set = HashMap::new();
    }

    pub fn find_id(&self, uuid: &Uuid) -> Option<&Alloc<JsVar>> {
        self.white_set.get(uuid).or_else(||
            self.grey_set.get(uuid).or_else(||
                self.black_set.get(uuid)))
    }

    fn find_id_mut(&mut self, uuid: &Uuid) -> Entry<Uuid, Alloc<JsVar>> {
        if let e @ Entry::Occupied(_) = self.white_set.entry(*uuid) {
            e
        } else if let e @ Entry::Occupied(_) = self.grey_set.entry(*uuid) {
            e
        } else { self.black_set.entry(*uuid) }
    }

    fn grey_children(&mut self, child_ids: HashSet<Uuid>) {
        for child_id in child_ids.iter() {
            if let Some(var) = self.white_set.remove(child_id) {
                self.grey_set.insert(*child_id, var);
            }
        }
    }

    fn get_var_children(var: &Alloc<JsVar>) -> HashSet<Uuid> {
        if let JsType::JsPtr(ref ptr) = (*var.borrow()).t {
            match ptr {
                &JsPtrEnum::JsObj(ref obj) => obj.get_children(),
                _ => HashSet::new(),
            }
        } else { HashSet::new() }
    }

}

#[cfg(test)]
mod tests {
    use super::*;
    use std::collections::hash_set::HashSet;
    use std::rc::{Rc, Weak};
    use js_types::js_type::{JsVar, JsType, JsPtrEnum, JsKey, JsKeyEnum};
    use js_types::js_obj::{JsObjStruct};
    use uuid::Uuid;

    fn dummy_get_roots() -> HashSet<Uuid> {
        HashSet::new()
    }

    fn make_num(i: f64) -> JsVar {
        JsVar::new(JsType::JsNum(i))
    }

    fn make_obj(kvs: Vec<(JsKey, Alloc<JsVar>)>) -> JsVar {
        JsVar::new(JsType::JsPtr(JsPtrEnum::JsObj(JsObjStruct::new(None, "test", kvs))))
    }

    #[test]
    fn test_new_scope() {
        let mut test_scope = Scope::new(dummy_get_roots);
        assert!(test_scope.parent.is_none());
        assert!(test_scope.black_set.is_empty());
        assert!(test_scope.grey_set.is_empty());
        assert!(test_scope.white_set.is_empty());
        assert_eq!(test_scope.children.len(), 0);
    }

    #[test]
    fn test_as_child_scope() {
        let parent_scope = Rc::new(Scope::new(dummy_get_roots));
        let mut test_scope = Scope::as_child(Rc::downgrade(&parent_scope.clone()), dummy_get_roots);

        assert!(test_scope.parent.is_some());
        assert!(test_scope.black_set.is_empty());
        assert!(test_scope.grey_set.is_empty());
        assert!(test_scope.white_set.is_empty());
        assert_eq!(test_scope.children.len(), 0);
    }

    #[test]
    fn test_set_parent() {
        let parent_scope = Rc::new(Scope::new(dummy_get_roots));
        let mut test_scope = Scope::new(dummy_get_roots);
        assert!(test_scope.parent.is_none());
        test_scope.set_parent(&parent_scope);
        assert!(test_scope.parent.is_some());
    }

    #[test]
    fn test_add_child() {
        let mut test_scope = Scope::new(dummy_get_roots);
        let child_scope1 = Scope::new(dummy_get_roots);
        let child_scope2 = Scope::new(dummy_get_roots);
        assert_eq!(test_scope.children.len(), 0);
        test_scope.add_child(child_scope1);
        assert_eq!(test_scope.children.len(), 1);
        test_scope.add_child(child_scope2);
        assert_eq!(test_scope.children.len(), 2);
    }

    #[test]
    fn test_alloc() {
        let mut test_scope = Scope::new(dummy_get_roots);
        let test_var = make_num(1.0);
        let test_uuid = test_var.uuid.clone();
        let uuid = test_scope.alloc(test_var);
        assert_eq!(test_uuid, uuid);
        assert!(test_scope.white_set.contains_key(&uuid));
        assert_eq!(test_scope.white_set.len(), 1);
        assert_eq!(test_scope.grey_set.len(), 0);
        assert_eq!(test_scope.black_set.len(), 0);
        let test_var2 = make_num(2.0);
        let uuid = test_scope.alloc(test_var2);
        assert!(test_scope.white_set.contains_key(&uuid));
        assert_eq!(test_scope.white_set.len(), 2);
        assert_eq!(test_scope.grey_set.len(), 0);
        assert_eq!(test_scope.black_set.len(), 0);
    }

    #[test]
    fn test_dealloc() {
        let mut test_scope = Scope::new(dummy_get_roots);
        let test_var = make_num(1.0);
        let uuid = test_scope.alloc(test_var);
        let bad_uuid = Uuid::new_v4();
        assert!(test_scope.dealloc(&uuid));
        assert_eq!(test_scope.white_set.len(), 0);
        assert_eq!(test_scope.grey_set.len(), 0);
        assert_eq!(test_scope.black_set.len(), 0);
        assert!(!test_scope.dealloc(&bad_uuid));
    }

    #[test]
    fn test_get_var_copy() {
        let mut test_scope = Scope::new(dummy_get_roots);
        let test_var = make_num(1.0);
        let uuid = test_scope.alloc(test_var);
        let bad_uuid = Uuid::new_v4();
        let var_copy = test_scope.get_var_copy(&uuid);
        assert!(var_copy.is_some());
        let var = var_copy.unwrap();
        assert_eq!(var.uuid, uuid);
        let bad_copy = test_scope.get_var_copy(&bad_uuid);
        assert!(bad_copy.is_none());
    }

    #[test]
    fn test_update_var() {
        let mut test_scope = Scope::new(dummy_get_roots);
        let test_var = make_num(1.0);
        let uuid = test_scope.alloc(test_var);
        let mut update = test_scope.get_var_copy(&uuid).unwrap();
        update = make_num(2.0);
        update.uuid = uuid;
        assert!(test_scope.update_var(update));
        let update = test_scope.get_var_copy(&uuid).unwrap();
        match update {
            JsVar{ t: JsType::JsNum(i), ..} => assert_eq!(i, 2.0),
            _ => ()
        }
        test_scope.dealloc(&uuid);
        assert!(!test_scope.update_var(update));
    }

    #[test]
    fn test_mark_roots() {
        let test_uuid = Uuid::new_v4();
        let mut test_var = make_num(1.0);
        let mut test_var2 = make_num(2.0);
        test_var.uuid = test_uuid;
        let simple_get_roots = move || { let mut set = HashSet::new();
                                    set.insert(test_uuid);
                                    set };
        let mut test_scope = Scope::new(simple_get_roots);
        let test_uuid = test_scope.alloc(test_var);
        let test_uuid2 = test_scope.alloc(test_var2);
        test_scope.mark_roots();
        assert_eq!(test_scope.black_set.len(), 1);
        assert!(test_scope.black_set.get(&test_uuid).is_some());
        assert!(test_scope.black_set.get(&test_uuid2).is_none());
    }

    #[test]
    fn test_mark_phase() {
        let test_uuid = Uuid::new_v4();
        let simple_get_roots = move || { let mut set = HashSet::new();
                                    set.insert(test_uuid);
                                    set };
        let mut test_scope = Scope::new(simple_get_roots);

        let mut test_var2 = make_num(2.0);
        let test_uuid2 = test_scope.alloc(test_var2);
        let test_var2_alloc = test_scope.find_id(&test_uuid2).unwrap().clone();

        let test_key = JsKey::new(JsKeyEnum::JsNum(1.0));
        let mut test_var = make_obj(vec![(test_key, test_var2_alloc)]);
        test_var.uuid = test_uuid;
        let test_uuid = test_scope.alloc(test_var);

        // Mark roots first...
        test_scope.mark_roots();
        assert!(test_scope.black_set.get(&test_uuid).is_some());
        assert_eq!(test_scope.black_set.len(), 1);
        assert_eq!(test_scope.grey_set.len(), 1);

        // ...then mark everything else
        test_scope.mark_phase();

        assert_eq!(test_scope.grey_set.len(), 0);
        assert!(test_scope.black_set.get(&test_uuid).is_some());
        assert!(test_scope.black_set.get(&test_uuid2).is_some());
    }
}
<|endoftext|>


<commit_before>//! `cargo rm`

#![deny(missing_docs, missing_debug_implementations, missing_copy_implementations, trivial_casts, trivial_numeric_casts, unsafe_code, unstable_features, unused_import_braces, unused_qualifications)]
#![cfg_attr(feature = "dev", allow(unstable_features))]
#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]

extern crate docopt;
extern crate toml;
extern crate semver;
extern crate rustc_serialize;

use std::error::Error;
use std::io::{self, Write};
use std::process;

extern crate cargo_edit;
use cargo_edit::Manifest;

mod args;
use args::Args;

static USAGE: &'static str = r"
Usage:
    cargo rm <crate> [--dev|--build] [options]
    cargo rm (-h|--help)
    cargo rm --version

Options:
    -D --dev                Remove crate as development dependency.
    -B --build              Remove crate as build dependency.
    --manifest-path=<path>  Path to the manifest to remove a dependency from.
    -h --help               Show this help page.
    --version               Show version.

Remove a dependency to a Cargo.toml manifest file.
";

fn handle_rm(args: &Args) -> Result<(), Box<Error>> {
    let mut manifest = try!(Manifest::open(&args.flag_manifest_path.as_ref().map(|s| &s[..])));

    manifest.remove_from_table(args.get_section(), args.arg_crate.as_ref())
        .map_err(From::from)
        .and_then(|_| {
            let mut file = try!(Manifest::find_file(&args.flag_manifest_path
                .as_ref()
                .map(|s| &s[..])));
            manifest.write_to_file(&mut file)
        })
}

fn main() {
    let args = docopt::Docopt::new(USAGE)
        .and_then(|d| d.decode::<Args>())
        .unwrap_or_else(|err| err.exit());

    if args.flag_version {
        println!("cargo-rm version {}", env!("CARGO_PKG_VERSION"));
        process::exit(0);
    }

    if let Err(err) = handle_rm(&args) {
        writeln!(io::stderr(),
                 "Could not edit `Cargo.toml`.\n\nERROR: {}",
                 err)
            .unwrap();
        process::exit(1);
    }
}
<commit_msg>-V is often short for --version<commit_after>//! `cargo rm`

#![deny(missing_docs, missing_debug_implementations, missing_copy_implementations, trivial_casts, trivial_numeric_casts, unsafe_code, unstable_features, unused_import_braces, unused_qualifications)]
#![cfg_attr(feature = "dev", allow(unstable_features))]
#![cfg_attr(feature = "dev", feature(plugin))]
#![cfg_attr(feature = "dev", plugin(clippy))]

extern crate docopt;
extern crate toml;
extern crate semver;
extern crate rustc_serialize;

use std::error::Error;
use std::io::{self, Write};
use std::process;

extern crate cargo_edit;
use cargo_edit::Manifest;

mod args;
use args::Args;

static USAGE: &'static str = r"
Usage:
    cargo rm <crate> [--dev|--build] [options]
    cargo rm (-h|--help)
    cargo rm --version

Options:
    -D --dev                Remove crate as development dependency.
    -B --build              Remove crate as build dependency.
    --manifest-path=<path>  Path to the manifest to remove a dependency from.
    -h --help               Show this help page.
    -V --version            Show version.

Remove a dependency to a Cargo.toml manifest file.
";

fn handle_rm(args: &Args) -> Result<(), Box<Error>> {
    let mut manifest = try!(Manifest::open(&args.flag_manifest_path.as_ref().map(|s| &s[..])));

    manifest.remove_from_table(args.get_section(), args.arg_crate.as_ref())
        .map_err(From::from)
        .and_then(|_| {
            let mut file = try!(Manifest::find_file(&args.flag_manifest_path
                .as_ref()
                .map(|s| &s[..])));
            manifest.write_to_file(&mut file)
        })
}

fn main() {
    let args = docopt::Docopt::new(USAGE)
        .and_then(|d| d.decode::<Args>())
        .unwrap_or_else(|err| err.exit());

    if args.flag_version {
        println!("cargo-rm version {}", env!("CARGO_PKG_VERSION"));
        process::exit(0);
    }

    if let Err(err) = handle_rm(&args) {
        writeln!(io::stderr(),
                 "Could not edit `Cargo.toml`.\n\nERROR: {}",
                 err)
            .unwrap();
        process::exit(1);
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![cfg(not(test))]

extern crate log;
extern crate rustfmt;
extern crate toml;
extern crate env_logger;
extern crate getopts;

use rustfmt::{run, Input, Summary};
use rustfmt::file_lines::FileLines;
use rustfmt::config::{Config, WriteMode};

use std::{env, error};
use std::fs::{self, File};
use std::io::{self, ErrorKind, Read, Write};
use std::path::{Path, PathBuf};
use std::str::FromStr;

use getopts::{Matches, Options};

// Include git commit hash and worktree status; contents are like
//   const COMMIT_HASH: Option<&'static str> = Some("c31a366");
//   const WORKTREE_CLEAN: Option<bool> = Some(false);
// with `None` if running git failed, eg if it is not installed.
include!(concat!(env!("OUT_DIR"), "/git_info.rs"));

type FmtError = Box<error::Error + Send + Sync>;
type FmtResult<T> = std::result::Result<T, FmtError>;

/// Rustfmt operations.
enum Operation {
    /// Format files and their child modules.
    Format {
        files: Vec<PathBuf>,
        config_path: Option<PathBuf>,
    },
    /// Print the help message.
    Help,
    // Print version information
    Version,
    /// Print detailed configuration help.
    ConfigHelp,
    /// No file specified, read from stdin
    Stdin {
        input: String,
        config_path: Option<PathBuf>,
    },
}

/// Parsed command line options.
#[derive(Clone, Debug, Default)]
struct CliOptions {
    skip_children: bool,
    verbose: bool,
    write_mode: Option<WriteMode>,
    file_lines: FileLines, // Default is all lines in all files.
}

impl CliOptions {
    fn from_matches(matches: &Matches) -> FmtResult<CliOptions> {
        let mut options = CliOptions::default();
        options.skip_children = matches.opt_present("skip-children");
        options.verbose = matches.opt_present("verbose");

        if let Some(ref write_mode) = matches.opt_str("write-mode") {
            if let Ok(write_mode) = WriteMode::from_str(write_mode) {
                options.write_mode = Some(write_mode);
            } else {
                return Err(FmtError::from(format!("Invalid write-mode: {}", write_mode)));
            }
        }

        if let Some(ref file_lines) = matches.opt_str("file-lines") {
            options.file_lines = try!(file_lines.parse());
        }

        Ok(options)
    }

    fn apply_to(self, config: &mut Config) {
        config.skip_children = self.skip_children;
        config.verbose = self.verbose;
        config.file_lines = self.file_lines;
        if let Some(write_mode) = self.write_mode {
            config.write_mode = write_mode;
        }
    }
}

/// Try to find a project file in the given directory and its parents. Returns the path of a the
/// nearest project file if one exists, or `None` if no project file was found.
fn lookup_project_file(dir: &Path) -> FmtResult<Option<PathBuf>> {
    let mut current = if dir.is_relative() {
        try!(env::current_dir()).join(dir)
    } else {
        dir.to_path_buf()
    };

    current = try!(fs::canonicalize(current));

    const CONFIG_FILE_NAMES: [&'static str; 2] = [".rustfmt.toml", "rustfmt.toml"];

    loop {
        for config_file_name in &CONFIG_FILE_NAMES {
            let config_file = current.join(config_file_name);
            match fs::metadata(&config_file) {
                // Only return if it's a file to handle the unlikely situation of a directory named
                // `rustfmt.toml`.
                Ok(ref md) if md.is_file() => return Ok(Some(config_file)),
                // Return the error if it's something other than `NotFound`; otherwise we didn't
                // find the project file yet, and continue searching.
                Err(e) => {
                    if e.kind() != ErrorKind::NotFound {
                        return Err(FmtError::from(e));
                    }
                }
                _ => {}
            }
        }

        // If the current directory has no parent, we're done searching.
        if !current.pop() {
            return Ok(None);
        }
    }
}

/// Resolve the config for input in `dir`.
///
/// Returns the `Config` to use, and the path of the project file if there was
/// one.
fn resolve_config(dir: &Path) -> FmtResult<(Config, Option<PathBuf>)> {
    let path = try!(lookup_project_file(dir));
    if path.is_none() {
        return Ok((Config::default(), None));
    }
    let path = path.unwrap();
    let mut file = try!(File::open(&path));
    let mut toml = String::new();
    try!(file.read_to_string(&mut toml));
    Ok((Config::from_toml(&toml), Some(path)))
}

/// read the given config file path recursively if present else read the project file path
fn match_cli_path_or_file(config_path: Option<PathBuf>,
                          input_file: &Path)
                          -> FmtResult<(Config, Option<PathBuf>)> {

    if let Some(config_file) = config_path {
        let (toml, path) = try!(resolve_config(config_file.as_ref()));
        if path.is_some() {
            return Ok((toml, path));
        }
    }
    resolve_config(input_file)
}

fn make_opts() -> Options {
    let mut opts = Options::new();
    opts.optflag("h", "help", "show this message");
    opts.optflag("V", "version", "show version information");
    opts.optflag("v", "verbose", "show progress");
    opts.optopt("",
                "write-mode",
                "mode to write in (not usable when piping from stdin)",
                "[replace|overwrite|display|diff|coverage|checkstyle]");
    opts.optflag("", "skip-children", "don't reformat child modules");

    opts.optflag("",
                 "config-help",
                 "show details of rustfmt configuration options");
    opts.optopt("",
                "config-path",
                "Recursively searches the given path for the rustfmt.toml config file. If not \
                 found reverts to the input file path",
                "[Path for the configuration file]");
    opts.optopt("",
                "file-lines",
                "Format specified line ranges. See README for more detail on the JSON format.",
                "JSON");

    opts
}

fn execute(opts: &Options) -> FmtResult<Summary> {
    let matches = try!(opts.parse(env::args().skip(1)));

    match try!(determine_operation(&matches)) {
        Operation::Help => {
            print_usage(opts, "");
            Ok(Summary::new())
        }
        Operation::Version => {
            print_version();
            Ok(Summary::new())
        }
        Operation::ConfigHelp => {
            Config::print_docs();
            Ok(Summary::new())
        }
        Operation::Stdin { input, config_path } => {
            // try to read config from local directory
            let (mut config, _) = match_cli_path_or_file(config_path, &env::current_dir().unwrap())
                .expect("Error resolving config");

            // write_mode is always Plain for Stdin.
            config.write_mode = WriteMode::Plain;

            Ok(run(Input::Text(input), &config))
        }
        Operation::Format { mut files, config_path } => {
            let options = try!(CliOptions::from_matches(&matches));

            // Add any additional files that were specified via `--file-lines`.
            files.extend(options.file_lines.files().cloned().map(PathBuf::from));

            let mut config = Config::default();
            let mut path = None;
            // Load the config path file if provided
            if let Some(config_file) = config_path {
                let (cfg_tmp, path_tmp) = resolve_config(config_file.as_ref())
                    .expect(&format!("Error resolving config for {:?}", config_file));
                config = cfg_tmp;
                path = path_tmp;
            };
            if let Some(path) = path.as_ref() {
                println!("Using rustfmt config file {}", path.display());
            }

            let mut error_summary = Summary::new();
            for file in files {
                // Check the file directory if the config-path could not be read or not provided
                if path.is_none() {
                    let (config_tmp, path_tmp) = resolve_config(file.parent().unwrap())
                        .expect(&format!("Error resolving config for {}", file.display()));
                    if let Some(path) = path_tmp.as_ref() {
                        println!("Using rustfmt config file {} for {}",
                                 path.display(),
                                 file.display());
                    }
                    config = config_tmp;
                }

                options.clone().apply_to(&mut config);
                error_summary.add(run(Input::File(file), &config));
            }
            Ok(error_summary)
        }
    }
}

fn main() {
    let _ = env_logger::init();

    let opts = make_opts();

    let exit_code = match execute(&opts) {
        Ok(summary) => {
            if summary.has_operational_errors() {
                1
            } else if summary.has_parsing_errors() {
                2
            } else if summary.has_formatting_errors() {
                3
            } else if summary.has_diff {
                // should only happen in diff mode
                4
            } else {
                assert!(summary.has_no_errors());
                0
            }
        }
        Err(e) => {
            print_usage(&opts, &e.to_string());
            1
        }
    };
    // Make sure standard output is flushed before we exit.
    std::io::stdout().flush().unwrap();

    // Exit with given exit code.
    //
    // NOTE: This immediately terminates the process without doing any cleanup,
    // so make sure to finish all necessary cleanup before this is called.
    std::process::exit(exit_code);
}

fn print_usage(opts: &Options, reason: &str) {
    let reason = format!("{}\nusage: {} [options] <file>...",
                         reason,
                         env::args_os().next().unwrap().to_string_lossy());
    println!("{}", opts.usage(&reason));
}

fn print_version() {
    println!("{} ({}{})",
             option_env!("CARGO_PKG_VERSION").unwrap_or("unknown"),
             COMMIT_HASH.unwrap_or("git commit unavailable"),
             match WORKTREE_CLEAN {
                 Some(false) => " worktree dirty",
                 _ => "",
             });
}

fn determine_operation(matches: &Matches) -> FmtResult<Operation> {
    if matches.opt_present("h") {
        return Ok(Operation::Help);
    }

    if matches.opt_present("config-help") {
        return Ok(Operation::ConfigHelp);
    }

    if matches.opt_present("version") {
        return Ok(Operation::Version);
    }

    // Read the config_path and convert to parent dir if a file is provided.
    let config_path: Option<PathBuf> = matches.opt_str("config-path")
        .map(PathBuf::from)
        .and_then(|dir| {
            if dir.is_file() {
                return dir.parent().map(|v| v.into());
            }
            Some(dir)
        });

    // if no file argument is supplied and `--file-lines` is not specified, read from stdin
    if matches.free.is_empty() && !matches.opt_present("file-lines") {

        let mut buffer = String::new();
        try!(io::stdin().read_to_string(&mut buffer));

        return Ok(Operation::Stdin {
            input: buffer,
            config_path: config_path,
        });
    }

    // We append files from `--file-lines` later in `execute()`.
    let files: Vec<_> = matches.free.iter().map(PathBuf::from).collect();

    Ok(Operation::Format {
        files: files,
        config_path: config_path,
    })
}
<commit_msg>Don't print config file by default (#1313)<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![cfg(not(test))]

extern crate log;
extern crate rustfmt;
extern crate toml;
extern crate env_logger;
extern crate getopts;

use rustfmt::{run, Input, Summary};
use rustfmt::file_lines::FileLines;
use rustfmt::config::{Config, WriteMode};

use std::{env, error};
use std::fs::{self, File};
use std::io::{self, ErrorKind, Read, Write};
use std::path::{Path, PathBuf};
use std::str::FromStr;

use getopts::{Matches, Options};

// Include git commit hash and worktree status; contents are like
//   const COMMIT_HASH: Option<&'static str> = Some("c31a366");
//   const WORKTREE_CLEAN: Option<bool> = Some(false);
// with `None` if running git failed, eg if it is not installed.
include!(concat!(env!("OUT_DIR"), "/git_info.rs"));

type FmtError = Box<error::Error + Send + Sync>;
type FmtResult<T> = std::result::Result<T, FmtError>;

/// Rustfmt operations.
enum Operation {
    /// Format files and their child modules.
    Format {
        files: Vec<PathBuf>,
        config_path: Option<PathBuf>,
    },
    /// Print the help message.
    Help,
    // Print version information
    Version,
    /// Print detailed configuration help.
    ConfigHelp,
    /// No file specified, read from stdin
    Stdin {
        input: String,
        config_path: Option<PathBuf>,
    },
}

/// Parsed command line options.
#[derive(Clone, Debug, Default)]
struct CliOptions {
    skip_children: bool,
    verbose: bool,
    write_mode: Option<WriteMode>,
    file_lines: FileLines, // Default is all lines in all files.
}

impl CliOptions {
    fn from_matches(matches: &Matches) -> FmtResult<CliOptions> {
        let mut options = CliOptions::default();
        options.skip_children = matches.opt_present("skip-children");
        options.verbose = matches.opt_present("verbose");

        if let Some(ref write_mode) = matches.opt_str("write-mode") {
            if let Ok(write_mode) = WriteMode::from_str(write_mode) {
                options.write_mode = Some(write_mode);
            } else {
                return Err(FmtError::from(format!("Invalid write-mode: {}", write_mode)));
            }
        }

        if let Some(ref file_lines) = matches.opt_str("file-lines") {
            options.file_lines = try!(file_lines.parse());
        }

        Ok(options)
    }

    fn apply_to(self, config: &mut Config) {
        config.skip_children = self.skip_children;
        config.verbose = self.verbose;
        config.file_lines = self.file_lines;
        if let Some(write_mode) = self.write_mode {
            config.write_mode = write_mode;
        }
    }
}

/// Try to find a project file in the given directory and its parents. Returns the path of a the
/// nearest project file if one exists, or `None` if no project file was found.
fn lookup_project_file(dir: &Path) -> FmtResult<Option<PathBuf>> {
    let mut current = if dir.is_relative() {
        try!(env::current_dir()).join(dir)
    } else {
        dir.to_path_buf()
    };

    current = try!(fs::canonicalize(current));

    const CONFIG_FILE_NAMES: [&'static str; 2] = [".rustfmt.toml", "rustfmt.toml"];

    loop {
        for config_file_name in &CONFIG_FILE_NAMES {
            let config_file = current.join(config_file_name);
            match fs::metadata(&config_file) {
                // Only return if it's a file to handle the unlikely situation of a directory named
                // `rustfmt.toml`.
                Ok(ref md) if md.is_file() => return Ok(Some(config_file)),
                // Return the error if it's something other than `NotFound`; otherwise we didn't
                // find the project file yet, and continue searching.
                Err(e) => {
                    if e.kind() != ErrorKind::NotFound {
                        return Err(FmtError::from(e));
                    }
                }
                _ => {}
            }
        }

        // If the current directory has no parent, we're done searching.
        if !current.pop() {
            return Ok(None);
        }
    }
}

/// Resolve the config for input in `dir`.
///
/// Returns the `Config` to use, and the path of the project file if there was
/// one.
fn resolve_config(dir: &Path) -> FmtResult<(Config, Option<PathBuf>)> {
    let path = try!(lookup_project_file(dir));
    if path.is_none() {
        return Ok((Config::default(), None));
    }
    let path = path.unwrap();
    let mut file = try!(File::open(&path));
    let mut toml = String::new();
    try!(file.read_to_string(&mut toml));
    Ok((Config::from_toml(&toml), Some(path)))
}

/// read the given config file path recursively if present else read the project file path
fn match_cli_path_or_file(config_path: Option<PathBuf>,
                          input_file: &Path)
                          -> FmtResult<(Config, Option<PathBuf>)> {

    if let Some(config_file) = config_path {
        let (toml, path) = try!(resolve_config(config_file.as_ref()));
        if path.is_some() {
            return Ok((toml, path));
        }
    }
    resolve_config(input_file)
}

fn make_opts() -> Options {
    let mut opts = Options::new();
    opts.optflag("h", "help", "show this message");
    opts.optflag("V", "version", "show version information");
    opts.optflag("v", "verbose", "print verbose output");
    opts.optopt("",
                "write-mode",
                "mode to write in (not usable when piping from stdin)",
                "[replace|overwrite|display|diff|coverage|checkstyle]");
    opts.optflag("", "skip-children", "don't reformat child modules");

    opts.optflag("",
                 "config-help",
                 "show details of rustfmt configuration options");
    opts.optopt("",
                "config-path",
                "Recursively searches the given path for the rustfmt.toml config file. If not \
                 found reverts to the input file path",
                "[Path for the configuration file]");
    opts.optopt("",
                "file-lines",
                "Format specified line ranges. See README for more detail on the JSON format.",
                "JSON");

    opts
}

fn execute(opts: &Options) -> FmtResult<Summary> {
    let matches = try!(opts.parse(env::args().skip(1)));

    match try!(determine_operation(&matches)) {
        Operation::Help => {
            print_usage(opts, "");
            Ok(Summary::new())
        }
        Operation::Version => {
            print_version();
            Ok(Summary::new())
        }
        Operation::ConfigHelp => {
            Config::print_docs();
            Ok(Summary::new())
        }
        Operation::Stdin { input, config_path } => {
            // try to read config from local directory
            let (mut config, _) = match_cli_path_or_file(config_path, &env::current_dir().unwrap())
                .expect("Error resolving config");

            // write_mode is always Plain for Stdin.
            config.write_mode = WriteMode::Plain;

            Ok(run(Input::Text(input), &config))
        }
        Operation::Format { mut files, config_path } => {
            let options = try!(CliOptions::from_matches(&matches));

            // Add any additional files that were specified via `--file-lines`.
            files.extend(options.file_lines.files().cloned().map(PathBuf::from));

            let mut config = Config::default();
            let mut path = None;
            // Load the config path file if provided
            if let Some(config_file) = config_path {
                let (cfg_tmp, path_tmp) = resolve_config(config_file.as_ref())
                    .expect(&format!("Error resolving config for {:?}", config_file));
                config = cfg_tmp;
                path = path_tmp;
            };

            if options.verbose {
                if let Some(path) = path.as_ref() {
                    println!("Using rustfmt config file {}", path.display());
                }
            }

            let mut error_summary = Summary::new();
            for file in files {
                // Check the file directory if the config-path could not be read or not provided
                if path.is_none() {
                    let (config_tmp, path_tmp) = resolve_config(file.parent().unwrap())
                        .expect(&format!("Error resolving config for {}", file.display()));
                    if options.verbose {
                        if let Some(path) = path_tmp.as_ref() {
                            println!("Using rustfmt config file {} for {}",
                                     path.display(),
                                     file.display());
                        }
                    }
                    config = config_tmp;
                }

                options.clone().apply_to(&mut config);
                error_summary.add(run(Input::File(file), &config));
            }
            Ok(error_summary)
        }
    }
}

fn main() {
    let _ = env_logger::init();

    let opts = make_opts();

    let exit_code = match execute(&opts) {
        Ok(summary) => {
            if summary.has_operational_errors() {
                1
            } else if summary.has_parsing_errors() {
                2
            } else if summary.has_formatting_errors() {
                3
            } else if summary.has_diff {
                // should only happen in diff mode
                4
            } else {
                assert!(summary.has_no_errors());
                0
            }
        }
        Err(e) => {
            print_usage(&opts, &e.to_string());
            1
        }
    };
    // Make sure standard output is flushed before we exit.
    std::io::stdout().flush().unwrap();

    // Exit with given exit code.
    //
    // NOTE: This immediately terminates the process without doing any cleanup,
    // so make sure to finish all necessary cleanup before this is called.
    std::process::exit(exit_code);
}

fn print_usage(opts: &Options, reason: &str) {
    let reason = format!("{}\nusage: {} [options] <file>...",
                         reason,
                         env::args_os().next().unwrap().to_string_lossy());
    println!("{}", opts.usage(&reason));
}

fn print_version() {
    println!("{} ({}{})",
             option_env!("CARGO_PKG_VERSION").unwrap_or("unknown"),
             COMMIT_HASH.unwrap_or("git commit unavailable"),
             match WORKTREE_CLEAN {
                 Some(false) => " worktree dirty",
                 _ => "",
             });
}

fn determine_operation(matches: &Matches) -> FmtResult<Operation> {
    if matches.opt_present("h") {
        return Ok(Operation::Help);
    }

    if matches.opt_present("config-help") {
        return Ok(Operation::ConfigHelp);
    }

    if matches.opt_present("version") {
        return Ok(Operation::Version);
    }

    // Read the config_path and convert to parent dir if a file is provided.
    let config_path: Option<PathBuf> = matches.opt_str("config-path")
        .map(PathBuf::from)
        .and_then(|dir| {
            if dir.is_file() {
                return dir.parent().map(|v| v.into());
            }
            Some(dir)
        });

    // if no file argument is supplied and `--file-lines` is not specified, read from stdin
    if matches.free.is_empty() && !matches.opt_present("file-lines") {

        let mut buffer = String::new();
        try!(io::stdin().read_to_string(&mut buffer));

        return Ok(Operation::Stdin {
            input: buffer,
            config_path: config_path,
        });
    }

    // We append files from `--file-lines` later in `execute()`.
    let files: Vec<_> = matches.free.iter().map(PathBuf::from).collect();

    Ok(Operation::Format {
        files: files,
        config_path: config_path,
    })
}
<|endoftext|>


<commit_before>use std::io::Read;
use std::io::Result;

pub enum Message {
    KeepAlive,

}

///len_prefix is big endian
///might want to use traits instead of returning an enum... haven't decided yet. would save a match
pub fn decode_message <T> (len_prefix: &[u8; 4], stream: &mut T) -> Message where T:Read {
    let i: u32 = (
        len_prefix[3] as u32
        | ((len_prefix[2] as u32) << 8)
        | ((len_prefix[1] as u32) << 16)
        | ((len_prefix[0] as u32) << 24));
    match i {
        0 => Message::KeepAlive,
        _ => {
            let mut id_buf = [0; 1];
            let _ = stream.read(&mut id_buf);
            let id = id_buf[0];

            println!("temp");
            Message::KeepAlive
        }
    }
}

pub fn test () {
    struct MockStream;

    impl Read for MockStream {
        fn read (&mut self, buf: &mut [u8]) -> Result<usize> {
            buf[0] = 0;
            buf[1] = 0;
            buf[2] = 0;
            buf[3] = 0;
            Ok(4)
        }
    }

    let mut stream = MockStream;
    let mut buf = [1; 4];
    stream.read(&mut buf);
    decode_message(&buf, &mut stream);
}

#[test]
fn test_decode () {

    struct MockStream;

    impl Read for MockStream {
        fn read (&mut self, buf: &mut [u8]) -> Result<usize> {
            buf[0] = 0;
            buf[1] = 0;
            buf[2] = 0;
            buf[3] = 0;
            Ok(4)
        }
    }

    let mut stream = MockStream;
    let mut buf = [1; 4];
    stream.read(&mut buf);
    decode_message(&buf, stream);
}
<commit_msg>adding some more messages<commit_after>use std::io::Read;
use std::io::Result;

pub enum Message {
    KeepAlive,
    Choke,
    Unchoke,
    Interested,
    NotInterested,
    Have {piece_index: u32},
    Bitfield(Vec<u8>)

}

///len_prefix is big endian
///might want to use traits instead of returning an enum... haven't decided yet. would save a match
pub fn decode_message <T> (len_prefix: &[u8; 4], stream: &mut T) -> Message where T:Read {
    let i = u8_4_to_u32(len_prefix);
    match i {
        0 => Message::KeepAlive,
        len => {
            let mut id_buf = [0; 1];
            let _ = stream.read(&mut id_buf);
            match id_buf[0] {
                0 => Message::Choke,
                1 => Message::Unchoke,
                2 => Message::Interested,
                3 => Message::NotInterested,
                4 => {
                    let mut buf = [0; 4];
                    stream.read(&mut buf);
                    let piece_index = u8_4_to_u32(&buf);
                    Message::Have{piece_index: piece_index}
                },
                5 => {
                    let bitfield_length = len - 1;
                    Message::Bitfield(read_out_variable(stream, bitfield_length as u64))
                }
                _ => Message::Choke
            }

        }
    }
}

fn u8_4_to_u32 (bytes: &[u8; 4]) -> u32 {
    (bytes[3] as u32
        | ((bytes[2] as u32) << 8)
        | ((bytes[1] as u32) << 16)
        | ((bytes[0] as u32) << 24))
}

fn read_out_variable <T> (stream: &mut T, num_bytes: u64) -> Vec<u8> where T:Read {
    let mut buf = Vec::new();
    stream.take(num_bytes).read(&mut buf);
    buf
}

pub fn test () {
    struct MockStream;

    impl Read for MockStream {
        fn read (&mut self, buf: &mut [u8]) -> Result<usize> {
            buf[0] = 0;
            buf[1] = 0;
            buf[2] = 0;
            buf[3] = 0;
            Ok(4)
        }
    }

    let mut stream = MockStream;
    let mut buf = [1; 4];
    stream.read(&mut buf);
    decode_message(&buf, &mut stream);
}

#[test]
fn test_decode () {

    struct MockStream;

    impl Read for MockStream {
        fn read (&mut self, buf: &mut [u8]) -> Result<usize> {
            buf[0] = 0;
            buf[1] = 0;
            buf[2] = 0;
            buf[3] = 0;
            Ok(4)
        }
    }

    let mut stream = MockStream;
    let mut buf = [1; 4];
    stream.read(&mut buf);
    decode_message(&buf, stream);
}
<|endoftext|>