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

/*! Non-blocking access to stdin, stdout, and stderr.

This module provides bindings to the local event loop's TTY interface, using it
to offer synchronous but non-blocking versions of stdio. These handles can be
inspected for information about terminal dimensions or for related information
about the stream or terminal to which it is attached.

# Example

```rust
# #![allow(unused_must_use)]
use std::io;

let mut out = io::stdout();
out.write(bytes!("Hello, world!"));
```

*/

use fmt;
use io::{Reader, Writer, IoResult, IoError, OtherIoError,
         standard_error, EndOfFile, LineBufferedWriter, BufferedReader};
use libc;
use kinds::Send;
use mem::replace;
use option::{Option, Some, None};
use owned::Box;
use prelude::drop;
use result::{Ok, Err};
use rt;
use rt::local::Local;
use rt::rtio::{DontClose, IoFactory, LocalIo, RtioFileStream, RtioTTY};
use rt::task::Task;
use str::StrSlice;

// And so begins the tale of acquiring a uv handle to a stdio stream on all
// platforms in all situations. Our story begins by splitting the world into two
// categories, windows and unix. Then one day the creators of unix said let
// there be redirection! And henceforth there was redirection away from the
// console for standard I/O streams.
//
// After this day, the world split into four factions:
//
// 1. Unix with stdout on a terminal.
// 2. Unix with stdout redirected.
// 3. Windows with stdout on a terminal.
// 4. Windows with stdout redirected.
//
// Many years passed, and then one day the nation of libuv decided to unify this
// world. After months of toiling, uv created three ideas: TTY, Pipe, File.
// These three ideas propagated throughout the lands and the four great factions
// decided to settle among them.
//
// The groups of 1, 2, and 3 all worked very hard towards the idea of TTY. Upon
// doing so, they even enhanced themselves further then their Pipe/File
// brethren, becoming the dominant powers.
//
// The group of 4, however, decided to work independently. They abandoned the
// common TTY belief throughout, and even abandoned the fledgling Pipe belief.
// The members of the 4th faction decided to only align themselves with File.
//
// tl;dr; TTY works on everything but when windows stdout is redirected, in that
//        case pipe also doesn't work, but magically file does!
enum StdSource {
    TTY(Box<RtioTTY:Send>),
    File(Box<RtioFileStream:Send>),
}

fn src<T>(fd: libc::c_int, readable: bool, f: |StdSource| -> T) -> T {
    LocalIo::maybe_raise(|io| {
        Ok(match io.tty_open(fd, readable) {
            Ok(tty) => f(TTY(tty)),
            Err(_) => f(File(io.fs_from_raw_fd(fd, DontClose))),
        })
    }).unwrap()
}

/// Creates a new non-blocking handle to the stdin of the current process.
///
/// The returned handled is buffered by default with a `BufferedReader`. If
/// buffered access is not desired, the `stdin_raw` function is provided to
/// provided unbuffered access to stdin.
///
/// Care should be taken when creating multiple handles to the stdin of a
/// process. Beause this is a buffered reader by default, it's possible for
/// pending input to be unconsumed in one reader and unavailable to other
/// readers. It is recommended that only one handle at a time is created for the
/// stdin of a process.
///
/// See `stdout()` for more notes about this function.
pub fn stdin() -> BufferedReader<StdReader> {
    // The default buffer capacity is 64k, but apparently windows doesn't like
    // 64k reads on stdin. See #13304 for details, but the idea is that on
    // windows we use a slighly smaller buffer that's been seen to be
    // acceptable.
    if cfg!(windows) {
        BufferedReader::with_capacity(8 * 1024, stdin_raw())
    } else {
        BufferedReader::new(stdin_raw())
    }
}

/// Creates a new non-blocking handle to the stdin of the current process.
///
/// Unlike `stdin()`, the returned reader is *not* a buffered reader.
///
/// See `stdout()` for more notes about this function.
pub fn stdin_raw() -> StdReader {
    src(libc::STDIN_FILENO, true, |src| StdReader { inner: src })
}

/// Creates a line-buffered handle to the stdout of the current process.
///
/// Note that this is a fairly expensive operation in that at least one memory
/// allocation is performed. Additionally, this must be called from a runtime
/// task context because the stream returned will be a non-blocking object using
/// the local scheduler to perform the I/O.
///
/// Care should be taken when creating multiple handles to an output stream for
/// a single process. While usage is still safe, the output may be surprising if
/// no synchronization is performed to ensure a sane output.
pub fn stdout() -> LineBufferedWriter<StdWriter> {
    LineBufferedWriter::new(stdout_raw())
}

/// Creates an unbuffered handle to the stdout of the current process
///
/// See notes in `stdout()` for more information.
pub fn stdout_raw() -> StdWriter {
    src(libc::STDOUT_FILENO, false, |src| StdWriter { inner: src })
}

/// Creates a line-buffered handle to the stderr of the current process.
///
/// See `stdout()` for notes about this function.
pub fn stderr() -> LineBufferedWriter<StdWriter> {
    LineBufferedWriter::new(stderr_raw())
}

/// Creates an unbuffered handle to the stderr of the current process
///
/// See notes in `stdout()` for more information.
pub fn stderr_raw() -> StdWriter {
    src(libc::STDERR_FILENO, false, |src| StdWriter { inner: src })
}

fn reset_helper(w: Box<Writer:Send>,
                f: |&mut Task, Box<Writer:Send>| -> Option<Box<Writer:Send>>)
                -> Option<Box<Writer:Send>> {
    let mut t = Local::borrow(None::<Task>);
    // Be sure to flush any pending output from the writer
    match f(&mut *t, w) {
        Some(mut w) => {
            drop(t);
            // FIXME: is failing right here?
            w.flush().unwrap();
            Some(w)
        }
        None => None
    }
}

/// Resets the task-local stdout handle to the specified writer
///
/// This will replace the current task's stdout handle, returning the old
/// handle. All future calls to `print` and friends will emit their output to
/// this specified handle.
///
/// Note that this does not need to be called for all new tasks; the default
/// output handle is to the process's stdout stream.
pub fn set_stdout(stdout: Box<Writer:Send>) -> Option<Box<Writer:Send>> {
    reset_helper(stdout, |t, w| replace(&mut t.stdout, Some(w)))
}

/// Resets the task-local stderr handle to the specified writer
///
/// This will replace the current task's stderr handle, returning the old
/// handle. Currently, the stderr handle is used for printing failure messages
/// during task failure.
///
/// Note that this does not need to be called for all new tasks; the default
/// output handle is to the process's stderr stream.
pub fn set_stderr(stderr: Box<Writer:Send>) -> Option<Box<Writer:Send>> {
    reset_helper(stderr, |t, w| replace(&mut t.stderr, Some(w)))
}

// Helper to access the local task's stdout handle
//
// Note that this is not a safe function to expose because you can create an
// aliased pointer very easily:
//
//  with_task_stdout(|io1| {
//      with_task_stdout(|io2| {
//          // io1 aliases io2
//      })
//  })
fn with_task_stdout(f: |&mut Writer| -> IoResult<()> ) {
    let task: Option<Box<Task>> = Local::try_take();
    let result = match task {
        Some(mut task) => {
            // Printing may run arbitrary code, so ensure that the task is in
            // TLS to allow all std services. Note that this means a print while
            // printing won't use the task's normal stdout handle, but this is
            // necessary to ensure safety (no aliasing).
            let mut my_stdout = task.stdout.take();
            Local::put(task);

            if my_stdout.is_none() {
                my_stdout = Some(box stdout() as Box<Writer:Send>);
            }
            let ret = f(*my_stdout.get_mut_ref());

            // Note that we need to be careful when putting the stdout handle
            // back into the task. If the handle was set to `Some` while
            // printing, then we can run aribitrary code when destroying the
            // previous handle. This means that the local task needs to be in
            // TLS while we do this.
            //
            // To protect against this, we do a little dance in which we
            // temporarily take the task, swap the handles, put the task in TLS,
            // and only then drop the previous handle.
            let prev = replace(&mut Local::borrow(None::<Task>).stdout, my_stdout);
            drop(prev);
            ret
        }

        None => {
            let mut io = rt::Stdout;
            f(&mut io as &mut Writer)
        }
    };

    match result {
        Ok(()) => {}
        Err(e) => fail!("failed printing to stdout: {}", e),
    }
}

/// Flushes the local task's stdout handle.
///
/// By default, this stream is a line-buffering stream, so flushing may be
/// necessary to ensure that all output is printed to the screen (if there are
/// no newlines printed).
///
/// Note that logging macros do not use this stream. Using the logging macros
/// will emit output to stderr, and while they are line buffered the log
/// messages are always terminated in a newline (no need to flush).
pub fn flush() {
    with_task_stdout(|io| io.flush())
}

/// Prints a string to the stdout of the current process. No newline is emitted
/// after the string is printed.
pub fn print(s: &str) {
    with_task_stdout(|io| io.write(s.as_bytes()))
}

/// Prints a string as a line. to the stdout of the current process. A literal
/// `\n` character is printed to the console after the string.
pub fn println(s: &str) {
    with_task_stdout(|io| {
        io.write(s.as_bytes()).and_then(|()| io.write(['\n' as u8]))
    })
}

/// Similar to `print`, but takes a `fmt::Arguments` structure to be compatible
/// with the `format_args!` macro.
pub fn print_args(fmt: &fmt::Arguments) {
    with_task_stdout(|io| write!(io, "{}", fmt))
}

/// Similar to `println`, but takes a `fmt::Arguments` structure to be
/// compatible with the `format_args!` macro.
pub fn println_args(fmt: &fmt::Arguments) {
    with_task_stdout(|io| writeln!(io, "{}", fmt))
}

/// Representation of a reader of a standard input stream
pub struct StdReader {
    inner: StdSource
}

impl Reader for StdReader {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        let ret = match self.inner {
            TTY(ref mut tty) => {
                // Flush the task-local stdout so that weird issues like a
                // print!'d prompt not being shown until after the user hits
                // enter.
                flush();
                tty.read(buf)
            },
            File(ref mut file) => file.read(buf).map(|i| i as uint),
        };
        match ret {
            // When reading a piped stdin, libuv will return 0-length reads when
            // stdin reaches EOF. For pretty much all other streams it will
            // return an actual EOF error, but apparently for stdin it's a
            // little different. Hence, here we convert a 0 length read to an
            // end-of-file indicator so the caller knows to stop reading.
            Ok(0) => { Err(standard_error(EndOfFile)) }
            ret @ Ok(..) | ret @ Err(..) => ret,
        }
    }
}

/// Representation of a writer to a standard output stream
pub struct StdWriter {
    inner: StdSource
}

impl StdWriter {
    /// Gets the size of this output window, if possible. This is typically used
    /// when the writer is attached to something like a terminal, this is used
    /// to fetch the dimensions of the terminal.
    ///
    /// If successful, returns `Ok((width, height))`.
    ///
    /// # Error
    ///
    /// This function will return an error if the output stream is not actually
    /// connected to a TTY instance, or if querying the TTY instance fails.
    pub fn winsize(&mut self) -> IoResult<(int, int)> {
        match self.inner {
            TTY(ref mut tty) => tty.get_winsize(),
            File(..) => {
                Err(IoError {
                    kind: OtherIoError,
                    desc: "stream is not a tty",
                    detail: None,
                })
            }
        }
    }

    /// Controls whether this output stream is a "raw stream" or simply a normal
    /// stream.
    ///
    /// # Error
    ///
    /// This function will return an error if the output stream is not actually
    /// connected to a TTY instance, or if querying the TTY instance fails.
    pub fn set_raw(&mut self, raw: bool) -> IoResult<()> {
        match self.inner {
            TTY(ref mut tty) => tty.set_raw(raw),
            File(..) => {
                Err(IoError {
                    kind: OtherIoError,
                    desc: "stream is not a tty",
                    detail: None,
                })
            }
        }
    }

    /// Returns whether this stream is attached to a TTY instance or not.
    pub fn isatty(&self) -> bool {
        match self.inner {
            TTY(..) => true,
            File(..) => false,
        }
    }
}

impl Writer for StdWriter {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        match self.inner {
            TTY(ref mut tty) => tty.write(buf),
            File(ref mut file) => file.write(buf),
        }
    }
}

#[cfg(test)]
mod tests {
    iotest!(fn smoke() {
        // Just make sure we can acquire handles
        stdin();
        stdout();
        stderr();
    })

    iotest!(fn capture_stdout() {
        use io::{ChanReader, ChanWriter};

        let (tx, rx) = channel();
        let (mut r, w) = (ChanReader::new(rx), ChanWriter::new(tx));
        spawn(proc() {
            set_stdout(box w);
            println!("hello!");
        });
        assert_eq!(r.read_to_str().unwrap(), "hello!\n".to_owned());
    })

    iotest!(fn capture_stderr() {
        use io::{ChanReader, ChanWriter};

        let (tx, rx) = channel();
        let (mut r, w) = (ChanReader::new(rx), ChanWriter::new(tx));
        spawn(proc() {
            set_stderr(box w);
            fail!("my special message");
        });
        let s = r.read_to_str().unwrap();
        assert!(s.contains("my special message"));
    })
}
<commit_msg>auto merge of #14315 : kballard/rust/stdreader_isatty, r=alexcrichton<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*! Non-blocking access to stdin, stdout, and stderr.

This module provides bindings to the local event loop's TTY interface, using it
to offer synchronous but non-blocking versions of stdio. These handles can be
inspected for information about terminal dimensions or for related information
about the stream or terminal to which it is attached.

# Example

```rust
# #![allow(unused_must_use)]
use std::io;

let mut out = io::stdout();
out.write(bytes!("Hello, world!"));
```

*/

use fmt;
use io::{Reader, Writer, IoResult, IoError, OtherIoError,
         standard_error, EndOfFile, LineBufferedWriter, BufferedReader};
use libc;
use kinds::Send;
use mem::replace;
use option::{Option, Some, None};
use owned::Box;
use prelude::drop;
use result::{Ok, Err};
use rt;
use rt::local::Local;
use rt::rtio::{DontClose, IoFactory, LocalIo, RtioFileStream, RtioTTY};
use rt::task::Task;
use str::StrSlice;

// And so begins the tale of acquiring a uv handle to a stdio stream on all
// platforms in all situations. Our story begins by splitting the world into two
// categories, windows and unix. Then one day the creators of unix said let
// there be redirection! And henceforth there was redirection away from the
// console for standard I/O streams.
//
// After this day, the world split into four factions:
//
// 1. Unix with stdout on a terminal.
// 2. Unix with stdout redirected.
// 3. Windows with stdout on a terminal.
// 4. Windows with stdout redirected.
//
// Many years passed, and then one day the nation of libuv decided to unify this
// world. After months of toiling, uv created three ideas: TTY, Pipe, File.
// These three ideas propagated throughout the lands and the four great factions
// decided to settle among them.
//
// The groups of 1, 2, and 3 all worked very hard towards the idea of TTY. Upon
// doing so, they even enhanced themselves further then their Pipe/File
// brethren, becoming the dominant powers.
//
// The group of 4, however, decided to work independently. They abandoned the
// common TTY belief throughout, and even abandoned the fledgling Pipe belief.
// The members of the 4th faction decided to only align themselves with File.
//
// tl;dr; TTY works on everything but when windows stdout is redirected, in that
//        case pipe also doesn't work, but magically file does!
enum StdSource {
    TTY(Box<RtioTTY:Send>),
    File(Box<RtioFileStream:Send>),
}

fn src<T>(fd: libc::c_int, readable: bool, f: |StdSource| -> T) -> T {
    LocalIo::maybe_raise(|io| {
        Ok(match io.tty_open(fd, readable) {
            Ok(tty) => f(TTY(tty)),
            Err(_) => f(File(io.fs_from_raw_fd(fd, DontClose))),
        })
    }).unwrap()
}

/// Creates a new non-blocking handle to the stdin of the current process.
///
/// The returned handled is buffered by default with a `BufferedReader`. If
/// buffered access is not desired, the `stdin_raw` function is provided to
/// provided unbuffered access to stdin.
///
/// Care should be taken when creating multiple handles to the stdin of a
/// process. Beause this is a buffered reader by default, it's possible for
/// pending input to be unconsumed in one reader and unavailable to other
/// readers. It is recommended that only one handle at a time is created for the
/// stdin of a process.
///
/// See `stdout()` for more notes about this function.
pub fn stdin() -> BufferedReader<StdReader> {
    // The default buffer capacity is 64k, but apparently windows doesn't like
    // 64k reads on stdin. See #13304 for details, but the idea is that on
    // windows we use a slighly smaller buffer that's been seen to be
    // acceptable.
    if cfg!(windows) {
        BufferedReader::with_capacity(8 * 1024, stdin_raw())
    } else {
        BufferedReader::new(stdin_raw())
    }
}

/// Creates a new non-blocking handle to the stdin of the current process.
///
/// Unlike `stdin()`, the returned reader is *not* a buffered reader.
///
/// See `stdout()` for more notes about this function.
pub fn stdin_raw() -> StdReader {
    src(libc::STDIN_FILENO, true, |src| StdReader { inner: src })
}

/// Creates a line-buffered handle to the stdout of the current process.
///
/// Note that this is a fairly expensive operation in that at least one memory
/// allocation is performed. Additionally, this must be called from a runtime
/// task context because the stream returned will be a non-blocking object using
/// the local scheduler to perform the I/O.
///
/// Care should be taken when creating multiple handles to an output stream for
/// a single process. While usage is still safe, the output may be surprising if
/// no synchronization is performed to ensure a sane output.
pub fn stdout() -> LineBufferedWriter<StdWriter> {
    LineBufferedWriter::new(stdout_raw())
}

/// Creates an unbuffered handle to the stdout of the current process
///
/// See notes in `stdout()` for more information.
pub fn stdout_raw() -> StdWriter {
    src(libc::STDOUT_FILENO, false, |src| StdWriter { inner: src })
}

/// Creates a line-buffered handle to the stderr of the current process.
///
/// See `stdout()` for notes about this function.
pub fn stderr() -> LineBufferedWriter<StdWriter> {
    LineBufferedWriter::new(stderr_raw())
}

/// Creates an unbuffered handle to the stderr of the current process
///
/// See notes in `stdout()` for more information.
pub fn stderr_raw() -> StdWriter {
    src(libc::STDERR_FILENO, false, |src| StdWriter { inner: src })
}

fn reset_helper(w: Box<Writer:Send>,
                f: |&mut Task, Box<Writer:Send>| -> Option<Box<Writer:Send>>)
                -> Option<Box<Writer:Send>> {
    let mut t = Local::borrow(None::<Task>);
    // Be sure to flush any pending output from the writer
    match f(&mut *t, w) {
        Some(mut w) => {
            drop(t);
            // FIXME: is failing right here?
            w.flush().unwrap();
            Some(w)
        }
        None => None
    }
}

/// Resets the task-local stdout handle to the specified writer
///
/// This will replace the current task's stdout handle, returning the old
/// handle. All future calls to `print` and friends will emit their output to
/// this specified handle.
///
/// Note that this does not need to be called for all new tasks; the default
/// output handle is to the process's stdout stream.
pub fn set_stdout(stdout: Box<Writer:Send>) -> Option<Box<Writer:Send>> {
    reset_helper(stdout, |t, w| replace(&mut t.stdout, Some(w)))
}

/// Resets the task-local stderr handle to the specified writer
///
/// This will replace the current task's stderr handle, returning the old
/// handle. Currently, the stderr handle is used for printing failure messages
/// during task failure.
///
/// Note that this does not need to be called for all new tasks; the default
/// output handle is to the process's stderr stream.
pub fn set_stderr(stderr: Box<Writer:Send>) -> Option<Box<Writer:Send>> {
    reset_helper(stderr, |t, w| replace(&mut t.stderr, Some(w)))
}

// Helper to access the local task's stdout handle
//
// Note that this is not a safe function to expose because you can create an
// aliased pointer very easily:
//
//  with_task_stdout(|io1| {
//      with_task_stdout(|io2| {
//          // io1 aliases io2
//      })
//  })
fn with_task_stdout(f: |&mut Writer| -> IoResult<()> ) {
    let task: Option<Box<Task>> = Local::try_take();
    let result = match task {
        Some(mut task) => {
            // Printing may run arbitrary code, so ensure that the task is in
            // TLS to allow all std services. Note that this means a print while
            // printing won't use the task's normal stdout handle, but this is
            // necessary to ensure safety (no aliasing).
            let mut my_stdout = task.stdout.take();
            Local::put(task);

            if my_stdout.is_none() {
                my_stdout = Some(box stdout() as Box<Writer:Send>);
            }
            let ret = f(*my_stdout.get_mut_ref());

            // Note that we need to be careful when putting the stdout handle
            // back into the task. If the handle was set to `Some` while
            // printing, then we can run aribitrary code when destroying the
            // previous handle. This means that the local task needs to be in
            // TLS while we do this.
            //
            // To protect against this, we do a little dance in which we
            // temporarily take the task, swap the handles, put the task in TLS,
            // and only then drop the previous handle.
            let prev = replace(&mut Local::borrow(None::<Task>).stdout, my_stdout);
            drop(prev);
            ret
        }

        None => {
            let mut io = rt::Stdout;
            f(&mut io as &mut Writer)
        }
    };

    match result {
        Ok(()) => {}
        Err(e) => fail!("failed printing to stdout: {}", e),
    }
}

/// Flushes the local task's stdout handle.
///
/// By default, this stream is a line-buffering stream, so flushing may be
/// necessary to ensure that all output is printed to the screen (if there are
/// no newlines printed).
///
/// Note that logging macros do not use this stream. Using the logging macros
/// will emit output to stderr, and while they are line buffered the log
/// messages are always terminated in a newline (no need to flush).
pub fn flush() {
    with_task_stdout(|io| io.flush())
}

/// Prints a string to the stdout of the current process. No newline is emitted
/// after the string is printed.
pub fn print(s: &str) {
    with_task_stdout(|io| io.write(s.as_bytes()))
}

/// Prints a string as a line. to the stdout of the current process. A literal
/// `\n` character is printed to the console after the string.
pub fn println(s: &str) {
    with_task_stdout(|io| {
        io.write(s.as_bytes()).and_then(|()| io.write(['\n' as u8]))
    })
}

/// Similar to `print`, but takes a `fmt::Arguments` structure to be compatible
/// with the `format_args!` macro.
pub fn print_args(fmt: &fmt::Arguments) {
    with_task_stdout(|io| write!(io, "{}", fmt))
}

/// Similar to `println`, but takes a `fmt::Arguments` structure to be
/// compatible with the `format_args!` macro.
pub fn println_args(fmt: &fmt::Arguments) {
    with_task_stdout(|io| writeln!(io, "{}", fmt))
}

/// Representation of a reader of a standard input stream
pub struct StdReader {
    inner: StdSource
}

impl StdReader {
    /// Returns whether this stream is attached to a TTY instance or not.
    pub fn isatty(&self) -> bool {
        match self.inner {
            TTY(..) => true,
            File(..) => false,
        }
    }
}

impl Reader for StdReader {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        let ret = match self.inner {
            TTY(ref mut tty) => {
                // Flush the task-local stdout so that weird issues like a
                // print!'d prompt not being shown until after the user hits
                // enter.
                flush();
                tty.read(buf)
            },
            File(ref mut file) => file.read(buf).map(|i| i as uint),
        };
        match ret {
            // When reading a piped stdin, libuv will return 0-length reads when
            // stdin reaches EOF. For pretty much all other streams it will
            // return an actual EOF error, but apparently for stdin it's a
            // little different. Hence, here we convert a 0 length read to an
            // end-of-file indicator so the caller knows to stop reading.
            Ok(0) => { Err(standard_error(EndOfFile)) }
            ret @ Ok(..) | ret @ Err(..) => ret,
        }
    }
}

/// Representation of a writer to a standard output stream
pub struct StdWriter {
    inner: StdSource
}

impl StdWriter {
    /// Gets the size of this output window, if possible. This is typically used
    /// when the writer is attached to something like a terminal, this is used
    /// to fetch the dimensions of the terminal.
    ///
    /// If successful, returns `Ok((width, height))`.
    ///
    /// # Error
    ///
    /// This function will return an error if the output stream is not actually
    /// connected to a TTY instance, or if querying the TTY instance fails.
    pub fn winsize(&mut self) -> IoResult<(int, int)> {
        match self.inner {
            TTY(ref mut tty) => tty.get_winsize(),
            File(..) => {
                Err(IoError {
                    kind: OtherIoError,
                    desc: "stream is not a tty",
                    detail: None,
                })
            }
        }
    }

    /// Controls whether this output stream is a "raw stream" or simply a normal
    /// stream.
    ///
    /// # Error
    ///
    /// This function will return an error if the output stream is not actually
    /// connected to a TTY instance, or if querying the TTY instance fails.
    pub fn set_raw(&mut self, raw: bool) -> IoResult<()> {
        match self.inner {
            TTY(ref mut tty) => tty.set_raw(raw),
            File(..) => {
                Err(IoError {
                    kind: OtherIoError,
                    desc: "stream is not a tty",
                    detail: None,
                })
            }
        }
    }

    /// Returns whether this stream is attached to a TTY instance or not.
    pub fn isatty(&self) -> bool {
        match self.inner {
            TTY(..) => true,
            File(..) => false,
        }
    }
}

impl Writer for StdWriter {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        match self.inner {
            TTY(ref mut tty) => tty.write(buf),
            File(ref mut file) => file.write(buf),
        }
    }
}

#[cfg(test)]
mod tests {
    iotest!(fn smoke() {
        // Just make sure we can acquire handles
        stdin();
        stdout();
        stderr();
    })

    iotest!(fn capture_stdout() {
        use io::{ChanReader, ChanWriter};

        let (tx, rx) = channel();
        let (mut r, w) = (ChanReader::new(rx), ChanWriter::new(tx));
        spawn(proc() {
            set_stdout(box w);
            println!("hello!");
        });
        assert_eq!(r.read_to_str().unwrap(), "hello!\n".to_owned());
    })

    iotest!(fn capture_stderr() {
        use io::{ChanReader, ChanWriter};

        let (tx, rx) = channel();
        let (mut r, w) = (ChanReader::new(rx), ChanWriter::new(tx));
        spawn(proc() {
            set_stderr(box w);
            fail!("my special message");
        });
        let s = r.read_to_str().unwrap();
        assert!(s.contains("my special message"));
    })
}
<|endoftext|>


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

//! Operations and constants for `uint`

use num;
use num::{CheckedAdd, CheckedSub, CheckedMul};
use option::{Option, Some, None};
use unstable::intrinsics;
use sys;

pub use self::generated::*;

uint_module!(uint, int, ::int::bits)

///
/// Divide two numbers, return the result, rounded up.
///
/// # Arguments
///
/// * x - an integer
/// * y - an integer distinct from 0u
///
/// # Return value
///
/// The smallest integer `q` such that `x/y <= q`.
///
pub fn div_ceil(x: uint, y: uint) -> uint {
    let div = x / y;
    if x % y == 0u { div }
    else { div + 1u }
}

///
/// Divide two numbers, return the result, rounded to the closest integer.
///
/// # Arguments
///
/// * x - an integer
/// * y - an integer distinct from 0u
///
/// # Return value
///
/// The integer `q` closest to `x/y`.
///
pub fn div_round(x: uint, y: uint) -> uint {
    let div = x / y;
    if x % y * 2u  < y { div }
    else { div + 1u }
}

///
/// Divide two numbers, return the result, rounded down.
///
/// Note: This is the same function as `div`.
///
/// # Arguments
///
/// * x - an integer
/// * y - an integer distinct from 0u
///
/// # Return value
///
/// The smallest integer `q` such that `x/y <= q`. This
/// is either `x/y` or `x/y + 1`.
///
pub fn div_floor(x: uint, y: uint) -> uint { return x / y; }

impl num::Times for uint {
    #[inline]
    ///
    /// A convenience form for basic repetition. Given a uint `x`,
    /// `do x.times { ... }` executes the given block x times.
    ///
    /// Equivalent to `for uint::range(0, x) |_| { ... }`.
    ///
    /// Not defined on all integer types to permit unambiguous
    /// use with integer literals of inferred integer-type as
    /// the self-value (eg. `do 100.times { ... }`).
    ///
    fn times(&self, it: &fn()) {
        let mut i = *self;
        while i > 0 {
            it();
            i -= 1;
        }
    }
}

/// Returns the smallest power of 2 greater than or equal to `n`
#[inline]
pub fn next_power_of_two(n: uint) -> uint {
    let halfbits: uint = sys::size_of::<uint>() * 4u;
    let mut tmp: uint = n - 1u;
    let mut shift: uint = 1u;
    while shift <= halfbits { tmp |= tmp >> shift; shift <<= 1u; }
    return tmp + 1u;
}

#[cfg(target_word_size = "32")]
impl CheckedAdd for uint {
    #[inline]
    fn checked_add(&self, v: &uint) -> Option<uint> {
        unsafe {
            let (x, y) = intrinsics::u32_add_with_overflow(*self as u32, *v as u32);
            if y { None } else { Some(x as uint) }
        }
    }
}

#[cfg(target_word_size = "64")]
impl CheckedAdd for uint {
    #[inline]
    fn checked_add(&self, v: &uint) -> Option<uint> {
        unsafe {
            let (x, y) = intrinsics::u64_add_with_overflow(*self as u64, *v as u64);
            if y { None } else { Some(x as uint) }
        }
    }
}

#[cfg(target_word_size = "32")]
impl CheckedSub for uint {
    #[inline]
    fn checked_sub(&self, v: &uint) -> Option<uint> {
        unsafe {
            let (x, y) = intrinsics::u32_sub_with_overflow(*self as u32, *v as u32);
            if y { None } else { Some(x as uint) }
        }
    }
}

#[cfg(target_word_size = "64")]
impl CheckedSub for uint {
    #[inline]
    fn checked_sub(&self, v: &uint) -> Option<uint> {
        unsafe {
            let (x, y) = intrinsics::u64_sub_with_overflow(*self as u64, *v as u64);
            if y { None } else { Some(x as uint) }
        }
    }
}

#[cfg(target_word_size = "32")]
impl CheckedMul for uint {
    #[inline]
    fn checked_mul(&self, v: &uint) -> Option<uint> {
        unsafe {
            let (x, y) = intrinsics::u32_mul_with_overflow(*self as u32, *v as u32);
            if y { None } else { Some(x as uint) }
        }
    }
}

#[cfg(target_word_size = "64")]
impl CheckedMul for uint {
    #[inline]
    fn checked_mul(&self, v: &uint) -> Option<uint> {
        unsafe {
            let (x, y) = intrinsics::u64_mul_with_overflow(*self as u64, *v as u64);
            if y { None } else { Some(x as uint) }
        }
    }
}

#[test]
fn test_next_power_of_two() {
    assert!((next_power_of_two(0u) == 0u));
    assert!((next_power_of_two(1u) == 1u));
    assert!((next_power_of_two(2u) == 2u));
    assert!((next_power_of_two(3u) == 4u));
    assert!((next_power_of_two(4u) == 4u));
    assert!((next_power_of_two(5u) == 8u));
    assert!((next_power_of_two(6u) == 8u));
    assert!((next_power_of_two(7u) == 8u));
    assert!((next_power_of_two(8u) == 8u));
    assert!((next_power_of_two(9u) == 16u));
    assert!((next_power_of_two(10u) == 16u));
    assert!((next_power_of_two(11u) == 16u));
    assert!((next_power_of_two(12u) == 16u));
    assert!((next_power_of_two(13u) == 16u));
    assert!((next_power_of_two(14u) == 16u));
    assert!((next_power_of_two(15u) == 16u));
    assert!((next_power_of_two(16u) == 16u));
    assert!((next_power_of_two(17u) == 32u));
    assert!((next_power_of_two(18u) == 32u));
    assert!((next_power_of_two(19u) == 32u));
    assert!((next_power_of_two(20u) == 32u));
    assert!((next_power_of_two(21u) == 32u));
    assert!((next_power_of_two(22u) == 32u));
    assert!((next_power_of_two(23u) == 32u));
    assert!((next_power_of_two(24u) == 32u));
    assert!((next_power_of_two(25u) == 32u));
    assert!((next_power_of_two(26u) == 32u));
    assert!((next_power_of_two(27u) == 32u));
    assert!((next_power_of_two(28u) == 32u));
    assert!((next_power_of_two(29u) == 32u));
    assert!((next_power_of_two(30u) == 32u));
    assert!((next_power_of_two(31u) == 32u));
    assert!((next_power_of_two(32u) == 32u));
    assert!((next_power_of_two(33u) == 64u));
    assert!((next_power_of_two(34u) == 64u));
    assert!((next_power_of_two(35u) == 64u));
    assert!((next_power_of_two(36u) == 64u));
    assert!((next_power_of_two(37u) == 64u));
    assert!((next_power_of_two(38u) == 64u));
    assert!((next_power_of_two(39u) == 64u));
}

#[test]
fn test_overflows() {
    use uint;
    assert!((uint::max_value > 0u));
    assert!((uint::min_value <= 0u));
    assert!((uint::min_value + uint::max_value + 1u == 0u));
}

#[test]
fn test_div() {
    assert!((div_floor(3u, 4u) == 0u));
    assert!((div_ceil(3u, 4u)  == 1u));
    assert!((div_round(3u, 4u) == 1u));
}

#[test]
pub fn test_times() {
    use num::Times;
    let ten = 10 as uint;
    let mut accum = 0;
    do ten.times { accum += 1; }
    assert!((accum == 10));
}
<commit_msg>std::num: Add uint::next_power_of_two_opt<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Operations and constants for `uint`

use num;
use num::{CheckedAdd, CheckedSub, CheckedMul};
use option::{Option, Some, None};
use unstable::intrinsics;
use sys;

pub use self::generated::*;

uint_module!(uint, int, ::int::bits)

///
/// Divide two numbers, return the result, rounded up.
///
/// # Arguments
///
/// * x - an integer
/// * y - an integer distinct from 0u
///
/// # Return value
///
/// The smallest integer `q` such that `x/y <= q`.
///
pub fn div_ceil(x: uint, y: uint) -> uint {
    let div = x / y;
    if x % y == 0u { div }
    else { div + 1u }
}

///
/// Divide two numbers, return the result, rounded to the closest integer.
///
/// # Arguments
///
/// * x - an integer
/// * y - an integer distinct from 0u
///
/// # Return value
///
/// The integer `q` closest to `x/y`.
///
pub fn div_round(x: uint, y: uint) -> uint {
    let div = x / y;
    if x % y * 2u  < y { div }
    else { div + 1u }
}

///
/// Divide two numbers, return the result, rounded down.
///
/// Note: This is the same function as `div`.
///
/// # Arguments
///
/// * x - an integer
/// * y - an integer distinct from 0u
///
/// # Return value
///
/// The smallest integer `q` such that `x/y <= q`. This
/// is either `x/y` or `x/y + 1`.
///
pub fn div_floor(x: uint, y: uint) -> uint { return x / y; }

impl num::Times for uint {
    #[inline]
    ///
    /// A convenience form for basic repetition. Given a uint `x`,
    /// `do x.times { ... }` executes the given block x times.
    ///
    /// Equivalent to `for uint::range(0, x) |_| { ... }`.
    ///
    /// Not defined on all integer types to permit unambiguous
    /// use with integer literals of inferred integer-type as
    /// the self-value (eg. `do 100.times { ... }`).
    ///
    fn times(&self, it: &fn()) {
        let mut i = *self;
        while i > 0 {
            it();
            i -= 1;
        }
    }
}

/// Returns the smallest power of 2 greater than or equal to `n`
#[inline]
pub fn next_power_of_two(n: uint) -> uint {
    let halfbits: uint = sys::size_of::<uint>() * 4u;
    let mut tmp: uint = n - 1u;
    let mut shift: uint = 1u;
    while shift <= halfbits { tmp |= tmp >> shift; shift <<= 1u; }
    tmp + 1u
}

/// Returns the smallest power of 2 greater than or equal to `n`
#[inline]
pub fn next_power_of_two_opt(n: uint) -> Option<uint> {
    let halfbits: uint = sys::size_of::<uint>() * 4u;
    let mut tmp: uint = n - 1u;
    let mut shift: uint = 1u;
    while shift <= halfbits { tmp |= tmp >> shift; shift <<= 1u; }
    tmp.checked_add(&1)
}

#[cfg(target_word_size = "32")]
impl CheckedAdd for uint {
    #[inline]
    fn checked_add(&self, v: &uint) -> Option<uint> {
        unsafe {
            let (x, y) = intrinsics::u32_add_with_overflow(*self as u32, *v as u32);
            if y { None } else { Some(x as uint) }
        }
    }
}

#[cfg(target_word_size = "64")]
impl CheckedAdd for uint {
    #[inline]
    fn checked_add(&self, v: &uint) -> Option<uint> {
        unsafe {
            let (x, y) = intrinsics::u64_add_with_overflow(*self as u64, *v as u64);
            if y { None } else { Some(x as uint) }
        }
    }
}

#[cfg(target_word_size = "32")]
impl CheckedSub for uint {
    #[inline]
    fn checked_sub(&self, v: &uint) -> Option<uint> {
        unsafe {
            let (x, y) = intrinsics::u32_sub_with_overflow(*self as u32, *v as u32);
            if y { None } else { Some(x as uint) }
        }
    }
}

#[cfg(target_word_size = "64")]
impl CheckedSub for uint {
    #[inline]
    fn checked_sub(&self, v: &uint) -> Option<uint> {
        unsafe {
            let (x, y) = intrinsics::u64_sub_with_overflow(*self as u64, *v as u64);
            if y { None } else { Some(x as uint) }
        }
    }
}

#[cfg(target_word_size = "32")]
impl CheckedMul for uint {
    #[inline]
    fn checked_mul(&self, v: &uint) -> Option<uint> {
        unsafe {
            let (x, y) = intrinsics::u32_mul_with_overflow(*self as u32, *v as u32);
            if y { None } else { Some(x as uint) }
        }
    }
}

#[cfg(target_word_size = "64")]
impl CheckedMul for uint {
    #[inline]
    fn checked_mul(&self, v: &uint) -> Option<uint> {
        unsafe {
            let (x, y) = intrinsics::u64_mul_with_overflow(*self as u64, *v as u64);
            if y { None } else { Some(x as uint) }
        }
    }
}

#[test]
fn test_next_power_of_two() {
    assert!((next_power_of_two(0u) == 0u));
    assert!((next_power_of_two(1u) == 1u));
    assert!((next_power_of_two(2u) == 2u));
    assert!((next_power_of_two(3u) == 4u));
    assert!((next_power_of_two(4u) == 4u));
    assert!((next_power_of_two(5u) == 8u));
    assert!((next_power_of_two(6u) == 8u));
    assert!((next_power_of_two(7u) == 8u));
    assert!((next_power_of_two(8u) == 8u));
    assert!((next_power_of_two(9u) == 16u));
    assert!((next_power_of_two(10u) == 16u));
    assert!((next_power_of_two(11u) == 16u));
    assert!((next_power_of_two(12u) == 16u));
    assert!((next_power_of_two(13u) == 16u));
    assert!((next_power_of_two(14u) == 16u));
    assert!((next_power_of_two(15u) == 16u));
    assert!((next_power_of_two(16u) == 16u));
    assert!((next_power_of_two(17u) == 32u));
    assert!((next_power_of_two(18u) == 32u));
    assert!((next_power_of_two(19u) == 32u));
    assert!((next_power_of_two(20u) == 32u));
    assert!((next_power_of_two(21u) == 32u));
    assert!((next_power_of_two(22u) == 32u));
    assert!((next_power_of_two(23u) == 32u));
    assert!((next_power_of_two(24u) == 32u));
    assert!((next_power_of_two(25u) == 32u));
    assert!((next_power_of_two(26u) == 32u));
    assert!((next_power_of_two(27u) == 32u));
    assert!((next_power_of_two(28u) == 32u));
    assert!((next_power_of_two(29u) == 32u));
    assert!((next_power_of_two(30u) == 32u));
    assert!((next_power_of_two(31u) == 32u));
    assert!((next_power_of_two(32u) == 32u));
    assert!((next_power_of_two(33u) == 64u));
    assert!((next_power_of_two(34u) == 64u));
    assert!((next_power_of_two(35u) == 64u));
    assert!((next_power_of_two(36u) == 64u));
    assert!((next_power_of_two(37u) == 64u));
    assert!((next_power_of_two(38u) == 64u));
    assert!((next_power_of_two(39u) == 64u));
}

#[test]
fn test_overflows() {
    use uint;
    assert!((uint::max_value > 0u));
    assert!((uint::min_value <= 0u));
    assert!((uint::min_value + uint::max_value + 1u == 0u));
}

#[test]
fn test_div() {
    assert!((div_floor(3u, 4u) == 0u));
    assert!((div_ceil(3u, 4u)  == 1u));
    assert!((div_round(3u, 4u) == 1u));
}

#[test]
pub fn test_times() {
    use num::Times;
    let ten = 10 as uint;
    let mut accum = 0;
    do ten.times { accum += 1; }
    assert!((accum == 10));
}
<|endoftext|>


<commit_before>//! A Module for accessing Blizzard's WoW API.
//! The exposed functionality of this module has been structured
//! around the particular needs of blood-money: Not all fields are
//! represented and it's probably not generally useful.
//! TODO: Add support for locales.
extern crate hyper;
extern crate serde_json;

use std::collections::BTreeMap;
use std::io::Read;
use std::time::Duration;

use hyper::client::{Client, Response};
use regex::bytes::Regex;
use serde::de::Deserialize;
use thread_throttler::ThreadThrottler;

/// The content we care about in the realm status response.
#[derive(Debug, Serialize, Deserialize)]
pub struct RealmInfo {
    pub name: String,
    pub slug: String,
    pub connected_realms: Vec<String>,
}

/// Content we care about in an item info response.
#[derive(Debug, Deserialize)]
pub struct ItemInfo {
    pub id: u64,
    pub name: String,
    pub icon: String,
}

/// Represents the reply from blizzard's auction data urls.
#[derive(Debug, Deserialize)]
struct AuctionListingsReply {
    realms: Vec<BTreeMap<String, String>>,  // Can't re-use RealmInfo because no connected_realms.
    auctions: Vec<AuctionListing>,
}

/// Represents the JSON reply from the auction data status endpoint.
#[derive(Debug, Deserialize)]
#[allow(non_snake_case)]
struct AuctionDataPointer {
    url: String,
    lastModified: u64,
}

#[derive(Debug, Deserialize)]
struct AuctionDataReply {
    files: Vec<AuctionDataPointer>, // Will always be 1 element.
}

/// The fields we care about in blizzard's auction reply.
#[derive(Debug, Deserialize)]
pub struct AuctionListing {
    pub item: u64,
    pub buyout: u64,
    pub quantity: u64,
}

#[derive(Clone, Copy, PartialEq)]
pub enum Region {
    US,
    EU,
}

pub struct BattleNetApiClient<'a> {
    pub token: String,
    client: Client,
    tt: ThreadThrottler,
    api_host: &'a str,
    api_locale: &'a str,
}

impl<'a> BattleNetApiClient<'a> {
    pub fn new(token: &str, region: Region) -> BattleNetApiClient {
        BattleNetApiClient {
            token: token.to_owned(),
            client: Client::new(),
            tt: ThreadThrottler::new(100, Duration::new(1, 0)),
            api_host: match region {
                Region::US => "us.api.battle.net",
                Region::EU => "eu.api.battle.net",
            },
            api_locale: match region {
                Region::US => "en_US",
                Region::EU => "en_GB",
            },
        }
    }

    /// Try to retrieve something from the Blizzard API. Will retry indefinitely.
    /// Returns the body as a String.
    /// `task` will be used to generate error messages.
    fn make_blizzard_api_call(&self, url: &str, task: &str) -> String {
        let mut s = String::new();
        let mut retries = 0;

        loop {
            let mut res: Response;
            retries += 1;

            self.tt.pass_through_or_block();
            match self.client.get(url).send() {
                Ok(r) => res = r,
                Err(e) => {
                    println!("Error downloading {}: {}. Retry {}.", task, e, retries);
                    continue;
                },
            }
            // TODO: 404 should really be handled differently here. Maybe make this return a Result<T>?
            // That would let us account for unrecoverable errors.
            if res.status != hyper::Ok {
                println!("Error downloading {}: {}. Retry {}.", task, res.status, retries);
                continue;
            }
            match res.read_to_string(&mut s) {
                Ok(_) => (),
                Err(e) => {
                    println!("Failed to process {}: {}. Retry {}.", task, e, retries);
                    continue;
                },
            }
            return s;
        }
    }

    /// Downloads a list of realms from the Blizzard API.
    /// Panics if the json response is malformed.
    pub fn get_realms(&self) -> Vec<RealmInfo> {
        let mut realm_data: BTreeMap<String, Vec<RealmInfo>> = serde_json::from_str(&self.make_blizzard_api_call(
            &format!("https://{}/wow/realm/status?locale={}&apikey={}", self.api_host, self.api_locale, self.token), "realm status")
        ).unwrap();
        realm_data.remove("realms").expect("Malformed realm response.")
    }

    /// Downloads the auction listings for the specified realm, or None if the listings haven't
    /// been updated since `cutoff` or if the json response is illformed.
    pub fn get_auction_listings(&self, realm_slug: &str, cutoff: u64) -> Option<(u64, Vec<AuctionListing>)> {
        let mut auction_data_reply: AuctionDataReply;
        match serde_json::from_str(&self.make_blizzard_api_call(
            &format!("https://{}/wow/auction/data/{}?locale={}&apikey={}", self.api_host, realm_slug, self.api_locale, self.token),
            &format!("auction data for {}", realm_slug)))
        {
            Ok(reply) => auction_data_reply = reply,
            Err(e) => {
                println!("Bad json in auction pointer reply for {}: {}", realm_slug, e);
                return None;
            },
        }
        let auction_data_pointer = auction_data_reply.files.pop().unwrap();
        if auction_data_pointer.lastModified <= cutoff {
            return None;
        }

        let mut auction_data_str = self.make_blizzard_api_call(&auction_data_pointer.url, &format!("auction listings for {}", realm_slug));
        // Auction data strings are especially problematic and often contain numerous invalid bytes in the "owner" and
        // "ownerRealm" fields. Unfortunately, String::from_utf8_lossy() doesn't appear sufficient to deal with this
        // so we use the heavy handed approach of a regex to rewrite these fields.
        // TODO: Make this a lazy_static!.
        let sanitize_re = Regex::new("\"owner\":\".*?\",\"ownerRealm\":\".*?\",\"bid").unwrap();
        auction_data_str = String::from_utf8(
            sanitize_re.replace_all(auction_data_str.as_bytes(),
                                    &b"\"owner\":\"_\",\"ownerRealm\":\"_\",\"bid"[..])
            ).unwrap();
        match serde_json::from_str::<AuctionListingsReply>(&auction_data_str) {
            Ok(auction_listings_data) => Some((auction_data_pointer.lastModified, auction_listings_data.auctions)),
            Err(e) => {
                println!("Error decoding json auction listings for {}: {}", realm_slug, e);
                None
            },
        }
    }

    /// Helpler function to process a vec of RealmInfo's into vec's of slugs for
    /// connected realms. Connected realms share an auction house.
    pub fn process_connected_realms(realm_infos: &Vec<RealmInfo>) -> Vec<Vec<String>> {
        let mut realm_sets: Vec<Vec<String>> = realm_infos.into_iter().map(|r|
            r.connected_realms.clone()
        ).collect();

        // This dedup logic relies on the ordering within a connected realms list being the same
        // for all realms in the list.
        realm_sets.sort_by(|a, b| a.iter().next().unwrap().cmp(b.iter().next().unwrap()));
        realm_sets.dedup();
        return realm_sets;
    }

    /// Get info on an item. Panics on a malformed json response.
    pub fn get_item_info(&self, id: u64) -> ItemInfo {
        serde_json::from_str(&self.make_blizzard_api_call(
            &format!("https://{}/wow/item/{}?locale={}&apikey={}", self.api_host, id, self.api_locale, self.token), "item info")
        ).unwrap()
    }
}
<commit_msg>Add a client timeout on hyper calls<commit_after>//! A Module for accessing Blizzard's WoW API.
//! The exposed functionality of this module has been structured
//! around the particular needs of blood-money: Not all fields are
//! represented and it's probably not generally useful.
//! TODO: Add support for locales.
extern crate hyper;
extern crate serde_json;

use std::collections::BTreeMap;
use std::io::Read;
use std::time::Duration;

use hyper::client::{Client, Response};
use regex::bytes::Regex;
use serde::de::Deserialize;
use thread_throttler::ThreadThrottler;

/// The content we care about in the realm status response.
#[derive(Debug, Serialize, Deserialize)]
pub struct RealmInfo {
    pub name: String,
    pub slug: String,
    pub connected_realms: Vec<String>,
}

/// Content we care about in an item info response.
#[derive(Debug, Deserialize)]
pub struct ItemInfo {
    pub id: u64,
    pub name: String,
    pub icon: String,
}

/// Represents the reply from blizzard's auction data urls.
#[derive(Debug, Deserialize)]
struct AuctionListingsReply {
    realms: Vec<BTreeMap<String, String>>,  // Can't re-use RealmInfo because no connected_realms.
    auctions: Vec<AuctionListing>,
}

/// Represents the JSON reply from the auction data status endpoint.
#[derive(Debug, Deserialize)]
#[allow(non_snake_case)]
struct AuctionDataPointer {
    url: String,
    lastModified: u64,
}

#[derive(Debug, Deserialize)]
struct AuctionDataReply {
    files: Vec<AuctionDataPointer>, // Will always be 1 element.
}

/// The fields we care about in blizzard's auction reply.
#[derive(Debug, Deserialize)]
pub struct AuctionListing {
    pub item: u64,
    pub buyout: u64,
    pub quantity: u64,
}

#[derive(Clone, Copy, PartialEq)]
pub enum Region {
    US,
    EU,
}

pub struct BattleNetApiClient<'a> {
    pub token: String,
    client: Client,
    tt: ThreadThrottler,
    api_host: &'a str,
    api_locale: &'a str,
}

impl<'a> BattleNetApiClient<'a> {
    pub fn new(token: &str, region: Region) -> BattleNetApiClient {
        let mut hyper_client = Client::new();
        hyper_client.set_read_timeout(Some(Duration::from_secs(300)));

        BattleNetApiClient {
            token: token.to_owned(),
            client: hyper_client,
            tt: ThreadThrottler::new(100, Duration::new(1, 0)),
            api_host: match region {
                Region::US => "us.api.battle.net",
                Region::EU => "eu.api.battle.net",
            },
            api_locale: match region {
                Region::US => "en_US",
                Region::EU => "en_GB",
            },
        }
    }

    /// Try to retrieve something from the Blizzard API. Will retry indefinitely.
    /// Returns the body as a String.
    /// `task` will be used to generate error messages.
    fn make_blizzard_api_call(&self, url: &str, task: &str) -> String {
        let mut s = String::new();
        let mut retries = 0;

        loop {
            let mut res: Response;
            retries += 1;

            self.tt.pass_through_or_block();
            match self.client.get(url).send() {
                Ok(r) => res = r,
                Err(e) => {
                    println!("Error downloading {}: {}. Retry {}.", task, e, retries);
                    continue;
                },
            }
            // TODO: 404 should really be handled differently here. Maybe make this return a Result<T>?
            // That would let us account for unrecoverable errors.
            if res.status != hyper::Ok {
                println!("Error downloading {}: {}. Retry {}.", task, res.status, retries);
                continue;
            }
            match res.read_to_string(&mut s) {
                Ok(_) => (),
                Err(e) => {
                    println!("Failed to process {}: {}. Retry {}.", task, e, retries);
                    continue;
                },
            }
            return s;
        }
    }

    /// Downloads a list of realms from the Blizzard API.
    /// Panics if the json response is malformed.
    pub fn get_realms(&self) -> Vec<RealmInfo> {
        let mut realm_data: BTreeMap<String, Vec<RealmInfo>> = serde_json::from_str(&self.make_blizzard_api_call(
            &format!("https://{}/wow/realm/status?locale={}&apikey={}", self.api_host, self.api_locale, self.token), "realm status")
        ).unwrap();
        realm_data.remove("realms").expect("Malformed realm response.")
    }

    /// Downloads the auction listings for the specified realm, or None if the listings haven't
    /// been updated since `cutoff` or if the json response is illformed.
    pub fn get_auction_listings(&self, realm_slug: &str, cutoff: u64) -> Option<(u64, Vec<AuctionListing>)> {
        let mut auction_data_reply: AuctionDataReply;
        match serde_json::from_str(&self.make_blizzard_api_call(
            &format!("https://{}/wow/auction/data/{}?locale={}&apikey={}", self.api_host, realm_slug, self.api_locale, self.token),
            &format!("auction data for {}", realm_slug)))
        {
            Ok(reply) => auction_data_reply = reply,
            Err(e) => {
                println!("Bad json in auction pointer reply for {}: {}", realm_slug, e);
                return None;
            },
        }
        let auction_data_pointer = auction_data_reply.files.pop().unwrap();
        if auction_data_pointer.lastModified <= cutoff {
            return None;
        }

        let mut auction_data_str = self.make_blizzard_api_call(&auction_data_pointer.url, &format!("auction listings for {}", realm_slug));
        // Auction data strings are especially problematic and often contain numerous invalid bytes in the "owner" and
        // "ownerRealm" fields. Unfortunately, String::from_utf8_lossy() doesn't appear sufficient to deal with this
        // so we use the heavy handed approach of a regex to rewrite these fields.
        // TODO: Make this a lazy_static!.
        let sanitize_re = Regex::new("\"owner\":\".*?\",\"ownerRealm\":\".*?\",\"bid").unwrap();
        auction_data_str = String::from_utf8(
            sanitize_re.replace_all(auction_data_str.as_bytes(),
                                    &b"\"owner\":\"_\",\"ownerRealm\":\"_\",\"bid"[..])
            ).unwrap();
        match serde_json::from_str::<AuctionListingsReply>(&auction_data_str) {
            Ok(auction_listings_data) => Some((auction_data_pointer.lastModified, auction_listings_data.auctions)),
            Err(e) => {
                println!("Error decoding json auction listings for {}: {}", realm_slug, e);
                None
            },
        }
    }

    /// Helpler function to process a vec of RealmInfo's into vec's of slugs for
    /// connected realms. Connected realms share an auction house.
    pub fn process_connected_realms(realm_infos: &Vec<RealmInfo>) -> Vec<Vec<String>> {
        let mut realm_sets: Vec<Vec<String>> = realm_infos.into_iter().map(|r|
            r.connected_realms.clone()
        ).collect();

        // This dedup logic relies on the ordering within a connected realms list being the same
        // for all realms in the list.
        realm_sets.sort_by(|a, b| a.iter().next().unwrap().cmp(b.iter().next().unwrap()));
        realm_sets.dedup();
        return realm_sets;
    }

    /// Get info on an item. Panics on a malformed json response.
    pub fn get_item_info(&self, id: u64) -> ItemInfo {
        serde_json::from_str(&self.make_blizzard_api_call(
            &format!("https://{}/wow/item/{}?locale={}&apikey={}", self.api_host, id, self.api_locale, self.token), "item info")
        ).unwrap()
    }
}
<|endoftext|>


<commit_before>use kay::{ID, Recipient, Actor, Individual, Swarm, ActorSystem, Fate, CreateWith};
use descartes::{Band, Curve, Into2d};
use ::core::geometry::{CPath, AnyShape};

use super::{SelectableStrokeRef, CurrentPlan, PlanControl};

#[derive(Actor, Compact, Clone)]
pub struct LaneStrokeSelectable{
    _id: ID,
    stroke_ref: SelectableStrokeRef,
    path: CPath
}

impl LaneStrokeSelectable{
    pub fn new(stroke_ref: SelectableStrokeRef, path: CPath) -> Self {
        LaneStrokeSelectable{
            _id: ID::invalid(),
            stroke_ref: stroke_ref,
            path: path
        }
    }
}

use super::AddToUI;
use ::core::ui::Add;

impl Recipient<AddToUI> for LaneStrokeSelectable {
    fn receive(&mut self, msg: &AddToUI) -> Fate {match *msg{
        AddToUI => {
            ::core::ui::UserInterface::id() << Add::Interactable3d(
                self.id(),
                AnyShape::Band(Band::new(self.path.clone(), 2.5)),
                1
            );
            Fate::Live
        }
    }}
}

use super::ClearSelectables;
use ::core::ui::Remove;

impl Recipient<ClearSelectables> for LaneStrokeSelectable {
    fn receive(&mut self, msg: &ClearSelectables) -> Fate {match *msg{
        ClearSelectables => {
            ::core::ui::UserInterface::id() << Remove::Interactable3d(self.id());
            Fate::Die
        }
    }}
}

use ::core::ui::Event3d;

impl Recipient<Event3d> for LaneStrokeSelectable {
    fn receive(&mut self, msg: &Event3d) -> Fate {match *msg{
        Event3d::DragOngoing{from, to} => {
            if let (Some(selection_start), Some(selection_end)) =
            (self.path.project(from.into_2d()), self.path.project(to.into_2d())) {
                CurrentPlan::id() << PlanControl::Select(self.stroke_ref, selection_start, selection_end);
            }
            Fate::Live
        },
        _ => Fate::Live
    }}
}

pub fn setup(system: &mut ActorSystem) {
    system.add_individual(Swarm::<LaneStrokeSelectable>::new());
    system.add_inbox::<CreateWith<LaneStrokeSelectable, AddToUI>, Swarm<LaneStrokeSelectable>>();
    system.add_inbox::<ClearSelectables, Swarm<LaneStrokeSelectable>>();
    system.add_inbox::<Event3d, Swarm<LaneStrokeSelectable>>();
}<commit_msg>Make selecting backwards possible #20<commit_after>use kay::{ID, Recipient, Actor, Individual, Swarm, ActorSystem, Fate, CreateWith};
use descartes::{Band, Curve, Into2d};
use ::core::geometry::{CPath, AnyShape};

use super::{SelectableStrokeRef, CurrentPlan, PlanControl};

#[derive(Actor, Compact, Clone)]
pub struct LaneStrokeSelectable{
    _id: ID,
    stroke_ref: SelectableStrokeRef,
    path: CPath
}

impl LaneStrokeSelectable{
    pub fn new(stroke_ref: SelectableStrokeRef, path: CPath) -> Self {
        LaneStrokeSelectable{
            _id: ID::invalid(),
            stroke_ref: stroke_ref,
            path: path
        }
    }
}

use super::AddToUI;
use ::core::ui::Add;

impl Recipient<AddToUI> for LaneStrokeSelectable {
    fn receive(&mut self, msg: &AddToUI) -> Fate {match *msg{
        AddToUI => {
            ::core::ui::UserInterface::id() << Add::Interactable3d(
                self.id(),
                AnyShape::Band(Band::new(self.path.clone(), 2.5)),
                1
            );
            Fate::Live
        }
    }}
}

use super::ClearSelectables;
use ::core::ui::Remove;

impl Recipient<ClearSelectables> for LaneStrokeSelectable {
    fn receive(&mut self, msg: &ClearSelectables) -> Fate {match *msg{
        ClearSelectables => {
            ::core::ui::UserInterface::id() << Remove::Interactable3d(self.id());
            Fate::Die
        }
    }}
}

use ::core::ui::Event3d;

impl Recipient<Event3d> for LaneStrokeSelectable {
    fn receive(&mut self, msg: &Event3d) -> Fate {match *msg{
        Event3d::DragOngoing{from, to} => {
            if let (Some(selection_start), Some(selection_end)) =
            (self.path.project(from.into_2d()), self.path.project(to.into_2d())) {
                CurrentPlan::id() << PlanControl::Select(
                    self.stroke_ref,
                    selection_start.min(selection_end),
                    selection_end.max(selection_start)
                );
            }
            Fate::Live
        },
        _ => Fate::Live
    }}
}

pub fn setup(system: &mut ActorSystem) {
    system.add_individual(Swarm::<LaneStrokeSelectable>::new());
    system.add_inbox::<CreateWith<LaneStrokeSelectable, AddToUI>, Swarm<LaneStrokeSelectable>>();
    system.add_inbox::<ClearSelectables, Swarm<LaneStrokeSelectable>>();
    system.add_inbox::<Event3d, Swarm<LaneStrokeSelectable>>();
}<|endoftext|>


<commit_before>#![feature(globs)]

extern crate graphics;
extern crate piston;
// extern crate sdl2_game_window;
extern crate glfw_game_window;

// use Window = sdl2_game_window::GameWindowSDL2;
use Window = glfw_game_window::GameWindowGLFW;
use piston::keyboard;
use piston::input;
use piston::{
    Input,
    Render,
    Update
};

pub struct App {
    capture_cursor: bool
}

impl App {
    /// Creates a new application.
    pub fn new() -> App {
        App {
            capture_cursor: false
        }
    }

    fn key_press<W: piston::GameWindow>(
        &mut self,
        window: &mut W,
        args: &input::KeyPressArgs
    ) {
        if args.key == keyboard::C {
            println!("Turned capture cursor on");
            self.capture_cursor = !self.capture_cursor;

            window.capture_cursor(self.capture_cursor);
        }

        println!("Pressed keyboard key '{}'", args.key);
    }

    fn key_release(
        &mut self,
        args: &input::KeyReleaseArgs
    ) {
        println!("Released keyboard key '{}'", args.key);
    }

    fn mouse_move(
        &mut self,
        args: &input::MouseMoveArgs
    ) {
        println!("Mouse moved '{} {}'", args.x, args.y);
    }

    fn mouse_relative_move(
        &mut self,
        args: &input::MouseRelativeMoveArgs
    ) {
        println!("Relative mouse moved '{} {}'", args.dx, args.dy);
    }

    fn mouse_press(
        &mut self,
        args: &input::MousePressArgs
    ) {
        println!("Pressed mouse button '{}'", args.button);
    }

    fn mouse_release(
        &mut self,
        args: &input::MouseReleaseArgs
    ) {
        println!("Released mouse button '{}'", args.button);
    }

    fn mouse_scroll(
        &mut self,
        args: &input::MouseScrollArgs
    ) {
        println!("Scrolled mouse '{}, {}'", args.x, args.y);
    }
}

fn main() {
    let mut window = Window::new(
        piston::shader_version::opengl::OpenGL_3_2,
        piston::GameWindowSettings {
            title: "Keycode".to_string(),
            size: [300, 300],
            fullscreen: false,
            exit_on_esc: true,
        }
    );

    println!("Press C to turn capture cursor on/off");

    let mut app = App::new();
    let game_iter_settings = piston::GameIteratorSettings {
            updates_per_second: 120,
            max_frames_per_second: 60,
        };
    for e in piston::GameIterator::new(&mut window, &game_iter_settings) {
        match e {
            Input(input::KeyPress(args)) => app.key_press(&mut window, &args),
            Input(input::KeyRelease(args)) => app.key_release(&args),
            Input(input::MousePress(args)) => app.mouse_press(&args),
            Input(input::MouseRelease(args)) => app.mouse_release(&args),
            Input(input::MouseMove(args)) => app.mouse_move(&args),
            Input(input::MouseScroll(args)) => app.mouse_scroll(&args),
            Input(input::MouseRelativeMove(args)) => app.mouse_relative_move(&args),
            Render(_) => {},
            Update(_) => {},
        }
    }
}

<commit_msg>Updated to latest Piston<commit_after>#![feature(globs)]

extern crate graphics;
extern crate piston;
// extern crate sdl2_game_window;
extern crate glfw_game_window;

// use Window = sdl2_game_window::GameWindowSDL2;
use Window = glfw_game_window::GameWindowGLFW;
use piston::input::keyboard;
use piston::input;
use piston::{
    Input,
    Render,
    Update
};

pub struct App {
    capture_cursor: bool
}

impl App {
    /// Creates a new application.
    pub fn new() -> App {
        App {
            capture_cursor: false
        }
    }

    fn key_press<W: piston::GameWindow>(
        &mut self,
        window: &mut W,
        args: &input::KeyPressArgs
    ) {
        if args.key == keyboard::C {
            println!("Turned capture cursor on");
            self.capture_cursor = !self.capture_cursor;

            window.capture_cursor(self.capture_cursor);
        }

        println!("Pressed keyboard key '{}'", args.key);
    }

    fn key_release(
        &mut self,
        args: &input::KeyReleaseArgs
    ) {
        println!("Released keyboard key '{}'", args.key);
    }

    fn mouse_move(
        &mut self,
        args: &input::MouseMoveArgs
    ) {
        println!("Mouse moved '{} {}'", args.x, args.y);
    }

    fn mouse_relative_move(
        &mut self,
        args: &input::MouseRelativeMoveArgs
    ) {
        println!("Relative mouse moved '{} {}'", args.dx, args.dy);
    }

    fn mouse_press(
        &mut self,
        args: &input::MousePressArgs
    ) {
        println!("Pressed mouse button '{}'", args.button);
    }

    fn mouse_release(
        &mut self,
        args: &input::MouseReleaseArgs
    ) {
        println!("Released mouse button '{}'", args.button);
    }

    fn mouse_scroll(
        &mut self,
        args: &input::MouseScrollArgs
    ) {
        println!("Scrolled mouse '{}, {}'", args.x, args.y);
    }
}

fn main() {
    let mut window = Window::new(
        piston::shader_version::opengl::OpenGL_3_2,
        piston::GameWindowSettings {
            title: "Keycode".to_string(),
            size: [300, 300],
            fullscreen: false,
            exit_on_esc: true,
        }
    );

    println!("Press C to turn capture cursor on/off");

    let mut app = App::new();
    let game_iter_settings = piston::GameIteratorSettings {
            updates_per_second: 120,
            max_frames_per_second: 60,
        };
    for e in piston::GameIterator::new(&mut window, &game_iter_settings) {
        match e {
            Input(input::KeyPress(args)) => app.key_press(&mut window, &args),
            Input(input::KeyRelease(args)) => app.key_release(&args),
            Input(input::MousePress(args)) => app.mouse_press(&args),
            Input(input::MouseRelease(args)) => app.mouse_release(&args),
            Input(input::MouseMove(args)) => app.mouse_move(&args),
            Input(input::MouseScroll(args)) => app.mouse_scroll(&args),
            Input(input::MouseRelativeMove(args)) => app.mouse_relative_move(&args),
            Render(_) => {},
            Update(_) => {},
        }
    }
}

<|endoftext|>


<commit_before>use std::collections::VecDeque;

use math::{self, FScalar};
use super::primitive::{Polygon, Polygonal, Triangle, Quad};

pub trait Interpolate: math::Interpolate<FScalar> {}

impl<T> Interpolate for T where T: math::Interpolate<FScalar> {}

pub trait PolygonalExt<T>: Polygonal<T>
    where T: Clone + Interpolate
{
    fn into_subdivisions<F>(self, n: usize, f: F) where F: FnMut(Polygon<T>);
}

pub trait QuadExt<T>
    where T: Clone + Interpolate
{
    fn into_tetrahedrons<F>(self, f: F) where F: FnMut(Triangle<T>);
}

impl<T> PolygonalExt<T> for Triangle<T>
    where T: Clone + Interpolate
{
    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn into_subdivisions<F>(self, n: usize, mut f: F)
        where F: FnMut(Polygon<T>)
    {
        for triangle in n_map_polygon(n, self, |triangle| {
            let Triangle { a, b, c } = triangle;
            let ac = a.midpoint(&c);
            vec![Triangle::new(b.clone(), ac.clone(), a),
                 Triangle::new(c, ac, b)]
        }) {
            f(Polygon::Triangle(triangle));
        }
    }
}

impl<T> PolygonalExt<T> for Quad<T>
    where T: Clone + Interpolate
{
    fn into_subdivisions<F>(self, n: usize, mut f: F)
        where F: FnMut(Polygon<T>)
    {
        for quad in n_map_polygon(n, self, |quad| {
            let Quad { a, b, c, d } = quad;
            let ab = a.midpoint(&b);
            let bc = b.midpoint(&c);
            let cd = c.midpoint(&d);
            let da = d.midpoint(&a);
            let ac = a.midpoint(&c); // Diagonal.
            vec![Quad::new(a, ab.clone(), ac.clone(), da.clone()),
                 Quad::new(ab, b, bc.clone(), ac.clone()),
                 Quad::new(ac.clone(), bc, c, cd.clone()),
                 Quad::new(da, ac, cd, d)]
        }) {
            f(Polygon::Quad(quad));
        }
    }
}

impl<T> QuadExt<T> for Quad<T>
    where T: Clone + Interpolate
{
    fn into_tetrahedrons<F>(self, mut f: F)
        where F: FnMut(Triangle<T>)
    {
        let Quad { a, b, c, d } = self;
        let ac = a.midpoint(&c); // Diagonal.
        f(Triangle::new(a.clone(), b.clone(), ac.clone()));
        f(Triangle::new(b, c.clone(), ac.clone()));
        f(Triangle::new(c, d.clone(), ac.clone()));
        f(Triangle::new(d, a, ac));
    }
}

impl<T> PolygonalExt<T> for Polygon<T>
    where T: Clone + Interpolate
{
    fn into_subdivisions<F>(self, n: usize, f: F)
        where F: FnMut(Polygon<T>)
    {
        match self {
            Polygon::Triangle(triangle) => triangle.into_subdivisions(n, f),
            Polygon::Quad(quad) => quad.into_subdivisions(n, f),
        }
    }
}

pub trait TessellatePolygon<T>: Sized {
    fn subdivide(self, n: usize) -> SubdivisionIter<Self, T>;
}

impl TessellatePolygon<T> for I
    where I: Iterator<Item = P>,
          T: Clone + Interpolate,
          P: PolygonalExt<T>
{
    fn subdivide(self, n: usize) -> SubdivisionIter<Self, T> {
        SubdivisionIter::new(self, n)
    }
}

pub struct SubdivisionIter {
    polygons: I,
    subdivisions: VecDeque<Polygon<T>>,
    n: usize,
}

impl SubdivisionIter {
    fn new(polygons: I, n: usize) -> Self {
        SubdivisionIter {
            polygons: polygons,
            subdivisions: VecDeque::new(),
            n: n,
        }
    }
}

impl Iterator for SubdivisionIter
    where I: Iterator<Item = P>,
          T: Clone + Interpolate,
          P: PolygonalExt<T>
{
    type Item = Polygon<T>;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if let Some(subdivision) = self.subdivisions.pop_front() {
                return Some(subdivision);
            }
            if let Some(polygon) = self.polygons.next() {
                polygon.into_subdivisions(self.n, |polygon| self.subdivisions.push_back(polygon))
            }
            else {
                return None;
            }
        }
    }
}

pub trait TessellateQuad<T>: Sized {
    fn tetrahedrons(self) -> TetrahedronIter<Self, T>;
}

impl TessellateQuad<T> for I
    where I: Iterator<Item = Quad<T>>
{
    fn tetrahedrons(self) -> TetrahedronIter<Self, T> {
        TetrahedronIter::new(self)
    }
}

pub struct TetrahedronIter {
    quads: I,
    triangles: VecDeque<Triangle<T>>,
}

impl TetrahedronIter {
    fn new(quads: I) -> Self {
        TetrahedronIter {
            quads: quads,
            triangles: VecDeque::new(),
        }
    }
}

impl Iterator for TetrahedronIter
    where I: Iterator<Item = Quad<T>>,
          T: Clone + Interpolate
{
    type Item = Triangle<T>;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if let Some(triangle) = self.triangles.pop_front() {
                return Some(triangle);
            }
            if let Some(quad) = self.quads.next() {
                quad.into_tetrahedrons(|triangle| self.triangles.push_back(triangle))
            }
            else {
                return None;
            }
        }
    }
}

fn n_map_polygon<T, P, F>(n: usize, polygon: P, f: F) -> Vec

    where P: Polygonal<T>,
          F: Fn(P) -> Vec

{
    let mut queued = vec![];
    let mut transformed = vec![polygon];
    for _ in 0..n {
        queued.extend(transformed.drain(..));
        while let Some(polygon) = queued.pop() {
            transformed.extend(f(polygon));
        }
    }
    transformed
}
<commit_msg>Replace tessellation iterators with `Tessellate`.<commit_after>use std::collections::VecDeque;
use std::iter::IntoIterator;
use std::marker::PhantomData;

use math::{self, FScalar};
use super::primitive::{Polygon, Polygonal, Triangle, Quad};

pub struct Tessellate
    where D: Copy,
          F: Fn(P, D) -> R,
          R: IntoIterator<Item = Q>
{
    source: I,
    sink: VecDeque<Q>,
    parameter: D,
    f: F,
    phantom: PhantomData<(P, R)>,
}

impl Tessellate
    where D: Copy,
          F: Fn(P, D) -> R,
          R: IntoIterator<Item = Q>
{
    pub(super) fn new(source: I, parameter: D, f: F) -> Self {
        Tessellate {
            source: source,
            sink: VecDeque::new(),
            parameter: parameter,
            f: f,
            phantom: PhantomData,
        }
    }
}

impl Iterator for Tessellate
    where I: Iterator<Item = P>,
          D: Copy,
          F: Fn(P, D) -> R,
          R: IntoIterator<Item = Q>
{
    type Item = Q;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if let Some(polygon) = self.sink.pop_front() {
                return Some(polygon);
            }
            if let Some(polygon) = self.source.next() {
                self.sink.extend((self.f)(polygon, self.parameter));
            }
            else {
                return None;
            }
        }
    }
}

pub trait Interpolate: math::Interpolate<FScalar> {}

impl<T> Interpolate for T where T: math::Interpolate<FScalar> {}

pub trait PolygonalExt<T>: Polygonal<T>
    where T: Clone + Interpolate
{
    fn into_subdivisions<F>(self, n: usize, f: F) where F: FnMut(Polygon<T>);
}

pub trait QuadExt<T>
    where T: Clone + Interpolate
{
    fn into_tetrahedrons<F>(self, f: F) where F: FnMut(Triangle<T>);
}

impl<T> PolygonalExt<T> for Triangle<T>
    where T: Clone + Interpolate
{
    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn into_subdivisions<F>(self, n: usize, mut f: F)
        where F: FnMut(Polygon<T>)
    {
        for triangle in n_map_polygon(n, self, |triangle| {
            let Triangle { a, b, c } = triangle;
            let ac = a.midpoint(&c);
            vec![Triangle::new(b.clone(), ac.clone(), a),
                 Triangle::new(c, ac, b)]
        }) {
            f(Polygon::Triangle(triangle));
        }
    }
}

impl<T> PolygonalExt<T> for Quad<T>
    where T: Clone + Interpolate
{
    fn into_subdivisions<F>(self, n: usize, mut f: F)
        where F: FnMut(Polygon<T>)
    {
        for quad in n_map_polygon(n, self, |quad| {
            let Quad { a, b, c, d } = quad;
            let ab = a.midpoint(&b);
            let bc = b.midpoint(&c);
            let cd = c.midpoint(&d);
            let da = d.midpoint(&a);
            let ac = a.midpoint(&c); // Diagonal.
            vec![Quad::new(a, ab.clone(), ac.clone(), da.clone()),
                 Quad::new(ab, b, bc.clone(), ac.clone()),
                 Quad::new(ac.clone(), bc, c, cd.clone()),
                 Quad::new(da, ac, cd, d)]
        }) {
            f(Polygon::Quad(quad));
        }
    }
}

impl<T> QuadExt<T> for Quad<T>
    where T: Clone + Interpolate
{
    fn into_tetrahedrons<F>(self, mut f: F)
        where F: FnMut(Triangle<T>)
    {
        let Quad { a, b, c, d } = self;
        let ac = a.midpoint(&c); // Diagonal.
        f(Triangle::new(a.clone(), b.clone(), ac.clone()));
        f(Triangle::new(b, c.clone(), ac.clone()));
        f(Triangle::new(c, d.clone(), ac.clone()));
        f(Triangle::new(d, a, ac));
    }
}

impl<T> PolygonalExt<T> for Polygon<T>
    where T: Clone + Interpolate
{
    fn into_subdivisions<F>(self, n: usize, f: F)
        where F: FnMut(Polygon<T>)
    {
        match self {
            Polygon::Triangle(triangle) => triangle.into_subdivisions(n, f),
            Polygon::Quad(quad) => quad.into_subdivisions(n, f),
        }
    }
}

pub trait TessellatePolygon
: Sized {
    fn subdivide(self, n: usize) -> Tessellate<Self, P, Q, usize, Vec<Q>, fn(P, usize) -> Vec<Q>>;
}

impl TessellatePolygon<P, Polygon<T>> for I
    where I: Iterator<Item = P>,
          T: Clone + Interpolate,
          P: PolygonalExt<T>
{
    fn subdivide(self, n: usize)
        -> Tessellate<Self, P, Polygon<T>, usize, Vec<Polygon<T>>, fn(P, usize) -> Vec<Polygon<T>>> {
        Tessellate::new(self, n, map_subdivisions)
    }
}

fn map_subdivisions
(polygon: P, n: usize) -> Vec<Polygon<T>>
    where P: PolygonalExt<T>,
          T: Clone + Interpolate
{
    let mut polygons = vec![];
    polygon.into_subdivisions(n, |polygon| polygons.push(polygon));
    polygons
}

pub trait TessellateQuad<T>: Sized {
    fn tetrahedrons(self)
        -> Tessellate<Self, Quad<T>, Triangle<T>, (), Vec<Triangle<T>>,
                     fn(Quad<T>, ()) -> Vec<Triangle<T>>>;
}

impl TessellateQuad<T> for I
    where I: Iterator<Item = Quad<T>>,
          T: Clone + Interpolate
{
    fn tetrahedrons(self)
        -> Tessellate<Self, Quad<T>, Triangle<T>, (), Vec<Triangle<T>>,
                     fn(Quad<T>, ()) -> Vec<Triangle<T>>>
    {
        Tessellate::new(self, (), map_tetrahedrons)
    }
}

fn map_tetrahedrons<T>(quad: Quad<T>, _: ()) -> Vec<Triangle<T>>
    where T: Clone + Interpolate
{
    let mut triangles = vec![];
    quad.into_tetrahedrons(|triangle| triangles.push(triangle));
    triangles
}

fn n_map_polygon<T, P, F>(n: usize, polygon: P, f: F) -> Vec

    where P: Polygonal<T>,
          F: Fn(P) -> Vec

{
    let mut queued = vec![];
    let mut transformed = vec![polygon];
    for _ in 0..n {
        queued.extend(transformed.drain(..));
        while let Some(polygon) = queued.pop() {
            transformed.extend(f(polygon));
        }
    }
    transformed
}
<|endoftext|>


<commit_before>//! SSL support provided by OpenSSL.

extern crate openssl;

use std::io::net::ip::SocketAddr;
use std::io::net::tcp::TcpStream;
use std::io::{IoResult, IoError, ConnectionAborted, OtherIoError};
use self::openssl::ssl::{SslStream, SslContext, Sslv23, Ssl};
use self::openssl::ssl::error::{SslError, StreamError, SslSessionClosed, OpenSslErrors};
use self::NetworkStream::{NormalStream, SslProtectedStream};
use connecter::Connecter;

/// A TCP stream, either plain text or SSL.
///
/// This build was made with **OpenSSL** providing SSL support.
pub enum NetworkStream {
    NormalStream(TcpStream),
    SslProtectedStream(SslStream<TcpStream>),
}

impl Connecter for NetworkStream {
    fn connect(addr: SocketAddr, host: &str, use_ssl: bool) -> IoResult<NetworkStream> {
        let stream = try!(TcpStream::connect(addr));
        if use_ssl {
            let context = try!(SslContext::new(Sslv23).map_err(lift_ssl_error));
            let ssl = try!(Ssl::new(&context).map_err(lift_ssl_error));
            ssl.set_hostname(host);
            let ssl_stream = try!(SslStream::new_from(ssl, stream).map_err(lift_ssl_error));
            Ok(SslProtectedStream(ssl_stream))
        } else {
            Ok(NormalStream(stream))
        }
    }
}

impl Reader for NetworkStream {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        match *self {
            NormalStream(ref mut ns) => ns.read(buf),
            SslProtectedStream(ref mut ns) => ns.read(buf),
        }
    }
}

impl Writer for NetworkStream {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        match *self {
            NormalStream(ref mut ns) => ns.write(buf),
            SslProtectedStream(ref mut ns) => ns.write(buf),
        }
    }

    fn flush(&mut self) -> IoResult<()> {
        match *self {
            NormalStream(ref mut ns) => ns.flush(),
            SslProtectedStream(ref mut ns) => ns.flush(),
        }
    }
}

fn lift_ssl_error(ssl: SslError) -> IoError {
    match ssl {
        StreamError(err) => err,
        SslSessionClosed => IoError {
            kind: ConnectionAborted,
            desc: "SSL Connection Closed",
            detail: None
        },
        // Unfortunately throw this away. No way to support this
        // detail without a better Error abstraction.
        OpenSslErrors(errs) => IoError {
            kind: OtherIoError,
            desc: "Error in OpenSSL",
            detail: Some(format!("{}", errs))
        }
    }
}
<commit_msg>Fix an unused result error.<commit_after>//! SSL support provided by OpenSSL.

extern crate openssl;

use std::io::net::ip::SocketAddr;
use std::io::net::tcp::TcpStream;
use std::io::{IoResult, IoError, ConnectionAborted, OtherIoError};
use self::openssl::ssl::{SslStream, SslContext, Sslv23, Ssl};
use self::openssl::ssl::error::{SslError, StreamError, SslSessionClosed, OpenSslErrors};
use self::NetworkStream::{NormalStream, SslProtectedStream};
use connecter::Connecter;

/// A TCP stream, either plain text or SSL.
///
/// This build was made with **OpenSSL** providing SSL support.
pub enum NetworkStream {
    NormalStream(TcpStream),
    SslProtectedStream(SslStream<TcpStream>),
}

impl Connecter for NetworkStream {
    fn connect(addr: SocketAddr, host: &str, use_ssl: bool) -> IoResult<NetworkStream> {
        let stream = try!(TcpStream::connect(addr));
        if use_ssl {
            let context = try!(SslContext::new(Sslv23).map_err(lift_ssl_error));
            let ssl = try!(Ssl::new(&context).map_err(lift_ssl_error));
            try!(ssl.set_hostname(host).map_err(lift_ssl_error));
            let ssl_stream = try!(SslStream::new_from(ssl, stream).map_err(lift_ssl_error));
            Ok(SslProtectedStream(ssl_stream))
        } else {
            Ok(NormalStream(stream))
        }
    }
}

impl Reader for NetworkStream {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        match *self {
            NormalStream(ref mut ns) => ns.read(buf),
            SslProtectedStream(ref mut ns) => ns.read(buf),
        }
    }
}

impl Writer for NetworkStream {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        match *self {
            NormalStream(ref mut ns) => ns.write(buf),
            SslProtectedStream(ref mut ns) => ns.write(buf),
        }
    }

    fn flush(&mut self) -> IoResult<()> {
        match *self {
            NormalStream(ref mut ns) => ns.flush(),
            SslProtectedStream(ref mut ns) => ns.flush(),
        }
    }
}

fn lift_ssl_error(ssl: SslError) -> IoError {
    match ssl {
        StreamError(err) => err,
        SslSessionClosed => IoError {
            kind: ConnectionAborted,
            desc: "SSL Connection Closed",
            detail: None
        },
        // Unfortunately throw this away. No way to support this
        // detail without a better Error abstraction.
        OpenSslErrors(errs) => IoError {
            kind: OtherIoError,
            desc: "Error in OpenSSL",
            detail: Some(format!("{}", errs))
        }
    }
}
<|endoftext|>


<commit_before>// This module implements simple request and response objects.
// Copyright (c) 2014 by Shipeng Feng.
// Licensed under the BSD License, see LICENSE for more details.

use core;
use std::iter;
use std::ascii::OwnedAsciiExt;

use http::status;

/// Headers iterator.
pub type HeaderEntries<'a> = iter::Map<'static, &'a(String, String), (&'a String, &'a String), core::slice::Items<'a, (String, String)>>;
/// Header keys iterator.
pub type HeaderKeys<'a> = iter::Map<'static, (&'a String, &'a String), &'a String, HeaderEntries<'a>>;
/// Header values iterator.
pub type HeaderValues<'a> = iter::Map<'static, (&'a String, &'a String), &'a String, HeaderEntries<'a>>;

/// Headers type that stores some headers.  It has a HashMap like interface
/// but is ordered and can store the same keys multiple times.
pub struct Headers {
    list: Vec<(String, String)>,
}

impl Headers {
    /// Create `Headers`.
    pub fn new(list: Option<Vec<(String, String)>>) -> Headers {
        match list {
            Some(list) => Headers{list: list},
            None => Headers{list: Vec::new()},
        }
    }

    /// Return a reference to the value corresponding to the header key.
    pub fn get(&self, key: String) -> Option<&String> {
        let ikey = key.into_ascii_lower();
        for ref kvpair in self.list.iter() {
            let k = kvpair.ref0();
            let v = kvpair.ref1();
            if k.clone().into_ascii_lower() == ikey {
                return Some(v)
            }
        }
        return None
    }

    /// Return a list of all the references to the values for a given key.
    /// If that key is not in the headers, the return value will be an empty vector.
    pub fn get_all(&self, key: String) -> Vec<&String> {
        let ikey = key.into_ascii_lower();
        let mut result = Vec::new();
        for ref kvpair in self.list.iter() {
            let k = kvpair.ref0();
            let v = kvpair.ref1();
            if k.clone().into_ascii_lower() == ikey {
                result.push(v);
            }
        }
        return result
    }

    /// An iterator visiting all key-value pairs in sorted order.
    /// Iterator element type is `(&'a String, &'a String)`.
    pub fn iter(&self) -> HeaderEntries {
        self.list.iter().map(|ref kvpair| (kvpair.ref0(), kvpair.ref1()))
    }

    /// An iterator visiting all keys in sorted order.
    /// Iterator element type is `&'a String`.
    pub fn keys(&self) -> HeaderKeys {
        self.iter().map(|(k, _v)| k)
    }

    /// An iterator visiting all values in sorted order.
    /// Iterator element type is `&'a String`.
    pub fn values(&self) -> HeaderValues {
        self.iter().map(|(_k, v)| v)
    }

    /// Add a new header key-value pair to headers.
    /// TODO: _options_header_vkw
    pub fn add(&mut self, key: String, value: String) {
        self.list.push((key, value));
    }

    /// Removes a key from the headers, returning the first value at the key
    /// if the key was previously in the headers.
    pub fn remove(&mut self, key: String) -> Option<String> {
        let ikey = key.into_ascii_lower();
        let mut rv: Option<String> = None;
        let mut newlist = Vec::new();
        for kvpair in self.list.iter() {
            let k = kvpair.ref0();
            let v = kvpair.ref1();
            if k.clone().into_ascii_lower() != ikey {
                newlist.push((k.clone(), v.clone()));
            } else if rv != None {
                rv = Some(v.clone());
            }
        }
        self.list = newlist;
        return rv;
    }

    /// Removes all headers for `key` and add a new one.  The newly added key either
    /// appears at the end of the list if there was no entry or replaces the old one.
    /// TODO: _option_header_vkw
    pub fn set(&mut self, key: String, value: String) {
        let ikey = key.clone().into_ascii_lower();
        let mut key_existed = false;
        let mut newlist = Vec::new();
        for kvpair in self.list.iter() {
            let k = kvpair.ref0();
            let v = kvpair.ref1();
            if k.clone().into_ascii_lower() != ikey {
                newlist.push((k.clone(), v.clone()));
            } else if !key_existed {
                newlist.push((key.clone(), value.clone()));
                key_existed = true;
            }
        }
        if !key_existed {
            newlist.push((key, value));
        }
        self.list = newlist;
    }

    /// Return ths number of elements in the headers.
    pub fn len(&self) -> uint {
        return self.list.len();
    }

    /// Clears all headers.
    pub fn clear(&mut self) {
        self.list.clear();
    }
}

/// Response type.  It is just one container with a couple of parameters
/// (headers, body, status code etc).
pub struct Response {
    pub status: status::Status,
    pub headers: Headers,
    pub body: String,
}

impl Response {
    /// Create a `Response`.
    pub fn new(body: String) -> Response {
        Response {
            status: status::Ok,
            headers: Headers::new(None),
            body: body,
        }
    }

    pub fn get_status_code(&self) -> u16 {
        self.status.code()
    }

    pub fn set_status_code(&mut self, code: u16) {
        match FromPrimitive::from_u64(code as u64) {
            Some(status) => { self.status = status; },
            None => { self.status = status::UnregisteredStatus(code as u16, String::from_str("UNKNOWN")); },
        }
    }

    pub fn get_status(&self) -> status::Status {
        self.status.clone()
    }

    pub fn set_status(&mut self, status: status::Status) {
        self.status = status;
    }
}
<commit_msg>Added response content length<commit_after>// This module implements simple request and response objects.
// Copyright (c) 2014 by Shipeng Feng.
// Licensed under the BSD License, see LICENSE for more details.

use core;
use std::iter;
use std::ascii::AsciiExt;

use http::status;

/// Headers iterator.
pub type HeaderEntries<'a> = iter::Map<'static, &'a(String, String), (&'a String, &'a String), core::slice::Items<'a, (String, String)>>;
/// Header keys iterator.
pub type HeaderKeys<'a> = iter::Map<'static, (&'a String, &'a String), &'a String, HeaderEntries<'a>>;
/// Header values iterator.
pub type HeaderValues<'a> = iter::Map<'static, (&'a String, &'a String), &'a String, HeaderEntries<'a>>;

/// Headers type that stores some headers.  It has a HashMap like interface
/// but is ordered and can store the same keys multiple times.
pub struct Headers {
    list: Vec<(String, String)>,
}

impl Headers {
    /// Create `Headers`.
    pub fn new(list: Option<Vec<(String, String)>>) -> Headers {
        match list {
            Some(list) => Headers{list: list},
            None => Headers{list: Vec::new()},
        }
    }

    /// Return a reference to the value corresponding to the header key.
    pub fn get(&self, key: String) -> Option<&String> {
        let ikey = key.to_ascii_lower();
        for ref kvpair in self.list.iter() {
            let k = kvpair.ref0();
            let v = kvpair.ref1();
            if k.to_ascii_lower() == ikey {
                return Some(v)
            }
        }
        return None
    }

    /// Return a list of all the references to the values for a given key.
    /// If that key is not in the headers, the return value will be an empty vector.
    pub fn get_all(&self, key: String) -> Vec<&String> {
        let ikey = key.to_ascii_lower();
        let mut result = Vec::new();
        for ref kvpair in self.list.iter() {
            let k = kvpair.ref0();
            let v = kvpair.ref1();
            if k.to_ascii_lower() == ikey {
                result.push(v);
            }
        }
        return result
    }

    /// An iterator visiting all key-value pairs in sorted order.
    /// Iterator element type is `(&'a String, &'a String)`.
    pub fn iter(&self) -> HeaderEntries {
        self.list.iter().map(|ref kvpair| (kvpair.ref0(), kvpair.ref1()))
    }

    /// An iterator visiting all keys in sorted order.
    /// Iterator element type is `&'a String`.
    pub fn keys(&self) -> HeaderKeys {
        self.iter().map(|(k, _v)| k)
    }

    /// An iterator visiting all values in sorted order.
    /// Iterator element type is `&'a String`.
    pub fn values(&self) -> HeaderValues {
        self.iter().map(|(_k, v)| v)
    }

    /// Add a new header key-value pair to headers.
    /// TODO: _options_header_vkw
    pub fn add(&mut self, key: String, value: String) {
        self.list.push((key, value));
    }

    /// Removes a key from the headers, returning the first value at the key
    /// if the key was previously in the headers.
    pub fn remove(&mut self, key: String) -> Option<String> {
        let ikey = key.to_ascii_lower();
        let mut rv: Option<String> = None;
        let mut newlist = Vec::new();
        for kvpair in self.list.iter() {
            let k = kvpair.ref0();
            let v = kvpair.ref1();
            if k.to_ascii_lower() != ikey {
                newlist.push((k.clone(), v.clone()));
            } else if rv != None {
                rv = Some(v.clone());
            }
        }
        self.list = newlist;
        return rv;
    }

    /// Removes all headers for `key` and add a new one.  The newly added key either
    /// appears at the end of the list if there was no entry or replaces the old one.
    /// TODO: _option_header_vkw
    pub fn set(&mut self, key: String, value: String) {
        let ikey = key.to_ascii_lower();
        let mut key_existed = false;
        let mut newlist = Vec::new();
        for kvpair in self.list.iter() {
            let k = kvpair.ref0();
            let v = kvpair.ref1();
            if k.to_ascii_lower() != ikey {
                newlist.push((k.clone(), v.clone()));
            } else if !key_existed {
                newlist.push((key.clone(), value.clone()));
                key_existed = true;
            }
        }
        if !key_existed {
            newlist.push((key, value));
        }
        self.list = newlist;
    }

    /// Return ths number of elements in the headers.
    pub fn len(&self) -> uint {
        return self.list.len();
    }

    /// Clears all headers.
    pub fn clear(&mut self) {
        self.list.clear();
    }
}

/// Response type.  It is just one container with a couple of parameters
/// (headers, body, status code etc).
pub struct Response {
    status: status::Status,
    pub headers: Headers,
    pub body: String,
}

impl Response {
    /// Create a `Response`.
    pub fn new(body: String) -> Response {
        let mut response = Response {
            status: status::Ok,
            headers: Headers::new(None),
            body: body,
        };
        let content_type = String::from_str("text/plain; charset=utf-8");
        let content_length = response.body.len().to_string();
        response.headers.set(String::from_str("Content-Type"), content_type);
        response.headers.set(String::from_str("Content-Length"), content_length);
        return response;
    }

    pub fn get_status_code(&self) -> u16 {
        self.status.code()
    }

    pub fn set_status_code(&mut self, code: u16) {
        match FromPrimitive::from_u64(code as u64) {
            Some(status) => { self.status = status; },
            None => { self.status = status::UnregisteredStatus(code as u16, String::from_str("UNKNOWN")); },
        }
    }

    pub fn get_status(&self) -> status::Status {
        self.status.clone()
    }

    pub fn set_status(&mut self, status: status::Status) {
        self.status = status;
    }

    /// Sets a new string as response body.  The content length is set
    /// automatically.
    pub fn set_data(&mut self, value: String) {
        self.body = value;
        let content_length = self.body.len().to_string();
        self.headers.set(String::from_str("Content-Length"), content_length);
    }

    /// Returns the response content type if available.
    pub fn get_content_type(&self) -> Option<String> {
        let rv = self.headers.get(String::from_str("Content-Type"));
        match rv {
            Some(content_type) => content_type.clone(),
            None => None,
        }
    }

    /// Set response content type.
    pub fn set_content_type(&mut self, value: String) {
        self.headers.set(String::from_str("Content-Type"), value);
    }

    /// Returns the response content length if available.
    pub fn get_content_length(&self) -> Option<uint> {
        let rv = self.headers.get(String::from_str("Content-Length"));
        match rv {
            Some(content_length) => from_str(content_length.as_slice()),
            None => None,
        }
    }

    /// Set content length.
    pub fn set_content_length(&mut self, value: uint) {
        self.headers.set(String::from_str("Content-Length"), value.to_string());
    }
}
<|endoftext|>