<commit_before>//! # Command Tokenization
//!
//! The command parser needs to be able to tokenize commands
//! into their constituent words and whitespace.
//!
//! The `tokenizer` breaks source text into a vector of tokens
//! which can be either whitespace or a word. The tokenizer
//! handles using double quotes to provide a single token
//! which may include whitespace.
//!
//! Tokens also track their source location within the source
//! text. This allows the parser using the tokenizer to provide
//! better error highlighting and other functionality.
//!
//! # Examples
//!
//! ```
//! use commands::tokenizer::tokenize;
//!
//! if let Ok(tokens) = tokenize("word") {
//!     assert_eq!(tokens.len(), 1);
//! }
//!
//! if let Ok(tokens) = tokenize("show interface") {
//!     assert_eq!(tokens.len(), 3);
//! }
//!
//! if let Ok(tokens) = tokenize("echo -n \"a b c\"") {
//!     assert_eq!(tokens.len(), 5);
//! }
//!
//! if let Ok(tokens) = tokenize("ls My\\ Documents") {
//!     assert_eq!(tokens.len(), 3);
//!     assert_eq!(tokens[2].text, "My\\ Documents");
//! }
//! ```

/// A position within a body of text.
///
/// The `SourceOffset` tracks 2 different ways of locating the
/// position:
///
/// * The index of the character within the body of text.
/// * The column and line number of the character.
///
/// The `SourceOffset` is typically used as a pair of offsets
/// indicating the start and end of a range of text as used
/// by the `SourceLocation`.
#[derive(Debug,PartialEq)]
pub struct SourceOffset {
    /// The index of this character within the body of text.
    pub char: usize,
    /// The line number on which this character may be found.
    pub line: usize,
    /// The column on which this character may be found.
    pub column: usize,
}

impl SourceOffset {
    /// Construct a `SourceOffset`.
    pub fn new(char: usize, line: usize, column: usize) -> SourceOffset {
        SourceOffset {
            char: char,
            line: line,
            column: column,
        }
    }
}

/// A range within a body of text.
#[derive(Debug,PartialEq)]
pub struct SourceLocation {
    /// The start of the range.
    pub start: SourceOffset,
    /// The end of the range.
    pub end: SourceOffset,
}

impl SourceLocation {
    /// Construct a `SourceLocation`.
    pub fn new(start: SourceOffset, end: SourceOffset) -> SourceLocation {
        SourceLocation {
            start: start,
            end: end,
        }
    }
}

/// Errors
pub enum TokenizerError {
    /// Character not allowed here
    CharacterNotAllowedHere(usize),

    /// Special not yet implemented
    SpecialNotYetImplemented(usize),

    /// Escaping backslash at end of input
    EscapingBackslashAtEndOfInput,

    /// Unclosed double quote at end of input
    UnclosedDoubleQuoteAtEndOfInput,

    /// Escaped double quote at end of input
    EscapedDoubleQuoteAtEndOfInput,
}

/// The role that a token plays: `Whitespace` or `Word`.
#[derive(Clone,Copy,Debug,PartialEq)]
pub enum TokenType {
    /// Internal usage only.
    Invalid,
    /// The token represents whitespace and not a word.
    Whitespace,
    /// The token represents a word within the body of text. This
    /// takes double quoted strings into account.
    Word,
}

/// A token from a body of text.
///
/// The lifetime parameter `'t` refers to the lifetime
/// of the body of text that was tokenized, creating this token.
#[derive(Debug,PartialEq)]
pub struct Token<'t> {
    /// The text of the token.
    pub text: &'t str,
    /// The type of the token (`Whitespace` or `Word`).
    pub token_type: TokenType,
    /// The location of the token in the source body of text.
    pub location: SourceLocation,
}

impl<'t> Token<'t> {
    /// Construct a `Token`. The lifetime parameter `'t` refers to the lifetime of the
    /// text being tokenized.
    pub fn new(text: &'t str, token_type: TokenType, location: SourceLocation) -> Token {
        Token {
            text: text,
            token_type: token_type,
            location: location,
        }
    }
}

#[derive(Clone,Copy,PartialEq)]
enum State {
    Initial,
    Special,
    Whitespace,
    Doublequote,
    DoublequoteBackslash,
    Word,
    WordBackslash,
}

struct Tokenizer<'t> {
    text: &'t str,
    state: State,
    token_type: TokenType,
    token_start: usize,
    token_end: usize,
    tokens: Vec<Token<'t>>,
}

impl<'t> Tokenizer<'t> {
    fn new(text: &'t str) -> Tokenizer {
        Tokenizer {
            text: text,
            state: State::Initial,
            token_type: TokenType::Invalid,
            token_start: 0,
            token_end: 0,
            tokens: vec![],
        }
    }

    fn reset(&mut self) {
        self.state = State::Initial;
        self.token_type = TokenType::Invalid;
        self.token_start = 0;
        self.token_end = 0;
    }

    fn reduce(&mut self) {
        let token_text = &self.text[self.token_start..self.token_end + 1];
        let loc = SourceLocation::new(SourceOffset::new(self.token_start, 0, self.token_start),
                                      SourceOffset::new(self.token_end, 0, self.token_end));
        self.tokens.push(Token::new(token_text, self.token_type, loc));
        self.reset();
    }

    fn shift(&mut self, offset: usize, next_state: State) {
        self.recognize(offset, next_state);
        self.token_end = offset;
        self.state = next_state;
    }

    fn recognize(&mut self, offset: usize, next_state: State) {
        if self.token_type == TokenType::Invalid {
            self.token_type = if next_state == State::Whitespace {
                TokenType::Whitespace
            } else {
                TokenType::Word
            };
            self.token_start = offset;
        }
    }

    fn special(&mut self, offset: usize) {
        self.shift(offset, State::Special);
        self.reduce();
    }

    fn initial(&mut self, offset: usize, c: char) {
        if c.is_whitespace() {
            self.shift(offset, State::Whitespace);
        } else if c == ';' {
            self.special(offset);
        } else if c == '?' {
            self.special(offset);
        } else if c == '|' {
            self.special(offset);
        } else if c == '"' {
            self.shift(offset, State::Doublequote);
        } else if c == '\\' {
            self.recognize(offset, State::Word);
            self.shift(offset, State::WordBackslash);
        } else {
            self.shift(offset, State::Word);
        }
    }

    fn tokenize(&mut self) -> Result<(), TokenizerError> {
        for (offset, c) in self.text.chars().enumerate() {
            match self.state {
                State::Initial => self.initial(offset, c),
                State::Whitespace => {
                    if c.is_whitespace() {
                        self.shift(offset, State::Whitespace);
                    } else {
                        self.reduce();
                        self.initial(offset, c);
                    };
                }
                State::Word => {
                    if c.is_whitespace() {
                        self.reduce();
                        self.shift(offset, State::Whitespace);
                    } else if c == ';' {
                        self.reduce();
                        self.special(offset);
                    } else if c == '|' {
                        self.reduce();
                        self.special(offset);
                    } else if c == '"' {
                        self.reduce();
                        self.shift(offset, State::Doublequote);
                    } else if c == '\\' {
                        self.shift(offset, State::WordBackslash);
                    } else {
                        self.shift(offset, State::Word);
                    }
                }
                State::WordBackslash => {
                    // XXX: This should be if !c.is_control() perhaps?
                    if c.is_alphanumeric() || c.is_whitespace() {
                        self.shift(offset, State::Word);
                    } else {
                        return Err(TokenizerError::CharacterNotAllowedHere(offset));
                    };
                }
                State::Doublequote => {
                    if c == '"' {
                        self.shift(offset, State::Doublequote);
                        self.reduce();
                    } else if c == '\\' {
                        self.shift(offset, State::DoublequoteBackslash);
                    } else {
                        self.shift(offset, State::Doublequote);
                    };
                }
                State::DoublequoteBackslash => {
                    if !c.is_whitespace() {
                        self.shift(offset, State::Doublequote);
                    } else {
                        return Err(TokenizerError::CharacterNotAllowedHere(offset));
                    };
                }
                State::Special => {
                    return Err(TokenizerError::SpecialNotYetImplemented(offset));
                }
            }
        }

        // Now for the end of the text...
        match self.state {
            State::Initial => {}
            State::Word => self.reduce(),
            State::Whitespace => self.reduce(),
            State::WordBackslash => return Err(TokenizerError::EscapingBackslashAtEndOfInput),
            State::Doublequote => return Err(TokenizerError::UnclosedDoubleQuoteAtEndOfInput),
            State::DoublequoteBackslash => {
                return Err(TokenizerError::EscapedDoubleQuoteAtEndOfInput)
            }
            State::Special => {
                return Err(TokenizerError::SpecialNotYetImplemented(self.text.len() - 1))
            }
        }

        Ok(())
    }
}

/// Tokenize a body of text.
pub fn tokenize(text: &str) -> Result<Vec<Token>, TokenizerError> {
    let mut tokenizer = Tokenizer::new(text);
    match tokenizer.tokenize() {
        Ok(_) => Ok(tokenizer.tokens),
        Err(error) => Err(error),
    }
}

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

    fn mk_token(text: &str, token_type: TokenType, start: usize, end: usize) -> Token {
        Token::new(text,
                   token_type,
                   SourceLocation::new(SourceOffset::new(start, 0, start),
                                       SourceOffset::new(end, 0, end)))
    }

    #[test]
    fn empty_test() {
        match tokenize("") {
            Ok(ts) => assert_eq!(ts.len(), 0),
            _ => {}
        };
    }

    #[test]
    fn single_word() {
        match tokenize("a") {
            Ok(ts) => {
                assert_eq!(ts.len(), 1);
                assert_eq!(ts[0], mk_token("a", TokenType::Word, 0, 0));
            }
            _ => {}
        };
    }

    #[test]
    fn multiple_words() {
        match tokenize(" aa bb  ccc ") {
            Ok(ts) => {
                assert_eq!(ts.len(), 7);
                assert_eq!(ts[0], mk_token(" ", TokenType::Whitespace, 0, 0));
                assert_eq!(ts[1], mk_token("aa", TokenType::Word, 1, 2));
                assert_eq!(ts[2], mk_token(" ", TokenType::Whitespace, 3, 3));
                assert_eq!(ts[3], mk_token("bb", TokenType::Word, 4, 5));
                assert_eq!(ts[4], mk_token("  ", TokenType::Whitespace, 6, 7));
                assert_eq!(ts[5], mk_token("ccc", TokenType::Word, 8, 10));
                assert_eq!(ts[6], mk_token(" ", TokenType::Whitespace, 11, 11));
            }
            _ => {}
        };
    }

    #[test]
    fn quoted_text() {
        match tokenize("a \"b c\"") {
            Ok(ts) => {
                assert_eq!(ts.len(), 3);
                assert_eq!(ts[0], mk_token("a", TokenType::Word, 0, 0));
                assert_eq!(ts[1], mk_token(" ", TokenType::Whitespace, 1, 1));
                assert_eq!(ts[2], mk_token("\"b c\"", TokenType::Word, 2, 6));
            }
            _ => {}
        };
    }

    #[test]
    fn escaped_whitespace_in_word() {
        match tokenize("a\\ b") {
            Ok(ts) => {
                assert_eq!(ts.len(), 1);
                assert_eq!(ts[0], mk_token("a\\ b", TokenType::Word, 0, 3));
            }
            _ => {}
        };
    }
}
<commit_msg>tokenizer: implemented Error and Display for TokenizerError<commit_after>//! # Command Tokenization
//!
//! The command parser needs to be able to tokenize commands
//! into their constituent words and whitespace.
//!
//! The `tokenizer` breaks source text into a vector of tokens
//! which can be either whitespace or a word. The tokenizer
//! handles using double quotes to provide a single token
//! which may include whitespace.
//!
//! Tokens also track their source location within the source
//! text. This allows the parser using the tokenizer to provide
//! better error highlighting and other functionality.
//!
//! # Examples
//!
//! ```
//! use commands::tokenizer::tokenize;
//!
//! if let Ok(tokens) = tokenize("word") {
//!     assert_eq!(tokens.len(), 1);
//! }
//!
//! if let Ok(tokens) = tokenize("show interface") {
//!     assert_eq!(tokens.len(), 3);
//! }
//!
//! if let Ok(tokens) = tokenize("echo -n \"a b c\"") {
//!     assert_eq!(tokens.len(), 5);
//! }
//!
//! if let Ok(tokens) = tokenize("ls My\\ Documents") {
//!     assert_eq!(tokens.len(), 3);
//!     assert_eq!(tokens[2].text, "My\\ Documents");
//! }
//! ```

use std::fmt;
use std::error::Error;

/// A position within a body of text.
///
/// The `SourceOffset` tracks 2 different ways of locating the
/// position:
///
/// * The index of the character within the body of text.
/// * The column and line number of the character.
///
/// The `SourceOffset` is typically used as a pair of offsets
/// indicating the start and end of a range of text as used
/// by the `SourceLocation`.
#[derive(Debug,PartialEq)]
pub struct SourceOffset {
    /// The index of this character within the body of text.
    pub char: usize,
    /// The line number on which this character may be found.
    pub line: usize,
    /// The column on which this character may be found.
    pub column: usize,
}

impl SourceOffset {
    /// Construct a `SourceOffset`.
    pub fn new(char: usize, line: usize, column: usize) -> SourceOffset {
        SourceOffset {
            char: char,
            line: line,
            column: column,
        }
    }
}

/// A range within a body of text.
#[derive(Debug,PartialEq)]
pub struct SourceLocation {
    /// The start of the range.
    pub start: SourceOffset,
    /// The end of the range.
    pub end: SourceOffset,
}

impl SourceLocation {
    /// Construct a `SourceLocation`.
    pub fn new(start: SourceOffset, end: SourceOffset) -> SourceLocation {
        SourceLocation {
            start: start,
            end: end,
        }
    }
}

/// Errors
#[derive(Clone,Debug)]
pub enum TokenizerError {
    /// Character not allowed here
    CharacterNotAllowedHere(usize),

    /// Special not yet implemented
    SpecialNotYetImplemented(usize),

    /// Escaping backslash at end of input
    EscapingBackslashAtEndOfInput,

    /// Unclosed double quote at end of input
    UnclosedDoubleQuoteAtEndOfInput,

    /// Escaped double quote at end of input
    EscapedDoubleQuoteAtEndOfInput,
}

impl Error for TokenizerError {
    fn description(&self) -> &str {
        match *self {
            TokenizerError::CharacterNotAllowedHere(_) => "Character not allowed here",
            TokenizerError::SpecialNotYetImplemented(_) => "Special not yet implemented",
            TokenizerError::EscapingBackslashAtEndOfInput => "Escaping backlash at end of input",
            TokenizerError::UnclosedDoubleQuoteAtEndOfInput => "Unclosed double quote at end of input",
            TokenizerError::EscapedDoubleQuoteAtEndOfInput => "Escaped double quote at end of input",
        }
    }
}

impl fmt::Display for TokenizerError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.description().fmt(f)
    }
}

/// The role that a token plays: `Whitespace` or `Word`.
#[derive(Clone,Copy,Debug,PartialEq)]
pub enum TokenType {
    /// Internal usage only.
    Invalid,
    /// The token represents whitespace and not a word.
    Whitespace,
    /// The token represents a word within the body of text. This
    /// takes double quoted strings into account.
    Word,
}

/// A token from a body of text.
///
/// The lifetime parameter `'t` refers to the lifetime
/// of the body of text that was tokenized, creating this token.
#[derive(Debug,PartialEq)]
pub struct Token<'t> {
    /// The text of the token.
    pub text: &'t str,
    /// The type of the token (`Whitespace` or `Word`).
    pub token_type: TokenType,
    /// The location of the token in the source body of text.
    pub location: SourceLocation,
}

impl<'t> Token<'t> {
    /// Construct a `Token`. The lifetime parameter `'t` refers to the lifetime of the
    /// text being tokenized.
    pub fn new(text: &'t str, token_type: TokenType, location: SourceLocation) -> Token {
        Token {
            text: text,
            token_type: token_type,
            location: location,
        }
    }
}

#[derive(Clone,Copy,PartialEq)]
enum State {
    Initial,
    Special,
    Whitespace,
    Doublequote,
    DoublequoteBackslash,
    Word,
    WordBackslash,
}

struct Tokenizer<'t> {
    text: &'t str,
    state: State,
    token_type: TokenType,
    token_start: usize,
    token_end: usize,
    tokens: Vec<Token<'t>>,
}

impl<'t> Tokenizer<'t> {
    fn new(text: &'t str) -> Tokenizer {
        Tokenizer {
            text: text,
            state: State::Initial,
            token_type: TokenType::Invalid,
            token_start: 0,
            token_end: 0,
            tokens: vec![],
        }
    }

    fn reset(&mut self) {
        self.state = State::Initial;
        self.token_type = TokenType::Invalid;
        self.token_start = 0;
        self.token_end = 0;
    }

    fn reduce(&mut self) {
        let token_text = &self.text[self.token_start..self.token_end + 1];
        let loc = SourceLocation::new(SourceOffset::new(self.token_start, 0, self.token_start),
                                      SourceOffset::new(self.token_end, 0, self.token_end));
        self.tokens.push(Token::new(token_text, self.token_type, loc));
        self.reset();
    }

    fn shift(&mut self, offset: usize, next_state: State) {
        self.recognize(offset, next_state);
        self.token_end = offset;
        self.state = next_state;
    }

    fn recognize(&mut self, offset: usize, next_state: State) {
        if self.token_type == TokenType::Invalid {
            self.token_type = if next_state == State::Whitespace {
                TokenType::Whitespace
            } else {
                TokenType::Word
            };
            self.token_start = offset;
        }
    }

    fn special(&mut self, offset: usize) {
        self.shift(offset, State::Special);
        self.reduce();
    }

    fn initial(&mut self, offset: usize, c: char) {
        if c.is_whitespace() {
            self.shift(offset, State::Whitespace);
        } else if c == ';' {
            self.special(offset);
        } else if c == '?' {
            self.special(offset);
        } else if c == '|' {
            self.special(offset);
        } else if c == '"' {
            self.shift(offset, State::Doublequote);
        } else if c == '\\' {
            self.recognize(offset, State::Word);
            self.shift(offset, State::WordBackslash);
        } else {
            self.shift(offset, State::Word);
        }
    }

    fn tokenize(&mut self) -> Result<(), TokenizerError> {
        for (offset, c) in self.text.chars().enumerate() {
            match self.state {
                State::Initial => self.initial(offset, c),
                State::Whitespace => {
                    if c.is_whitespace() {
                        self.shift(offset, State::Whitespace);
                    } else {
                        self.reduce();
                        self.initial(offset, c);
                    };
                }
                State::Word => {
                    if c.is_whitespace() {
                        self.reduce();
                        self.shift(offset, State::Whitespace);
                    } else if c == ';' {
                        self.reduce();
                        self.special(offset);
                    } else if c == '|' {
                        self.reduce();
                        self.special(offset);
                    } else if c == '"' {
                        self.reduce();
                        self.shift(offset, State::Doublequote);
                    } else if c == '\\' {
                        self.shift(offset, State::WordBackslash);
                    } else {
                        self.shift(offset, State::Word);
                    }
                }
                State::WordBackslash => {
                    // XXX: This should be if !c.is_control() perhaps?
                    if c.is_alphanumeric() || c.is_whitespace() {
                        self.shift(offset, State::Word);
                    } else {
                        return Err(TokenizerError::CharacterNotAllowedHere(offset));
                    };
                }
                State::Doublequote => {
                    if c == '"' {
                        self.shift(offset, State::Doublequote);
                        self.reduce();
                    } else if c == '\\' {
                        self.shift(offset, State::DoublequoteBackslash);
                    } else {
                        self.shift(offset, State::Doublequote);
                    };
                }
                State::DoublequoteBackslash => {
                    if !c.is_whitespace() {
                        self.shift(offset, State::Doublequote);
                    } else {
                        return Err(TokenizerError::CharacterNotAllowedHere(offset));
                    };
                }
                State::Special => {
                    return Err(TokenizerError::SpecialNotYetImplemented(offset));
                }
            }
        }

        // Now for the end of the text...
        match self.state {
            State::Initial => {}
            State::Word => self.reduce(),
            State::Whitespace => self.reduce(),
            State::WordBackslash => return Err(TokenizerError::EscapingBackslashAtEndOfInput),
            State::Doublequote => return Err(TokenizerError::UnclosedDoubleQuoteAtEndOfInput),
            State::DoublequoteBackslash => {
                return Err(TokenizerError::EscapedDoubleQuoteAtEndOfInput)
            }
            State::Special => {
                return Err(TokenizerError::SpecialNotYetImplemented(self.text.len() - 1))
            }
        }

        Ok(())
    }
}

/// Tokenize a body of text.
pub fn tokenize(text: &str) -> Result<Vec<Token>, TokenizerError> {
    let mut tokenizer = Tokenizer::new(text);
    match tokenizer.tokenize() {
        Ok(_) => Ok(tokenizer.tokens),
        Err(error) => Err(error),
    }
}

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

    fn mk_token(text: &str, token_type: TokenType, start: usize, end: usize) -> Token {
        Token::new(text,
                   token_type,
                   SourceLocation::new(SourceOffset::new(start, 0, start),
                                       SourceOffset::new(end, 0, end)))
    }

    #[test]
    fn empty_test() {
        match tokenize("") {
            Ok(ts) => assert_eq!(ts.len(), 0),
            _ => {}
        };
    }

    #[test]
    fn single_word() {
        match tokenize("a") {
            Ok(ts) => {
                assert_eq!(ts.len(), 1);
                assert_eq!(ts[0], mk_token("a", TokenType::Word, 0, 0));
            }
            _ => {}
        };
    }

    #[test]
    fn multiple_words() {
        match tokenize(" aa bb  ccc ") {
            Ok(ts) => {
                assert_eq!(ts.len(), 7);
                assert_eq!(ts[0], mk_token(" ", TokenType::Whitespace, 0, 0));
                assert_eq!(ts[1], mk_token("aa", TokenType::Word, 1, 2));
                assert_eq!(ts[2], mk_token(" ", TokenType::Whitespace, 3, 3));
                assert_eq!(ts[3], mk_token("bb", TokenType::Word, 4, 5));
                assert_eq!(ts[4], mk_token("  ", TokenType::Whitespace, 6, 7));
                assert_eq!(ts[5], mk_token("ccc", TokenType::Word, 8, 10));
                assert_eq!(ts[6], mk_token(" ", TokenType::Whitespace, 11, 11));
            }
            _ => {}
        };
    }

    #[test]
    fn quoted_text() {
        match tokenize("a \"b c\"") {
            Ok(ts) => {
                assert_eq!(ts.len(), 3);
                assert_eq!(ts[0], mk_token("a", TokenType::Word, 0, 0));
                assert_eq!(ts[1], mk_token(" ", TokenType::Whitespace, 1, 1));
                assert_eq!(ts[2], mk_token("\"b c\"", TokenType::Word, 2, 6));
            }
            _ => {}
        };
    }

    #[test]
    fn escaped_whitespace_in_word() {
        match tokenize("a\\ b") {
            Ok(ts) => {
                assert_eq!(ts.len(), 1);
                assert_eq!(ts[0], mk_token("a\\ b", TokenType::Word, 0, 3));
            }
            _ => {}
        };
    }
}
<|endoftext|>


<commit_before>use Printer;
use direction::Direction;
use event::{Event, EventResult};
use std::any::Any;
use vec::Vec2;
use view::{AnyView, Selector};

/// Main trait defining a view behaviour.
///
/// This is what you should implement to define a custom View.
pub trait View: Any + AnyView {

    /// Draws the view with the given printer (includes bounds) and focus.
    ///
    /// This is the only *required* method to implement.
    fn draw(&self, printer: &Printer);

    /// Called once the size for this view has been decided.
    ///
    /// It can be used to pre-compute the configuration of child views.
    ///
    /// View groups should propagate the information to their children.
    ///
    /// At this point, the given size is final and cannot be negociated.
    /// It is guaranteed to be the size available for the call to `draw()`.
    fn layout(&mut self, Vec2) {}

    /// Returns `true` if the view content changed since last layout phase.
    ///
    /// This is mostly an optimisation for views where the layout phase is
    /// expensive.
    ///
    /// * Views can ignore it and always return true (default implementation).
    ///   They will always be assumed to have changed.
    /// * View Groups can ignore it and always re-layout their children.
    ///     * If they call `required_size` or `layout` with stable parameters,
    ///       the children may cache the result themselves and speed up the
    ///       process anyway.
    fn needs_relayout(&self) -> bool {
        true
    }

    /// Returns the minimum size the view requires with the given restrictions.
    ///
    /// This is the main way a view communicate its size to its parent.
    ///
    /// If the view is flexible (it has multiple size options), it can try
    /// to return one that fits the given `constraint`.
    /// It's also fine to ignore it and return a fixed value.
    ///
    /// Default implementation always return `(1,1)`.
    fn required_size(&mut self, constraint: Vec2) -> Vec2 {
        let _ = constraint;
        Vec2::new(1, 1)
    }

    /// Called when an event is received (key press, mouse event, ...).
    ///
    /// You can return an `EventResult`, with an optional callback to be run.
    ///
    /// Default implementation just ignores it.
    fn on_event(&mut self, Event) -> EventResult {
        EventResult::Ignored
    }

    /// Runs a closure on the view identified by the given selector.
    ///
    /// See [`Finder::call_on`] for a nicer interface, implemented for all
    /// views.
    ///
    /// [`Finder::call_on`]: trait.Finder.html#method.call_on
    ///
    /// If the selector doesn't find a match, the closure will not be run.
    ///
    /// Default implementation is a no-op.
    fn call_on_any<'a>(&mut self, _: &Selector, _: Box<FnMut(&mut Any) + 'a>) {
        // TODO: FnMut -> FnOnce once it works
    }

    /// Moves the focus to the view identified by the given selector.
    ///
    /// Returns `Ok(())` if the view was found and selected.
    ///
    /// Default implementation simply returns `Err(())`.
    fn focus_view(&mut self, &Selector) -> Result<(), ()> {
        Err(())
    }

    /// This view is offered focus. Will it take it?
    ///
    /// `source` indicates where the focus comes from.
    /// When the source is unclear, `Front` is usually used.
    ///
    /// Default implementation always return `false`.
    fn take_focus(&mut self, source: Direction) -> bool {
        let _ = source;
        false
    }
}
<commit_msg>Add View::important_area<commit_after>use Printer;
use direction::Direction;
use event::{Event, EventResult};
use rect::Rect;
use std::any::Any;
use vec::Vec2;
use view::{AnyView, Selector};

/// Main trait defining a view behaviour.
///
/// This is what you should implement to define a custom View.
pub trait View: Any + AnyView {
    /// Draws the view with the given printer (includes bounds) and focus.
    ///
    /// This is the only *required* method to implement.
    fn draw(&self, printer: &Printer);

    /// Called once the size for this view has been decided.
    ///
    /// It can be used to pre-compute the configuration of child views.
    ///
    /// View groups should propagate the information to their children.
    ///
    /// At this point, the given size is final and cannot be negociated.
    /// It is guaranteed to be the size available for the call to `draw()`.
    fn layout(&mut self, Vec2) {}

    /// Returns `true` if the view content changed since last layout phase.
    ///
    /// This is mostly an optimisation for views where the layout phase is
    /// expensive.
    ///
    /// * Views can ignore it and always return true (default implementation).
    ///   They will always be assumed to have changed.
    /// * View Groups can ignore it and always re-layout their children.
    ///     * If they call `required_size` or `layout` with stable parameters,
    ///       the children may cache the result themselves and speed up the
    ///       process anyway.
    fn needs_relayout(&self) -> bool {
        true
    }

    /// Returns the minimum size the view requires with the given restrictions.
    ///
    /// This is the main way a view communicate its size to its parent.
    ///
    /// If the view is flexible (it has multiple size options), it can try
    /// to return one that fits the given `constraint`.
    /// It's also fine to ignore it and return a fixed value.
    ///
    /// Default implementation always return `(1,1)`.
    fn required_size(&mut self, constraint: Vec2) -> Vec2 {
        let _ = constraint;
        Vec2::new(1, 1)
    }

    /// Called when an event is received (key press, mouse event, ...).
    ///
    /// You can return an `EventResult`, with an optional callback to be run.
    ///
    /// Default implementation just ignores it.
    fn on_event(&mut self, Event) -> EventResult {
        EventResult::Ignored
    }

    /// Runs a closure on the view identified by the given selector.
    ///
    /// See [`Finder::call_on`] for a nicer interface, implemented for all
    /// views.
    ///
    /// [`Finder::call_on`]: trait.Finder.html#method.call_on
    ///
    /// If the selector doesn't find a match, the closure will not be run.
    ///
    /// Default implementation is a no-op.
    fn call_on_any<'a>(&mut self, _: &Selector, _: Box<FnMut(&mut Any) + 'a>) {
        // TODO: FnMut -> FnOnce once it works
    }

    /// Moves the focus to the view identified by the given selector.
    ///
    /// Returns `Ok(())` if the view was found and selected.
    ///
    /// Default implementation simply returns `Err(())`.
    fn focus_view(&mut self, &Selector) -> Result<(), ()> {
        Err(())
    }

    /// This view is offered focus. Will it take it?
    ///
    /// `source` indicates where the focus comes from.
    /// When the source is unclear, `Front` is usually used.
    ///
    /// Default implementation always return `false`.
    fn take_focus(&mut self, source: Direction) -> bool {
        let _ = source;
        false
    }

    /// What part of the view is important and should be visible?
    ///
    /// When only part of this view can be visible, this helps
    /// determine which part.
    ///
    /// It is given the view size (same size given to `layout`).
    ///
    /// Default implementation return the entire view.
    fn important_area(&self, view_size: Vec2) -> Rect {
        Rect::from_corners((0, 0), view_size)
    }
}
<|endoftext|>


<commit_before>use std::vec::Vec;
use std::io::{BufReader, SeekSet};
use super::types::*;

pub struct Image {
    width: uint,
    height: uint,
    x_offset: int,
    y_offset: int,
    pixels: Vec<u16>,
}

macro_rules! io_try(
    ($e:expr) => (try!($e.map_err(|e| String::from_str(e.desc))))
)

impl Image {
    pub fn new(width: uint, height: uint) -> Image{
        Image { width: width,
                height: height,
                x_offset: 0,
                y_offset: 0,
                pixels: Vec::from_elem(width * height, 0xff00) }
    }

    pub fn new_from_header(header: &WadTextureHeader) -> Image {
        Image::new(header.width as uint, header.height as uint)
    }

    pub fn from_buffer(buffer: &[u8]) -> Image {
        let mut reader = BufReader::new(buffer);

        let width = reader.read_le_u16().unwrap() as uint;
        let height = reader.read_le_u16().unwrap() as uint;
        let x_offset = reader.read_le_i16().unwrap() as int;
        let y_offset = reader.read_le_i16().unwrap() as int;

        let mut pixels = Vec::from_elem(width * height, -1);
        for i_column in range(0, width as int) { unsafe {
            let offset = reader.read_le_u32().unwrap() as int;
            let mut s_ptr = buffer.as_ptr().offset(offset);
            loop {
                let row_start = *s_ptr as int; s_ptr = s_ptr.offset(1);
                if row_start == 255 { break }
                let run_length = *s_ptr as int; s_ptr = s_ptr.offset(2);
                let s_end = s_ptr.offset(run_length);
                let mut d_ptr = pixels.as_mut_ptr()
                                      .offset(row_start * width as int
                                              + i_column);
                while s_ptr < s_end {
                    *d_ptr = *s_ptr as u16;
                    d_ptr = d_ptr.offset(width as int);
                    s_ptr = s_ptr.offset(1);
                }
                s_ptr = s_ptr.offset(1);
            }
        }}
        let pixels = pixels;

        Image { width: width,
                height: height,
                x_offset: x_offset,
                y_offset: y_offset,
                pixels: pixels }
    }

    pub fn blit(&mut self, source: &Image, x_offset: int, y_offset: int,
                overwrite: bool) {
        let y_start = if y_offset < 0 { -y_offset as uint } else { 0 };
        let x_start = if x_offset < 0 { -x_offset as uint } else { 0 };
        let y_end = if self.height as int > source.height as int + y_offset {
            source.height
        } else {
            self.height - y_offset as uint
        };
        let x_end = if self.width as int > source.width as int + x_offset {
            source.width
        } else {
            self.width - x_offset as uint
        };

        if overwrite {
            for source_y in range(y_start, y_end) {
                let self_y = source_y as int + y_offset;
                for source_x in range(x_start, x_end) {
                    let self_x = source_x as int + x_offset;

                    let (self_x, self_y) = (self_x as uint, self_y as uint);
                    let self_index = (self_x + self_y * self.width) as int;
                    let source_index = (source_x + source_y * source.width)
                        as int;

                    unsafe {
                        let source_pixel = *source.pixels.as_ptr()
                                                         .offset(source_index);
                        *self.pixels.as_mut_ptr().offset(self_index) =
                            source_pixel;
                    }
                }
            }
        } else {
            for source_y in range(y_start, y_end) {
                let self_y = source_y as int + y_offset;
                for source_x in range(x_start, x_end) {
                    let self_x = source_x as int + x_offset;

                    let (self_x, self_y) = (self_x as uint, self_y as uint);
                    let self_index = (self_x + self_y * self.width) as int;
                    let source_index = (source_x + source_y * source.width)
                        as int;

                    unsafe {
                        let source_pixel = *source.pixels.as_ptr()
                                                         .offset(source_index);
                        if source_pixel & 0xff00 == 0 {
                            *self.pixels.as_mut_ptr().offset(self_index) =
                                source_pixel;
                        }
                    }
                }
            }
        }
    }

    pub fn get_x_offset(&self) -> int { self.x_offset }
    pub fn get_y_offset(&self) -> int { self.y_offset }

    pub fn get_width(&self) -> uint { self.width }
    pub fn get_height(&self) -> uint { self.height }

    pub fn get_pixels<'a>(&'a self) -> &'a [u16] { self.pixels.as_slice() }
}

<commit_msg>Some cleanup of image blitting & loading<commit_after>use std::vec::Vec;
use std::io::BufReader;
use super::types::*;
use std::ptr::copy_nonoverlapping_memory;

pub struct Image {
    width: uint,
    height: uint,
    x_offset: int,
    y_offset: int,
    pixels: Vec<u16>,
}

macro_rules! io_try(
    ($e:expr) => (try!($e.map_err(|e| String::from_str(e.desc))))
)

impl Image {
    pub fn new(width: uint, height: uint) -> Image{
        Image { width: width,
                height: height,
                x_offset: 0,
                y_offset: 0,
                pixels: Vec::from_elem(width * height, 0xff00) }
    }

    pub fn new_from_header(header: &WadTextureHeader) -> Image {
        Image::new(header.width as uint, header.height as uint)
    }

    pub fn from_buffer(buffer: &[u8]) -> Image {
        let mut reader = BufReader::new(buffer);

        let width = reader.read_le_u16().unwrap() as uint;
        let height = reader.read_le_u16().unwrap() as uint;
        let x_offset = reader.read_le_i16().unwrap() as int;
        let y_offset = reader.read_le_i16().unwrap() as int;

        let mut pixels = Vec::from_elem(width * height, -1);
        // Sorry for the messy/unsafe code, but the array bounds checks in this
        // tight loop make it 6x slower.
        for i_column in range(0, width as int) { unsafe {
            // Each column is defined as a number of vertical `runs' which are
            // defined starting at `offset' in the buffer.
            let offset = reader.read_le_u32().unwrap() as int;
            let mut src_ptr = buffer.as_ptr().offset(offset);
            'this_column: loop {
                // The first byte contains the vertical coordinate of the run's
                // start.
                let row_start = *src_ptr as int; src_ptr = src_ptr.offset(1);

                // Pointer to the beginning of the run in `pixels'.
                let mut dest_ptr = pixels
                    .as_mut_ptr().offset(row_start * width as int + i_column);

                // The special value of 255 means this is the last run in the
                // column, so move on to the next one.
                if row_start == 255 { break 'this_column; }

                // The second byte is the length of this run. Skip an additional
                // byte which is ignored for some reason.
                let run_length = *src_ptr as int; src_ptr = src_ptr.offset(2);

                let src_end = src_ptr.offset(run_length);  // Ptr to end of run.
                while src_ptr < src_end {
                    // Copy one byte converting it into an opaque pixels (high
                    // bits are zero) and advance the pointers.
                    *dest_ptr = *src_ptr as u16;
                    dest_ptr = dest_ptr.offset(width as int);
                    src_ptr = src_ptr.offset(1);
                }
                // And another ignored byte after the run.
                src_ptr = src_ptr.offset(1);
            }
        }}
        let pixels = pixels;

        Image { width: width,
                height: height,
                x_offset: x_offset,
                y_offset: y_offset,
                pixels: pixels }
    }

    #[allow(unsigned_negate)]
    pub fn blit(&mut self, source: &Image, x_offset: int, y_offset: int,
                ignore_transparency: bool) {
        // Figure out the region in source which is not out of bounds when
        // copied into self.
        let y_start = if y_offset < 0 { -y_offset as uint } else { 0 };
        let x_start = if x_offset < 0 { -x_offset as uint } else { 0 };
        let y_end = if self.height as int > source.height as int + y_offset {
            source.height
        } else {
            self.height - y_offset as uint
        };
        let x_end = if self.width as int > source.width as int + x_offset {
            source.width
        } else {
            self.width - x_offset as uint
        };

        if ignore_transparency {
            // If we don't care about transparency we can memcpy row by row.
            let src_pitch = source.width as int;
            let dest_pitch = self.width as int;
            let copy_width = x_end - x_start;
            let copy_height = (y_end - y_start) as int;
            let (x_start, y_start) = (x_start as int, y_start as int);
            unsafe {
                let mut src_ptr = source.pixels.as_ptr().offset(
                    x_start + y_start * src_pitch);
                let mut dest_ptr = self.pixels.as_mut_ptr().offset(
                    x_start + x_offset + (y_start + y_offset) * dest_pitch);

                let src_end = src_ptr.offset(copy_height * src_pitch);
                while src_ptr < src_end {
                    copy_nonoverlapping_memory(dest_ptr, src_ptr, copy_width);
                    src_ptr = src_ptr.offset(src_pitch);
                    dest_ptr = dest_ptr.offset(dest_pitch);
                }
            }
        } else {
            // Only copy pixels whose high bits are not set.
            let dest_ptr = self.pixels.as_mut_ptr();
            let src_ptr = source.pixels.as_ptr();
            for src_y in range(y_start, y_end) {
                let dest_y = (src_y as int + y_offset) as uint;
                for src_x in range(x_start, x_end) {
                    let dest_x = (src_x as int + x_offset) as uint;

                    let (dest_x, dest_y) = (dest_x as uint, dest_y as uint);
                    let dest_index = (dest_x + dest_y * self.width) as int;
                    let src_index = (src_x + src_y * source.width) as int;

                    unsafe {
                        // `Blending' is a simple copy/no copy, but using bit
                        // ops we can avoid branching.
                        let src_pixel = *src_ptr.offset(src_index);
                        let dest_pixel = dest_ptr.offset(dest_index);
                        let blend = (-(src_pixel >> 15)) as u16;
                        *dest_pixel = (src_pixel & !blend) |
                                      (*dest_pixel & blend);
                    }
                }
            }
        }
    }

    pub fn get_x_offset(&self) -> int { self.x_offset }
    pub fn get_y_offset(&self) -> int { self.y_offset }

    pub fn get_width(&self) -> uint { self.width }
    pub fn get_height(&self) -> uint { self.height }

    pub fn get_pixels<'a>(&'a self) -> &'a [u16] { self.pixels.as_slice() }
}

<|endoftext|>


<commit_before>#[macro_use]
extern crate glium;
extern crate rusttype;
extern crate arrayvec;
extern crate unicode_normalization;

use glium::{DisplayBuild, Surface};
use glium::glutin;

use rusttype::{FontCollection, Font, Scale, point, vector, PositionedGlyph};
use rusttype::gpu_cache::{Cache};
use rusttype::Rect;

use std::borrow::Cow;

fn layout_paragraph<'a>(font: &'a Font,
                        scale: Scale,
                        width: u32,
                        text: &str) -> Vec<PositionedGlyph<'a>> {
    use unicode_normalization::UnicodeNormalization;
    let mut result = Vec::new();
    let v_metrics = font.v_metrics(scale);
    let advance_height = v_metrics.ascent - v_metrics.descent + v_metrics.line_gap;
    let mut caret = point(0.0, v_metrics.ascent);
    let mut last_glyph_id = None;
    for c in text.nfc() {
        if c.is_control() {
            match c {
                '\r' => {
                    caret = point(0.0, caret.y + advance_height);
                }
                '\n' => {},
                _ => {}
            }
            continue;
        }
        let base_glyph = if let Some(glyph) = font.glyph(c) {
            glyph
        } else {
            continue;
        };
        if let Some(id) = last_glyph_id.take() {
            caret.x += font.pair_kerning(scale, id, base_glyph.id());
        }
        last_glyph_id = Some(base_glyph.id());
        let mut glyph = base_glyph.scaled(scale).positioned(caret);
        if let Some(bb) = glyph.pixel_bounding_box() {
            if bb.max.x > width as i32 {
                caret = point(0.0, caret.y + advance_height);
                glyph = glyph.into_unpositioned().positioned(caret);
                last_glyph_id = None;
            }
        }
        caret.x += glyph.unpositioned().h_metrics().advance_width;
        result.push(glyph);
    }
    result
}

fn main() {
    let font_data = include_bytes!("Arial Unicode.ttf");
    let font = FontCollection::from_bytes(font_data as &[u8]).into_font().unwrap();

    let display = glutin::WindowBuilder::new()
        .with_vsync()
        .with_dimensions(512, 512)
        .with_title("RustType GPU cache example".into())
        .with_srgb(Some(true))
        .build_glium()
        .unwrap();

    let dpi_factor = display.get_window().unwrap().hidpi_factor();

    let (cache_width, cache_height) = (512 * dpi_factor as u32, 512 * dpi_factor as u32);
    let mut cache = Cache::new(cache_width, cache_height, 0.1, 0.1);

    let program = program!(
        &display,
        140 => {
            vertex: "
                #version 140

                in vec2 position;
                in vec2 tex_coords;
                in vec4 colour;

                out vec2 v_tex_coords;
                out vec4 v_colour;

                void main() {
                    gl_Position = vec4(position, 0.0, 1.0);
                    v_tex_coords = tex_coords;
                    v_colour = colour;
                }
            ",

            fragment: "
                #version 140
                uniform sampler2D tex;
                in vec2 v_tex_coords;
                in vec4 v_colour;
                out vec4 f_colour;

                void main() {
                    f_colour = v_colour * vec4(1.0, 1.0, 1.0, texture(tex, v_tex_coords).r);
                }
            "
        }).unwrap();
    let cache_tex = glium::texture::Texture2d::with_format(
        &display,
        glium::texture::RawImage2d {
            data: Cow::Owned(vec![128u8; cache_width as usize * cache_height as usize]),
            width: cache_width,
            height: cache_height,
            format: glium::texture::ClientFormat::U8
        },
        glium::texture::UncompressedFloatFormat::U8,
        glium::texture::MipmapsOption::NoMipmap).unwrap();
    let mut text: String = "A japanese poem:\r
\r
色は匂へど散りぬるを我が世誰ぞ常ならむ有為の奥山今日越えて浅き夢見じ酔ひもせず\r
\r
Feel free to type out some text, and delete it with Backspace. You can also try resizing this window."
        .into();
    'main: loop {
        let width = display.get_window().unwrap().get_inner_size_pixels().unwrap().0;
        let glyphs = layout_paragraph(&font, Scale::uniform(24.0 * dpi_factor), width, &text);
        for glyph in &glyphs {
            cache.queue_glyph(0, glyph.clone());
        }
        cache.cache_queued(|rect, data| {
            cache_tex.main_level().write(glium::Rect {
                left: rect.min.x,
                bottom: rect.min.y,
                width: rect.width(),
                height: rect.height()
            }, glium::texture::RawImage2d {
                data: Cow::Borrowed(data),
                width: rect.width(),
                height: rect.height(),
                format: glium::texture::ClientFormat::U8
            });
        }).unwrap();

        let uniforms = uniform! {
            tex: cache_tex.sampled().magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest)
        };

        let vertex_buffer = {
            #[derive(Copy, Clone)]
            struct Vertex {
                position: [f32; 2],
                tex_coords: [f32; 2],
                colour: [f32; 4]
            }

            implement_vertex!(Vertex, position, tex_coords, colour);
            let colour = [0.0, 0.0, 0.0, 1.0];
            let (screen_width, screen_height) = {
                let (w, h) = display.get_framebuffer_dimensions();
                (w as f32, h as f32)
            };
            let origin = point(0.0, 0.0);
            let vertices: Vec<Vertex> = glyphs.iter().flat_map(|g| {
                if let Ok(Some((uv_rect, screen_rect))) = cache.rect_for(0, g) {
                    let gl_rect = Rect {
                        min: origin
                            + (vector(screen_rect.min.x as f32 / screen_width - 0.5,
                                      1.0 - screen_rect.min.y as f32 / screen_height - 0.5)) * 2.0,
                        max: origin
                            + (vector(screen_rect.max.x as f32 / screen_width - 0.5,
                                      1.0 - screen_rect.max.y as f32 / screen_height - 0.5)) * 2.0
                    };
                    arrayvec::ArrayVec::<[Vertex; 6]>::from([
                        Vertex {
                            position: [gl_rect.min.x, gl_rect.max.y],
                            tex_coords: [uv_rect.min.x, uv_rect.max.y],
                            colour: colour
                        },
                        Vertex {
                            position: [gl_rect.min.x,  gl_rect.min.y],
                            tex_coords: [uv_rect.min.x, uv_rect.min.y],
                            colour: colour
                        },
                        Vertex {
                            position: [gl_rect.max.x,  gl_rect.min.y],
                            tex_coords: [uv_rect.max.x, uv_rect.min.y],
                            colour: colour
                        },
                        Vertex {
                            position: [gl_rect.max.x,  gl_rect.min.y],
                            tex_coords: [uv_rect.max.x, uv_rect.min.y],
                            colour: colour },
                        Vertex {
                            position: [gl_rect.max.x, gl_rect.max.y],
                            tex_coords: [uv_rect.max.x, uv_rect.max.y],
                            colour: colour
                        },
                        Vertex {
                            position: [gl_rect.min.x, gl_rect.max.y],
                            tex_coords: [uv_rect.min.x, uv_rect.max.y],
                            colour: colour
                        }])
                } else {
                    arrayvec::ArrayVec::new()
                }
            }).collect();

            glium::VertexBuffer::new(
                &display,
                &vertices).unwrap()
        };

        let mut target = display.draw();
        target.clear_color(1.0, 1.0, 1.0, 0.0);
        target.draw(&vertex_buffer,
                    glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList),
                    &program, &uniforms,
                    &glium::DrawParameters {
                        blend: glium::Blend::alpha_blending(),
                        ..Default::default()
                    }).unwrap();

        target.finish().unwrap();

        for event in display.poll_events() {
            match event {
                glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) |
                glutin::Event::Closed => break 'main,
                glutin::Event::ReceivedCharacter(c) => if c != '\u{7f}' {
                    text.push(c);
                },
                glutin::Event::KeyboardInput(
                    glutin::ElementState::Pressed,
                    _,
                    Some(glutin::VirtualKeyCode::Back)) => {
                    text.pop();
                },
                _ => {}
            }
        }
    }
}
<commit_msg>Removed srgb from example due to glutin bug. Fixes #10.<commit_after>#[macro_use]
extern crate glium;
extern crate rusttype;
extern crate arrayvec;
extern crate unicode_normalization;

use glium::{DisplayBuild, Surface};
use glium::glutin;

use rusttype::{FontCollection, Font, Scale, point, vector, PositionedGlyph};
use rusttype::gpu_cache::{Cache};
use rusttype::Rect;

use std::borrow::Cow;

fn layout_paragraph<'a>(font: &'a Font,
                        scale: Scale,
                        width: u32,
                        text: &str) -> Vec<PositionedGlyph<'a>> {
    use unicode_normalization::UnicodeNormalization;
    let mut result = Vec::new();
    let v_metrics = font.v_metrics(scale);
    let advance_height = v_metrics.ascent - v_metrics.descent + v_metrics.line_gap;
    let mut caret = point(0.0, v_metrics.ascent);
    let mut last_glyph_id = None;
    for c in text.nfc() {
        if c.is_control() {
            match c {
                '\r' => {
                    caret = point(0.0, caret.y + advance_height);
                }
                '\n' => {},
                _ => {}
            }
            continue;
        }
        let base_glyph = if let Some(glyph) = font.glyph(c) {
            glyph
        } else {
            continue;
        };
        if let Some(id) = last_glyph_id.take() {
            caret.x += font.pair_kerning(scale, id, base_glyph.id());
        }
        last_glyph_id = Some(base_glyph.id());
        let mut glyph = base_glyph.scaled(scale).positioned(caret);
        if let Some(bb) = glyph.pixel_bounding_box() {
            if bb.max.x > width as i32 {
                caret = point(0.0, caret.y + advance_height);
                glyph = glyph.into_unpositioned().positioned(caret);
                last_glyph_id = None;
            }
        }
        caret.x += glyph.unpositioned().h_metrics().advance_width;
        result.push(glyph);
    }
    result
}

fn main() {
    let font_data = include_bytes!("Arial Unicode.ttf");
    let font = FontCollection::from_bytes(font_data as &[u8]).into_font().unwrap();

    let display = glutin::WindowBuilder::new()
        .with_vsync()
        .with_dimensions(512, 512)
        .with_title("RustType GPU cache example".into())
        .build_glium()
        .unwrap();

    let dpi_factor = display.get_window().unwrap().hidpi_factor();

    let (cache_width, cache_height) = (512 * dpi_factor as u32, 512 * dpi_factor as u32);
    let mut cache = Cache::new(cache_width, cache_height, 0.1, 0.1);

    let program = program!(
        &display,
        140 => {
            vertex: "
                #version 140

                in vec2 position;
                in vec2 tex_coords;
                in vec4 colour;

                out vec2 v_tex_coords;
                out vec4 v_colour;

                void main() {
                    gl_Position = vec4(position, 0.0, 1.0);
                    v_tex_coords = tex_coords;
                    v_colour = colour;
                }
            ",

            fragment: "
                #version 140
                uniform sampler2D tex;
                in vec2 v_tex_coords;
                in vec4 v_colour;
                out vec4 f_colour;

                void main() {
                    f_colour = v_colour * vec4(1.0, 1.0, 1.0, texture(tex, v_tex_coords).r);
                }
            "
        }).unwrap();
    let cache_tex = glium::texture::Texture2d::with_format(
        &display,
        glium::texture::RawImage2d {
            data: Cow::Owned(vec![128u8; cache_width as usize * cache_height as usize]),
            width: cache_width,
            height: cache_height,
            format: glium::texture::ClientFormat::U8
        },
        glium::texture::UncompressedFloatFormat::U8,
        glium::texture::MipmapsOption::NoMipmap).unwrap();
    let mut text: String = "A japanese poem:\r
\r
色は匂へど散りぬるを我が世誰ぞ常ならむ有為の奥山今日越えて浅き夢見じ酔ひもせず\r
\r
Feel free to type out some text, and delete it with Backspace. You can also try resizing this window."
        .into();
    'main: loop {
        let width = display.get_window().unwrap().get_inner_size_pixels().unwrap().0;
        let glyphs = layout_paragraph(&font, Scale::uniform(24.0 * dpi_factor), width, &text);
        for glyph in &glyphs {
            cache.queue_glyph(0, glyph.clone());
        }
        cache.cache_queued(|rect, data| {
            cache_tex.main_level().write(glium::Rect {
                left: rect.min.x,
                bottom: rect.min.y,
                width: rect.width(),
                height: rect.height()
            }, glium::texture::RawImage2d {
                data: Cow::Borrowed(data),
                width: rect.width(),
                height: rect.height(),
                format: glium::texture::ClientFormat::U8
            });
        }).unwrap();

        let uniforms = uniform! {
            tex: cache_tex.sampled().magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest)
        };

        let vertex_buffer = {
            #[derive(Copy, Clone)]
            struct Vertex {
                position: [f32; 2],
                tex_coords: [f32; 2],
                colour: [f32; 4]
            }

            implement_vertex!(Vertex, position, tex_coords, colour);
            let colour = [0.0, 0.0, 0.0, 1.0];
            let (screen_width, screen_height) = {
                let (w, h) = display.get_framebuffer_dimensions();
                (w as f32, h as f32)
            };
            let origin = point(0.0, 0.0);
            let vertices: Vec<Vertex> = glyphs.iter().flat_map(|g| {
                if let Ok(Some((uv_rect, screen_rect))) = cache.rect_for(0, g) {
                    let gl_rect = Rect {
                        min: origin
                            + (vector(screen_rect.min.x as f32 / screen_width - 0.5,
                                      1.0 - screen_rect.min.y as f32 / screen_height - 0.5)) * 2.0,
                        max: origin
                            + (vector(screen_rect.max.x as f32 / screen_width - 0.5,
                                      1.0 - screen_rect.max.y as f32 / screen_height - 0.5)) * 2.0
                    };
                    arrayvec::ArrayVec::<[Vertex; 6]>::from([
                        Vertex {
                            position: [gl_rect.min.x, gl_rect.max.y],
                            tex_coords: [uv_rect.min.x, uv_rect.max.y],
                            colour: colour
                        },
                        Vertex {
                            position: [gl_rect.min.x,  gl_rect.min.y],
                            tex_coords: [uv_rect.min.x, uv_rect.min.y],
                            colour: colour
                        },
                        Vertex {
                            position: [gl_rect.max.x,  gl_rect.min.y],
                            tex_coords: [uv_rect.max.x, uv_rect.min.y],
                            colour: colour
                        },
                        Vertex {
                            position: [gl_rect.max.x,  gl_rect.min.y],
                            tex_coords: [uv_rect.max.x, uv_rect.min.y],
                            colour: colour },
                        Vertex {
                            position: [gl_rect.max.x, gl_rect.max.y],
                            tex_coords: [uv_rect.max.x, uv_rect.max.y],
                            colour: colour
                        },
                        Vertex {
                            position: [gl_rect.min.x, gl_rect.max.y],
                            tex_coords: [uv_rect.min.x, uv_rect.max.y],
                            colour: colour
                        }])
                } else {
                    arrayvec::ArrayVec::new()
                }
            }).collect();

            glium::VertexBuffer::new(
                &display,
                &vertices).unwrap()
        };

        let mut target = display.draw();
        target.clear_color(1.0, 1.0, 1.0, 0.0);
        target.draw(&vertex_buffer,
                    glium::index::NoIndices(glium::index::PrimitiveType::TrianglesList),
                    &program, &uniforms,
                    &glium::DrawParameters {
                        blend: glium::Blend::alpha_blending(),
                        ..Default::default()
                    }).unwrap();

        target.finish().unwrap();

        for event in display.poll_events() {
            match event {
                glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) |
                glutin::Event::Closed => break 'main,
                glutin::Event::ReceivedCharacter(c) => if c != '\u{7f}' {
                    text.push(c);
                },
                glutin::Event::KeyboardInput(
                    glutin::ElementState::Pressed,
                    _,
                    Some(glutin::VirtualKeyCode::Back)) => {
                    text.pop();
                },
                _ => {}
            }
        }
    }
}
<|endoftext|>


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

use ursa::cl::Proof as CryptoProof;

use super::schema::SchemaId;
use super::credential_definition::CredentialDefinitionId;
use super::revocation_registry_definition::RevocationRegistryId;
use indy_api_types::validation::Validatable;

#[derive(Debug, Serialize, Deserialize)]
pub struct Proof {
    pub proof: CryptoProof,
    pub requested_proof: RequestedProof,
    pub identifiers: Vec<Identifier>
}

#[derive(Debug, Serialize, Deserialize)]
pub struct RequestedProof {
    pub revealed_attrs: HashMap<String, RevealedAttributeInfo>,
    #[serde(skip_serializing_if="HashMap::is_empty")]
    #[serde(default = "HashMap::new")]
    pub revealed_attr_groups: HashMap<String, RevealedAttributeGroupInfo>,
    pub self_attested_attrs: HashMap<String, String>,
    pub unrevealed_attrs: HashMap<String, SubProofReferent>,
    pub predicates: HashMap<String, SubProofReferent>
}

impl Default for RequestedProof {
    fn default() -> Self {
        RequestedProof {
            revealed_attrs: HashMap::new(),
            revealed_attr_groups: HashMap::new(),
            self_attested_attrs: HashMap::new(),
            unrevealed_attrs: HashMap::new(),
            predicates: HashMap::new(),
        }
    }
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct SubProofReferent {
    pub sub_proof_index: u32,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct RevealedAttributeInfo {
    pub sub_proof_index: u32,
    pub raw: String,
    pub encoded: String
}

#[derive(Debug, Deserialize, Serialize)]
pub struct RevealedAttributeGroupInfo {
    pub sub_proof_index: u32,
    pub values: HashMap<String /* attribute name */, AttributeValue>,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct AttributeValue {
    pub raw: String,
    pub encoded: String
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, Hash)]
pub struct Identifier {
    pub schema_id: SchemaId,
    pub cred_def_id: CredentialDefinitionId,
    pub rev_reg_id: Option<RevocationRegistryId>,
    pub timestamp: Option<u64>
}

impl Validatable for Proof {}

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

    #[test]
    fn deserialize_requested_proof_with_empty_revealed_attr_groups() {
        let mut req_proof_old: RequestedProof = Default::default();
        req_proof_old.revealed_attrs.insert("attr1".to_string(), RevealedAttributeInfo {
            sub_proof_index: 0,
            raw: "123".to_string(),
            encoded: "123".to_string()
        });
        let json = json!(req_proof_old).to_string();
        println!("{}", json);

        let req_proof: RequestedProof = serde_json::from_str(&json).unwrap();
        assert!(req_proof.revealed_attr_groups.is_empty())
    }
}
<commit_msg>IS-1381 -- making default simpler<commit_after>use std::collections::HashMap;

use ursa::cl::Proof as CryptoProof;

use super::schema::SchemaId;
use super::credential_definition::CredentialDefinitionId;
use super::revocation_registry_definition::RevocationRegistryId;
use indy_api_types::validation::Validatable;

#[derive(Debug, Serialize, Deserialize)]
pub struct Proof {
    pub proof: CryptoProof,
    pub requested_proof: RequestedProof,
    pub identifiers: Vec<Identifier>
}

#[derive(Debug, Serialize, Deserialize)]
pub struct RequestedProof {
    pub revealed_attrs: HashMap<String, RevealedAttributeInfo>,
    #[serde(skip_serializing_if="HashMap::is_empty")]
    #[serde(default)]
    pub revealed_attr_groups: HashMap<String, RevealedAttributeGroupInfo>,
    pub self_attested_attrs: HashMap<String, String>,
    pub unrevealed_attrs: HashMap<String, SubProofReferent>,
    pub predicates: HashMap<String, SubProofReferent>
}

impl Default for RequestedProof {
    fn default() -> Self {
        RequestedProof {
            revealed_attrs: HashMap::new(),
            revealed_attr_groups: HashMap::new(),
            self_attested_attrs: HashMap::new(),
            unrevealed_attrs: HashMap::new(),
            predicates: HashMap::new(),
        }
    }
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct SubProofReferent {
    pub sub_proof_index: u32,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct RevealedAttributeInfo {
    pub sub_proof_index: u32,
    pub raw: String,
    pub encoded: String
}

#[derive(Debug, Deserialize, Serialize)]
pub struct RevealedAttributeGroupInfo {
    pub sub_proof_index: u32,
    pub values: HashMap<String /* attribute name */, AttributeValue>,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct AttributeValue {
    pub raw: String,
    pub encoded: String
}

#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, Hash)]
pub struct Identifier {
    pub schema_id: SchemaId,
    pub cred_def_id: CredentialDefinitionId,
    pub rev_reg_id: Option<RevocationRegistryId>,
    pub timestamp: Option<u64>
}

impl Validatable for Proof {}

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

    #[test]
    fn deserialize_requested_proof_with_empty_revealed_attr_groups() {
        let mut req_proof_old: RequestedProof = Default::default();
        req_proof_old.revealed_attrs.insert("attr1".to_string(), RevealedAttributeInfo {
            sub_proof_index: 0,
            raw: "123".to_string(),
            encoded: "123".to_string()
        });
        let json = json!(req_proof_old).to_string();
        println!("{}", json);

        let req_proof: RequestedProof = serde_json::from_str(&json).unwrap();
        assert!(req_proof.revealed_attr_groups.is_empty())
    }
}
<|endoftext|>


<commit_before>use netbuf::Buf;
use {Transport, StreamSocket};

/// Transport is thing that provides buffered I/O for stream sockets
impl<'a, S: StreamSocket> Transport<'a, S> {
    /// Get the reference to the underlying stream
    ///
    /// It's here so you can inspect socket state or tune it. For example you
    /// might want to set TCP_CORK option or find out peer or local address.
    ///
    /// Reading from and writing to a socket directly may lead to unexpected
    /// behavior. Use `input()` and `output()` buffers instead.
    pub fn socket<'x>(&'x mut self) -> &'x mut S {
        self.sock
    }
    /// Get a reference to the input buffer
    ///
    /// It's expected that you only read and `consume()` bytes from buffer
    /// but never write.
    pub fn input<'x>(&'x mut self) -> &'x mut Buf {
        self.inbuf
    }
    /// Get a reference to the output buffer
    ///
    /// It's expected that you only inspect and write to the output buffer
    /// but never `consume()`
    pub fn output<'x>(&'x mut self) -> &'x mut Buf {
        self.outbuf
    }
}
<commit_msg>Add `buffers()` method to `Transport`<commit_after>use netbuf::Buf;
use {Transport, StreamSocket};

/// Transport is thing that provides buffered I/O for stream sockets
impl<'a, S: StreamSocket> Transport<'a, S> {
    /// Get the reference to the underlying stream
    ///
    /// It's here so you can inspect socket state or tune it. For example you
    /// might want to set TCP_CORK option or find out peer or local address.
    ///
    /// Reading from and writing to a socket directly may lead to unexpected
    /// behavior. Use `input()` and `output()` buffers instead.
    pub fn socket<'x>(&'x mut self) -> &'x mut S {
        self.sock
    }
    /// Get a reference to the input buffer
    ///
    /// It's expected that you only read and `consume()` bytes from buffer
    /// but never write.
    pub fn input<'x>(&'x mut self) -> &'x mut Buf {
        self.inbuf
    }
    /// Get a reference to the output buffer
    ///
    /// It's expected that you only inspect and write to the output buffer
    /// but never `consume()`
    pub fn output<'x>(&'x mut self) -> &'x mut Buf {
        self.outbuf
    }
    /// Get a references to both buffers (input, output)
    ///
    /// It's useful when you want to pass both things somewhere along the
    /// chain of calls. See `input()` and `output()` methods for more comments
    /// on buffer usage
    pub fn buffers<'x>(&'x mut self) -> (&'x mut Buf, &'x mut Buf) {
        (self.inbuf, self.outbuf)
    }
}
<|endoftext|>


<commit_before>#![feature(test)]
extern crate test;
extern crate lzf;
use test::Bencher;

#[bench]
fn bench_basic_zfs_compression_decompression(b: &mut Bencher) {
    b.iter(|| {
        let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

        let compressed = lzf::compress(lorem.as_bytes()).unwrap();
        let _ = lzf::decompress(&compressed, lorem.len());
    })
}
<commit_msg>Test decompression speed in comparison<commit_after>#![feature(test)]
extern crate test;
extern crate lzf;
use test::Bencher;

#[bench]
fn bench_basic_zfs_compression_decompression(b: &mut Bencher) {
    b.iter(|| {
        let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

        let compressed = lzf::compress(lorem.as_bytes()).unwrap();
        let _ = lzf::decompress(&compressed, lorem.len());
    })
}

#[bench]
fn bench_basic_zfs_decompression(b: &mut Bencher) {
    b.iter(|| {
        let lorem = [31, 76, 111, 114, 101, 109, 32, 105, 112, 115, 117, 109, 32, 100, 111, 108, 111, 114, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32, 99, 111, 110, 115, 4, 101, 116, 101, 116, 117, 32, 20, 1, 97, 100, 32, 35, 31, 99, 105, 110, 103, 32, 101, 108, 105, 116, 114, 44, 32, 115, 101, 100, 32, 100, 105, 97, 109, 32, 110, 111, 110, 117, 109, 121, 32, 101, 105, 114, 109, 6, 111, 100, 32, 116, 101, 109, 112, 32, 68, 14, 105, 110, 118, 105, 100, 117, 110, 116, 32, 117, 116, 32, 108, 97, 98, 32, 100, 2, 32, 101, 116, 128, 96, 13, 101, 32, 109, 97, 103, 110, 97, 32, 97, 108, 105, 113, 117, 121, 32, 64, 2, 101, 114, 97, 32, 108, 224, 0, 79, 20, 118, 111, 108, 117, 112, 116, 117, 97, 46, 32, 65, 116, 32, 118, 101, 114, 111, 32, 101, 111, 115, 64, 61, 4, 97, 99, 99, 117, 115, 64, 47, 9, 116, 32, 106, 117, 115, 116, 111, 32, 100, 117, 32, 3, 64, 179, 0, 101, 96, 31, 10, 101, 97, 32, 114, 101, 98, 117, 109, 46, 32, 83, 32, 180, 1, 32, 99, 32, 167, 16, 97, 32, 107, 97, 115, 100, 32, 103, 117, 98, 101, 114, 103, 114, 101, 110, 44, 32, 173, 32, 105, 7, 97, 32, 116, 97, 107, 105, 109, 97, 32, 31, 5, 115, 97, 110, 99, 116, 117, 32, 63, 3, 115, 116, 32, 76, 32, 73, 225, 13, 11, 0, 46, 224, 18, 27, 225, 118, 39, 1, 97, 46];

        let _ = lzf::decompress(&lorem, 451);
    })
}

#[bench]
fn bench_basic_zfs_native_decompression(b: &mut Bencher) {
    b.iter(|| {
        let lorem = [31, 76, 111, 114, 101, 109, 32, 105, 112, 115, 117, 109, 32, 100, 111, 108, 111, 114, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32, 99, 111, 110, 115, 4, 101, 116, 101, 116, 117, 32, 20, 1, 97, 100, 32, 35, 31, 99, 105, 110, 103, 32, 101, 108, 105, 116, 114, 44, 32, 115, 101, 100, 32, 100, 105, 97, 109, 32, 110, 111, 110, 117, 109, 121, 32, 101, 105, 114, 109, 6, 111, 100, 32, 116, 101, 109, 112, 32, 68, 14, 105, 110, 118, 105, 100, 117, 110, 116, 32, 117, 116, 32, 108, 97, 98, 32, 100, 2, 32, 101, 116, 128, 96, 13, 101, 32, 109, 97, 103, 110, 97, 32, 97, 108, 105, 113, 117, 121, 32, 64, 2, 101, 114, 97, 32, 108, 224, 0, 79, 20, 118, 111, 108, 117, 112, 116, 117, 97, 46, 32, 65, 116, 32, 118, 101, 114, 111, 32, 101, 111, 115, 64, 61, 4, 97, 99, 99, 117, 115, 64, 47, 9, 116, 32, 106, 117, 115, 116, 111, 32, 100, 117, 32, 3, 64, 179, 0, 101, 96, 31, 10, 101, 97, 32, 114, 101, 98, 117, 109, 46, 32, 83, 32, 180, 1, 32, 99, 32, 167, 16, 97, 32, 107, 97, 115, 100, 32, 103, 117, 98, 101, 114, 103, 114, 101, 110, 44, 32, 173, 32, 105, 7, 97, 32, 116, 97, 107, 105, 109, 97, 32, 31, 5, 115, 97, 110, 99, 116, 117, 32, 63, 3, 115, 116, 32, 76, 32, 73, 225, 13, 11, 0, 46, 224, 18, 27, 225, 118, 39, 1, 97, 46];

        let _ = lzf::native::decompress(&lorem, 451);
    })
}
<|endoftext|>


<commit_before>#![feature(test)]
extern crate test;
extern crate lzf;
use test::Bencher;

#[bench]
fn bench_basic_zfs_compression_decompression(b: &mut Bencher) {
    b.iter(|| {
        let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

        let compressed = lzf::compress(lorem.as_bytes()).unwrap();
        let _ = lzf::decompress(&compressed, lorem.len());
    })
}

#[bench]
fn bench_basic_zfs_decompression(b: &mut Bencher) {
    b.iter(|| {
        let lorem = [31, 76, 111, 114, 101, 109, 32, 105, 112, 115, 117, 109, 32, 100, 111, 108, 111, 114, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32, 99, 111, 110, 115, 4, 101, 116, 101, 116, 117, 32, 20, 1, 97, 100, 32, 35, 31, 99, 105, 110, 103, 32, 101, 108, 105, 116, 114, 44, 32, 115, 101, 100, 32, 100, 105, 97, 109, 32, 110, 111, 110, 117, 109, 121, 32, 101, 105, 114, 109, 6, 111, 100, 32, 116, 101, 109, 112, 32, 68, 14, 105, 110, 118, 105, 100, 117, 110, 116, 32, 117, 116, 32, 108, 97, 98, 32, 100, 2, 32, 101, 116, 128, 96, 13, 101, 32, 109, 97, 103, 110, 97, 32, 97, 108, 105, 113, 117, 121, 32, 64, 2, 101, 114, 97, 32, 108, 224, 0, 79, 20, 118, 111, 108, 117, 112, 116, 117, 97, 46, 32, 65, 116, 32, 118, 101, 114, 111, 32, 101, 111, 115, 64, 61, 4, 97, 99, 99, 117, 115, 64, 47, 9, 116, 32, 106, 117, 115, 116, 111, 32, 100, 117, 32, 3, 64, 179, 0, 101, 96, 31, 10, 101, 97, 32, 114, 101, 98, 117, 109, 46, 32, 83, 32, 180, 1, 32, 99, 32, 167, 16, 97, 32, 107, 97, 115, 100, 32, 103, 117, 98, 101, 114, 103, 114, 101, 110, 44, 32, 173, 32, 105, 7, 97, 32, 116, 97, 107, 105, 109, 97, 32, 31, 5, 115, 97, 110, 99, 116, 117, 32, 63, 3, 115, 116, 32, 76, 32, 73, 225, 13, 11, 0, 46, 224, 18, 27, 225, 118, 39, 1, 97, 46];

        let _ = lzf::decompress(&lorem, 451);
    })
}

#[bench]
fn bench_basic_zfs_native_decompression(b: &mut Bencher) {
    b.iter(|| {
        let lorem = [31, 76, 111, 114, 101, 109, 32, 105, 112, 115, 117, 109, 32, 100, 111, 108, 111, 114, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32, 99, 111, 110, 115, 4, 101, 116, 101, 116, 117, 32, 20, 1, 97, 100, 32, 35, 31, 99, 105, 110, 103, 32, 101, 108, 105, 116, 114, 44, 32, 115, 101, 100, 32, 100, 105, 97, 109, 32, 110, 111, 110, 117, 109, 121, 32, 101, 105, 114, 109, 6, 111, 100, 32, 116, 101, 109, 112, 32, 68, 14, 105, 110, 118, 105, 100, 117, 110, 116, 32, 117, 116, 32, 108, 97, 98, 32, 100, 2, 32, 101, 116, 128, 96, 13, 101, 32, 109, 97, 103, 110, 97, 32, 97, 108, 105, 113, 117, 121, 32, 64, 2, 101, 114, 97, 32, 108, 224, 0, 79, 20, 118, 111, 108, 117, 112, 116, 117, 97, 46, 32, 65, 116, 32, 118, 101, 114, 111, 32, 101, 111, 115, 64, 61, 4, 97, 99, 99, 117, 115, 64, 47, 9, 116, 32, 106, 117, 115, 116, 111, 32, 100, 117, 32, 3, 64, 179, 0, 101, 96, 31, 10, 101, 97, 32, 114, 101, 98, 117, 109, 46, 32, 83, 32, 180, 1, 32, 99, 32, 167, 16, 97, 32, 107, 97, 115, 100, 32, 103, 117, 98, 101, 114, 103, 114, 101, 110, 44, 32, 173, 32, 105, 7, 97, 32, 116, 97, 107, 105, 109, 97, 32, 31, 5, 115, 97, 110, 99, 116, 117, 32, 63, 3, 115, 116, 32, 76, 32, 73, 225, 13, 11, 0, 46, 224, 18, 27, 225, 118, 39, 1, 97, 46];

        let _ = lzf::native::decompress(&lorem, 451);
    })
}
<commit_msg>zfs, you'd wish…<commit_after>#![feature(test)]
extern crate test;
extern crate lzf;
use test::Bencher;

#[bench]
fn bench_basic_lzf_compression_decompression(b: &mut Bencher) {
    b.iter(|| {
        let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.";

        let compressed = lzf::compress(lorem.as_bytes()).unwrap();
        let _ = lzf::decompress(&compressed, lorem.len());
    })
}

#[bench]
fn bench_basic_lzf_decompression(b: &mut Bencher) {
    b.iter(|| {
        let lorem = [31, 76, 111, 114, 101, 109, 32, 105, 112, 115, 117, 109, 32, 100, 111, 108, 111, 114, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32, 99, 111, 110, 115, 4, 101, 116, 101, 116, 117, 32, 20, 1, 97, 100, 32, 35, 31, 99, 105, 110, 103, 32, 101, 108, 105, 116, 114, 44, 32, 115, 101, 100, 32, 100, 105, 97, 109, 32, 110, 111, 110, 117, 109, 121, 32, 101, 105, 114, 109, 6, 111, 100, 32, 116, 101, 109, 112, 32, 68, 14, 105, 110, 118, 105, 100, 117, 110, 116, 32, 117, 116, 32, 108, 97, 98, 32, 100, 2, 32, 101, 116, 128, 96, 13, 101, 32, 109, 97, 103, 110, 97, 32, 97, 108, 105, 113, 117, 121, 32, 64, 2, 101, 114, 97, 32, 108, 224, 0, 79, 20, 118, 111, 108, 117, 112, 116, 117, 97, 46, 32, 65, 116, 32, 118, 101, 114, 111, 32, 101, 111, 115, 64, 61, 4, 97, 99, 99, 117, 115, 64, 47, 9, 116, 32, 106, 117, 115, 116, 111, 32, 100, 117, 32, 3, 64, 179, 0, 101, 96, 31, 10, 101, 97, 32, 114, 101, 98, 117, 109, 46, 32, 83, 32, 180, 1, 32, 99, 32, 167, 16, 97, 32, 107, 97, 115, 100, 32, 103, 117, 98, 101, 114, 103, 114, 101, 110, 44, 32, 173, 32, 105, 7, 97, 32, 116, 97, 107, 105, 109, 97, 32, 31, 5, 115, 97, 110, 99, 116, 117, 32, 63, 3, 115, 116, 32, 76, 32, 73, 225, 13, 11, 0, 46, 224, 18, 27, 225, 118, 39, 1, 97, 46];

        let _ = lzf::decompress(&lorem, 451);
    })
}

#[bench]
fn bench_basic_lzf_native_decompression(b: &mut Bencher) {
    b.iter(|| {
        let lorem = [31, 76, 111, 114, 101, 109, 32, 105, 112, 115, 117, 109, 32, 100, 111, 108, 111, 114, 32, 115, 105, 116, 32, 97, 109, 101, 116, 44, 32, 99, 111, 110, 115, 4, 101, 116, 101, 116, 117, 32, 20, 1, 97, 100, 32, 35, 31, 99, 105, 110, 103, 32, 101, 108, 105, 116, 114, 44, 32, 115, 101, 100, 32, 100, 105, 97, 109, 32, 110, 111, 110, 117, 109, 121, 32, 101, 105, 114, 109, 6, 111, 100, 32, 116, 101, 109, 112, 32, 68, 14, 105, 110, 118, 105, 100, 117, 110, 116, 32, 117, 116, 32, 108, 97, 98, 32, 100, 2, 32, 101, 116, 128, 96, 13, 101, 32, 109, 97, 103, 110, 97, 32, 97, 108, 105, 113, 117, 121, 32, 64, 2, 101, 114, 97, 32, 108, 224, 0, 79, 20, 118, 111, 108, 117, 112, 116, 117, 97, 46, 32, 65, 116, 32, 118, 101, 114, 111, 32, 101, 111, 115, 64, 61, 4, 97, 99, 99, 117, 115, 64, 47, 9, 116, 32, 106, 117, 115, 116, 111, 32, 100, 117, 32, 3, 64, 179, 0, 101, 96, 31, 10, 101, 97, 32, 114, 101, 98, 117, 109, 46, 32, 83, 32, 180, 1, 32, 99, 32, 167, 16, 97, 32, 107, 97, 115, 100, 32, 103, 117, 98, 101, 114, 103, 114, 101, 110, 44, 32, 173, 32, 105, 7, 97, 32, 116, 97, 107, 105, 109, 97, 32, 31, 5, 115, 97, 110, 99, 116, 117, 32, 63, 3, 115, 116, 32, 76, 32, 73, 225, 13, 11, 0, 46, 224, 18, 27, 225, 118, 39, 1, 97, 46];

        let _ = lzf::native::decompress(&lorem, 451);
    })
}
<|endoftext|>


<commit_before>//! Checks for useless borrowed references.
//!
//! This lint is **warn** by default

use rustc::lint::*;
use rustc::hir::{MutImmutable, Pat, PatKind, BindingAnnotation};
use rustc::ty;
use utils::{span_lint, in_macro};

/// **What it does:** Checks for useless borrowed references.
///
/// **Why is this bad?** It is completely useless and make the code look more
/// complex than it
/// actually is.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
///     let mut v = Vec::<String>::new();
///     let _ = v.iter_mut().filter(|&ref a| a.is_empty());
/// ```
/// This clojure takes a reference on something that has been matched as a
/// reference and
/// de-referenced.
/// As such, it could just be |a| a.is_empty()
declare_lint! {
    pub NEEDLESS_BORROWED_REFERENCE,
    Warn,
    "taking a needless borrowed reference"
}

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

impl LintPass for NeedlessBorrowedRef {
    fn get_lints(&self) -> LintArray {
        lint_array!(NEEDLESS_BORROWED_REFERENCE)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrowedRef {
    fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat) {
        if in_macro(pat.span) {
            // OK, simple enough, lints doesn't check in macro.
            return;
        }

        if_let_chain! {[
            // Pat is a pattern whose node
            // is a binding which "involves" a immutable reference...
            let PatKind::Binding(BindingAnnotation::Ref, ..) = pat.node,
            // Pattern's type is a reference. Get the type and mutability of referenced value (tam: TypeAndMut).
            let ty::TyRef(_, ref tam) = cx.tables.pat_ty(pat).sty,
            // This is an immutable reference.
            tam.mutbl == MutImmutable,
        ], {
            span_lint(cx, NEEDLESS_BORROWED_REFERENCE, pat.span, "this pattern takes a reference on something that is being de-referenced")
        }}
    }
}
<commit_msg>Improve needless_borrowed_ref lint comments.<commit_after>//! Checks for useless borrowed references.
//!
//! This lint is **warn** by default

use rustc::lint::*;
use rustc::hir::{MutImmutable, Pat, PatKind, BindingAnnotation};
use rustc::ty;
use utils::{span_lint, in_macro};

/// **What it does:** Checks for useless borrowed references.
///
/// **Why is this bad?** It is completely useless and make the code look more
/// complex than it
/// actually is.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
///     let mut v = Vec::<String>::new();
///     let _ = v.iter_mut().filter(|&ref a| a.is_empty());
/// ```
/// This clojure takes a reference on something that has been matched as a
/// reference and
/// de-referenced.
/// As such, it could just be |a| a.is_empty()
declare_lint! {
    pub NEEDLESS_BORROWED_REFERENCE,
    Warn,
    "taking a needless borrowed reference"
}

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

impl LintPass for NeedlessBorrowedRef {
    fn get_lints(&self) -> LintArray {
        lint_array!(NEEDLESS_BORROWED_REFERENCE)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessBorrowedRef {
    fn check_pat(&mut self, cx: &LateContext<'a, 'tcx>, pat: &'tcx Pat) {
        if in_macro(pat.span) {
            // OK, simple enough, lints doesn't check in macro.
            return;
        }

        if_let_chain! {[
            // Pat is a pattern whose node
            // is a binding which "involves" an immutable reference...
            let PatKind::Binding(BindingAnnotation::Ref, ..) = pat.node,
            // Pattern's type is a reference. Get the type and mutability of referenced value (tam: TypeAndMut).
            let ty::TyRef(_, ref tam) = cx.tables.pat_ty(pat).sty,
            // Only lint immutable refs, because `&mut ref T` may be useful.
            tam.mutbl == MutImmutable,
        ], {
            span_lint(cx, NEEDLESS_BORROWED_REFERENCE, pat.span, "this pattern takes a reference on something that is being de-referenced")
        }}
    }
}
<|endoftext|>