<commit_before>#[derive(Debug, PartialEq, Copy, Clone)]
pub enum TokenError {
    // If a token not a valid number
    // For example "+0a" starts as a number, but contains invalid characters.
    InvalidNumber,

    // missing terminating quote "
    MissingQuoteEnd,

    InvalidUnquotedString,

    InvalidEscape,
}

#[derive(Debug, PartialEq, Clone)]
pub enum Token<'a> {
    Error((&'a str, TokenError)),
    Whitespace(&'a str),
    Comment(&'a str),

    Str(&'a str),
    QStr(String),

    OpenBracket,  // '['
    CloseBracket, // ']'
    OpenParens,   // '('
    CloseParens,  // ')'
    OpenCurly,    // '{'
    CloseCurly,   // '}'

    UInt(u64),
    SInt(i64),
    Float(f64),
}

#[inline]
fn scan<F: Fn(char) -> bool>(s: &str, cond: F) -> (&str, &str) {
    // split at the first non-"cond" character
    match s.find(|c: char| !cond(c)) {
        None => (s, ""),
        Some(pos) => s.split_at(pos),
    }
}

#[inline]
pub fn is_token_delim(c: char) -> bool {
    c.is_whitespace()
        || c == '('
        || c == ')'
        || c == '['
        || c == ']'
        || c == '{'
        || c == '}'
        || c == '#'
}

fn is_valid_unquoted_string(s: &str) -> bool {
    !(s.contains('\\') || s.contains('"'))
}

fn next_token<'a>(s: &'a str) -> Option<(Token<'a>, &'a str)> {
    let mut chars = s.chars();
    match chars.next() {
        None => None,
        Some(c) => {
            match c {
                '(' => Some((Token::OpenParens, chars.as_str())),
                ')' => Some((Token::CloseParens, chars.as_str())),

                '[' => Some((Token::OpenBracket, chars.as_str())),
                ']' => Some((Token::CloseBracket, chars.as_str())),

                '{' => Some((Token::OpenCurly, chars.as_str())),
                '}' => Some((Token::CloseCurly, chars.as_str())),

                '#' => {
                    // comment
                    let (comment, rest) = scan(chars.as_str(), |ch| ch != '\n');
                    Some((Token::Comment(comment), rest))
                }

                '"' => {
                    let mut unquoted_string = String::new();

                    loop {
                        match chars.next() {
                            None => {
                                // Error. No terminating quoting character found
                                return Some((
                                    Token::Error((chars.as_str(), TokenError::MissingQuoteEnd)),
                                    s,
                                ));
                            }
                            Some(ch) => {
                                match ch {
                                    '"' => {
                                        // found good string
                                        break;
                                    }
                                    '\\' => {
                                        // next character is escaped
                                        match chars.next() {
                                            Some('\\') => {
                                                unquoted_string.push('\\');
                                            }
                                            Some('"') => {
                                                unquoted_string.push('"');
                                            }
                                            _ => {
                                                return Some((
                                                    Token::Error((
                                                        chars.as_str(),
                                                        TokenError::InvalidEscape,
                                                    )),
                                                    s,
                                                ));
                                            }
                                        }
                                    }
                                    _ => {
                                        unquoted_string.push(ch);
                                    }
                                }
                            }
                        }
                    }

                    Some((Token::QStr(unquoted_string), chars.as_str()))
                }

                c if char::is_whitespace(c) => {
                    let (ws, rest) = scan(s, char::is_whitespace);
                    Some((Token::Whitespace(ws), rest))
                }

                '+' | '-' => {
                    let (string, rest) = scan(s, |ch| !is_token_delim(ch));
                    assert!(string.len() > 0);

                    // parse +|- always as a signed integer first.
                    // this is the way to distinguish a positive signed
                    // integer from a positive unsigned (+1 == SInt, while 1 == UInt).

                    // if it is followed by a digit, this is should be a number.
                    match chars.next() {
                        Some(ch) if char::is_digit(ch, 10) => {
                            // +|- followed by [0-9]. This must be a number!

                            if let Ok(i) = string.parse::<i64>() {
                                Some((Token::SInt(i), rest))
                            } else if let Ok(i) = string.parse::<f64>() {
                                Some((Token::Float(i), rest))
                            } else {
                                Some((Token::Error((string, TokenError::InvalidNumber)), rest))
                            }
                        }
                        _ => {
                            // If it is followed by any other character (or none) it is a valid
                            // string token.
                            if is_valid_unquoted_string(string) {
                                Some((Token::Str(string), rest))
                            } else {
                                Some((
                                    Token::Error((string, TokenError::InvalidUnquotedString)),
                                    rest,
                                ))
                            }
                        }
                    }
                }

                '0'...'9' => {
                    // this should be either a unsigned integer of a floating point number. If not,
                    // it's invalid.
                    let (string, rest) = scan(s, |ch| !is_token_delim(ch));
                    assert!(string.len() > 0);

                    if let Ok(i) = string.parse::<u64>() {
                        Some((Token::UInt(i), rest))
                    } else if let Ok(i) = string.parse::<f64>() {
                        Some((Token::Float(i), rest))
                    } else {
                        Some((Token::Error((string, TokenError::InvalidNumber)), rest))
                    }
                }

                _ => {
                    // this neither starts with '+' or '-' or 'digit'. this is definitively a
                    // string.

                    let (string, rest) = scan(s, |ch| !is_token_delim(ch));
                    assert!(string.len() > 0);

                    if is_valid_unquoted_string(string) {
                        Some((Token::Str(string), rest))
                    } else {
                        Some((
                            Token::Error((string, TokenError::InvalidUnquotedString)),
                            rest,
                        ))
                    }
                }
            }
        }
    }
}

pub struct Tokenizer<'a> {
    current: &'a str,
    ignore_ws: bool,
}

impl<'a> Tokenizer<'a> {
    pub fn new(s: &'a str, ignore_ws: bool) -> Tokenizer<'a> {
        Tokenizer {
            current: s,
            ignore_ws: ignore_ws,
        }
    }

    pub fn with_curly_around(self) -> CurlyAroundTokenizer<'a> {
        CurlyAroundTokenizer::new(self)
    }
}

impl<'a> Iterator for Tokenizer<'a> {
    type Item = Token<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            match next_token(self.current) {
                Some((tok, rest)) => {
                    self.current = rest;
                    if self.ignore_ws {
                        match tok {
                            Token::Whitespace(_) | Token::Comment(_) => continue,
                            _ => {}
                        }
                    }
                    return Some(tok);
                }
                None => {
                    return None;
                }
            }
        }
    }
}

enum State {
    Begin,
    Inner,
    End,
}

pub struct CurlyAroundTokenizer<'a> {
    inner: Tokenizer<'a>,
    state: State,
}

impl<'a> CurlyAroundTokenizer<'a> {
    pub fn new(inner: Tokenizer<'a>) -> CurlyAroundTokenizer<'a> {
        CurlyAroundTokenizer {
            inner: inner,
            state: State::Begin,
        }
    }
}

impl<'a> Iterator for CurlyAroundTokenizer<'a> {
    type Item = Token<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        match self.state {
            State::Begin => {
                self.state = State::Inner;
                Some(Token::OpenCurly)
            }
            State::Inner => {
                if let Some(tok) = self.inner.next() {
                    return Some(tok);
                }
                self.state = State::End;
                Some(Token::CloseCurly)
            }
            State::End => None,
        }
    }
}

#[test]
fn test_tokenizer_whitespace() {
    let t = Tokenizer::new(" (abc 123)", false);
    let tokens: Vec<_> = t.into_iter().collect();
    assert_eq!(
        vec![
            Token::Whitespace(" "),
            Token::OpenParens,
            Token::Str("abc"),
            Token::Whitespace(" "),
            Token::UInt(123),
            Token::CloseParens
        ],
        tokens
    );
}

#[test]
fn test_tokenizer_comment() {
    let t = Tokenizer::new(" (abc#comment\n 123)", false);
    let tokens: Vec<_> = t.into_iter().collect();
    assert_eq!(
        vec![
            Token::Whitespace(" "),
            Token::OpenParens,
            Token::Str("abc"),
            Token::Comment("comment"),
            Token::Whitespace("\n "),
            Token::UInt(123),
            Token::CloseParens
        ],
        tokens
    );
}

#[test]
fn test_tokenizer_curly_around() {
    let t = CurlyAroundTokenizer::new(Tokenizer::new(" (abc 123)", true));
    let tokens: Vec<_> = t.into_iter().collect();
    assert_eq!(
        vec![
            Token::OpenCurly,
            Token::OpenParens,
            Token::Str("abc"),
            Token::UInt(123),
            Token::CloseParens,
            Token::CloseCurly
        ],
        tokens
    );
}

#[test]
fn test_tokenizer_no_whitespace() {
    let t = Tokenizer::new(" (abc 123)", true);
    let tokens: Vec<_> = t.into_iter().collect();
    assert_eq!(
        vec![
            Token::OpenParens,
            Token::Str("abc"),
            Token::UInt(123),
            Token::CloseParens
        ],
        tokens
    );
}

#[test]
fn test_token() {
    assert_eq!(Some((Token::Whitespace("  "), "abc")), next_token("  abc"));
    assert_eq!(Some((Token::Str("abc"), "")), next_token("abc"));
    assert_eq!(Some((Token::Str("abc"), "(")), next_token("abc("));

    assert_eq!(Some((Token::OpenParens, ")")), next_token("()"));

    assert_eq!(Some((Token::UInt(12345), "")), next_token("12345"));
    assert_eq!(Some((Token::UInt(12345), " ")), next_token("12345 "));
    assert_eq!(Some((Token::SInt(12345), " ")), next_token("+12345 "));
    assert_eq!(Some((Token::SInt(-12345), " ")), next_token("-12345 "));
    assert_eq!(Some((Token::Str("-a"), " ")), next_token("-a "));
    assert_eq!(Some((Token::Str("+a"), " ")), next_token("+a "));
    assert_eq!(Some((Token::Str("+a"), "(")), next_token("+a("));

    assert_eq!(
        Some((Token::Error(("12345+", TokenError::InvalidNumber)), "")),
        next_token("12345+")
    );
    assert_eq!(Some((Token::UInt(12345), " +")), next_token("12345 +"));
    assert_eq!(Some((Token::Float(12345.123), "")), next_token("12345.123"));
    assert_eq!(
        Some((Token::Float(12345.123), "(")),
        next_token("12345.123(")
    );

    assert_eq!(
        Some((
            Token::Error(("abc\\", TokenError::InvalidUnquotedString)),
            " test"
        )),
        next_token("abc\\ test")
    );
    assert_eq!(
        Some((
            Token::Error(("abc\"", TokenError::InvalidUnquotedString)),
            " test"
        )),
        next_token("abc\" test")
    );

    assert_eq!(
        Some((Token::QStr("".to_string()), "(")),
        next_token("\"\"(")
    );
    assert_eq!(
        Some((Token::QStr("abc".to_string()), "(")),
        next_token("\"abc\"(")
    );
    assert_eq!(
        Some((Token::QStr("a\"b".to_string()), "(")),
        next_token("\"a\\\"b\"(")
    );
    assert_eq!(
        Some((Token::QStr("a\\b".to_string()), "(")),
        next_token("\"a\\\\b\"(")
    );

    assert_eq!(
        Some((Token::Error(("", TokenError::MissingQuoteEnd)), "\"abc ")),
        next_token("\"abc ")
    );

    //assert_eq!(Some((Token::Error(("n ", TokenError::InvalidEscape)), "\"abc\\n ")),
    assert_eq!(
        Some((Token::Error((" ", TokenError::InvalidEscape)), "\"abc\\n ")),
        next_token("\"abc\\n ")
    );
}
<commit_msg>Silence warning<commit_after>#[derive(Debug, PartialEq, Copy, Clone)]
pub enum TokenError {
    // If a token not a valid number
    // For example "+0a" starts as a number, but contains invalid characters.
    InvalidNumber,

    // missing terminating quote "
    MissingQuoteEnd,

    InvalidUnquotedString,

    InvalidEscape,
}

#[derive(Debug, PartialEq, Clone)]
pub enum Token<'a> {
    Error((&'a str, TokenError)),
    Whitespace(&'a str),
    Comment(&'a str),

    Str(&'a str),
    QStr(String),

    OpenBracket,  // '['
    CloseBracket, // ']'
    OpenParens,   // '('
    CloseParens,  // ')'
    OpenCurly,    // '{'
    CloseCurly,   // '}'

    UInt(u64),
    SInt(i64),
    Float(f64),
}

#[inline]
fn scan<F: Fn(char) -> bool>(s: &str, cond: F) -> (&str, &str) {
    // split at the first non-"cond" character
    match s.find(|c: char| !cond(c)) {
        None => (s, ""),
        Some(pos) => s.split_at(pos),
    }
}

#[inline]
pub fn is_token_delim(c: char) -> bool {
    c.is_whitespace()
        || c == '('
        || c == ')'
        || c == '['
        || c == ']'
        || c == '{'
        || c == '}'
        || c == '#'
}

fn is_valid_unquoted_string(s: &str) -> bool {
    !(s.contains('\\') || s.contains('"'))
}

fn next_token<'a>(s: &'a str) -> Option<(Token<'a>, &'a str)> {
    let mut chars = s.chars();
    match chars.next() {
        None => None,
        Some(c) => {
            match c {
                '(' => Some((Token::OpenParens, chars.as_str())),
                ')' => Some((Token::CloseParens, chars.as_str())),

                '[' => Some((Token::OpenBracket, chars.as_str())),
                ']' => Some((Token::CloseBracket, chars.as_str())),

                '{' => Some((Token::OpenCurly, chars.as_str())),
                '}' => Some((Token::CloseCurly, chars.as_str())),

                '#' => {
                    // comment
                    let (comment, rest) = scan(chars.as_str(), |ch| ch != '\n');
                    Some((Token::Comment(comment), rest))
                }

                '"' => {
                    let mut unquoted_string = String::new();

                    loop {
                        match chars.next() {
                            None => {
                                // Error. No terminating quoting character found
                                return Some((
                                    Token::Error((chars.as_str(), TokenError::MissingQuoteEnd)),
                                    s,
                                ));
                            }
                            Some(ch) => {
                                match ch {
                                    '"' => {
                                        // found good string
                                        break;
                                    }
                                    '\\' => {
                                        // next character is escaped
                                        match chars.next() {
                                            Some('\\') => {
                                                unquoted_string.push('\\');
                                            }
                                            Some('"') => {
                                                unquoted_string.push('"');
                                            }
                                            _ => {
                                                return Some((
                                                    Token::Error((
                                                        chars.as_str(),
                                                        TokenError::InvalidEscape,
                                                    )),
                                                    s,
                                                ));
                                            }
                                        }
                                    }
                                    _ => {
                                        unquoted_string.push(ch);
                                    }
                                }
                            }
                        }
                    }

                    Some((Token::QStr(unquoted_string), chars.as_str()))
                }

                c if char::is_whitespace(c) => {
                    let (ws, rest) = scan(s, char::is_whitespace);
                    Some((Token::Whitespace(ws), rest))
                }

                '+' | '-' => {
                    let (string, rest) = scan(s, |ch| !is_token_delim(ch));
                    assert!(string.len() > 0);

                    // parse +|- always as a signed integer first.
                    // this is the way to distinguish a positive signed
                    // integer from a positive unsigned (+1 == SInt, while 1 == UInt).

                    // if it is followed by a digit, this is should be a number.
                    match chars.next() {
                        Some(ch) if char::is_digit(ch, 10) => {
                            // +|- followed by [0-9]. This must be a number!

                            if let Ok(i) = string.parse::<i64>() {
                                Some((Token::SInt(i), rest))
                            } else if let Ok(i) = string.parse::<f64>() {
                                Some((Token::Float(i), rest))
                            } else {
                                Some((Token::Error((string, TokenError::InvalidNumber)), rest))
                            }
                        }
                        _ => {
                            // If it is followed by any other character (or none) it is a valid
                            // string token.
                            if is_valid_unquoted_string(string) {
                                Some((Token::Str(string), rest))
                            } else {
                                Some((
                                    Token::Error((string, TokenError::InvalidUnquotedString)),
                                    rest,
                                ))
                            }
                        }
                    }
                }

                '0'..='9' => {
                    // this should be either a unsigned integer of a floating point number. If not,
                    // it's invalid.
                    let (string, rest) = scan(s, |ch| !is_token_delim(ch));
                    assert!(string.len() > 0);

                    if let Ok(i) = string.parse::<u64>() {
                        Some((Token::UInt(i), rest))
                    } else if let Ok(i) = string.parse::<f64>() {
                        Some((Token::Float(i), rest))
                    } else {
                        Some((Token::Error((string, TokenError::InvalidNumber)), rest))
                    }
                }

                _ => {
                    // this neither starts with '+' or '-' or 'digit'. this is definitively a
                    // string.

                    let (string, rest) = scan(s, |ch| !is_token_delim(ch));
                    assert!(string.len() > 0);

                    if is_valid_unquoted_string(string) {
                        Some((Token::Str(string), rest))
                    } else {
                        Some((
                            Token::Error((string, TokenError::InvalidUnquotedString)),
                            rest,
                        ))
                    }
                }
            }
        }
    }
}

pub struct Tokenizer<'a> {
    current: &'a str,
    ignore_ws: bool,
}

impl<'a> Tokenizer<'a> {
    pub fn new(s: &'a str, ignore_ws: bool) -> Tokenizer<'a> {
        Tokenizer {
            current: s,
            ignore_ws: ignore_ws,
        }
    }

    pub fn with_curly_around(self) -> CurlyAroundTokenizer<'a> {
        CurlyAroundTokenizer::new(self)
    }
}

impl<'a> Iterator for Tokenizer<'a> {
    type Item = Token<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            match next_token(self.current) {
                Some((tok, rest)) => {
                    self.current = rest;
                    if self.ignore_ws {
                        match tok {
                            Token::Whitespace(_) | Token::Comment(_) => continue,
                            _ => {}
                        }
                    }
                    return Some(tok);
                }
                None => {
                    return None;
                }
            }
        }
    }
}

enum State {
    Begin,
    Inner,
    End,
}

pub struct CurlyAroundTokenizer<'a> {
    inner: Tokenizer<'a>,
    state: State,
}

impl<'a> CurlyAroundTokenizer<'a> {
    pub fn new(inner: Tokenizer<'a>) -> CurlyAroundTokenizer<'a> {
        CurlyAroundTokenizer {
            inner: inner,
            state: State::Begin,
        }
    }
}

impl<'a> Iterator for CurlyAroundTokenizer<'a> {
    type Item = Token<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        match self.state {
            State::Begin => {
                self.state = State::Inner;
                Some(Token::OpenCurly)
            }
            State::Inner => {
                if let Some(tok) = self.inner.next() {
                    return Some(tok);
                }
                self.state = State::End;
                Some(Token::CloseCurly)
            }
            State::End => None,
        }
    }
}

#[test]
fn test_tokenizer_whitespace() {
    let t = Tokenizer::new(" (abc 123)", false);
    let tokens: Vec<_> = t.into_iter().collect();
    assert_eq!(
        vec![
            Token::Whitespace(" "),
            Token::OpenParens,
            Token::Str("abc"),
            Token::Whitespace(" "),
            Token::UInt(123),
            Token::CloseParens
        ],
        tokens
    );
}

#[test]
fn test_tokenizer_comment() {
    let t = Tokenizer::new(" (abc#comment\n 123)", false);
    let tokens: Vec<_> = t.into_iter().collect();
    assert_eq!(
        vec![
            Token::Whitespace(" "),
            Token::OpenParens,
            Token::Str("abc"),
            Token::Comment("comment"),
            Token::Whitespace("\n "),
            Token::UInt(123),
            Token::CloseParens
        ],
        tokens
    );
}

#[test]
fn test_tokenizer_curly_around() {
    let t = CurlyAroundTokenizer::new(Tokenizer::new(" (abc 123)", true));
    let tokens: Vec<_> = t.into_iter().collect();
    assert_eq!(
        vec![
            Token::OpenCurly,
            Token::OpenParens,
            Token::Str("abc"),
            Token::UInt(123),
            Token::CloseParens,
            Token::CloseCurly
        ],
        tokens
    );
}

#[test]
fn test_tokenizer_no_whitespace() {
    let t = Tokenizer::new(" (abc 123)", true);
    let tokens: Vec<_> = t.into_iter().collect();
    assert_eq!(
        vec![
            Token::OpenParens,
            Token::Str("abc"),
            Token::UInt(123),
            Token::CloseParens
        ],
        tokens
    );
}

#[test]
fn test_token() {
    assert_eq!(Some((Token::Whitespace("  "), "abc")), next_token("  abc"));
    assert_eq!(Some((Token::Str("abc"), "")), next_token("abc"));
    assert_eq!(Some((Token::Str("abc"), "(")), next_token("abc("));

    assert_eq!(Some((Token::OpenParens, ")")), next_token("()"));

    assert_eq!(Some((Token::UInt(12345), "")), next_token("12345"));
    assert_eq!(Some((Token::UInt(12345), " ")), next_token("12345 "));
    assert_eq!(Some((Token::SInt(12345), " ")), next_token("+12345 "));
    assert_eq!(Some((Token::SInt(-12345), " ")), next_token("-12345 "));
    assert_eq!(Some((Token::Str("-a"), " ")), next_token("-a "));
    assert_eq!(Some((Token::Str("+a"), " ")), next_token("+a "));
    assert_eq!(Some((Token::Str("+a"), "(")), next_token("+a("));

    assert_eq!(
        Some((Token::Error(("12345+", TokenError::InvalidNumber)), "")),
        next_token("12345+")
    );
    assert_eq!(Some((Token::UInt(12345), " +")), next_token("12345 +"));
    assert_eq!(Some((Token::Float(12345.123), "")), next_token("12345.123"));
    assert_eq!(
        Some((Token::Float(12345.123), "(")),
        next_token("12345.123(")
    );

    assert_eq!(
        Some((
            Token::Error(("abc\\", TokenError::InvalidUnquotedString)),
            " test"
        )),
        next_token("abc\\ test")
    );
    assert_eq!(
        Some((
            Token::Error(("abc\"", TokenError::InvalidUnquotedString)),
            " test"
        )),
        next_token("abc\" test")
    );

    assert_eq!(
        Some((Token::QStr("".to_string()), "(")),
        next_token("\"\"(")
    );
    assert_eq!(
        Some((Token::QStr("abc".to_string()), "(")),
        next_token("\"abc\"(")
    );
    assert_eq!(
        Some((Token::QStr("a\"b".to_string()), "(")),
        next_token("\"a\\\"b\"(")
    );
    assert_eq!(
        Some((Token::QStr("a\\b".to_string()), "(")),
        next_token("\"a\\\\b\"(")
    );

    assert_eq!(
        Some((Token::Error(("", TokenError::MissingQuoteEnd)), "\"abc ")),
        next_token("\"abc ")
    );

    //assert_eq!(Some((Token::Error(("n ", TokenError::InvalidEscape)), "\"abc\\n ")),
    assert_eq!(
        Some((Token::Error((" ", TokenError::InvalidEscape)), "\"abc\\n ")),
        next_token("\"abc\\n ")
    );
}
<|endoftext|>


<commit_before>/*
 * Implemenation of a bitfield as a vec. Only
 * supports bytes (Vec<u8>) as the underlying
 * storage.
 *
 * A future implementation should be more efficient,
 * this is just to get the job done for now.
 */
use std::cmp::max;

#[derive(Eq)]
pub struct BooleanBitfield{
    len: usize,
    vec: Vec<u8>
}

impl BooleanBitfield {
    /// Create a new bitfield with a length of zero.
    pub fn new() -> Self {
        Self {
            len: 0,
            vec: vec![]
        }
    }

    /// Create a new bitfield of a certain capacity
    pub fn with_capacity(capacity: usize) -> Self {
        Self {
            len: 0,
            vec: Vec::with_capacity(capacity / 8 + 1)
        }
    }

    /// Read the value of a bit.
    ///
    /// Will return `true` if the bit has been set to `true`
    /// without then being set to `False`.
    pub fn get_bit(&self, i: &usize) -> bool {
        let bit = |i: &usize| *i % 8;
        let byte = |i: &usize| *i / 8;

        if byte(i) >= self.vec.len() {
            false
        } else {
             self.vec[byte(i)] & (1 << (bit(i) as u8)) != 0
        }
    }

    /// Set the value of a bit.
    ///
    /// If this bit is larger than the length of the underlying byte
    /// array it will be extended.
    pub fn set_bit(&mut self, i: &usize, to: &bool) {
        let bit = |i: &usize| *i % 8;
        let byte = |i: &usize| *i / 8;

        self.len = max(self.len, i + 1);

        if byte(i) >= self.vec.len() {
            self.vec.resize(byte(i) + 1, 0);
        }
        match to {
            true =>  {
                self.vec[byte(i)] =
                    self.vec[byte(i)] |  (1 << (bit(i) as u8))
            }
            false => {
                self.vec[byte(i)] =
                    self.vec[byte(i)] & !(1 << (bit(i) as u8))
            }
        }
    }

    /// Return the "length" of this bitfield. Length is defined as
    /// the highest bit that has been set.
    ///
    /// Note: this is distinct from the length of the underlying
    /// vector.
    pub fn len(&self) -> usize { self.len }

    /// Iterate through the underlying vector and count the number of
    /// true bits.
    pub fn num_true_bits(&self) -> u64 {
        let mut count: u64 = 0;
        for byte in &self.vec {
            for bit in 0..8 {
                if byte & (1 << (bit as u8)) != 0 {
                    count += 1;
                }
            }
        }
        count
    }

    /// Clone and return the underlying byte array (`Vec<u8>`).
    pub fn to_vec(&self) -> Vec<u8> {
        let mut o = self.vec.clone();
        o.reverse();
        o
    }
}

impl PartialEq for BooleanBitfield {
    fn eq(&self, other: &BooleanBitfield) -> bool {
        (self.vec == other.vec) &
            (self.len == other.len)
    }
}

impl Clone for BooleanBitfield {
    fn clone(&self) -> Self {
        Self {
            vec: self.vec.to_vec(),
            ..*self
        }
    }
}

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

    #[test]
    fn test_bitfield_set() {
        let mut b = BooleanBitfield::new();
        b.set_bit(&0, &false);
        assert_eq!(b.to_vec(), [0]);

        b = BooleanBitfield::new();
        b.set_bit(&7, &true);
        assert_eq!(b.to_vec(), [128]);
        b.set_bit(&7, &false);
        assert_eq!(b.to_vec(), [0]);
        assert_eq!(b.len(), 8);

        b = BooleanBitfield::new();
        b.set_bit(&7, &true);
        b.set_bit(&0, &true);
        assert_eq!(b.to_vec(), [129]);
        b.set_bit(&7, &false);
        assert_eq!(b.to_vec(), [1]);
        assert_eq!(b.len(), 8);

        b = BooleanBitfield::new();
        b.set_bit(&8, &true);
        assert_eq!(b.to_vec(), [1, 0]);
        assert_eq!(b.len(), 9);
        b.set_bit(&8, &false);
        assert_eq!(b.to_vec(), [0, 0]);
        assert_eq!(b.len(), 9);

        b = BooleanBitfield::new();
        b.set_bit(&15, &true);
        assert_eq!(b.to_vec(), [128, 0]);
        b.set_bit(&15, &false);
        assert_eq!(b.to_vec(), [0, 0]);
        assert_eq!(b.len(), 16);

        b = BooleanBitfield::new();
        b.set_bit(&8, &true);
        b.set_bit(&15, &true);
        assert_eq!(b.to_vec(), [129, 0]);
        b.set_bit(&15, &false);
        assert_eq!(b.to_vec(), [1, 0]);
        assert_eq!(b.len(), 16);
    }

    #[test]
    fn test_bitfield_get() {
        let test_nums = vec![0, 8, 15, 42, 1337];
        for i in test_nums {
            let mut b = BooleanBitfield::new();
            assert_eq!(b.get_bit(&i), false);
            b.set_bit(&i, &true);
            assert_eq!(b.get_bit(&i), true);
            b.set_bit(&i, &true);
        }
    }

    #[test]
    fn test_bitfield_num_true_bits() {
        let mut b = BooleanBitfield::new();
        assert_eq!(b.num_true_bits(), 0);
        b.set_bit(&15, &true);
        assert_eq!(b.num_true_bits(), 1);
        b.set_bit(&15, &false);
        assert_eq!(b.num_true_bits(), 0);
        b.set_bit(&0, &true);
        b.set_bit(&7, &true);
        b.set_bit(&8, &true);
        b.set_bit(&1337, &true);
        assert_eq!(b.num_true_bits(), 4);
    }
}
<commit_msg>Tidy up boolean_bitfield<commit_after>/*
 * Implemenation of a bitfield as a vec. Only
 * supports bytes (Vec<u8>) as the underlying
 * storage.
 *
 * A future implementation should be more efficient,
 * this is just to get the job done for now.
 */
use std::cmp::max;

#[derive(Eq,Clone)]
pub struct BooleanBitfield{
    len: usize,
    vec: Vec<u8>
}

impl BooleanBitfield {
    /// Create a new bitfield with a length of zero.
    pub fn new() -> Self {
        Self {
            len: 0,
            vec: vec![]
        }
    }

    /// Create a new bitfield of a certain capacity
    pub fn with_capacity(capacity: usize) -> Self {
        Self {
            len: 0,
            vec: Vec::with_capacity(capacity / 8 + 1)
        }
    }

    /// Read the value of a bit.
    ///
    /// Will return `true` if the bit has been set to `true`
    /// without then being set to `False`.
    pub fn get_bit(&self, i: &usize) -> bool {
        let bit = |i: &usize| *i % 8;
        let byte = |i: &usize| *i / 8;

        if byte(i) >= self.vec.len() {
            false
        } else {
             self.vec[byte(i)] & (1 << (bit(i) as u8)) != 0
        }
    }

    /// Set the value of a bit.
    ///
    /// If this bit is larger than the length of the underlying byte
    /// array it will be extended.
    pub fn set_bit(&mut self, i: &usize, to: &bool) {
        let bit = |i: &usize| *i % 8;
        let byte = |i: &usize| *i / 8;

        self.len = max(self.len, i + 1);

        if byte(i) >= self.vec.len() {
            self.vec.resize(byte(i) + 1, 0);
        }
        match to {
            true =>  {
                self.vec[byte(i)] =
                    self.vec[byte(i)] |  (1 << (bit(i) as u8))
            }
            false => {
                self.vec[byte(i)] =
                    self.vec[byte(i)] & !(1 << (bit(i) as u8))
            }
        }
    }

    /// Return the "length" of this bitfield. Length is defined as
    /// the highest bit that has been set.
    ///
    /// Note: this is distinct from the length of the underlying
    /// vector.
    pub fn len(&self) -> usize { self.len }

    /// Iterate through the underlying vector and count the number of
    /// true bits.
    pub fn num_true_bits(&self) -> u64 {
        let mut count: u64 = 0;
        for byte in &self.vec {
            for bit in 0..8 {
                if byte & (1 << (bit as u8)) != 0 {
                    count += 1;
                }
            }
        }
        count
    }

    /// Clone and return the underlying byte array (`Vec<u8>`).
    pub fn to_be_vec(&self) -> Vec<u8> {
        let mut o = self.vec.clone();
        o.reverse();
        o
    }
}

impl PartialEq for BooleanBitfield {
    fn eq(&self, other: &BooleanBitfield) -> bool {
        (self.vec == other.vec) &
            (self.len == other.len)
    }
}

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

    #[test]
    fn test_bitfield_set() {
        let mut b = BooleanBitfield::new();
        b.set_bit(&0, &false);
        assert_eq!(b.to_be_vec(), [0]);

        b = BooleanBitfield::new();
        b.set_bit(&7, &true);
        assert_eq!(b.to_be_vec(), [128]);
        b.set_bit(&7, &false);
        assert_eq!(b.to_be_vec(), [0]);
        assert_eq!(b.len(), 8);

        b = BooleanBitfield::new();
        b.set_bit(&7, &true);
        b.set_bit(&0, &true);
        assert_eq!(b.to_be_vec(), [129]);
        b.set_bit(&7, &false);
        assert_eq!(b.to_be_vec(), [1]);
        assert_eq!(b.len(), 8);

        b = BooleanBitfield::new();
        b.set_bit(&8, &true);
        assert_eq!(b.to_be_vec(), [1, 0]);
        assert_eq!(b.len(), 9);
        b.set_bit(&8, &false);
        assert_eq!(b.to_be_vec(), [0, 0]);
        assert_eq!(b.len(), 9);

        b = BooleanBitfield::new();
        b.set_bit(&15, &true);
        assert_eq!(b.to_be_vec(), [128, 0]);
        b.set_bit(&15, &false);
        assert_eq!(b.to_be_vec(), [0, 0]);
        assert_eq!(b.len(), 16);

        b = BooleanBitfield::new();
        b.set_bit(&8, &true);
        b.set_bit(&15, &true);
        assert_eq!(b.to_be_vec(), [129, 0]);
        b.set_bit(&15, &false);
        assert_eq!(b.to_be_vec(), [1, 0]);
        assert_eq!(b.len(), 16);
    }

    #[test]
    fn test_bitfield_get() {
        let test_nums = vec![0, 8, 15, 42, 1337];
        for i in test_nums {
            let mut b = BooleanBitfield::new();
            assert_eq!(b.get_bit(&i), false);
            b.set_bit(&i, &true);
            assert_eq!(b.get_bit(&i), true);
            b.set_bit(&i, &true);
        }
    }

    #[test]
    fn test_bitfield_num_true_bits() {
        let mut b = BooleanBitfield::new();
        assert_eq!(b.num_true_bits(), 0);
        b.set_bit(&15, &true);
        assert_eq!(b.num_true_bits(), 1);
        b.set_bit(&15, &false);
        assert_eq!(b.num_true_bits(), 0);
        b.set_bit(&0, &true);
        b.set_bit(&7, &true);
        b.set_bit(&8, &true);
        b.set_bit(&1337, &true);
        assert_eq!(b.num_true_bits(), 4);
    }
}
<|endoftext|>


<commit_before>use rustc::hir::*;
use rustc::hir::intravisit::FnKind;
use rustc::lint::*;
use rustc::ty::{self, RegionKind, TypeFoldable};
use rustc::traits;
use rustc::middle::expr_use_visitor as euv;
use rustc::middle::mem_categorization as mc;
use syntax::ast::NodeId;
use syntax_pos::Span;
use syntax::errors::DiagnosticBuilder;
use utils::{get_trait_def_id, implements_trait, in_macro, is_copy, is_self, match_type, multispan_sugg, paths,
            snippet, snippet_opt, span_lint_and_then};
use utils::ptr::get_spans;
use std::collections::{HashMap, HashSet};
use std::borrow::Cow;

/// **What it does:** Checks for functions taking arguments by value, but not
/// consuming them in its
/// body.
///
/// **Why is this bad?** Taking arguments by reference is more flexible and can
/// sometimes avoid
/// unnecessary allocations.
///
/// **Known problems:** Hopefully none.
///
/// **Example:**
/// ```rust
/// fn foo(v: Vec<i32>) {
///     assert_eq!(v.len(), 42);
/// }
/// ```
declare_lint! {
    pub NEEDLESS_PASS_BY_VALUE,
    Warn,
    "functions taking arguments by value, but not consuming them in its body"
}

pub struct NeedlessPassByValue;

impl LintPass for NeedlessPassByValue {
    fn get_lints(&self) -> LintArray {
        lint_array![NEEDLESS_PASS_BY_VALUE]
    }
}

macro_rules! need {
    ($e: expr) => { if let Some(x) = $e { x } else { return; } };
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
    fn check_fn(
        &mut self,
        cx: &LateContext<'a, 'tcx>,
        kind: FnKind<'tcx>,
        decl: &'tcx FnDecl,
        body: &'tcx Body,
        span: Span,
        node_id: NodeId,
    ) {
        if in_macro(span) {
            return;
        }

        match kind {
            FnKind::ItemFn(.., attrs) => for a in attrs {
                if_let_chain!{[
                    a.meta_item_list().is_some(),
                    let Some(name) = a.name(),
                    name == "proc_macro_derive",
                ], {
                    return;
                }}
            },
            _ => return,
        }

        // Allow `Borrow` or functions to be taken by value
        let borrow_trait = need!(get_trait_def_id(cx, &paths::BORROW_TRAIT));
        let fn_traits = [
            need!(cx.tcx.lang_items().fn_trait()),
            need!(cx.tcx.lang_items().fn_once_trait()),
            need!(cx.tcx.lang_items().fn_mut_trait()),
        ];

        let sized_trait = need!(cx.tcx.lang_items().sized_trait());

        let fn_def_id = cx.tcx.hir.local_def_id(node_id);

        let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds.to_vec())
            .filter(|p| !p.is_global())
            .collect::<Vec<_>>();
        let preds = preds
            .iter()
            .filter_map(|pred| if let ty::Predicate::Trait(ref poly_trait_ref) = *pred {
                Some(poly_trait_ref.skip_binder())
            } else {
                None
            })
            .filter(|t| t.def_id() != sized_trait && !t.has_escaping_regions())
            .collect::<Vec<_>>();

        // Collect moved variables and spans which will need dereferencings from the
        // function body.
        let MovedVariablesCtxt {
            moved_vars,
            spans_need_deref,
            ..
        } = {
            let mut ctx = MovedVariablesCtxt::new(cx);
            let region_scope_tree = &cx.tcx.region_scope_tree(fn_def_id);
            euv::ExprUseVisitor::new(&mut ctx, cx.tcx, cx.param_env, region_scope_tree, cx.tables).consume_body(body);
            ctx
        };

        let fn_sig = cx.tcx.fn_sig(fn_def_id);
        let fn_sig = cx.tcx.erase_late_bound_regions(&fn_sig);

        for (idx, ((input, &ty), arg)) in decl.inputs
            .iter()
            .zip(fn_sig.inputs())
            .zip(&body.arguments)
            .enumerate()
        {
            // * Exclude a type that is specifically bounded by `Borrow`.
            // * Exclude a type whose reference also fulfills its bound.
            //   (e.g. `std::convert::AsRef`, `serde::Serialize`)
            let (implements_borrow_trait, all_borrowable_trait) = {
                let preds = preds
                    .iter()
                    .filter(|t| t.self_ty() == ty)
                    .collect::<Vec<_>>();

                (
                    preds.iter().any(|t| t.def_id() == borrow_trait),
                    !preds.is_empty() && preds.iter().all(|t| {
                        implements_trait(
                            cx,
                            cx.tcx.mk_imm_ref(&RegionKind::ReErased, ty),
                            t.def_id(),
                            &t.input_types().skip(1).collect::<Vec<_>>(),
                        )
                    }),
                )
            };

            if_let_chain! {[
                !is_self(arg),
                !ty.is_mutable_pointer(),
                !is_copy(cx, ty),
                !fn_traits.iter().any(|&t| implements_trait(cx, ty, t, &[])),
                !implements_borrow_trait,
                !all_borrowable_trait,

                let PatKind::Binding(mode, canonical_id, ..) = arg.pat.node,
                !moved_vars.contains(&canonical_id),
            ], {
                if mode == BindingAnnotation::Mutable || mode == BindingAnnotation::RefMut {
                    continue;
                }

                // Dereference suggestion
                let sugg = |db: &mut DiagnosticBuilder| {
                    let deref_span = spans_need_deref.get(&canonical_id);
                    if_let_chain! {[
                        match_type(cx, ty, &paths::VEC),
                        let Some(clone_spans) =
                            get_spans(cx, Some(body.id()), idx, &[("clone", ".to_owned()")]),
                        let TyPath(QPath::Resolved(_, ref path)) = input.node,
                        let Some(elem_ty) = path.segments.iter()
                            .find(|seg| seg.name == "Vec")
                            .and_then(|ps| ps.parameters.as_ref())
                            .map(|params| &params.types[0]),
                    ], {
                        let slice_ty = format!("&[{}]", snippet(cx, elem_ty.span, "_"));
                        db.span_suggestion(input.span,
                                        "consider changing the type to",
                                        slice_ty);

                        for (span, suggestion) in clone_spans {
                            db.span_suggestion(
                                span,
                                &snippet_opt(cx, span)
                                    .map_or(
                                        "change the call to".into(),
                                        |x| Cow::from(format!("change `{}` to", x)),
                                    ),
                                suggestion.into()
                            );
                        }

                        // cannot be destructured, no need for `*` suggestion
                        assert!(deref_span.is_none());
                        return;
                    }}

                    if match_type(cx, ty, &paths::STRING) {
                        if let Some(clone_spans) =
                            get_spans(cx, Some(body.id()), idx, &[("clone", ".to_string()"), ("as_str", "")]) {
                            db.span_suggestion(input.span, "consider changing the type to", "&str".to_string());

                            for (span, suggestion) in clone_spans {
                                db.span_suggestion(
                                    span,
                                    &snippet_opt(cx, span)
                                        .map_or(
                                            "change the call to".into(),
                                            |x| Cow::from(format!("change `{}` to", x))
                                        ),
                                    suggestion.into(),
                                );
                            }

                            assert!(deref_span.is_none());
                            return;
                        }
                    }

                    let mut spans = vec![(input.span, format!("&{}", snippet(cx, input.span, "_")))];

                    // Suggests adding `*` to dereference the added reference.
                    if let Some(deref_span) = deref_span {
                        spans.extend(
                            deref_span
                                .iter()
                                .cloned()
                                .map(|span| (span, format!("*{}", snippet(cx, span, "<expr>")))),
                        );
                        spans.sort_by_key(|&(span, _)| span);
                    }
                    multispan_sugg(db, "consider taking a reference instead".to_string(), spans);
                };

                span_lint_and_then(
                    cx,
                    NEEDLESS_PASS_BY_VALUE,
                    input.span,
                    "this argument is passed by value, but not consumed in the function body",
                    sugg,
                );
            }}
        }
    }
}

struct MovedVariablesCtxt<'a, 'tcx: 'a> {
    cx: &'a LateContext<'a, 'tcx>,
    moved_vars: HashSet<NodeId>,
    /// Spans which need to be prefixed with `*` for dereferencing the
    /// suggested additional reference.
    spans_need_deref: HashMap<NodeId, HashSet<Span>>,
}

impl<'a, 'tcx> MovedVariablesCtxt<'a, 'tcx> {
    fn new(cx: &'a LateContext<'a, 'tcx>) -> Self {
        Self {
            cx: cx,
            moved_vars: HashSet::new(),
            spans_need_deref: HashMap::new(),
        }
    }

    fn move_common(&mut self, _consume_id: NodeId, _span: Span, cmt: mc::cmt<'tcx>) {
        let cmt = unwrap_downcast_or_interior(cmt);

        if let mc::Categorization::Local(vid) = cmt.cat {
            self.moved_vars.insert(vid);
        }
    }

    fn non_moving_pat(&mut self, matched_pat: &Pat, cmt: mc::cmt<'tcx>) {
        let cmt = unwrap_downcast_or_interior(cmt);

        if let mc::Categorization::Local(vid) = cmt.cat {
            let mut id = matched_pat.id;
            loop {
                let parent = self.cx.tcx.hir.get_parent_node(id);
                if id == parent {
                    // no parent
                    return;
                }
                id = parent;

                if let Some(node) = self.cx.tcx.hir.find(id) {
                    match node {
                        map::Node::NodeExpr(e) => {
                            // `match` and `if let`
                            if let ExprMatch(ref c, ..) = e.node {
                                self.spans_need_deref
                                    .entry(vid)
                                    .or_insert_with(HashSet::new)
                                    .insert(c.span);
                            }
                        },

                        map::Node::NodeStmt(s) => {
                            // `let <pat> = x;`
                            if_let_chain! {[
                                let StmtDecl(ref decl, _) = s.node,
                                let DeclLocal(ref local) = decl.node,
                            ], {
                                self.spans_need_deref
                                    .entry(vid)
                                    .or_insert_with(HashSet::new)
                                    .insert(local.init
                                        .as_ref()
                                        .map(|e| e.span)
                                        .expect("`let` stmt without init aren't caught by match_pat"));
                            }}
                        },

                        _ => {},
                    }
                }
            }
        }
    }
}

impl<'a, 'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt<'a, 'tcx> {
    fn consume(&mut self, consume_id: NodeId, consume_span: Span, cmt: mc::cmt<'tcx>, mode: euv::ConsumeMode) {
        if let euv::ConsumeMode::Move(_) = mode {
            self.move_common(consume_id, consume_span, cmt);
        }
    }

    fn matched_pat(&mut self, matched_pat: &Pat, cmt: mc::cmt<'tcx>, mode: euv::MatchMode) {
        if let euv::MatchMode::MovingMatch = mode {
            self.move_common(matched_pat.id, matched_pat.span, cmt);
        } else {
            self.non_moving_pat(matched_pat, cmt);
        }
    }

    fn consume_pat(&mut self, consume_pat: &Pat, cmt: mc::cmt<'tcx>, mode: euv::ConsumeMode) {
        if let euv::ConsumeMode::Move(_) = mode {
            self.move_common(consume_pat.id, consume_pat.span, cmt);
        }
    }

    fn borrow(&mut self, _: NodeId, _: Span, _: mc::cmt<'tcx>, _: ty::Region, _: ty::BorrowKind, _: euv::LoanCause) {}

    fn mutate(&mut self, _: NodeId, _: Span, _: mc::cmt<'tcx>, _: euv::MutateMode) {}

    fn decl_without_init(&mut self, _: NodeId, _: Span) {}
}

fn unwrap_downcast_or_interior(mut cmt: mc::cmt) -> mc::cmt {
    loop {
        match cmt.cat.clone() {
            mc::Categorization::Downcast(c, _) | mc::Categorization::Interior(c, _) => {
                cmt = c;
            },
            _ => return cmt,
        }
    }
}
<commit_msg>Remove intermediate vec<commit_after>use rustc::hir::*;
use rustc::hir::intravisit::FnKind;
use rustc::lint::*;
use rustc::ty::{self, RegionKind, TypeFoldable};
use rustc::traits;
use rustc::middle::expr_use_visitor as euv;
use rustc::middle::mem_categorization as mc;
use syntax::ast::NodeId;
use syntax_pos::Span;
use syntax::errors::DiagnosticBuilder;
use utils::{get_trait_def_id, implements_trait, in_macro, is_copy, is_self, match_type, multispan_sugg, paths,
            snippet, snippet_opt, span_lint_and_then};
use utils::ptr::get_spans;
use std::collections::{HashMap, HashSet};
use std::borrow::Cow;

/// **What it does:** Checks for functions taking arguments by value, but not
/// consuming them in its
/// body.
///
/// **Why is this bad?** Taking arguments by reference is more flexible and can
/// sometimes avoid
/// unnecessary allocations.
///
/// **Known problems:** Hopefully none.
///
/// **Example:**
/// ```rust
/// fn foo(v: Vec<i32>) {
///     assert_eq!(v.len(), 42);
/// }
/// ```
declare_lint! {
    pub NEEDLESS_PASS_BY_VALUE,
    Warn,
    "functions taking arguments by value, but not consuming them in its body"
}

pub struct NeedlessPassByValue;

impl LintPass for NeedlessPassByValue {
    fn get_lints(&self) -> LintArray {
        lint_array![NEEDLESS_PASS_BY_VALUE]
    }
}

macro_rules! need {
    ($e: expr) => { if let Some(x) = $e { x } else { return; } };
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for NeedlessPassByValue {
    fn check_fn(
        &mut self,
        cx: &LateContext<'a, 'tcx>,
        kind: FnKind<'tcx>,
        decl: &'tcx FnDecl,
        body: &'tcx Body,
        span: Span,
        node_id: NodeId,
    ) {
        if in_macro(span) {
            return;
        }

        match kind {
            FnKind::ItemFn(.., attrs) => for a in attrs {
                if_let_chain!{[
                    a.meta_item_list().is_some(),
                    let Some(name) = a.name(),
                    name == "proc_macro_derive",
                ], {
                    return;
                }}
            },
            _ => return,
        }

        // Allow `Borrow` or functions to be taken by value
        let borrow_trait = need!(get_trait_def_id(cx, &paths::BORROW_TRAIT));
        let fn_traits = [
            need!(cx.tcx.lang_items().fn_trait()),
            need!(cx.tcx.lang_items().fn_once_trait()),
            need!(cx.tcx.lang_items().fn_mut_trait()),
        ];

        let sized_trait = need!(cx.tcx.lang_items().sized_trait());

        let fn_def_id = cx.tcx.hir.local_def_id(node_id);

        let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds.to_vec())
            .filter(|p| !p.is_global())
            .filter_map(|pred| if let ty::Predicate::Trait(poly_trait_ref) = pred {
                if poly_trait_ref.def_id() == sized_trait || poly_trait_ref.skip_binder().has_escaping_regions() {
                    return None;
                }
                Some(poly_trait_ref)
            } else {
                None
            })
            .collect::<Vec<_>>();

        // Collect moved variables and spans which will need dereferencings from the
        // function body.
        let MovedVariablesCtxt {
            moved_vars,
            spans_need_deref,
            ..
        } = {
            let mut ctx = MovedVariablesCtxt::new(cx);
            let region_scope_tree = &cx.tcx.region_scope_tree(fn_def_id);
            euv::ExprUseVisitor::new(&mut ctx, cx.tcx, cx.param_env, region_scope_tree, cx.tables).consume_body(body);
            ctx
        };

        let fn_sig = cx.tcx.fn_sig(fn_def_id);
        let fn_sig = cx.tcx.erase_late_bound_regions(&fn_sig);

        for (idx, ((input, &ty), arg)) in decl.inputs
            .iter()
            .zip(fn_sig.inputs())
            .zip(&body.arguments)
            .enumerate()
        {
            // * Exclude a type that is specifically bounded by `Borrow`.
            // * Exclude a type whose reference also fulfills its bound.
            //   (e.g. `std::convert::AsRef`, `serde::Serialize`)
            let (implements_borrow_trait, all_borrowable_trait) = {
                let preds = preds
                    .iter()
                    .filter(|t| t.skip_binder().self_ty() == ty)
                    .collect::<Vec<_>>();

                (
                    preds.iter().any(|t| t.def_id() == borrow_trait),
                    !preds.is_empty() && preds.iter().all(|t| {
                        implements_trait(
                            cx,
                            cx.tcx.mk_imm_ref(&RegionKind::ReErased, ty),
                            t.def_id(),
                            &t.skip_binder().input_types().skip(1).collect::<Vec<_>>(),
                        )
                    }),
                )
            };

            if_let_chain! {[
                !is_self(arg),
                !ty.is_mutable_pointer(),
                !is_copy(cx, ty),
                !fn_traits.iter().any(|&t| implements_trait(cx, ty, t, &[])),
                !implements_borrow_trait,
                !all_borrowable_trait,

                let PatKind::Binding(mode, canonical_id, ..) = arg.pat.node,
                !moved_vars.contains(&canonical_id),
            ], {
                if mode == BindingAnnotation::Mutable || mode == BindingAnnotation::RefMut {
                    continue;
                }

                // Dereference suggestion
                let sugg = |db: &mut DiagnosticBuilder| {
                    let deref_span = spans_need_deref.get(&canonical_id);
                    if_let_chain! {[
                        match_type(cx, ty, &paths::VEC),
                        let Some(clone_spans) =
                            get_spans(cx, Some(body.id()), idx, &[("clone", ".to_owned()")]),
                        let TyPath(QPath::Resolved(_, ref path)) = input.node,
                        let Some(elem_ty) = path.segments.iter()
                            .find(|seg| seg.name == "Vec")
                            .and_then(|ps| ps.parameters.as_ref())
                            .map(|params| &params.types[0]),
                    ], {
                        let slice_ty = format!("&[{}]", snippet(cx, elem_ty.span, "_"));
                        db.span_suggestion(input.span,
                                        "consider changing the type to",
                                        slice_ty);

                        for (span, suggestion) in clone_spans {
                            db.span_suggestion(
                                span,
                                &snippet_opt(cx, span)
                                    .map_or(
                                        "change the call to".into(),
                                        |x| Cow::from(format!("change `{}` to", x)),
                                    ),
                                suggestion.into()
                            );
                        }

                        // cannot be destructured, no need for `*` suggestion
                        assert!(deref_span.is_none());
                        return;
                    }}

                    if match_type(cx, ty, &paths::STRING) {
                        if let Some(clone_spans) =
                            get_spans(cx, Some(body.id()), idx, &[("clone", ".to_string()"), ("as_str", "")]) {
                            db.span_suggestion(input.span, "consider changing the type to", "&str".to_string());

                            for (span, suggestion) in clone_spans {
                                db.span_suggestion(
                                    span,
                                    &snippet_opt(cx, span)
                                        .map_or(
                                            "change the call to".into(),
                                            |x| Cow::from(format!("change `{}` to", x))
                                        ),
                                    suggestion.into(),
                                );
                            }

                            assert!(deref_span.is_none());
                            return;
                        }
                    }

                    let mut spans = vec![(input.span, format!("&{}", snippet(cx, input.span, "_")))];

                    // Suggests adding `*` to dereference the added reference.
                    if let Some(deref_span) = deref_span {
                        spans.extend(
                            deref_span
                                .iter()
                                .cloned()
                                .map(|span| (span, format!("*{}", snippet(cx, span, "<expr>")))),
                        );
                        spans.sort_by_key(|&(span, _)| span);
                    }
                    multispan_sugg(db, "consider taking a reference instead".to_string(), spans);
                };

                span_lint_and_then(
                    cx,
                    NEEDLESS_PASS_BY_VALUE,
                    input.span,
                    "this argument is passed by value, but not consumed in the function body",
                    sugg,
                );
            }}
        }
    }
}

struct MovedVariablesCtxt<'a, 'tcx: 'a> {
    cx: &'a LateContext<'a, 'tcx>,
    moved_vars: HashSet<NodeId>,
    /// Spans which need to be prefixed with `*` for dereferencing the
    /// suggested additional reference.
    spans_need_deref: HashMap<NodeId, HashSet<Span>>,
}

impl<'a, 'tcx> MovedVariablesCtxt<'a, 'tcx> {
    fn new(cx: &'a LateContext<'a, 'tcx>) -> Self {
        Self {
            cx: cx,
            moved_vars: HashSet::new(),
            spans_need_deref: HashMap::new(),
        }
    }

    fn move_common(&mut self, _consume_id: NodeId, _span: Span, cmt: mc::cmt<'tcx>) {
        let cmt = unwrap_downcast_or_interior(cmt);

        if let mc::Categorization::Local(vid) = cmt.cat {
            self.moved_vars.insert(vid);
        }
    }

    fn non_moving_pat(&mut self, matched_pat: &Pat, cmt: mc::cmt<'tcx>) {
        let cmt = unwrap_downcast_or_interior(cmt);

        if let mc::Categorization::Local(vid) = cmt.cat {
            let mut id = matched_pat.id;
            loop {
                let parent = self.cx.tcx.hir.get_parent_node(id);
                if id == parent {
                    // no parent
                    return;
                }
                id = parent;

                if let Some(node) = self.cx.tcx.hir.find(id) {
                    match node {
                        map::Node::NodeExpr(e) => {
                            // `match` and `if let`
                            if let ExprMatch(ref c, ..) = e.node {
                                self.spans_need_deref
                                    .entry(vid)
                                    .or_insert_with(HashSet::new)
                                    .insert(c.span);
                            }
                        },

                        map::Node::NodeStmt(s) => {
                            // `let <pat> = x;`
                            if_let_chain! {[
                                let StmtDecl(ref decl, _) = s.node,
                                let DeclLocal(ref local) = decl.node,
                            ], {
                                self.spans_need_deref
                                    .entry(vid)
                                    .or_insert_with(HashSet::new)
                                    .insert(local.init
                                        .as_ref()
                                        .map(|e| e.span)
                                        .expect("`let` stmt without init aren't caught by match_pat"));
                            }}
                        },

                        _ => {},
                    }
                }
            }
        }
    }
}

impl<'a, 'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt<'a, 'tcx> {
    fn consume(&mut self, consume_id: NodeId, consume_span: Span, cmt: mc::cmt<'tcx>, mode: euv::ConsumeMode) {
        if let euv::ConsumeMode::Move(_) = mode {
            self.move_common(consume_id, consume_span, cmt);
        }
    }

    fn matched_pat(&mut self, matched_pat: &Pat, cmt: mc::cmt<'tcx>, mode: euv::MatchMode) {
        if let euv::MatchMode::MovingMatch = mode {
            self.move_common(matched_pat.id, matched_pat.span, cmt);
        } else {
            self.non_moving_pat(matched_pat, cmt);
        }
    }

    fn consume_pat(&mut self, consume_pat: &Pat, cmt: mc::cmt<'tcx>, mode: euv::ConsumeMode) {
        if let euv::ConsumeMode::Move(_) = mode {
            self.move_common(consume_pat.id, consume_pat.span, cmt);
        }
    }

    fn borrow(&mut self, _: NodeId, _: Span, _: mc::cmt<'tcx>, _: ty::Region, _: ty::BorrowKind, _: euv::LoanCause) {}

    fn mutate(&mut self, _: NodeId, _: Span, _: mc::cmt<'tcx>, _: euv::MutateMode) {}

    fn decl_without_init(&mut self, _: NodeId, _: Span) {}
}

fn unwrap_downcast_or_interior(mut cmt: mc::cmt) -> mc::cmt {
    loop {
        match cmt.cat.clone() {
            mc::Categorization::Downcast(c, _) | mc::Categorization::Interior(c, _) => {
                cmt = c;
            },
            _ => return cmt,
        }
    }
}
<|endoftext|>


<commit_before>use errors;
use std::result;

// see OSC Type Tag String: http://opensoundcontrol.org/spec-1_0
// padding: zero bytes (n*4)

#[derive(Debug)]
pub enum OscType {
    Int(i32),
    Float(f32),
    String(String),
    Blob(Vec<u8>),
    // use struct for time tag to avoid destructuring
    Time(u32, u32),
    Long(i64),
    Double(f64),
    Char(char),
    Color(OscColor),
    Midi(OscMidiMessage),
    Bool(bool),
    Nil,
    Inf,
}

#[derive(Debug)]
pub struct OscMidiMessage {
    pub port: u8,
    pub status: u8,
    pub data1: u8, // maybe use an enum for data?
    pub data2: u8,
}

/// An *osc packet* can contain an *osc message* or a bundle of nested messages
/// which is called *osc bundle*.
#[derive(Debug)]
pub enum OscPacket {
    Message(OscMessage),
    Bundle(OscBundle),
}

#[derive(Debug)]
pub struct OscMessage {
    pub addr: String,
    pub args: Option<Vec<OscType>>,
}

#[derive(Debug)]
pub struct OscBundle {
    pub timetag: OscType,
    pub content: Vec<OscPacket>,
}

#[derive(Debug)]
pub struct OscColor {
    pub red: u8,
    pub green: u8,
    pub blue: u8,
    pub alpha: u8,
}

pub type Result<T> = result::Result<T, errors::OscError>;
<commit_msg>Implement `PartialEq` trait<commit_after>use errors;
use std::result;

// see OSC Type Tag String: http://opensoundcontrol.org/spec-1_0
// padding: zero bytes (n*4)

#[derive(Debug)]
pub enum OscType {
    Int(i32),
    Float(f32),
    String(String),
    Blob(Vec<u8>),
    // use struct for time tag to avoid destructuring
    Time(u32, u32),
    Long(i64),
    Double(f64),
    Char(char),
    Color(OscColor),
    Midi(OscMidiMessage),
    Bool(bool),
    Nil,
    Inf,
}

#[derive(Debug)]
pub struct OscMidiMessage {
    pub port: u8,
    pub status: u8,
    pub data1: u8, // maybe use an enum for data?
    pub data2: u8,
}
impl PartialEq for OscMidiMessage {
    fn eq(&self, other: &Self) -> bool {
        self.port == other.port && self.status == other.status && self.data1 == other.data1 &&
        self.data2 == other.data2
    }
}

/// An *osc packet* can contain an *osc message* or a bundle of nested messages
/// which is called *osc bundle*.
#[derive(Debug)]
pub enum OscPacket {
    Message(OscMessage),
    Bundle(OscBundle),
}
impl PartialEq for OscPacket {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (&OscPacket::Message(ref m1), &OscPacket::Message(ref m2)) => m1 == m2,
            (&OscPacket::Bundle(ref b1), &OscPacket::Bundle(ref b2)) => b1 == b2,
            (_, _) => false,
        }
    }
}

#[derive(Debug)]
pub struct OscMessage {
    pub addr: String,
    pub args: Option<Vec<OscType>>,
}
impl PartialEq for OscMessage {
    fn eq(&self, other: &Self) -> bool {
        (self.addr == other.addr) &&
        match (&self.args, &other.args) {
            (&Some(ref self_args), &Some(ref other_args)) => {
                self_args.iter()
                         .zip(other_args)
                         .map(|(x, y)| {
                             match (x, y) {
                                 (&OscType::Int(x), &OscType::Int(y)) => x == y,
                                 (&OscType::Long(x), &OscType::Long(y)) => x == y,
                                 (&OscType::Float(x), &OscType::Float(y)) => x == y,
                                 (&OscType::Double(x), &OscType::Double(y)) => x == y,
                                 (&OscType::String(ref x), &OscType::String(ref y)) => x == y,
                                 (&OscType::Blob(ref x), &OscType::Blob(ref y)) => x == y,
                                 (&OscType::Time(x_sec, x_frac), &OscType::Time(y_sec, y_frac)) =>
                                     (x_sec, x_frac) == (y_sec, y_frac),
                                 (&OscType::Char(x), &OscType::Char(y)) => x == y,
                                 (&OscType::Bool(x), &OscType::Bool(y)) => x == y,
                                 (&OscType::Midi(ref x), &OscType::Midi(ref y)) => x == y,
                                 (&OscType::Color(ref x), &OscType::Color(ref y)) => x == y,
                                 (&OscType::Inf, &OscType::Inf) => true,
                                 (&OscType::Nil, &OscType::Nil) => true,
                                 (_, _) => false,
                             }
                         })
                         .all(|x| x == true)
            }
            (&None, &None) => true,
            _ => false,
        }
    }
}

#[derive(Debug)]
pub struct OscBundle {
    pub timetag: OscType,
    pub content: Vec<OscPacket>,
}
impl PartialEq for OscBundle {
    fn eq(&self, other: &Self) -> bool {
        self.content.iter().zip(&other.content).map(|(x, y)| x == y).all(|x| x == true) &&
        match (&self.timetag, &other.timetag) {
            (&OscType::Time(self_sec, self_frac),
             &OscType::Time(other_sec, other_frac)) =>
                self_sec == other_sec && self_frac == other_frac,
            (_, _) => false,
        }
    }
}

#[derive(Debug)]
pub struct OscColor {
    pub red: u8,
    pub green: u8,
    pub blue: u8,
    pub alpha: u8,
}
impl PartialEq for OscColor {
    fn eq(&self, other: &Self) -> bool {
        self.red == other.red && self.green == other.green && self.blue == other.blue &&
        self.alpha == other.alpha
    }
}

pub type Result<T> = result::Result<T, errors::OscError>;
<|endoftext|>


<commit_before>//! Viewports and scissor boxes.
//!
//! There are two different concepts to determine where things will be drawn:
//!
//! - The viewport is the region of the image which corresponds to the
//!   vertex coordinates `-1.0` to `1.0`.
//! - Any pixel outside of the scissor box will be discarded.
//!
//! In other words modifying the viewport will stretch the image, while modifying the scissor
//! box acts like a filter.
//!
//! It is legal and sensible to use a viewport that is larger than the target image.
//!
//! # Multiple viewports
//!
//! In most situations, you only need a single viewport and a single scissor box.
//!
//! If, however, you use a geometry shader, you can specify multiple viewports and scissor boxes.
//! Then in your geometry shader you can specify in which viewport and scissor box the primitive
//! should be written to. In GLSL this is done by writing to the special variable
//! `gl_ViewportIndex`.
//!
//! # Dynamic and fixed
//!
//! Vulkan allows four different setups:
//!
//! - The state of both the viewports and scissor boxes is known at pipeline creation.
//! - The state of viewports is known at pipeline creation, but the state of scissor boxes is
//!   only known when submitting the draw command.
//! - The state of scissor boxes is known at pipeline creation, but the state of viewports is
//!   only known when submitting the draw command.
//! - The state of both the viewports and scissor boxes is only known when submitting the
//!   draw command.
//!
//! In all cases the number of viewports and scissor boxes must be the same.
//!
use std::ops::Range;
use vk;

/// List of viewports and scissors that are used when creating a graphics pipeline object.
///
/// Note that the number of viewports and scissors must be the same.
#[derive(Debug, Clone)]
pub enum ViewportsState {
    /// The state is known in advance.
    Fixed {
        /// State of the viewports and scissors.
        data: Vec<(Viewport, Scissor)>,
    },

    /// The state of scissors is known in advance, but the state of viewports is dynamic and will
    /// bet set when drawing.
    ///
    /// Note that the number of viewports and scissors must be the same.
    DynamicViewports {
        /// State of the scissors.
        scissors: Vec<Scissor>,
    },

    /// The state of viewports is known in advance, but the state of scissors is dynamic and will
    /// bet set when drawing.
    ///
    /// Note that the number of viewports and scissors must be the same.
    DynamicScissors {
        /// State of the viewports
        viewports: Vec<Viewport>,
    },

    /// The state of both the viewports and scissors is dynamic and will be set when drawing.
    Dynamic {
        /// Number of viewports and scissors.
        num: u32,
    },
}

impl ViewportsState {
    /// Returns true if the state of the viewports is dynamic.
    pub fn dynamic_viewports(&self) -> bool {
        match *self {
            ViewportsState::Fixed { .. } => false,
            ViewportsState::DynamicViewports { .. } => true,
            ViewportsState::DynamicScissors { .. } => false,
            ViewportsState::Dynamic { .. } => true,
        }
    }

    /// Returns true if the state of the scissors is dynamic.
    pub fn dynamic_scissors(&self) -> bool {
        match *self {
            ViewportsState::Fixed { .. } => false,
            ViewportsState::DynamicViewports { .. } => false,
            ViewportsState::DynamicScissors { .. } => true,
            ViewportsState::Dynamic { .. } => true,
        }
    }

    /// Returns the number of viewports and scissors.
    pub fn num_viewports(&self) -> u32 {
        match *self {
            ViewportsState::Fixed { ref data } => data.len() as u32,
            ViewportsState::DynamicViewports { ref scissors } => scissors.len() as u32,
            ViewportsState::DynamicScissors { ref viewports } => viewports.len() as u32,
            ViewportsState::Dynamic { num } => num,
        }
    }
}

/// State of a single viewport.
// FIXME: check that:
//        x + width must be less than or equal to viewportBoundsRange[0]
//        y + height must be less than or equal to viewportBoundsRange[1]
#[derive(Debug, Clone)]
pub struct Viewport {
    /// Coordinates in pixels of the top-left hand corner of the viewport.
    pub origin: [f32; 2],

    /// Dimensions in pixels of the viewport.
    pub dimensions: [f32; 2],

    /// Minimum and maximum values of the depth.
    ///
    /// The values `-1.0` to `1.0` of each vertex's Z coordinate will be mapped to this
    /// `depth_range` before being compared to the existing depth value.
    ///
    /// This is equivalents to `glDepthRange` in OpenGL.
    pub depth_range: Range<f32>,
}

#[doc(hidden)]
impl Into<vk::Viewport> for Viewport {
    #[inline]
    fn into(self) -> vk::Viewport {
        vk::Viewport {
            x: self.origin[0],
            y: self.origin[1],
            width: self.dimensions[0],
            height: self.dimensions[1],
            minDepth: self.depth_range.start,
            maxDepth: self.depth_range.end,
        }
    }
}

/// State of a single scissor box.
// FIXME: add a check:
//      Evaluation of (offset.x + extent.width) must not cause a signed integer addition overflow
//      Evaluation of (offset.y + extent.height) must not cause a signed integer addition overflow
#[derive(Debug, Copy, Clone)]
pub struct Scissor {
    /// Coordinates in pixels of the top-left hand corner of the box.
    pub origin: [i32; 2],

    /// Dimensions in pixels of the box.
    pub dimensions: [u32; 2],
}

impl Scissor {
    /// Defines a scissor box that it outside of the image.
    #[inline]
    pub fn irrelevant() -> Scissor {
        Scissor {
            origin: [0, 0],
            dimensions: [0x7fffffff, 0x7fffffff],
        }
    }
}

impl Default for Scissor {
    #[inline]
    fn default() -> Scissor {
        Scissor::irrelevant()
    }
}

#[doc(hidden)]
impl Into<vk::Rect2D> for Scissor {
    #[inline]
    fn into(self) -> vk::Rect2D {
        vk::Rect2D {
            offset: vk::Offset2D {
                x: self.origin[0],
                y: self.origin[1],
            },
            extent: vk::Extent2D {
                width: self.dimensions[0],
                height: self.dimensions[1],
            },
        }
    }
}
<commit_msg>More viewport docs<commit_after>//! Viewports and scissor boxes.
//!
//! There are two different concepts to determine where things will be drawn:
//!
//! - The viewport is the region of the image which corresponds to the
//!   vertex coordinates `-1.0` to `1.0`.
//! - Any pixel outside of the scissor box will be discarded.
//!
//! In other words modifying the viewport will stretch the image, while modifying the scissor
//! box acts like a filter.
//!
//! It is legal and sensible to use a viewport that is larger than the target image or that
//! only partially overlaps the target image.
//!
//! # Multiple viewports
//!
//! In most situations, you only need a single viewport and a single scissor box.
//!
//! If, however, you use a geometry shader, you can specify multiple viewports and scissor boxes.
//! Then in your geometry shader you can specify in which viewport and scissor box the primitive
//! should be written to. In GLSL this is done by writing to the special variable
//! `gl_ViewportIndex`.
//!
//! If you don't use a geometry shader or use a geometry shader where don't set which viewport to
//! use, then the first viewport and scissor box will be used.
//!
//! # Dynamic and fixed
//!
//! Vulkan allows four different setups:
//!
//! - The state of both the viewports and scissor boxes is known at pipeline creation.
//! - The state of viewports is known at pipeline creation, but the state of scissor boxes is
//!   only known when submitting the draw command.
//! - The state of scissor boxes is known at pipeline creation, but the state of viewports is
//!   only known when submitting the draw command.
//! - The state of both the viewports and scissor boxes is only known when submitting the
//!   draw command.
//!
//! In all cases the number of viewports and scissor boxes must be the same.
//!
use std::ops::Range;
use vk;

/// List of viewports and scissors that are used when creating a graphics pipeline object.
///
/// Note that the number of viewports and scissors must be the same.
#[derive(Debug, Clone)]
pub enum ViewportsState {
    /// The state is known in advance.
    Fixed {
        /// State of the viewports and scissors.
        data: Vec<(Viewport, Scissor)>,
    },

    /// The state of scissors is known in advance, but the state of viewports is dynamic and will
    /// bet set when drawing.
    ///
    /// Note that the number of viewports and scissors must be the same.
    DynamicViewports {
        /// State of the scissors.
        scissors: Vec<Scissor>,
    },

    /// The state of viewports is known in advance, but the state of scissors is dynamic and will
    /// bet set when drawing.
    ///
    /// Note that the number of viewports and scissors must be the same.
    DynamicScissors {
        /// State of the viewports
        viewports: Vec<Viewport>,
    },

    /// The state of both the viewports and scissors is dynamic and will be set when drawing.
    Dynamic {
        /// Number of viewports and scissors.
        num: u32,
    },
}

impl ViewportsState {
    /// Returns true if the state of the viewports is dynamic.
    pub fn dynamic_viewports(&self) -> bool {
        match *self {
            ViewportsState::Fixed { .. } => false,
            ViewportsState::DynamicViewports { .. } => true,
            ViewportsState::DynamicScissors { .. } => false,
            ViewportsState::Dynamic { .. } => true,
        }
    }

    /// Returns true if the state of the scissors is dynamic.
    pub fn dynamic_scissors(&self) -> bool {
        match *self {
            ViewportsState::Fixed { .. } => false,
            ViewportsState::DynamicViewports { .. } => false,
            ViewportsState::DynamicScissors { .. } => true,
            ViewportsState::Dynamic { .. } => true,
        }
    }

    /// Returns the number of viewports and scissors.
    pub fn num_viewports(&self) -> u32 {
        match *self {
            ViewportsState::Fixed { ref data } => data.len() as u32,
            ViewportsState::DynamicViewports { ref scissors } => scissors.len() as u32,
            ViewportsState::DynamicScissors { ref viewports } => viewports.len() as u32,
            ViewportsState::Dynamic { num } => num,
        }
    }
}

/// State of a single viewport.
// FIXME: check that:
//        x + width must be less than or equal to viewportBoundsRange[0]
//        y + height must be less than or equal to viewportBoundsRange[1]
#[derive(Debug, Clone)]
pub struct Viewport {
    /// Coordinates in pixels of the top-left hand corner of the viewport.
    pub origin: [f32; 2],

    /// Dimensions in pixels of the viewport.
    pub dimensions: [f32; 2],

    /// Minimum and maximum values of the depth.
    ///
    /// The values `-1.0` to `1.0` of each vertex's Z coordinate will be mapped to this
    /// `depth_range` before being compared to the existing depth value.
    ///
    /// This is equivalents to `glDepthRange` in OpenGL.
    pub depth_range: Range<f32>,
}

#[doc(hidden)]
impl Into<vk::Viewport> for Viewport {
    #[inline]
    fn into(self) -> vk::Viewport {
        vk::Viewport {
            x: self.origin[0],
            y: self.origin[1],
            width: self.dimensions[0],
            height: self.dimensions[1],
            minDepth: self.depth_range.start,
            maxDepth: self.depth_range.end,
        }
    }
}

/// State of a single scissor box.
// FIXME: add a check:
//      Evaluation of (offset.x + extent.width) must not cause a signed integer addition overflow
//      Evaluation of (offset.y + extent.height) must not cause a signed integer addition overflow
#[derive(Debug, Copy, Clone)]
pub struct Scissor {
    /// Coordinates in pixels of the top-left hand corner of the box.
    pub origin: [i32; 2],

    /// Dimensions in pixels of the box.
    pub dimensions: [u32; 2],
}

impl Scissor {
    /// Defines a scissor box that it outside of the image.
    #[inline]
    pub fn irrelevant() -> Scissor {
        Scissor {
            origin: [0, 0],
            dimensions: [0x7fffffff, 0x7fffffff],
        }
    }
}

impl Default for Scissor {
    #[inline]
    fn default() -> Scissor {
        Scissor::irrelevant()
    }
}

#[doc(hidden)]
impl Into<vk::Rect2D> for Scissor {
    #[inline]
    fn into(self) -> vk::Rect2D {
        vk::Rect2D {
            offset: vk::Offset2D {
                x: self.origin[0],
                y: self.origin[1],
            },
            extent: vk::Extent2D {
                width: self.dimensions[0],
                height: self.dimensions[1],
            },
        }
    }
}
<|endoftext|>


<commit_before>use std::num;

pub trait Addressable<ADDR: Int, DATA: Int> {
	pub fn get (&self, addr: ADDR) -> DATA;
}

// FIXME: With default methods, we won't need this anymore
trait AddressableUtil<ADDR: Int, DATA: Int> {
	pub fn get_be<T: Int> (&self, addr: ADDR) -> T;
	pub fn get_le<T: Int> (&self, addr: ADDR) -> T;
}

impl<ADDR: Int+Copy, DATA: Int, A: Addressable<ADDR, DATA>> AddressableUtil<ADDR, DATA> for A {
	pub fn get_be<T: Int> (&self, addr: ADDR) -> T {
		assert!(num::Primitive::bits::<T>() % num::Primitive::bits::<DATA>() == 0);
		let count = num::Primitive::bits::<T>() / num::Primitive::bits::<DATA>();
		let mut val = num::Zero::zero::<T>();
		let mut i = count;
		while i > 0 {
			i -= 1;
			let d: T = num::cast(self.get(addr + num::cast(i)));
			let shift: T = num::cast((count-i-1) * num::Primitive::bits::<DATA>());
			val = val + (d << shift);
		}
		val
	}

	pub fn get_le<T: Int> (&self, addr: ADDR) -> T {
		assert!(num::Primitive::bits::<T>() % num::Primitive::bits::<DATA>() == 0);
		let count = num::Primitive::bits::<T>() / num::Primitive::bits::<DATA>();
		let mut val = num::Zero::zero::<T>();
		let mut i = count;
		while i > 0 {
			i -= 1;
			let d: T = num::cast(self.get(addr + num::cast(i)));
			let shift: T = num::cast(i * num::Primitive::bits::<DATA>());
			val = val + (d << shift);
		}
		val
	}
}

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

	struct DummyData;
	impl Addressable<u16, u8> for DummyData {
		pub fn get (&self, addr: u16) -> u8 {
			addr as u8
		}
	}

	#[test]
	fn test_get () {
		let data = DummyData;
		assert_eq!(data.get(123), 123);
		assert_eq!(data.get(1234), 210);
	}

	#[test]
	fn test_get_big_endian () {
		let data = DummyData;
		assert_eq!(         2u8 , data.get_be(  2u16));
		assert_eq!(       123u8 , data.get_be(123u16));
		assert_eq!(       515u16, data.get_be(  2u16));		//   2<<8 |   3
		assert_eq!(     31612u16, data.get_be(123u16));		// 123<<8 | 124
		assert_eq!(  33752069u32, data.get_be(  2u16));		//   2<<24 |   3<<16 |   4<<8 |   5
		assert_eq!(2071756158u32, data.get_be(123u16));		// 123<<24 | 124<<16 | 125<<8 | 126
	}

	#[test]
	fn test_get_little_endian () {
		let data = DummyData;
		assert_eq!(         2u8 , data.get_le(  2u16));
		assert_eq!(       123u8 , data.get_le(123u16));
		assert_eq!(       770u16, data.get_le(  2u16));		//   2 |   3<<8
		assert_eq!(     31867u16, data.get_le(123u16));		// 123 | 124<<8
		assert_eq!(  84148994u32, data.get_le(  2u16));		//   2 |   3<<8 |   4<<16 |   5<<24
		assert_eq!(2122153083u32, data.get_le(123u16));		// 123 | 124<<8 | 125<<16 | 126<<24
	}
}
<commit_msg>Refactored little/big endian tests to use better readable hex values<commit_after>use std::num;

pub trait Addressable<ADDR: Int, DATA: Int> {
	pub fn get (&self, addr: ADDR) -> DATA;
}

// FIXME: With default methods, we won't need this anymore
trait AddressableUtil<ADDR: Int, DATA: Int> {
	pub fn get_be<T: Int> (&self, addr: ADDR) -> T;
	pub fn get_le<T: Int> (&self, addr: ADDR) -> T;
}

impl<ADDR: Int+Copy, DATA: Int, A: Addressable<ADDR, DATA>> AddressableUtil<ADDR, DATA> for A {
	pub fn get_be<T: Int> (&self, addr: ADDR) -> T {
		assert!(num::Primitive::bits::<T>() % num::Primitive::bits::<DATA>() == 0);
		let count = num::Primitive::bits::<T>() / num::Primitive::bits::<DATA>();
		let mut val = num::Zero::zero::<T>();
		let mut i = count;
		while i > 0 {
			i -= 1;
			let d: T = num::cast(self.get(addr + num::cast(i)));
			let shift: T = num::cast((count-i-1) * num::Primitive::bits::<DATA>());
			val = val + (d << shift);
		}
		val
	}

	pub fn get_le<T: Int> (&self, addr: ADDR) -> T {
		assert!(num::Primitive::bits::<T>() % num::Primitive::bits::<DATA>() == 0);
		let count = num::Primitive::bits::<T>() / num::Primitive::bits::<DATA>();
		let mut val = num::Zero::zero::<T>();
		let mut i = count;
		while i > 0 {
			i -= 1;
			let d: T = num::cast(self.get(addr + num::cast(i)));
			let shift: T = num::cast(i * num::Primitive::bits::<DATA>());
			val = val + (d << shift);
		}
		val
	}
}

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

	struct DummyData;
	impl Addressable<u16, u8> for DummyData {
		pub fn get (&self, addr: u16) -> u8 {
			addr as u8
		}
	}

	#[test]
	fn test_get () {
		let data = DummyData;
		assert_eq!(data.get(0x12), 0x12);
		assert_eq!(data.get(0x1234), 0x34);
	}

	#[test]
	fn test_get_big_endian () {
		let data = DummyData;
		assert_eq!(      0x02_u8 , data.get_be(0x0002_u16));
		assert_eq!(      0x54_u8 , data.get_be(0x0054_u16));
		assert_eq!(    0x0203_u16, data.get_be(0x0002_u16));
		assert_eq!(    0x5455_u16, data.get_be(0x0054_u16));
		assert_eq!(0x02030405_u32, data.get_be(0x0002_u16));
		assert_eq!(0x54555657_u32, data.get_be(0x0054_u16));
	}

	#[test]
	fn test_get_little_endian () {
		let data = DummyData;
		assert_eq!(      0x02_u8 , data.get_le(0x0002_u16));
		assert_eq!(      0x54_u8 , data.get_le(0x0054_u16));
		assert_eq!(    0x0302_u16, data.get_le(0x0002_u16));
		assert_eq!(    0x5554_u16, data.get_le(0x0054_u16));
		assert_eq!(0x05040302_u32, data.get_le(0x0002_u16));
		assert_eq!(0x57565554_u32, data.get_le(0x0054_u16));
	}
}
<|endoftext|>