<commit_before>extern crate tinyrsh;

use std::collections::HashMap;
use std::net::{TcpListener, TcpStream};
use std::io::{Write};
use std::io;
use std::process;
use std::os::unix::io::{RawFd};
use tinyrsh::child::PersistentChild;
use tinyrsh::fdstore::{FdStore, OnceAccept, OnceRead, Clients};

#[derive(Debug)]
struct AuxData {
    total_cons: u64,
    rbytes: u64,
    wbytes: u64,
}

//print only safe ascii characters for debugging. In particular don't print shell escapes.
fn safe_ascii_debug(v: &[u8]) -> String {
    let mut s = String::new();
    for &c in v.iter() {
        if c >= 0x20u8 && c <= 0x7Eu8 && c != 0x5Cu8 {
            s.push(c as char);
        } else {
            s.push('X')
        }
    }
    s
}

fn main() {
    println!("Hello, world!");

    let mut aux = AuxData{ total_cons: 0, rbytes:0, wbytes:0 };

    let child = PersistentChild::new("../py-ptysh/ptysh.py");

    assert!(!child.has_terminated());

    // TODO linebuffered? how is child output buffered at all?
    let listener = TcpListener::bind("127.0.0.1:6699").unwrap();

    let mut fdstore = FdStore::new(listener, child, aux);

   println!("select-looping");
   loop {
       let srvacceptfun = |  a: OnceAccept, clients: &Clients, aux: &mut AuxData | -> io::Result<TcpStream> {
              println!("Accepting new connection");
              aux.total_cons += 1;
              println!("{:?}", aux);
              a.do_accept().map( | (mut stream, addr) | {
                      println!("new client: {:?}", addr);
                      assert_eq!(stream.write(b"hello\n").expect("greet client failed"), 6);
                      stream.write_all(b"Your fellow peers:").expect("client write");
                      let mut v = vec![];
                      for other in clients.values() {
                          v.push(format!("ip {}", other.peer_addr().expect("peer addr")));
                      }
                      stream.write_all(v.join(", ").as_bytes()).expect("client write");
                      stream.write(b"\n").expect("client write");
                      for mut client in clients.values() {
                          client.write_all(b"new client connected\n").expect("client write");
                      }
                      stream
              })
           };
       let clientfun = | client: OnceRead<TcpStream>, to: &mut process::ChildStdin, aux: &mut AuxData | -> bool {
            let mut buf = [0; 1024];
            let n = client.do_read(&mut buf).expect("copy_to read");
            let written = to.write(&buf[..n]).expect("copy_to write");
            to.flush();
            assert_eq!(n, written);
            aux.rbytes += n as u64;
            n != 0
           };
       let childstdoutfun = | stdout: OnceRead<process::ChildStdout>, clients: &Clients, aux: &mut AuxData | -> bool {
            println!("child (stdout) got active");
            let mut buf = [0; 1024];
            let n = stdout.do_read(&mut buf).expect("read_child");
            let child_eof = n == 0;
            if clients.is_empty() {
                println!("Warning: child output but no remote connected");
                println!("({} bytes) `{}'", n, safe_ascii_debug(&buf[..n]));
            }
            for mut remote in clients.values(){
                //println!("forwarding to {}", remote.peer_addr().unwrap());
                let written = remote.write(&buf[..n]).expect("remote write");
                assert_eq!(n, written);
                aux.wbytes += written as u64;
            }
            !child_eof
           };
       let childstderrfun = | stderr: OnceRead<process::ChildStderr>, clients: &Clients, aux: &mut AuxData | -> bool {
            println!("child (stderr) got active");
            let mut buf = [0; 1024];
            let n = stderr.do_read(&mut buf).expect("read_child");
            println!("({} bytes) `{}'", n, safe_ascii_debug(&buf[..n]));
            n != 0
           };

       //do all the stuff
       fdstore.select(&srvacceptfun, &clientfun, &childstdoutfun, &childstderrfun);
   } //loop
}
<commit_msg>cleaned imports<commit_after>extern crate tinyrsh;

use std::net::{TcpListener, TcpStream};
use std::io::{Write};
use std::io;
use std::process;
use tinyrsh::child::PersistentChild;
use tinyrsh::fdstore::{FdStore, OnceAccept, OnceRead, Clients};

#[derive(Debug)]
struct AuxData {
    total_cons: u64,
    rbytes: u64,
    wbytes: u64,
}

//print only safe ascii characters for debugging. In particular don't print shell escapes.
fn safe_ascii_debug(v: &[u8]) -> String {
    let mut s = String::new();
    for &c in v.iter() {
        if c >= 0x20u8 && c <= 0x7Eu8 && c != 0x5Cu8 {
            s.push(c as char);
        } else {
            s.push('X')
        }
    }
    s
}

fn main() {
    println!("Hello, world!");

    let mut aux = AuxData{ total_cons: 0, rbytes:0, wbytes:0 };

    let child = PersistentChild::new("../py-ptysh/ptysh.py");

    assert!(!child.has_terminated());

    // TODO linebuffered? how is child output buffered at all?
    let listener = TcpListener::bind("127.0.0.1:6699").unwrap();

    let mut fdstore = FdStore::new(listener, child, aux);

   println!("select-looping");
   loop {
       let srvacceptfun = |  a: OnceAccept, clients: &Clients, aux: &mut AuxData | -> io::Result<TcpStream> {
              println!("Accepting new connection");
              aux.total_cons += 1;
              println!("{:?}", aux);
              a.do_accept().map( | (mut stream, addr) | {
                      println!("new client: {:?}", addr);
                      assert_eq!(stream.write(b"hello\n").expect("greet client failed"), 6);
                      stream.write_all(b"Your fellow peers:").expect("client write");
                      let mut v = vec![];
                      for other in clients.values() {
                          v.push(format!("ip {}", other.peer_addr().expect("peer addr")));
                      }
                      stream.write_all(v.join(", ").as_bytes()).expect("client write");
                      stream.write(b"\n").expect("client write");
                      for mut client in clients.values() {
                          client.write_all(b"new client connected\n").expect("client write");
                      }
                      stream
              })
           };
       let clientfun = | client: OnceRead<TcpStream>, to: &mut process::ChildStdin, aux: &mut AuxData | -> bool {
            let mut buf = [0; 1024];
            let n = client.do_read(&mut buf).expect("copy_to read");
            let written = to.write(&buf[..n]).expect("copy_to write");
            to.flush();
            assert_eq!(n, written);
            aux.rbytes += n as u64;
            n != 0
           };
       let childstdoutfun = | stdout: OnceRead<process::ChildStdout>, clients: &Clients, aux: &mut AuxData | -> bool {
            println!("child (stdout) got active");
            let mut buf = [0; 1024];
            let n = stdout.do_read(&mut buf).expect("read_child");
            let child_eof = n == 0;
            if clients.is_empty() {
                println!("Warning: child output but no remote connected");
                println!("({} bytes) `{}'", n, safe_ascii_debug(&buf[..n]));
            }
            for mut remote in clients.values(){
                //println!("forwarding to {}", remote.peer_addr().unwrap());
                let written = remote.write(&buf[..n]).expect("remote write");
                assert_eq!(n, written);
                aux.wbytes += written as u64;
            }
            !child_eof
           };
       let childstderrfun = | stderr: OnceRead<process::ChildStderr>, clients: &Clients, aux: &mut AuxData | -> bool {
            println!("child (stderr) got active");
            let mut buf = [0; 1024];
            let n = stderr.do_read(&mut buf).expect("read_child");
            println!("({} bytes) `{}'", n, safe_ascii_debug(&buf[..n]));
            n != 0
           };

       //do all the stuff
       fdstore.select(&srvacceptfun, &clientfun, &childstdoutfun, &childstderrfun);
   } //loop
}
<|endoftext|>


<commit_before>#![cfg_attr(loom, allow(dead_code, unreachable_pub))]

//! Traits, helpers, and type definitions for asynchronous I/O functionality.
//!
//! This module is the asynchronous version of `std::io`. Primarily, it
//! defines two traits, [`AsyncRead`] and [`AsyncWrite`], which are asynchronous
//! versions of the [`Read`] and [`Write`] traits in the standard library.
//!
//! # AsyncRead and AsyncWrite
//!
//! Like the standard library's [`Read`] and [`Write`] traits, [`AsyncRead`] and
//! [`AsyncWrite`] provide the most general interface for reading and writing
//! input and output. Unlike the standard library's traits, however, they are
//! _asynchronous_ — meaning that reading from or writing to a `tokio::io`
//! type will _yield_ to the Tokio scheduler when IO is not ready, rather than
//! blocking. This allows other tasks to run while waiting on IO.
//!
//! Another difference is that `AsyncRead` and `AsyncWrite` only contain
//! core methods needed to provide asynchronous reading and writing
//! functionality. Instead, utility methods are defined in the [`AsyncReadExt`]
//! and [`AsyncWriteExt`] extension traits. These traits are automatically
//! implemented for all values that implement `AsyncRead` and `AsyncWrite`
//! respectively.
//!
//! End users will rarely interact directly with `AsyncRead` and
//! `AsyncWrite`. Instead, they will use the async functions defined in the
//! extension traits. Library authors are expected to implement `AsyncRead`
//! and `AsyncWrite` in order to provide types that behave like byte streams.
//!
//! Even with these differences, Tokio's `AsyncRead` and `AsyncWrite` traits
//! can be used in almost exactly the same manner as the standard library's
//! `Read` and `Write`. Most types in the standard library that implement `Read`
//! and `Write` have asynchronous equivalents in `tokio` that implement
//! `AsyncRead` and `AsyncWrite`, such as [`File`] and [`TcpStream`].
//!
//! For example, the standard library documentation introduces `Read` by
//! [demonstrating][std_example] reading some bytes from a [`std::fs::File`]. We
//! can do the same with [`tokio::fs::File`][`File`]:
//!
//! ```no_run
//! use tokio::io::{self, AsyncReadExt};
//! use tokio::fs::File;
//!
//! #[tokio::main]
//! async fn main() -> io::Result<()> {
//!     let mut f = File::open("foo.txt").await?;
//!     let mut buffer = [0; 10];
//!
//!     // read up to 10 bytes
//!     let n = f.read(&mut buffer).await?;
//!
//!     println!("The bytes: {:?}", &buffer[..n]);
//!     Ok(())
//! }
//! ```
//!
//! [`File`]: crate::fs::File
//! [`TcpStream`]: crate::net::TcpStream
//! [`std::fs::File`]: std::fs::File
//! [std_example]: std::io#read-and-write
//!
//! ## Buffered Readers and Writers
//!
//! Byte-based interfaces are unwieldy and can be inefficient, as we'd need to be
//! making near-constant calls to the operating system. To help with this,
//! `std::io` comes with [support for _buffered_ readers and writers][stdbuf],
//! and therefore, `tokio::io` does as well.
//!
//! Tokio provides an async version of the [`std::io::BufRead`] trait,
//! [`AsyncBufRead`]; and async [`BufReader`] and [`BufWriter`] structs, which
//! wrap readers and writers. These wrappers use a buffer, reducing the number
//! of calls and providing nicer methods for accessing exactly what you want.
//!
//! For example, [`BufReader`] works with the [`AsyncBufRead`] trait to add
//! extra methods to any async reader:
//!
//! ```no_run
//! use tokio::io::{self, BufReader, AsyncBufReadExt};
//! use tokio::fs::File;
//!
//! #[tokio::main]
//! async fn main() -> io::Result<()> {
//!     let f = File::open("foo.txt").await?;
//!     let mut reader = BufReader::new(f);
//!     let mut buffer = String::new();
//!
//!     // read a line into buffer
//!     reader.read_line(&mut buffer).await?;
//!
//!     println!("{}", buffer);
//!     Ok(())
//! }
//! ```
//!
//! [`BufWriter`] doesn't add any new ways of writing; it just buffers every call
//! to [`write`](crate::io::AsyncWriteExt::write):
//!
//! ```no_run
//! use tokio::io::{self, BufWriter, AsyncWriteExt};
//! use tokio::fs::File;
//!
//! #[tokio::main]
//! async fn main() -> io::Result<()> {
//!     let f = File::create("foo.txt").await?;
//!     {
//!         let mut writer = BufWriter::new(f);
//!
//!         // write a byte to the buffer
//!         writer.write(&[42u8]).await?;
//!
//!     } // the buffer is flushed once writer goes out of scope
//!
//!     Ok(())
//! }
//! ```
//!
//! [stdbuf]: std::io#bufreader-and-bufwriter
//! [`std::io::BufRead`]: std::io::BufRead
//! [`AsyncBufRead`]: crate::io::AsyncBufRead
//! [`BufReader`]: crate::io::BufReader
//! [`BufWriter`]: crate::io::BufWriter
//!
//! ## Implementing AsyncRead and AsyncWrite
//!
//! Because they are traits, we can implement [`AsyncRead`] and [`AsyncWrite`] for
//! our own types, as well. Note that these traits must only be implemented for
//! non-blocking I/O types that integrate with the futures type system. In
//! other words, these types must never block the thread, and instead the
//! current task is notified when the I/O resource is ready.
//!
//! ## Conversion to and from Sink/Stream
//!
//! It is often convenient to encapsulate the reading and writing of
//! bytes and instead work with a [`Sink`] or [`Stream`] of some data
//! type that is encoded as bytes and/or decoded from bytes. Tokio
//! provides some utility traits in the [tokio-util] crate that
//! abstract the asynchronous buffering that is required and allows
//! you to write [`Encoder`] and [`Decoder`] functions working with a
//! buffer of bytes, and then use that ["codec"] to transform anything
//! that implements [`AsyncRead`] and [`AsyncWrite`] into a `Sink`/`Stream` of
//! your structured data.
//!
//! [tokio-util]: https://docs.rs/tokio-util/0.3/tokio_util/codec/index.html
//!
//! # Standard input and output
//!
//! Tokio provides asynchronous APIs to standard [input], [output], and [error].
//! These APIs are very similar to the ones provided by `std`, but they also
//! implement [`AsyncRead`] and [`AsyncWrite`].
//!
//! Note that the standard input / output APIs  **must** be used from the
//! context of the Tokio runtime, as they require Tokio-specific features to
//! function. Calling these functions outside of a Tokio runtime will panic.
//!
//! [input]: fn@stdin
//! [output]: fn@stdout
//! [error]: fn@stderr
//!
//! # `std` re-exports
//!
//! Additionally, [`Error`], [`ErrorKind`], and [`Result`] are re-exported
//! from `std::io` for ease of use.
//!
//! [`AsyncRead`]: trait@AsyncRead
//! [`AsyncWrite`]: trait@AsyncWrite
//! [`AsyncReadExt`]: trait@AsyncReadExt
//! [`AsyncWriteExt`]: trait@AsyncWriteExt
//! ["codec"]: https://docs.rs/tokio-util/0.3/tokio_util/codec/index.html
//! [`Encoder`]: https://docs.rs/tokio-util/0.3/tokio_util/codec/trait.Encoder.html
//! [`Decoder`]: https://docs.rs/tokio-util/0.3/tokio_util/codec/trait.Decoder.html
//! [`Error`]: struct@Error
//! [`ErrorKind`]: enum@ErrorKind
//! [`Result`]: type@Result
//! [`Read`]: std::io::Read
//! [`Sink`]: https://docs.rs/futures/0.3/futures/sink/trait.Sink.html
//! [`Stream`]: crate::stream::Stream
//! [`Write`]: std::io::Write
cfg_io_blocking! {
    pub(crate) mod blocking;
}

mod async_buf_read;
pub use self::async_buf_read::AsyncBufRead;

mod async_read;

pub use self::async_read::AsyncRead;

mod async_seek;
pub use self::async_seek::AsyncSeek;

mod async_write;
pub use self::async_write::AsyncWrite;

cfg_io_driver! {
    pub(crate) mod driver;

    mod poll_evented;
    pub use poll_evented::PollEvented;

    mod registration;
    pub use registration::Registration;
}

cfg_io_std! {
    mod stderr;
    pub use stderr::{stderr, Stderr};

    mod stdin;
    pub use stdin::{stdin, Stdin};

    mod stdout;
    pub use stdout::{stdout, Stdout};
}

cfg_io_util! {
    mod split;
    pub use split::{split, ReadHalf, WriteHalf};

    pub(crate) mod seek;
    pub use self::seek::Seek;

    pub(crate) mod util;
    pub use util::{
        copy, empty, repeat, sink, AsyncBufReadExt, AsyncReadExt, AsyncSeekExt, AsyncWriteExt,
        BufReader, BufStream, BufWriter, Copy, Empty, Lines, Repeat, Sink, Split, Take,
    };

    cfg_stream! {
        pub use util::{stream_reader, StreamReader};
    }

    // Re-export io::Error so that users don't have to deal with conflicts when
    // `use`ing `tokio::io` and `std::io`.
    pub use std::io::{Error, ErrorKind, Result};
}

cfg_not_io_util! {
    cfg_process! {
        pub(crate) mod util;
    }
}

cfg_io_blocking! {
    /// Types in this module can be mocked out in tests.
    mod sys {
        // TODO: don't rename
        pub(crate) use crate::runtime::spawn_blocking as run;
        pub(crate) use crate::task::JoinHandle as Blocking;
    }
}
<commit_msg>docs: BufWriter does not flush on drop (#2487)<commit_after>#![cfg_attr(loom, allow(dead_code, unreachable_pub))]

//! Traits, helpers, and type definitions for asynchronous I/O functionality.
//!
//! This module is the asynchronous version of `std::io`. Primarily, it
//! defines two traits, [`AsyncRead`] and [`AsyncWrite`], which are asynchronous
//! versions of the [`Read`] and [`Write`] traits in the standard library.
//!
//! # AsyncRead and AsyncWrite
//!
//! Like the standard library's [`Read`] and [`Write`] traits, [`AsyncRead`] and
//! [`AsyncWrite`] provide the most general interface for reading and writing
//! input and output. Unlike the standard library's traits, however, they are
//! _asynchronous_ — meaning that reading from or writing to a `tokio::io`
//! type will _yield_ to the Tokio scheduler when IO is not ready, rather than
//! blocking. This allows other tasks to run while waiting on IO.
//!
//! Another difference is that `AsyncRead` and `AsyncWrite` only contain
//! core methods needed to provide asynchronous reading and writing
//! functionality. Instead, utility methods are defined in the [`AsyncReadExt`]
//! and [`AsyncWriteExt`] extension traits. These traits are automatically
//! implemented for all values that implement `AsyncRead` and `AsyncWrite`
//! respectively.
//!
//! End users will rarely interact directly with `AsyncRead` and
//! `AsyncWrite`. Instead, they will use the async functions defined in the
//! extension traits. Library authors are expected to implement `AsyncRead`
//! and `AsyncWrite` in order to provide types that behave like byte streams.
//!
//! Even with these differences, Tokio's `AsyncRead` and `AsyncWrite` traits
//! can be used in almost exactly the same manner as the standard library's
//! `Read` and `Write`. Most types in the standard library that implement `Read`
//! and `Write` have asynchronous equivalents in `tokio` that implement
//! `AsyncRead` and `AsyncWrite`, such as [`File`] and [`TcpStream`].
//!
//! For example, the standard library documentation introduces `Read` by
//! [demonstrating][std_example] reading some bytes from a [`std::fs::File`]. We
//! can do the same with [`tokio::fs::File`][`File`]:
//!
//! ```no_run
//! use tokio::io::{self, AsyncReadExt};
//! use tokio::fs::File;
//!
//! #[tokio::main]
//! async fn main() -> io::Result<()> {
//!     let mut f = File::open("foo.txt").await?;
//!     let mut buffer = [0; 10];
//!
//!     // read up to 10 bytes
//!     let n = f.read(&mut buffer).await?;
//!
//!     println!("The bytes: {:?}", &buffer[..n]);
//!     Ok(())
//! }
//! ```
//!
//! [`File`]: crate::fs::File
//! [`TcpStream`]: crate::net::TcpStream
//! [`std::fs::File`]: std::fs::File
//! [std_example]: std::io#read-and-write
//!
//! ## Buffered Readers and Writers
//!
//! Byte-based interfaces are unwieldy and can be inefficient, as we'd need to be
//! making near-constant calls to the operating system. To help with this,
//! `std::io` comes with [support for _buffered_ readers and writers][stdbuf],
//! and therefore, `tokio::io` does as well.
//!
//! Tokio provides an async version of the [`std::io::BufRead`] trait,
//! [`AsyncBufRead`]; and async [`BufReader`] and [`BufWriter`] structs, which
//! wrap readers and writers. These wrappers use a buffer, reducing the number
//! of calls and providing nicer methods for accessing exactly what you want.
//!
//! For example, [`BufReader`] works with the [`AsyncBufRead`] trait to add
//! extra methods to any async reader:
//!
//! ```no_run
//! use tokio::io::{self, BufReader, AsyncBufReadExt};
//! use tokio::fs::File;
//!
//! #[tokio::main]
//! async fn main() -> io::Result<()> {
//!     let f = File::open("foo.txt").await?;
//!     let mut reader = BufReader::new(f);
//!     let mut buffer = String::new();
//!
//!     // read a line into buffer
//!     reader.read_line(&mut buffer).await?;
//!
//!     println!("{}", buffer);
//!     Ok(())
//! }
//! ```
//!
//! [`BufWriter`] doesn't add any new ways of writing; it just buffers every call
//! to [`write`](crate::io::AsyncWriteExt::write). However, you **must** flush
//! [`BufWriter`] to ensure that any buffered data is written.
//!
//! ```no_run
//! use tokio::io::{self, BufWriter, AsyncWriteExt};
//! use tokio::fs::File;
//!
//! #[tokio::main]
//! async fn main() -> io::Result<()> {
//!     let f = File::create("foo.txt").await?;
//!     {
//!         let mut writer = BufWriter::new(f);
//!
//!         // Write a byte to the buffer.
//!         writer.write(&[42u8]).await?;
//!
//!         // Flush the buffer before it goes out of scope.
//!         writer.flush().await?;
//!
//!     } // Unless flushed or shut down, the contents of the buffer is discarded on drop.
//!
//!     Ok(())
//! }
//! ```
//!
//! [stdbuf]: std::io#bufreader-and-bufwriter
//! [`std::io::BufRead`]: std::io::BufRead
//! [`AsyncBufRead`]: crate::io::AsyncBufRead
//! [`BufReader`]: crate::io::BufReader
//! [`BufWriter`]: crate::io::BufWriter
//!
//! ## Implementing AsyncRead and AsyncWrite
//!
//! Because they are traits, we can implement [`AsyncRead`] and [`AsyncWrite`] for
//! our own types, as well. Note that these traits must only be implemented for
//! non-blocking I/O types that integrate with the futures type system. In
//! other words, these types must never block the thread, and instead the
//! current task is notified when the I/O resource is ready.
//!
//! ## Conversion to and from Sink/Stream
//!
//! It is often convenient to encapsulate the reading and writing of
//! bytes and instead work with a [`Sink`] or [`Stream`] of some data
//! type that is encoded as bytes and/or decoded from bytes. Tokio
//! provides some utility traits in the [tokio-util] crate that
//! abstract the asynchronous buffering that is required and allows
//! you to write [`Encoder`] and [`Decoder`] functions working with a
//! buffer of bytes, and then use that ["codec"] to transform anything
//! that implements [`AsyncRead`] and [`AsyncWrite`] into a `Sink`/`Stream` of
//! your structured data.
//!
//! [tokio-util]: https://docs.rs/tokio-util/0.3/tokio_util/codec/index.html
//!
//! # Standard input and output
//!
//! Tokio provides asynchronous APIs to standard [input], [output], and [error].
//! These APIs are very similar to the ones provided by `std`, but they also
//! implement [`AsyncRead`] and [`AsyncWrite`].
//!
//! Note that the standard input / output APIs  **must** be used from the
//! context of the Tokio runtime, as they require Tokio-specific features to
//! function. Calling these functions outside of a Tokio runtime will panic.
//!
//! [input]: fn@stdin
//! [output]: fn@stdout
//! [error]: fn@stderr
//!
//! # `std` re-exports
//!
//! Additionally, [`Error`], [`ErrorKind`], and [`Result`] are re-exported
//! from `std::io` for ease of use.
//!
//! [`AsyncRead`]: trait@AsyncRead
//! [`AsyncWrite`]: trait@AsyncWrite
//! [`AsyncReadExt`]: trait@AsyncReadExt
//! [`AsyncWriteExt`]: trait@AsyncWriteExt
//! ["codec"]: https://docs.rs/tokio-util/0.3/tokio_util/codec/index.html
//! [`Encoder`]: https://docs.rs/tokio-util/0.3/tokio_util/codec/trait.Encoder.html
//! [`Decoder`]: https://docs.rs/tokio-util/0.3/tokio_util/codec/trait.Decoder.html
//! [`Error`]: struct@Error
//! [`ErrorKind`]: enum@ErrorKind
//! [`Result`]: type@Result
//! [`Read`]: std::io::Read
//! [`Sink`]: https://docs.rs/futures/0.3/futures/sink/trait.Sink.html
//! [`Stream`]: crate::stream::Stream
//! [`Write`]: std::io::Write
cfg_io_blocking! {
    pub(crate) mod blocking;
}

mod async_buf_read;
pub use self::async_buf_read::AsyncBufRead;

mod async_read;

pub use self::async_read::AsyncRead;

mod async_seek;
pub use self::async_seek::AsyncSeek;

mod async_write;
pub use self::async_write::AsyncWrite;

cfg_io_driver! {
    pub(crate) mod driver;

    mod poll_evented;
    pub use poll_evented::PollEvented;

    mod registration;
    pub use registration::Registration;
}

cfg_io_std! {
    mod stderr;
    pub use stderr::{stderr, Stderr};

    mod stdin;
    pub use stdin::{stdin, Stdin};

    mod stdout;
    pub use stdout::{stdout, Stdout};
}

cfg_io_util! {
    mod split;
    pub use split::{split, ReadHalf, WriteHalf};

    pub(crate) mod seek;
    pub use self::seek::Seek;

    pub(crate) mod util;
    pub use util::{
        copy, empty, repeat, sink, AsyncBufReadExt, AsyncReadExt, AsyncSeekExt, AsyncWriteExt,
        BufReader, BufStream, BufWriter, Copy, Empty, Lines, Repeat, Sink, Split, Take,
    };

    cfg_stream! {
        pub use util::{stream_reader, StreamReader};
    }

    // Re-export io::Error so that users don't have to deal with conflicts when
    // `use`ing `tokio::io` and `std::io`.
    pub use std::io::{Error, ErrorKind, Result};
}

cfg_not_io_util! {
    cfg_process! {
        pub(crate) mod util;
    }
}

cfg_io_blocking! {
    /// Types in this module can be mocked out in tests.
    mod sys {
        // TODO: don't rename
        pub(crate) use crate::runtime::spawn_blocking as run;
        pub(crate) use crate::task::JoinHandle as Blocking;
    }
}
<|endoftext|>


<commit_before>extern crate rusoto_mock;

use ::{CloudFront, CloudFrontClient, ListDistributionsRequest};

use rusoto_core::Region;
use self::rusoto_mock::*;

#[test]
fn should_list_distributions() {
    // reproduced from botocore `cloudfront-list-distributions.xml`
    let mock = MockRequestDispatcher::with_status(200)
        .with_body(r#"<?xml version="1.0" encoding="UTF-8"?>
<DistributionList xmlns="http://cloudfront.amazonaws.com/doc/2014-05-31/">
   <Marker>RMPARXS293KSTG7</Marker>
   <NextMarker>EMLARXS9EXAMPLE</NextMarker>
   <MaxItems>2</MaxItems>
   <IsTruncated>true</IsTruncated>
   <Quantity>1</Quantity>
   <Items>
      <DistributionSummary>
         <Id>EDFDVBD6EXAMPLE</Id>
         <Status>Deployed</Status>
         <LastModifiedTime>2012-05-19T19:37:58Z</LastModifiedTime>
         <DomainName>d111111abcdef8.cloudfront.net</DomainName>
         <Aliases>
            <Quantity>1</Quantity>
            <Items>
               <CNAME>www.example.com</CNAME>
            </Items>
         </Aliases>
         <Origins>
            <Quantity>2</Quantity>
            <Items>
               <Origin>
                  <Id>example-Amazon S3-origin</Id>
                  <DomainName>myawsbucket.s3.amazonaws.com</DomainName>
                  <S3OriginConfig>
                     <OriginAccessIdentity>origin-access-identity/cloudfront/E74FTE3AEXAMPLE</OriginAccessIdentity>
                  </S3OriginConfig>
               </Origin>
               <Origin>
                  <Id>example-custom-origin</Id>
                  <DomainName>example.com</DomainName>
                  <CustomOriginConfig>
                     <HTTPPort>80</HTTPPort>
                     <HTTPSPort>443</HTTPSPort>
                     <OriginProtocolPolicy>match-viewer</OriginProtocolPolicy>
                  </CustomOriginConfig>
               </Origin>
            </Items>
         </Origins>
         <DefaultCacheBehavior>
            <TargetOriginId>example-Amazon S3-origin</TargetOriginId>
            <ForwardedValues>
               <QueryString>true</QueryString>
               <Cookies>
                  <Forward>whitelist</Forward>
                  <WhitelistedNames>
                     <Quantity>1</Quantity>
                     <Items>
                        <Name>example-cookie</Name>
                     </Items>
                  </WhitelistedNames>
               </Cookies>
            </ForwardedValues>
            <TrustedSigners>
               <Enabled>true</Enabled>
               <Quantity>3</Quantity>
               <Items>
                  <AwsAccountNumber>self</AwsAccountNumber>
                  <AwsAccountNumber>111122223333</AwsAccountNumber>
                  <AwsAccountNumber>444455556666</AwsAccountNumber>
               </Items>
            </TrustedSigners>
            <ViewerProtocolPolicy>https-only</ViewerProtocolPolicy>
            <MinTTL>0</MinTTL>
         </DefaultCacheBehavior>
         <CacheBehaviors>
            <Quantity>1</Quantity>
            <Items>
               <CacheBehavior>
                  <PathPattern>*.jpg</PathPattern>
                  <TargetOriginId>example-custom-origin</TargetOriginId>
                  <ForwardedValues>
                     <QueryString>false</QueryString>
                     <Cookies>
                        <Forward>all</Forward>
                     </Cookies>
                  </ForwardedValues>
                  <TrustedSigners>
                     <Enabled>true</Enabled>
                     <Quantity>2</Quantity>
                     <Items>
                        <AwsAccountNumber>self</AwsAccountNumber>
                        <AwsAccountNumber>111122223333</AwsAccountNumber>
                     </Items>
                  </TrustedSigners>
                  <ViewerProtocolPolicy>allow-all</ViewerProtocolPolicy>
                  <MinTTL>86400</MinTTL>
               </CacheBehavior>
            </Items>
         </CacheBehaviors>
         <Comment>example comment</Comment>
         <Logging>
            <Enabled>true</Enabled>
            <IncludeCookies>true</IncludeCookies>
            <Bucket>myawslogbucket.s3.amazonaws.com</Bucket>
            <Prefix>example.com.</Prefix>
         </Logging>
         <ViewerCertificate>
            <IAMCertificateId>AS1A2M3P4L5E67SIIXR3J</IAMCertificateId>
         </ViewerCertificate>
         <PriceClass>PriceClass_All</PriceClass>
         <Enabled>true</Enabled>
      </DistributionSummary>
   </Items>
</DistributionList>"#);

    let request = ListDistributionsRequest::default();

    let client = CloudFrontClient::new_with(mock, MockCredentialsProvider, Region::UsEast1);
    let result = client.list_distributions(request).sync().unwrap();
    assert!(&result.distribution_list.is_some());
    let parsed_result = result.distribution_list.unwrap();
    assert!(&parsed_result.items.is_some());
    let items = parsed_result.items.unwrap();
    assert_eq!(items.len(), 1);
    let first_item = &items[0];
    assert_eq!(first_item.id, "EDFDVBD6EXAMPLE");
    assert_eq!(first_item.status, "Deployed");
    assert_eq!(first_item.domain_name, "d111111abcdef8.cloudfront.net");
    assert_eq!(first_item.origins.quantity, 2);
    match first_item.origins.items {
        Some(ref i) => assert_eq!(i[1].domain_name, "example.com"),
        None => panic!("Should have items"),
    }
}
<commit_msg>Use external test file.<commit_after>extern crate rusoto_mock;

use ::{CloudFront, CloudFrontClient, ListDistributionsRequest};

use rusoto_core::Region;
use self::rusoto_mock::*;

#[test]
fn should_list_distributions() {
    let body = MockResponseReader::read_response("test_resources/generated/valid", "cloudfront-list-distributions.xml");
    let mock = MockRequestDispatcher::with_status(200).with_body(&body);

    let request = ListDistributionsRequest::default();

    let client = CloudFrontClient::new_with(mock, MockCredentialsProvider, Region::UsEast1);
    let result = client.list_distributions(request).sync().unwrap();
    assert!(&result.distribution_list.is_some());
    let parsed_result = result.distribution_list.unwrap();
    assert!(&parsed_result.items.is_some());
    let items = parsed_result.items.unwrap();
    assert_eq!(items.len(), 1);
    let first_item = &items[0];
    assert_eq!(first_item.id, "EDFDVBD6EXAMPLE");
    assert_eq!(first_item.status, "Deployed");
    assert_eq!(first_item.domain_name, "d111111abcdef8.cloudfront.net");
    assert_eq!(first_item.origins.quantity, 2);
    match first_item.origins.items {
        Some(ref i) => assert_eq!(i[1].domain_name, "example.com"),
        None => panic!("Should have items"),
    }
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, VecDeque};
use std::time::Duration;
use libusb::{Result as UsbResult, Error as UsbError};
use nix::sys::signal::{SigAction, sigaction, SaFlags, SigSet, SigHandler, SIGINT, SIGTERM};
use nix::Result as NixResult;
use handle::{Handle, ControlPacket, ToControlPacket};
use color::*;
use keys::*;
use parser::*;
use event::{GenericHandler, Handler};

pub trait Keyboard {
    fn set_key_colors(&mut self, key_colors: Vec<KeyColor>) -> UsbResult<()>;
    fn set_color(&mut self, key_color: KeyColor) -> UsbResult<()>;
    fn set_all_colors(&mut self, color: Color) -> UsbResult<()>;
    fn set_reconnect_interval(&mut self, interval: Duration);
    fn set_reconnect_attempts(&mut self, attempts: i32);
    fn set_auto_reconnect(&mut self, enabled: bool);
    fn reconnect(&mut self) -> UsbResult<()>;
    unsafe fn enable_signal_handling(&mut self) -> NixResult<()>;
    fn disable_signal_handling(&mut self) -> NixResult<()>;
}

pub struct KeyboardInternal {
    handle: Handle,
    control_packet_queue: VecDeque<ControlPacket>,
    sending_control: bool,
    reconnect_interval: Duration,
    reconnect_attempts: i32,
    auto_reconnect: bool,
}

impl KeyboardInternal {
    pub fn new() -> UsbResult<KeyboardInternal> {
        let handle = try!(Handle::new());
        Ok(KeyboardInternal {
            handle: handle,
            control_packet_queue: VecDeque::new(),
            sending_control: false,
            reconnect_interval: Duration::from_secs(1),
            reconnect_attempts: 10,
            auto_reconnect: true,
        })
    }

    pub fn queue_control_packet(&mut self, packet: ControlPacket) -> UsbResult<()> {
        self.control_packet_queue.push_back(packet);
        if !self.sending_control {
            self.send_next_control()
        } else {
            Ok(())
        }
    }

    pub fn send_next_control(&mut self) -> UsbResult<()> {
        if self.control_packet_queue.len() == 0 {
            self.sending_control = false;
            return Ok(());
        }
        if !self.sending_control {
            self.sending_control = true;
        }
        self.handle.send_control(self.control_packet_queue.pop_front().unwrap())
    }

    fn send_color<T: KeyType>(&mut self, color_packet: ColorPacket<T>) -> UsbResult<()> {
        self.queue_control_packet(color_packet.to_control_packet())
    }

    fn flush_color(&mut self) -> UsbResult<()> {
        self.queue_control_packet(FlushPacket::new().to_control_packet())
    }
}

impl Keyboard for KeyboardInternal {
    fn set_key_colors(&mut self, key_colors: Vec<KeyColor>) -> UsbResult<()> {
        let mut standard_packet = ColorPacket::new();
        let mut gaming_packet = ColorPacket::new();
        let mut logo_packet = ColorPacket::new();

        for key_color in key_colors {
            match key_color.key {
                Key::Standard(s) => {
                    match standard_packet.add(s, key_color.color) {
                        Some(p) => try!(self.send_color(p)),
                        None => {}
                    }
                },
                Key::Gaming(g) => {
                    match gaming_packet.add(g, key_color.color) {
                        Some(p) => try!(self.send_color(p)),
                        None => {}
                    }
                },
                Key::Logo(l) => {
                    match logo_packet.add(l, key_color.color) {
                        Some(p) => try!(self.send_color(p)),
                        None => {}
                    }
                },
                Key::Media(_) => return Err(UsbError::InvalidParam)
            }
        }
        if standard_packet.len() > 0 {
            try!(self.send_color(standard_packet));
        }
        if gaming_packet.len() > 0 {
            try!(self.send_color(gaming_packet));
        }
        if logo_packet.len() > 0 {
            try!(self.send_color(logo_packet));
        }
        self.flush_color()
    }

    fn set_color(&mut self, key_color: KeyColor) -> UsbResult<()> {
        let key_colors = vec![key_color];
        self.set_key_colors(key_colors)
    }

    fn set_all_colors(&mut self, color: Color) -> UsbResult<()> {
        let mut values = Key::values();
        let key_colors = values.drain(..)
            .filter(|k| match k {
                // we can't set the color of media keys
                &Key::Media(_) => false,
                _ => true
            }).map(|k| KeyColor::new(k, color.clone()))
            .collect();
        self.set_key_colors(key_colors)
    }

    fn set_reconnect_interval(&mut self, interval: Duration) {
        self.reconnect_interval = interval;
    }

    fn set_reconnect_attempts(&mut self, attempts: i32) {
        self.reconnect_attempts = attempts;
    }
    fn set_auto_reconnect(&mut self, enabled: bool) {
        self.auto_reconnect = enabled;
    }

    fn reconnect(&mut self) -> UsbResult<()> {
        println!("Connection lost. Starting reconnect...");
        let mut last_err = UsbError::NoDevice;
        for _ in 0..self.reconnect_attempts {
            match self.handle.reconnect() {
                Ok(_) => {
                    println!("Reconnected");
                    return Ok(());
                },
                Err(e) => {
                    println!("Reconnecting failed: {:?}", e);
                    last_err = e;
                }
            }
            ::std::thread::sleep(self.reconnect_interval);
        }
        Err(last_err)
    }

    unsafe fn enable_signal_handling(&mut self) -> NixResult<()> {
        let sig_action = SigAction::new(SigHandler::Handler(panic_on_sig), SaFlags::empty(), SigSet::empty());
        try!(sigaction(SIGINT, &sig_action).map(|_| ()));
        sigaction(SIGTERM, &sig_action).map(|_| ())
    }

    fn disable_signal_handling(&mut self) -> NixResult<()> {
        let sig_action = SigAction::new(SigHandler::Handler(exit_on_sig), SaFlags::empty(), SigSet::empty());
        unsafe {
            try!(sigaction(SIGINT, &sig_action).map(|_| ()));
            sigaction(SIGTERM, &sig_action).map(|_| ())
        }
    }
}

extern fn panic_on_sig(_: i32) {
    panic!("Got Sigint: Panicking to drop UsbWrapper to reattach kernel driver");
}

extern fn exit_on_sig(_: i32) {
    ::std::process::exit(1);
}

pub struct KeyboardImpl {
    keyboard_internal: KeyboardInternal,
    parser_index: u32,
    parsers: HashMap<u32, Parser>,
    handler_index: u32,
    handlers: HashMap<u32, Box<GenericHandler>>,
}

impl KeyboardImpl {
    pub fn new() -> UsbResult<KeyboardImpl> {
        let mut keyboard = KeyboardImpl {
            keyboard_internal: try!(KeyboardInternal::new()),
            parser_index: 0,
            parsers: HashMap::new(),
            handler_index: 0,
            handlers: HashMap::new(),
        };
        keyboard.add_parser(KeyParser::new().into());
        keyboard.add_parser(ControlParser::new().into());
        Ok(keyboard)
    }

    pub fn add_handler(&mut self, handler: Handler) -> u32 {
        let index = self.handler_index;
        self.handlers.insert(index, handler.into());
        self.handler_index += 1;
        index
    }

    pub fn remove_handler(&mut self, index: u32) -> Option<Box<GenericHandler>> {
        self.handlers.remove(&index)
    }

    fn add_parser(&mut self, parser: Parser) -> u32 {
        let index = self.parser_index;
        self.parsers.insert(index, parser);
        self.parser_index += 1;
        index
    }

    // FIXME: Currently unused, but maybe needed later
    //fn remove_parser(&mut self, index: u32) -> Option<Parser> {
        //self.parsers.remove(&index)
    //}

    fn handle(&mut self) -> UsbResult<()> {
        let &mut KeyboardImpl {
            ref mut keyboard_internal,
            parser_index: _,
            ref mut parsers,
            handler_index: _,
            ref mut handlers,
        } = self;

        let endpoint_direction;
        let buf;
        loop {
            let timeout = match handlers.iter().filter_map(|(_,h)| h.sleep_duration()).min() {
                Some(d) => d,
                None => Duration::from_secs(3600*24*365)
            };
            let res = keyboard_internal.handle.recv(timeout);
            match res {
                Some(Ok((e, b))) => {
                    endpoint_direction = e;
                    buf = b;
                    break
                },
                Some(Err(err)) => return Err(err),
                None => {
                    for handler in handlers.iter_mut().filter_map(|(_,h)| match h.sleep_duration() {
                        Some(dur) if dur == Duration::from_secs(0) => Some(h),
                        _ => None
                    }) {
                        try!(handler.handle_time(keyboard_internal));
                    }
                }
            }
        }
        let packet = Packet::new(endpoint_direction, &buf);
        let mut handled = false;
        let mut parsed = false;
        for (_, parser) in parsers.iter_mut() {
            match parser {
                &mut Parser::ParseKey(ref mut p) if p.accept(&packet) => {
                    parsed = true;
                    let key_events = try!(p.parse(&packet, keyboard_internal));
                    for key_event in key_events {
                        for (_, handler) in handlers.iter_mut() {
                            if handler.accept_key(&key_event) {
                                handled = true;
                                try!(handler.handle_key(&key_event, keyboard_internal));
                            }
                        }
                    }
                },
                &mut Parser::ParseControl(ref mut p) if p.accept(&packet) => {
                    parsed = true;
                    handled = true;
                    try!(p.parse(&packet, keyboard_internal));
                },
                _ => {}
            }
        }
        if !parsed {
            println!("Packet not parsed: {:?}", packet);
        } else if !handled {
            println!("Packet not handled: {:?}", packet);
        }
        Ok(())
    }

    pub fn start_handle_loop(&mut self) -> UsbResult<()> {
        // init handlers
        {
            let &mut KeyboardImpl {
                ref mut keyboard_internal,
                parser_index: _,
                parsers: _,
                handler_index: _,
                ref mut handlers,
            } = self;
            for (_, handler) in handlers {
                try!(handler.init(keyboard_internal));
            }
        }
        loop {
            match self.handle() {
                Ok(()) => {},
                Err(UsbError::NoDevice) => try!(self.reconnect()),
                Err(UsbError::Io) => try!(self.reconnect()),
                Err(e) => return Err(e),
            }
        }
    }
}

impl Keyboard for KeyboardImpl {
    fn set_key_colors(&mut self, key_colors: Vec<KeyColor>) -> UsbResult<()> {
        self.keyboard_internal.set_key_colors(key_colors)
    }
    fn set_color(&mut self, key_color: KeyColor) -> UsbResult<()> {
        self.keyboard_internal.set_color(key_color)
    }
    fn set_all_colors(&mut self, color: Color) -> UsbResult<()> {
        self.keyboard_internal.set_all_colors(color)
    }
    fn set_reconnect_interval(&mut self, interval: Duration) {
        self.keyboard_internal.set_reconnect_interval(interval)
    }
    fn set_reconnect_attempts(&mut self, attempts: i32) {
        self.keyboard_internal.set_reconnect_attempts(attempts)
    }
    fn set_auto_reconnect(&mut self, enabled: bool) {
        self.keyboard_internal.set_auto_reconnect(enabled)
    }
    fn reconnect(&mut self) -> UsbResult<()> {
        self.keyboard_internal.reconnect()
    }
    unsafe fn enable_signal_handling(&mut self) -> NixResult<()> {
        self.keyboard_internal.enable_signal_handling()
    }
    fn disable_signal_handling(&mut self) -> NixResult<()> {
        self.keyboard_internal.disable_signal_handling()
    }
}

<commit_msg>fix(reconnect): Continue reconnect on `Busy`<commit_after>use std::collections::{HashMap, VecDeque};
use std::time::Duration;
use libusb::{Result as UsbResult, Error as UsbError};
use nix::sys::signal::{SigAction, sigaction, SaFlags, SigSet, SigHandler, SIGINT, SIGTERM};
use nix::Result as NixResult;
use handle::{Handle, ControlPacket, ToControlPacket};
use color::*;
use keys::*;
use parser::*;
use event::{GenericHandler, Handler};

pub trait Keyboard {
    fn set_key_colors(&mut self, key_colors: Vec<KeyColor>) -> UsbResult<()>;
    fn set_color(&mut self, key_color: KeyColor) -> UsbResult<()>;
    fn set_all_colors(&mut self, color: Color) -> UsbResult<()>;
    fn set_reconnect_interval(&mut self, interval: Duration);
    fn set_reconnect_attempts(&mut self, attempts: i32);
    fn set_auto_reconnect(&mut self, enabled: bool);
    fn reconnect(&mut self) -> UsbResult<()>;
    unsafe fn enable_signal_handling(&mut self) -> NixResult<()>;
    fn disable_signal_handling(&mut self) -> NixResult<()>;
}

pub struct KeyboardInternal {
    handle: Handle,
    control_packet_queue: VecDeque<ControlPacket>,
    sending_control: bool,
    reconnect_interval: Duration,
    reconnect_attempts: i32,
    auto_reconnect: bool,
}

impl KeyboardInternal {
    pub fn new() -> UsbResult<KeyboardInternal> {
        let handle = try!(Handle::new());
        Ok(KeyboardInternal {
            handle: handle,
            control_packet_queue: VecDeque::new(),
            sending_control: false,
            reconnect_interval: Duration::from_secs(1),
            reconnect_attempts: 10,
            auto_reconnect: true,
        })
    }

    pub fn queue_control_packet(&mut self, packet: ControlPacket) -> UsbResult<()> {
        self.control_packet_queue.push_back(packet);
        if !self.sending_control {
            self.send_next_control()
        } else {
            Ok(())
        }
    }

    pub fn send_next_control(&mut self) -> UsbResult<()> {
        if self.control_packet_queue.len() == 0 {
            self.sending_control = false;
            return Ok(());
        }
        if !self.sending_control {
            self.sending_control = true;
        }
        self.handle.send_control(self.control_packet_queue.pop_front().unwrap())
    }

    fn send_color<T: KeyType>(&mut self, color_packet: ColorPacket<T>) -> UsbResult<()> {
        self.queue_control_packet(color_packet.to_control_packet())
    }

    fn flush_color(&mut self) -> UsbResult<()> {
        self.queue_control_packet(FlushPacket::new().to_control_packet())
    }
}

impl Keyboard for KeyboardInternal {
    fn set_key_colors(&mut self, key_colors: Vec<KeyColor>) -> UsbResult<()> {
        let mut standard_packet = ColorPacket::new();
        let mut gaming_packet = ColorPacket::new();
        let mut logo_packet = ColorPacket::new();

        for key_color in key_colors {
            match key_color.key {
                Key::Standard(s) => {
                    match standard_packet.add(s, key_color.color) {
                        Some(p) => try!(self.send_color(p)),
                        None => {}
                    }
                },
                Key::Gaming(g) => {
                    match gaming_packet.add(g, key_color.color) {
                        Some(p) => try!(self.send_color(p)),
                        None => {}
                    }
                },
                Key::Logo(l) => {
                    match logo_packet.add(l, key_color.color) {
                        Some(p) => try!(self.send_color(p)),
                        None => {}
                    }
                },
                Key::Media(_) => return Err(UsbError::InvalidParam)
            }
        }
        if standard_packet.len() > 0 {
            try!(self.send_color(standard_packet));
        }
        if gaming_packet.len() > 0 {
            try!(self.send_color(gaming_packet));
        }
        if logo_packet.len() > 0 {
            try!(self.send_color(logo_packet));
        }
        self.flush_color()
    }

    fn set_color(&mut self, key_color: KeyColor) -> UsbResult<()> {
        let key_colors = vec![key_color];
        self.set_key_colors(key_colors)
    }

    fn set_all_colors(&mut self, color: Color) -> UsbResult<()> {
        let mut values = Key::values();
        let key_colors = values.drain(..)
            .filter(|k| match k {
                // we can't set the color of media keys
                &Key::Media(_) => false,
                _ => true
            }).map(|k| KeyColor::new(k, color.clone()))
            .collect();
        self.set_key_colors(key_colors)
    }

    fn set_reconnect_interval(&mut self, interval: Duration) {
        self.reconnect_interval = interval;
    }

    fn set_reconnect_attempts(&mut self, attempts: i32) {
        self.reconnect_attempts = attempts;
    }
    fn set_auto_reconnect(&mut self, enabled: bool) {
        self.auto_reconnect = enabled;
    }

    fn reconnect(&mut self) -> UsbResult<()> {
        println!("Connection lost. Starting reconnect...");
        let mut last_err = UsbError::NoDevice;
        for _ in 0..self.reconnect_attempts {
            match self.handle.reconnect() {
                Ok(_) => {
                    println!("Reconnected");
                    return Ok(());
                },
                Err(e) => {
                    println!("Reconnecting failed: {:?}", e);
                    last_err = e;
                }
            }
            ::std::thread::sleep(self.reconnect_interval);
        }
        Err(last_err)
    }

    unsafe fn enable_signal_handling(&mut self) -> NixResult<()> {
        let sig_action = SigAction::new(SigHandler::Handler(panic_on_sig), SaFlags::empty(), SigSet::empty());
        try!(sigaction(SIGINT, &sig_action).map(|_| ()));
        sigaction(SIGTERM, &sig_action).map(|_| ())
    }

    fn disable_signal_handling(&mut self) -> NixResult<()> {
        let sig_action = SigAction::new(SigHandler::Handler(exit_on_sig), SaFlags::empty(), SigSet::empty());
        unsafe {
            try!(sigaction(SIGINT, &sig_action).map(|_| ()));
            sigaction(SIGTERM, &sig_action).map(|_| ())
        }
    }
}

extern fn panic_on_sig(_: i32) {
    panic!("Got Sigint: Panicking to drop UsbWrapper to reattach kernel driver");
}

extern fn exit_on_sig(_: i32) {
    ::std::process::exit(1);
}

pub struct KeyboardImpl {
    keyboard_internal: KeyboardInternal,
    parser_index: u32,
    parsers: HashMap<u32, Parser>,
    handler_index: u32,
    handlers: HashMap<u32, Box<GenericHandler>>,
}

impl KeyboardImpl {
    pub fn new() -> UsbResult<KeyboardImpl> {
        let mut keyboard = KeyboardImpl {
            keyboard_internal: try!(KeyboardInternal::new()),
            parser_index: 0,
            parsers: HashMap::new(),
            handler_index: 0,
            handlers: HashMap::new(),
        };
        keyboard.add_parser(KeyParser::new().into());
        keyboard.add_parser(ControlParser::new().into());
        Ok(keyboard)
    }

    pub fn add_handler(&mut self, handler: Handler) -> u32 {
        let index = self.handler_index;
        self.handlers.insert(index, handler.into());
        self.handler_index += 1;
        index
    }

    pub fn remove_handler(&mut self, index: u32) -> Option<Box<GenericHandler>> {
        self.handlers.remove(&index)
    }

    fn add_parser(&mut self, parser: Parser) -> u32 {
        let index = self.parser_index;
        self.parsers.insert(index, parser);
        self.parser_index += 1;
        index
    }

    // FIXME: Currently unused, but maybe needed later
    //fn remove_parser(&mut self, index: u32) -> Option<Parser> {
        //self.parsers.remove(&index)
    //}

    fn handle(&mut self) -> UsbResult<()> {
        let &mut KeyboardImpl {
            ref mut keyboard_internal,
            parser_index: _,
            ref mut parsers,
            handler_index: _,
            ref mut handlers,
        } = self;

        let endpoint_direction;
        let buf;
        loop {
            let timeout = match handlers.iter().filter_map(|(_,h)| h.sleep_duration()).min() {
                Some(d) => d,
                None => Duration::from_secs(3600*24*365)
            };
            let res = keyboard_internal.handle.recv(timeout);
            match res {
                Some(Ok((e, b))) => {
                    endpoint_direction = e;
                    buf = b;
                    break
                },
                Some(Err(err)) => return Err(err),
                None => {
                    for handler in handlers.iter_mut().filter_map(|(_,h)| match h.sleep_duration() {
                        Some(dur) if dur == Duration::from_secs(0) => Some(h),
                        _ => None
                    }) {
                        try!(handler.handle_time(keyboard_internal));
                    }
                }
            }
        }
        let packet = Packet::new(endpoint_direction, &buf);
        let mut handled = false;
        let mut parsed = false;
        for (_, parser) in parsers.iter_mut() {
            match parser {
                &mut Parser::ParseKey(ref mut p) if p.accept(&packet) => {
                    parsed = true;
                    let key_events = try!(p.parse(&packet, keyboard_internal));
                    for key_event in key_events {
                        for (_, handler) in handlers.iter_mut() {
                            if handler.accept_key(&key_event) {
                                handled = true;
                                try!(handler.handle_key(&key_event, keyboard_internal));
                            }
                        }
                    }
                },
                &mut Parser::ParseControl(ref mut p) if p.accept(&packet) => {
                    parsed = true;
                    handled = true;
                    try!(p.parse(&packet, keyboard_internal));
                },
                _ => {}
            }
        }
        if !parsed {
            println!("Packet not parsed: {:?}", packet);
        } else if !handled {
            println!("Packet not handled: {:?}", packet);
        }
        Ok(())
    }

    pub fn start_handle_loop(&mut self) -> UsbResult<()> {
        // init handlers
        {
            let &mut KeyboardImpl {
                ref mut keyboard_internal,
                parser_index: _,
                parsers: _,
                handler_index: _,
                ref mut handlers,
            } = self;
            for (_, handler) in handlers {
                try!(handler.init(keyboard_internal));
            }
        }
        loop {
            match self.handle() {
                Ok(()) => {},
                Err(UsbError::NoDevice) | Err(UsbError::Io) | Err(UsbError::Busy) => try!(self.reconnect()),
                Err(e) => return Err(e),
            }
        }
    }
}

impl Keyboard for KeyboardImpl {
    fn set_key_colors(&mut self, key_colors: Vec<KeyColor>) -> UsbResult<()> {
        self.keyboard_internal.set_key_colors(key_colors)
    }
    fn set_color(&mut self, key_color: KeyColor) -> UsbResult<()> {
        self.keyboard_internal.set_color(key_color)
    }
    fn set_all_colors(&mut self, color: Color) -> UsbResult<()> {
        self.keyboard_internal.set_all_colors(color)
    }
    fn set_reconnect_interval(&mut self, interval: Duration) {
        self.keyboard_internal.set_reconnect_interval(interval)
    }
    fn set_reconnect_attempts(&mut self, attempts: i32) {
        self.keyboard_internal.set_reconnect_attempts(attempts)
    }
    fn set_auto_reconnect(&mut self, enabled: bool) {
        self.keyboard_internal.set_auto_reconnect(enabled)
    }
    fn reconnect(&mut self) -> UsbResult<()> {
        self.keyboard_internal.reconnect()
    }
    unsafe fn enable_signal_handling(&mut self) -> NixResult<()> {
        self.keyboard_internal.enable_signal_handling()
    }
    fn disable_signal_handling(&mut self) -> NixResult<()> {
        self.keyboard_internal.disable_signal_handling()
    }
}

<|endoftext|>


<commit_before>extern crate mime_guess;

use std::convert::TryInto;
use std::path::{Path, PathBuf};
use task_maker_format::ioi;
use turingarena::content::*;
use turingarena::evaluation::record::*;
use turingarena::feedback::{table::*, *};
use turingarena::problem::material::*;
use turingarena::award::*;
use turingarena::submission::form::*;

fn subtasks_of(task: &ioi::Task) -> Vec<&ioi::SubtaskInfo> {
    let mut subtasks: Vec<_> = task.subtasks.values().collect();
    subtasks.sort_by(|a, b| a.id.cmp(&b.id));
    subtasks
}

fn testcases_of(subtask: &ioi::SubtaskInfo) -> Vec<&ioi::TestcaseInfo> {
    let mut testcases: Vec<_> = subtask.testcases.values().collect();
    testcases.sort_by(|a, b| a.id.cmp(&b.id));
    testcases
}

fn submission_form() -> Form {
    Form {
        fields: vec![Field {
            id: FieldId("solution".into()),
            title: vec![TextVariant {
                attributes: vec![],
                value: "Solution".into(),
            }],
            types: vec![FileType {
                id: FileTypeId("cpp".into()),
                title: vec![TextVariant {
                    attributes: vec![],
                    value: "C++".into(),
                }],
                extensions: vec![
                    FileTypeExtension(".cpp".into()),
                    FileTypeExtension(".cc".into()),
                ],
                primary_extension: FileTypeExtension(".cpp".into()),
            }],
        }],
    }
}

fn award_of(subtask: &ioi::SubtaskInfo) -> Award {
    Award {
        name: AwardName(format!("subtask.{}", subtask.id)),
        title: vec![TextVariant {
            attributes: vec![],
            value: format!("Subtask {}", subtask.id),
        }],
        content: if subtask.max_score > 0.0 {
            AwardContent::Score(ScoreAwardContent {
                range: ScoreRange {
                    // TODO: assuming IOI-like tasks have integer scores
                    precision: 0,
                    max: Score(subtask.max_score),
                },
            })
        } else {
            AwardContent::Badge(BadgeAwardContent)
        }

    }
}

fn cols() -> Vec<Col> {
    vec![
        Col {
            title: vec![TextVariant {
                attributes: vec![],
                value: format!("Case"),
            }],
            content: ColContent::RowNumber(RowNumberColContent {}),
        },
        Col {
            title: vec![TextVariant {
                attributes: vec![],
                value: format!("Score"),
            }],
            content: ColContent::Score(ScoreColContent {
                range: ScoreRange {
                    // FIXME: assuming per-test-case score has fixed precision
                    precision: 2,
                    max: Score(1.),
                },
            }),
        },
    ]
}

fn caption() -> Text {
    vec![TextVariant {
        attributes: vec![],
        value: format!("Test case results"),
    }]
}

fn row_group_of(subtask: &ioi::SubtaskInfo) -> RowGroup {
    RowGroup {
        title: vec![TextVariant {
            attributes: vec![],
            value: format!("Subtask {}", subtask.id),
        }],
        rows: testcases_of(subtask).into_iter().map(row_of).collect(),
    }
}

fn row_of(testcase: &ioi::TestcaseInfo) -> Row {
    Row {
        content: RowContent::Data,
        cells: vec![
            Cell {
                content: CellContent::RowNumber(RowNumberCellContent {
                    number: testcase.id.try_into().expect("Testcase ID too large"),
                }),
            },
            Cell {
                content: CellContent::Score(ScoreCellContent {
                    range: ScoreRange {
                        precision: 2,
                        max: Score(1.),
                    },
                    r#ref: Key(format!("testcase.{}.score", testcase.id)),
                }),
            },
        ],
    }
}

fn files_in_dir(dir_path: &std::path::PathBuf) -> impl Iterator<Item = std::path::PathBuf> {
    std::fs::read_dir(dir_path)
        .expect("unable to read_dir")
        .map(|entry| entry.expect("unable to read_dir").path())
}

fn attachment_at_path(file_path: std::path::PathBuf) -> Attachment {
    Attachment {
        title: vec![TextVariant {
            attributes: vec![],
            value: file_path
                .file_name()
                .unwrap()
                .to_string_lossy()
                .into_owned(),
        }],
        file: vec![FileVariant {
            attributes: vec![],
            name: Some(FileName(
                file_path
                    .file_name()
                    .unwrap()
                    .to_string_lossy()
                    .into_owned(),
            )),
            r#type: mime_guess::from_path(&file_path)
                .first_raw()
                .map(|t| MediaType(t.to_owned())),
            content: FileContent(std::fs::read(&file_path.to_string_lossy().as_ref()).unwrap()),
        }],
    }
}

/// Mapping (extension, MIME type)
const STATEMENT_FORMATS: [(&'static str, &'static str); 3] = [
    ("pdf", "application/pdf"),
    ("html", "text/html"),
    ("md", "application/markdown"),
];

/// Find the statements directory, as in the italy_yaml task format
/// Searches the paths $task_dir/statement and $task_dir/testo
fn statements_dir(task_dir: &Path) -> Option<PathBuf> {
    for dir in vec!["statement", "testo"] {
        let dir = task_dir.join(dir);
        if dir.exists() && dir.is_dir() {
            return Some(dir);
        }
    }
    None
}

/// Tries to match the filename, returning the mimetype of the
/// matched item, if any
fn match_statement(path: &Path) -> Option<(String, FileName, MediaType)> {
    let ext = path.extension().unwrap().to_str().unwrap();
    let filename = path.file_name().unwrap().to_str().unwrap();
    let language = path.file_stem().unwrap().to_str().unwrap();
    for &(extension, mime_type) in &STATEMENT_FORMATS {
        if ext == extension {
            return Some((
                language.to_owned(),
                FileName(filename.to_owned()),
                MediaType(mime_type.to_owned()),
            ));
        }
    }
    None
}

/// find all the statements in the directory
fn statements_of(task_dir: &Path) -> Vec<FileVariant> {
    let mut result = Vec::new();
    let dir = statements_dir(task_dir);
    if let Some(dir) = dir {
        for file in dir.read_dir().unwrap() {
            let file = file.unwrap().path();
            if let Some((language, filename, mime_type)) = match_statement(&file) {
                result.push(FileVariant {
                    attributes: vec![VariantAttribute {
                        key: "language_name".to_owned(),
                        value: language,
                    }],
                    name: Some(filename),
                    r#type: Some(mime_type),
                    content: FileContent(
                        std::fs::read(file).expect("Unable to read statement file"),
                    ),
                });
            }
        }
    }
    result
}

pub fn gen_material(task: &ioi::Task) -> Material {
    Material {
        title: vec![TextVariant {
            attributes: vec![],
            value: task.title.clone().into(),
        }],
        statement: statements_of(&task.path),
        attachments: files_in_dir(&task.path.join("att"))
            .map(attachment_at_path)
            .collect(),
        submission_form: submission_form(),
        awards: {
            subtasks_of(task)
                .into_iter()
                .filter(|s| s.max_score > 0.0)
                .map(award_of)
                .collect()
        },
        feedback: vec![Section::Table(TableSection {
            caption: caption(),
            cols: cols(),
            row_groups: subtasks_of(task).into_iter().map(row_group_of).collect(),
        })],
    }
}
<commit_msg>task-maker: fix missing zero-score subtasks<commit_after>extern crate mime_guess;

use std::convert::TryInto;
use std::path::{Path, PathBuf};
use task_maker_format::ioi;
use turingarena::award::*;
use turingarena::content::*;
use turingarena::evaluation::record::*;
use turingarena::feedback::{table::*, *};
use turingarena::problem::material::*;
use turingarena::submission::form::*;

fn subtasks_of(task: &ioi::Task) -> Vec<&ioi::SubtaskInfo> {
    let mut subtasks: Vec<_> = task.subtasks.values().collect();
    subtasks.sort_by(|a, b| a.id.cmp(&b.id));
    subtasks
}

fn testcases_of(subtask: &ioi::SubtaskInfo) -> Vec<&ioi::TestcaseInfo> {
    let mut testcases: Vec<_> = subtask.testcases.values().collect();
    testcases.sort_by(|a, b| a.id.cmp(&b.id));
    testcases
}

fn submission_form() -> Form {
    Form {
        fields: vec![Field {
            id: FieldId("solution".into()),
            title: vec![TextVariant {
                attributes: vec![],
                value: "Solution".into(),
            }],
            types: vec![FileType {
                id: FileTypeId("cpp".into()),
                title: vec![TextVariant {
                    attributes: vec![],
                    value: "C++".into(),
                }],
                extensions: vec![
                    FileTypeExtension(".cpp".into()),
                    FileTypeExtension(".cc".into()),
                ],
                primary_extension: FileTypeExtension(".cpp".into()),
            }],
        }],
    }
}

fn award_of(subtask: &ioi::SubtaskInfo) -> Award {
    Award {
        name: AwardName(format!("subtask.{}", subtask.id)),
        title: vec![TextVariant {
            attributes: vec![],
            value: format!("Subtask {}", subtask.id),
        }],
        content: if subtask.max_score > 0.0 {
            AwardContent::Score(ScoreAwardContent {
                range: ScoreRange {
                    // TODO: assuming IOI-like tasks have integer scores
                    precision: 0,
                    max: Score(subtask.max_score),
                },
            })
        } else {
            AwardContent::Badge(BadgeAwardContent)
        },
    }
}

fn cols() -> Vec<Col> {
    vec![
        Col {
            title: vec![TextVariant {
                attributes: vec![],
                value: format!("Case"),
            }],
            content: ColContent::RowNumber(RowNumberColContent {}),
        },
        Col {
            title: vec![TextVariant {
                attributes: vec![],
                value: format!("Score"),
            }],
            content: ColContent::Score(ScoreColContent {
                range: ScoreRange {
                    // FIXME: assuming per-test-case score has fixed precision
                    precision: 2,
                    max: Score(1.),
                },
            }),
        },
    ]
}

fn caption() -> Text {
    vec![TextVariant {
        attributes: vec![],
        value: format!("Test case results"),
    }]
}

fn row_group_of(subtask: &ioi::SubtaskInfo) -> RowGroup {
    RowGroup {
        title: vec![TextVariant {
            attributes: vec![],
            value: format!("Subtask {}", subtask.id),
        }],
        rows: testcases_of(subtask).into_iter().map(row_of).collect(),
    }
}

fn row_of(testcase: &ioi::TestcaseInfo) -> Row {
    Row {
        content: RowContent::Data,
        cells: vec![
            Cell {
                content: CellContent::RowNumber(RowNumberCellContent {
                    number: testcase.id.try_into().expect("Testcase ID too large"),
                }),
            },
            Cell {
                content: CellContent::Score(ScoreCellContent {
                    range: ScoreRange {
                        precision: 2,
                        max: Score(1.),
                    },
                    r#ref: Key(format!("testcase.{}.score", testcase.id)),
                }),
            },
        ],
    }
}

fn files_in_dir(dir_path: &std::path::PathBuf) -> impl Iterator<Item = std::path::PathBuf> {
    std::fs::read_dir(dir_path)
        .expect("unable to read_dir")
        .map(|entry| entry.expect("unable to read_dir").path())
}

fn attachment_at_path(file_path: std::path::PathBuf) -> Attachment {
    Attachment {
        title: vec![TextVariant {
            attributes: vec![],
            value: file_path
                .file_name()
                .unwrap()
                .to_string_lossy()
                .into_owned(),
        }],
        file: vec![FileVariant {
            attributes: vec![],
            name: Some(FileName(
                file_path
                    .file_name()
                    .unwrap()
                    .to_string_lossy()
                    .into_owned(),
            )),
            r#type: mime_guess::from_path(&file_path)
                .first_raw()
                .map(|t| MediaType(t.to_owned())),
            content: FileContent(std::fs::read(&file_path.to_string_lossy().as_ref()).unwrap()),
        }],
    }
}

/// Mapping (extension, MIME type)
const STATEMENT_FORMATS: [(&'static str, &'static str); 3] = [
    ("pdf", "application/pdf"),
    ("html", "text/html"),
    ("md", "application/markdown"),
];

/// Find the statements directory, as in the italy_yaml task format
/// Searches the paths $task_dir/statement and $task_dir/testo
fn statements_dir(task_dir: &Path) -> Option<PathBuf> {
    for dir in vec!["statement", "testo"] {
        let dir = task_dir.join(dir);
        if dir.exists() && dir.is_dir() {
            return Some(dir);
        }
    }
    None
}

/// Tries to match the filename, returning the mimetype of the
/// matched item, if any
fn match_statement(path: &Path) -> Option<(String, FileName, MediaType)> {
    let ext = path.extension().unwrap().to_str().unwrap();
    let filename = path.file_name().unwrap().to_str().unwrap();
    let language = path.file_stem().unwrap().to_str().unwrap();
    for &(extension, mime_type) in &STATEMENT_FORMATS {
        if ext == extension {
            return Some((
                language.to_owned(),
                FileName(filename.to_owned()),
                MediaType(mime_type.to_owned()),
            ));
        }
    }
    None
}

/// find all the statements in the directory
fn statements_of(task_dir: &Path) -> Vec<FileVariant> {
    let mut result = Vec::new();
    let dir = statements_dir(task_dir);
    if let Some(dir) = dir {
        for file in dir.read_dir().unwrap() {
            let file = file.unwrap().path();
            if let Some((language, filename, mime_type)) = match_statement(&file) {
                result.push(FileVariant {
                    attributes: vec![VariantAttribute {
                        key: "language_name".to_owned(),
                        value: language,
                    }],
                    name: Some(filename),
                    r#type: Some(mime_type),
                    content: FileContent(
                        std::fs::read(file).expect("Unable to read statement file"),
                    ),
                });
            }
        }
    }
    result
}

pub fn gen_material(task: &ioi::Task) -> Material {
    Material {
        title: vec![TextVariant {
            attributes: vec![],
            value: task.title.clone().into(),
        }],
        statement: statements_of(&task.path),
        attachments: files_in_dir(&task.path.join("att"))
            .map(attachment_at_path)
            .collect(),
        submission_form: submission_form(),
        awards: { subtasks_of(task).into_iter().map(award_of).collect() },
        feedback: vec![Section::Table(TableSection {
            caption: caption(),
            cols: cols(),
            row_groups: subtasks_of(task).into_iter().map(row_group_of).collect(),
        })],
    }
}
<|endoftext|>


<commit_before>
import vec::len;
import vec::slice;
import ilen = ivec::len;
import islice = ivec::slice;
export ivector;
export lteq;
export merge_sort;
export quick_sort;
export quick_sort3;

type lteq[T] = fn(&T, &T) -> bool ;

fn merge_sort[T](lteq[T] le, vec[T] v) -> vec[T] {
    fn merge[T](lteq[T] le, vec[T] a, vec[T] b) -> vec[T] {
        let vec[T] rs = [];
        let uint a_len = len[T](a);
        let uint a_ix = 0u;
        let uint b_len = len[T](b);
        let uint b_ix = 0u;
        while (a_ix < a_len && b_ix < b_len) {
            if (le(a.(a_ix), b.(b_ix))) {
                rs += [a.(a_ix)];
                a_ix += 1u;
            } else { rs += [b.(b_ix)]; b_ix += 1u; }
        }
        rs += slice[T](a, a_ix, a_len);
        rs += slice[T](b, b_ix, b_len);
        ret rs;
    }
    let uint v_len = len[T](v);
    if (v_len <= 1u) { ret v; }
    let uint mid = v_len / 2u;
    let vec[T] a = slice[T](v, 0u, mid);
    let vec[T] b = slice[T](v, mid, v_len);
    ret merge[T](le, merge_sort[T](le, a), merge_sort[T](le, b));
}

fn swap[T](vec[mutable T] arr, uint x, uint y) {
    auto a = arr.(x);
    arr.(x) = arr.(y);
    arr.(y) = a;
}

fn part[T](lteq[T] compare_func, vec[mutable T] arr, uint left, uint right,
           uint pivot) -> uint {
    auto pivot_value = arr.(pivot);
    swap[T](arr, pivot, right);
    let uint storage_index = left;
    let uint i = left;
    while (i < right) {
        if (compare_func({ arr.(i) }, pivot_value)) {
            swap[T](arr, i, storage_index);
            storage_index += 1u;
        }
        i += 1u;
    }
    swap[T](arr, storage_index, right);
    ret storage_index;
}

fn qsort[T](lteq[T] compare_func, vec[mutable T] arr, uint left, uint right) {
    if (right > left) {
        auto pivot = (left + right) / 2u;
        auto new_pivot = part[T](compare_func, arr, left, right, pivot);
        if (new_pivot == 0u) { ret; }
        qsort[T](compare_func, arr, left, new_pivot - 1u);
        qsort[T](compare_func, arr, new_pivot + 1u, right);
    }
}

fn quick_sort[T](lteq[T] compare_func, vec[mutable T] arr) {
    if (len[T](arr) == 0u) { ret; }
    qsort[T](compare_func, arr, 0u, len[T](arr) - 1u);
}

// Based on algorithm presented by Sedgewick and Bentley here:
// http://www.cs.princeton.edu/~rs/talks/QuicksortIsOptimal.pdf
// According to these slides this is the algorithm of choice for
// 'randomly ordered keys, abstract compare' & 'small number of key values'
fn qsort3[T](lteq[T] compare_func_lt, lteq[T] compare_func_eq,
             vec[mutable T] arr, int left, int right) {
    if (right <= left) { ret; }
    let T v = arr.(right);
    let int i = left - 1;
    let int j = right;
    let int p = i;
    let int q = j;
    while (true) {
        i += 1;
        while (compare_func_lt({ arr.(i) }, v)) { i += 1; }
        j -= 1;
        while (compare_func_lt(v, { arr.(j) })) {
            if (j == left) { break; }
            j -= 1;
        }
        if (i >= j) { break; }
        swap[T](arr, i as uint, j as uint);
        if (compare_func_eq({ arr.(i) }, v)) {
            p += 1;
            swap[T](arr, p as uint, i as uint);
        }
        if (compare_func_eq(v, { arr.(j) })) {
            q -= 1;
            swap[T](arr, j as uint, q as uint);
        }
    }
    swap[T](arr, i as uint, right as uint);
    j = i - 1;
    i += 1;
    let int k = left;
    while (k < p) {
        swap[T](arr, k as uint, j as uint);
        k += 1;
        j -= 1;
        if (k == vec::len[T](arr) as int) { break; }
    }
    k = right - 1;
    while (k > q) {
        swap[T](arr, i as uint, k as uint);
        k -= 1;
        i += 1;
        if (k == 0) { break; }
    }
    qsort3[T](compare_func_lt, compare_func_eq, arr, left, j);
    qsort3[T](compare_func_lt, compare_func_eq, arr, i, right);
}

fn quick_sort3[T](lteq[T] compare_func_lt, lteq[T] compare_func_eq,
                  vec[mutable T] arr) {
    if (vec::len[T](arr) == 0u) { ret; }
    qsort3[T](compare_func_lt, compare_func_eq, arr, 0,
              (vec::len[T](arr) as int) - 1);
}

mod ivector {
    export merge_sort;
    export quick_sort;
    export quick_sort3;

    type lteq[T] = fn(&T, &T) -> bool;

    fn merge_sort[T](lteq[T] le, &T[] v) -> T[] {
        fn merge[T](lteq[T] le, &T[] a, &T[] b) -> T[] {
            let T[] rs = ~[];
            let uint a_len = ilen[T](a);
            let uint a_ix = 0u;
            let uint b_len = ilen[T](b);
            let uint b_ix = 0u;
            while (a_ix < a_len && b_ix < b_len) {
                if (le(a.(a_ix), b.(b_ix))) {
                    rs += ~[a.(a_ix)];
                    a_ix += 1u;
                } else { rs += ~[b.(b_ix)]; b_ix += 1u; }
            }
            rs += islice[T](a, a_ix, a_len);
            rs += islice[T](b, b_ix, b_len);
            ret rs;
        }
        let uint v_len = ilen[T](v);
        if (v_len <= 1u) { ret v; }
        let uint mid = v_len / 2u;
        let T[] a = islice[T](v, 0u, mid);
        let T[] b = islice[T](v, mid, v_len);
        ret merge[T](le, merge_sort[T](le, a), merge_sort[T](le, b));
    }

    fn swap[T](&T[mutable] arr, uint x, uint y) {
        auto a = arr.(x);
        arr.(x) = arr.(y);
        arr.(y) = a;
    }

    fn part[T](lteq[T] compare_func, &T[mutable] arr, uint left, uint right,
               uint pivot) -> uint {
        auto pivot_value = arr.(pivot);
        swap[T](arr, pivot, right);
        let uint storage_index = left;
        let uint i = left;
        while (i < right) {
            if (compare_func({ arr.(i) }, pivot_value)) {
                swap[T](arr, i, storage_index);
                storage_index += 1u;
            }
            i += 1u;
        }
        swap[T](arr, storage_index, right);
        ret storage_index;
    }

    fn qsort[T](lteq[T] compare_func, &T[mutable] arr, uint left,
                uint right) {
        if (right > left) {
            auto pivot = (left + right) / 2u;
            auto new_pivot = part[T](compare_func, arr, left, right, pivot);
            if (new_pivot == 0u) { ret; }
            qsort[T](compare_func, arr, left, new_pivot - 1u);
            qsort[T](compare_func, arr, new_pivot + 1u, right);
        }
    }

    fn quick_sort[T](lteq[T] compare_func, &T[mutable] arr) {
        if (ilen[T](arr) == 0u) { ret; }
        qsort[T](compare_func, arr, 0u, ilen[T](arr) - 1u);
    }

    // Based on algorithm presented by Sedgewick and Bentley here:
    // http://www.cs.princeton.edu/~rs/talks/QuicksortIsOptimal.pdf
    // According to these slides this is the algorithm of choice for
    // 'randomly ordered keys, abstract compare' & 'small number of key values'
    fn qsort3[T](lteq[T] compare_func_lt, lteq[T] compare_func_eq,
                 &T[mutable] arr, int left, int right) {
        if (right <= left) { ret; }
        let T v = arr.(right);
        let int i = left - 1;
        let int j = right;
        let int p = i;
        let int q = j;
        while (true) {
            i += 1;
            while (compare_func_lt({ arr.(i) }, v)) { i += 1; }
            j -= 1;
            while (compare_func_lt(v, { arr.(j) })) {
                if (j == left) { break; }
                j -= 1;
            }
            if (i >= j) { break; }
            swap[T](arr, i as uint, j as uint);
            if (compare_func_eq({ arr.(i) }, v)) {
                p += 1;
                swap[T](arr, p as uint, i as uint);
            }
            if (compare_func_eq(v, { arr.(j) })) {
                q -= 1;
                swap[T](arr, j as uint, q as uint);
            }
        }
        swap[T](arr, i as uint, right as uint);
        j = i - 1;
        i += 1;
        let int k = left;
        while (k < p) {
            swap[T](arr, k as uint, j as uint);
            k += 1;
            j -= 1;
            if (k == ilen[T](arr) as int) { break; }
        }
        k = right - 1;
        while (k > q) {
            swap[T](arr, i as uint, k as uint);
            k -= 1;
            i += 1;
            if (k == 0) { break; }
        }
        qsort3[T](compare_func_lt, compare_func_eq, arr, left, j);
        qsort3[T](compare_func_lt, compare_func_eq, arr, i, right);
    }

    fn quick_sort3[T](lteq[T] compare_func_lt, lteq[T] compare_func_eq,
                      &T[mutable] arr) {
        if (ilen[T](arr) == 0u) { ret; }
        qsort3[T](compare_func_lt, compare_func_eq, arr, 0,
                  (ilen[T](arr) as int) - 1);
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>stdlib: Fix long line in sort.rs<commit_after>
import vec::len;
import vec::slice;
import ilen = ivec::len;
import islice = ivec::slice;
export ivector;
export lteq;
export merge_sort;
export quick_sort;
export quick_sort3;

type lteq[T] = fn(&T, &T) -> bool ;

fn merge_sort[T](lteq[T] le, vec[T] v) -> vec[T] {
    fn merge[T](lteq[T] le, vec[T] a, vec[T] b) -> vec[T] {
        let vec[T] rs = [];
        let uint a_len = len[T](a);
        let uint a_ix = 0u;
        let uint b_len = len[T](b);
        let uint b_ix = 0u;
        while (a_ix < a_len && b_ix < b_len) {
            if (le(a.(a_ix), b.(b_ix))) {
                rs += [a.(a_ix)];
                a_ix += 1u;
            } else { rs += [b.(b_ix)]; b_ix += 1u; }
        }
        rs += slice[T](a, a_ix, a_len);
        rs += slice[T](b, b_ix, b_len);
        ret rs;
    }
    let uint v_len = len[T](v);
    if (v_len <= 1u) { ret v; }
    let uint mid = v_len / 2u;
    let vec[T] a = slice[T](v, 0u, mid);
    let vec[T] b = slice[T](v, mid, v_len);
    ret merge[T](le, merge_sort[T](le, a), merge_sort[T](le, b));
}

fn swap[T](vec[mutable T] arr, uint x, uint y) {
    auto a = arr.(x);
    arr.(x) = arr.(y);
    arr.(y) = a;
}

fn part[T](lteq[T] compare_func, vec[mutable T] arr, uint left, uint right,
           uint pivot) -> uint {
    auto pivot_value = arr.(pivot);
    swap[T](arr, pivot, right);
    let uint storage_index = left;
    let uint i = left;
    while (i < right) {
        if (compare_func({ arr.(i) }, pivot_value)) {
            swap[T](arr, i, storage_index);
            storage_index += 1u;
        }
        i += 1u;
    }
    swap[T](arr, storage_index, right);
    ret storage_index;
}

fn qsort[T](lteq[T] compare_func, vec[mutable T] arr, uint left, uint right) {
    if (right > left) {
        auto pivot = (left + right) / 2u;
        auto new_pivot = part[T](compare_func, arr, left, right, pivot);
        if (new_pivot == 0u) { ret; }
        qsort[T](compare_func, arr, left, new_pivot - 1u);
        qsort[T](compare_func, arr, new_pivot + 1u, right);
    }
}

fn quick_sort[T](lteq[T] compare_func, vec[mutable T] arr) {
    if (len[T](arr) == 0u) { ret; }
    qsort[T](compare_func, arr, 0u, len[T](arr) - 1u);
}

// Based on algorithm presented by Sedgewick and Bentley here:
// http://www.cs.princeton.edu/~rs/talks/QuicksortIsOptimal.pdf
// According to these slides this is the algorithm of choice for
// 'randomly ordered keys, abstract compare' & 'small number of key values'
fn qsort3[T](lteq[T] compare_func_lt, lteq[T] compare_func_eq,
             vec[mutable T] arr, int left, int right) {
    if (right <= left) { ret; }
    let T v = arr.(right);
    let int i = left - 1;
    let int j = right;
    let int p = i;
    let int q = j;
    while (true) {
        i += 1;
        while (compare_func_lt({ arr.(i) }, v)) { i += 1; }
        j -= 1;
        while (compare_func_lt(v, { arr.(j) })) {
            if (j == left) { break; }
            j -= 1;
        }
        if (i >= j) { break; }
        swap[T](arr, i as uint, j as uint);
        if (compare_func_eq({ arr.(i) }, v)) {
            p += 1;
            swap[T](arr, p as uint, i as uint);
        }
        if (compare_func_eq(v, { arr.(j) })) {
            q -= 1;
            swap[T](arr, j as uint, q as uint);
        }
    }
    swap[T](arr, i as uint, right as uint);
    j = i - 1;
    i += 1;
    let int k = left;
    while (k < p) {
        swap[T](arr, k as uint, j as uint);
        k += 1;
        j -= 1;
        if (k == vec::len[T](arr) as int) { break; }
    }
    k = right - 1;
    while (k > q) {
        swap[T](arr, i as uint, k as uint);
        k -= 1;
        i += 1;
        if (k == 0) { break; }
    }
    qsort3[T](compare_func_lt, compare_func_eq, arr, left, j);
    qsort3[T](compare_func_lt, compare_func_eq, arr, i, right);
}

fn quick_sort3[T](lteq[T] compare_func_lt, lteq[T] compare_func_eq,
                  vec[mutable T] arr) {
    if (vec::len[T](arr) == 0u) { ret; }
    qsort3[T](compare_func_lt, compare_func_eq, arr, 0,
              (vec::len[T](arr) as int) - 1);
}

mod ivector {
    export merge_sort;
    export quick_sort;
    export quick_sort3;

    type lteq[T] = fn(&T, &T) -> bool;

    fn merge_sort[T](lteq[T] le, &T[] v) -> T[] {
        fn merge[T](lteq[T] le, &T[] a, &T[] b) -> T[] {
            let T[] rs = ~[];
            let uint a_len = ilen[T](a);
            let uint a_ix = 0u;
            let uint b_len = ilen[T](b);
            let uint b_ix = 0u;
            while (a_ix < a_len && b_ix < b_len) {
                if (le(a.(a_ix), b.(b_ix))) {
                    rs += ~[a.(a_ix)];
                    a_ix += 1u;
                } else { rs += ~[b.(b_ix)]; b_ix += 1u; }
            }
            rs += islice[T](a, a_ix, a_len);
            rs += islice[T](b, b_ix, b_len);
            ret rs;
        }
        let uint v_len = ilen[T](v);
        if (v_len <= 1u) { ret v; }
        let uint mid = v_len / 2u;
        let T[] a = islice[T](v, 0u, mid);
        let T[] b = islice[T](v, mid, v_len);
        ret merge[T](le, merge_sort[T](le, a), merge_sort[T](le, b));
    }

    fn swap[T](&T[mutable] arr, uint x, uint y) {
        auto a = arr.(x);
        arr.(x) = arr.(y);
        arr.(y) = a;
    }

    fn part[T](lteq[T] compare_func, &T[mutable] arr, uint left, uint right,
               uint pivot) -> uint {
        auto pivot_value = arr.(pivot);
        swap[T](arr, pivot, right);
        let uint storage_index = left;
        let uint i = left;
        while (i < right) {
            if (compare_func({ arr.(i) }, pivot_value)) {
                swap[T](arr, i, storage_index);
                storage_index += 1u;
            }
            i += 1u;
        }
        swap[T](arr, storage_index, right);
        ret storage_index;
    }

    fn qsort[T](lteq[T] compare_func, &T[mutable] arr, uint left,
                uint right) {
        if (right > left) {
            auto pivot = (left + right) / 2u;
            auto new_pivot = part[T](compare_func, arr, left, right, pivot);
            if (new_pivot == 0u) { ret; }
            qsort[T](compare_func, arr, left, new_pivot - 1u);
            qsort[T](compare_func, arr, new_pivot + 1u, right);
        }
    }

    fn quick_sort[T](lteq[T] compare_func, &T[mutable] arr) {
        if (ilen[T](arr) == 0u) { ret; }
        qsort[T](compare_func, arr, 0u, ilen[T](arr) - 1u);
    }

    // Based on algorithm presented by Sedgewick and Bentley here:
    // http://www.cs.princeton.edu/~rs/talks/QuicksortIsOptimal.pdf
    // According to these slides this is the algorithm of choice for
    // 'randomly ordered keys, abstract compare' & 'small number of key
    // values'
    fn qsort3[T](lteq[T] compare_func_lt, lteq[T] compare_func_eq,
                 &T[mutable] arr, int left, int right) {
        if (right <= left) { ret; }
        let T v = arr.(right);
        let int i = left - 1;
        let int j = right;
        let int p = i;
        let int q = j;
        while (true) {
            i += 1;
            while (compare_func_lt({ arr.(i) }, v)) { i += 1; }
            j -= 1;
            while (compare_func_lt(v, { arr.(j) })) {
                if (j == left) { break; }
                j -= 1;
            }
            if (i >= j) { break; }
            swap[T](arr, i as uint, j as uint);
            if (compare_func_eq({ arr.(i) }, v)) {
                p += 1;
                swap[T](arr, p as uint, i as uint);
            }
            if (compare_func_eq(v, { arr.(j) })) {
                q -= 1;
                swap[T](arr, j as uint, q as uint);
            }
        }
        swap[T](arr, i as uint, right as uint);
        j = i - 1;
        i += 1;
        let int k = left;
        while (k < p) {
            swap[T](arr, k as uint, j as uint);
            k += 1;
            j -= 1;
            if (k == ilen[T](arr) as int) { break; }
        }
        k = right - 1;
        while (k > q) {
            swap[T](arr, i as uint, k as uint);
            k -= 1;
            i += 1;
            if (k == 0) { break; }
        }
        qsort3[T](compare_func_lt, compare_func_eq, arr, left, j);
        qsort3[T](compare_func_lt, compare_func_eq, arr, i, right);
    }

    fn quick_sort3[T](lteq[T] compare_func_lt, lteq[T] compare_func_eq,
                      &T[mutable] arr) {
        if (ilen[T](arr) == 0u) { ret; }
        qsort3[T](compare_func_lt, compare_func_eq, arr, 0,
                  (ilen[T](arr) as int) - 1);
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>