<commit_before>/*
Copyright (c) 2016-2017, Robert Ou <rqou@robertou.com> and contributors
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

//! Xilinx JED file I/O

use std::error;
use std::error::Error;
use std::fmt;
use std::num;
use std::num::Wrapping;
use std::str;

/// Errors that can occur when parsing a .jed file
#[derive(Debug, PartialEq, Eq)]
pub enum JedParserError {
    /// No STX byte found
    MissingSTX,
    /// No ETX byte found
    MissingETX,
    /// An invalid UTF-8 sequence occurred
    InvalidUtf8(str::Utf8Error),
    /// A field contains a character not appropriate for that field (e.g. non-hex digit in a hex field)
    InvalidCharacter,
    /// An unexpected end of file was encountered in the file checksum
    UnexpectedEnd,
    /// The file checksum was nonzero and incorrect
    BadFileChecksum,
    /// The fuse checksum (`C` command) was incorrect
    BadFuseChecksum,
    /// A `L` field index was out of range
    InvalidFuseIndex,
    /// There was no `QF` field
    MissingQF,
    /// There was no `F` field, but not all fuses had a value specified
    MissingF,
    /// There was a field that this program does not recognize
    UnrecognizedField,
}

impl error::Error for JedParserError {
    fn description(&self) -> &'static str {
        match *self {
            JedParserError::MissingSTX => "STX not found",
            JedParserError::MissingETX => "ETX not found",
            JedParserError::InvalidUtf8(_) => "invalid utf8 character",
            JedParserError::InvalidCharacter => "invalid character in field",
            JedParserError::UnexpectedEnd => "unexpected end of file",
            JedParserError::BadFileChecksum => "invalid file checksum",
            JedParserError::BadFuseChecksum => "invalid fuse checksum",
            JedParserError::InvalidFuseIndex => "invalid fuse index value",
            JedParserError::MissingQF => "missing QF field",
            JedParserError::MissingF => "missing F field",
            JedParserError::UnrecognizedField => "unrecognized field",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            JedParserError::MissingSTX => None,
            JedParserError::MissingETX => None,
            JedParserError::InvalidUtf8(ref err) => Some(err),
            JedParserError::InvalidCharacter => None,
            JedParserError::UnexpectedEnd => None,
            JedParserError::BadFileChecksum => None,
            JedParserError::BadFuseChecksum => None,
            JedParserError::InvalidFuseIndex => None,
            JedParserError::MissingQF => None,
            JedParserError::MissingF => None,
            JedParserError::UnrecognizedField => None,
        }
    }
}

impl fmt::Display for JedParserError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(cause) = self.cause() {
            write!(f, "{}: {}", self.description(), cause)
        } else {
            write!(f, "{}", self.description())
        }
    }
}

impl From<str::Utf8Error> for JedParserError {
    fn from(err: str::Utf8Error) -> Self {
        JedParserError::InvalidUtf8(err)
    }
}

impl From<num::ParseIntError> for JedParserError {
    fn from(_: num::ParseIntError) -> Self {
        JedParserError::InvalidCharacter
    }
}

#[derive(Eq, PartialEq, Copy, Clone)]
enum Ternary {
    Zero,
    One,
    Undef,
}

const STX: u8 = 0x02;
const ETX: u8 = 0x03;

/// Reads .jed file and outputs the fuses as an array of booleans and optional device name
pub fn read_jed(in_bytes: &[u8]) -> Result<(Vec<bool>, Option<String>), JedParserError> {
    let mut fuse_csum = Wrapping(0u16);
    let mut fuse_expected_csum = None;
    let mut file_csum = Wrapping(0u16);
    let mut num_fuses: u32 = 0;
    let mut device = None;
    let mut jed_stx: usize = 0;
    let mut jed_etx: usize;
    let mut fuses_ternary = vec![];
    let mut default_fuse = Ternary::Undef;

    // Find STX
    while in_bytes[jed_stx] != STX {
        jed_stx += 1;
        if jed_stx >= in_bytes.len() {
            return Err(JedParserError::MissingSTX);
        }
    }

    // Checksum and find ETX
    jed_etx = jed_stx;
    while in_bytes[jed_etx] != ETX {
        file_csum += Wrapping(in_bytes[jed_etx] as u16);
        jed_etx += 1;
        if jed_etx >= in_bytes.len() {
            return Err(JedParserError::MissingETX);
        }
    }
    // Add the ETX to the checksum too
    file_csum += Wrapping(ETX as u16);

    // Check the checksum
    if jed_etx + 4 >= in_bytes.len() {
        return Err(JedParserError::UnexpectedEnd);
    }
    let csum_expected = &in_bytes[jed_etx + 1..jed_etx + 5];
    let csum_expected = str::from_utf8(csum_expected)?;
    let csum_expected = u16::from_str_radix(csum_expected, 16)?;
    if csum_expected != 0 && csum_expected != file_csum.0 {
        return Err(JedParserError::BadFileChecksum);
    }

    // Make a str object out of the body
    let jed_body = str::from_utf8(&in_bytes[jed_stx + 1..jed_etx])?;

    // Ready to parse each line
    for l in jed_body.split('*') {
        let l = l.trim_matches(|c| c == ' ' || c == '\r' || c == '\n');
        if l.len() == 0 {
            // FIXME: Should we do something else here?
            // ignore empty fields
            continue;
        }

        // Now we can look at the first byte to figure out what we have
        match l.chars().next().unwrap() {
            'X' | 'J' => {}, // Do nothing, don't care about these
            'F' => {
                // Default state
                let (_, default_state_str) = l.split_at(1);
                default_fuse = match default_state_str {
                    "0" => Ternary::Zero,
                    "1" => Ternary::One,
                    _ => return Err(JedParserError::InvalidCharacter)
                }
            },
            'N' => {
                // Notes; we want to extract N DEVICE but otherwise ignore it
                let note_pieces = l.split(|c| c == ' ' || c == '\r' || c == '\n').collect::<Vec<_>>();
                if note_pieces.len() == 3 && note_pieces[1] == "DEVICE" {
                    device = Some(note_pieces[2].to_owned());
                }
            },
            'Q' => {
                // Look for QF
                if l.starts_with("QF") {
                    let (_, num_fuses_str) = l.split_at(2);
                    num_fuses = u32::from_str_radix(num_fuses_str, 10)?;
                    fuses_ternary.reserve(num_fuses as usize);
                    for _ in 0..num_fuses {
                        fuses_ternary.push(Ternary::Undef);
                    }
                }
            },
            'L' => {
                // A set of fuses
                if num_fuses == 0 {
                    return Err(JedParserError::MissingQF);
                }

                let mut fuse_field_splitter = l.splitn(2, |c| c == ' ' || c == '\r' || c == '\n');
                let fuse_idx_str = fuse_field_splitter.next();
                let (_, fuse_idx_str) = fuse_idx_str.unwrap().split_at(1);
                let mut fuse_idx = u32::from_str_radix(fuse_idx_str, 10)?;

                let fuse_bits_part = fuse_field_splitter.next();
                if fuse_bits_part.is_none() {
                    return Err(JedParserError::InvalidFuseIndex);
                }
                let fuse_bits_part = fuse_bits_part.unwrap();
                for fuse in fuse_bits_part.chars() {
                    match fuse {
                        '0' => {
                            if fuse_idx >= num_fuses {
                                return Err(JedParserError::InvalidFuseIndex);
                            }
                            fuses_ternary[fuse_idx as usize] = Ternary::Zero;
                            fuse_idx += 1;
                        },
                        '1' => {
                            if fuse_idx >= num_fuses {
                                return Err(JedParserError::InvalidFuseIndex);
                            }
                            fuses_ternary[fuse_idx as usize] = Ternary::One;
                            fuse_idx += 1;
                        },
                        ' ' | '\r' | '\n' => {}, // Do nothing
                        _ => return Err(JedParserError::InvalidCharacter),
                    }
                }
            },
            'C' => {
                // Checksum
                let (_, csum_str) = l.split_at(1);
                if csum_str.len() != 4 {
                    return Err(JedParserError::BadFuseChecksum);
                }
                fuse_expected_csum = Some(u16::from_str_radix(csum_str, 16)?);
            }
            _ => return Err(JedParserError::UnrecognizedField),
        }
    }

    // Fill in the default values
    for x in &mut fuses_ternary {
        if *x == Ternary::Undef {
            // There cannot be undefined fuses if there isn't an F field
            if default_fuse == Ternary::Undef {
                return Err(JedParserError::MissingF)
            }

            *x = default_fuse;
        }
    }

    // Un-ternary it
    let fuses = fuses_ternary.iter().map(|&x| match x {
        Ternary::Zero => false,
        Ternary::One => true,
        _ => unreachable!(),
    }).collect::<Vec<_>>();

    // Fuse checksum
    if let Some(fuse_expected_csum) = fuse_expected_csum {
        for i in 0..num_fuses {
            if fuses[i as usize] {
                // Fuse is a 1 and contributes to the sum
                fuse_csum += Wrapping(1u16 << (i % 8));
            }
        }

        if fuse_expected_csum != fuse_csum.0 {
            return Err(JedParserError::BadFuseChecksum);
        }
    }

    Ok((fuses, device))
}

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

    #[test]
    fn read_no_stx() {
        let ret = read_jed(b"asdf");

        assert_eq!(ret, Err(JedParserError::MissingSTX));
    }

    #[test]
    fn read_no_etx() {
        let ret = read_jed(b"asdf\x02fdsa");

        assert_eq!(ret, Err(JedParserError::MissingETX));
    }

    #[test]
    fn read_no_csum() {
        let ret = read_jed(b"asdf\x02fdsa\x03");
        assert_eq!(ret, Err(JedParserError::UnexpectedEnd));

        let ret = read_jed(b"asdf\x02fdsa\x03AAA");
        assert_eq!(ret, Err(JedParserError::UnexpectedEnd));
    }

    #[test]
    fn read_bad_csum() {
        let ret = read_jed(b"asdf\x02fdsa\x03AAAA");

        assert_eq!(ret, Err(JedParserError::BadFileChecksum));
    }

    #[test]
    fn read_malformed_csum() {
        let ret = read_jed(b"asdf\x02fdsa\x03AAAZ");

        assert_eq!(ret, Err(JedParserError::InvalidCharacter));
    }

    #[test]
    fn read_no_f() {
        let ret = read_jed(b"\x02QF1*\x030000");

        assert_eq!(ret, Err(JedParserError::MissingF));
    }

    #[test]
    fn read_empty_no_fuses() {
        let ret = read_jed(b"\x02F0*\x030000");

        assert_eq!(ret, Ok((vec![], None)));
    }

    #[test]
    fn read_bogus_f_command() {
        let ret = read_jed(b"\x02F2*\x030000");

        assert_eq!(ret, Err(JedParserError::InvalidCharacter));
    }

    #[test]
    fn read_empty_with_device() {
        let ret = read_jed(b"\x02F0*N DEVICE asdf*\x030000");

        assert_eq!(ret, Ok((vec![], Some(String::from("asdf")))));
    }

    #[test]
    fn read_l_without_qf() {
        let ret = read_jed(b"\x02F0*L0 0*\x030000");

        assert_eq!(ret, Err(JedParserError::MissingQF));
    }

    #[test]
    fn read_one_fuse() {
        let ret = read_jed(b"\x02F0*QF1*L0 1*\x030000");

        assert_eq!(ret, Ok((vec![true], None)));
    }

    #[test]
    fn read_one_fuse_csum_good() {
        let ret = read_jed(b"\x02F0*QF1*L0 1*C0001*\x030000");

        assert_eq!(ret, Ok((vec![true], None)));
    }

    #[test]
    fn read_one_fuse_csum_bad() {
        let ret = read_jed(b"\x02F0*QF1*L0 1*C0002*\x030000");

        assert_eq!(ret, Err(JedParserError::BadFuseChecksum));
    }

    #[test]
    fn read_two_fuses_space() {
        let ret = read_jed(b"\x02F0*QF2*L0 0 1*\x030000");

        assert_eq!(ret, Ok((vec![false, true], None)));
    }
}
<commit_msg>jedec: "Support" (ignore) more field types<commit_after>/*
Copyright (c) 2016-2017, Robert Ou <rqou@robertou.com> and contributors
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

//! Xilinx JED file I/O

use std::error;
use std::error::Error;
use std::fmt;
use std::num;
use std::num::Wrapping;
use std::str;

/// Errors that can occur when parsing a .jed file
#[derive(Debug, PartialEq, Eq)]
pub enum JedParserError {
    /// No STX byte found
    MissingSTX,
    /// No ETX byte found
    MissingETX,
    /// An invalid UTF-8 sequence occurred
    InvalidUtf8(str::Utf8Error),
    /// A field contains a character not appropriate for that field (e.g. non-hex digit in a hex field)
    InvalidCharacter,
    /// An unexpected end of file was encountered in the file checksum
    UnexpectedEnd,
    /// The file checksum was nonzero and incorrect
    BadFileChecksum,
    /// The fuse checksum (`C` command) was incorrect
    BadFuseChecksum,
    /// A `L` field index was out of range
    InvalidFuseIndex,
    /// There was no `QF` field
    MissingQF,
    /// There was no `F` field, but not all fuses had a value specified
    MissingF,
    /// There was a field that this program does not recognize
    UnrecognizedField,
}

impl error::Error for JedParserError {
    fn description(&self) -> &'static str {
        match *self {
            JedParserError::MissingSTX => "STX not found",
            JedParserError::MissingETX => "ETX not found",
            JedParserError::InvalidUtf8(_) => "invalid utf8 character",
            JedParserError::InvalidCharacter => "invalid character in field",
            JedParserError::UnexpectedEnd => "unexpected end of file",
            JedParserError::BadFileChecksum => "invalid file checksum",
            JedParserError::BadFuseChecksum => "invalid fuse checksum",
            JedParserError::InvalidFuseIndex => "invalid fuse index value",
            JedParserError::MissingQF => "missing QF field",
            JedParserError::MissingF => "missing F field",
            JedParserError::UnrecognizedField => "unrecognized field",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            JedParserError::MissingSTX => None,
            JedParserError::MissingETX => None,
            JedParserError::InvalidUtf8(ref err) => Some(err),
            JedParserError::InvalidCharacter => None,
            JedParserError::UnexpectedEnd => None,
            JedParserError::BadFileChecksum => None,
            JedParserError::BadFuseChecksum => None,
            JedParserError::InvalidFuseIndex => None,
            JedParserError::MissingQF => None,
            JedParserError::MissingF => None,
            JedParserError::UnrecognizedField => None,
        }
    }
}

impl fmt::Display for JedParserError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(cause) = self.cause() {
            write!(f, "{}: {}", self.description(), cause)
        } else {
            write!(f, "{}", self.description())
        }
    }
}

impl From<str::Utf8Error> for JedParserError {
    fn from(err: str::Utf8Error) -> Self {
        JedParserError::InvalidUtf8(err)
    }
}

impl From<num::ParseIntError> for JedParserError {
    fn from(_: num::ParseIntError) -> Self {
        JedParserError::InvalidCharacter
    }
}

#[derive(Eq, PartialEq, Copy, Clone)]
enum Ternary {
    Zero,
    One,
    Undef,
}

const STX: u8 = 0x02;
const ETX: u8 = 0x03;

/// Reads .jed file and outputs the fuses as an array of booleans and optional device name
pub fn read_jed(in_bytes: &[u8]) -> Result<(Vec<bool>, Option<String>), JedParserError> {
    let mut fuse_csum = Wrapping(0u16);
    let mut fuse_expected_csum = None;
    let mut file_csum = Wrapping(0u16);
    let mut num_fuses: u32 = 0;
    let mut device = None;
    let mut jed_stx: usize = 0;
    let mut jed_etx: usize;
    let mut fuses_ternary = vec![];
    let mut default_fuse = Ternary::Undef;

    // Find STX
    while in_bytes[jed_stx] != STX {
        jed_stx += 1;
        if jed_stx >= in_bytes.len() {
            return Err(JedParserError::MissingSTX);
        }
    }

    // Checksum and find ETX
    jed_etx = jed_stx;
    while in_bytes[jed_etx] != ETX {
        file_csum += Wrapping(in_bytes[jed_etx] as u16);
        jed_etx += 1;
        if jed_etx >= in_bytes.len() {
            return Err(JedParserError::MissingETX);
        }
    }
    // Add the ETX to the checksum too
    file_csum += Wrapping(ETX as u16);

    // Check the checksum
    if jed_etx + 4 >= in_bytes.len() {
        return Err(JedParserError::UnexpectedEnd);
    }
    let csum_expected = &in_bytes[jed_etx + 1..jed_etx + 5];
    let csum_expected = str::from_utf8(csum_expected)?;
    let csum_expected = u16::from_str_radix(csum_expected, 16)?;
    if csum_expected != 0 && csum_expected != file_csum.0 {
        return Err(JedParserError::BadFileChecksum);
    }

    // Make a str object out of the body
    let jed_body = str::from_utf8(&in_bytes[jed_stx + 1..jed_etx])?;

    // Ready to parse each line
    for l in jed_body.split('*') {
        let l = l.trim_matches(|c| c == ' ' || c == '\r' || c == '\n');
        if l.len() == 0 {
            // FIXME: Should we do something else here?
            // ignore empty fields
            continue;
        }

        // Now we can look at the first byte to figure out what we have
        match l.chars().next().unwrap() {
            'J' => {}, // TODO: "Official" device type
            'G' => {}, // TODO: Security fuse
            'B' | 'I' | 'K' | 'M' | 'O' | 'W' | 'Y' | 'Z' => {}, // Explicitly reserved in spec, ignore
            'D' => {}, // Obsolete
            'E' | 'U' => {}, // TODO: Extra fuses, unsupported for now
            'X' | 'V' | 'P' | 'S' | 'R' | 'T' | 'A' => {}, // Testing-related, no intent to support for now
            'F' => {
                // Default state
                let (_, default_state_str) = l.split_at(1);
                default_fuse = match default_state_str {
                    "0" => Ternary::Zero,
                    "1" => Ternary::One,
                    _ => return Err(JedParserError::InvalidCharacter)
                }
            },
            'N' => {
                // Notes; we want to extract N DEVICE but otherwise ignore it
                let note_pieces = l.split(|c| c == ' ' || c == '\r' || c == '\n').collect::<Vec<_>>();
                if note_pieces.len() == 3 && note_pieces[1] == "DEVICE" {
                    device = Some(note_pieces[2].to_owned());
                }
            },
            'Q' => {
                // Look for QF
                if l.starts_with("QF") {
                    let (_, num_fuses_str) = l.split_at(2);
                    num_fuses = u32::from_str_radix(num_fuses_str, 10)?;
                    fuses_ternary.reserve(num_fuses as usize);
                    for _ in 0..num_fuses {
                        fuses_ternary.push(Ternary::Undef);
                    }
                }
            },
            'L' => {
                // A set of fuses
                if num_fuses == 0 {
                    return Err(JedParserError::MissingQF);
                }

                let mut fuse_field_splitter = l.splitn(2, |c| c == ' ' || c == '\r' || c == '\n');
                let fuse_idx_str = fuse_field_splitter.next();
                let (_, fuse_idx_str) = fuse_idx_str.unwrap().split_at(1);
                let mut fuse_idx = u32::from_str_radix(fuse_idx_str, 10)?;

                let fuse_bits_part = fuse_field_splitter.next();
                if fuse_bits_part.is_none() {
                    return Err(JedParserError::InvalidFuseIndex);
                }
                let fuse_bits_part = fuse_bits_part.unwrap();
                for fuse in fuse_bits_part.chars() {
                    match fuse {
                        '0' => {
                            if fuse_idx >= num_fuses {
                                return Err(JedParserError::InvalidFuseIndex);
                            }
                            fuses_ternary[fuse_idx as usize] = Ternary::Zero;
                            fuse_idx += 1;
                        },
                        '1' => {
                            if fuse_idx >= num_fuses {
                                return Err(JedParserError::InvalidFuseIndex);
                            }
                            fuses_ternary[fuse_idx as usize] = Ternary::One;
                            fuse_idx += 1;
                        },
                        ' ' | '\r' | '\n' => {}, // Do nothing
                        _ => return Err(JedParserError::InvalidCharacter),
                    }
                }
            },
            'C' => {
                // Checksum
                let (_, csum_str) = l.split_at(1);
                if csum_str.len() != 4 {
                    return Err(JedParserError::BadFuseChecksum);
                }
                fuse_expected_csum = Some(u16::from_str_radix(csum_str, 16)?);
            }
            _ => return Err(JedParserError::UnrecognizedField),
        }
    }

    // Fill in the default values
    for x in &mut fuses_ternary {
        if *x == Ternary::Undef {
            // There cannot be undefined fuses if there isn't an F field
            if default_fuse == Ternary::Undef {
                return Err(JedParserError::MissingF)
            }

            *x = default_fuse;
        }
    }

    // Un-ternary it
    let fuses = fuses_ternary.iter().map(|&x| match x {
        Ternary::Zero => false,
        Ternary::One => true,
        _ => unreachable!(),
    }).collect::<Vec<_>>();

    // Fuse checksum
    if let Some(fuse_expected_csum) = fuse_expected_csum {
        for i in 0..num_fuses {
            if fuses[i as usize] {
                // Fuse is a 1 and contributes to the sum
                fuse_csum += Wrapping(1u16 << (i % 8));
            }
        }

        if fuse_expected_csum != fuse_csum.0 {
            return Err(JedParserError::BadFuseChecksum);
        }
    }

    Ok((fuses, device))
}

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

    #[test]
    fn read_no_stx() {
        let ret = read_jed(b"asdf");

        assert_eq!(ret, Err(JedParserError::MissingSTX));
    }

    #[test]
    fn read_no_etx() {
        let ret = read_jed(b"asdf\x02fdsa");

        assert_eq!(ret, Err(JedParserError::MissingETX));
    }

    #[test]
    fn read_no_csum() {
        let ret = read_jed(b"asdf\x02fdsa\x03");
        assert_eq!(ret, Err(JedParserError::UnexpectedEnd));

        let ret = read_jed(b"asdf\x02fdsa\x03AAA");
        assert_eq!(ret, Err(JedParserError::UnexpectedEnd));
    }

    #[test]
    fn read_bad_csum() {
        let ret = read_jed(b"asdf\x02fdsa\x03AAAA");

        assert_eq!(ret, Err(JedParserError::BadFileChecksum));
    }

    #[test]
    fn read_malformed_csum() {
        let ret = read_jed(b"asdf\x02fdsa\x03AAAZ");

        assert_eq!(ret, Err(JedParserError::InvalidCharacter));
    }

    #[test]
    fn read_no_f() {
        let ret = read_jed(b"\x02QF1*\x030000");

        assert_eq!(ret, Err(JedParserError::MissingF));
    }

    #[test]
    fn read_empty_no_fuses() {
        let ret = read_jed(b"\x02F0*\x030000");

        assert_eq!(ret, Ok((vec![], None)));
    }

    #[test]
    fn read_bogus_f_command() {
        let ret = read_jed(b"\x02F2*\x030000");

        assert_eq!(ret, Err(JedParserError::InvalidCharacter));
    }

    #[test]
    fn read_empty_with_device() {
        let ret = read_jed(b"\x02F0*N DEVICE asdf*\x030000");

        assert_eq!(ret, Ok((vec![], Some(String::from("asdf")))));
    }

    #[test]
    fn read_l_without_qf() {
        let ret = read_jed(b"\x02F0*L0 0*\x030000");

        assert_eq!(ret, Err(JedParserError::MissingQF));
    }

    #[test]
    fn read_one_fuse() {
        let ret = read_jed(b"\x02F0*QF1*L0 1*\x030000");

        assert_eq!(ret, Ok((vec![true], None)));
    }

    #[test]
    fn read_one_fuse_csum_good() {
        let ret = read_jed(b"\x02F0*QF1*L0 1*C0001*\x030000");

        assert_eq!(ret, Ok((vec![true], None)));
    }

    #[test]
    fn read_one_fuse_csum_bad() {
        let ret = read_jed(b"\x02F0*QF1*L0 1*C0002*\x030000");

        assert_eq!(ret, Err(JedParserError::BadFuseChecksum));
    }

    #[test]
    fn read_two_fuses_space() {
        let ret = read_jed(b"\x02F0*QF2*L0 0 1*\x030000");

        assert_eq!(ret, Ok((vec![false, true], None)));
    }
}
<|endoftext|>


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

extern crate capnp;

use std::{env, process, time};

fn run_one(executable: &str, case: &str, mode: &str, scratch: &str, compression: &str, iteration_count: u64) {
    let mut command = process::Command::new(executable);
    command.arg(case)
        .arg(mode)
        .arg(scratch)
        .arg(compression)
        .arg(format!("{}", iteration_count));

    println!("{} {} {}", mode, compression, scratch);
    let start_time = time::Instant::now();
    let result_status = command.spawn().unwrap().wait().unwrap();
    let elapsed = start_time.elapsed();

    if !result_status.success() {
        panic!("failed to run test case");
    }

    let elapsed_secs = elapsed.as_secs() as f64 + (elapsed.subsec_nanos() as f64 / 1e9);
    println!("{}\n", elapsed_secs);

}

fn run_case(executable: &str, case: &str, scratch_options: &[&str], iteration_count: u64) {
    for scratch in scratch_options {
        run_one(executable, case, "object", scratch, "none", iteration_count);
    }

    for mode in &["bytes", "pipe"] {
        for compression in &["none", "packed"] {
            for scratch in scratch_options {
                run_one(executable, case, mode, scratch, compression, iteration_count);
            }
        }
    }
}

fn try_main() -> ::capnp::Result<()> {
    let args: Vec<String> = env::args().collect();

    assert!(args.len() == 2 || args.len() == 5,
            "USAGE: {} BENCHMARK_EXECUTABLE [CARSALES_ITERS CATRANK_ITERS EVAL_ITERS]",
            args[0]);

    let (carsales_iters, catrank_iters, eval_iters) = if args.len() > 2 {
        (args[2].parse::<u64>().unwrap(), args[3].parse::<u64>().unwrap(), args[4].parse::<u64>().unwrap())
    } else {
        (10000, 1000, 200000)
    };

    let executable = &*args[1];

    println!("running carsales with {} iterations", carsales_iters);
    run_case(executable, "carsales", &["reuse", "no-reuse"], carsales_iters);

    println!("running catrank with {} iterations", catrank_iters);
    run_case(executable, "catrank", &["no-reuse"], catrank_iters);

    println!("running eval with {} iterations", eval_iters);
    run_case(executable, "eval", &["no-reuse"], eval_iters);

    Ok(())
}

pub fn main() {
    match try_main() {
        Ok(()) => (),
        Err(e) => {
            panic!("error: {:?}", e);
        }
    }
}
<commit_msg>use new as_secs_f64() function<commit_after>// Copyright (c) 2017 David Renshaw and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

extern crate capnp;

use std::{env, process, time};

fn run_one(executable: &str, case: &str, mode: &str, scratch: &str, compression: &str, iteration_count: u64) {
    let mut command = process::Command::new(executable);
    command.arg(case)
        .arg(mode)
        .arg(scratch)
        .arg(compression)
        .arg(format!("{}", iteration_count));

    println!("{} {} {}", mode, compression, scratch);
    let start_time = time::Instant::now();
    let result_status = command.spawn().unwrap().wait().unwrap();
    let elapsed = start_time.elapsed();

    if !result_status.success() {
        panic!("failed to run test case");
    }

    println!("{}\n", elapsed.as_secs_f64());
}

fn run_case(executable: &str, case: &str, scratch_options: &[&str], iteration_count: u64) {
    for scratch in scratch_options {
        run_one(executable, case, "object", scratch, "none", iteration_count);
    }

    for mode in &["bytes", "pipe"] {
        for compression in &["none", "packed"] {
            for scratch in scratch_options {
                run_one(executable, case, mode, scratch, compression, iteration_count);
            }
        }
    }
}

fn try_main() -> ::capnp::Result<()> {
    let args: Vec<String> = env::args().collect();

    assert!(args.len() == 2 || args.len() == 5,
            "USAGE: {} BENCHMARK_EXECUTABLE [CARSALES_ITERS CATRANK_ITERS EVAL_ITERS]",
            args[0]);

    let (carsales_iters, catrank_iters, eval_iters) = if args.len() > 2 {
        (args[2].parse::<u64>().unwrap(), args[3].parse::<u64>().unwrap(), args[4].parse::<u64>().unwrap())
    } else {
        (10000, 1000, 200000)
    };

    let executable = &*args[1];

    println!("running carsales with {} iterations", carsales_iters);
    run_case(executable, "carsales", &["reuse", "no-reuse"], carsales_iters);

    println!("running catrank with {} iterations", catrank_iters);
    run_case(executable, "catrank", &["no-reuse"], catrank_iters);

    println!("running eval with {} iterations", eval_iters);
    run_case(executable, "eval", &["no-reuse"], eval_iters);

    Ok(())
}

pub fn main() {
    match try_main() {
        Ok(()) => (),
        Err(e) => {
            panic!("error: {:?}", e);
        }
    }
}
<|endoftext|>


<commit_before>// xfail-win32 - not sure why this is busted
// xfail-fast - check-fast doesn't understand aux-build
// aux-build:cci_borrow_lib.rs

use cci_borrow_lib;
import cci_borrow_lib::foo;

fn main() {
    let p = @22u;
    let r = foo(p);
    #debug["r=%u", r];
    assert r == 22u;
}
<commit_msg>Revert "test: xfail-win32 run-pass/cci_borrow.rs"<commit_after>// xfail-fast - check-fast doesn't understand aux-build
// aux-build:cci_borrow_lib.rs

use cci_borrow_lib;
import cci_borrow_lib::foo;

fn main() {
    let p = @22u;
    let r = foo(p);
    #debug["r=%u", r];
    assert r == 22u;
}
<|endoftext|>


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

use ffi;
use python::{Python, ToPythonPointer, PythonObject};
use conversion::ToPyObject;
use objects::{PyObject, PyList};
use err::{self, PyResult, PyErr};

/// Represents a Python `dict`.
pub struct PyDict<'p>(PyObject<'p>);

pyobject_newtype!(PyDict, PyDict_Check, PyDict_Type);

impl <'p> PyDict<'p> {
    /// Creates a new empty dictionary.
    ///
    /// May panic when running out of memory.
    pub fn new(py: Python<'p>) -> PyDict<'p> {
        unsafe {
            err::cast_from_owned_ptr_or_panic(py, ffi::PyDict_New())
        }
    }

    /// Return a new dictionary that contains the same key-value pairs as self.
    /// Corresponds to `dict(self)` in Python.
    pub fn copy(&self) -> PyResult<'p, PyDict<'p>> {
        let py = self.python();
        unsafe {
            err::result_cast_from_owned_ptr(py, ffi::PyDict_Copy(self.as_ptr()))
        }
    }

    /// Empty an existing dictionary of all key-value pairs.
    #[inline]
    pub fn clear(&self) {
        unsafe { ffi::PyDict_Clear(self.as_ptr()) }
    }

    /// Return the number of items in the dictionary.
    /// This is equivalent to len(p) on a dictionary.
    #[inline]
    pub fn len(&self) -> usize {
        unsafe { ffi::PyDict_Size(self.as_ptr()) as usize }
    }

    /// Determine if the dictionary contains the specified key.
    /// This is equivalent to the Python expression `key in self`.
    pub fn contains<K>(&self, key: K) -> PyResult<'p, bool> where K: ToPyObject<'p> {
        let py = self.python();
        key.with_borrowed_ptr(py, |key| unsafe {
            match ffi::PyDict_Contains(self.as_ptr(), key) {
                1 => Ok(true),
                0 => Ok(false),
                _ => Err(PyErr::fetch(py))
            }
        })
    }

    /// Gets an item from the dictionary.
    /// Returns None if the item is not present, or if an error occurs.
    pub fn get_item<K>(&self, key: K) -> Option<PyObject<'p>> where K: ToPyObject<'p> {
        let py = self.python();
        key.with_borrowed_ptr(py, |key| unsafe {
            PyObject::from_borrowed_ptr_opt(py,
                ffi::PyDict_GetItem(self.as_ptr(), key))
        })
    }

    /// Sets an item value.
    /// This is equivalent to the Python expression `self[key] = value`.
    pub fn set_item<K, V>(&self, key: K, value: V) -> PyResult<'p, ()> where K: ToPyObject<'p>, V: ToPyObject<'p> {
        let py = self.python();
        key.with_borrowed_ptr(py, move |key|
            value.with_borrowed_ptr(py, |value| unsafe {
                err::error_on_minusone(py,
                    ffi::PyDict_SetItem(self.as_ptr(), key, value))
            }))
    }

    /// Deletes an item.
    /// This is equivalent to the Python expression `del self[key]`.
    pub fn del_item<K>(&self, key: K) -> PyResult<'p, ()> where K: ToPyObject<'p> {
        let py = self.python();
        key.with_borrowed_ptr(py, |key| unsafe {
            err::error_on_minusone(py,
                ffi::PyDict_DelItem(self.as_ptr(), key))
        })
    }

    // List of dict items.
    // This is equivalent to the `dict.items()` method.
    pub fn items(&self) -> PyList {
        let py = self.python();
        unsafe {
            let pyobj = PyObject::from_borrowed_ptr(py, ffi::PyDict_Items(self.as_ptr()));
            pyobj.unchecked_cast_into::<PyList>()
        }
    }
}
<commit_msg>Use err::cast_from_owned_ptr_or_panic, because PyDict_Items creates a new reference to list and can fail.<commit_after>// Copyright (c) 2015 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use ffi;
use python::{Python, ToPythonPointer, PythonObject};
use conversion::ToPyObject;
use objects::{PyObject, PyList};
use err::{self, PyResult, PyErr};

/// Represents a Python `dict`.
pub struct PyDict<'p>(PyObject<'p>);

pyobject_newtype!(PyDict, PyDict_Check, PyDict_Type);

impl <'p> PyDict<'p> {
    /// Creates a new empty dictionary.
    ///
    /// May panic when running out of memory.
    pub fn new(py: Python<'p>) -> PyDict<'p> {
        unsafe {
            err::cast_from_owned_ptr_or_panic(py, ffi::PyDict_New())
        }
    }

    /// Return a new dictionary that contains the same key-value pairs as self.
    /// Corresponds to `dict(self)` in Python.
    pub fn copy(&self) -> PyResult<'p, PyDict<'p>> {
        let py = self.python();
        unsafe {
            err::result_cast_from_owned_ptr(py, ffi::PyDict_Copy(self.as_ptr()))
        }
    }

    /// Empty an existing dictionary of all key-value pairs.
    #[inline]
    pub fn clear(&self) {
        unsafe { ffi::PyDict_Clear(self.as_ptr()) }
    }

    /// Return the number of items in the dictionary.
    /// This is equivalent to len(p) on a dictionary.
    #[inline]
    pub fn len(&self) -> usize {
        unsafe { ffi::PyDict_Size(self.as_ptr()) as usize }
    }

    /// Determine if the dictionary contains the specified key.
    /// This is equivalent to the Python expression `key in self`.
    pub fn contains<K>(&self, key: K) -> PyResult<'p, bool> where K: ToPyObject<'p> {
        let py = self.python();
        key.with_borrowed_ptr(py, |key| unsafe {
            match ffi::PyDict_Contains(self.as_ptr(), key) {
                1 => Ok(true),
                0 => Ok(false),
                _ => Err(PyErr::fetch(py))
            }
        })
    }

    /// Gets an item from the dictionary.
    /// Returns None if the item is not present, or if an error occurs.
    pub fn get_item<K>(&self, key: K) -> Option<PyObject<'p>> where K: ToPyObject<'p> {
        let py = self.python();
        key.with_borrowed_ptr(py, |key| unsafe {
            PyObject::from_borrowed_ptr_opt(py,
                ffi::PyDict_GetItem(self.as_ptr(), key))
        })
    }

    /// Sets an item value.
    /// This is equivalent to the Python expression `self[key] = value`.
    pub fn set_item<K, V>(&self, key: K, value: V) -> PyResult<'p, ()> where K: ToPyObject<'p>, V: ToPyObject<'p> {
        let py = self.python();
        key.with_borrowed_ptr(py, move |key|
            value.with_borrowed_ptr(py, |value| unsafe {
                err::error_on_minusone(py,
                    ffi::PyDict_SetItem(self.as_ptr(), key, value))
            }))
    }

    /// Deletes an item.
    /// This is equivalent to the Python expression `del self[key]`.
    pub fn del_item<K>(&self, key: K) -> PyResult<'p, ()> where K: ToPyObject<'p> {
        let py = self.python();
        key.with_borrowed_ptr(py, |key| unsafe {
            err::error_on_minusone(py,
                ffi::PyDict_DelItem(self.as_ptr(), key))
        })
    }

    // List of dict items.
    // This is equivalent to the `dict.items()` method.
    pub fn items(&self) -> PyList {
        let py = self.python();
        unsafe {
            err::cast_from_owned_ptr_or_panic(py, ffi::PyDict_Items(self.as_ptr()))
        }
    }
}
<|endoftext|>


<commit_before>use base::world::{self, Chunk, HexPillar, PillarSection, PropType};
use base::math::*;
use glium::{self, DrawParameters, IndexBuffer, Program, VertexBuffer};
use glium::draw_parameters::{BackfaceCullingMode, DepthTest};
use glium::backend::Facade;
use glium::index::PrimitiveType;
use Camera;
use util::ToArr;
use std::f32::consts;
use world::plant_view::PlantView;

/// Graphical representation of the `base::Chunk`.
pub struct ChunkView {
    vertices: VertexBuffer<Vertex>,
    program: Program,
    pillars: Vec<PillarView>,
    index_buffer: IndexBuffer<u32>,
}

impl ChunkView {
    /// Creates the graphical representation of given chunk at the given chunk
    /// offset
    pub fn from_chunk<F: Facade>(chunk: &Chunk, offset: AxialPoint, facade: &F) -> Self {

        let mut vertices = Vec::new();
        let mut indices = Vec::new();
        let (mut top_vertices, mut top_indices) = get_top_hexagon_model();
        vertices.append(&mut top_vertices);
        indices.append(&mut top_indices);
        let (mut bottom_vertices, mut bottom_indices) = get_bottom_hexagon_model();
        vertices.append(&mut bottom_vertices);
        indices.append(&mut bottom_indices);
        let (mut north_vertices, mut north_indices) = get_side_hexagon_model(4, 5, vertices.len());
        vertices.append(&mut north_vertices);
        indices.append(&mut north_indices);
        let (mut south_vertices, mut south_indices) = get_side_hexagon_model(1, 2, vertices.len());
        vertices.append(&mut south_vertices);
        indices.append(&mut south_indices);
        let (mut ne_vertices, mut ne_indices) = get_side_hexagon_model(5, 0, vertices.len());
        vertices.append(&mut ne_vertices);
        indices.append(&mut ne_indices);
        let (mut se_vertices, mut se_indices) = get_side_hexagon_model(0, 1, vertices.len());
        vertices.append(&mut se_vertices);
        indices.append(&mut se_indices);
        let (mut nw_vertices, mut nw_indices) = get_side_hexagon_model(3, 4, vertices.len());
        vertices.append(&mut nw_vertices);
        indices.append(&mut nw_indices);
        let (mut sw_vertices, mut sw_indices) = get_side_hexagon_model(2, 3, vertices.len());
        vertices.append(&mut sw_vertices);
        indices.append(&mut sw_indices);

        let vbuf = VertexBuffer::new(facade, &vertices).unwrap();
        let prog = Program::from_source(facade,
                                        include_str!("chunk_std.vert"),
                                        include_str!("chunk_std.frag"),
                                        None)
            .unwrap();

        let mut pillars = Vec::new();
        for q in 0..world::CHUNK_SIZE * world::CHUNK_SIZE {
            let pos = offset.to_real() +
                      AxialVector::new((q / world::CHUNK_SIZE).into(),
                                       (q % world::CHUNK_SIZE).into())
                .to_real();
            let pillar = &chunk.pillars()[q as usize];
            pillars.push(PillarView::from_pillar(pos, pillar, facade));
        }

        let ibuf = IndexBuffer::new(facade, PrimitiveType::TrianglesList, &indices).unwrap();

        ChunkView {
            vertices: vbuf,
            program: prog,
            pillars: pillars,
            index_buffer: ibuf,
        }
    }

    pub fn draw<S: glium::Surface>(&self, surface: &mut S, camera: &Camera) {
        for pillar in &self.pillars {
            for section in &pillar.sections {
                let height = section.top.units() - section.bottom.units();

                let uniforms = uniform! {
                    height: height as f32,
                    offset: [pillar.pos.x, pillar.pos.y, section.bottom.to_real()],
                    proj_matrix: camera.proj_matrix().to_arr(),
                    view_matrix: camera.view_matrix().to_arr(),
                    material_color: section.ground.get_color(),
                };
                let params = DrawParameters {
                    depth: glium::Depth {
                        write: true,
                        test: DepthTest::IfLess,
                        ..Default::default()
                    },
                    backface_culling: BackfaceCullingMode::CullCounterClockwise,
                    ..Default::default()
                };

                surface.draw(&self.vertices,
                          &self.index_buffer,
                          &self.program,
                          &uniforms,
                          &params)
                    .unwrap();
            }

            for plant in &pillar.plants {
                plant.draw(surface, camera);
            }
        }
    }
}

/// Vertex type used to render chunks (or hex pillars).
#[derive(Debug, Copy, Clone)]
pub struct Vertex {
    pub position: [f32; 3],
    pub normal: [f32; 3],
}

implement_vertex!(Vertex, position, normal);

pub struct PillarView {
    pos: Point2f,
    sections: Vec<PillarSection>,
    plants: Vec<PlantView>,
}

impl PillarView {
    fn from_pillar<F: Facade>(pos: Point2f, pillar: &HexPillar, facade: &F) -> PillarView {
        PillarView {
            pos: pos,
            sections: pillar.sections().to_vec(),
            plants: pillar.props()
                .iter()
                .map(|prop| {
                    match prop.prop {
                        PropType::Plant(ref plant) => {
                            let pos = Point3f::new(pos.x, pos.y, prop.baseline.to_real());
                            PlantView::from_plant(pos, plant, facade)
                        }
                    }
                })
                .collect(),
        }
    }
}

/// Calculates one Point-coordinates of a Hexagon
fn hex_corner(size: f32, i: i32) -> (f32, f32) {
    let angle_deg = 60.0 * (i as f32) + 30.0;
    let angle_rad = (consts::PI / 180.0) * angle_deg;

    (size * angle_rad.cos(), size * angle_rad.sin())
}
/// Calculates the top face of the Hexagon and normals
pub fn get_top_hexagon_model() -> (Vec<Vertex>, Vec<u32>) {
    let mut vertices = Vec::new();

    for i in 0..6 {
        let (x, y) = hex_corner(world::HEX_OUTER_RADIUS, i);

        vertices.push(Vertex {
            position: [x, y, world::PILLAR_STEP_HEIGHT],
            normal: [0.0, 0.0, 1.0],
        });
    }

    vertices.push(Vertex {
        position: [0.0, 0.0, world::PILLAR_STEP_HEIGHT],
        normal: [0.0, 0.0, 1.0],
    });

    (vertices, vec![0, 6, 1, 5, 6, 0, 4, 6, 5, 3, 6, 4, 2, 6, 3, 1, 6, 2])
}

/// Calculates the bottom face of the Hexagon and the normals
pub fn get_bottom_hexagon_model() -> (Vec<Vertex>, Vec<u32>) {
    let mut vertices = Vec::new();

    for i in 0..6 {
        let (x, y) = hex_corner(world::HEX_OUTER_RADIUS, i);

        vertices.push(Vertex {
            position: [x, y, 0.0],
            normal: [0.0, 0.0, -1.0],
        });
    }

    vertices.push(Vertex {
        position: [0.0, 0.0, 0.0],
        normal: [0.0, 0.0, -1.0],
    });

    (vertices, vec![8, 13, 7, 7, 13, 12, 12, 13, 11, 11, 13, 10, 10, 13, 9, 9, 13, 8])
}

/// Calculates the sides of the Hexagon and normals
pub fn get_side_hexagon_model(ind1: i32, ind2: i32, cur_len: usize) -> (Vec<Vertex>, Vec<u32>) {
    let mut vertices = Vec::new();

    let (x1, y1) = hex_corner(world::HEX_OUTER_RADIUS, ind1);
    let (x2, y2) = hex_corner(world::HEX_OUTER_RADIUS, ind2);
    let normal = [y1 + y2, x1 + x2, 0.0];

    vertices.push(Vertex {
        position: [x1, y1, world::PILLAR_STEP_HEIGHT],
        normal: normal,
    });
    vertices.push(Vertex {
        position: [x1, y1, 0.0],
        normal: normal,
    });
    vertices.push(Vertex {
        position: [x2, y2, world::PILLAR_STEP_HEIGHT],
        normal: normal,
    });
    vertices.push(Vertex {
        position: [x2, y2, 0.0],
        normal: normal,
    });

    (vertices,
     vec![cur_len as u32 + 0,
          cur_len as u32 + 2,
          cur_len as u32 + 1,
          cur_len as u32 + 1,
          cur_len as u32 + 2,
          cur_len as u32 + 3])
}
<commit_msg>replaced 'modell' with 'model'<commit_after>use base::world::{self, Chunk, HexPillar, PillarSection, PropType};
use base::math::*;
use glium::{self, DrawParameters, IndexBuffer, Program, VertexBuffer};
use glium::draw_parameters::{BackfaceCullingMode, DepthTest};
use glium::backend::Facade;
use glium::index::PrimitiveType;
use Camera;
use util::ToArr;
use std::f32::consts;
use world::plant_view::PlantView;

/// Graphical representation of the `base::Chunk`.
pub struct ChunkView {
    vertices: VertexBuffer<Vertex>,
    program: Program,
    pillars: Vec<PillarView>,
    index_buffer: IndexBuffer<u32>,
}

impl ChunkView {
    /// Creates the graphical representation of given chunk at the given chunk
    /// offset
    pub fn from_chunk<F: Facade>(chunk: &Chunk, offset: AxialPoint, facade: &F) -> Self {

        let mut vertices = Vec::new();
        let mut indices = Vec::new();
        let (mut top_vertices, mut top_indices) = get_top_hexagon_model();
        vertices.append(&mut top_vertices);
        indices.append(&mut top_indices);
        let (mut bottom_vertices, mut bottom_indices) = get_bottom_hexagon_model();
        vertices.append(&mut bottom_vertices);
        indices.append(&mut bottom_indices);
        let (mut north_vertices, mut north_indices) = get_side_hexagon_model(4, 5, vertices.len());
        vertices.append(&mut north_vertices);
        indices.append(&mut north_indices);
        let (mut south_vertices, mut south_indices) = get_side_hexagon_model(1, 2, vertices.len());
        vertices.append(&mut south_vertices);
        indices.append(&mut south_indices);
        let (mut ne_vertices, mut ne_indices) = get_side_hexagon_model(5, 0, vertices.len());
        vertices.append(&mut ne_vertices);
        indices.append(&mut ne_indices);
        let (mut se_vertices, mut se_indices) = get_side_hexagon_model(0, 1, vertices.len());
        vertices.append(&mut se_vertices);
        indices.append(&mut se_indices);
        let (mut nw_vertices, mut nw_indices) = get_side_hexagon_model(3, 4, vertices.len());
        vertices.append(&mut nw_vertices);
        indices.append(&mut nw_indices);
        let (mut sw_vertices, mut sw_indices) = get_side_hexagon_model(2, 3, vertices.len());
        vertices.append(&mut sw_vertices);
        indices.append(&mut sw_indices);

        let vbuf = VertexBuffer::new(facade, &vertices).unwrap();
        let prog = Program::from_source(facade,
                                        include_str!("chunk_std.vert"),
                                        include_str!("chunk_std.frag"),
                                        None)
            .unwrap();

        let mut pillars = Vec::new();
        for q in 0..world::CHUNK_SIZE * world::CHUNK_SIZE {
            let pos = offset.to_real() +
                      AxialVector::new((q / world::CHUNK_SIZE).into(),
                                       (q % world::CHUNK_SIZE).into())
                .to_real();
            let pillar = &chunk.pillars()[q as usize];
            pillars.push(PillarView::from_pillar(pos, pillar, facade));
        }

        let ibuf = IndexBuffer::new(facade, PrimitiveType::TrianglesList, &indices).unwrap();

        ChunkView {
            vertices: vbuf,
            program: prog,
            pillars: pillars,
            index_buffer: ibuf,
        }
    }

    pub fn draw<S: glium::Surface>(&self, surface: &mut S, camera: &Camera) {
        for pillar in &self.pillars {
            for section in &pillar.sections {
                let height = section.top.units() - section.bottom.units();

                let uniforms = uniform! {
                    height: height as f32,
                    offset: [pillar.pos.x, pillar.pos.y, section.bottom.to_real()],
                    proj_matrix: camera.proj_matrix().to_arr(),
                    view_matrix: camera.view_matrix().to_arr(),
                    material_color: section.ground.get_color(),
                };
                let params = DrawParameters {
                    depth: glium::Depth {
                        write: true,
                        test: DepthTest::IfLess,
                        ..Default::default()
                    },
                    backface_culling: BackfaceCullingMode::CullCounterClockwise,
                    ..Default::default()
                };

                surface.draw(&self.vertices,
                          &self.index_buffer,
                          &self.program,
                          &uniforms,
                          &params)
                    .unwrap();
            }

            for plant in &pillar.plants {
                plant.draw(surface, camera);
            }
        }
    }
}

/// Vertex type used to render chunks (or hex pillars).
#[derive(Debug, Copy, Clone)]
pub struct Vertex {
    pub position: [f32; 3],
    pub normal: [f32; 3],
}

implement_vertex!(Vertex, position, normal);

pub struct PillarView {
    pos: Point2f,
    sections: Vec<PillarSection>,
    plants: Vec<PlantView>,
}

impl PillarView {
    fn from_pillar<F: Facade>(pos: Point2f, pillar: &HexPillar, facade: &F) -> PillarView {
        PillarView {
            pos: pos,
            sections: pillar.sections().to_vec(),
            plants: pillar.props()
                .iter()
                .map(|prop| {
                    match prop.prop {
                        PropType::Plant(ref plant) => {
                            let pos = Point3f::new(pos.x, pos.y, prop.baseline.to_real());
                            PlantView::from_plant(pos, plant, facade)
                        }
                    }
                })
                .collect(),
        }
    }
}

/// Calculates one Point-coordinates of a Hexagon
fn hex_corner(size: f32, i: i32) -> (f32, f32) {
    let angle_deg = 60.0 * (i as f32) + 30.0;
    let angle_rad = (consts::PI / 180.0) * angle_deg;

    (size * angle_rad.cos(), size * angle_rad.sin())
}
/// Calculates the top face of the Hexagon and normals
fn get_top_hexagon_model() -> (Vec<Vertex>, Vec<u32>) {
    let mut vertices = Vec::new();

    for i in 0..6 {
        let (x, y) = hex_corner(world::HEX_OUTER_RADIUS, i);

        vertices.push(Vertex {
            position: [x, y, world::PILLAR_STEP_HEIGHT],
            normal: [0.0, 0.0, 1.0],
        });
    }

    vertices.push(Vertex {
        position: [0.0, 0.0, world::PILLAR_STEP_HEIGHT],
        normal: [0.0, 0.0, 1.0],
    });

    (vertices, vec![0, 6, 1, 5, 6, 0, 4, 6, 5, 3, 6, 4, 2, 6, 3, 1, 6, 2])
}

/// Calculates the bottom face of the Hexagon and the normals
fn get_bottom_hexagon_model() -> (Vec<Vertex>, Vec<u32>) {
    let mut vertices = Vec::new();

    for i in 0..6 {
        let (x, y) = hex_corner(world::HEX_OUTER_RADIUS, i);

        vertices.push(Vertex {
            position: [x, y, 0.0],
            normal: [0.0, 0.0, -1.0],
        });
    }

    vertices.push(Vertex {
        position: [0.0, 0.0, 0.0],
        normal: [0.0, 0.0, -1.0],
    });

    (vertices, vec![8, 13, 7, 7, 13, 12, 12, 13, 11, 11, 13, 10, 10, 13, 9, 9, 13, 8])
}

/// Calculates the sides of the Hexagon and normals
fn get_side_hexagon_model(ind1: i32, ind2: i32, cur_len: usize) -> (Vec<Vertex>, Vec<u32>) {
    let mut vertices = Vec::new();

    let (x1, y1) = hex_corner(world::HEX_OUTER_RADIUS, ind1);
    let (x2, y2) = hex_corner(world::HEX_OUTER_RADIUS, ind2);
    let normal = [y1 + y2, x1 + x2, 0.0];

    vertices.push(Vertex {
        position: [x1, y1, world::PILLAR_STEP_HEIGHT],
        normal: normal,
    });
    vertices.push(Vertex {
        position: [x1, y1, 0.0],
        normal: normal,
    });
    vertices.push(Vertex {
        position: [x2, y2, world::PILLAR_STEP_HEIGHT],
        normal: normal,
    });
    vertices.push(Vertex {
        position: [x2, y2, 0.0],
        normal: normal,
    });

    (vertices,
     vec![cur_len as u32 + 0,
          cur_len as u32 + 2,
          cur_len as u32 + 1,
          cur_len as u32 + 1,
          cur_len as u32 + 2,
          cur_len as u32 + 3])
}
<|endoftext|>


<commit_before>//! TODO(tailhook) maybe unbundle this module into separate crate?
//!
use std::io;
use std::str::from_utf8;

use futures::{AsyncSink, Async, Future};
use futures::sink::Sink;

use rustc_serialize::json::{Json};
use tokio_core::io::Io;
use tokio_core::net::TcpStream;
use futures::sync::oneshot::{channel, Sender};
use futures::sync::mpsc::SendError;
use minihttp::client::{Error, Codec, Encoder, EncoderDone, Head, RecvMode};
use minihttp::OptFuture;

use http_pools::UpstreamRef;

pub struct JsonRequest<F> {
    request: Option<F>,
    sender: Option<Sender<Result<Json, Error>>>,
}

pub fn request_fn_buffered<F, E>(mut pool: UpstreamRef, f: F)
    -> OptFuture<Json, E>
    where F: FnOnce(Encoder<TcpStream>) -> EncoderDone<TcpStream> + Send + 'static,
          E: From<Error>,
          E: From<SendError<Box<Codec<TcpStream>+Send>>>,
{
    let (tx, rx) = channel();
    let codec = JsonRequest {
        request: Some(f),
        sender: Some(tx),
    };
    let mut guard = pool.get_mut();
    let ref mut pool = match guard.get_mut() {
        Some(pool) => pool,
        None => return OptFuture::Value(Err(Error::Busy.into())),
    };
    match pool.start_send(Box::new(codec)) {
        Ok(AsyncSink::NotReady(_)) => {
            OptFuture::Value(Err(Error::Busy.into()))
        }
        Ok(AsyncSink::Ready) => {
            OptFuture::Future(
                rx
                .map_err(|_| Error::Canceled.into())
                .and_then(|res| res)
                .map_err(|e| e.into())
                .boxed())
        }
        Err(e) => {
            OptFuture::Value(Err(e.into()))
        }
    }
}

impl<F, S: Io> Codec<S> for JsonRequest<F>
    where F: FnOnce(Encoder<S>) -> EncoderDone<S>
{
    fn start_write(&mut self, e: Encoder<S>)
        -> OptFuture<EncoderDone<S>, Error>
    {
        OptFuture::Value(Ok(self.request.take().expect("called once")(e)))
    }
    fn headers_received(&mut self, headers: &Head) -> Result<RecvMode, Error> {
        if headers.code != 200 {
            // TODO(tailhook) fix error
            return Err(Error::Io(io::Error::new(
                io::ErrorKind::Other,
                "bad response code")));
        }
        Ok(RecvMode::Buffered(10_048_576))
    }
    fn data_received(&mut self, data: &[u8], end: bool)
        -> Result<Async<usize>, Error>
    {
        assert!(end);
        let response = from_utf8(data)
            .map_err(|_| {
                // TODO(tailhook) fix error
                Error::Io(io::Error::new(io::ErrorKind::Other,
                    "bad response code"))
            })
            .and_then(|s| {
                Json::from_str(s)
                .map_err(|e| {
                    Error::Io(io::Error::new(io::ErrorKind::Other, e))
                })
            });
        self.sender.take().unwrap().complete(response);
        Ok(Async::Ready(data.len()))
    }
}
<commit_msg>Remove unused module<commit_after><|endoftext|>


<commit_before>#![allow(non_snake_case)]
#[derive(RustcDecodable, Debug)]
pub struct Senderaddress {
    pub addressLine1: Option<String>,
    pub addressLine2: Option<String>,
    pub postalCode: Option<String>,
    pub city: Option<String>,
    pub countryCode: Option<String>,
    pub country: Option<String>,
}
#[derive(RustcDecodable, Debug)]
pub struct Recipientsignature {
    pub name: Option<String>,
}
#[derive(RustcDecodable, Debug)]
pub struct EventsetDefinition {
    pub term: Option<String>,
    pub explanation: Option<String>,
}
#[derive(RustcDecodable, Debug)]
pub struct Eventset {
    pub description: String,
    pub status: String,
    pub recipientSignature: Option<Recipientsignature>,
    pub unitId: Option<String>,
    pub unitInformationUrl: Option<String>,
    pub unitType: Option<String>,
    pub postalCode: Option<String>,
    pub city: Option<String>,
    pub countryCode: Option<String>,
    pub country: Option<String>,
    pub dateIso: Option<String>,
    pub displayDate: Option<String>,
    pub displayTime: Option<String>,
    pub consignmentEvent: bool,
    pub definitions: Option<Vec<EventsetDefinition>>
}
#[derive(RustcDecodable, Debug)]
pub struct Packageset {
    pub statusDescription: String,
    pub descriptions: Vec<String>,
    pub packageNumber: String,
    pub previousPackageNumber: Option<String>,
    pub productName: Option<String>,
    pub productCode: Option<String>,
    pub brand: Option<String>,
    pub lengthInCm: Option<i64>,
    pub widthInCm: Option<i64>,
    pub heightInCm: Option<i64>,
    pub volumeInDm3: Option<f64>,
    pub weightInKgs: Option<f64>,
    pub pickupCode: Option<String>,
    pub dateOfReturn: Option<String>,
    pub senderName: Option<String>,
    pub senderAddress: Option<Senderaddress>,
    pub recipientHandlingAddress: Option<Senderaddress>,
    pub eventSet: Vec<Eventset>,
}

#[derive(RustcDecodable, Debug)]
pub struct Consignmentset {
    pub consignmentId: Option<String>,
    pub previousConsignmentId: Option<String>,
    pub packageSet: Vec<Packageset>,
    pub senderName: Option<String>,
    pub senderAddress: Option<Senderaddress>,
    pub recipientHandlingAddress: Option<Senderaddress>,
    pub senderReference: Option<String>,
    pub totalWeightInKgs: Option<f64>,
    pub totalVolumeInDm3: Option<f64>,
}
#[derive(RustcDecodable, Debug)]
pub struct BringResponse {
    pub consignmentSet: Vec<Consignmentset>,
}
<commit_msg>use serde_macros<commit_after>#![allow(non_snake_case)]
#[derive(Serialize, Deserialize, Debug)]

pub struct ConsignmentsetError {
    #[serde(skip_serializing_if="Option::is_none")]
    pub code: Option<i64>,
    pub message: Option<String>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Senderaddress {
    pub addressLine1: Option<String>,
    pub addressLine2: Option<String>,
    pub postalCode: Option<String>,
    pub city: Option<String>,
    pub countryCode: Option<String>,
    pub country: Option<String>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Recipientsignature {
    pub name: Option<String>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct EventsetDefinition {
    pub term: Option<String>,
    pub explanation: Option<String>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Eventset {
    pub description: String,
    pub status: String,
    pub recipientSignature: Option<Recipientsignature>,
    pub unitId: Option<String>,
    pub unitInformationUrl: Option<String>,
    pub unitType: Option<String>,
    pub postalCode: Option<String>,
    pub city: Option<String>,
    pub countryCode: Option<String>,
    pub country: Option<String>,
    pub dateIso: Option<String>,
    pub displayDate: Option<String>,
    pub displayTime: Option<String>,
    pub consignmentEvent: bool,
    pub definitions: Option<Vec<EventsetDefinition>>
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Packageset {
    pub statusDescription: String,
    pub descriptions: Vec<String>,
    pub packageNumber: String,
    pub previousPackageNumber: Option<String>,
    pub productName: Option<String>,
    pub productCode: Option<String>,
    pub brand: Option<String>,
    pub lengthInCm: Option<i64>,
    pub widthInCm: Option<i64>,
    pub heightInCm: Option<i64>,
    pub volumeInDm3: Option<f64>,
    pub weightInKgs: Option<f64>,
    pub pickupCode: Option<String>,
    pub dateOfReturn: Option<String>,
    pub senderName: String,
    pub senderAddress: Option<Senderaddress>,
    pub recipientHandlingAddress: Option<Senderaddress>,
    pub eventSet: Vec<Eventset>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Consignmentset {
    pub consignmentId: Option<String>,
    pub previousConsignmentId: Option<String>,
    pub packageSet: Vec<Packageset>,
    pub senderName: Option<String>,
    pub senderAddress: Option<Senderaddress>,
    pub recipientHandlingAddress: Option<Senderaddress>,
    pub senderReference: Option<String>,
    pub totalWeightInKgs: Option<f64>,
    pub totalVolumeInDm3: Option<f64>,
    #[serde(skip_serializing_if="Vec::is_empty")]
    pub error: Vec<ConsignmentsetError>, // This probably shouldn't be a Vec?
}
#[derive(Serialize, Deserialize, Debug)]
pub struct BringResponse {
    pub consignmentSet: Vec<Consignmentset>,
}
<|endoftext|>


<commit_before>use clippy_utils::diagnostics::span_lint_and_note;
use clippy_utils::{is_uninit_ty_valid, match_def_path, path_to_local_id, paths, peel_hir_expr_while, SpanlessEq};
use rustc_hir::def::Res;
use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;

declare_clippy_lint! {
    /// ### What it does
    /// Checks for the creation of uninitialized `Vec<T>` by calling `set_len()`
    /// immediately after `with_capacity()` or `reserve()`.
    ///
    /// ### Why is this bad?
    /// It creates `Vec<T>` that contains uninitialized data, which leads to an
    /// undefined behavior with most safe operations.
    /// Notably, using uninitialized `Vec<u8>` with generic `Read` is unsound.
    ///
    /// ### Example
    /// ```rust,ignore
    /// let mut vec: Vec<u8> = Vec::with_capacity(1000);
    /// unsafe { vec.set_len(1000); }
    /// reader.read(&mut vec); // undefined behavior!
    /// ```
    /// Use an initialized buffer:
    /// ```rust,ignore
    /// let mut vec: Vec<u8> = vec![0; 1000];
    /// reader.read(&mut vec);
    /// ```
    /// Or, wrap the content in `MaybeUninit`:
    /// ```rust,ignore
    /// let mut vec: Vec<MaybeUninit<T>> = Vec::with_capacity(1000);
    /// unsafe { vec.set_len(1000); }
    /// ```
    pub UNINIT_VEC,
    correctness,
    "Vec with uninitialized data"
}

declare_lint_pass!(UninitVec => [UNINIT_VEC]);

impl<'tcx> LateLintPass<'tcx> for UninitVec {
    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
        for w in block.stmts.windows(2) {
            if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = w[1].kind {
                handle_pair(cx, &w[0], expr);
            }
        }

        if let (Some(stmt), Some(expr)) = (block.stmts.last(), block.expr) {
            handle_pair(cx, stmt, expr);
        }
    }
}

fn handle_pair(cx: &LateContext<'tcx>, first: &'tcx Stmt<'tcx>, second: &'tcx Expr<'tcx>) {
    if_chain! {
        if let Some(vec) = extract_with_capacity_or_reserve_target(cx, first);
        if let Some((set_len_self, call_span)) = extract_set_len_self(cx, second);
        if vec.eq_expr(cx, set_len_self);
        if let ty::Ref(_, vec_ty, _) = cx.typeck_results().expr_ty_adjusted(set_len_self).kind();
        if let ty::Adt(_, substs) = vec_ty.kind();
        // Check T of Vec<T>
        if !is_uninit_ty_valid(cx, substs.type_at(0));
        then {
            span_lint_and_note(
                cx,
                UNINIT_VEC,
                call_span,
                "calling `set_len()` immediately after reserving a buffer creates uninitialized values",
                Some(first.span),
                "the buffer is reserved here"
            );
        }
    }
}

#[derive(Clone, Copy, Debug)]
enum LocalOrExpr<'tcx> {
    Local(HirId),
    Expr(&'tcx Expr<'tcx>),
}

impl<'tcx> LocalOrExpr<'tcx> {
    fn eq_expr(self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
        match self {
            LocalOrExpr::Local(hir_id) => path_to_local_id(expr, hir_id),
            LocalOrExpr::Expr(self_expr) => SpanlessEq::new(cx).eq_expr(self_expr, expr),
        }
    }
}

/// Returns the target vec of Vec::with_capacity() or Vec::reserve()
fn extract_with_capacity_or_reserve_target(cx: &LateContext<'_>, stmt: &'tcx Stmt<'_>) -> Option<LocalOrExpr<'tcx>> {
    match stmt.kind {
        StmtKind::Local(local) => {
            // let mut x = Vec::with_capacity()
            if_chain! {
                if let Some(init_expr) = local.init;
                if let PatKind::Binding(_, hir_id, _, None) = local.pat.kind;
                if is_with_capacity(cx, init_expr);
                then {
                    Some(LocalOrExpr::Local(hir_id))
                } else {
                    None
                }
            }
        },
        StmtKind::Expr(expr) | StmtKind::Semi(expr) => {
            match expr.kind {
                ExprKind::Assign(lhs, rhs, _span) if is_with_capacity(cx, rhs) => {
                    // self.vec = Vec::with_capacity()
                    Some(LocalOrExpr::Expr(lhs))
                },
                ExprKind::MethodCall(_, _, [vec_expr, _], _) => {
                    // self.vec.reserve()
                    if_chain! {
                        if let Some(id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
                        if match_def_path(cx, id, &paths::VEC_RESERVE);
                        then {
                            Some(LocalOrExpr::Expr(vec_expr))
                        } else {
                            None
                        }
                    }
                },
                _ => None,
            }
        },
        _ => None,
    }
}

fn is_with_capacity(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> bool {
    if_chain! {
        if let ExprKind::Call(path_expr, _) = &expr.kind;
        if let ExprKind::Path(qpath) = &path_expr.kind;
        if let Res::Def(_, def_id) = cx.qpath_res(qpath, path_expr.hir_id);
        then {
            match_def_path(cx, def_id, &paths::VEC_WITH_CAPACITY)
        } else {
            false
        }
    }
}

/// Returns self if the expression is Vec::set_len()
fn extract_set_len_self(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(&'tcx Expr<'tcx>, Span)> {
    // peel unsafe blocks in `unsafe { vec.set_len() }`
    let expr = peel_hir_expr_while(expr, |e| {
        if let ExprKind::Block(block, _) = e.kind {
            match (block.stmts.get(0).map(|stmt| &stmt.kind), block.expr) {
                (None, Some(expr)) => Some(expr),
                (Some(StmtKind::Expr(expr) | StmtKind::Semi(expr)), None) => Some(expr),
                _ => None,
            }
        } else {
            None
        }
    });
    match expr.kind {
        ExprKind::MethodCall(_, _, [vec_expr, _], _) => {
            cx.typeck_results().type_dependent_def_id(expr.hir_id).and_then(|id| {
                if match_def_path(cx, id, &paths::VEC_SET_LEN) {
                    Some((vec_expr, expr.span))
                } else {
                    None
                }
            })
        },
        _ => None,
    }
}
<commit_msg>Fix clippy lints<commit_after>use clippy_utils::diagnostics::span_lint_and_note;
use clippy_utils::{is_uninit_ty_valid, match_def_path, path_to_local_id, paths, peel_hir_expr_while, SpanlessEq};
use rustc_hir::def::Res;
use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::Span;

declare_clippy_lint! {
    /// ### What it does
    /// Checks for the creation of uninitialized `Vec<T>` by calling `set_len()`
    /// immediately after `with_capacity()` or `reserve()`.
    ///
    /// ### Why is this bad?
    /// It creates `Vec<T>` that contains uninitialized data, which leads to an
    /// undefined behavior with most safe operations.
    /// Notably, using uninitialized `Vec<u8>` with generic `Read` is unsound.
    ///
    /// ### Example
    /// ```rust,ignore
    /// let mut vec: Vec<u8> = Vec::with_capacity(1000);
    /// unsafe { vec.set_len(1000); }
    /// reader.read(&mut vec); // undefined behavior!
    /// ```
    /// Use an initialized buffer:
    /// ```rust,ignore
    /// let mut vec: Vec<u8> = vec![0; 1000];
    /// reader.read(&mut vec);
    /// ```
    /// Or, wrap the content in `MaybeUninit`:
    /// ```rust,ignore
    /// let mut vec: Vec<MaybeUninit<T>> = Vec::with_capacity(1000);
    /// unsafe { vec.set_len(1000); }
    /// ```
    pub UNINIT_VEC,
    correctness,
    "Vec with uninitialized data"
}

declare_lint_pass!(UninitVec => [UNINIT_VEC]);

impl<'tcx> LateLintPass<'tcx> for UninitVec {
    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
        for w in block.stmts.windows(2) {
            if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = w[1].kind {
                handle_pair(cx, &w[0], expr);
            }
        }

        if let (Some(stmt), Some(expr)) = (block.stmts.last(), block.expr) {
            handle_pair(cx, stmt, expr);
        }
    }
}

fn handle_pair(cx: &LateContext<'tcx>, first: &'tcx Stmt<'tcx>, second: &'tcx Expr<'tcx>) {
    if_chain! {
        if let Some(vec) = extract_with_capacity_or_reserve_target(cx, first);
        if let Some((set_len_self, call_span)) = extract_set_len_self(cx, second);
        if vec.eq_expr(cx, set_len_self);
        if let ty::Ref(_, vec_ty, _) = cx.typeck_results().expr_ty_adjusted(set_len_self).kind();
        if let ty::Adt(_, substs) = vec_ty.kind();
        // Check T of Vec<T>
        if !is_uninit_ty_valid(cx, substs.type_at(0));
        then {
            span_lint_and_note(
                cx,
                UNINIT_VEC,
                call_span,
                "calling `set_len()` immediately after reserving a buffer creates uninitialized values",
                Some(first.span),
                "the buffer is reserved here"
            );
        }
    }
}

#[derive(Clone, Copy, Debug)]
enum LocalOrExpr<'tcx> {
    Local(HirId),
    Expr(&'tcx Expr<'tcx>),
}

impl<'tcx> LocalOrExpr<'tcx> {
    fn eq_expr(self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
        match self {
            LocalOrExpr::Local(hir_id) => path_to_local_id(expr, hir_id),
            LocalOrExpr::Expr(self_expr) => SpanlessEq::new(cx).eq_expr(self_expr, expr),
        }
    }
}

/// Returns the target vec of `Vec::with_capacity()` or `Vec::reserve()`
fn extract_with_capacity_or_reserve_target(cx: &LateContext<'_>, stmt: &'tcx Stmt<'_>) -> Option<LocalOrExpr<'tcx>> {
    match stmt.kind {
        StmtKind::Local(local) => {
            // let mut x = Vec::with_capacity()
            if_chain! {
                if let Some(init_expr) = local.init;
                if let PatKind::Binding(_, hir_id, _, None) = local.pat.kind;
                if is_with_capacity(cx, init_expr);
                then {
                    Some(LocalOrExpr::Local(hir_id))
                } else {
                    None
                }
            }
        },
        StmtKind::Expr(expr) | StmtKind::Semi(expr) => {
            match expr.kind {
                ExprKind::Assign(lhs, rhs, _span) if is_with_capacity(cx, rhs) => {
                    // self.vec = Vec::with_capacity()
                    Some(LocalOrExpr::Expr(lhs))
                },
                ExprKind::MethodCall(_, _, [vec_expr, _], _) => {
                    // self.vec.reserve()
                    if_chain! {
                        if let Some(id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
                        if match_def_path(cx, id, &paths::VEC_RESERVE);
                        then {
                            Some(LocalOrExpr::Expr(vec_expr))
                        } else {
                            None
                        }
                    }
                },
                _ => None,
            }
        },
        StmtKind::Item(_) => None,
    }
}

fn is_with_capacity(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> bool {
    if_chain! {
        if let ExprKind::Call(path_expr, _) = &expr.kind;
        if let ExprKind::Path(qpath) = &path_expr.kind;
        if let Res::Def(_, def_id) = cx.qpath_res(qpath, path_expr.hir_id);
        then {
            match_def_path(cx, def_id, &paths::VEC_WITH_CAPACITY)
        } else {
            false
        }
    }
}

/// Returns self if the expression is `Vec::set_len()`
fn extract_set_len_self(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(&'tcx Expr<'tcx>, Span)> {
    // peel unsafe blocks in `unsafe { vec.set_len() }`
    let expr = peel_hir_expr_while(expr, |e| {
        if let ExprKind::Block(block, _) = e.kind {
            match (block.stmts.get(0).map(|stmt| &stmt.kind), block.expr) {
                (None, Some(expr)) => Some(expr),
                (Some(StmtKind::Expr(expr) | StmtKind::Semi(expr)), None) => Some(expr),
                _ => None,
            }
        } else {
            None
        }
    });
    match expr.kind {
        ExprKind::MethodCall(_, _, [vec_expr, _], _) => {
            cx.typeck_results().type_dependent_def_id(expr.hir_id).and_then(|id| {
                if match_def_path(cx, id, &paths::VEC_SET_LEN) {
                    Some((vec_expr, expr.span))
                } else {
                    None
                }
            })
        },
        _ => None,
    }
}
<|endoftext|>


<commit_before>//! Read configurations files.

#![deny(missing_docs_in_private_items)]

use std::{env, fmt, fs, io, path};
use std::io::Read;
use syntax::{ast, codemap};
use toml;

/// Get the configuration file from arguments.
pub fn file_from_args(args: &[codemap::Spanned<ast::NestedMetaItemKind>]) -> Result<Option<path::PathBuf>, (&'static str, codemap::Span)> {
    for arg in args.iter().filter_map(|a| a.meta_item()) {
        match arg.node {
            ast::MetaItemKind::Word(ref name) |
            ast::MetaItemKind::List(ref name, _) => {
                if name == &"conf_file" {
                    return Err(("`conf_file` must be a named value", arg.span));
                }
            }
            ast::MetaItemKind::NameValue(ref name, ref value) => {
                if name == &"conf_file" {
                    return if let ast::LitKind::Str(ref file, _) = value.node {
                        Ok(Some(file.to_string().into()))
                    } else {
                        Err(("`conf_file` value must be a string", value.span))
                    };
                }
            }
        }
    }

    Ok(None)
}

/// Error from reading a configuration file.
#[derive(Debug)]
pub enum Error {
    /// An I/O error.
    Io(io::Error),
    /// The file is not valid TOML.
    Toml(Vec<toml::ParserError>),
    /// Type error.
    Type(
        /// The name of the key.
        &'static str,
        /// The expected type.
        &'static str,
        /// The type we got instead.
        &'static str
    ),
    /// There is an unknown key is the file.
    UnknownKey(String),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Error::Io(ref err) => err.fmt(f),
            Error::Toml(ref errs) => {
                let mut first = true;
                for err in errs {
                    if !first {
                        try!(", ".fmt(f));
                        first = false;
                    }

                    try!(err.fmt(f));
                }

                Ok(())
            }
            Error::Type(key, expected, got) => {
                write!(f, "`{}` is expected to be a `{}` but is a `{}`", key, expected, got)
            }
            Error::UnknownKey(ref key) => write!(f, "unknown key `{}`", key),
        }
    }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Error::Io(e)
    }
}

macro_rules! define_Conf {
    ($(#[$doc: meta] ($toml_name: tt, $rust_name: ident, $default: expr => $($ty: tt)+),)+) => {
        /// Type used to store lint configuration.
        pub struct Conf {
            $(#[$doc] pub $rust_name: define_Conf!(TY $($ty)+),)+
        }

        impl Default for Conf {
            fn default() -> Conf {
                Conf {
                    $($rust_name: define_Conf!(DEFAULT $($ty)+, $default),)+
                }
            }
        }

        impl Conf {
            /// Set the property `name` (which must be the `toml` name) to the given value
            #[allow(cast_sign_loss)]
            fn set(&mut self, name: String, value: toml::Value) -> Result<(), Error> {
                match name.as_str() {
                    $(
                        define_Conf!(PAT $toml_name) => {
                            if let Some(value) = define_Conf!(CONV $($ty)+, value) {
                                self.$rust_name = value;
                            }
                            else {
                                return Err(Error::Type(define_Conf!(EXPR $toml_name),
                                                       stringify!($($ty)+),
                                                       value.type_str()));
                            }
                        },
                    )+
                    "third-party" => {
                        // for external tools such as clippy-service
                        return Ok(());
                    }
                    _ => {
                        return Err(Error::UnknownKey(name));
                    }
                }

                Ok(())
            }
        }
    };

    // hack to convert tts
    (PAT $pat: pat) => { $pat };
    (EXPR $e: expr) => { $e };
    (TY $ty: ty) => { $ty };

    // how to read the value?
    (CONV i64, $value: expr) => { $value.as_integer() };
    (CONV u64, $value: expr) => { $value.as_integer().iter().filter_map(|&i| if i >= 0 { Some(i as u64) } else { None }).next() };
    (CONV String, $value: expr) => { $value.as_str().map(Into::into) };
    (CONV Vec<String>, $value: expr) => {{
        let slice = $value.as_slice();

        if let Some(slice) = slice {
            if slice.iter().any(|v| v.as_str().is_none()) {
                None
            }
            else {
                Some(slice.iter().map(|v| v.as_str().unwrap_or_else(|| unreachable!()).to_owned()).collect())
            }
        }
        else {
            None
        }
    }};

    // provide a nicer syntax to declare the default value of `Vec<String>` variables
    (DEFAULT Vec<String>, $e: expr) => { $e.iter().map(|&e| e.to_owned()).collect() };
    (DEFAULT $ty: ty, $e: expr) => { $e };
}

define_Conf! {
    /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about
    ("blacklisted-names", blacklisted_names, ["foo", "bar", "baz"] => Vec<String>),
    /// Lint: CYCLOMATIC_COMPLEXITY. The maximum cyclomatic complexity a function can have
    ("cyclomatic-complexity-threshold", cyclomatic_complexity_threshold, 25 => u64),
    /// Lint: DOC_MARKDOWN. The list of words this lint should not consider as identifiers needing ticks
    ("doc-valid-idents", doc_valid_idents, ["MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "GPLv2", "GPLv3", "GitHub", "IPv4", "IPv6", "JavaScript", "NaN", "OAuth", "OpenGL", "TrueType", "iOS", "macOS"] => Vec<String>),
    /// Lint: TOO_MANY_ARGUMENTS. The maximum number of argument a function or method can have
    ("too-many-arguments-threshold", too_many_arguments_threshold, 7 => u64),
    /// Lint: TYPE_COMPLEXITY. The maximum complexity a type can have
    ("type-complexity-threshold", type_complexity_threshold, 250 => u64),
    /// Lint: MANY_SINGLE_CHAR_NAMES. The maximum number of single char bindings a scope may have
    ("single-char-binding-names-threshold", max_single_char_names, 5 => u64),
    /// Lint: BOXED_LOCAL. The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
    ("too-large-for-stack", too_large_for_stack, 200 => u64),
    /// Lint: ENUM_VARIANT_NAMES. The minimum number of enum variants for the lints about variant names to trigger
    ("enum-variant-name-threshold", enum_variant_name_threshold, 3 => u64),
}

/// Search for the configuration file.
pub fn lookup_conf_file() -> io::Result<Option<path::PathBuf>> {
    /// Possible filename to search for.
    const CONFIG_FILE_NAMES: [&'static str; 2] = [".clippy.toml", "clippy.toml"];

    let mut current = try!(env::current_dir());

    loop {
        for config_file_name in &CONFIG_FILE_NAMES {
            let config_file = current.join(config_file_name);
            match fs::metadata(&config_file) {
                // Only return if it's a file to handle the unlikely situation of a directory named
                // `clippy.toml`.
                Ok(ref md) if md.is_file() => return Ok(Some(config_file)),
                // Return the error if it's something other than `NotFound`; otherwise we didn't
                // find the project file yet, and continue searching.
                Err(e) => {
                    if e.kind() != io::ErrorKind::NotFound {
                        return Err(e);
                    }
                }
                _ => (),
            }
        }

        // If the current directory has no parent, we're done searching.
        if !current.pop() {
            return Ok(None);
        }
    }
}

/// Read the `toml` configuration file.
///
/// In case of error, the function tries to continue as much as possible.
pub fn read(path: Option<&path::Path>) -> (Conf, Vec<Error>) {
    let mut conf = Conf::default();
    let mut errors = Vec::new();

    let path = if let Some(path) = path {
        path
    } else {
        return (conf, errors);
    };

    let file = match fs::File::open(path) {
        Ok(mut file) => {
            let mut buf = String::new();

            if let Err(err) = file.read_to_string(&mut buf) {
                errors.push(err.into());
                return (conf, errors);
            }

            buf
        }
        Err(err) => {
            errors.push(err.into());
            return (conf, errors);
        }
    };

    let mut parser = toml::Parser::new(&file);
    let toml = if let Some(toml) = parser.parse() {
        toml
    } else {
        errors.push(Error::Toml(parser.errors));
        return (conf, errors);
    };

    for (key, value) in toml {
        if let Err(err) = conf.set(key, value) {
            errors.push(err);
        }
    }

    (conf, errors)
}
<commit_msg>Recognize quux as a metasyntactic variable<commit_after>//! Read configurations files.

#![deny(missing_docs_in_private_items)]

use std::{env, fmt, fs, io, path};
use std::io::Read;
use syntax::{ast, codemap};
use toml;

/// Get the configuration file from arguments.
pub fn file_from_args(args: &[codemap::Spanned<ast::NestedMetaItemKind>]) -> Result<Option<path::PathBuf>, (&'static str, codemap::Span)> {
    for arg in args.iter().filter_map(|a| a.meta_item()) {
        match arg.node {
            ast::MetaItemKind::Word(ref name) |
            ast::MetaItemKind::List(ref name, _) => {
                if name == &"conf_file" {
                    return Err(("`conf_file` must be a named value", arg.span));
                }
            }
            ast::MetaItemKind::NameValue(ref name, ref value) => {
                if name == &"conf_file" {
                    return if let ast::LitKind::Str(ref file, _) = value.node {
                        Ok(Some(file.to_string().into()))
                    } else {
                        Err(("`conf_file` value must be a string", value.span))
                    };
                }
            }
        }
    }

    Ok(None)
}

/// Error from reading a configuration file.
#[derive(Debug)]
pub enum Error {
    /// An I/O error.
    Io(io::Error),
    /// The file is not valid TOML.
    Toml(Vec<toml::ParserError>),
    /// Type error.
    Type(
        /// The name of the key.
        &'static str,
        /// The expected type.
        &'static str,
        /// The type we got instead.
        &'static str
    ),
    /// There is an unknown key is the file.
    UnknownKey(String),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Error::Io(ref err) => err.fmt(f),
            Error::Toml(ref errs) => {
                let mut first = true;
                for err in errs {
                    if !first {
                        try!(", ".fmt(f));
                        first = false;
                    }

                    try!(err.fmt(f));
                }

                Ok(())
            }
            Error::Type(key, expected, got) => {
                write!(f, "`{}` is expected to be a `{}` but is a `{}`", key, expected, got)
            }
            Error::UnknownKey(ref key) => write!(f, "unknown key `{}`", key),
        }
    }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Error::Io(e)
    }
}

macro_rules! define_Conf {
    ($(#[$doc: meta] ($toml_name: tt, $rust_name: ident, $default: expr => $($ty: tt)+),)+) => {
        /// Type used to store lint configuration.
        pub struct Conf {
            $(#[$doc] pub $rust_name: define_Conf!(TY $($ty)+),)+
        }

        impl Default for Conf {
            fn default() -> Conf {
                Conf {
                    $($rust_name: define_Conf!(DEFAULT $($ty)+, $default),)+
                }
            }
        }

        impl Conf {
            /// Set the property `name` (which must be the `toml` name) to the given value
            #[allow(cast_sign_loss)]
            fn set(&mut self, name: String, value: toml::Value) -> Result<(), Error> {
                match name.as_str() {
                    $(
                        define_Conf!(PAT $toml_name) => {
                            if let Some(value) = define_Conf!(CONV $($ty)+, value) {
                                self.$rust_name = value;
                            }
                            else {
                                return Err(Error::Type(define_Conf!(EXPR $toml_name),
                                                       stringify!($($ty)+),
                                                       value.type_str()));
                            }
                        },
                    )+
                    "third-party" => {
                        // for external tools such as clippy-service
                        return Ok(());
                    }
                    _ => {
                        return Err(Error::UnknownKey(name));
                    }
                }

                Ok(())
            }
        }
    };

    // hack to convert tts
    (PAT $pat: pat) => { $pat };
    (EXPR $e: expr) => { $e };
    (TY $ty: ty) => { $ty };

    // how to read the value?
    (CONV i64, $value: expr) => { $value.as_integer() };
    (CONV u64, $value: expr) => { $value.as_integer().iter().filter_map(|&i| if i >= 0 { Some(i as u64) } else { None }).next() };
    (CONV String, $value: expr) => { $value.as_str().map(Into::into) };
    (CONV Vec<String>, $value: expr) => {{
        let slice = $value.as_slice();

        if let Some(slice) = slice {
            if slice.iter().any(|v| v.as_str().is_none()) {
                None
            }
            else {
                Some(slice.iter().map(|v| v.as_str().unwrap_or_else(|| unreachable!()).to_owned()).collect())
            }
        }
        else {
            None
        }
    }};

    // provide a nicer syntax to declare the default value of `Vec<String>` variables
    (DEFAULT Vec<String>, $e: expr) => { $e.iter().map(|&e| e.to_owned()).collect() };
    (DEFAULT $ty: ty, $e: expr) => { $e };
}

define_Conf! {
    /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about
    ("blacklisted-names", blacklisted_names, ["foo", "bar", "baz", "quux"] => Vec<String>),
    /// Lint: CYCLOMATIC_COMPLEXITY. The maximum cyclomatic complexity a function can have
    ("cyclomatic-complexity-threshold", cyclomatic_complexity_threshold, 25 => u64),
    /// Lint: DOC_MARKDOWN. The list of words this lint should not consider as identifiers needing ticks
    ("doc-valid-idents", doc_valid_idents, ["MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "GPLv2", "GPLv3", "GitHub", "IPv4", "IPv6", "JavaScript", "NaN", "OAuth", "OpenGL", "TrueType", "iOS", "macOS"] => Vec<String>),
    /// Lint: TOO_MANY_ARGUMENTS. The maximum number of argument a function or method can have
    ("too-many-arguments-threshold", too_many_arguments_threshold, 7 => u64),
    /// Lint: TYPE_COMPLEXITY. The maximum complexity a type can have
    ("type-complexity-threshold", type_complexity_threshold, 250 => u64),
    /// Lint: MANY_SINGLE_CHAR_NAMES. The maximum number of single char bindings a scope may have
    ("single-char-binding-names-threshold", max_single_char_names, 5 => u64),
    /// Lint: BOXED_LOCAL. The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
    ("too-large-for-stack", too_large_for_stack, 200 => u64),
    /// Lint: ENUM_VARIANT_NAMES. The minimum number of enum variants for the lints about variant names to trigger
    ("enum-variant-name-threshold", enum_variant_name_threshold, 3 => u64),
}

/// Search for the configuration file.
pub fn lookup_conf_file() -> io::Result<Option<path::PathBuf>> {
    /// Possible filename to search for.
    const CONFIG_FILE_NAMES: [&'static str; 2] = [".clippy.toml", "clippy.toml"];

    let mut current = try!(env::current_dir());

    loop {
        for config_file_name in &CONFIG_FILE_NAMES {
            let config_file = current.join(config_file_name);
            match fs::metadata(&config_file) {
                // Only return if it's a file to handle the unlikely situation of a directory named
                // `clippy.toml`.
                Ok(ref md) if md.is_file() => return Ok(Some(config_file)),
                // Return the error if it's something other than `NotFound`; otherwise we didn't
                // find the project file yet, and continue searching.
                Err(e) => {
                    if e.kind() != io::ErrorKind::NotFound {
                        return Err(e);
                    }
                }
                _ => (),
            }
        }

        // If the current directory has no parent, we're done searching.
        if !current.pop() {
            return Ok(None);
        }
    }
}

/// Read the `toml` configuration file.
///
/// In case of error, the function tries to continue as much as possible.
pub fn read(path: Option<&path::Path>) -> (Conf, Vec<Error>) {
    let mut conf = Conf::default();
    let mut errors = Vec::new();

    let path = if let Some(path) = path {
        path
    } else {
        return (conf, errors);
    };

    let file = match fs::File::open(path) {
        Ok(mut file) => {
            let mut buf = String::new();

            if let Err(err) = file.read_to_string(&mut buf) {
                errors.push(err.into());
                return (conf, errors);
            }

            buf
        }
        Err(err) => {
            errors.push(err.into());
            return (conf, errors);
        }
    };

    let mut parser = toml::Parser::new(&file);
    let toml = if let Some(toml) = parser.parse() {
        toml
    } else {
        errors.push(Error::Toml(parser.errors));
        return (conf, errors);
    };

    for (key, value) in toml {
        if let Err(err) = conf.set(key, value) {
            errors.push(err);
        }
    }

    (conf, errors)
}
<|endoftext|>