<commit_before>use mio::net::{TcpListener, TcpStream};
use mio::*;
use std::sync::{Arc, Barrier};
use std::thread;
use std::time::Duration;

mod util;

use util::{any_local_address, assert_send, assert_sync, init};

#[test]
fn is_send_and_sync() {
    assert_sync::<Poll>();
    assert_send::<Poll>();

    assert_sync::<Registry>();
    assert_send::<Registry>();
}

#[test]
fn run_once_with_nothing() {
    init();

    let mut events = Events::with_capacity(16);
    let mut poll = Poll::new().unwrap();
    poll.poll(&mut events, Some(Duration::from_millis(100)))
        .unwrap();
}

#[test]
fn add_then_drop() {
    init();

    let mut events = Events::with_capacity(16);
    let l = TcpListener::bind(any_local_address()).unwrap();
    let mut poll = Poll::new().unwrap();
    poll.registry()
        .register(&l, Token(1), Interests::READABLE | Interests::WRITABLE)
        .unwrap();
    drop(l);
    poll.poll(&mut events, Some(Duration::from_millis(100)))
        .unwrap();
}

#[test]
fn test_poll_closes_fd() {
    init();

    for _ in 0..2000 {
        let mut poll = Poll::new().unwrap();
        let mut events = Events::with_capacity(4);

        poll.poll(&mut events, Some(Duration::from_millis(0)))
            .unwrap();

        drop(poll);
    }
}

#[test]
fn test_drop_cancels_interest_and_shuts_down() {
    init();

    use mio::net::TcpStream;
    use std::io;
    use std::io::Read;
    use std::net::TcpListener;
    use std::thread;

    let l = TcpListener::bind("127.0.0.1:0").unwrap();
    let addr = l.local_addr().unwrap();

    let t = thread::spawn(move || {
        let mut s = l.incoming().next().unwrap().unwrap();
        s.set_read_timeout(Some(Duration::from_secs(5)))
            .expect("set_read_timeout");
        let r = s.read(&mut [0; 16]);
        match r {
            Ok(_) => (),
            Err(e) => {
                if e.kind() != io::ErrorKind::UnexpectedEof {
                    panic!(e);
                }
            }
        }
    });

    let mut poll = Poll::new().unwrap();
    let mut s = TcpStream::connect(addr).unwrap();

    poll.registry()
        .register(&s, Token(1), Interests::READABLE | Interests::WRITABLE)
        .unwrap();
    let mut events = Events::with_capacity(16);
    'outer: loop {
        poll.poll(&mut events, None).unwrap();
        for event in &events {
            if event.token() == Token(1) {
                // connected
                break 'outer;
            }
        }
    }

    let mut b = [0; 1024];
    match s.read(&mut b) {
        Ok(_) => panic!("unexpected ok"),
        Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => (),
        Err(e) => panic!("unexpected error: {:?}", e),
    }

    drop(s);
    t.join().unwrap();
}

#[test]
fn test_registry_behind_arc() {
    // `Registry` should work behind an `Arc`, being `Sync` and `Send`.
    init();

    let mut poll = Poll::new().unwrap();
    let registry = Arc::new(poll.registry().try_clone().unwrap());
    let mut events = Events::with_capacity(128);

    let listener = TcpListener::bind(any_local_address()).unwrap();
    let addr = listener.local_addr().unwrap();
    let barrier = Arc::new(Barrier::new(3));

    let registry2 = Arc::clone(&registry);
    let registry3 = Arc::clone(&registry);
    let barrier2 = Arc::clone(&barrier);
    let barrier3 = Arc::clone(&barrier);

    let handle1 = thread::spawn(move || {
        registry2
            .register(&listener, Token(0), Interests::READABLE)
            .unwrap();
        barrier2.wait();
    });
    let handle2 = thread::spawn(move || {
        let stream = TcpStream::connect(addr).unwrap();
        registry3
            .register(&stream, Token(1), Interests::READABLE | Interests::WRITABLE)
            .unwrap();
        barrier3.wait();
    });

    poll.poll(&mut events, Some(Duration::from_millis(1000)))
        .unwrap();
    assert!(events.iter().count() >= 1);

    // Let the threads return.
    barrier.wait();

    handle1.join().unwrap();
    handle2.join().unwrap();
}

// On kqueue platforms registering twice (not *re*registering) works.
#[test]
#[cfg(any(target_os = "linux", target_os = "windows"))]
pub fn test_double_register() {
    init();
    let poll = Poll::new().unwrap();

    let l = TcpListener::bind("127.0.0.1:0".parse().unwrap()).unwrap();

    poll.registry()
        .register(&l, Token(0), Interests::READABLE)
        .unwrap();

    assert!(poll
        .registry()
        .register(&l, Token(1), Interests::READABLE)
        .is_err());
}
<commit_msg>Add a test for polling with zero duration (#1065)<commit_after>use mio::net::{TcpListener, TcpStream};
use mio::*;
use std::net;
use std::sync::{Arc, Barrier};
use std::thread::{self, sleep};
use std::time::Duration;

mod util;

use util::{any_local_address, assert_send, assert_sync, init};

#[test]
fn is_send_and_sync() {
    assert_sync::<Poll>();
    assert_send::<Poll>();

    assert_sync::<Registry>();
    assert_send::<Registry>();
}

#[test]
fn run_once_with_nothing() {
    init();

    let mut events = Events::with_capacity(16);
    let mut poll = Poll::new().unwrap();
    poll.poll(&mut events, Some(Duration::from_millis(100)))
        .unwrap();
}

#[test]
fn add_then_drop() {
    init();

    let mut events = Events::with_capacity(16);
    let l = TcpListener::bind(any_local_address()).unwrap();
    let mut poll = Poll::new().unwrap();
    poll.registry()
        .register(&l, Token(1), Interests::READABLE | Interests::WRITABLE)
        .unwrap();
    drop(l);
    poll.poll(&mut events, Some(Duration::from_millis(100)))
        .unwrap();
}

#[test]
fn zero_duration_polls_events() {
    init();

    let mut poll = Poll::new().unwrap();
    let mut events = Events::with_capacity(16);

    let listener = net::TcpListener::bind(any_local_address()).unwrap();
    let addr = listener.local_addr().unwrap();

    let streams: Vec<TcpStream> = (0..3)
        .map(|n| {
            let stream = TcpStream::connect(addr).unwrap();
            poll.registry()
                .register(&stream, Token(n), Interests::WRITABLE)
                .unwrap();
            stream
        })
        .collect();

    // Ensure the TcpStreams have some time to connection and for the events to
    // show up.
    sleep(Duration::from_millis(10));

    // Even when passing a zero duration timeout we still want do the system
    // call.
    poll.poll(&mut events, Some(Duration::from_nanos(0)))
        .unwrap();
    assert!(!events.is_empty());

    // Both need to live until here.
    drop(streams);
    drop(listener);
}

#[test]
fn test_poll_closes_fd() {
    init();

    for _ in 0..2000 {
        let mut poll = Poll::new().unwrap();
        let mut events = Events::with_capacity(4);

        poll.poll(&mut events, Some(Duration::from_millis(0)))
            .unwrap();

        drop(poll);
    }
}

#[test]
fn test_drop_cancels_interest_and_shuts_down() {
    init();

    use mio::net::TcpStream;
    use std::io;
    use std::io::Read;
    use std::net::TcpListener;
    use std::thread;

    let l = TcpListener::bind("127.0.0.1:0").unwrap();
    let addr = l.local_addr().unwrap();

    let t = thread::spawn(move || {
        let mut s = l.incoming().next().unwrap().unwrap();
        s.set_read_timeout(Some(Duration::from_secs(5)))
            .expect("set_read_timeout");
        let r = s.read(&mut [0; 16]);
        match r {
            Ok(_) => (),
            Err(e) => {
                if e.kind() != io::ErrorKind::UnexpectedEof {
                    panic!(e);
                }
            }
        }
    });

    let mut poll = Poll::new().unwrap();
    let mut s = TcpStream::connect(addr).unwrap();

    poll.registry()
        .register(&s, Token(1), Interests::READABLE | Interests::WRITABLE)
        .unwrap();
    let mut events = Events::with_capacity(16);
    'outer: loop {
        poll.poll(&mut events, None).unwrap();
        for event in &events {
            if event.token() == Token(1) {
                // connected
                break 'outer;
            }
        }
    }

    let mut b = [0; 1024];
    match s.read(&mut b) {
        Ok(_) => panic!("unexpected ok"),
        Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => (),
        Err(e) => panic!("unexpected error: {:?}", e),
    }

    drop(s);
    t.join().unwrap();
}

#[test]
fn test_registry_behind_arc() {
    // `Registry` should work behind an `Arc`, being `Sync` and `Send`.
    init();

    let mut poll = Poll::new().unwrap();
    let registry = Arc::new(poll.registry().try_clone().unwrap());
    let mut events = Events::with_capacity(128);

    let listener = TcpListener::bind(any_local_address()).unwrap();
    let addr = listener.local_addr().unwrap();
    let barrier = Arc::new(Barrier::new(3));

    let registry2 = Arc::clone(&registry);
    let registry3 = Arc::clone(&registry);
    let barrier2 = Arc::clone(&barrier);
    let barrier3 = Arc::clone(&barrier);

    let handle1 = thread::spawn(move || {
        registry2
            .register(&listener, Token(0), Interests::READABLE)
            .unwrap();
        barrier2.wait();
    });
    let handle2 = thread::spawn(move || {
        let stream = TcpStream::connect(addr).unwrap();
        registry3
            .register(&stream, Token(1), Interests::READABLE | Interests::WRITABLE)
            .unwrap();
        barrier3.wait();
    });

    poll.poll(&mut events, Some(Duration::from_millis(1000)))
        .unwrap();
    assert!(events.iter().count() >= 1);

    // Let the threads return.
    barrier.wait();

    handle1.join().unwrap();
    handle2.join().unwrap();
}

// On kqueue platforms registering twice (not *re*registering) works.
#[test]
#[cfg(any(target_os = "linux", target_os = "windows"))]
pub fn test_double_register() {
    init();
    let poll = Poll::new().unwrap();

    let l = TcpListener::bind("127.0.0.1:0".parse().unwrap()).unwrap();

    poll.registry()
        .register(&l, Token(0), Interests::READABLE)
        .unwrap();

    assert!(poll
        .registry()
        .register(&l, Token(1), Interests::READABLE)
        .is_err());
}
<|endoftext|>


<commit_before>use std::process::{Command, exit};
use git2::{Repository, Error, ErrorCode};

/// Gets the current branch from the given Git repository.
///
/// # Examples
///
/// ```ignore
/// let repo = try!(Repository::open("."));
/// let branchname = try!(branch(&repo));
/// ```
pub fn branch<'a>(repo: &'a Repository) -> Result<String, Error> {
    let head = match repo.head() {
        Ok(head) => Some(head),
        Err(ref e) if e.code() == ErrorCode::UnbornBranch ||
                      e.code() == ErrorCode::NotFound
                   => None,
        Err(e) => return Err(e),
    };
    let branchref = head.as_ref().and_then(|h| h.shorthand());
    let branchname = branchref.unwrap_or("HEAD (no branch)").to_string();

    Ok(branchname)
}

pub fn checkout(target_branch: &str) {
    let output = Command::new("git")
                         .arg("checkout")
                         .arg(target_branch)
                         .output()
                         .unwrap_or_else(|e| {
                            panic!("failed to execute process: {}", e) });
    let status_code = output.status.code();

    println!("Checking out {} ...", target_branch);

    match status_code {
        Some(0) => println!("{}", String::from_utf8_lossy(&output.stdout)),
        Some(_) => {
             println!("{}", String::from_utf8_lossy(&output.stderr));
             exit(status_code.unwrap());
        }
        None => println!("Something wrong happened"),
    }
}

pub fn pull(target_remote: &str, target_branch: &str) {
    let output = Command::new("git")
                         .arg("pull")
                         .arg("--quiet")
                         .arg("--rebase=preserve")
                         .arg(target_remote)
                         .arg(target_branch)
                         .output()
                         .unwrap_or_else(|e| {
                            panic!("failed to execute process: {}", e) });
    let status_code = output.status.code();

    println!("Pulling {} {} ...", target_remote, target_branch);

    match status_code {
        Some(0) => println!("{}", String::from_utf8_lossy(&output.stdout)),
        Some(_) => {
             println!("{}", String::from_utf8_lossy(&output.stderr));
             exit(status_code.unwrap());
        }
        None => println!("Something wrong happened"),
    }
}

pub fn rebase(target_branch: &str) {
    let output = Command::new("git")
                         .arg("rebase")
                         .arg(target_branch)
                         .output()
                         .unwrap_or_else(|e| {
                            panic!("failed to execute process: {}", e) });
    let status_code = output.status.code();

    println!("Rebasing {} ...", target_branch);

    match status_code {
        Some(0) => println!("{}", String::from_utf8_lossy(&output.stdout)),
        Some(_) => {
             println!("{}", String::from_utf8_lossy(&output.stderr));
             exit(status_code.unwrap());
        }
        None => println!("Something wrong happened"),
    }
}
<commit_msg>Removing unnecessary lifetime marks<commit_after>use std::process::{Command, exit};
use git2::{Repository, Error, ErrorCode};

/// Gets the current branch from the given Git repository.
///
/// # Examples
///
/// ```ignore
/// let repo = try!(Repository::open("."));
/// let branchname = try!(branch(&repo));
/// ```
pub fn branch(repo: &Repository) -> Result<String, Error> {
    let head = match repo.head() {
        Ok(head) => Some(head),
        Err(ref e) if e.code() == ErrorCode::UnbornBranch ||
                      e.code() == ErrorCode::NotFound
                   => None,
        Err(e) => return Err(e),
    };
    let branchref = head.as_ref().and_then(|h| h.shorthand());
    let branchname = branchref.unwrap_or("HEAD (no branch)").to_string();

    Ok(branchname)
}

pub fn checkout(target_branch: &str) {
    let output = Command::new("git")
                         .arg("checkout")
                         .arg(target_branch)
                         .output()
                         .unwrap_or_else(|e| {
                            panic!("failed to execute process: {}", e) });
    let status_code = output.status.code();

    println!("Checking out {} ...", target_branch);

    match status_code {
        Some(0) => println!("{}", String::from_utf8_lossy(&output.stdout)),
        Some(_) => {
             println!("{}", String::from_utf8_lossy(&output.stderr));
             exit(status_code.unwrap());
        }
        None => println!("Something wrong happened"),
    }
}

pub fn pull(target_remote: &str, target_branch: &str) {
    let output = Command::new("git")
                         .arg("pull")
                         .arg("--quiet")
                         .arg("--rebase=preserve")
                         .arg(target_remote)
                         .arg(target_branch)
                         .output()
                         .unwrap_or_else(|e| {
                            panic!("failed to execute process: {}", e) });
    let status_code = output.status.code();

    println!("Pulling {} {} ...", target_remote, target_branch);

    match status_code {
        Some(0) => println!("{}", String::from_utf8_lossy(&output.stdout)),
        Some(_) => {
             println!("{}", String::from_utf8_lossy(&output.stderr));
             exit(status_code.unwrap());
        }
        None => println!("Something wrong happened"),
    }
}

pub fn rebase(target_branch: &str) {
    let output = Command::new("git")
                         .arg("rebase")
                         .arg(target_branch)
                         .output()
                         .unwrap_or_else(|e| {
                            panic!("failed to execute process: {}", e) });
    let status_code = output.status.code();

    println!("Rebasing {} ...", target_branch);

    match status_code {
        Some(0) => println!("{}", String::from_utf8_lossy(&output.stdout)),
        Some(_) => {
             println!("{}", String::from_utf8_lossy(&output.stderr));
             exit(status_code.unwrap());
        }
        None => println!("Something wrong happened"),
    }
}
<|endoftext|>


<commit_before>use std::os;
use std::io;
use std::uint;
use ptrie::PTrie;

fn get_word(line : ~str) -> (~str, uint)
{
  let words = line.word_iter().collect::<~[&str]>();
  let word  = words[0];
  let freq  = uint::from_str(words[1]);

  match freq
  {
    None => fail!("Error: could not convert `" + words[1] + "` to an int"),
    Some (ret) => (word.to_str(), ret)
  }
}

// FIXME: exit comme un grand
#[main]
fn main()
{
  let args : ~[~str] = os::args();

  if (args.len() != 3)
  {
    fail!("Usage: " + args[0] + " /path/to/word/freq.txt /path/to/output/dict.bin");
  }
  else
  {
    let path    = PosixPath(args[1]);
    let freader = io::file_reader(&path);

    if freader.is_err()
    {
      fail!("Error: could not open file");
    }
    else
    {
      let reader   = freader.unwrap();
      let lines    = reader.read_lines();
      let mut it = lines.consume_iter().transform(|l| get_word(l));
      let (w, f) = it.next().unwrap();
      let mut trie = PTrie::new(w);
      trie.freq = f;

      let mut i: uint = 1;

      for it.advance |(word, freq)|
      {
          trie.add_word(word, freq);
          i = i + 1;
          // println(i.to_str());
      }

      // println("Num nodes: " + trie.len().to_str());

      {
        let path          = PosixPath(args[2]);
        let fwriter       = io::buffered_file_writer(&path).unwrap();
        let serialization = trie.serialize();

        for serialization.iter().advance |i|
        { fwriter.write_le_u64((*i) as u64) }
      }

      println(trie.to_dot_str());
    }
  // Serialize
  // Write
  }

}
<commit_msg>Refactor main<commit_after>use std::os;
use std::io;
use std::uint;
use ptrie::PTrie;

fn get_word(line : ~str) -> (~str, uint)
{
  let words = line.word_iter().collect::<~[&str]>();
  let word  = words[0];
  let freq  = uint::from_str(words[1]);

  match freq
  {
    None => fail!("Error: could not convert `" + words[1] + "` to an int"),
         Some (ret) => (word.to_str(), ret)
  }
}

fn make_trie(args : &[~str]) -> ~PTrie
{
  if (args.len() != 3)
  {
    fail!("Usage: " + args[0] + " /path/to/word/freq.txt /path/to/output/dict.bin")
  }
  else
  {
    let path    = PosixPath(args[1]);

    match io::file_reader(&path)
    {
      Err (_) =>
      {
        fail!("Error: could not open file");
      },
      Ok (freader) =>
      {
        let lines    = freader.read_lines();
        let mut it = lines.consume_iter().transform(|l| get_word(l));
        let (w, f) = it.next().unwrap();
        let mut trie = ~PTrie::new(w);
        trie.freq = f;

        for it.advance |(word, freq)|
        {
          trie.add_word(word, freq);
        }
        trie
      }
    }
  }
}

fn serialize_trie(args : &[~str], trie : ~PTrie)
{
  let path          = PosixPath(args[2]);
  let fwriter       = io::buffered_file_writer(&path).unwrap();
  let serialization = trie.serialize();

  for serialization.iter().advance |i|
  { fwriter.write_le_u64((*i) as u64) }
}

// FIXME: exit comme un grand
#[main]
fn main()
{
  let args : ~[~str] = os::args();
  serialize_trie(args, make_trie(args));
    // println("Num nodes: " + trie.len().to_str());

    {
    }
    //println(trie.to_dot_str());
    // Serialize
    // Write
}

<|endoftext|>


<commit_before>//! The consumer module contains a type that can connect to an `nsqd` instance
//! to receive messages from and handle accordingly.
#![deny(missing_docs)]

use std::net::ToSocketAddrs;

use byteorder::{BigEndian, ByteOrder};
use futures::{Future, Stream};
use tokio_core::net::TcpStream as TokioTcp;
use tokio_io::AsyncRead;
use tokio_io::codec::{FramedWrite, length_delimited};
use tokio_io::io::write_all;

use config::NsqConfig;
use errors::{NsqResult, NsqError};
use message::{Handler, MessageBuilder, MessageReply, NsqResponder};
use nsq_conn::NsqConn;

/// `Consumer` represents a long-lived connection to an nsqd instance that can read messages
/// and reply depending on a handler function.
pub struct Consumer {
    channel: String,
    config: NsqConfig,
    conn: Option<NsqConn>,
    handler: Option<Box<Handler>>,
    topic: String,
}

// Public methods.
impl Consumer {
    /// Given a topic, channel, and config, set up a new Consumer instance.
    pub fn new(topic: &str, channel: &str, config: NsqConfig) -> Consumer {
        Consumer {
            channel: channel.to_owned(),
            config: config,
            conn: None,
            handler: None,
            topic: topic.to_owned(),
        }
    }

    /// Connect to a single nsqd instance supplied with a host and port.
    pub fn connect_to_nsqd<A: ToSocketAddrs>(&mut self, addr: A) -> NsqResult<()> {
        let conn = NsqConn::new(addr)?;
        self.conn = Some(conn);
        Ok(())
    }

    /// Add a handler for messages that are consumed.
    pub fn add_handler<H>(&mut self, handler: H)
    where
        H: Handler + 'static,
    {
        self.handler = Some(Box::new(handler));
    }

    /// Start consuming from nsqd by initiating an event loop. This function moves the consumer
    /// to take ownership of the internal connection.
    pub fn begin_consuming(self) -> NsqResult<()> {
        match self.conn {
            Some(_) => {
                self.read_loop();
                Ok(())
            }
            None => Err(NsqError::InvalidConn),
        }
    }
}

// Private methods.
impl Consumer {
    // TODO: I want to split this into more functions.
    fn read_loop(self) {
        // This only gets called if the connection is valid.
        let mut conn = self.conn.unwrap();
        let sock_clone = conn.socket.try_clone().expect("cloning TCP socket");

        // The socket used to stream events in.
        let stream_sock = TokioTcp::from_stream(conn.socket, &conn.event_loop.handle()).unwrap();
        let (stream_read, stream_write) = stream_sock.split();

        // The socket for our framed writer that will handle message finishing or re-queuing.
        let framed_sock = TokioTcp::from_stream(sock_clone, &conn.event_loop.handle()).unwrap();

        // Write out the config if there are any values and subscribe to a channel and topic.
        let subscribe = format!("SUB {} {}\n", self.topic, self.channel);
        let ready_count = format!("RDY {}\n", self.config.max_in_flight());

        let prelude = write_all(stream_write, b"  V2")
            .and_then(|(stream, _)| write_all(stream, subscribe.as_bytes()))
            .and_then(|(stream, _)| write_all(stream, ready_count.as_bytes()));

        let framed_writer = FramedWrite::new(framed_sock, NsqResponder::default());
        let framed_read = length_delimited::Builder::new()
            .length_field_length(4)
            .new_read(stream_read);
        let handler = self.handler;
        let reader = framed_read
            .map(|mut buf| {
                let frame_type = BigEndian::read_i32(buf.as_ref());
                // Ditch the frame type.
                buf.split_to(4);
                let mut response = MessageReply::Nop;

                // TODO: Handle other frame types and consider constants for reading the bytes.
                if frame_type == 2 {
                    let time_bytes = buf.split_to(8);
                    let time = BigEndian::read_i64(time_bytes.as_ref());

                    let attempt_bytes = buf.split_to(2);
                    let attempts = BigEndian::read_u16(attempt_bytes.as_ref());

                    let id = buf.split_to(16);
                    let message = MessageBuilder::default()
                        .timestamp(time)
                        .attempts(attempts)
                        .id(id)
                        .body(buf)
                        .build()
                        .unwrap();
                    match handler {
                        Some(ref h) => response = h.handle_message(&message),
                        None => {}
                    }
                }

                response
            })
            .forward(framed_writer);

        conn.event_loop.run(prelude.join(reader)).unwrap();
    }
}
<commit_msg>run some lints and fix small match arm<commit_after>//! The consumer module contains a type that can connect to an `nsqd` instance
//! to receive messages from and handle accordingly.
#![deny(missing_docs)]

use std::net::ToSocketAddrs;

use byteorder::{BigEndian, ByteOrder};
use futures::{Future, Stream};
use tokio_core::net::TcpStream as TokioTcp;
use tokio_io::AsyncRead;
use tokio_io::codec::{FramedWrite, length_delimited};
use tokio_io::io::write_all;

use config::NsqConfig;
use errors::{NsqResult, NsqError};
use message::{Handler, MessageBuilder, MessageReply, NsqResponder};
use nsq_conn::NsqConn;

/// `Consumer` represents a long-lived connection to an nsqd instance that can read messages
/// and reply depending on a handler function.
pub struct Consumer {
    channel: String,
    config: NsqConfig,
    conn: Option<NsqConn>,
    handler: Option<Box<Handler>>,
    topic: String,
}

// Public methods.
impl Consumer {
    /// Given a topic, channel, and config, set up a new Consumer instance.
    pub fn new(topic: &str, channel: &str, config: NsqConfig) -> Consumer {
        Consumer {
            channel: channel.to_owned(),
            config: config,
            conn: None,
            handler: None,
            topic: topic.to_owned(),
        }
    }

    /// Connect to a single nsqd instance supplied with a host and port.
    pub fn connect_to_nsqd<A: ToSocketAddrs>(&mut self, addr: A) -> NsqResult<()> {
        let conn = NsqConn::new(addr)?;
        self.conn = Some(conn);
        Ok(())
    }

    /// Add a handler for messages that are consumed.
    pub fn add_handler<H>(&mut self, handler: H)
    where
        H: Handler + 'static,
    {
        self.handler = Some(Box::new(handler));
    }

    /// Start consuming from nsqd by initiating an event loop. This function moves the consumer
    /// to take ownership of the internal connection.
    pub fn begin_consuming(self) -> NsqResult<()> {
        match self.conn {
            Some(_) => {
                self.read_loop();
                Ok(())
            }
            None => Err(NsqError::InvalidConn),
        }
    }
}

// Private methods.
impl Consumer {
    // TODO: I want to split this into more functions.
    fn read_loop(self) {
        // This only gets called if the connection is valid.
        let mut conn = self.conn.unwrap();
        let sock_clone = conn.socket.try_clone().expect("cloning TCP socket");

        // The socket used to stream events in.
        let stream_sock = TokioTcp::from_stream(conn.socket, &conn.event_loop.handle()).unwrap();
        let (stream_read, stream_write) = stream_sock.split();

        // The socket for our framed writer that will handle message finishing or re-queuing.
        let framed_sock = TokioTcp::from_stream(sock_clone, &conn.event_loop.handle()).unwrap();

        // Write out the config if there are any values and subscribe to a channel and topic.
        let subscribe = format!("SUB {} {}\n", self.topic, self.channel);
        let ready_count = format!("RDY {}\n", self.config.max_in_flight());

        let prelude = write_all(stream_write, b"  V2")
            .and_then(|(stream, _)| write_all(stream, subscribe.as_bytes()))
            .and_then(|(stream, _)| write_all(stream, ready_count.as_bytes()));

        let framed_writer = FramedWrite::new(framed_sock, NsqResponder::default());
        let framed_read = length_delimited::Builder::new()
            .length_field_length(4)
            .new_read(stream_read);
        let handler = self.handler;
        let reader = framed_read
            .map(|mut buf| {
                let frame_type = BigEndian::read_i32(buf.as_ref());
                // Ditch the frame type.
                buf.split_to(4);
                let mut response = MessageReply::Nop;

                // TODO: Handle other frame types and consider constants for reading the bytes.
                if frame_type == 2 {
                    let time_bytes = buf.split_to(8);
                    let time = BigEndian::read_i64(time_bytes.as_ref());

                    let attempt_bytes = buf.split_to(2);
                    let attempts = BigEndian::read_u16(attempt_bytes.as_ref());

                    let id = buf.split_to(16);
                    let message = MessageBuilder::default()
                        .timestamp(time)
                        .attempts(attempts)
                        .id(id)
                        .body(buf)
                        .build()
                        .unwrap();
                    if let Some(ref h) = handler {
                        response = h.handle_message(&message);
                    }
                }

                response
            })
            .forward(framed_writer);

        conn.event_loop.run(prelude.join(reader)).unwrap();
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::default::Default;
use std::fs::File;
use std::io::{Read, Write};
use std::path::{Path, PathBuf};

use digest::Digest;
use ignore::WalkBuilder;
use time;

use serde_bytes;
use serde_cbor;
use serde_json;

use sha2;
use sha3;

use error;

#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
pub struct Database(Entry);

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Entry {
    Directory(BTreeMap<PathBuf, Entry>),
    File(Metrics),
}

impl Default for Entry {
    fn default() -> Entry {
        Entry::Directory(BTreeMap::default())
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Metrics {
    sha2: HashSum,
    sha3: HashSum,
    size: u64,      // File size
    nul: bool,      // Does the file contain a NUL byte?
    nonascii: bool, // Does the file contain non-ASCII bytes?
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct HashSum(#[serde(with = "serde_bytes")] Vec<u8>);

#[derive(Default)]
struct EngineSize(u64);
impl EngineSize {
    fn input(&mut self, input: &[u8]) {
        self.0 += input.len() as u64;
    }
    fn result(self) -> u64 {
        self.0
    }
}

#[derive(Default)]
struct EngineNul(bool);
impl EngineNul {
    fn input(&mut self, input: &[u8]) {
        self.0 = self.0 || input.iter().any(|x| *x == 0);
    }
    fn result(self) -> bool {
        self.0
    }
}

#[derive(Default)]
struct EngineNonascii(bool);
impl EngineNonascii {
    fn input(&mut self, input: &[u8]) {
        self.0 = self.0 || input.iter().any(|x| x & 0x80 != 0);
    }
    fn result(self) -> bool {
        self.0
    }
}

#[derive(Default)]
struct Engines {
    sha2: sha2::Sha256,
    sha3: sha3::Sha3_256,
    size: EngineSize,
    nul: EngineNul,
    nonascii: EngineNonascii,
}

impl Engines {
    fn input(&mut self, input: &[u8]) {
        self.sha2.input(input);
        self.sha3.input(input);
        self.size.input(input);
        self.nul.input(input);
        self.nonascii.input(input);
    }
    fn result(self) -> Metrics {
        Metrics {
            sha2: HashSum(Vec::from(self.sha2.result().as_slice())),
            sha3: HashSum(Vec::from(self.sha3.result().as_slice())),
            size: self.size.result(),
            nul: self.nul.result(),
            nonascii: self.nonascii.result(),
        }
    }
}

fn compute_metrics<P>(path: P) -> Result<Metrics, error::Error>
where
    P: AsRef<Path>
{
    let mut f = File::open(path)?;

    let mut engines = Engines::default();

    let mut buffer = [0; 4096];
    loop {
        let n = f.read(&mut buffer[..])?;
        if n == 0 { break }
        engines.input(&buffer[0..n]);
    }
    Ok(engines.result())
}

trait BTreeMapExt<K, V> where K: Ord, V: Default {
    fn get_default(&mut self, key: K) -> &mut V;
}

impl<K, V> BTreeMapExt<K, V> for BTreeMap<K, V>
where
    K: Ord + Clone,
    V: Default,
{
    fn get_default(&mut self, key: K) -> &mut V {
        self.entry(key).or_insert_with(|| V::default())
    }
}

impl Entry {
    fn insert(&mut self, path: PathBuf, file: Entry) {
        // Inner nodes in the tree should always be directories. If
        // the node is not a directory, that means we are inserting a
        // duplicate file. However, this function is only called from
        // the directory walker, which makes it impossible to observe
        // any duplicates. (And the database, after construction, is
        // always immutable.)
        match self {
            &mut Entry::Directory(ref mut entries) => {
                let mut components = path.components();
                let count = components.clone().count();
                let first = Path::new(components.next().expect("unreachable").as_os_str()).to_owned();
                let rest = components.as_path().to_owned();
                if count > 1 {
                    let mut subentry = entries.get_default(first);
                    subentry.insert(rest, file);
                } else {
                    match entries.insert(first, file) {
                        Some(_) => unreachable!(), // See above
                        None => (),
                    }
                }
            }
            &mut Entry::File(_) => unreachable!()
        }
    }

    fn lookup(&self, path: &PathBuf) -> Option<&Entry> {
        match *self {
            Entry::Directory(ref entries) => {
                let mut components = path.components();
                let count = components.clone().count();
                let first = Path::new(components.next().expect("unreachable").as_os_str()).to_owned();
                let rest = components.as_path().to_owned();
                if count > 1 {
                    entries.get(&first).and_then(
                        |subentry| subentry.lookup(&rest))
                } else {
                    entries.get(&first)
                }
            }
            Entry::File(_) => unreachable!()
        }
    }
}

fn summarize<P>(path: P, expected: &Metrics, actual: &Metrics)
where
    P: AsRef<Path>,
{
    let diff = expected.size != actual.size ||
        expected.sha2 != actual.sha2 ||
        expected.sha3 != actual.sha3;
    if diff {
        let suspicious_size = expected.size > 0 && actual.size == 0;
        let suspicious_nul = expected.nul != actual.nul;
        let suspicious_nonascii = expected.nonascii != actual.nonascii;
        println!("{} differs", path.as_ref().display());
        if suspicious_size {
            println!("  suspicious: file was truncated");
        }
        if suspicious_nul {
            println!("  suspicious: original had no NUL bytes, but now does");
        }
        if suspicious_nonascii {
            println!("  suspicious: original had no non-ASCII bytes, but now does");
        }
    }
}

impl Database {
    fn insert(&mut self, path: PathBuf, entry: Entry) {
        self.0.insert(path, entry);
    }

    fn lookup(&self, path: &PathBuf) -> Option<&Entry> {
        self.0.lookup(path)
    }

    pub fn build<P>(root: P) -> Result<Database, error::Error>
    where
        P: AsRef<Path>,
    {
        let mut total_bytes = 0;
        let start_time_ns = time::precise_time_ns();
        let mut database = Database::default();
        for entry in WalkBuilder::new(&root).build() {
            let entry = entry?;
            if entry.file_type().map_or(false, |t| t.is_file()) {
                let metrics = compute_metrics(entry.path())?;
                total_bytes += metrics.size;
                let result = Entry::File(metrics);
                let short_path = if entry.path() == root.as_ref() {
                    Path::new(entry.path().file_name().expect("unreachable"))
                } else {
                    entry.path().strip_prefix(&root)?
                };
                database.insert(short_path.to_owned(), result);
            }
        }
        let stop_time_ns = time::precise_time_ns();
        println!("Database::build took {:.3} seconds, read {} bytes, {:.1} MB/s",
                 (stop_time_ns - start_time_ns) as f64/1e9,
                 total_bytes,
                 total_bytes as f64/((stop_time_ns - start_time_ns) as f64/1e3));
        Ok(database)
    }

    pub fn check<P>(&self, root: P) -> Result<(), error::Error>
    where
        P: AsRef<Path>,
    {
        // FIXME: Doesn't check for missing entries
        for entry in WalkBuilder::new(&root).build() {
            let entry = entry?;
            if entry.file_type().map_or(false, |t| t.is_file()) {
                let actual = compute_metrics(entry.path())?;

                let short_path = if entry.path() == root.as_ref() {
                    Path::new(entry.path().file_name().expect("unreachable"))
                } else {
                    entry.path().strip_prefix(&root)?
                };
                let expected = self.lookup(&short_path.to_owned());
                match expected {
                    Some(&Entry::File(ref metrics)) => summarize(
                        short_path, metrics, &actual),
                    Some(&Entry::Directory(_)) => unreachable!(),
                    None => println!("{} was created", short_path.display()),
                }
            }
        }
        Ok(())
    }

    pub fn load_json<P>(path: P) -> Result<Database, error::Error>
    where
        P: AsRef<Path>
    {
        let f = File::open(path)?;
        Ok(serde_json::from_reader(f)?)
    }

    pub fn dump_json<P>(&self, path: P) -> Result<(), error::Error>
    where
        P: AsRef<Path>
    {
        let json = serde_json::to_string(self)?;
        let mut f = File::create(path)?;
        write!(f, "{}", json)?;
        Ok(())
    }

    pub fn load_cbor<P>(path: P) -> Result<Database, error::Error>
    where
        P: AsRef<Path>
    {
        let f = File::open(path)?;
        Ok(serde_cbor::from_reader(f)?)
    }

    pub fn dump_cbor<P>(&self, path: P) -> Result<(), error::Error>
    where
        P: AsRef<Path>
    {
        let cbor = serde_cbor::to_vec(self)?;
        let mut f = File::create(path)?;
        f.write_all(cbor.as_slice())?;
        Ok(())
    }
}

// impl std::fmt::Display for Database {
//     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
//         for (path, entry) in self.0.iter() {
//             match entry {
//                 &Entry::File(ref hashes) => {
//                     let hash: Vec<_> = hashes.sha2.0.iter().map(
//                         |b| format!("{:02x}", b)).collect();
//                     writeln!(f, "{} {}", hash.join(""), Path::new(path).display())?
//                 }
//             }
//         }
//         Ok(())
//     }
// }
<commit_msg>Better diffs.<commit_after>use std::collections::BTreeMap;
use std::cmp::Ordering;
use std::default::Default;
use std::fs::File;
use std::io::{Read, Write};
use std::path::{Path, PathBuf};

use digest::Digest;
use ignore::WalkBuilder;
use time;

use serde_bytes;
use serde_cbor;
use serde_json;

use sha2;
use sha3;

use error;

#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
pub struct Database(Entry);

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Entry {
    Directory(BTreeMap<PathBuf, Entry>),
    File(Metrics),
}

impl Default for Entry {
    fn default() -> Entry {
        Entry::Directory(BTreeMap::default())
    }
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Metrics {
    sha2: HashSum,
    sha3: HashSum,
    size: u64,      // File size
    nul: bool,      // Does the file contain a NUL byte?
    nonascii: bool, // Does the file contain non-ASCII bytes?
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct HashSum(#[serde(with = "serde_bytes")] Vec<u8>);

#[derive(Default)]
struct EngineSize(u64);
impl EngineSize {
    fn input(&mut self, input: &[u8]) {
        self.0 += input.len() as u64;
    }
    fn result(self) -> u64 {
        self.0
    }
}

#[derive(Default)]
struct EngineNul(bool);
impl EngineNul {
    fn input(&mut self, input: &[u8]) {
        self.0 = self.0 || input.iter().any(|x| *x == 0);
    }
    fn result(self) -> bool {
        self.0
    }
}

#[derive(Default)]
struct EngineNonascii(bool);
impl EngineNonascii {
    fn input(&mut self, input: &[u8]) {
        self.0 = self.0 || input.iter().any(|x| x & 0x80 != 0);
    }
    fn result(self) -> bool {
        self.0
    }
}

#[derive(Default)]
struct Engines {
    sha2: sha2::Sha256,
    sha3: sha3::Sha3_256,
    size: EngineSize,
    nul: EngineNul,
    nonascii: EngineNonascii,
}

impl Engines {
    fn input(&mut self, input: &[u8]) {
        self.sha2.input(input);
        self.sha3.input(input);
        self.size.input(input);
        self.nul.input(input);
        self.nonascii.input(input);
    }
    fn result(self) -> Metrics {
        Metrics {
            sha2: HashSum(Vec::from(self.sha2.result().as_slice())),
            sha3: HashSum(Vec::from(self.sha3.result().as_slice())),
            size: self.size.result(),
            nul: self.nul.result(),
            nonascii: self.nonascii.result(),
        }
    }
}

fn compute_metrics<P>(path: P) -> Result<Metrics, error::Error>
where
    P: AsRef<Path>
{
    let mut f = File::open(path)?;

    let mut engines = Engines::default();

    let mut buffer = [0; 4096];
    loop {
        let n = f.read(&mut buffer[..])?;
        if n == 0 { break }
        engines.input(&buffer[0..n]);
    }
    Ok(engines.result())
}

trait BTreeMapExt<K, V> where K: Ord, V: Default {
    fn get_default(&mut self, key: K) -> &mut V;
}

impl<K, V> BTreeMapExt<K, V> for BTreeMap<K, V>
where
    K: Ord + Clone,
    V: Default,
{
    fn get_default(&mut self, key: K) -> &mut V {
        self.entry(key).or_insert_with(|| V::default())
    }
}

impl Entry {
    fn insert(&mut self, path: PathBuf, file: Entry) {
        // Inner nodes in the tree should always be directories. If
        // the node is not a directory, that means we are inserting a
        // duplicate file. However, this function is only called from
        // the directory walker, which makes it impossible to observe
        // any duplicates. (And the database, after construction, is
        // always immutable.)
        match self {
            &mut Entry::Directory(ref mut entries) => {
                let mut components = path.components();
                let count = components.clone().count();
                let first = Path::new(components.next().expect("unreachable").as_os_str()).to_owned();
                let rest = components.as_path().to_owned();
                if count > 1 {
                    let mut subentry = entries.get_default(first);
                    subentry.insert(rest, file);
                } else {
                    match entries.insert(first, file) {
                        Some(_) => unreachable!(), // See above
                        None => (),
                    }
                }
            }
            &mut Entry::File(_) => unreachable!()
        }
    }

    fn lookup(&self, path: &PathBuf) -> Option<&Entry> {
        match *self {
            Entry::Directory(ref entries) => {
                let mut components = path.components();
                let count = components.clone().count();
                let first = Path::new(components.next().expect("unreachable").as_os_str()).to_owned();
                let rest = components.as_path().to_owned();
                if count > 1 {
                    entries.get(&first).and_then(
                        |subentry| subentry.lookup(&rest))
                } else {
                    entries.get(&first)
                }
            }
            Entry::File(_) => unreachable!()
        }
    }
}

fn summarize<P>(path: P, expected: &Metrics, actual: &Metrics)
where
    P: AsRef<Path>,
{
    let diff = expected.size != actual.size ||
        expected.sha2 != actual.sha2 ||
        expected.sha3 != actual.sha3;
    if diff {
        let suspicious_size = expected.size > 0 && actual.size == 0;
        let suspicious_nul = expected.nul != actual.nul;
        let suspicious_nonascii = expected.nonascii != actual.nonascii;
        println!("{} differs", path.as_ref().display());
        if suspicious_size {
            println!("  suspicious: file was truncated");
        }
        if suspicious_nul {
            println!("  suspicious: original had no NUL bytes, but now does");
        }
        if suspicious_nonascii {
            println!("  suspicious: original had no non-ASCII bytes, but now does");
        }
    }
}

#[derive(Debug)]
pub enum EntryDiff {
    Directory(BTreeMap<PathBuf, EntryDiff>, DirectoryDiff),
    File(MetricsDiff),
    KindChanged,
}

#[derive(Debug)]
pub struct DirectoryDiff {
    added: u64,
    removed: u64,
    changed: u64,
    unchanged: u64,
}

#[derive(Debug)]
pub struct MetricsDiff {
    changed_content: bool,
    zeroed: bool,
    changed_nul: bool,
    changed_nonascii: bool,
}

impl EntryDiff {
    fn show_diff(&self, path: &PathBuf, depth: usize) {
        match *self {
            EntryDiff::Directory(ref entries, ref diff) => {
                println!("{}{}: {} changed, {} added, {} removed, {} unchanged",
                         "  ".repeat(depth),
                         path.display(),
                         diff.changed,
                         diff.added,
                         diff.removed,
                         diff.unchanged);
                for (key, entry) in entries.iter() {
                    entry.show_diff(key, depth+1);
                }
            }
            EntryDiff::File(ref diff) => {
                if diff.changed_content {
                    println!("{}{} changed",
                             "  ".repeat(depth),
                             path.display());
                    if diff.zeroed {
                        println!("{}suspicious: file was truncated",
                                 "  ".repeat(depth+1));
                    }
                    if diff.changed_nul {
                        println!("{}suspicious: original had no NUL bytes, but now does",
                                 "  ".repeat(depth+1));
                    }
                    if diff.changed_nonascii {
                        println!("{}suspicious: original had no non-ASCII bytes, but now does",
                                 "  ".repeat(depth+1));
                    }
                }
            }
            EntryDiff::KindChanged => {
            }
        }
    }
}

impl Entry {
    fn diff(&self, other: &Entry) -> EntryDiff {
        match (self, other) {
            (&Entry::Directory(ref old), &Entry::Directory(ref new)) => {
                let mut entries = BTreeMap::default();
                let mut added = 0;
                let mut removed = 0;
                let mut changed = 0;
                let mut unchanged = 0;

                let mut old_iter = old.iter();
                let mut new_iter = new.iter();
                let mut old_entry = old_iter.next();
                let mut new_entry = new_iter.next();
                while old_entry.is_some() && new_entry.is_some() {
                    let (old_key, old_value) = old_entry.unwrap();
                    let (new_key, new_value) = new_entry.unwrap();
                    match old_key.cmp(new_key) {
                        Ordering::Less => {
                            removed += 1;
                            old_entry = old_iter.next();
                        }
                        Ordering::Greater => {
                            added += 1;
                            new_entry = new_iter.next();
                        }
                        Ordering::Equal => {
                            let diff = old_value.diff(new_value);
                            match diff {
                                EntryDiff::Directory(_, ref stats) => {
                                    if stats.added > 0 || stats.removed > 0 || stats.changed > 0 {
                                        changed += 1;
                                    } else {
                                        unchanged += 1;
                                    }
                                }
                                EntryDiff::File(ref stats) => {
                                    if stats.changed_content {
                                        changed += 1;
                                    } else {
                                        unchanged += 1;
                                    }
                                }
                                EntryDiff::KindChanged => {
                                    changed += 1;
                                }
                            }
                            entries.insert(old_key.clone(), diff);
                            old_entry = old_iter.next();
                            new_entry = new_iter.next();
                        }
                    }
                }
                removed += old_iter.count() as u64;
                added += new_iter.count() as u64;
                EntryDiff::Directory(
                    entries,
                    DirectoryDiff { added, removed, changed, unchanged })
            },
            (&Entry::File(ref old), &Entry::File(ref new)) =>
                EntryDiff::File(
                    MetricsDiff {
                        changed_content: old.size != new.size ||
                            old.sha2 != new.sha2 ||
                            old.sha3 != new.sha3,
                        zeroed: old.size > 0 && new.size == 0,
                        changed_nul: old.nul != new.nul,
                        changed_nonascii: old.nonascii != new.nonascii,
                    }
                ),
            (_, _) => EntryDiff::KindChanged,
        }
    }
}

impl Database {
    fn insert(&mut self, path: PathBuf, entry: Entry) {
        self.0.insert(path, entry);
    }

    pub fn lookup(&self, path: &PathBuf) -> Option<&Entry> {
        self.0.lookup(path)
    }

    pub fn diff(&self, other: &Database) -> EntryDiff {
        self.0.diff(&other.0)
    }

    pub fn build<P>(root: P) -> Result<Database, error::Error>
    where
        P: AsRef<Path>,
    {
        let mut total_bytes = 0;
        let start_time_ns = time::precise_time_ns();
        let mut database = Database::default();
        for entry in WalkBuilder::new(&root).build() {
            let entry = entry?;
            if entry.file_type().map_or(false, |t| t.is_file()) {
                let metrics = compute_metrics(entry.path())?;
                total_bytes += metrics.size;
                let result = Entry::File(metrics);
                let short_path = if entry.path() == root.as_ref() {
                    Path::new(entry.path().file_name().expect("unreachable"))
                } else {
                    entry.path().strip_prefix(&root)?
                };
                database.insert(short_path.to_owned(), result);
            }
        }
        let stop_time_ns = time::precise_time_ns();
        println!("Database::build took {:.3} seconds, read {} bytes, {:.1} MB/s",
                 (stop_time_ns - start_time_ns) as f64/1e9,
                 total_bytes,
                 total_bytes as f64/((stop_time_ns - start_time_ns) as f64/1e3));
        Ok(database)
    }

    pub fn show_diff(&self, other: &Database) {
        let diff = self.diff(other);
        diff.show_diff(&Path::new(".").to_owned(), 0);
    }

    pub fn check<P>(&self, root: P) -> Result<(), error::Error>
    where
        P: AsRef<Path>,
    {
        // FIXME: This is non-interactive, but vastly simply than
        // trying to implement the same functionality interactively.
        let other = Database::build(root)?;
        self.show_diff(&other);
        Ok(())
    }

    pub fn load_json<P>(path: P) -> Result<Database, error::Error>
    where
        P: AsRef<Path>
    {
        let f = File::open(path)?;
        Ok(serde_json::from_reader(f)?)
    }

    pub fn dump_json<P>(&self, path: P) -> Result<(), error::Error>
    where
        P: AsRef<Path>
    {
        let json = serde_json::to_string(self)?;
        let mut f = File::create(path)?;
        write!(f, "{}", json)?;
        Ok(())
    }

    pub fn load_cbor<P>(path: P) -> Result<Database, error::Error>
    where
        P: AsRef<Path>
    {
        let f = File::open(path)?;
        Ok(serde_cbor::from_reader(f)?)
    }

    pub fn dump_cbor<P>(&self, path: P) -> Result<(), error::Error>
    where
        P: AsRef<Path>
    {
        let cbor = serde_cbor::to_vec(self)?;
        let mut f = File::create(path)?;
        f.write_all(cbor.as_slice())?;
        Ok(())
    }
}

// impl std::fmt::Display for Database {
//     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
//         for (path, entry) in self.0.iter() {
//             match entry {
//                 &Entry::File(ref hashes) => {
//                     let hash: Vec<_> = hashes.sha2.0.iter().map(
//                         |b| format!("{:02x}", b)).collect();
//                     writeln!(f, "{} {}", hash.join(""), Path::new(path).display())?
//                 }
//             }
//         }
//         Ok(())
//     }
// }
<|endoftext|>


<commit_before>extern crate debugserver_types;
extern crate env_logger;
extern crate futures;
extern crate jsonrpc_core;
extern crate serde;
extern crate serde_json;

extern crate gluon_language_server;

use std::error::Error as StdError;
use std::io::{BufReader, Write};
use std::net::{TcpListener, TcpStream};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::thread::spawn;

use futures::{BoxFuture, Future, IntoFuture};

use jsonrpc_core::IoHandler;

use serde_json::Value;

use debugserver_types::*;

use gluon_language_server::rpc::{LanguageServerCommand, ServerCommand, ServerError, main_loop};

pub struct InitializeHandler {
    stream: Arc<TcpStream>,
    seq: Arc<AtomicUsize>,
}

impl LanguageServerCommand for InitializeHandler {
    type Param = InitializeRequestArguments;
    type Output = Option<Capabilities>;
    type Error = ();
    fn execute(&self,
               _args: InitializeRequestArguments)
               -> BoxFuture<Option<Capabilities>, ServerError<Self::Error>> {

        let initialized = InitializedEvent {
            body: None,
            event: "initialized".into(),
            seq: self.seq.fetch_add(1, Ordering::SeqCst) as i64,
            type_: "event".into(),
        };
        let response = serde_json::to_string(&initialized).unwrap();
        write!(&*self.stream,
               "Content-Length: {}\r\n\r\n{}",
               response.len(),
               response)
            .map_err(|err| {
                ServerError {
                    message: format!("Unable to write result to initialize: {}", err),
                    data: None,
                }
            })
            .map(|_| None)
            .into_future()
            .boxed()
    }
}

pub struct LaunchHandler;

impl LanguageServerCommand for LaunchHandler {
    type Param = Value;
    type Output = Option<Value>;
    type Error = ();
    fn execute(&self, _args: Value) -> BoxFuture<Option<Value>, ServerError<()>> {
        Ok(None).into_future().boxed()
    }
}

// Translate debug server messages into jsonrpc-2.0
fn translate_request(message: String) -> Result<String, Box<StdError>> {
    use serde_json::Value;
    let mut data: Value = try!(serde_json::from_str(&message));
    if data.is_object() {
        let data = data.as_object_mut().unwrap();
        let command = data.get("command").and_then(|c| c.as_str()).expect("command").to_string();
        let seq = data.get("seq")
            .and_then(|c| {
                c.as_str()
                    .map(|s| Value::String(s.to_string()))
                    .or_else(|| c.as_i64().map(Value::from))
            })
            .expect("seq");
        let arguments = data.remove("arguments").expect("arguments");
        let map = vec![("method".to_string(), Value::String(command)),
                       ("id".to_string(), seq),
                       ("params".to_string(), arguments),
                       ("jsonrpc".to_owned(), Value::String("2.0".to_string()))]
            .into_iter()
            .collect();
        return Ok(try!(serde_json::to_string(&Value::Object(map))));
    }
    Ok(message)
}

fn translate_response(message: String) -> Result<String, Box<StdError>> {
    use serde_json::Value;
    let mut data: Value = try!(serde_json::from_str(&message));
    if data.is_object() {
        let data = data.as_object_mut().unwrap();
        let seq = data.get("id")
            .and_then(|c| {
                c.as_str()
                    .map(|s| Value::String(s.to_string()))
                    .or_else(|| c.as_i64().map(Value::from))
            })
            .expect("id");
        let result = data.remove("result");
        let error = data.remove("error");

        let mut map = vec![("success".to_string(), Value::Bool(result.is_some())),
                           ("request_seq".to_string(), seq.clone()),
                           ("seq".to_string(), seq),
                           ("type".to_owned(), Value::String("response".to_string()))];

        if let Some(result) = result {
            map.push(("body".to_string(), result));
        }
        if let Some(mut error) = error {
            map.push(("message".to_string(),
                      error.as_object_mut().unwrap().remove("message").expect("error message")));
        }

        let map = map.into_iter().collect();
        return Ok(try!(serde_json::to_string(&Value::Object(map))));
    }
    Ok(message)
}

pub fn main() {
    env_logger::init().unwrap();

    let listener = TcpListener::bind("127.0.0.1:4711").unwrap();
    for stream in listener.incoming() {
        let stream = Arc::new(stream.unwrap());

        let exit_token = Arc::new(AtomicBool::new(false));
        let seq = Arc::new(AtomicUsize::new(0));

        let mut io = IoHandler::new();
        io.add_async_method("initialize",
                            ServerCommand(InitializeHandler {
                                stream: stream.clone(),
                                seq: seq,
                            }));
        io.add_async_method("launch", ServerCommand(LaunchHandler));
        spawn(move || {
            let read = BufReader::new(&*stream);
            main_loop(read,
                      &*stream,
                      &io,
                      exit_token,
                      translate_request,
                      translate_response)
                .unwrap()
        });
    }
}
<commit_msg>feat: Add a handler for the terminate method in the debug server<commit_after>extern crate debugserver_types;
extern crate env_logger;
extern crate futures;
extern crate jsonrpc_core;
extern crate serde;
extern crate serde_json;

extern crate gluon_language_server;

use std::error::Error as StdError;
use std::io::{BufReader, Write};
use std::net::{TcpListener, TcpStream};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::thread::spawn;

use futures::{BoxFuture, Future, IntoFuture};

use jsonrpc_core::IoHandler;

use serde_json::Value;

use debugserver_types::*;

use gluon_language_server::rpc::{LanguageServerCommand, ServerCommand, ServerError, main_loop};

pub struct InitializeHandler {
    stream: Arc<TcpStream>,
    seq: Arc<AtomicUsize>,
}

impl LanguageServerCommand for InitializeHandler {
    type Param = InitializeRequestArguments;
    type Output = Option<Capabilities>;
    type Error = ();
    fn execute(&self,
               _args: InitializeRequestArguments)
               -> BoxFuture<Option<Capabilities>, ServerError<Self::Error>> {

        let initialized = InitializedEvent {
            body: None,
            event: "initialized".into(),
            seq: self.seq.fetch_add(1, Ordering::SeqCst) as i64,
            type_: "event".into(),
        };
        let response = serde_json::to_string(&initialized).unwrap();
        write!(&*self.stream,
               "Content-Length: {}\r\n\r\n{}",
               response.len(),
               response)
            .map_err(|err| {
                ServerError {
                    message: format!("Unable to write result to initialize: {}", err),
                    data: None,
                }
            })
            .map(|_| None)
            .into_future()
            .boxed()
    }
}

pub struct LaunchHandler;

impl LanguageServerCommand for LaunchHandler {
    type Param = Value;
    type Output = Option<Value>;
    type Error = ();
    fn execute(&self, _args: Value) -> BoxFuture<Option<Value>, ServerError<()>> {
        Ok(None).into_future().boxed()
    }
}

pub struct DisconnectHandler {
    exit_token: Arc<AtomicBool>,
}

impl LanguageServerCommand for DisconnectHandler {
    type Param = DisconnectArguments;
    type Output = Option<Value>;
    type Error = ();
    fn execute(&self, _args: Value) -> Result<Option<Value>, ServerError<()>> {
        self.exit_token.store(true, Ordering::SeqCst);
        Ok(None)
    }
}

// Translate debug server messages into jsonrpc-2.0
fn translate_request(message: String) -> Result<String, Box<StdError>> {
    use serde_json::Value;
    let mut data: Value = try!(serde_json::from_str(&message));
    if data.is_object() {
        let data = data.as_object_mut().unwrap();
        let command = data.get("command").and_then(|c| c.as_str()).expect("command").to_string();
        let seq = data.get("seq")
            .and_then(|c| {
                c.as_str()
                    .map(|s| Value::String(s.to_string()))
                    .or_else(|| c.as_i64().map(Value::from))
            })
            .expect("seq");
        let arguments = data.remove("arguments").expect("arguments");
        let map = vec![("method".to_string(), Value::String(command)),
                       ("id".to_string(), seq),
                       ("params".to_string(), arguments),
                       ("jsonrpc".to_owned(), Value::String("2.0".to_string()))]
            .into_iter()
            .collect();
        return Ok(try!(serde_json::to_string(&Value::Object(map))));
    }
    Ok(message)
}

fn translate_response(message: String) -> Result<String, Box<StdError>> {
    use serde_json::Value;
    let mut data: Value = try!(serde_json::from_str(&message));
    if data.is_object() {
        let data = data.as_object_mut().unwrap();
        let seq = data.get("id")
            .and_then(|c| {
                c.as_str()
                    .map(|s| Value::String(s.to_string()))
                    .or_else(|| c.as_i64().map(Value::from))
            })
            .expect("id");
        let result = data.remove("result");
        let error = data.remove("error");

        let mut map = vec![("success".to_string(), Value::Bool(result.is_some())),
                           ("request_seq".to_string(), seq.clone()),
                           ("seq".to_string(), seq),
                           ("type".to_owned(), Value::String("response".to_string()))];

        if let Some(result) = result {
            map.push(("body".to_string(), result));
        }
        if let Some(mut error) = error {
            map.push(("message".to_string(),
                      error.as_object_mut().unwrap().remove("message").expect("error message")));
        }

        let map = map.into_iter().collect();
        return Ok(try!(serde_json::to_string(&Value::Object(map))));
    }
    Ok(message)
}

pub fn main() {
    env_logger::init().unwrap();

    let listener = TcpListener::bind("127.0.0.1:4711").unwrap();
    for stream in listener.incoming() {
        let stream = Arc::new(stream.unwrap());

        let exit_token = Arc::new(AtomicBool::new(false));
        let seq = Arc::new(AtomicUsize::new(0));

        let mut io = IoHandler::new();
        io.add_async_method("initialize",
                            ServerCommand(InitializeHandler {
                                stream: stream.clone(),
                                seq: seq,
                            }));
        io.add_async_method("launch", ServerCommand(LaunchHandler));
        io.add_method("disconnect",
                      ServerCommand(DisconnectHandler { exit_token: exit_token.clone() }));

        spawn(move || {
            let read = BufReader::new(&*stream);
            main_loop(read,
                      &*stream,
                      &io,
                      exit_token,
                      translate_request,
                      translate_response)
                .unwrap()
        });
    }
}
<|endoftext|>


<commit_before>use minhashes::KmerCount;
use serialization::SketchDistance;

pub fn distance(sketch1: &[KmerCount], sketch2: &[KmerCount], sketch1_name: &str, sketch2_name: &str, mash_mode: bool) -> Result<SketchDistance, &'static str> {
    if sketch1[0].kmer.len() != sketch2[0].kmer.len() {
        return Err("Sketches have different sized kmers");
    }
    let distances;
    if mash_mode {
        distances = raw_mash_distance(sketch1, sketch2);
    } else {
        distances = raw_distance(sketch1, sketch2);
    }
    let containment = distances.0;
    let jaccard = distances.1;
    let common = distances.2;
    let total = distances.3;
    let mash_distance: f64 = -1.0 * ((2.0 * jaccard) / (1.0 + jaccard)).ln() / sketch1[0].kmer.len() as f64;
    Ok(SketchDistance {
        containment: containment,
        jaccard: jaccard,
        mashDistance: f64::min(1f64, f64::max(0f64, mash_distance)),
        commonHashes: common,
        totalHashes: total,
        query: sketch1_name.to_string(),
        reference: sketch2_name.to_string(),
    })
}

fn raw_mash_distance(sketch1: &[KmerCount], sketch2: &[KmerCount]) -> (f64, f64, u64, u64) {
    let mut i: usize = 0;
    let mut j: usize = 0;
    let mut common: u64 = 0;
    let mut total: u64 = 0;
    let sketch_size = sketch1.len();

    while (total < sketch_size as u64) && (i < sketch1.len()) && (j < sketch2.len()) {
        if sketch1[i].hash < sketch2[j].hash {
            i += 1;
        } else if sketch2[j].hash < sketch1[i].hash {
            j += 1;
        } else {
            i += 1;
            j += 1;
            common += 1;
        }
        total += 1;
    }

    if total < sketch_size as u64 {
        if i < sketch1.len() {
            total += (sketch1.len() - 1) as u64;
        }

        if j < sketch2.len() {
            total += (sketch2.len() - 1) as u64;
        }

        if total > sketch_size as u64 {
            total = sketch_size as u64;
        }
    }

    let containment: f64 = common as f64 / i as f64;
    let jaccard: f64 = common as f64 / total as f64;
    (containment, jaccard, common, total)
}

pub fn raw_distance(sketch1: &[KmerCount], sketch2: &[KmerCount]) -> (f64, f64, u64, u64) {
    let mut j: usize = 0;
    let mut common: u64 = 0;
    let mut total: u64 = 0;

    for i in 0..sketch1.len() {
        while (sketch2[j].hash < sketch1[i].hash) && (j < sketch2.len() - 1) {
            j += 1;
        }

        if sketch2[j].hash == sketch1[i].hash {
            common += 1;
        }

        total += 1;
    }

    // Numerator is A-intersect-B, |A| is the denominator, we enforce |A| == |B|
    let containment: f64 = common as f64 / total as f64;
    let jaccard: f64 = common as f64 / (common + 2 * (total - common)) as f64;
    (containment, jaccard, common, total)
}
<commit_msg>Drop kmer length comparison in distance calc<commit_after>use minhashes::KmerCount;
use serialization::SketchDistance;

pub fn distance(sketch1: &[KmerCount], sketch2: &[KmerCount], sketch1_name: &str, sketch2_name: &str, mash_mode: bool) -> Result<SketchDistance, &'static str> {
    // // TODO: in principle this is a good check, but sometimes one of the kmers will be "" if
    // // serialized without and that break this
    // if sketch1[0].kmer.len() != sketch2[0].kmer.len() {
    //     return Err("Sketches have different sized kmers");
    // }
    let distances;
    if mash_mode {
        distances = raw_mash_distance(sketch1, sketch2);
    } else {
        distances = raw_distance(sketch1, sketch2);
    }
    let containment = distances.0;
    let jaccard = distances.1;
    let common = distances.2;
    let total = distances.3;
    let mash_distance: f64 = -1.0 * ((2.0 * jaccard) / (1.0 + jaccard)).ln() / sketch1[0].kmer.len() as f64;
    Ok(SketchDistance {
        containment: containment,
        jaccard: jaccard,
        mashDistance: f64::min(1f64, f64::max(0f64, mash_distance)),
        commonHashes: common,
        totalHashes: total,
        query: sketch1_name.to_string(),
        reference: sketch2_name.to_string(),
    })
}

fn raw_mash_distance(sketch1: &[KmerCount], sketch2: &[KmerCount]) -> (f64, f64, u64, u64) {
    let mut i: usize = 0;
    let mut j: usize = 0;
    let mut common: u64 = 0;
    let mut total: u64 = 0;
    let sketch_size = sketch1.len();

    while (total < sketch_size as u64) && (i < sketch1.len()) && (j < sketch2.len()) {
        if sketch1[i].hash < sketch2[j].hash {
            i += 1;
        } else if sketch2[j].hash < sketch1[i].hash {
            j += 1;
        } else {
            i += 1;
            j += 1;
            common += 1;
        }
        total += 1;
    }

    if total < sketch_size as u64 {
        if i < sketch1.len() {
            total += (sketch1.len() - 1) as u64;
        }

        if j < sketch2.len() {
            total += (sketch2.len() - 1) as u64;
        }

        if total > sketch_size as u64 {
            total = sketch_size as u64;
        }
    }

    let containment: f64 = common as f64 / i as f64;
    let jaccard: f64 = common as f64 / total as f64;
    (containment, jaccard, common, total)
}

pub fn raw_distance(sketch1: &[KmerCount], sketch2: &[KmerCount]) -> (f64, f64, u64, u64) {
    let mut j: usize = 0;
    let mut common: u64 = 0;
    let mut total: u64 = 0;

    for i in 0..sketch1.len() {
        while (sketch2[j].hash < sketch1[i].hash) && (j < sketch2.len() - 1) {
            j += 1;
        }

        if sketch2[j].hash == sketch1[i].hash {
            common += 1;
        }

        total += 1;
    }

    // Numerator is A-intersect-B, |A| is the denominator, we enforce |A| == |B|
    let containment: f64 = common as f64 / total as f64;
    let jaccard: f64 = common as f64 / (common + 2 * (total - common)) as f64;
    (containment, jaccard, common, total)
}
<|endoftext|>


<commit_before>use std::str::FromStr;

use crate::parser;
use crate::table::Iter;
use crate::{InternalString, Table};

/// Type representing a TOML document
#[derive(Debug, Clone)]
pub struct Document {
    pub(crate) root: Table,
    // Trailing comments and whitespaces
    pub(crate) trailing: InternalString,
}

impl Document {
    /// Creates an empty document
    pub fn new() -> Self {
        Default::default()
    }

    /// Returns a reference to the root table.
    pub fn as_table(&self) -> &Table {
        &self.root
    }

    /// Returns a mutable reference to the root table.
    pub fn as_table_mut(&mut self) -> &mut Table {
        &mut self.root
    }

    /// Returns an iterator over the root table.
    pub fn iter(&self) -> Iter<'_> {
        self.root.iter()
    }

    /// Set whitespace after last element
    pub fn set_trailing(&mut self, trailing: &str) {
        self.trailing = InternalString::from(trailing);
    }

    /// Whitespace after last element
    pub fn trailing(&self) -> &str {
        self.trailing.as_str()
    }
}

impl Default for Document {
    fn default() -> Self {
        Self {
            root: Table::with_pos(Some(0)),
            trailing: Default::default(),
        }
    }
}

impl FromStr for Document {
    type Err = parser::TomlError;

    /// Parses a document from a &str
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        parser::TomlParser::parse(s.as_bytes())
    }
}

impl std::ops::Deref for Document {
    type Target = Table;

    fn deref(&self) -> &Self::Target {
        &self.root
    }
}

impl std::ops::DerefMut for Document {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.root
    }
}

impl From<Table> for Document {
    fn from(root: Table) -> Self {
        Self {
            root,
            ..Default::default()
        }
    }
}
<commit_msg>feat: Re-expose Document's Item<commit_after>use std::str::FromStr;

use crate::parser;
use crate::table::Iter;
use crate::{InternalString, Item, Table};

/// Type representing a TOML document
#[derive(Debug, Clone)]
pub struct Document {
    pub(crate) root: Item,
    // Trailing comments and whitespaces
    pub(crate) trailing: InternalString,
}

impl Document {
    /// Creates an empty document
    pub fn new() -> Self {
        Default::default()
    }

    /// Returns a reference to the root item.
    pub fn as_item(&self) -> &Item {
        &self.root
    }

    /// Returns a mutable reference to the root item.
    pub fn as_item_mut(&mut self) -> &mut Item {
        &mut self.root
    }

    /// Returns a reference to the root table.
    pub fn as_table(&self) -> &Table {
        self.root.as_table().expect("root should always be a table")
    }

    /// Returns a mutable reference to the root table.
    pub fn as_table_mut(&mut self) -> &mut Table {
        self.root
            .as_table_mut()
            .expect("root should always be a table")
    }

    /// Returns an iterator over the root table.
    pub fn iter(&self) -> Iter<'_> {
        self.as_table().iter()
    }

    /// Set whitespace after last element
    pub fn set_trailing(&mut self, trailing: &str) {
        self.trailing = InternalString::from(trailing);
    }

    /// Whitespace after last element
    pub fn trailing(&self) -> &str {
        self.trailing.as_str()
    }
}

impl Default for Document {
    fn default() -> Self {
        Self {
            root: Item::Table(Table::with_pos(Some(0))),
            trailing: Default::default(),
        }
    }
}

impl FromStr for Document {
    type Err = parser::TomlError;

    /// Parses a document from a &str
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        parser::TomlParser::parse(s.as_bytes())
    }
}

impl std::ops::Deref for Document {
    type Target = Table;

    fn deref(&self) -> &Self::Target {
        self.as_table()
    }
}

impl std::ops::DerefMut for Document {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.as_table_mut()
    }
}

impl From<Table> for Document {
    fn from(root: Table) -> Self {
        Self {
            root: Item::Table(root),
            ..Default::default()
        }
    }
}
<|endoftext|>


<commit_before>use extcmp::{ Cmp, Eq, Lt, Gt, ExtOrd };
use cmp::{ Cmp, Ord };

pub enum Sign {
    Minus, Zero, Plus
}

impl Sign: ExtOrd {
    pure fn cmp(other: &Sign) -> Cmp {
        match (self, *other) {
          (Minus, Minus) | (Zero,  Zero) | (Plus, Plus) => Eq,
          (Minus, Zero)  | (Minus, Plus) | (Zero, Plus) => Lt,
          _                                             => Gt
        }
    }
}

impl Sign {
    pure fn neg() -> Sign {
        match(self) {
          Minus => Plus,
          Zero  => Zero,
          Plus  => Minus
        }
    }

    pure fn to_int() -> int {
        match self {
          Minus => -1,
          Zero  => 0,
          Plus  => 1
        }
    }

    static pure fn from_int(n: int) -> Sign {
        if n < 0  { return Minus; }
        if n == 0 { return Zero; }
        return Plus;
    }
}

impl Sign : Eq {
    pure fn eq(other: &Sign) -> bool { match self.cmp(other) { Eq => true, _ => false } }
    pure fn ne(other: &Sign) -> bool { !self.eq(other) }
}

impl Sign : Ord {
    pure fn lt(other: &Sign) -> bool { match self.cmp(other) { Lt      => true, _ => false} }
    pure fn le(other: &Sign) -> bool { match self.cmp(other) { Lt | Eq => true, _ => false} }
    pure fn ge(other: &Sign) -> bool { match self.cmp(other) { Eq | Gt => true, _ => false} }
    pure fn gt(other: &Sign) -> bool { match self.cmp(other) { Gt      => true, _ => false} }
}

pub trait ExtNum {
    pure fn abs() -> self;
    pure fn quot(other: &self) -> self;
    pure fn rem(other: &self) -> self;
    pure fn divmod(other: &self) -> (self, self);
    pure fn quotrem(other: &self) -> (self, self);

    pure fn is_zero() -> bool;
    pure fn is_not_zero() -> bool;
    pure fn is_positive() -> bool;
    pure fn is_negative() -> bool;
    pure fn is_nonpositive() -> bool;
    pure fn is_nonnegative() -> bool;

    pure fn to_uint() -> uint;
    pure fn to_str_radix(radix: uint) -> ~str;

    static pure fn zero() -> self;
    static pure fn one() -> self;
    static pure fn from_uint(n: uint) -> self;
    static fn parse_bytes(buf: &[u8], radix: uint) -> Option<self>;
    static fn from_str_radix(s: &str, radix: uint) -> Option<self>;
}
<commit_msg>Fix invalid use statements<commit_after>use cmp::{ Ord, Eq };
use extcmp::{ Cmp, Eq, Lt, Gt, ExtOrd };

pub enum Sign {
    Minus, Zero, Plus
}

impl Sign: ExtOrd {
    pure fn cmp(other: &Sign) -> Cmp {
        match (self, *other) {
          (Minus, Minus) | (Zero,  Zero) | (Plus, Plus) => Eq,
          (Minus, Zero)  | (Minus, Plus) | (Zero, Plus) => Lt,
          _                                             => Gt
        }
    }
}

impl Sign {
    pure fn neg() -> Sign {
        match(self) {
          Minus => Plus,
          Zero  => Zero,
          Plus  => Minus
        }
    }

    pure fn to_int() -> int {
        match self {
          Minus => -1,
          Zero  => 0,
          Plus  => 1
        }
    }

    static pure fn from_int(n: int) -> Sign {
        if n < 0  { return Minus; }
        if n == 0 { return Zero; }
        return Plus;
    }
}

impl Sign : Eq {
    pure fn eq(other: &Sign) -> bool { match self.cmp(other) { Eq => true, _ => false } }
    pure fn ne(other: &Sign) -> bool { !self.eq(other) }
}

impl Sign : Ord {
    pure fn lt(other: &Sign) -> bool { match self.cmp(other) { Lt      => true, _ => false} }
    pure fn le(other: &Sign) -> bool { match self.cmp(other) { Lt | Eq => true, _ => false} }
    pure fn ge(other: &Sign) -> bool { match self.cmp(other) { Eq | Gt => true, _ => false} }
    pure fn gt(other: &Sign) -> bool { match self.cmp(other) { Gt      => true, _ => false} }
}

pub trait ExtNum {
    pure fn abs() -> self;
    pure fn quot(other: &self) -> self;
    pure fn rem(other: &self) -> self;
    pure fn divmod(other: &self) -> (self, self);
    pure fn quotrem(other: &self) -> (self, self);

    pure fn is_zero() -> bool;
    pure fn is_not_zero() -> bool;
    pure fn is_positive() -> bool;
    pure fn is_negative() -> bool;
    pure fn is_nonpositive() -> bool;
    pure fn is_nonnegative() -> bool;

    pure fn to_uint() -> uint;
    pure fn to_str_radix(radix: uint) -> ~str;

    static pure fn zero() -> self;
    static pure fn one() -> self;
    static pure fn from_uint(n: uint) -> self;
    static fn parse_bytes(buf: &[u8], radix: uint) -> Option<self>;
    static fn from_str_radix(s: &str, radix: uint) -> Option<self>;
}
<|endoftext|>