<commit_before>// Copyright (c) 2017 Jason White
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::io;
use std::io::Write as IoWrite;
use std::fmt;
use std::fmt::Write as FmtWrite;
use std::time::Duration;
use std::path::PathBuf;
use std::process;
use std::collections::BTreeMap;
use std::ffi::OsString;

use tempfile::{NamedTempFile, TempPath};

use node::{Error, Task};
use util::{NeverAlwaysAuto, Counter};
use retry;

/// A task that executes a single command. A command is simply a process to be
/// spawned.
#[derive(Serialize, Deserialize, Ord, PartialOrd, Eq, PartialEq, Hash, Clone)]
pub struct Command {
    /// Process and arguments to spawn.
    args: Vec<String>,

    /// Optional working directory to spawn the process in. If `None`, uses the
    /// working directory of the parent process (i.e., the build process).
    cwd: Option<PathBuf>,

    /// Optional environment variables.
    env: Option<BTreeMap<String, String>>,

    /// Response file creation.
    ///
    /// If `Never`, never creates a response file. If the command line length
    /// exceeds the operating system limits, the command will fail.
    ///
    /// If `Always`, creates a temporary response file with all the command line
    /// arguments and passes that as the first command line argument instead.
    /// This is useful for very long command lines that exceed operating system
    /// limits.
    ///
    /// If `Auto`, creates a temporary response file only if the size of the
    /// arguments exceeds the operating system limits.
    #[serde(default)]
    response_file: NeverAlwaysAuto,

    /// Redirect standard output to a file instead.
    stdout: Option<PathBuf>,

    /// String to display when executing the task. If `None`, the command
    /// arguments are displayed in full instead.
    display: Option<String>,

    /// How much time to give the command to execute. If `None`, there is no
    /// time limit.
    timeout: Option<Duration>,

    /// Retry settings.
    #[serde(default)]
    retry: retry::Retry,
}

impl Command {
    #[cfg(test)]
    pub fn new(args: Vec<String>) -> Box<Command> {
        Box::new(Command {
            args: args,
            cwd: None,
            env: None,
            response_file: NeverAlwaysAuto::default(),
            stdout: None,
            display: None,
            timeout: None,
            retry: retry::Retry::new(),
        })
    }
}

impl Command {
    // Sets the working directory for the command.
    #[allow(dead_code)]
    pub fn cwd(mut self, path: PathBuf) -> Command {
        self.cwd = Some(path);
        self
    }

    // Sets the stdout file for the command.
    #[allow(dead_code)]
    pub fn stdout(mut self, path: PathBuf) -> Command {
        self.stdout = Some(path);
        self
    }

    // Sets the display string for the command.
    #[allow(dead_code)]
    pub fn display(mut self, display: String) -> Command {
        self.display = Some(display);
        self
    }

    // Sets the timeout for the command.
    #[allow(dead_code)]
    pub fn timeout(mut self, timeout: Duration) -> Command {
        self.timeout = Some(timeout);
        self
    }

    // Sets the retry configuration.
    #[allow(dead_code)]
    pub fn retry(mut self, retry: retry::Retry) -> Command {
        self.retry = retry;
        self
    }

    fn execute_impl(&self, log: &mut io::Write) -> Result<(), Error> {
        //writeln!(log, "Executing `{}`", self)?;

        assert!(self.args.len() > 0);

        // TODO:
        //  1. Spawn the process
        //  2. Capture stdout/stderr appropriately.
        //  4. Add implicit dependency detection framework and refactor all of
        //     the above to make it work.
        //  5. Implement timeouts.

        let mut cmd = process::Command::new(&self.args[0]);
        cmd.stdin(process::Stdio::null());

        // Generate a response file if necessary.
        let generate_response_file = match self.response_file {
            NeverAlwaysAuto::Never => false,
            NeverAlwaysAuto::Always => true,
            NeverAlwaysAuto::Auto => args_too_large(&self.args),
        };

        // The temporary response file needs to outlive the spawned process, so
        // it needs to be bound to a variable even if it is never used.
        let _rsp = if generate_response_file {
            let temp = response_file(&self.args[1..])?;

            let mut arg = OsString::new();
            arg.push("@");
            arg.push(&temp);
            cmd.arg(&arg);

            Some(temp)
        } else {
            cmd.args(&self.args[1..]);
            None
        };

        if let Some(ref cwd) = self.cwd {
            cmd.current_dir(cwd);
        }

        if let Some(ref env) = self.env {
            cmd.envs(env);
        }

        let output = cmd.output()?;

        // TODO: Interleave stdout and stderr.
        log.write(&output.stdout)?;
        log.write(&output.stderr)?;

        if output.status.success() {
            Ok(())
        } else {
            match output.status.code() {
                Some(code) => {
                    Err(io::Error::new(io::ErrorKind::Other,
                                       format!("Process exited with error code {}",
                                               code)))
                }
                None => {
                    Err(io::Error::new(
                            io::ErrorKind::Other, "Process terminated by signal"))
                }
            }
        }
    }
}

impl fmt::Display for Command {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(ref display) = self.display {
            write!(f, "{}", display)
        } else {
            let mut args = self.args.iter();

            if let Some(arg) = args.next() {
                write!(f, "{}", Arg::new(arg))?;
            }

            for arg in args {
                write!(f, " {}", Arg::new(arg))?;
            }

            Ok(())
        }
    }
}

impl fmt::Debug for Command {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

        write!(f, "\"")?;

        let mut args = self.args.iter();

        if let Some(arg) = args.next() {
            write!(f, "{}", Arg::new(arg))?;
        }

        for arg in args {
            write!(f, " {}", Arg::new(arg))?;
        }

        write!(f, "\"")?;

        Ok(())
    }
}

impl Task for Command {
    fn execute(&self, log: &mut io::Write) -> Result<(), Error> {
        self.retry
            .call(|| self.execute_impl(log), retry::progress_dummy)
    }
}

/// Helper type for formatting command line arguments.
struct Arg<'a> {
    arg: &'a str,
}

impl<'a> Arg<'a> {
    pub fn new(arg: &'a str) -> Arg<'a> {
        Arg { arg: arg }
    }

    /// Quotes the argument such that it is safe to pass to the shell.
    #[cfg(windows)]
    pub fn quote(&self, writer: &mut fmt::Write) -> fmt::Result {
        let quote = self.arg.chars().any(|c| c == ' ' || c == '\t') ||
                    self.arg.is_empty();

        if quote {
            writer.write_char('"')?;
        }

        let mut backslashes: usize = 0;

        for x in self.arg.chars() {
            if x == '\\' {
                backslashes += 1;
            } else {
                // Dump backslashes if we hit a quotation mark.
                if x == '"' {
                    // We need 2n+1 backslashes to escape a quote.
                    for _ in 0..(backslashes+1) {
                        writer.write_char('\\')?;
                    }
                }

                backslashes = 0;
            }

            writer.write_char(x)?;
        }

        if quote {
            // Escape any trailing backslashes.
            for _ in 0..backslashes {
                writer.write_char('\\')?;
            }

            writer.write_char('"')?;
        }

        Ok(())
    }
}

impl<'a> fmt::Display for Arg<'a> {
    /// Converts an argument such that it is safe to append to a command line
    /// string.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.quote(f)
    }
}

/// Writes the response file to a stream.
fn write_response_file<S, I>(args: I, writer: &mut io::Write) -> io::Result<()>
    where I: IntoIterator<Item = S>,
          S: AsRef<str>
{
    let mut iter = args.into_iter();

    // Write UTF-8 BOM. Some tools require this to properly decode it as UTF-8
    // instead of ASCII.
    writer.write(b"\xEF\xBB\xBF")?;

    if let Some(arg) = iter.next() {
        write!(writer, "{}", Arg::new(arg.as_ref())).unwrap();
    }

    for arg in iter {
        write!(writer, " {}", Arg::new(arg.as_ref())).unwrap();
    }

    // Some programs require a trailing new line (notably LIB.exe and LINK.exe).
    writer.write(b"\n")?;

    Ok(())
}

/// Generates a temporary response file for the given command line arguments.
fn response_file<S, I>(args: I) -> io::Result<TempPath>
    where I: IntoIterator<Item = S>,
          S: AsRef<str>
{
    let tempfile = NamedTempFile::new()?;

    {
        let mut writer = io::BufWriter::new(&tempfile);
        write_response_file(args, &mut writer)?;

        // Explicitly flush to catch any errors.
        writer.flush()?;
    }

    Ok(tempfile.into_temp_path())
}

/// Checks if the given command line arguments are too large and should instead
/// go into a response file. The entire list of arguments, including the program
/// name should be passed to this function.
#[cfg(windows)]
fn args_too_large<S, I>(args: I) -> bool
    where I: IntoIterator<Item = S>,
          S: AsRef<str>
{
    // The maximum length is 32768 characters, including the NULL terminator.
    let mut counter = Counter::new();

    let mut iter = args.into_iter();

    if let Some(arg) = iter.next() {
        write!(counter, "{}", Arg::new(arg.as_ref())).unwrap();
    }

    for arg in iter {
        write!(counter, " {}", Arg::new(arg.as_ref())).unwrap();
    }

    // Final NULL terminator.
    counter += 1;

    counter.count() > 32768
}

#[cfg(unix)]
fn args_too_large<S, I>(args: I) -> bool
    where I: IntoIterator<Item = S>,
          S: AsRef<str>
{
    let mut size: usize = 0;

    for arg in args.into_iter() {
        // +1 for the NULL terminator.
        size += arg.len() + 1;
    }

    // +1 for the final NULL terminator.
    size += 1;

    // Can't be larger than 128 kB.
    size > 0x20000
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    #[cfg(windows)]
    fn test_arg_display() {
        assert_eq!(format!("{}", Arg::new("foo bar")), "\"foo bar\"");
        assert_eq!(format!("{}", Arg::new("foo\tbar")), "\"foo\tbar\"");
        assert_eq!(format!("{}", Arg::new("foobar")), "foobar");
        assert_eq!(format!("{}", Arg::new("\"foo bar\"")), "\"\\\"foo bar\\\"\"");
        assert_eq!(format!("{}", Arg::new(r"C:\foo\bar")), r"C:\foo\bar");
        assert_eq!(format!("{}", Arg::new(r"\\foo\bar")), r"\\foo\bar");
    }
}
<commit_msg>Add stdin/stdout/stderr file redirection<commit_after>// Copyright (c) 2017 Jason White
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::io;
use std::fs;
use std::io::Write as IoWrite;
use std::fmt;
use std::fmt::Write as FmtWrite;
use std::time::Duration;
use std::path::{Path, PathBuf};
use std::process;
use std::collections::BTreeMap;
use std::ffi::OsString;

use tempfile::{NamedTempFile, TempPath};

use node::{Error, Task};
use util::{NeverAlwaysAuto, Counter};
use retry;

/// A task that executes a single command. A command is simply a process to be
/// spawned.
#[derive(Serialize, Deserialize, Ord, PartialOrd, Eq, PartialEq, Hash, Clone)]
pub struct Command {
    /// Process and arguments to spawn.
    args: Vec<String>,

    /// Optional working directory to spawn the process in. If `None`, uses the
    /// working directory of the parent process (i.e., the build process).
    cwd: Option<PathBuf>,

    /// Optional environment variables.
    env: Option<BTreeMap<String, String>>,

    /// Response file creation.
    ///
    /// If `Never`, never creates a response file. If the command line length
    /// exceeds the operating system limits, the command will fail.
    ///
    /// If `Always`, creates a temporary response file with all the command line
    /// arguments and passes that as the first command line argument instead.
    /// This is useful for very long command lines that exceed operating system
    /// limits.
    ///
    /// If `Auto`, creates a temporary response file only if the size of the
    /// arguments exceeds the operating system limits.
    #[serde(default)]
    response_file: NeverAlwaysAuto,

    /// File to send to standard input. If `None`, the standard input stream
    /// reads from `/dev/null` or equivalent.
    stdin: Option<PathBuf>,

    /// Redirect standard output to a file instead. If the path is `/dev/null`,
    /// a cross-platform way of sending the output to a black hole is used. If
    /// `None`, the output is logged by this task.
    stdout: Option<PathBuf>,

    /// Redirect standard error to a file instead. If the path is `/dev/null`, a
    /// cross-platform way of sending the output to a black hole is used. If
    /// `None`, the output is logged by this task.
    stderr: Option<PathBuf>,

    /// String to display when executing the task. If `None`, the command
    /// arguments are displayed in full instead.
    display: Option<String>,

    /// How much time to give the command to execute. If `None`, there is no
    /// time limit.
    timeout: Option<Duration>,

    /// Retry settings.
    retry: Option<retry::Retry>,
}

impl Command {
    #[cfg(test)]
    pub fn new(args: Vec<String>) -> Box<Command> {
        Box::new(Command {
            args: args,
            cwd: None,
            env: None,
            response_file: NeverAlwaysAuto::default(),
            stdin: None,
            stdout: None,
            stderr: None,
            display: None,
            timeout: None,
            retry: None,
        })
    }
}

impl Command {
    // Sets the working directory for the command.
    #[allow(dead_code)]
    pub fn cwd(&mut self, path: PathBuf) -> &mut Command {
        self.cwd = Some(path);
        self
    }

    // Sets the stdout file for the command.
    #[allow(dead_code)]
    pub fn stdout(&mut self, path: PathBuf) -> &mut Command {
        self.stdout = Some(path);
        self
    }

    // Sets the display string for the command.
    #[allow(dead_code)]
    pub fn display(&mut self, display: String) -> &mut Command {
        self.display = Some(display);
        self
    }

    // Sets the timeout for the command.
    #[allow(dead_code)]
    pub fn timeout(&mut self, timeout: Duration) -> &mut Command {
        self.timeout = Some(timeout);
        self
    }

    // Sets the retry configuration.
    #[allow(dead_code)]
    pub fn retry(&mut self, retry: retry::Retry) -> &mut Command {
        self.retry = Some(retry);
        self
    }

    fn execute_impl(&self, log: &mut io::Write) -> Result<(), Error> {
        //writeln!(log, "Executing `{}`", self)?;

        assert!(self.args.len() > 0);

        // TODO:
        //  1. Spawn the process
        //  2. Capture stdout/stderr appropriately.
        //  4. Add implicit dependency detection framework and refactor all of
        //     the above to make it work.
        //  5. Implement timeouts.

        let mut cmd = process::Command::new(&self.args[0]);

        if let Some(ref path) = self.stdin {
            if path == Path::new("/dev/null") {
                cmd.stdin(process::Stdio::null());
            } else {
                cmd.stdin(fs::File::open(path)?);
            }
        } else {
            // We don't ever want the build system to pause waiting for user
            // input from the parent process' input stream.
            cmd.stdin(process::Stdio::null());
        }

        if let Some(ref path) = self.stdout {
            if path == Path::new("/dev/null") {
                // Use cross-platform method.
                cmd.stdout(process::Stdio::null());
            } else {
                cmd.stdout(fs::File::create(path)?);
            }
        }

        if let Some(ref path) = self.stderr {
            if path == Path::new("/dev/null") {
                // Use cross-platform method.
                cmd.stderr(process::Stdio::null());
            } else {
                cmd.stderr(fs::File::create(path)?);
            }
        }

        // Generate a response file if necessary.
        let generate_response_file = match self.response_file {
            NeverAlwaysAuto::Never => false,
            NeverAlwaysAuto::Always => true,
            NeverAlwaysAuto::Auto => args_too_large(&self.args),
        };

        // The temporary response file needs to outlive the spawned process, so
        // it needs to be bound to a variable even if it is never used.
        let _rsp = if generate_response_file {
            let temp = response_file(&self.args[1..])?;

            let mut arg = OsString::new();
            arg.push("@");
            arg.push(&temp);
            cmd.arg(&arg);

            Some(temp)
        } else {
            cmd.args(&self.args[1..]);
            None
        };

        if let Some(ref cwd) = self.cwd {
            cmd.current_dir(cwd);
        }

        if let Some(ref env) = self.env {
            cmd.envs(env);
        }

        let output = cmd.output()?;

        // TODO: Interleave stdout and stderr.
        log.write(&output.stdout)?;
        log.write(&output.stderr)?;

        if output.status.success() {
            Ok(())
        } else {
            match output.status.code() {
                Some(code) => {
                    Err(io::Error::new(io::ErrorKind::Other,
                                       format!("Process exited with error code {}",
                                               code)))
                }
                None => {
                    Err(io::Error::new(
                            io::ErrorKind::Other, "Process terminated by signal"))
                }
            }
        }
    }
}

impl fmt::Display for Command {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(ref display) = self.display {
            write!(f, "{}", display)
        } else {
            let mut args = self.args.iter();

            if let Some(arg) = args.next() {
                write!(f, "{}", Arg::new(arg))?;
            }

            for arg in args {
                write!(f, " {}", Arg::new(arg))?;
            }

            Ok(())
        }
    }
}

impl fmt::Debug for Command {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {

        write!(f, "\"")?;

        let mut args = self.args.iter();

        if let Some(arg) = args.next() {
            write!(f, "{}", Arg::new(arg))?;
        }

        for arg in args {
            write!(f, " {}", Arg::new(arg))?;
        }

        write!(f, "\"")?;

        Ok(())
    }
}

impl Task for Command {
    fn execute(&self, log: &mut io::Write) -> Result<(), Error> {
        if let Some(ref retry) = self.retry {
            retry.call(|| self.execute_impl(log), retry::progress_dummy)
        } else {
            self.execute_impl(log)
        }
    }
}

/// Helper type for formatting command line arguments.
struct Arg<'a> {
    arg: &'a str,
}

impl<'a> Arg<'a> {
    pub fn new(arg: &'a str) -> Arg<'a> {
        Arg { arg: arg }
    }

    /// Quotes the argument such that it is safe to pass to the shell.
    #[cfg(windows)]
    pub fn quote(&self, writer: &mut fmt::Write) -> fmt::Result {
        let quote = self.arg.chars().any(|c| c == ' ' || c == '\t') ||
                    self.arg.is_empty();

        if quote {
            writer.write_char('"')?;
        }

        let mut backslashes: usize = 0;

        for x in self.arg.chars() {
            if x == '\\' {
                backslashes += 1;
            } else {
                // Dump backslashes if we hit a quotation mark.
                if x == '"' {
                    // We need 2n+1 backslashes to escape a quote.
                    for _ in 0..(backslashes+1) {
                        writer.write_char('\\')?;
                    }
                }

                backslashes = 0;
            }

            writer.write_char(x)?;
        }

        if quote {
            // Escape any trailing backslashes.
            for _ in 0..backslashes {
                writer.write_char('\\')?;
            }

            writer.write_char('"')?;
        }

        Ok(())
    }
}

impl<'a> fmt::Display for Arg<'a> {
    /// Converts an argument such that it is safe to append to a command line
    /// string.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.quote(f)
    }
}

/// Writes the response file to a stream.
fn write_response_file<S, I>(args: I, writer: &mut io::Write) -> io::Result<()>
    where I: IntoIterator<Item = S>,
          S: AsRef<str>
{
    let mut iter = args.into_iter();

    // Write UTF-8 BOM. Some tools require this to properly decode it as UTF-8
    // instead of ASCII.
    writer.write(b"\xEF\xBB\xBF")?;

    if let Some(arg) = iter.next() {
        write!(writer, "{}", Arg::new(arg.as_ref())).unwrap();
    }

    for arg in iter {
        write!(writer, " {}", Arg::new(arg.as_ref())).unwrap();
    }

    // Some programs require a trailing new line (notably LIB.exe and LINK.exe).
    writer.write(b"\n")?;

    Ok(())
}

/// Generates a temporary response file for the given command line arguments.
fn response_file<S, I>(args: I) -> io::Result<TempPath>
    where I: IntoIterator<Item = S>,
          S: AsRef<str>
{
    let tempfile = NamedTempFile::new()?;

    {
        let mut writer = io::BufWriter::new(&tempfile);
        write_response_file(args, &mut writer)?;

        // Explicitly flush to catch any errors.
        writer.flush()?;
    }

    Ok(tempfile.into_temp_path())
}

/// Checks if the given command line arguments are too large and should instead
/// go into a response file. The entire list of arguments, including the program
/// name should be passed to this function.
#[cfg(windows)]
fn args_too_large<S, I>(args: I) -> bool
    where I: IntoIterator<Item = S>,
          S: AsRef<str>
{
    // The maximum length is 32768 characters, including the NULL terminator.
    let mut counter = Counter::new();

    let mut iter = args.into_iter();

    if let Some(arg) = iter.next() {
        write!(counter, "{}", Arg::new(arg.as_ref())).unwrap();
    }

    for arg in iter {
        write!(counter, " {}", Arg::new(arg.as_ref())).unwrap();
    }

    // Final NULL terminator.
    counter += 1;

    counter.count() > 32768
}

#[cfg(unix)]
fn args_too_large<S, I>(args: I) -> bool
    where I: IntoIterator<Item = S>,
          S: AsRef<str>
{
    let mut size: usize = 0;

    for arg in args.into_iter() {
        // +1 for the NULL terminator.
        size += arg.len() + 1;
    }

    // +1 for the final NULL terminator.
    size += 1;

    // Can't be larger than 128 kB.
    size > 0x20000
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    #[cfg(windows)]
    fn test_arg_display() {
        assert_eq!(format!("{}", Arg::new("foo bar")), "\"foo bar\"");
        assert_eq!(format!("{}", Arg::new("foo\tbar")), "\"foo\tbar\"");
        assert_eq!(format!("{}", Arg::new("foobar")), "foobar");
        assert_eq!(format!("{}", Arg::new("\"foo bar\"")), "\"\\\"foo bar\\\"\"");
        assert_eq!(format!("{}", Arg::new(r"C:\foo\bar")), r"C:\foo\bar");
        assert_eq!(format!("{}", Arg::new(r"\\foo\bar")), r"\\foo\bar");
    }
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use error::TimeTrackError as TTE;
use error::TimeTrackErrorKind as TTEK;
use error::MapErrInto;

use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;
use libimagstore::storeid::StoreIdIterator;
use libimagerror::into::IntoError;

use iter::get::GetTimeTrackIter;
use tag::TimeTrackingTag as TTT;
use timetracking::TimeTracking;

pub struct WithOneOf<'a> {
    iter: GetTimeTrackIter<'a>,
    allowed_tags: &'a Vec<TTT>,
}

impl<'a> WithOneOf<'a> {

    pub fn new(iter: GetTimeTrackIter<'a>, allowed_tags: &'a Vec<TTT>) -> WithOneOf<'a> {
        WithOneOf {
            iter: iter,
            allowed_tags: allowed_tags
        }
    }
}

impl<'a> Iterator for WithOneOf<'a> {
    type Item = Result<FileLockEntry<'a>, TTE>;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            match self.iter.next() {
                Some(Ok(fle)) => {
                    match fle.get_timetrack_tag() {
                        Err(e) => return Some(Err(e)),
                        Ok(t) => if self.allowed_tags.contains(&t) {
                            return Some(Ok(fle))
                        } else {
                            // loop
                        },
                    }
                },
                Some(Err(e)) => return Some(Err(e)),
                None => return None,
            }
        }
    }
}

pub struct WithNoneOf<'a> {
    iter: GetTimeTrackIter<'a>,
    disallowed_tags: &'a Vec<TTT>,
}

impl<'a> WithNoneOf<'a> {

    pub fn new(iter: GetTimeTrackIter<'a>, disallowed_tags: &'a Vec<TTT>) -> WithNoneOf<'a> {
        WithNoneOf {
            iter: iter,
            disallowed_tags: disallowed_tags
        }
    }
}

impl<'a> Iterator for WithNoneOf<'a> {
    type Item = Result<FileLockEntry<'a>, TTE>;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            match self.iter.next() {
                Some(Ok(fle)) => {
                    match fle.get_timetrack_tag() {
                        Err(e) => return Some(Err(e)),
                        Ok(t) => if !self.disallowed_tags.contains(&t) {
                            return Some(Ok(fle))
                        } else {
                            // loop
                        },
                    }
                },
                Some(Err(e)) => return Some(Err(e)),
                None => return None,
            }
        }
    }
}

<commit_msg>Make filter iterators generic for all iterators<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use error::TimeTrackError as TTE;
use error::TimeTrackErrorKind as TTEK;
use error::MapErrInto;
use result::Result;

use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;
use libimagstore::storeid::StoreIdIterator;
use libimagerror::into::IntoError;

use iter::get::GetTimeTrackIter;
use tag::TimeTrackingTag as TTT;
use timetracking::TimeTracking;

pub struct WithOneOf<'a, I>
    where I: Iterator<Item = Result<FileLockEntry<'a>>>
{
    iter: I,
    allowed_tags: &'a Vec<TTT>,
}

impl<'a, I> WithOneOf<'a, I>
    where I: Iterator<Item = Result<FileLockEntry<'a>>>
{

    pub fn new(iter: I, allowed_tags: &'a Vec<TTT>) -> WithOneOf<'a, I> {
        WithOneOf {
            iter: iter,
            allowed_tags: allowed_tags
        }
    }
}

impl<'a, I> Iterator for WithOneOf<'a, I>
    where I: Iterator<Item = Result<FileLockEntry<'a>>>
{
    type Item = Result<FileLockEntry<'a>>;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            match self.iter.next() {
                Some(Ok(fle)) => {
                    match fle.get_timetrack_tag() {
                        Err(e) => return Some(Err(e)),
                        Ok(t) => if self.allowed_tags.contains(&t) {
                            return Some(Ok(fle))
                        } else {
                            // loop
                        },
                    }
                },
                Some(Err(e)) => return Some(Err(e)),
                None => return None,
            }
        }
    }
}

pub struct WithNoneOf<'a, I>
    where I: Iterator<Item = Result<FileLockEntry<'a>>>
{
    iter: I,
    disallowed_tags: &'a Vec<TTT>,
}

impl<'a, I> WithNoneOf<'a, I>
    where I: Iterator<Item = Result<FileLockEntry<'a>>>
{

    pub fn new(iter: I, disallowed_tags: &'a Vec<TTT>) -> WithNoneOf<'a, I> {
        WithNoneOf {
            iter: iter,
            disallowed_tags: disallowed_tags
        }
    }
}

impl<'a, I> Iterator for WithNoneOf<'a, I>
    where I: Iterator<Item = Result<FileLockEntry<'a>>>
{
    type Item = Result<FileLockEntry<'a>>;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            match self.iter.next() {
                Some(Ok(fle)) => {
                    match fle.get_timetrack_tag() {
                        Err(e) => return Some(Err(e)),
                        Ok(t) => if !self.disallowed_tags.contains(&t) {
                            return Some(Ok(fle))
                        } else {
                            // loop
                        },
                    }
                },
                Some(Err(e)) => return Some(Err(e)),
                None => return None,
            }
        }
    }
}

<|endoftext|>


<commit_before>use std::fmt;
use std::cmp::{max, min};
use world::{HEX_INNER_RADIUS, HEX_OUTER_RADIUS};
use super::{AxialType, DefaultFloat, Point2f};
use std::ops::{Add, Div, Index, IndexMut, Mul, Rem, Sub};
use math::cgmath::{Array, EuclideanSpace, MetricSpace};
use super::AxialVector;
/// A 2-dimensional point in axial coordinates. See [here][hex-blog] for more
/// information.
///
/// [hex-blog]: http://www.redblobgames.com/grids/hexagons/#coordinates
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[repr(C, packed)]
pub struct AxialPoint {
    pub q: AxialType,
    pub r: AxialType,
}
// TODO: implement cgmath::Array
// TODO: implement cgmath::MatricSpace
// TODO: implement cgmath::EuclideanSpace
// TODO: implement ops::{ ... }
// For all of the above, see
// http://bjz.github.io/cgmath/cgmath/struct.Point2.html
//
impl AxialPoint {
    pub fn new(q: AxialType, r: AxialType) -> Self {
        AxialPoint { q: q, r: r }
    }
    /// Returns the position of the hexagons center in the standard coordinate
    /// system using `world::{HEX_INNER_RADIUS, HEX_OUTER_RADIUS}`.
    pub fn to_real(&self) -> Point2f {
        Point2f {
            x: ((2 * self.q + self.r) as DefaultFloat) * HEX_INNER_RADIUS,
            y: (self.r as DefaultFloat) * (3.0 / 2.0) * HEX_OUTER_RADIUS,
        }
    }
    /// Returns the `s` component of corresponding cube coordinates. In cube
    /// coordinates 'q + r + s = 0', so saving `s` is redundant and can be
    /// calculated on the fly when needed.
    pub fn s(&self) -> AxialType {
        -self.q - self.r
    }
}
impl fmt::Debug for AxialPoint {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_tuple("")
            .field(&self.q)
            .field(&self.r)
            .finish()
    }
}
/// ********************Basic Arithmetics************
impl Add<AxialVector> for AxialPoint {
    type Output = AxialPoint;
    fn add(self, rhs: AxialVector) -> AxialPoint {
        AxialPoint {
            q: self.q + rhs.q,
            r: self.r + rhs.r,
        }
    }
}
impl Sub<AxialPoint> for AxialPoint {
    type Output = AxialVector;
    fn sub(self, rhs: AxialPoint) -> AxialVector {
        AxialVector {
            q: self.q - rhs.q,
            r: self.r - rhs.r,
        }
    }
}
impl Mul<AxialType> for AxialPoint {
    type Output = AxialPoint;
    fn mul(self, rhs: AxialType) -> AxialPoint {
        AxialPoint {
            q: self.q * rhs,
            r: self.r * rhs,
        }
    }
}
impl Div<AxialType> for AxialPoint {
    type Output = AxialPoint;
    fn div(self, rhs: AxialType) -> AxialPoint {
        AxialPoint {
            q: self.q / rhs,
            r: self.r / rhs,
        }
    }
}
impl Rem<AxialType> for AxialPoint {
    type Output = AxialPoint;
    fn rem(self, d: AxialType) -> AxialPoint {
        AxialPoint {
            q: self.q % d,
            r: self.r % d,
        }
    }
}
/// ********************Index************
impl Index<usize> for AxialPoint {
    type Output = AxialType;
    fn index(&self, index: usize) -> &AxialType {
        match index {
            0 => &self.q,
            1 => &self.r,
            _ => panic!("Index out of bounds!"),
        }
    }
}
impl IndexMut<usize> for AxialPoint {
    fn index_mut(&mut self, index: usize) -> &mut AxialType {
        match index {
            0 => &mut self.q,
            1 => &mut self.r,
            _ => panic!("Index out of bounds!"),
        }
    }
}
/// ********************Array************
impl Array for AxialPoint {
    type Element = AxialType;
    fn from_value(x: AxialType) -> AxialPoint {
        AxialPoint { q: x, r: x }
    }
    fn sum(self) -> AxialType {
        self.q + self.r
    }
    fn product(self) -> AxialType {
        self.q * self.r
    }
    fn min(self) -> AxialType {
        min(self.q, self.r)
    }
    fn max(self) -> AxialType {
        max(self.q, self.r)
    }
}
/// ******************* Metric-Space************************
impl MetricSpace for AxialPoint {
    type Metric = f32;
    fn distance2(self, other: AxialPoint) -> Self::Metric {
        (((self.q - other.q) * (self.q - other.q)) +
         ((self.r - other.r) * (self.r - other.r))) as f32
    }
}
/// ******************* EuclideanSpace**********************
impl EuclideanSpace for AxialPoint {
    type Scalar = i32;
    type Diff = AxialVector;
    fn origin() -> Self {
        AxialPoint { q: 0, r: 0 }
    }
    fn from_vec(v: Self::Diff) -> Self {
        AxialPoint { q: v.q, r: v.r }
    }
    fn to_vec(self) -> Self::Diff {
        AxialVector {
            q: self.q,
            r: self.r,
        }
    }
    fn dot(self, v: Self::Diff) -> Self::Scalar {
        (self.q * v.q) + (self.r * v.r)
    }
}

#[test]
fn test() {
    let a: AxialPoint = AxialPoint { q: 5, r: 7 };
    let mut b: AxialPoint = AxialPoint { q: -2, r: 0 };
    let v: AxialVector = AxialVector { q: 8, r: 1 };
    assert!(a.add(v) == AxialPoint { q: 13, r: 8 });
    assert!(a.sub(b) == AxialVector { q: 7, r: 7 });
    assert!(b.mul(4) == AxialPoint { q: -8, r: 0 });
    assert!(b.div(2) == AxialPoint { q: -1, r: 0 });
    assert!(a.rem(3) == AxialPoint { q: 2, r: 1 });
    assert!(a[0] == 5);
    assert!(a[1] == 7);
    b[0] = 5;
    b[1] = 5;
    assert!(b.q == 5 && b.r == 5);
    let c = AxialPoint::from_value(7);
    assert!(c.q == 7 && c.r == 7);
    assert!(c.sum() == 14);
    assert!(c.product() == 49);
    assert!(a.min() == 5);
    assert!(a.max() == 7);
    let d = AxialPoint { q: 0, r: 0 };
    let e = AxialPoint { q: 1, r: 1 };
    let f = 2.0;
    assert!(d.distance2(e) == f);
    assert!(d.distance(e) == f.sqrt());
    assert!(AxialPoint::from_vec(v) == AxialPoint { q: 8, r: 1 });
    assert!(e.to_vec() == AxialVector { q: 1, r: 1 });
    assert!(e.dot(v) == 9);
}
<commit_msg>split test method into several mthods for better testing<commit_after>use std::fmt;
use std::cmp::{max, min};
use world::{HEX_INNER_RADIUS, HEX_OUTER_RADIUS};
use super::{AxialType, DefaultFloat, Point2f};
use std::ops::{Add, Div, Index, IndexMut, Mul, Rem, Sub};
use math::cgmath::{Array, EuclideanSpace, MetricSpace};
use super::AxialVector;
/// A 2-dimensional point in axial coordinates. See [here][hex-blog] for more
/// information.
///
/// [hex-blog]: http://www.redblobgames.com/grids/hexagons/#coordinates
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[repr(C, packed)]
pub struct AxialPoint {
    pub q: AxialType,
    pub r: AxialType,
}
// TODO: implement cgmath::Array
// TODO: implement cgmath::MatricSpace
// TODO: implement cgmath::EuclideanSpace
// TODO: implement ops::{ ... }
// For all of the above, see
// http://bjz.github.io/cgmath/cgmath/struct.Point2.html
//
impl AxialPoint {
    pub fn new(q: AxialType, r: AxialType) -> Self {
        AxialPoint { q: q, r: r }
    }
    /// Returns the position of the hexagons center in the standard coordinate
    /// system using `world::{HEX_INNER_RADIUS, HEX_OUTER_RADIUS}`.
    pub fn to_real(&self) -> Point2f {
        Point2f {
            x: ((2 * self.q + self.r) as DefaultFloat) * HEX_INNER_RADIUS,
            y: (self.r as DefaultFloat) * (3.0 / 2.0) * HEX_OUTER_RADIUS,
        }
    }
    /// Returns the `s` component of corresponding cube coordinates. In cube
    /// coordinates 'q + r + s = 0', so saving `s` is redundant and can be
    /// calculated on the fly when needed.
    pub fn s(&self) -> AxialType {
        -self.q - self.r
    }
}
impl fmt::Debug for AxialPoint {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_tuple("")
            .field(&self.q)
            .field(&self.r)
            .finish()
    }
}
/// ********************Basic Arithmetics************
impl Add<AxialVector> for AxialPoint {
    type Output = AxialPoint;
    fn add(self, rhs: AxialVector) -> AxialPoint {
        AxialPoint {
            q: self.q + rhs.q,
            r: self.r + rhs.r,
        }
    }
}
impl Sub<AxialPoint> for AxialPoint {
    type Output = AxialVector;
    fn sub(self, rhs: AxialPoint) -> AxialVector {
        AxialVector {
            q: self.q - rhs.q,
            r: self.r - rhs.r,
        }
    }
}
impl Mul<AxialType> for AxialPoint {
    type Output = AxialPoint;
    fn mul(self, rhs: AxialType) -> AxialPoint {
        AxialPoint {
            q: self.q * rhs,
            r: self.r * rhs,
        }
    }
}
impl Div<AxialType> for AxialPoint {
    type Output = AxialPoint;
    fn div(self, rhs: AxialType) -> AxialPoint {
        AxialPoint {
            q: self.q / rhs,
            r: self.r / rhs,
        }
    }
}
impl Rem<AxialType> for AxialPoint {
    type Output = AxialPoint;
    fn rem(self, d: AxialType) -> AxialPoint {
        AxialPoint {
            q: self.q % d,
            r: self.r % d,
        }
    }
}
/// ********************Index************
impl Index<usize> for AxialPoint {
    type Output = AxialType;
    fn index(&self, index: usize) -> &AxialType {
        match index {
            0 => &self.q,
            1 => &self.r,
            _ => panic!("Index out of bounds!"),
        }
    }
}
impl IndexMut<usize> for AxialPoint {
    fn index_mut(&mut self, index: usize) -> &mut AxialType {
        match index {
            0 => &mut self.q,
            1 => &mut self.r,
            _ => panic!("Index out of bounds!"),
        }
    }
}
/// ********************Array************
impl Array for AxialPoint {
    type Element = AxialType;
    fn from_value(x: AxialType) -> AxialPoint {
        AxialPoint { q: x, r: x }
    }
    fn sum(self) -> AxialType {
        self.q + self.r
    }
    fn product(self) -> AxialType {
        self.q * self.r
    }
    fn min(self) -> AxialType {
        min(self.q, self.r)
    }
    fn max(self) -> AxialType {
        max(self.q, self.r)
    }
}
/// ******************* Metric-Space************************
impl MetricSpace for AxialPoint {
    type Metric = f32;
    fn distance2(self, other: AxialPoint) -> Self::Metric {
        (((self.q - other.q) * (self.q - other.q)) +
         ((self.r - other.r) * (self.r - other.r))) as f32
    }
}
/// ******************* EuclideanSpace**********************
impl EuclideanSpace for AxialPoint {
    type Scalar = i32;
    type Diff = AxialVector;
    fn origin() -> Self {
        AxialPoint { q: 0, r: 0 }
    }
    fn from_vec(v: Self::Diff) -> Self {
        AxialPoint { q: v.q, r: v.r }
    }
    fn to_vec(self) -> Self::Diff {
        AxialVector {
            q: self.q,
            r: self.r,
        }
    }
    fn dot(self, v: Self::Diff) -> Self::Scalar {
        (self.q * v.q) + (self.r * v.r)
    }
}

#[test]
fn arithmetic_test_point() {
    let a: AxialPoint = AxialPoint { q: 5, r: 7 };
    let b: AxialPoint = AxialPoint { q: -2, r: 0 };
    let v: AxialVector = AxialVector { q: 8, r: 1 };
    assert!(a.add(v) == AxialPoint { q: 13, r: 8 });
    assert!(a.sub(b) == AxialVector { q: 7, r: 7 });
    assert!(b.mul(4) == AxialPoint { q: -8, r: 0 });
    assert!(b.div(2) == AxialPoint { q: -1, r: 0 });
    assert!(a.rem(3) == AxialPoint { q: 2, r: 1 });
}
#[test]
fn index_test_point() {
    let a: AxialPoint = AxialPoint { q: 5, r: 7 };
    let mut b: AxialPoint = AxialPoint { q: -2, r: 0 };
    assert!(a[0] == 5);
    assert!(a[1] == 7);
    b[0] = 5;
    b[1] = 5;
    assert!(b.q == 5 && b.r == 5);
}
#[test]
fn array_test_point() {
    let a = AxialPoint::from_value(7);
    let b: AxialPoint = AxialPoint { q: 5, r: 7 };
    assert!(a.q == 7 && a.r == 7);
    assert!(a.sum() == 14);
    assert!(a.product() == 49);
    assert!(b.min() == 5);
    assert!(b.max() == 7);
}
#[test]
fn meticspace_test_point() {
    let a = AxialPoint { q: 0, r: 0 };
    let b = AxialPoint { q: 1, r: 1 };
    assert!(a.distance2(b) == 2.0);
}
#[test]
fn euclideanspace_test_point() {
    let v: AxialVector = AxialVector { q: 8, r: 1 };
    let a = AxialPoint { q: 1, r: 1 };
    assert!(AxialPoint::from_vec(v) == AxialPoint { q: 8, r: 1 });
    assert!(a.to_vec() == AxialVector { q: 1, r: 1 });
    assert!(a.dot(v) == 9);
}
<|endoftext|>


<commit_before>/*
 * Copyright 2017 Sreejith Krishnan R
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

use super::{Drawable, BoundingBox, MeasureMode};
use ::paint::{Point, Canvas};
use ::elements::Element;
use ::platform::Context;
use ::props::{Color, Directionality};

pub type SizeReader<T> = fn(&T) -> f32;
pub type DirReader<T> = fn(&T) -> &Directionality;
pub type ColorReader<T> = fn(&T) -> &Color;

pub struct Glyph<'a, T: Element + 'a> {
    glyph_index: u32,
    element: &'a T,
    size_reader: SizeReader<T>,
    dir_reader: DirReader<T>,
    color_reader: ColorReader<T>,

    bounding_box: BoundingBox,
}

impl<'a, T: Element + 'a> Drawable for Glyph<'a, T> {
    fn draw(&self, canvas: &Canvas, pen_pos: &Point) {
        canvas.draw_glyph(pen_pos, &self.bounding_box, self.glyph_index,
                          (self.color_reader)(self.element),
                          (self.size_reader)(self.element),
                          (self.dir_reader)(self.element));
    }

    fn calculate(&mut self, context: &Context, width: f32, width_measure_mode: &MeasureMode,
                 height: f32, height_measure_mode: &MeasureMode) {
        let base_size = (self.size_reader)(self.element);
        let ruler = context.platform().get_math_ruler(self.element, base_size);
        self.bounding_box = BoundingBox {
            rect: ruler.measure_glyph(self.glyph_index, (self.dir_reader)(self.element)),
            baseline: -ruler.descent(),
            axis: ruler.axis_height()-ruler.descent(),
        }
    }

    fn bounding_box(&self) -> &BoundingBox {
        &self.bounding_box
    }
}

impl<'a, T: Element + 'a> Glyph<'a, T> {
    pub fn new(element: &'a T, glyph_index: u32, size_reader: SizeReader<T>,
               color_reader: ColorReader<T>, dir_reader: DirReader<T>) -> Glyph<'a, T> {
        Glyph {
            glyph_index,
            element,
            size_reader,
            dir_reader,
            color_reader,
            bounding_box: BoundingBox::default(),
        }
    }
}<commit_msg>Update API to draw both single character and glyph<commit_after>/*
 * Copyright 2017 Sreejith Krishnan R
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

use std::char::from_u32;

use super::{Drawable, BoundingBox, MeasureMode};
use ::paint::{Point, Canvas};
use ::elements::Element;
use ::platform::Context;
use ::props::{Color, Directionality};

pub type SizeReader<T> = fn(&T) -> f32;
pub type DirReader<T> = fn(&T) -> &Directionality;
pub type ColorReader<T> = fn(&T) -> &Color;

pub enum GlyphIndex {
    Char(u32),
    Index(u32),
}

pub struct Glyph<'a, T: Element + 'a> {
    glyph_index: GlyphIndex,
    element: &'a T,
    size_reader: SizeReader<T>,
    dir_reader: DirReader<T>,
    color_reader: ColorReader<T>,

    bounding_box: BoundingBox,
}

impl<'a, T: Element + 'a> Drawable for Glyph<'a, T> {
    fn draw(&self, canvas: &Canvas, pen_pos: &Point) {
        match self.glyph_index {
            GlyphIndex::Index(index) => {
                canvas.draw_glyph(pen_pos, &self.bounding_box, index,
                                  (self.color_reader)(self.element),
                                  (self.size_reader)(self.element),
                                  (self.dir_reader)(self.element));
            },
            GlyphIndex::Char(unicode) => {
                canvas.draw_text(pen_pos, &self.bounding_box,
                                 &from_u32(unicode).unwrap().to_string(),
                                 (self.color_reader)(self.element),
                                 (self.size_reader)(self.element),
                                 (self.dir_reader)(self.element));
            }
        }
    }

    fn calculate(&mut self, context: &Context, width: f32, width_measure_mode: &MeasureMode,
                 height: f32, height_measure_mode: &MeasureMode) {
        let base_size = (self.size_reader)(self.element);
        let ruler = context.platform().get_math_ruler(self.element, base_size);
        let dir = (self.dir_reader)(self.element);

        let bounds = match self.glyph_index {
            GlyphIndex::Char(unicode) => ruler.measure_char(unicode, dir),
            GlyphIndex::Index(index) => ruler.measure_glyph(index, dir),
        };

        self.bounding_box = BoundingBox {
            rect: bounds,
            baseline: -ruler.descent(),
            axis: ruler.axis_height()-ruler.descent(),
        }
    }

    fn bounding_box(&self) -> &BoundingBox {
        &self.bounding_box
    }
}

impl<'a, T: Element + 'a> Glyph<'a, T> {
    pub fn new(element: &'a T, glyph_index: GlyphIndex, size_reader: SizeReader<T>,
               color_reader: ColorReader<T>, dir_reader: DirReader<T>) -> Glyph<'a, T> {
        Glyph {
            glyph_index,
            element,
            size_reader,
            dir_reader,
            color_reader,
            bounding_box: BoundingBox::default(),
        }
    }
}<|endoftext|>


<commit_before>pub mod window {
    use cocoa::base::id;
    use cocoa::foundation::NSUInteger;
    use cocoa::appkit::NSWindow;
    use core_graphics::geometry::{CGRect, CGPoint, CGSize};
    use objc::runtime::{BOOL, Class, YES};
    use raw::{AsRaw, FromRaw, FromRawError, IntoRaw};
    use std::error::Error;
    use std::fmt;
    use std::marker;
    use std::ops::{Deref, DerefMut};
    use sys::{MTLClearColor, MTLPixelFormat};
    use winit;
    use winit::os::macos::WindowExt;
    use {ClearColor, Device, PixelFormat, RenderPassDescriptor, Texture};

    pub use winit::{
        CursorState,
        Event,
        MonitorId,
        MouseCursor,
        PollEventsIterator,
        WaitEventsIterator,
        ElementState,
        MouseButton,
        MouseScrollDelta,
        Touch,
        TouchPhase,
        ScanCode,
        VirtualKeyCode
    };

    pub struct WindowBuilder {
        window: winit::WindowBuilder,
        device: Device
    }

    #[derive(Debug)]
    pub enum CreationError {
        ViewCreation(ViewError),
        Winit(winit::CreationError)
    }

    impl fmt::Display for CreationError {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "{}", self.description())
        }
    }

    impl Error for CreationError {
        fn description(&self) -> &str {
            match *self {
                CreationError::ViewCreation(ref e) => e.description(),
                CreationError::Winit(ref e) => e.description()
            }
        }

        fn cause(&self) -> Option<&Error> {
            match *self {
                CreationError::ViewCreation(ref e) => Some(e),
                CreationError::Winit(ref e) => Some(e)
            }
        }
    }

    impl From<winit::CreationError> for CreationError {
        fn from(error: winit::CreationError) -> Self {
            CreationError::Winit(error)
        }
    }

    impl From<ViewError> for CreationError {
        fn from(error: ViewError) -> Self {
            CreationError::ViewCreation(error)
        }
    }

    impl WindowBuilder {
        /// Initializes a new `WindowBuilder` with default values.
        #[inline]
        pub fn new(device: Device) -> Self {
            WindowBuilder {
                window: winit::WindowBuilder::new(),
                device: device
            }
        }

        /// Requests the window to be of specific dimensions.
        ///
        /// Width and height are in pixels.
        #[inline]
        pub fn with_dimensions(self, width: u32, height: u32) -> WindowBuilder {
            WindowBuilder {window: self.window.with_dimensions(width, height), ..self}
        }

        /// Sets a minimum dimension size for the window
        ///
        /// Width and height are in pixels.
        #[inline]
        pub fn with_min_dimensions(self, width: u32, height: u32) -> WindowBuilder {
            WindowBuilder {window: self.window.with_min_dimensions(width, height), ..self}
        }

        /// Sets a maximum dimension size for the window
        ///
        /// Width and height are in pixels.
        #[inline]
        pub fn with_max_dimensions(self, width: u32, height: u32) -> WindowBuilder {
            WindowBuilder {window: self.window.with_max_dimensions(width, height), ..self}
        }

        /// Requests a specific title for the window.
        #[inline]
        pub fn with_title(self, title: String) -> WindowBuilder {
            WindowBuilder {window: self.window.with_title(title), ..self}
        }

        /// Requests fullscreen mode.
        ///
        /// If you don't specify dimensions for the window, it will match the monitor's.
        #[inline]
        pub fn with_fullscreen(self, monitor: MonitorId) -> WindowBuilder {
            WindowBuilder {window: self.window.with_fullscreen(monitor), ..self}
        }

        /// Sets whether the window will be initially hidden or visible.
        #[inline]
        pub fn with_visibility(self, visible: bool) -> WindowBuilder {
            WindowBuilder {window: self.window.with_visibility(visible), ..self}
        }

        /// Sets whether the background of the window should be transparent.
        #[inline]
        pub fn with_transparency(self, transparent: bool) -> WindowBuilder {
            WindowBuilder {window: self.window.with_transparency(transparent), ..self}
        }

        /// Sets whether the window should have a border, a title bar, etc.
        #[inline]
        pub fn with_decorations(self, decorations: bool) -> WindowBuilder {
            WindowBuilder {window: self.window.with_decorations(decorations), ..self}
        }

        /// Enables multitouch
        #[inline]
        pub fn with_multitouch(self) -> WindowBuilder {
            WindowBuilder {window: self.window.with_multitouch(), ..self}
        }

        /// Builds the window.
        ///
        /// Error should be very rare and only occur in case of permission denied, incompatible system,
        /// out of memory, etc.
        pub fn build(self) -> Result<Window, CreationError> {
            let window = try!(self.window.build());
            let view = try!(View::new(&window, self.device));

            unsafe {
                let native_window: id = window.get_nswindow() as id;
                native_window.setContentView_(view.mtk_view.0);
            }

            Ok(Window {
                window: window,
                view: view
            })
        }

        /// Builds the window.
        ///
        /// The context is build in a *strict* way. That means that if the backend couldn't give
        /// you what you requested, an `Err` will be returned.
        #[inline]
        pub fn build_strict(self) -> Result<Window, CreationError> {
            self.build()
        }
    }

    pub struct Window {
        window: winit::Window,
        pub view: View
    }

    impl Window {
        pub fn poll_events(&self) -> PollEventsIterator {
            self.window.poll_events()
        }

        pub fn wait_events(&self) -> WaitEventsIterator {
            self.window.wait_events()
        }

        pub fn window(&self) -> Ref<winit::Window> {
            Ref(&self.window)
        }
    }

    pub struct View {
        mtk_view: MtkView
    }

    struct MtkView(id);
    impl_from_into_raw!(MtkView, of class "MTKView");

    impl View {
        fn new(window: &winit::Window, device: Device) -> Result<Self, ViewError> {
            let window_origin = {
                let (x, y) = try!(window.get_position().ok_or(ViewError::no_window()));
                CGPoint { x: x as f64, y: y as f64 }
            };

            let window_size = {
                let (w, h) = try!(window.get_inner_size().ok_or(ViewError::no_window()));
                CGSize { width: w as f64, height: h as f64 }
            };

            let view_frame = CGRect { origin: window_origin, size: window_size };

            let view_object: id = unsafe {
                // Dummy function to ensure that we link against MetalKit
                #[allow(dead_code)]
                #[link(name = "MetalKit", kind = "framework")]
                extern "C" {
                    fn MTKModelIOVertexDescriptorFromMetal(metalDescriptor: id) -> id;
                }

                let view_class = Class::get("MTKView").expect("Could not find MTKView class");
                let view: id = msg_send![view_class, alloc];
                msg_send![view, initWithFrame:view_frame
                                       device:device.into_raw()]
            };

            Ok(View {
                mtk_view: try!(MtkView::from_raw(view_object)),
            })
        }

        fn raw_view(&self) -> id {
            self.mtk_view.0
        }

        pub fn device<'a>(&self) -> Option<PhantomRef<'a, Device>> {
            let device = unsafe {
                Device::from_raw(msg_send![*self.mtk_view.as_raw(), device])
            };
            device.ok().map(|d| PhantomRef(d, marker::PhantomData))
        }

        pub fn device_mut<'a>(&mut self) -> Option<PhantomRefMut<'a, Device>> {
            let device = unsafe {
                Device::from_raw(msg_send![*self.mtk_view.as_raw(), device])
            };
            device.ok().map(|d| PhantomRefMut(d, marker::PhantomData))
        }

        pub fn clear_color(&self) -> ClearColor {
            let color: MTLClearColor = unsafe {
                msg_send![*self.mtk_view.as_raw(), clearColor]
            };
            color.into()
        }

        pub fn set_clear_color<C: Into<MTLClearColor>>(&mut self, clear_color: C) {
            unsafe { msg_send![*self.mtk_view.as_raw(), setClearColor:clear_color.into()] }
        }

        pub fn clear_depth(&self) -> f64 {
            unsafe { msg_send![*self.mtk_view.as_raw(), clearDepth] }
        }

        pub fn set_clear_depth(&mut self, clear_depth: f64) {
            unsafe { msg_send![*self.mtk_view.as_raw(), setClearDepth:clear_depth] }
        }

        pub fn clear_stencil(&self) -> u32 {
            unsafe { msg_send![*self.mtk_view.as_raw(), clearStencil] }
        }

        pub fn set_clear_stencil(&mut self, clear_stencil: u32) {
            unsafe { msg_send![*self.mtk_view.as_raw(), setClearStencil:clear_stencil] }
        }

        pub fn color_pixel_format(&self) -> PixelFormat {
            let pixel_format: MTLPixelFormat = unsafe {
                msg_send![*self.mtk_view.as_raw(), colorPixelFormat]
            };
            pixel_format.into()
        }

        pub fn set_color_pixel_format<P: Into<MTLPixelFormat>>(&mut self, color_pixel_format: P) {
            unsafe { msg_send![*self.mtk_view.as_raw(), setColorPixelFormat:color_pixel_format.into()] }
        }

        pub fn depth_stencil_pixel_format(&self) -> PixelFormat {
            let pixel_format: MTLPixelFormat = unsafe {
                msg_send![*self.mtk_view.as_raw(), depthStencilPixelFormat]
            };
            pixel_format.into()
        }

        pub fn set_depth_stencil_pixel_format<P: Into<MTLPixelFormat>>(&mut self, depth_stencil_pixel_format: P) {
            unsafe { msg_send![*self.mtk_view.as_raw(), setDepthStencilPixelFormat:depth_stencil_pixel_format.into()] }
        }

        pub fn sample_count(&self) -> usize {
            let sample_count: NSUInteger = unsafe {
                msg_send![*self.mtk_view.as_raw(), sampleCount]
            };
            sample_count as usize
        }

        pub fn set_sample_count(&mut self, sample_count: usize) {
            let sample_count = sample_count as NSUInteger;
            unsafe { msg_send![*self.mtk_view.as_raw(), setSampleCount:sample_count] }
        }

        pub fn current_render_pass_descriptor(&self) -> Option<PhantomRef<RenderPassDescriptor>> {
            let descriptor: id = unsafe { msg_send![self.raw_view(), currentRenderPassDescriptor] };
            FromRaw::from_raw(descriptor).ok().map(|d| PhantomRef(d, marker::PhantomData))
        }

        pub fn current_depth_stencil_texture(&self) -> Option<PhantomRef<Texture>> {
            let texture: id = unsafe { msg_send![self.raw_view(), depthStencilTexture] };
            FromRaw::from_raw(texture).ok().map(|t| PhantomRef(t, marker::PhantomData))
        }

        pub fn multisample_color_texture(&self) -> Option<PhantomRef<Texture>> {
            let texture: id = unsafe { msg_send![self.raw_view(), multisampleColorTexture] };
            FromRaw::from_raw(texture).ok().map(|t| PhantomRef(t, marker::PhantomData))
        }

        pub fn preferred_frames_per_second(&self) -> usize {
            let fps: NSUInteger = unsafe { msg_send![self.raw_view(), sampleCount] };
            fps as usize
        }

        pub fn set_preferred_frames_per_second(&self, preferred_fps: usize) {
            let preferred_fps = preferred_fps as NSUInteger;
            unsafe { msg_send![self.raw_view(), setPreferredFramesPerSecond:preferred_fps] }
        }

        pub fn is_paused(&self) -> bool {
            let is_paused: BOOL = unsafe { msg_send![self.raw_view(), isPaused] };
            is_paused == YES
        }

        pub fn draw(&self) {
            unsafe { msg_send![self.raw_view(), draw] }
        }
    }

    #[derive(Clone, Debug)]
    pub struct ViewError(ViewErrorInner);

    #[derive(Clone, Debug)]
    enum ViewErrorInner {
        NoWindow,
        CreateError(FromRawError)
    }

    impl ViewError {
        fn no_window() -> Self {
            ViewError(ViewErrorInner::NoWindow)
        }
    }

    impl fmt::Display for ViewError {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "{}", self.description())
        }
    }

    impl Error for ViewError {
        fn description(&self) -> &str {
            match self.0 {
                ViewErrorInner::NoWindow => "The native window no longer exists",
                ViewErrorInner::CreateError(_) => "There was an issue creating the view",
            }
        }

        fn cause(&self) -> Option<&Error> {
            if let ViewErrorInner::CreateError(ref e) = self.0 {
                Some(e)
            } else {
                None
            }
        }
    }

    impl From<FromRawError> for ViewError {
        fn from(error: FromRawError) -> Self {
            ViewError(ViewErrorInner::CreateError(error))
        }
    }

    pub struct Ref<'a, T: 'a>(&'a T);

    impl<'a, T> Deref for Ref<'a, T> {
        type Target = T;
        fn deref(&self) -> &Self::Target {
            self.0
        }
    }

    pub struct PhantomRef<'a, T: 'a>(T, marker::PhantomData<&'a ()>);

    impl<'a, T> Deref for PhantomRef<'a, T> {
        type Target = T;
        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }

    pub struct PhantomRefMut<'a, T: 'a>(T, marker::PhantomData<&'a mut ()>);

    impl<'a, T> Deref for PhantomRefMut<'a, T> {
        type Target = T;
        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }

    impl<'a, T> DerefMut for PhantomRefMut<'a, T> {
        fn deref_mut(&mut self) -> &mut <Self as Deref>::Target {
            &mut self.0
        }
    }

    pub trait WindowBuilderExt {
        fn build_metal(self, device: Device) -> Result<MetalFacade, CreationError>;
    }

    impl WindowBuilderExt for WindowBuilder {
        fn build_metal(self, device: Device) -> Result<MetalFacade, CreationError> {
            let window = try!(self.build());
            Ok(MetalFacade {
                window: window,
                device: device
            })
        }
    }

    pub struct MetalFacade {
        window: Window,
        device: Device
    }

    impl MetalFacade {
        #[inline]
        pub fn window(&self) -> &Window {
            &self.window
        }

        #[inline]
        pub fn window_mut(&mut self) -> &mut Window {
            &mut self.window
        }

        #[inline]
        pub fn device(&self) -> &Device {
            &self.device
        }

        #[inline]
        pub fn device_mut(&mut self) -> &mut Device {
            &mut self.device
        }

        #[inline]
        pub fn poll_events(&self) -> PollEventsIterator {
            self.window.poll_events()
        }

        #[inline]
        pub fn wait_events(&self) -> WaitEventsIterator {
            self.window.wait_events()
        }
    }

}
<commit_msg>Don't need the MetalFacade<commit_after>pub mod window {
    use cocoa::base::id;
    use cocoa::foundation::NSUInteger;
    use cocoa::appkit::NSWindow;
    use core_graphics::geometry::{CGRect, CGPoint, CGSize};
    use objc::runtime::{BOOL, Class, YES};
    use raw::{AsRaw, FromRaw, FromRawError, IntoRaw};
    use std::error::Error;
    use std::fmt;
    use std::marker;
    use std::ops::{Deref, DerefMut};
    use sys::{MTLClearColor, MTLPixelFormat};
    use winit;
    use winit::os::macos::WindowExt;
    use {ClearColor, Device, PixelFormat, RenderPassDescriptor, Texture};

    pub use winit::{
        CursorState,
        Event,
        MonitorId,
        MouseCursor,
        PollEventsIterator,
        WaitEventsIterator,
        ElementState,
        MouseButton,
        MouseScrollDelta,
        Touch,
        TouchPhase,
        ScanCode,
        VirtualKeyCode
    };

    pub struct WindowBuilder {
        window: winit::WindowBuilder,
        device: Device
    }

    #[derive(Debug)]
    pub enum CreationError {
        ViewCreation(ViewError),
        Winit(winit::CreationError)
    }

    impl fmt::Display for CreationError {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "{}", self.description())
        }
    }

    impl Error for CreationError {
        fn description(&self) -> &str {
            match *self {
                CreationError::ViewCreation(ref e) => e.description(),
                CreationError::Winit(ref e) => e.description()
            }
        }

        fn cause(&self) -> Option<&Error> {
            match *self {
                CreationError::ViewCreation(ref e) => Some(e),
                CreationError::Winit(ref e) => Some(e)
            }
        }
    }

    impl From<winit::CreationError> for CreationError {
        fn from(error: winit::CreationError) -> Self {
            CreationError::Winit(error)
        }
    }

    impl From<ViewError> for CreationError {
        fn from(error: ViewError) -> Self {
            CreationError::ViewCreation(error)
        }
    }

    impl WindowBuilder {
        /// Initializes a new `WindowBuilder` with default values.
        #[inline]
        pub fn new(device: Device) -> Self {
            WindowBuilder {
                window: winit::WindowBuilder::new(),
                device: device
            }
        }

        /// Requests the window to be of specific dimensions.
        ///
        /// Width and height are in pixels.
        #[inline]
        pub fn with_dimensions(self, width: u32, height: u32) -> WindowBuilder {
            WindowBuilder {window: self.window.with_dimensions(width, height), ..self}
        }

        /// Sets a minimum dimension size for the window
        ///
        /// Width and height are in pixels.
        #[inline]
        pub fn with_min_dimensions(self, width: u32, height: u32) -> WindowBuilder {
            WindowBuilder {window: self.window.with_min_dimensions(width, height), ..self}
        }

        /// Sets a maximum dimension size for the window
        ///
        /// Width and height are in pixels.
        #[inline]
        pub fn with_max_dimensions(self, width: u32, height: u32) -> WindowBuilder {
            WindowBuilder {window: self.window.with_max_dimensions(width, height), ..self}
        }

        /// Requests a specific title for the window.
        #[inline]
        pub fn with_title(self, title: String) -> WindowBuilder {
            WindowBuilder {window: self.window.with_title(title), ..self}
        }

        /// Requests fullscreen mode.
        ///
        /// If you don't specify dimensions for the window, it will match the monitor's.
        #[inline]
        pub fn with_fullscreen(self, monitor: MonitorId) -> WindowBuilder {
            WindowBuilder {window: self.window.with_fullscreen(monitor), ..self}
        }

        /// Sets whether the window will be initially hidden or visible.
        #[inline]
        pub fn with_visibility(self, visible: bool) -> WindowBuilder {
            WindowBuilder {window: self.window.with_visibility(visible), ..self}
        }

        /// Sets whether the background of the window should be transparent.
        #[inline]
        pub fn with_transparency(self, transparent: bool) -> WindowBuilder {
            WindowBuilder {window: self.window.with_transparency(transparent), ..self}
        }

        /// Sets whether the window should have a border, a title bar, etc.
        #[inline]
        pub fn with_decorations(self, decorations: bool) -> WindowBuilder {
            WindowBuilder {window: self.window.with_decorations(decorations), ..self}
        }

        /// Enables multitouch
        #[inline]
        pub fn with_multitouch(self) -> WindowBuilder {
            WindowBuilder {window: self.window.with_multitouch(), ..self}
        }

        /// Builds the window.
        ///
        /// Error should be very rare and only occur in case of permission denied, incompatible system,
        /// out of memory, etc.
        pub fn build(self) -> Result<Window, CreationError> {
            let window = try!(self.window.build());
            let view = try!(View::new(&window, self.device));

            unsafe {
                let native_window: id = window.get_nswindow() as id;
                native_window.setContentView_(view.mtk_view.0);
            }

            Ok(Window {
                window: window,
                view: view
            })
        }

        /// Builds the window.
        ///
        /// The context is build in a *strict* way. That means that if the backend couldn't give
        /// you what you requested, an `Err` will be returned.
        #[inline]
        pub fn build_strict(self) -> Result<Window, CreationError> {
            self.build()
        }
    }

    pub struct Window {
        window: winit::Window,
        pub view: View
    }

    impl Window {
        pub fn poll_events(&self) -> PollEventsIterator {
            self.window.poll_events()
        }

        pub fn wait_events(&self) -> WaitEventsIterator {
            self.window.wait_events()
        }

        pub fn window(&self) -> Ref<winit::Window> {
            Ref(&self.window)
        }
    }

    pub struct View {
        mtk_view: MtkView
    }

    struct MtkView(id);
    impl_from_into_raw!(MtkView, of class "MTKView");

    impl View {
        fn new(window: &winit::Window, device: Device) -> Result<Self, ViewError> {
            let window_origin = {
                let (x, y) = try!(window.get_position().ok_or(ViewError::no_window()));
                CGPoint { x: x as f64, y: y as f64 }
            };

            let window_size = {
                let (w, h) = try!(window.get_inner_size().ok_or(ViewError::no_window()));
                CGSize { width: w as f64, height: h as f64 }
            };

            let view_frame = CGRect { origin: window_origin, size: window_size };

            let view_object: id = unsafe {
                // Dummy function to ensure that we link against MetalKit
                #[allow(dead_code)]
                #[link(name = "MetalKit", kind = "framework")]
                extern "C" {
                    fn MTKModelIOVertexDescriptorFromMetal(metalDescriptor: id) -> id;
                }

                let view_class = Class::get("MTKView").expect("Could not find MTKView class");
                let view: id = msg_send![view_class, alloc];
                msg_send![view, initWithFrame:view_frame
                                       device:device.into_raw()]
            };

            Ok(View {
                mtk_view: try!(MtkView::from_raw(view_object)),
            })
        }

        fn raw_view(&self) -> id {
            self.mtk_view.0
        }

        pub fn device<'a>(&self) -> Option<PhantomRef<'a, Device>> {
            let device = unsafe {
                Device::from_raw(msg_send![*self.mtk_view.as_raw(), device])
            };
            device.ok().map(|d| PhantomRef(d, marker::PhantomData))
        }

        pub fn device_mut<'a>(&mut self) -> Option<PhantomRefMut<'a, Device>> {
            let device = unsafe {
                Device::from_raw(msg_send![*self.mtk_view.as_raw(), device])
            };
            device.ok().map(|d| PhantomRefMut(d, marker::PhantomData))
        }

        pub fn clear_color(&self) -> ClearColor {
            let color: MTLClearColor = unsafe {
                msg_send![*self.mtk_view.as_raw(), clearColor]
            };
            color.into()
        }

        pub fn set_clear_color<C: Into<MTLClearColor>>(&mut self, clear_color: C) {
            unsafe { msg_send![*self.mtk_view.as_raw(), setClearColor:clear_color.into()] }
        }

        pub fn clear_depth(&self) -> f64 {
            unsafe { msg_send![*self.mtk_view.as_raw(), clearDepth] }
        }

        pub fn set_clear_depth(&mut self, clear_depth: f64) {
            unsafe { msg_send![*self.mtk_view.as_raw(), setClearDepth:clear_depth] }
        }

        pub fn clear_stencil(&self) -> u32 {
            unsafe { msg_send![*self.mtk_view.as_raw(), clearStencil] }
        }

        pub fn set_clear_stencil(&mut self, clear_stencil: u32) {
            unsafe { msg_send![*self.mtk_view.as_raw(), setClearStencil:clear_stencil] }
        }

        pub fn color_pixel_format(&self) -> PixelFormat {
            let pixel_format: MTLPixelFormat = unsafe {
                msg_send![*self.mtk_view.as_raw(), colorPixelFormat]
            };
            pixel_format.into()
        }

        pub fn set_color_pixel_format<P: Into<MTLPixelFormat>>(&mut self, color_pixel_format: P) {
            unsafe { msg_send![*self.mtk_view.as_raw(), setColorPixelFormat:color_pixel_format.into()] }
        }

        pub fn depth_stencil_pixel_format(&self) -> PixelFormat {
            let pixel_format: MTLPixelFormat = unsafe {
                msg_send![*self.mtk_view.as_raw(), depthStencilPixelFormat]
            };
            pixel_format.into()
        }

        pub fn set_depth_stencil_pixel_format<P: Into<MTLPixelFormat>>(&mut self, depth_stencil_pixel_format: P) {
            unsafe { msg_send![*self.mtk_view.as_raw(), setDepthStencilPixelFormat:depth_stencil_pixel_format.into()] }
        }

        pub fn sample_count(&self) -> usize {
            let sample_count: NSUInteger = unsafe {
                msg_send![*self.mtk_view.as_raw(), sampleCount]
            };
            sample_count as usize
        }

        pub fn set_sample_count(&mut self, sample_count: usize) {
            let sample_count = sample_count as NSUInteger;
            unsafe { msg_send![*self.mtk_view.as_raw(), setSampleCount:sample_count] }
        }

        pub fn current_render_pass_descriptor(&self) -> Option<PhantomRef<RenderPassDescriptor>> {
            let descriptor: id = unsafe { msg_send![self.raw_view(), currentRenderPassDescriptor] };
            FromRaw::from_raw(descriptor).ok().map(|d| PhantomRef(d, marker::PhantomData))
        }

        pub fn current_depth_stencil_texture(&self) -> Option<PhantomRef<Texture>> {
            let texture: id = unsafe { msg_send![self.raw_view(), depthStencilTexture] };
            FromRaw::from_raw(texture).ok().map(|t| PhantomRef(t, marker::PhantomData))
        }

        pub fn multisample_color_texture(&self) -> Option<PhantomRef<Texture>> {
            let texture: id = unsafe { msg_send![self.raw_view(), multisampleColorTexture] };
            FromRaw::from_raw(texture).ok().map(|t| PhantomRef(t, marker::PhantomData))
        }

        pub fn preferred_frames_per_second(&self) -> usize {
            let fps: NSUInteger = unsafe { msg_send![self.raw_view(), sampleCount] };
            fps as usize
        }

        pub fn set_preferred_frames_per_second(&self, preferred_fps: usize) {
            let preferred_fps = preferred_fps as NSUInteger;
            unsafe { msg_send![self.raw_view(), setPreferredFramesPerSecond:preferred_fps] }
        }

        pub fn is_paused(&self) -> bool {
            let is_paused: BOOL = unsafe { msg_send![self.raw_view(), isPaused] };
            is_paused == YES
        }

        pub fn draw(&self) {
            unsafe { msg_send![self.raw_view(), draw] }
        }
    }

    #[derive(Clone, Debug)]
    pub struct ViewError(ViewErrorInner);

    #[derive(Clone, Debug)]
    enum ViewErrorInner {
        NoWindow,
        CreateError(FromRawError)
    }

    impl ViewError {
        fn no_window() -> Self {
            ViewError(ViewErrorInner::NoWindow)
        }
    }

    impl fmt::Display for ViewError {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "{}", self.description())
        }
    }

    impl Error for ViewError {
        fn description(&self) -> &str {
            match self.0 {
                ViewErrorInner::NoWindow => "The native window no longer exists",
                ViewErrorInner::CreateError(_) => "There was an issue creating the view",
            }
        }

        fn cause(&self) -> Option<&Error> {
            if let ViewErrorInner::CreateError(ref e) = self.0 {
                Some(e)
            } else {
                None
            }
        }
    }

    impl From<FromRawError> for ViewError {
        fn from(error: FromRawError) -> Self {
            ViewError(ViewErrorInner::CreateError(error))
        }
    }

    pub struct Ref<'a, T: 'a>(&'a T);

    impl<'a, T> Deref for Ref<'a, T> {
        type Target = T;
        fn deref(&self) -> &Self::Target {
            self.0
        }
    }

    pub struct PhantomRef<'a, T: 'a>(T, marker::PhantomData<&'a ()>);

    impl<'a, T> Deref for PhantomRef<'a, T> {
        type Target = T;
        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }

    pub struct PhantomRefMut<'a, T: 'a>(T, marker::PhantomData<&'a mut ()>);

    impl<'a, T> Deref for PhantomRefMut<'a, T> {
        type Target = T;
        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }

    impl<'a, T> DerefMut for PhantomRefMut<'a, T> {
        fn deref_mut(&mut self) -> &mut <Self as Deref>::Target {
            &mut self.0
        }
    }
}
<|endoftext|>


<commit_before>pub fn nth(n: usize) -> Result<usize, String> {
    if n == 0 {
        Err("For some reason we're 1-indexing…".to_string())
    } else {
        let mut ps = vec![2];
        let mut q = 3;
        while ps.len() < n {
            if ps.iter().all(|p| q % p != 0) {
                ps.push(q);
            }
            q += 2;
        }
        ps.pop().ok_or("OH NO".to_string())
    }
}
<commit_msg>Custom error type<commit_after>#[derive(Debug, PartialEq)]
pub enum NthPrimeError {
    WhyAreWeIndexingFromOneInsteadOfZero,
    IveMadeATerribleMistake,
}

pub fn nth(n: usize) -> Result<usize, NthPrimeError> {
    if n == 0 {
        Err(NthPrimeError::WhyAreWeIndexingFromOneInsteadOfZero)
    } else {
        let mut ps = vec![2];
        let mut q = 3;
        while ps.len() < n {
            if ps.iter().all(|p| q % p != 0) {
                ps.push(q);
            }
            q += 2;
        }
        ps.pop().ok_or(NthPrimeError::IveMadeATerribleMistake)
    }
}
<|endoftext|>


<commit_before>use std::sync::{Arc};
use std::net::{IpAddr};

use trust_dns::op::{Message, Query};
use trust_dns::rr::RData;
use itertools::Itertools;

use utils::{Result};
use cache::RecordSource;
use config::Config;
use resolver::{RcResolver, ErrorKind};
use query::query;
use utils::{IpSet, MessageExt};

pub struct ForwardingResolver {
    server: IpAddr,
    accepted_ips: Option<Arc<IpSet>>,
}
impl ForwardingResolver {
    pub fn create_all(config: &Config) -> Vec<Arc<Self>> {
        config.forwarders.iter()
        .map(|group| group.servers.iter().map(|server| Arc::new(ForwardingResolver {
            server: *server,
            accepted_ips: group.accepted_ip_list.as_ref().map(|x| (**x).clone()),
        })).collect_vec())
        .flatten()
        .collect_vec()
    }
    pub fn resolve(&self, q: Query, parent: RcResolver) -> Result<Message> {
        let msg = try!(query(q.clone(), self.server, *parent.config.query.timeout));
        if let Some(ref ipset) = self.accepted_ips {
            // FIXME: Do we need IPv6 here?
            if msg.answers().iter().any(|x| if let RData::A(address) = *x.rdata()
                { !ipset.test(IpAddr::V4(address)) } else { false })
            {
                // Not in accepted IP list
                return Err(ErrorKind::RejectedIp.into());
            }
        }
        // Treat all messages from forwarder as non-authenticated
        let msg = msg.strip_dnssec_records();
        parent.cache.update_from_message(&msg, RecordSource::Forwarder);
        // Set TTL to 1 second so that clients can come back and fetch better result
        let mut ret = Message::new();
        ret.copy_resp_with(&msg, |rec| {
            let mut new_rec = rec.clone();
            new_rec.set_ttl(1);
            new_rec
        });
        Ok(ret)
    }
}
<commit_msg>Filter bad responses from forwarders<commit_after>use std::sync::{Arc};
use std::net::{IpAddr};

use trust_dns::op::{Message, Query};
use trust_dns::rr::RData;
use itertools::Itertools;

use utils::{Result};
use cache::RecordSource;
use config::Config;
use resolver::{RcResolver, ErrorKind};
use query::query;
use utils::{IpSet, MessageExt};

pub struct ForwardingResolver {
    server: IpAddr,
    accepted_ips: Option<Arc<IpSet>>,
}
impl ForwardingResolver {
    pub fn create_all(config: &Config) -> Vec<Arc<Self>> {
        config.forwarders.iter()
        .map(|group| group.servers.iter().map(|server| Arc::new(ForwardingResolver {
            server: *server,
            accepted_ips: group.accepted_ip_list.as_ref().map(|x| (**x).clone()),
        })).collect_vec())
        .flatten()
        .collect_vec()
    }
    pub fn resolve(&self, q: Query, parent: RcResolver) -> Result<Message> {
        let msg = try!(query(q.clone(), self.server, *parent.config.query.timeout));
        if !msg.answers().iter().any(|x| x.rr_type() == q.query_type()) {
            // Invalid response
            return Err(ErrorKind::RejectedIp.into());
        }
        if let Some(ref ipset) = self.accepted_ips {
            // FIXME: Do we need IPv6 here?
            if msg.answers().iter().any(|x| if let RData::A(address) = *x.rdata()
                { !ipset.test(IpAddr::V4(address)) } else { false })
            {
                // Not in accepted IP list
                return Err(ErrorKind::RejectedIp.into());
            }
        }
        // Treat all messages from forwarder as non-authenticated
        let msg = msg.strip_dnssec_records();
        parent.cache.update_from_message(&msg, RecordSource::Forwarder);
        // Set TTL to 1 second so that clients can come back and fetch better result
        let mut ret = Message::new();
        ret.copy_resp_with(&msg, |rec| {
            let mut new_rec = rec.clone();
            new_rec.set_ttl(1);
            new_rec
        });
        Ok(ret)
    }
}
<|endoftext|>


<commit_before>use std::time;
use std::ops;

use chrono;
use chrono::{Timelike};

#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub struct FloatDuration {
    secs: f64,
}

impl FloatDuration {
    pub fn new(secs: f64) -> FloatDuration {
        FloatDuration {secs}
    }

    pub fn days(days: f64) -> FloatDuration {
        FloatDuration {secs: days * (3600.0 * 24.0)}
    }
    pub fn hours(hours: f64) -> FloatDuration {
        FloatDuration {secs: hours * 3600.0}
    }
    pub fn minutes(mins: f64) -> FloatDuration {
        FloatDuration {secs: mins * 60.0}
    }
    pub fn seconds(secs: f64) -> FloatDuration {
        FloatDuration {secs}
    }
    pub fn milliseconds(millis: f64) -> FloatDuration {
        FloatDuration {secs: millis / 1000.0}
    }
    pub fn microseconds(micros: f64) -> FloatDuration {
        FloatDuration {secs: micros / 1.0e6}
    }
    pub fn nanoseconds(nanos: f64) -> FloatDuration {
        FloatDuration {secs: nanos / 1.0e9}
    }

    pub fn as_days(&self) -> f64 {
        self.secs / (3600.0*24.0)
    }
    pub fn as_hours(&self) -> f64 {
        self.secs / 3600.0
    }
    pub fn as_minutes(&self) -> f64 {
        self.secs / 60.0
    }
    pub fn as_seconds(&self) -> f64 {
        self.secs
    }
    pub fn as_milliseconds(&self) -> f64 {
        self.secs * 1.0e3
    }
    pub fn as_microseconds(&self) -> f64 {
        self.secs * 1.0e6
    }
    pub fn as_nanoseconds(&self) -> f64 {
        self.secs * 1.0e9
    }

    pub fn as_std(&self) -> Option<time::Duration> {
        if self.secs.is_sign_negative() {
            None
        } else {
            let seconds = self.secs.trunc();
            let nanos = self.secs.fract() * 1e9;

            Some(time::Duration::new(seconds as u64, nanos as u32))
        }
    }

    pub fn from_std(duration: time::Duration) -> FloatDuration {
        return FloatDuration::seconds(
            (duration.as_secs() as f64) * (duration.subsec_nanos() as f64)/1.0e-9);
    }
}

impl ops::Neg for FloatDuration {
    type Output = FloatDuration;

    fn neg(self) -> FloatDuration {
        FloatDuration {secs: -self.secs}
    }
}

impl ops::Add<FloatDuration> for FloatDuration {
    type Output = FloatDuration;

    fn add(self, rhs: FloatDuration) -> FloatDuration {
        FloatDuration {secs: self.secs + rhs.secs}
    }
}
impl ops::Sub<FloatDuration> for FloatDuration {
    type Output = FloatDuration;

    fn sub(self, rhs: FloatDuration) -> FloatDuration {
        FloatDuration {secs: self.secs - rhs.secs}
    }
}

impl ops::Mul<f64> for FloatDuration {
    type Output = FloatDuration;

    fn mul(self, rhs: f64) -> FloatDuration {
        FloatDuration {secs: self.secs * rhs}
    }
}
impl ops::Div<f64> for FloatDuration {
    type Output = FloatDuration;

    fn div(self, rhs: f64) -> FloatDuration {
        FloatDuration {secs: self.secs / rhs}
    }
}

impl ops::AddAssign<FloatDuration> for FloatDuration {
    fn add_assign(&mut self, rhs: FloatDuration) {
        self.secs += rhs.secs;
    }
}
impl ops::SubAssign<FloatDuration> for FloatDuration {
    fn sub_assign(&mut self, rhs: FloatDuration) {
        self.secs -= rhs.secs;
    }
}

impl ops::MulAssign<f64> for FloatDuration {
    fn mul_assign(&mut self, rhs: f64) {
        self.secs *= rhs;
    }
}
impl ops::DivAssign<f64> for FloatDuration {
    fn div_assign(&mut self, rhs: f64) {
        self.secs /= rhs;
    }
}
<commit_msg>Further fleshed out duration classes. Added tests.<commit_after>use std::time;
use std::fmt;
use std::ops;

pub const SECS_PER_DAY: f64 = 60.0*60.0*24.0;
pub const SECS_PER_HOUR: f64 = 60.0*60.0;
pub const SECS_PER_MINUTE: f64 = 60.0;

#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub struct FloatDuration {
    secs: f64,
}

#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct DecomposedTime {
    pub days: u32,
    pub hours: u32,
    pub minutes: u32,
    pub seconds: u32,
    pub fractional_seconds: f64,
    pub sign: i8,
}

impl FloatDuration {
    pub fn new(secs: f64) -> FloatDuration {
        FloatDuration {secs}
    }

    pub fn days(days: f64) -> FloatDuration {
        FloatDuration {secs: days * (3600.0 * 24.0)}
    }
    pub fn hours(hours: f64) -> FloatDuration {
        FloatDuration {secs: hours * 3600.0}
    }
    pub fn minutes(mins: f64) -> FloatDuration {
        FloatDuration {secs: mins * 60.0}
    }
    pub fn seconds(secs: f64) -> FloatDuration {
        FloatDuration {secs}
    }
    pub fn milliseconds(millis: f64) -> FloatDuration {
        FloatDuration {secs: millis / 1000.0}
    }
    pub fn microseconds(micros: f64) -> FloatDuration {
        FloatDuration {secs: micros / 1.0e6}
    }
    pub fn nanoseconds(nanos: f64) -> FloatDuration {
        FloatDuration {secs: nanos / 1.0e9}
    }

    pub fn decompose(&self) -> DecomposedTime {
        let mut secs_left = self.secs;

        let days = (secs_left / SECS_PER_DAY).trunc();
        secs_left -= days*SECS_PER_DAY;
        let hours = (secs_left / SECS_PER_HOUR).trunc();
        secs_left -= hours*SECS_PER_HOUR;
        let minutes = (secs_left / SECS_PER_MINUTE).trunc();
        secs_left -= hours*SECS_PER_MINUTE;
        let seconds = secs_left.trunc();
        let fract = secs_left.fract();

        DecomposedTime {
            days: days as u32,
            hours: hours as u32,
            minutes: minutes as u32,
            seconds: seconds as u32,
            fractional_seconds: fract,
            sign: self.secs.signum() as i8,
        }
    }

    pub fn as_days(&self) -> f64 {
        self.secs / SECS_PER_DAY
    }
    pub fn as_hours(&self) -> f64 {
        self.secs / SECS_PER_HOUR
    }
    pub fn as_minutes(&self) -> f64 {
        self.secs / SECS_PER_MINUTE
    }
    pub fn as_seconds(&self) -> f64 {
        self.secs
    }
    pub fn as_milliseconds(&self) -> f64 {
        self.secs * 1.0e3
    }
    pub fn as_microseconds(&self) -> f64 {
        self.secs * 1.0e6
    }
    pub fn as_nanoseconds(&self) -> f64 {
        self.secs * 1.0e9
    }

    pub fn zero() -> FloatDuration {
        FloatDuration {secs: 0.0}
    }
    pub fn is_zero(&self) -> bool {
        self.secs == 0.0
    }
    pub fn is_positive(&self) -> bool {
        self.secs.is_sign_positive()
    }
    pub fn is_negative(&self) -> bool {
        self.secs.is_sign_negative()
    }

    pub fn as_std(&self) -> Option<time::Duration> {
        if self.secs.is_sign_negative() {
            None
        } else {
            let seconds = self.secs.trunc();
            let nanos = self.secs.fract() * 1e9;

            Some(time::Duration::new(seconds as u64, nanos as u32))
        }
    }

    pub fn from_std(duration: time::Duration) -> FloatDuration {
        return FloatDuration::seconds(
            (duration.as_secs() as f64) + (duration.subsec_nanos() as f64)*1.0e-9);
    }

    pub fn from_decomposed(decomposed: &DecomposedTime) -> FloatDuration {
        let seconds = (decomposed.days as f64)*SECS_PER_DAY
            + (decomposed.hours as f64)*SECS_PER_HOUR
            + (decomposed.minutes as f64)*SECS_PER_MINUTE
            + (decomposed.seconds as f64)
            + decomposed.fractional_seconds;

        FloatDuration {
            secs: seconds
        }
    }
}

impl DecomposedTime {
    pub fn from_components(days: u32, hours: u32, minutes: u32,
               seconds: u32, fractional_seconds: f64) -> DecomposedTime
    {
        DecomposedTime {
            days, hours, minutes, seconds, fractional_seconds, sign: 1}
    }

    pub fn negate(mut self) -> DecomposedTime {
        self.sign *= -1;
        self
    }
}

impl fmt::Display for FloatDuration {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let decompose_time = self.decompose();

        if decompose_time.days > 0 {
            write!(fmt, "{}d ", decompose_time.days as u64)?;
        }

        if decompose_time.sign.is_negative() {
            write!(fmt, "-")?;
        }
        write!(fmt, "{:02}:{:02}:{:02}.{}",
            decompose_time.hours,
            decompose_time.minutes,
            decompose_time.seconds,
            decompose_time.fractional_seconds)
    }
}

impl ops::Neg for FloatDuration {
    type Output = FloatDuration;

    fn neg(self) -> FloatDuration {
        FloatDuration {secs: -self.secs}
    }
}

impl ops::Add<FloatDuration> for FloatDuration {
    type Output = FloatDuration;

    fn add(self, rhs: FloatDuration) -> FloatDuration {
        FloatDuration {secs: self.secs + rhs.secs}
    }
}
impl ops::Sub<FloatDuration> for FloatDuration {
    type Output = FloatDuration;

    fn sub(self, rhs: FloatDuration) -> FloatDuration {
        FloatDuration {secs: self.secs - rhs.secs}
    }
}

impl ops::Mul<f64> for FloatDuration {
    type Output = FloatDuration;

    fn mul(self, rhs: f64) -> FloatDuration {
        FloatDuration {secs: self.secs * rhs}
    }
}
impl ops::Div<f64> for FloatDuration {
    type Output = FloatDuration;

    fn div(self, rhs: f64) -> FloatDuration {
        FloatDuration {secs: self.secs / rhs}
    }
}

impl ops::AddAssign<FloatDuration> for FloatDuration {
    fn add_assign(&mut self, rhs: FloatDuration) {
        self.secs += rhs.secs;
    }
}
impl ops::SubAssign<FloatDuration> for FloatDuration {
    fn sub_assign(&mut self, rhs: FloatDuration) {
        self.secs -= rhs.secs;
    }
}

impl ops::MulAssign<f64> for FloatDuration {
    fn mul_assign(&mut self, rhs: f64) {
        self.secs *= rhs;
    }
}
impl ops::DivAssign<f64> for FloatDuration {
    fn div_assign(&mut self, rhs: f64) {
        self.secs /= rhs;
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::time;

    #[test]
    fn test_construct() {
        let duration1 = FloatDuration::hours(3.0);
        assert_eq!(duration1.as_hours(), 3.0);
        assert_eq!(duration1.as_minutes(), 180.0);
        assert_eq!(duration1.as_seconds(), 180.0*60.0);
        assert_eq!(duration1.as_days(), 3.0/24.0);
        assert_eq!(duration1.as_milliseconds(), 180.0*60.0*1000.0);

        let duration2 = FloatDuration::milliseconds(55.0);
        assert_eq!(duration2.as_seconds(), 0.055);
        assert_eq!(duration2.as_milliseconds(), 55.0);
        assert_eq!(duration2.as_microseconds(), 55000.0);
        assert_eq!(duration2.as_nanoseconds(), 55000000.0);
        assert!(!duration2.is_zero());

        let duration3 = FloatDuration::zero();
        assert!(duration3.is_zero());

        assert_eq!(FloatDuration::days(1.5), FloatDuration::hours(36.0));
        assert_eq!(FloatDuration::minutes(30.0), FloatDuration::hours(0.5));
        assert_eq!(FloatDuration::seconds(180.0), FloatDuration::minutes(3.0));
        assert_eq!(FloatDuration::seconds(3.5), FloatDuration::milliseconds(3500.0));
        assert_eq!(FloatDuration::microseconds(300.0), FloatDuration::milliseconds(0.30));
        assert_eq!(FloatDuration::nanoseconds(1000.0), FloatDuration::microseconds(1.0));
    }

    #[test]
    fn test_arithmetic() {
        let duration1 = FloatDuration::minutes(5.0) + FloatDuration::seconds(30.0);
        assert_eq!(duration1, FloatDuration::seconds(330.0));

        let duration2 = FloatDuration::hours(3.0) * 2.5;
        assert_eq!(duration2, FloatDuration::hours(7.5));

        let duration3 = FloatDuration::days(3.0) / 3.0 - FloatDuration::hours(2.0);
        assert_eq!(duration3, FloatDuration::hours(22.0));

        let duration4 = FloatDuration::zero() + FloatDuration::milliseconds(500.0)
            + FloatDuration::microseconds(500.0);
        assert_eq!(duration4, FloatDuration::microseconds(500500.0));

    }

    #[test]
    fn test_std_conversion() {
        let duration1 = FloatDuration::minutes(5.0);
        let std_duration1 = duration1.as_std().unwrap();
        assert!(duration1.is_positive());
        assert_eq!(std_duration1, time::Duration::new(300, 0));
        assert_eq!(FloatDuration::from_std(std_duration1), duration1);

        let duration2 = FloatDuration::hours(-2.0);
        assert!(duration2.is_negative());
        assert_eq!(duration2.as_std(), None);
        let std_duration2 = (-duration2).as_std().unwrap();
        assert_eq!(std_duration2, time::Duration::new(3600*2, 0));
        assert_eq!(FloatDuration::from_std(std_duration2), -duration2);
    }
}
<|endoftext|>