<commit_before>//! The neural network struct.

use std::ops::Range;
use std::io;

use utils::Stack;
use file;
use gene::*;
use gene::GeneExtras::*;
use transfer::*;

const BIAS_GENE_VALUE: f64 = 1.0;

#[derive(Clone, Debug, PartialEq)]
pub struct Network {
    // size should be the length of the genome minus one, don't forget
    pub size: usize,
    pub genome: Vec<Gene>,
    pub function: TransferFunction
}

impl Network {
    /// Evaluates the neural network with the given inputs, returning a vector of outputs. The encoding can
    /// encode recurrent connections and bias inputs, so an internal state is used. It is important to run
    /// the clear_state method before calling evaluate again, unless it is desired to allow data
    /// carry over from the previous evaluation, for example if the network is being used as a real
    /// time controller.
    ///
    /// If too little inputs are given, the empty inputs will have a value of zero. If too many
    /// inputs are given, the extras are discarded.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use cge::Network;
    ///
    /// // Load a neural network
    /// let mut network = Network::load_from_file("neural_network.ann").unwrap();
    ///
    /// // Get the output of the neural network the the specified inputs
    /// let result = network.evaluate(&vec![1.0, 1.0]);
    ///
    /// // Get the output of the neural network with no inputs
    /// let result = network.evaluate(&[]);
    ///
    /// // Get the output of the neural network with too many inputs (extras aren't used)
    /// let result = network.evaluate(&[1.0, 1.0, 1.0]);
    ///
    /// // Let's say adder.ann is a file with a neural network with recurrent connections, used for
    /// // adding numbers together.
    /// let mut adder = Network::load_from_file("adder.ann").unwrap();
    ///
    /// // result_one will be 1.0
    /// let result_one = adder.evaluate(&[1.0]);
    ///
    /// // result_two will be 3.0
    /// let result_two = adder.evaluate(&[2.0]);
    ///
    /// // result_three will be 5.0
    /// let result_three = adder.evaluate(&[2.0]);
    ///
    /// // If this behavior is not desired, call the clear_state method between evaluations:
    /// let result_one = adder.evaluate(&[1.0]);
    ///
    /// adder.clear_state();
    ///
    /// // The 1.0 from the previous call is gone, so result_two will be 2.0
    /// let result_two = adder.evaluate(&[2.0]);
    /// ```
    pub fn evaluate(&mut self, inputs: &[f64]) -> Vec<f64> {
        self.set_inputs(inputs);

        let size = self.size;
        self.evaluate_slice(0..size, true, false)
    }

    /// Evaluates the neural network the same as `evaluate`, but prints debug info.
    pub fn debug_eval(&mut self, inputs: &[f64]) -> Vec<f64> {
        self.set_inputs(inputs);

        let size = self.size;
        self.evaluate_slice(0..size, true, true)
    }

    /// Clears the internal state of the neural network.
    pub fn clear_state(&mut self) {
        for gene in &mut self.genome {
            match gene.variant {
                Input(ref mut current_value) => {
                    *current_value = 0.0;
                },
                Neuron(ref mut current_value, _) => {
                    *current_value = 0.0;
                }
                _ => {}
            }
        }
    }

    /// Loads a neural network from a string. Returns `None` if the format is incorrect.
    ///
    /// # Examples
    ///
    /// ```
    /// use cge::Network;
    ///
    /// // Store the neural network in a string
    /// let string = "0: n 1 0 2,n 1 1 2,n 1 3 2,
    ///               i 1 0,i 1 1,i 1 1,n 1 2 4,
    ///               f 1 3,i 1 0,i 1 1,r 1 0";
    ///
    /// // Load a neural network from the string
    /// let network = Network::from_str(string).unwrap();
    /// ```
    ///
    /// # Format
    ///
    /// The format for the string is simple enough to build by hand:
    ///
    /// First, the number 0, 1, 2 or 3 is entered to represent the linear, threshold, sign, or
    /// sigmoid function, followed by a colon. The rest is the genome, encoded with comma
    /// separated genes:
    ///
    /// Neuron:     n [weight] [id] [input count]
    /// Input:      i [weight] [id]
    /// Connection: f [weight] [id]
    /// Recurrent:  r [weight] [id]
    /// Bias:       b [weight]
    ///
    /// For more information about what this means, see [here][1].
    ///
    /// [1]: http://www.academia.edu/6923193/A_common_genetic_encoding_for_both_direct_and_indirect_encodings_of_networks
    pub fn from_str(string: &str) -> Option<Network> {
        file::from_str(string)
    }

    /// Saves the neural network to a string. Allows embedding a neural network in source code.
    ///
    /// # Examples
    ///
    /// ```
    /// use cge::*;
    ///
    /// // Create a neural network
    /// let network = Network {
    ///     size: 0,
    ///     genome: Vec::new(),
    ///     function: TransferFunction::Sign
    /// };
    ///
    /// // Save the neural network to the string
    /// let string = network.to_str();
    /// ```
    pub fn to_str(&self) -> String {
        file::to_str(self)
    }

    /// Saves the neural network to a file. Returns an empty tuple on success, or an io error.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use cge::*;
    ///
    /// // Create a neural network
    /// let network = Network {
    ///     size: 0,
    ///     genome: Vec::new(),
    ///     function: TransferFunction::Sign
    /// };
    ///
    /// // Save the neural network to neural_network.ann
    /// network.save_to_file("neural_network.ann").unwrap();
    /// ```
    pub fn save_to_file(&self, path: &str) -> io::Result<()> {
        file::write_network(self, path)
    }

    /// Loads a neural network from a file. No guarantees are made about the validity of the
    /// genome. Returns the network, or an io error. If the file is in a bad format,
    /// `std::io::ErrorKind::InvalidData` is returned.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use cge::Network;
    ///
    /// // Loads a neural network from the file neural_network.ann
    /// let mut network = Network::load_from_file("neural_network.ann").unwrap();
    /// ```
    pub fn load_from_file(path: &str) -> io::Result<Network> {
        file::read_network(path)
    }

    // Returns the output of sub-linear genome in the given range
    fn evaluate_slice(&mut self, range: Range<usize>, neuron_update: bool, debug: bool) -> Vec<f64> {
        let mut gene_index = range.end;
        // Initialize a stack for evaluating the neural network
        let mut stack = Stack::new();

        // Iterate backwards over the specified slice
        while gene_index >= range.start {
            let variant = self.genome[gene_index].variant.clone();

            if debug {
                println!("{:?}", variant);
            }

            match variant {
                Input(_) => {
                    // If the gene is an input, push its value multiplied by the inputs weight onto
                    // the stack
                    let (weight, _, value) = self.genome[gene_index].ref_input().unwrap();
                    stack.push(weight * value);
                },
                Neuron(_, _) => {
                    // If the gene is a neuron, pop a number (the neurons input count) of inputs
                    // off the stack, and push the transfer function applied to the sum of these
                    // inputs multiplied by the neurons weight onto the stack
                    let (weight, _, value, inputs) = self.genome[gene_index].ref_mut_neuron().unwrap();
                    let mut new_value = stack.pop(*inputs)
                                         .expect("A neuron did not receive enough inputs")
                                         .iter()
                                         .fold(0.0, |acc, i| acc + i);

                    new_value = match self.function {
                        TransferFunction::Linear => new_value,
                        TransferFunction::Threshold => threshold(new_value),
                        TransferFunction::Sign => sign(new_value),
                        TransferFunction::Sigmoid => sigmoid(new_value),
                    };

                    if neuron_update {
                        *value = new_value;
                    }

                    stack.push(*weight * new_value);
                },
                Forward => {
                    // This is inefficient because it can run the neuron evaluation code multiple
                    // times
                    // TODO: Turn current value of neurons into a struct with a flag representing
                    // whether the neuron has been evaluated this network evaluation. Reset this
                    // flag after every network evaluation.

                    // If the gene is a forward jumper, evaluate the subnetwork starting at the
                    // neuron with id of the jumper, and push the result multiplied by the jumpers
                    // weight onto the stack
                    let weight = self.genome[gene_index].weight;
                    let id = self.genome[gene_index].id;
                    let subnetwork_range = self.get_subnetwork_index(id)
                                               .expect("Found forward connection with invalid neuron id");

                    let result = self.evaluate_slice(subnetwork_range, false, debug);

                    if debug {
                        println!("{:?}", result);
                    }

                    stack.push(weight * result[0]);
                },
                Recurrent => {
                    // If the gene is a recurrent jumper, push the previous value of the neuron
                    // with the id of the jumper multiplied by the jumpers weight onto the stack
                    let gene = &self.genome[gene_index];
                    let neuron = &self.genome[self.get_neuron_index(gene.id)
                                                  .expect("Found recurrent connection with invalid neuron id")];

                    if let Neuron(ref current_value, _) = neuron.variant {
                        stack.push(gene.weight * *current_value);
                    }
                },
                Bias => {
                    // If the gene is a bias input, push the bias constant multiplied by the genes
                    // weight onto the stack
                    let gene = &self.genome[gene_index];
                    stack.push(gene.weight * BIAS_GENE_VALUE);
                }
            }

            if gene_index == range.start {
                break;
            }

            gene_index -= 1;

            if debug {
                println!("{:?}", stack.data);
            }
        }

        stack.data
    }

    fn set_inputs(&mut self, inputs: &[f64]) {
        for gene in &mut self.genome {
            if let Input(ref mut current_value) = gene.variant {
                *current_value = 0.0;

                *current_value = match inputs.get(gene.id) {
                    Some(v) => *v,
                    None => 0.0
                }
            }
        }
    }

    /// Returns the start and end index of the subnetwork starting at the neuron with the given id,
    /// or None if it does not exist.
    pub fn get_subnetwork_index(&self, id: usize) -> Option<Range<usize>> {
        let start = match self.get_neuron_index(id) {
            Some(i) => i,
            None => return None
        };

        let mut end = start;
        let mut sum = 0;

        // Iterate through genes after the start index, modifying the sum each step
        // I could use an iterator here, but it would be messy
        for gene in &self.genome[start..self.size + 1] {
            match gene.variant {
                Neuron(_, ref inputs) => {
                    sum += 1 - *inputs as i32;
                },
                _ => {
                    sum += 1;
                }
            }

            if sum == 1 {
                break;
            }

            end += 1;
        }

        if sum != 1 {
            None
        } else {
            Some(Range {
                start: start,
                end: end
            })
        }
    }

    /// Returns the index of the neuron with the given id, or None if it does not exist.
    pub fn get_neuron_index(&self, id: usize) -> Option<usize> {
        let mut result = None;

        for (i, gene) in self.genome.iter().enumerate() {
            if let Neuron(_, _) = gene.variant {
                if gene.id == id {
                    result = Some(i);
                }
            }
        }

        result
    }
}
<commit_msg>Fix documentation formatting<commit_after>//! The neural network struct.

use std::ops::Range;
use std::io;

use utils::Stack;
use file;
use gene::*;
use gene::GeneExtras::*;
use transfer::*;

const BIAS_GENE_VALUE: f64 = 1.0;

#[derive(Clone, Debug, PartialEq)]
pub struct Network {
    // size should be the length of the genome minus one, don't forget
    pub size: usize,
    pub genome: Vec<Gene>,
    pub function: TransferFunction
}

impl Network {
    /// Evaluates the neural network with the given inputs, returning a vector of outputs. The encoding can
    /// encode recurrent connections and bias inputs, so an internal state is used. It is important to run
    /// the clear_state method before calling evaluate again, unless it is desired to allow data
    /// carry over from the previous evaluation, for example if the network is being used as a real
    /// time controller.
    ///
    /// If too little inputs are given, the empty inputs will have a value of zero. If too many
    /// inputs are given, the extras are discarded.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use cge::Network;
    ///
    /// // Load a neural network
    /// let mut network = Network::load_from_file("neural_network.ann").unwrap();
    ///
    /// // Get the output of the neural network the the specified inputs
    /// let result = network.evaluate(&vec![1.0, 1.0]);
    ///
    /// // Get the output of the neural network with no inputs
    /// let result = network.evaluate(&[]);
    ///
    /// // Get the output of the neural network with too many inputs (extras aren't used)
    /// let result = network.evaluate(&[1.0, 1.0, 1.0]);
    ///
    /// // Let's say adder.ann is a file with a neural network with recurrent connections, used for
    /// // adding numbers together.
    /// let mut adder = Network::load_from_file("adder.ann").unwrap();
    ///
    /// // result_one will be 1.0
    /// let result_one = adder.evaluate(&[1.0]);
    ///
    /// // result_two will be 3.0
    /// let result_two = adder.evaluate(&[2.0]);
    ///
    /// // result_three will be 5.0
    /// let result_three = adder.evaluate(&[2.0]);
    ///
    /// // If this behavior is not desired, call the clear_state method between evaluations:
    /// let result_one = adder.evaluate(&[1.0]);
    ///
    /// adder.clear_state();
    ///
    /// // The 1.0 from the previous call is gone, so result_two will be 2.0
    /// let result_two = adder.evaluate(&[2.0]);
    /// ```
    pub fn evaluate(&mut self, inputs: &[f64]) -> Vec<f64> {
        self.set_inputs(inputs);

        let size = self.size;
        self.evaluate_slice(0..size, true, false)
    }

    /// Evaluates the neural network the same as `evaluate`, but prints debug info.
    pub fn debug_eval(&mut self, inputs: &[f64]) -> Vec<f64> {
        self.set_inputs(inputs);

        let size = self.size;
        self.evaluate_slice(0..size, true, true)
    }

    /// Clears the internal state of the neural network.
    pub fn clear_state(&mut self) {
        for gene in &mut self.genome {
            match gene.variant {
                Input(ref mut current_value) => {
                    *current_value = 0.0;
                },
                Neuron(ref mut current_value, _) => {
                    *current_value = 0.0;
                }
                _ => {}
            }
        }
    }

    /// Loads a neural network from a string. Returns `None` if the format is incorrect.
    ///
    /// # Examples
    ///
    /// ```
    /// use cge::Network;
    ///
    /// // Store the neural network in a string
    /// let string = "0: n 1 0 2,n 1 1 2,n 1 3 2,
    ///               i 1 0,i 1 1,i 1 1,n 1 2 4,
    ///               f 1 3,i 1 0,i 1 1,r 1 0";
    ///
    /// // Load a neural network from the string
    /// let network = Network::from_str(string).unwrap();
    /// ```
    ///
    /// # Format
    ///
    /// The format for the string is simple enough to build by hand:
    ///
    /// First, the number 0, 1, 2 or 3 is entered to represent the linear, threshold, sign, or
    /// sigmoid function, followed by a colon. The rest is the genome, encoded with comma
    /// separated genes:
    ///
    /// Neuron:     n [weight] [id] [input count]
    /// Input:      i [weight] [id]
    /// Connection: f [weight] [id]
    /// Recurrent:  r [weight] [id]
    /// Bias:       b [weight]
    ///
    /// For more information about what this means, see [here][1].
    ///
    /// [1]: http://www.academia.edu/6923193/A_common_genetic_encoding_for_both_direct_and_indirect_encodings_of_networks
    pub fn from_str(string: &str) -> Option<Network> {
        file::from_str(string)
    }

    /// Saves the neural network to a string. Allows embedding a neural network in source code.
    ///
    /// # Examples
    ///
    /// ```
    /// use cge::*;
    ///
    /// // Create a neural network
    /// let network = Network {
    ///     size: 0,
    ///     genome: Vec::new(),
    ///     function: TransferFunction::Sign
    /// };
    ///
    /// // Save the neural network to the string
    /// let string = network.to_str();
    /// ```
    pub fn to_str(&self) -> String {
        file::to_str(self)
    }

    /// Saves the neural network to a file. Returns an empty tuple on success, or an io error.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use cge::*;
    ///
    /// // Create a neural network
    /// let network = Network {
    ///     size: 0,
    ///     genome: Vec::new(),
    ///     function: TransferFunction::Sign
    /// };
    ///
    /// // Save the neural network to neural_network.ann
    /// network.save_to_file("neural_network.ann").unwrap();
    /// ```
    pub fn save_to_file(&self, path: &str) -> io::Result<()> {
        file::write_network(self, path)
    }

    /// Loads a neural network from a file. No guarantees are made about the validity of the
    /// genome. Returns the network, or an io error. If the file is in a bad format,
    /// `std::io::ErrorKind::InvalidData` is returned.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use cge::Network;
    ///
    /// // Loads a neural network from the file neural_network.ann
    /// let mut network = Network::load_from_file("neural_network.ann").unwrap();
    /// ```
    pub fn load_from_file(path: &str) -> io::Result<Network> {
        file::read_network(path)
    }

    // Returns the output of sub-linear genome in the given range
    fn evaluate_slice(&mut self, range: Range<usize>, neuron_update: bool, debug: bool) -> Vec<f64> {
        let mut gene_index = range.end;
        // Initialize a stack for evaluating the neural network
        let mut stack = Stack::new();

        // Iterate backwards over the specified slice
        while gene_index >= range.start {
            let variant = self.genome[gene_index].variant.clone();

            if debug {
                println!("{:?}", variant);
            }

            match variant {
                Input(_) => {
                    // If the gene is an input, push its value multiplied by the inputs weight onto
                    // the stack
                    let (weight, _, value) = self.genome[gene_index].ref_input().unwrap();
                    stack.push(weight * value);
                },
                Neuron(_, _) => {
                    // If the gene is a neuron, pop a number (the neurons input count) of inputs
                    // off the stack, and push the transfer function applied to the sum of these
                    // inputs multiplied by the neurons weight onto the stack
                    let (weight, _, value, inputs) = self.genome[gene_index].ref_mut_neuron().unwrap();
                    let mut new_value = stack.pop(*inputs)
                                         .expect("A neuron did not receive enough inputs")
                                         .iter()
                                         .fold(0.0, |acc, i| acc + i);

                    new_value = match self.function {
                        TransferFunction::Linear => new_value,
                        TransferFunction::Threshold => threshold(new_value),
                        TransferFunction::Sign => sign(new_value),
                        TransferFunction::Sigmoid => sigmoid(new_value),
                    };

                    if neuron_update {
                        *value = new_value;
                    }

                    stack.push(*weight * new_value);
                },
                Forward => {
                    // This is inefficient because it can run the neuron evaluation code multiple
                    // times
                    // TODO: Turn current value of neurons into a struct with a flag representing
                    // whether the neuron has been evaluated this network evaluation. Reset this
                    // flag after every network evaluation.

                    // If the gene is a forward jumper, evaluate the subnetwork starting at the
                    // neuron with id of the jumper, and push the result multiplied by the jumpers
                    // weight onto the stack
                    let weight = self.genome[gene_index].weight;
                    let id = self.genome[gene_index].id;
                    let subnetwork_range = self.get_subnetwork_index(id)
                                               .expect("Found forward connection with invalid neuron id");

                    let result = self.evaluate_slice(subnetwork_range, false, debug);

                    if debug {
                        println!("{:?}", result);
                    }

                    stack.push(weight * result[0]);
                },
                Recurrent => {
                    // If the gene is a recurrent jumper, push the previous value of the neuron
                    // with the id of the jumper multiplied by the jumpers weight onto the stack
                    let gene = &self.genome[gene_index];
                    let neuron = &self.genome[self.get_neuron_index(gene.id)
                                                  .expect("Found recurrent connection with invalid neuron id")];

                    if let Neuron(ref current_value, _) = neuron.variant {
                        stack.push(gene.weight * *current_value);
                    }
                },
                Bias => {
                    // If the gene is a bias input, push the bias constant multiplied by the genes
                    // weight onto the stack
                    let gene = &self.genome[gene_index];
                    stack.push(gene.weight * BIAS_GENE_VALUE);
                }
            }

            if gene_index == range.start {
                break;
            }

            gene_index -= 1;

            if debug {
                println!("{:?}", stack.data);
            }
        }

        stack.data
    }

    fn set_inputs(&mut self, inputs: &[f64]) {
        for gene in &mut self.genome {
            if let Input(ref mut current_value) = gene.variant {
                *current_value = 0.0;

                *current_value = match inputs.get(gene.id) {
                    Some(v) => *v,
                    None => 0.0
                }
            }
        }
    }

    /// Returns the start and end index of the subnetwork starting at the neuron with the given id,
    /// or None if it does not exist.
    pub fn get_subnetwork_index(&self, id: usize) -> Option<Range<usize>> {
        let start = match self.get_neuron_index(id) {
            Some(i) => i,
            None => return None
        };

        let mut end = start;
        let mut sum = 0;

        // Iterate through genes after the start index, modifying the sum each step
        // I could use an iterator here, but it would be messy
        for gene in &self.genome[start..self.size + 1] {
            match gene.variant {
                Neuron(_, ref inputs) => {
                    sum += 1 - *inputs as i32;
                },
                _ => {
                    sum += 1;
                }
            }

            if sum == 1 {
                break;
            }

            end += 1;
        }

        if sum != 1 {
            None
        } else {
            Some(Range {
                start: start,
                end: end
            })
        }
    }

    /// Returns the index of the neuron with the given id, or None if it does not exist.
    pub fn get_neuron_index(&self, id: usize) -> Option<usize> {
        let mut result = None;

        for (i, gene) in self.genome.iter().enumerate() {
            if let Neuron(_, _) = gene.variant {
                if gene.id == id {
                    result = Some(i);
                }
            }
        }

        result
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 Serde Developers
//
// 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.

use std::borrow::Cow;

use super::Value;
use map::Map;
use number::Number;

macro_rules! from_integer {
    ($($ty:ident)*) => {
        $(
            impl From<$ty> for Value {
                fn from(n: $ty) -> Self {
                    Value::Number(n.into())
                }
            }
        )*
    };
}

from_integer! {
    i8 i16 i32 i64 isize
    u8 u16 u32 u64 usize
}

impl From<f32> for Value {
    /// Convert 32-bit floating point number to `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_json;
    /// #
    /// # fn main() {
    /// use serde_json::Value;
    ///
    /// let f: f32 = 13.37;
    /// let x: Value = f.into();
    /// # }
    /// ```
    fn from(f: f32) -> Self {
        From::from(f as f64)
    }
}

impl From<f64> for Value {
    /// Convert 64-bit floating point number to `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_json;
    /// #
    /// # fn main() {
    /// use serde_json::Value;
    ///
    /// let f: f64 = 13.37;
    /// let x: Value = f.into();
    /// # }
    /// ```
    fn from(f: f64) -> Self {
        Number::from_f64(f).map_or(Value::Null, Value::Number)
    }
}

impl From<bool> for Value {
    /// Convert boolean to `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_json;
    /// #
    /// # fn main() {
    /// use serde_json::Value;
    ///
    /// let b = false;
    /// let x: Value = b.into();
    /// # }
    /// ```
    fn from(f: bool) -> Self {
        Value::Bool(f)
    }
}

impl From<String> for Value {
    /// Convert `String` to `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_json;
    /// #
    /// # fn main() {
    /// use serde_json::Value;
    ///
    /// let s: String = "lorem".to_string();
    /// let x: Value = s.into();
    /// # }
    /// ```
    fn from(f: String) -> Self {
        Value::String(f)
    }
}

impl<'a> From<&'a str> for Value {
    /// Convert string slice to `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_json;
    /// #
    /// # fn main() {
    /// use serde_json::Value;
    ///
    /// let s: &str = "lorem";
    /// let x: Value = s.into();
    /// # }
    /// ```
    fn from(f: &str) -> Self {
        Value::String(f.to_string())
    }
}

impl<'a> From<Cow<'a, str>> for Value {
    /// Convert copy-on-write string to `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_json;
    /// #
    /// # fn main() {
    /// use serde_json::Value;
    /// use std::borrow::Cow;
    ///
    /// let s: Cow<str> = Cow::Borrowed("lorem");
    /// let x: Value = s.into();
    /// # }
    /// ```
    ///
    /// ```rust
    /// # extern crate serde_json;
    /// #
    /// # fn main() {
    /// use serde_json::Value;
    /// use std::borrow::Cow;
    ///
    /// let s: Cow<str> = Cow::Owned("lorem".to_string());
    /// let x: Value = s.into();
    /// # }
    /// ```
    fn from(f: Cow<'a, str>) -> Self {
        Value::String(f.into_owned())
    }
}

impl From<Map<String, Value>> for Value {
    /// Convert map (with string keys) to `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_json;
    /// #
    /// # fn main() {
    /// use serde_json::{Map, Value};
    ///
    /// let mut m = Map::new();
    /// m.insert("Lorem".to_string(), "ipsum".into());
    /// let x: Value = m.into();
    /// # }
    /// ```
    fn from(f: Map<String, Value>) -> Self {
        Value::Object(f)
    }
}

impl<T: Into<Value>> From<Vec<T>> for Value {
    /// Convert a `Vec` to `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_json;
    /// #
    /// # fn main() {
    /// use serde_json::Value;
    ///
    /// let v = vec!["lorem", "ipsum", "dolor"];
    /// let x: Value = v.into();
    /// # }
    /// ```
    fn from(f: Vec<T>) -> Self {
        Value::Array(f.into_iter().map(Into::into).collect())
    }
}

impl<'a, T: Clone + Into<Value>> From<&'a [T]> for Value {
    /// Convert a slice to `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_json;
    /// #
    /// # fn main() {
    /// use serde_json::Value;
    ///
    /// let v: &[&str] = &["lorem", "ipsum", "dolor"];
    /// let x: Value = v.into();
    /// # }
    /// ```
    fn from(f: &'a [T]) -> Self {
        Value::Array(f.into_iter().cloned().map(Into::into).collect())
    }
}

impl<T: Into<Value>> ::std::iter::FromIterator<T> for Value {
    /// Convert an iteratable type to a `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_json;
    /// #
    /// # fn main() {
    /// use serde_json::Value;
    ///
    /// let v = std::iter::repeat(42).take(5);
    /// let x: Value = v.collect();
    /// # }
    /// ```
    ///
    /// ```rust
    /// # extern crate serde_json;
    /// #
    /// # fn main() {
    /// use serde_json::Value;
    ///
    /// let v: Vec<_> = vec!["lorem", "ipsum", "dolor"];
    /// let x: Value = v.into_iter().collect();
    /// # }
    /// ```
    ///
    /// ```rust
    /// # extern crate serde_json;
    /// #
    /// # fn main() {
    /// use std::iter::FromIterator;
    /// use serde_json::Value;
    ///
    /// let x: Value = Value::from_iter(vec!["lorem", "ipsum", "dolor"]);
    /// # }
    /// ```
    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
        Value::Array(iter.into_iter().map(Into::into).collect())
    }
}
<commit_msg>Address into_iter_on_ref lint<commit_after>// Copyright 2017 Serde Developers
//
// 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.

use std::borrow::Cow;

use super::Value;
use map::Map;
use number::Number;

macro_rules! from_integer {
    ($($ty:ident)*) => {
        $(
            impl From<$ty> for Value {
                fn from(n: $ty) -> Self {
                    Value::Number(n.into())
                }
            }
        )*
    };
}

from_integer! {
    i8 i16 i32 i64 isize
    u8 u16 u32 u64 usize
}

impl From<f32> for Value {
    /// Convert 32-bit floating point number to `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_json;
    /// #
    /// # fn main() {
    /// use serde_json::Value;
    ///
    /// let f: f32 = 13.37;
    /// let x: Value = f.into();
    /// # }
    /// ```
    fn from(f: f32) -> Self {
        From::from(f as f64)
    }
}

impl From<f64> for Value {
    /// Convert 64-bit floating point number to `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_json;
    /// #
    /// # fn main() {
    /// use serde_json::Value;
    ///
    /// let f: f64 = 13.37;
    /// let x: Value = f.into();
    /// # }
    /// ```
    fn from(f: f64) -> Self {
        Number::from_f64(f).map_or(Value::Null, Value::Number)
    }
}

impl From<bool> for Value {
    /// Convert boolean to `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_json;
    /// #
    /// # fn main() {
    /// use serde_json::Value;
    ///
    /// let b = false;
    /// let x: Value = b.into();
    /// # }
    /// ```
    fn from(f: bool) -> Self {
        Value::Bool(f)
    }
}

impl From<String> for Value {
    /// Convert `String` to `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_json;
    /// #
    /// # fn main() {
    /// use serde_json::Value;
    ///
    /// let s: String = "lorem".to_string();
    /// let x: Value = s.into();
    /// # }
    /// ```
    fn from(f: String) -> Self {
        Value::String(f)
    }
}

impl<'a> From<&'a str> for Value {
    /// Convert string slice to `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_json;
    /// #
    /// # fn main() {
    /// use serde_json::Value;
    ///
    /// let s: &str = "lorem";
    /// let x: Value = s.into();
    /// # }
    /// ```
    fn from(f: &str) -> Self {
        Value::String(f.to_string())
    }
}

impl<'a> From<Cow<'a, str>> for Value {
    /// Convert copy-on-write string to `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_json;
    /// #
    /// # fn main() {
    /// use serde_json::Value;
    /// use std::borrow::Cow;
    ///
    /// let s: Cow<str> = Cow::Borrowed("lorem");
    /// let x: Value = s.into();
    /// # }
    /// ```
    ///
    /// ```rust
    /// # extern crate serde_json;
    /// #
    /// # fn main() {
    /// use serde_json::Value;
    /// use std::borrow::Cow;
    ///
    /// let s: Cow<str> = Cow::Owned("lorem".to_string());
    /// let x: Value = s.into();
    /// # }
    /// ```
    fn from(f: Cow<'a, str>) -> Self {
        Value::String(f.into_owned())
    }
}

impl From<Map<String, Value>> for Value {
    /// Convert map (with string keys) to `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_json;
    /// #
    /// # fn main() {
    /// use serde_json::{Map, Value};
    ///
    /// let mut m = Map::new();
    /// m.insert("Lorem".to_string(), "ipsum".into());
    /// let x: Value = m.into();
    /// # }
    /// ```
    fn from(f: Map<String, Value>) -> Self {
        Value::Object(f)
    }
}

impl<T: Into<Value>> From<Vec<T>> for Value {
    /// Convert a `Vec` to `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_json;
    /// #
    /// # fn main() {
    /// use serde_json::Value;
    ///
    /// let v = vec!["lorem", "ipsum", "dolor"];
    /// let x: Value = v.into();
    /// # }
    /// ```
    fn from(f: Vec<T>) -> Self {
        Value::Array(f.into_iter().map(Into::into).collect())
    }
}

impl<'a, T: Clone + Into<Value>> From<&'a [T]> for Value {
    /// Convert a slice to `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_json;
    /// #
    /// # fn main() {
    /// use serde_json::Value;
    ///
    /// let v: &[&str] = &["lorem", "ipsum", "dolor"];
    /// let x: Value = v.into();
    /// # }
    /// ```
    fn from(f: &'a [T]) -> Self {
        Value::Array(f.iter().cloned().map(Into::into).collect())
    }
}

impl<T: Into<Value>> ::std::iter::FromIterator<T> for Value {
    /// Convert an iteratable type to a `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_json;
    /// #
    /// # fn main() {
    /// use serde_json::Value;
    ///
    /// let v = std::iter::repeat(42).take(5);
    /// let x: Value = v.collect();
    /// # }
    /// ```
    ///
    /// ```rust
    /// # extern crate serde_json;
    /// #
    /// # fn main() {
    /// use serde_json::Value;
    ///
    /// let v: Vec<_> = vec!["lorem", "ipsum", "dolor"];
    /// let x: Value = v.into_iter().collect();
    /// # }
    /// ```
    ///
    /// ```rust
    /// # extern crate serde_json;
    /// #
    /// # fn main() {
    /// use std::iter::FromIterator;
    /// use serde_json::Value;
    ///
    /// let x: Value = Value::from_iter(vec!["lorem", "ipsum", "dolor"]);
    /// # }
    /// ```
    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
        Value::Array(iter.into_iter().map(Into::into).collect())
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate immutable_map;
extern crate rand;
extern crate test;

use immutable_map::{Map, Set};
use rand::{Rng, IsaacRng};
use test::Bencher;

#[bench]
fn insert(b: &mut Bencher) {
    let mut rng = IsaacRng::new_unseeded();
    let mut map = Map::new();
    let mut v: usize = 0;

    b.iter(|| {
        let k = rng.gen::<u16>() as usize;

        map = map.insert(k, v);

        v += 1;
    })
}

#[bench]
fn get(b: &mut Bencher) {
    let mut rng = IsaacRng::new_unseeded();
    let mut map = Map::new();
    let mut v: usize = 0;

    for _ in 0 .. 10000 {
        let k = rng.gen::<u16>() as usize;
        map = map.insert(k, v);
        v += 1;
    }

    b.iter(|| {
        let k = rng.gen::<u16>() as usize;

        map.get(&k);
    })
}

#[bench]
fn remove(b: &mut Bencher) {
    let input_size = 10000;

    let mut rng = IsaacRng::new_unseeded();
    let mut inputs = Vec::new();
    let mut map = Map::new();
    let mut v = 0usize;

    for _ in 0 .. input_size {
        let k = rng.gen::<u16>() as usize;
        inputs.push(k);
        map = map.insert(k, v);
        v += 1;
    }

    rng.shuffle(&mut inputs);
    let mut idx = 0;

    b.iter(|| {
        let k = inputs[idx];

        if let Some((removed, _)) = map.remove(&k) {
            map = removed;
        }

        idx = (idx + 1) % input_size;
    })
}

#[bench]
fn iter_small(b: &mut Bencher) {
    let mut rng = IsaacRng::new_unseeded();
    let mut map = Map::new();
    let mut v: usize = 0;

    for _ in 0 .. 10 {
        let k = rng.gen::<u16>() as usize;
        map = map.insert(k, v);
        v += 1;
    }

    b.iter(|| {
        map.iter().count();
    })
}

#[bench]
fn iter_large(b: &mut Bencher) {
    let mut rng = IsaacRng::new_unseeded();
    let mut map = Map::new();
    let mut v: usize = 0;

    for _ in 0 .. 1000 {
        let k = rng.gen::<u16>() as usize;
        map = map.insert(k, v);
        v += 1;
    }

    b.iter(|| {
        map.iter().count();
    })
}

#[bench]
fn set_iter_small(b: &mut Bencher) {
    let mut rng = IsaacRng::new_unseeded();
    let mut set = Set::new();

    for _ in 0 .. 10 {
        let k = rng.gen::<u16>() as usize;
        set = set.insert(k);
    }

    b.iter(|| {
        set.iter().count();
    })
}

#[bench]
fn set_iter_large(b: &mut Bencher) {
    let mut rng = IsaacRng::new_unseeded();
    let mut set = Set::new();

    for _ in 0 .. 1000 {
        let k = rng.gen::<u16>() as usize;
        set = set.insert(k);
    }

    b.iter(|| {
        set.iter().count();
    })
}
<commit_msg>Update benchmark code<commit_after>#![feature(test)]

extern crate immutable_map;
extern crate rand;
extern crate test;

use immutable_map::{TreeMap, TreeSet};
use rand::{Rng, IsaacRng};
use test::Bencher;

#[bench]
fn insert(b: &mut Bencher) {
    let mut rng = IsaacRng::new_unseeded();
    let mut map = TreeMap::new();
    let mut v: usize = 0;

    b.iter(|| {
        let k = rng.gen::<u16>() as usize;

        map = map.insert(k, v);

        v += 1;
    })
}

#[bench]
fn get(b: &mut Bencher) {
    let mut rng = IsaacRng::new_unseeded();
    let mut map = TreeMap::new();
    let mut v: usize = 0;

    for _ in 0 .. 10000 {
        let k = rng.gen::<u16>() as usize;
        map = map.insert(k, v);
        v += 1;
    }

    b.iter(|| {
        let k = rng.gen::<u16>() as usize;

        map.get(&k);
    })
}

#[bench]
fn remove(b: &mut Bencher) {
    let input_size = 10000;

    let mut rng = IsaacRng::new_unseeded();
    let mut inputs = Vec::new();
    let mut map = TreeMap::new();
    let mut v = 0usize;

    for _ in 0 .. input_size {
        let k = rng.gen::<u16>() as usize;
        inputs.push(k);
        map = map.insert(k, v);
        v += 1;
    }

    rng.shuffle(&mut inputs);
    let mut idx = 0;

    b.iter(|| {
        let k = inputs[idx];

        if let Some((removed, _)) = map.remove(&k) {
            map = removed;
        }

        idx = (idx + 1) % input_size;
    })
}

#[bench]
fn iter_small(b: &mut Bencher) {
    let mut rng = IsaacRng::new_unseeded();
    let mut map = TreeMap::new();
    let mut v: usize = 0;

    for _ in 0 .. 10 {
        let k = rng.gen::<u16>() as usize;
        map = map.insert(k, v);
        v += 1;
    }

    b.iter(|| {
        map.iter().count();
    })
}

#[bench]
fn iter_large(b: &mut Bencher) {
    let mut rng = IsaacRng::new_unseeded();
    let mut map = TreeMap::new();
    let mut v: usize = 0;

    for _ in 0 .. 1000 {
        let k = rng.gen::<u16>() as usize;
        map = map.insert(k, v);
        v += 1;
    }

    b.iter(|| {
        map.iter().count();
    })
}

#[bench]
fn set_iter_small(b: &mut Bencher) {
    let mut rng = IsaacRng::new_unseeded();
    let mut set = TreeSet::new();

    for _ in 0 .. 10 {
        let k = rng.gen::<u16>() as usize;
        set = set.insert(k);
    }

    b.iter(|| {
        set.iter().count();
    })
}

#[bench]
fn set_iter_large(b: &mut Bencher) {
    let mut rng = IsaacRng::new_unseeded();
    let mut set = TreeSet::new();

    for _ in 0 .. 1000 {
        let k = rng.gen::<u16>() as usize;
        set = set.insert(k);
    }

    b.iter(|| {
        set.iter().count();
    })
}
<|endoftext|>


<commit_before><commit_msg>Use objdump on Macos x86_64 as well.<commit_after><|endoftext|>


<commit_before>extern crate getopts;
extern crate natord;

use file::File;
use column::{Column, SizeFormat};
use column::Column::*;
use output::View;
use term::dimensions;

use std::ascii::AsciiExt;
use std::slice::Iter;
use std::fmt;

use self::Misfire::*;

/// The *Options* struct represents a parsed version of the user's
/// command-line options.
#[derive(PartialEq, Debug)]
pub struct Options {
    pub list_dirs: bool,
    path_strs: Vec<String>,
    reverse: bool,
    show_invisibles: bool,
    sort_field: SortField,
    view: View,
}

impl Options {

    /// Call getopts on the given slice of command-line strings.
    pub fn getopts(args: &[String]) -> Result<Options, Misfire> {
        let opts = &[
            getopts::optflag("1", "oneline",   "display one entry per line"),
            getopts::optflag("a", "all",       "show dot-files"),
            getopts::optflag("b", "binary",    "use binary prefixes in file sizes"),
            getopts::optflag("B", "bytes",     "list file sizes in bytes, without prefixes"),
            getopts::optflag("d", "list-dirs", "list directories as regular files"),
            getopts::optflag("g", "group",     "show group as well as user"),
            getopts::optflag("h", "header",    "show a header row at the top"),
            getopts::optflag("H", "links",     "show number of hard links"),
            getopts::optflag("l", "long",      "display extended details and attributes"),
            getopts::optflag("i", "inode",     "show each file's inode number"),
            getopts::optflag("r", "reverse",   "reverse order of files"),
            getopts::optopt ("s", "sort",      "field to sort by", "WORD"),
            getopts::optflag("S", "blocks",    "show number of file system blocks"),
            getopts::optflag("x", "across",    "sort multi-column view entries across"),
            getopts::optflag("?", "help",      "show list of command-line options"),
        ];

        let matches = match getopts::getopts(args, opts) {
            Ok(m) => m,
            Err(e) => return Err(Misfire::InvalidOptions(e)),
        };

        if matches.opt_present("help") {
            return Err(Misfire::Help(getopts::usage("Usage:\n  exa [options] [files...]", opts)));
        }

        let sort_field = match matches.opt_str("sort") {
            Some(word) => try!(SortField::from_word(word)),
            None => SortField::Name,
        };

        Ok(Options {
            list_dirs:       matches.opt_present("list-dirs"),
            path_strs:       if matches.free.is_empty() { vec![ ".".to_string() ] } else { matches.free.clone() },
            reverse:         matches.opt_present("reverse"),
            show_invisibles: matches.opt_present("all"),
            sort_field:      sort_field,
            view:            try!(view(&matches)),
        })
    }

    /// Iterate over the non-option arguments left oven from getopts.
    pub fn path_strings(&self) -> Iter<String> {
        self.path_strs.iter()
    }

    /// Display the files using this Option's View.
    pub fn view(&self, files: Vec<File>) {
        self.view.view(files)
    }

    /// Transform the files somehow before listing them.
    pub fn transform_files<'a>(&self, mut files: Vec<File<'a>>) -> Vec<File<'a>> {

        if !self.show_invisibles {
            files = files.into_iter().filter(|f| !f.is_dotfile()).collect();
        }

        match self.sort_field {
            SortField::Unsorted => {},
            SortField::Name => files.sort_by(|a, b| natord::compare(a.name.as_slice(), b.name.as_slice())),
            SortField::Size => files.sort_by(|a, b| a.stat.size.cmp(&b.stat.size)),
            SortField::FileInode => files.sort_by(|a, b| a.stat.unstable.inode.cmp(&b.stat.unstable.inode)),
            SortField::Extension => files.sort_by(|a, b| {
                let exts  = a.ext.clone().map(|e| e.to_ascii_lowercase()).cmp(&b.ext.clone().map(|e| e.to_ascii_lowercase()));
                let names = a.name.to_ascii_lowercase().cmp(&b.name.to_ascii_lowercase());
                exts.cmp(&names)
            }),
        }

        if self.reverse {
            files.reverse();
        }

        files
    }
}

/// User-supplied field to sort by
#[derive(PartialEq, Debug)]
pub enum SortField {
    Unsorted, Name, Extension, Size, FileInode
}

impl Copy for SortField { }

impl SortField {

    /// Find which field to use based on a user-supplied word.
    fn from_word(word: String) -> Result<SortField, Misfire> {
        match word.as_slice() {
            "name"  => Ok(SortField::Name),
            "size"  => Ok(SortField::Size),
            "ext"   => Ok(SortField::Extension),
            "none"  => Ok(SortField::Unsorted),
            "inode" => Ok(SortField::FileInode),
            field   => Err(SortField::none(field))
        }
    }

    /// How to display an error when the word didn't match with anything.
    fn none(field: &str) -> Misfire {
        Misfire::InvalidOptions(getopts::Fail::UnrecognizedOption(format!("--sort {}", field)))
    }
}

/// One of these things could happen instead of listing files.
#[derive(PartialEq, Debug)]
pub enum Misfire {

    /// The getopts crate didn't like these arguments.
    InvalidOptions(getopts::Fail),

    /// The user asked for help. This isn't strictly an error, which is why
    /// this enum isn't named Error!
    Help(String),

    /// Two options were given that conflict with one another
    Conflict(&'static str, &'static str),

    /// An option was given that does nothing when another one either is or
    /// isn't present.
    Useless(&'static str, bool, &'static str),
}

impl Misfire {
    /// The OS return code this misfire should signify.
    pub fn error_code(&self) -> isize {
        if let Help(_) = *self { 2 }
                          else { 3 }
    }
}

impl fmt::Display for Misfire {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            InvalidOptions(ref e) => write!(f, "{}", e),
            Help(ref text)        => write!(f, "{}", text),
            Conflict(a, b)        => write!(f, "Option --{} conflicts with option {}", a, b),
            Useless(a, false, b)  => write!(f, "Option --{} is useless without option --{}", a, b),
            Useless(a, true, b)   => write!(f, "Option --{} is useless given option --{}", a, b),
        }
    }
}

/// Turns the Getopts results object into a View object.
fn view(matches: &getopts::Matches) -> Result<View, Misfire> {
    if matches.opt_present("long") {
        if matches.opt_present("across") {
            Err(Misfire::Useless("across", true, "long"))
        }
        else if matches.opt_present("oneline") {
            Err(Misfire::Useless("across", true, "long"))
        }
        else {
            Ok(View::Details(try!(columns(matches)), matches.opt_present("header")))
        }
    }
    else if matches.opt_present("binary") {
        Err(Misfire::Useless("binary", false, "long"))
    }
    else if matches.opt_present("bytes") {
        Err(Misfire::Useless("bytes", false, "long"))
    }
    else if matches.opt_present("oneline") {
        if matches.opt_present("across") {
            Err(Misfire::Useless("across", true, "oneline"))
        }
        else {
            Ok(View::Lines)
        }
    }
    else {
        match dimensions() {
            None => Ok(View::Lines),
            Some((width, _)) => Ok(View::Grid(matches.opt_present("across"), width)),
        }
    }
}

/// Finds out which file size the user has asked for.
fn file_size(matches: &getopts::Matches) -> Result<SizeFormat, Misfire> {
    let binary = matches.opt_present("binary");
    let bytes = matches.opt_present("bytes");

    match (binary, bytes) {
        (true,  true ) => Err(Misfire::Conflict("binary", "bytes")),
        (true,  false) => Ok(SizeFormat::BinaryBytes),
        (false, true ) => Ok(SizeFormat::JustBytes),
        (false, false) => Ok(SizeFormat::DecimalBytes),
    }
}

/// Turns the Getopts results object into a list of columns for the columns
/// view, depending on the passed-in command-line arguments.
fn columns(matches: &getopts::Matches) -> Result<Vec<Column>, Misfire> {
    let mut columns = vec![];

    if matches.opt_present("inode") {
        columns.push(Inode);
    }

    columns.push(Permissions);

    if matches.opt_present("links") {
        columns.push(HardLinks);
    }

    // Fail early here if two file size flags are given
    columns.push(FileSize(try!(file_size(matches))));

    if matches.opt_present("blocks") {
        columns.push(Blocks);
    }

    columns.push(User);

    if matches.opt_present("group") {
        columns.push(Group);
    }

    columns.push(FileName);
    Ok(columns)
}

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

    use std::fmt;

    fn is_helpful(misfire: Result<Options, Misfire>) -> bool {
        match misfire {
            Err(Help(_)) => true,
            _            => false,
        }
    }

    impl fmt::Display for Options {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, "{:?}", self)
        }
    }

    #[test]
    fn help() {
        let opts = Options::getopts(&[ "--help".to_string() ]);
        assert!(is_helpful(opts))
    }

    #[test]
    fn help_with_file() {
        let opts = Options::getopts(&[ "--help".to_string(), "me".to_string() ]);
        assert!(is_helpful(opts))
    }

    #[test]
    fn files() {
        let opts = Options::getopts(&[ "this file".to_string(), "that file".to_string() ]).unwrap();
        let args: Vec<&String> = opts.path_strings().collect();
        assert_eq!(args, vec![ &"this file".to_string(), &"that file".to_string() ])
    }

    #[test]
    fn no_args() {
        let opts = Options::getopts(&[]).unwrap();
        let args: Vec<&String> = opts.path_strings().collect();
        assert_eq!(args, vec![ &".".to_string() ])
    }

    #[test]
    fn file_sizes() {
        let opts = Options::getopts(&[ "--long".to_string(), "--binary".to_string(), "--bytes".to_string() ]);
        assert_eq!(opts.unwrap_err(), Misfire::Conflict("binary", "bytes"))
    }

    #[test]
    fn just_binary() {
        let opts = Options::getopts(&[ "--binary".to_string() ]);
        assert_eq!(opts.unwrap_err(), Misfire::Useless("binary", false, "long"))
    }

    #[test]
    fn just_bytes() {
        let opts = Options::getopts(&[ "--bytes".to_string() ]);
        assert_eq!(opts.unwrap_err(), Misfire::Useless("bytes", false, "long"))
    }

    #[test]
    fn long_across() {
        let opts = Options::getopts(&[ "--long".to_string(), "--across".to_string() ]);
        assert_eq!(opts.unwrap_err(), Misfire::Useless("across", true, "long"))
    }

    #[test]
    fn oneline_across() {
        let opts = Options::getopts(&[ "--oneline".to_string(), "--across".to_string() ]);
        assert_eq!(opts.unwrap_err(), Misfire::Useless("across", true, "oneline"))
    }
}
<commit_msg>Add all-important dots<commit_after>extern crate getopts;
extern crate natord;

use file::File;
use column::{Column, SizeFormat};
use column::Column::*;
use output::View;
use term::dimensions;

use std::ascii::AsciiExt;
use std::slice::Iter;
use std::fmt;

use self::Misfire::*;

/// The *Options* struct represents a parsed version of the user's
/// command-line options.
#[derive(PartialEq, Debug)]
pub struct Options {
    pub list_dirs: bool,
    path_strs: Vec<String>,
    reverse: bool,
    show_invisibles: bool,
    sort_field: SortField,
    view: View,
}

impl Options {

    /// Call getopts on the given slice of command-line strings.
    pub fn getopts(args: &[String]) -> Result<Options, Misfire> {
        let opts = &[
            getopts::optflag("1", "oneline",   "display one entry per line"),
            getopts::optflag("a", "all",       "show dot-files"),
            getopts::optflag("b", "binary",    "use binary prefixes in file sizes"),
            getopts::optflag("B", "bytes",     "list file sizes in bytes, without prefixes"),
            getopts::optflag("d", "list-dirs", "list directories as regular files"),
            getopts::optflag("g", "group",     "show group as well as user"),
            getopts::optflag("h", "header",    "show a header row at the top"),
            getopts::optflag("H", "links",     "show number of hard links"),
            getopts::optflag("l", "long",      "display extended details and attributes"),
            getopts::optflag("i", "inode",     "show each file's inode number"),
            getopts::optflag("r", "reverse",   "reverse order of files"),
            getopts::optopt ("s", "sort",      "field to sort by", "WORD"),
            getopts::optflag("S", "blocks",    "show number of file system blocks"),
            getopts::optflag("x", "across",    "sort multi-column view entries across"),
            getopts::optflag("?", "help",      "show list of command-line options"),
        ];

        let matches = match getopts::getopts(args, opts) {
            Ok(m) => m,
            Err(e) => return Err(Misfire::InvalidOptions(e)),
        };

        if matches.opt_present("help") {
            return Err(Misfire::Help(getopts::usage("Usage:\n  exa [options] [files...]", opts)));
        }

        let sort_field = match matches.opt_str("sort") {
            Some(word) => try!(SortField::from_word(word)),
            None => SortField::Name,
        };

        Ok(Options {
            list_dirs:       matches.opt_present("list-dirs"),
            path_strs:       if matches.free.is_empty() { vec![ ".".to_string() ] } else { matches.free.clone() },
            reverse:         matches.opt_present("reverse"),
            show_invisibles: matches.opt_present("all"),
            sort_field:      sort_field,
            view:            try!(view(&matches)),
        })
    }

    /// Iterate over the non-option arguments left oven from getopts.
    pub fn path_strings(&self) -> Iter<String> {
        self.path_strs.iter()
    }

    /// Display the files using this Option's View.
    pub fn view(&self, files: Vec<File>) {
        self.view.view(files)
    }

    /// Transform the files somehow before listing them.
    pub fn transform_files<'a>(&self, mut files: Vec<File<'a>>) -> Vec<File<'a>> {

        if !self.show_invisibles {
            files = files.into_iter().filter(|f| !f.is_dotfile()).collect();
        }

        match self.sort_field {
            SortField::Unsorted => {},
            SortField::Name => files.sort_by(|a, b| natord::compare(a.name.as_slice(), b.name.as_slice())),
            SortField::Size => files.sort_by(|a, b| a.stat.size.cmp(&b.stat.size)),
            SortField::FileInode => files.sort_by(|a, b| a.stat.unstable.inode.cmp(&b.stat.unstable.inode)),
            SortField::Extension => files.sort_by(|a, b| {
                let exts  = a.ext.clone().map(|e| e.to_ascii_lowercase()).cmp(&b.ext.clone().map(|e| e.to_ascii_lowercase()));
                let names = a.name.to_ascii_lowercase().cmp(&b.name.to_ascii_lowercase());
                exts.cmp(&names)
            }),
        }

        if self.reverse {
            files.reverse();
        }

        files
    }
}

/// User-supplied field to sort by
#[derive(PartialEq, Debug)]
pub enum SortField {
    Unsorted, Name, Extension, Size, FileInode
}

impl Copy for SortField { }

impl SortField {

    /// Find which field to use based on a user-supplied word.
    fn from_word(word: String) -> Result<SortField, Misfire> {
        match word.as_slice() {
            "name"  => Ok(SortField::Name),
            "size"  => Ok(SortField::Size),
            "ext"   => Ok(SortField::Extension),
            "none"  => Ok(SortField::Unsorted),
            "inode" => Ok(SortField::FileInode),
            field   => Err(SortField::none(field))
        }
    }

    /// How to display an error when the word didn't match with anything.
    fn none(field: &str) -> Misfire {
        Misfire::InvalidOptions(getopts::Fail::UnrecognizedOption(format!("--sort {}", field)))
    }
}

/// One of these things could happen instead of listing files.
#[derive(PartialEq, Debug)]
pub enum Misfire {

    /// The getopts crate didn't like these arguments.
    InvalidOptions(getopts::Fail),

    /// The user asked for help. This isn't strictly an error, which is why
    /// this enum isn't named Error!
    Help(String),

    /// Two options were given that conflict with one another
    Conflict(&'static str, &'static str),

    /// An option was given that does nothing when another one either is or
    /// isn't present.
    Useless(&'static str, bool, &'static str),
}

impl Misfire {
    /// The OS return code this misfire should signify.
    pub fn error_code(&self) -> isize {
        if let Help(_) = *self { 2 }
                          else { 3 }
    }
}

impl fmt::Display for Misfire {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            InvalidOptions(ref e) => write!(f, "{}", e),
            Help(ref text)        => write!(f, "{}", text),
            Conflict(a, b)        => write!(f, "Option --{} conflicts with option {}.", a, b),
            Useless(a, false, b)  => write!(f, "Option --{} is useless without option --{}.", a, b),
            Useless(a, true, b)   => write!(f, "Option --{} is useless given option --{}.", a, b),
        }
    }
}

/// Turns the Getopts results object into a View object.
fn view(matches: &getopts::Matches) -> Result<View, Misfire> {
    if matches.opt_present("long") {
        if matches.opt_present("across") {
            Err(Misfire::Useless("across", true, "long"))
        }
        else if matches.opt_present("oneline") {
            Err(Misfire::Useless("across", true, "long"))
        }
        else {
            Ok(View::Details(try!(columns(matches)), matches.opt_present("header")))
        }
    }
    else if matches.opt_present("binary") {
        Err(Misfire::Useless("binary", false, "long"))
    }
    else if matches.opt_present("bytes") {
        Err(Misfire::Useless("bytes", false, "long"))
    }
    else if matches.opt_present("oneline") {
        if matches.opt_present("across") {
            Err(Misfire::Useless("across", true, "oneline"))
        }
        else {
            Ok(View::Lines)
        }
    }
    else {
        match dimensions() {
            None => Ok(View::Lines),
            Some((width, _)) => Ok(View::Grid(matches.opt_present("across"), width)),
        }
    }
}

/// Finds out which file size the user has asked for.
fn file_size(matches: &getopts::Matches) -> Result<SizeFormat, Misfire> {
    let binary = matches.opt_present("binary");
    let bytes = matches.opt_present("bytes");

    match (binary, bytes) {
        (true,  true ) => Err(Misfire::Conflict("binary", "bytes")),
        (true,  false) => Ok(SizeFormat::BinaryBytes),
        (false, true ) => Ok(SizeFormat::JustBytes),
        (false, false) => Ok(SizeFormat::DecimalBytes),
    }
}

/// Turns the Getopts results object into a list of columns for the columns
/// view, depending on the passed-in command-line arguments.
fn columns(matches: &getopts::Matches) -> Result<Vec<Column>, Misfire> {
    let mut columns = vec![];

    if matches.opt_present("inode") {
        columns.push(Inode);
    }

    columns.push(Permissions);

    if matches.opt_present("links") {
        columns.push(HardLinks);
    }

    // Fail early here if two file size flags are given
    columns.push(FileSize(try!(file_size(matches))));

    if matches.opt_present("blocks") {
        columns.push(Blocks);
    }

    columns.push(User);

    if matches.opt_present("group") {
        columns.push(Group);
    }

    columns.push(FileName);
    Ok(columns)
}

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

    use std::fmt;

    fn is_helpful(misfire: Result<Options, Misfire>) -> bool {
        match misfire {
            Err(Help(_)) => true,
            _            => false,
        }
    }

    impl fmt::Display for Options {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, "{:?}", self)
        }
    }

    #[test]
    fn help() {
        let opts = Options::getopts(&[ "--help".to_string() ]);
        assert!(is_helpful(opts))
    }

    #[test]
    fn help_with_file() {
        let opts = Options::getopts(&[ "--help".to_string(), "me".to_string() ]);
        assert!(is_helpful(opts))
    }

    #[test]
    fn files() {
        let opts = Options::getopts(&[ "this file".to_string(), "that file".to_string() ]).unwrap();
        let args: Vec<&String> = opts.path_strings().collect();
        assert_eq!(args, vec![ &"this file".to_string(), &"that file".to_string() ])
    }

    #[test]
    fn no_args() {
        let opts = Options::getopts(&[]).unwrap();
        let args: Vec<&String> = opts.path_strings().collect();
        assert_eq!(args, vec![ &".".to_string() ])
    }

    #[test]
    fn file_sizes() {
        let opts = Options::getopts(&[ "--long".to_string(), "--binary".to_string(), "--bytes".to_string() ]);
        assert_eq!(opts.unwrap_err(), Misfire::Conflict("binary", "bytes"))
    }

    #[test]
    fn just_binary() {
        let opts = Options::getopts(&[ "--binary".to_string() ]);
        assert_eq!(opts.unwrap_err(), Misfire::Useless("binary", false, "long"))
    }

    #[test]
    fn just_bytes() {
        let opts = Options::getopts(&[ "--bytes".to_string() ]);
        assert_eq!(opts.unwrap_err(), Misfire::Useless("bytes", false, "long"))
    }

    #[test]
    fn long_across() {
        let opts = Options::getopts(&[ "--long".to_string(), "--across".to_string() ]);
        assert_eq!(opts.unwrap_err(), Misfire::Useless("across", true, "long"))
    }

    #[test]
    fn oneline_across() {
        let opts = Options::getopts(&[ "--oneline".to_string(), "--across".to_string() ]);
        assert_eq!(opts.unwrap_err(), Misfire::Useless("across", true, "oneline"))
    }
}
<|endoftext|>


<commit_before>//! Argument passing

use crate::prelude::*;
use crate::value_and_place::assert_assignable;

use cranelift_codegen::ir::ArgumentPurpose;
use rustc_target::abi::call::{ArgAbi, CastTarget, PassMode, Reg, RegKind};
use smallvec::{smallvec, SmallVec};

pub(super) trait ArgAbiExt<'tcx> {
    fn get_abi_param(&self, tcx: TyCtxt<'tcx>) -> SmallVec<[AbiParam; 2]>;
    fn get_abi_return(&self, tcx: TyCtxt<'tcx>) -> (Option<AbiParam>, Vec<AbiParam>);
}

fn reg_to_abi_param(reg: Reg) -> AbiParam {
    let clif_ty = match (reg.kind, reg.size.bytes()) {
        (RegKind::Integer, 1) => types::I8,
        (RegKind::Integer, 2) => types::I16,
        (RegKind::Integer, 4) => types::I32,
        (RegKind::Integer, 8) => types::I64,
        (RegKind::Integer, 16) => types::I128,
        (RegKind::Float, 4) => types::F32,
        (RegKind::Float, 8) => types::F64,
        (RegKind::Vector, size) => types::I8.by(u16::try_from(size).unwrap()).unwrap(),
        _ => unreachable!("{:?}", reg),
    };
    AbiParam::new(clif_ty)
}

fn cast_target_to_abi_params(cast: CastTarget) -> SmallVec<[AbiParam; 2]> {
    let (rest_count, rem_bytes) = if cast.rest.unit.size.bytes() == 0 {
        (0, 0)
    } else {
        (
            cast.rest.total.bytes() / cast.rest.unit.size.bytes(),
            cast.rest.total.bytes() % cast.rest.unit.size.bytes(),
        )
    };

    if cast.prefix.iter().all(|x| x.is_none()) {
        // Simplify to a single unit when there is no prefix and size <= unit size
        if cast.rest.total <= cast.rest.unit.size {
            let clif_ty = match (cast.rest.unit.kind, cast.rest.unit.size.bytes()) {
                (RegKind::Integer, 1) => types::I8,
                (RegKind::Integer, 2) => types::I16,
                (RegKind::Integer, 3..=4) => types::I32,
                (RegKind::Integer, 5..=8) => types::I64,
                (RegKind::Integer, 9..=16) => types::I128,
                (RegKind::Float, 4) => types::F32,
                (RegKind::Float, 8) => types::F64,
                (RegKind::Vector, size) => types::I8.by(u16::try_from(size).unwrap()).unwrap(),
                _ => unreachable!("{:?}", cast.rest.unit),
            };
            return smallvec![AbiParam::new(clif_ty)];
        }
    }

    // Create list of fields in the main structure
    let mut args = cast
        .prefix
        .iter()
        .flatten()
        .map(|&kind| {
            reg_to_abi_param(Reg {
                kind,
                size: cast.prefix_chunk_size,
            })
        })
        .chain((0..rest_count).map(|_| reg_to_abi_param(cast.rest.unit)))
        .collect::<SmallVec<_>>();

    // Append final integer
    if rem_bytes != 0 {
        // Only integers can be really split further.
        assert_eq!(cast.rest.unit.kind, RegKind::Integer);
        args.push(reg_to_abi_param(Reg {
            kind: RegKind::Integer,
            size: Size::from_bytes(rem_bytes),
        }));
    }

    args
}

// FIXME respect argument extension mode

impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
    fn get_abi_param(&self, tcx: TyCtxt<'tcx>) -> SmallVec<[AbiParam; 2]> {
        match self.mode {
            PassMode::Ignore => smallvec![],
            PassMode::Direct(_) => match &self.layout.abi {
                Abi::Scalar(scalar) => {
                    smallvec![AbiParam::new(scalar_to_clif_type(tcx, scalar.clone()))]
                }
                Abi::Vector { .. } => {
                    let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout).unwrap();
                    smallvec![AbiParam::new(vector_ty)]
                }
                _ => unreachable!("{:?}", self.layout.abi),
            },
            PassMode::Pair(_, _) => match &self.layout.abi {
                Abi::ScalarPair(a, b) => {
                    let a = scalar_to_clif_type(tcx, a.clone());
                    let b = scalar_to_clif_type(tcx, b.clone());
                    smallvec![AbiParam::new(a), AbiParam::new(b)]
                }
                _ => unreachable!("{:?}", self.layout.abi),
            },
            PassMode::Cast(cast) => cast_target_to_abi_params(cast),
            PassMode::Indirect {
                attrs: _,
                extra_attrs: None,
                on_stack,
            } => {
                if on_stack {
                    let size = u32::try_from(self.layout.size.bytes()).unwrap();
                    smallvec![AbiParam::special(
                        pointer_ty(tcx),
                        ArgumentPurpose::StructArgument(size),
                    )]
                } else {
                    smallvec![AbiParam::new(pointer_ty(tcx))]
                }
            }
            PassMode::Indirect {
                attrs: _,
                extra_attrs: Some(_),
                on_stack,
            } => {
                assert!(!on_stack);
                smallvec![
                    AbiParam::new(pointer_ty(tcx)),
                    AbiParam::new(pointer_ty(tcx)),
                ]
            }
        }
    }

    fn get_abi_return(&self, tcx: TyCtxt<'tcx>) -> (Option<AbiParam>, Vec<AbiParam>) {
        match self.mode {
            PassMode::Ignore => (None, vec![]),
            PassMode::Direct(_) => match &self.layout.abi {
                Abi::Scalar(scalar) => (
                    None,
                    vec![AbiParam::new(scalar_to_clif_type(tcx, scalar.clone()))],
                ),
                Abi::Vector { .. } => {
                    let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout).unwrap();
                    (None, vec![AbiParam::new(vector_ty)])
                }
                _ => unreachable!("{:?}", self.layout.abi),
            },
            PassMode::Pair(_, _) => match &self.layout.abi {
                Abi::ScalarPair(a, b) => {
                    let a = scalar_to_clif_type(tcx, a.clone());
                    let b = scalar_to_clif_type(tcx, b.clone());
                    (None, vec![AbiParam::new(a), AbiParam::new(b)])
                }
                _ => unreachable!("{:?}", self.layout.abi),
            },
            PassMode::Cast(cast) => (None, cast_target_to_abi_params(cast).into_iter().collect()),
            PassMode::Indirect {
                attrs: _,
                extra_attrs: None,
                on_stack,
            } => {
                assert!(!on_stack);
                (
                    Some(AbiParam::special(
                        pointer_ty(tcx),
                        ArgumentPurpose::StructReturn,
                    )),
                    vec![],
                )
            }
            PassMode::Indirect {
                attrs: _,
                extra_attrs: Some(_),
                on_stack: _,
            } => unreachable!("unsized return value"),
        }
    }
}

pub(super) fn to_casted_value<'tcx>(
    fx: &mut FunctionCx<'_, 'tcx, impl Module>,
    arg: CValue<'tcx>,
    cast: CastTarget,
) -> SmallVec<[Value; 2]> {
    let (ptr, meta) = arg.force_stack(fx);
    assert!(meta.is_none());
    let mut offset = 0;
    cast_target_to_abi_params(cast)
        .into_iter()
        .map(|param| {
            let val = ptr
                .offset_i64(fx, offset)
                .load(fx, param.value_type, MemFlags::new());
            offset += i64::from(param.value_type.bytes());
            val
        })
        .collect()
}

pub(super) fn from_casted_value<'tcx>(
    fx: &mut FunctionCx<'_, 'tcx, impl Module>,
    block_params: &[Value],
    layout: TyAndLayout<'tcx>,
    cast: CastTarget,
) -> CValue<'tcx> {
    let abi_params = cast_target_to_abi_params(cast);
    let size: u32 = abi_params
        .iter()
        .map(|param| param.value_type.bytes())
        .sum();
    // Stack slot size may be bigger for for example `[u8; 3]` which is packed into an `i32`.
    assert!(u64::from(size) >= layout.size.bytes());
    let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
        kind: StackSlotKind::ExplicitSlot,
        // FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to
        // specify stack slot alignment.
        size: (size + 15) / 16 * 16,
        offset: None,
    });
    let ptr = Pointer::new(fx.bcx.ins().stack_addr(pointer_ty(fx.tcx), stack_slot, 0));
    let mut offset = 0;
    let mut block_params_iter = block_params.into_iter().copied();
    for param in abi_params {
        let val = ptr.offset_i64(fx, offset).store(
            fx,
            block_params_iter.next().unwrap(),
            MemFlags::new(),
        );
        offset += i64::from(param.value_type.bytes());
        val
    }
    assert_eq!(block_params_iter.next(), None, "Leftover block param");
    CValue::by_ref(ptr, layout)
}

/// Get a set of values to be passed as function arguments.
pub(super) fn adjust_arg_for_abi<'tcx>(
    fx: &mut FunctionCx<'_, 'tcx, impl Module>,
    arg: CValue<'tcx>,
    arg_abi: &ArgAbi<'tcx, Ty<'tcx>>,
) -> SmallVec<[Value; 2]> {
    assert_assignable(fx, arg.layout().ty, arg_abi.layout.ty);
    match arg_abi.mode {
        PassMode::Ignore => smallvec![],
        PassMode::Direct(_) => smallvec![arg.load_scalar(fx)],
        PassMode::Pair(_, _) => {
            let (a, b) = arg.load_scalar_pair(fx);
            smallvec![a, b]
        }
        PassMode::Cast(cast) => to_casted_value(fx, arg, cast),
        PassMode::Indirect { .. } => match arg.force_stack(fx) {
            (ptr, None) => smallvec![ptr.get_addr(fx)],
            (ptr, Some(meta)) => smallvec![ptr.get_addr(fx), meta],
        },
    }
}

/// Create a [`CValue`] containing the value of a function parameter adding clif function parameters
/// as necessary.
pub(super) fn cvalue_for_param<'tcx>(
    fx: &mut FunctionCx<'_, 'tcx, impl Module>,
    #[cfg_attr(not(debug_assertions), allow(unused_variables))] local: Option<mir::Local>,
    #[cfg_attr(not(debug_assertions), allow(unused_variables))] local_field: Option<usize>,
    arg_abi: &ArgAbi<'tcx, Ty<'tcx>>,
    block_params_iter: &mut impl Iterator<Item = Value>,
) -> Option<CValue<'tcx>> {
    let block_params = arg_abi
        .get_abi_param(fx.tcx)
        .into_iter()
        .map(|abi_param| {
            let block_param = block_params_iter.next().unwrap();
            assert_eq!(
                fx.bcx.func.dfg.value_type(block_param),
                abi_param.value_type
            );
            block_param
        })
        .collect::<SmallVec<[_; 2]>>();

    #[cfg(debug_assertions)]
    crate::abi::comments::add_arg_comment(
        fx,
        "arg",
        local,
        local_field,
        &block_params,
        arg_abi.mode,
        arg_abi.layout,
    );

    match arg_abi.mode {
        PassMode::Ignore => None,
        PassMode::Direct(_) => {
            assert_eq!(block_params.len(), 1, "{:?}", block_params);
            Some(CValue::by_val(block_params[0], arg_abi.layout))
        }
        PassMode::Pair(_, _) => {
            assert_eq!(block_params.len(), 2, "{:?}", block_params);
            Some(CValue::by_val_pair(
                block_params[0],
                block_params[1],
                arg_abi.layout,
            ))
        }
        PassMode::Cast(cast) => Some(from_casted_value(fx, &block_params, arg_abi.layout, cast)),
        PassMode::Indirect {
            attrs: _,
            extra_attrs: None,
            on_stack: _,
        } => {
            assert_eq!(block_params.len(), 1, "{:?}", block_params);
            Some(CValue::by_ref(
                Pointer::new(block_params[0]),
                arg_abi.layout,
            ))
        }
        PassMode::Indirect {
            attrs: _,
            extra_attrs: Some(_),
            on_stack: _,
        } => {
            assert_eq!(block_params.len(), 2, "{:?}", block_params);
            Some(CValue::by_ref_unsized(
                Pointer::new(block_params[0]),
                block_params[1],
                arg_abi.layout,
            ))
        }
    }
}
<commit_msg>Handle argument extension mode<commit_after>//! Argument passing

use crate::prelude::*;
use crate::value_and_place::assert_assignable;

use cranelift_codegen::ir::{ArgumentExtension, ArgumentPurpose};
use rustc_target::abi::call::{
    ArgAbi, ArgAttributes, ArgExtension as RustcArgExtension, CastTarget, PassMode, Reg, RegKind,
};
use smallvec::{smallvec, SmallVec};

pub(super) trait ArgAbiExt<'tcx> {
    fn get_abi_param(&self, tcx: TyCtxt<'tcx>) -> SmallVec<[AbiParam; 2]>;
    fn get_abi_return(&self, tcx: TyCtxt<'tcx>) -> (Option<AbiParam>, Vec<AbiParam>);
}

fn reg_to_abi_param(reg: Reg) -> AbiParam {
    let clif_ty = match (reg.kind, reg.size.bytes()) {
        (RegKind::Integer, 1) => types::I8,
        (RegKind::Integer, 2) => types::I16,
        (RegKind::Integer, 4) => types::I32,
        (RegKind::Integer, 8) => types::I64,
        (RegKind::Integer, 16) => types::I128,
        (RegKind::Float, 4) => types::F32,
        (RegKind::Float, 8) => types::F64,
        (RegKind::Vector, size) => types::I8.by(u16::try_from(size).unwrap()).unwrap(),
        _ => unreachable!("{:?}", reg),
    };
    AbiParam::new(clif_ty)
}

fn apply_arg_attrs_to_abi_param(mut param: AbiParam, arg_attrs: ArgAttributes) -> AbiParam {
    match arg_attrs.arg_ext {
        RustcArgExtension::None => {}
        RustcArgExtension::Zext => param.extension = ArgumentExtension::Uext,
        RustcArgExtension::Sext => param.extension = ArgumentExtension::Sext,
    }
    param
}

fn cast_target_to_abi_params(cast: CastTarget) -> SmallVec<[AbiParam; 2]> {
    let (rest_count, rem_bytes) = if cast.rest.unit.size.bytes() == 0 {
        (0, 0)
    } else {
        (
            cast.rest.total.bytes() / cast.rest.unit.size.bytes(),
            cast.rest.total.bytes() % cast.rest.unit.size.bytes(),
        )
    };

    if cast.prefix.iter().all(|x| x.is_none()) {
        // Simplify to a single unit when there is no prefix and size <= unit size
        if cast.rest.total <= cast.rest.unit.size {
            let clif_ty = match (cast.rest.unit.kind, cast.rest.unit.size.bytes()) {
                (RegKind::Integer, 1) => types::I8,
                (RegKind::Integer, 2) => types::I16,
                (RegKind::Integer, 3..=4) => types::I32,
                (RegKind::Integer, 5..=8) => types::I64,
                (RegKind::Integer, 9..=16) => types::I128,
                (RegKind::Float, 4) => types::F32,
                (RegKind::Float, 8) => types::F64,
                (RegKind::Vector, size) => types::I8.by(u16::try_from(size).unwrap()).unwrap(),
                _ => unreachable!("{:?}", cast.rest.unit),
            };
            return smallvec![AbiParam::new(clif_ty)];
        }
    }

    // Create list of fields in the main structure
    let mut args = cast
        .prefix
        .iter()
        .flatten()
        .map(|&kind| {
            reg_to_abi_param(Reg {
                kind,
                size: cast.prefix_chunk_size,
            })
        })
        .chain((0..rest_count).map(|_| reg_to_abi_param(cast.rest.unit)))
        .collect::<SmallVec<_>>();

    // Append final integer
    if rem_bytes != 0 {
        // Only integers can be really split further.
        assert_eq!(cast.rest.unit.kind, RegKind::Integer);
        args.push(reg_to_abi_param(Reg {
            kind: RegKind::Integer,
            size: Size::from_bytes(rem_bytes),
        }));
    }

    args
}

impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
    fn get_abi_param(&self, tcx: TyCtxt<'tcx>) -> SmallVec<[AbiParam; 2]> {
        match self.mode {
            PassMode::Ignore => smallvec![],
            PassMode::Direct(attrs) => match &self.layout.abi {
                Abi::Scalar(scalar) => {
                    smallvec![apply_arg_attrs_to_abi_param(
                        AbiParam::new(scalar_to_clif_type(tcx, scalar.clone())),
                        attrs
                    )]
                }
                Abi::Vector { .. } => {
                    let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout).unwrap();
                    smallvec![AbiParam::new(vector_ty)]
                }
                _ => unreachable!("{:?}", self.layout.abi),
            },
            PassMode::Pair(attrs_a, attrs_b) => match &self.layout.abi {
                Abi::ScalarPair(a, b) => {
                    let a = scalar_to_clif_type(tcx, a.clone());
                    let b = scalar_to_clif_type(tcx, b.clone());
                    smallvec![
                        apply_arg_attrs_to_abi_param(AbiParam::new(a), attrs_a),
                        apply_arg_attrs_to_abi_param(AbiParam::new(b), attrs_b),
                    ]
                }
                _ => unreachable!("{:?}", self.layout.abi),
            },
            PassMode::Cast(cast) => cast_target_to_abi_params(cast),
            PassMode::Indirect {
                attrs,
                extra_attrs: None,
                on_stack,
            } => {
                if on_stack {
                    let size = u32::try_from(self.layout.size.bytes()).unwrap();
                    smallvec![apply_arg_attrs_to_abi_param(
                        AbiParam::special(pointer_ty(tcx), ArgumentPurpose::StructArgument(size),),
                        attrs
                    )]
                } else {
                    smallvec![apply_arg_attrs_to_abi_param(
                        AbiParam::new(pointer_ty(tcx)),
                        attrs
                    )]
                }
            }
            PassMode::Indirect {
                attrs,
                extra_attrs: Some(extra_attrs),
                on_stack,
            } => {
                assert!(!on_stack);
                smallvec![
                    apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), attrs),
                    apply_arg_attrs_to_abi_param(AbiParam::new(pointer_ty(tcx)), extra_attrs),
                ]
            }
        }
    }

    fn get_abi_return(&self, tcx: TyCtxt<'tcx>) -> (Option<AbiParam>, Vec<AbiParam>) {
        match self.mode {
            PassMode::Ignore => (None, vec![]),
            PassMode::Direct(_) => match &self.layout.abi {
                Abi::Scalar(scalar) => (
                    None,
                    vec![AbiParam::new(scalar_to_clif_type(tcx, scalar.clone()))],
                ),
                Abi::Vector { .. } => {
                    let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout).unwrap();
                    (None, vec![AbiParam::new(vector_ty)])
                }
                _ => unreachable!("{:?}", self.layout.abi),
            },
            PassMode::Pair(_, _) => match &self.layout.abi {
                Abi::ScalarPair(a, b) => {
                    let a = scalar_to_clif_type(tcx, a.clone());
                    let b = scalar_to_clif_type(tcx, b.clone());
                    (None, vec![AbiParam::new(a), AbiParam::new(b)])
                }
                _ => unreachable!("{:?}", self.layout.abi),
            },
            PassMode::Cast(cast) => (None, cast_target_to_abi_params(cast).into_iter().collect()),
            PassMode::Indirect {
                attrs: _,
                extra_attrs: None,
                on_stack,
            } => {
                assert!(!on_stack);
                (
                    Some(AbiParam::special(
                        pointer_ty(tcx),
                        ArgumentPurpose::StructReturn,
                    )),
                    vec![],
                )
            }
            PassMode::Indirect {
                attrs: _,
                extra_attrs: Some(_),
                on_stack: _,
            } => unreachable!("unsized return value"),
        }
    }
}

pub(super) fn to_casted_value<'tcx>(
    fx: &mut FunctionCx<'_, 'tcx, impl Module>,
    arg: CValue<'tcx>,
    cast: CastTarget,
) -> SmallVec<[Value; 2]> {
    let (ptr, meta) = arg.force_stack(fx);
    assert!(meta.is_none());
    let mut offset = 0;
    cast_target_to_abi_params(cast)
        .into_iter()
        .map(|param| {
            let val = ptr
                .offset_i64(fx, offset)
                .load(fx, param.value_type, MemFlags::new());
            offset += i64::from(param.value_type.bytes());
            val
        })
        .collect()
}

pub(super) fn from_casted_value<'tcx>(
    fx: &mut FunctionCx<'_, 'tcx, impl Module>,
    block_params: &[Value],
    layout: TyAndLayout<'tcx>,
    cast: CastTarget,
) -> CValue<'tcx> {
    let abi_params = cast_target_to_abi_params(cast);
    let size: u32 = abi_params
        .iter()
        .map(|param| param.value_type.bytes())
        .sum();
    // Stack slot size may be bigger for for example `[u8; 3]` which is packed into an `i32`.
    assert!(u64::from(size) >= layout.size.bytes());
    let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
        kind: StackSlotKind::ExplicitSlot,
        // FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to
        // specify stack slot alignment.
        size: (size + 15) / 16 * 16,
        offset: None,
    });
    let ptr = Pointer::new(fx.bcx.ins().stack_addr(pointer_ty(fx.tcx), stack_slot, 0));
    let mut offset = 0;
    let mut block_params_iter = block_params.into_iter().copied();
    for param in abi_params {
        let val = ptr.offset_i64(fx, offset).store(
            fx,
            block_params_iter.next().unwrap(),
            MemFlags::new(),
        );
        offset += i64::from(param.value_type.bytes());
        val
    }
    assert_eq!(block_params_iter.next(), None, "Leftover block param");
    CValue::by_ref(ptr, layout)
}

/// Get a set of values to be passed as function arguments.
pub(super) fn adjust_arg_for_abi<'tcx>(
    fx: &mut FunctionCx<'_, 'tcx, impl Module>,
    arg: CValue<'tcx>,
    arg_abi: &ArgAbi<'tcx, Ty<'tcx>>,
) -> SmallVec<[Value; 2]> {
    assert_assignable(fx, arg.layout().ty, arg_abi.layout.ty);
    match arg_abi.mode {
        PassMode::Ignore => smallvec![],
        PassMode::Direct(_) => smallvec![arg.load_scalar(fx)],
        PassMode::Pair(_, _) => {
            let (a, b) = arg.load_scalar_pair(fx);
            smallvec![a, b]
        }
        PassMode::Cast(cast) => to_casted_value(fx, arg, cast),
        PassMode::Indirect { .. } => match arg.force_stack(fx) {
            (ptr, None) => smallvec![ptr.get_addr(fx)],
            (ptr, Some(meta)) => smallvec![ptr.get_addr(fx), meta],
        },
    }
}

/// Create a [`CValue`] containing the value of a function parameter adding clif function parameters
/// as necessary.
pub(super) fn cvalue_for_param<'tcx>(
    fx: &mut FunctionCx<'_, 'tcx, impl Module>,
    #[cfg_attr(not(debug_assertions), allow(unused_variables))] local: Option<mir::Local>,
    #[cfg_attr(not(debug_assertions), allow(unused_variables))] local_field: Option<usize>,
    arg_abi: &ArgAbi<'tcx, Ty<'tcx>>,
    block_params_iter: &mut impl Iterator<Item = Value>,
) -> Option<CValue<'tcx>> {
    let block_params = arg_abi
        .get_abi_param(fx.tcx)
        .into_iter()
        .map(|abi_param| {
            let block_param = block_params_iter.next().unwrap();
            assert_eq!(
                fx.bcx.func.dfg.value_type(block_param),
                abi_param.value_type
            );
            block_param
        })
        .collect::<SmallVec<[_; 2]>>();

    #[cfg(debug_assertions)]
    crate::abi::comments::add_arg_comment(
        fx,
        "arg",
        local,
        local_field,
        &block_params,
        arg_abi.mode,
        arg_abi.layout,
    );

    match arg_abi.mode {
        PassMode::Ignore => None,
        PassMode::Direct(_) => {
            assert_eq!(block_params.len(), 1, "{:?}", block_params);
            Some(CValue::by_val(block_params[0], arg_abi.layout))
        }
        PassMode::Pair(_, _) => {
            assert_eq!(block_params.len(), 2, "{:?}", block_params);
            Some(CValue::by_val_pair(
                block_params[0],
                block_params[1],
                arg_abi.layout,
            ))
        }
        PassMode::Cast(cast) => Some(from_casted_value(fx, &block_params, arg_abi.layout, cast)),
        PassMode::Indirect {
            attrs: _,
            extra_attrs: None,
            on_stack: _,
        } => {
            assert_eq!(block_params.len(), 1, "{:?}", block_params);
            Some(CValue::by_ref(
                Pointer::new(block_params[0]),
                arg_abi.layout,
            ))
        }
        PassMode::Indirect {
            attrs: _,
            extra_attrs: Some(_),
            on_stack: _,
        } => {
            assert_eq!(block_params.len(), 2, "{:?}", block_params);
            Some(CValue::by_ref_unsized(
                Pointer::new(block_params[0]),
                block_params[1],
                arg_abi.layout,
            ))
        }
    }
}
<|endoftext|>


<commit_before>use super::utils::types::{ Hash256, Bitfield };
use super::utils::bls::{ AggregateSignature };

pub struct AttestationRecord {
    pub slot: u64,
    pub shard_id: u16,
    pub oblique_parent_hashes: Vec<Hash256>,
    pub shard_block_hash: Hash256,
    pub attester_bitfield: Bitfield,
    pub aggregate_sig: Option<AggregateSignature>,
}

impl AttestationRecord {
    pub fn zero() -> Self {
        Self {
            slot: 0,
            shard_id: 0,
            oblique_parent_hashes: vec![],
            shard_block_hash: Hash256::zero(),
            attester_bitfield: Bitfield::new(),
            aggregate_sig: None,
        }
    }
}
<commit_msg>Add ssz for AttestationRecord<commit_after>use super::utils::types::{ Hash256, Bitfield };
use super::utils::bls::{ AggregateSignature };
use super::ssz::{ Encodable, SszStream };

pub struct AttestationRecord {
    pub slot: u64,
    pub shard_id: u16,
    pub oblique_parent_hashes: Vec<Hash256>,
    pub shard_block_hash: Hash256,
    pub attester_bitfield: Bitfield,
    pub aggregate_sig: Option<AggregateSignature>,
}

impl Encodable for AttestationRecord {
    fn ssz_append(&self, s: &mut SszStream) {
        s.append(&self.slot);
        s.append(&self.shard_id);
        s.append_vec(&self.oblique_parent_hashes);
        s.append(&self.shard_block_hash);
        s.append(&self.attester_bitfield);
        // TODO: add aggregate signature
    }
}

impl AttestationRecord {
    pub fn zero() -> Self {
        Self {
            slot: 0,
            shard_id: 0,
            oblique_parent_hashes: vec![],
            shard_block_hash: Hash256::zero(),
            attester_bitfield: Bitfield::new(),
            aggregate_sig: None,
        }
    }
}
<|endoftext|>


<commit_before>//!
//! A toolset is a factory that can create a number of tools for a particular environment. It's convenient for
//! initialising new environments.
//!

use std::result::Result;
use serde_json::*;

use super::super::tool::*;
use super::super::environment::*;

///
/// Tool with a name for an environment
///
pub trait NamedTool : Tool {
    ///
    /// Retrieves the name of this tool
    ///
    fn get_name<'a>(&'a self) -> &'a str;
}

///
/// Represents a factory for a set of tools
///
pub trait ToolSet {
    ///
    /// Creates the tools in this toolset
    ///
    fn create_tools(&self, environment: &Environment) -> Vec<Box<NamedTool>>;
}

impl<T: Tool> Tool for (String, T) {
    #[inline]
    fn invoke_json(&self, input: Value, environment: &Environment) -> Result<Value, Value> {
        let (_, ref tool) = *self;
        tool.invoke_json(input, environment)
    }
}

impl<T: Tool> NamedTool for (String, T) {
    #[inline]
    fn get_name<'a>(&'a self) -> &'a str {
        let (ref name, _) = *self;
        &**name
    }
}

#[cfg(test)]
mod test {
    use std::result::Result;
    use serde_json::*;

    use super::*;
    use super::super::functional_tool::*;
    use super::super::empty_environment::*;

    #[test]
    fn can_invoke_named_tool() {
        let empty       = EmptyEnvironment::new();
        let base_tool   = make_tool(|x: i32| -> Result<i32, ()> { Ok(x+1) });
        let named_tool  = (String::from("name"), base_tool);

        let result = named_tool.invoke_json(json![ 2 ], &empty);
        assert!(result == Ok(json![ 3 ]));
    }

    #[test]
    fn can_get_tool_name() {
        let base_tool   = make_tool(|x: i32| -> Result<i32, ()> { Ok(x+1) });
        let named_tool  = (String::from("name"), base_tool);

        let name = named_tool.get_name();
        assert!(name == "name");
    }
}
<commit_msg>Add a basic toolset we can use to generate tools from vectors<commit_after>//!
//! A toolset is a factory that can create a number of tools for a particular environment. It's convenient for
//! initialising new environments.
//!

use std::result::Result;
use serde_json::*;

use super::super::tool::*;
use super::super::environment::*;

///
/// Tool with a name for an environment
///
pub trait NamedTool : Tool {
    ///
    /// Retrieves the name of this tool
    ///
    fn get_name<'a>(&'a self) -> &'a str;
}

///
/// Represents a factory for a set of tools
///
pub trait ToolSet {
    ///
    /// Creates the tools in this toolset
    ///
    fn create_tools(self, environment: &Environment) -> Vec<Box<NamedTool>>;
}

///
/// Represents a simple toolset that just returns a constant set of tools
///
pub struct BasicToolSet {
    tools: Vec<Box<NamedTool>>
}

impl BasicToolSet {
    pub fn from<T: NamedTool+'static>(source: Vec<T>) -> BasicToolSet {
        let mut result: Vec<Box<NamedTool>> = vec![];

        for item in source {
            result.push(Box::new(item));
        }

        BasicToolSet { tools: result }
    }
}

impl ToolSet for BasicToolSet {
    fn create_tools(self, _environment: &Environment) -> Vec<Box<NamedTool>> {
        self.tools
    }
}

impl<'a, T: Tool> Tool for (&'a str, T) {
    #[inline]
    fn invoke_json(&self, input: Value, environment: &Environment) -> Result<Value, Value> {
        let (_, ref tool) = *self;
        tool.invoke_json(input, environment)
    }
}

impl<'a, T: Tool> NamedTool for (&'a str, T) {
    #[inline]
    fn get_name<'b>(&'b self) -> &'b str {
        let (ref name, _) = *self;
        *name
    }
}

impl<T: Tool> Tool for (String, T) {
    #[inline]
    fn invoke_json(&self, input: Value, environment: &Environment) -> Result<Value, Value> {
        let (_, ref tool) = *self;
        tool.invoke_json(input, environment)
    }
}

impl<T: Tool> NamedTool for (String, T) {
    #[inline]
    fn get_name<'a>(&'a self) -> &'a str {
        let (ref name, _) = *self;
        &**name
    }
}

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

    #[test]
    fn can_invoke_named_tool() {
        let empty       = EmptyEnvironment::new();
        let base_tool   = make_pure_tool(|x: i32| { x+1 });
        let named_tool  = (String::from("name"), base_tool);

        let result = named_tool.invoke_json(json![ 2 ], &empty);
        assert!(result == Ok(json![ 3 ]));
    }

    #[test]
    fn can_get_tool_name() {
        let base_tool   = make_pure_tool(|x: i32| { x+1 });
        let named_tool  = (String::from("name"), base_tool);

        let name = named_tool.get_name();
        assert!(name == "name");
    }

    #[test]
    fn can_invoke_named_tool_str() {
        let empty       = EmptyEnvironment::new();
        let base_tool   = make_pure_tool(|x: i32| { x+1 });
        let named_tool  = ("name", base_tool);

        let result = named_tool.invoke_json(json![ 2 ], &empty);
        assert!(result == Ok(json![ 3 ]));
    }

    #[test]
    fn can_get_tool_name_str() {
        let base_tool   = make_pure_tool(|x: i32| { x+1 });
        let named_tool  = ("name", base_tool);

        let name = named_tool.get_name();
        assert!(name == "name");
    }
}
<|endoftext|>