<commit_before>use rustc_front::hir::*;
use rustc::lint::{LateLintPass, LateContext, LintArray, LintPass};
use rustc_front::intravisit::{Visitor, walk_expr};
use utils::*;

/// **What it does:** This lint checks for `if` conditions that use blocks to contain an expression. It is `Warn` by default.
///
/// **Why is this bad?** It isn't really rust style, same as using parentheses to contain expressions.
///
/// **Known problems:** None
///
/// **Example:** `if { true } ..`
declare_lint! {
    pub BLOCK_IN_IF_CONDITION_EXPR, Warn,
    "braces can be eliminated in conditions that are expressions, e.g `if { true } ...`"
}

/// **What it does:** This lint checks for `if` conditions that use blocks containing statements, or conditions that use closures with blocks. It is `Warn` by default.
///
/// **Why is this bad?** Using blocks in the condition makes it hard to read.
///
/// **Known problems:** None
///
/// **Example:** `if { let x = somefunc(); x } ..` or `if somefunc(|x| { x == 47 }) ..`
declare_lint! {
    pub BLOCK_IN_IF_CONDITION_STMT, Warn,
    "avoid complex blocks in conditions, instead move the block higher and bind it \
    with 'let'; e.g: `if { let x = true; x } ...`"
}

#[derive(Copy,Clone)]
pub struct BlockInIfCondition;

impl LintPass for BlockInIfCondition {
    fn get_lints(&self) -> LintArray {
        lint_array!(BLOCK_IN_IF_CONDITION_EXPR, BLOCK_IN_IF_CONDITION_STMT)
    }
}

struct ExVisitor<'v> {
    found_block: Option<&'v Expr>,
}

impl<'v> Visitor<'v> for ExVisitor<'v> {
    fn visit_expr(&mut self, expr: &'v Expr) {
        if let ExprClosure(_, _, ref block) = expr.node {
            let complex = {
                if !block.stmts.is_empty() {
                    true
                } else {
                    if let Some(ref ex) = block.expr {
                        match ex.node {
                            ExprBlock(_) => true,
                            _ => false,
                        }
                    } else {
                        false
                    }
                }
            };
            if complex {
                self.found_block = Some(&expr);
                return;
            }
        }
        walk_expr(self, expr);
    }
}

const BRACED_EXPR_MESSAGE: &'static str = "omit braces around single expression condition";
const COMPLEX_BLOCK_MESSAGE: &'static str = "in an 'if' condition, avoid complex blocks or closures with blocks; \
                                             instead, move the block or closure higher and bind it with a 'let'";

impl LateLintPass for BlockInIfCondition {
    fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
        if let ExprIf(ref check, ref then, _) = expr.node {
            if let ExprBlock(ref block) = check.node {
                if block.rules == DefaultBlock {
                    if block.stmts.is_empty() {
                        if let Some(ref ex) = block.expr {
                            // don't dig into the expression here, just suggest that they remove
                            // the block
                            if differing_macro_contexts(expr.span, ex.span) {
                                return;
                            }
                            span_help_and_lint(cx,
                                               BLOCK_IN_IF_CONDITION_EXPR,
                                               check.span,
                                               BRACED_EXPR_MESSAGE,
                                               &format!("try\nif {} {} ... ",
                                                        snippet_block(cx, ex.span, ".."),
                                                        snippet_block(cx, then.span, "..")));
                        }
                    } else {
                        if differing_macro_contexts(expr.span, block.stmts[0].span) {
                            return;
                        }
                        // move block higher
                        span_help_and_lint(cx,
                                           BLOCK_IN_IF_CONDITION_STMT,
                                           check.span,
                                           COMPLEX_BLOCK_MESSAGE,
                                           &format!("try\nlet res = {};\nif res {} ... ",
                                                    snippet_block(cx, block.span, ".."),
                                                    snippet_block(cx, then.span, "..")));
                    }
                }
            } else {
                let mut visitor = ExVisitor { found_block: None };
                walk_expr(&mut visitor, check);
                if let Some(ref block) = visitor.found_block {
                    span_help_and_lint(cx, BLOCK_IN_IF_CONDITION_STMT, block.span, COMPLEX_BLOCK_MESSAGE, "");
                }
            }
        }
    }
}
<commit_msg>Stronger macro check<commit_after>use rustc_front::hir::*;
use rustc::lint::{LateLintPass, LateContext, LintArray, LintPass};
use rustc_front::intravisit::{Visitor, walk_expr};
use utils::*;

/// **What it does:** This lint checks for `if` conditions that use blocks to contain an expression. It is `Warn` by default.
///
/// **Why is this bad?** It isn't really rust style, same as using parentheses to contain expressions.
///
/// **Known problems:** None
///
/// **Example:** `if { true } ..`
declare_lint! {
    pub BLOCK_IN_IF_CONDITION_EXPR, Warn,
    "braces can be eliminated in conditions that are expressions, e.g `if { true } ...`"
}

/// **What it does:** This lint checks for `if` conditions that use blocks containing statements, or conditions that use closures with blocks. It is `Warn` by default.
///
/// **Why is this bad?** Using blocks in the condition makes it hard to read.
///
/// **Known problems:** None
///
/// **Example:** `if { let x = somefunc(); x } ..` or `if somefunc(|x| { x == 47 }) ..`
declare_lint! {
    pub BLOCK_IN_IF_CONDITION_STMT, Warn,
    "avoid complex blocks in conditions, instead move the block higher and bind it \
    with 'let'; e.g: `if { let x = true; x } ...`"
}

#[derive(Copy,Clone)]
pub struct BlockInIfCondition;

impl LintPass for BlockInIfCondition {
    fn get_lints(&self) -> LintArray {
        lint_array!(BLOCK_IN_IF_CONDITION_EXPR, BLOCK_IN_IF_CONDITION_STMT)
    }
}

struct ExVisitor<'v> {
    found_block: Option<&'v Expr>,
}

impl<'v> Visitor<'v> for ExVisitor<'v> {
    fn visit_expr(&mut self, expr: &'v Expr) {
        if let ExprClosure(_, _, ref block) = expr.node {
            let complex = {
                if !block.stmts.is_empty() {
                    true
                } else {
                    if let Some(ref ex) = block.expr {
                        match ex.node {
                            ExprBlock(_) => true,
                            _ => false,
                        }
                    } else {
                        false
                    }
                }
            };
            if complex {
                self.found_block = Some(&expr);
                return;
            }
        }
        walk_expr(self, expr);
    }
}

const BRACED_EXPR_MESSAGE: &'static str = "omit braces around single expression condition";
const COMPLEX_BLOCK_MESSAGE: &'static str = "in an 'if' condition, avoid complex blocks or closures with blocks; \
                                             instead, move the block or closure higher and bind it with a 'let'";

impl LateLintPass for BlockInIfCondition {
    fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
        if let ExprIf(ref check, ref then, _) = expr.node {
            if let ExprBlock(ref block) = check.node {
                if block.rules == DefaultBlock {
                    if block.stmts.is_empty() {
                        if let Some(ref ex) = block.expr {
                            // don't dig into the expression here, just suggest that they remove
                            // the block
                            if in_macro(cx, expr.span) || differing_macro_contexts(expr.span, ex.span) {
                                return;
                            }
                            span_help_and_lint(cx,
                                               BLOCK_IN_IF_CONDITION_EXPR,
                                               check.span,
                                               BRACED_EXPR_MESSAGE,
                                               &format!("try\nif {} {} ... ",
                                                        snippet_block(cx, ex.span, ".."),
                                                        snippet_block(cx, then.span, "..")));
                        }
                    } else {
                        if in_macro(cx, expr.span) || differing_macro_contexts(expr.span, block.stmts[0].span) {
                            return;
                        }
                        // move block higher
                        span_help_and_lint(cx,
                                           BLOCK_IN_IF_CONDITION_STMT,
                                           check.span,
                                           COMPLEX_BLOCK_MESSAGE,
                                           &format!("try\nlet res = {};\nif res {} ... ",
                                                    snippet_block(cx, block.span, ".."),
                                                    snippet_block(cx, then.span, "..")));
                    }
                }
            } else {
                let mut visitor = ExVisitor { found_block: None };
                walk_expr(&mut visitor, check);
                if let Some(ref block) = visitor.found_block {
                    span_help_and_lint(cx, BLOCK_IN_IF_CONDITION_STMT, block.span, COMPLEX_BLOCK_MESSAGE, "");
                }
            }
        }
    }
}
<|endoftext|>


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

use std::fs;
use std::path::Path;

use build::Build;

pub fn clean(build: &Build) {
    for host in build.config.host.iter() {

        let out = build.out.join(host);

        rm_rf(build, &out.join("compiler-rt"));

        for stage in 0..4 {
            rm_rf(build, &out.join(format!("stage{}", stage)));
            rm_rf(build, &out.join(format!("stage{}-std", stage)));
            rm_rf(build, &out.join(format!("stage{}-rustc", stage)));
        }
    }
}

fn rm_rf(build: &Build, path: &Path) {
    if path.exists() {
        build.verbose(&format!("removing `{}`", path.display()));
        t!(fs::remove_dir_all(path));
    }
}
<commit_msg>Auto merge of #33042 - alexcrichton:clean-doc, r=nikomatsakis<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::fs;
use std::path::Path;

use build::Build;

pub fn clean(build: &Build) {
    for host in build.config.host.iter() {

        let out = build.out.join(host);

        rm_rf(build, &out.join("compiler-rt"));
        rm_rf(build, &out.join("doc"));

        for stage in 0..4 {
            rm_rf(build, &out.join(format!("stage{}", stage)));
            rm_rf(build, &out.join(format!("stage{}-std", stage)));
            rm_rf(build, &out.join(format!("stage{}-rustc", stage)));
            rm_rf(build, &out.join(format!("stage{}-test", stage)));
            rm_rf(build, &out.join(format!("stage{}-tools", stage)));
        }
    }
}

fn rm_rf(build: &Build, path: &Path) {
    if path.exists() {
        build.verbose(&format!("removing `{}`", path.display()));
        t!(fs::remove_dir_all(path));
    }
}
<|endoftext|>


<commit_before>//! CGRAM definitions and methods

use super::Rgb;

/// Color RAM size in Bytes
pub const CGRAM_SIZE: usize = 512;

byte_array!(pub Cgram[CGRAM_SIZE] with u16 indexing, save state please);

impl Cgram {
    /// Looks up a color index in the CGRAM and converts the stored 15-bit BGR color to 24-bit RGB
    /// (the 15-bit range is stretched to 24 bits).
    ///
    /// CGRAM contains 256 colors, so any index is valid.
    pub fn get_color(&self, index: u8) -> Rgb {
        let (r, g, b) = self.get_color_unadjusted(index);

        // Convert to RGB
        let mut rgb = Rgb { r: (r as u8) << 3, g: (g as u8) << 3, b: (b as u8) << 3 };

        // Adjust color range
        rgb.r += rgb.r / 32;
        rgb.g += rgb.g / 32;
        rgb.b += rgb.b / 32;

        rgb
    }

    /// Looks up a color in CGRAM and returns the RGB color values stored inside, without adjusting
    /// the color range to full RGB.
    pub fn get_color_unadjusted(&self, color: u8) -> (u8, u8, u8) {
        // -bbbbbgg gggrrrrr (16-bit big endian value! (high byte, high address first))
        let val = self.get_color_raw(color);

        // Extract components
        let b = (val & 0x7c00) >> 10;
        let g = (val & 0x03e0) >> 5;
        let r = val & 0x001f;

        (r as u8, g as u8, b as u8)
    }

    /// Gets the raw, 16-bit (technically 15), big endian color value stored at the given color
    /// index
    pub fn get_color_raw(&self, color: u8) -> u16 {
        // -bbbbbgg gggrrrrr (16-bit big endian value! (high byte, high address first))
        let lo = self[color as u16 * 2] as u16;
        let hi = self[color as u16 * 2 + 1] as u16;
        let val = (hi << 8) | lo;
        val
    }
}
<commit_msg>Add Cgram::set_color_raw<commit_after>//! CGRAM definitions and methods

use super::Rgb;

/// Color RAM size in Bytes
pub const CGRAM_SIZE: usize = 512;

byte_array!(pub Cgram[CGRAM_SIZE] with u16 indexing, save state please);

impl Cgram {
    /// Looks up a color index in the CGRAM and converts the stored 15-bit BGR color to 24-bit RGB
    /// (the 15-bit range is stretched to 24 bits).
    ///
    /// CGRAM contains 256 colors, so any index is valid.
    pub fn get_color(&self, index: u8) -> Rgb {
        let (r, g, b) = self.get_color_unadjusted(index);

        // Convert to RGB
        let mut rgb = Rgb { r: (r as u8) << 3, g: (g as u8) << 3, b: (b as u8) << 3 };

        // Adjust color range
        rgb.r += rgb.r / 32;
        rgb.g += rgb.g / 32;
        rgb.b += rgb.b / 32;

        rgb
    }

    /// Looks up a color in CGRAM and returns the RGB color values stored inside, without adjusting
    /// the color range to full RGB.
    pub fn get_color_unadjusted(&self, color: u8) -> (u8, u8, u8) {
        // -bbbbbgg gggrrrrr (16-bit big endian value! (high byte, high address first))
        let val = self.get_color_raw(color);

        // Extract components
        let b = (val & 0x7c00) >> 10;
        let g = (val & 0x03e0) >> 5;
        let r = val & 0x001f;

        (r as u8, g as u8, b as u8)
    }

    /// Gets the raw, 16-bit (technically 15), big endian color value stored at the given color
    /// index
    pub fn get_color_raw(&self, color: u8) -> u16 {
        // -bbbbbgg gggrrrrr (16-bit big endian value! (high byte, high address first))
        let lo = self[color as u16 * 2] as u16;
        let hi = self[color as u16 * 2 + 1] as u16;
        let val = (hi << 8) | lo;
        val
    }

    /// Set a raw color value
    ///
    /// `-bbbbbgg gggrrrrr` (16-bit big endian value! (high byte, high address first))
    pub fn set_color_raw(&mut self, index: u8, raw: u16) {
        self[index as u16 * 2] = raw as u8;
        self[index as u16 * 2 + 1] = (raw >> 8) as u8;
    }
}
<|endoftext|>


<commit_before>use tokenizer::{ParseResult};
use tokenizer::TomlFragment::Integer;

pub fn parse_integer(s : &str) -> Option<ParseResult> {
    if s.is_empty() {
        return None;
    }

    let first_char = s.char_at(0);
    if !(first_char == '+' || first_char == '-' || first_char.is_digit(10)) {
        return None;
    }

    let index : usize =
        if first_char == '+' || first_char == '-' { 1 }
        else { 0 };

    match get_end_of_number(&s[index..]) {
        None => None,
        Some(end_index) => {
            let fragment = Integer(&s[..index + end_index]);
            let remainder = &s[index + end_index..];

            //if this didn't end the token, this token isn't an Integer
            if !(remainder.is_empty() || remainder.char_at(0).is_whitespace()) {
                return None;
            }

            Some(ParseResult { fragment: fragment, remainder: remainder })
        }
    }
}

pub fn get_end_of_number(s : &str) -> Option<usize> {
    if s.is_empty() {
        return None;
    }

    if !s.char_at(0).is_digit(10) {
        return None;
    }

    let mut index : usize = 0;

    for c in s.chars() {
        if !c.is_digit(10) {
            break;
        }

        index = index + 1;
    }

    Some(index)
}

#[test]
fn parse_integer_empty_str() {
    assert_eq!(None, parse_integer(""));
}

#[test]
fn parse_integer_text() {
    assert_eq!(None, parse_integer("gw"));
}

#[test]
fn parse_integer_one_digit() {
    let expected = ParseResult { fragment: Integer("9"), remainder: "" };
    assert_eq!(Some(expected), parse_integer("9"));
}

#[test]
fn parse_integer_two_digits() {
    let expected = ParseResult { fragment: Integer("55"), remainder: "" };
    assert_eq!(Some(expected), parse_integer("55"));
}

#[test]
fn parse_integer_positive() {
    let expected = ParseResult { fragment: Integer("+123"), remainder: "" };
    assert_eq!(Some(expected), parse_integer("+123"));
}

#[test]
fn parse_integer_negative() {
    let expected = ParseResult { fragment: Integer("-987"), remainder: "" };
    assert_eq!(Some(expected), parse_integer("-987"));
}

#[test]
fn parse_integer_number_trailing_whitespace() {
    let expected = ParseResult { fragment: Integer("33"), remainder: " " };
    assert_eq!(Some(expected), parse_integer("33 "));
}

#[test]
fn parse_integer_almost_an_int() {
    assert_eq!(None, parse_integer("12345abc"));
}

#[test]
fn parse_integer_decimal() {
    assert_eq!(None, parse_integer("123.456"));
}

#[test]
fn get_end_of_number_empty_str() {
    assert_eq!(None, get_end_of_number(""));
}

#[test]
fn get_end_of_number_text() {
    assert_eq!(None, get_end_of_number("awf"));
}

#[test]
fn get_end_of_number_one_digit() {
    assert_eq!(Some(1), get_end_of_number("5"));
}

#[test]
fn get_end_of_number_two_digits() {
    assert_eq!(Some(2), get_end_of_number("12"));
}
<commit_msg>The integer tokenizer is too specific<commit_after>use tokenizer::{ParseResult};
use tokenizer::TomlFragment::Integer;

pub fn parse_integer(s : &str) -> Option<ParseResult> {
    if s.is_empty() {
        return None;
    }

    let first_char = s.char_at(0);
    if !(first_char == '+' || first_char == '-' || first_char.is_digit(10)) {
        return None;
    }

    let index : usize =
        if first_char == '+' || first_char == '-' { 1 }
        else { 0 };

    match get_end_of_number(&s[index..]) {
        None => None,
        Some(end_index) => {
            let fragment = Integer(&s[..index + end_index]);
            let remainder = &s[index + end_index..];

            //if the next char is a '.', then this isn't an Integer
            if !remainder.is_empty() && remainder.char_at(0) == '.' {
                return None;
            }

            Some(ParseResult { fragment: fragment, remainder: remainder })
        }
    }
}

pub fn get_end_of_number(s : &str) -> Option<usize> {
    if s.is_empty() {
        return None;
    }

    if !s.char_at(0).is_digit(10) {
        return None;
    }

    let mut index : usize = 0;

    for c in s.chars() {
        if !c.is_digit(10) {
            break;
        }

        index = index + 1;
    }

    Some(index)
}

#[test]
fn parse_integer_empty_str() {
    assert_eq!(None, parse_integer(""));
}

#[test]
fn parse_integer_text() {
    assert_eq!(None, parse_integer("gw"));
}

#[test]
fn parse_integer_one_digit() {
    let expected = ParseResult { fragment: Integer("9"), remainder: "" };
    assert_eq!(Some(expected), parse_integer("9"));
}

#[test]
fn parse_integer_two_digits() {
    let expected = ParseResult { fragment: Integer("55"), remainder: "" };
    assert_eq!(Some(expected), parse_integer("55"));
}

#[test]
fn parse_integer_positive() {
    let expected = ParseResult { fragment: Integer("+123"), remainder: "" };
    assert_eq!(Some(expected), parse_integer("+123"));
}

#[test]
fn parse_integer_negative() {
    let expected = ParseResult { fragment: Integer("-987"), remainder: "" };
    assert_eq!(Some(expected), parse_integer("-987"));
}

#[test]
fn parse_integer_number_trailing_whitespace() {
    let expected = ParseResult { fragment: Integer("33"), remainder: " " };
    assert_eq!(Some(expected), parse_integer("33 "));
}

#[test]
fn parse_integer_decimal() {
    assert_eq!(None, parse_integer("123.456"));
}

#[test]
fn get_end_of_number_empty_str() {
    assert_eq!(None, get_end_of_number(""));
}

#[test]
fn get_end_of_number_text() {
    assert_eq!(None, get_end_of_number("awf"));
}

#[test]
fn get_end_of_number_one_digit() {
    assert_eq!(Some(1), get_end_of_number("5"));
}

#[test]
fn get_end_of_number_two_digits() {
    assert_eq!(Some(2), get_end_of_number("12"));
}
<|endoftext|>


<commit_before>extern crate orbclient;

use orbclient::Color;

use std::io::{Read, Write};
use std::process::{Command, Stdio};
use std::sync::{Arc, Mutex};
use std::thread;

use window::{ConsoleEvent, ConsoleWindow};

mod window;

fn main() {
    let mut window = ConsoleWindow::new(-1, -1, 576, 400, "Terminal");

    let shell = "../ion/target/debug/ion-shell";
    match Command::new(shell)
            .stdin(Stdio::piped())
            .stdout(Stdio::piped())
            .stderr(Stdio::piped())
            .spawn()
    {
        Ok(process) => {
            let output_mutex = Arc::new(Mutex::new(Vec::new()));

            {
                let mut stdout = process.stdout.unwrap();
                let stdout_output_mutex = output_mutex.clone();
                thread::spawn(move || {
                    'stdout: loop {
                        let mut buf = [0; 4096];
                        match stdout.read(&mut buf) {
                            Ok(0) => break 'stdout,
                            Ok(count) => match stdout_output_mutex.lock() {
                                Ok(mut stdout_output) => stdout_output.extend_from_slice(&buf[..count]),
                                Err(err) => {
                                    println!("failed to lock stdout output mutex: {}", err);
                                    break 'stdout;
                                }
                            },
                            Err(err) => {
                                println!("failed to read stdout: {}", err);
                                break 'stdout;
                            }
                        }
                    }
                });
            }

            {
                let mut stderr = process.stderr.unwrap();
                let stderr_output_mutex = output_mutex.clone();
                thread::spawn(move || {
                    'stderr: loop {
                        let mut buf = [0; 4096];
                        match stderr.read(&mut buf) {
                            Ok(0) => break 'stderr,
                            Ok(count) => match stderr_output_mutex.lock() {
                                Ok(mut stderr_output) => stderr_output.extend_from_slice(&buf[..count]),
                                Err(err) => {
                                    println!("failed to lock stderr output mutex: {}", err);
                                    break 'stderr;
                                }
                            },
                            Err(err) => {
                                println!("failed to read stderr: {}", err);
                                break 'stderr;
                            }
                        }
                    }
                });
            }

            let mut stdin = process.stdin.unwrap();
            'events: loop {
                match output_mutex.lock() {
                    Ok(mut output) => {
                        let mut string = String::new();
                        for byte in output.drain(..) {
                            string.push(byte as char);
                        }
                        window.print(&string, Color::rgb(255, 255, 255));
                    },
                    Err(err) => {
                        println!("failed to lock print output mutex: {}", err);
                        break 'events;
                    }
                }

                for console_event in window.read() {
                    match console_event {
                        ConsoleEvent::Line(mut line) => {
                            line.push('\n');
                            match stdin.write(&line.as_bytes()) {
                                Ok(_) => (),
                                Err(err) => {
                                    println!("failed to write stdin: {}", err);
                                    break 'events;
                                }
                            }
                        },
                        ConsoleEvent::Quit => break 'events
                    }
                }

                thread::sleep_ms(30);
            }
        },
        Err(err) => println!("failed to execute '{}': {}\n", shell, err)
    }
}
<commit_msg>Specify command as first argument<commit_after>extern crate orbclient;

use orbclient::Color;

use std::env;
use std::io::{Read, Write};
use std::process::{Command, Stdio};
use std::sync::{Arc, Mutex};
use std::thread;

use window::{ConsoleEvent, ConsoleWindow};

mod window;

fn main() {
    let mut window = ConsoleWindow::new(-1, -1, 576, 400, "Terminal");

    let shell = env::args().nth(1).unwrap_or("sh".to_string());
    match Command::new(&shell)
            .stdin(Stdio::piped())
            .stdout(Stdio::piped())
            .stderr(Stdio::piped())
            .spawn()
    {
        Ok(process) => {
            let output_mutex = Arc::new(Mutex::new(Vec::new()));

            {
                let mut stdout = process.stdout.unwrap();
                let stdout_output_mutex = output_mutex.clone();
                thread::spawn(move || {
                    'stdout: loop {
                        let mut buf = [0; 4096];
                        match stdout.read(&mut buf) {
                            Ok(0) => break 'stdout,
                            Ok(count) => match stdout_output_mutex.lock() {
                                Ok(mut stdout_output) => stdout_output.extend_from_slice(&buf[..count]),
                                Err(err) => {
                                    println!("failed to lock stdout output mutex: {}", err);
                                    break 'stdout;
                                }
                            },
                            Err(err) => {
                                println!("failed to read stdout: {}", err);
                                break 'stdout;
                            }
                        }
                    }
                });
            }

            {
                let mut stderr = process.stderr.unwrap();
                let stderr_output_mutex = output_mutex.clone();
                thread::spawn(move || {
                    'stderr: loop {
                        let mut buf = [0; 4096];
                        match stderr.read(&mut buf) {
                            Ok(0) => break 'stderr,
                            Ok(count) => match stderr_output_mutex.lock() {
                                Ok(mut stderr_output) => stderr_output.extend_from_slice(&buf[..count]),
                                Err(err) => {
                                    println!("failed to lock stderr output mutex: {}", err);
                                    break 'stderr;
                                }
                            },
                            Err(err) => {
                                println!("failed to read stderr: {}", err);
                                break 'stderr;
                            }
                        }
                    }
                });
            }

            let mut stdin = process.stdin.unwrap();
            'events: loop {
                match output_mutex.lock() {
                    Ok(mut output) => {
                        let mut string = String::new();
                        for byte in output.drain(..) {
                            string.push(byte as char);
                        }
                        window.print(&string, Color::rgb(255, 255, 255));
                    },
                    Err(err) => {
                        println!("failed to lock print output mutex: {}", err);
                        break 'events;
                    }
                }

                for console_event in window.read() {
                    match console_event {
                        ConsoleEvent::Line(mut line) => {
                            line.push('\n');
                            match stdin.write(&line.as_bytes()) {
                                Ok(_) => (),
                                Err(err) => {
                                    println!("failed to write stdin: {}", err);
                                    break 'events;
                                }
                            }
                        },
                        ConsoleEvent::Quit => break 'events
                    }
                }

                thread::sleep_ms(30);
            }
        },
        Err(err) => println!("failed to execute '{}': {}\n", shell, err)
    }
}
<|endoftext|>


<commit_before>
mod daterecord;
mod direction;
mod error;
mod timeentry;
mod traits;
mod iterators;

pub use self::daterecord::DateRecord;
pub use self::direction::Direction;
pub use self::error::TimeClockError;
pub use self::iterators::*;
pub use self::timeentry::{TimeEntry, TimeEntryPair};
pub use self::traits::*;
use chrono::*;
use csv;
use std::io::SeekFrom;
use std::io::prelude::*;

pub fn read_timesheet<R: Read>(file: R)
                               -> Result<Vec<TimeEntry>, TimeClockError> {
    let mut rdr = csv::ReaderBuilder::new()
        .has_headers(false)
        .from_reader(file);
    let mut in_v: Vec<TimeEntry> = try!(rdr.deserialize().collect());
    in_v.sort_by_key(|k| k.time);
    Ok(in_v)
}

/// Reduce pairs of `TimeEntrys` into `DateRecords`
pub fn collect_date_records(records: Vec<TimeEntry>) -> Vec<DateRecord> {
    let mut res: Vec<DateRecord> = Vec::new();
    for rec in timeentry_pairs(records.into_iter()).daterecords() {
        match res.pop() {
            Some(mut r) => {
                if r.combine(&rec) {
                    res.push(r);
                } else {
                    res.push(r);
                    res.push(rec);
                }
            }
            None => res.push(rec),
        }
    }
    res
}

/// Marks the time.
pub fn mark_time<W: Write + Seek>(dir: Direction,
                                  time: DateTime<FixedOffset>,
                                  memo: &str,
                                  file: &mut W) {
    let record = TimeEntry::new(dir, time, memo);
    // seek in case we write without reading first
    let _ = file.seek(SeekFrom::End(0));
    let mut wtr = csv::WriterBuilder::new()
        .has_headers(false)
        .from_writer(file);
    let _ = wtr.serialize(record);
}

/// Get the current date and time as a `DateTime`<`FixedOffset`>
pub fn now() -> DateTime<FixedOffset> {
    let lt: DateTime<Local> = Local::now();
    DateTime::parse_from_rfc3339(lt.to_rfc3339().as_ref()).unwrap()
}

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

    #[test]
    fn read_timesheet_test() {
        // test for sorting and general function
        let s = "Out,2016-12-18T16:53:33-0600,\n\
                 In,2016-12-19T20:54:53-0600,\n\
                 In,2016-12-18T13:01:50-0600,\n\
                 Out,2016-12-19T20:54:57-0600,";
        let buff = Cursor::new(s.as_bytes());
        let records = read_timesheet(buff).unwrap();
        for slc in records.chunks(2) {
            assert!(slc[0].dir == Direction::In);
            assert!(slc[1].dir == Direction::Out);
        }
        // test ordering
        assert!(records[0].time < records[1].time);
        assert!(records[1].time < records[2].time);
        assert!(records[2].time < records[3].time);
    }

    #[test]
    fn read_timesheet_haggis_test() {
        // test for sorting and general function
        let s = "Fair fa' your honest, sonsie face,\n\
                 Great chieftain o' the pudding-race!\n\
                 Aboon them a' ye tak your place,\n\
                 Painch, tripe, or thairm:\n\
                 Weel are ye wordy o' a grace\n\
                 As lang's my arm.";
        let buff = Cursor::new(s.as_bytes());
        let records = read_timesheet(buff);
        assert!(records.is_err());
    }

    #[test]
    fn pair_time_entries_test() {
        let s = "Out,2016-12-18T13:01:50-0600,\n\
                 In,2016-12-19T20:54:57-0600,\n\
                 Out,2016-12-20T20:50:57-0600,\n\
                 Out,2016-12-20T20:50:59-0600,\n\
                 In,2016-12-20T21:04:57-0600,";
        let buff = Cursor::new(s.as_bytes());
        let entries = read_timesheet(buff).unwrap();
        let records = timeentry_pairs(entries.into_iter())
            .collect::<Vec<TimeEntryPair>>();

        assert!(records.len() == 4);

        for tep in records {
            assert!(tep.start().dir == Direction::In);
            assert!(tep.end().dir == Direction::Out);
        }
    }

    #[test]
    fn pair_time_entries_double_in_test() {
        let s = "In,2016-12-20T21:01:57-0600,\n\
                 In,2016-12-20T21:04:57-0600,";
        let buff = Cursor::new(s.as_bytes());
        let entries = read_timesheet(buff).unwrap();
        let records = timeentry_pairs(entries.into_iter())
            .collect::<Vec<TimeEntryPair>>();

        assert!(records.len() == 2);

        for tep in records {
            assert!(tep.start().dir == Direction::In);
            assert!(tep.end().dir == Direction::Out);
        }
    }

    #[test]
    fn collect_date_records_test() {
        let time = now();
        let day = Duration::days(1);
        let records = vec![TimeEntry::new(Direction::In, time, "In"),
                           TimeEntry::new(Direction::Out, time, "Out"),
                           TimeEntry::new(Direction::In, time, "In"),
                           TimeEntry::new(Direction::Out, time, "Out"),
                           TimeEntry::new(Direction::In, time + day, "In"),
                           TimeEntry::new(Direction::Out, time + day, "Out")];

        let res = collect_date_records(records);
        assert_eq!(res.len(), 2);
        let dr = res.first().unwrap();
        assert_eq!(dr.date(), time.date());
        assert_eq!(dr.hours(), 0.0);
        let dr = res.last().unwrap();
        assert_eq!(dr.date(), time.date() + day);
        assert_eq!(dr.hours(), 0.0);
    }

    #[test]
    fn collect_date_records_tz_test() {
        // test mismatched timezones
        let s = "In,2016-12-18T13:01:50-0500,\n\
                 Out,2016-12-18T13:01:50-0600,";
        let buff = Cursor::new(s.as_bytes());
        let entries = read_timesheet(buff).unwrap();
        let records = collect_date_records(entries);

        assert!(records.len() == 1);
        println!("\n{}", records[0].seconds());
        assert!(records[0].seconds() == 3600.0);
    }

    #[test]
    fn mark_time_test() {
        let mut buff: Cursor<Vec<u8>> = Cursor::new(Vec::new());
        let time = DateTime::parse_from_rfc3339("2017-01-18T12:50:13-06:00")
            .unwrap();
        mark_time(Direction::In, time, "Test", &mut buff);
        let v = buff.into_inner();
        let s = String::from_utf8(v).unwrap();
        assert_eq!(s, "In,2017-01-18T12:50:13-06:00,Test\n");
    }
}
<commit_msg>Refactor now() function to be more skookum<commit_after>
mod daterecord;
mod direction;
mod error;
mod timeentry;
mod traits;
mod iterators;

pub use self::daterecord::DateRecord;
pub use self::direction::Direction;
pub use self::error::TimeClockError;
pub use self::iterators::*;
pub use self::timeentry::{TimeEntry, TimeEntryPair};
pub use self::traits::*;
use chrono::*;
use csv;
use std::io::SeekFrom;
use std::io::prelude::*;

pub fn read_timesheet<R: Read>(file: R)
                               -> Result<Vec<TimeEntry>, TimeClockError> {
    let mut rdr = csv::ReaderBuilder::new()
        .has_headers(false)
        .from_reader(file);
    let mut in_v: Vec<TimeEntry> = try!(rdr.deserialize().collect());
    in_v.sort_by_key(|k| k.time);
    Ok(in_v)
}

/// Reduce pairs of `TimeEntrys` into `DateRecords`
pub fn collect_date_records(records: Vec<TimeEntry>) -> Vec<DateRecord> {
    let mut res: Vec<DateRecord> = Vec::new();
    for rec in timeentry_pairs(records.into_iter()).daterecords() {
        match res.pop() {
            Some(mut r) => {
                if r.combine(&rec) {
                    res.push(r);
                } else {
                    res.push(r);
                    res.push(rec);
                }
            }
            None => res.push(rec),
        }
    }
    res
}

/// Marks the time.
pub fn mark_time<W: Write + Seek>(dir: Direction,
                                  time: DateTime<FixedOffset>,
                                  memo: &str,
                                  file: &mut W) {
    let record = TimeEntry::new(dir, time, memo);
    // seek in case we write without reading first
    let _ = file.seek(SeekFrom::End(0));
    let mut wtr = csv::WriterBuilder::new()
        .has_headers(false)
        .from_writer(file);
    let _ = wtr.serialize(record);
}

/// Get the current date and time as a `DateTime`<`FixedOffset`>
pub fn now() -> DateTime<FixedOffset> {
    let lt: DateTime<Local> = Local::now();
    lt.with_timezone(lt.offset())
}

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

    #[test]
    fn read_timesheet_test() {
        // test for sorting and general function
        let s = "Out,2016-12-18T16:53:33-0600,\n\
                 In,2016-12-19T20:54:53-0600,\n\
                 In,2016-12-18T13:01:50-0600,\n\
                 Out,2016-12-19T20:54:57-0600,";
        let buff = Cursor::new(s.as_bytes());
        let records = read_timesheet(buff).unwrap();
        for slc in records.chunks(2) {
            assert!(slc[0].dir == Direction::In);
            assert!(slc[1].dir == Direction::Out);
        }
        // test ordering
        assert!(records[0].time < records[1].time);
        assert!(records[1].time < records[2].time);
        assert!(records[2].time < records[3].time);
    }

    #[test]
    fn read_timesheet_haggis_test() {
        // test for sorting and general function
        let s = "Fair fa' your honest, sonsie face,\n\
                 Great chieftain o' the pudding-race!\n\
                 Aboon them a' ye tak your place,\n\
                 Painch, tripe, or thairm:\n\
                 Weel are ye wordy o' a grace\n\
                 As lang's my arm.";
        let buff = Cursor::new(s.as_bytes());
        let records = read_timesheet(buff);
        assert!(records.is_err());
    }

    #[test]
    fn pair_time_entries_test() {
        let s = "Out,2016-12-18T13:01:50-0600,\n\
                 In,2016-12-19T20:54:57-0600,\n\
                 Out,2016-12-20T20:50:57-0600,\n\
                 Out,2016-12-20T20:50:59-0600,\n\
                 In,2016-12-20T21:04:57-0600,";
        let buff = Cursor::new(s.as_bytes());
        let entries = read_timesheet(buff).unwrap();
        let records = timeentry_pairs(entries.into_iter())
            .collect::<Vec<TimeEntryPair>>();

        assert!(records.len() == 4);

        for tep in records {
            assert!(tep.start().dir == Direction::In);
            assert!(tep.end().dir == Direction::Out);
        }
    }

    #[test]
    fn pair_time_entries_double_in_test() {
        let s = "In,2016-12-20T21:01:57-0600,\n\
                 In,2016-12-20T21:04:57-0600,";
        let buff = Cursor::new(s.as_bytes());
        let entries = read_timesheet(buff).unwrap();
        let records = timeentry_pairs(entries.into_iter())
            .collect::<Vec<TimeEntryPair>>();

        assert!(records.len() == 2);

        for tep in records {
            assert!(tep.start().dir == Direction::In);
            assert!(tep.end().dir == Direction::Out);
        }
    }

    #[test]
    fn collect_date_records_test() {
        let time = now();
        let day = Duration::days(1);
        let records = vec![TimeEntry::new(Direction::In, time, "In"),
                           TimeEntry::new(Direction::Out, time, "Out"),
                           TimeEntry::new(Direction::In, time, "In"),
                           TimeEntry::new(Direction::Out, time, "Out"),
                           TimeEntry::new(Direction::In, time + day, "In"),
                           TimeEntry::new(Direction::Out, time + day, "Out")];

        let res = collect_date_records(records);
        assert_eq!(res.len(), 2);
        let dr = res.first().unwrap();
        assert_eq!(dr.date(), time.date());
        assert_eq!(dr.hours(), 0.0);
        let dr = res.last().unwrap();
        assert_eq!(dr.date(), time.date() + day);
        assert_eq!(dr.hours(), 0.0);
    }

    #[test]
    fn collect_date_records_tz_test() {
        // test mismatched timezones
        let s = "In,2016-12-18T13:01:50-0500,\n\
                 Out,2016-12-18T13:01:50-0600,";
        let buff = Cursor::new(s.as_bytes());
        let entries = read_timesheet(buff).unwrap();
        let records = collect_date_records(entries);

        assert!(records.len() == 1);
        println!("\n{}", records[0].seconds());
        assert!(records[0].seconds() == 3600.0);
    }

    #[test]
    fn mark_time_test() {
        let mut buff: Cursor<Vec<u8>> = Cursor::new(Vec::new());
        let time = DateTime::parse_from_rfc3339("2017-01-18T12:50:13-06:00")
            .unwrap();
        mark_time(Direction::In, time, "Test", &mut buff);
        let v = buff.into_inner();
        let s = String::from_utf8(v).unwrap();
        assert_eq!(s, "In,2017-01-18T12:50:13-06:00,Test\n");
    }
}
<|endoftext|>


<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Alan Andrade <alan.andradec@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

// spell-checker:ignore (ToDO) MAKEWORD addrs hashset

extern crate clap;
extern crate hostname;
extern crate libc;
#[cfg(windows)]
extern crate winapi;

#[macro_use]
extern crate uucore;

use clap::{App, Arg, ArgMatches};
use std::collections::hash_set::HashSet;
use std::net::ToSocketAddrs;
use std::str;

#[cfg(windows)]
use winapi::shared::minwindef::MAKEWORD;
#[cfg(windows)]
use winapi::um::winsock2::{WSACleanup, WSAStartup};

static ABOUT: &str = "Display or set the system's host name.";
static VERSION: &str = env!("CARGO_PKG_VERSION");

static OPT_DOMAIN: &str = "domain";
static OPT_IP_ADDRESS: &str = "ip-address";
static OPT_FQDN: &str = "fqdn";
static OPT_SHORT: &str = "short";
static OPT_HOST: &str = "host";

pub fn uumain(args: impl uucore::Args) -> i32 {
    #![allow(clippy::let_and_return)]
    #[cfg(windows)]
    unsafe {
        #[allow(deprecated)]
        let mut data = std::mem::uninitialized();
        if WSAStartup(MAKEWORD(2, 2), &mut data as *mut _) != 0 {
            eprintln!("Failed to start Winsock 2.2");
            return 1;
        }
    }
    let result = execute(args);
    #[cfg(windows)]
    unsafe {
        WSACleanup();
    }
    result
}

fn get_usage() -> String {
    format!("{0} [OPTION]... [HOSTNAME]", executable!())
}
fn execute(args: impl uucore::Args) -> i32 {
    let usage = get_usage();
    let matches = App::new(executable!())
        .version(VERSION)
        .about(ABOUT)
        .usage(&usage[..])
        .arg(
            Arg::with_name(OPT_DOMAIN)
                .short("d")
                .long("domain")
                .help("Display the name of the DNS domain if possible"),
        )
        .arg(
            Arg::with_name(OPT_IP_ADDRESS)
                .short("i")
                .long("ip-address")
                .help("Display the network address(es) of the host"),
        )
        // TODO: support --long
        .arg(
            Arg::with_name(OPT_FQDN)
                .short("f")
                .long("fqdn")
                .help("Display the FQDN (Fully Qualified Domain Name) (default)"),
        )
        .arg(Arg::with_name(OPT_SHORT).short("s").long("short").help(
            "Display the short hostname (the portion before the first dot) if \
                possible",
        ))
        .arg(Arg::with_name(OPT_HOST))
        .get_matches_from(args);

    match matches.value_of(OPT_HOST) {
        None => display_hostname(&matches),
        Some(host) => {
            if let Err(err) = hostname::set(host) {
                show_error!("{}", err);
                1
            } else {
                0
            }
        }
    }
}

fn display_hostname(matches: &ArgMatches) -> i32 {
    let hostname = hostname::get().unwrap().into_string().unwrap();

    if matches.is_present(OPT_IP_ADDRESS) {
        // XXX: to_socket_addrs needs hostname:port so append a dummy port and remove it later.
        // This was originally supposed to use std::net::lookup_host, but that seems to be
        // deprecated.  Perhaps we should use the dns-lookup crate?
        let hostname = hostname + ":1";
        match hostname.to_socket_addrs() {
            Ok(addresses) => {
                let mut hashset = HashSet::new();
                let mut output = String::new();
                for addr in addresses {
                    // XXX: not sure why this is necessary...
                    if !hashset.contains(&addr) {
                        let mut ip = format!("{}", addr);
                        if ip.ends_with(":1") {
                            let len = ip.len();
                            ip.truncate(len - 2);
                        }
                        output.push_str(&ip);
                        output.push_str(" ");
                        hashset.insert(addr);
                    }
                }
                let len = output.len();
                if len > 0 {
                    println!("{}", &output[0..len - 1]);
                }

                0
            }
            Err(f) => {
                show_error!("{}", f);

                1
            }
        }
    } else {
        if matches.is_present(OPT_SHORT) || matches.is_present(OPT_DOMAIN) {
            let mut it = hostname.char_indices().filter(|&ci| ci.1 == '.');
            if let Some(ci) = it.next() {
                if matches.is_present(OPT_SHORT) {
                    println!("{}", &hostname[0..ci.0]);
                } else {
                    println!("{}", &hostname[ci.0 + 1..]);
                }
                return 0;
            }
        }

        println!("{}", hostname);

        0
    }
}
<commit_msg>maint/hostname: Fix a clippy warning 'single_char_push_str'<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Alan Andrade <alan.andradec@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

// spell-checker:ignore (ToDO) MAKEWORD addrs hashset

extern crate clap;
extern crate hostname;
extern crate libc;
#[cfg(windows)]
extern crate winapi;

#[macro_use]
extern crate uucore;

use clap::{App, Arg, ArgMatches};
use std::collections::hash_set::HashSet;
use std::net::ToSocketAddrs;
use std::str;

#[cfg(windows)]
use winapi::shared::minwindef::MAKEWORD;
#[cfg(windows)]
use winapi::um::winsock2::{WSACleanup, WSAStartup};

static ABOUT: &str = "Display or set the system's host name.";
static VERSION: &str = env!("CARGO_PKG_VERSION");

static OPT_DOMAIN: &str = "domain";
static OPT_IP_ADDRESS: &str = "ip-address";
static OPT_FQDN: &str = "fqdn";
static OPT_SHORT: &str = "short";
static OPT_HOST: &str = "host";

pub fn uumain(args: impl uucore::Args) -> i32 {
    #![allow(clippy::let_and_return)]
    #[cfg(windows)]
    unsafe {
        #[allow(deprecated)]
        let mut data = std::mem::uninitialized();
        if WSAStartup(MAKEWORD(2, 2), &mut data as *mut _) != 0 {
            eprintln!("Failed to start Winsock 2.2");
            return 1;
        }
    }
    let result = execute(args);
    #[cfg(windows)]
    unsafe {
        WSACleanup();
    }
    result
}

fn get_usage() -> String {
    format!("{0} [OPTION]... [HOSTNAME]", executable!())
}
fn execute(args: impl uucore::Args) -> i32 {
    let usage = get_usage();
    let matches = App::new(executable!())
        .version(VERSION)
        .about(ABOUT)
        .usage(&usage[..])
        .arg(
            Arg::with_name(OPT_DOMAIN)
                .short("d")
                .long("domain")
                .help("Display the name of the DNS domain if possible"),
        )
        .arg(
            Arg::with_name(OPT_IP_ADDRESS)
                .short("i")
                .long("ip-address")
                .help("Display the network address(es) of the host"),
        )
        // TODO: support --long
        .arg(
            Arg::with_name(OPT_FQDN)
                .short("f")
                .long("fqdn")
                .help("Display the FQDN (Fully Qualified Domain Name) (default)"),
        )
        .arg(Arg::with_name(OPT_SHORT).short("s").long("short").help(
            "Display the short hostname (the portion before the first dot) if \
                possible",
        ))
        .arg(Arg::with_name(OPT_HOST))
        .get_matches_from(args);

    match matches.value_of(OPT_HOST) {
        None => display_hostname(&matches),
        Some(host) => {
            if let Err(err) = hostname::set(host) {
                show_error!("{}", err);
                1
            } else {
                0
            }
        }
    }
}

fn display_hostname(matches: &ArgMatches) -> i32 {
    let hostname = hostname::get().unwrap().into_string().unwrap();

    if matches.is_present(OPT_IP_ADDRESS) {
        // XXX: to_socket_addrs needs hostname:port so append a dummy port and remove it later.
        // This was originally supposed to use std::net::lookup_host, but that seems to be
        // deprecated.  Perhaps we should use the dns-lookup crate?
        let hostname = hostname + ":1";
        match hostname.to_socket_addrs() {
            Ok(addresses) => {
                let mut hashset = HashSet::new();
                let mut output = String::new();
                for addr in addresses {
                    // XXX: not sure why this is necessary...
                    if !hashset.contains(&addr) {
                        let mut ip = format!("{}", addr);
                        if ip.ends_with(":1") {
                            let len = ip.len();
                            ip.truncate(len - 2);
                        }
                        output.push_str(&ip);
                        output.push(' ');
                        hashset.insert(addr);
                    }
                }
                let len = output.len();
                if len > 0 {
                    println!("{}", &output[0..len - 1]);
                }

                0
            }
            Err(f) => {
                show_error!("{}", f);

                1
            }
        }
    } else {
        if matches.is_present(OPT_SHORT) || matches.is_present(OPT_DOMAIN) {
            let mut it = hostname.char_indices().filter(|&ci| ci.1 == '.');
            if let Some(ci) = it.next() {
                if matches.is_present(OPT_SHORT) {
                    println!("{}", &hostname[0..ci.0]);
                } else {
                    println!("{}", &hostname[ci.0 + 1..]);
                }
                return 0;
            }
        }

        println!("{}", hostname);

        0
    }
}
<|endoftext|>


<commit_before>use arc = std::arc;
use arc::ARC;
use au = gfx::geometry;
use font::{RunMetrics, Font};
use font_cache::FontCache;
use geom::point::Point2D;
use geom::size::Size2D;
use gfx::geometry::Au;
use glyph::GlyphStore;
use layout::context::LayoutContext;
use libc::{c_void};
use servo_util::color;
use shaper::shape_textrun;
use std::arc;
use servo_util::range::{Range, MutableRange};

pub struct TextRun {
    text: ~str,
    font: @Font,
    priv glyphs: GlyphStore,
}

// This is a hack until TextRuns are normally sendable, or
// we instead use ARC<TextRun> everywhere.
pub struct SendableTextRun {
    text: ~str,
    font_descriptor: (),
    priv glyphs: GlyphStore,
}

pub fn serialize(_cache: @FontCache, run: &TextRun) -> ~SendableTextRun {
    ~SendableTextRun {
        text: copy run.text,
        // TODO: actually serialize a font descriptor thingy
        font_descriptor: (),
        glyphs: copy run.glyphs,
    }
}

pub fn deserialize(cache: @FontCache, run: &SendableTextRun) -> @TextRun {
    @TextRun {
        text: copy run.text,
        // TODO: actually deserialize a font descriptor thingy
        font: cache.get_test_font(),
        glyphs: copy run.glyphs
    }
}

trait TextRunMethods {
    pure fn glyphs(&self) -> &self/GlyphStore;
    fn iter_indivisible_pieces_for_range(&self, range: Range, f: fn&(Range) -> bool);
    // TODO: needs to take box style as argument, or move to TextBox.
    // see Gecko's IsTrimmableSpace methods for details.
    pure fn range_is_trimmable_whitespace(&self, range: Range) -> bool;

    fn metrics_for_range(&self, range: Range) -> RunMetrics;
    fn min_width_for_range(&self, range: Range) -> Au;
    fn iter_natural_lines_for_range(&self, range: Range, f: fn&(Range) -> bool);
}

impl TextRun : TextRunMethods {
    pure fn glyphs(&self) -> &self/GlyphStore { &self.glyphs }

    pure fn range_is_trimmable_whitespace(&self, range: Range) -> bool {
        let mut i = range.begin();
        while i < range.end() {
            // jump i to each new char
            let {ch, next} = str::char_range_at(self.text, i);
            match ch {
                ' ' | '\t' | '\r'  => {},
                _ => { return false; }
            }
            i = next;
        }
        return true;
    }

    fn metrics_for_range(&self, range: Range) -> RunMetrics {
        self.font.measure_text(self, range)
    }

    fn min_width_for_range(&self, range: Range) -> Au {
        assert range.is_valid_for_string(self.text);

        let mut max_piece_width = Au(0);
        for self.iter_indivisible_pieces_for_range(range) |piece_range| {
            let metrics = self.font.measure_text(self, piece_range);
            max_piece_width = au::max(max_piece_width, metrics.advance_width);
        }
        return max_piece_width;
    }

    fn iter_natural_lines_for_range(&self, range: Range, f: fn(Range) -> bool) {
        assert range.is_valid_for_string(self.text);

        let clump = MutableRange(range.begin(), 0);
        let mut in_clump = false;

        // clump non-linebreaks of nonzero length
        for range.eachi |i| {
            match (self.glyphs.char_is_newline(i), in_clump) {
                (false, true)  => { clump.extend_by(1); }
                (false, false) => { in_clump = true; clump.reset(i, 1); }
                (true, false) => { /* chomp whitespace */ }
                (true, true)  => {
                    in_clump = false;
                    // don't include the linebreak 'glyph'
                    // (we assume there's one GlyphEntry for a newline, and no actual glyphs)
                    if !f(clump.as_immutable()) { break }
                }
            }
        }

        // flush any remaining chars as a line
        if in_clump {
            clump.extend_to(range.end());
            f(clump.as_immutable());
        }
    }

    fn iter_indivisible_pieces_for_range(&self, range: Range, f: fn(Range) -> bool) {
        assert range.is_valid_for_string(self.text);

        let clump = MutableRange(range.begin(), 0);
        loop {
            // find next non-whitespace byte index, then clump all whitespace before it.
            if clump.end() == range.end() { break }
            match str::find_from(self.text, clump.begin(), |c| !char::is_whitespace(c)) {
                Some(nonws_char_offset) => {
                    clump.extend_to(nonws_char_offset);
                    if !f(clump.as_immutable()) { break }
                    clump.reset(clump.end(), 0);
                },
                None => {
                    // nothing left, flush last piece containing only whitespace
                    if clump.end() < range.end() {
                        clump.extend_to(range.end());
                        f(clump.as_immutable());
                    }
                }
            };

            // find next whitespace byte index, then clump all non-whitespace before it.
            if clump.end() == range.end() { break }
            match str::find_from(self.text, clump.begin(), |c| char::is_whitespace(c)) {
                Some(ws_char_offset) => {
                    clump.extend_to(ws_char_offset);
                    if !f(clump.as_immutable()) { break }
                    clump.reset(clump.end(), 0);
                }
                None => {
                    // nothing left, flush last piece containing only non-whitespaces
                    if clump.end() < range.end() {
                        clump.extend_to(range.end());
                        f(clump.as_immutable());
                    }
                }
            }
        }
    }
}

fn TextRun(font: @Font, text: ~str) -> TextRun {
    let glyph_store = GlyphStore(text.len());
    let run = TextRun {
        text: move text,
        font: font,
        glyphs: move glyph_store,
    };

    shape_textrun(&run);
    return move run;
}

// this test can't run until LayoutContext is removed as an argument
// to min_width_for_range.
/*
#[test]
fn test_calc_min_break_width() {

    fn test_min_width_for_run(text: ~str, width: Au) {
        let flib = FontCache();
        let font = flib.get_test_font();
        let run = TextRun(font, text);
        run.min_width_for_range(0, text.len())
    }

    test_min_width_for_run(~"firecracker", au::from_px(84));
    test_min_width_for_run(~"firecracker yumyum", au::from_px(84));
    test_min_width_for_run(~"yumyum firecracker", au::from_px(84));
    test_min_width_for_run(~"yumyum firecracker yumyum", au::from_px(84));
}
*/

#[test]
#[ignore]
fn test_iter_indivisible_pieces() {
    fn test_pieces(text: ~str, res: ~[~str]) {
        let flib = FontCache();
        let font = flib.get_test_font();
        let run = TextRun(font, copy text);
        let mut slices : ~[~str] = ~[];
        for run.iter_indivisible_pieces_for_range(Range(0, text.len())) |subrange| {
            slices.push(str::slice(text, subrange.begin(), subrange.length()));
        }
        assert slices == res;
    }

    test_pieces(~"firecracker yumyum woopwoop", ~[~"firecracker", ~" ", ~"yumyum", ~" ", ~"woopwoop"]);
    test_pieces(~"firecracker yumyum     ", ~[~"firecracker", ~" ", ~"yumyum", ~"     "]);
    test_pieces(~"     firecracker yumyum", ~[~"     ", ~"firecracker", ~" ", ~"yumyum"]);
    test_pieces(~"  ", ~[~"  "]);
    test_pieces(~"", ~[]);
}

<commit_msg>Fix a range-respecting bug in iter_indivisible_pieces_for_range.<commit_after>use arc = std::arc;
use arc::ARC;
use au = gfx::geometry;
use font::{RunMetrics, Font};
use font_cache::FontCache;
use geom::point::Point2D;
use geom::size::Size2D;
use gfx::geometry::Au;
use glyph::GlyphStore;
use layout::context::LayoutContext;
use libc::{c_void};
use servo_util::color;
use shaper::shape_textrun;
use std::arc;
use servo_util::range::{Range, MutableRange};

pub struct TextRun {
    text: ~str,
    font: @Font,
    priv glyphs: GlyphStore,
}

// This is a hack until TextRuns are normally sendable, or
// we instead use ARC<TextRun> everywhere.
pub struct SendableTextRun {
    text: ~str,
    font_descriptor: (),
    priv glyphs: GlyphStore,
}

pub fn serialize(_cache: @FontCache, run: &TextRun) -> ~SendableTextRun {
    ~SendableTextRun {
        text: copy run.text,
        // TODO: actually serialize a font descriptor thingy
        font_descriptor: (),
        glyphs: copy run.glyphs,
    }
}

pub fn deserialize(cache: @FontCache, run: &SendableTextRun) -> @TextRun {
    @TextRun {
        text: copy run.text,
        // TODO: actually deserialize a font descriptor thingy
        font: cache.get_test_font(),
        glyphs: copy run.glyphs
    }
}

trait TextRunMethods {
    pure fn glyphs(&self) -> &self/GlyphStore;
    fn iter_indivisible_pieces_for_range(&self, range: Range, f: fn&(Range) -> bool);
    // TODO: needs to take box style as argument, or move to TextBox.
    // see Gecko's IsTrimmableSpace methods for details.
    pure fn range_is_trimmable_whitespace(&self, range: Range) -> bool;

    fn metrics_for_range(&self, range: Range) -> RunMetrics;
    fn min_width_for_range(&self, range: Range) -> Au;
    fn iter_natural_lines_for_range(&self, range: Range, f: fn&(Range) -> bool);
}

impl TextRun : TextRunMethods {
    pure fn glyphs(&self) -> &self/GlyphStore { &self.glyphs }

    pure fn range_is_trimmable_whitespace(&self, range: Range) -> bool {
        let mut i = range.begin();
        while i < range.end() {
            // jump i to each new char
            let {ch, next} = str::char_range_at(self.text, i);
            match ch {
                ' ' | '\t' | '\r'  => {},
                _ => { return false; }
            }
            i = next;
        }
        return true;
    }

    fn metrics_for_range(&self, range: Range) -> RunMetrics {
        self.font.measure_text(self, range)
    }

    fn min_width_for_range(&self, range: Range) -> Au {
        assert range.is_valid_for_string(self.text);

        let mut max_piece_width = Au(0);
        for self.iter_indivisible_pieces_for_range(range) |piece_range| {
            let metrics = self.font.measure_text(self, piece_range);
            max_piece_width = au::max(max_piece_width, metrics.advance_width);
        }
        return max_piece_width;
    }

    fn iter_natural_lines_for_range(&self, range: Range, f: fn(Range) -> bool) {
        assert range.is_valid_for_string(self.text);

        let clump = MutableRange(range.begin(), 0);
        let mut in_clump = false;

        // clump non-linebreaks of nonzero length
        for range.eachi |i| {
            match (self.glyphs.char_is_newline(i), in_clump) {
                (false, true)  => { clump.extend_by(1); }
                (false, false) => { in_clump = true; clump.reset(i, 1); }
                (true, false) => { /* chomp whitespace */ }
                (true, true)  => {
                    in_clump = false;
                    // don't include the linebreak 'glyph'
                    // (we assume there's one GlyphEntry for a newline, and no actual glyphs)
                    if !f(clump.as_immutable()) { break }
                }
            }
        }

        // flush any remaining chars as a line
        if in_clump {
            clump.extend_to(range.end());
            f(clump.as_immutable());
        }
    }

    fn iter_indivisible_pieces_for_range(&self, range: Range, f: fn(Range) -> bool) {
        assert range.is_valid_for_string(self.text);

        let clump = MutableRange(range.begin(), 0);
        loop {
            // find next non-whitespace byte index, then clump all whitespace before it.
            match str::find_between(self.text, clump.begin(), range.end(), |c| !char::is_whitespace(c)) {
                Some(nonws_char_offset) => {
                    clump.extend_to(nonws_char_offset);
                    if !f(clump.as_immutable()) { break }
                    clump.reset(clump.end(), 0);
                },
                None => {
                    // nothing left, flush last piece containing only whitespace
                    if clump.end() < range.end() {
                        clump.extend_to(range.end());
                        f(clump.as_immutable());
                        break;
                    }
                }
            };

            // find next whitespace byte index, then clump all non-whitespace before it.
            match str::find_between(self.text, clump.begin(), range.end(), |c| char::is_whitespace(c)) {
                Some(ws_char_offset) => {
                    clump.extend_to(ws_char_offset);
                    if !f(clump.as_immutable()) { break }
                    clump.reset(clump.end(), 0);
                }
                None => {
                    // nothing left, flush last piece containing only non-whitespaces
                    if clump.end() < range.end() {
                        clump.extend_to(range.end());
                        f(clump.as_immutable());
                        break;
                    }
                }
            }
        }
    }
}

fn TextRun(font: @Font, text: ~str) -> TextRun {
    let glyph_store = GlyphStore(text.len());
    let run = TextRun {
        text: move text,
        font: font,
        glyphs: move glyph_store,
    };

    shape_textrun(&run);
    return move run;
}

// this test can't run until LayoutContext is removed as an argument
// to min_width_for_range.
/*
#[test]
fn test_calc_min_break_width() {

    fn test_min_width_for_run(text: ~str, width: Au) {
        let flib = FontCache();
        let font = flib.get_test_font();
        let run = TextRun(font, text);
        run.min_width_for_range(0, text.len())
    }

    test_min_width_for_run(~"firecracker", au::from_px(84));
    test_min_width_for_run(~"firecracker yumyum", au::from_px(84));
    test_min_width_for_run(~"yumyum firecracker", au::from_px(84));
    test_min_width_for_run(~"yumyum firecracker yumyum", au::from_px(84));
}
*/

#[test]
#[ignore]
fn test_iter_indivisible_pieces() {
    fn test_pieces(text: ~str, res: ~[~str]) {
        let flib = FontCache();
        let font = flib.get_test_font();
        let run = TextRun(font, copy text);
        let mut slices : ~[~str] = ~[];
        for run.iter_indivisible_pieces_for_range(Range(0, text.len())) |subrange| {
            slices.push(str::slice(text, subrange.begin(), subrange.length()));
        }
        assert slices == res;
    }

    test_pieces(~"firecracker yumyum woopwoop", ~[~"firecracker", ~" ", ~"yumyum", ~" ", ~"woopwoop"]);
    test_pieces(~"firecracker yumyum     ", ~[~"firecracker", ~" ", ~"yumyum", ~"     "]);
    test_pieces(~"     firecracker yumyum", ~[~"     ", ~"firecracker", ~" ", ~"yumyum"]);
    test_pieces(~"  ", ~[~"  "]);
    test_pieces(~"", ~[]);
}

<|endoftext|>


<commit_before>use nom::{IResult, Needed};

use std::io::{self, Read};
use std::ptr;
use std::cmp;

use super::StreamProducer;

#[derive(Debug)]
pub enum ErrorKind {
  IO(io::Error),
  Incomplete(usize),
  Continue,
  EndOfInput,
  Unknown,
}

/// Structure that hold a slice of bytes.
pub struct ByteStream<'a> {
  offset: usize,
  bytes: &'a [u8],
}

impl<'a> ByteStream<'a> {
  /// Construct a `ByteStream` based on the passed in byte slice.
  pub fn new(bytes: &'a [u8]) -> Self {
    ByteStream {
      offset: 0,
      bytes: bytes,
    }
  }

  /// Return the number of bytes that haven't been consumed yet.
  #[inline]
  pub fn len(&self) -> usize {
    self.bytes.len() - self.offset
  }

  /// Return true if the stream contains no more bytes.
  #[inline]
  pub fn is_empty(&self) -> bool {
    self.len() == 0
  }
}

impl<'a> StreamProducer for ByteStream<'a> {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T> {
    if self.is_empty() {
      return Err(ErrorKind::EndOfInput);
    }

    match f(&self.bytes[self.offset..]) {
      IResult::Done(i, o)    => {
        self.offset += self.len() - i.len();

        Ok(o)
      }
      IResult::Incomplete(n) => {
        let mut needed = self.len();

        if let Needed::Size(size) = n {
          needed = size;
        }

        Err(ErrorKind::Incomplete(needed))
      }
      IResult::Error(_)      => Err(ErrorKind::Unknown),
    }
  }
}

// Growable buffer of bytes.
//
// Mainly used to the `ReadStream` structure but can be used seperately for
// manually filling with some `Read` source.
pub struct Buffer {
  data: Vec<u8>,
  filled: usize,
  offset: usize,
}

impl Buffer {
  // Default constructor for `Buffer`
  pub fn new() -> Self {
    Self::with_capacity(1024)
  }

  // Explicitly set the buffer capacity.
  pub fn with_capacity(capacity: usize) -> Self {
    let mut buffer = Vec::with_capacity(capacity);

    unsafe {
      buffer.set_len(capacity);
    }

    Buffer {
      data: buffer,
      filled: 0,
      offset: 0,
    }
  }

  // Return the number of read bytes that haven't been consumed yet.
  #[inline]
  pub fn len(&self) -> usize {
    self.filled - self.offset
  }

  // Return true if buffer contains no more bytes.
  #[inline]
  pub fn is_empty(&self) -> bool {
    self.len() == 0
  }

  // The set length of the unlining buffer.
  #[inline]
  pub fn capacity(&self) -> usize {
    self.data.len()
  }

  // Return a reference to the slice of unread bytes.
  pub fn as_slice(&self) -> &[u8] {
    &self.data[self.offset..self.filled]
  }

  // Fill the buffer with bytes from a `Read` source.
  pub fn fill<R: Read>(&mut self, reader: &mut R) -> io::Result<usize> {
    reader.read(&mut self.data[self.filled..]).map(|consumed| {
      self.filled += consumed;

      consumed
    })
  }

  // Resize the current buffer
  //
  // This will only allocate data when the size requests is larger than the
  // current capacity of the buffer, otherwise it moves the currently filled
  // data to the beginning of the buffer.
  pub fn resize(&mut self, size: usize) {
    if size > self.data.capacity() {
      self.data.reserve(size);

      let capacity = self.data.capacity();

      unsafe {
        self.data.set_len(capacity);
      }
    }

    if self.data.len() - self.filled < size  {
      let length  = self.filled - self.offset;
      let mut_ptr = self.data.as_mut_ptr();

      unsafe {
        let offset_ptr  = self.data.as_ptr().offset(self.offset as isize);

        ptr::copy(offset_ptr, mut_ptr, length);
      }

      self.filled -= self.offset;
      self.offset  = 0;
    }
  }

  // Move the offset by the amount of consumed bytes.
  pub fn consume(&mut self, consumed: usize) {
    self.offset += consumed;
  }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ParserState {
  Incomplete,
  EndOfInput,
}

fn fill<R: Read>(buffer: &mut Buffer, reader: &mut R, needed: usize)
                 -> io::Result<usize> {
  let mut read = 0;

  if buffer.len() < needed {
    buffer.resize(needed);

    while buffer.len() < needed {
      let size_read = try!(buffer.fill(reader));

      if size_read > 0 {
        read += size_read;
      } else {
        break;
      }
    }
  }

  Ok(read)
}

/// Structure that hold a reader for a source of bytes.
pub struct ReadStream<R: Read> {
  reader: R,
  buffer: Buffer,
  needed: usize,
  state: ParserState,
}

impl<R> ReadStream<R> where R: Read {
  /// Constructor for `ReadStream` based on a `Read` source.
  pub fn new(reader: R) -> Self {
    ReadStream {
      reader: reader,
      buffer: Buffer::new(),
      needed: 0,
      state: ParserState::Incomplete,
    }
  }

  // Fill the stream with bytes from a `Read` source.
  fn fill(&mut self) -> io::Result<usize> {
    let needed = cmp::max(1, self.needed);

    fill(&mut self.buffer, &mut self.reader, needed).map(|consumed| {
      if self.buffer.len() < needed {
        self.state = ParserState::EndOfInput;
      }

      consumed
    })
  }
}

fn from_iresult<T>(buffer: &Buffer, result: IResult<&[u8], T>)
                   -> Result<(usize, T), ErrorKind> {
  match result {
    IResult::Done(i, o)    => Ok((buffer.len() - i.len(), o)),
    IResult::Incomplete(n) => {
      let mut needed = buffer.capacity() + 1024;

      if let Needed::Size(size) = n {
        needed = size;
      }

      Err(ErrorKind::Incomplete(needed))
    }
    IResult::Error(_)      => Err(ErrorKind::Unknown),
  }
}

impl<R> StreamProducer for ReadStream<R> where R: Read {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T> {
    if self.state != ParserState::EndOfInput {
      try!(self.fill().map_err(ErrorKind::IO));
    }

    let mut buffer = &mut self.buffer;

    if buffer.is_empty() {
      self.state = ParserState::EndOfInput;

      return Err(ErrorKind::EndOfInput);
    }

    let result = {
      let iresult = f(buffer.as_slice());

      from_iresult(&buffer, iresult)
    };

    match result {
      Ok((consumed, o)) => {
        buffer.consume(consumed);

        Ok(o)
      }
      Err(kind)         => {
        if let ErrorKind::Incomplete(needed) = kind {
          self.needed = needed;

          Err(ErrorKind::Continue)
        } else {
          Err(kind)
        }
      }
    }
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use utility::StreamProducer;
  use nom::be_u32;

  #[test]
  fn test_buffer() {
    let mut buffer = Buffer::new();
    let bytes      = b"Hello World";
    let mut reader = &bytes[..];

    assert!(buffer.is_empty());
    assert_eq!(buffer.capacity(), 1024);

    let bytes_read = buffer.fill(&mut reader).unwrap_or(0);
    let bytes_len  = bytes.len();

    assert_eq!(bytes_read, bytes_len);
    assert_eq!(buffer.len(), bytes_len);
    assert_eq!(buffer.as_slice(), bytes);

    buffer.resize(512);
    assert_eq!(buffer.capacity(), 1024);
  }

  #[test]
  fn test_byte_stream() {
    let bytes      = b"Hello World";
    let mut stream = ByteStream::new(bytes);

    assert_eq!(stream.len(), bytes.len());

    let result = stream.parse(be_u32).unwrap_or(0);

    assert_eq!(result, 1214606444);
    assert_eq!(stream.len(), 7);
  }

  #[test]
  fn test_read_stream() {
    let bytes      = b"Hello World";
    let mut stream = ReadStream::new(&bytes[..]);

    let result = stream.parse(be_u32).unwrap_or(0);

    assert_eq!(result, 1214606444)
  }
}
<commit_msg>Add parser errors to ErrorKind<commit_after>use nom::{IResult, Needed};

use std::io::{self, Read};
use std::ptr;
use std::cmp;

use super::StreamProducer;

#[derive(Debug)]
pub enum ErrorKind {
  IO(io::Error),
  Incomplete(usize),
  Continue,
  EndOfInput,
  Unknown,
  // Parser Error
  HeaderParser,
}

/// Structure that hold a slice of bytes.
pub struct ByteStream<'a> {
  offset: usize,
  bytes: &'a [u8],
}

impl<'a> ByteStream<'a> {
  /// Construct a `ByteStream` based on the passed in byte slice.
  pub fn new(bytes: &'a [u8]) -> Self {
    ByteStream {
      offset: 0,
      bytes: bytes,
    }
  }

  /// Return the number of bytes that haven't been consumed yet.
  #[inline]
  pub fn len(&self) -> usize {
    self.bytes.len() - self.offset
  }

  /// Return true if the stream contains no more bytes.
  #[inline]
  pub fn is_empty(&self) -> bool {
    self.len() == 0
  }
}

impl<'a> StreamProducer for ByteStream<'a> {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T> {
    if self.is_empty() {
      return Err(ErrorKind::EndOfInput);
    }

    match f(&self.bytes[self.offset..]) {
      IResult::Done(i, o)    => {
        self.offset += self.len() - i.len();

        Ok(o)
      }
      IResult::Incomplete(n) => {
        let mut needed = self.len();

        if let Needed::Size(size) = n {
          needed = size;
        }

        Err(ErrorKind::Incomplete(needed))
      }
      IResult::Error(_)      => Err(ErrorKind::Unknown),
    }
  }
}

// Growable buffer of bytes.
//
// Mainly used to the `ReadStream` structure but can be used seperately for
// manually filling with some `Read` source.
pub struct Buffer {
  data: Vec<u8>,
  filled: usize,
  offset: usize,
}

impl Buffer {
  // Default constructor for `Buffer`
  pub fn new() -> Self {
    Self::with_capacity(1024)
  }

  // Explicitly set the buffer capacity.
  pub fn with_capacity(capacity: usize) -> Self {
    let mut buffer = Vec::with_capacity(capacity);

    unsafe {
      buffer.set_len(capacity);
    }

    Buffer {
      data: buffer,
      filled: 0,
      offset: 0,
    }
  }

  // Return the number of read bytes that haven't been consumed yet.
  #[inline]
  pub fn len(&self) -> usize {
    self.filled - self.offset
  }

  // Return true if buffer contains no more bytes.
  #[inline]
  pub fn is_empty(&self) -> bool {
    self.len() == 0
  }

  // The set length of the unlining buffer.
  #[inline]
  pub fn capacity(&self) -> usize {
    self.data.len()
  }

  // Return a reference to the slice of unread bytes.
  pub fn as_slice(&self) -> &[u8] {
    &self.data[self.offset..self.filled]
  }

  // Fill the buffer with bytes from a `Read` source.
  pub fn fill<R: Read>(&mut self, reader: &mut R) -> io::Result<usize> {
    reader.read(&mut self.data[self.filled..]).map(|consumed| {
      self.filled += consumed;

      consumed
    })
  }

  // Resize the current buffer
  //
  // This will only allocate data when the size requests is larger than the
  // current capacity of the buffer, otherwise it moves the currently filled
  // data to the beginning of the buffer.
  pub fn resize(&mut self, size: usize) {
    if size > self.data.capacity() {
      self.data.reserve(size);

      let capacity = self.data.capacity();

      unsafe {
        self.data.set_len(capacity);
      }
    }

    if self.data.len() - self.filled < size  {
      let length  = self.filled - self.offset;
      let mut_ptr = self.data.as_mut_ptr();

      unsafe {
        let offset_ptr  = self.data.as_ptr().offset(self.offset as isize);

        ptr::copy(offset_ptr, mut_ptr, length);
      }

      self.filled -= self.offset;
      self.offset  = 0;
    }
  }

  // Move the offset by the amount of consumed bytes.
  pub fn consume(&mut self, consumed: usize) {
    self.offset += consumed;
  }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ParserState {
  Incomplete,
  EndOfInput,
}

fn fill<R: Read>(buffer: &mut Buffer, reader: &mut R, needed: usize)
                 -> io::Result<usize> {
  let mut read = 0;

  if buffer.len() < needed {
    buffer.resize(needed);

    while buffer.len() < needed {
      let size_read = try!(buffer.fill(reader));

      if size_read > 0 {
        read += size_read;
      } else {
        break;
      }
    }
  }

  Ok(read)
}

/// Structure that hold a reader for a source of bytes.
pub struct ReadStream<R: Read> {
  reader: R,
  buffer: Buffer,
  needed: usize,
  state: ParserState,
}

impl<R> ReadStream<R> where R: Read {
  /// Constructor for `ReadStream` based on a `Read` source.
  pub fn new(reader: R) -> Self {
    ReadStream {
      reader: reader,
      buffer: Buffer::new(),
      needed: 0,
      state: ParserState::Incomplete,
    }
  }

  // Fill the stream with bytes from a `Read` source.
  fn fill(&mut self) -> io::Result<usize> {
    let needed = cmp::max(1, self.needed);

    fill(&mut self.buffer, &mut self.reader, needed).map(|consumed| {
      if self.buffer.len() < needed {
        self.state = ParserState::EndOfInput;
      }

      consumed
    })
  }
}

fn from_iresult<T>(buffer: &Buffer, result: IResult<&[u8], T>)
                   -> Result<(usize, T), ErrorKind> {
  match result {
    IResult::Done(i, o)    => Ok((buffer.len() - i.len(), o)),
    IResult::Incomplete(n) => {
      let mut needed = buffer.capacity() + 1024;

      if let Needed::Size(size) = n {
        needed = size;
      }

      Err(ErrorKind::Incomplete(needed))
    }
    IResult::Error(_)      => Err(ErrorKind::Unknown),
  }
}

impl<R> StreamProducer for ReadStream<R> where R: Read {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T> {
    if self.state != ParserState::EndOfInput {
      try!(self.fill().map_err(ErrorKind::IO));
    }

    let mut buffer = &mut self.buffer;

    if buffer.is_empty() {
      self.state = ParserState::EndOfInput;

      return Err(ErrorKind::EndOfInput);
    }

    let result = {
      let iresult = f(buffer.as_slice());

      from_iresult(&buffer, iresult)
    };

    match result {
      Ok((consumed, o)) => {
        buffer.consume(consumed);

        Ok(o)
      }
      Err(kind)         => {
        if let ErrorKind::Incomplete(needed) = kind {
          self.needed = needed;

          Err(ErrorKind::Continue)
        } else {
          Err(kind)
        }
      }
    }
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use utility::StreamProducer;
  use nom::be_u32;

  #[test]
  fn test_buffer() {
    let mut buffer = Buffer::new();
    let bytes      = b"Hello World";
    let mut reader = &bytes[..];

    assert!(buffer.is_empty());
    assert_eq!(buffer.capacity(), 1024);

    let bytes_read = buffer.fill(&mut reader).unwrap_or(0);
    let bytes_len  = bytes.len();

    assert_eq!(bytes_read, bytes_len);
    assert_eq!(buffer.len(), bytes_len);
    assert_eq!(buffer.as_slice(), bytes);

    buffer.resize(512);
    assert_eq!(buffer.capacity(), 1024);
  }

  #[test]
  fn test_byte_stream() {
    let bytes      = b"Hello World";
    let mut stream = ByteStream::new(bytes);

    assert_eq!(stream.len(), bytes.len());

    let result = stream.parse(be_u32).unwrap_or(0);

    assert_eq!(result, 1214606444);
    assert_eq!(stream.len(), 7);
  }

  #[test]
  fn test_read_stream() {
    let bytes      = b"Hello World";
    let mut stream = ReadStream::new(&bytes[..]);

    let result = stream.parse(be_u32).unwrap_or(0);

    assert_eq!(result, 1214606444)
  }
}
<|endoftext|>


<commit_before>//! Bounding sphere

use cgmath::{BaseFloat, Point3, Vector3};
use cgmath::prelude::*;

use {Aabb3, Line3, Plane, Ray3};
use prelude::*;

/// Bounding sphere.
#[derive(Copy, Clone, PartialEq, Debug)]
#[cfg_attr(feature = "eders", derive(Serialize, Deserialize))]
pub struct Sphere<S: BaseFloat> {
    /// Center point of the sphere in world space
    pub center: Point3<S>,
    /// Sphere radius
    pub radius: S,
}

impl<S> Bound for Sphere<S>
where
    S: BaseFloat,
{
    type Point = Point3<S>;

    fn min_extent(&self) -> Point3<S> {
        self.center + Vector3::from_value(-self.radius)
    }

    fn max_extent(&self) -> Point3<S> {
        self.center + Vector3::from_value(self.radius)
    }

    fn with_margin(&self, add: Vector3<S>) -> Self {
        let max = add.x.max(add.y).max(add.z);
        Sphere {
            center: self.center.clone(),
            radius: self.radius + max,
        }
    }

    fn transform_volume<T>(&self, transform: &T) -> Self
    where
        T: Transform<Self::Point>,
    {
        Sphere {
            center: transform.transform_point(self.center),
            radius: self.radius,
        }
    }

    fn empty() -> Self {
        Self {
            center: Point3::origin(),
            radius: S::zero(),
        }
    }
}

impl<S: BaseFloat> Continuous<Ray3<S>> for Sphere<S> {
    type Result = Point3<S>;
    fn intersection(&self, r: &Ray3<S>) -> Option<Point3<S>> {
        let s = self;

        let l = s.center - r.origin;
        let tca = l.dot(r.direction);
        if tca < S::zero() {
            return None;
        }
        let d2 = l.dot(l) - tca * tca;
        if d2 > s.radius * s.radius {
            return None;
        }
        let thc = (s.radius * s.radius - d2).sqrt();
        Some(r.origin + r.direction * (tca - thc))
    }
}

impl<S: BaseFloat> Discrete<Ray3<S>> for Sphere<S> {
    fn intersects(&self, r: &Ray3<S>) -> bool {
        let s = self;
        let l = s.center - r.origin;
        let tca = l.dot(r.direction);
        if tca < S::zero() {
            return false;
        }
        let d2 = l.dot(l) - tca * tca;
        if d2 > s.radius * s.radius {
            return false;
        }
        return true;
    }
}

impl<S: BaseFloat> Discrete<Sphere<S>> for Sphere<S> {
    fn intersects(&self, s2: &Sphere<S>) -> bool {
        let s1 = self;

        let distance = s1.center.distance2(s2.center);
        let radiuses = s1.radius + s2.radius;

        distance <= radiuses
    }
}

impl<S: BaseFloat> PlaneBound<S> for Sphere<S> {
    fn relate_plane(&self, plane: Plane<S>) -> Relation {
        let dist = self.center.dot(plane.n) - plane.d;
        if dist > self.radius {
            Relation::In
        } else if dist < -self.radius {
            Relation::Out
        } else {
            Relation::Cross
        }
    }
}

impl<S: BaseFloat> Contains<Aabb3<S>> for Sphere<S> {
    // will return true for border hits
    #[inline]
    fn contains(&self, aabb: &Aabb3<S>) -> bool {
        let radius_sq = self.radius * self.radius;
        for c in aabb.to_corners().iter() {
            if c.distance2(self.center) > radius_sq {
                return false;
            }
        }
        true
    }
}

impl<S: BaseFloat> Contains<Point3<S>> for Sphere<S> {
    #[inline]
    fn contains(&self, p: &Point3<S>) -> bool {
        self.center.distance2(*p) <= self.radius * self.radius
    }
}

impl<S: BaseFloat> Contains<Line3<S>> for Sphere<S> {
    #[inline]
    fn contains(&self, line: &Line3<S>) -> bool {
        self.contains(&line.origin) && self.contains(&line.dest)
    }
}

impl<S: BaseFloat> Contains<Sphere<S>> for Sphere<S> {
    #[inline]
    fn contains(&self, other: &Sphere<S>) -> bool {
        let center_dist = self.center.distance(other.center);
        (center_dist + other.radius) <= self.radius
    }
}

impl<S: BaseFloat> Union for Sphere<S> {
    type Output = Sphere<S>;

    fn union(&self, other: &Sphere<S>) -> Sphere<S> {
        if self.contains(other) {
            return self.clone();
        }
        if other.contains(self) {
            return other.clone();
        }
        let two = S::one() + S::one();
        let center_diff = other.center - self.center;
        let center_diff_s = center_diff.magnitude();
        let radius = (self.radius + other.radius + center_diff_s) / two;
        Sphere {
            radius,
            center: self.center + center_diff * (radius - self.radius) / center_diff_s,
        }
    }
}

impl<S: BaseFloat> Union<Aabb3<S>> for Sphere<S> {
    type Output = Sphere<S>;

    fn union(&self, aabb: &Aabb3<S>) -> Sphere<S> {
        if self.contains(aabb) {
            return self.clone();
        }
        let aabb_radius = aabb.max().distance(aabb.center());
        if aabb.contains(self) {
            return Sphere {
                center: aabb.center(),
                radius: aabb_radius,
            };
        }
        let two = S::one() + S::one();
        let center_diff = aabb.center() - self.center;
        let center_diff_s = aabb.center().distance(self.center);
        let radius = (self.radius + aabb_radius + center_diff_s) / two;
        Sphere {
            center: self.center + center_diff * (radius - self.radius) / center_diff_s,
            radius,
        }
    }
}

impl<S: BaseFloat> SurfaceArea for Sphere<S> {
    type Scalar = S;

    fn surface_area(&self) -> S {
        use std::f64::consts::PI;

        let two = S::one() + S::one();
        let four = two + two;
        let pi = S::from(PI).unwrap();
        four * pi * self.radius * self.radius
    }
}
<commit_msg>Fix sphere discrete intersection test<commit_after>//! Bounding sphere

use cgmath::{BaseFloat, Point3, Vector3};
use cgmath::prelude::*;

use {Aabb3, Line3, Plane, Ray3};
use prelude::*;

/// Bounding sphere.
#[derive(Copy, Clone, PartialEq, Debug)]
#[cfg_attr(feature = "eders", derive(Serialize, Deserialize))]
pub struct Sphere<S: BaseFloat> {
    /// Center point of the sphere in world space
    pub center: Point3<S>,
    /// Sphere radius
    pub radius: S,
}

impl<S> Bound for Sphere<S>
where
    S: BaseFloat,
{
    type Point = Point3<S>;

    fn min_extent(&self) -> Point3<S> {
        self.center + Vector3::from_value(-self.radius)
    }

    fn max_extent(&self) -> Point3<S> {
        self.center + Vector3::from_value(self.radius)
    }

    fn with_margin(&self, add: Vector3<S>) -> Self {
        let max = add.x.max(add.y).max(add.z);
        Sphere {
            center: self.center.clone(),
            radius: self.radius + max,
        }
    }

    fn transform_volume<T>(&self, transform: &T) -> Self
    where
        T: Transform<Self::Point>,
    {
        Sphere {
            center: transform.transform_point(self.center),
            radius: self.radius,
        }
    }

    fn empty() -> Self {
        Self {
            center: Point3::origin(),
            radius: S::zero(),
        }
    }
}

impl<S: BaseFloat> Continuous<Ray3<S>> for Sphere<S> {
    type Result = Point3<S>;
    fn intersection(&self, r: &Ray3<S>) -> Option<Point3<S>> {
        let s = self;

        let l = s.center - r.origin;
        let tca = l.dot(r.direction);
        if tca < S::zero() {
            return None;
        }
        let d2 = l.dot(l) - tca * tca;
        if d2 > s.radius * s.radius {
            return None;
        }
        let thc = (s.radius * s.radius - d2).sqrt();
        Some(r.origin + r.direction * (tca - thc))
    }
}

impl<S: BaseFloat> Discrete<Ray3<S>> for Sphere<S> {
    fn intersects(&self, r: &Ray3<S>) -> bool {
        let s = self;
        let l = s.center - r.origin;
        let tca = l.dot(r.direction);
        if tca < S::zero() {
            return false;
        }
        let d2 = l.dot(l) - tca * tca;
        if d2 > s.radius * s.radius {
            return false;
        }
        return true;
    }
}

impl<S: BaseFloat> Discrete<Sphere<S>> for Sphere<S> {
    fn intersects(&self, s2: &Sphere<S>) -> bool {
        let s1 = self;

        let distance = s1.center.distance2(s2.center);
        let radiuses = s1.radius + s2.radius;

        distance <= radiuses * radiuses
    }
}

impl<S: BaseFloat> PlaneBound<S> for Sphere<S> {
    fn relate_plane(&self, plane: Plane<S>) -> Relation {
        let dist = self.center.dot(plane.n) - plane.d;
        if dist > self.radius {
            Relation::In
        } else if dist < -self.radius {
            Relation::Out
        } else {
            Relation::Cross
        }
    }
}

impl<S: BaseFloat> Contains<Aabb3<S>> for Sphere<S> {
    // will return true for border hits
    #[inline]
    fn contains(&self, aabb: &Aabb3<S>) -> bool {
        let radius_sq = self.radius * self.radius;
        for c in aabb.to_corners().iter() {
            if c.distance2(self.center) > radius_sq {
                return false;
            }
        }
        true
    }
}

impl<S: BaseFloat> Contains<Point3<S>> for Sphere<S> {
    #[inline]
    fn contains(&self, p: &Point3<S>) -> bool {
        self.center.distance2(*p) <= self.radius * self.radius
    }
}

impl<S: BaseFloat> Contains<Line3<S>> for Sphere<S> {
    #[inline]
    fn contains(&self, line: &Line3<S>) -> bool {
        self.contains(&line.origin) && self.contains(&line.dest)
    }
}

impl<S: BaseFloat> Contains<Sphere<S>> for Sphere<S> {
    #[inline]
    fn contains(&self, other: &Sphere<S>) -> bool {
        let center_dist = self.center.distance(other.center);
        (center_dist + other.radius) <= self.radius
    }
}

impl<S: BaseFloat> Union for Sphere<S> {
    type Output = Sphere<S>;

    fn union(&self, other: &Sphere<S>) -> Sphere<S> {
        if self.contains(other) {
            return self.clone();
        }
        if other.contains(self) {
            return other.clone();
        }
        let two = S::one() + S::one();
        let center_diff = other.center - self.center;
        let center_diff_s = center_diff.magnitude();
        let radius = (self.radius + other.radius + center_diff_s) / two;
        Sphere {
            radius,
            center: self.center + center_diff * (radius - self.radius) / center_diff_s,
        }
    }
}

impl<S: BaseFloat> Union<Aabb3<S>> for Sphere<S> {
    type Output = Sphere<S>;

    fn union(&self, aabb: &Aabb3<S>) -> Sphere<S> {
        if self.contains(aabb) {
            return self.clone();
        }
        let aabb_radius = aabb.max().distance(aabb.center());
        if aabb.contains(self) {
            return Sphere {
                center: aabb.center(),
                radius: aabb_radius,
            };
        }
        let two = S::one() + S::one();
        let center_diff = aabb.center() - self.center;
        let center_diff_s = aabb.center().distance(self.center);
        let radius = (self.radius + aabb_radius + center_diff_s) / two;
        Sphere {
            center: self.center + center_diff * (radius - self.radius) / center_diff_s,
            radius,
        }
    }
}

impl<S: BaseFloat> SurfaceArea for Sphere<S> {
    type Scalar = S;

    fn surface_area(&self) -> S {
        use std::f64::consts::PI;

        let two = S::one() + S::one();
        let four = two + two;
        let pi = S::from(PI).unwrap();
        four * pi * self.radius * self.radius
    }
}
<|endoftext|>