<commit_before>//!
//! WebSocket Serial Server
//!
//! WebSocket Serial Server is a program that allows
//! that allows browsers to access serial ports
//! on localhost

// `error_chain!` can recurse deeply
#![recursion_limit = "1024"]

extern crate argparse;
extern crate base64;
extern crate env_logger;
#[macro_use]
extern crate error_chain;
extern crate hyper;
#[macro_use]
extern crate log;
extern crate rand;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate serialport;
extern crate websocket;

mod serial_support;

use std::io::Write;
use std::net::TcpStream;
use std::sync::mpsc::{channel, Sender};
use std::thread;
use std::time::Duration;

use argparse::{ArgumentParser, Store};
use websocket::client::Writer;
use websocket::result::WebSocketError;
use websocket::message::Type;
use websocket::{Server, Message};
use websocket::server::upgrade::WsUpgrade;
use hyper::Server as HttpServer;
use hyper::net::Fresh;
use hyper::server::request::Request;
use hyper::server::response::Response;
use rand::{thread_rng, Rng};

use serial_support::manage::Manager;
use serial_support::messages::*;
use serial_support::errors as e;

fn main() {

  // Init logger
  env_logger::init().unwrap();

  let sr = SerialRequest::List {};
  info!("serialized = {}", serde_json::to_string(&sr).unwrap());

  // Default port number
  let mut port = 8080;
  // Parse cmdline args
  {
    let mut ap = ArgumentParser::new();
    ap.set_description("Provide access to serial ports over JSON Websockets");
    ap.refer(&mut port)
      .add_option(&["-p", "--port"], Store, "Http Port");
    ap.parse_args_or_exit();
  }

  // websocket port
  let ws_port = port + 1;

  // html file for landing page
  let websocket_html = include_str!("websockets.html").replace("__WS_PORT__ = 8080",&format!("__WS_PORT__ = {}",ws_port));

  // The HTTP server handler
  let http_handler = move |_: Request, response: Response<Fresh>| {
    let mut response = response.start().expect(&"Could not start response");
    // Send a client webpage
    response
      .write_all(websocket_html.as_bytes())
      .expect(&"Could not get template as bytes");
    response.end().expect(&"Send response failed");
  };

  info!("Using ports {} {}", port, ws_port);

  // Set up channels and Manager
  let (sub_tx, sub_rx) = channel::<SubscriptionRequest>();
  let (sreq_tx, sreq_rx) = channel::<(String, SerialRequest)>();
  Manager::spawn(sreq_rx, sub_rx);

  // Start listening for http connections
  thread::spawn(
    move || {
      let http_server = HttpServer::http(format!("127.0.0.1:{}", port)).expect(
        &format!(
          "Failed to create http server on port {}",
          port
        ),
      );
      http_server
        .handle(http_handler)
        .expect(&"Failed to listen");
    },
  );

  // Start listening for WebSocket connections
  let ws_server = Server::bind(format!("127.0.0.1:{}", ws_port)).expect(
    &format!(
      "Failed bind on websocket port {}",
      ws_port
    ),
  );

  for connection in ws_server.filter_map(Result::ok) {
    // Spawn a new thread for each connection.
    let sub_tx_clone = sub_tx.clone();
    let sreq_tx_clone = sreq_tx.clone();
    spawn_ws_handler(sub_tx_clone, sreq_tx_clone, connection);
  }
}

fn spawn_ws_handler(
  sub_tx_clone: Sender<SubscriptionRequest>,
  sreq_tx_clone: Sender<(String, SerialRequest)>,
  connection: WsUpgrade<TcpStream>,
) {
  thread::spawn(move || ws_handler(&sub_tx_clone, &sreq_tx_clone, connection),);
}

fn ws_handler(
  sub_tx: &Sender<SubscriptionRequest>,
  sreq_tx: &Sender<(String, SerialRequest)>,
  connection: WsUpgrade<TcpStream>,
) {

  // Set up subscription id
  // let ts = SystemTime::now() - UNIX_EPOCH
  let prefix: String = thread_rng().gen_ascii_chars().take(8).collect();
  let sub_id = format!("thread-{}-{}", prefix, rand::random::<u16>());
  debug!("Spawned thread with subId '{}'", sub_id);

  if !connection
        .protocols()
        .contains(&"websocket-serial-json".to_string()) {
    connection
      .reject()
      .expect(&"Connection rejection failed.");
    return;
  }

  connection
    .tcp_stream()
    .set_nonblocking(true)
    .expect(&"Setting stream non-blocking failed.");

  // Create response channel
  let (sub_resp_tx, sub_resp_rx) = channel::<SerialResponse>();

  // Register sub_id with manager
  sub_tx
    .send(
      SubscriptionRequest {
        sub_id: sub_id.clone(),
        subscriber: sub_resp_tx,
      },
    )
    .expect(&format!("{}: Registering with manager failed.", sub_id));

  let client = connection
    .use_protocol(format!("websocket-serial-json"))
    .accept()
    .expect(&format!("{}: Accept protocol failed.", sub_id));

  let ip = client
    .peer_addr()
    .expect(&format!("{}: Could not get peer address", sub_id));

  info!("{}: Connection from {}", sub_id, ip);

  //   let message = Message::text("Hello".to_string());
  //   client.send_message(&message).unwrap();

  let (mut receiver, mut sender) = client
    .split()
    .expect(&format!("{}: WS client error", sub_id));

  // TODO Check thread cleanup
  // The new WS Client thread msg loop
  let mut exit = false;

  let sleep_dur = Duration::from_millis(33);

  while !exit {
    // Try and read a WS message
    match receiver.recv_message::<Message, _, _>() {
      Ok(message) => {
        match message.opcode {

          Type::Close => {
            let message = Message::close();
            sender
              .send_message(&message)
              .unwrap_or(info!("{}: Client {} hung up!", sub_id, ip));
            // Send close request to cleanup resources
            sreq_tx
              .send((sub_id.clone(), SerialRequest::Close { port: None }))
              .unwrap_or_else(
                |e| {
                  warn!(
                    "Client exit cleanup failed for sub_id '{}', cause '{}'",
                    sub_id,
                    e
                  )
                },
              );
            info!("{}: Client {} disconnected", sub_id, ip);
            exit = true;
          }

          Type::Ping => {
            let message = Message::pong(message.payload);
            sender
              .send_message(&message)
              .unwrap_or(info!("{}:  Could not ping client {}!", sub_id, ip));
          }

          _ => {

            // Get the payload, in a lossy manner
            let msg = String::from_utf8_lossy(&message.payload);

            // So we will get a result <SerialRequest::*,SerialResponse::Error> back
            match serde_json::from_str(&msg) {
              Ok(req) => {
                match sreq_tx.send((sub_id.clone(), req)) {
                  Err(err) => {
                    let error = e::ErrorKind::SendRequest(err).into();
                    send_serial_response_error(&sub_id, &mut sender, error);

                  }
                  _ => {}
                };
              }
              Err(err) => {
                let error = e::ErrorKind::Json(err).into();
                send_serial_response_error(&sub_id, &mut sender, error);
              }
            };
          }
        };
      }
      Err(e) => {
        match e {
          WebSocketError::NoDataAvailable => { /*Logging?*/ }
          _ => { /*Logging?*/ }
        };
      }
    }

    // Send on any serial responses
    match sub_resp_rx.try_recv() {
      Ok(resp) => {
        match serde_json::to_string(&resp) {
          Ok(json) => {
            let reply = Message::text(json.clone());
            // Weird, but message sending dose work
            // Do I misunderstand unwrap_or?
            sender
              .send_message(&reply)
              .unwrap_or_else(
                |e| {
                  info!(
                    "{}: Could not send message '{}' to client '{}', cause '{}'",
                    sub_id,
                    json,
                    ip,
                    e
                  )
                },
              );
          }
          Err(_) => {}
        }
      }
      _ => { /*Logging*/ }
    };
    thread::sleep(sleep_dur);
  }

  info!("Thread {} exiting!", sub_id);

}

fn send_serial_response_error(sub_id: &String, sender: &mut Writer<TcpStream>, error: e::Error) {
  let error = e::to_serial_response_error(error);
  serde_json::to_string(&error)
    .map_err(|err| e::ErrorKind::Json(err))
    .map(|json| Message::text(json))
    .map(
      |msg| {
        sender
          .send_message::<Message, _>(&msg)
          .map_err::<e::Error, _>(|err| e::ErrorKind::SendWsMessage(err).into())
      },
    )
    .unwrap_or_else(
      |_| {
        warn!("{}: Problem sending bad json error response", sub_id);
        Ok(())
      },
    )
    .is_ok(); // This shouldn't be needed?

}
<commit_msg>Using labeled loop and break statements to handle ws client thread termination now<commit_after>//!
//! WebSocket Serial Server
//!
//! WebSocket Serial Server is a program that allows
//! that allows browsers to access serial ports
//! on localhost

// `error_chain!` can recurse deeply
#![recursion_limit = "1024"]

extern crate argparse;
extern crate base64;
extern crate env_logger;
#[macro_use]
extern crate error_chain;
extern crate hyper;
#[macro_use]
extern crate log;
extern crate rand;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate serialport;
extern crate websocket;

mod serial_support;

use std::io::Write;
use std::net::TcpStream;
use std::sync::mpsc::{channel, Sender};
use std::thread;
use std::time::Duration;

use argparse::{ArgumentParser, Store};
use websocket::client::Writer;
use websocket::result::WebSocketError;
use websocket::message::Type;
use websocket::{Server, Message};
use websocket::server::upgrade::WsUpgrade;
use hyper::Server as HttpServer;
use hyper::net::Fresh;
use hyper::server::request::Request;
use hyper::server::response::Response;
use rand::{thread_rng, Rng};

use serial_support::manage::Manager;
use serial_support::messages::*;
use serial_support::errors as e;

// Max number of failures we allow when trying to send
// data to client before exiting
// TODO: Make configurable
const MAX_SEND_ERROR_COUNT: u32 = 5;

fn main() {

  // Init logger
  env_logger::init().unwrap();

  let sr = SerialRequest::List {};
  info!("serialized = {}", serde_json::to_string(&sr).unwrap());

  // Default port number
  let mut port = 8080;
  // Parse cmdline args
  {
    let mut ap = ArgumentParser::new();
    ap.set_description("Provide access to serial ports over JSON Websockets");
    ap.refer(&mut port)
      .add_option(&["-p", "--port"], Store, "Http Port");
    ap.parse_args_or_exit();
  }

  // websocket port
  let ws_port = port + 1;

  // html file for landing page
  let websocket_html = include_str!("websockets.html").replace(
    "__WS_PORT__ = 8081",
    &format!("__WS_PORT__ = {}", ws_port),
  );

  // The HTTP server handler
  let http_handler = move |_: Request, response: Response<Fresh>| {
    let mut response = response.start().expect(&"Could not start response");
    // Send a client webpage
    response
      .write_all(websocket_html.as_bytes())
      .expect(&"Could not get template as bytes");
    response.end().expect(&"Send response failed");
  };

  info!("Using ports {} {}", port, ws_port);

  // Set up channels and Manager
  let (sub_tx, sub_rx) = channel::<SubscriptionRequest>();
  let (sreq_tx, sreq_rx) = channel::<(String, SerialRequest)>();
  Manager::spawn(sreq_rx, sub_rx);

  // Start listening for http connections
  thread::spawn(
    move || {
      let http_server = HttpServer::http(format!("127.0.0.1:{}", port)).expect(
        &format!(
          "Failed to create http server on port {}",
          port
        ),
      );
      http_server
        .handle(http_handler)
        .expect(&"Failed to listen");
    },
  );

  // Start listening for WebSocket connections
  let ws_server = Server::bind(format!("127.0.0.1:{}", ws_port)).expect(
    &format!(
      "Failed bind on websocket port {}",
      ws_port
    ),
  );

  // Continuously iterate over connections,
  // spawning handlers
  for connection in ws_server.filter_map(Result::ok) {
    // Spawn a new thread for each connection.
    let sub_tx_clone = sub_tx.clone();
    let sreq_tx_clone = sreq_tx.clone();
    spawn_ws_handler(sub_tx_clone, sreq_tx_clone, connection);
  }
}

/// Spawn a websocket handler into its own thread
fn spawn_ws_handler(
  sub_tx_clone: Sender<SubscriptionRequest>,
  sreq_tx_clone: Sender<(String, SerialRequest)>,
  connection: WsUpgrade<TcpStream>,
) {
  thread::spawn(move || ws_handler(&sub_tx_clone, &sreq_tx_clone, connection),);
}

/// Websocket handler
fn ws_handler(
  sub_tx: &Sender<SubscriptionRequest>,
  sreq_tx: &Sender<(String, SerialRequest)>,
  connection: WsUpgrade<TcpStream>,
) {

  // Set up subscription id
  // let ts = SystemTime::now() - UNIX_EPOCH
  let prefix: String = thread_rng().gen_ascii_chars().take(8).collect();
  let sub_id = format!("thread-{}-{}", prefix, rand::random::<u16>());
  debug!("Spawned thread with subId '{}'", sub_id);

  if !connection
        .protocols()
        .contains(&"websocket-serial-json".to_string()) {
    connection
      .reject()
      .expect(&"Connection rejection failed.");
    return;
  }

  connection
    .tcp_stream()
    .set_nonblocking(true)
    .expect(&"Setting stream non-blocking failed.");

  // Create response channel
  let (sub_resp_tx, sub_resp_rx) = channel::<SerialResponse>();

  // Register sub_id with manager
  sub_tx
    .send(
      SubscriptionRequest {
        sub_id: sub_id.clone(),
        subscriber: sub_resp_tx,
      },
    )
    .expect(&format!("{}: Registering with manager failed.", sub_id));

  let client = connection
    .use_protocol(format!("websocket-serial-json"))
    .accept()
    .expect(&format!("{}: Accept protocol failed.", sub_id));

  let ip = client
    .peer_addr()
    .expect(&format!("{}: Could not get peer address", sub_id));

  info!("{}: Connection from {}", sub_id, ip);

  //   let message = Message::text("Hello".to_string());
  //   client.send_message(&message).unwrap();

  let (mut receiver, mut sender) = client
    .split()
    .expect(&format!("{}: WS client error", sub_id));

  let mut send_error_count = 0;

  let sleep_dur = Duration::from_millis(33);

  'msg_loop: loop {
    // Try and read a WS message
    match receiver.recv_message::<Message, _, _>() {
      Ok(message) => {
        match message.opcode {

          Type::Close => {
            let message = Message::close();
            sender
              .send_message(&message)
              .unwrap_or(info!("{}: Client {} hung up!", sub_id, ip));
            // Send close request to cleanup resources
            sreq_tx
              .send((sub_id.clone(), SerialRequest::Close { port: None }))
              .unwrap_or_else(
                |e| {
                  warn!(
                    "Client exit cleanup failed for sub_id '{}', cause '{}'",
                    sub_id,
                    e
                  )
                },
              );
            info!("{}: Client {} disconnected", sub_id, ip);
            break 'msg_loop;
          }

          Type::Ping => {
            let message = Message::pong(message.payload);
            sender
              .send_message(&message)
              .unwrap_or(info!("{}:  Could not ping client {}!", sub_id, ip));
          }

          _ => {

            // Get the payload, in a lossy manner
            let msg = String::from_utf8_lossy(&message.payload);

            // So we will get a result <SerialRequest::*,SerialResponse::Error> back
            match serde_json::from_str(&msg) {
              Ok(req) => {
                match sreq_tx.send((sub_id.clone(), req)) {
                  Err(err) => {
                    let error = e::ErrorKind::SendRequest(err).into();
                    send_serial_response_error(&sub_id, &mut sender, error);

                  }
                  _ => {}
                };
              }
              Err(err) => {
                let error = e::ErrorKind::Json(err).into();
                send_serial_response_error(&sub_id, &mut sender, error);
              }
            };
          }
        };
      }
      Err(e) => {
        match e {
          WebSocketError::NoDataAvailable => { /*Logging?*/ }
          _ => { /*Logging?*/ }
        };
      }
    }

    // Send on any serial responses
    match sub_resp_rx.try_recv() {
      Ok(resp) => {
        match serde_json::to_string(&resp) {
          Ok(json) => {
            let reply = Message::text(json.clone());
            sender
              .send_message(&reply)
              .unwrap_or_else(
                |e| {
                  send_error_count += 1;
                  info!(
                    "{}: Could not send message '{}' to client '{}', cause '{}'",
                    sub_id,
                    json,
                    ip,
                    e
                  )
                },
              );
          }
          Err(_) => {}
        }
      }
      _ => { /*Logging*/ }
    };

    if send_error_count > MAX_SEND_ERROR_COUNT {
      warn!("{}: Client send error count exceeded! Shutting down msg loop.",&sub_id);
      break 'msg_loop;
    }

    thread::sleep(sleep_dur);
  }

  info!("Thread {} exiting!", sub_id);

}

fn send_serial_response_error(sub_id: &String, sender: &mut Writer<TcpStream>, error: e::Error) {
  let error = e::to_serial_response_error(error);
  serde_json::to_string(&error)
    .map_err(|err| e::ErrorKind::Json(err))
    .map(|json| Message::text(json))
    .map(
      |msg| {
        sender
          .send_message::<Message, _>(&msg)
          .map_err::<e::Error, _>(|err| e::ErrorKind::SendWsMessage(err).into())
      },
    )
    .unwrap_or_else(
      |_| {
        warn!("{}: Problem sending bad json error response", sub_id);
        Ok(())
      },
    )
    .is_ok(); // This shouldn't be needed?

}
<|endoftext|>


<commit_before>//
// zhttpto.rs
//
// Starting code for PS1
// Running on Rust 0.12
//
// Note that this code has serious security risks! You should not run it
// on any system with access to sensitive files.
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu and David Evans
// Version 0.3

#![feature(globs)]

use std::io::*;
use std::str;

fn main() {

    let addr = "127.0.0.1:4414";
    let mut acceptor = net::tcp::TcpListener::bind(addr).listen().unwrap();

    println!("Listening on [{}] ...", addr);

    for stream in acceptor.incoming() {
        // Spawn a task to handle the connection
        spawn(proc() {

            let mut stream = stream;

            match stream {
                Ok(ref mut s) => {
                    match s.peer_name() {
                        Ok(pn) => println!("Received connection from: [{}]", pn),
                        Err(_) => ()
                    }
                },
                Err(_) => ()
            }

            let mut buf = [0, ..500];
            stream.read(&mut buf);
            let request_str = str::from_utf8(&buf);
            println!("Received request :\n{}", request_str);

            let response =
                "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                 <doctype !html><title>Hello, Rust!</title>

Greetings, Krusty!

                 \r\n";
            stream.write(response.as_bytes());
            println!("Connection terminates.");
        });
    }
}
<commit_msg>Explicitly ignore return values (silences warnings)<commit_after>//
// zhttpto.rs
//
// Starting code for PS1
// Running on Rust 0.12
//
// Note that this code has serious security risks! You should not run it
// on any system with access to sensitive files.
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu and David Evans
// Version 0.3

#![feature(globs)]

use std::io::*;
use std::str;

fn main() {

    let addr = "127.0.0.1:4414";
    let mut acceptor = net::tcp::TcpListener::bind(addr).listen().unwrap();

    println!("Listening on [{}] ...", addr);

    for stream in acceptor.incoming() {
        // Spawn a task to handle the connection
        spawn(proc() {

            let mut stream = stream;

            match stream {
                Ok(ref mut s) => {
                    match s.peer_name() {
                        Ok(pn) => println!("Received connection from: [{}]", pn),
                        Err(_) => ()
                    }
                },
                Err(_) => ()
            }

            let mut buf = [0, ..500];
            let _ = stream.read(&mut buf);
            let request_str = str::from_utf8(&buf);
            println!("Received request :\n{}", request_str);

            let response =
                "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                 <doctype !html><title>Hello, Rust!</title>

Greetings, Krusty!

                 \r\n";
            let _ = stream.write(response.as_bytes());
            println!("Connection terminates.");
        });
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::ascii::AsciiExt;
use std::io::{self, Read, Write, Cursor};
use std::cell::RefCell;
use std::net::{SocketAddr, Shutdown};
use std::sync::{Arc, Mutex};
#[cfg(feature = "timeouts")]
use std::time::Duration;
#[cfg(feature = "timeouts")]
use std::cell::Cell;

use solicit::http::HttpScheme;
use solicit::http::transport::TransportStream;
use solicit::http::frame::{SettingsFrame, Frame};
use solicit::http::connection::{HttpConnection, EndStream, DataChunk};

use header::Headers;
use net::{NetworkStream, NetworkConnector};

#[derive(Clone)]
pub struct MockStream {
    pub read: Cursor<Vec<u8>>,
    pub write: Vec<u8>,
    pub is_closed: bool,
    pub error_on_write: bool,
    pub error_on_read: bool,
    #[cfg(feature = "timeouts")]
    pub read_timeout: Cell<Option<Duration>>,
    #[cfg(feature = "timeouts")]
    pub write_timeout: Cell<Option<Duration>>,
}

impl fmt::Debug for MockStream {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "MockStream {{ read: {:?}, write: {:?} }}", self.read.get_ref(), self.write)
    }
}

impl PartialEq for MockStream {
    fn eq(&self, other: &MockStream) -> bool {
        self.read.get_ref() == other.read.get_ref() && self.write == other.write
    }
}

impl MockStream {
    pub fn new() -> MockStream {
        MockStream::with_input(b"")
    }

    #[cfg(not(feature = "timeouts"))]
    pub fn with_input(input: &[u8]) -> MockStream {
        MockStream {
            read: Cursor::new(input.to_vec()),
            write: vec![],
            is_closed: false,
            error_on_write: false,
            error_on_read: false,
        }
    }

    #[cfg(feature = "timeouts")]
    pub fn with_input(input: &[u8]) -> MockStream {
        MockStream {
            read: Cursor::new(input.to_vec()),
            write: vec![],
            is_closed: false,
            error_on_write: false,
            error_on_read: false,
            read_timeout: Cell::new(None),
            write_timeout: Cell::new(None),
        }
    }
}

impl Read for MockStream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        if self.error_on_read {
            Err(io::Error::new(io::ErrorKind::Other, "mock error"))
        } else {
            self.read.read(buf)
        }
    }
}

impl Write for MockStream {
    fn write(&mut self, msg: &[u8]) -> io::Result<usize> {
        if self.error_on_write {
            Err(io::Error::new(io::ErrorKind::Other, "mock error"))
        } else {
            Write::write(&mut self.write, msg)
        }
    }

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

impl NetworkStream for MockStream {
    fn peer_addr(&mut self) -> io::Result<SocketAddr> {
        Ok("127.0.0.1:1337".parse().unwrap())
    }

    #[cfg(feature = "timeouts")]
    fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
        self.read_timeout.set(dur);
        Ok(())
    }

    #[cfg(feature = "timeouts")]
    fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
        self.write_timeout.set(dur);
        Ok(())
    }

    fn close(&mut self, _how: Shutdown) -> io::Result<()> {
        self.is_closed = true;
        Ok(())
    }
}

/// A wrapper around a `MockStream` that allows one to clone it and keep an independent copy to the
/// same underlying stream.
#[derive(Clone)]
pub struct CloneableMockStream {
    pub inner: Arc<Mutex<MockStream>>,
}

impl Write for CloneableMockStream {
    fn write(&mut self, msg: &[u8]) -> io::Result<usize> {
        self.inner.lock().unwrap().write(msg)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.inner.lock().unwrap().flush()
    }
}

impl Read for CloneableMockStream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.inner.lock().unwrap().read(buf)
    }
}

impl TransportStream for CloneableMockStream {
    fn try_split(&self) -> Result<CloneableMockStream, io::Error> {
        Ok(self.clone())
    }

    fn close(&mut self) -> Result<(), io::Error> {
        Ok(())
    }
}

impl NetworkStream for CloneableMockStream {
    fn peer_addr(&mut self) -> io::Result<SocketAddr> {
        self.inner.lock().unwrap().peer_addr()
    }

    #[cfg(feature = "timeouts")]
    fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
        self.inner.lock().unwrap().set_read_timeout(dur)
    }

    #[cfg(feature = "timeouts")]
    fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
        self.inner.lock().unwrap().set_write_timeout(dur)
    }

    fn close(&mut self, how: Shutdown) -> io::Result<()> {
        NetworkStream::close(&mut *self.inner.lock().unwrap(), how)
    }
}

impl CloneableMockStream {
    pub fn with_stream(stream: MockStream) -> CloneableMockStream {
        CloneableMockStream {
            inner: Arc::new(Mutex::new(stream)),
        }
    }
}

pub struct MockConnector;

impl NetworkConnector for MockConnector {
    type Stream = MockStream;

    fn connect(&self, _host: &str, _port: u16, _scheme: &str) -> ::Result<MockStream> {
        Ok(MockStream::new())
    }
}

/// new connectors must be created if you wish to intercept requests.
macro_rules! mock_connector (
    ($name:ident {
        $($url:expr => $res:expr)*
    }) => (

        struct $name;

        impl ::net::NetworkConnector for $name {
            type Stream = ::mock::MockStream;
            fn connect(&self, host: &str, port: u16, scheme: &str)
                    -> $crate::Result<::mock::MockStream> {
                use std::collections::HashMap;
                debug!("MockStream::connect({:?}, {:?}, {:?})", host, port, scheme);
                let mut map = HashMap::new();
                $(map.insert($url, $res);)*

                let key = format!("{}://{}", scheme, host);
                // ignore port for now
                match map.get(&*key) {
                    Some(&res) => Ok($crate::mock::MockStream::with_input(res.as_bytes())),
                    None => panic!("{:?} doesn't know url {}", stringify!($name), key)
                }
            }
        }

    )
);

impl TransportStream for MockStream {
    fn try_split(&self) -> Result<MockStream, io::Error> {
        Ok(self.clone())
    }

    fn close(&mut self) -> Result<(), io::Error> {
        Ok(())
    }
}

impl MockStream {
    /// Creates a new `MockStream` that will return the response described by the parameters as an
    /// HTTP/2 response. This will also include the correct server preface.
    pub fn new_http2_response(status: &[u8], headers: &Headers, body: Option<Vec<u8>>)
            -> MockStream {
        let resp_bytes = build_http2_response(status, headers, body);
        MockStream::with_input(&resp_bytes)
    }
}

/// Builds up a sequence of bytes that represent a server's response based on the given parameters.
pub fn build_http2_response(status: &[u8], headers: &Headers, body: Option<Vec<u8>>) -> Vec<u8> {
    let mut conn = HttpConnection::new(MockStream::new(), MockStream::new(), HttpScheme::Http);
    // Server preface first
    conn.sender.write(&SettingsFrame::new().serialize()).unwrap();

    let mut resp_headers: Vec<_> = headers.iter().map(|h| {
        (h.name().to_ascii_lowercase().into_bytes(), h.value_string().into_bytes())
    }).collect();
    resp_headers.insert(0, (b":status".to_vec(), status.into()));

    let end = if body.is_none() {
        EndStream::Yes
    } else {
        EndStream::No
    };
    conn.send_headers(resp_headers, 1, end).unwrap();
    if body.is_some() {
        let chunk = DataChunk::new_borrowed(&body.as_ref().unwrap()[..], 1, EndStream::Yes);
        conn.send_data(chunk).unwrap();
    }

    conn.sender.write
}

/// A mock connector that produces `MockStream`s that are set to return HTTP/2 responses.
///
/// This means that the streams' payloads are fairly opaque byte sequences (as HTTP/2 is a binary
/// protocol), which can be understood only be HTTP/2 clients.
pub struct MockHttp2Connector {
    /// The list of streams that the connector returns, in the given order.
    pub streams: RefCell<Vec<CloneableMockStream>>,
}

impl MockHttp2Connector {
    /// Creates a new `MockHttp2Connector` with no streams.
    pub fn new() -> MockHttp2Connector {
        MockHttp2Connector {
            streams: RefCell::new(Vec::new()),
        }
    }

    /// Adds a new `CloneableMockStream` to the end of the connector's stream queue.
    ///
    /// Streams are returned in a FIFO manner.
    pub fn add_stream(&mut self, stream: CloneableMockStream) {
        self.streams.borrow_mut().push(stream);
    }

    /// Adds a new response stream that will be placed to the end of the connector's stream queue.
    ///
    /// Returns a separate `CloneableMockStream` that allows the user to inspect what is written
    /// into the original stream.
    pub fn new_response_stream(&mut self, status: &[u8], headers: &Headers, body: Option<Vec<u8>>)
            -> CloneableMockStream {
        let stream = MockStream::new_http2_response(status, headers, body);
        let stream = CloneableMockStream::with_stream(stream);
        let ret = stream.clone();
        self.add_stream(stream);

        ret
    }
}

impl NetworkConnector for MockHttp2Connector {
    type Stream = CloneableMockStream;
    #[inline]
    fn connect(&self, _host: &str, _port: u16, _scheme: &str)
            -> ::Result<CloneableMockStream> {
        Ok(self.streams.borrow_mut().remove(0))
    }
}
<commit_msg>refactor(mock): derive Debug for MockStream<commit_after>use std::ascii::AsciiExt;
use std::io::{self, Read, Write, Cursor};
use std::cell::RefCell;
use std::net::{SocketAddr, Shutdown};
use std::sync::{Arc, Mutex};
#[cfg(feature = "timeouts")]
use std::time::Duration;
#[cfg(feature = "timeouts")]
use std::cell::Cell;

use solicit::http::HttpScheme;
use solicit::http::transport::TransportStream;
use solicit::http::frame::{SettingsFrame, Frame};
use solicit::http::connection::{HttpConnection, EndStream, DataChunk};

use header::Headers;
use net::{NetworkStream, NetworkConnector};

#[derive(Clone, Debug)]
pub struct MockStream {
    pub read: Cursor<Vec<u8>>,
    pub write: Vec<u8>,
    pub is_closed: bool,
    pub error_on_write: bool,
    pub error_on_read: bool,
    #[cfg(feature = "timeouts")]
    pub read_timeout: Cell<Option<Duration>>,
    #[cfg(feature = "timeouts")]
    pub write_timeout: Cell<Option<Duration>>,
}

impl PartialEq for MockStream {
    fn eq(&self, other: &MockStream) -> bool {
        self.read.get_ref() == other.read.get_ref() && self.write == other.write
    }
}

impl MockStream {
    pub fn new() -> MockStream {
        MockStream::with_input(b"")
    }

    #[cfg(not(feature = "timeouts"))]
    pub fn with_input(input: &[u8]) -> MockStream {
        MockStream {
            read: Cursor::new(input.to_vec()),
            write: vec![],
            is_closed: false,
            error_on_write: false,
            error_on_read: false,
        }
    }

    #[cfg(feature = "timeouts")]
    pub fn with_input(input: &[u8]) -> MockStream {
        MockStream {
            read: Cursor::new(input.to_vec()),
            write: vec![],
            is_closed: false,
            error_on_write: false,
            error_on_read: false,
            read_timeout: Cell::new(None),
            write_timeout: Cell::new(None),
        }
    }
}

impl Read for MockStream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        if self.error_on_read {
            Err(io::Error::new(io::ErrorKind::Other, "mock error"))
        } else {
            self.read.read(buf)
        }
    }
}

impl Write for MockStream {
    fn write(&mut self, msg: &[u8]) -> io::Result<usize> {
        if self.error_on_write {
            Err(io::Error::new(io::ErrorKind::Other, "mock error"))
        } else {
            Write::write(&mut self.write, msg)
        }
    }

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

impl NetworkStream for MockStream {
    fn peer_addr(&mut self) -> io::Result<SocketAddr> {
        Ok("127.0.0.1:1337".parse().unwrap())
    }

    #[cfg(feature = "timeouts")]
    fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
        self.read_timeout.set(dur);
        Ok(())
    }

    #[cfg(feature = "timeouts")]
    fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
        self.write_timeout.set(dur);
        Ok(())
    }

    fn close(&mut self, _how: Shutdown) -> io::Result<()> {
        self.is_closed = true;
        Ok(())
    }
}

/// A wrapper around a `MockStream` that allows one to clone it and keep an independent copy to the
/// same underlying stream.
#[derive(Clone)]
pub struct CloneableMockStream {
    pub inner: Arc<Mutex<MockStream>>,
}

impl Write for CloneableMockStream {
    fn write(&mut self, msg: &[u8]) -> io::Result<usize> {
        self.inner.lock().unwrap().write(msg)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.inner.lock().unwrap().flush()
    }
}

impl Read for CloneableMockStream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.inner.lock().unwrap().read(buf)
    }
}

impl TransportStream for CloneableMockStream {
    fn try_split(&self) -> Result<CloneableMockStream, io::Error> {
        Ok(self.clone())
    }

    fn close(&mut self) -> Result<(), io::Error> {
        Ok(())
    }
}

impl NetworkStream for CloneableMockStream {
    fn peer_addr(&mut self) -> io::Result<SocketAddr> {
        self.inner.lock().unwrap().peer_addr()
    }

    #[cfg(feature = "timeouts")]
    fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
        self.inner.lock().unwrap().set_read_timeout(dur)
    }

    #[cfg(feature = "timeouts")]
    fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
        self.inner.lock().unwrap().set_write_timeout(dur)
    }

    fn close(&mut self, how: Shutdown) -> io::Result<()> {
        NetworkStream::close(&mut *self.inner.lock().unwrap(), how)
    }
}

impl CloneableMockStream {
    pub fn with_stream(stream: MockStream) -> CloneableMockStream {
        CloneableMockStream {
            inner: Arc::new(Mutex::new(stream)),
        }
    }
}

pub struct MockConnector;

impl NetworkConnector for MockConnector {
    type Stream = MockStream;

    fn connect(&self, _host: &str, _port: u16, _scheme: &str) -> ::Result<MockStream> {
        Ok(MockStream::new())
    }
}

/// new connectors must be created if you wish to intercept requests.
macro_rules! mock_connector (
    ($name:ident {
        $($url:expr => $res:expr)*
    }) => (

        struct $name;

        impl ::net::NetworkConnector for $name {
            type Stream = ::mock::MockStream;
            fn connect(&self, host: &str, port: u16, scheme: &str)
                    -> $crate::Result<::mock::MockStream> {
                use std::collections::HashMap;
                debug!("MockStream::connect({:?}, {:?}, {:?})", host, port, scheme);
                let mut map = HashMap::new();
                $(map.insert($url, $res);)*

                let key = format!("{}://{}", scheme, host);
                // ignore port for now
                match map.get(&*key) {
                    Some(&res) => Ok($crate::mock::MockStream::with_input(res.as_bytes())),
                    None => panic!("{:?} doesn't know url {}", stringify!($name), key)
                }
            }
        }

    )
);

impl TransportStream for MockStream {
    fn try_split(&self) -> Result<MockStream, io::Error> {
        Ok(self.clone())
    }

    fn close(&mut self) -> Result<(), io::Error> {
        Ok(())
    }
}

impl MockStream {
    /// Creates a new `MockStream` that will return the response described by the parameters as an
    /// HTTP/2 response. This will also include the correct server preface.
    pub fn new_http2_response(status: &[u8], headers: &Headers, body: Option<Vec<u8>>)
            -> MockStream {
        let resp_bytes = build_http2_response(status, headers, body);
        MockStream::with_input(&resp_bytes)
    }
}

/// Builds up a sequence of bytes that represent a server's response based on the given parameters.
pub fn build_http2_response(status: &[u8], headers: &Headers, body: Option<Vec<u8>>) -> Vec<u8> {
    let mut conn = HttpConnection::new(MockStream::new(), MockStream::new(), HttpScheme::Http);
    // Server preface first
    conn.sender.write(&SettingsFrame::new().serialize()).unwrap();

    let mut resp_headers: Vec<_> = headers.iter().map(|h| {
        (h.name().to_ascii_lowercase().into_bytes(), h.value_string().into_bytes())
    }).collect();
    resp_headers.insert(0, (b":status".to_vec(), status.into()));

    let end = if body.is_none() {
        EndStream::Yes
    } else {
        EndStream::No
    };
    conn.send_headers(resp_headers, 1, end).unwrap();
    if body.is_some() {
        let chunk = DataChunk::new_borrowed(&body.as_ref().unwrap()[..], 1, EndStream::Yes);
        conn.send_data(chunk).unwrap();
    }

    conn.sender.write
}

/// A mock connector that produces `MockStream`s that are set to return HTTP/2 responses.
///
/// This means that the streams' payloads are fairly opaque byte sequences (as HTTP/2 is a binary
/// protocol), which can be understood only be HTTP/2 clients.
pub struct MockHttp2Connector {
    /// The list of streams that the connector returns, in the given order.
    pub streams: RefCell<Vec<CloneableMockStream>>,
}

impl MockHttp2Connector {
    /// Creates a new `MockHttp2Connector` with no streams.
    pub fn new() -> MockHttp2Connector {
        MockHttp2Connector {
            streams: RefCell::new(Vec::new()),
        }
    }

    /// Adds a new `CloneableMockStream` to the end of the connector's stream queue.
    ///
    /// Streams are returned in a FIFO manner.
    pub fn add_stream(&mut self, stream: CloneableMockStream) {
        self.streams.borrow_mut().push(stream);
    }

    /// Adds a new response stream that will be placed to the end of the connector's stream queue.
    ///
    /// Returns a separate `CloneableMockStream` that allows the user to inspect what is written
    /// into the original stream.
    pub fn new_response_stream(&mut self, status: &[u8], headers: &Headers, body: Option<Vec<u8>>)
            -> CloneableMockStream {
        let stream = MockStream::new_http2_response(status, headers, body);
        let stream = CloneableMockStream::with_stream(stream);
        let ret = stream.clone();
        self.add_stream(stream);

        ret
    }
}

impl NetworkConnector for MockHttp2Connector {
    type Stream = CloneableMockStream;
    #[inline]
    fn connect(&self, _host: &str, _port: u16, _scheme: &str)
            -> ::Result<CloneableMockStream> {
        Ok(self.streams.borrow_mut().remove(0))
    }
}
<|endoftext|>


<commit_before>use num::BigUint;
use num::traits::One;
use digit_slice::{DigitSlice, FromDigits, msb};
use {Shape, Noun, NockError, NockResult};

/// Interface for a virtual machine for Nock code.
///
/// A virtual machine can process Hint operations and accelerate Call
/// operations.
pub trait Nock {
    /// Accelerate computation of a formula, if possible.
    ///
    /// Nock `*[a 9 b c]`, will trigger `call(*[a c], *[*[a c] 0 b])`.
    /// If call returns a noun, that noun will be used as the result of the
    /// Nock evaluation. Otherwise the formula will be evaluated as standard
    /// Nock.
    ///
    /// The return value must be exactly the same as you would get for
    /// evaluating the formula on the subject with a standard Nock
    /// interpreter.
    #[allow(unused_variables)]
    fn call(&mut self, subject: &Noun, formula: &Noun) -> Option<Noun> {
        None
    }

    /// Handle a Nock hint.
    ///
    /// Nock `*[a 10 b c]` will trigger `hint(a, b, c)`.
    #[allow(unused_variables)]
    fn hint(&mut self,
            subject: &Noun,
            hint: &Noun,
            c: &Noun)
            -> Result<(), NockError> {
        Ok(())
    }

    /// Evaluate the nock `*[subject formula]`
    fn nock_on(&mut self, mut subject: Noun, mut formula: Noun) -> NockResult {
        loop {
            if let Shape::Cell(ops, tail) = formula.clone().get() {
                match ops.as_u32() {
                    // Axis
                    Some(0) => return get_axis(&tail, &subject),

                    // Just
                    Some(1) => return Ok(tail.clone()),

                    // Fire
                    Some(2) => {
                        match tail.get() {
                            Shape::Cell(ref b, ref c) => {
                                let p = try!(self.nock_on(subject.clone(),
                                                          (*b).clone()));
                                let q = try!(self.nock_on(subject,
                                                          (*c).clone()));
                                subject = p;
                                formula = q;
                                continue;
                            }
                            _ => return Err(NockError(format!("fire"))),
                        }
                    }

                    // Depth
                    Some(3) => {
                        let p = try!(self.nock_on(subject.clone(),
                                                  (*tail).clone()));
                        return match p.get() {
                            Shape::Cell(_, _) => Ok(Noun::from(0u32)),
                            _ => Ok(Noun::from(1u32)),
                        };
                    }

                    // Bump
                    Some(4) => {
                        let p = try!(self.nock_on(subject.clone(),
                                                  (*tail).clone()));
                        return match p.get() {
                            Shape::Atom(ref x) => {
                                // TODO: Non-bignum optimization
                                Ok(Noun::from(BigUint::from_digits(x).unwrap() +
                                              BigUint::one()))
                            }
                            _ => Err(NockError(format!("bump"))),
                        };
                    }

                    // Same
                    Some(5) => {
                        let p = try!(self.nock_on(subject.clone(),
                                                  (*tail).clone()));
                        return match p.get() {
                            Shape::Cell(ref a, ref b) => {
                                if a == b {
                                    // Yes.
                                    return Ok(Noun::from(0u32));
                                } else {
                                    // No.
                                    return Ok(Noun::from(1u32));
                                }
                            }
                            _ => return Err(NockError(format!("same"))),
                        };
                    }

                    // If
                    Some(6) => {
                        if let Some((b, c, d)) = tail.get_122() {
                            let p = try!(self.nock_on(subject.clone(),
                                                      (*b).clone()));
                            match p.get() {
                                Shape::Atom(ref x) => {
                                    if x == &0u32.as_digits() {
                                        formula = (*c).clone();
                                    } else if x == &1u32.as_digits() {
                                        formula = (*d).clone();
                                    } else {
                                        return Err(NockError(format!("if")));
                                    }
                                }
                                _ => return Err(NockError(format!("if"))),
                            }
                            continue;
                        } else {
                            return Err(NockError(format!("if")));
                        }
                    }

                    // Compose
                    Some(7) => {
                        match tail.get() {
                            Shape::Cell(ref b, ref c) => {
                                let p = try!(self.nock_on(subject.clone(),
                                                          (*b).clone()));
                                subject = p;
                                formula = (*c).clone();
                                continue;
                            }
                            _ => return Err(NockError(format!("compose"))),
                        }
                    }

                    // Push
                    Some(8) => {
                        match tail.get() {
                            Shape::Cell(ref b, ref c) => {
                                let p = try!(self.nock_on(subject.clone(),
                                                          (*b).clone()));
                                subject = Noun::cell(p, subject);
                                formula = (*c).clone();
                                continue;
                            }
                            _ => return Err(NockError(format!("push"))),
                        }
                    }

                    // Call
                    Some(9) => {
                        match tail.get() {
                            Shape::Cell(ref axis, ref c) => {
                                // Construct core.
                                subject = try!(self.nock_on(subject.clone(),
                                                            (*c).clone()));
                                // Fetch from core using axis.
                                formula = try!(get_axis(axis, &subject));

                                if let Some(result) = self.call(&subject,
                                                                &formula) {
                                    return Ok(result);
                                }

                                continue;
                            }
                            _ => return Err(NockError(format!("call"))),
                        }
                    }

                    // Hint
                    Some(10) => {
                        match tail.get() {
                            Shape::Cell(ref b, ref c) => {
                                try!(self.hint(&subject, b, c));
                                formula = (*c).clone();
                                continue;
                            }
                            _ => return Err(NockError(format!("hint"))),
                        }
                    }

                    // Unhandled opcode
                    Some(code) => {
                        return Err(NockError(format!("unknown opcode {}",
                                                     code)));
                    }

                    None => {
                        if let Shape::Cell(_, _) = ops.get() {
                            // Autocons
                            let a = try!(self.nock_on(subject.clone(),
                                                      ops.clone()));
                            let b = try!(self.nock_on(subject, tail.clone()));
                            return Ok(Noun::cell(a, b));
                        } else {
                            return Err(NockError(format!("autocons")));
                        }
                    }
                }
            } else {
                return Err(NockError(format!("nock")));
            }
        }
    }
}

/// Evaluate nock `/[axis subject]`
pub fn get_axis(axis: &Noun, subject: &Noun) -> NockResult {
    fn fas(x: &[u8], n: usize, mut subject: &Noun) -> NockResult {
        for i in (0..(n - 1)).rev() {
            if let Shape::Cell(ref a, ref b) = subject.get() {
                if bit(x, i) {
                    subject = b;
                } else {
                    subject = a;
                }
            } else {
                return Err(NockError(format!("axis")));
            }
        }
        Ok((*subject).clone())
    }

    #[inline]
    fn bit(data: &[u8], pos: usize) -> bool {
        data[pos / 8] & (1 << (pos % 8)) != 0
    }

    match axis.get() {
        Shape::Atom(ref x) => {
            let start = msb(x);
            fas(x, start, subject)
        }
        _ => Err(NockError(format!("axis"))),
    }
}
<commit_msg>Call hook can return errors<commit_after>use num::BigUint;
use num::traits::One;
use digit_slice::{DigitSlice, FromDigits, msb};
use {Shape, Noun, NockError, NockResult};

/// Interface for a virtual machine for Nock code.
///
/// A virtual machine can process Hint operations and accelerate Call
/// operations.
pub trait Nock {
    /// Accelerate computation of a formula, if possible.
    ///
    /// Nock `*[a 9 b c]`, will trigger `call(*[a c], *[*[a c] 0 b])`.
    /// If call returns a noun, that noun will be used as the result of the
    /// Nock evaluation. Otherwise the formula will be evaluated as standard
    /// Nock.
    ///
    /// The return value must be exactly the same as you would get for
    /// evaluating the formula on the subject with a standard Nock
    /// interpreter.
    #[allow(unused_variables)]
    fn call(&mut self, subject: &Noun, formula: &Noun) -> Option<NockResult> {
        None
    }

    /// Handle a Nock hint.
    ///
    /// Nock `*[a 10 b c]` will trigger `hint(a, b, c)`.
    #[allow(unused_variables)]
    fn hint(&mut self,
            subject: &Noun,
            hint: &Noun,
            c: &Noun)
            -> Result<(), NockError> {
        Ok(())
    }

    /// Evaluate the nock `*[subject formula]`
    fn nock_on(&mut self, mut subject: Noun, mut formula: Noun) -> NockResult {
        loop {
            if let Shape::Cell(ops, tail) = formula.clone().get() {
                match ops.as_u32() {
                    // Axis
                    Some(0) => return get_axis(&tail, &subject),

                    // Just
                    Some(1) => return Ok(tail.clone()),

                    // Fire
                    Some(2) => {
                        match tail.get() {
                            Shape::Cell(ref b, ref c) => {
                                let p = try!(self.nock_on(subject.clone(),
                                                          (*b).clone()));
                                let q = try!(self.nock_on(subject,
                                                          (*c).clone()));
                                subject = p;
                                formula = q;
                                continue;
                            }
                            _ => return Err(NockError(format!("fire"))),
                        }
                    }

                    // Depth
                    Some(3) => {
                        let p = try!(self.nock_on(subject.clone(),
                                                  (*tail).clone()));
                        return match p.get() {
                            Shape::Cell(_, _) => Ok(Noun::from(0u32)),
                            _ => Ok(Noun::from(1u32)),
                        };
                    }

                    // Bump
                    Some(4) => {
                        let p = try!(self.nock_on(subject.clone(),
                                                  (*tail).clone()));
                        return match p.get() {
                            Shape::Atom(ref x) => {
                                // TODO: Non-bignum optimization
                                Ok(Noun::from(BigUint::from_digits(x).unwrap() +
                                              BigUint::one()))
                            }
                            _ => Err(NockError(format!("bump"))),
                        };
                    }

                    // Same
                    Some(5) => {
                        let p = try!(self.nock_on(subject.clone(),
                                                  (*tail).clone()));
                        return match p.get() {
                            Shape::Cell(ref a, ref b) => {
                                if a == b {
                                    // Yes.
                                    return Ok(Noun::from(0u32));
                                } else {
                                    // No.
                                    return Ok(Noun::from(1u32));
                                }
                            }
                            _ => return Err(NockError(format!("same"))),
                        };
                    }

                    // If
                    Some(6) => {
                        if let Some((b, c, d)) = tail.get_122() {
                            let p = try!(self.nock_on(subject.clone(),
                                                      (*b).clone()));
                            match p.get() {
                                Shape::Atom(ref x) => {
                                    if x == &0u32.as_digits() {
                                        formula = (*c).clone();
                                    } else if x == &1u32.as_digits() {
                                        formula = (*d).clone();
                                    } else {
                                        return Err(NockError(format!("if")));
                                    }
                                }
                                _ => return Err(NockError(format!("if"))),
                            }
                            continue;
                        } else {
                            return Err(NockError(format!("if")));
                        }
                    }

                    // Compose
                    Some(7) => {
                        match tail.get() {
                            Shape::Cell(ref b, ref c) => {
                                let p = try!(self.nock_on(subject.clone(),
                                                          (*b).clone()));
                                subject = p;
                                formula = (*c).clone();
                                continue;
                            }
                            _ => return Err(NockError(format!("compose"))),
                        }
                    }

                    // Push
                    Some(8) => {
                        match tail.get() {
                            Shape::Cell(ref b, ref c) => {
                                let p = try!(self.nock_on(subject.clone(),
                                                          (*b).clone()));
                                subject = Noun::cell(p, subject);
                                formula = (*c).clone();
                                continue;
                            }
                            _ => return Err(NockError(format!("push"))),
                        }
                    }

                    // Call
                    Some(9) => {
                        match tail.get() {
                            Shape::Cell(ref axis, ref c) => {
                                // Construct core.
                                subject = try!(self.nock_on(subject.clone(),
                                                            (*c).clone()));
                                // Fetch from core using axis.
                                formula = try!(get_axis(axis, &subject));

                                if let Some(result) = self.call(&subject,
                                                                &formula) {
                                    return result;
                                }

                                continue;
                            }
                            _ => return Err(NockError(format!("call"))),
                        }
                    }

                    // Hint
                    Some(10) => {
                        match tail.get() {
                            Shape::Cell(ref b, ref c) => {
                                try!(self.hint(&subject, b, c));
                                formula = (*c).clone();
                                continue;
                            }
                            _ => return Err(NockError(format!("hint"))),
                        }
                    }

                    // Unhandled opcode
                    Some(code) => {
                        return Err(NockError(format!("unknown opcode {}",
                                                     code)));
                    }

                    None => {
                        if let Shape::Cell(_, _) = ops.get() {
                            // Autocons
                            let a = try!(self.nock_on(subject.clone(),
                                                      ops.clone()));
                            let b = try!(self.nock_on(subject, tail.clone()));
                            return Ok(Noun::cell(a, b));
                        } else {
                            return Err(NockError(format!("autocons")));
                        }
                    }
                }
            } else {
                return Err(NockError(format!("nock")));
            }
        }
    }
}

/// Evaluate nock `/[axis subject]`
pub fn get_axis(axis: &Noun, subject: &Noun) -> NockResult {
    fn fas(x: &[u8], n: usize, mut subject: &Noun) -> NockResult {
        for i in (0..(n - 1)).rev() {
            if let Shape::Cell(ref a, ref b) = subject.get() {
                if bit(x, i) {
                    subject = b;
                } else {
                    subject = a;
                }
            } else {
                return Err(NockError(format!("axis")));
            }
        }
        Ok((*subject).clone())
    }

    #[inline]
    fn bit(data: &[u8], pos: usize) -> bool {
        data[pos / 8] & (1 << (pos % 8)) != 0
    }

    match axis.get() {
        Shape::Atom(ref x) => {
            let start = msb(x);
            fas(x, start, subject)
        }
        _ => Err(NockError(format!("axis"))),
    }
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};
use std::cmp::{max, min};

use itertools::Itertools;
use petgraph::{Directed, Direction, Graph};
use petgraph::graph::{node_index, EdgeIndex, NodeIndex};
use petgraph::visit::{Bfs, EdgeRef, NodeFiltered, Walker};

use {BfsWithDepth, GraphError, Token};

pub trait Deprojectivize {
    fn deprojectivize(&self, sentence: &[Token]) -> Result<Vec<Token>, GraphError>;
}

pub trait Projectivize {
    fn projectivize(&self, sentence: &[Token]) -> Result<Vec<Token>, GraphError>;
}

/// A projectivizer using the 'head' marking strategy. See: *Pseudo-Projective
/// Dependency Parsing*, Nivre and Nilsson, 2005.
pub struct HeadProjectivizer;

impl HeadProjectivizer {
    pub fn new() -> Self {
        HeadProjectivizer {}
    }

    /// Deprojectivize the next node in the array of lifted nodes.
    ///
    /// Returns the index of the node that was lifted.
    fn deprojectivize_next(
        &self,
        graph: &mut Graph<(), String, Directed>,
        lifted_sorted: &[NodeIndex],
        head_labels: &HashMap<NodeIndex, String>,
    ) -> Option<usize> {
        for (idx, lifted_node) in lifted_sorted.iter().enumerate() {
            let pref_head_rel = head_labels
                .get(lifted_node)
                .expect("Lifted node without preferred head relation");

            let head_edge = graph
                .first_edge(*lifted_node, Direction::Incoming)
                .expect("Lifted node without an incoming edge");
            let (cur_head, _) = graph
                .edge_endpoints(head_edge)
                .expect("Endpoints of lifted edge could not be found");

            if let Some(new_head) =
                self.search_attachment_point(&graph, cur_head, *lifted_node, pref_head_rel)
            {
                let head_rel = graph
                    .remove_edge(head_edge)
                    .expect("Lifted edge to be removed could not be found");
                graph.add_edge(new_head, *lifted_node, head_rel);
                return Some(idx);
            }
        }

        None
    }

    /// Find the correct attachment point for the lifted token/node.
    fn search_attachment_point(
        &self,
        graph: &Graph<(), String, Directed>,
        cur_head: NodeIndex,
        lifted_node: NodeIndex,
        pref_head_rel: &str,
    ) -> Option<NodeIndex> {
        // We are looking for a token dominated by cur_head to attach
        // lifted_node to. This token should:
        //
        // 1. Be attached to its head using pref_head_rel.
        // 2. Not be lifted_node itself or any of its decendants.
        // 3. As high in the tree as possible.
        //
        // From the set of candidates, we pick the token that is the
        // closest to the current head.

        // Requirement (2): use a view of the graph that excludes
        // to avoid attachment to the lifted_node or any of its children.
        let graph_without_lifted = NodeFiltered::from_fn(graph, |n| n != lifted_node);

        // Requirement (3): process the dependency tree by increasing depth
        // until the reattachment token is found.
        for (_, nodes) in &BfsWithDepth::new(&graph_without_lifted, node_index(0))
            .iter(&graph_without_lifted)
            .skip(1)
            .group_by(|&(_, depth)| depth)
        {
            // Requirement (1): Only retain edges with the preferred relation.
            let level_candidates = nodes.map(|(node, _)| node).filter(|&node| {
                let edge = match graph.first_edge(node, Direction::Incoming) {
                    Some(edge) => edge,
                    None => return false,
                };

                graph[edge] == pref_head_rel
            });

            // When there are multiple candidates, return the token closes to the head.
            let min_candidate = level_candidates.min_by_key(|&node| {
                max(node.index(), cur_head.index()) - min(node.index(), cur_head.index())
            });

            if min_candidate.is_some() {
                return min_candidate;
            }
        }

        None
    }

    /// Lift the edge identified by `edge_idx`. This will reattach the edge
    /// to the parent of the head. If this was the first lifting operation,
    /// the dependency relation of the original head is added to the dependency
    /// relation (following the head-strategy).
    fn lift(
        &self,
        graph: &mut Graph<(), String, Directed>,
        lifted: &mut HashSet<NodeIndex>,
        edge_idx: EdgeIndex,
    ) {
        let (source, target) = graph
            .edge_endpoints(edge_idx)
            .expect("lift() called with invalid index");
        let parent_edge = graph
            .first_edge(source, Direction::Incoming)
            .expect("Cannot find incoming edge of the to-be lifted node");
        let parent_rel = graph[parent_edge].clone();
        let (parent, _) = graph
            .edge_endpoints(parent_edge)
            .expect("Cannot find endpoints of to-be lifted edge");

        let rel = graph
            .remove_edge(edge_idx)
            .expect("Cannot remove edge to-be lifted");

        if lifted.contains(&target) {
            graph.add_edge(parent, target, rel);
        } else {
            graph.add_edge(parent, target, format!("{}|{}", rel, parent_rel));
            lifted.insert(target);
        }
    }

    /// Prepare for deprojectivizing: remove head annotations from lifted
    /// relations. Return the transformed graph + indices of lifted nodes
    /// and their head labels.
    fn prepare_deproj(
        &self,
        graph: &Graph<(), String, Directed>,
    ) -> (Graph<(), String, Directed>, HashMap<NodeIndex, String>) {
        let mut pref_head_labels = HashMap::new();

        let prepared_graph = graph.map(
            |_, &node_val| node_val,
            |edge_idx, edge_val| {
                let sep_idx = match edge_val.find('|') {
                    Some(idx) => idx,
                    None => return edge_val.clone(),
                };

                let (_, dep) = graph
                    .edge_endpoints(edge_idx)
                    .expect("Cannot lookup edge endpoints");

                pref_head_labels.insert(dep, edge_val[sep_idx + 1..].to_owned());

                edge_val[..sep_idx].to_owned()
            },
        );

        (prepared_graph, pref_head_labels)
    }
}

impl Projectivize for HeadProjectivizer {
    fn projectivize(&self, sentence: &[Token]) -> Result<Vec<Token>, GraphError> {
        let mut graph = sentence_to_graph(sentence)?;
        let mut lifted = HashSet::new();

        // Lift non-projective edges until there are no non-projective
        // edges left.
        loop {
            let np_edges = non_projective_edges(&graph);
            if np_edges.is_empty() {
                break;
            }

            self.lift(&mut graph, &mut lifted, np_edges[0]);
        }

        // The graph is now a projective tree. Update the dependency relations
        // in the sentence to correspond to the graph.
        Ok(update_sentence(&graph, sentence))
    }
}

impl Deprojectivize for HeadProjectivizer {
    fn deprojectivize(&self, sentence: &[Token]) -> Result<Vec<Token>, GraphError> {
        let graph = sentence_to_graph(sentence)?;

        // Find nodes and corresponding edges that are lifted and remove
        // head labels from dependency relations.
        let (mut graph, head_labels) = self.prepare_deproj(&graph);
        if head_labels.is_empty() {
            return Ok(sentence.to_owned());
        }

        // Get and sort lifted tokens by increasing depth.
        let mut lifted_sorted = Vec::new();
        let mut bfs = Bfs::new(&graph, node_index(0));
        while let Some(node) = bfs.next(&graph) {
            if head_labels.get(&node).is_some() {
                lifted_sorted.push(node);
            }
        }

        // Deprojectivize the graph, re-attaching one token at a time,
        // with the preference of a token that is not deep in the tree.
        loop {
            match self.deprojectivize_next(&mut graph, &lifted_sorted, &head_labels) {
                Some(idx) => lifted_sorted.remove(idx),
                None => break,
            };
        }

        Ok(update_sentence(&graph, sentence))
    }
}

pub fn sentence_to_graph(sentence: &[Token]) -> Result<Graph<(), String, Directed>, GraphError> {
    let mut edges = Vec::with_capacity(sentence.len() + 1);
    for (idx, token) in sentence.iter().enumerate() {
        let (head, dependent) = match token.head() {
            Some(head) => (node_index(head), node_index(idx + 1)),
            None => continue,
        };

        let head_rel = match token.head_rel() {
            Some(head_rel) => head_rel,
            None => {
                return Err(GraphError::IncompleteGraph {
                    value: format!(
                        "edge from {} to {} does not have a label",
                        head.index(),
                        dependent.index()
                    ),
                })
            }
        };

        edges.push((head, dependent, head_rel.to_owned()))
    }

    Ok(Graph::<(), String, Directed>::from_edges(edges))
}

/// Returns non-projective edges in the graph, ordered by length.
pub fn non_projective_edges(graph: &Graph<(), String, Directed>) -> Vec<EdgeIndex> {
    let mut non_projective = Vec::new();

    for i in 0..graph.node_count() {
        let mut i_reachable = HashSet::new();
        let mut bfs = Bfs::new(&graph, node_index(i));
        while let Some(node) = bfs.next(&graph) {
            i_reachable.insert(node.index());
        }

        for edge in graph.edges(node_index(i)) {
            // An edge i -> k is projective, iff:
            //
            // i > j > k or i < j < k, and i ->* j
            for j in min(i, edge.target().index())..max(i, edge.target().index()) {
                if !i_reachable.contains(&j) {
                    non_projective.push(edge);
                    break;
                }
            }
        }
    }

    non_projective.sort_by(|a, b| {
        let a_len = max(a.source().index(), a.target().index())
            - min(a.source().index(), a.target().index());
        let b_len = max(b.source().index(), b.target().index())
            - min(b.source().index(), b.target().index());

        a_len.cmp(&b_len)
    });

    non_projective.iter().map(|eref| eref.id()).collect()
}

/// Update a sentence with dependency relations from a graph.
fn update_sentence(graph: &Graph<(), String, Directed>, sent: &[Token]) -> Vec<Token> {
    let mut new_sent = sent.to_owned();
    {
        for edge_ref in graph.edge_references() {
            new_sent[edge_ref.target().index() - 1].set_head(Some(edge_ref.source().index()));
            new_sent[edge_ref.target().index() - 1].set_head_rel(Some(edge_ref.weight().clone()));
        }
    }

    new_sent
}

#[cfg(test)]
mod tests {
    use petgraph::graph::{node_index, NodeIndex};

    use {non_projective_edges, sentence_to_graph, Deprojectivize, HeadProjectivizer, Projectivize, Token};
    use tests::read_sentences;

    lazy_static! {
        static ref NON_PROJECTIVE_EDGES: Vec<Vec<(NodeIndex, NodeIndex)>> = vec![
        vec![(node_index(8), node_index(1))],
        vec![(node_index(10), node_index(2))],
        vec![(node_index(5), node_index(1))],
        vec![(node_index(1), node_index(3)), (node_index(7), node_index(5))],
        ];
    }

    fn sent_non_projective_edges(sents: &[Vec<Token>]) -> Vec<Vec<(NodeIndex, NodeIndex)>> {
        let mut np_edges = Vec::new();

        for sent in sents {
            let graph = sentence_to_graph(sent).unwrap();
            let np: Vec<_> = non_projective_edges(&graph)
                .iter()
                .map(|idx| graph.edge_endpoints(*idx).unwrap())
                .collect();
            np_edges.push(np);
        }

        np_edges
    }

    static PROJECTIVE_SENTENCES_FILENAME: &str = "testdata/projective.conll";

    static NONPROJECTIVE_SENTENCES_FILENAME: &str = "testdata/nonprojective.conll";

    #[test]
    fn deprojectivize_test() {
        let projectivizer = HeadProjectivizer::new();
        let non_projective: Vec<_> = read_sentences(PROJECTIVE_SENTENCES_FILENAME)
            .iter()
            .map(|s| {
                projectivizer
                    .deprojectivize(s)
                    .expect("Cannot deprojectivize sentence")
            })
            .collect();

        assert_eq!(
            read_sentences(NONPROJECTIVE_SENTENCES_FILENAME),
            non_projective
        );
    }

    #[test]
    fn non_projective_test() {
        let test_edges =
            sent_non_projective_edges(&read_sentences(NONPROJECTIVE_SENTENCES_FILENAME));
        assert_eq!(*NON_PROJECTIVE_EDGES, test_edges);
    }

    #[test]
    fn projectivize_test() {
        let projectivizer = HeadProjectivizer::new();
        let projective: Vec<_> = read_sentences(NONPROJECTIVE_SENTENCES_FILENAME)
            .iter()
            .map(|s| {
                projectivizer
                    .projectivize(s)
                    .expect("Cannot projectivize sentence")
            })
            .collect();

        assert_eq!(read_sentences(PROJECTIVE_SENTENCES_FILENAME), projective);
    }
}
<commit_msg>In-place use of projectivize/deprojectivize.<commit_after>use std::collections::{HashMap, HashSet};
use std::cmp::{max, min};

use itertools::Itertools;
use petgraph::{Directed, Direction, Graph};
use petgraph::graph::{node_index, EdgeIndex, NodeIndex};
use petgraph::visit::{Bfs, EdgeRef, NodeFiltered, Walker};

use {BfsWithDepth, GraphError, Token};

pub trait Deprojectivize {
    fn deprojectivize(&self, sentence: &mut [Token]) -> Result<(), GraphError>;
}

pub trait Projectivize {
    fn projectivize(&self, sentence: &mut [Token]) -> Result<(), GraphError>;
}

/// A projectivizer using the 'head' marking strategy. See: *Pseudo-Projective
/// Dependency Parsing*, Nivre and Nilsson, 2005.
pub struct HeadProjectivizer;

impl HeadProjectivizer {
    pub fn new() -> Self {
        HeadProjectivizer {}
    }

    /// Deprojectivize the next node in the array of lifted nodes.
    ///
    /// Returns the index of the node that was lifted.
    fn deprojectivize_next(
        &self,
        graph: &mut Graph<(), String, Directed>,
        lifted_sorted: &[NodeIndex],
        head_labels: &HashMap<NodeIndex, String>,
    ) -> Option<usize> {
        for (idx, lifted_node) in lifted_sorted.iter().enumerate() {
            let pref_head_rel = head_labels
                .get(lifted_node)
                .expect("Lifted node without preferred head relation");

            let head_edge = graph
                .first_edge(*lifted_node, Direction::Incoming)
                .expect("Lifted node without an incoming edge");
            let (cur_head, _) = graph
                .edge_endpoints(head_edge)
                .expect("Endpoints of lifted edge could not be found");

            if let Some(new_head) =
                self.search_attachment_point(&graph, cur_head, *lifted_node, pref_head_rel)
            {
                let head_rel = graph
                    .remove_edge(head_edge)
                    .expect("Lifted edge to be removed could not be found");
                graph.add_edge(new_head, *lifted_node, head_rel);
                return Some(idx);
            }
        }

        None
    }

    /// Find the correct attachment point for the lifted token/node.
    fn search_attachment_point(
        &self,
        graph: &Graph<(), String, Directed>,
        cur_head: NodeIndex,
        lifted_node: NodeIndex,
        pref_head_rel: &str,
    ) -> Option<NodeIndex> {
        // We are looking for a token dominated by cur_head to attach
        // lifted_node to. This token should:
        //
        // 1. Be attached to its head using pref_head_rel.
        // 2. Not be lifted_node itself or any of its decendants.
        // 3. As high in the tree as possible.
        //
        // From the set of candidates, we pick the token that is the
        // closest to the current head.

        // Requirement (2): use a view of the graph that excludes
        // to avoid attachment to the lifted_node or any of its children.
        let graph_without_lifted = NodeFiltered::from_fn(graph, |n| n != lifted_node);

        // Requirement (3): process the dependency tree by increasing depth
        // until the reattachment token is found.
        for (_, nodes) in &BfsWithDepth::new(&graph_without_lifted, node_index(0))
            .iter(&graph_without_lifted)
            .skip(1)
            .group_by(|&(_, depth)| depth)
        {
            // Requirement (1): Only retain edges with the preferred relation.
            let level_candidates = nodes.map(|(node, _)| node).filter(|&node| {
                let edge = match graph.first_edge(node, Direction::Incoming) {
                    Some(edge) => edge,
                    None => return false,
                };

                graph[edge] == pref_head_rel
            });

            // When there are multiple candidates, return the token closes to the head.
            let min_candidate = level_candidates.min_by_key(|&node| {
                max(node.index(), cur_head.index()) - min(node.index(), cur_head.index())
            });

            if min_candidate.is_some() {
                return min_candidate;
            }
        }

        None
    }

    /// Lift the edge identified by `edge_idx`. This will reattach the edge
    /// to the parent of the head. If this was the first lifting operation,
    /// the dependency relation of the original head is added to the dependency
    /// relation (following the head-strategy).
    fn lift(
        &self,
        graph: &mut Graph<(), String, Directed>,
        lifted: &mut HashSet<NodeIndex>,
        edge_idx: EdgeIndex,
    ) {
        let (source, target) = graph
            .edge_endpoints(edge_idx)
            .expect("lift() called with invalid index");
        let parent_edge = graph
            .first_edge(source, Direction::Incoming)
            .expect("Cannot find incoming edge of the to-be lifted node");
        let parent_rel = graph[parent_edge].clone();
        let (parent, _) = graph
            .edge_endpoints(parent_edge)
            .expect("Cannot find endpoints of to-be lifted edge");

        let rel = graph
            .remove_edge(edge_idx)
            .expect("Cannot remove edge to-be lifted");

        if lifted.contains(&target) {
            graph.add_edge(parent, target, rel);
        } else {
            graph.add_edge(parent, target, format!("{}|{}", rel, parent_rel));
            lifted.insert(target);
        }
    }

    /// Prepare for deprojectivizing: remove head annotations from lifted
    /// relations. Return the transformed graph + indices of lifted nodes
    /// and their head labels.
    fn prepare_deproj(
        &self,
        graph: &Graph<(), String, Directed>,
    ) -> (Graph<(), String, Directed>, HashMap<NodeIndex, String>) {
        let mut pref_head_labels = HashMap::new();

        let prepared_graph = graph.map(
            |_, &node_val| node_val,
            |edge_idx, edge_val| {
                let sep_idx = match edge_val.find('|') {
                    Some(idx) => idx,
                    None => return edge_val.clone(),
                };

                let (_, dep) = graph
                    .edge_endpoints(edge_idx)
                    .expect("Cannot lookup edge endpoints");

                pref_head_labels.insert(dep, edge_val[sep_idx + 1..].to_owned());

                edge_val[..sep_idx].to_owned()
            },
        );

        (prepared_graph, pref_head_labels)
    }
}

impl Projectivize for HeadProjectivizer {
    fn projectivize(&self, sentence: &mut [Token]) -> Result<(), GraphError> {
        let mut graph = sentence_to_graph(sentence)?;
        let mut lifted = HashSet::new();

        // Lift non-projective edges until there are no non-projective
        // edges left.
        loop {
            let np_edges = non_projective_edges(&graph);
            if np_edges.is_empty() {
                break;
            }

            self.lift(&mut graph, &mut lifted, np_edges[0]);
        }

        // The graph is now a projective tree. Update the dependency relations
        // in the sentence to correspond to the graph.
        Ok(update_sentence(&graph, sentence))
    }
}

impl Deprojectivize for HeadProjectivizer {
    fn deprojectivize(&self, sentence: &mut [Token]) -> Result<(), GraphError> {
        let graph = sentence_to_graph(sentence)?;

        // Find nodes and corresponding edges that are lifted and remove
        // head labels from dependency relations.
        let (mut graph, head_labels) = self.prepare_deproj(&graph);
        if head_labels.is_empty() {
            return Ok(());
        }

        // Get and sort lifted tokens by increasing depth.
        let mut lifted_sorted = Vec::new();
        let mut bfs = Bfs::new(&graph, node_index(0));
        while let Some(node) = bfs.next(&graph) {
            if head_labels.get(&node).is_some() {
                lifted_sorted.push(node);
            }
        }

        // Deprojectivize the graph, re-attaching one token at a time,
        // with the preference of a token that is not deep in the tree.
        loop {
            match self.deprojectivize_next(&mut graph, &lifted_sorted, &head_labels) {
                Some(idx) => lifted_sorted.remove(idx),
                None => break,
            };
        }

        Ok(update_sentence(&graph, sentence))
    }
}

pub fn sentence_to_graph(sentence: &[Token]) -> Result<Graph<(), String, Directed>, GraphError> {
    let mut edges = Vec::with_capacity(sentence.len() + 1);
    for (idx, token) in sentence.iter().enumerate() {
        let (head, dependent) = match token.head() {
            Some(head) => (node_index(head), node_index(idx + 1)),
            None => continue,
        };

        let head_rel = match token.head_rel() {
            Some(head_rel) => head_rel,
            None => {
                return Err(GraphError::IncompleteGraph {
                    value: format!(
                        "edge from {} to {} does not have a label",
                        head.index(),
                        dependent.index()
                    ),
                })
            }
        };

        edges.push((head, dependent, head_rel.to_owned()))
    }

    Ok(Graph::<(), String, Directed>::from_edges(edges))
}

/// Returns non-projective edges in the graph, ordered by length.
pub fn non_projective_edges(graph: &Graph<(), String, Directed>) -> Vec<EdgeIndex> {
    let mut non_projective = Vec::new();

    for i in 0..graph.node_count() {
        let mut i_reachable = HashSet::new();
        let mut bfs = Bfs::new(&graph, node_index(i));
        while let Some(node) = bfs.next(&graph) {
            i_reachable.insert(node.index());
        }

        for edge in graph.edges(node_index(i)) {
            // An edge i -> k is projective, iff:
            //
            // i > j > k or i < j < k, and i ->* j
            for j in min(i, edge.target().index())..max(i, edge.target().index()) {
                if !i_reachable.contains(&j) {
                    non_projective.push(edge);
                    break;
                }
            }
        }
    }

    non_projective.sort_by(|a, b| {
        let a_len = max(a.source().index(), a.target().index())
            - min(a.source().index(), a.target().index());
        let b_len = max(b.source().index(), b.target().index())
            - min(b.source().index(), b.target().index());

        a_len.cmp(&b_len)
    });

    non_projective.iter().map(|eref| eref.id()).collect()
}

/// Update a sentence with dependency relations from a graph.
fn update_sentence(graph: &Graph<(), String, Directed>, sentence: &mut [Token]) {
    {
        for edge_ref in graph.edge_references() {
            sentence[edge_ref.target().index() - 1].set_head(Some(edge_ref.source().index()));
            sentence[edge_ref.target().index() - 1].set_head_rel(Some(edge_ref.weight().clone()));
        }
    }
}

#[cfg(test)]
mod tests {
    use petgraph::graph::{node_index, NodeIndex};

    use {non_projective_edges, sentence_to_graph, Deprojectivize, HeadProjectivizer, Projectivize, Token};
    use tests::read_sentences;

    lazy_static! {
        static ref NON_PROJECTIVE_EDGES: Vec<Vec<(NodeIndex, NodeIndex)>> = vec![
        vec![(node_index(8), node_index(1))],
        vec![(node_index(10), node_index(2))],
        vec![(node_index(5), node_index(1))],
        vec![(node_index(1), node_index(3)), (node_index(7), node_index(5))],
        ];
    }

    fn sent_non_projective_edges(sents: &[Vec<Token>]) -> Vec<Vec<(NodeIndex, NodeIndex)>> {
        let mut np_edges = Vec::new();

        for sent in sents {
            let graph = sentence_to_graph(sent).unwrap();
            let np: Vec<_> = non_projective_edges(&graph)
                .iter()
                .map(|idx| graph.edge_endpoints(*idx).unwrap())
                .collect();
            np_edges.push(np);
        }

        np_edges
    }

    static PROJECTIVE_SENTENCES_FILENAME: &str = "testdata/projective.conll";

    static NONPROJECTIVE_SENTENCES_FILENAME: &str = "testdata/nonprojective.conll";

    #[test]
    fn deprojectivize_test() {
        let projectivizer = HeadProjectivizer::new();
        let non_projective: Vec<_> = read_sentences(PROJECTIVE_SENTENCES_FILENAME)
            .into_iter()
            .map(|mut s| {
                projectivizer
                    .deprojectivize(&mut s)
                    .expect("Cannot deprojectivize sentence");
                s
            })
            .collect();

        assert_eq!(
            read_sentences(NONPROJECTIVE_SENTENCES_FILENAME),
            non_projective
        );
    }

    #[test]
    fn non_projective_test() {
        let test_edges =
            sent_non_projective_edges(&read_sentences(NONPROJECTIVE_SENTENCES_FILENAME));
        assert_eq!(*NON_PROJECTIVE_EDGES, test_edges);
    }

    #[test]
    fn projectivize_test() {
        let projectivizer = HeadProjectivizer::new();
        let projective: Vec<_> = read_sentences(NONPROJECTIVE_SENTENCES_FILENAME)
            .into_iter()
            .map(|mut s| {
                projectivizer
                    .projectivize(&mut s)
                    .expect("Cannot projectivize sentence");
                s
            })
            .collect();

        assert_eq!(read_sentences(PROJECTIVE_SENTENCES_FILENAME), projective);
    }
}
<|endoftext|>


<commit_before>extern crate rustbox;
use std::comm::{Receiver};
use std::io::{File, Open, ReadWrite};

pub struct Editor {
    pub events: Receiver<rustbox::Event>,
    pub buffers: Vec<Buf>
}

pub struct Buf {
    pub first_line: Vec<Line>,
    pub last_line: Vec<Line>,
}

pub struct Line {
    pub data: Vec<u8>,
}

enum Response {
    Continue,
    Quit,
}

impl Editor {
    pub fn handle_key_event(&self, ch: u32) -> Response {
        match std::char::from_u32(ch) {
            Some('q') => Quit,
            _ => Continue,
        }
    }

    pub fn start(&self) -> bool {
        loop {
            let status = match self.events.recv() {
                rustbox::KeyEvent(_, _, ch) => {
                    let status = self.handle_key_event(ch);
                    match status {
                        Quit => { false },
                        _ => { true },
                    }
                },
                _ => { true }
            };
            if status == false {
                return false;
            }
        }
    }

    pub fn open_file(&self, fp: &str) {
        let path = Path::new(fp);

        let mut file = std::io::BufferedReader::new(File::open(&path));
        for line in file.lines() {
            rustbox::print(1, 1, rustbox::Bold, rustbox::White, rustbox::Black, line.to_string());
            rustbox::present();
        }
    }
}

<commit_msg>Unwrap lines, duh<commit_after>extern crate rustbox;
use std::comm::{Receiver};
use std::io::{File, Open, ReadWrite, BufferedReader};

pub struct Editor {
    pub events: Receiver<rustbox::Event>,
    pub buffers: Vec<Buf>
}

pub struct Buf {
    pub first_line: Vec<Line>,
    pub last_line: Vec<Line>,
}

pub struct Line {
    pub data: Vec<u8>,
}

enum Response {
    Continue,
    Quit,
}

impl Editor {
    pub fn handle_key_event(&self, ch: u32) -> Response {
        match std::char::from_u32(ch) {
            Some('q') => Quit,
            _ => Continue,
        }
    }

    pub fn start(&self) -> bool {
        loop {
            let status = match self.events.recv() {
                rustbox::KeyEvent(_, _, ch) => {
                    let status = self.handle_key_event(ch);
                    match status {
                        Quit => { false },
                        _ => { true },
                    }
                },
                _ => { true }
            };
            if status == false {
                return false;
            }
        }
    }

    pub fn open_file(&self, fp: &str) {
        let path = Path::new(fp);
        let file = match File::open(&path) {
            Ok(f) => f,
            Err(e) => fail!("New file - not implemented"),
        };

        let mut buf = BufferedReader::new(file);

        for (index, line) in buf.lines().enumerate() {
            rustbox::print(1, index + 1, rustbox::Bold, rustbox::White, rustbox::Black, line.unwrap());
            rustbox::present();
        }
    }
}

<|endoftext|>


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

//! Rust wrappers around the raw JS apis

use libc::types::os::arch::c95::{size_t, c_uint};
use libc::uintptr_t;
use libc::c_char;
use std::cmp;
use std::rc;
use std::string;
use jsapi::*;
use jsapi::JSVersion::JSVERSION_LATEST;
use jsval::{JSVal, NullValue};
use default_stacksize;
use default_heapsize;
use JSOPTION_VAROBJFIX;
use JSOPTION_METHODJIT;
use JSOPTION_TYPE_INFERENCE;
use ERR;

// ___________________________________________________________________________
// friendly Rustic API to runtimes

pub type rt = rc::Rc<rt_rsrc>;

pub struct rt_rsrc {
    pub ptr : *mut JSRuntime,
}

impl Drop for rt_rsrc {
    fn drop(&mut self) {
        unsafe {
            JS_Finish(self.ptr);
        }
    }
}

pub fn new_runtime(p: *mut JSRuntime) -> rt {
    return rc::Rc::new(rt_rsrc {
        ptr: p
    })
}

pub trait RtUtils {
    fn cx(&self) -> rc::Rc<Cx>;
}

impl RtUtils for rc::Rc<rt_rsrc> {
    fn cx(&self) -> rc::Rc<Cx> {
        unsafe {
            new_context(JS_NewContext(self.deref().ptr,
                                      default_stacksize as size_t), self.clone())
        }
    }
}

pub fn rt() -> rt {
    unsafe {
        let runtime = JS_Init(default_heapsize);
        return new_runtime(runtime);
    }
}

// ___________________________________________________________________________
// contexts

pub struct Cx {
    pub ptr: *mut JSContext,
    pub rt: rt,
}

#[unsafe_destructor]
impl Drop for Cx {
    fn drop(&mut self) {
        unsafe {
            JS_DestroyContext(self.ptr);
        }
    }
}

pub fn new_context(ptr: *mut JSContext, rt: rt) -> rc::Rc<Cx> {
    return rc::Rc::new(Cx {
        ptr: ptr,
        rt: rt,
    })
}

impl Cx {
    pub fn set_default_options_and_version(&self) {
        self.set_options(JSOPTION_VAROBJFIX | JSOPTION_METHODJIT |
                         JSOPTION_TYPE_INFERENCE |
                         JSOPTION_DONT_REPORT_UNCAUGHT |
                         JSOPTION_AUTOJSAPI_OWNS_ERROR_REPORTING);
        self.set_version(JSVERSION_LATEST);
    }

    pub fn set_options(&self, v: c_uint) {
        unsafe {
            JS_SetOptions(self.ptr, v);
        }
    }

    pub fn set_version(&self, v: JSVersion) {
        unsafe {
            JS_SetVersion(self.ptr, v);
        }
    }

    pub fn set_logging_error_reporter(&self) {
        unsafe {
            JS_SetErrorReporter(self.ptr, Some(reportError));
        }
    }

    pub fn set_error_reporter(&self, reportfn: unsafe extern "C" fn(*mut JSContext, *const c_char, *mut JSErrorReport)) {
        unsafe {
            JS_SetErrorReporter(self.ptr, Some(reportfn));
        }
    }

    pub fn evaluate_script(&self, glob: *mut JSObject, script: String, filename: String, line_num: uint)
                    -> Result<(),()> {
        let script_utf16: Vec<u16> = script.as_slice().utf16_units().collect();
        let filename_cstr = filename.to_c_str();
        let mut rval: JSVal = NullValue();
        debug!("Evaluating script from {} with content {}", filename, script);
        // SpiderMonkey does not approve of null pointers.
        let (ptr, len) = if script_utf16.len() == 0 {
            static empty: &'static [u16] = &[];
            (empty.as_ptr(), 0)
        } else {
            (script_utf16.as_ptr(), script_utf16.len() as c_uint)
        };
        assert!(ptr.is_not_null());
        unsafe {
            if ERR == JS_EvaluateUCScript(self.ptr, glob, ptr, len,
                                          filename_cstr.as_ptr(), line_num as c_uint,
                                          &mut rval) {
                debug!("...err!");
                Err(())
            } else {
                // we could return the script result but then we'd have
                // to root it and so forth and, really, who cares?
                debug!("...ok!");
                Ok(())
            }
        }
    }
}

pub unsafe extern fn reportError(_cx: *mut JSContext, msg: *const c_char, report: *mut JSErrorReport) {
    let fnptr = (*report).filename;
    let fname = if fnptr.is_not_null() {string::raw::from_buf(fnptr as *const i8 as *const u8)} else {"none".to_string()};
    let lineno = (*report).lineno;
    let msg = string::raw::from_buf(msg as *const i8 as *const u8);
    error!("Error at {}:{}: {}\n", fname, lineno, msg);
}

pub fn with_compartment<R>(cx: *mut JSContext, object: *mut JSObject, cb: || -> R) -> R {
    unsafe {
        let call = JS_EnterCrossCompartmentCall(cx, object);
        let result = cb();
        JS_LeaveCrossCompartmentCall(call);
        result
    }
}

#[cfg(test)]
pub mod test {
    use super::rt;
    use super::RtUtils;

    #[test]
    pub fn dummy() {
        let rt = rt();
        let cx = rt.cx();
        cx.deref().set_default_options_and_version();
        cx.deref().set_logging_error_reporter();
    }

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

//! Rust wrappers around the raw JS apis

use libc::types::os::arch::c95::{size_t, c_uint};
use libc::uintptr_t;
use libc::c_char;
use std::cmp;
use std::rc;
use std::string;
use jsapi::*;
use jsapi::JSVersion::JSVERSION_LATEST;
use jsval::{JSVal, NullValue};
use default_stacksize;
use default_heapsize;
use JSOPTION_VAROBJFIX;
use JSOPTION_METHODJIT;
use JSOPTION_TYPE_INFERENCE;
use JSOPTION_DONT_REPORT_UNCAUGHT;
use JSOPTION_AUTOJSAPI_OWNS_ERROR_REPORTING;
use ERR;

// ___________________________________________________________________________
// friendly Rustic API to runtimes

pub type rt = rc::Rc<rt_rsrc>;

pub struct rt_rsrc {
    pub ptr : *mut JSRuntime,
}

impl Drop for rt_rsrc {
    fn drop(&mut self) {
        unsafe {
            JS_Finish(self.ptr);
        }
    }
}

pub fn new_runtime(p: *mut JSRuntime) -> rt {
    return rc::Rc::new(rt_rsrc {
        ptr: p
    })
}

pub trait RtUtils {
    fn cx(&self) -> rc::Rc<Cx>;
}

impl RtUtils for rc::Rc<rt_rsrc> {
    fn cx(&self) -> rc::Rc<Cx> {
        unsafe {
            new_context(JS_NewContext(self.deref().ptr,
                                      default_stacksize as size_t), self.clone())
        }
    }
}

pub fn rt() -> rt {
    unsafe {
        let runtime = JS_Init(default_heapsize);
        return new_runtime(runtime);
    }
}

// ___________________________________________________________________________
// contexts

pub struct Cx {
    pub ptr: *mut JSContext,
    pub rt: rt,
}

#[unsafe_destructor]
impl Drop for Cx {
    fn drop(&mut self) {
        unsafe {
            JS_DestroyContext(self.ptr);
        }
    }
}

pub fn new_context(ptr: *mut JSContext, rt: rt) -> rc::Rc<Cx> {
    return rc::Rc::new(Cx {
        ptr: ptr,
        rt: rt,
    })
}

impl Cx {
    pub fn set_default_options_and_version(&self) {
        self.set_options(JSOPTION_VAROBJFIX | JSOPTION_METHODJIT |
                         JSOPTION_TYPE_INFERENCE |
                         JSOPTION_DONT_REPORT_UNCAUGHT |
                         JSOPTION_AUTOJSAPI_OWNS_ERROR_REPORTING);
        self.set_version(JSVERSION_LATEST);
    }

    pub fn set_options(&self, v: c_uint) {
        unsafe {
            JS_SetOptions(self.ptr, v);
        }
    }

    pub fn set_version(&self, v: JSVersion) {
        unsafe {
            JS_SetVersion(self.ptr, v);
        }
    }

    pub fn set_logging_error_reporter(&self) {
        unsafe {
            JS_SetErrorReporter(self.ptr, Some(reportError));
        }
    }

    pub fn set_error_reporter(&self, reportfn: unsafe extern "C" fn(*mut JSContext, *const c_char, *mut JSErrorReport)) {
        unsafe {
            JS_SetErrorReporter(self.ptr, Some(reportfn));
        }
    }

    pub fn evaluate_script(&self, glob: *mut JSObject, script: String, filename: String, line_num: uint)
                    -> Result<(),()> {
        let script_utf16: Vec<u16> = script.as_slice().utf16_units().collect();
        let filename_cstr = filename.to_c_str();
        let mut rval: JSVal = NullValue();
        debug!("Evaluating script from {} with content {}", filename, script);
        // SpiderMonkey does not approve of null pointers.
        let (ptr, len) = if script_utf16.len() == 0 {
            static empty: &'static [u16] = &[];
            (empty.as_ptr(), 0)
        } else {
            (script_utf16.as_ptr(), script_utf16.len() as c_uint)
        };
        assert!(ptr.is_not_null());
        unsafe {
            if ERR == JS_EvaluateUCScript(self.ptr, glob, ptr, len,
                                          filename_cstr.as_ptr(), line_num as c_uint,
                                          &mut rval) {
                debug!("...err!");
                Err(())
            } else {
                // we could return the script result but then we'd have
                // to root it and so forth and, really, who cares?
                debug!("...ok!");
                Ok(())
            }
        }
    }
}

pub unsafe extern fn reportError(_cx: *mut JSContext, msg: *const c_char, report: *mut JSErrorReport) {
    let fnptr = (*report).filename;
    let fname = if fnptr.is_not_null() {string::raw::from_buf(fnptr as *const i8 as *const u8)} else {"none".to_string()};
    let lineno = (*report).lineno;
    let msg = string::raw::from_buf(msg as *const i8 as *const u8);
    error!("Error at {}:{}: {}\n", fname, lineno, msg);
}

pub fn with_compartment<R>(cx: *mut JSContext, object: *mut JSObject, cb: || -> R) -> R {
    unsafe {
        let call = JS_EnterCrossCompartmentCall(cx, object);
        let result = cb();
        JS_LeaveCrossCompartmentCall(call);
        result
    }
}

#[cfg(test)]
pub mod test {
    use super::rt;
    use super::RtUtils;

    #[test]
    pub fn dummy() {
        let rt = rt();
        let cx = rt.cx();
        cx.deref().set_default_options_and_version();
        cx.deref().set_logging_error_reporter();
    }

}
<|endoftext|>