<commit_before>//! Utility module for lexer implementations,
//! providing types to help manage states and tokens.

use std::str::Chars;
use super::token::Token;
use super::token::Category;

/// A recursive function type used by lexers to manage their state.
/// Based on Rob Pike's "Lexical Scanning in Go" talk, these functions are
/// invoked in a call/return loop (letting the current function determine
/// the next) until a `None` value is returned, after which lexing is complete.
///
/// See the `lexers` module for examples.
pub struct StateFunction(pub fn(&mut Tokenizer) -> Option<StateFunction>);

/// The Tokenizer type is used to produce and store tokens for lexers.
pub struct Tokenizer<'a> {
    data: Chars<'a>,
    current_token: String,
    tokens: Vec<Token>,
    pub states: Vec<StateFunction>,
}

/// Initializes a new tokenizer with the given data.
///
/// # Examples
///
/// ```
/// let tokenizer = luthor::tokenizer::new("luthor");
/// ```
pub fn new(data: &str) -> Tokenizer {
    Tokenizer{
      data: data.chars(),
      current_token: String::new(),
      tokens: vec![],
      states: vec![]
    }
}

impl<'a> Tokenizer<'a> {
    /// Returns a copy of the tokens processed to date, in addition to any
    /// in-progress or remaining data appended as a text-category token.
    /// As a result, the returned tokens always produce the original dataset
    /// when their lexemes are concatenated.
    ///
    /// # Examples
    ///
    /// ```
    /// use luthor::token::{Category, Token};
    ///
    /// // Set up a new tokenizer.
    /// let mut tokenizer = luthor::tokenizer::new("luthor");
    /// tokenizer.tokenize_next(2, Category::Keyword);
    ///
    /// assert_eq!(
    ///     tokenizer.tokens(),
    ///     vec![
    ///         Token{ lexeme: "lu".to_string(), category: Category::Keyword },
    ///         Token{ lexeme: "thor".to_string(), category: Category::Text }
    ///     ]
    /// );
    ///
    /// ```
    pub fn tokens(&self) -> Vec<Token> {
        let mut tokens = self.tokens.clone();

        // Duplicate the tokenizer's character iterator so that we can
        // advance it to check for equality without affecting the original.
        let data_iter = self.data.clone();

        // Append any remaining data to the in-progress token.
        let mut remaining_data = self.current_token.clone();
        for c in data_iter {
            remaining_data.push(c);
        }

        // If there was any remaining or in-progress data, add it as a text token.
        if !remaining_data.is_empty() {
            tokens.push(Token{ lexeme: remaining_data, category: Category::Text});
        }

        tokens
    }

    /// Moves to the next character in the data.
    /// Does nothing if there is no more data to process.
    ///
    /// # Examples
    ///
    /// ```
    /// // Set up a new tokenizer.
    /// let mut tokenizer = luthor::tokenizer::new("luthor");
    ///
    /// // Ensure that we're at the first character.
    /// assert_eq!(tokenizer.current_char().unwrap(), 'l');
    ///
    /// // Consume the first character.
    /// tokenizer.advance();
    ///
    /// // Ensure that we're at the next character.
    /// assert_eq!(tokenizer.current_char().unwrap(), 'u');
    /// ```
    pub fn advance(&mut self) {
        match self.data.next() {
            Some(c) => self.current_token.push(c),
            None => ()
        }
    }

    /// Returns the character at the current position,
    /// unless all of the data has been processed.
    ///
    /// # Examples
    ///
    /// ```
    /// // Set up a new tokenizer.
    /// let mut tokenizer = luthor::tokenizer::new("l");
    ///
    /// // Ensure that the current character is correct.
    /// assert_eq!(tokenizer.current_char().unwrap(), 'l');
    ///
    /// // Consume the last bit of data.
    /// tokenizer.advance();
    ///
    /// // Ensure that there is no current character.
    /// assert_eq!(tokenizer.current_char(), None);
    /// ```
    pub fn current_char(&self) -> Option<char> {
        match self.data.clone().peekable().peek() {
            Some(c) => Some(c.clone()),
            None => None
        }
    }

    /// Whether or not the remaining data starts with the specified prefix.
    ///
    /// # Examples
    ///
    /// ```
    /// // Set up a new tokenizer.
    /// let tokenizer = luthor::tokenizer::new("lex");
    ///
    /// assert!(tokenizer.has_prefix("le"));
    /// ```
    pub fn has_prefix(&self, prefix: &str) -> bool {
        // Duplicate the tokenizer's character iterator so that we can
        // advance it to check for equality without affecting the original.
        let mut data_iter = self.data.clone();

        // Check that the subject is a prefix, character by character.
        // This is much faster than building a string of equal length from
        // self.data and deferring to a straight string comparison using ==.
        prefix.chars().all(|c| {
            match data_iter.next() {
                Some(d) => c == d,
                None => false
            }
        })
    }

    /// Whether or not the remaining data starts with the specified lexeme.
    /// Ensures that the specified lexeme is not just a prefix by checking that
    /// the data that follows it is a newline, space, comma, or nothing at all.
    ///
    /// # Examples
    ///
    /// ```
    /// use luthor::token::Category;
    ///
    /// // Set up a new tokenizer.
    /// let mut tokenizer = luthor::tokenizer::new("lex\nluthor lib,rary");
    ///
    /// // Prefixes don't count.
    /// assert!(!tokenizer.starts_with_lexeme("le"));
    ///
    /// // Newlines delineate lexemes.
    /// assert!(tokenizer.starts_with_lexeme("lex"));
    ///
    /// // Consume 4 characters, advancing to the next lexeme.
    /// tokenizer.tokenize_next(4, Category::Text);
    ///
    /// // Spaces delineate lexemes.
    /// assert!(tokenizer.starts_with_lexeme("luthor"));
    ///
    /// // Consume 7 characters, advancing to the next lexeme.
    /// tokenizer.tokenize_next(7, Category::Text);
    ///
    /// // Commas delineate lexemes.
    /// assert!(tokenizer.starts_with_lexeme("lib"));
    ///
    /// // Consume 4 characters, advancing to the next lexeme.
    /// tokenizer.tokenize_next(4, Category::Text);
    ///
    /// // End of string delineates lexemes.
    /// assert!(tokenizer.starts_with_lexeme("rary"));
    /// ```
    pub fn starts_with_lexeme(&self, lexeme: &str) -> bool {
        // Duplicate the tokenizer's character iterator so that we can
        // advance it to check for equality without affecting the original.
        let data_iter = self.data.clone();

        self.has_prefix(lexeme) && match data_iter.skip(lexeme.len()).next() {
            Some(' ') | Some('\n') | Some(',') => true,
            None => true,
            _ => false
        }
    }

    /// Creates and stores a token with the given category containing any
    /// data processed using `advance` since the last call to this method.
    ///
    /// # Examples
    ///
    /// ```
    /// use luthor::token::Category;
    ///
    /// // Set up a new tokenizer.
    /// let mut tokenizer = luthor::tokenizer::new("luthor");
    ///
    /// // Consume two characters and then tokenize them.
    /// tokenizer.advance();
    /// tokenizer.advance();
    /// tokenizer.tokenize(Category::Text);
    ///
    /// // Ensure that we have a correctly-categorized token.
    /// assert_eq!(tokenizer.tokens()[0].lexeme, "lu");
    /// ```
    pub fn tokenize(&mut self, category: Category) {
        if !self.current_token.is_empty() {
            let token = Token{
                lexeme: self.current_token.clone(),
                category: category,
            };
            self.tokens.push(token);
            self.current_token = String::new();
        }
    }

    /// Creates and stores a token with the given category and the
    /// next `amount` characters of the data. Before doing this, it
    /// tokenizes any previously processed characters with the generic
    /// `Category::Text` category.
    ///
    /// # Examples
    ///
    /// ```
    /// use luthor::token::Category;
    /// use luthor::token::Token;
    ///
    /// // Set up a new tokenizer.
    /// let mut tokenizer = luthor::tokenizer::new("luthor");
    ///
    /// // Consume one character, and then tokenize the next 5.
    /// tokenizer.advance();
    /// tokenizer.tokenize_next(5, Category::Keyword);
    ///
    /// // Ensure that we have two properly-categorized tokens.
    /// assert_eq!(
    ///     tokenizer.tokens()[0],
    ///     Token{ lexeme: "l".to_string(), category: Category::Text }
    /// );
    /// assert_eq!(
    ///     tokenizer.tokens()[1],
    ///     Token{ lexeme: "uthor".to_string(), category: Category::Keyword }
    /// );
    /// ```
    pub fn tokenize_next(&mut self, amount: usize, category: Category) {
        // If there's any data that has yet
        // to be tokenized, take care of that.
        self.tokenize(Category::Text);

        // Mark the next series of characters.
        for _ in 0..amount { self.advance(); }

        // Tokenize the marked characters.
        self.tokenize(category);
    }

    /// Consumes consecutive whitespace characters as a single token.
    ///
    /// # Examples
    ///
    /// ```
    /// use luthor::token::Category;
    /// use luthor::token::Token;
    ///
    /// let mut tokenizer = luthor::tokenizer::new("  \nluthor");
    /// tokenizer.consume_whitespace();
    ///
    /// assert_eq!(
    ///     tokenizer.tokens()[0],
    ///     Token{ lexeme: "  \n".to_string(), category: Category::Whitespace }
    /// );
    /// ```
    pub fn consume_whitespace(&mut self) {
        let mut found_whitespace = false;
        loop {
            match self.current_char() {
                Some(' ') | Some('\n') => {
                    if !found_whitespace {
                        self.tokenize(Category::Text);
                        found_whitespace = true;
                    }

                    self.advance();
                },
                _ => {
                    if found_whitespace {
                        self.tokenize(Category::Whitespace);
                    }
                    return
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::new;
    use super::super::token::Token;
    use super::super::token::Category;

    #[test]
    fn current_char_returns_the_char_at_head() {
        let data = "él";
        let tokenizer = new(data);

        assert_eq!(tokenizer.current_char().unwrap(), 'é');
    }

    #[test]
    fn current_char_returns_none_if_at_the_end() {
        let data = "él";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.advance();

        assert_eq!(tokenizer.current_char(), None);
    }

    #[test]
    fn tokenize_creates_the_correct_token() {
        let data = "élégant";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.advance();
        tokenizer.tokenize(Category::Text);

        let token = tokenizer.tokens.pop().unwrap();
        let expected_token = Token{ lexeme: "él".to_string(), category: Category::Text};
        assert_eq!(token, expected_token);
    }

    #[test]
    fn tokenize_does_nothing_if_range_is_empty() {
        let data = "élégant";
        let mut tokenizer = new(data);
        tokenizer.tokenize(Category::Text);

        assert_eq!(tokenizer.tokens.len(), 0);
    }

    #[test]
    fn tokenize_next_tokenizes_previous_data_as_text() {
        let data = "élégant";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.advance();
        tokenizer.tokenize_next(1, Category::Keyword);

        let token = tokenizer.tokens.remove(0);
        let expected_token = Token{ lexeme: "él".to_string(), category: Category::Text};
        assert_eq!(token, expected_token);
    }

    #[test]
    fn tokenize_next_tokenizes_next_x_chars() {
        let data = "élégant";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.advance();
        tokenizer.tokenize_next(5, Category::Keyword);

        let token = tokenizer.tokens.pop().unwrap();
        let expected_token = Token{ lexeme: "égant".to_string(), category: Category::Keyword};
        assert_eq!(token, expected_token);
    }

    #[test]
    fn tokenize_next_takes_at_most_what_is_left() {
        let data = "élégant";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.advance();
        tokenizer.tokenize_next(15, Category::Keyword);

        let token = tokenizer.tokens.pop().unwrap();
        let expected_token = Token{ lexeme: "égant".to_string(), category: Category::Keyword};
        assert_eq!(token, expected_token);
    }

    #[test]
    fn consume_whitespace_handles_preexisting_noncategorized_chars() {
        let data = "e  ";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.consume_whitespace();

        assert_eq!(
            tokenizer.tokens()[0],
            Token{ lexeme: "e".to_string(), category: Category::Text }
        );
        assert_eq!(
            tokenizer.tokens()[1],
            Token{ lexeme: "  ".to_string(), category: Category::Whitespace }
        );
    }

    #[test]
    fn tokens_returns_unprocessed_data_as_text_token() {
        let tokenizer = new("luthor");

        assert_eq!(
            tokenizer.tokens()[0],
            Token{ lexeme: "luthor".to_string(), category: Category::Text }
        );
    }

    #[test]
    fn tokens_joins_advanced_data_with_unprocessed_data_as_text_token() {
        let mut tokenizer = new("luthor");
        tokenizer.advance();

        assert_eq!(
            tokenizer.tokens()[0],
            Token{ lexeme: "luthor".to_string(), category: Category::Text }
        );
    }
}
<commit_msg>Add next_non_whitespace_character method to tokenizer type.<commit_after>//! Utility module for lexer implementations,
//! providing types to help manage states and tokens.

use std::str::Chars;
use super::token::Token;
use super::token::Category;

/// A recursive function type used by lexers to manage their state.
/// Based on Rob Pike's "Lexical Scanning in Go" talk, these functions are
/// invoked in a call/return loop (letting the current function determine
/// the next) until a `None` value is returned, after which lexing is complete.
///
/// See the `lexers` module for examples.
pub struct StateFunction(pub fn(&mut Tokenizer) -> Option<StateFunction>);

/// The Tokenizer type is used to produce and store tokens for lexers.
pub struct Tokenizer<'a> {
    data: Chars<'a>,
    current_token: String,
    tokens: Vec<Token>,
    pub states: Vec<StateFunction>,
}

/// Initializes a new tokenizer with the given data.
///
/// # Examples
///
/// ```
/// let tokenizer = luthor::tokenizer::new("luthor");
/// ```
pub fn new(data: &str) -> Tokenizer {
    Tokenizer{
      data: data.chars(),
      current_token: String::new(),
      tokens: vec![],
      states: vec![]
    }
}

impl<'a> Tokenizer<'a> {
    /// Returns a copy of the tokens processed to date, in addition to any
    /// in-progress or remaining data appended as a text-category token.
    /// As a result, the returned tokens always produce the original dataset
    /// when their lexemes are concatenated.
    ///
    /// # Examples
    ///
    /// ```
    /// use luthor::token::{Category, Token};
    ///
    /// // Set up a new tokenizer.
    /// let mut tokenizer = luthor::tokenizer::new("luthor");
    /// tokenizer.tokenize_next(2, Category::Keyword);
    ///
    /// assert_eq!(
    ///     tokenizer.tokens(),
    ///     vec![
    ///         Token{ lexeme: "lu".to_string(), category: Category::Keyword },
    ///         Token{ lexeme: "thor".to_string(), category: Category::Text }
    ///     ]
    /// );
    ///
    /// ```
    pub fn tokens(&self) -> Vec<Token> {
        let mut tokens = self.tokens.clone();

        // Duplicate the tokenizer's character iterator so that we can
        // advance it to check for equality without affecting the original.
        let data_iter = self.data.clone();

        // Append any remaining data to the in-progress token.
        let mut remaining_data = self.current_token.clone();
        for c in data_iter {
            remaining_data.push(c);
        }

        // If there was any remaining or in-progress data, add it as a text token.
        if !remaining_data.is_empty() {
            tokens.push(Token{ lexeme: remaining_data, category: Category::Text});
        }

        tokens
    }

    /// Moves to the next character in the data.
    /// Does nothing if there is no more data to process.
    ///
    /// # Examples
    ///
    /// ```
    /// // Set up a new tokenizer.
    /// let mut tokenizer = luthor::tokenizer::new("luthor");
    ///
    /// // Ensure that we're at the first character.
    /// assert_eq!(tokenizer.current_char().unwrap(), 'l');
    ///
    /// // Consume the first character.
    /// tokenizer.advance();
    ///
    /// // Ensure that we're at the next character.
    /// assert_eq!(tokenizer.current_char().unwrap(), 'u');
    /// ```
    pub fn advance(&mut self) {
        match self.data.next() {
            Some(c) => self.current_token.push(c),
            None => ()
        }
    }

    /// Returns the character at the current position,
    /// unless all of the data has been processed.
    ///
    /// # Examples
    ///
    /// ```
    /// // Set up a new tokenizer.
    /// let mut tokenizer = luthor::tokenizer::new("l");
    ///
    /// // Ensure that the current character is correct.
    /// assert_eq!(tokenizer.current_char().unwrap(), 'l');
    ///
    /// // Consume the last bit of data.
    /// tokenizer.advance();
    ///
    /// // Ensure that there is no current character.
    /// assert_eq!(tokenizer.current_char(), None);
    /// ```
    pub fn current_char(&self) -> Option<char> {
        match self.data.clone().peekable().peek() {
            Some(c) => Some(c.clone()),
            None => None
        }
    }

    /// Returns the next non-whitespace character, without advancing the cursor.
    ///
    /// # Examples
    ///
    /// ```
    /// // Set up a new tokenizer.
    /// let mut tokenizer = luthor::tokenizer::new("  b");
    ///
    /// // Ask for the next non-whitespace character.
    /// assert_eq!(tokenizer.next_non_whitespace_char().unwrap(), 'b');
    ///
    /// // Advance past the "b" character and ask again.
    /// for _ in 0..3 { tokenizer.advance(); }
    /// assert!(tokenizer.next_non_whitespace_char().is_none());
    ///
    /// ```
    pub fn next_non_whitespace_char(&self) -> Option<char> {
        // Duplicate the tokenizer's character iterator so that we can
        // advance it to check for equality without affecting the original.
        let mut data_iter = self.data.clone();

        data_iter.find(|&c| c != ' ' && c != '\n')
    }

    /// Whether or not the remaining data starts with the specified prefix.
    ///
    /// # Examples
    ///
    /// ```
    /// // Set up a new tokenizer.
    /// let tokenizer = luthor::tokenizer::new("lex");
    ///
    /// assert!(tokenizer.has_prefix("le"));
    /// ```
    pub fn has_prefix(&self, prefix: &str) -> bool {
        // Duplicate the tokenizer's character iterator so that we can
        // advance it to check for equality without affecting the original.
        let mut data_iter = self.data.clone();

        // Check that the subject is a prefix, character by character.
        // This is much faster than building a string of equal length from
        // self.data and deferring to a straight string comparison using ==.
        prefix.chars().all(|c| {
            match data_iter.next() {
                Some(d) => c == d,
                None => false
            }
        })
    }

    /// Whether or not the remaining data starts with the specified lexeme.
    /// Ensures that the specified lexeme is not just a prefix by checking that
    /// the data that follows it is a newline, space, comma, or nothing at all.
    ///
    /// # Examples
    ///
    /// ```
    /// use luthor::token::Category;
    ///
    /// // Set up a new tokenizer.
    /// let mut tokenizer = luthor::tokenizer::new("lex\nluthor lib,rary");
    ///
    /// // Prefixes don't count.
    /// assert!(!tokenizer.starts_with_lexeme("le"));
    ///
    /// // Newlines delineate lexemes.
    /// assert!(tokenizer.starts_with_lexeme("lex"));
    ///
    /// // Consume 4 characters, advancing to the next lexeme.
    /// tokenizer.tokenize_next(4, Category::Text);
    ///
    /// // Spaces delineate lexemes.
    /// assert!(tokenizer.starts_with_lexeme("luthor"));
    ///
    /// // Consume 7 characters, advancing to the next lexeme.
    /// tokenizer.tokenize_next(7, Category::Text);
    ///
    /// // Commas delineate lexemes.
    /// assert!(tokenizer.starts_with_lexeme("lib"));
    ///
    /// // Consume 4 characters, advancing to the next lexeme.
    /// tokenizer.tokenize_next(4, Category::Text);
    ///
    /// // End of string delineates lexemes.
    /// assert!(tokenizer.starts_with_lexeme("rary"));
    /// ```
    pub fn starts_with_lexeme(&self, lexeme: &str) -> bool {
        // Duplicate the tokenizer's character iterator so that we can
        // advance it to check for equality without affecting the original.
        let data_iter = self.data.clone();

        self.has_prefix(lexeme) && match data_iter.skip(lexeme.len()).next() {
            Some(' ') | Some('\n') | Some(',') => true,
            None => true,
            _ => false
        }
    }

    /// Creates and stores a token with the given category containing any
    /// data processed using `advance` since the last call to this method.
    ///
    /// # Examples
    ///
    /// ```
    /// use luthor::token::Category;
    ///
    /// // Set up a new tokenizer.
    /// let mut tokenizer = luthor::tokenizer::new("luthor");
    ///
    /// // Consume two characters and then tokenize them.
    /// tokenizer.advance();
    /// tokenizer.advance();
    /// tokenizer.tokenize(Category::Text);
    ///
    /// // Ensure that we have a correctly-categorized token.
    /// assert_eq!(tokenizer.tokens()[0].lexeme, "lu");
    /// ```
    pub fn tokenize(&mut self, category: Category) {
        if !self.current_token.is_empty() {
            let token = Token{
                lexeme: self.current_token.clone(),
                category: category,
            };
            self.tokens.push(token);
            self.current_token = String::new();
        }
    }

    /// Creates and stores a token with the given category and the
    /// next `amount` characters of the data. Before doing this, it
    /// tokenizes any previously processed characters with the generic
    /// `Category::Text` category.
    ///
    /// # Examples
    ///
    /// ```
    /// use luthor::token::Category;
    /// use luthor::token::Token;
    ///
    /// // Set up a new tokenizer.
    /// let mut tokenizer = luthor::tokenizer::new("luthor");
    ///
    /// // Consume one character, and then tokenize the next 5.
    /// tokenizer.advance();
    /// tokenizer.tokenize_next(5, Category::Keyword);
    ///
    /// // Ensure that we have two properly-categorized tokens.
    /// assert_eq!(
    ///     tokenizer.tokens()[0],
    ///     Token{ lexeme: "l".to_string(), category: Category::Text }
    /// );
    /// assert_eq!(
    ///     tokenizer.tokens()[1],
    ///     Token{ lexeme: "uthor".to_string(), category: Category::Keyword }
    /// );
    /// ```
    pub fn tokenize_next(&mut self, amount: usize, category: Category) {
        // If there's any data that has yet
        // to be tokenized, take care of that.
        self.tokenize(Category::Text);

        // Mark the next series of characters.
        for _ in 0..amount { self.advance(); }

        // Tokenize the marked characters.
        self.tokenize(category);
    }

    /// Consumes consecutive whitespace characters as a single token.
    ///
    /// # Examples
    ///
    /// ```
    /// use luthor::token::Category;
    /// use luthor::token::Token;
    ///
    /// let mut tokenizer = luthor::tokenizer::new("  \nluthor");
    /// tokenizer.consume_whitespace();
    ///
    /// assert_eq!(
    ///     tokenizer.tokens()[0],
    ///     Token{ lexeme: "  \n".to_string(), category: Category::Whitespace }
    /// );
    /// ```
    pub fn consume_whitespace(&mut self) {
        let mut found_whitespace = false;
        loop {
            match self.current_char() {
                Some(' ') | Some('\n') => {
                    if !found_whitespace {
                        self.tokenize(Category::Text);
                        found_whitespace = true;
                    }

                    self.advance();
                },
                _ => {
                    if found_whitespace {
                        self.tokenize(Category::Whitespace);
                    }
                    return
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::new;
    use super::super::token::Token;
    use super::super::token::Category;

    #[test]
    fn current_char_returns_the_char_at_head() {
        let data = "él";
        let tokenizer = new(data);

        assert_eq!(tokenizer.current_char().unwrap(), 'é');
    }

    #[test]
    fn current_char_returns_none_if_at_the_end() {
        let data = "él";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.advance();

        assert_eq!(tokenizer.current_char(), None);
    }

    #[test]
    fn tokenize_creates_the_correct_token() {
        let data = "élégant";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.advance();
        tokenizer.tokenize(Category::Text);

        let token = tokenizer.tokens.pop().unwrap();
        let expected_token = Token{ lexeme: "él".to_string(), category: Category::Text};
        assert_eq!(token, expected_token);
    }

    #[test]
    fn tokenize_does_nothing_if_range_is_empty() {
        let data = "élégant";
        let mut tokenizer = new(data);
        tokenizer.tokenize(Category::Text);

        assert_eq!(tokenizer.tokens.len(), 0);
    }

    #[test]
    fn tokenize_next_tokenizes_previous_data_as_text() {
        let data = "élégant";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.advance();
        tokenizer.tokenize_next(1, Category::Keyword);

        let token = tokenizer.tokens.remove(0);
        let expected_token = Token{ lexeme: "él".to_string(), category: Category::Text};
        assert_eq!(token, expected_token);
    }

    #[test]
    fn tokenize_next_tokenizes_next_x_chars() {
        let data = "élégant";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.advance();
        tokenizer.tokenize_next(5, Category::Keyword);

        let token = tokenizer.tokens.pop().unwrap();
        let expected_token = Token{ lexeme: "égant".to_string(), category: Category::Keyword};
        assert_eq!(token, expected_token);
    }

    #[test]
    fn tokenize_next_takes_at_most_what_is_left() {
        let data = "élégant";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.advance();
        tokenizer.tokenize_next(15, Category::Keyword);

        let token = tokenizer.tokens.pop().unwrap();
        let expected_token = Token{ lexeme: "égant".to_string(), category: Category::Keyword};
        assert_eq!(token, expected_token);
    }

    #[test]
    fn consume_whitespace_handles_preexisting_noncategorized_chars() {
        let data = "e  ";
        let mut tokenizer = new(data);
        tokenizer.advance();
        tokenizer.consume_whitespace();

        assert_eq!(
            tokenizer.tokens()[0],
            Token{ lexeme: "e".to_string(), category: Category::Text }
        );
        assert_eq!(
            tokenizer.tokens()[1],
            Token{ lexeme: "  ".to_string(), category: Category::Whitespace }
        );
    }

    #[test]
    fn tokens_returns_unprocessed_data_as_text_token() {
        let tokenizer = new("luthor");

        assert_eq!(
            tokenizer.tokens()[0],
            Token{ lexeme: "luthor".to_string(), category: Category::Text }
        );
    }

    #[test]
    fn tokens_joins_advanced_data_with_unprocessed_data_as_text_token() {
        let mut tokenizer = new("luthor");
        tokenizer.advance();

        assert_eq!(
            tokenizer.tokens()[0],
            Token{ lexeme: "luthor".to_string(), category: Category::Text }
        );
    }
}
<|endoftext|>


<commit_before>use super::Endec;
use std::marker::PhantomData;
use std::io;
use std::io::prelude::*;
use num::{NumCast, ToPrimitive};
use std::iter::FromIterator;

#[derive(PartialEq, Debug)]
pub struct Arr<X, Y>(PhantomData<X>, PhantomData<Y>);

//impl<X: Endec, Y: Endec> Endec for Arr<X, Y> where X::T: NumCast {
    //type T = Vec<Y::T>;

    //fn encode(value: &Vec<Y::T>, dst: &mut Write) -> io::Result<usize> {
        //let mut arrlen = try!(<X::T as NumCast>::from(value.len()).ok_or(()));
        //let mut len = try!(<X as Endec>::encode(&arrlen, dst));
        //for elem in value {
            //len += try!(<Y as Endec>::encode(elem, dst));
        //}
        //Ok(len)
    //}

    //fn decode(src: &mut Read) -> io::Result<Vec<Y::T>> {
        //let len = try!(try!(<X as Endec>::decode(src)).to_usize().ok_or(()));
        //Ok(Vec::from_iter((0..len).map(|_| <Y as Endec>::decode(src).unwrap())))
    //}
//}

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

    //#[test]
    //fn test_decode_string_array() {
        //let buf = vec![0x00, 0x01, 0x00, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f];
        //let arr = <Arr<u16, String> as Endec>::proto_decode(&mut &buf[..]).unwrap();

        //assert_eq!(1, arr.len());
        //assert_eq!("hello".to_string(), arr[0]);
    //}

    //#[test]
    //fn test_decode_u16_array() {
        //let buf = vec![0x00, 0x02, 0x00, 0x01, 0x00, 0x02];
        //let arr = <Arr<u16, u16> as Endec>::proto_decode(&mut &buf[..]).unwrap();

        //assert_eq!(2, arr.len());
        //assert_eq!(vec![1,2], arr);
    //}

    //#[test]
    //fn test_encode_string_array() {
        //let expected = vec![0x00, 0x01, 0x00, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f];
        //let mut vec: Vec<u8> = Vec::new();

        //<Arr<u16, String> as Endec>::encode(&vec!["hello".to_string()], &mut vec);

        //assert_eq!(9, <Arr<u16, String> as Endec>::proto_len(&vec!["hello".to_string()]));
        //assert_eq!(expected, vec);
    //}

    //#[test]
    //fn test_encode_u16_array() {
        //let expected = vec![0x00, 0x02, 0x00, 0x01, 0x00, 0x02];
        //let mut vec = Vec::new();

        //<Arr<u16,u16> as Endec>::encode(&vec![1,2], &mut vec);

        //assert_eq!(6, <Arr<u16,u16> as Endec>::proto_len(&vec![1,2]));
        //assert_eq!(expected, vec);
    //}
//}
<commit_msg>uncomment and fix arr type<commit_after>use std::io;
use std::io::prelude::*;
use super::Endec;
use std::iter::FromIterator;
use std::marker::PhantomData;
use num::{NumCast, ToPrimitive};

#[derive(PartialEq, Debug)]
pub struct Arr<X, Y>(PhantomData<X>, PhantomData<Y>);

impl<X: Endec, Y: Endec> Endec for Arr<X, Y> where X::T: NumCast {
    type T = Vec<Y::T>;

    fn encode(value: &Vec<Y::T>, dst: &mut Write) -> io::Result<usize> {
        let arrlen = <X::T as NumCast>::from(value.len()).ok_or(()).unwrap();
        let mut len = try!(<X as Endec>::encode(&arrlen, dst));
        for elem in value {
            len += try!(<Y as Endec>::encode(elem, dst));
        }
        Ok(len)
    }

    fn decode(src: &mut Read) -> io::Result<Vec<Y::T>> {
        let len = try!(<X as Endec>::decode(src)).to_usize().ok_or(()).unwrap();
        Ok(Vec::from_iter((0..len).map(|_| <Y as Endec>::decode(src).unwrap())))
    }
}

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

    #[test]
    fn test_decode_string_array() {
        let buf = vec![0x00, 0x01, 0x00, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f];
        let arr = <Arr<u16, String> as Endec>::decode(&mut &buf[..]).unwrap();

        //assert_eq!(1, arr.len());
        assert_eq!("hello".to_string(), arr[0]);
    }

    #[test]
    fn test_decode_u16_array() {
        let buf = vec![0x00, 0x02, 0x00, 0x01, 0x00, 0x02];
        let arr = <Arr<u16, u16> as Endec>::decode(&mut &buf[..]).unwrap();

        //assert_eq!(2, arr.len());
        assert_eq!(vec![1,2], arr);
    }

    #[test]
    fn test_encode_string_array() {
        let expected = vec![0x00, 0x01, 0x00, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f];
        let mut vec: Vec<u8> = Vec::new();

        <Arr<u16, String> as Endec>::encode(&vec!["hello".to_string()], &mut vec);

        //assert_eq!(9, <Arr<u16, String> as Endec>::len(&vec!["hello".to_string()]));
        assert_eq!(expected, vec);
    }

    #[test]
    fn test_encode_u16_array() {
        let expected = vec![0x00, 0x02, 0x00, 0x01, 0x00, 0x02];
        let mut vec = Vec::new();

        <Arr<u16,u16> as Endec>::encode(&vec![1,2], &mut vec);

        //assert_eq!(6, <Arr<u16,u16> as Endec>::len(&vec![1,2]));
        assert_eq!(expected, vec);
    }
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/merge-similar-items/
pub fn merge_similar_items(items1: Vec<Vec<i32>>, items2: Vec<Vec<i32>>) -> Vec<Vec<i32>> {
    todo!()
}

fn main() {
    println!(
        "{}",
        merge_similar_items(
            vec![vec![1, 1], vec![4, 5], vec![3, 8]],
            vec![vec![3, 1], vec![1, 5]]
        )
    ); // [[1,6],[3,9],[4,5]]
    println!(
        "{}",
        merge_similar_items(
            vec![vec![1, 1], vec![3, 2], vec![2, 3]],
            vec![vec![2, 1], vec![3, 2], vec![1, 3]]
        )
    ); // [[1,4],[2,4],[3,4]]
    println!(
        "{}",
        merge_similar_items(
            vec![vec![1, 3], vec![2, 2]],
            vec![vec![7, 1], vec![2, 2], vec![1, 4]]
        )
    ); // [[1,7],[2,4],[7,1]]
}
<commit_msg>Solve problem 2363<commit_after>use std::collections::HashMap;

// https://leetcode.com/problems/merge-similar-items/
pub fn merge_similar_items(items1: Vec<Vec<i32>>, items2: Vec<Vec<i32>>) -> Vec<Vec<i32>> {
    let mut map: HashMap<i32, i32> = HashMap::new();
    for item1 in items1.into_iter() {
        map.insert(item1[0], item1[1]);
    }
    for item2 in items2.into_iter() {
        match map.get(&item2[0]) {
            Some(weight) => {
                map.insert(item2[0], *weight + item2[1]);
            }
            None => {
                map.insert(item2[0], item2[1]);
            }
        }
    }
    let mut answer: Vec<Vec<i32>> = map.into_iter().map(|a| vec![a.0, a.1]).collect();
    answer.sort();
    answer
}

fn main() {
    println!(
        "{:?}",
        merge_similar_items(
            vec![vec![1, 1], vec![4, 5], vec![3, 8]],
            vec![vec![3, 1], vec![1, 5]]
        )
    ); // [[1,6],[3,9],[4,5]]
    println!(
        "{:?}",
        merge_similar_items(
            vec![vec![1, 1], vec![3, 2], vec![2, 3]],
            vec![vec![2, 1], vec![3, 2], vec![1, 3]]
        )
    ); // [[1,4],[2,4],[3,4]]
    println!(
        "{:?}",
        merge_similar_items(
            vec![vec![1, 3], vec![2, 2]],
            vec![vec![7, 1], vec![2, 2], vec![1, 4]]
        )
    ); // [[1,7],[2,4],[7,1]]
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/count-days-spent-together/
pub fn count_days_together(
    arrive_alice: String,
    leave_alice: String,
    arrive_bob: String,
    leave_bob: String,
) -> i32 {
    todo!()
}

fn main() {
    println!(
        "{}",
        count_days_together(
            "08-15".to_string(),
            "08-18".to_string(),
            "08-16".to_string(),
            "08-19".to_string()
        )
    ); // 3
    println!(
        "{}",
        count_days_together(
            "10-01".to_string(),
            "10-31".to_string(),
            "11-01".to_string(),
            "12-31".to_string()
        )
    ); // 0
}
<commit_msg>Solve problem 2409<commit_after>extern crate core;

// https://leetcode.com/problems/count-days-spent-together/
pub fn count_days_together(
    arrive_alice: String,
    leave_alice: String,
    arrive_bob: String,
    leave_bob: String,
) -> i32 {
    const NUM_DAYS: [i32; 12] = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

    fn to_days(date: String) -> i32 {
        let v: Vec<&str> = date.split("-").collect();
        let month: i32 = v[0].parse().unwrap();
        let day: i32 = v[1].parse().unwrap();
        let mut days = day;
        for i in 0..month - 1 {
            days += NUM_DAYS[i as usize];
        }
        days
    }
    let mut answer = 0;
    let arrive_alice_days = to_days(arrive_alice);
    let leave_alice_days = to_days(leave_alice);
    let arrive_bob_days = to_days(arrive_bob);
    let leave_bob_days = to_days(leave_bob);
    if (arrive_alice_days <= arrive_bob_days && arrive_bob_days <= leave_alice_days)
        || (arrive_bob_days <= arrive_alice_days && arrive_alice_days <= leave_bob_days)
    {
        answer += leave_alice_days.min(leave_bob_days) - arrive_alice_days.max(arrive_bob_days) + 1;
    }
    answer
}

fn main() {
    println!(
        "{}",
        count_days_together(
            "08-15".to_string(),
            "08-18".to_string(),
            "08-16".to_string(),
            "08-19".to_string()
        )
    ); // 3
    println!(
        "{}",
        count_days_together(
            "08-15".to_string(),
            "08-18".to_string(),
            "08-18".to_string(),
            "08-19".to_string()
        )
    ); // 1
    println!(
        "{}",
        count_days_together(
            "08-15".to_string(),
            "11-18".to_string(),
            "07-19".to_string(),
            "12-19".to_string()
        )
    ); // 96
    println!(
        "{}",
        count_days_together(
            "10-01".to_string(),
            "10-31".to_string(),
            "11-01".to_string(),
            "12-31".to_string()
        )
    ); // 0
}
<|endoftext|>


<commit_before>use conduit::Request;
use krate::Crate;
use util::{CargoResult, internal, ChainError};
use util::{LimitErrorReader, HashingReader, read_le_u32};
use s3;
use semver;
use app::{App, RequestApp};
use std::sync::Arc;
use std::fs::{self, File};
use std::env;
use std::io;

#[derive(Clone, Debug)]
pub enum Uploader {
    /// For production usage, uploads and redirects to s3.
    /// For test usage with a proxy.
    S3 {
        bucket: s3::Bucket,
        proxy: Option<String>,
    },

    /// For development usage only: "uploads" crate files to `dist` and serves them
    /// from there as well to enable local publishing and download
    Local,

    /// For one-off scripts where creating a Config is needed, but uploading is not.
    NoOp,
}

impl Uploader {
    pub fn proxy(&self) -> Option<&str> {
        match *self {
            Uploader::S3 { ref proxy, .. } => proxy.as_ref().map(String::as_str),
            Uploader::Local | Uploader::NoOp => None,
        }
    }

    /// Returns the URL of an uploaded crate's version archive.
    ///
    /// The function doesn't check for the existence of the file.
    /// It returns `None` if the current `Uploader` is `NoOp`.
    pub fn crate_location(&self, crate_name: &str, version: &str) -> Option<String> {
        match *self {
            Uploader::S3 { ref bucket, .. } => {
                Some(format!(
                    "https://{}/{}",
                    bucket.host(),
                    Uploader::crate_path(crate_name, version)
                ))
            }
            Uploader::Local => {
                Some(format!(
                    "/local_uploads/{}",
                    Uploader::crate_path(crate_name, version)
                ))
            }
            Uploader::NoOp => None,
        }
    }

    /// Returns the URL of an uploaded crate's version readme.
    ///
    /// The function doesn't check for the existence of the file.
    /// It returns `None` if the current `Uploader` is `NoOp`.
    pub fn readme_location(&self, crate_name: &str, version: &str) -> Option<String> {
        match *self {
            Uploader::S3 { ref bucket, .. } => {
                Some(format!(
                    "https://{}/{}",
                    bucket.host(),
                    Uploader::readme_path(crate_name, version)
                ))
            }
            Uploader::Local => {
                Some(format!(
                    "/local_uploads/{}",
                    Uploader::readme_path(crate_name, version)
                ))
            }
            Uploader::NoOp => None,
        }
    }

    /// Returns the interna path of an uploaded crate's version archive.
    fn crate_path(name: &str, version: &str) -> String {
        // No slash in front so we can use join
        format!("crates/{}/{}-{}.crate", name, name, version)
    }

    /// Returns the interna path of an uploaded crate's version readme.
    fn readme_path(name: &str, version: &str) -> String {
        format!("readmes/{}/{}-{}.html", name, name, version)
    }

    /// Uploads a file using the configured uploader (either `S3`, `Local` or `NoOp`).
    ///
    /// It returns a a tuple containing the path of the uploaded file
    /// and its checksum.
    pub fn upload(
        &self,
        app: Arc<App>,
        path: &str,
        body: &mut io::Read,
        content_type: &str,
        content_length: u64,
    ) -> CargoResult<(Option<String>, Vec<u8>)> {
        match *self {
            Uploader::S3 { ref bucket, .. } => {
                let mut handle = app.handle();
                let (response, cksum) = {
                    let mut body = HashingReader::new(body);
                    let mut response = Vec::new();
                    {
                        let mut s3req =
                            bucket.put(&mut handle, path, &mut body, content_type, content_length);
                        s3req
                            .write_function(|data| {
                                response.extend(data);
                                Ok(data.len())
                            })
                            .unwrap();
                        s3req.perform().chain_error(|| {
                            internal(&format_args!("failed to upload to S3: `{}`", path))
                        })?;
                    }
                    (response, body.finalize())
                };
                if handle.response_code().unwrap() != 200 {
                    let response = String::from_utf8_lossy(&response);
                    return Err(internal(&format_args!(
                        "failed to get a 200 response from S3: {}",
                        response
                    )));
                }
                Ok((Some(String::from(path)), cksum))
            }
            Uploader::Local => {
                let filename = env::current_dir()
                    .unwrap()
                    .join("dist")
                    .join("local_uploads")
                    .join(path);
                let dir = filename.parent().unwrap();
                fs::create_dir_all(dir)?;
                let mut file = File::create(&filename)?;
                let mut body = HashingReader::new(body);
                io::copy(&mut body, &mut file)?;
                Ok((filename.to_str().map(String::from), body.finalize()))
            }
            Uploader::NoOp => Ok((None, vec![])),
        }
    }

    /// Uploads a crate and its readme. Returns the checksum of the uploaded crate
    /// file, and bombs for the uploaded crate and the uploaded readme.
    pub fn upload_crate(
        &self,
        req: &mut Request,
        krate: &Crate,
        readme: Option<String>,
        max: u64,
        vers: &semver::Version,
    ) -> CargoResult<(Vec<u8>, Bomb, Bomb)> {
        let app = req.app().clone();
        let (crate_path, checksum) = {
            let path = format!("/{}", Uploader::crate_path(&krate.name, &vers.to_string()));
            let length = read_le_u32(req.body())?;
            let mut body = LimitErrorReader::new(req.body(), max);
            self.upload(
                app.clone(),
                &path,
                &mut body,
                "application/x-tar",
                length as u64,
            )?
        };
        // We create the bomb for the crate file before uploading the readme so that if the
        // readme upload fails, the uploaded crate file is automatically deleted.
        let crate_bomb = Bomb {
            app: app.clone(),
            path: crate_path,
        };
        let (readme_path, _) = if let Some(rendered) = readme {
            let path = format!("/{}", Uploader::readme_path(&krate.name, &vers.to_string()));
            let length = rendered.len();
            let mut body = io::Cursor::new(rendered.into_bytes());
            self.upload(
                app.clone(),
                &path,
                &mut body,
                "text/html",
                length as u64,
            )?
        } else {
            (None, vec![])
        };
        Ok((
            checksum,
            crate_bomb,
            Bomb {
                app: app.clone(),
                path: readme_path,
            },
        ))
    }

    /// Deletes an uploaded file.
    fn delete(&self, app: Arc<App>, path: &str) -> CargoResult<()> {
        match *self {
            Uploader::S3 { ref bucket, .. } => {
                let mut handle = app.handle();
                bucket.delete(&mut handle, path).perform()?;
                Ok(())
            }
            Uploader::Local => {
                fs::remove_file(path)?;
                Ok(())
            }
            Uploader::NoOp => Ok(()),
        }
    }
}

pub struct Bomb {
    app: Arc<App>,
    pub path: Option<String>,
}

impl Drop for Bomb {
    fn drop(&mut self) {
        if let Some(ref path) = self.path {
            if let Err(e) = self.app.config.uploader.delete(self.app.clone(), path) {
                println!("unable to delete {}, {:?}", path, e);
            }
        }
    }
}
<commit_msg>Remove leading slash in the path of the uploaded file<commit_after>use conduit::Request;
use krate::Crate;
use util::{CargoResult, internal, ChainError};
use util::{LimitErrorReader, HashingReader, read_le_u32};
use s3;
use semver;
use app::{App, RequestApp};
use std::sync::Arc;
use std::fs::{self, File};
use std::env;
use std::io;

#[derive(Clone, Debug)]
pub enum Uploader {
    /// For production usage, uploads and redirects to s3.
    /// For test usage with a proxy.
    S3 {
        bucket: s3::Bucket,
        proxy: Option<String>,
    },

    /// For development usage only: "uploads" crate files to `dist` and serves them
    /// from there as well to enable local publishing and download
    Local,

    /// For one-off scripts where creating a Config is needed, but uploading is not.
    NoOp,
}

impl Uploader {
    pub fn proxy(&self) -> Option<&str> {
        match *self {
            Uploader::S3 { ref proxy, .. } => proxy.as_ref().map(String::as_str),
            Uploader::Local | Uploader::NoOp => None,
        }
    }

    /// Returns the URL of an uploaded crate's version archive.
    ///
    /// The function doesn't check for the existence of the file.
    /// It returns `None` if the current `Uploader` is `NoOp`.
    pub fn crate_location(&self, crate_name: &str, version: &str) -> Option<String> {
        match *self {
            Uploader::S3 { ref bucket, .. } => {
                Some(format!(
                    "https://{}/{}",
                    bucket.host(),
                    Uploader::crate_path(crate_name, version)
                ))
            }
            Uploader::Local => {
                Some(format!(
                    "/local_uploads/{}",
                    Uploader::crate_path(crate_name, version)
                ))
            }
            Uploader::NoOp => None,
        }
    }

    /// Returns the URL of an uploaded crate's version readme.
    ///
    /// The function doesn't check for the existence of the file.
    /// It returns `None` if the current `Uploader` is `NoOp`.
    pub fn readme_location(&self, crate_name: &str, version: &str) -> Option<String> {
        match *self {
            Uploader::S3 { ref bucket, .. } => {
                Some(format!(
                    "https://{}/{}",
                    bucket.host(),
                    Uploader::readme_path(crate_name, version)
                ))
            }
            Uploader::Local => {
                Some(format!(
                    "/local_uploads/{}",
                    Uploader::readme_path(crate_name, version)
                ))
            }
            Uploader::NoOp => None,
        }
    }

    /// Returns the interna path of an uploaded crate's version archive.
    fn crate_path(name: &str, version: &str) -> String {
        // No slash in front so we can use join
        format!("crates/{}/{}-{}.crate", name, name, version)
    }

    /// Returns the interna path of an uploaded crate's version readme.
    fn readme_path(name: &str, version: &str) -> String {
        format!("readmes/{}/{}-{}.html", name, name, version)
    }

    /// Uploads a file using the configured uploader (either `S3`, `Local` or `NoOp`).
    ///
    /// It returns a a tuple containing the path of the uploaded file
    /// and its checksum.
    pub fn upload(
        &self,
        app: Arc<App>,
        path: &str,
        body: &mut io::Read,
        content_type: &str,
        content_length: u64,
    ) -> CargoResult<(Option<String>, Vec<u8>)> {
        match *self {
            Uploader::S3 { ref bucket, .. } => {
                let mut handle = app.handle();
                let (response, cksum) = {
                    let mut body = HashingReader::new(body);
                    let mut response = Vec::new();
                    {
                        let mut s3req =
                            bucket.put(&mut handle, path, &mut body, content_type, content_length);
                        s3req
                            .write_function(|data| {
                                response.extend(data);
                                Ok(data.len())
                            })
                            .unwrap();
                        s3req.perform().chain_error(|| {
                            internal(&format_args!("failed to upload to S3: `{}`", path))
                        })?;
                    }
                    (response, body.finalize())
                };
                if handle.response_code().unwrap() != 200 {
                    let response = String::from_utf8_lossy(&response);
                    return Err(internal(&format_args!(
                        "failed to get a 200 response from S3: {}",
                        response
                    )));
                }
                Ok((Some(String::from(path)), cksum))
            }
            Uploader::Local => {
                let filename = env::current_dir()
                    .unwrap()
                    .join("dist")
                    .join("local_uploads")
                    .join(path);
                let dir = filename.parent().unwrap();
                fs::create_dir_all(dir)?;
                let mut file = File::create(&filename)?;
                let mut body = HashingReader::new(body);
                io::copy(&mut body, &mut file)?;
                Ok((filename.to_str().map(String::from), body.finalize()))
            }
            Uploader::NoOp => Ok((None, vec![])),
        }
    }

    /// Uploads a crate and its readme. Returns the checksum of the uploaded crate
    /// file, and bombs for the uploaded crate and the uploaded readme.
    pub fn upload_crate(
        &self,
        req: &mut Request,
        krate: &Crate,
        readme: Option<String>,
        max: u64,
        vers: &semver::Version,
    ) -> CargoResult<(Vec<u8>, Bomb, Bomb)> {
        let app = req.app().clone();
        let (crate_path, checksum) = {
            let path = Uploader::crate_path(&krate.name, &vers.to_string());
            let length = read_le_u32(req.body())?;
            let mut body = LimitErrorReader::new(req.body(), max);
            self.upload(
                app.clone(),
                &path,
                &mut body,
                "application/x-tar",
                length as u64,
            )?
        };
        // We create the bomb for the crate file before uploading the readme so that if the
        // readme upload fails, the uploaded crate file is automatically deleted.
        let crate_bomb = Bomb {
            app: app.clone(),
            path: crate_path,
        };
        let (readme_path, _) = if let Some(rendered) = readme {
            let path = Uploader::readme_path(&krate.name, &vers.to_string());
            let length = rendered.len();
            let mut body = io::Cursor::new(rendered.into_bytes());
            self.upload(
                app.clone(),
                &path,
                &mut body,
                "text/html",
                length as u64,
            )?
        } else {
            (None, vec![])
        };
        Ok((
            checksum,
            crate_bomb,
            Bomb {
                app: app.clone(),
                path: readme_path,
            },
        ))
    }

    /// Deletes an uploaded file.
    fn delete(&self, app: Arc<App>, path: &str) -> CargoResult<()> {
        match *self {
            Uploader::S3 { ref bucket, .. } => {
                let mut handle = app.handle();
                bucket.delete(&mut handle, path).perform()?;
                Ok(())
            }
            Uploader::Local => {
                fs::remove_file(path)?;
                Ok(())
            }
            Uploader::NoOp => Ok(()),
        }
    }
}

pub struct Bomb {
    app: Arc<App>,
    pub path: Option<String>,
}

impl Drop for Bomb {
    fn drop(&mut self) {
        if let Some(ref path) = self.path {
            if let Err(e) = self.app.config.uploader.delete(self.app.clone(), path) {
                println!("unable to delete {}, {:?}", path, e);
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::path::{Path, PathBuf, Component};
use std::error::Error;
use std::fs::{self, metadata, File};

/// Takes a path and returns a path containing just enough `../` to point to the root of the given path.
///
/// This is mostly interesting for a relative path to point back to the directory from where the
/// path starts.
///
/// ```ignore
/// let mut path = Path::new("some/relative/path");
///
/// println!("{}", path_to_root(&path));
/// ```
///
/// **Outputs**
///
/// ```text
/// "../../"
/// ```
///
/// **note:** it's not very fool-proof, if you find a situation where it doesn't return the correct
/// path. Consider [submitting a new issue](https://github.com/azerupi/mdBook/issues) or a
/// [pull-request](https://github.com/azerupi/mdBook/pulls) to improve it.

pub fn path_to_root(path: &Path) -> String {
    debug!("[fn]: path_to_root");
    // Remove filename and add "../" for every directory

    path.to_path_buf().parent().expect("")
        .components().fold(String::new(), |mut s, c| {
            match c {
                Component::Normal(_) => s.push_str("../"),
                _ => {
                    debug!("[*]: Other path component... {:?}", c);
                }
            }
            s
        })
}

/// This function checks for every component in a path if the directory exists,
/// if it does not it is created.

pub fn create_path(path: &Path) -> Result<(), Box<Error>> {
    debug!("[fn]: create_path");

    // Create directories if they do not exist
    let mut constructed_path = PathBuf::new();

    for component in path.components() {

        let mut dir;
        match component {
            Component::Normal(_) => { dir = PathBuf::from(component.as_os_str()); },
            Component::RootDir => {
                debug!("[*]: Root directory");
                // This doesn't look very compatible with Windows...
                constructed_path.push("/");
                continue
            },
            _ => continue,
        }

        constructed_path.push(&dir);
        debug!("[*]: {:?}", constructed_path);

        // Check if path exists
        match metadata(&constructed_path) {
            // Any way to combine the Err and first Ok branch ??
            Err(_) => {
                try!(fs::create_dir(&constructed_path));
                debug!("[*]: Directory created {:?}", constructed_path);
            },
            Ok(f) => {
                if !f.is_dir() {
                    try!(fs::create_dir(&constructed_path));
                    debug!("[*]: Directory created {:?}", constructed_path);
                } else {
                    debug!("[*]: Directory exists {:?}", constructed_path);
                    continue
                }
            },
        }
    }

    debug!("[*]: Constructed path: {:?}", constructed_path);

    Ok(())
}

/// This function creates a file and returns it. But before creating the file it checks every
/// directory in the path to see if it exists, and if it does not it will be created.

pub fn create_file(path: &Path) -> Result<File, Box<Error>> {
    debug!("[fn]: create_file");

    // Construct path
    if let Some(p) = path.parent() {
        try!(create_path(p));
    }

    debug!("[*]: Create file: {}", path);
    let f = try!(File::create(path));

    Ok(f)
}
<commit_msg>Copied the PathExt trait from the rust source code as temporary fix. Now I can replace the hacky code I used. When it goes to rust stable I will just have to remove and eventually change some<commit_after>use std::path::{Path, PathBuf, Component};
use std::error::Error;
use std::fs::{self, metadata, File};

/// This is copied from the rust source code until Path_ Ext stabilizes.
/// You can use it, but be aware that it will be removed when those features go to rust stable
pub trait PathExt {
    fn exists(&self) -> bool;
    fn is_file(&self) -> bool;
    fn is_dir(&self) -> bool;
}

impl PathExt for Path {
    fn exists(&self) -> bool {
        metadata(self).is_ok()
    }

    fn is_file(&self) -> bool {
       metadata(self).map(|s| s.is_file()).unwrap_or(false)
    }

    fn is_dir(&self) -> bool {
       metadata(self).map(|s| s.is_dir()).unwrap_or(false)
    }
}

/// Takes a path and returns a path containing just enough `../` to point to the root of the given path.
///
/// This is mostly interesting for a relative path to point back to the directory from where the
/// path starts.
///
/// ```ignore
/// let mut path = Path::new("some/relative/path");
///
/// println!("{}", path_to_root(&path));
/// ```
///
/// **Outputs**
///
/// ```text
/// "../../"
/// ```
///
/// **note:** it's not very fool-proof, if you find a situation where it doesn't return the correct
/// path. Consider [submitting a new issue](https://github.com/azerupi/mdBook/issues) or a
/// [pull-request](https://github.com/azerupi/mdBook/pulls) to improve it.

pub fn path_to_root(path: &Path) -> String {
    debug!("[fn]: path_to_root");
    // Remove filename and add "../" for every directory

    path.to_path_buf().parent().expect("")
        .components().fold(String::new(), |mut s, c| {
            match c {
                Component::Normal(_) => s.push_str("../"),
                _ => {
                    debug!("[*]: Other path component... {:?}", c);
                }
            }
            s
        })
}

/// This function checks for every component in a path if the directory exists,
/// if it does not it is created.

pub fn create_path(path: &Path) -> Result<(), Box<Error>> {
    debug!("[fn]: create_path");

    // Create directories if they do not exist
    let mut constructed_path = PathBuf::new();

    for component in path.components() {

        let mut dir;
        match component {
            Component::Normal(_) => { dir = PathBuf::from(component.as_os_str()); },
            Component::RootDir => {
                debug!("[*]: Root directory");
                // This doesn't look very compatible with Windows...
                constructed_path.push("/");
                continue
            },
            _ => continue,
        }

        constructed_path.push(&dir);
        debug!("[*]: {:?}", constructed_path);

        // Check if path exists
        match metadata(&constructed_path) {
            // Any way to combine the Err and first Ok branch ??
            Err(_) => {
                try!(fs::create_dir(&constructed_path));
                debug!("[*]: Directory created {:?}", constructed_path);
            },
            Ok(f) => {
                if !f.is_dir() {
                    try!(fs::create_dir(&constructed_path));
                    debug!("[*]: Directory created {:?}", constructed_path);
                } else {
                    debug!("[*]: Directory exists {:?}", constructed_path);
                    continue
                }
            },
        }
    }

    debug!("[*]: Constructed path: {:?}", constructed_path);

    Ok(())
}

/// This function creates a file and returns it. But before creating the file it checks every
/// directory in the path to see if it exists, and if it does not it will be created.

pub fn create_file(path: &Path) -> Result<File, Box<Error>> {
    debug!("[fn]: create_file");

    // Construct path
    if let Some(p) = path.parent() {
        try!(create_path(p));
    }

    debug!("[*]: Create file: {}", path);
    let f = try!(File::create(path));

    Ok(f)
}
<|endoftext|>


<commit_before>//! This module will hold the generic structs to wrap the arbitrary types being stored

/// A genreal structure to hide the actual content being stored in the KV store
/// At some point, may forgo this. However, right now, provides a good way of forcing
/// stored objects to be on the heap.
pub struct Value<T: Clone> {
    val: Box<T>
}

impl <T:Clone> Value<T> {

    /// Returns a new instance of the 'Value' struct.
    /// Holds the data pointed to by the 'Key'
    pub fn new(store: T) -> Value<T> {
        return Value{val: Box::new(store)};
    }

    /// Returns a Box to the value stored
    pub fn get_val(&self) -> Box<T> {
        return self.val.clone();
    }
}

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

    #[test]
    fn store_str() {
        let x = Value::new("Hello World!");
    }

    #[test]
    fn get_str() {
        let x = Value::new("Hello World!");
        let y = x.get_val();
        let z = x.get_val();
        assert_eq!(*y,"Hello World!");
        assert_eq!(*z,"Hello World!");
        assert_eq!(*y,*z);
    }

    #[test]
    fn store_String() {
        let x = Value::new("Hello World!".to_string());
    }

    #[test]
    fn get_String() {
        let x = Value::new("Hello World!".to_string());
        let y = x.get_val();
        let z = x.get_val();
        assert_eq!(*y,"Hello World!".to_string());
        assert_eq!(*z,"Hello World!".to_string());
        assert_eq!(*y,*z);
    }

    #[test]
    fn store_int() {
        let x = Value::new(356);
    }

    #[test]
    fn store_float() {
        let x = Value::new(123.456);
    }
}
<commit_msg>Fixed issues with lint in tests<commit_after>//! This module will hold the generic structs to wrap the arbitrary types being stored

/// A genreal structure to hide the actual content being stored in the KV store
/// At some point, may forgo this. However, right now, provides a good way of forcing
/// stored objects to be on the heap.
pub struct Value<T: Clone> {
    val: Box<T>
}

impl <T:Clone> Value<T> {

    /// Returns a new instance of the 'Value' struct.
    /// Holds the data pointed to by the 'Key'
    pub fn new(store: T) -> Value<T> {
        return Value{val: Box::new(store)};
    }

    /// Returns a Box to the value stored
    pub fn get_val(&self) -> Box<T> {
        return self.val.clone();
    }
}

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

    #[test]
    fn store_str() {
        let phrase = "Hello World!";
        let x = Value::new(&phrase);
        assert_eq!(*x.val,&phrase);
    }

    #[test]
    fn get_str() {
        let x = Value::new("Hello World!");
        let y = x.get_val();
        let z = x.get_val();
        assert_eq!(*y,"Hello World!");
        assert_eq!(*z,"Hello World!");
        assert_eq!(*y,*z);
    }

    #[test]
    fn store_string() {
        let phrase = "Hello World!".to_string();
        let x = Value::new(&phrase);
        assert_eq!(*x.val,&phrase);
    }

    #[test]
    fn get_string() {
        let x = Value::new("Hello World!".to_string());
        let y = x.get_val();
        let z = x.get_val();
        assert_eq!(*y,"Hello World!".to_string());
        assert_eq!(*z,"Hello World!".to_string());
        assert_eq!(*y,*z);
    }

    #[test]
    fn store_int() {
        let myint = 356;
        let x = Value::new(myint);
        assert_eq!(*x.val, myint);
    }

    #[test]
    fn store_float() {
        let myfloat = 123.456;
        let x = Value::new(myfloat);
        assert_eq!(*x.val, myfloat);
    }
}
<|endoftext|>


<commit_before>//! Defines the Whitted integrator which implements Whitted recursive ray tracing

use std::f32;
use rand::StdRng;

use scene::Scene;
use linalg::{self, Ray};
use geometry::{Intersection, Emitter, Instance};
use film::Colorf;
use integrator::Integrator;
use bxdf::BxDFType;
use light::Light;
use sampler::Sampler;

/// The Whitted integrator implementing the Whitted recursive ray tracing algorithm
/// See [Whitted, An improved illumination model for shaded display](http://dl.acm.org/citation.cfm?id=358882)
#[derive(Clone, Copy, Debug)]
pub struct Whitted {
    /// The maximum recursion depth for rays
    max_depth: u32,
}

impl Whitted {
    /// Create a new Whitted integrator with the desired maximum recursion depth for rays
    pub fn new(max_depth: u32) -> Whitted { Whitted { max_depth: max_depth } }
}

impl Integrator for Whitted {
    fn illumination(&self, scene: &Scene, light_list: &Vec<&Emitter>, ray: &Ray,
                    hit: &Intersection, sampler: &mut Sampler, rng: &mut StdRng) -> Colorf {
        let bsdf = hit.material.bsdf(hit);
        let w_o = -ray.d;
        let mut sample_2d = [(0.0, 0.0)];
        sampler.get_samples_2d(&mut sample_2d[..], rng);
        let mut illum = Colorf::broadcast(0.0);
        if let &Instance::Emitter(ref e) = hit.instance {
            let w = -ray.d;
            illum = illum + e.radiance(&w, &hit.dg.p, &hit.dg.ng);
        }

        for light in light_list {
            let (li, w_i, pdf, occlusion) = light.sample_incident(&hit.dg.p, &sample_2d[0]);
            let f = bsdf.eval(&w_o, &w_i, BxDFType::all());
            if !li.is_black() && !f.is_black() && !occlusion.occluded(scene) {
                illum = illum + f * li * f32::abs(linalg::dot(&w_i, &bsdf.n)) / pdf;
            }
        }
        if ray.depth < self.max_depth {
            illum = illum + self.specular_reflection(scene, light_list, ray, &bsdf, sampler, rng);
            illum = illum + self.specular_transmission(scene, light_list, ray, &bsdf, sampler, rng);
        }
        illum
    }
}

<commit_msg>Should only include emitted light on the first hit<commit_after>//! Defines the Whitted integrator which implements Whitted recursive ray tracing

use std::f32;
use rand::StdRng;

use scene::Scene;
use linalg::{self, Ray};
use geometry::{Intersection, Emitter, Instance};
use film::Colorf;
use integrator::Integrator;
use bxdf::BxDFType;
use light::Light;
use sampler::Sampler;

/// The Whitted integrator implementing the Whitted recursive ray tracing algorithm
/// See [Whitted, An improved illumination model for shaded display](http://dl.acm.org/citation.cfm?id=358882)
#[derive(Clone, Copy, Debug)]
pub struct Whitted {
    /// The maximum recursion depth for rays
    max_depth: u32,
}

impl Whitted {
    /// Create a new Whitted integrator with the desired maximum recursion depth for rays
    pub fn new(max_depth: u32) -> Whitted { Whitted { max_depth: max_depth } }
}

impl Integrator for Whitted {
    fn illumination(&self, scene: &Scene, light_list: &Vec<&Emitter>, ray: &Ray,
                    hit: &Intersection, sampler: &mut Sampler, rng: &mut StdRng) -> Colorf {
        let bsdf = hit.material.bsdf(hit);
        let w_o = -ray.d;
        let mut sample_2d = [(0.0, 0.0)];
        sampler.get_samples_2d(&mut sample_2d[..], rng);
        let mut illum = Colorf::broadcast(0.0);
        if ray.depth == 0 {
            if let &Instance::Emitter(ref e) = hit.instance {
                let w = -ray.d;
                illum = illum + e.radiance(&w, &hit.dg.p, &hit.dg.ng);
            }
        }

        for light in light_list {
            let (li, w_i, pdf, occlusion) = light.sample_incident(&hit.dg.p, &sample_2d[0]);
            let f = bsdf.eval(&w_o, &w_i, BxDFType::all());
            if !li.is_black() && !f.is_black() && !occlusion.occluded(scene) {
                illum = illum + f * li * f32::abs(linalg::dot(&w_i, &bsdf.n)) / pdf;
            }
        }
        if ray.depth < self.max_depth {
            illum = illum + self.specular_reflection(scene, light_list, ray, &bsdf, sampler, rng);
            illum = illum + self.specular_transmission(scene, light_list, ray, &bsdf, sampler, rng);
        }
        illum
    }
}

<|endoftext|>


<commit_before>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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 crate::utils::paths;
use crate::utils::sugg::DiagnosticBuilderExt;
use crate::utils::{get_trait_def_id, implements_trait, return_ty, same_tys, span_lint_node_and_then};
use if_chain::if_chain;
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use rustc::ty::{self, Ty};
use rustc::util::nodemap::NodeSet;
use rustc::{declare_tool_lint, lint_array};
use rustc_errors::Applicability;
use syntax::source_map::Span;

/// **What it does:** Checks for types with a `fn new() -> Self` method and no
/// implementation of
/// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html).
///
/// It detects both the case when a manual
/// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html)
/// implementation is required and also when it can be created with
/// `#[derive(Default)]
///
/// **Why is this bad?** The user might expect to be able to use
/// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) as the
/// type can be constructed without arguments.
///
/// **Known problems:** Hopefully none.
///
/// **Example:**
///
/// ```rust
/// struct Foo(Bar);
///
/// impl Foo {
///     fn new() -> Self {
///         Foo(Bar::new())
///     }
/// }
/// ```
///
/// Instead, use:
///
/// ```rust
/// struct Foo(Bar);
///
/// impl Default for Foo {
///     fn default() -> Self {
///         Foo(Bar::new())
///     }
/// }
/// ```
///
/// Or, if
/// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html)
/// can be derived by `#[derive(Default)]`:
///
/// ```rust
/// struct Foo;
///
/// impl Foo {
///     fn new() -> Self {
///         Foo
///     }
/// }
/// ```
///
/// Instead, use:
///
/// ```rust
/// #[derive(Default)]
/// struct Foo;
///
/// impl Foo {
///     fn new() -> Self {
///         Foo
///     }
/// }
/// ```
///
/// You can also have `new()` call `Default::default()`.
declare_clippy_lint! {
    pub NEW_WITHOUT_DEFAULT,
    style,
    "`fn new() -> Self` method without `Default` implementation"
}

#[derive(Clone, Default)]
pub struct NewWithoutDefault {
    impling_types: Option<NodeSet>,
}

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

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault {
    fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) {
        if let hir::ItemKind::Impl(_, _, _, _, None, _, ref items) = item.node {
            for assoc_item in items {
                if let hir::AssociatedItemKind::Method { has_self: false } = assoc_item.kind {
                    let impl_item = cx.tcx.hir().impl_item(assoc_item.id);
                    if in_external_macro(cx.sess(), impl_item.span) {
                        return;
                    }
                    if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node {
                        let name = impl_item.ident.name;
                        let id = impl_item.id;
                        if sig.header.constness == hir::Constness::Const {
                            // can't be implemented by default
                            return;
                        }
                        if sig.header.unsafety == hir::Unsafety::Unsafe {
                            // can't be implemented for unsafe new
                            return;
                        }
                        if impl_item.generics.params.iter().any(|gen| match gen.kind {
                            hir::GenericParamKind::Type { .. } => true,
                            _ => false,
                        }) {
                            // when the result of `new()` depends on a type parameter we should not require
                            // an
                            // impl of `Default`
                            return;
                        }
                        if sig.decl.inputs.is_empty() && name == "new" && cx.access_levels.is_reachable(id) {
                            let self_did = cx.tcx.hir().local_def_id(cx.tcx.hir().get_parent(id));
                            let self_ty = cx.tcx.type_of(self_did);
                            if_chain! {
                                if same_tys(cx, self_ty, return_ty(cx, id));
                                if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT);
                                then {
                                    if self.impling_types.is_none() {
                                        let mut impls = NodeSet::default();
                                        cx.tcx.for_each_impl(default_trait_id, |d| {
                                            if let Some(ty_def) = cx.tcx.type_of(d).ty_adt_def() {
                                                if let Some(node_id) = cx.tcx.hir().as_local_node_id(ty_def.did) {
                                                    impls.insert(node_id);
                                                }
                                            }
                                        });
                                        self.impling_types = Some(impls);
                                    }

                                    // Check if a Default implementation exists for the Self type, regardless of
                                    // generics
                                    if_chain! {
                                        if let Some(ref impling_types) = self.impling_types;
                                        if let Some(self_def) = cx.tcx.type_of(self_did).ty_adt_def();
                                        if self_def.did.is_local();
                                        then {
                                            let self_id = cx.tcx.hir().local_def_id_to_node_id(self_def.did.to_local());
                                            if impling_types.contains(&self_id) {
                                                return;
                                            }
                                        }
                                    }

                                    if let Some(sp) = can_derive_default(self_ty, cx, default_trait_id) {
                                        span_lint_node_and_then(
                                            cx,
                                            NEW_WITHOUT_DEFAULT,
                                            id,
                                            impl_item.span,
                                            &format!(
                                                "you should consider deriving a `Default` implementation for `{}`",
                                                self_ty
                                            ),
                                            |db| {
                                                db.suggest_item_with_attr(
                                                    cx,
                                                    sp,
                                                    "try this",
                                                    "#[derive(Default)]",
                                                    Applicability::MaybeIncorrect,
                                                );
                                            });
                                    } else {
                                        span_lint_node_and_then(
                                            cx,
                                            NEW_WITHOUT_DEFAULT,
                                            id,
                                            impl_item.span,
                                            &format!(
                                                "you should consider adding a `Default` implementation for `{}`",
                                                self_ty
                                            ),
                                            |db| {
                                                db.suggest_prepend_item(
                                                    cx,
                                                    item.span,
                                                    "try this",
                                                    &create_new_without_default_suggest_msg(self_ty),
                                                    Applicability::MaybeIncorrect,
                                                );
                                            },
                                        );
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

fn create_new_without_default_suggest_msg(ty: Ty<'_>) -> String {
    #[rustfmt::skip]
    format!(
"impl Default for {} {{
    fn default() -> Self {{
        Self::new()
    }}
}}", ty)
}

fn can_derive_default<'t, 'c>(ty: Ty<'t>, cx: &LateContext<'c, 't>, default_trait_id: DefId) -> Option<Span> {
    match ty.sty {
        ty::Adt(adt_def, substs) if adt_def.is_struct() => {
            for field in adt_def.all_fields() {
                let f_ty = field.ty(cx.tcx, substs);
                if !implements_trait(cx, f_ty, default_trait_id, &[]) {
                    return None;
                }
            }
            Some(cx.tcx.def_span(adt_def.did))
        },
        _ => None,
    }
}
<commit_msg>Auto merge of #3641 - hellow554:patch-1, r=flip1995<commit_after>// Copyright 2014-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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 crate::utils::paths;
use crate::utils::sugg::DiagnosticBuilderExt;
use crate::utils::{get_trait_def_id, implements_trait, return_ty, same_tys, span_lint_node_and_then};
use if_chain::if_chain;
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use rustc::ty::{self, Ty};
use rustc::util::nodemap::NodeSet;
use rustc::{declare_tool_lint, lint_array};
use rustc_errors::Applicability;
use syntax::source_map::Span;

/// **What it does:** Checks for types with a `fn new() -> Self` method and no
/// implementation of
/// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html).
///
/// It detects both the case when a manual
/// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html)
/// implementation is required and also when it can be created with
/// `#[derive(Default)]`
///
/// **Why is this bad?** The user might expect to be able to use
/// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html) as the
/// type can be constructed without arguments.
///
/// **Known problems:** Hopefully none.
///
/// **Example:**
///
/// ```rust
/// struct Foo(Bar);
///
/// impl Foo {
///     fn new() -> Self {
///         Foo(Bar::new())
///     }
/// }
/// ```
///
/// Instead, use:
///
/// ```rust
/// struct Foo(Bar);
///
/// impl Default for Foo {
///     fn default() -> Self {
///         Foo(Bar::new())
///     }
/// }
/// ```
///
/// Or, if
/// [`Default`](https://doc.rust-lang.org/std/default/trait.Default.html)
/// can be derived by `#[derive(Default)]`:
///
/// ```rust
/// struct Foo;
///
/// impl Foo {
///     fn new() -> Self {
///         Foo
///     }
/// }
/// ```
///
/// Instead, use:
///
/// ```rust
/// #[derive(Default)]
/// struct Foo;
///
/// impl Foo {
///     fn new() -> Self {
///         Foo
///     }
/// }
/// ```
///
/// You can also have `new()` call `Default::default()`.
declare_clippy_lint! {
    pub NEW_WITHOUT_DEFAULT,
    style,
    "`fn new() -> Self` method without `Default` implementation"
}

#[derive(Clone, Default)]
pub struct NewWithoutDefault {
    impling_types: Option<NodeSet>,
}

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

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NewWithoutDefault {
    fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::Item) {
        if let hir::ItemKind::Impl(_, _, _, _, None, _, ref items) = item.node {
            for assoc_item in items {
                if let hir::AssociatedItemKind::Method { has_self: false } = assoc_item.kind {
                    let impl_item = cx.tcx.hir().impl_item(assoc_item.id);
                    if in_external_macro(cx.sess(), impl_item.span) {
                        return;
                    }
                    if let hir::ImplItemKind::Method(ref sig, _) = impl_item.node {
                        let name = impl_item.ident.name;
                        let id = impl_item.id;
                        if sig.header.constness == hir::Constness::Const {
                            // can't be implemented by default
                            return;
                        }
                        if sig.header.unsafety == hir::Unsafety::Unsafe {
                            // can't be implemented for unsafe new
                            return;
                        }
                        if impl_item.generics.params.iter().any(|gen| match gen.kind {
                            hir::GenericParamKind::Type { .. } => true,
                            _ => false,
                        }) {
                            // when the result of `new()` depends on a type parameter we should not require
                            // an
                            // impl of `Default`
                            return;
                        }
                        if sig.decl.inputs.is_empty() && name == "new" && cx.access_levels.is_reachable(id) {
                            let self_did = cx.tcx.hir().local_def_id(cx.tcx.hir().get_parent(id));
                            let self_ty = cx.tcx.type_of(self_did);
                            if_chain! {
                                if same_tys(cx, self_ty, return_ty(cx, id));
                                if let Some(default_trait_id) = get_trait_def_id(cx, &paths::DEFAULT_TRAIT);
                                then {
                                    if self.impling_types.is_none() {
                                        let mut impls = NodeSet::default();
                                        cx.tcx.for_each_impl(default_trait_id, |d| {
                                            if let Some(ty_def) = cx.tcx.type_of(d).ty_adt_def() {
                                                if let Some(node_id) = cx.tcx.hir().as_local_node_id(ty_def.did) {
                                                    impls.insert(node_id);
                                                }
                                            }
                                        });
                                        self.impling_types = Some(impls);
                                    }

                                    // Check if a Default implementation exists for the Self type, regardless of
                                    // generics
                                    if_chain! {
                                        if let Some(ref impling_types) = self.impling_types;
                                        if let Some(self_def) = cx.tcx.type_of(self_did).ty_adt_def();
                                        if self_def.did.is_local();
                                        then {
                                            let self_id = cx.tcx.hir().local_def_id_to_node_id(self_def.did.to_local());
                                            if impling_types.contains(&self_id) {
                                                return;
                                            }
                                        }
                                    }

                                    if let Some(sp) = can_derive_default(self_ty, cx, default_trait_id) {
                                        span_lint_node_and_then(
                                            cx,
                                            NEW_WITHOUT_DEFAULT,
                                            id,
                                            impl_item.span,
                                            &format!(
                                                "you should consider deriving a `Default` implementation for `{}`",
                                                self_ty
                                            ),
                                            |db| {
                                                db.suggest_item_with_attr(
                                                    cx,
                                                    sp,
                                                    "try this",
                                                    "#[derive(Default)]",
                                                    Applicability::MaybeIncorrect,
                                                );
                                            });
                                    } else {
                                        span_lint_node_and_then(
                                            cx,
                                            NEW_WITHOUT_DEFAULT,
                                            id,
                                            impl_item.span,
                                            &format!(
                                                "you should consider adding a `Default` implementation for `{}`",
                                                self_ty
                                            ),
                                            |db| {
                                                db.suggest_prepend_item(
                                                    cx,
                                                    item.span,
                                                    "try this",
                                                    &create_new_without_default_suggest_msg(self_ty),
                                                    Applicability::MaybeIncorrect,
                                                );
                                            },
                                        );
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

fn create_new_without_default_suggest_msg(ty: Ty<'_>) -> String {
    #[rustfmt::skip]
    format!(
"impl Default for {} {{
    fn default() -> Self {{
        Self::new()
    }}
}}", ty)
}

fn can_derive_default<'t, 'c>(ty: Ty<'t>, cx: &LateContext<'c, 't>, default_trait_id: DefId) -> Option<Span> {
    match ty.sty {
        ty::Adt(adt_def, substs) if adt_def.is_struct() => {
            for field in adt_def.all_fields() {
                let f_ty = field.ty(cx.tcx, substs);
                if !implements_trait(cx, f_ty, default_trait_id, &[]) {
                    return None;
                }
            }
            Some(cx.tcx.def_span(adt_def.did))
        },
        _ => None,
    }
}
<|endoftext|>


<commit_before>use std::iter;

pub fn verse(n: int) -> ~str {
    match n {
        0 =>
            ~"No more bottles of beer on the wall, no more bottles of beer.\nGo to the store and buy some more, 99 bottles of beer on the wall.\n",
        1 =>
            ~"1 bottle of beer on the wall, 1 bottle of beer.\nTake it down and pass it around, no more bottles of beer on the wall.\n",
        2 =>
            ~"2 bottles of beer on the wall, 2 bottles of beer.\nTake one down and pass it around, 1 bottle of beer on the wall.\n",
        n if n > 2 && n <= 99 =>
            format!("{n} bottles of beer on the wall, {n} bottles of beer.\nTake one down and pass it around, {n_minus_1} bottles of beer on the wall.\n", n=n, n_minus_1=n - 1),
        _ =>
            fail!(),
    }
}

pub fn sing(start: int, end: int) -> ~str {
    let mut s = iter::range_inclusive(end, start)
        .invert()
        .map(verse)
        .to_owned_vec()
        .connect("\n");
    s.push_char('\n');
    s
}
<commit_msg>rust - add whitespace to beer-song to ensure logic is in the first 80 cols and strings wrap before 100<commit_after>use std::iter;

pub fn verse(n: int) -> ~str {
    match n {
        0 =>
            ~"No more bottles of beer on the wall, no more bottles of beer.\n\
              Go to the store and buy some more, 99 bottles of beer on the wall.\n",
        1 =>
            ~"1 bottle of beer on the wall, 1 bottle of beer.\n\
              Take it down and pass it around, no more bottles of beer on the wall.\n",
        2 =>
            ~"2 bottles of beer on the wall, 2 bottles of beer.\n\
              Take one down and pass it around, 1 bottle of beer on the wall.\n",
        n if n > 2 && n <= 99 =>
            format!(
                "{n} bottles of beer on the wall, {n} bottles of beer.\n\
                 Take one down and pass it around, {n_minus_1} bottles of beer on the wall.\n",
                n=n,
                n_minus_1=n - 1),
        _ =>
            fail!(),
    }
}

pub fn sing(start: int, end: int) -> ~str {
    let mut s = iter::range_inclusive(end, start)
        .invert()
        .map(verse)
        .to_owned_vec()
        .connect("\n");
    s.push_char('\n');
    s
}
<|endoftext|>