<commit_before>use std::collections::{HashSet, HashMap};
use std::io::{BufReader, BufRead};
use std::str::FromStr;
use std::fs::File;
use std::cmp;
use rand::Rng;
use tar::Archive;
use spiral::Spiral;
use dfa::{Dfa, DfaState};
use player::Player;
use cell::Cell;
use field::{Pos, Field};

#[derive(Clone, Debug)]
struct Move {
  x: u32,
  y: u32,
  p: f64 // probability
}

struct Pattern {
  p: f64, // priority
  width: u32,
  height: u32,
  moves: Vec<Move>
}

pub struct Patterns {
  min_size: u32,
  dfa: Dfa,
  patterns: Vec<Pattern>
}

impl Patterns {
  pub fn empty() -> Patterns {
    Patterns {
      min_size: u32::max_value(),
      dfa: Dfa::empty(),
      patterns: Vec::with_capacity(0)
    }
  }

  fn read_header<T: BufRead>(input: &mut T, s: &mut String) -> (u32, u32, u32, f64) {
    s.clear();
    input.read_line(s).ok();
    s.pop();
    let mut split = s.split(' ').fuse();
    let width = u32::from_str(split.next().expect("Invalid pattern format: expected width.")).expect("Invalid pattern format: width must be u32."); //TODO: validate all this.
    let height = u32::from_str(split.next().expect("Invalid pattern format: expected height.")).expect("Invalid pattern format: height must be u32.");
    let moves_count = u32::from_str(split.next().expect("Invalid pattern format: expected moves count.")).expect("Invalid pattern format: moves count must be u32.");
    let priority = f64::from_str(split.next().expect("Invalid pattern format: expected priority.")).expect("Invalid pattern format: priority must be f64.");
    (width, height, moves_count, priority)
  }

  fn read_pattern<T: BufRead>(input: &mut T, s: &mut String, width: u32, height: u32) {
    s.clear();
    for y in 0 .. height {
      input.read_line(s).ok(); //TODO: check sizes.
      s.pop();
    }
  }

  fn read_moves<T: BufRead>(input: &mut T, s: &mut String, moves_count: u32) -> Vec<Move> {
    let mut moves = Vec::with_capacity(moves_count as usize);
    let mut priorities_sum = 0f64;
    for _ in 0 .. moves_count {
      s.clear();
      input.read_line(s).ok();
      s.pop();
      let mut split = s.split(' ').fuse();
      let x = u32::from_str(split.next().expect("Invalid pattern format: expected x coordinate.")).expect("Invalid pattern format: x coordinate must be u32.");
      let y = u32::from_str(split.next().expect("Invalid pattern format: expected x coordinate.")).expect("Invalid pattern format: x coordinate must be u32.");
      let p = f64::from_str(split.next().expect("Invalid pattern format: expected probability.")).expect("Invalid pattern format: probability must be f64.");
      priorities_sum += p;
      moves.push(Move {
        x: x,
        y: y,
        p: p
      });
    }
    for m in &mut moves {
      m.p /= priorities_sum;
    }
    moves
  }

  fn covering_spiral_length(side_of_square: u32) -> u32 {
    let x = side_of_square / 2 + 1;
    let y = (1 - side_of_square % 2) * side_of_square * 2;
    (8 * x - 13) * x + 6 - y
  }

  fn rotate(width: u32, height: u32, x: i32, y: i32, rotation: u32) -> (i32, i32) {
    match rotation {
      0 => (x, y),
      1 => (width as i32 - x - 1, y),
      2 => (x, height as i32 - y - 1),
      3 => (width as i32 - x - 1, height as i32 - y - 1),
      4 => (y, x),
      5 => (height as i32 - y - 1, x),
      6 => (y, width as i32 - x - 1),
      7 => (height as i32 - y - 1, width as i32 - x - 1),
      r => panic!("Invalid rotation number: {}", r)
    }
  }

  fn build_dfa(width: u32, height: u32, pattern: usize, rotation: u32, s: &str) -> Dfa {
    let center_x = (width - 1) / 2;
    let center_y = (height - 1) / 2;
    let spiral_length = Patterns::covering_spiral_length(cmp::max(width, height)) as usize;
    let mut states = Vec::with_capacity(spiral_length + 2);
    let fs = spiral_length; // "Found" state.
    let nfs = spiral_length + 1; // "Not found" state.
    for (i, (shift_x, shift_y)) in Spiral::new().into_iter().take(spiral_length).enumerate() {
      let nxt = i + 1;
      let (x, y) = Patterns::rotate(width, height, center_x as i32 + shift_x, center_y as i32 + shift_y, rotation);
      let state = if x >= 0 && x < width as i32 && y >= 0 && y < height as i32 {
        let pos = y as u32 * width + x as u32;
        match s.char_at(pos as usize) {
          '.' => DfaState::new(nxt, nfs, nfs, nfs, false, HashSet::with_capacity(0)),
          '?' => DfaState::new(nxt, nxt, nxt, nfs, false, HashSet::with_capacity(0)),
          '*' => DfaState::new(nxt, nxt, nxt, nxt, false, HashSet::with_capacity(0)),
          'R' => DfaState::new(nfs, nxt, nfs, nfs, false, HashSet::with_capacity(0)),
          'B' => DfaState::new(nfs, nfs, nxt, nfs, false, HashSet::with_capacity(0)),
          'r' => DfaState::new(nxt, nxt, nfs, nfs, false, HashSet::with_capacity(0)),
          'b' => DfaState::new(nxt, nfs, nxt, nfs, false, HashSet::with_capacity(0)),
          '#' => DfaState::new(nfs, nfs, nfs, nxt, false, HashSet::with_capacity(0)),
          c   => panic!("Invalid character in pattern: {}", c)
        }
      } else {
        DfaState::new(nxt, nxt, nxt, nxt, false, HashSet::with_capacity(0))
      };
      states.push(state);
    }
    let mut patterns = HashSet::with_capacity(1);
    patterns.insert(pattern);
    states.push(DfaState::new(fs, fs, fs, fs, true, patterns));
    states.push(DfaState::new(nfs, nfs, nfs, nfs, true, HashSet::with_capacity(0)));
    Dfa::new(states)
  }

  pub fn load(file: File) -> Patterns {
    let archive = Archive::new(file);
    let mut s = String::new();
    let mut pattern_s = String::new();
    let mut patterns = Vec::new();
    let iter = archive.files().expect("Reading of tar archive is failed.").into_iter().map(|file| file.expect("Reading of file in tar archive is failed."));
    let mut dfa = Dfa::empty();
    let mut min_size = u32::max_value();
    for file in iter {
      let mut input = BufReader::new(file);
      let (width, height, moves_count, priority) = Patterns::read_header(&mut input, &mut s);
      if width < min_size {
        min_size = width;
      }
      if height < min_size {
        min_size = height;
      }
      Patterns::read_pattern(&mut input, &mut pattern_s, width, height);
      let moves = Patterns::read_moves(&mut input, &mut s, moves_count);
      for i in 0 .. 8 {
        let cur_dfa = Patterns::build_dfa(width, height, patterns.len(), i, &pattern_s);
        dfa = dfa.product(&cur_dfa);
        patterns.push(Pattern {
          p: priority,
          width: width,
          height: height,
          moves: moves.iter().map(|m| {
            let (x, y) = Patterns::rotate(width, height, m.x as i32, m.y as i32, i);
            Move {
              x: x as u32,
              y: y as u32,
              p: m.p
            }
          }).collect()
        });
      }
    }
    Patterns {
      min_size: min_size,
      dfa: dfa,
      patterns: patterns
    }
  }

  pub fn find(&self, field: &Field, player: Player, first_match: bool) -> Vec<(Pos, f64)> {
    if self.dfa.is_empty() {
      return Vec::with_capacity(0);
    }
    let mut priorities_sum = 0f64;
    let mut moves_count = 0usize;
    let mut matched = Vec::new();
    let left_border = (self.min_size - 1) / 2;
    let right_border = self.min_size / 2;
    let inv_color = player == Player::Black;
    for y in left_border .. field.height() - right_border {
      for x in left_border .. field.width() - right_border {
        let patterns = self.dfa.run(&mut Spiral::new().into_iter().map(|(shift_x, shift_y)| {
          let cur_x = x as i32 + shift_x;
          let cur_y = y as i32 + shift_y;
          if cur_x >= 0 && cur_x < field.width() as i32 && cur_y >= 0 && cur_y < field.height() as i32 {
            let pos = field.to_pos(cur_x as u32, cur_y as u32);
            field.cell(pos)
          } else {
            Cell::new(true)
          }
        }), inv_color, first_match);
        for &pattern_number in patterns {
          let pattern = &self.patterns[pattern_number];
          priorities_sum += pattern.p;
          moves_count += pattern.moves.len();
          matched.push((pattern_number, x, y));
        }
      }
    }
    let mut result = Vec::with_capacity(moves_count);
    for (pattern_number, center_x, center_y) in matched {
      let pattern = &self.patterns[pattern_number];
      for &Move { x, y, p: probability } in &pattern.moves {
        let move_x = center_x - (pattern.width - 1) / 2 + x;
        let move_y = center_y - (pattern.height - 1) / 2 + y;
        result.push((field.to_pos(move_x, move_y), probability * pattern.p / priorities_sum));
      }
    }
    result
  }

  pub fn find_sorted(&self, field: &Field, player: Player, first_match: bool) -> Vec<(Pos, f64)> {
    let moves = self.find(field, player, first_match);
    let mut map = HashMap::with_capacity(moves.len());
    for (pos, p) in moves {
      let sum_p = map.get(&pos).cloned().unwrap_or(0f64) + p;
      map.insert(pos, sum_p);
    }
    let mut result = map.into_iter().collect::<Vec<(Pos, f64)>>();
    result.sort_by(|&(_, a), &(_, b)| b.partial_cmp(&a).expect("Cann't compare f64 types."));
    result
  }

  pub fn find_foreground(&self, field: &Field, player: Player, first_match: bool) -> Option<Pos> {
    self.find_sorted(field, player, first_match).first().map(|&(pos, _)| pos)
  }

  pub fn find_rand<T: Rng>(&self, field: &Field, player: Player, first_match: bool, rng: &mut T) -> Option<Pos> {
    let moves = self.find_sorted(field, player, first_match);
    if moves.is_empty() {
      return None;
    }
    let rand = rng.gen();
    let mut sum = 0f64;
    let mut idx = 0;
    while sum < rand && idx < moves.len() {
      sum += moves[idx].1;
      idx += 1;
    }
    Some(moves[idx - 1].0)
  }
}
<commit_msg>Fix warnings.<commit_after>use std::collections::{HashSet, HashMap};
use std::io::{BufReader, BufRead};
use std::str::FromStr;
use std::fs::File;
use std::cmp;
use rand::Rng;
use tar::Archive;
use spiral::Spiral;
use dfa::{Dfa, DfaState};
use player::Player;
use cell::Cell;
use field::{Pos, Field};

#[derive(Clone, Debug)]
struct Move {
  x: u32,
  y: u32,
  p: f64 // probability
}

struct Pattern {
  p: f64, // priority
  width: u32,
  height: u32,
  moves: Vec<Move>
}

pub struct Patterns {
  min_size: u32,
  dfa: Dfa,
  patterns: Vec<Pattern>
}

impl Patterns {
  pub fn empty() -> Patterns {
    Patterns {
      min_size: u32::max_value(),
      dfa: Dfa::empty(),
      patterns: Vec::with_capacity(0)
    }
  }

  fn read_header<T: BufRead>(input: &mut T, s: &mut String) -> (u32, u32, u32, f64) {
    s.clear();
    input.read_line(s).ok();
    s.pop();
    let mut split = s.split(' ').fuse();
    let width = u32::from_str(split.next().expect("Invalid pattern format: expected width.")).expect("Invalid pattern format: width must be u32."); //TODO: validate all this.
    let height = u32::from_str(split.next().expect("Invalid pattern format: expected height.")).expect("Invalid pattern format: height must be u32.");
    let moves_count = u32::from_str(split.next().expect("Invalid pattern format: expected moves count.")).expect("Invalid pattern format: moves count must be u32.");
    let priority = f64::from_str(split.next().expect("Invalid pattern format: expected priority.")).expect("Invalid pattern format: priority must be f64.");
    (width, height, moves_count, priority)
  }

  fn read_pattern<T: BufRead>(input: &mut T, s: &mut String, width: u32, height: u32) {
    s.clear();
    for _ in 0 .. height {
      let last_len = s.len();
      input.read_line(s).ok();
      s.pop();
      assert_eq!((s.len() - last_len) as u32, width)
    }
  }

  fn read_moves<T: BufRead>(input: &mut T, s: &mut String, moves_count: u32) -> Vec<Move> {
    let mut moves = Vec::with_capacity(moves_count as usize);
    let mut priorities_sum = 0f64;
    for _ in 0 .. moves_count {
      s.clear();
      input.read_line(s).ok();
      s.pop();
      let mut split = s.split(' ').fuse();
      let x = u32::from_str(split.next().expect("Invalid pattern format: expected x coordinate.")).expect("Invalid pattern format: x coordinate must be u32.");
      let y = u32::from_str(split.next().expect("Invalid pattern format: expected x coordinate.")).expect("Invalid pattern format: x coordinate must be u32.");
      let p = f64::from_str(split.next().expect("Invalid pattern format: expected probability.")).expect("Invalid pattern format: probability must be f64.");
      priorities_sum += p;
      moves.push(Move {
        x: x,
        y: y,
        p: p
      });
    }
    for m in &mut moves {
      m.p /= priorities_sum;
    }
    moves
  }

  fn covering_spiral_length(side_of_square: u32) -> u32 {
    let x = side_of_square / 2 + 1;
    let y = (1 - side_of_square % 2) * side_of_square * 2;
    (8 * x - 13) * x + 6 - y
  }

  fn rotate(width: u32, height: u32, x: i32, y: i32, rotation: u32) -> (i32, i32) {
    match rotation {
      0 => (x, y),
      1 => (width as i32 - x - 1, y),
      2 => (x, height as i32 - y - 1),
      3 => (width as i32 - x - 1, height as i32 - y - 1),
      4 => (y, x),
      5 => (height as i32 - y - 1, x),
      6 => (y, width as i32 - x - 1),
      7 => (height as i32 - y - 1, width as i32 - x - 1),
      r => panic!("Invalid rotation number: {}", r)
    }
  }

  fn build_dfa(width: u32, height: u32, pattern: usize, rotation: u32, s: &str) -> Dfa {
    let center_x = (width - 1) / 2;
    let center_y = (height - 1) / 2;
    let spiral_length = Patterns::covering_spiral_length(cmp::max(width, height)) as usize;
    let mut states = Vec::with_capacity(spiral_length + 2);
    let fs = spiral_length; // "Found" state.
    let nfs = spiral_length + 1; // "Not found" state.
    for (i, (shift_x, shift_y)) in Spiral::new().into_iter().take(spiral_length).enumerate() {
      let nxt = i + 1;
      let (x, y) = Patterns::rotate(width, height, center_x as i32 + shift_x, center_y as i32 + shift_y, rotation);
      let state = if x >= 0 && x < width as i32 && y >= 0 && y < height as i32 {
        let pos = y as u32 * width + x as u32;
        match s.char_at(pos as usize) {
          '.' => DfaState::new(nxt, nfs, nfs, nfs, false, HashSet::with_capacity(0)),
          '?' => DfaState::new(nxt, nxt, nxt, nfs, false, HashSet::with_capacity(0)),
          '*' => DfaState::new(nxt, nxt, nxt, nxt, false, HashSet::with_capacity(0)),
          'R' => DfaState::new(nfs, nxt, nfs, nfs, false, HashSet::with_capacity(0)),
          'B' => DfaState::new(nfs, nfs, nxt, nfs, false, HashSet::with_capacity(0)),
          'r' => DfaState::new(nxt, nxt, nfs, nfs, false, HashSet::with_capacity(0)),
          'b' => DfaState::new(nxt, nfs, nxt, nfs, false, HashSet::with_capacity(0)),
          '#' => DfaState::new(nfs, nfs, nfs, nxt, false, HashSet::with_capacity(0)),
          c   => panic!("Invalid character in pattern: {}", c)
        }
      } else {
        DfaState::new(nxt, nxt, nxt, nxt, false, HashSet::with_capacity(0))
      };
      states.push(state);
    }
    let mut patterns = HashSet::with_capacity(1);
    patterns.insert(pattern);
    states.push(DfaState::new(fs, fs, fs, fs, true, patterns));
    states.push(DfaState::new(nfs, nfs, nfs, nfs, true, HashSet::with_capacity(0)));
    Dfa::new(states)
  }

  pub fn load(file: File) -> Patterns {
    let archive = Archive::new(file);
    let mut s = String::new();
    let mut pattern_s = String::new();
    let mut patterns = Vec::new();
    let iter = archive.files().expect("Reading of tar archive is failed.").into_iter().map(|file| file.expect("Reading of file in tar archive is failed."));
    let mut dfa = Dfa::empty();
    let mut min_size = u32::max_value();
    for file in iter {
      let mut input = BufReader::new(file);
      let (width, height, moves_count, priority) = Patterns::read_header(&mut input, &mut s);
      if width < min_size {
        min_size = width;
      }
      if height < min_size {
        min_size = height;
      }
      Patterns::read_pattern(&mut input, &mut pattern_s, width, height);
      let moves = Patterns::read_moves(&mut input, &mut s, moves_count);
      for i in 0 .. 8 {
        let cur_dfa = Patterns::build_dfa(width, height, patterns.len(), i, &pattern_s);
        dfa = dfa.product(&cur_dfa);
        patterns.push(Pattern {
          p: priority,
          width: width,
          height: height,
          moves: moves.iter().map(|m| {
            let (x, y) = Patterns::rotate(width, height, m.x as i32, m.y as i32, i);
            Move {
              x: x as u32,
              y: y as u32,
              p: m.p
            }
          }).collect()
        });
      }
    }
    Patterns {
      min_size: min_size,
      dfa: dfa,
      patterns: patterns
    }
  }

  pub fn find(&self, field: &Field, player: Player, first_match: bool) -> Vec<(Pos, f64)> {
    if self.dfa.is_empty() {
      return Vec::with_capacity(0);
    }
    let mut priorities_sum = 0f64;
    let mut moves_count = 0usize;
    let mut matched = Vec::new();
    let left_border = (self.min_size - 1) / 2;
    let right_border = self.min_size / 2;
    let inv_color = player == Player::Black;
    for y in left_border .. field.height() - right_border {
      for x in left_border .. field.width() - right_border {
        let patterns = self.dfa.run(&mut Spiral::new().into_iter().map(|(shift_x, shift_y)| {
          let cur_x = x as i32 + shift_x;
          let cur_y = y as i32 + shift_y;
          if cur_x >= 0 && cur_x < field.width() as i32 && cur_y >= 0 && cur_y < field.height() as i32 {
            let pos = field.to_pos(cur_x as u32, cur_y as u32);
            field.cell(pos)
          } else {
            Cell::new(true)
          }
        }), inv_color, first_match);
        for &pattern_number in patterns {
          let pattern = &self.patterns[pattern_number];
          priorities_sum += pattern.p;
          moves_count += pattern.moves.len();
          matched.push((pattern_number, x, y));
        }
      }
    }
    let mut result = Vec::with_capacity(moves_count);
    for (pattern_number, center_x, center_y) in matched {
      let pattern = &self.patterns[pattern_number];
      for &Move { x, y, p: probability } in &pattern.moves {
        let move_x = center_x - (pattern.width - 1) / 2 + x;
        let move_y = center_y - (pattern.height - 1) / 2 + y;
        result.push((field.to_pos(move_x, move_y), probability * pattern.p / priorities_sum));
      }
    }
    result
  }

  pub fn find_sorted(&self, field: &Field, player: Player, first_match: bool) -> Vec<(Pos, f64)> {
    let moves = self.find(field, player, first_match);
    let mut map = HashMap::with_capacity(moves.len());
    for (pos, p) in moves {
      let sum_p = map.get(&pos).cloned().unwrap_or(0f64) + p;
      map.insert(pos, sum_p);
    }
    let mut result = map.into_iter().collect::<Vec<(Pos, f64)>>();
    result.sort_by(|&(_, a), &(_, b)| b.partial_cmp(&a).expect("Cann't compare f64 types."));
    result
  }

  pub fn find_foreground(&self, field: &Field, player: Player, first_match: bool) -> Option<Pos> {
    self.find_sorted(field, player, first_match).first().map(|&(pos, _)| pos)
  }

  pub fn find_rand<T: Rng>(&self, field: &Field, player: Player, first_match: bool, rng: &mut T) -> Option<Pos> {
    let moves = self.find_sorted(field, player, first_match);
    if moves.is_empty() {
      return None;
    }
    let rand = rng.gen();
    let mut sum = 0f64;
    let mut idx = 0;
    while sum < rand && idx < moves.len() {
      sum += moves[idx].1;
      idx += 1;
    }
    Some(moves[idx - 1].0)
  }
}
<|endoftext|>


<commit_before>//! Super fast HTML template engine.

#![allow(unstable)]

use std::fmt;
use std::fmt::Writer as FmtWriter;
use std::io::{IoError, IoErrorKind, IoResult};

pub type FmtResult<T> = Result<T, fmt::Error>;

/// Escape an HTML value.
pub fn escape(s: &str) -> String {
    let mut buf = String::new();
    rt::escape(&mut buf, |w| w.write_str(s)).unwrap();
    buf
}

/// A block of HTML markup, as returned by the `html!` macro.
pub struct Markup<'a, 'b: 'a> {
    callback: &'a (Fn(&mut FmtWriter) -> FmtResult<()> + 'b),
}

impl<'a, 'b> Markup<'a, 'b> {
    /// Render the markup to a `String`.
    pub fn render(&self) -> String {
        let mut buf = String::new();
        self.render_fmt(&mut buf).unwrap();
        buf
    }

    /// Render the markup to a `std::io::Writer`.
    pub fn render_to(&self, w: &mut Writer) -> IoResult<()> {
        struct WriterWrapper<'a, 'b: 'a> {
            inner: &'a mut (Writer + 'b),
        }
        impl<'a, 'b> FmtWriter for WriterWrapper<'a, 'b> {
            fn write_str(&mut self, s: &str) -> FmtResult<()> {
                self.inner.write_str(s).map_err(|_| fmt::Error)
            }
        }
        self.render_fmt(&mut WriterWrapper { inner: w })
            .map_err(|_| IoError {
                kind: IoErrorKind::OtherIoError,
                desc: "formatting error",
                detail: None,
            })
    }

    /// Render the markup to a `std::fmt::Writer`.
    pub fn render_fmt(&self, w: &mut FmtWriter) -> FmtResult<()> {
        (self.callback)(w)
    }
}

/// Internal functions used by the `maud_macros` package. You should
/// never need to call these directly.
#[experimental = "These functions should not be called directly.
Use the macros in `maud_macros` instead."]
pub mod rt {
    use std::fmt::Writer as FmtWriter;
    use super::{FmtResult, Markup};

    #[inline]
    pub fn make_markup<'a, 'b>(f: &'a (Fn(&mut FmtWriter) -> FmtResult<()> + 'b)) -> Markup<'a, 'b> {
        Markup { callback: f }
    }

    struct Escaper<'a, 'b: 'a> {
        inner: &'a mut (FmtWriter + 'b),
    }

    impl<'a, 'b> FmtWriter for Escaper<'a, 'b> {
        fn write_str(&mut self, s: &str) -> FmtResult<()> {
            for c in s.chars() {
                try!(match c {
                    '&' => self.inner.write_str("&"),
                    '<' => self.inner.write_str("<"),
                    '>' => self.inner.write_str(">"),
                    '"' => self.inner.write_str("""),
                    '\'' => self.inner.write_str("'"),
                    _ => write!(self.inner, "{}", c),
                });
            }
            Ok(())
        }
    }

    #[inline]
    pub fn escape<F>(w: &mut FmtWriter, f: F) -> FmtResult<()> where
        F: FnOnce(&mut FmtWriter) -> FmtResult<()>
    {
        f(&mut Escaper { inner: w })
    }
}
<commit_msg>Refer to std::fmt types directly instead of using aliases<commit_after>//! Super fast HTML template engine.

#![allow(unstable)]

use std::fmt;
use std::io::{IoError, IoErrorKind, IoResult};

/// Escape an HTML value.
pub fn escape(s: &str) -> String {
    let mut buf = String::new();
    rt::escape(&mut buf, |w| w.write_str(s)).unwrap();
    buf
}

/// A block of HTML markup, as returned by the `html!` macro.
pub struct Markup<'a, 'b: 'a> {
    callback: &'a (Fn(&mut fmt::Writer) -> fmt::Result + 'b),
}

impl<'a, 'b> Markup<'a, 'b> {
    /// Render the markup to a `String`.
    pub fn render(&self) -> String {
        let mut buf = String::new();
        self.render_fmt(&mut buf).unwrap();
        buf
    }

    /// Render the markup to a `std::io::Writer`.
    pub fn render_to(&self, w: &mut Writer) -> IoResult<()> {
        struct WriterWrapper<'a, 'b: 'a> {
            inner: &'a mut (Writer + 'b),
        }
        impl<'a, 'b> fmt::Writer for WriterWrapper<'a, 'b> {
            fn write_str(&mut self, s: &str) -> fmt::Result {
                self.inner.write_str(s).map_err(|_| fmt::Error)
            }
        }
        self.render_fmt(&mut WriterWrapper { inner: w })
            .map_err(|_| IoError {
                kind: IoErrorKind::OtherIoError,
                desc: "formatting error",
                detail: None,
            })
    }

    /// Render the markup to a `std::fmt::Writer`.
    pub fn render_fmt(&self, w: &mut fmt::Writer) -> fmt::Result {
        (self.callback)(w)
    }
}

/// Internal functions used by the `maud_macros` package. You should
/// never need to call these directly.
#[experimental = "These functions should not be called directly.
Use the macros in `maud_macros` instead."]
pub mod rt {
    use std::fmt;
    use super::Markup;

    #[inline]
    pub fn make_markup<'a, 'b>(f: &'a (Fn(&mut fmt::Writer) -> fmt::Result + 'b)) -> Markup<'a, 'b> {
        Markup { callback: f }
    }

    struct Escaper<'a, 'b: 'a> {
        inner: &'a mut (fmt::Writer + 'b),
    }

    impl<'a, 'b> fmt::Writer for Escaper<'a, 'b> {
        fn write_str(&mut self, s: &str) -> fmt::Result {
            for c in s.chars() {
                try!(match c {
                    '&' => self.inner.write_str("&"),
                    '<' => self.inner.write_str("<"),
                    '>' => self.inner.write_str(">"),
                    '"' => self.inner.write_str("""),
                    '\'' => self.inner.write_str("'"),
                    _ => write!(self.inner, "{}", c),
                });
            }
            Ok(())
        }
    }

    #[inline]
    pub fn escape<F>(w: &mut fmt::Writer, f: F) -> fmt::Result where
        F: FnOnce(&mut fmt::Writer) -> fmt::Result
    {
        f(&mut Escaper { inner: w })
    }
}
<|endoftext|>


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

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

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

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

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

            Pointer(PointerCast::ReifyFnPointer) => {
                // The src operand does not matter, just its type
                match src.layout.ty.kind {
                    ty::FnDef(def_id, substs) => {
                        // All reifications must be monomorphic, bail out otherwise.
                        if src.layout.ty.needs_subst() {
                            throw_inval!(TooGeneric);
                        }

                        if self.tcx.has_attr(def_id, sym::rustc_args_required_const) {
                            bug!("reifying a fn ptr that requires const arguments");
                        }
                        let instance = self.resolve(def_id, substs)?;
                        let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
                        self.write_scalar(Scalar::Ptr(fn_ptr.into()), dest)?;
                    }
                    _ => bug!("reify fn pointer on {:?}", src.layout.ty),
                }
            }

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

            Pointer(PointerCast::ClosureFnPointer(_)) => {
                // The src operand does not matter, just its type
                match src.layout.ty.kind {
                    ty::Closure(def_id, substs) => {
                        // All reifications must be monomorphic, bail out otherwise.
                        if src.layout.ty.needs_subst() {
                            throw_inval!(TooGeneric);
                        }

                        let instance = ty::Instance::resolve_closure(
                            *self.tcx,
                            def_id,
                            substs,
                            ty::ClosureKind::FnOnce,
                        );
                        let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
                        let val = Immediate::Scalar(Scalar::Ptr(fn_ptr.into()).into());
                        self.write_immediate(val, dest)?;
                    }
                    _ => bug!("closure fn pointer on {:?}", src.layout.ty),
                }
            }
        }
        Ok(())
    }

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

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

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

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

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

        // For all remaining casts, we either
        // (a) cast a raw ptr to usize, or
        // (b) cast from an integer-like (including bool, char, enums).
        // In both cases we want the bits.
        let bits = self.force_bits(src.to_scalar()?, src.layout.size)?;
        Ok(self.cast_from_int(bits, src.layout, dest_layout)?.into())
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            Pointer(PointerCast::ReifyFnPointer) => {
                // The src operand does not matter, just its type
                match src.layout.ty.kind {
                    ty::FnDef(def_id, substs) => {
                        // All reifications must be monomorphic, bail out otherwise.
                        if src.layout.ty.needs_subst() {
                            throw_inval!(TooGeneric);
                        }

                        if self.tcx.has_attr(def_id, sym::rustc_args_required_const) {
                            bug!("reifying a fn ptr that requires const arguments");
                        }

                        let instance = ty::Instance::resolve_for_fn_ptr(
                            *self.tcx,
                            self.param_env,
                            def_id,
                            substs,
                        ).ok_or_else(|| err_inval!(TooGeneric))?;

                        let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
                        self.write_scalar(Scalar::Ptr(fn_ptr.into()), dest)?;
                    }
                    _ => bug!("reify fn pointer on {:?}", src.layout.ty),
                }
            }

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

            Pointer(PointerCast::ClosureFnPointer(_)) => {
                // The src operand does not matter, just its type
                match src.layout.ty.kind {
                    ty::Closure(def_id, substs) => {
                        // All reifications must be monomorphic, bail out otherwise.
                        if src.layout.ty.needs_subst() {
                            throw_inval!(TooGeneric);
                        }

                        let instance = ty::Instance::resolve_closure(
                            *self.tcx,
                            def_id,
                            substs,
                            ty::ClosureKind::FnOnce,
                        );
                        let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
                        let val = Immediate::Scalar(Scalar::Ptr(fn_ptr.into()).into());
                        self.write_immediate(val, dest)?;
                    }
                    _ => bug!("closure fn pointer on {:?}", src.layout.ty),
                }
            }
        }
        Ok(())
    }

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

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

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

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

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

        // For all remaining casts, we either
        // (a) cast a raw ptr to usize, or
        // (b) cast from an integer-like (including bool, char, enums).
        // In both cases we want the bits.
        let bits = self.force_bits(src.to_scalar()?, src.layout.size)?;
        Ok(self.cast_from_int(bits, src.layout, dest_layout)?.into())
    }

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

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

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

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

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

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

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

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

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

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


<commit_before>use std::iter::repeat;
use std::io::{stdout, Write};
use std::ops::{AddAssign, SubAssign};
use terminal_size::{terminal_size, Height, Width};

/// Tracks progress of a task.
///
/// There should be not more than a single instance started at a given point in
/// time, it will mangle your terminal output.
pub struct Progress {
    current: usize,
    total: usize,

    caption: String,

    width: Option<u16>,

    started: bool,
}

impl Default for Progress {
    fn default() -> Progress {
        Progress::new("Progress", 0, 100)
    }
}

impl Progress {
    pub fn new<S: Into<String>>(caption: S, start: usize, end: usize) -> Self {
        Progress {
            current: start,
            total: end,
            caption: caption.into(),
            width: None,
            started: false,
        }
    }

    pub fn new_with_width<S>(caption: S, start: usize, end: usize, width: u16) -> Self
    where
        S: Into<String>,
    {
        Progress {
            current: start,
            total: end,
            caption: caption.into(),
            width: Some(width),
            started: false,
        }
    }

    /// Returns the current progress absolute value.
    ///
    /// # Example
    ///
    /// ```
    /// use progress::Progress;
    /// let p = Progress::default();
    /// assert_eq!(0, p.current());
    /// ```
    pub fn current(&self) -> usize {
        self.current
    }

    /// Returns the total value.
    ///
    /// # Example
    ///
    /// ```
    /// use progress::Progress;
    /// let p = Progress::default();
    /// assert_eq!(100, p.total());
    /// ```
    pub fn total(&self) -> usize {
        self.total
    }

    /// Advances the Progress by a certain amount.
    ///
    /// # Examplw
    ///
    /// ```
    /// use progress::Progress;
    /// let mut p = Progress::default();
    /// assert_eq!(0, p.current());
    /// p.forward(10);
    /// assert_eq!(10, p.current());
    /// p += 20;
    /// assert_eq!(30, p.current());
    /// ```
    pub fn forward(&mut self, step: usize) -> &Self {
        *self += step;
        self
    }

    /// Advances the Progress by a certain amount.
    ///
    /// # Examplw
    ///
    /// ```
    /// use progress::Builder;
    /// let mut p = Builder::new().set_start(30).build();
    /// assert_eq!(30, p.current());
    /// p.backward(10);
    /// assert_eq!(20, p.current());
    /// p -= 20;
    /// assert_eq!(0, p.current());
    /// ```
    pub fn backward(&mut self, step: usize) -> &Self {
        *self -= step;
        self
    }

    /// Advances the Progress by exactly one.
    pub fn increment(&mut self) -> &Self {
        self.forward(1)
    }

    /// Does a step backwards at the Progress.
    pub fn decrement(&mut self) -> &Self {
        self.backward(1)
    }

    /// Determines wheter a Progress has finished (reached the total) or not.
    pub fn finished(&self) -> bool {
        self.current >= self.total
    }

    /// Returns the relative value of the Progress.
    pub fn process(&self) -> u8 {
        (self.current * 100 / self.total) as u8
    }

    /// Activates the Progress.
    pub fn start(&mut self) -> &Self {
        self.started = true;
        self
    }

    /// Returns the current caption.
    pub fn caption(&self) -> &String {
        &self.caption
    }
}

impl AddAssign<usize> for Progress {
    fn add_assign(&mut self, step: usize) {
        let new = self.current + step;
        if new > self.total {
            self.current = self.total;
        } else {
            self.current += step;
        }
        print_bar(self);
    }
}

impl SubAssign<usize> for Progress {
    fn sub_assign(&mut self, step: usize) {
        self.current = self.current.saturating_sub(step);
        print_bar(self);
    }
}

fn print_bar(p: &Progress) {
    let p_info = format!(
        "{current} / {total} ({process})",
        current = p.current(),
        total = p.total(),
        process = p.process()
    );
    let caption = p.caption();

    let terminal_width = p.width
        .unwrap_or_else(|| terminal_size().unwrap_or((Width(79), Height(0))).0 .0); // terminal_size().unwrap_or((Width(79), Height(0)));

    let bar_width = terminal_width as usize // Width of terminal
        - p_info.len()  // Width of right summary
        - caption.len() // Width of caption
        - 3  // Colon and spaces
        - 2; // vertical bars in the progress meter
    let done_width = (bar_width * p.process() as usize) / 100;
    let todo_width = bar_width - done_width;
    let done_bar = repeat("#").take(done_width).collect::<String>();
    let todo_bar = repeat("-").take(todo_width).collect::<String>();
    let bar = format!("|{}{}|", done_bar, todo_bar);

    print!(
        "{caption}: {bar} {info}\r",
        caption = caption,
        bar = bar,
        info = p_info
    );
    stdout().flush().unwrap();
}
<commit_msg>micro-deoptimisations ;)<commit_after>use std::iter::repeat;
use std::io::{stdout, Write};
use std::ops::{AddAssign, SubAssign};
use terminal_size::{terminal_size, Height, Width};

/// Tracks progress of a task.
///
/// There should be not more than a single instance started at a given point in
/// time, it will mangle your terminal output.
pub struct Progress {
    current: usize,
    total: usize,

    caption: String,

    width: Option<u16>,

    started: bool,
}

impl Default for Progress {
    fn default() -> Progress {
        Progress::new("Progress", 0, 100)
    }
}

impl Progress {
    pub fn new<S: Into<String>>(caption: S, start: usize, end: usize) -> Self {
        Progress {
            current: start,
            total: end,
            caption: caption.into(),
            width: None,
            started: false,
        }
    }

    pub fn new_with_width<S>(caption: S, start: usize, end: usize, width: u16) -> Self
    where
        S: Into<String>,
    {
        Progress {
            current: start,
            total: end,
            caption: caption.into(),
            width: Some(width),
            started: false,
        }
    }

    /// Returns the current progress absolute value.
    ///
    /// # Example
    ///
    /// ```
    /// use progress::Progress;
    /// let p = Progress::default();
    /// assert_eq!(0, p.current());
    /// ```
    pub fn current(&self) -> usize {
        self.current
    }

    /// Returns the total value.
    ///
    /// # Example
    ///
    /// ```
    /// use progress::Progress;
    /// let p = Progress::default();
    /// assert_eq!(100, p.total());
    /// ```
    pub fn total(&self) -> usize {
        self.total
    }

    /// Advances the Progress by a certain amount.
    ///
    /// # Examplw
    ///
    /// ```
    /// use progress::Progress;
    /// let mut p = Progress::default();
    /// assert_eq!(0, p.current());
    /// p.forward(10);
    /// assert_eq!(10, p.current());
    /// p += 20;
    /// assert_eq!(30, p.current());
    /// ```
    pub fn forward(&mut self, step: usize) -> &Self {
        *self += step;
        self
    }

    /// Advances the Progress by a certain amount.
    ///
    /// # Examplw
    ///
    /// ```
    /// use progress::Builder;
    /// let mut p = Builder::new().set_start(30).build();
    /// assert_eq!(30, p.current());
    /// p.backward(10);
    /// assert_eq!(20, p.current());
    /// p -= 20;
    /// assert_eq!(0, p.current());
    /// ```
    pub fn backward(&mut self, step: usize) -> &Self {
        *self -= step;
        self
    }

    /// Advances the Progress by exactly one.
    pub fn increment(&mut self) -> &Self {
        self.forward(1)
    }

    /// Does a step backwards at the Progress.
    pub fn decrement(&mut self) -> &Self {
        self.backward(1)
    }

    /// Determines wheter a Progress has finished (reached the total) or not.
    pub fn finished(&self) -> bool {
        self.current >= self.total
    }

    /// Returns the relative value of the Progress.
    pub fn process(&self) -> u8 {
        (self.current * 100 / self.total) as u8
    }

    /// Activates the Progress.
    pub fn start(&mut self) -> &Self {
        self.started = true;
        self
    }

    /// Returns the current caption.
    pub fn caption(&self) -> &String {
        &self.caption
    }
}

impl AddAssign<usize> for Progress {
    fn add_assign(&mut self, step: usize) {
        let new = self.current + step;
        if new > self.total {
            self.current = self.total;
        } else {
            self.current += step;
        }
        print_bar(self);
    }
}

impl SubAssign<usize> for Progress {
    fn sub_assign(&mut self, step: usize) {
        self.current = self.current.saturating_sub(step);
        print_bar(self);
    }
}

fn print_bar(p: &Progress) {
    const COLONS: usize = 1;
    const SPACES: usize = 2;
    const PIPES: usize = 2;
    const OTHER: usize = COLONS + SPACES + PIPES;
    let p_info = format!(
        "{current} / {total} ({process})",
        current = p.current(),
        total = p.total(),
        process = p.process()
    );
    let caption = p.caption();

    let terminal_width = p.width
        .unwrap_or_else(|| terminal_size().unwrap_or((Width(79), Height(0))).0 .0);

    let bar_width = terminal_width as usize // Width of terminal
        - p_info.len()  // Width of right summary
        - caption.len() // Width of caption
        - OTHER;
    let done_width = (bar_width * p.process() as usize) / 100;
    let todo_width = bar_width - done_width;
    let done_bar = repeat('#').take(done_width).collect::<String>();
    let todo_bar = repeat('-').take(todo_width).collect::<String>();
    let bar = format!("|{}{}|", done_bar, todo_bar);

    print!(
        "{caption}: {bar} {info}\r",
        caption = caption,
        bar = bar,
        info = p_info
    );
    stdout().flush().unwrap();
}
<|endoftext|>


<commit_before>use crate::fs::OpenOptions;
use crate::io;
use crate::io::Result;
use crate::io::SeekFrom;
use crate::io::{BufRead, Read, Seek, Write};
use crate::os::unix::io::AsRawFd;
use crate::sys_common::io::test::tmpdir;

#[test]
fn copy_specialization() -> Result<()> {
    use crate::io::{BufReader, BufWriter};

    let tmp_path = tmpdir();
    let source_path = tmp_path.join("copy-spec.source");
    let sink_path = tmp_path.join("copy-spec.sink");

    let result: Result<()> = try {
        let mut source = crate::fs::OpenOptions::new()
            .read(true)
            .write(true)
            .create(true)
            .truncate(true)
            .open(&source_path)?;
        source.write_all(b"abcdefghiklmnopqr")?;
        source.seek(SeekFrom::Start(8))?;
        let mut source = BufReader::with_capacity(8, source.take(5));
        source.fill_buf()?;
        assert_eq!(source.buffer(), b"iklmn");
        source.get_mut().set_limit(6);
        source.get_mut().get_mut().seek(SeekFrom::Start(1))?; // "bcdefg"
        let mut source = source.take(10); // "iklmnbcdef"

        let mut sink = crate::fs::OpenOptions::new()
            .read(true)
            .write(true)
            .create(true)
            .truncate(true)
            .open(&sink_path)?;
        sink.write_all(b"000000")?;
        let mut sink = BufWriter::with_capacity(5, sink);
        sink.write_all(b"wxyz")?;
        assert_eq!(sink.buffer(), b"wxyz");

        let copied = crate::io::copy(&mut source, &mut sink)?;
        assert_eq!(copied, 10, "copy obeyed limit imposed by Take");
        assert_eq!(sink.buffer().len(), 0, "sink buffer was flushed");
        assert_eq!(source.limit(), 0, "outer Take was exhausted");
        assert_eq!(source.get_ref().buffer().len(), 0, "source buffer should be drained");
        assert_eq!(
            source.get_ref().get_ref().limit(),
            1,
            "inner Take allowed reading beyond end of file, some bytes should be left"
        );

        let mut sink = sink.into_inner()?;
        sink.seek(SeekFrom::Start(0))?;
        let mut copied = Vec::new();
        sink.read_to_end(&mut copied)?;
        assert_eq!(&copied, b"000000wxyziklmnbcdef");
    };

    let rm1 = crate::fs::remove_file(source_path);
    let rm2 = crate::fs::remove_file(sink_path);

    result.and(rm1).and(rm2)
}

#[bench]
fn bench_file_to_file_copy(b: &mut test::Bencher) {
    const BYTES: usize = 128 * 1024;
    let temp_path = tmpdir();
    let src_path = temp_path.join("file-copy-bench-src");
    let mut src = crate::fs::OpenOptions::new()
        .create(true)
        .truncate(true)
        .read(true)
        .write(true)
        .open(src_path)
        .unwrap();
    src.write(&vec![0u8; BYTES]).unwrap();

    let sink_path = temp_path.join("file-copy-bench-sink");
    let mut sink = crate::fs::OpenOptions::new()
        .create(true)
        .truncate(true)
        .write(true)
        .open(sink_path)
        .unwrap();

    b.bytes = BYTES as u64;
    b.iter(|| {
        src.seek(SeekFrom::Start(0)).unwrap();
        sink.seek(SeekFrom::Start(0)).unwrap();
        assert_eq!(BYTES as u64, io::copy(&mut src, &mut sink).unwrap());
    });
}

#[bench]
fn bench_file_to_socket_copy(b: &mut test::Bencher) {
    const BYTES: usize = 128 * 1024;
    let temp_path = tmpdir();
    let src_path = temp_path.join("pipe-copy-bench-src");
    let mut src = OpenOptions::new()
        .create(true)
        .truncate(true)
        .read(true)
        .write(true)
        .open(src_path)
        .unwrap();
    src.write(&vec![0u8; BYTES]).unwrap();

    let sink_drainer = crate::net::TcpListener::bind("localhost:0").unwrap();
    let mut sink = crate::net::TcpStream::connect(sink_drainer.local_addr().unwrap()).unwrap();
    let mut sink_drainer = sink_drainer.accept().unwrap().0;

    crate::thread::spawn(move || {
        let mut sink_buf = vec![0u8; 1024 * 1024];
        loop {
            sink_drainer.read(&mut sink_buf[..]).unwrap();
        }
    });

    b.bytes = BYTES as u64;
    b.iter(|| {
        src.seek(SeekFrom::Start(0)).unwrap();
        assert_eq!(BYTES as u64, io::copy(&mut src, &mut sink).unwrap());
    });
}

#[bench]
fn bench_file_to_uds_copy(b: &mut test::Bencher) {
    const BYTES: usize = 128 * 1024;
    let temp_path = tmpdir();
    let src_path = temp_path.join("uds-copy-bench-src");
    let mut src = OpenOptions::new()
        .create(true)
        .truncate(true)
        .read(true)
        .write(true)
        .open(src_path)
        .unwrap();
    src.write(&vec![0u8; BYTES]).unwrap();

    let (mut sink, mut sink_drainer) = crate::os::unix::net::UnixStream::pair().unwrap();

    crate::thread::spawn(move || {
        let mut sink_buf = vec![0u8; 1024 * 1024];
        loop {
            sink_drainer.read(&mut sink_buf[..]).unwrap();
        }
    });

    b.bytes = BYTES as u64;
    b.iter(|| {
        src.seek(SeekFrom::Start(0)).unwrap();
        assert_eq!(BYTES as u64, io::copy(&mut src, &mut sink).unwrap());
    });
}

#[cfg(any(target_os = "linux", target_os = "android"))]
#[bench]
fn bench_socket_pipe_socket_copy(b: &mut test::Bencher) {
    use super::CopyResult;
    use crate::io::ErrorKind;
    use crate::process::{ChildStdin, ChildStdout};
    use crate::sys_common::FromInner;

    let (read_end, write_end) = crate::sys::pipe::anon_pipe().unwrap();

    let mut read_end = ChildStdout::from_inner(read_end);
    let write_end = ChildStdin::from_inner(write_end);

    let acceptor = crate::net::TcpListener::bind("localhost:0").unwrap();
    let mut remote_end = crate::net::TcpStream::connect(acceptor.local_addr().unwrap()).unwrap();

    let local_end = crate::sync::Arc::new(acceptor.accept().unwrap().0);

    // the data flow in this benchmark:
    //
    //                      socket(tx)  local_source
    // remote_end (write)  +-------->   (splice to)
    //                                  write_end
    //                                     +
    //                                     |
    //                                     | pipe
    //                                     v
    //                                  read_end
    // remote_end (read)   <---------+  (splice to) *
    //                      socket(rx)  local_end
    //
    // * benchmark loop using io::copy

    crate::thread::spawn(move || {
        let mut sink_buf = vec![0u8; 1024 * 1024];
        remote_end.set_nonblocking(true).unwrap();
        loop {
            match remote_end.write(&mut sink_buf[..]) {
                Err(err) if err.kind() == ErrorKind::WouldBlock => {}
                Ok(_) => {}
                err => {
                    err.expect("write failed");
                }
            };
            match remote_end.read(&mut sink_buf[..]) {
                Err(err) if err.kind() == ErrorKind::WouldBlock => {}
                Ok(_) => {}
                err => {
                    err.expect("read failed");
                }
            };
        }
    });

    // check that splice works, otherwise the benchmark would hang
    let probe = super::sendfile_splice(
        super::SpliceMode::Splice,
        local_end.as_raw_fd(),
        write_end.as_raw_fd(),
        1,
    );

    match probe {
        CopyResult::Ended(1) => {
            // splice works
        }
        _ => {
            eprintln!("splice failed, skipping benchmark");
            return;
        }
    }

    let local_source = local_end.clone();
    crate::thread::spawn(move || {
        loop {
            super::sendfile_splice(
                super::SpliceMode::Splice,
                local_source.as_raw_fd(),
                write_end.as_raw_fd(),
                u64::MAX,
            );
        }
    });

    const BYTES: usize = 128 * 1024;
    b.bytes = BYTES as u64;
    b.iter(|| {
        assert_eq!(
            BYTES as u64,
            io::copy(&mut (&mut read_end).take(BYTES as u64), &mut &*local_end).unwrap()
        );
    });
}
<commit_msg>add test for failing io::copy specialization<commit_after>use crate::fs::OpenOptions;
use crate::io;
use crate::io::Result;
use crate::io::SeekFrom;
use crate::io::{BufRead, Read, Seek, Write};
use crate::os::unix::io::AsRawFd;
use crate::sys_common::io::test::tmpdir;

#[test]
fn copy_specialization() -> Result<()> {
    use crate::io::{BufReader, BufWriter};

    let tmp_path = tmpdir();
    let source_path = tmp_path.join("copy-spec.source");
    let sink_path = tmp_path.join("copy-spec.sink");

    let result: Result<()> = try {
        let mut source = crate::fs::OpenOptions::new()
            .read(true)
            .write(true)
            .create(true)
            .truncate(true)
            .open(&source_path)?;
        source.write_all(b"abcdefghiklmnopqr")?;
        source.seek(SeekFrom::Start(8))?;
        let mut source = BufReader::with_capacity(8, source.take(5));
        source.fill_buf()?;
        assert_eq!(source.buffer(), b"iklmn");
        source.get_mut().set_limit(6);
        source.get_mut().get_mut().seek(SeekFrom::Start(1))?; // "bcdefg"
        let mut source = source.take(10); // "iklmnbcdef"

        let mut sink = crate::fs::OpenOptions::new()
            .read(true)
            .write(true)
            .create(true)
            .truncate(true)
            .open(&sink_path)?;
        sink.write_all(b"000000")?;
        let mut sink = BufWriter::with_capacity(5, sink);
        sink.write_all(b"wxyz")?;
        assert_eq!(sink.buffer(), b"wxyz");

        let copied = crate::io::copy(&mut source, &mut sink)?;
        assert_eq!(copied, 10, "copy obeyed limit imposed by Take");
        assert_eq!(sink.buffer().len(), 0, "sink buffer was flushed");
        assert_eq!(source.limit(), 0, "outer Take was exhausted");
        assert_eq!(source.get_ref().buffer().len(), 0, "source buffer should be drained");
        assert_eq!(
            source.get_ref().get_ref().limit(),
            1,
            "inner Take allowed reading beyond end of file, some bytes should be left"
        );

        let mut sink = sink.into_inner()?;
        sink.seek(SeekFrom::Start(0))?;
        let mut copied = Vec::new();
        sink.read_to_end(&mut copied)?;
        assert_eq!(&copied, b"000000wxyziklmnbcdef");
    };

    let rm1 = crate::fs::remove_file(source_path);
    let rm2 = crate::fs::remove_file(sink_path);

    result.and(rm1).and(rm2)
}

#[test]
fn copies_append_mode_sink() -> Result<()> {
    let tmp_path = tmpdir();
    let source_path = tmp_path.join("copies_append_mode.source");
    let sink_path = tmp_path.join("copies_append_mode.sink");
    let mut source =
        OpenOptions::new().create(true).truncate(true).write(true).read(true).open(&source_path)?;
    write!(source, "not empty")?;
    source.seek(SeekFrom::Start(0))?;
    let mut sink = OpenOptions::new().create(true).append(true).open(&sink_path)?;

    let copied = crate::io::copy(&mut source, &mut sink)?;

    assert_eq!(copied, 9);

    Ok(())
}

#[bench]
fn bench_file_to_file_copy(b: &mut test::Bencher) {
    const BYTES: usize = 128 * 1024;
    let temp_path = tmpdir();
    let src_path = temp_path.join("file-copy-bench-src");
    let mut src = crate::fs::OpenOptions::new()
        .create(true)
        .truncate(true)
        .read(true)
        .write(true)
        .open(src_path)
        .unwrap();
    src.write(&vec![0u8; BYTES]).unwrap();

    let sink_path = temp_path.join("file-copy-bench-sink");
    let mut sink = crate::fs::OpenOptions::new()
        .create(true)
        .truncate(true)
        .write(true)
        .open(sink_path)
        .unwrap();

    b.bytes = BYTES as u64;
    b.iter(|| {
        src.seek(SeekFrom::Start(0)).unwrap();
        sink.seek(SeekFrom::Start(0)).unwrap();
        assert_eq!(BYTES as u64, io::copy(&mut src, &mut sink).unwrap());
    });
}

#[bench]
fn bench_file_to_socket_copy(b: &mut test::Bencher) {
    const BYTES: usize = 128 * 1024;
    let temp_path = tmpdir();
    let src_path = temp_path.join("pipe-copy-bench-src");
    let mut src = OpenOptions::new()
        .create(true)
        .truncate(true)
        .read(true)
        .write(true)
        .open(src_path)
        .unwrap();
    src.write(&vec![0u8; BYTES]).unwrap();

    let sink_drainer = crate::net::TcpListener::bind("localhost:0").unwrap();
    let mut sink = crate::net::TcpStream::connect(sink_drainer.local_addr().unwrap()).unwrap();
    let mut sink_drainer = sink_drainer.accept().unwrap().0;

    crate::thread::spawn(move || {
        let mut sink_buf = vec![0u8; 1024 * 1024];
        loop {
            sink_drainer.read(&mut sink_buf[..]).unwrap();
        }
    });

    b.bytes = BYTES as u64;
    b.iter(|| {
        src.seek(SeekFrom::Start(0)).unwrap();
        assert_eq!(BYTES as u64, io::copy(&mut src, &mut sink).unwrap());
    });
}

#[bench]
fn bench_file_to_uds_copy(b: &mut test::Bencher) {
    const BYTES: usize = 128 * 1024;
    let temp_path = tmpdir();
    let src_path = temp_path.join("uds-copy-bench-src");
    let mut src = OpenOptions::new()
        .create(true)
        .truncate(true)
        .read(true)
        .write(true)
        .open(src_path)
        .unwrap();
    src.write(&vec![0u8; BYTES]).unwrap();

    let (mut sink, mut sink_drainer) = crate::os::unix::net::UnixStream::pair().unwrap();

    crate::thread::spawn(move || {
        let mut sink_buf = vec![0u8; 1024 * 1024];
        loop {
            sink_drainer.read(&mut sink_buf[..]).unwrap();
        }
    });

    b.bytes = BYTES as u64;
    b.iter(|| {
        src.seek(SeekFrom::Start(0)).unwrap();
        assert_eq!(BYTES as u64, io::copy(&mut src, &mut sink).unwrap());
    });
}

#[cfg(any(target_os = "linux", target_os = "android"))]
#[bench]
fn bench_socket_pipe_socket_copy(b: &mut test::Bencher) {
    use super::CopyResult;
    use crate::io::ErrorKind;
    use crate::process::{ChildStdin, ChildStdout};
    use crate::sys_common::FromInner;

    let (read_end, write_end) = crate::sys::pipe::anon_pipe().unwrap();

    let mut read_end = ChildStdout::from_inner(read_end);
    let write_end = ChildStdin::from_inner(write_end);

    let acceptor = crate::net::TcpListener::bind("localhost:0").unwrap();
    let mut remote_end = crate::net::TcpStream::connect(acceptor.local_addr().unwrap()).unwrap();

    let local_end = crate::sync::Arc::new(acceptor.accept().unwrap().0);

    // the data flow in this benchmark:
    //
    //                      socket(tx)  local_source
    // remote_end (write)  +-------->   (splice to)
    //                                  write_end
    //                                     +
    //                                     |
    //                                     | pipe
    //                                     v
    //                                  read_end
    // remote_end (read)   <---------+  (splice to) *
    //                      socket(rx)  local_end
    //
    // * benchmark loop using io::copy

    crate::thread::spawn(move || {
        let mut sink_buf = vec![0u8; 1024 * 1024];
        remote_end.set_nonblocking(true).unwrap();
        loop {
            match remote_end.write(&mut sink_buf[..]) {
                Err(err) if err.kind() == ErrorKind::WouldBlock => {}
                Ok(_) => {}
                err => {
                    err.expect("write failed");
                }
            };
            match remote_end.read(&mut sink_buf[..]) {
                Err(err) if err.kind() == ErrorKind::WouldBlock => {}
                Ok(_) => {}
                err => {
                    err.expect("read failed");
                }
            };
        }
    });

    // check that splice works, otherwise the benchmark would hang
    let probe = super::sendfile_splice(
        super::SpliceMode::Splice,
        local_end.as_raw_fd(),
        write_end.as_raw_fd(),
        1,
    );

    match probe {
        CopyResult::Ended(1) => {
            // splice works
        }
        _ => {
            eprintln!("splice failed, skipping benchmark");
            return;
        }
    }

    let local_source = local_end.clone();
    crate::thread::spawn(move || {
        loop {
            super::sendfile_splice(
                super::SpliceMode::Splice,
                local_source.as_raw_fd(),
                write_end.as_raw_fd(),
                u64::MAX,
            );
        }
    });

    const BYTES: usize = 128 * 1024;
    b.bytes = BYTES as u64;
    b.iter(|| {
        assert_eq!(
            BYTES as u64,
            io::copy(&mut (&mut read_end).take(BYTES as u64), &mut &*local_end).unwrap()
        );
    });
}
<|endoftext|>


<commit_before>use std::ffi::CString;
use std::io;
use std::path::Path;
use std::marker::PhantomData;
use libc::{c_void, c_int, size_t, c_char};
use get_error;

use sys::rwops as ll;

/// A structure that provides an abstract interface to stream I/O.
pub struct RWops<'a> {
    raw: *mut ll::SDL_RWops,
    _marker: PhantomData<&'a ()>
}

impl<'a> RWops<'a> {
    pub unsafe fn raw(&self) -> *mut ll::SDL_RWops { self.raw }

    pub unsafe fn from_ll<'b>(raw: *mut ll::SDL_RWops) -> RWops<'b> {
        RWops {
            raw: raw,
            _marker: PhantomData
        }
    }

    /// Creates an SDL file stream.
    pub fn from_file<P: AsRef<Path>>(path: P, mode: &str) -> Result<RWops <'static>, String> {
        let raw = unsafe {
            let path_c = CString::new(path.as_ref().to_str().unwrap()).unwrap();
            let mode_c = CString::new(mode).unwrap();
            ll::SDL_RWFromFile(path_c.as_ptr() as *const c_char, mode_c.as_ptr() as *const c_char)
        };

        if raw.is_null() {
            Err(get_error())
        } else {
            Ok(RWops {
                raw: raw,
                _marker: PhantomData
            })
        }
    }

    /// Prepares a read-only memory buffer for use with `RWops`.
    ///
    /// This method can only fail if the buffer size is zero.
    pub fn from_bytes(buf: &'a [u8]) -> Result<RWops <'a>, String> {
        let raw = unsafe {
            ll::SDL_RWFromConstMem(buf.as_ptr() as *const c_void, buf.len() as c_int)
        };

        if raw.is_null() {
            Err(get_error())
        } else {
            Ok(RWops {
                raw: raw,
                _marker: PhantomData
            })
        }
    }

    /// Prepares a read-write memory buffer for use with `RWops`.
    ///
    /// This method can only fail if the buffer size is zero.
    pub fn from_bytes_mut(buf: &'a mut [u8]) -> Result<RWops <'a>, String> {
        let raw = unsafe {
            ll::SDL_RWFromMem(buf.as_ptr() as *mut c_void, buf.len() as c_int)
        };

        if raw.is_null() {
            Err(get_error())
        } else {
            Ok(RWops {
                raw: raw,
                _marker: PhantomData
            })
        }
    }

    /// Gets the stream's total size in bytes.
    ///
    /// Returns `None` if the stream size can't be determined
    /// (either because it doesn't make sense for the stream type, or there was an error).
    pub fn len(&self) -> Option<usize> {
        let result = unsafe { ((*self.raw).size)(self.raw) };

        match result {
            -1 => None,
            v => Some(v as usize)
        }
    }
}

impl<'a> Drop for RWops<'a> {
    fn drop(&mut self) {
        let ret = unsafe { ((*self.raw).close)(self.raw) };
        if ret != 0 {
            panic!(get_error());
        }
    }
}

impl<'a> io::Read for RWops<'a> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let out_len = buf.len() as size_t;
        // FIXME: it's better to use as_mut_ptr().
        // number of objects read, or 0 at error or end of file.
        let ret = unsafe {
            ((*self.raw).read)(self.raw, buf.as_ptr() as *mut c_void, 1, out_len)
        };
        Ok(ret as usize)
    }
}

impl<'a> io::Write for RWops<'a> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let in_len = buf.len() as size_t;
        let ret = unsafe {
            ((*self.raw).write)(self.raw, buf.as_ptr() as *const c_void, 1, in_len)
        };
        Ok(ret as usize)
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl<'a> io::Seek for RWops<'a> {
    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
        // whence code is different from SeekStyle
        let (whence, offset) = match pos {
            io::SeekFrom::Start(pos) => (ll::RW_SEEK_SET, pos as i64),
            io::SeekFrom::End(pos) => (ll::RW_SEEK_END, pos),
            io::SeekFrom::Current(pos) => (ll::RW_SEEK_CUR, pos)
        };
        let ret = unsafe {
            ((*self.raw).seek)(self.raw, offset, whence)
        };
        if ret == -1 {
            Err(io::Error::last_os_error())
        } else {
            Ok(ret as u64)
        }
    }
}
<commit_msg>Added a from_read() method to RWops<commit_after>use std::ffi::CString;
use std::io;
use std::path::Path;
use std::marker::PhantomData;
use libc::{c_void, c_int, size_t, c_char};
use get_error;

use sys::rwops as ll;

/// A structure that provides an abstract interface to stream I/O.
pub struct RWops<'a> {
    raw: *mut ll::SDL_RWops,
    _marker: PhantomData<&'a ()>
}

impl<'a> RWops<'a> {
    pub unsafe fn raw(&self) -> *mut ll::SDL_RWops { self.raw }

    pub unsafe fn from_ll<'b>(raw: *mut ll::SDL_RWops) -> RWops<'b> {
        RWops {
            raw: raw,
            _marker: PhantomData
        }
    }

    /// Creates an SDL file stream.
    pub fn from_file<P: AsRef<Path>>(path: P, mode: &str) -> Result<RWops <'static>, String> {
        let raw = unsafe {
            let path_c = CString::new(path.as_ref().to_str().unwrap()).unwrap();
            let mode_c = CString::new(mode).unwrap();
            ll::SDL_RWFromFile(path_c.as_ptr() as *const c_char, mode_c.as_ptr() as *const c_char)
        };

        if raw.is_null() {
            Err(get_error())
        } else {
            Ok(RWops {
                raw: raw,
                _marker: PhantomData
            })
        }
    }

    /// Prepares a read-only memory buffer for use with `RWops`.
    ///
    /// This method can only fail if the buffer size is zero.
    pub fn from_bytes(buf: &'a [u8]) -> Result<RWops <'a>, String> {
        let raw = unsafe {
            ll::SDL_RWFromConstMem(buf.as_ptr() as *const c_void, buf.len() as c_int)
        };

        if raw.is_null() {
            Err(get_error())
        } else {
            Ok(RWops {
                raw: raw,
                _marker: PhantomData
            })
        }
    }

    /// Reads a `Read` object into a buffer and then passes it to `RWops.from_bytes`.
    ///
    /// The buffer must be provided to this function and must live as long as the
    /// `RWops`, but the `RWops` does not take ownership of it.
    pub fn from_read<T>(r: &mut T, buffer: &'a mut Vec<u8>) -> Result<RWops<'a>, String>
        where T: io::Read + Sized {
        match r.read_to_end(buffer) {
            Ok(_size) => RWops::from_bytes(buffer),
            Err(ioerror) => {
                let msg = format!("IO error: {}", ioerror);
                Err(msg)
            }
        }
    }

    /// Prepares a read-write memory buffer for use with `RWops`.
    ///
    /// This method can only fail if the buffer size is zero.
    pub fn from_bytes_mut(buf: &'a mut [u8]) -> Result<RWops <'a>, String> {
        let raw = unsafe {
            ll::SDL_RWFromMem(buf.as_ptr() as *mut c_void, buf.len() as c_int)
        };

        if raw.is_null() {
            Err(get_error())
        } else {
            Ok(RWops {
                raw: raw,
                _marker: PhantomData
            })
        }
    }

    /// Gets the stream's total size in bytes.
    ///
    /// Returns `None` if the stream size can't be determined
    /// (either because it doesn't make sense for the stream type, or there was an error).
    pub fn len(&self) -> Option<usize> {
        let result = unsafe { ((*self.raw).size)(self.raw) };

        match result {
            -1 => None,
            v => Some(v as usize)
        }
    }
}

impl<'a> Drop for RWops<'a> {
    fn drop(&mut self) {
        let ret = unsafe { ((*self.raw).close)(self.raw) };
        if ret != 0 {
            panic!(get_error());
        }
    }
}

impl<'a> io::Read for RWops<'a> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let out_len = buf.len() as size_t;
        // FIXME: it's better to use as_mut_ptr().
        // number of objects read, or 0 at error or end of file.
        let ret = unsafe {
            ((*self.raw).read)(self.raw, buf.as_ptr() as *mut c_void, 1, out_len)
        };
        Ok(ret as usize)
    }
}

impl<'a> io::Write for RWops<'a> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let in_len = buf.len() as size_t;
        let ret = unsafe {
            ((*self.raw).write)(self.raw, buf.as_ptr() as *const c_void, 1, in_len)
        };
        Ok(ret as usize)
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl<'a> io::Seek for RWops<'a> {
    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
        // whence code is different from SeekStyle
        let (whence, offset) = match pos {
            io::SeekFrom::Start(pos) => (ll::RW_SEEK_SET, pos as i64),
            io::SeekFrom::End(pos) => (ll::RW_SEEK_END, pos),
            io::SeekFrom::Current(pos) => (ll::RW_SEEK_CUR, pos)
        };
        let ret = unsafe {
            ((*self.raw).seek)(self.raw, offset, whence)
        };
        if ret == -1 {
            Err(io::Error::last_os_error())
        } else {
            Ok(ret as u64)
        }
    }
}
<|endoftext|>