<commit_before>/*
 * Copyright (c) 2014-2015 Mathias Hällman
 *
 * 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/.
 */

extern crate term;
#[cfg(not(test))]
extern crate unicode_width;

#[cfg(not(test))]
use self::unicode_width::UnicodeWidthChar as CharWidth;

use std::cmp;
#[cfg(not(test))]
use std::iter;
use std::ops::{Add, Sub};

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Size(pub u16, pub u16);

#[cfg(not(test))]
impl Size {
  fn from_cell(Cell(row, col): Cell) -> Size {
    Size(row, col)
  }
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Cell(pub u16, pub u16);

#[cfg(not(test))]
impl Cell {
  fn within(self, size: Size) -> Option<Cell> {
    let Cell(cell_row, cell_col) = self;
    let Size(end_row, end_col) = size;
    if cell_row < end_row && cell_col < end_col { Some(self) } else { None }
  }

  fn from_size(Size(row, col): Size) -> Cell {
    Cell(row, col)
  }
}

impl Add for Cell {
  type Output = Cell;
  fn add(self, rhs: Cell) -> Cell {
    let Cell(r1, c1) = self;
    let Cell(r2, c2) = rhs;
    Cell(r1 + r2, c1 + c2)
  }
}

impl Sub for Cell {
  type Output = Cell;
  fn sub(self, rhs: Cell) -> Cell {
    let Cell(r1, c1) = self;
    let Cell(r2, c2) = rhs;
    Cell(cmp::max(r1 as i16 - r2 as i16, 0) as u16,
         cmp::max(c1 as i16 - c2 as i16, 0) as u16)
  }
}

#[derive(Clone, Copy, PartialEq)]
pub struct Rect(pub Cell, pub Size);

impl Rect {
  pub fn contains(&self, Cell(row, col): Cell) -> bool {
    let Rect(Cell(start_row, start_col), Size(rows, cols)) = *self;
    row >= start_row && row < start_row + rows &&
      col >= start_col && col < start_col + cols
  }
}

/*
 * Iterates over a region of the screen, defined by a starting cell and a size.
 */
#[cfg(not(test))]
pub struct CellIterator {
  next_cell: Option<Cell>,
  size: Size,
  width: u16,
}

#[cfg(not(test))]
impl CellIterator {
  pub fn new(Rect(start, size): Rect) -> CellIterator {
    let Size(_, rel_end_col) = size;
    let abs_size = Size::from_cell(start + Cell::from_size(size));
    CellIterator {
      next_cell: start.within(abs_size), size: abs_size, width: rel_end_col
    }
  }
}

#[cfg(not(test))]
impl Iterator for CellIterator {
  type Item = Cell;

  fn next(&mut self) -> Option<Cell> {
    let ret = self.next_cell;
    self.next_cell = self.next_cell.and_then(|cell|
      (cell + Cell(0, 1)).within(self.size).or(
        (cell - Cell(0, self.width - 1) + Cell(1, 0)).within(self.size)));
    return ret;
  }
}

/*
 * Screen is the output surface. You can put characters within its borders and
 * clear it again. Go nuts!
 */
#[cfg(not(test))]
pub struct Screen {
  size: Size,
  terminal: Terminal,
  buffer: ScreenBuffer,
}

#[cfg(not(test))]
impl Drop for Screen {
  fn drop(&mut self) {
    self.terminal.clear();
    self.terminal.show_cursor();
    self.terminal.disable_altscreen();
  }
}

#[cfg(not(test))]
impl Screen {
  pub fn setup() -> Result<Screen, String> {
    Terminal::new().map_or(
      Err("Failed creating a terminal for stdout.".to_string()),
      |mut terminal| {
        terminal.enable_altscreen();
        terminal.hide_cursor();
        terminal.clear();
        Ok(Screen {
          size: Size(0, 0),
          terminal: terminal,
          buffer: ScreenBuffer::new()
        })
      })
  }

  pub fn update_size(&mut self) -> bool {
    term_size::size().map(|(rows, cols)| Size(rows, cols)).
    and_then(|new_size| if new_size == self.size { None } else { Some({
      self.buffer.resize(new_size);
      self.size = new_size; }) }).
    is_some()
  }

  pub fn size(&self) -> Size {
    self.size
  }

  pub fn clear(&mut self) {
    self.terminal.clear();
    self.buffer.clear();
  }

  pub fn put(&mut self, position: Cell, character: char, fg: Color, bg: Color) {
    position.within(self.size).map(|Cell(row, col)| {
      if self.buffer.update(position, character, fg, bg) {
        self.terminal.set_cursor_position(row, col);
        self.terminal.set_fg(fg);
        self.terminal.set_bg(bg);
        self.terminal.put(character);
      }
    });
  }

  pub fn set_cursor_position(&mut self, position: Cell) {
    position.within(self.size).map(|Cell(row, col)|
      self.terminal.set_cursor_position(row, col));
  }

  pub fn flush(&mut self) {
    self.terminal.flush();
  }
}

/*
 * ScreenBuffer mirrors what's known to be on the screen, allowing us to draw
 * new information only when necessary.
 */
#[cfg(not(test))]
struct ScreenBuffer {
  cells: Vec<Option<(char, Color, Color)>>,
  width: u16,
}

#[cfg(not(test))]
impl ScreenBuffer {
  fn new() -> ScreenBuffer {
    ScreenBuffer { cells: Vec::new(), width: 0 }
  }

  fn resize(&mut self, Size(rows, cols): Size) {
    let current_size = self.cells.len();
    let new_size = rows as usize * cols as usize;
    if new_size > current_size {
      self.cells.reserve_exact(new_size);
      self.cells.extend(iter::repeat(None).take(new_size - current_size))
    }
    else if current_size > new_size {
      self.cells.truncate(new_size);
      self.cells.shrink_to_fit();
    }
    self.width = cols;
  }

  fn clear(&mut self) {
    for i in 0..self.cells.len() {
      self.cells[i] = None;
    }
  }

  // a character taking up multiple screen columns is represented in the buffer
  // by one Some(character) followed by Nones in the additional cells it covers
  fn update(&mut self, Cell(row, col): Cell, character: char, fg: Color,
      bg: Color) -> bool {
    let cell = Some((character, fg, bg));
    let idx = (row as usize * self.width as usize) + col as usize;
    let buffer_size = self.cells.len();
    let nones = || (1..CharWidth::width(character).unwrap_or(1)).
                   map(|i| idx + i).filter(|i| *i < buffer_size);
    let update =
      self.cells[idx] != cell || nones().any(|i| self.cells[i] != None);
    if update {
      self.cells[idx] = cell;
      for i in nones() { self.cells[i] = None; }
    }
    update
  }
}

/*
 * Terminal is a simple wrapper that provides some helpful methods for common
 * ouput operations.
 */
#[cfg(not(test))]
struct Terminal {
  terminal: Box<term::Terminal<::std::io::Stdout> + Send>,
}

#[cfg(not(test))]
impl Terminal {
  pub fn new() -> Option<Terminal> {
    term::stdout().map(|terminal| Terminal { terminal: terminal })
  }

  pub fn set_fg(&mut self, fg: Color) {
    self.terminal.fg(fg.to_term_color()).unwrap();
  }

  pub fn set_bg(&mut self, bg: Color) {
    self.terminal.bg(bg.to_term_color()).unwrap();
  }

  pub fn clear(&mut self) {
    (write!(self.terminal, "\x1B[2J")).unwrap();
  }

  pub fn enable_altscreen(&mut self) {
    (write!(self.terminal, "\x1B7\x1B[?47h")).unwrap();
  }

  pub fn disable_altscreen(&mut self) {
    (write!(self.terminal, "\x1B[?47l\x1B8")).unwrap();
  }

  pub fn hide_cursor(&mut self) {
    (write!(self.terminal, "\x1B[?25l")).unwrap();
  }

  pub fn show_cursor(&mut self) {
    (write!(self.terminal, "\x1B[?25h")).unwrap();
  }

  pub fn set_cursor_position(&mut self, row: u16, col: u16) {
    // add (1, 1) becase terminal row/col is one-indexed
    (write!(self.terminal, "\x1B[{};{}H", row + 1, col + 1)).unwrap();
  }

  pub fn put(&mut self, character: char) {
    (write!(self.terminal, "{}", character)).unwrap();
  }

  pub fn flush(&mut self) {
    self.terminal.flush().unwrap();
  }
}

/*
 * Color values for terminal output.
 */
#[allow(dead_code)]  // colors are not used much yet
#[cfg(not(test))]
#[derive(Clone, Copy, PartialEq)]
pub enum Color {
  Black,
  Red,
  Green,
  Yellow,
  Blue,
  Magenta,
  Cyan,
  White,
  BrightBlack,
  BrightRed,
  BrightGreen,
  BrightYellow,
  BrightBlue,
  BrightMagenta,
  BrightCyan,
  BrightWhite,
}

#[allow(dead_code)]  // colors are not used much yet
#[cfg(not(test))]
impl Color {
  pub fn to_term_color(&self) -> term::color::Color {
    match *self {
      Color::Black         => term::color::BLACK,
      Color::Red           => term::color::RED,
      Color::Green         => term::color::GREEN,
      Color::Yellow        => term::color::YELLOW,
      Color::Blue          => term::color::BLUE,
      Color::Magenta       => term::color::MAGENTA,
      Color::Cyan          => term::color::CYAN,
      Color::White         => term::color::WHITE,
      Color::BrightBlack   => term::color::BRIGHT_BLACK,
      Color::BrightRed     => term::color::BRIGHT_RED,
      Color::BrightGreen   => term::color::BRIGHT_GREEN,
      Color::BrightYellow  => term::color::BRIGHT_YELLOW,
      Color::BrightBlue    => term::color::BRIGHT_BLUE,
      Color::BrightMagenta => term::color::BRIGHT_MAGENTA,
      Color::BrightCyan    => term::color::BRIGHT_CYAN,
      Color::BrightWhite   => term::color::BRIGHT_WHITE,
    }
  }
}

/*
 * Helper module to capture the ugly. Provides a mean to poll the screen size.
 */
#[cfg(not(test))]
mod term_size {
  extern crate libc;

  use self::libc::funcs::bsd44::ioctl;

  const STDOUT_FILENO: libc::c_int = 1;

  #[cfg(target_os = "macos")]
  const TIOCGWINSZ: libc::c_ulong = 0x40087468;
  #[cfg(target_os = "linux")]
  const TIOCGWINSZ: libc::c_int = 0x5413;

  pub fn size() -> Option<(u16, u16)> {
    #[allow(dead_code)]  // not interested in pixel sizes
    struct WinSize {
      rows: libc::c_ushort,  // rows, in screen cells
      cols: libc::c_ushort,  // columns, in screen cells
      h_pixels: libc::c_ushort,  // horizontal size, pixels
      v_pixels: libc::c_ushort,  // vertical size, pixels
    }

    unsafe {
      let mut size = WinSize { rows: 0, cols: 0, h_pixels: 0, v_pixels: 0 };
      match ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut size) {
        0 => Some((size.rows, size.cols)),
        _ => None,
      }
    }
  }
}
<commit_msg>Follow API changes in term crate<commit_after>/*
 * Copyright (c) 2014-2015 Mathias Hällman
 *
 * 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/.
 */

extern crate term;
#[cfg(not(test))]
extern crate unicode_width;

#[cfg(not(test))]
use self::unicode_width::UnicodeWidthChar as CharWidth;

use std::cmp;
#[cfg(not(test))]
use std::iter;
use std::ops::{Add, Sub};

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Size(pub u16, pub u16);

#[cfg(not(test))]
impl Size {
  fn from_cell(Cell(row, col): Cell) -> Size {
    Size(row, col)
  }
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Cell(pub u16, pub u16);

#[cfg(not(test))]
impl Cell {
  fn within(self, size: Size) -> Option<Cell> {
    let Cell(cell_row, cell_col) = self;
    let Size(end_row, end_col) = size;
    if cell_row < end_row && cell_col < end_col { Some(self) } else { None }
  }

  fn from_size(Size(row, col): Size) -> Cell {
    Cell(row, col)
  }
}

impl Add for Cell {
  type Output = Cell;
  fn add(self, rhs: Cell) -> Cell {
    let Cell(r1, c1) = self;
    let Cell(r2, c2) = rhs;
    Cell(r1 + r2, c1 + c2)
  }
}

impl Sub for Cell {
  type Output = Cell;
  fn sub(self, rhs: Cell) -> Cell {
    let Cell(r1, c1) = self;
    let Cell(r2, c2) = rhs;
    Cell(cmp::max(r1 as i16 - r2 as i16, 0) as u16,
         cmp::max(c1 as i16 - c2 as i16, 0) as u16)
  }
}

#[derive(Clone, Copy, PartialEq)]
pub struct Rect(pub Cell, pub Size);

impl Rect {
  pub fn contains(&self, Cell(row, col): Cell) -> bool {
    let Rect(Cell(start_row, start_col), Size(rows, cols)) = *self;
    row >= start_row && row < start_row + rows &&
      col >= start_col && col < start_col + cols
  }
}

/*
 * Iterates over a region of the screen, defined by a starting cell and a size.
 */
#[cfg(not(test))]
pub struct CellIterator {
  next_cell: Option<Cell>,
  size: Size,
  width: u16,
}

#[cfg(not(test))]
impl CellIterator {
  pub fn new(Rect(start, size): Rect) -> CellIterator {
    let Size(_, rel_end_col) = size;
    let abs_size = Size::from_cell(start + Cell::from_size(size));
    CellIterator {
      next_cell: start.within(abs_size), size: abs_size, width: rel_end_col
    }
  }
}

#[cfg(not(test))]
impl Iterator for CellIterator {
  type Item = Cell;

  fn next(&mut self) -> Option<Cell> {
    let ret = self.next_cell;
    self.next_cell = self.next_cell.and_then(|cell|
      (cell + Cell(0, 1)).within(self.size).or(
        (cell - Cell(0, self.width - 1) + Cell(1, 0)).within(self.size)));
    return ret;
  }
}

/*
 * Screen is the output surface. You can put characters within its borders and
 * clear it again. Go nuts!
 */
#[cfg(not(test))]
pub struct Screen {
  size: Size,
  terminal: Terminal,
  buffer: ScreenBuffer,
}

#[cfg(not(test))]
impl Drop for Screen {
  fn drop(&mut self) {
    self.terminal.clear();
    self.terminal.show_cursor();
    self.terminal.disable_altscreen();
  }
}

#[cfg(not(test))]
impl Screen {
  pub fn setup() -> Result<Screen, String> {
    Terminal::new().map_or(
      Err("Failed creating a terminal for stdout.".to_string()),
      |mut terminal| {
        terminal.enable_altscreen();
        terminal.hide_cursor();
        terminal.clear();
        Ok(Screen {
          size: Size(0, 0),
          terminal: terminal,
          buffer: ScreenBuffer::new()
        })
      })
  }

  pub fn update_size(&mut self) -> bool {
    term_size::size().map(|(rows, cols)| Size(rows, cols)).
    and_then(|new_size| if new_size == self.size { None } else { Some({
      self.buffer.resize(new_size);
      self.size = new_size; }) }).
    is_some()
  }

  pub fn size(&self) -> Size {
    self.size
  }

  pub fn clear(&mut self) {
    self.terminal.clear();
    self.buffer.clear();
  }

  pub fn put(&mut self, position: Cell, character: char, fg: Color, bg: Color) {
    position.within(self.size).map(|Cell(row, col)| {
      if self.buffer.update(position, character, fg, bg) {
        self.terminal.set_cursor_position(row, col);
        self.terminal.set_fg(fg);
        self.terminal.set_bg(bg);
        self.terminal.put(character);
      }
    });
  }

  pub fn set_cursor_position(&mut self, position: Cell) {
    position.within(self.size).map(|Cell(row, col)|
      self.terminal.set_cursor_position(row, col));
  }

  pub fn flush(&mut self) {
    self.terminal.flush();
  }
}

/*
 * ScreenBuffer mirrors what's known to be on the screen, allowing us to draw
 * new information only when necessary.
 */
#[cfg(not(test))]
struct ScreenBuffer {
  cells: Vec<Option<(char, Color, Color)>>,
  width: u16,
}

#[cfg(not(test))]
impl ScreenBuffer {
  fn new() -> ScreenBuffer {
    ScreenBuffer { cells: Vec::new(), width: 0 }
  }

  fn resize(&mut self, Size(rows, cols): Size) {
    let current_size = self.cells.len();
    let new_size = rows as usize * cols as usize;
    if new_size > current_size {
      self.cells.reserve_exact(new_size);
      self.cells.extend(iter::repeat(None).take(new_size - current_size))
    }
    else if current_size > new_size {
      self.cells.truncate(new_size);
      self.cells.shrink_to_fit();
    }
    self.width = cols;
  }

  fn clear(&mut self) {
    for i in 0..self.cells.len() {
      self.cells[i] = None;
    }
  }

  // a character taking up multiple screen columns is represented in the buffer
  // by one Some(character) followed by Nones in the additional cells it covers
  fn update(&mut self, Cell(row, col): Cell, character: char, fg: Color,
      bg: Color) -> bool {
    let cell = Some((character, fg, bg));
    let idx = (row as usize * self.width as usize) + col as usize;
    let buffer_size = self.cells.len();
    let nones = || (1..CharWidth::width(character).unwrap_or(1)).
                   map(|i| idx + i).filter(|i| *i < buffer_size);
    let update =
      self.cells[idx] != cell || nones().any(|i| self.cells[i] != None);
    if update {
      self.cells[idx] = cell;
      for i in nones() { self.cells[i] = None; }
    }
    update
  }
}

/*
 * Terminal is a simple wrapper that provides some helpful methods for common
 * ouput operations.
 */
#[cfg(not(test))]
struct Terminal {
  terminal: Box<term::StdoutTerminal>,
}

#[cfg(not(test))]
impl Terminal {
  pub fn new() -> Option<Terminal> {
    term::stdout().map(|terminal| Terminal { terminal: terminal })
  }

  pub fn set_fg(&mut self, fg: Color) {
    self.terminal.fg(fg.to_term_color()).unwrap();
  }

  pub fn set_bg(&mut self, bg: Color) {
    self.terminal.bg(bg.to_term_color()).unwrap();
  }

  pub fn clear(&mut self) {
    (write!(self.terminal, "\x1B[2J")).unwrap();
  }

  pub fn enable_altscreen(&mut self) {
    (write!(self.terminal, "\x1B7\x1B[?47h")).unwrap();
  }

  pub fn disable_altscreen(&mut self) {
    (write!(self.terminal, "\x1B[?47l\x1B8")).unwrap();
  }

  pub fn hide_cursor(&mut self) {
    (write!(self.terminal, "\x1B[?25l")).unwrap();
  }

  pub fn show_cursor(&mut self) {
    (write!(self.terminal, "\x1B[?25h")).unwrap();
  }

  pub fn set_cursor_position(&mut self, row: u16, col: u16) {
    // add (1, 1) becase terminal row/col is one-indexed
    (write!(self.terminal, "\x1B[{};{}H", row + 1, col + 1)).unwrap();
  }

  pub fn put(&mut self, character: char) {
    (write!(self.terminal, "{}", character)).unwrap();
  }

  pub fn flush(&mut self) {
    self.terminal.flush().unwrap();
  }
}

/*
 * Color values for terminal output.
 */
#[allow(dead_code)]  // colors are not used much yet
#[cfg(not(test))]
#[derive(Clone, Copy, PartialEq)]
pub enum Color {
  Black,
  Red,
  Green,
  Yellow,
  Blue,
  Magenta,
  Cyan,
  White,
  BrightBlack,
  BrightRed,
  BrightGreen,
  BrightYellow,
  BrightBlue,
  BrightMagenta,
  BrightCyan,
  BrightWhite,
}

#[allow(dead_code)]  // colors are not used much yet
#[cfg(not(test))]
impl Color {
  pub fn to_term_color(&self) -> term::color::Color {
    match *self {
      Color::Black         => term::color::BLACK,
      Color::Red           => term::color::RED,
      Color::Green         => term::color::GREEN,
      Color::Yellow        => term::color::YELLOW,
      Color::Blue          => term::color::BLUE,
      Color::Magenta       => term::color::MAGENTA,
      Color::Cyan          => term::color::CYAN,
      Color::White         => term::color::WHITE,
      Color::BrightBlack   => term::color::BRIGHT_BLACK,
      Color::BrightRed     => term::color::BRIGHT_RED,
      Color::BrightGreen   => term::color::BRIGHT_GREEN,
      Color::BrightYellow  => term::color::BRIGHT_YELLOW,
      Color::BrightBlue    => term::color::BRIGHT_BLUE,
      Color::BrightMagenta => term::color::BRIGHT_MAGENTA,
      Color::BrightCyan    => term::color::BRIGHT_CYAN,
      Color::BrightWhite   => term::color::BRIGHT_WHITE,
    }
  }
}

/*
 * Helper module to capture the ugly. Provides a mean to poll the screen size.
 */
#[cfg(not(test))]
mod term_size {
  extern crate libc;

  use self::libc::funcs::bsd44::ioctl;

  const STDOUT_FILENO: libc::c_int = 1;

  #[cfg(target_os = "macos")]
  const TIOCGWINSZ: libc::c_ulong = 0x40087468;
  #[cfg(target_os = "linux")]
  const TIOCGWINSZ: libc::c_int = 0x5413;

  pub fn size() -> Option<(u16, u16)> {
    #[allow(dead_code)]  // not interested in pixel sizes
    struct WinSize {
      rows: libc::c_ushort,  // rows, in screen cells
      cols: libc::c_ushort,  // columns, in screen cells
      h_pixels: libc::c_ushort,  // horizontal size, pixels
      v_pixels: libc::c_ushort,  // vertical size, pixels
    }

    unsafe {
      let mut size = WinSize { rows: 0, cols: 0, h_pixels: 0, v_pixels: 0 };
      match ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut size) {
        0 => Some((size.rows, size.cols)),
        _ => None,
      }
    }
  }
}
<|endoftext|>


<commit_before>//! etcd's members API.
//!
//! These API endpoints are used to manage cluster membership.

use std::str::FromStr;

use futures::{Future, IntoFuture, Stream};
use hyper::{StatusCode, Uri};
use hyper::client::Connect;
use serde_json;

use async::first_ok;
use client::{Client, ClusterInfo, Response};
use error::{ApiError, Error};

/// An etcd server that is a member of a cluster.
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq)]
pub struct Member {
    /// An internal identifier for the cluster member.
    pub id: String,
    /// A human-readable name for the cluster member.
    pub name: String,
    /// URLs exposing this cluster member's peer API.
    #[serde(rename = "peerURLs")]
    pub peer_urls: Vec<String>,
    /// URLs exposing this cluster member's client API.
    #[serde(rename = "clientURLs")]
    pub client_urls: Vec<String>,
}

/// The request body for `POST /v2/members`.
#[derive(Debug, Serialize)]
struct AddMember {
    #[serde(rename = "peerURLs")]
    pub peer_urls: Vec<String>,
}

/// A small wrapper around `Member` to match the response of `GET /v2/members`.
#[derive(Debug, Deserialize)]
struct ListResponse {
    members: Vec<Member>,
}

/// Add a new member to the cluster.
///
/// # Parameters
///
/// * client: A `Client` to use to make the API call.
/// * peer_urls: URLs exposing this cluster member's peer API.
pub fn add_member<C>(
    client: &Client<C>,
    peer_urls: Vec<String>,
) -> Box<Future<Item = Response<()>, Error = Vec<Error>>>
where
    C: Clone + Connect,
{
    let add_member = AddMember { peer_urls };

    let body = match serde_json::to_string(&add_member) {
        Ok(body) => body,
        Err(error) => return Box::new(Err(vec![Error::Serialization(error)]).into_future()),
    };

    let http_client = client.http_client().clone();

    let result = first_ok(client.endpoints().to_vec(), move |member| {
        let url = build_url(member, "");
        let uri = Uri::from_str(url.as_str())
            .map_err(Error::from)
            .into_future();

        let body = body.clone();
        let http_client = http_client.clone();

        let response = uri.and_then(move |uri| http_client.post(uri, body).map_err(Error::from));

        let result = response.and_then(|response| {
            let status = response.status();
            let cluster_info = ClusterInfo::from(response.headers());
            let body = response.body().concat2().map_err(Error::from);

            body.and_then(move |ref body| if status == StatusCode::Created {
                Ok(Response {
                    data: (),
                    cluster_info,
                })
            } else {
                match serde_json::from_slice::<ApiError>(body) {
                    Ok(error) => Err(Error::Api(error)),
                    Err(error) => Err(Error::Serialization(error)),
                }
            })
        });

        Box::new(result)
    });

    Box::new(result)
}

/// Delete a member from the cluster.
///
/// # Parameters
///
/// * client: A `Client` to use to make the API call.
/// * id: The unique identifier of the member to delete.
pub fn delete_member<C>(
    client: &Client<C>,
    id: String,
) -> Box<Future<Item = Response<()>, Error = Vec<Error>>>
where
    C: Clone + Connect,
{
    let http_client = client.http_client().clone();

    let result = first_ok(client.endpoints().to_vec(), move |member| {
        let url = build_url(member, &format!("/{}", id));
        let uri = Uri::from_str(url.as_str())
            .map_err(Error::from)
            .into_future();

        let http_client = http_client.clone();

        let response = uri.and_then(move |uri| http_client.delete(uri).map_err(Error::from));

        let result = response.and_then(|response| {
            let status = response.status();
            let cluster_info = ClusterInfo::from(response.headers());
            let body = response.body().concat2().map_err(Error::from);

            body.and_then(move |ref body| if status == StatusCode::NoContent {
                Ok(Response {
                    data: (),
                    cluster_info,
                })
            } else {
                match serde_json::from_slice::<ApiError>(body) {
                    Ok(error) => Err(Error::Api(error)),
                    Err(error) => Err(Error::Serialization(error)),
                }
            })
        });

        Box::new(result)
    });

    Box::new(result)
}
/// Lists the members of the cluster.
///
/// # Parameters
///
/// * client: A `Client` to use to make the API call.
pub fn list<C>(client: &Client<C>) -> Box<Future<Item = Response<Vec<Member>>, Error = Vec<Error>>>
where
    C: Clone + Connect,
{
    let http_client = client.http_client().clone();

    let result = first_ok(client.endpoints().to_vec(), move |member| {
        let url = build_url(member, "");
        let uri = Uri::from_str(url.as_str())
            .map_err(Error::from)
            .into_future();

        let http_client = http_client.clone();

        let response = uri.and_then(move |uri| http_client.get(uri).map_err(Error::from));

        let result = response.and_then(|response| {
            let status = response.status();
            let cluster_info = ClusterInfo::from(response.headers());
            let body = response.body().concat2().map_err(Error::from);

            body.and_then(move |ref body| if status == StatusCode::Ok {
                match serde_json::from_slice::<ListResponse>(body) {
                    Ok(data) => Ok(Response {
                        data: data.members,
                        cluster_info,
                    }),
                    Err(error) => Err(Error::Serialization(error)),
                }
            } else {
                match serde_json::from_slice::<ApiError>(body) {
                    Ok(error) => Err(Error::Api(error)),
                    Err(error) => Err(Error::Serialization(error)),
                }
            })
        });

        Box::new(result)
    });

    Box::new(result)
}

/// Constructs the full URL for an API call.
fn build_url(endpoint: &Uri, path: &str) -> String {
    let maybe_slash = if endpoint.as_ref().ends_with("/") {
        ""
    } else {
        "/"
    };

    format!("{}{}v2/members{}", endpoint, maybe_slash, path)
}
<commit_msg>add_member/delete_member --> add/delete<commit_after>//! etcd's members API.
//!
//! These API endpoints are used to manage cluster membership.

use std::str::FromStr;

use futures::{Future, IntoFuture, Stream};
use hyper::{StatusCode, Uri};
use hyper::client::Connect;
use serde_json;

use async::first_ok;
use client::{Client, ClusterInfo, Response};
use error::{ApiError, Error};

/// An etcd server that is a member of a cluster.
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq)]
pub struct Member {
    /// An internal identifier for the cluster member.
    pub id: String,
    /// A human-readable name for the cluster member.
    pub name: String,
    /// URLs exposing this cluster member's peer API.
    #[serde(rename = "peerURLs")]
    pub peer_urls: Vec<String>,
    /// URLs exposing this cluster member's client API.
    #[serde(rename = "clientURLs")]
    pub client_urls: Vec<String>,
}

/// The request body for `POST /v2/members`.
#[derive(Debug, Serialize)]
struct AddMember {
    #[serde(rename = "peerURLs")]
    pub peer_urls: Vec<String>,
}

/// A small wrapper around `Member` to match the response of `GET /v2/members`.
#[derive(Debug, Deserialize)]
struct ListResponse {
    members: Vec<Member>,
}

/// Add a new member to the cluster.
///
/// # Parameters
///
/// * client: A `Client` to use to make the API call.
/// * peer_urls: URLs exposing this cluster member's peer API.
pub fn add<C>(
    client: &Client<C>,
    peer_urls: Vec<String>,
) -> Box<Future<Item = Response<()>, Error = Vec<Error>>>
where
    C: Clone + Connect,
{
    let add_member = AddMember { peer_urls };

    let body = match serde_json::to_string(&add_member) {
        Ok(body) => body,
        Err(error) => return Box::new(Err(vec![Error::Serialization(error)]).into_future()),
    };

    let http_client = client.http_client().clone();

    let result = first_ok(client.endpoints().to_vec(), move |member| {
        let url = build_url(member, "");
        let uri = Uri::from_str(url.as_str())
            .map_err(Error::from)
            .into_future();

        let body = body.clone();
        let http_client = http_client.clone();

        let response = uri.and_then(move |uri| http_client.post(uri, body).map_err(Error::from));

        let result = response.and_then(|response| {
            let status = response.status();
            let cluster_info = ClusterInfo::from(response.headers());
            let body = response.body().concat2().map_err(Error::from);

            body.and_then(move |ref body| if status == StatusCode::Created {
                Ok(Response {
                    data: (),
                    cluster_info,
                })
            } else {
                match serde_json::from_slice::<ApiError>(body) {
                    Ok(error) => Err(Error::Api(error)),
                    Err(error) => Err(Error::Serialization(error)),
                }
            })
        });

        Box::new(result)
    });

    Box::new(result)
}

/// Delete a member from the cluster.
///
/// # Parameters
///
/// * client: A `Client` to use to make the API call.
/// * id: The unique identifier of the member to delete.
pub fn delete<C>(
    client: &Client<C>,
    id: String,
) -> Box<Future<Item = Response<()>, Error = Vec<Error>>>
where
    C: Clone + Connect,
{
    let http_client = client.http_client().clone();

    let result = first_ok(client.endpoints().to_vec(), move |member| {
        let url = build_url(member, &format!("/{}", id));
        let uri = Uri::from_str(url.as_str())
            .map_err(Error::from)
            .into_future();

        let http_client = http_client.clone();

        let response = uri.and_then(move |uri| http_client.delete(uri).map_err(Error::from));

        let result = response.and_then(|response| {
            let status = response.status();
            let cluster_info = ClusterInfo::from(response.headers());
            let body = response.body().concat2().map_err(Error::from);

            body.and_then(move |ref body| if status == StatusCode::NoContent {
                Ok(Response {
                    data: (),
                    cluster_info,
                })
            } else {
                match serde_json::from_slice::<ApiError>(body) {
                    Ok(error) => Err(Error::Api(error)),
                    Err(error) => Err(Error::Serialization(error)),
                }
            })
        });

        Box::new(result)
    });

    Box::new(result)
}
/// Lists the members of the cluster.
///
/// # Parameters
///
/// * client: A `Client` to use to make the API call.
pub fn list<C>(client: &Client<C>) -> Box<Future<Item = Response<Vec<Member>>, Error = Vec<Error>>>
where
    C: Clone + Connect,
{
    let http_client = client.http_client().clone();

    let result = first_ok(client.endpoints().to_vec(), move |member| {
        let url = build_url(member, "");
        let uri = Uri::from_str(url.as_str())
            .map_err(Error::from)
            .into_future();

        let http_client = http_client.clone();

        let response = uri.and_then(move |uri| http_client.get(uri).map_err(Error::from));

        let result = response.and_then(|response| {
            let status = response.status();
            let cluster_info = ClusterInfo::from(response.headers());
            let body = response.body().concat2().map_err(Error::from);

            body.and_then(move |ref body| if status == StatusCode::Ok {
                match serde_json::from_slice::<ListResponse>(body) {
                    Ok(data) => Ok(Response {
                        data: data.members,
                        cluster_info,
                    }),
                    Err(error) => Err(Error::Serialization(error)),
                }
            } else {
                match serde_json::from_slice::<ApiError>(body) {
                    Ok(error) => Err(Error::Api(error)),
                    Err(error) => Err(Error::Serialization(error)),
                }
            })
        });

        Box::new(result)
    });

    Box::new(result)
}

/// Constructs the full URL for an API call.
fn build_url(endpoint: &Uri, path: &str) -> String {
    let maybe_slash = if endpoint.as_ref().ends_with("/") {
        ""
    } else {
        "/"
    };

    format!("{}{}v2/members{}", endpoint, maybe_slash, path)
}
<|endoftext|>


<commit_before>use sentry::{ClientInitGuard, ClientOptions, IntoDsn};
use std::borrow::Cow;

/// Initializes the Sentry SDK from the environment variables.
///
/// If `SENTRY_DSN_API` is not set then Sentry will not be initialized,
/// otherwise it is required to be a valid DSN string. `SENTRY_ENV_API` must
/// be set if a DSN is provided.
///
/// `HEROKU_SLUG_COMMIT`, if present, will be used as the `release` property
/// on all events.
#[must_use]
pub fn init() -> Option<ClientInitGuard> {
    dotenv::var("SENTRY_DSN_API")
        .ok()
        .into_dsn()
        .expect("SENTRY_DSN_API is not a valid Sentry DSN value")
        .map(|dsn| {
            let mut opts = ClientOptions::from(dsn);
            opts.environment = Some(
                dotenv::var("SENTRY_ENV_API")
                    .map(Cow::Owned)
                    .expect("SENTRY_ENV_API must be set when using SENTRY_DSN_API"),
            );

            opts.release = dotenv::var("HEROKU_SLUG_COMMIT").ok().map(Into::into);

            sentry::init(opts)
        })
}
<commit_msg>sentry: Use `default()` to initialize `ClientOptions` instead of `mut`<commit_after>use sentry::{ClientInitGuard, ClientOptions, IntoDsn};
use std::borrow::Cow;

/// Initializes the Sentry SDK from the environment variables.
///
/// If `SENTRY_DSN_API` is not set then Sentry will not be initialized,
/// otherwise it is required to be a valid DSN string. `SENTRY_ENV_API` must
/// be set if a DSN is provided.
///
/// `HEROKU_SLUG_COMMIT`, if present, will be used as the `release` property
/// on all events.
#[must_use]
pub fn init() -> Option<ClientInitGuard> {
    dotenv::var("SENTRY_DSN_API")
        .ok()
        .into_dsn()
        .expect("SENTRY_DSN_API is not a valid Sentry DSN value")
        .map(|dsn| {
            let environment = Some(
                dotenv::var("SENTRY_ENV_API")
                    .map(Cow::Owned)
                    .expect("SENTRY_ENV_API must be set when using SENTRY_DSN_API"),
            );

            let release = dotenv::var("HEROKU_SLUG_COMMIT").ok().map(Into::into);

            let opts = ClientOptions {
                dsn: Some(dsn),
                environment,
                release,
                ..Default::default()
            };

            sentry::init(opts)
        })
}
<|endoftext|>


<commit_before>use std::net::SocketAddr;
use std::sync::mpsc::{self, SyncSender, SendError, Receiver, TryRecvError};
use std::sync::Arc;
use std::time::Duration;
use std::thread;

use rotor::{self, Scope, Time};
use rotor::mio::tcp::TcpListener;
use rotor::void::Void;
use rotor_http::server::{RecvMode, Server, Head, Response, Fsm};
use rotor_tools::timer::{IntervalFunc, interval_func};

use super::context::Context;
use super::handler::Handler;

rotor_compose!(enum Machine/Seed<Context> {
    Http(Fsm<Responder, TcpListener>),
    Timer(IntervalFunc<Context>),
});

pub struct Guard(SyncSender<()>);

impl Guard {
    pub fn stop(self) -> Result<(), SendError<()>> {
        self.0.send(())
    }
}

fn create_interval(scope: &mut Scope<Context>, duration: Duration, rx: Receiver<()>)
-> rotor::Response<IntervalFunc<Context>, Void>
{
    interval_func(scope, duration, move |scope: &mut Scope<Context>| {
        match rx.try_recv() {
            Ok(_) | Err(TryRecvError::Disconnected) => {
                println!("Stopping server");
                scope.shutdown_loop();
            }
            _ => {},
        }
    })
}

pub fn start(context: Context, address: &str)
    -> Result<Guard, String>
{
    let (tx, rx) = mpsc::sync_channel::<()>(0);

    let event_loop = rotor::Loop::new(&rotor::Config::new()).unwrap();
    let mut loop_inst = event_loop.instantiate(context);

    let address: SocketAddr = try!(address.parse().map_err(|e| format!("{}", e)));
    let lst = try!(TcpListener::bind(&address).map_err(|e| format!("{}", e)));

    try!(loop_inst.add_machine_with(|scope| {
        Fsm::<Responder, TcpListener>::new(lst, (), scope)
            .wrap(|fsm| Machine::Http(fsm))
    }).map_err(|e| format!("{}", e)));

    try!(loop_inst.add_machine_with(|scope| {
        create_interval(scope, Duration::new(1, 0), rx)
            .wrap(|fsm| Machine::Timer(fsm))
    }).map_err(|e| format!("{}", e)));

    thread::spawn(move || {
        loop_inst.run().unwrap();
    });

    Ok(Guard(tx))
}

pub fn run(context: Context, address: &str)
    -> Result<(), String>
{
    let event_loop = rotor::Loop::new(&rotor::Config::new()).unwrap();
    let mut loop_inst = event_loop.instantiate(context);

    let address: SocketAddr = try!(address.parse().map_err(|e| format!("{}", e)));
    let lst = try!(TcpListener::bind(&address).map_err(|e| format!("{}", e)));

    try!(loop_inst.add_machine_with(|scope| {
        Fsm::<Responder, TcpListener>::new(lst, (), scope)
    }).map_err(|e| format!("{}", e)));

    try!(loop_inst.run().map_err(|e| format!("{}", e)));

    Ok(())
}

pub trait Router {
    fn match_route(&self, method: &str, path: &str) -> Option<Arc<Handler>>;
}

impl Router for Context {
    fn match_route(&self, method: &str, path: &str) -> Option<Arc<Handler>> {
        for ref route in self.routes().iter() {
            if route.is_match(method, path) {
                return Some(route.handler())
            }
        }
        None
    }
}

#[derive(Clone, Debug)]
pub enum Responder {
    Respond(Arc<Handler>),
    NotFound,
}

fn send_not_found(res: &mut Response) {
    let data = b"404 - Page not found";
    res.status(404, "Not Found");
    res.add_length(data.len() as u64).unwrap();
    res.add_header("Content-Type", b"text/plain").unwrap();
    res.done_headers().unwrap();
    res.write_body(data);
    res.done();
}

fn send_error(res: &mut Response, data: &str) {
    let data = data.as_bytes();
    res.status(500, "Internal Server Error");
    res.add_length(data.len() as u64).unwrap();
    res.add_header("Content-Type", b"text/plain").unwrap();
    res.done_headers().unwrap();
    res.write_body(data);
    res.done();
}

impl Server for Responder {
    type Seed = ();
    type Context = Context;

    fn headers_received(_seed: Self::Seed, head: Head, _res: &mut Response,
        scope: &mut Scope<Self::Context>)
        -> Option<(Self, RecvMode, Time)>
    {
        if scope.autoreload() {
            match scope.rebuild() {
                Ok(_) => {}
                Err(e) => {
                    println!("{}", e);
                    return None
                }
            }
        }

        // let shutdown = if let Some(rx) = scope.recv() {
        //     match rx.try_recv() {
        //         Ok(_) | Err(TryRecvError::Disconnected) => true,
        //         _ => false,
        //     }
        // } else {
        //     false
        // };
        //
        // if shutdown { scope.shutdown_loop(); }

        let responder = match scope.match_route(head.method, head.path) {
            Some(route) => Responder::Respond(route.clone()),
            None => Responder::NotFound,
        };

        Some((responder, RecvMode::Buffered(1024), scope.now() + Duration::new(10, 0)))
    }

    fn request_received(self, _data: &[u8], res: &mut Response,
        scope: &mut Scope<Context>)
        -> Option<Self>
    {
        let result = match self {
            Responder::Respond(handler) => {
                handler.handle(res)
            },
            Responder::NotFound => {
                match scope.not_found_handler() {
                    Some(ref handler) => handler.handle(res),
                    None => { send_not_found(res); Ok(()) },
                }
            }
        };
        result.map_err(|e| send_error(res, &e)).ok();

        None
    }

    fn request_chunk(self, _chunk: &[u8], _response: &mut Response,
        _scope: &mut Scope<Context>)
        -> Option<Self>
    {
        unreachable!();
    }

    /// End of request body, only for Progressive requests
    fn request_end(self, _response: &mut Response, _scope: &mut Scope<Context>)
        -> Option<Self>
    {
        unreachable!();
    }

    fn timeout(self, _response: &mut Response, _scope: &mut Scope<Context>)
        -> Option<(Self, Time)>
    {
        unimplemented!();
    }

    fn wakeup(self, _response: &mut Response, _scope: &mut Scope<Context>)
        -> Option<Self>
    {
        unimplemented!();
    }
}

#[cfg(test)]
mod tests {
    use std::thread;
    use std::time::Duration;
    use context::Context;
    use super::start as start_server;

    #[test]
    fn server_shutdown() {
        let context = Context::new();
        let guard = start_server(context, "127.0.0.1:7000").unwrap();
        guard.stop().unwrap();
    }
}
<commit_msg>Remove commented code<commit_after>use std::net::SocketAddr;
use std::sync::mpsc::{self, SyncSender, SendError, Receiver, TryRecvError};
use std::sync::Arc;
use std::time::Duration;
use std::thread;

use rotor::{self, Scope, Time};
use rotor::mio::tcp::TcpListener;
use rotor::void::Void;
use rotor_http::server::{RecvMode, Server, Head, Response, Fsm};
use rotor_tools::timer::{IntervalFunc, interval_func};

use super::context::Context;
use super::handler::Handler;

rotor_compose!(enum Machine/Seed<Context> {
    Http(Fsm<Responder, TcpListener>),
    Timer(IntervalFunc<Context>),
});

pub struct Guard(SyncSender<()>);

impl Guard {
    pub fn stop(self) -> Result<(), SendError<()>> {
        self.0.send(())
    }
}

fn create_interval(scope: &mut Scope<Context>, duration: Duration, rx: Receiver<()>)
-> rotor::Response<IntervalFunc<Context>, Void>
{
    interval_func(scope, duration, move |scope: &mut Scope<Context>| {
        match rx.try_recv() {
            Ok(_) | Err(TryRecvError::Disconnected) => {
                println!("Stopping server");
                scope.shutdown_loop();
            }
            _ => {},
        }
    })
}

pub fn start(context: Context, address: &str)
    -> Result<Guard, String>
{
    let (tx, rx) = mpsc::sync_channel::<()>(0);

    let event_loop = rotor::Loop::new(&rotor::Config::new()).unwrap();
    let mut loop_inst = event_loop.instantiate(context);

    let address: SocketAddr = try!(address.parse().map_err(|e| format!("{}", e)));
    let lst = try!(TcpListener::bind(&address).map_err(|e| format!("{}", e)));

    try!(loop_inst.add_machine_with(|scope| {
        Fsm::<Responder, TcpListener>::new(lst, (), scope)
            .wrap(|fsm| Machine::Http(fsm))
    }).map_err(|e| format!("{}", e)));

    try!(loop_inst.add_machine_with(|scope| {
        create_interval(scope, Duration::new(1, 0), rx)
            .wrap(|fsm| Machine::Timer(fsm))
    }).map_err(|e| format!("{}", e)));

    thread::spawn(move || {
        loop_inst.run().unwrap();
    });

    Ok(Guard(tx))
}

pub fn run(context: Context, address: &str)
    -> Result<(), String>
{
    let event_loop = rotor::Loop::new(&rotor::Config::new()).unwrap();
    let mut loop_inst = event_loop.instantiate(context);

    let address: SocketAddr = try!(address.parse().map_err(|e| format!("{}", e)));
    let lst = try!(TcpListener::bind(&address).map_err(|e| format!("{}", e)));

    try!(loop_inst.add_machine_with(|scope| {
        Fsm::<Responder, TcpListener>::new(lst, (), scope)
    }).map_err(|e| format!("{}", e)));

    try!(loop_inst.run().map_err(|e| format!("{}", e)));

    Ok(())
}

pub trait Router {
    fn match_route(&self, method: &str, path: &str) -> Option<Arc<Handler>>;
}

impl Router for Context {
    fn match_route(&self, method: &str, path: &str) -> Option<Arc<Handler>> {
        for ref route in self.routes().iter() {
            if route.is_match(method, path) {
                return Some(route.handler())
            }
        }
        None
    }
}

#[derive(Clone, Debug)]
pub enum Responder {
    Respond(Arc<Handler>),
    NotFound,
}

fn send_not_found(res: &mut Response) {
    let data = b"404 - Page not found";
    res.status(404, "Not Found");
    res.add_length(data.len() as u64).unwrap();
    res.add_header("Content-Type", b"text/plain").unwrap();
    res.done_headers().unwrap();
    res.write_body(data);
    res.done();
}

fn send_error(res: &mut Response, data: &str) {
    let data = data.as_bytes();
    res.status(500, "Internal Server Error");
    res.add_length(data.len() as u64).unwrap();
    res.add_header("Content-Type", b"text/plain").unwrap();
    res.done_headers().unwrap();
    res.write_body(data);
    res.done();
}

impl Server for Responder {
    type Seed = ();
    type Context = Context;

    fn headers_received(_seed: Self::Seed, head: Head, _res: &mut Response,
        scope: &mut Scope<Self::Context>)
        -> Option<(Self, RecvMode, Time)>
    {
        if scope.autoreload() {
            match scope.rebuild() {
                Ok(_) => {}
                Err(e) => {
                    println!("{}", e);
                    return None
                }
            }
        }

        let responder = match scope.match_route(head.method, head.path) {
            Some(route) => Responder::Respond(route.clone()),
            None => Responder::NotFound,
        };

        Some((responder, RecvMode::Buffered(1024), scope.now() + Duration::new(10, 0)))
    }

    fn request_received(self, _data: &[u8], res: &mut Response,
        scope: &mut Scope<Context>)
        -> Option<Self>
    {
        let result = match self {
            Responder::Respond(handler) => {
                handler.handle(res)
            },
            Responder::NotFound => {
                match scope.not_found_handler() {
                    Some(ref handler) => handler.handle(res),
                    None => { send_not_found(res); Ok(()) },
                }
            }
        };
        result.map_err(|e| send_error(res, &e)).ok();

        None
    }

    fn request_chunk(self, _chunk: &[u8], _response: &mut Response,
        _scope: &mut Scope<Context>)
        -> Option<Self>
    {
        unreachable!();
    }

    /// End of request body, only for Progressive requests
    fn request_end(self, _response: &mut Response, _scope: &mut Scope<Context>)
        -> Option<Self>
    {
        unreachable!();
    }

    fn timeout(self, _response: &mut Response, _scope: &mut Scope<Context>)
        -> Option<(Self, Time)>
    {
        unimplemented!();
    }

    fn wakeup(self, _response: &mut Response, _scope: &mut Scope<Context>)
        -> Option<Self>
    {
        unimplemented!();
    }
}

#[cfg(test)]
mod tests {
    use std::thread;
    use std::time::Duration;
    use context::Context;
    use super::start as start_server;

    #[test]
    fn server_shutdown() {
        let context = Context::new();
        let guard = start_server(context, "127.0.0.1:7000").unwrap();
        guard.stop().unwrap();
    }
}
<|endoftext|>


<commit_before>use grain_capnp::{PowerboxCapability, UiView, UiSession};
use web_session_capnp::{WebSession};

use capnp::capability::{ClientHook, FromServer};
use capnp::AnyPointer;
use capnp_rpc::rpc::{RpcConnectionState, SturdyRefRestorer};
use capnp_rpc::capability::{LocalClient};

pub struct UiViewImpl;

impl PowerboxCapability::Server for UiViewImpl {
    fn get_powerbox_info(&mut self, context : PowerboxCapability::GetPowerboxInfoContext) {
        context.done()
    }
}

impl UiView::Server for UiViewImpl {
    fn get_view_info(&mut self, context : UiView::GetViewInfoContext) {
        context.done()
    }

    fn new_session(&mut self, mut context : UiView::NewSessionContext) {
        println!("asked for a new session!");
        let (_, results) = context.get();

        let client : WebSession::Client = FromServer::new(None::<LocalClient>, ~WebSessionImpl);
        // we need to do this dance to upcast.
        results.set_session(UiSession::Client { client : client.client});

        context.done()
    }
}

pub struct WebSessionImpl;

impl UiSession::Server for WebSessionImpl {

}

static main_css : &'static str =
    "body { font-family: Helvetica, Sans, Arial;
            font-size: medium;
             margin-left: auto;
             margin-right: auto;
             width: 600px;
     }";

static header : &'static str =
  r#"<title> acronymy </title><link rel="stylesheet" type="text/css" href="main.css" >
 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
  "#;

fn html_body(body :&str) -> ~str {
    format!("{}{}", header, body)
}

struct Path {
    path : ~str,
    query : Vec<(~str,Vec<~str>)>,
}

impl Path {
    fn new() -> Path {
        Path { path : ~"", query : Vec::new() }
    }
}

fn parse_path(path : &str) -> Path {
    let mut result = Path::new();

    let v : ~[&str] = path.splitn('?', 2).collect();
    if v.len() == 0 {
        return result;
    }
    result.path = v[0].into_owned();
    if v.len() == 1 {
        return result;
    }
    for attr in v[1].split('&') {
        let a : ~[&str] = attr.splitn('=', 2).collect();
        if a.len() == 2 {
            result.query.push((a[0].into_owned(),
                               a[1].split('+').map(|s| {s.into_owned() }).collect()));
        }
    }
    return result;
}

impl WebSession::Server for WebSessionImpl {
    fn get(&mut self, mut context : WebSession::GetContext) {
        println!("GET");
        let (params, results) = context.get();
        let raw_path = params.get_path();
        let content = results.init_content();
        content.set_mime_type("text/html");

        let path = parse_path(raw_path);
        println!("path = {}", raw_path);
        println!("{}, {}", path.path, path.query);

        if raw_path == "main.css" {
            content.get_body().set_bytes(main_css.as_bytes())
        } else if path.path.as_slice() == "define" {
            if path.query.len() != 1 {
                return context.fail();
            }
            let &(_, ref v) = path.query.get(0);

            content.get_body().set_bytes(
                html_body(
                    "
AWESOME

                     <form action=\"define\" method=\"get\">
                     <input name=\"word\"/><button>go</button></form>").as_bytes());

        } else {
            content.get_body().set_bytes(
                html_body(
                    "<form action=\"define\" method=\"get\">
                     <input name=\"word\"/><button>go</button></form>").as_bytes());
        }
        context.done()
    }
    fn post(&mut self, context : WebSession::PostContext) {
        println!("POST");
        context.done()
    }
    fn put(&mut self, context : WebSession::PutContext) {
        println!("PUT");
        context.done()
    }
    fn delete(&mut self, context : WebSession::DeleteContext) {
        println!("DELETE");
        context.done()
    }
    fn open_web_socket(&mut self, context : WebSession::OpenWebSocketContext) {
        println!("OPEN WEB SOCKET");
        context.done()
    }
}

pub struct FdStream {
    inner : ~::std::rt::rtio::RtioFileStream:Send,
}

impl FdStream {
    pub fn new(fd : ::libc::c_int) -> ::std::io::IoResult<FdStream> {
        ::std::rt::rtio::LocalIo::maybe_raise(|io| {
            Ok (FdStream { inner : io.fs_from_raw_fd(fd, ::std::rt::rtio::DontClose) })
        })
    }
}

impl Reader for FdStream {
    fn read(&mut self, buf : &mut [u8]) -> ::std::io::IoResult<uint> {
        self.inner.read(buf).map(|i| i as uint)
    }
}

impl Writer for FdStream {
    fn write(&mut self, buf : &[u8]) -> ::std::io::IoResult<()> {
        self.inner.write(buf)
    }
}

pub struct Restorer;

impl SturdyRefRestorer for Restorer {
    fn restore(&self, obj_id : AnyPointer::Reader) -> Option<~ClientHook:Send> {
        if obj_id.is_null() {
            let client : UiView::Client = FromServer::new(None::<LocalClient>, ~UiViewImpl);
            Some(client.client.hook)
        } else {
            None
        }
    }
}

pub fn main() -> ::std::io::IoResult<()> {
    let ifs = try!(FdStream::new(3));
    let ofs = try!(FdStream::new(3));

    let connection_state = RpcConnectionState::new();
    connection_state.run(ifs, ofs, Restorer);

    Ok(())
}

<commit_msg>make it look prettier?<commit_after>use grain_capnp::{PowerboxCapability, UiView, UiSession};
use web_session_capnp::{WebSession};

use capnp::capability::{ClientHook, FromServer};
use capnp::AnyPointer;
use capnp_rpc::rpc::{RpcConnectionState, SturdyRefRestorer};
use capnp_rpc::capability::{LocalClient};

pub struct UiViewImpl;

impl PowerboxCapability::Server for UiViewImpl {
    fn get_powerbox_info(&mut self, context : PowerboxCapability::GetPowerboxInfoContext) {
        context.done()
    }
}

impl UiView::Server for UiViewImpl {
    fn get_view_info(&mut self, context : UiView::GetViewInfoContext) {
        context.done()
    }

    fn new_session(&mut self, mut context : UiView::NewSessionContext) {
        println!("asked for a new session!");
        let (_, results) = context.get();

        let client : WebSession::Client = FromServer::new(None::<LocalClient>, ~WebSessionImpl);
        // we need to do this dance to upcast.
        results.set_session(UiSession::Client { client : client.client});

        context.done()
    }
}

pub struct WebSessionImpl;

impl UiSession::Server for WebSessionImpl {

}

static main_css : &'static str =
    "body { font-family: Helvetica, Sans, Arial;
            font-size: medium;
             margin-left: auto;
             margin-right: auto;
             width: 600px;
     }
    .word {
        text-align: center;
        font-size: 500%;
     }
     ";

static header : &'static str =
  r#"<title> acronymy </title><link rel="stylesheet" type="text/css" href="main.css" >
 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
  "#;

fn html_body(body :&str) -> ~str {
    format!("{}{}", header, body)
}

struct Path {
    path : ~str,
    query : Vec<(~str,Vec<~str>)>,
}

impl Path {
    fn new() -> Path {
        Path { path : ~"", query : Vec::new() }
    }
}

fn parse_path(path : &str) -> Path {
    let mut result = Path::new();

    let v : ~[&str] = path.splitn('?', 2).collect();
    if v.len() == 0 {
        return result;
    }
    result.path = v[0].into_owned();
    if v.len() == 1 {
        return result;
    }
    for attr in v[1].split('&') {
        let a : ~[&str] = attr.splitn('=', 2).collect();
        if a.len() == 2 {
            result.query.push((a[0].into_owned(),
                               a[1].split('+').map(|s| {s.into_owned() }).collect()));
        }
    }
    return result;
}

impl WebSession::Server for WebSessionImpl {
    fn get(&mut self, mut context : WebSession::GetContext) {
        println!("GET");
        let (params, results) = context.get();
        let raw_path = params.get_path();
        let content = results.init_content();
        content.set_mime_type("text/html");

        let path = parse_path(raw_path);
        println!("path = {}", raw_path);
        println!("{}, {}", path.path, path.query);

        if raw_path == "main.css" {
            content.get_body().set_bytes(main_css.as_bytes())
        } else if path.path.as_slice() == "define" {
            if path.query.len() != 1 {
                return context.fail();
            }
            let &(_, ref v) = path.query.get(0);

            content.get_body().set_bytes(
                html_body(
                    format!(
                        "
{word}

                     <form action=\"define/{word}\" method=\"get\">
                     <input name=\"word\"/><button>define</button></form>",
                        word=v.get(0))).as_bytes());

        } else {
            content.get_body().set_bytes(
                html_body(
                    "<form action=\"define\" method=\"get\">
                     <input name=\"word\"/><button>go</button></form>").as_bytes());
        }
        context.done()
    }
    fn post(&mut self, context : WebSession::PostContext) {
        println!("POST");
        context.done()
    }
    fn put(&mut self, context : WebSession::PutContext) {
        println!("PUT");
        context.done()
    }
    fn delete(&mut self, context : WebSession::DeleteContext) {
        println!("DELETE");
        context.done()
    }
    fn open_web_socket(&mut self, context : WebSession::OpenWebSocketContext) {
        println!("OPEN WEB SOCKET");
        context.done()
    }
}

pub struct FdStream {
    inner : ~::std::rt::rtio::RtioFileStream:Send,
}

impl FdStream {
    pub fn new(fd : ::libc::c_int) -> ::std::io::IoResult<FdStream> {
        ::std::rt::rtio::LocalIo::maybe_raise(|io| {
            Ok (FdStream { inner : io.fs_from_raw_fd(fd, ::std::rt::rtio::DontClose) })
        })
    }
}

impl Reader for FdStream {
    fn read(&mut self, buf : &mut [u8]) -> ::std::io::IoResult<uint> {
        self.inner.read(buf).map(|i| i as uint)
    }
}

impl Writer for FdStream {
    fn write(&mut self, buf : &[u8]) -> ::std::io::IoResult<()> {
        self.inner.write(buf)
    }
}

pub struct Restorer;

impl SturdyRefRestorer for Restorer {
    fn restore(&self, obj_id : AnyPointer::Reader) -> Option<~ClientHook:Send> {
        if obj_id.is_null() {
            let client : UiView::Client = FromServer::new(None::<LocalClient>, ~UiViewImpl);
            Some(client.client.hook)
        } else {
            None
        }
    }
}

pub fn main() -> ::std::io::IoResult<()> {
    let ifs = try!(FdStream::new(3));
    let ofs = try!(FdStream::new(3));

    let connection_state = RpcConnectionState::new();
    connection_state.run(ifs, ofs, Restorer);

    Ok(())
}

<|endoftext|>


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

use core::prelude::*;
use core::str;
use core::io;

use driver::session::{OptLevel, No, Less, Aggressive};
use driver::session::{Session};
use lib::llvm::{PassRef, ModuleRef,PassManagerRef,TargetDataRef};
use lib::llvm::llvm;
use lib;

pub struct PassManager {
    priv llpm: PassManagerRef
}

impl Drop for PassManager {
    fn finalize(&self) {
        unsafe {
            llvm::LLVMDisposePassManager(self.llpm);
        }
    }
}

impl PassManager {
    pub fn new(td: TargetDataRef) -> PassManager {
        unsafe {
            let pm = PassManager {
                llpm: llvm::LLVMCreatePassManager()
            };
            llvm::LLVMAddTargetData(td, pm.llpm);

            return pm;
        }
    }

    pub fn add_pass(&mut self, pass:PassRef) {
        unsafe {
            llvm::LLVMAddPass(self.llpm, pass);
        }
    }

    pub fn add_pass_from_name(&mut self, name:&str) {
        let pass = create_pass(name).unwrap();
        self.add_pass(pass);
    }

    pub fn run(&self, md:ModuleRef) -> bool {
        unsafe {
            llvm::LLVMRunPassManager(self.llpm, md) == lib::llvm::True
        }
    }
}

pub fn create_standard_passes(level:OptLevel) -> ~[~str] {
    let mut passes = ~[~"strip-dead-prototypes"];

    if level == No {
        passes.push(~"always-inline");
        return passes;
    }

    passes.push(~"targetlibinfo");

    passes.push(~"tbaa");
    passes.push(~"basicaa");

    passes.push(~"early-cse");

    passes.push(~"globalopt");
    passes.push(~"ipsccp");
    passes.push(~"deadargelim");
    passes.push(~"instcombine");
    passes.push(~"simplifycfg");

    passes.push(~"prune-eh");

    if level == Aggressive {
        passes.push(~"mergefunc");
    }

    passes.push(~"inline");

    passes.push(~"functionattrs");

    if level == Aggressive {
        passes.push(~"argpromotion");
    }

    passes.push(~"early-cse");
    passes.push(~"simplify-libcalls");
    passes.push(~"jump-threading");
    passes.push(~"correlated-propagation");
    passes.push(~"simplifycfg");
    passes.push(~"instcombine");

    passes.push(~"tailcallelim");
    passes.push(~"simplifycfg");
    passes.push(~"reassociate");
    passes.push(~"loop-rotate");
    passes.push(~"licm");

    passes.push(~"lcssa");
    passes.push(~"loop-unswitch");

    passes.push(~"instcombine");
    passes.push(~"indvars");
    passes.push(~"loop-idiom");
    passes.push(~"loop-deletion");

    if level == Aggressive {
        passes.push(~"loop-vectorize");
    }

    passes.push(~"loop-unroll");

    if level != Less {
        passes.push(~"gvn");
    }

    passes.push(~"memcpyopt");
    passes.push(~"sccp");

    passes.push(~"instcombine");
    passes.push(~"jump-threading");
    passes.push(~"correlated-propagation");
    passes.push(~"dse");

    passes.push(~"instcombine");
    passes.push(~"early-cse");

    passes.push(~"loop-unroll");

    passes.push(~"adce");
    passes.push(~"simplifycfg");
    passes.push(~"instsimplify");

    if level != Less {
        passes.push(~"globaldce");
        passes.push(~"constmerge");
    }

    return passes;
}

pub fn populate_pass_manager(sess: Session, pm: &mut PassManager, pass_list:&[~str]) {
    for pass_list.each |&nm| {
        match create_pass(nm) {
            Some(p) => pm.add_pass(p),
            None    => sess.warn(fmt!("Unknown pass %s", nm))
        }
    }
}

pub fn create_pass(name:&str) -> Option<PassRef> {
    do str::as_c_str(name) |s| {
        unsafe {
            let p = llvm::LLVMCreatePass(s);
            if p.is_null() {
                None
            } else {
                Some(p)
            }
        }
    }
}

pub fn list_passes() {
    io::println("\nAvailable Passes:");

    io::println("\nAnalysis Passes:");
    for analysis_passes.each |&(name, desc)| {
        io::println(fmt!("    %-30s -- %s", name, desc));
    }
    io::println("\nTransformation Passes:");
    for transform_passes.each |&(name, desc)| {
        io::println(fmt!("    %-30s -- %s", name, desc));
    }
    io::println("\nUtility Passes:");
    for utility_passes.each |&(name, desc)| {
        io::println(fmt!("    %-30s -- %s", name, desc));
    }
}

/** Analysis Passes */
pub static analysis_passes : &'static [(&'static str, &'static str)] = &'static [
    ("aa-eval",                         "Exhausive Alias Analysis Precision Evaluator"),
    ("asan",                            "AddressSanitizer"),
    ("basicaa",                         "Basic Alias Analysis"),
    ("basiccg",                         "Basic CallGraph Construction"),
    ("block-freq",                      "Block Frequency Analysis"),
    ("cost-model",                      "Cost Model Analysis"),
    ("count-aa",                        "Count Alias Analysis Query Responses"),
    ("da",                              "Dependence Analysis"),
    ("debug-aa",                        "AA Use Debugger"),
    ("domfrontier",                     "Dominance Frontier Construction"),
    ("domtree",                         "Dominator Tree Construction"),
    ("globalsmodref-aa",                "Simple mod/ref analysis for globals"),
    ("instcount",                       "Count the various types of Instructions"),
    ("intervals",                       "Interval Partition Construction"),
    ("iv-users",                        "Induction Variable Users"),
    ("lazy-value-info",                 "Lazy Value Information Analysis"),
    ("libcall-aa",                      "LibCall Alias Analysis"),
    ("lint",                            "Statically lint-check LLVM IR"),
    ("loops",                           "Natural Loop Information"),
    ("memdep",                          "Memory Dependence Analysis"),
    ("module-debuginfo",                "Decodes module-level debug info"),
    ("profile-estimator",               "Estimate profiling information"),
    ("profile-loader",                  "Load profile information from llvmprof.out"),
    ("profile-verifier",                "Verify profiling information"),
    ("regions",                         "Detect single entry single exit regions"),
    ("scalar-evolution",                "Scalar Evolution Analysis"),
    ("scev-aa",                         "Scalar Evolution-based Alias Analysis"),
    ("tbaa",                            "Type-Based Alias Analysis"),
    ("tsan",                            "ThreadSanitizer"),
];

/** Transformation Passes */
pub static transform_passes : &'static [(&'static str, &'static str)] = &'static [
    ("adce",                            "Aggressive Dead Code Elimination"),
    ("always-inline",                   "Inliner for #[inline(always)] functions"),
    ("argpromotion",                    "Promote 'by reference' arguments to scalars"),
    ("bb-vectorize",                    "Basic-Block Vectorization"),
    ("block-placement",                 "Profile Guided Basic Block Placement"),
    ("bounds-checking",                 "Run-time bounds checking"),
    ("break-crit-edges",                "Break critical edges in CFG"),
    ("codegenprepare",                  "Optimize for code generation"),
    ("constmerge",                      "Merge Duplicate Global Constants"),
    ("constprop",                       "Simple constant propagation"),
    ("correlated-propagation",          "Value Propagation"),
    ("da",                              "Data Layout"),
    ("dce",                             "Dead Code Elimination"),
    ("deadargelim",                     "Dead Argument Elimination"),
    ("die",                             "Dead Instruction Elimination"),
    ("dse",                             "Dead Store Elimination"),
    ("early-cse",                       "Early CSE"),
    ("functionattrs",                   "Deduce function attributes"),
    ("globaldce",                       "Dead Global Elimination"),
    ("globalopt",                       "Global Variable Optimizer"),
    ("gvn",                             "Global Value Numbering"),
    ("indvars",                         "Canonicalize Induction Variables"),
    ("inline",                          "Function Integration/Inlining"),
    ("insert-edge-profiling",           "Insert instrumentation for edge profiling"),
    ("insert-gcov-profiling",           "Insert instrumentation for GCOV profiling"),
    ("insert-optimal-edge-profiling",   "Insert optimal instrumentation for edge profiling"),
    ("instcombine",                     "Combine redundant instructions"),
    ("instsimplify",                    "Remove redundant instructions"),
    ("ipconstprop",                     "Interprocedural constant propagation"),
    ("ipsccp",                          "Interprocedural Sparse Conditional Constant Propagation"),
    ("jump-threading",                  "Jump Threading"),
    ("lcssa",                           "Loop-Closed SSA Form Pass"),
    ("licm",                            "Loop Invariant Code Motion"),
    ("loop-deletion",                   "Delete dead loops"),
    ("loop-extract",                    "Extract loops into new functions"),
    ("loop-extract-single",             "Extract at most one loop into a new function"),
    ("loop-idiom",                      "Recognise loop idioms"),
    ("loop-instsimplify",               "Simplify instructions in loops"),
    ("loop-reduce",                     "Loop Strength Reduction"),
    ("loop-rotate",                     "Rotate Loops"),
    ("loop-simplify",                   "Canonicalize natural loops"),
    ("loop-unroll",                     "Unroll loops"),
    ("loop-unswitch",                   "Unswitch loops"),
    ("loop-vectorize",                  "Loop Vectorization"),
    ("lower-expect",                    "Lower 'expect' Intrinsics"),
    ("mem2reg",                         "Promote Memory to Register"),
    ("memcpyopt",                       "MemCpy Optimization"),
    ("mergefunc",                       "Merge Functions"),
    ("mergereturn",                     "Unify function exit nodes"),
    ("partial-inliner",                 "Partial Inliner"),
    ("prune-eh",                        "Remove unused exception handling info"),
    ("reassociate",                     "Reassociate expressions"),
    ("reg2mem",                         "Demote all values to stack slots"),
    ("scalarrepl",                      "Scalar Replacement of Aggregates (DT)"),
    ("scalarrepl-ssa",                  "Scalar Replacement of Aggregates (SSAUp)"),
    ("sccp",                            "Sparse Conditional Constant Propagation"),
    ("simplify-libcalls",               "Simplify well-known library calls"),
    ("simplifycfg",                     "Simplify the CFG"),
    ("sink",                            "Code sinking"),
    ("strip",                           "Strip all symbols from a module"),
    ("strip-dead-debug-info",           "Strip debug info for unused symbols"),
    ("strip-dead-prototypes",           "Strip Unused Function Prototypes"),
    ("strip-debug-declare",             "Strip all llvm.dbg.declare intrinsics"),
    ("strip-nondebug",                  "Strip all symbols, except dbg symbols, from a module"),
    ("sroa",                            "Scalar Replacement of Aggregates"),
    ("tailcallelim",                    "Tail Call Elimination"),
];

/** Utility Passes */
static utility_passes : &'static [(&'static str, &'static str)] = &'static [
    ("instnamer",                       "Assign names to anonymous instructions"),
    ("verify",                          "Module Verifier"),
];

#[test]
fn passes_exist() {
    let mut failed = ~[];
    unsafe { llvm::LLVMInitializePasses(); }
    for analysis_passes.each() |&(name,_)| {
        if !create_pass(name).is_some() {
            failed.push(name);
        }
    }
    for transform_passes.each() |&(name,_)| {
        if !create_pass(name).is_some() {
            failed.push(name);
        }
    }
    for utility_passes.each() |&(name,_)| {
        if !create_pass(name).is_some() {
            failed.push(name);
        }
    }

    if failed.len() > 0 {
        io::println("Some passes don't exist:");
        for failed.each |&n| {
            io::println(fmt!("    %s", n));
        }
        fail!();
    }
}
<commit_msg>auto merge of #6881 : Aatch/rust/new-passes-2, r=thestinger<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use core::prelude::*;
use core::str;
use core::io;

use driver::session::{OptLevel, No, Less, Aggressive};
use driver::session::{Session};
use lib::llvm::{PassRef, ModuleRef,PassManagerRef,TargetDataRef};
use lib::llvm::llvm;
use lib;

pub struct PassManager {
    priv llpm: PassManagerRef
}

impl Drop for PassManager {
    fn finalize(&self) {
        unsafe {
            llvm::LLVMDisposePassManager(self.llpm);
        }
    }
}

impl PassManager {
    pub fn new(td: TargetDataRef) -> PassManager {
        unsafe {
            let pm = PassManager {
                llpm: llvm::LLVMCreatePassManager()
            };
            llvm::LLVMAddTargetData(td, pm.llpm);

            return pm;
        }
    }

    pub fn add_pass(&mut self, pass:PassRef) {
        unsafe {
            llvm::LLVMAddPass(self.llpm, pass);
        }
    }

    pub fn add_pass_from_name(&mut self, name:&str) {
        let pass = create_pass(name).unwrap();
        self.add_pass(pass);
    }

    pub fn run(&self, md:ModuleRef) -> bool {
        unsafe {
            llvm::LLVMRunPassManager(self.llpm, md) == lib::llvm::True
        }
    }
}

pub fn create_standard_passes(level:OptLevel) -> ~[~str] {
    let mut passes = ~[~"strip-dead-prototypes"];

    if level == No {
        passes.push(~"always-inline");
        return passes;
    }

    passes.push(~"targetlibinfo");

    passes.push(~"scev-aa");
    passes.push(~"basicaa");

    passes.push(~"instcombine");
    passes.push(~"simplifycfg");
    passes.push(~"scalarrepl-ssa");
    passes.push(~"early-cse");

    passes.push(~"globalopt");
    passes.push(~"ipsccp");
    passes.push(~"deadargelim");
    passes.push(~"instcombine");
    passes.push(~"simplifycfg");

    passes.push(~"prune-eh");

    passes.push(~"inline");

    passes.push(~"functionattrs");

    if level == Aggressive {
        passes.push(~"argpromotion");
    }

    passes.push(~"scalarrepl-ssa");
    passes.push(~"early-cse");
    passes.push(~"simplify-libcalls");
    passes.push(~"jump-threading");
    passes.push(~"correlated-propagation");
    passes.push(~"simplifycfg");
    passes.push(~"instcombine");

    passes.push(~"tailcallelim");
    passes.push(~"simplifycfg");
    passes.push(~"reassociate");
    passes.push(~"loop-rotate");
    passes.push(~"licm");

    passes.push(~"lcssa");
    passes.push(~"loop-unswitch");

    passes.push(~"instcombine");
    passes.push(~"indvars");
    passes.push(~"loop-idiom");
    passes.push(~"loop-deletion");

    if level == Aggressive {
        passes.push(~"loop-vectorize");
    }

    passes.push(~"loop-unroll");

    if level != Less {
        passes.push(~"gvn");
    }

    passes.push(~"memcpyopt");
    passes.push(~"sccp");

    passes.push(~"instcombine");
    passes.push(~"jump-threading");
    passes.push(~"correlated-propagation");
    passes.push(~"dse");

    passes.push(~"adce");
    passes.push(~"simplifycfg");
    passes.push(~"instsimplify");

    if level != Less {
        passes.push(~"globaldce");
        passes.push(~"constmerge");
    }

    return passes;
}

pub fn populate_pass_manager(sess: Session, pm: &mut PassManager, pass_list:&[~str]) {
    for pass_list.each |&nm| {
        match create_pass(nm) {
            Some(p) => pm.add_pass(p),
            None    => sess.warn(fmt!("Unknown pass %s", nm))
        }
    }
}

pub fn create_pass(name:&str) -> Option<PassRef> {
    do str::as_c_str(name) |s| {
        unsafe {
            let p = llvm::LLVMCreatePass(s);
            if p.is_null() {
                None
            } else {
                Some(p)
            }
        }
    }
}

pub fn list_passes() {
    io::println("\nAvailable Passes:");

    io::println("\nAnalysis Passes:");
    for analysis_passes.each |&(name, desc)| {
        io::println(fmt!("    %-30s -- %s", name, desc));
    }
    io::println("\nTransformation Passes:");
    for transform_passes.each |&(name, desc)| {
        io::println(fmt!("    %-30s -- %s", name, desc));
    }
    io::println("\nUtility Passes:");
    for utility_passes.each |&(name, desc)| {
        io::println(fmt!("    %-30s -- %s", name, desc));
    }
}

/** Analysis Passes */
pub static analysis_passes : &'static [(&'static str, &'static str)] = &'static [
    ("aa-eval",                         "Exhausive Alias Analysis Precision Evaluator"),
    ("asan",                            "AddressSanitizer"),
    ("basicaa",                         "Basic Alias Analysis"),
    ("basiccg",                         "Basic CallGraph Construction"),
    ("block-freq",                      "Block Frequency Analysis"),
    ("cost-model",                      "Cost Model Analysis"),
    ("count-aa",                        "Count Alias Analysis Query Responses"),
    ("da",                              "Dependence Analysis"),
    ("debug-aa",                        "AA Use Debugger"),
    ("domfrontier",                     "Dominance Frontier Construction"),
    ("domtree",                         "Dominator Tree Construction"),
    ("globalsmodref-aa",                "Simple mod/ref analysis for globals"),
    ("instcount",                       "Count the various types of Instructions"),
    ("intervals",                       "Interval Partition Construction"),
    ("iv-users",                        "Induction Variable Users"),
    ("lazy-value-info",                 "Lazy Value Information Analysis"),
    ("libcall-aa",                      "LibCall Alias Analysis"),
    ("lint",                            "Statically lint-check LLVM IR"),
    ("loops",                           "Natural Loop Information"),
    ("memdep",                          "Memory Dependence Analysis"),
    ("module-debuginfo",                "Decodes module-level debug info"),
    ("profile-estimator",               "Estimate profiling information"),
    ("profile-loader",                  "Load profile information from llvmprof.out"),
    ("profile-verifier",                "Verify profiling information"),
    ("regions",                         "Detect single entry single exit regions"),
    ("scalar-evolution",                "Scalar Evolution Analysis"),
    ("scev-aa",                         "Scalar Evolution-based Alias Analysis"),
    ("tbaa",                            "Type-Based Alias Analysis"),
    ("tsan",                            "ThreadSanitizer"),
];

/** Transformation Passes */
pub static transform_passes : &'static [(&'static str, &'static str)] = &'static [
    ("adce",                            "Aggressive Dead Code Elimination"),
    ("always-inline",                   "Inliner for #[inline(always)] functions"),
    ("argpromotion",                    "Promote 'by reference' arguments to scalars"),
    ("bb-vectorize",                    "Basic-Block Vectorization"),
    ("block-placement",                 "Profile Guided Basic Block Placement"),
    ("bounds-checking",                 "Run-time bounds checking"),
    ("break-crit-edges",                "Break critical edges in CFG"),
    ("codegenprepare",                  "Optimize for code generation"),
    ("constmerge",                      "Merge Duplicate Global Constants"),
    ("constprop",                       "Simple constant propagation"),
    ("correlated-propagation",          "Value Propagation"),
    ("da",                              "Data Layout"),
    ("dce",                             "Dead Code Elimination"),
    ("deadargelim",                     "Dead Argument Elimination"),
    ("die",                             "Dead Instruction Elimination"),
    ("dse",                             "Dead Store Elimination"),
    ("early-cse",                       "Early CSE"),
    ("functionattrs",                   "Deduce function attributes"),
    ("globaldce",                       "Dead Global Elimination"),
    ("globalopt",                       "Global Variable Optimizer"),
    ("gvn",                             "Global Value Numbering"),
    ("indvars",                         "Canonicalize Induction Variables"),
    ("inline",                          "Function Integration/Inlining"),
    ("insert-edge-profiling",           "Insert instrumentation for edge profiling"),
    ("insert-gcov-profiling",           "Insert instrumentation for GCOV profiling"),
    ("insert-optimal-edge-profiling",   "Insert optimal instrumentation for edge profiling"),
    ("instcombine",                     "Combine redundant instructions"),
    ("instsimplify",                    "Remove redundant instructions"),
    ("ipconstprop",                     "Interprocedural constant propagation"),
    ("ipsccp",                          "Interprocedural Sparse Conditional Constant Propagation"),
    ("jump-threading",                  "Jump Threading"),
    ("lcssa",                           "Loop-Closed SSA Form Pass"),
    ("licm",                            "Loop Invariant Code Motion"),
    ("loop-deletion",                   "Delete dead loops"),
    ("loop-extract",                    "Extract loops into new functions"),
    ("loop-extract-single",             "Extract at most one loop into a new function"),
    ("loop-idiom",                      "Recognise loop idioms"),
    ("loop-instsimplify",               "Simplify instructions in loops"),
    ("loop-reduce",                     "Loop Strength Reduction"),
    ("loop-rotate",                     "Rotate Loops"),
    ("loop-simplify",                   "Canonicalize natural loops"),
    ("loop-unroll",                     "Unroll loops"),
    ("loop-unswitch",                   "Unswitch loops"),
    ("loop-vectorize",                  "Loop Vectorization"),
    ("lower-expect",                    "Lower 'expect' Intrinsics"),
    ("mem2reg",                         "Promote Memory to Register"),
    ("memcpyopt",                       "MemCpy Optimization"),
    ("mergefunc",                       "Merge Functions"),
    ("mergereturn",                     "Unify function exit nodes"),
    ("partial-inliner",                 "Partial Inliner"),
    ("prune-eh",                        "Remove unused exception handling info"),
    ("reassociate",                     "Reassociate expressions"),
    ("reg2mem",                         "Demote all values to stack slots"),
    ("scalarrepl",                      "Scalar Replacement of Aggregates (DT)"),
    ("scalarrepl-ssa",                  "Scalar Replacement of Aggregates (SSAUp)"),
    ("sccp",                            "Sparse Conditional Constant Propagation"),
    ("simplify-libcalls",               "Simplify well-known library calls"),
    ("simplifycfg",                     "Simplify the CFG"),
    ("sink",                            "Code sinking"),
    ("strip",                           "Strip all symbols from a module"),
    ("strip-dead-debug-info",           "Strip debug info for unused symbols"),
    ("strip-dead-prototypes",           "Strip Unused Function Prototypes"),
    ("strip-debug-declare",             "Strip all llvm.dbg.declare intrinsics"),
    ("strip-nondebug",                  "Strip all symbols, except dbg symbols, from a module"),
    ("sroa",                            "Scalar Replacement of Aggregates"),
    ("tailcallelim",                    "Tail Call Elimination"),
];

/** Utility Passes */
static utility_passes : &'static [(&'static str, &'static str)] = &'static [
    ("instnamer",                       "Assign names to anonymous instructions"),
    ("verify",                          "Module Verifier"),
];

#[test]
fn passes_exist() {
    let mut failed = ~[];
    unsafe { llvm::LLVMInitializePasses(); }
    for analysis_passes.each() |&(name,_)| {
        if !create_pass(name).is_some() {
            failed.push(name);
        }
    }
    for transform_passes.each() |&(name,_)| {
        if !create_pass(name).is_some() {
            failed.push(name);
        }
    }
    for utility_passes.each() |&(name,_)| {
        if !create_pass(name).is_some() {
            failed.push(name);
        }
    }

    if failed.len() > 0 {
        io::println("Some passes don't exist:");
        for failed.each |&n| {
            io::println(fmt!("    %s", n));
        }
        fail!();
    }
}
<|endoftext|>


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

use clone::Clone;
use kinds::Send;
use sync::arc::UnsafeArc;
use unstable::mutex::NativeMutex;

struct ExData<T> {
    lock: NativeMutex,
    failed: bool,
    data: T,
}

/**
 * An arc over mutable data that is protected by a lock. For library use only.
 *
 * # Safety note
 *
 * This uses a pthread mutex, not one that's aware of the userspace scheduler.
 * The user of an Exclusive must be careful not to invoke any functions that may
 * reschedule the task while holding the lock, or deadlock may result. If you
 * need to block or deschedule while accessing shared state, use extra::sync::RWArc.
 */
pub struct Exclusive<T> {
    x: UnsafeArc<ExData<T>>
}

impl<T:Send> Clone for Exclusive<T> {
    // Duplicate an Exclusive Arc, as std::arc::clone.
    fn clone(&self) -> Exclusive<T> {
        Exclusive { x: self.x.clone() }
    }
}

impl<T:Send> Exclusive<T> {
    pub fn new(user_data: T) -> Exclusive<T> {
        let data = ExData {
            lock: unsafe {NativeMutex::new()},
            failed: false,
            data: user_data
        };
        Exclusive {
            x: UnsafeArc::new(data)
        }
    }

    // Exactly like sync::MutexArc.access(). Same reason for being
    // unsafe.
    //
    // Currently, scheduling operations (i.e., descheduling, receiving on a pipe,
    // accessing the provided condition variable) are prohibited while inside
    // the Exclusive. Supporting that is a work in progress.
    #[inline]
    pub unsafe fn with<U>(&self, f: |x: &mut T| -> U) -> U {
        let rec = self.x.get();
        let _l = (*rec).lock.lock();
        if (*rec).failed {
            fail!("Poisoned Exclusive::new - another task failed inside!");
        }
        (*rec).failed = true;
        let result = f(&mut (*rec).data);
        (*rec).failed = false;
        result
    }

    #[inline]
    pub unsafe fn with_imm<U>(&self, f: |x: &T| -> U) -> U {
        self.with(|x| f(x))
    }

    #[inline]
    pub unsafe fn hold_and_signal(&self, f: |x: &mut T|) {
        let rec = self.x.get();
        let guard = (*rec).lock.lock();
        if (*rec).failed {
            fail!("Poisoned Exclusive::new - another task failed inside!");
        }
        (*rec).failed = true;
        f(&mut (*rec).data);
        (*rec).failed = false;
        guard.signal();
    }

    #[inline]
    pub unsafe fn hold_and_wait(&self, f: |x: &T| -> bool) {
        let rec = self.x.get();
        let l = (*rec).lock.lock();
        if (*rec).failed {
            fail!("Poisoned Exclusive::new - another task failed inside!");
        }
        (*rec).failed = true;
        let result = f(&(*rec).data);
        (*rec).failed = false;
        if result {
            l.wait();
        }
    }
}

#[cfg(test)]
mod tests {
    use option::*;
    use prelude::*;
    use super::Exclusive;
    use task;

    #[test]
    fn exclusive_new_arc() {
        unsafe {
            let mut futures = Vec::new();

            let num_tasks = 10;
            let count = 10;

            let total = Exclusive::new(box 0);

            for _ in range(0u, num_tasks) {
                let total = total.clone();
                let (tx, rx) = channel();
                futures.push(rx);

                task::spawn(proc() {
                    for _ in range(0u, count) {
                        total.with(|count| **count += 1);
                    }
                    tx.send(());
                });
            };

            for f in futures.mut_iter() { f.recv() }

            total.with(|total| assert!(**total == num_tasks * count));
        }
    }

    #[test] #[should_fail]
    fn exclusive_new_poison() {
        unsafe {
            // Tests that if one task fails inside of an Exclusive::new, subsequent
            // accesses will also fail.
            let x = Exclusive::new(1);
            let x2 = x.clone();
            let _ = task::try(proc() {
                x2.with(|one| assert_eq!(*one, 2))
            });
            x.with(|one| assert_eq!(*one, 1));
        }
    }
}
<commit_msg>std: Build Exclusive on Arc<Unsafe<T>><commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use alloc::arc::Arc;

use clone::Clone;
use kinds::Send;
use ty::Unsafe;
use unstable::mutex::NativeMutex;

struct ExData<T> {
    lock: NativeMutex,
    failed: bool,
    data: T,
}

/**
 * An arc over mutable data that is protected by a lock. For library use only.
 *
 * # Safety note
 *
 * This uses a pthread mutex, not one that's aware of the userspace scheduler.
 * The user of an Exclusive must be careful not to invoke any functions that may
 * reschedule the task while holding the lock, or deadlock may result. If you
 * need to block or deschedule while accessing shared state, use extra::sync::RWArc.
 */
pub struct Exclusive<T> {
    x: Arc<Unsafe<ExData<T>>>
}

impl<T:Send> Clone for Exclusive<T> {
    // Duplicate an Exclusive Arc, as std::arc::clone.
    fn clone(&self) -> Exclusive<T> {
        Exclusive { x: self.x.clone() }
    }
}

impl<T:Send> Exclusive<T> {
    pub fn new(user_data: T) -> Exclusive<T> {
        let data = ExData {
            lock: unsafe {NativeMutex::new()},
            failed: false,
            data: user_data
        };
        Exclusive {
            x: Arc::new(Unsafe::new(data))
        }
    }

    // Exactly like sync::MutexArc.access(). Same reason for being
    // unsafe.
    //
    // Currently, scheduling operations (i.e., descheduling, receiving on a pipe,
    // accessing the provided condition variable) are prohibited while inside
    // the Exclusive. Supporting that is a work in progress.
    #[inline]
    pub unsafe fn with<U>(&self, f: |x: &mut T| -> U) -> U {
        let rec = self.x.get();
        let _l = (*rec).lock.lock();
        if (*rec).failed {
            fail!("Poisoned Exclusive::new - another task failed inside!");
        }
        (*rec).failed = true;
        let result = f(&mut (*rec).data);
        (*rec).failed = false;
        result
    }

    #[inline]
    pub unsafe fn with_imm<U>(&self, f: |x: &T| -> U) -> U {
        self.with(|x| f(x))
    }

    #[inline]
    pub unsafe fn hold_and_signal(&self, f: |x: &mut T|) {
        let rec = self.x.get();
        let guard = (*rec).lock.lock();
        if (*rec).failed {
            fail!("Poisoned Exclusive::new - another task failed inside!");
        }
        (*rec).failed = true;
        f(&mut (*rec).data);
        (*rec).failed = false;
        guard.signal();
    }

    #[inline]
    pub unsafe fn hold_and_wait(&self, f: |x: &T| -> bool) {
        let rec = self.x.get();
        let l = (*rec).lock.lock();
        if (*rec).failed {
            fail!("Poisoned Exclusive::new - another task failed inside!");
        }
        (*rec).failed = true;
        let result = f(&(*rec).data);
        (*rec).failed = false;
        if result {
            l.wait();
        }
    }
}

#[cfg(test)]
mod tests {
    use option::*;
    use prelude::*;
    use super::Exclusive;
    use task;

    #[test]
    fn exclusive_new_arc() {
        unsafe {
            let mut futures = Vec::new();

            let num_tasks = 10;
            let count = 10;

            let total = Exclusive::new(box 0);

            for _ in range(0u, num_tasks) {
                let total = total.clone();
                let (tx, rx) = channel();
                futures.push(rx);

                task::spawn(proc() {
                    for _ in range(0u, count) {
                        total.with(|count| **count += 1);
                    }
                    tx.send(());
                });
            };

            for f in futures.mut_iter() { f.recv() }

            total.with(|total| assert!(**total == num_tasks * count));
        }
    }

    #[test] #[should_fail]
    fn exclusive_new_poison() {
        unsafe {
            // Tests that if one task fails inside of an Exclusive::new, subsequent
            // accesses will also fail.
            let x = Exclusive::new(1);
            let x2 = x.clone();
            let _ = task::try(proc() {
                x2.with(|one| assert_eq!(*one, 2))
            });
            x.with(|one| assert_eq!(*one, 1));
        }
    }
}
<|endoftext|>