<commit_before>/*
 * Copyright (c) 2014 Arcterus
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

use core::prelude::*;
use core::intrinsics::transmute;
use core::iter;
use core::fmt;
use core::fmt::{FormatWriter, Error};

#[allow(dead_code)]
pub enum Color {
   Black      = 0,
   Blue       = 1,
   Green      = 2,
   Cyan       = 3,
   Red        = 4,
   Magenta    = 5,
   Brown      = 6,
   LightGray  = 7,
   DarkGray   = 8,
   LightBlue  = 9,
   LightGreen = 10,
   LightCyan  = 11,
   LightRed   = 12,
   Pink       = 13,
   Yellow     = 14,
   White      = 15
}
impl Copy for Color{}

static SCREEN_ADDR: uint = 0xb8000;
static MAX_ROW: uint = 25;
static MAX_COLUMN: uint = 80;

pub struct Writer {
   row: uint,
   col: uint,
   foreground: Color,
   background: Color,
}

#[packed]
#[allow(dead_code)]
struct ScreenCharacter {
   character: u8,
   color: u8,
}

static mut std_writer: Writer = Writer{row:0, col: 0, foreground: Color::Green,
   background: Color::Black};

pub fn clear_screen() {
   unsafe{std_writer.clear_screen()};
}
pub fn print_args(args: &fmt::Arguments) {
   match unsafe{fmt::write(&mut std_writer, args)} {
      Err(_) => panic!("error writing to vga_buffer"),
      _ => {},
   }
}
pub fn print_err(args: &fmt::Arguments, file_line: &(&'static str, uint)) {
   unsafe{
      let foreground = std_writer.foreground;
      let background = std_writer.background;
      std_writer.foreground = Color::White;
      std_writer.background = Color::Red;
      print!("Error: ");
      print_args(args);
      print!(" in {} at line {}", file_line.0, file_line.1);
      std_writer.foreground = foreground;
      std_writer.background = background;
   }
}

pub fn set_foreground(color:Color) {
   unsafe{std_writer.foreground = color};
}
pub fn set_background(color:Color) {
   unsafe{std_writer.background = color};
}

impl ScreenCharacter {
   #[inline]
   fn new(character:u8, foreground:Color, background:Color) -> ScreenCharacter {
      ScreenCharacter{
         character:character,
         color:((background as u8) << 4) + foreground as u8,
      }
   }
}
impl Copy for ScreenCharacter {}

impl FormatWriter for Writer {
   fn write(&mut self, msg: &[u8]) -> Result<(),Error> {
      for &byte in msg.iter() {
         self.print_byte(byte);
      }
      self.move_cursor();
      Ok::<(), Error>(())
   }
}

impl Writer {
   #[inline]
   fn screen_char_at(pos:uint) -> &'static ScreenCharacter {
      unsafe{transmute::<uint,&ScreenCharacter>(SCREEN_ADDR + pos * 2)}
   }
   #[inline]
   fn mut_screen_char_at(pos:uint) -> &'static mut ScreenCharacter {
      unsafe{transmute::<uint,&mut ScreenCharacter>(SCREEN_ADDR + pos * 2)}
   }

   fn clear_screen(&mut self) {
      for line in iter::range(0, MAX_ROW) {
         self.clear_line(line);
      }
      self.row = 0;
      self.col = 0;
      self.move_cursor();
   }

   #[inline]
   fn print_byte(&mut self, byte: u8) {
      match byte {
         0x0a /* newline */ => self.add_line(),
         0x0d /* carriage return */ => self.col = 0,
         0x08 /* backspace */ => {
            if self.col == 0 && self.row != 0 {
               self.col = MAX_COLUMN - 1;
               self.row -= 1;
            } else if self.col != 0 {
               self.col -= 1;
            }
         }
         byte => {
            let pos = self.row * MAX_COLUMN + self.col;

            let screen_char = Writer::mut_screen_char_at(pos);
            *screen_char = ScreenCharacter::new(byte as u8, self.foreground, self.background);

            self.col += 1;
            if self.col == MAX_COLUMN {
               self.add_line();
            }
         }
      }
   }

   fn clear_line(&mut self, row: uint) {
      let c = self.col;
      let r = self.row;
      self.col = 0;
      self.row = row;
      self.clear_rem_line();
      self.row = r;
      self.col = c;
   }

   fn clear_rem_line(&mut self) {
      let rpos = self.row * MAX_COLUMN;
      for i in iter::range(self.col, MAX_COLUMN) {
         let pos = rpos + i;
         let screen_char = Writer::mut_screen_char_at(pos);
         *screen_char = ScreenCharacter::new(' ' as u8, self.foreground, self.background);
      }
   }

   fn add_line(&mut self) {
      self.clear_rem_line();
      self.col = 0;
      self.row += 1;
      if self.row == MAX_ROW {
         self.row -= 1;
         self.shift_rows_up();
      }
   }

   fn shift_rows_up(&mut self) {
      for r in iter::range(0, MAX_ROW-1) {
         for c in iter::range(0, MAX_COLUMN) {
            let new_pos = r * MAX_COLUMN + c;
            let old_pos = (r+1) * MAX_COLUMN + c;

            let new_field = Writer::mut_screen_char_at(new_pos);
            let old_field = Writer::screen_char_at(old_pos);
            *new_field = *old_field;
         }
      }
      self.clear_line(MAX_ROW - 1);
   }

   fn move_cursor(&mut self) {
      let pos = self.row * MAX_COLUMN + self.col;
      unsafe {
         asm!("
            mov al, 0xF
            mov dx, 0x3D4
            out dx, al

            mov ax, bx
            mov dx, 0x3D5
            out dx, al

            mov al, 0xE
            mov dx, 0x3D4
            out dx, al

            mov ax, bx
            shr ax, 8
            mov dx, 0x3D5
            out dx, al
         " : : "{bx}" (pos) : "al", "dx": "intel");
      }
   }
}<commit_msg>silence dead code warnings at module level<commit_after>/*
 * Copyright (c) 2014 Arcterus
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#![allow(dead_code)]

use core::prelude::*;
use core::intrinsics::transmute;
use core::iter;
use core::fmt;
use core::fmt::{FormatWriter, Error};

pub enum Color {
   Black      = 0,
   Blue       = 1,
   Green      = 2,
   Cyan       = 3,
   Red        = 4,
   Magenta    = 5,
   Brown      = 6,
   LightGray  = 7,
   DarkGray   = 8,
   LightBlue  = 9,
   LightGreen = 10,
   LightCyan  = 11,
   LightRed   = 12,
   Pink       = 13,
   Yellow     = 14,
   White      = 15
}
impl Copy for Color{}

static SCREEN_ADDR: uint = 0xb8000;
static MAX_ROW: uint = 25;
static MAX_COLUMN: uint = 80;

pub struct Writer {
   row: uint,
   col: uint,
   foreground: Color,
   background: Color,
}

#[packed]
struct ScreenCharacter {
   character: u8,
   color: u8,
}

static mut std_writer: Writer = Writer{row:0, col: 0, foreground: Color::Green,
   background: Color::Black};

pub fn clear_screen() {
   unsafe{std_writer.clear_screen()};
}
pub fn print_args(args: &fmt::Arguments) {
   match unsafe{fmt::write(&mut std_writer, args)} {
      Err(_) => panic!("error writing to vga_buffer"),
      _ => {},
   }
}
pub fn print_err(args: &fmt::Arguments, file_line: &(&'static str, uint)) {
   unsafe{
      let foreground = std_writer.foreground;
      let background = std_writer.background;
      std_writer.foreground = Color::White;
      std_writer.background = Color::Red;
      print!("Error: ");
      print_args(args);
      print!(" in {} at line {}", file_line.0, file_line.1);
      std_writer.foreground = foreground;
      std_writer.background = background;
   }
}

pub fn set_foreground(color:Color) {
   unsafe{std_writer.foreground = color};
}
pub fn set_background(color:Color) {
   unsafe{std_writer.background = color};
}

impl ScreenCharacter {
   #[inline]
   fn new(character:u8, foreground:Color, background:Color) -> ScreenCharacter {
      ScreenCharacter{
         character:character,
         color:((background as u8) << 4) + foreground as u8,
      }
   }
}
impl Copy for ScreenCharacter {}

impl FormatWriter for Writer {
   fn write(&mut self, msg: &[u8]) -> Result<(),Error> {
      for &byte in msg.iter() {
         self.print_byte(byte);
      }
      self.move_cursor();
      Ok::<(), Error>(())
   }
}

impl Writer {
   #[inline]
   fn screen_char_at(pos:uint) -> &'static ScreenCharacter {
      unsafe{transmute::<uint,&ScreenCharacter>(SCREEN_ADDR + pos * 2)}
   }
   #[inline]
   fn mut_screen_char_at(pos:uint) -> &'static mut ScreenCharacter {
      unsafe{transmute::<uint,&mut ScreenCharacter>(SCREEN_ADDR + pos * 2)}
   }

   fn clear_screen(&mut self) {
      for line in iter::range(0, MAX_ROW) {
         self.clear_line(line);
      }
      self.row = 0;
      self.col = 0;
      self.move_cursor();
   }

   #[inline]
   fn print_byte(&mut self, byte: u8) {
      match byte {
         0x0a /* newline */ => self.add_line(),
         0x0d /* carriage return */ => self.col = 0,
         0x08 /* backspace */ => {
            if self.col == 0 && self.row != 0 {
               self.col = MAX_COLUMN - 1;
               self.row -= 1;
            } else if self.col != 0 {
               self.col -= 1;
            }
         }
         byte => {
            let pos = self.row * MAX_COLUMN + self.col;

            let screen_char = Writer::mut_screen_char_at(pos);
            *screen_char = ScreenCharacter::new(byte as u8, self.foreground, self.background);

            self.col += 1;
            if self.col == MAX_COLUMN {
               self.add_line();
            }
         }
      }
   }

   fn clear_line(&mut self, row: uint) {
      let c = self.col;
      let r = self.row;
      self.col = 0;
      self.row = row;
      self.clear_rem_line();
      self.row = r;
      self.col = c;
   }

   fn clear_rem_line(&mut self) {
      let rpos = self.row * MAX_COLUMN;
      for i in iter::range(self.col, MAX_COLUMN) {
         let pos = rpos + i;
         let screen_char = Writer::mut_screen_char_at(pos);
         *screen_char = ScreenCharacter::new(' ' as u8, self.foreground, self.background);
      }
   }

   fn add_line(&mut self) {
      self.clear_rem_line();
      self.col = 0;
      self.row += 1;
      if self.row == MAX_ROW {
         self.row -= 1;
         self.shift_rows_up();
      }
   }

   fn shift_rows_up(&mut self) {
      for r in iter::range(0, MAX_ROW-1) {
         for c in iter::range(0, MAX_COLUMN) {
            let new_pos = r * MAX_COLUMN + c;
            let old_pos = (r+1) * MAX_COLUMN + c;

            let new_field = Writer::mut_screen_char_at(new_pos);
            let old_field = Writer::screen_char_at(old_pos);
            *new_field = *old_field;
         }
      }
      self.clear_line(MAX_ROW - 1);
   }

   fn move_cursor(&mut self) {
      let pos = self.row * MAX_COLUMN + self.col;
      unsafe {
         asm!("
            mov al, 0xF
            mov dx, 0x3D4
            out dx, al

            mov ax, bx
            mov dx, 0x3D5
            out dx, al

            mov al, 0xE
            mov dx, 0x3D4
            out dx, al

            mov ax, bx
            shr ax, 8
            mov dx, 0x3D5
            out dx, al
         " : : "{bx}" (pos) : "al", "dx": "intel");
      }
   }
}<|endoftext|>


<commit_before>use activation_function::ActivationFunction;
use acyclic_network::{NodeType, Network};
pub use acyclic_network::NodeIndex as CppnNodeIndex;
use fixedbitset::FixedBitSet;

pub trait CppnNodeType: NodeType + ActivationFunction {
    fn is_input_node(&self) -> bool;
    fn is_output_node(&self) -> bool;
}

/// A concrete implementation of a CppnNodeType.
#[derive(Clone, Debug)]
pub enum CppnNode<A: ActivationFunction> {
    Bias,
    Input,
    Output,
    Hidden(A),
}

const CPPN_BIAS_WEIGHT: f64 = 1.0;
impl<A: ActivationFunction> ActivationFunction for CppnNode<A> {
    fn formula(&self) -> &'static str {
        // XXX
        ""
    }

    fn calculate(&self, input: f64) -> f64 {
        match *self {
            CppnNode::Hidden(ref activation_function) => {
                // apply activation function on `input`
                activation_function.calculate(input)
            }
            CppnNode::Input | CppnNode::Output => {
                // Simply pass on the input signal.
                input
            }
            CppnNode::Bias => CPPN_BIAS_WEIGHT,
        }
    }
}

impl<A: ActivationFunction> NodeType for CppnNode<A> {
    fn accept_incoming_links(&self) -> bool {
        match *self {
            CppnNode::Input | CppnNode::Bias => false,
            _ => true,
        }
    }

    fn accept_outgoing_links(&self) -> bool {
        match *self {
            CppnNode::Output => false,
            _ => true,
        }
    }
}

impl<A: ActivationFunction> CppnNodeType for CppnNode<A> {
    fn is_input_node(&self) -> bool {
        match *self {
            CppnNode::Input => true,
            _ => false,
        }
    }
    fn is_output_node(&self) -> bool {
        match *self {
            CppnNode::Output => true,
            _ => false,
        }
    }
}

pub type CppnGraph<N: CppnNodeType> = Network<N, f64>;

/// Represents a Compositional Pattern Producing Network (CPPN)
pub struct Cppn<'a, N: CppnNodeType + 'a> {
    graph: &'a CppnGraph<N>,
    inputs: Vec<CppnNodeIndex>,
    outputs: Vec<CppnNodeIndex>,

    // For each node in `graph` there exists a corresponding field in `incoming_signals` describing
    // the sum of all input signals for that node.  We could store it inline in the `CppnNode`, but
    // this would require to make the whole CppnGraph mutable.
    incoming_signals: Vec<f64>,
}

impl<'a, N: CppnNodeType> Cppn<'a, N> {
    pub fn new(graph: &'a CppnGraph<N>) -> Cppn<'a, N> {
        let mut inputs = Vec::new();
        let mut outputs = Vec::new();

        graph.each_node_with_index(|node, index| {
            if node.node_type().is_input_node() {
                inputs.push(index);
            }
            if node.node_type().is_output_node() {
                outputs.push(index);
            }
        });

        Cppn {
            graph: graph,
            inputs: inputs,
            outputs: outputs,
            incoming_signals: graph.nodes().iter().map(|_| 0.0).collect(),
        }
    }

    fn set_signal(&mut self, node_idx: CppnNodeIndex, value: f64) {
        self.incoming_signals[node_idx.index()] = value;
    }

    fn reset_signals(&mut self) {
        for value in self.incoming_signals.iter_mut() {
            *value = 0.0;
        }
    }

    /// Forward-propagate the signals starting from `from_nodes`. We use
    /// breadth-first-search (BFS).
    fn propagate_signals(&mut self, mut nodes: Vec<CppnNodeIndex>, mut seen: FixedBitSet) {
        while let Some(node_idx) = nodes.pop() {
            let input = self.incoming_signals[node_idx.index()];
            let output = self.graph.node(node_idx).node_type().calculate(input);

            // propagate output signal to outgoing links.
            self.graph.each_active_forward_link_of_node(node_idx, |out_node_idx, weight| {
                let out_node = out_node_idx.index();
                self.incoming_signals[out_node] += weight * output;
                if !seen.contains(out_node) {
                    seen.insert(out_node);
                    nodes.push(out_node_idx);
                }
            });
        }
    }

    /// Calculate all outputs
    pub fn calculate(&mut self, inputs: &[&[f64]]) -> Vec<f64> {
        assert!(self.incoming_signals.len() == self.graph.nodes().len());
        self.reset_signals();

        // assign all inputs
        let mut i = 0;
        for input_list in inputs.iter() {
            for &input in input_list.iter() {
                let input_idx = self.inputs[i];
                self.set_signal(input_idx, input);
                i += 1;
            }
        }
        assert!(i == self.inputs.len());

        let mut nodes = Vec::new(); // XXX: worst case capacity
        let mut seen = FixedBitSet::with_capacity(self.incoming_signals.len());

        // start from all nodes which have zero in_degree()
        self.graph.each_node_with_index(|node, index| {
            if node.in_degree() == 0 {
                nodes.push(index);
                seen.insert(index.index());
            }
        });

        // propagate the signals starting from the nodes with zero in degree.
        self.propagate_signals(nodes, seen);

        self.outputs
            .iter()
            .map(|&node_idx| self.incoming_signals[node_idx.index()])
            .collect()
    }
}

#[cfg(test)]
mod tests {
    use bipolar::BipolarActivationFunction as AF;
    use super::{Cppn, CppnGraph, CppnNode};
    use acyclic_network::ExternalNodeId;
    use rand;

#[test]
fn test_cycle() {
    let mut g = CppnGraph::new();
    let i1 = g.add_node(CppnNode::Input, ExternalNodeId(1));
    let h1 = g.add_node(CppnNode::Hidden(AF::Identity), ExternalNodeId(2));
    let h2 = g.add_node(CppnNode::Hidden(AF::Identity), ExternalNodeId(3));
    assert_eq!(true, g.valid_link(i1, i1).is_err());
    assert_eq!(true, g.valid_link(h1, h1).is_err());

    assert_eq!(true, g.valid_link(h1, i1).is_err());
    assert_eq!(Ok(()), g.valid_link(i1, h1));
    assert_eq!(Ok(()), g.valid_link(i1, h2));
    assert_eq!(Ok(()), g.valid_link(h1, h2));

    g.add_link(i1, h1, 0.0);
    assert_eq!(true, g.link_would_cycle(h1, i1));
    assert_eq!(false, g.link_would_cycle(i1, h1));
    assert_eq!(false, g.link_would_cycle(i1, h2));
    assert_eq!(true, g.link_would_cycle(i1, i1));
    assert_eq!(false, g.link_would_cycle(h1, h2));
    assert_eq!(false, g.link_would_cycle(h2, h1));
    assert_eq!(false, g.link_would_cycle(h2, i1));

    g.add_link(h1, h2, 0.0);
    assert_eq!(true, g.link_would_cycle(h2, i1));
    assert_eq!(true, g.link_would_cycle(h1, i1));
    assert_eq!(true, g.link_would_cycle(h2, h1));
    assert_eq!(false, g.link_would_cycle(i1, h2));
}

#[test]
fn test_simple_cppn() {
    let mut g = CppnGraph::new();
    let i1 = g.add_node(CppnNode::Input, ExternalNodeId(1));
    let h1 = g.add_node(CppnNode::Hidden(AF::Linear), ExternalNodeId(2));
    let o1 = g.add_node(CppnNode::Output, ExternalNodeId(3));
    g.add_link(i1, h1, 0.5);
    g.add_link(h1, o1, 1.0);

    let mut cppn = Cppn::new(&g);

    assert_eq!(vec![0.5 * 0.5], cppn.calculate(&[&[0.5]]));
    assert_eq!(vec![1.0], cppn.calculate(&[&[4.0]]));
    assert_eq!(vec![-1.0], cppn.calculate(&[&[-4.0]]));
}

#[test]
fn test_find_random_unconnected_link_no_cycle() {
    let mut g = CppnGraph::<CppnNode<AF>>::new();
    let i1 = g.add_node(CppnNode::Input, ExternalNodeId(1));
    let o1 = g.add_node(CppnNode::Output, ExternalNodeId(2));
    let o2 = g.add_node(CppnNode::Output, ExternalNodeId(3));

    let mut rng = rand::thread_rng();

    let link = g.find_random_unconnected_link_no_cycle(&mut rng);
    assert_eq!(true, link.is_some());
    let l = link.unwrap();
    assert!((i1, o1) == l || (i1, o2) == l);

    g.add_link(i1, o2, 0.0);
    let link = g.find_random_unconnected_link_no_cycle(&mut rng);
    assert_eq!(true, link.is_some());
    assert_eq!((i1, o1), link.unwrap());

    g.add_link(i1, o1, 0.0);
    let link = g.find_random_unconnected_link_no_cycle(&mut rng);
    assert_eq!(false, link.is_some());
}

}
<commit_msg>rustfmt<commit_after>use activation_function::ActivationFunction;
use acyclic_network::{NodeType, Network};
pub use acyclic_network::NodeIndex as CppnNodeIndex;
use fixedbitset::FixedBitSet;

pub trait CppnNodeType: NodeType + ActivationFunction {
    fn is_input_node(&self) -> bool;
    fn is_output_node(&self) -> bool;
}

/// A concrete implementation of a CppnNodeType.
#[derive(Clone, Debug)]
pub enum CppnNode<A: ActivationFunction> {
    Bias,
    Input,
    Output,
    Hidden(A),
}

const CPPN_BIAS_WEIGHT: f64 = 1.0;
impl<A: ActivationFunction> ActivationFunction for CppnNode<A> {
    fn formula(&self) -> &'static str {
        // XXX
        ""
    }

    fn calculate(&self, input: f64) -> f64 {
        match *self {
            CppnNode::Hidden(ref activation_function) => {
                // apply activation function on `input`
                activation_function.calculate(input)
            }
            CppnNode::Input | CppnNode::Output => {
                // Simply pass on the input signal.
                input
            }
            CppnNode::Bias => CPPN_BIAS_WEIGHT,
        }
    }
}

impl<A: ActivationFunction> NodeType for CppnNode<A> {
    fn accept_incoming_links(&self) -> bool {
        match *self {
            CppnNode::Input | CppnNode::Bias => false,
            _ => true,
        }
    }

    fn accept_outgoing_links(&self) -> bool {
        match *self {
            CppnNode::Output => false,
            _ => true,
        }
    }
}

impl<A: ActivationFunction> CppnNodeType for CppnNode<A> {
    fn is_input_node(&self) -> bool {
        match *self {
            CppnNode::Input => true,
            _ => false,
        }
    }
    fn is_output_node(&self) -> bool {
        match *self {
            CppnNode::Output => true,
            _ => false,
        }
    }
}

pub type CppnGraph<N: CppnNodeType> = Network<N, f64>;

/// Represents a Compositional Pattern Producing Network (CPPN)
pub struct Cppn<'a, N: CppnNodeType + 'a> {
    graph: &'a CppnGraph<N>,
    inputs: Vec<CppnNodeIndex>,
    outputs: Vec<CppnNodeIndex>,

    // For each node in `graph` there exists a corresponding field in `incoming_signals` describing
    // the sum of all input signals for that node.  We could store it inline in the `CppnNode`, but
    // this would require to make the whole CppnGraph mutable.
    incoming_signals: Vec<f64>,
}

impl<'a, N: CppnNodeType> Cppn<'a, N> {
    pub fn new(graph: &'a CppnGraph<N>) -> Cppn<'a, N> {
        let mut inputs = Vec::new();
        let mut outputs = Vec::new();

        graph.each_node_with_index(|node, index| {
            if node.node_type().is_input_node() {
                inputs.push(index);
            }
            if node.node_type().is_output_node() {
                outputs.push(index);
            }
        });

        Cppn {
            graph: graph,
            inputs: inputs,
            outputs: outputs,
            incoming_signals: graph.nodes().iter().map(|_| 0.0).collect(),
        }
    }

    fn set_signal(&mut self, node_idx: CppnNodeIndex, value: f64) {
        self.incoming_signals[node_idx.index()] = value;
    }

    fn reset_signals(&mut self) {
        for value in self.incoming_signals.iter_mut() {
            *value = 0.0;
        }
    }

    /// Forward-propagate the signals starting from `from_nodes`. We use
    /// breadth-first-search (BFS).
    fn propagate_signals(&mut self, mut nodes: Vec<CppnNodeIndex>, mut seen: FixedBitSet) {
        while let Some(node_idx) = nodes.pop() {
            let input = self.incoming_signals[node_idx.index()];
            let output = self.graph.node(node_idx).node_type().calculate(input);

            // propagate output signal to outgoing links.
            self.graph.each_active_forward_link_of_node(node_idx, |out_node_idx, weight| {
                let out_node = out_node_idx.index();
                self.incoming_signals[out_node] += weight * output;
                if !seen.contains(out_node) {
                    seen.insert(out_node);
                    nodes.push(out_node_idx);
                }
            });
        }
    }

    /// Calculate all outputs
    pub fn calculate(&mut self, inputs: &[&[f64]]) -> Vec<f64> {
        assert!(self.incoming_signals.len() == self.graph.nodes().len());
        self.reset_signals();

        // assign all inputs
        let mut i = 0;
        for input_list in inputs.iter() {
            for &input in input_list.iter() {
                let input_idx = self.inputs[i];
                self.set_signal(input_idx, input);
                i += 1;
            }
        }
        assert!(i == self.inputs.len());

        let mut nodes = Vec::new(); // XXX: worst case capacity
        let mut seen = FixedBitSet::with_capacity(self.incoming_signals.len());

        // start from all nodes which have zero in_degree()
        self.graph.each_node_with_index(|node, index| {
            if node.in_degree() == 0 {
                nodes.push(index);
                seen.insert(index.index());
            }
        });

        // propagate the signals starting from the nodes with zero in degree.
        self.propagate_signals(nodes, seen);

        self.outputs
            .iter()
            .map(|&node_idx| self.incoming_signals[node_idx.index()])
            .collect()
    }
}

#[cfg(test)]
mod tests {
    use bipolar::BipolarActivationFunction as AF;
    use super::{Cppn, CppnGraph, CppnNode};
    use acyclic_network::ExternalNodeId;
    use rand;

    #[test]
    fn test_cycle() {
        let mut g = CppnGraph::new();
        let i1 = g.add_node(CppnNode::Input, ExternalNodeId(1));
        let h1 = g.add_node(CppnNode::Hidden(AF::Identity), ExternalNodeId(2));
        let h2 = g.add_node(CppnNode::Hidden(AF::Identity), ExternalNodeId(3));
        assert_eq!(true, g.valid_link(i1, i1).is_err());
        assert_eq!(true, g.valid_link(h1, h1).is_err());

        assert_eq!(true, g.valid_link(h1, i1).is_err());
        assert_eq!(Ok(()), g.valid_link(i1, h1));
        assert_eq!(Ok(()), g.valid_link(i1, h2));
        assert_eq!(Ok(()), g.valid_link(h1, h2));

        g.add_link(i1, h1, 0.0);
        assert_eq!(true, g.link_would_cycle(h1, i1));
        assert_eq!(false, g.link_would_cycle(i1, h1));
        assert_eq!(false, g.link_would_cycle(i1, h2));
        assert_eq!(true, g.link_would_cycle(i1, i1));
        assert_eq!(false, g.link_would_cycle(h1, h2));
        assert_eq!(false, g.link_would_cycle(h2, h1));
        assert_eq!(false, g.link_would_cycle(h2, i1));

        g.add_link(h1, h2, 0.0);
        assert_eq!(true, g.link_would_cycle(h2, i1));
        assert_eq!(true, g.link_would_cycle(h1, i1));
        assert_eq!(true, g.link_would_cycle(h2, h1));
        assert_eq!(false, g.link_would_cycle(i1, h2));
    }

    #[test]
    fn test_simple_cppn() {
        let mut g = CppnGraph::new();
        let i1 = g.add_node(CppnNode::Input, ExternalNodeId(1));
        let h1 = g.add_node(CppnNode::Hidden(AF::Linear), ExternalNodeId(2));
        let o1 = g.add_node(CppnNode::Output, ExternalNodeId(3));
        g.add_link(i1, h1, 0.5);
        g.add_link(h1, o1, 1.0);

        let mut cppn = Cppn::new(&g);

        assert_eq!(vec![0.5 * 0.5], cppn.calculate(&[&[0.5]]));
        assert_eq!(vec![1.0], cppn.calculate(&[&[4.0]]));
        assert_eq!(vec![-1.0], cppn.calculate(&[&[-4.0]]));
    }

    #[test]
    fn test_find_random_unconnected_link_no_cycle() {
        let mut g = CppnGraph::<CppnNode<AF>>::new();
        let i1 = g.add_node(CppnNode::Input, ExternalNodeId(1));
        let o1 = g.add_node(CppnNode::Output, ExternalNodeId(2));
        let o2 = g.add_node(CppnNode::Output, ExternalNodeId(3));

        let mut rng = rand::thread_rng();

        let link = g.find_random_unconnected_link_no_cycle(&mut rng);
        assert_eq!(true, link.is_some());
        let l = link.unwrap();
        assert!((i1, o1) == l || (i1, o2) == l);

        g.add_link(i1, o2, 0.0);
        let link = g.find_random_unconnected_link_no_cycle(&mut rng);
        assert_eq!(true, link.is_some());
        assert_eq!((i1, o1), link.unwrap());

        g.add_link(i1, o1, 0.0);
        let link = g.find_random_unconnected_link_no_cycle(&mut rng);
        assert_eq!(false, link.is_some());
    }

}
<|endoftext|>


<commit_before>use std::{any::type_name, ops::Deref, sync::Arc};

use actix_http::Extensions;
use actix_utils::future::{err, ok, Ready};
use futures_core::future::LocalBoxFuture;
use serde::Serialize;

use crate::{
    dev::Payload, error::ErrorInternalServerError, extract::FromRequest, request::HttpRequest,
    Error,
};

/// Data factory.
pub(crate) trait DataFactory {
    /// Return true if modifications were made to extensions map.
    fn create(&self, extensions: &mut Extensions) -> bool;
}

pub(crate) type FnDataFactory =
    Box<dyn Fn() -> LocalBoxFuture<'static, Result<Box<dyn DataFactory>, ()>>>;

/// Application data.
///
/// Application level data is a piece of arbitrary data attached to the app, scope, or resource.
/// Application data is available to all routes and can be added during the application
/// configuration process via `App::data()`.
///
/// Application data can be accessed by using `Data<T>` extractor where `T` is data type.
///
/// **Note**: HTTP server accepts an application factory rather than an application instance. HTTP
/// server constructs an application instance for each thread, thus application data must be
/// constructed multiple times. If you want to share data between different threads, a shareable
/// object should be used, e.g. `Send + Sync`. Application data does not need to be `Send`
/// or `Sync`. Internally `Data` uses `Arc`.
///
/// If route data is not set for a handler, using `Data<T>` extractor would cause *Internal
/// Server Error* response.
///
// TODO: document `dyn T` functionality through converting an Arc
// TODO: note equivalence of req.app_data<Data<T>> and Data<T> extractor
// TODO: note that data must be inserted using Data<T> in order to extract it
///
/// # Examples
/// ```
/// use std::sync::Mutex;
/// use actix_web::{web, App, HttpResponse, Responder};
///
/// struct MyData {
///     counter: usize,
/// }
///
/// /// Use the `Data<T>` extractor to access data in a handler.
/// async fn index(data: web::Data<Mutex<MyData>>) -> impl Responder {
///     let mut data = data.lock().unwrap();
///     data.counter += 1;
///     HttpResponse::Ok()
/// }
///
/// fn main() {
///     let data = web::Data::new(Mutex::new(MyData{ counter: 0 }));
///
///     let app = App::new()
///         // Store `MyData` in application storage.
///         .app_data(data.clone())
///         .service(
///             web::resource("/index.html").route(
///                 web::get().to(index)));
/// }
/// ```
#[derive(Debug)]
pub struct Data<T: ?Sized>(Arc<T>);

impl<T> Data<T> {
    /// Create new `Data` instance.
    pub fn new(state: T) -> Data<T> {
        Data(Arc::new(state))
    }
}

impl<T: ?Sized> Data<T> {
    /// Get reference to inner app data.
    pub fn get_ref(&self) -> &T {
        self.0.as_ref()
    }

    /// Convert to the internal Arc<T>
    pub fn into_inner(self) -> Arc<T> {
        self.0
    }
}

impl<T: ?Sized> Deref for Data<T> {
    type Target = Arc<T>;

    fn deref(&self) -> &Arc<T> {
        &self.0
    }
}

impl<T: ?Sized> Clone for Data<T> {
    fn clone(&self) -> Data<T> {
        Data(self.0.clone())
    }
}

impl<T: ?Sized> From<Arc<T>> for Data<T> {
    fn from(arc: Arc<T>) -> Self {
        Data(arc)
    }
}

impl<T> Serialize for Data<T>
where
    T: Serialize,
{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        self.0.serialize(serializer)
    }
}

impl<T: ?Sized + 'static> FromRequest for Data<T> {
    type Error = Error;
    type Future = Ready<Result<Self, Error>>;

    #[inline]
    fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
        if let Some(st) = req.app_data::<Data<T>>() {
            ok(st.clone())
        } else {
            log::debug!(
                "Failed to construct App-level Data extractor. \
                 Request path: {:?} (type: {})",
                req.path(),
                type_name::<T>(),
            );
            err(ErrorInternalServerError(
                "App data is not configured, to configure construct it with web::Data::new() and pass it to App::app_data()",
            ))
        }
    }
}

impl<T: ?Sized + 'static> DataFactory for Data<T> {
    fn create(&self, extensions: &mut Extensions) -> bool {
        extensions.insert(Data(self.0.clone()));
        true
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{
        dev::Service,
        http::StatusCode,
        test::{init_service, TestRequest},
        web, App, HttpResponse,
    };

    // allow deprecated App::data
    #[allow(deprecated)]
    #[actix_rt::test]
    async fn test_data_extractor() {
        let srv = init_service(App::new().data("TEST".to_string()).service(
            web::resource("/").to(|data: web::Data<String>| {
                assert_eq!(data.to_lowercase(), "test");
                HttpResponse::Ok()
            }),
        ))
        .await;

        let req = TestRequest::default().to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::OK);

        let srv = init_service(
            App::new()
                .data(10u32)
                .service(web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok())),
        )
        .await;
        let req = TestRequest::default().to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);

        let srv = init_service(
            App::new()
                .data(10u32)
                .data(13u32)
                .app_data(12u64)
                .app_data(15u64)
                .default_service(web::to(|n: web::Data<u32>, req: HttpRequest| {
                    // in each case, the latter insertion should be preserved
                    assert_eq!(*req.app_data::<u64>().unwrap(), 15);
                    assert_eq!(*n.into_inner(), 13);
                    HttpResponse::Ok()
                })),
        )
        .await;
        let req = TestRequest::default().to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::OK);
    }

    #[actix_rt::test]
    async fn test_app_data_extractor() {
        let srv = init_service(
            App::new()
                .app_data(Data::new(10usize))
                .service(web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok())),
        )
        .await;

        let req = TestRequest::default().to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::OK);

        let srv = init_service(
            App::new()
                .app_data(Data::new(10u32))
                .service(web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok())),
        )
        .await;
        let req = TestRequest::default().to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
    }

    // allow deprecated App::data
    #[allow(deprecated)]
    #[actix_rt::test]
    async fn test_route_data_extractor() {
        let srv = init_service(
            App::new().service(
                web::resource("/")
                    .data(10usize)
                    .route(web::get().to(|_data: web::Data<usize>| HttpResponse::Ok())),
            ),
        )
        .await;

        let req = TestRequest::default().to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::OK);

        // different type
        let srv = init_service(
            App::new().service(
                web::resource("/")
                    .data(10u32)
                    .route(web::get().to(|_: web::Data<usize>| HttpResponse::Ok())),
            ),
        )
        .await;
        let req = TestRequest::default().to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
    }

    // allow deprecated App::data
    #[allow(deprecated)]
    #[actix_rt::test]
    async fn test_override_data() {
        let srv =
            init_service(App::new().data(1usize).service(
                web::resource("/").data(10usize).route(web::get().to(
                    |data: web::Data<usize>| {
                        assert_eq!(**data, 10);
                        HttpResponse::Ok()
                    },
                )),
            ))
            .await;

        let req = TestRequest::default().to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::OK);
    }

    #[actix_rt::test]
    async fn test_data_from_arc() {
        let data_new = Data::new(String::from("test-123"));
        let data_from_arc = Data::from(Arc::new(String::from("test-123")));
        assert_eq!(data_new.0, data_from_arc.0);
    }

    #[actix_rt::test]
    async fn test_data_from_dyn_arc() {
        trait TestTrait {
            fn get_num(&self) -> i32;
        }
        struct A {}
        impl TestTrait for A {
            fn get_num(&self) -> i32 {
                42
            }
        }
        // This works when Sized is required
        let dyn_arc_box: Arc<Box<dyn TestTrait>> = Arc::new(Box::new(A {}));
        let data_arc_box = Data::from(dyn_arc_box);
        // This works when Data Sized Bound is removed
        let dyn_arc: Arc<dyn TestTrait> = Arc::new(A {});
        let data_arc = Data::from(dyn_arc);
        assert_eq!(data_arc_box.get_num(), data_arc.get_num())
    }

    #[actix_rt::test]
    async fn test_dyn_data_into_arc() {
        trait TestTrait {
            fn get_num(&self) -> i32;
        }
        struct A {}
        impl TestTrait for A {
            fn get_num(&self) -> i32 {
                42
            }
        }
        let dyn_arc: Arc<dyn TestTrait> = Arc::new(A {});
        let data_arc = Data::from(dyn_arc);
        let arc_from_data = data_arc.clone().into_inner();
        assert_eq!(data_arc.get_num(), arc_from_data.get_num())
    }

    #[actix_rt::test]
    async fn test_get_ref_from_dyn_data() {
        trait TestTrait {
            fn get_num(&self) -> i32;
        }
        struct A {}
        impl TestTrait for A {
            fn get_num(&self) -> i32 {
                42
            }
        }
        let dyn_arc: Arc<dyn TestTrait> = Arc::new(A {});
        let data_arc = Data::from(dyn_arc);
        let ref_data = data_arc.get_ref();
        assert_eq!(data_arc.get_num(), ref_data.get_num())
    }
}
<commit_msg>improve Data docs<commit_after>use std::{any::type_name, ops::Deref, sync::Arc};

use actix_http::Extensions;
use actix_utils::future::{err, ok, Ready};
use futures_core::future::LocalBoxFuture;
use serde::Serialize;

use crate::{
    dev::Payload, error::ErrorInternalServerError, extract::FromRequest, request::HttpRequest,
    Error,
};

/// Data factory.
pub(crate) trait DataFactory {
    /// Return true if modifications were made to extensions map.
    fn create(&self, extensions: &mut Extensions) -> bool;
}

pub(crate) type FnDataFactory =
    Box<dyn Fn() -> LocalBoxFuture<'static, Result<Box<dyn DataFactory>, ()>>>;

/// Application data.
///
/// Application level data is a piece of arbitrary data attached to the app, scope, or resource.
/// Application data is available to all routes and can be added during the application
/// configuration process via `App::data()`.
///
/// Application data can be accessed by using `Data<T>` extractor where `T` is data type.
///
/// **Note**: HTTP server accepts an application factory rather than an application instance. HTTP
/// server constructs an application instance for each thread, thus application data must be
/// constructed multiple times. If you want to share data between different threads, a shareable
/// object should be used, e.g. `Send + Sync`. Application data does not need to be `Send`
/// or `Sync`. Internally `Data` contains an `Arc`.
///
/// If route data is not set for a handler, using `Data<T>` extractor would cause a `500 Internal
/// Server Error` response.
///
/// # Unsized Data
/// For types that are unsized, most commonly `dyn T`, `Data` can wrap these types by first
/// constructing an `Arc<dyn T>` and using the `From` implementation to convert it.
///
/// ```
/// # use std::{fmt::Display, sync::Arc};
/// # use actix_web::web::Data;
/// let displayable_arc: Arc<dyn Display> = Arc::new(42usize);
/// let displayable_data: Data<dyn Display> = Data::from(displayable_arc);
/// ```
///
/// # Examples
/// ```
/// use std::sync::Mutex;
/// use actix_web::{App, HttpRequest, HttpResponse, Responder, web::{self, Data}};
///
/// struct MyData {
///     counter: usize,
/// }
///
/// /// Use the `Data<T>` extractor to access data in a handler.
/// async fn index(data: Data<Mutex<MyData>>) -> impl Responder {
///     let mut my_data = data.lock().unwrap();
///     my_data.counter += 1;
///     HttpResponse::Ok()
/// }
///
/// /// Alteratively, use the `HttpRequest::app_data` method to access data in a handler.
/// async fn index_alt(req: HttpRequest) -> impl Responder {
///     let data = req.app_data::<Data<Mutex<MyData>>>().unwrap();
///     let mut my_data = data.lock().unwrap();
///     my_data.counter += 1;
///     HttpResponse::Ok()
/// }
///
/// let data = Data::new(Mutex::new(MyData { counter: 0 }));
///
/// let app = App::new()
///     // Store `MyData` in application storage.
///     .app_data(Data::clone(&data))
///     .route("/index.html", web::get().to(index))
///     .route("/index-alt.html", web::get().to(index_alt));
/// ```
#[derive(Debug)]
pub struct Data<T: ?Sized>(Arc<T>);

impl<T> Data<T> {
    /// Create new `Data` instance.
    pub fn new(state: T) -> Data<T> {
        Data(Arc::new(state))
    }
}

impl<T: ?Sized> Data<T> {
    /// Get reference to inner app data.
    pub fn get_ref(&self) -> &T {
        self.0.as_ref()
    }

    /// Convert to the internal Arc<T>
    pub fn into_inner(self) -> Arc<T> {
        self.0
    }
}

impl<T: ?Sized> Deref for Data<T> {
    type Target = Arc<T>;

    fn deref(&self) -> &Arc<T> {
        &self.0
    }
}

impl<T: ?Sized> Clone for Data<T> {
    fn clone(&self) -> Data<T> {
        Data(self.0.clone())
    }
}

impl<T: ?Sized> From<Arc<T>> for Data<T> {
    fn from(arc: Arc<T>) -> Self {
        Data(arc)
    }
}

impl<T> Serialize for Data<T>
where
    T: Serialize,
{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        self.0.serialize(serializer)
    }
}

impl<T: ?Sized + 'static> FromRequest for Data<T> {
    type Error = Error;
    type Future = Ready<Result<Self, Error>>;

    #[inline]
    fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future {
        if let Some(st) = req.app_data::<Data<T>>() {
            ok(st.clone())
        } else {
            log::debug!(
                "Failed to construct App-level Data extractor. \
                 Request path: {:?} (type: {})",
                req.path(),
                type_name::<T>(),
            );
            err(ErrorInternalServerError(
                "App data is not configured, to configure construct it with web::Data::new() and pass it to App::app_data()",
            ))
        }
    }
}

impl<T: ?Sized + 'static> DataFactory for Data<T> {
    fn create(&self, extensions: &mut Extensions) -> bool {
        extensions.insert(Data(self.0.clone()));
        true
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::{
        dev::Service,
        http::StatusCode,
        test::{init_service, TestRequest},
        web, App, HttpResponse,
    };

    // allow deprecated App::data
    #[allow(deprecated)]
    #[actix_rt::test]
    async fn test_data_extractor() {
        let srv = init_service(App::new().data("TEST".to_string()).service(
            web::resource("/").to(|data: web::Data<String>| {
                assert_eq!(data.to_lowercase(), "test");
                HttpResponse::Ok()
            }),
        ))
        .await;

        let req = TestRequest::default().to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::OK);

        let srv = init_service(
            App::new()
                .data(10u32)
                .service(web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok())),
        )
        .await;
        let req = TestRequest::default().to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);

        let srv = init_service(
            App::new()
                .data(10u32)
                .data(13u32)
                .app_data(12u64)
                .app_data(15u64)
                .default_service(web::to(|n: web::Data<u32>, req: HttpRequest| {
                    // in each case, the latter insertion should be preserved
                    assert_eq!(*req.app_data::<u64>().unwrap(), 15);
                    assert_eq!(*n.into_inner(), 13);
                    HttpResponse::Ok()
                })),
        )
        .await;
        let req = TestRequest::default().to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::OK);
    }

    #[actix_rt::test]
    async fn test_app_data_extractor() {
        let srv = init_service(
            App::new()
                .app_data(Data::new(10usize))
                .service(web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok())),
        )
        .await;

        let req = TestRequest::default().to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::OK);

        let srv = init_service(
            App::new()
                .app_data(Data::new(10u32))
                .service(web::resource("/").to(|_: web::Data<usize>| HttpResponse::Ok())),
        )
        .await;
        let req = TestRequest::default().to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
    }

    // allow deprecated App::data
    #[allow(deprecated)]
    #[actix_rt::test]
    async fn test_route_data_extractor() {
        let srv = init_service(
            App::new().service(
                web::resource("/")
                    .data(10usize)
                    .route(web::get().to(|_data: web::Data<usize>| HttpResponse::Ok())),
            ),
        )
        .await;

        let req = TestRequest::default().to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::OK);

        // different type
        let srv = init_service(
            App::new().service(
                web::resource("/")
                    .data(10u32)
                    .route(web::get().to(|_: web::Data<usize>| HttpResponse::Ok())),
            ),
        )
        .await;
        let req = TestRequest::default().to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::INTERNAL_SERVER_ERROR);
    }

    // allow deprecated App::data
    #[allow(deprecated)]
    #[actix_rt::test]
    async fn test_override_data() {
        let srv =
            init_service(App::new().data(1usize).service(
                web::resource("/").data(10usize).route(web::get().to(
                    |data: web::Data<usize>| {
                        assert_eq!(**data, 10);
                        HttpResponse::Ok()
                    },
                )),
            ))
            .await;

        let req = TestRequest::default().to_request();
        let resp = srv.call(req).await.unwrap();
        assert_eq!(resp.status(), StatusCode::OK);
    }

    #[actix_rt::test]
    async fn test_data_from_arc() {
        let data_new = Data::new(String::from("test-123"));
        let data_from_arc = Data::from(Arc::new(String::from("test-123")));
        assert_eq!(data_new.0, data_from_arc.0);
    }

    #[actix_rt::test]
    async fn test_data_from_dyn_arc() {
        trait TestTrait {
            fn get_num(&self) -> i32;
        }
        struct A {}
        impl TestTrait for A {
            fn get_num(&self) -> i32 {
                42
            }
        }
        // This works when Sized is required
        let dyn_arc_box: Arc<Box<dyn TestTrait>> = Arc::new(Box::new(A {}));
        let data_arc_box = Data::from(dyn_arc_box);
        // This works when Data Sized Bound is removed
        let dyn_arc: Arc<dyn TestTrait> = Arc::new(A {});
        let data_arc = Data::from(dyn_arc);
        assert_eq!(data_arc_box.get_num(), data_arc.get_num())
    }

    #[actix_rt::test]
    async fn test_dyn_data_into_arc() {
        trait TestTrait {
            fn get_num(&self) -> i32;
        }
        struct A {}
        impl TestTrait for A {
            fn get_num(&self) -> i32 {
                42
            }
        }
        let dyn_arc: Arc<dyn TestTrait> = Arc::new(A {});
        let data_arc = Data::from(dyn_arc);
        let arc_from_data = data_arc.clone().into_inner();
        assert_eq!(data_arc.get_num(), arc_from_data.get_num())
    }

    #[actix_rt::test]
    async fn test_get_ref_from_dyn_data() {
        trait TestTrait {
            fn get_num(&self) -> i32;
        }
        struct A {}
        impl TestTrait for A {
            fn get_num(&self) -> i32 {
                42
            }
        }
        let dyn_arc: Arc<dyn TestTrait> = Arc::new(A {});
        let data_arc = Data::from(dyn_arc);
        let ref_data = data_arc.get_ref();
        assert_eq!(data_arc.get_num(), ref_data.get_num())
    }
}
<|endoftext|>


<commit_before>pub use self::os::{wctrans_t};

#[cfg(target_os = "linux")]
#[path = "linux/mod.rs"]
mod os;

pub fn iswalnum_l(wc: ::wchar::wint_t, locale: ::locale::locale_t) -> ::int_t {
    extern { fn iswalnum_l(wc: ::wchar::wint_t, locale: ::locale::locale_t) -> ::int_t; }
    unsafe { iswalnum_l(wc, locale) }
}

pub fn iswalnum(wc: ::wchar::wint_t) -> ::int_t {
    extern { fn iswalnum(wc: ::wchar::wint_t) -> ::int_t; }
    unsafe { iswalnum(wc) }
}

pub fn iswalpha_l(wc: ::wchar::wint_t, locale: ::locale::locale_t) -> ::int_t {
    extern { fn iswalpha_l(wc: ::wchar::wint_t, locale: ::locale::locale_t) -> ::int_t; }
    unsafe { iswalpha_l(wc, locale) }
}

pub fn iswalpha(wc: ::wchar::wint_t) -> ::int_t {
    extern { fn iswalpha(wc: ::wchar::wint_t) -> ::int_t; }
    unsafe { iswalpha(wc) }
}

pub fn iswblank_l(wc: ::wchar::wint_t, locale: ::locale::locale_t) -> ::int_t {
    extern { fn iswblank_l(wc: ::wchar::wint_t, locale: ::locale::locale_t) -> ::int_t; }
    unsafe { iswblank_l(wc, locale) }
}

pub fn iswblank(wc: ::wchar::wint_t) -> ::int_t {
    extern { fn iswblank(wc: ::wchar::wint_t) -> ::int_t; }
    unsafe { iswblank(wc) }
}

pub fn iswcntrl_l(wc: ::wchar::wint_t, locale: ::locale::locale_t) -> ::int_t {
    extern { fn iswcntrl_l(wc: ::wchar::wint_t, locale: ::locale::locale_t) -> ::int_t; }
    unsafe { iswcntrl_l(wc, locale) }
}

pub fn iswcntrl(wc: ::wchar::wint_t) -> ::int_t {
    extern { fn iswcntrl(wc: ::wchar::wint_t) -> ::int_t; }
    unsafe { iswcntrl(wc) }
}

pub fn iswctype_l(wc: ::wchar::wint_t, desc: ::wchar::wctype_t, locale: ::locale::locale_t) -> ::int_t {
    extern { fn iswctype_l(wc: ::wchar::wint_t, desc: ::wchar::wctype_t, locale: ::locale::locale_t) -> ::int_t; }
    unsafe { iswctype_l(wc, desc, locale) }
}

pub fn iswctype(wc: ::wchar::wint_t, desc: ::wchar::wctype_t) -> ::int_t {
    extern { fn iswctype(wc: ::wchar::wint_t, desc: ::wchar::wctype_t) -> ::int_t; }
    unsafe { iswctype(wc, desc) }
}

pub fn iswdigit_l(wc: ::wchar::wint_t, locale: ::locale::locale_t) -> ::int_t {
    extern { fn iswdigit_l(wc: ::wchar::wint_t, locale: ::locale::locale_t) -> ::int_t; }
    unsafe { iswdigit_l(wc, locale) }
}

pub fn iswdigit(wc: ::wchar::wint_t) -> ::int_t {
    extern { fn iswdigit(wc: ::wchar::wint_t) -> ::int_t; }
    unsafe { iswdigit(wc) }
}

pub fn iswgraph_l(wc: ::wchar::wint_t, locale: ::locale::locale_t) -> ::int_t {
    extern { fn iswgraph_l(wc: ::wchar::wint_t, locale: ::locale::locale_t) -> ::int_t; }
    unsafe { iswgraph_l(wc, locale) }
}

pub fn iswgraph(wc: ::wchar::wint_t) -> ::int_t {
    extern { fn iswgraph(wc: ::wchar::wint_t) -> ::int_t; }
    unsafe { iswgraph(wc) }
}

pub fn iswlower_l(wc: ::wchar::wint_t, locale: ::locale::locale_t) -> ::int_t {
    extern { fn iswlower_l(wc: ::wchar::wint_t, locale: ::locale::locale_t) -> ::int_t; }
    unsafe { iswlower_l(wc, locale) }
}

pub fn iswlower(wc: ::wchar::wint_t) -> ::int_t {
    extern { fn iswlower(wc: ::wchar::wint_t) -> ::int_t; }
    unsafe { iswlower(wc) }
}

pub fn iswprint_l(wc: ::wchar::wint_t, locale: ::locale::locale_t) -> ::int_t {
    extern { fn iswprint_l(wc: ::wchar::wint_t, locale: ::locale::locale_t) -> ::int_t; }
    unsafe { iswprint_l(wc, locale) }
}

pub fn iswprint(wc: ::wchar::wint_t) -> ::int_t {
    extern { fn iswprint(wc: ::wchar::wint_t) -> ::int_t; }
    unsafe { iswprint(wc) }
}

pub fn iswpunct_l(wc: ::wchar::wint_t, locale: ::locale::locale_t) -> ::int_t {
    extern { fn iswpunct_l(wc: ::wchar::wint_t, locale: ::locale::locale_t) -> ::int_t; }
    unsafe { iswpunct_l(wc, locale) }
}

pub fn iswpunct(wc: ::wchar::wint_t) -> ::int_t {
    extern { fn iswpunct(wc: ::wchar::wint_t) -> ::int_t; }
    unsafe { iswpunct(wc) }
}

pub fn iswspace_l(wc: ::wchar::wint_t, locale: ::locale::locale_t) -> ::int_t {
    extern { fn iswspace_l(wc: ::wchar::wint_t, locale: ::locale::locale_t) -> ::int_t; }
    unsafe { iswspace_l(wc, locale) }
}

pub fn iswspace(wc: ::wchar::wint_t) -> ::int_t {
    extern { fn iswspace(wc: ::wchar::wint_t) -> ::int_t; }
    unsafe { iswspace(wc) }
}

pub fn iswupper_l(wc: ::wchar::wint_t, locale: ::locale::locale_t) -> ::int_t {
    extern { fn iswupper_l(wc: ::wchar::wint_t, locale: ::locale::locale_t) -> ::int_t; }
    unsafe { iswupper_l(wc, locale) }
}

pub fn iswupper(wc: ::wchar::wint_t) -> ::int_t {
    extern { fn iswupper(wc: ::wchar::wint_t) -> ::int_t; }
    unsafe { iswupper(wc) }
}

pub fn iswxdigit_l(wc: ::wchar::wint_t, locale: ::locale::locale_t) -> ::int_t {
    extern { fn iswxdigit_l(wc: ::wchar::wint_t, locale: ::locale::locale_t) -> ::int_t; }
    unsafe { iswxdigit_l(wc, locale) }
}

pub fn iswxdigit(wc: ::wchar::wint_t) -> ::int_t {
    extern { fn iswxdigit(wc: ::wchar::wint_t) -> ::int_t; }
    unsafe { iswxdigit(wc) }
}

pub fn towctrans_l(wc: ::wchar::wint_t, desc: wctrans_t, locale: ::locale::locale_t) -> ::wchar::wint_t {
    extern { fn towctrans_l(wc: ::wchar::wint_t, desc: wctrans_t, locale: ::locale::locale_t) -> ::wchar::wint_t; }
    unsafe { towctrans_l(wc, desc, locale) }
}

pub fn towctrans(wc: ::wchar::wint_t, desc: wctrans_t) -> ::wchar::wint_t {
    extern { fn towctrans(wc: ::wchar::wint_t, desc: wctrans_t) -> ::wchar::wint_t; }
    unsafe { towctrans(wc, desc) }
}

pub fn towlower_l(wc: ::wchar::wint_t, locale: ::locale::locale_t) -> ::wchar::wint_t {
    extern { fn towlower_l(wc: ::wchar::wint_t, locale: ::locale::locale_t) -> ::wchar::wint_t; }
    unsafe { towlower_l(wc, locale) }
}

pub fn towlower(wc: ::wchar::wint_t) -> ::wchar::wint_t {
    extern { fn towlower(wc: ::wchar::wint_t) -> ::wchar::wint_t; }
    unsafe { towlower(wc) }
}

pub fn towupper_l(wc: ::wchar::wint_t, locale: ::locale::locale_t) -> ::wchar::wint_t {
    extern { fn towupper_l(wc: ::wchar::wint_t, locale: ::locale::locale_t) -> ::wchar::wint_t; }
    unsafe { towupper_l(wc, locale) }
}

pub fn towupper(wc: ::wchar::wint_t) -> ::wchar::wint_t {
    extern { fn towupper(wc: ::wchar::wint_t) -> ::wchar::wint_t; }
    unsafe { towupper(wc) }
}

extern {
    pub fn wctrans_l(property: *const ::char_t, locale: ::locale::locale_t) -> wctrans_t;
    pub fn wctrans(property: *const ::char_t) -> wctrans_t;
    pub fn wctype_l(property: *const ::char_t, locale: ::locale::locale_t) -> ::wchar::wctype_t;
    pub fn wctype(property: *const ::char_t) -> ::wchar::wctype_t;
}
<commit_msg>wctype.h<commit_after>pub use self::os::{wctrans_t};

use {int_t, char_t};
use locale::{locale_t};
use wchar::{wctype_t, wint_t};

#[cfg(target_os = "linux")]
#[path = "linux/mod.rs"]
mod os;

pub fn iswalnum_l(wc: wint_t, locale: locale_t) -> int_t {
    extern { fn iswalnum_l(wc: wint_t, locale: locale_t) -> int_t; }
    unsafe { iswalnum_l(wc, locale) }
}

pub fn iswalnum(wc: wint_t) -> int_t {
    extern { fn iswalnum(wc: wint_t) -> int_t; }
    unsafe { iswalnum(wc) }
}

pub fn iswalpha_l(wc: wint_t, locale: locale_t) -> int_t {
    extern { fn iswalpha_l(wc: wint_t, locale: locale_t) -> int_t; }
    unsafe { iswalpha_l(wc, locale) }
}

pub fn iswalpha(wc: wint_t) -> int_t {
    extern { fn iswalpha(wc: wint_t) -> int_t; }
    unsafe { iswalpha(wc) }
}

pub fn iswblank_l(wc: wint_t, locale: locale_t) -> int_t {
    extern { fn iswblank_l(wc: wint_t, locale: locale_t) -> int_t; }
    unsafe { iswblank_l(wc, locale) }
}

pub fn iswblank(wc: wint_t) -> int_t {
    extern { fn iswblank(wc: wint_t) -> int_t; }
    unsafe { iswblank(wc) }
}

pub fn iswcntrl_l(wc: wint_t, locale: locale_t) -> int_t {
    extern { fn iswcntrl_l(wc: wint_t, locale: locale_t) -> int_t; }
    unsafe { iswcntrl_l(wc, locale) }
}

pub fn iswcntrl(wc: wint_t) -> int_t {
    extern { fn iswcntrl(wc: wint_t) -> int_t; }
    unsafe { iswcntrl(wc) }
}

pub fn iswctype_l(wc: wint_t, desc: wctype_t, locale: locale_t) -> int_t {
    extern { fn iswctype_l(wc: wint_t, desc: wctype_t, locale: locale_t) -> int_t; }
    unsafe { iswctype_l(wc, desc, locale) }
}

pub fn iswctype(wc: wint_t, desc: wctype_t) -> int_t {
    extern { fn iswctype(wc: wint_t, desc: wctype_t) -> int_t; }
    unsafe { iswctype(wc, desc) }
}

pub fn iswdigit_l(wc: wint_t, locale: locale_t) -> int_t {
    extern { fn iswdigit_l(wc: wint_t, locale: locale_t) -> int_t; }
    unsafe { iswdigit_l(wc, locale) }
}

pub fn iswdigit(wc: wint_t) -> int_t {
    extern { fn iswdigit(wc: wint_t) -> int_t; }
    unsafe { iswdigit(wc) }
}

pub fn iswgraph_l(wc: wint_t, locale: locale_t) -> int_t {
    extern { fn iswgraph_l(wc: wint_t, locale: locale_t) -> int_t; }
    unsafe { iswgraph_l(wc, locale) }
}

pub fn iswgraph(wc: wint_t) -> int_t {
    extern { fn iswgraph(wc: wint_t) -> int_t; }
    unsafe { iswgraph(wc) }
}

pub fn iswlower_l(wc: wint_t, locale: locale_t) -> int_t {
    extern { fn iswlower_l(wc: wint_t, locale: locale_t) -> int_t; }
    unsafe { iswlower_l(wc, locale) }
}

pub fn iswlower(wc: wint_t) -> int_t {
    extern { fn iswlower(wc: wint_t) -> int_t; }
    unsafe { iswlower(wc) }
}

pub fn iswprint_l(wc: wint_t, locale: locale_t) -> int_t {
    extern { fn iswprint_l(wc: wint_t, locale: locale_t) -> int_t; }
    unsafe { iswprint_l(wc, locale) }
}

pub fn iswprint(wc: wint_t) -> int_t {
    extern { fn iswprint(wc: wint_t) -> int_t; }
    unsafe { iswprint(wc) }
}

pub fn iswpunct_l(wc: wint_t, locale: locale_t) -> int_t {
    extern { fn iswpunct_l(wc: wint_t, locale: locale_t) -> int_t; }
    unsafe { iswpunct_l(wc, locale) }
}

pub fn iswpunct(wc: wint_t) -> int_t {
    extern { fn iswpunct(wc: wint_t) -> int_t; }
    unsafe { iswpunct(wc) }
}

pub fn iswspace_l(wc: wint_t, locale: locale_t) -> int_t {
    extern { fn iswspace_l(wc: wint_t, locale: locale_t) -> int_t; }
    unsafe { iswspace_l(wc, locale) }
}

pub fn iswspace(wc: wint_t) -> int_t {
    extern { fn iswspace(wc: wint_t) -> int_t; }
    unsafe { iswspace(wc) }
}

pub fn iswupper_l(wc: wint_t, locale: locale_t) -> int_t {
    extern { fn iswupper_l(wc: wint_t, locale: locale_t) -> int_t; }
    unsafe { iswupper_l(wc, locale) }
}

pub fn iswupper(wc: wint_t) -> int_t {
    extern { fn iswupper(wc: wint_t) -> int_t; }
    unsafe { iswupper(wc) }
}

pub fn iswxdigit_l(wc: wint_t, locale: locale_t) -> int_t {
    extern { fn iswxdigit_l(wc: wint_t, locale: locale_t) -> int_t; }
    unsafe { iswxdigit_l(wc, locale) }
}

pub fn iswxdigit(wc: wint_t) -> int_t {
    extern { fn iswxdigit(wc: wint_t) -> int_t; }
    unsafe { iswxdigit(wc) }
}

pub fn towctrans_l(wc: wint_t, desc: wctrans_t, locale: locale_t) -> wint_t {
    extern { fn towctrans_l(wc: wint_t, desc: wctrans_t, locale: locale_t) -> wint_t; }
    unsafe { towctrans_l(wc, desc, locale) }
}

pub fn towctrans(wc: wint_t, desc: wctrans_t) -> wint_t {
    extern { fn towctrans(wc: wint_t, desc: wctrans_t) -> wint_t; }
    unsafe { towctrans(wc, desc) }
}

pub fn towlower_l(wc: wint_t, locale: locale_t) -> wint_t {
    extern { fn towlower_l(wc: wint_t, locale: locale_t) -> wint_t; }
    unsafe { towlower_l(wc, locale) }
}

pub fn towlower(wc: wint_t) -> wint_t {
    extern { fn towlower(wc: wint_t) -> wint_t; }
    unsafe { towlower(wc) }
}

pub fn towupper_l(wc: wint_t, locale: locale_t) -> wint_t {
    extern { fn towupper_l(wc: wint_t, locale: locale_t) -> wint_t; }
    unsafe { towupper_l(wc, locale) }
}

pub fn towupper(wc: wint_t) -> wint_t {
    extern { fn towupper(wc: wint_t) -> wint_t; }
    unsafe { towupper(wc) }
}

extern {
    pub fn wctrans_l(property: *const char_t, locale: locale_t) -> wctrans_t;
    pub fn wctrans(property: *const char_t) -> wctrans_t;
    pub fn wctype_l(property: *const char_t, locale: locale_t) -> wctype_t;
    pub fn wctype(property: *const char_t) -> wctype_t;
}
<|endoftext|>


<commit_before>use crate::background_jobs::Environment;
use crate::git::{Crate, Credentials};
use crate::schema;
use anyhow::Context;
use chrono::Utc;
use diesel::prelude::*;
use std::fs::{self, OpenOptions};
use std::io::prelude::*;
use swirl::PerformError;

#[swirl::background_job]
pub fn add_crate(env: &Environment, krate: Crate) -> Result<(), PerformError> {
    use std::io::prelude::*;

    let repo = env.lock_index()?;
    let dst = repo.index_file(&krate.name);

    // Add the crate to its relevant file
    fs::create_dir_all(dst.parent().unwrap())?;
    let mut file = OpenOptions::new().append(true).create(true).open(&dst)?;
    serde_json::to_writer(&mut file, &krate)?;
    file.write_all(b"\n")?;

    let message: String = format!("Updating crate `{}#{}`", krate.name, krate.vers);

    repo.commit_and_push(&message, &dst)
}

/// Yanks or unyanks a crate version. This requires finding the index
/// file, deserlialise the crate from JSON, change the yank boolean to
/// `true` or `false`, write all the lines back out, and commit and
/// push the changes.
#[swirl::background_job]
pub fn sync_yanked(
    env: &Environment,
    conn: &PgConnection,
    krate: String,
    version_num: String,
) -> Result<(), PerformError> {
    trace!(?krate, ?version_num, "Load yanked status from database");

    let yanked: bool = schema::versions::table
        .inner_join(schema::crates::table)
        .filter(schema::crates::name.eq(&krate))
        .filter(schema::versions::num.eq(&version_num))
        .select(schema::versions::yanked)
        .get_result(conn)
        .context("Failed to load yanked status from database")?;

    trace!(?krate, ?version_num, yanked);

    let repo = env.lock_index()?;
    let dst = repo.index_file(&krate);

    let prev = fs::read_to_string(&dst)?;
    let new = prev
        .lines()
        .map(|line| {
            let mut git_crate = serde_json::from_str::<Crate>(line)
                .map_err(|_| format!("couldn't decode: `{}`", line))?;
            if git_crate.name != krate || git_crate.vers != version_num {
                return Ok(line.to_string());
            }
            git_crate.yanked = Some(yanked);
            Ok(serde_json::to_string(&git_crate)?)
        })
        .collect::<Result<Vec<_>, PerformError>>();
    let new = new?.join("\n") + "\n";
    fs::write(&dst, new.as_bytes())?;

    let message: String = format!(
        "{} crate `{}#{}`",
        if yanked { "Yanking" } else { "Unyanking" },
        krate,
        version_num
    );

    repo.commit_and_push(&message, &dst)?;

    Ok(())
}

/// Collapse the index into a single commit, archiving the current history in a snapshot branch.
#[swirl::background_job]
pub fn squash_index(env: &Environment) -> Result<(), PerformError> {
    let repo = env.lock_index()?;
    println!("Squashing the index into a single commit.");

    let now = Utc::now().format("%Y-%m-%d");
    let original_head = repo.head_oid()?.to_string();
    let msg = format!("Collapse index into one commit\n\n\
        Previous HEAD was {}, now on the `snapshot-{}` branch\n\n\
        More information about this change can be found [online] and on [this issue].\n\n\
        [online]: https://internals.rust-lang.org/t/cargos-crate-index-upcoming-squash-into-one-commit/8440\n\
        [this issue]: https://github.com/rust-lang/crates-io-cargo-teams/issues/47", original_head, now);

    repo.squash_to_single_commit(&msg)?;

    // Shell out to git because libgit2 does not currently support push leases

    let key = match &repo.credentials {
        Credentials::Ssh { key } => key,
        Credentials::Http { .. } => {
            return Err(String::from("squash_index: Password auth not supported").into())
        }
        _ => return Err(String::from("squash_index: Could not determine credentials").into()),
    };

    // When running on production, ensure the file is created in tmpfs and not persisted to disk
    #[cfg(target_os = "linux")]
    let mut temp_key_file = tempfile::Builder::new().tempfile_in("/dev/shm")?;

    // For other platforms, default to std::env::tempdir()
    #[cfg(not(target_os = "linux"))]
    let mut temp_key_file = tempfile::Builder::new().tempfile()?;

    temp_key_file.write_all(key.as_bytes())?;

    let checkout_path = repo.checkout_path.path();
    let output = std::process::Command::new("git")
        .current_dir(checkout_path)
        .env(
            "GIT_SSH_COMMAND",
            format!(
                "ssh -o StrictHostKeyChecking=accept-new -i {}",
                temp_key_file.path().display()
            ),
        )
        .args(&[
            "push",
            // Both updates should succeed or fail together
            "--atomic",
            "origin",
            // Overwrite master, but only if it server matches the expected value
            &format!("--force-with-lease=refs/heads/master:{}", original_head),
            // The new squashed commit is pushed to master
            "HEAD:refs/heads/master",
            // The previous value of HEAD is pushed to a snapshot branch
            &format!("{}:refs/heads/snapshot-{}", original_head, now),
        ])
        .output()?;

    if !output.status.success() {
        let stderr = String::from_utf8_lossy(&output.stderr);
        let message = format!("Running git command failed with: {}", stderr);
        return Err(message.into());
    }

    println!("The index has been successfully squashed.");

    Ok(())
}
<commit_msg>worker::git: Avoid unnecessary commits if index is already up-to-date<commit_after>use crate::background_jobs::Environment;
use crate::git::{Crate, Credentials};
use crate::schema;
use anyhow::Context;
use chrono::Utc;
use diesel::prelude::*;
use std::fs::{self, OpenOptions};
use std::io::prelude::*;
use swirl::PerformError;

#[swirl::background_job]
pub fn add_crate(env: &Environment, krate: Crate) -> Result<(), PerformError> {
    use std::io::prelude::*;

    let repo = env.lock_index()?;
    let dst = repo.index_file(&krate.name);

    // Add the crate to its relevant file
    fs::create_dir_all(dst.parent().unwrap())?;
    let mut file = OpenOptions::new().append(true).create(true).open(&dst)?;
    serde_json::to_writer(&mut file, &krate)?;
    file.write_all(b"\n")?;

    let message: String = format!("Updating crate `{}#{}`", krate.name, krate.vers);

    repo.commit_and_push(&message, &dst)
}

/// Yanks or unyanks a crate version. This requires finding the index
/// file, deserlialise the crate from JSON, change the yank boolean to
/// `true` or `false`, write all the lines back out, and commit and
/// push the changes.
#[swirl::background_job]
pub fn sync_yanked(
    env: &Environment,
    conn: &PgConnection,
    krate: String,
    version_num: String,
) -> Result<(), PerformError> {
    trace!(?krate, ?version_num, "Load yanked status from database");

    let yanked: bool = schema::versions::table
        .inner_join(schema::crates::table)
        .filter(schema::crates::name.eq(&krate))
        .filter(schema::versions::num.eq(&version_num))
        .select(schema::versions::yanked)
        .get_result(conn)
        .context("Failed to load yanked status from database")?;

    trace!(?krate, ?version_num, yanked);

    let repo = env.lock_index()?;
    let dst = repo.index_file(&krate);

    let prev = fs::read_to_string(&dst)?;
    let new = prev
        .lines()
        .map(|line| {
            let mut git_crate = serde_json::from_str::<Crate>(line)
                .map_err(|_| format!("couldn't decode: `{}`", line))?;
            if git_crate.name != krate || git_crate.vers != version_num {
                return Ok(line.to_string());
            }
            git_crate.yanked = Some(yanked);
            Ok(serde_json::to_string(&git_crate)?)
        })
        .collect::<Result<Vec<_>, PerformError>>();
    let new = new?.join("\n") + "\n";

    if new != prev {
        fs::write(&dst, new.as_bytes())?;

        let message: String = format!(
            "{} crate `{}#{}`",
            if yanked { "Yanking" } else { "Unyanking" },
            krate,
            version_num
        );

        repo.commit_and_push(&message, &dst)?;
    } else {
        debug!("Skipping `yanked` update because index is up-to-date");
    }

    Ok(())
}

/// Collapse the index into a single commit, archiving the current history in a snapshot branch.
#[swirl::background_job]
pub fn squash_index(env: &Environment) -> Result<(), PerformError> {
    let repo = env.lock_index()?;
    println!("Squashing the index into a single commit.");

    let now = Utc::now().format("%Y-%m-%d");
    let original_head = repo.head_oid()?.to_string();
    let msg = format!("Collapse index into one commit\n\n\
        Previous HEAD was {}, now on the `snapshot-{}` branch\n\n\
        More information about this change can be found [online] and on [this issue].\n\n\
        [online]: https://internals.rust-lang.org/t/cargos-crate-index-upcoming-squash-into-one-commit/8440\n\
        [this issue]: https://github.com/rust-lang/crates-io-cargo-teams/issues/47", original_head, now);

    repo.squash_to_single_commit(&msg)?;

    // Shell out to git because libgit2 does not currently support push leases

    let key = match &repo.credentials {
        Credentials::Ssh { key } => key,
        Credentials::Http { .. } => {
            return Err(String::from("squash_index: Password auth not supported").into())
        }
        _ => return Err(String::from("squash_index: Could not determine credentials").into()),
    };

    // When running on production, ensure the file is created in tmpfs and not persisted to disk
    #[cfg(target_os = "linux")]
    let mut temp_key_file = tempfile::Builder::new().tempfile_in("/dev/shm")?;

    // For other platforms, default to std::env::tempdir()
    #[cfg(not(target_os = "linux"))]
    let mut temp_key_file = tempfile::Builder::new().tempfile()?;

    temp_key_file.write_all(key.as_bytes())?;

    let checkout_path = repo.checkout_path.path();
    let output = std::process::Command::new("git")
        .current_dir(checkout_path)
        .env(
            "GIT_SSH_COMMAND",
            format!(
                "ssh -o StrictHostKeyChecking=accept-new -i {}",
                temp_key_file.path().display()
            ),
        )
        .args(&[
            "push",
            // Both updates should succeed or fail together
            "--atomic",
            "origin",
            // Overwrite master, but only if it server matches the expected value
            &format!("--force-with-lease=refs/heads/master:{}", original_head),
            // The new squashed commit is pushed to master
            "HEAD:refs/heads/master",
            // The previous value of HEAD is pushed to a snapshot branch
            &format!("{}:refs/heads/snapshot-{}", original_head, now),
        ])
        .output()?;

    if !output.status.success() {
        let stderr = String::from_utf8_lossy(&output.stderr);
        let message = format!("Running git command failed with: {}", stderr);
        return Err(message.into());
    }

    println!("The index has been successfully squashed.");

    Ok(())
}
<|endoftext|>


<commit_before>use nom::{self,Needed,is_digit};
use nom::IResult::*;
use nom::Err::*;

use helper::*;
use super::{Date,Time,DateTime};

named!(take_4_digits, take_n_filter!(4, is_digit));
named!(take_2_digits, take_n_filter!(2, is_digit));

named!(sign, alt!(tag!("+") | tag!("-")));
named!(positive_year  <&[u8], i32>, map!(call!(take_4_digits), buf_to_i32));
named!(pub year <&[u8], i32>, chain!(
        pref: opt!(sign) ~
        y: positive_year
        ,
        || {
            match pref {
                Some(b"-") => -y,
                _ => y
            }
        }));

named!(pub month <&[u8], u32>, map!(call!(take_2_digits), buf_to_u32));
named!(pub day   <&[u8], u32>, map!(call!(take_2_digits), buf_to_u32));

named!(pub date <&[u8], Date>, chain!(
        y: year ~ tag!("-") ~ m: month ~ tag!("-") ~ d: day
        , || { Date{ year: y, month: m, day: d }
        }
        ));

named!(pub hour   <&[u8], u32>, map!(call!(take_2_digits), buf_to_u32));
named!(pub minute <&[u8], u32>, map!(call!(take_2_digits), buf_to_u32));
named!(pub second <&[u8], u32>, map!(call!(take_2_digits), buf_to_u32));

named!(pub time <&[u8], Time>, chain!(
        h: hour ~
        tag!(":") ~
        m: minute ~
        s: empty_or!(chain!(
                tag!(":") ~ s:second , || { s }))
        ,
        || { Time{ hour: h,
                   minute: m,
                   second: s.unwrap_or(0),
                   tz_offset: 0 }
           }
        ));

named!(timezone_hour <&[u8], i32>, chain!(
        s: sign ~
        h: hour ~
        empty_or!(
            chain!(
                tag!(":")? ~ m: minute , || { m }
            ))
        ,
        || {
            match s {
                b"-" => -(h as i32),
                _ => h as i32
            }
        }));

named!(tag_z, tag!("Z"));
named!(timezone_utc <&[u8], i32>, map!(tag_z, |_| 0));
named!(timezone <&[u8], i32>, alt!(timezone_utc | timezone_hour));

named!(pub datetime <&[u8], DateTime>, chain!(
        d: date ~
        tag!("T") ~
        t: time ~
        tzo: empty_or!(call!(timezone))
        ,
        || {
            DateTime{
                date: d,
                time: t.set_tz(tzo.unwrap_or(0)),
            }
        }
        ));
<commit_msg>Map sign to numeric<commit_after>use nom::{self,Needed,is_digit};
use nom::IResult::*;
use nom::Err::*;

use helper::*;
use super::{Date,Time,DateTime};

named!(take_4_digits, take_n_filter!(4, is_digit));
named!(take_2_digits, take_n_filter!(2, is_digit));

named!(sign, alt!(tag!("+") | tag!("-")));
named!(numeric_sign <&[u8], i32>, map!(sign, |s: &[u8]| {
    match s {
        b"-" => -1,
        _ => 1,
    }
}));

named!(positive_year  <&[u8], i32>, map!(call!(take_4_digits), buf_to_i32));
named!(pub year <&[u8], i32>, chain!(
        pref: opt!(numeric_sign) ~
        y: positive_year
        ,
        || {
            pref.unwrap_or(1) * y
        }));

named!(pub month <&[u8], u32>, map!(call!(take_2_digits), buf_to_u32));
named!(pub day   <&[u8], u32>, map!(call!(take_2_digits), buf_to_u32));

named!(pub date <&[u8], Date>, chain!(
        y: year ~ tag!("-") ~ m: month ~ tag!("-") ~ d: day
        , || { Date{ year: y, month: m, day: d }
        }
        ));

named!(pub hour   <&[u8], u32>, map!(call!(take_2_digits), buf_to_u32));
named!(pub minute <&[u8], u32>, map!(call!(take_2_digits), buf_to_u32));
named!(pub second <&[u8], u32>, map!(call!(take_2_digits), buf_to_u32));

named!(pub time <&[u8], Time>, chain!(
        h: hour ~
        tag!(":") ~
        m: minute ~
        s: empty_or!(chain!(
                tag!(":") ~ s:second , || { s }))
        ,
        || { Time{ hour: h,
                   minute: m,
                   second: s.unwrap_or(0),
                   tz_offset: 0 }
           }
        ));

named!(timezone_hour <&[u8], i32>, chain!(
        s: numeric_sign ~
        h: hour ~
        empty_or!(
            chain!(
                tag!(":")? ~ m: minute , || { m }
            ))
        ,
        || { s * (h as i32) }
        ));

named!(tag_z, tag!("Z"));
named!(timezone_utc <&[u8], i32>, map!(tag_z, |_| 0));
named!(timezone <&[u8], i32>, alt!(timezone_utc | timezone_hour));

named!(pub datetime <&[u8], DateTime>, chain!(
        d: date ~
        tag!("T") ~
        t: time ~
        tzo: empty_or!(call!(timezone))
        ,
        || {
            DateTime{
                date: d,
                time: t.set_tz(tzo.unwrap_or(0)),
            }
        }
        ));
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use cookie_storage::CookieSource;
use resource_task::{Metadata, TargetedLoadResponse, LoadData, start_sending_opt, ResponseSenders};
use resource_task::ControlMsg;
use resource_task::ProgressMsg::{Payload, Done};

use log;
use std::collections::HashSet;
use file_loader;
use hyper::client::Request;
use hyper::header::common::{ContentLength, ContentType, Host, Location, SetCookie};
use hyper::HttpError;
use hyper::method::Method;
use hyper::net::HttpConnector;
use hyper::status::{StatusCode, StatusClass};
use std::error::Error;
use openssl::ssl::{SslContext, SslVerifyMode};
use std::io::{IoError, IoErrorKind, Reader};
use std::sync::mpsc::{Sender, channel};
use std::thunk::Invoke;
use util::task::spawn_named;
use util::resource_files::resources_dir_path;
use url::{Url, UrlParser};

use std::borrow::ToOwned;

pub fn factory(cookies_chan: Sender<ControlMsg>)
               -> Box<Invoke<(LoadData, Sender<TargetedLoadResponse>)> + Send> {
    box move |:(load_data, start_chan)| {
        spawn_named("http_loader".to_owned(), move || load(load_data, start_chan, cookies_chan))
    }
}

fn send_error(url: Url, err: String, senders: ResponseSenders) {
    let mut metadata = Metadata::default(url);
    metadata.status = None;

    match start_sending_opt(senders, metadata) {
        Ok(p) => p.send(Done(Err(err))).unwrap(),
        _ => {}
    };
}

fn load(mut load_data: LoadData, start_chan: Sender<TargetedLoadResponse>, cookies_chan: Sender<ControlMsg>) {
    // FIXME: At the time of writing this FIXME, servo didn't have any central
    //        location for configuration. If you're reading this and such a
    //        repository DOES exist, please update this constant to use it.
    let max_redirects = 50u;
    let mut iters = 0u;
    let mut url = load_data.url.clone();
    let mut redirected_to = HashSet::new();

    let senders = ResponseSenders {
        immediate_consumer: start_chan,
        eventual_consumer: load_data.consumer
    };

    // Loop to handle redirects.
    loop {
        iters = iters + 1;

        if iters > max_redirects {
            send_error(url, "too many redirects".to_string(), senders);
            return;
        }

        match url.scheme.as_slice() {
            "http" | "https" => {}
            _ => {
                let s = format!("{} request, but we don't support that scheme", url.scheme);
                send_error(url, s, senders);
                return;
            }
        }

        info!("requesting {}", url.serialize());

        fn verifier(ssl: &mut SslContext) {
            ssl.set_verify(SslVerifyMode::SslVerifyPeer, None);
            let mut certs = resources_dir_path();
            certs.push("certs");
            ssl.set_CA_file(&certs);
        };

        let ssl_err_string = "[UnknownError { library: \"SSL routines\", \
function: \"SSL3_GET_SERVER_CERTIFICATE\", \
reason: \"certificate verify failed\" }]";

        let mut connector = HttpConnector(Some(box verifier as Box<FnMut(&mut SslContext)>));
        let mut req = match Request::with_connector(load_data.method.clone(), url.clone(), &mut connector) {
            Ok(req) => req,
            Err(HttpError::HttpIoError(IoError {kind: IoErrorKind::OtherIoError,
                                                desc: "Error in OpenSSL",
                                                detail: Some(ref det)})) if det.as_slice() == ssl_err_string => {
                let mut image = resources_dir_path();
                image.push("badcert.html");
                let load_data = LoadData::new(Url::from_file_path(&image).unwrap(), senders.eventual_consumer);
                file_loader::factory(load_data, senders.immediate_consumer);
                return;
            },
            Err(e) => {
                println!("{:?}", e);
                send_error(url, e.description().to_string(), senders);
                return;
            }
        };

        let (tx, rx) = channel();
        cookies_chan.send(ControlMsg::GetCookiesForUrl(url.clone(), tx, CookieSource::HTTP));
        if let Some(cookies) = rx.recv().unwrap() {
            let mut v = Vec::new();
            v.push(cookies.into_bytes());
            load_data.headers.set_raw("Cookie".to_owned(), v);
        }

        // Avoid automatically preserving request headers when redirects occur.
        // See https://bugzilla.mozilla.org/show_bug.cgi?id=401564 and
        // https://bugzilla.mozilla.org/show_bug.cgi?id=216828
        if iters == 1 {
            // Preserve the `host` header set automatically by Request.
            let host = req.headers().get::<Host>().unwrap().clone();
            *req.headers_mut() = load_data.headers.clone();
            req.headers_mut().set(host);
        }

        // FIXME(seanmonstar): use AcceptEncoding from Hyper once available
        //if !req.headers.has::<AcceptEncoding>() {
            // We currently don't support HTTP Compression (FIXME #2587)
            req.headers_mut().set_raw("Accept-Encoding".to_owned(), vec![b"identity".to_vec()]);
        //}
        if log_enabled!(log::INFO) {
            info!("{}", load_data.method);
            for header in req.headers().iter() {
                info!(" - {}", header);
            }
            info!("{:?}", load_data.data);
        }

        // Avoid automatically sending request body if a redirect has occurred.
        let writer = match load_data.data {
            Some(ref data) if iters == 1 => {
                req.headers_mut().set(ContentLength(data.len() as u64));
                let mut writer = match req.start() {
                    Ok(w) => w,
                    Err(e) => {
                        send_error(url, e.description().to_string(), senders);
                        return;
                    }
                };
                match writer.write(data.as_slice()) {
                    Err(e) => {
                        send_error(url, e.desc.to_string(), senders);
                        return;
                    }
                    _ => {}
                };
                writer
            },
            _ => {
                match load_data.method {
                    Method::Get | Method::Head => (),
                    _ => req.headers_mut().set(ContentLength(0))
                }
                match req.start() {
                    Ok(w) => w,
                    Err(e) => {
                        send_error(url, e.description().to_string(), senders);
                        return;
                    }
                }
            }
        };
        let mut response = match writer.send() {
            Ok(r) => r,
            Err(e) => {
                send_error(url, e.description().to_string(), senders);
                return;
            }
        };

        // Dump headers, but only do the iteration if info!() is enabled.
        info!("got HTTP response {}, headers:", response.status);
        if log_enabled!(log::INFO) {
            for header in response.headers.iter() {
                info!(" - {}", header);
            }
        }

        if let Some(&SetCookie(ref cookies)) = response.headers.get::<SetCookie>() {
            cookies_chan.send(ControlMsg::SetCookies(cookies.clone(), url.clone(),
                                                     CookieSource::HTTP));
        }

        if response.status.class() == StatusClass::Redirection {
            match response.headers.get::<Location>() {
                Some(&Location(ref new_url)) => {
                    // CORS (http://fetch.spec.whatwg.org/#http-fetch, status section, point 9, 10)
                    match load_data.cors {
                        Some(ref c) => {
                            if c.preflight {
                                // The preflight lied
                                send_error(url, "Preflight fetch inconsistent with main fetch".to_string(), senders);
                                return;
                            } else {
                                // XXXManishearth There are some CORS-related steps here,
                                // but they don't seem necessary until credentials are implemented
                            }
                        }
                        _ => {}
                    }
                    let new_url = match UrlParser::new().base_url(&url).parse(new_url.as_slice()) {
                        Ok(u) => u,
                        Err(e) => {
                            send_error(url, e.to_string(), senders);
                            return;
                        }
                    };
                    info!("redirecting to {}", new_url);
                    url = new_url;

                    // According to https://tools.ietf.org/html/rfc7231#section-6.4.2,
                    // historically UAs have rewritten POST->GET on 301 and 302 responses.
                    if load_data.method == Method::Post &&
                        (response.status == StatusCode::MovedPermanently ||
                         response.status == StatusCode::Found) {
                        load_data.method = Method::Get;
                    }

                    if redirected_to.contains(&url) {
                        send_error(url, "redirect loop".to_string(), senders);
                        return;
                    }

                    redirected_to.insert(url.clone());
                    continue;
                }
                None => ()
            }
        }

        let mut metadata = Metadata::default(url);
        metadata.set_content_type(match response.headers.get() {
            Some(&ContentType(ref mime)) => Some(mime),
            None => None
        });
        metadata.headers = Some(response.headers.clone());
        metadata.status = Some(response.status_raw().clone());

        let progress_chan = match start_sending_opt(senders, metadata) {
            Ok(p) => p,
            _ => return
        };
        loop {
            let mut buf = Vec::with_capacity(1024);

            unsafe { buf.set_len(1024); }
            match response.read(buf.as_mut_slice()) {
                Ok(len) => {
                    unsafe { buf.set_len(len); }
                    if progress_chan.send(Payload(buf)).is_err() {
                        // The send errors when the receiver is out of scope,
                        // which will happen if the fetch has timed out (or has been aborted)
                        // so we don't need to continue with the loading of the file here.
                        return;
                    }
                }
                Err(_) => {
                    let _ = progress_chan.send(Done(Ok(())));
                    break;
                }
            }
        }

        // We didn't get redirected.
        break;
    }
}
<commit_msg>Set cookie headers on the request, rather than the load data, to ensure they are used after redirects occur.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use cookie_storage::CookieSource;
use resource_task::{Metadata, TargetedLoadResponse, LoadData, start_sending_opt, ResponseSenders};
use resource_task::ControlMsg;
use resource_task::ProgressMsg::{Payload, Done};

use log;
use std::collections::HashSet;
use file_loader;
use hyper::client::Request;
use hyper::header::common::{ContentLength, ContentType, Host, Location, SetCookie};
use hyper::HttpError;
use hyper::method::Method;
use hyper::net::HttpConnector;
use hyper::status::{StatusCode, StatusClass};
use std::error::Error;
use openssl::ssl::{SslContext, SslVerifyMode};
use std::io::{IoError, IoErrorKind, Reader};
use std::sync::mpsc::{Sender, channel};
use std::thunk::Invoke;
use util::task::spawn_named;
use util::resource_files::resources_dir_path;
use url::{Url, UrlParser};

use std::borrow::ToOwned;

pub fn factory(cookies_chan: Sender<ControlMsg>)
               -> Box<Invoke<(LoadData, Sender<TargetedLoadResponse>)> + Send> {
    box move |:(load_data, start_chan)| {
        spawn_named("http_loader".to_owned(), move || load(load_data, start_chan, cookies_chan))
    }
}

fn send_error(url: Url, err: String, senders: ResponseSenders) {
    let mut metadata = Metadata::default(url);
    metadata.status = None;

    match start_sending_opt(senders, metadata) {
        Ok(p) => p.send(Done(Err(err))).unwrap(),
        _ => {}
    };
}

fn load(mut load_data: LoadData, start_chan: Sender<TargetedLoadResponse>, cookies_chan: Sender<ControlMsg>) {
    // FIXME: At the time of writing this FIXME, servo didn't have any central
    //        location for configuration. If you're reading this and such a
    //        repository DOES exist, please update this constant to use it.
    let max_redirects = 50u;
    let mut iters = 0u;
    let mut url = load_data.url.clone();
    let mut redirected_to = HashSet::new();

    let senders = ResponseSenders {
        immediate_consumer: start_chan,
        eventual_consumer: load_data.consumer
    };

    // Loop to handle redirects.
    loop {
        iters = iters + 1;

        if iters > max_redirects {
            send_error(url, "too many redirects".to_string(), senders);
            return;
        }

        match url.scheme.as_slice() {
            "http" | "https" => {}
            _ => {
                let s = format!("{} request, but we don't support that scheme", url.scheme);
                send_error(url, s, senders);
                return;
            }
        }

        info!("requesting {}", url.serialize());

        fn verifier(ssl: &mut SslContext) {
            ssl.set_verify(SslVerifyMode::SslVerifyPeer, None);
            let mut certs = resources_dir_path();
            certs.push("certs");
            ssl.set_CA_file(&certs);
        };

        let ssl_err_string = "[UnknownError { library: \"SSL routines\", \
function: \"SSL3_GET_SERVER_CERTIFICATE\", \
reason: \"certificate verify failed\" }]";

        let mut connector = HttpConnector(Some(box verifier as Box<FnMut(&mut SslContext)>));
        let mut req = match Request::with_connector(load_data.method.clone(), url.clone(), &mut connector) {
            Ok(req) => req,
            Err(HttpError::HttpIoError(IoError {kind: IoErrorKind::OtherIoError,
                                                desc: "Error in OpenSSL",
                                                detail: Some(ref det)})) if det.as_slice() == ssl_err_string => {
                let mut image = resources_dir_path();
                image.push("badcert.html");
                let load_data = LoadData::new(Url::from_file_path(&image).unwrap(), senders.eventual_consumer);
                file_loader::factory(load_data, senders.immediate_consumer);
                return;
            },
            Err(e) => {
                println!("{:?}", e);
                send_error(url, e.description().to_string(), senders);
                return;
            }
        };

        // Avoid automatically preserving request headers when redirects occur.
        // See https://bugzilla.mozilla.org/show_bug.cgi?id=401564 and
        // https://bugzilla.mozilla.org/show_bug.cgi?id=216828
        if iters == 1 {
            // Preserve the `host` header set automatically by Request.
            let host = req.headers().get::<Host>().unwrap().clone();
            *req.headers_mut() = load_data.headers.clone();
            req.headers_mut().set(host);
        }

        let (tx, rx) = channel();
        cookies_chan.send(ControlMsg::GetCookiesForUrl(url.clone(), tx, CookieSource::HTTP));
        if let Some(cookies) = rx.recv().unwrap() {
            let mut v = Vec::new();
            v.push(cookies.into_bytes());
            load_data.headers.set_raw("Cookie".to_owned(), v);
        }

        // FIXME(seanmonstar): use AcceptEncoding from Hyper once available
        //if !req.headers.has::<AcceptEncoding>() {
            // We currently don't support HTTP Compression (FIXME #2587)
            req.headers_mut().set_raw("Accept-Encoding".to_owned(), vec![b"identity".to_vec()]);
        //}
        if log_enabled!(log::INFO) {
            info!("{}", load_data.method);
            for header in req.headers().iter() {
                info!(" - {}", header);
            }
            info!("{:?}", load_data.data);
        }

        // Avoid automatically sending request body if a redirect has occurred.
        let writer = match load_data.data {
            Some(ref data) if iters == 1 => {
                req.headers_mut().set(ContentLength(data.len() as u64));
                let mut writer = match req.start() {
                    Ok(w) => w,
                    Err(e) => {
                        send_error(url, e.description().to_string(), senders);
                        return;
                    }
                };
                match writer.write(data.as_slice()) {
                    Err(e) => {
                        send_error(url, e.desc.to_string(), senders);
                        return;
                    }
                    _ => {}
                };
                writer
            },
            _ => {
                match load_data.method {
                    Method::Get | Method::Head => (),
                    _ => req.headers_mut().set(ContentLength(0))
                }
                match req.start() {
                    Ok(w) => w,
                    Err(e) => {
                        send_error(url, e.description().to_string(), senders);
                        return;
                    }
                }
            }
        };
        let mut response = match writer.send() {
            Ok(r) => r,
            Err(e) => {
                send_error(url, e.description().to_string(), senders);
                return;
            }
        };

        // Dump headers, but only do the iteration if info!() is enabled.
        info!("got HTTP response {}, headers:", response.status);
        if log_enabled!(log::INFO) {
            for header in response.headers.iter() {
                info!(" - {}", header);
            }
        }

        if let Some(&SetCookie(ref cookies)) = response.headers.get::<SetCookie>() {
            cookies_chan.send(ControlMsg::SetCookies(cookies.clone(), url.clone(),
                                                     CookieSource::HTTP));
        }

        if response.status.class() == StatusClass::Redirection {
            match response.headers.get::<Location>() {
                Some(&Location(ref new_url)) => {
                    // CORS (http://fetch.spec.whatwg.org/#http-fetch, status section, point 9, 10)
                    match load_data.cors {
                        Some(ref c) => {
                            if c.preflight {
                                // The preflight lied
                                send_error(url, "Preflight fetch inconsistent with main fetch".to_string(), senders);
                                return;
                            } else {
                                // XXXManishearth There are some CORS-related steps here,
                                // but they don't seem necessary until credentials are implemented
                            }
                        }
                        _ => {}
                    }
                    let new_url = match UrlParser::new().base_url(&url).parse(new_url.as_slice()) {
                        Ok(u) => u,
                        Err(e) => {
                            send_error(url, e.to_string(), senders);
                            return;
                        }
                    };
                    info!("redirecting to {}", new_url);
                    url = new_url;

                    // According to https://tools.ietf.org/html/rfc7231#section-6.4.2,
                    // historically UAs have rewritten POST->GET on 301 and 302 responses.
                    if load_data.method == Method::Post &&
                        (response.status == StatusCode::MovedPermanently ||
                         response.status == StatusCode::Found) {
                        load_data.method = Method::Get;
                    }

                    if redirected_to.contains(&url) {
                        send_error(url, "redirect loop".to_string(), senders);
                        return;
                    }

                    redirected_to.insert(url.clone());
                    continue;
                }
                None => ()
            }
        }

        let mut metadata = Metadata::default(url);
        metadata.set_content_type(match response.headers.get() {
            Some(&ContentType(ref mime)) => Some(mime),
            None => None
        });
        metadata.headers = Some(response.headers.clone());
        metadata.status = Some(response.status_raw().clone());

        let progress_chan = match start_sending_opt(senders, metadata) {
            Ok(p) => p,
            _ => return
        };
        loop {
            let mut buf = Vec::with_capacity(1024);

            unsafe { buf.set_len(1024); }
            match response.read(buf.as_mut_slice()) {
                Ok(len) => {
                    unsafe { buf.set_len(len); }
                    if progress_chan.send(Payload(buf)).is_err() {
                        // The send errors when the receiver is out of scope,
                        // which will happen if the fetch has timed out (or has been aborted)
                        // so we don't need to continue with the loading of the file here.
                        return;
                    }
                }
                Err(_) => {
                    let _ = progress_chan.send(Done(Ok(())));
                    break;
                }
            }
        }

        // We didn't get redirected.
        break;
    }
}
<|endoftext|>