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

//! Miscellaneous helpers for common patterns.

use cast;
use ptr;
use prelude::*;
use unstable::intrinsics;

/// The identity function.
#[inline]
pub fn id<T>(x: T) -> T { x }

/// Ignores a value.
#[inline]
pub fn ignore<T>(_x: T) { }

/// Sets `*ptr` to `new_value`, invokes `op()`, and then restores the
/// original value of `*ptr`.
///
/// NB: This function accepts `@mut T` and not `&mut T` to avoid
/// an obvious borrowck hazard. Typically passing in `&mut T` will
/// cause borrow check errors because it freezes whatever location
/// that `&mut T` is stored in (either statically or dynamically).
#[inline]
pub fn with<T,R>(
    ptr: @mut T,
    value: T,
    op: &fn() -> R) -> R
{
    let prev = replace(ptr, value);
    let result = op();
    *ptr = prev;
    return result;
}

/**
 * Swap the values at two mutable locations of the same type, without
 * deinitialising or copying either one.
 */
#[inline]
pub fn swap<T>(x: &mut T, y: &mut T) {
    unsafe {
        // Give ourselves some scratch space to work with
        let mut tmp: T = intrinsics::uninit();
        let t: *mut T = &mut tmp;

        // Perform the swap, `&mut` pointers never alias
        let x_raw: *mut T = x;
        let y_raw: *mut T = y;
        ptr::copy_nonoverlapping_memory(t, x_raw, 1);
        ptr::copy_nonoverlapping_memory(x, y_raw, 1);
        ptr::copy_nonoverlapping_memory(y, t, 1);

        // y and t now point to the same thing, but we need to completely forget `tmp`
        // because it's no longer relevant.
        cast::forget(tmp);
    }
}

/**
 * Replace the value at a mutable location with a new one, returning the old
 * value, without deinitialising or copying either one.
 */
#[inline]
pub fn replace<T>(dest: &mut T, mut src: T) -> T {
    swap(dest, &mut src);
    src
}

/// A non-copyable dummy type.
#[deriving(Eq, TotalEq, Ord, TotalOrd)]
#[unsafe_no_drop_flag]
pub struct NonCopyable;

impl NonCopyable {
    // FIXME(#8233) should not be necessary
    /// Create a new noncopyable token.
    pub fn new() -> NonCopyable { NonCopyable }
}

impl Drop for NonCopyable {
    fn drop(&mut self) { }
}

/// A type with no inhabitants
pub enum Void { }

impl Void {
    /// A utility function for ignoring this uninhabited type
    pub fn uninhabited(self) -> ! {
        match self {
            // Nothing to match on
        }
    }
}

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

    use clone::Clone;
    use option::{None, Some};
    use either::{Either, Left, Right};
    use sys::size_of;
    use kinds::Drop;

    #[test]
    fn identity_crisis() {
        // Writing a test for the identity function. How did it come to this?
        let x = ~[(5, false)];
        //FIXME #3387 assert!(x.eq(id(x.clone())));
        let y = x.clone();
        assert!(x.eq(&id(y)));
    }

    #[test]
    fn test_swap() {
        let mut x = 31337;
        let mut y = 42;
        swap(&mut x, &mut y);
        assert_eq!(x, 42);
        assert_eq!(y, 31337);
    }

    #[test]
    fn test_replace() {
        let mut x = Some(NonCopyable);
        let y = replace(&mut x, None);
        assert!(x.is_none());
        assert!(y.is_some());
    }

    #[test]
    fn test_uninhabited() {
        let could_only_be_coin : Either <Void, ()> = Right (());
        match could_only_be_coin {
            Right (coin) => coin,
            Left (is_void) => is_void.uninhabited ()
        }
    }

    #[test]
    fn test_noncopyable() {
        assert_eq!(size_of::<NonCopyable>(), 0);

        // verify that `#[unsafe_no_drop_flag]` works as intended on a zero-size struct

        static mut did_run: bool = false;

        struct Foo { five: int }

        impl Drop for Foo {
            fn drop(&mut self) {
                assert_eq!(self.five, 5);
                unsafe {
                    did_run = true;
                }
            }
        }

        {
            let _a = (NonCopyable, Foo { five: 5 }, NonCopyable);
        }

        unsafe { assert_eq!(did_run, true); }
    }
}

/// Completely miscellaneous language-construct benchmarks.
#[cfg(test)]
mod bench {

    use extra::test::BenchHarness;
    use option::{Some,None};

    // Static/dynamic method dispatch

    struct Struct {
        field: int
    }

    trait Trait {
        fn method(&self) -> int;
    }

    impl Trait for Struct {
        fn method(&self) -> int {
            self.field
        }
    }

    #[bench]
    fn trait_vtable_method_call(bh: &mut BenchHarness) {
        let s = Struct { field: 10 };
        let t = &s as &Trait;
        do bh.iter {
            t.method();
        }
    }

    #[bench]
    fn trait_static_method_call(bh: &mut BenchHarness) {
        let s = Struct { field: 10 };
        do bh.iter {
            s.method();
        }
    }

    // Overhead of various match forms

    #[bench]
    fn match_option_some(bh: &mut BenchHarness) {
        let x = Some(10);
        do bh.iter {
            let _q = match x {
                Some(y) => y,
                None => 11
            };
        }
    }

    #[bench]
    fn match_vec_pattern(bh: &mut BenchHarness) {
        let x = [1,2,3,4,5,6];
        do bh.iter {
            let _q = match x {
                [1,2,3,.._] => 10,
                _ => 11
            };
        }
    }
}
<commit_msg>auto merge of #9354 : thestinger/rust/cleanup, r=alexcrichton<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Miscellaneous helpers for common patterns.

use cast;
use ptr;
use prelude::*;
use unstable::intrinsics;

/// The identity function.
#[inline]
pub fn id<T>(x: T) -> T { x }

/// Ignores a value.
#[inline]
pub fn ignore<T>(_x: T) { }

/**
 * Swap the values at two mutable locations of the same type, without
 * deinitialising or copying either one.
 */
#[inline]
pub fn swap<T>(x: &mut T, y: &mut T) {
    unsafe {
        // Give ourselves some scratch space to work with
        let mut tmp: T = intrinsics::uninit();
        let t: *mut T = &mut tmp;

        // Perform the swap, `&mut` pointers never alias
        let x_raw: *mut T = x;
        let y_raw: *mut T = y;
        ptr::copy_nonoverlapping_memory(t, x_raw, 1);
        ptr::copy_nonoverlapping_memory(x, y_raw, 1);
        ptr::copy_nonoverlapping_memory(y, t, 1);

        // y and t now point to the same thing, but we need to completely forget `tmp`
        // because it's no longer relevant.
        cast::forget(tmp);
    }
}

/**
 * Replace the value at a mutable location with a new one, returning the old
 * value, without deinitialising or copying either one.
 */
#[inline]
pub fn replace<T>(dest: &mut T, mut src: T) -> T {
    swap(dest, &mut src);
    src
}

/// A non-copyable dummy type.
#[deriving(Eq, TotalEq, Ord, TotalOrd)]
#[unsafe_no_drop_flag]
pub struct NonCopyable;

impl NonCopyable {
    // FIXME(#8233) should not be necessary
    /// Create a new noncopyable token.
    pub fn new() -> NonCopyable { NonCopyable }
}

impl Drop for NonCopyable {
    fn drop(&mut self) { }
}

/// A type with no inhabitants
pub enum Void { }

impl Void {
    /// A utility function for ignoring this uninhabited type
    pub fn uninhabited(self) -> ! {
        match self {
            // Nothing to match on
        }
    }
}

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

    use clone::Clone;
    use option::{None, Some};
    use either::{Either, Left, Right};
    use sys::size_of;
    use kinds::Drop;

    #[test]
    fn identity_crisis() {
        // Writing a test for the identity function. How did it come to this?
        let x = ~[(5, false)];
        //FIXME #3387 assert!(x.eq(id(x.clone())));
        let y = x.clone();
        assert!(x.eq(&id(y)));
    }

    #[test]
    fn test_swap() {
        let mut x = 31337;
        let mut y = 42;
        swap(&mut x, &mut y);
        assert_eq!(x, 42);
        assert_eq!(y, 31337);
    }

    #[test]
    fn test_replace() {
        let mut x = Some(NonCopyable);
        let y = replace(&mut x, None);
        assert!(x.is_none());
        assert!(y.is_some());
    }

    #[test]
    fn test_uninhabited() {
        let could_only_be_coin : Either <Void, ()> = Right (());
        match could_only_be_coin {
            Right (coin) => coin,
            Left (is_void) => is_void.uninhabited ()
        }
    }

    #[test]
    fn test_noncopyable() {
        assert_eq!(size_of::<NonCopyable>(), 0);

        // verify that `#[unsafe_no_drop_flag]` works as intended on a zero-size struct

        static mut did_run: bool = false;

        struct Foo { five: int }

        impl Drop for Foo {
            fn drop(&mut self) {
                assert_eq!(self.five, 5);
                unsafe {
                    did_run = true;
                }
            }
        }

        {
            let _a = (NonCopyable, Foo { five: 5 }, NonCopyable);
        }

        unsafe { assert_eq!(did_run, true); }
    }
}

/// Completely miscellaneous language-construct benchmarks.
#[cfg(test)]
mod bench {

    use extra::test::BenchHarness;
    use option::{Some,None};

    // Static/dynamic method dispatch

    struct Struct {
        field: int
    }

    trait Trait {
        fn method(&self) -> int;
    }

    impl Trait for Struct {
        fn method(&self) -> int {
            self.field
        }
    }

    #[bench]
    fn trait_vtable_method_call(bh: &mut BenchHarness) {
        let s = Struct { field: 10 };
        let t = &s as &Trait;
        do bh.iter {
            t.method();
        }
    }

    #[bench]
    fn trait_static_method_call(bh: &mut BenchHarness) {
        let s = Struct { field: 10 };
        do bh.iter {
            s.method();
        }
    }

    // Overhead of various match forms

    #[bench]
    fn match_option_some(bh: &mut BenchHarness) {
        let x = Some(10);
        do bh.iter {
            let _q = match x {
                Some(y) => y,
                None => 11
            };
        }
    }

    #[bench]
    fn match_vec_pattern(bh: &mut BenchHarness) {
        let x = [1,2,3,4,5,6];
        do bh.iter {
            let _q = match x {
                [1,2,3,.._] => 10,
                _ => 11
            };
        }
    }
}
<|endoftext|>


<commit_before>use structs::Data;
use nn::Network;
use nalgebra::{DVector, DMatrix};

pub fn sgd(mut nn: &mut Network,
           mut training_data: Vec<Data>,
           epochs: u8, mini_batch_size: u8,
           eta: f32, mut test_data: Option<Vec<Data>>) {
    use rand::{ self, Rng};
    let mut rng = rand::thread_rng();

    let test_data_n = match test_data{
        Some(value) => value.len(),
        None => 0,
    };

    for j in 0..epochs {
        rng.shuffle(&mut training_data);
        for mut mini_batch in training_data.chunks_mut(mini_batch_size as usize) {
            update_mini_batch(&mut nn, &mut mini_batch, eta);
        }
        if test_data_n > 0 {
            println!("Epoch {}: {}/{}", j, evaluate(&nn, test_data.unwrap()), test_data_n);
        } else {
            println!("Epoch {} complete!", j);
        }
    }
}

fn update_mini_batch(mut nn: &mut Network, mut mini_batch: &mut [Data], eta: f32) {
    // holds all biases of the network
    let mut nabla_b: Vec<DVector<f32>> = Vec::with_capacity(nn.get_biases().len());
    for biases in nn.get_biases() {
        nabla_b.push(DVector::from_element(biases.len(), 0.0f32));
    }
    // holds all weights of the network
    let mut nabla_w: Vec<DMatrix<f32>> = Vec::with_capacity(nn.get_weights().len());
    for weights in nn.get_weights() {
        nabla_w.push(DMatrix::from_element(weights.nrows(), weights.ncols(), 0.0f32));
    }

    let mini_batch_len = mini_batch.len();

    // for each dataset in mini_batch: calculate gradients, add to nablas
    for data in mini_batch {
        let (delta_nabla_b, delta_nabla_w) = backprop(&mut nn,
                                                      data.get_input(),
                                                      data.get_class_vector());
        for (mut nb, dnb) in nabla_b.iter_mut().zip(delta_nabla_b.iter()) {
            // TODO: This is really not good. Someone needs to fix this.
            *nb += dnb.clone();
        }
        for (mut nw, dnw) in nabla_w.iter_mut().zip(delta_nabla_w.iter()) {
            // TODO: Same as above.
            *nw += dnw.clone();
        }
    }

    for (mut w, nw) in nn.get_weights_mut().iter_mut().zip( nabla_w.iter() ) {
        *w -= eta / (mini_batch_len as f32) * nw.clone();
    }

    for (mut b, nb) in nn.get_biases_mut().iter_mut().zip( nabla_b.iter() ) {
        *b -= eta / (mini_batch_len as f32) * nb.clone();
    }
}

/// Gets the desired changes in weights and biases for one training example
fn backprop(nn: &mut Network, data: &DVector<f32>, desired_output: &DVector<f32>)
            -> (Vec<DVector<f32>>, Vec<DMatrix<f32>>) {
    use nalgebra::{self, Dot, Outer};
    //use nalgebra::Dot;
    use nn;

    // holds all biases of the network
    let mut nabla_b: Vec<DVector<f32>> = Vec::with_capacity(nn.get_biases().len());
    for biases in nn.get_biases() {
        nabla_b.push(DVector::new_zeros(biases.len()));
    }
    // holds all weights of the network
    let mut nabla_w: Vec<DMatrix<f32>> = Vec::with_capacity(nn.get_weights().len());
    for weights in nn.get_weights() {
        nabla_w.push(DMatrix::new_zeros(weights.nrows(), weights.ncols()));
    }

    // feedforward
    // current activation layer, at the beginning this is the input
    // Note: Clone here because in later iterations activation will actually hold the
    // ownership of the Vector (or rather the activations vector will). However this might
    // still be a performance issue since we call this once per training data.
    let mut activation = data.clone();

    // hold all activation layers (including output)
    let mut activations: Vec<DVector<f32>> = Vec::with_capacity(nn.get_layers().len());
    // hold z where z is the input of the sigmoid function for each layer
    let mut zs: Vec<DVector<f32>> = Vec::with_capacity(nn.get_layers().len());

    activations.push(activation);
    // execute feedforward
    for (biases, weights) in nn.get_biases().iter().zip(nn.get_weights().iter()) {
        // TODO: Remove Clone
        let z = weights * &activations[activations.len()-1] + biases.clone();
        zs.push(z);
        activation = nn::sigmoid(&zs[zs.len()-1]);
        activations.push(activation)
    }

    // backward pass
    let mut delta = cost_derivative(&activations[activations.len()], desired_output)
        * sigmoid_prime(&zs[zs.len()-1]);
    let nabla_b_len = nabla_b.len() -1;
    let nabla_w_len = nabla_w.len() -1;
    // TODO: Remove clone
    nabla_b[nabla_b_len] = delta.clone();
    nabla_w[nabla_w_len] = (&nabla_b[nabla_b_len]).outer(&activations[activations.len()-2]);

    //TODO: Verify if we need to iterate only to ...len()-1 because of input layer
    for l in 2..nn.get_layers().len() {
        let z = &zs[zs.len()-l];
        let sp = sigmoid_prime(&z);
        //TODO: Verify that this line does what it's supposed to
        delta = &nn.get_weights()[nn.get_weights().len()-l+1] * (&delta) * sp;
        nabla_b[nabla_b_len-l] = delta.clone();
        nabla_w[nabla_w_len-l] = (&delta).outer(&activations[activations.len()-l-1]);
    }
    (nabla_b, nabla_w)
}

/// Derivative of the cost function
fn cost_derivative(output_activations: &DVector<f32>, desired_output: &DVector<f32>)
                   -> DVector<f32> {
    // easy, derivative of quadratic cost function is:
    //TODO: Get rid of clone
    output_activations.clone()-desired_output.clone()
}

/// Derivative of the sigmoid function
fn sigmoid_prime(z: &DVector<f32>) -> DVector<f32>{
    use nn;
    // Derivative of sigmoid function, ask wolfram alpha if you don't believe me
    nn::sigmoid(z) * (1.0f32 - nn::sigmoid(z))
}

fn evaluate(nn: &Network, &test_data: Vec<Data>) -> u8 {
    test_results = test_data.iter().flat_map(|x|x.iter()).map(|ref x| nn.feedforward(x)).enumerate().max_by(|&(_, item)| item).collect();
    unimplemented!();
        //array.iter().enumerate().max_by(|&(_, item)| item)
}

/*
    def evaluate(self, test_data):
        """Return the number of test inputs for which the neural
        network outputs the correct result. Note that the neural
        network's output is assumed to be the index of whichever
        neuron in the final layer has the highest activation."""
        test_results = [(np.argmax(self.feedforward(x)), y)
                        for (x, y) in test_data]
        return sum(int(x == y) for (x, y) in test_results)*/
<commit_msg>we use na as alias for nalgebra<commit_after>use structs::Data;
use nn::Network;
use na::{DVector, DMatrix};

pub fn sgd(mut nn: &mut Network,
           mut training_data: Vec<Data>,
           epochs: u8,
           mini_batch_size: u8,
           eta: f32,
           mut test_data: Option<Vec<Data>>) {
    use rand::{self, Rng};
    let mut rng = rand::thread_rng();

    let test_data_n = match test_data {
        Some(value) => value.len(),
        None => 0,
    };

    for j in 0..epochs {
        rng.shuffle(&mut training_data);
        for mut mini_batch in training_data.chunks_mut(mini_batch_size as usize) {
            update_mini_batch(&mut nn, &mut mini_batch, eta);
        }
        if test_data_n > 0 {
            println!("Epoch {}: {}/{}",
                     j,
                     evaluate(&nn, test_data.unwrap()),
                     test_data_n);
        } else {
            println!("Epoch {} complete!", j);
        }
    }
}

fn update_mini_batch(mut nn: &mut Network, mut mini_batch: &mut [Data], eta: f32) {
    // holds all biases of the network
    let mut nabla_b: Vec<DVector<f32>> = Vec::with_capacity(nn.get_biases().len());
    for biases in nn.get_biases() {
        nabla_b.push(DVector::from_element(biases.len(), 0.0f32));
    }
    // holds all weights of the network
    let mut nabla_w: Vec<DMatrix<f32>> = Vec::with_capacity(nn.get_weights().len());
    for weights in nn.get_weights() {
        nabla_w.push(DMatrix::from_element(weights.nrows(), weights.ncols(), 0.0f32));
    }

    let mini_batch_len = mini_batch.len();

    // for each dataset in mini_batch: calculate gradients, add to nablas
    for data in mini_batch {
        let (delta_nabla_b, delta_nabla_w) =
            backprop(&mut nn, data.get_input(), data.get_class_vector());
        for (mut nb, dnb) in nabla_b.iter_mut().zip(delta_nabla_b.iter()) {
            // TODO: This is really not good. Someone needs to fix this.
            *nb += dnb.clone();
        }
        for (mut nw, dnw) in nabla_w.iter_mut().zip(delta_nabla_w.iter()) {
            // TODO: Same as above.
            *nw += dnw.clone();
        }
    }

    for (mut w, nw) in nn.get_weights_mut().iter_mut().zip(nabla_w.iter()) {
        *w -= eta / (mini_batch_len as f32) * nw.clone();
    }

    for (mut b, nb) in nn.get_biases_mut().iter_mut().zip(nabla_b.iter()) {
        *b -= eta / (mini_batch_len as f32) * nb.clone();
    }
}

/// Gets the desired changes in weights and biases for one training example
fn backprop(nn: &mut Network,
            data: &DVector<f32>,
            desired_output: &DVector<f32>)
            -> (Vec<DVector<f32>>, Vec<DMatrix<f32>>) {
    use na::{self, Dot, Outer};
    use nn;

    // holds all biases of the network
    let mut nabla_b: Vec<DVector<f32>> = Vec::with_capacity(nn.get_biases().len());
    for biases in nn.get_biases() {
        nabla_b.push(DVector::new_zeros(biases.len()));
    }
    // holds all weights of the network
    let mut nabla_w: Vec<DMatrix<f32>> = Vec::with_capacity(nn.get_weights().len());
    for weights in nn.get_weights() {
        nabla_w.push(DMatrix::new_zeros(weights.nrows(), weights.ncols()));
    }

    // feedforward
    // current activation layer, at the beginning this is the input
    // Note: Clone here because in later iterations activation will actually hold the
    // ownership of the Vector (or rather the activations vector will). However this might
    // still be a performance issue since we call this once per training data.
    let mut activation = data.clone();

    // hold all activation layers (including output)
    let mut activations: Vec<DVector<f32>> = Vec::with_capacity(nn.get_layers().len());
    // hold z where z is the input of the sigmoid function for each layer
    let mut zs: Vec<DVector<f32>> = Vec::with_capacity(nn.get_layers().len());

    activations.push(activation);
    // execute feedforward
    for (biases, weights) in nn.get_biases().iter().zip(nn.get_weights().iter()) {
        // TODO: Remove Clone
        let z = weights * &activations[activations.len() - 1] + biases.clone();
        zs.push(z);
        activation = nn::sigmoid(&zs[zs.len() - 1]);
        activations.push(activation)
    }

    // backward pass
    let mut delta = cost_derivative(&activations[activations.len()], desired_output) *
                    sigmoid_prime(&zs[zs.len() - 1]);
    let nabla_b_len = nabla_b.len() - 1;
    let nabla_w_len = nabla_w.len() - 1;
    // TODO: Remove clone
    nabla_b[nabla_b_len] = delta.clone();
    nabla_w[nabla_w_len] = (&nabla_b[nabla_b_len]).outer(&activations[activations.len() - 2]);

    //TODO: Verify if we need to iterate only to ...len()-1 because of input layer
    for l in 2..nn.get_layers().len() {
        let z = &zs[zs.len() - l];
        let sp = sigmoid_prime(&z);
        //TODO: Verify that this line does what it's supposed to
        delta = &nn.get_weights()[nn.get_weights().len() - l + 1] * (&delta) * sp;
        nabla_b[nabla_b_len - l] = delta.clone();
        nabla_w[nabla_w_len - l] = (&delta).outer(&activations[activations.len() - l - 1]);
    }
    (nabla_b, nabla_w)
}

/// Derivative of the cost function
fn cost_derivative(output_activations: &DVector<f32>,
                   desired_output: &DVector<f32>)
                   -> DVector<f32> {
    // easy, derivative of quadratic cost function is:
    //TODO: Get rid of clone
    output_activations.clone() - desired_output.clone()
}

/// Derivative of the sigmoid function
fn sigmoid_prime(z: &DVector<f32>) -> DVector<f32> {
    use nn;
    // Derivative of sigmoid function, ask wolfram alpha if you don't believe me
    nn::sigmoid(z) * (1.0f32 - nn::sigmoid(z))
}

fn evaluate(nn: &Network, &test_data: Vec<Data>) -> u8 {
    test_results = test_data.iter()
        .flat_map(|x| x.iter())
        .map(|ref x| nn.feedforward(x))
        .enumerate()
        .max_by(|&(_, item)| item)
        .collect();
    unimplemented!();
    //array.iter().enumerate().max_by(|&(_, item)| item)
}

/*
    def evaluate(self, test_data):
        """Return the number of test inputs for which the neural
        network outputs the correct result. Note that the neural
        network's output is assumed to be the index of whichever
        neuron in the final layer has the highest activation."""
        test_results = [(np.argmax(self.feedforward(x)), y)
                        for (x, y) in test_data]
        return sum(int(x == y) for (x, y) in test_results)*/
<|endoftext|>


<commit_before>mod chunks;

use super::rules::LRules;
use super::state::{LSystem, RulesValue};

pub use self::chunks::ChunksProcessor;

/// L-System processors are responsible for taking a L-System and evolving it to
// its next state.
pub trait LProcessor<S: Clone + Eq> {
    /// Try and iterate the given L-System into its next state according to
    /// its production rules.
    /// Return None if successful, Some(error_string) otherwise.
    fn iterate<'a>(&mut self, lsystem: &LSystem<'a, S>) -> Result<LSystem<'a, S>, String>;
}

/// Simple, linear L-System interpreter.
/// NB: can rapidly freeze its container thread.
pub struct SimpleProcessor;

impl SimpleProcessor {
    /// Iterate a slice of symbols into its next iteration according to the given
    /// production rules.
    pub fn iterate_slice<'a, S: Clone + Eq>(state: &[S],
                                            rules: &RulesValue<'a, S>)
                                            -> Result<Vec<S>, String> {
        let estimated_result_size = rules.biggest_expansion();
        let result_size = match state.len().checked_mul(estimated_result_size) {
            Some(v) => v,
            None => {
                return Err(format!("SimpleProcessor::iterate_slice : usize overflow when \
                                    computing new Vec size"))
            }
        };
        let mut result: Vec<S> = Vec::with_capacity(result_size);

        for s in state {
            match rules.production(&s) {
                Some(symbols) => result.extend(symbols.iter().cloned()),
                None => result.push(s.clone()),
            }
        }
        result.shrink_to_fit();

        Ok(result)
    }
}

impl<S> LProcessor<S> for SimpleProcessor
    where S: Clone + Eq
{
    fn iterate<'a>(&mut self, lsystem: &LSystem<'a, S>) -> Result<LSystem<'a, S>, String> {
        // allocate a new state with the worst possible size
        // (may cause overflow one or more iteration(s) earlier with huge states/production rules)
        let rules = lsystem.rules().clone();
        let new_state = try!(SimpleProcessor::iterate_slice(lsystem.state(), &rules));

        // return the evolved L-System
        Ok(LSystem::<S>::new(new_state, rules, Some(lsystem.iteration() + 1)))
    }
}

#[cfg(test)]
mod test {
    use rules::HashMapRules;
    use state::{LSystem, new_rules_value};
    use interpret::TurtleCommand;
    use super::*;

    #[test]
    fn simple_processing() {
        let mut rules = HashMapRules::new(); // algae rules
        rules.set_str('A', "AB", TurtleCommand::None);
        rules.set_str('B', "A", TurtleCommand::None);
        let expected_states = ["A",
                               "AB",
                               "ABA",
                               "ABAAB",
                               "ABAABABA",
                               "ABAABABAABAAB",
                               "ABAABABAABAABABAABABA",
                               "ABAABABAABAABABAABABAABAABABAABAAB"];
        let mut lsystem = LSystem::new_with_char(&expected_states[0], new_rules_value(rules));

        for n in 0..expected_states.len() {
            assert_eq!(lsystem.iteration(), n as u64);
            let expected: Vec<char> = expected_states[n].chars().collect();
            assert_eq!(lsystem.state(), &expected[..]);
            lsystem = SimpleProcessor.iterate(&lsystem).ok().unwrap();
        }
    }
}
<commit_msg>clarified variable name<commit_after>mod chunks;

use super::rules::LRules;
use super::state::{LSystem, RulesValue};

pub use self::chunks::ChunksProcessor;

/// L-System processors are responsible for taking a L-System and evolving it to
// its next state.
pub trait LProcessor<S: Clone + Eq> {
    /// Try and iterate the given L-System into its next state according to
    /// its production rules.
    /// Return None if successful, Some(error_string) otherwise.
    fn iterate<'a>(&mut self, lsystem: &LSystem<'a, S>) -> Result<LSystem<'a, S>, String>;
}

/// Simple, linear L-System interpreter.
/// NB: can rapidly freeze its container thread.
pub struct SimpleProcessor;

impl SimpleProcessor {
    /// Iterate a slice of symbols into its next iteration according to the given
    /// production rules.
    pub fn iterate_slice<'a, S: Clone + Eq>(state: &[S],
                                            rules: &RulesValue<'a, S>)
                                            -> Result<Vec<S>, String> {
        let size_factor = rules.biggest_expansion();
        let result_size = match state.len().checked_mul(size_factor) {
            Some(v) => v,
            None => {
                return Err(format!("SimpleProcessor::iterate_slice : usize overflow when \
                                    computing new Vec size"))
            }
        };
        let mut result: Vec<S> = Vec::with_capacity(result_size);

        for s in state {
            match rules.production(&s) {
                Some(symbols) => result.extend(symbols.iter().cloned()),
                None => result.push(s.clone()),
            }
        }
        result.shrink_to_fit();

        Ok(result)
    }
}

impl<S> LProcessor<S> for SimpleProcessor
    where S: Clone + Eq
{
    fn iterate<'a>(&mut self, lsystem: &LSystem<'a, S>) -> Result<LSystem<'a, S>, String> {
        // allocate a new state with the worst possible size
        // (may cause overflow one or more iteration(s) earlier with huge states/production rules)
        let rules = lsystem.rules().clone();
        let new_state = try!(SimpleProcessor::iterate_slice(lsystem.state(), &rules));

        // return the evolved L-System
        Ok(LSystem::<S>::new(new_state, rules, Some(lsystem.iteration() + 1)))
    }
}

#[cfg(test)]
mod test {
    use rules::HashMapRules;
    use state::{LSystem, new_rules_value};
    use interpret::TurtleCommand;
    use super::*;

    #[test]
    fn simple_processing() {
        let mut rules = HashMapRules::new(); // algae rules
        rules.set_str('A', "AB", TurtleCommand::None);
        rules.set_str('B', "A", TurtleCommand::None);
        let expected_states = ["A",
                               "AB",
                               "ABA",
                               "ABAAB",
                               "ABAABABA",
                               "ABAABABAABAAB",
                               "ABAABABAABAABABAABABA",
                               "ABAABABAABAABABAABABAABAABABAABAAB"];
        let mut lsystem = LSystem::new_with_char(&expected_states[0], new_rules_value(rules));

        for n in 0..expected_states.len() {
            assert_eq!(lsystem.iteration(), n as u64);
            let expected: Vec<char> = expected_states[n].chars().collect();
            assert_eq!(lsystem.state(), &expected[..]);
            lsystem = SimpleProcessor.iterate(&lsystem).ok().unwrap();
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};
use std::fmt;
use std::iter::FromIterator;

use url::Url;

use core::{Dependency, PackageId, PackageIdSpec, Summary};
use util::Graph;
use util::errors::CargoResult;
use util::graph::{Edges, Nodes};

use super::encode::Metadata;

/// Represents a fully resolved package dependency graph. Each node in the graph
/// is a package and edges represent dependencies between packages.
///
/// Each instance of `Resolve` also understands the full set of features used
/// for each package.
#[derive(PartialEq)]
pub struct Resolve {
    graph: Graph<PackageId, Vec<Dependency>>,
    replacements: HashMap<PackageId, PackageId>,
    reverse_replacements: HashMap<PackageId, PackageId>,
    empty_features: HashSet<String>,
    features: HashMap<PackageId, HashSet<String>>,
    checksums: HashMap<PackageId, Option<String>>,
    metadata: Metadata,
    unused_patches: Vec<PackageId>,
}

impl Resolve {
    pub fn new(
        graph: Graph<PackageId, Vec<Dependency>>,
        replacements: HashMap<PackageId, PackageId>,
        features: HashMap<PackageId, HashSet<String>>,
        checksums: HashMap<PackageId, Option<String>>,
        metadata: Metadata,
        unused_patches: Vec<PackageId>,
    ) -> Resolve {
        let reverse_replacements = replacements
            .iter()
            .map(|p| (p.1.clone(), p.0.clone()))
            .collect();
        Resolve {
            graph,
            replacements,
            features,
            checksums,
            metadata,
            unused_patches,
            empty_features: HashSet::new(),
            reverse_replacements,
        }
    }

    /// Resolves one of the paths from the given dependent package up to
    /// the root.
    pub fn path_to_top<'a>(&'a self, pkg: &'a PackageId) -> Vec<&'a PackageId> {
        self.graph.path_to_top(pkg)
    }

    pub fn register_used_patches(&mut self, patches: &HashMap<Url, Vec<Summary>>) {
        for summary in patches.values().flat_map(|v| v) {
            if self.iter().any(|id| id == summary.package_id()) {
                continue;
            }
            self.unused_patches.push(summary.package_id().clone());
        }
    }

    pub fn merge_from(&mut self, previous: &Resolve) -> CargoResult<()> {
        // Given a previous instance of resolve, it should be forbidden to ever
        // have a checksums which *differ*. If the same package id has differing
        // checksums, then something has gone wrong such as:
        //
        // * Something got seriously corrupted
        // * A "mirror" isn't actually a mirror as some changes were made
        // * A replacement source wasn't actually a replacment, some changes
        //   were made
        //
        // In all of these cases, we want to report an error to indicate that
        // something is awry. Normal execution (esp just using crates.io) should
        // never run into this.
        for (id, cksum) in previous.checksums.iter() {
            if let Some(mine) = self.checksums.get(id) {
                if mine == cksum {
                    continue;
                }

                // If the previous checksum wasn't calculated, the current
                // checksum is `Some`. This may indicate that a source was
                // erroneously replaced or was replaced with something that
                // desires stronger checksum guarantees than can be afforded
                // elsewhere.
                if cksum.is_none() {
                    bail!(
                        "\
checksum for `{}` was not previously calculated, but a checksum could now \
be calculated

this could be indicative of a few possible situations:

    * the source `{}` did not previously support checksums,
      but was replaced with one that does
    * newer Cargo implementations know how to checksum this source, but this
      older implementation does not
    * the lock file is corrupt
",
                        id,
                        id.source_id()
                    )

                // If our checksum hasn't been calculated, then it could mean
                // that future Cargo figured out how to checksum something or
                // more realistically we were overridden with a source that does
                // not have checksums.
                } else if mine.is_none() {
                    bail!(
                        "\
checksum for `{}` could not be calculated, but a checksum is listed in \
the existing lock file

this could be indicative of a few possible situations:

    * the source `{}` supports checksums,
      but was replaced with one that doesn't
    * the lock file is corrupt

unable to verify that `{0}` is the same as when the lockfile was generated
",
                        id,
                        id.source_id()
                    )

                // If the checksums aren't equal, and neither is None, then they
                // must both be Some, in which case the checksum now differs.
                // That's quite bad!
                } else {
                    bail!(
                        "\
checksum for `{}` changed between lock files

this could be indicative of a few possible errors:

    * the lock file is corrupt
    * a replacement source in use (e.g. a mirror) returned a different checksum
    * the source itself may be corrupt in one way or another

unable to verify that `{0}` is the same as when the lockfile was generated
",
                        id
                    );
                }
            }
        }

        // Be sure to just copy over any unknown metadata.
        self.metadata = previous.metadata.clone();
        Ok(())
    }

    pub fn iter(&self) -> Nodes<PackageId, Vec<Dependency>> {
        self.graph.iter()
    }

    pub fn deps(&self, pkg: &PackageId) -> Deps {
        Deps {
            edges: self.graph.edges(pkg),
            resolve: self,
        }
    }

    pub fn deps_not_replaced(&self, pkg: &PackageId) -> DepsNotReplaced {
        DepsNotReplaced {
            edges: self.graph.edges(pkg),
        }
    }

    pub fn replacement(&self, pkg: &PackageId) -> Option<&PackageId> {
        self.replacements.get(pkg)
    }

    pub fn replacements(&self) -> &HashMap<PackageId, PackageId> {
        &self.replacements
    }

    pub fn features(&self, pkg: &PackageId) -> &HashSet<String> {
        self.features.get(pkg).unwrap_or(&self.empty_features)
    }

    pub fn features_sorted(&self, pkg: &PackageId) -> Vec<&str> {
        let mut v = Vec::from_iter(self.features(pkg).iter().map(|s| s.as_ref()));
        v.sort();
        v
    }

    pub fn query(&self, spec: &str) -> CargoResult<&PackageId> {
        PackageIdSpec::query_str(spec, self.iter())
    }

    pub fn unused_patches(&self) -> &[PackageId] {
        &self.unused_patches
    }

    pub fn checksums(&self) -> &HashMap<PackageId, Option<String>> {
        &self.checksums
    }

    pub fn metadata(&self) -> &Metadata {
        &self.metadata
    }

    pub fn dependencies_listed(&self, from: &PackageId, to: &PackageId) -> &[Dependency] {
        // We've got a dependency on `from` to `to`, but this dependency edge
        // may be affected by [replace]. If the `to` package is listed as the
        // target of a replacement (aka the key of a reverse replacement map)
        // then we try to find our dependency edge through that. If that fails
        // then we go down below assuming it's not replaced.
        //
        // Note that we don't treat `from` as if it's been replaced because
        // that's where the dependency originates from, and we only replace
        // targets of dependencies not the originator.
        if let Some(replace) = self.reverse_replacements.get(to) {
            if let Some(deps) = self.graph.edge(from, replace) {
                return deps;
            }
        }
        match self.graph.edge(from, to) {
            Some(ret) => ret,
            None => panic!("no Dependency listed for `{}` => `{}`", from, to),
        }
    }
}

impl fmt::Debug for Resolve {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "graph: {:?}\n", self.graph)?;
        write!(fmt, "\nfeatures: {{\n")?;
        for (pkg, features) in &self.features {
            write!(fmt, "  {}: {:?}\n", pkg, features)?;
        }
        write!(fmt, "}}")
    }
}

pub struct Deps<'a> {
    edges: Option<Edges<'a, PackageId, Vec<Dependency>>>,
    resolve: &'a Resolve,
}

impl<'a> Iterator for Deps<'a> {
    type Item = (&'a PackageId, &'a [Dependency]);

    fn next(&mut self) -> Option<(&'a PackageId, &'a [Dependency])> {
        let (id, deps) = self.edges.as_mut()?.next()?;
        let id_ret = self.resolve.replacement(id).unwrap_or(id);
        Some((id_ret, deps))
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        // Note: Edges is actually a std::collections::hash_set::Iter, which
        // is an ExactSizeIterator.
        let len = self.edges.as_ref().map(ExactSizeIterator::len).unwrap_or(0);
        (len, Some(len))
    }
}

impl<'a> ExactSizeIterator for Deps<'a> {}

pub struct DepsNotReplaced<'a> {
    edges: Option<Edges<'a, PackageId, Vec<Dependency>>>,
}

impl<'a> Iterator for DepsNotReplaced<'a> {
    type Item = &'a PackageId;

    fn next(&mut self) -> Option<&'a PackageId> {
        Some(self.edges.as_mut()?.next()?.0)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        // Note: Edges is actually a std::collections::hash_set::Iter, which
        // is an ExactSizeIterator.
        let len = self.edges.as_ref().map(ExactSizeIterator::len).unwrap_or(0);
        (len, Some(len))
    }
}

impl<'a> ExactSizeIterator for DepsNotReplaced<'a> {}
<commit_msg>Auto merge of #5459 - matklad:more-comments, r=alexcrichton<commit_after>use std::collections::{HashMap, HashSet};
use std::fmt;
use std::iter::FromIterator;

use url::Url;

use core::{Dependency, PackageId, PackageIdSpec, Summary};
use util::Graph;
use util::errors::CargoResult;
use util::graph::{Edges, Nodes};

use super::encode::Metadata;

/// Represents a fully resolved package dependency graph. Each node in the graph
/// is a package and edges represent dependencies between packages.
///
/// Each instance of `Resolve` also understands the full set of features used
/// for each package.
#[derive(PartialEq)]
pub struct Resolve {
    /// A graph, whose vertices are packages and edges are dependency specifications
    /// from Cargo.toml. We need a `Vec` here because the same package
    /// might be present in both `[dependencies]` and `[build-dependencies]`.
    graph: Graph<PackageId, Vec<Dependency>>,
    replacements: HashMap<PackageId, PackageId>,
    reverse_replacements: HashMap<PackageId, PackageId>,
    empty_features: HashSet<String>,
    features: HashMap<PackageId, HashSet<String>>,
    checksums: HashMap<PackageId, Option<String>>,
    metadata: Metadata,
    unused_patches: Vec<PackageId>,
}

impl Resolve {
    pub fn new(
        graph: Graph<PackageId, Vec<Dependency>>,
        replacements: HashMap<PackageId, PackageId>,
        features: HashMap<PackageId, HashSet<String>>,
        checksums: HashMap<PackageId, Option<String>>,
        metadata: Metadata,
        unused_patches: Vec<PackageId>,
    ) -> Resolve {
        let reverse_replacements = replacements
            .iter()
            .map(|p| (p.1.clone(), p.0.clone()))
            .collect();
        Resolve {
            graph,
            replacements,
            features,
            checksums,
            metadata,
            unused_patches,
            empty_features: HashSet::new(),
            reverse_replacements,
        }
    }

    /// Resolves one of the paths from the given dependent package up to
    /// the root.
    pub fn path_to_top<'a>(&'a self, pkg: &'a PackageId) -> Vec<&'a PackageId> {
        self.graph.path_to_top(pkg)
    }

    pub fn register_used_patches(&mut self, patches: &HashMap<Url, Vec<Summary>>) {
        for summary in patches.values().flat_map(|v| v) {
            if self.iter().any(|id| id == summary.package_id()) {
                continue;
            }
            self.unused_patches.push(summary.package_id().clone());
        }
    }

    pub fn merge_from(&mut self, previous: &Resolve) -> CargoResult<()> {
        // Given a previous instance of resolve, it should be forbidden to ever
        // have a checksums which *differ*. If the same package id has differing
        // checksums, then something has gone wrong such as:
        //
        // * Something got seriously corrupted
        // * A "mirror" isn't actually a mirror as some changes were made
        // * A replacement source wasn't actually a replacment, some changes
        //   were made
        //
        // In all of these cases, we want to report an error to indicate that
        // something is awry. Normal execution (esp just using crates.io) should
        // never run into this.
        for (id, cksum) in previous.checksums.iter() {
            if let Some(mine) = self.checksums.get(id) {
                if mine == cksum {
                    continue;
                }

                // If the previous checksum wasn't calculated, the current
                // checksum is `Some`. This may indicate that a source was
                // erroneously replaced or was replaced with something that
                // desires stronger checksum guarantees than can be afforded
                // elsewhere.
                if cksum.is_none() {
                    bail!(
                        "\
checksum for `{}` was not previously calculated, but a checksum could now \
be calculated

this could be indicative of a few possible situations:

    * the source `{}` did not previously support checksums,
      but was replaced with one that does
    * newer Cargo implementations know how to checksum this source, but this
      older implementation does not
    * the lock file is corrupt
",
                        id,
                        id.source_id()
                    )

                // If our checksum hasn't been calculated, then it could mean
                // that future Cargo figured out how to checksum something or
                // more realistically we were overridden with a source that does
                // not have checksums.
                } else if mine.is_none() {
                    bail!(
                        "\
checksum for `{}` could not be calculated, but a checksum is listed in \
the existing lock file

this could be indicative of a few possible situations:

    * the source `{}` supports checksums,
      but was replaced with one that doesn't
    * the lock file is corrupt

unable to verify that `{0}` is the same as when the lockfile was generated
",
                        id,
                        id.source_id()
                    )

                // If the checksums aren't equal, and neither is None, then they
                // must both be Some, in which case the checksum now differs.
                // That's quite bad!
                } else {
                    bail!(
                        "\
checksum for `{}` changed between lock files

this could be indicative of a few possible errors:

    * the lock file is corrupt
    * a replacement source in use (e.g. a mirror) returned a different checksum
    * the source itself may be corrupt in one way or another

unable to verify that `{0}` is the same as when the lockfile was generated
",
                        id
                    );
                }
            }
        }

        // Be sure to just copy over any unknown metadata.
        self.metadata = previous.metadata.clone();
        Ok(())
    }

    pub fn iter(&self) -> Nodes<PackageId, Vec<Dependency>> {
        self.graph.iter()
    }

    pub fn deps(&self, pkg: &PackageId) -> Deps {
        Deps {
            edges: self.graph.edges(pkg),
            resolve: self,
        }
    }

    pub fn deps_not_replaced(&self, pkg: &PackageId) -> DepsNotReplaced {
        DepsNotReplaced {
            edges: self.graph.edges(pkg),
        }
    }

    pub fn replacement(&self, pkg: &PackageId) -> Option<&PackageId> {
        self.replacements.get(pkg)
    }

    pub fn replacements(&self) -> &HashMap<PackageId, PackageId> {
        &self.replacements
    }

    pub fn features(&self, pkg: &PackageId) -> &HashSet<String> {
        self.features.get(pkg).unwrap_or(&self.empty_features)
    }

    pub fn features_sorted(&self, pkg: &PackageId) -> Vec<&str> {
        let mut v = Vec::from_iter(self.features(pkg).iter().map(|s| s.as_ref()));
        v.sort();
        v
    }

    pub fn query(&self, spec: &str) -> CargoResult<&PackageId> {
        PackageIdSpec::query_str(spec, self.iter())
    }

    pub fn unused_patches(&self) -> &[PackageId] {
        &self.unused_patches
    }

    pub fn checksums(&self) -> &HashMap<PackageId, Option<String>> {
        &self.checksums
    }

    pub fn metadata(&self) -> &Metadata {
        &self.metadata
    }

    pub fn dependencies_listed(&self, from: &PackageId, to: &PackageId) -> &[Dependency] {
        // We've got a dependency on `from` to `to`, but this dependency edge
        // may be affected by [replace]. If the `to` package is listed as the
        // target of a replacement (aka the key of a reverse replacement map)
        // then we try to find our dependency edge through that. If that fails
        // then we go down below assuming it's not replaced.
        //
        // Note that we don't treat `from` as if it's been replaced because
        // that's where the dependency originates from, and we only replace
        // targets of dependencies not the originator.
        if let Some(replace) = self.reverse_replacements.get(to) {
            if let Some(deps) = self.graph.edge(from, replace) {
                return deps;
            }
        }
        match self.graph.edge(from, to) {
            Some(ret) => ret,
            None => panic!("no Dependency listed for `{}` => `{}`", from, to),
        }
    }
}

impl fmt::Debug for Resolve {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "graph: {:?}\n", self.graph)?;
        write!(fmt, "\nfeatures: {{\n")?;
        for (pkg, features) in &self.features {
            write!(fmt, "  {}: {:?}\n", pkg, features)?;
        }
        write!(fmt, "}}")
    }
}

pub struct Deps<'a> {
    edges: Option<Edges<'a, PackageId, Vec<Dependency>>>,
    resolve: &'a Resolve,
}

impl<'a> Iterator for Deps<'a> {
    type Item = (&'a PackageId, &'a [Dependency]);

    fn next(&mut self) -> Option<(&'a PackageId, &'a [Dependency])> {
        let (id, deps) = self.edges.as_mut()?.next()?;
        let id_ret = self.resolve.replacement(id).unwrap_or(id);
        Some((id_ret, deps))
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        // Note: Edges is actually a std::collections::hash_set::Iter, which
        // is an ExactSizeIterator.
        let len = self.edges.as_ref().map(ExactSizeIterator::len).unwrap_or(0);
        (len, Some(len))
    }
}

impl<'a> ExactSizeIterator for Deps<'a> {}

pub struct DepsNotReplaced<'a> {
    edges: Option<Edges<'a, PackageId, Vec<Dependency>>>,
}

impl<'a> Iterator for DepsNotReplaced<'a> {
    type Item = &'a PackageId;

    fn next(&mut self) -> Option<&'a PackageId> {
        Some(self.edges.as_mut()?.next()?.0)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        // Note: Edges is actually a std::collections::hash_set::Iter, which
        // is an ExactSizeIterator.
        let len = self.edges.as_ref().map(ExactSizeIterator::len).unwrap_or(0);
        (len, Some(len))
    }
}

impl<'a> ExactSizeIterator for DepsNotReplaced<'a> {}
<|endoftext|>


<commit_before>// Options
// Space before /
// Quote style
// Ordering of attributes

#[cfg(test)]
mod test {
    use std::io::{IoResult,MemWriter};

    use super::super::{Document,Element,Text,Comment,ProcessingInstruction};
    use super::super::{ElementElementChild,TextElementChild,CommentElementChild,PIElementChild};

    macro_rules! assert_str_eq(
        ($l:expr, $r:expr) => (assert_eq!($l.as_slice(), $r.as_slice()));
    )

    enum Content {
        WElement(Element),
        WElementEnd(String),
        WText(Text),
        WComment(Comment),
        WProcessingInstruction(ProcessingInstruction),
    }

    fn format_element<W : Writer>(element: Element, todo: &mut Vec<Content>, writer: &mut W) -> IoResult<()> {
        try!(write!(writer, "<{}", element.name()));

        for attr in element.attributes().iter() {
            try!(write!(writer, " {}='{}'", attr.name(), attr.value()));
        }

        let mut children = element.children();
        if children.is_empty() {
            writer.write_str("/>")
        } else {
            try!(writer.write_str(">"));

            todo.push(WElementEnd(element.name()));
            children.reverse();
            let x = children.move_iter().map(|c| match c {
                ElementElementChild(element) => WElement(element),
                TextElementChild(t) => WText(t),
                CommentElementChild(c) => WComment(c),
                PIElementChild(p) => WProcessingInstruction(p),
            }).collect();
            todo.push_all_move(x);

            Ok(())
        }
    }

    fn format_document<W : Writer>(doc: &Document, writer: &mut W) -> IoResult<()> {
        let mut todo = Vec::new();

        try!(writer.write_str("<?xml version='1.0'?>"));
        let e = doc.root().children()[0].element().expect("not an element?");

        todo.push(WElement(e));

        while ! todo.is_empty() {
            match todo.pop().unwrap() {
                WElement(e) => try!(format_element(e, &mut todo, writer)),
                WElementEnd(name) => try!(write!(writer, "</{}>", name)),
                WText(t) => try!(writer.write_str(t.text().as_slice())),
                WComment(c) => try!(write!(writer, "<!--{}-->", c.text())),
                WProcessingInstruction(p) => try!(write!(writer, "<?{}?>", p.target())),
            }
        }

        Ok(())
    }

    fn format_xml(doc: &Document) -> String {
        let mut w = MemWriter::new();
        format_document(doc, &mut w).ok().expect("Not formatted");
        String::from_utf8(w.unwrap()).ok().expect("Not a string")
    }

    #[test]
    fn top_element() {
        let d = Document::new();
        let e = d.new_element("hello".to_string());
        d.root().append_child(e);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello/>");
    }

    #[test]
    fn element_with_attributes() {
        let d = Document::new();
        let e = d.new_element("hello".to_string());
        e.set_attribute("a".to_string(), "b".to_string());
        d.root().append_child(e);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello a='b'/>");
    }

    #[test]
    fn nested_element() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let world = d.new_element("world".to_string());
        hello.append_child(world);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><world/></hello>");
    }

    #[test]
    fn nested_text() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let text = d.new_text("A fine day to you!".to_string());
        hello.append_child(text);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello>A fine day to you!</hello>");
    }

    #[test]
    fn nested_comment() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let comment = d.new_comment(" Fill this in ".to_string());
        hello.append_child(comment);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><!-- Fill this in --></hello>");
    }

    #[test]
    fn nested_processing_instruction_without_value() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let pi = d.new_processing_instruction("display".to_string(), None);
        hello.append_child(pi);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><?display?></hello>");
    }
}
<commit_msg>Write processing instructions with values<commit_after>// Options
// Space before /
// Quote style
// Ordering of attributes

#[cfg(test)]
mod test {
    use std::io::{IoResult,MemWriter};

    use super::super::{Document,Element,Text,Comment,ProcessingInstruction};
    use super::super::{ElementElementChild,TextElementChild,CommentElementChild,PIElementChild};

    macro_rules! assert_str_eq(
        ($l:expr, $r:expr) => (assert_eq!($l.as_slice(), $r.as_slice()));
    )

    enum Content {
        WElement(Element),
        WElementEnd(String),
        WText(Text),
        WComment(Comment),
        WProcessingInstruction(ProcessingInstruction),
    }

    fn format_element<W : Writer>(element: Element, todo: &mut Vec<Content>, writer: &mut W) -> IoResult<()> {
        try!(write!(writer, "<{}", element.name()));

        for attr in element.attributes().iter() {
            try!(write!(writer, " {}='{}'", attr.name(), attr.value()));
        }

        let mut children = element.children();
        if children.is_empty() {
            writer.write_str("/>")
        } else {
            try!(writer.write_str(">"));

            todo.push(WElementEnd(element.name()));
            children.reverse();
            let x = children.move_iter().map(|c| match c {
                ElementElementChild(element) => WElement(element),
                TextElementChild(t) => WText(t),
                CommentElementChild(c) => WComment(c),
                PIElementChild(p) => WProcessingInstruction(p),
            }).collect();
            todo.push_all_move(x);

            Ok(())
        }
    }

    fn format_processing_instruction<W : Writer>(pi: ProcessingInstruction, writer: &mut W) -> IoResult<()> {
        match pi.value() {
            None    => write!(writer, "<?{}?>", pi.target()),
            Some(v) => write!(writer, "<?{} {}?>", pi.target(), v),
        }
    }

    fn format_document<W : Writer>(doc: &Document, writer: &mut W) -> IoResult<()> {
        let mut todo = Vec::new();

        try!(writer.write_str("<?xml version='1.0'?>"));
        let e = doc.root().children()[0].element().expect("not an element?");

        todo.push(WElement(e));

        while ! todo.is_empty() {
            match todo.pop().unwrap() {
                WElement(e) => try!(format_element(e, &mut todo, writer)),
                WElementEnd(name) => try!(write!(writer, "</{}>", name)),
                WText(t) => try!(writer.write_str(t.text().as_slice())),
                WComment(c) => try!(write!(writer, "<!--{}-->", c.text())),
                WProcessingInstruction(p) => try!(format_processing_instruction(p, writer)),
            }
        }

        Ok(())
    }

    fn format_xml(doc: &Document) -> String {
        let mut w = MemWriter::new();
        format_document(doc, &mut w).ok().expect("Not formatted");
        String::from_utf8(w.unwrap()).ok().expect("Not a string")
    }

    #[test]
    fn top_element() {
        let d = Document::new();
        let e = d.new_element("hello".to_string());
        d.root().append_child(e);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello/>");
    }

    #[test]
    fn element_with_attributes() {
        let d = Document::new();
        let e = d.new_element("hello".to_string());
        e.set_attribute("a".to_string(), "b".to_string());
        d.root().append_child(e);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello a='b'/>");
    }

    #[test]
    fn nested_element() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let world = d.new_element("world".to_string());
        hello.append_child(world);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><world/></hello>");
    }

    #[test]
    fn nested_text() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let text = d.new_text("A fine day to you!".to_string());
        hello.append_child(text);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello>A fine day to you!</hello>");
    }

    #[test]
    fn nested_comment() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let comment = d.new_comment(" Fill this in ".to_string());
        hello.append_child(comment);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><!-- Fill this in --></hello>");
    }

    #[test]
    fn nested_processing_instruction_without_value() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let pi = d.new_processing_instruction("display".to_string(), None);
        hello.append_child(pi);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><?display?></hello>");
    }

    #[test]
    fn nested_processing_instruction_with_value() {
        let d = Document::new();
        let hello = d.new_element("hello".to_string());
        let pi = d.new_processing_instruction("display".to_string(), Some("screen".to_string()));
        hello.append_child(pi);
        d.root().append_child(hello);

        let xml = format_xml(&d);
        assert_str_eq!(xml, "<?xml version='1.0'?><hello><?display screen?></hello>");
    }
}
<|endoftext|>


<commit_before>use rustc::ty::{self, Ty, TypeAndMut};
use rustc::ty::layout::{self, TyLayout, Size};
use rustc::ty::adjustment::{PointerCast};
use syntax::ast::FloatTy;
use syntax::symbol::sym;

use rustc_apfloat::ieee::{Single, Double};
use rustc_apfloat::{Float, FloatConvert};
use rustc::mir::interpret::{
    Scalar, InterpResult, Pointer, PointerArithmetic,
};
use rustc::mir::CastKind;

use super::{InterpCx, Machine, PlaceTy, OpTy, ImmTy, Immediate, FnVal};

impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
    pub fn cast(
        &mut self,
        src: OpTy<'tcx, M::PointerTag>,
        kind: CastKind,
        dest: PlaceTy<'tcx, M::PointerTag>,
    ) -> InterpResult<'tcx> {
        use rustc::mir::CastKind::*;
        match kind {
            Pointer(PointerCast::Unsize) => {
                self.unsize_into(src, dest)?;
            }

            Misc | Pointer(PointerCast::MutToConstPointer) => {
                let src = self.read_immediate(src)?;
                let res = self.cast_immediate(src, dest.layout)?;
                self.write_immediate(res, dest)?;
            }

            Pointer(PointerCast::ReifyFnPointer) => {
                // The src operand does not matter, just its type
                match src.layout.ty.sty {
                    ty::FnDef(def_id, substs) => {
                        if self.tcx.has_attr(def_id, sym::rustc_args_required_const) {
                            bug!("reifying a fn ptr that requires const arguments");
                        }
                        let instance = ty::Instance::resolve(
                            *self.tcx,
                            self.param_env,
                            def_id,
                            substs,
                        ).ok_or_else(|| err_inval!(TooGeneric))?;
                        let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
                        self.write_scalar(Scalar::Ptr(fn_ptr.into()), dest)?;
                    }
                    _ => bug!("reify fn pointer on {:?}", src.layout.ty),
                }
            }

            Pointer(PointerCast::UnsafeFnPointer) => {
                let src = self.read_immediate(src)?;
                match dest.layout.ty.sty {
                    ty::FnPtr(_) => {
                        // No change to value
                        self.write_immediate(*src, dest)?;
                    }
                    _ => bug!("fn to unsafe fn cast on {:?}", dest.layout.ty),
                }
            }

            Pointer(PointerCast::ClosureFnPointer(_)) => {
                // The src operand does not matter, just its type
                match src.layout.ty.sty {
                    ty::Closure(def_id, substs) => {
                        let substs = self.subst_and_normalize_erasing_regions(substs)?;
                        let instance = ty::Instance::resolve_closure(
                            *self.tcx,
                            def_id,
                            substs,
                            ty::ClosureKind::FnOnce,
                        );
                        let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
                        let val = Immediate::Scalar(Scalar::Ptr(fn_ptr.into()).into());
                        self.write_immediate(val, dest)?;
                    }
                    _ => bug!("closure fn pointer on {:?}", src.layout.ty),
                }
            }
        }
        Ok(())
    }

    fn cast_immediate(
        &self,
        src: ImmTy<'tcx, M::PointerTag>,
        dest_layout: TyLayout<'tcx>,
    ) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
        use rustc::ty::TyKind::*;
        trace!("Casting {:?}: {:?} to {:?}", *src, src.layout.ty, dest_layout.ty);

        match src.layout.ty.sty {
            // Floating point
            Float(FloatTy::F32) =>
                return Ok(self.cast_from_float(src.to_scalar()?.to_f32()?, dest_layout.ty)?.into()),
            Float(FloatTy::F64) =>
                return Ok(self.cast_from_float(src.to_scalar()?.to_f64()?, dest_layout.ty)?.into()),
            // The rest is integer/pointer-"like", including fn ptr casts and casts from enums that
            // are represented as integers.
            _ =>
                assert!(
                    src.layout.ty.is_bool()       || src.layout.ty.is_char()     ||
                    src.layout.ty.is_enum()       || src.layout.ty.is_integral() ||
                    src.layout.ty.is_unsafe_ptr() || src.layout.ty.is_fn_ptr()   ||
                    src.layout.ty.is_region_ptr(),
                    "Unexpected cast from type {:?}", src.layout.ty
                )
        }

        // Handle cast the metadata away from a fat pointer.
        if dest_layout.size != src.layout.size {
            assert_eq!(dest_layout.size, self.memory.pointer_size());
            return match *src {
                Immediate::ScalarPair(data, _) => Ok(data.into()),
                Immediate::Scalar(..) =>
                    bug!(
                        "{:?} input to a fat-to-thin cast ({:?} -> {:?})",
                        *src, src.layout.ty, dest_layout.ty
                    ),
            };
        }

        // Handle cast from a univariant (ZST) enum
        match src.layout.variants {
            layout::Variants::Single { index } => {
                if let Some(discr) =
                    src.layout.ty.discriminant_for_variant(*self.tcx, index)
                {
                    assert!(src.layout.is_zst());
                    return Ok(Scalar::from_uint(discr.val, dest_layout.size).into());
                }
            }
            layout::Variants::Multiple { .. } => {},
        }

        // Handle all the rest.
        let val = src.to_scalar()?;
        Ok(match val.to_bits_or_ptr(src.layout.size, self) {
            Err(ptr) => self.cast_from_ptr(ptr, src.layout, dest_layout)?,
            Ok(data) => self.cast_from_int(data, src.layout, dest_layout)?,
        }.into())
    }

    fn cast_from_int(
        &self,
        v: u128, // raw bits
        src_layout: TyLayout<'tcx>,
        dest_layout: TyLayout<'tcx>,
    ) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
        // Let's make sure v is sign-extended *if* it has a signed type.
        let signed = src_layout.abi.is_signed();
        let v = if signed {
            self.sign_extend(v, src_layout)
        } else {
            v
        };
        trace!("cast_from_int: {}, {}, {}", v, src_layout.ty, dest_layout.ty);
        use rustc::ty::TyKind::*;
        match dest_layout.ty.sty {
            Int(_) | Uint(_) | RawPtr(_) => {
                let v = self.truncate(v, dest_layout);
                Ok(Scalar::from_uint(v, dest_layout.size))
            }

            Float(FloatTy::F32) if signed => Ok(Scalar::from_f32(
                Single::from_i128(v as i128).value
            )),
            Float(FloatTy::F64) if signed => Ok(Scalar::from_f64(
                Double::from_i128(v as i128).value
            )),
            Float(FloatTy::F32) => Ok(Scalar::from_f32(
                Single::from_u128(v).value
            )),
            Float(FloatTy::F64) => Ok(Scalar::from_f64(
                Double::from_u128(v).value
            )),

            Char => {
                // `u8` to `char` cast
                debug_assert_eq!(v as u8 as u128, v);
                Ok(Scalar::from_uint(v, Size::from_bytes(4)))
            },

            // Casts to bool are not permitted by rustc, no need to handle them here.
            _ => throw_unsup!(Unimplemented(format!("int to {:?} cast", dest_layout.ty))),
        }
    }

    fn cast_from_float<F>(
        &self,
        f: F,
        dest_ty: Ty<'tcx>
    ) -> InterpResult<'tcx, Scalar<M::PointerTag>>
    where F: Float + Into<Scalar<M::PointerTag>> + FloatConvert<Single> + FloatConvert<Double>
    {
        use rustc::ty::TyKind::*;
        match dest_ty.sty {
            // float -> uint
            Uint(t) => {
                let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize);
                let v = f.to_u128(width).value;
                // This should already fit the bit width
                Ok(Scalar::from_uint(v, Size::from_bits(width as u64)))
            },
            // float -> int
            Int(t) => {
                let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize);
                let v = f.to_i128(width).value;
                Ok(Scalar::from_int(v, Size::from_bits(width as u64)))
            },
            // float -> f32
            Float(FloatTy::F32) =>
                Ok(Scalar::from_f32(f.convert(&mut false).value)),
            // float -> f64
            Float(FloatTy::F64) =>
                Ok(Scalar::from_f64(f.convert(&mut false).value)),
            // That's it.
            _ => bug!("invalid float to {:?} cast", dest_ty),
        }
    }

    fn cast_from_ptr(
        &self,
        ptr: Pointer<M::PointerTag>,
        src_layout: TyLayout<'tcx>,
        dest_layout: TyLayout<'tcx>,
    ) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
        use rustc::ty::TyKind::*;

        match dest_layout.ty.sty {
            // Casting to a reference or fn pointer is not permitted by rustc,
            // no need to support it here.
            RawPtr(_) => Ok(ptr.into()),
            Int(_) | Uint(_) => {
                let size = self.memory.pointer_size();
                let bits = self.force_bits(Scalar::Ptr(ptr), size)?;
                self.cast_from_int(bits, src_layout, dest_layout)
            }
            _ => bug!("invalid MIR: ptr to {:?} cast", dest_layout.ty)
        }
    }

    fn unsize_into_ptr(
        &mut self,
        src: OpTy<'tcx, M::PointerTag>,
        dest: PlaceTy<'tcx, M::PointerTag>,
        // The pointee types
        sty: Ty<'tcx>,
        dty: Ty<'tcx>,
    ) -> InterpResult<'tcx> {
        // A<Struct> -> A<Trait> conversion
        let (src_pointee_ty, dest_pointee_ty) =
            self.tcx.struct_lockstep_tails_erasing_lifetimes(sty, dty, self.param_env);

        match (&src_pointee_ty.sty, &dest_pointee_ty.sty) {
            (&ty::Array(_, length), &ty::Slice(_)) => {
                let ptr = self.read_immediate(src)?.to_scalar_ptr()?;
                // u64 cast is from usize to u64, which is always good
                let val = Immediate::new_slice(
                    ptr,
                    length.unwrap_usize(self.tcx.tcx),
                    self,
                );
                self.write_immediate(val, dest)
            }
            (&ty::Dynamic(..), &ty::Dynamic(..)) => {
                // For now, upcasts are limited to changes in marker
                // traits, and hence never actually require an actual
                // change to the vtable.
                let val = self.read_immediate(src)?;
                self.write_immediate(*val, dest)
            }
            (_, &ty::Dynamic(ref data, _)) => {
                // Initial cast from sized to dyn trait
                let vtable = self.get_vtable(src_pointee_ty, data.principal())?;
                let ptr = self.read_immediate(src)?.to_scalar_ptr()?;
                let val = Immediate::new_dyn_trait(ptr, vtable);
                self.write_immediate(val, dest)
            }

            _ => bug!("invalid unsizing {:?} -> {:?}", src.layout.ty, dest.layout.ty),
        }
    }

    fn unsize_into(
        &mut self,
        src: OpTy<'tcx, M::PointerTag>,
        dest: PlaceTy<'tcx, M::PointerTag>,
    ) -> InterpResult<'tcx> {
        trace!("Unsizing {:?} into {:?}", src, dest);
        match (&src.layout.ty.sty, &dest.layout.ty.sty) {
            (&ty::Ref(_, s, _), &ty::Ref(_, d, _)) |
            (&ty::Ref(_, s, _), &ty::RawPtr(TypeAndMut { ty: d, .. })) |
            (&ty::RawPtr(TypeAndMut { ty: s, .. }),
             &ty::RawPtr(TypeAndMut { ty: d, .. })) => {
                self.unsize_into_ptr(src, dest, s, d)
            }
            (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
                assert_eq!(def_a, def_b);
                if def_a.is_box() || def_b.is_box() {
                    if !def_a.is_box() || !def_b.is_box() {
                        bug!("invalid unsizing between {:?} -> {:?}", src.layout, dest.layout);
                    }
                    return self.unsize_into_ptr(
                        src,
                        dest,
                        src.layout.ty.boxed_ty(),
                        dest.layout.ty.boxed_ty(),
                    );
                }

                // unsizing of generic struct with pointer fields
                // Example: `Arc<T>` -> `Arc<Trait>`
                // here we need to increase the size of every &T thin ptr field to a fat ptr
                for i in 0..src.layout.fields.count() {
                    let dst_field = self.place_field(dest, i as u64)?;
                    if dst_field.layout.is_zst() {
                        continue;
                    }
                    let src_field = self.operand_field(src, i as u64)?;
                    if src_field.layout.ty == dst_field.layout.ty {
                        self.copy_op(src_field, dst_field)?;
                    } else {
                        self.unsize_into(src_field, dst_field)?;
                    }
                }
                Ok(())
            }
            _ => {
                bug!(
                    "unsize_into: invalid conversion: {:?} -> {:?}",
                    src.layout,
                    dest.layout
                )
            }
        }
    }
}
<commit_msg>fix casts from fat pointers<commit_after>use rustc::ty::{self, Ty, TypeAndMut};
use rustc::ty::layout::{self, TyLayout, Size};
use rustc::ty::adjustment::{PointerCast};
use syntax::ast::FloatTy;
use syntax::symbol::sym;

use rustc_apfloat::ieee::{Single, Double};
use rustc_apfloat::{Float, FloatConvert};
use rustc::mir::interpret::{
    Scalar, InterpResult, Pointer, PointerArithmetic,
};
use rustc::mir::CastKind;

use super::{InterpCx, Machine, PlaceTy, OpTy, ImmTy, Immediate, FnVal};

impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
    pub fn cast(
        &mut self,
        src: OpTy<'tcx, M::PointerTag>,
        kind: CastKind,
        dest: PlaceTy<'tcx, M::PointerTag>,
    ) -> InterpResult<'tcx> {
        use rustc::mir::CastKind::*;
        match kind {
            Pointer(PointerCast::Unsize) => {
                self.unsize_into(src, dest)?;
            }

            Misc | Pointer(PointerCast::MutToConstPointer) => {
                let src = self.read_immediate(src)?;
                let res = self.cast_immediate(src, dest.layout)?;
                self.write_immediate(res, dest)?;
            }

            Pointer(PointerCast::ReifyFnPointer) => {
                // The src operand does not matter, just its type
                match src.layout.ty.sty {
                    ty::FnDef(def_id, substs) => {
                        if self.tcx.has_attr(def_id, sym::rustc_args_required_const) {
                            bug!("reifying a fn ptr that requires const arguments");
                        }
                        let instance = ty::Instance::resolve(
                            *self.tcx,
                            self.param_env,
                            def_id,
                            substs,
                        ).ok_or_else(|| err_inval!(TooGeneric))?;
                        let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
                        self.write_scalar(Scalar::Ptr(fn_ptr.into()), dest)?;
                    }
                    _ => bug!("reify fn pointer on {:?}", src.layout.ty),
                }
            }

            Pointer(PointerCast::UnsafeFnPointer) => {
                let src = self.read_immediate(src)?;
                match dest.layout.ty.sty {
                    ty::FnPtr(_) => {
                        // No change to value
                        self.write_immediate(*src, dest)?;
                    }
                    _ => bug!("fn to unsafe fn cast on {:?}", dest.layout.ty),
                }
            }

            Pointer(PointerCast::ClosureFnPointer(_)) => {
                // The src operand does not matter, just its type
                match src.layout.ty.sty {
                    ty::Closure(def_id, substs) => {
                        let substs = self.subst_and_normalize_erasing_regions(substs)?;
                        let instance = ty::Instance::resolve_closure(
                            *self.tcx,
                            def_id,
                            substs,
                            ty::ClosureKind::FnOnce,
                        );
                        let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
                        let val = Immediate::Scalar(Scalar::Ptr(fn_ptr.into()).into());
                        self.write_immediate(val, dest)?;
                    }
                    _ => bug!("closure fn pointer on {:?}", src.layout.ty),
                }
            }
        }
        Ok(())
    }

    fn cast_immediate(
        &self,
        src: ImmTy<'tcx, M::PointerTag>,
        dest_layout: TyLayout<'tcx>,
    ) -> InterpResult<'tcx, Immediate<M::PointerTag>> {
        use rustc::ty::TyKind::*;
        trace!("Casting {:?}: {:?} to {:?}", *src, src.layout.ty, dest_layout.ty);

        match src.layout.ty.sty {
            // Floating point
            Float(FloatTy::F32) =>
                return Ok(self.cast_from_float(src.to_scalar()?.to_f32()?, dest_layout.ty)?.into()),
            Float(FloatTy::F64) =>
                return Ok(self.cast_from_float(src.to_scalar()?.to_f64()?, dest_layout.ty)?.into()),
            // The rest is integer/pointer-"like", including fn ptr casts and casts from enums that
            // are represented as integers.
            _ =>
                assert!(
                    src.layout.ty.is_bool()       || src.layout.ty.is_char()     ||
                    src.layout.ty.is_enum()       || src.layout.ty.is_integral() ||
                    src.layout.ty.is_unsafe_ptr() || src.layout.ty.is_fn_ptr()   ||
                    src.layout.ty.is_region_ptr(),
                    "Unexpected cast from type {:?}", src.layout.ty
                )
        }

        // Handle casting the metadata away from a fat pointer.
        if src.layout.ty.is_unsafe_ptr() && dest_layout.ty.is_unsafe_ptr() &&
            dest_layout.size != src.layout.size
        {
            assert_eq!(src.layout.size, 2*self.memory.pointer_size());
            assert_eq!(dest_layout.size, self.memory.pointer_size());
            assert!(dest_layout.ty.is_unsafe_ptr());
            return match *src {
                Immediate::ScalarPair(data, _) => Ok(data.into()),
                Immediate::Scalar(..) =>
                    bug!(
                        "{:?} input to a fat-to-thin cast ({:?} -> {:?})",
                        *src, src.layout.ty, dest_layout.ty
                    ),
            };
        }

        // Handle casting reference to raw ptr or raw to other raw (might be a fat ptr).
        if (src.layout.ty.is_region_ptr() || src.layout.ty.is_unsafe_ptr()) &&
            dest_layout.ty.is_unsafe_ptr()
        {
            // The only possible size-unequal case was handled above.
            assert_eq!(src.layout.size, dest_layout.size);
            return Ok(*src);
        }

        // Handle cast from a univariant (ZST) enum
        match src.layout.variants {
            layout::Variants::Single { index } => {
                if let Some(discr) =
                    src.layout.ty.discriminant_for_variant(*self.tcx, index)
                {
                    assert!(src.layout.is_zst());
                    return Ok(Scalar::from_uint(discr.val, dest_layout.size).into());
                }
            }
            layout::Variants::Multiple { .. } => {},
        }

        // Handle all the rest.
        let val = src.to_scalar()?;
        Ok(match val.to_bits_or_ptr(src.layout.size, self) {
            Err(ptr) => self.cast_from_ptr(ptr, src.layout, dest_layout)?,
            Ok(data) => self.cast_from_int(data, src.layout, dest_layout)?,
        }.into())
    }

    fn cast_from_int(
        &self,
        v: u128, // raw bits
        src_layout: TyLayout<'tcx>,
        dest_layout: TyLayout<'tcx>,
    ) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
        // Let's make sure v is sign-extended *if* it has a signed type.
        let signed = src_layout.abi.is_signed();
        let v = if signed {
            self.sign_extend(v, src_layout)
        } else {
            v
        };
        trace!("cast_from_int: {}, {}, {}", v, src_layout.ty, dest_layout.ty);
        use rustc::ty::TyKind::*;
        match dest_layout.ty.sty {
            Int(_) | Uint(_) | RawPtr(_) => {
                let v = self.truncate(v, dest_layout);
                Ok(Scalar::from_uint(v, dest_layout.size))
            }

            Float(FloatTy::F32) if signed => Ok(Scalar::from_f32(
                Single::from_i128(v as i128).value
            )),
            Float(FloatTy::F64) if signed => Ok(Scalar::from_f64(
                Double::from_i128(v as i128).value
            )),
            Float(FloatTy::F32) => Ok(Scalar::from_f32(
                Single::from_u128(v).value
            )),
            Float(FloatTy::F64) => Ok(Scalar::from_f64(
                Double::from_u128(v).value
            )),

            Char => {
                // `u8` to `char` cast
                debug_assert_eq!(v as u8 as u128, v);
                Ok(Scalar::from_uint(v, Size::from_bytes(4)))
            },

            // Casts to bool are not permitted by rustc, no need to handle them here.
            _ => throw_unsup!(Unimplemented(format!("int to {:?} cast", dest_layout.ty))),
        }
    }

    fn cast_from_float<F>(
        &self,
        f: F,
        dest_ty: Ty<'tcx>
    ) -> InterpResult<'tcx, Scalar<M::PointerTag>>
    where F: Float + Into<Scalar<M::PointerTag>> + FloatConvert<Single> + FloatConvert<Double>
    {
        use rustc::ty::TyKind::*;
        match dest_ty.sty {
            // float -> uint
            Uint(t) => {
                let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize);
                let v = f.to_u128(width).value;
                // This should already fit the bit width
                Ok(Scalar::from_uint(v, Size::from_bits(width as u64)))
            },
            // float -> int
            Int(t) => {
                let width = t.bit_width().unwrap_or_else(|| self.pointer_size().bits() as usize);
                let v = f.to_i128(width).value;
                Ok(Scalar::from_int(v, Size::from_bits(width as u64)))
            },
            // float -> f32
            Float(FloatTy::F32) =>
                Ok(Scalar::from_f32(f.convert(&mut false).value)),
            // float -> f64
            Float(FloatTy::F64) =>
                Ok(Scalar::from_f64(f.convert(&mut false).value)),
            // That's it.
            _ => bug!("invalid float to {:?} cast", dest_ty),
        }
    }

    fn cast_from_ptr(
        &self,
        ptr: Pointer<M::PointerTag>,
        src_layout: TyLayout<'tcx>,
        dest_layout: TyLayout<'tcx>,
    ) -> InterpResult<'tcx, Scalar<M::PointerTag>> {
        use rustc::ty::TyKind::*;

        match dest_layout.ty.sty {
            // Casting to a reference or fn pointer is not permitted by rustc,
            // no need to support it here.
            RawPtr(_) => Ok(ptr.into()),
            Int(_) | Uint(_) => {
                let size = self.memory.pointer_size();
                let bits = self.force_bits(Scalar::Ptr(ptr), size)?;
                self.cast_from_int(bits, src_layout, dest_layout)
            }
            _ => bug!("invalid MIR: ptr to {:?} cast", dest_layout.ty)
        }
    }

    fn unsize_into_ptr(
        &mut self,
        src: OpTy<'tcx, M::PointerTag>,
        dest: PlaceTy<'tcx, M::PointerTag>,
        // The pointee types
        sty: Ty<'tcx>,
        dty: Ty<'tcx>,
    ) -> InterpResult<'tcx> {
        // A<Struct> -> A<Trait> conversion
        let (src_pointee_ty, dest_pointee_ty) =
            self.tcx.struct_lockstep_tails_erasing_lifetimes(sty, dty, self.param_env);

        match (&src_pointee_ty.sty, &dest_pointee_ty.sty) {
            (&ty::Array(_, length), &ty::Slice(_)) => {
                let ptr = self.read_immediate(src)?.to_scalar_ptr()?;
                // u64 cast is from usize to u64, which is always good
                let val = Immediate::new_slice(
                    ptr,
                    length.unwrap_usize(self.tcx.tcx),
                    self,
                );
                self.write_immediate(val, dest)
            }
            (&ty::Dynamic(..), &ty::Dynamic(..)) => {
                // For now, upcasts are limited to changes in marker
                // traits, and hence never actually require an actual
                // change to the vtable.
                let val = self.read_immediate(src)?;
                self.write_immediate(*val, dest)
            }
            (_, &ty::Dynamic(ref data, _)) => {
                // Initial cast from sized to dyn trait
                let vtable = self.get_vtable(src_pointee_ty, data.principal())?;
                let ptr = self.read_immediate(src)?.to_scalar_ptr()?;
                let val = Immediate::new_dyn_trait(ptr, vtable);
                self.write_immediate(val, dest)
            }

            _ => bug!("invalid unsizing {:?} -> {:?}", src.layout.ty, dest.layout.ty),
        }
    }

    fn unsize_into(
        &mut self,
        src: OpTy<'tcx, M::PointerTag>,
        dest: PlaceTy<'tcx, M::PointerTag>,
    ) -> InterpResult<'tcx> {
        trace!("Unsizing {:?} into {:?}", src, dest);
        match (&src.layout.ty.sty, &dest.layout.ty.sty) {
            (&ty::Ref(_, s, _), &ty::Ref(_, d, _)) |
            (&ty::Ref(_, s, _), &ty::RawPtr(TypeAndMut { ty: d, .. })) |
            (&ty::RawPtr(TypeAndMut { ty: s, .. }),
             &ty::RawPtr(TypeAndMut { ty: d, .. })) => {
                self.unsize_into_ptr(src, dest, s, d)
            }
            (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
                assert_eq!(def_a, def_b);
                if def_a.is_box() || def_b.is_box() {
                    if !def_a.is_box() || !def_b.is_box() {
                        bug!("invalid unsizing between {:?} -> {:?}", src.layout, dest.layout);
                    }
                    return self.unsize_into_ptr(
                        src,
                        dest,
                        src.layout.ty.boxed_ty(),
                        dest.layout.ty.boxed_ty(),
                    );
                }

                // unsizing of generic struct with pointer fields
                // Example: `Arc<T>` -> `Arc<Trait>`
                // here we need to increase the size of every &T thin ptr field to a fat ptr
                for i in 0..src.layout.fields.count() {
                    let dst_field = self.place_field(dest, i as u64)?;
                    if dst_field.layout.is_zst() {
                        continue;
                    }
                    let src_field = self.operand_field(src, i as u64)?;
                    if src_field.layout.ty == dst_field.layout.ty {
                        self.copy_op(src_field, dst_field)?;
                    } else {
                        self.unsize_into(src_field, dst_field)?;
                    }
                }
                Ok(())
            }
            _ => {
                bug!(
                    "unsize_into: invalid conversion: {:?} -> {:?}",
                    src.layout,
                    dest.layout
                )
            }
        }
    }
}
<|endoftext|>