<commit_before>use checksum::Crc8Reader;
use error::{FlacError, FlacResult};

#[deriving(Copy)]
enum BlockingStrategy {
    Fixed,
    Variable
}

#[deriving(Copy)]
enum BlockTime {
    FrameNumber(u32),
    SampleNumber(u64)
}

#[deriving(Copy)]
enum ChannelMode {
    /// The channels are coded as-is.
    Raw,
    /// Channel 0 is the left channel, channel 1 is the side channel.
    LeftSideStereo,
    /// Channel 0 is the side channel, channel 1 is the right channel.
    RightSideStereo,
    /// Channel 0 is the mid channel, channel 1 is the side channel.
    MidSideStereo
}

#[deriving(Copy)]
struct FrameHeader {
    pub block_time: BlockTime,
    pub block_size: u16,
    pub sample_rate: Option<u32>,
    pub n_channels: u8,
    pub channel_mode: ChannelMode,
    pub bits_per_sample: Option<u8>
    // TODO: there is also a sample or frame number.
}

/// Reads a variable-length integer encoded as what is called "UTF-8" coding
/// in the specification. (It is not real UTF-8.) This function can read
/// integers encoded in this way up to 36-bit integers.
fn read_var_length_int(input: &mut Reader) -> FlacResult<u64> {
    use std::iter::range_step_inclusive;
    use std::io::stdio::flush;
    // The number of consecutive 1s followed by a 0 is the number of additional
    // bytes to read.
    let first = try!(input.read_byte());
    let mut read_additional = 0u;
    let mut mask_data = 0b0111_1111u8;
    let mut mask_mark = 0b1000_0000u8;

    // Determine the number of leading 1s.
    while first & mask_mark != 0 {
        read_additional = read_additional + 1;
        mask_data = mask_data >> 1;
        mask_mark = mask_mark >> 1;
    }

    // A single leading 1 is a follow-up byte and thus invalid.
    if read_additional > 0 {
        if read_additional == 1 {
            return Err(FlacError::InvalidVarLengthInt);
        } else {
            // The number of 1s (if > 1) is the total number of bytes, not the
            // number of additional bytes.
            read_additional = read_additional - 1;
        }
    }

    // Each additional byte will yield 6 extra bits, so shift the most
    // significant bits into the correct position.
    let mut result = (first & mask_data) as u64 << (6 * read_additional);
    for i in range_step_inclusive(read_additional as int - 1, 0, -1) {
        let byte = try!(input.read_byte());

        // The two most significant bits _must_ be 10.
        if byte & 0b1100_0000 != 0b1000_0000 {
            return Err(FlacError::InvalidVarLengthInt);
        }

        result = result | ((byte & 0b0011_1111) as u64 << (6 * i as uint));
    }

    Ok(result)
}

#[test]
fn verify_read_var_length_int() {
    use std::io::MemReader;

    let mut reader = MemReader::new(vec!(0x24, 0xc2, 0xa2, 0xe2, 0x82, 0xac,
                                         0xf0, 0x90, 0x8d, 0x88, 0xc2, 0x00,
                                         0x80));
    assert_eq!(read_var_length_int(&mut reader).unwrap(), 0x24);
    assert_eq!(read_var_length_int(&mut reader).unwrap(), 0xa2);
    assert_eq!(read_var_length_int(&mut reader).unwrap(), 0x20ac);
    assert_eq!(read_var_length_int(&mut reader).unwrap(), 0x010348);
    // Two-byte integer with invalid continuation byte should fail.
    assert_eq!(read_var_length_int(&mut reader).err().unwrap(),
               FlacError::InvalidVarLengthInt);
    // Continuation byte can never be the first byte.
    assert_eq!(read_var_length_int(&mut reader).err().unwrap(),
               FlacError::InvalidVarLengthInt);
}

fn read_frame_header(input: &mut Reader) -> FlacResult<FrameHeader> {
    // The frame header includes a CRC-8 at the end. It can be computed
    // automatically while reading, by wrapping the input reader in a reader
    // that computes the CRC.
    let mut crc_input = Crc8Reader::new(input);

    // First are 14 bits frame sync code, a reserved bit, and blocking stategy.
    let sync_res_block = try!(crc_input.read_be_u16());

    // The first 14 bits must be 11111111111110.
    let sync_code = sync_res_block & 0b1111_1111_1111_1100;
    if sync_code != 0b1111_1111_1111_1000 {
        return Err(FlacError::MissingFrameSyncCode);
    }

    // The next bit has a mandatory value of 0 (at the moment of writing, if
    // the bit has a different value, it could be a future stream that we
    // cannot read).
    if sync_res_block & 0b0000_0000_0000_0010 != 0 {
        return Err(FlacError::InvalidFrameHeader);
    }

    // The final bit determines the blocking strategy.
    let blocking_strategy = if sync_res_block & 0b0000_0000_0000_0001 == 0 {
        BlockingStrategy::Fixed
    } else {
        BlockingStrategy::Variable
    };

    // Next are 4 bits block size and 4 bits sample rate.
    let bs_sr = try!(crc_input.read_byte());
    let mut block_size = 0u16;
    let mut read_8bit_bs = false;
    let mut read_16bit_bs = false;

    // There are some pre-defined bit patterns. Some mean 'get from end of
    // header instead'.
    match bs_sr >> 4 {
        // The value 0000 is reserved.
        0b0000 => return Err(FlacError::InvalidFrameHeader),
        0b0001 => block_size = 192,
        n if 0b0010 <= n && n <= 0b0101 => block_size = 576 * (1 << (n - 2) as uint),
        0b0110 => read_8bit_bs = true,
        0b0111 => read_16bit_bs = true,
        n => block_size = 256 * (1 << (n - 8) as uint)
    }

    // For the sample rate there is a number of pre-defined bit patterns as
    // well. Again, some mean 'get from end of header instead'.
    let mut sample_rate = None;
    let mut read_8bit_sr = false;
    let mut read_16bit_sr = false;
    let mut read_16bit_sr_ten = false;

    match bs_sr & 0b0000_1111 {
        0b0000 => sample_rate = None, // 0000 means 'get from streaminfo block'.
        0b0001 => sample_rate = Some( 88_200),
        0b0010 => sample_rate = Some(176_400),
        0b0011 => sample_rate = Some(192_000),
        0b0100 => sample_rate = Some(  8_000),
        0b0101 => sample_rate = Some( 16_000),
        0b0110 => sample_rate = Some( 22_050),
        0b0111 => sample_rate = Some( 24_000),
        0b1000 => sample_rate = Some( 32_000),
        0b1001 => sample_rate = Some( 44_100),
        0b1010 => sample_rate = Some( 48_000),
        0b1011 => sample_rate = Some( 96_000),
        0b1100 => read_8bit_sr = true, // Read Hz from end of header.
        0b1101 => read_16bit_sr = true, // Read Hz from end of header.
        0b1110 => read_16bit_sr_ten = true, // Read tens of Hz from end of header.
        // 1111 is invalid to prevent sync-fooling.
        // Other values are impossible at this point.
        _ => return Err(FlacError::InvalidFrameHeader)
    }

    // Next are 4 bits channel assignment, 3 bits sample size, and 1 reserved bit.
    let chan_bps_res = try!(crc_input.read_byte());

    // The most significant 4 bits determine channel assignment.
    let (n_channels, channel_mode) = match chan_bps_res >> 4 {
        // Values 0 through 7 indicate n + 1 channels without mixing.
        n if n < 8 => (n + 1, ChannelMode::Raw),
        0b1000 => (2, ChannelMode::LeftSideStereo),
        0b1001 => (2, ChannelMode::RightSideStereo),
        0b1010 => (2, ChannelMode::MidSideStereo),
        // Values 1011 through 1111 are reserved and thus invalid.
        _ => return Err(FlacError::InvalidFrameHeader)
    };

    // The next three bits indicate bits per sample.
    let bits_per_sample = match (chan_bps_res & 0b0000_1110) >> 1 {
        0b000 => None, // 000 means 'get from streaminfo block'.
        0b001 => Some(8),
        0b010 => Some(12),
        0b100 => Some(16),
        0b101 => Some(20),
        0b110 => Some(24),
        // Values 011 and 111 are reserved. Other values are impossible.
        _ => return Err(FlacError::InvalidFrameHeader)
    };

    // The final bit has a mandatory value of 0.
    if chan_bps_res & 0b0000_0001 != 0 {
        return Err(FlacError::InvalidFrameHeader);
    }

    let block_time = match blocking_strategy {
        BlockingStrategy::Variable => {
            // The sample number is encoded in 8-56 bits, at most a 36-bit int.
            let sample = try!(read_var_length_int(&mut crc_input));
            BlockTime::SampleNumber(sample)
        },
        BlockingStrategy::Fixed => {
            // The frame number is encoded in 8-48 bits, at most a 31-bit int.
            let frame = try!(read_var_length_int(&mut crc_input));
            // A frame number larger than 31 bits is therefore invalid.
            if frame > 0x7fffffff {
                return Err(FlacError::InvalidFrameHeader);
            }
            BlockTime::FrameNumber(frame as u32)
        }
    };

    if read_8bit_bs {
        // 8 bit block size - 1 is stored.
        let bs = try!(crc_input.read_byte());
        block_size = bs as u16 + 1;
    }
    if read_16bit_bs {
        // 16-bit block size - 1 is stored. Note that the max block size that
        // can be indicated in the streaminfo block is a 16-bit number, so a
        // value of 0xffff would be invalid because it exceeds the max block
        // size, though this is not mentioned explicitly in the specification.
        let bs = try!(crc_input.read_be_u16());
        if bs == 0xffff { return Err(FlacError::InvalidBlockSize); }
        block_size = bs + 1;
    }

    if read_8bit_sr {
        let sr = try!(crc_input.read_byte());
        sample_rate = Some(sr as u32);
    }
    if read_16bit_sr {
        let sr = try!(crc_input.read_be_u16());
        sample_rate = Some(sr as u32);
    }
    if read_16bit_sr_ten {
        let sr_ten = try!(crc_input.read_be_u16());
        sample_rate = Some(sr_ten as u32 * 10);
    }

    // Next is an 8-bit CRC that is computed over the entire header so far.
    let computed_crc = crc_input.crc();
    let presumed_crc = try!(crc_input.read_byte());

    if computed_crc != presumed_crc {
        return Err(FlacError::FrameHeaderCrcMismatch);
    }

    let frame_header = FrameHeader {
       block_time: block_time,
       block_size: block_size,
       sample_rate: sample_rate,
       n_channels: n_channels,
       channel_mode: channel_mode,
       bits_per_sample: bits_per_sample
    };
    Ok(frame_header)
}

/// Reads frames from a stream and exposes them as an iterator.
///
/// TODO: for now, it is assumes that the reader starts at a frame header;
/// no searching for a sync code is performed at the moment.
pub struct FrameReader<'r> {
    input: &'r mut (Reader + 'r),
}

/// TODO
struct Frame;

/// Either a `Frame` or a `FlacError`.
pub type FrameResult = FlacResult<Frame>;

impl<'r> FrameReader<'r> {

    /// Creates a new frame reader that will yield at least one element.
    pub fn new(input: &'r mut Reader) -> FrameReader<'r> {
        FrameReader { input: input }
    }

    fn read_next(&mut self) -> FrameResult {
        let header = try!(read_frame_header(self.input));
        // TODO: read the subframes and padding
        // TODO: read frame footer

        Ok(Frame)
    }
}

impl<'r> Iterator<FrameResult> for FrameReader<'r> {
    fn next(&mut self) -> Option<FrameResult> {
        // TODO: there needs to be a way to determine whether stream has ended.
        // In that case, we need to know the stream lengh, so we need to know
        // the streaminfo (which we might need anyway) ...
        Some(self.read_next())
    }

    // TODO: it would be possible to give quite an accurate size hint.
}
<commit_msg>add debug printing to frame header reading<commit_after>use checksum::Crc8Reader;
use error::{FlacError, FlacResult};

#[deriving(Copy)]
enum BlockingStrategy {
    Fixed,
    Variable
}

#[deriving(Copy)]
enum BlockTime {
    FrameNumber(u32),
    SampleNumber(u64)
}

#[deriving(Copy, Show)] // TODO: should not derive show.
enum ChannelMode {
    /// The channels are coded as-is.
    Raw,
    /// Channel 0 is the left channel, channel 1 is the side channel.
    LeftSideStereo,
    /// Channel 0 is the side channel, channel 1 is the right channel.
    RightSideStereo,
    /// Channel 0 is the mid channel, channel 1 is the side channel.
    MidSideStereo
}

#[deriving(Copy)]
struct FrameHeader {
    pub block_time: BlockTime,
    pub block_size: u16,
    pub sample_rate: Option<u32>,
    pub n_channels: u8,
    pub channel_mode: ChannelMode,
    pub bits_per_sample: Option<u8>
    // TODO: there is also a sample or frame number.
}

/// Reads a variable-length integer encoded as what is called "UTF-8" coding
/// in the specification. (It is not real UTF-8.) This function can read
/// integers encoded in this way up to 36-bit integers.
fn read_var_length_int(input: &mut Reader) -> FlacResult<u64> {
    use std::iter::range_step_inclusive;
    use std::io::stdio::flush;
    // The number of consecutive 1s followed by a 0 is the number of additional
    // bytes to read.
    let first = try!(input.read_byte());
    let mut read_additional = 0u;
    let mut mask_data = 0b0111_1111u8;
    let mut mask_mark = 0b1000_0000u8;

    // Determine the number of leading 1s.
    while first & mask_mark != 0 {
        read_additional = read_additional + 1;
        mask_data = mask_data >> 1;
        mask_mark = mask_mark >> 1;
    }

    // A single leading 1 is a follow-up byte and thus invalid.
    if read_additional > 0 {
        if read_additional == 1 {
            return Err(FlacError::InvalidVarLengthInt);
        } else {
            // The number of 1s (if > 1) is the total number of bytes, not the
            // number of additional bytes.
            read_additional = read_additional - 1;
        }
    }

    // Each additional byte will yield 6 extra bits, so shift the most
    // significant bits into the correct position.
    let mut result = (first & mask_data) as u64 << (6 * read_additional);
    for i in range_step_inclusive(read_additional as int - 1, 0, -1) {
        let byte = try!(input.read_byte());

        // The two most significant bits _must_ be 10.
        if byte & 0b1100_0000 != 0b1000_0000 {
            return Err(FlacError::InvalidVarLengthInt);
        }

        result = result | ((byte & 0b0011_1111) as u64 << (6 * i as uint));
    }

    Ok(result)
}

#[test]
fn verify_read_var_length_int() {
    use std::io::MemReader;

    let mut reader = MemReader::new(vec!(0x24, 0xc2, 0xa2, 0xe2, 0x82, 0xac,
                                         0xf0, 0x90, 0x8d, 0x88, 0xc2, 0x00,
                                         0x80));
    assert_eq!(read_var_length_int(&mut reader).unwrap(), 0x24);
    assert_eq!(read_var_length_int(&mut reader).unwrap(), 0xa2);
    assert_eq!(read_var_length_int(&mut reader).unwrap(), 0x20ac);
    assert_eq!(read_var_length_int(&mut reader).unwrap(), 0x010348);
    // Two-byte integer with invalid continuation byte should fail.
    assert_eq!(read_var_length_int(&mut reader).err().unwrap(),
               FlacError::InvalidVarLengthInt);
    // Continuation byte can never be the first byte.
    assert_eq!(read_var_length_int(&mut reader).err().unwrap(),
               FlacError::InvalidVarLengthInt);
}

fn read_frame_header(input: &mut Reader) -> FlacResult<FrameHeader> {
    // The frame header includes a CRC-8 at the end. It can be computed
    // automatically while reading, by wrapping the input reader in a reader
    // that computes the CRC.
    let mut crc_input = Crc8Reader::new(input);

    // First are 14 bits frame sync code, a reserved bit, and blocking stategy.
    let sync_res_block = try!(crc_input.read_be_u16());

    // The first 14 bits must be 11111111111110.
    let sync_code = sync_res_block & 0b1111_1111_1111_1100;
    if sync_code != 0b1111_1111_1111_1000 {
        return Err(FlacError::MissingFrameSyncCode);
    }

    // The next bit has a mandatory value of 0 (at the moment of writing, if
    // the bit has a different value, it could be a future stream that we
    // cannot read).
    if sync_res_block & 0b0000_0000_0000_0010 != 0 {
        return Err(FlacError::InvalidFrameHeader);
    }

    // The final bit determines the blocking strategy.
    let blocking_strategy = if sync_res_block & 0b0000_0000_0000_0001 == 0 {
        BlockingStrategy::Fixed
    } else {
        BlockingStrategy::Variable
    };

    // Next are 4 bits block size and 4 bits sample rate.
    let bs_sr = try!(crc_input.read_byte());
    let mut block_size = 0u16;
    let mut read_8bit_bs = false;
    let mut read_16bit_bs = false;

    // There are some pre-defined bit patterns. Some mean 'get from end of
    // header instead'.
    match bs_sr >> 4 {
        // The value 0000 is reserved.
        0b0000 => return Err(FlacError::InvalidFrameHeader),
        0b0001 => block_size = 192,
        n if 0b0010 <= n && n <= 0b0101 => block_size = 576 * (1 << (n - 2) as uint),
        0b0110 => read_8bit_bs = true,
        0b0111 => read_16bit_bs = true,
        n => block_size = 256 * (1 << (n - 8) as uint)
    }

    // For the sample rate there is a number of pre-defined bit patterns as
    // well. Again, some mean 'get from end of header instead'.
    let mut sample_rate = None;
    let mut read_8bit_sr = false;
    let mut read_16bit_sr = false;
    let mut read_16bit_sr_ten = false;

    match bs_sr & 0b0000_1111 {
        0b0000 => sample_rate = None, // 0000 means 'get from streaminfo block'.
        0b0001 => sample_rate = Some( 88_200),
        0b0010 => sample_rate = Some(176_400),
        0b0011 => sample_rate = Some(192_000),
        0b0100 => sample_rate = Some(  8_000),
        0b0101 => sample_rate = Some( 16_000),
        0b0110 => sample_rate = Some( 22_050),
        0b0111 => sample_rate = Some( 24_000),
        0b1000 => sample_rate = Some( 32_000),
        0b1001 => sample_rate = Some( 44_100),
        0b1010 => sample_rate = Some( 48_000),
        0b1011 => sample_rate = Some( 96_000),
        0b1100 => read_8bit_sr = true, // Read Hz from end of header.
        0b1101 => read_16bit_sr = true, // Read Hz from end of header.
        0b1110 => read_16bit_sr_ten = true, // Read tens of Hz from end of header.
        // 1111 is invalid to prevent sync-fooling.
        // Other values are impossible at this point.
        _ => return Err(FlacError::InvalidFrameHeader)
    }

    // Next are 4 bits channel assignment, 3 bits sample size, and 1 reserved bit.
    let chan_bps_res = try!(crc_input.read_byte());

    // The most significant 4 bits determine channel assignment.
    let (n_channels, channel_mode) = match chan_bps_res >> 4 {
        // Values 0 through 7 indicate n + 1 channels without mixing.
        n if n < 8 => (n + 1, ChannelMode::Raw),
        0b1000 => (2, ChannelMode::LeftSideStereo),
        0b1001 => (2, ChannelMode::RightSideStereo),
        0b1010 => (2, ChannelMode::MidSideStereo),
        // Values 1011 through 1111 are reserved and thus invalid.
        _ => return Err(FlacError::InvalidFrameHeader)
    };

    // The next three bits indicate bits per sample.
    let bits_per_sample = match (chan_bps_res & 0b0000_1110) >> 1 {
        0b000 => None, // 000 means 'get from streaminfo block'.
        0b001 => Some(8),
        0b010 => Some(12),
        0b100 => Some(16),
        0b101 => Some(20),
        0b110 => Some(24),
        // Values 011 and 111 are reserved. Other values are impossible.
        _ => return Err(FlacError::InvalidFrameHeader)
    };

    // The final bit has a mandatory value of 0.
    if chan_bps_res & 0b0000_0001 != 0 {
        return Err(FlacError::InvalidFrameHeader);
    }

    let block_time = match blocking_strategy {
        BlockingStrategy::Variable => {
            // The sample number is encoded in 8-56 bits, at most a 36-bit int.
            let sample = try!(read_var_length_int(&mut crc_input));
            BlockTime::SampleNumber(sample)
        },
        BlockingStrategy::Fixed => {
            // The frame number is encoded in 8-48 bits, at most a 31-bit int.
            let frame = try!(read_var_length_int(&mut crc_input));
            // A frame number larger than 31 bits is therefore invalid.
            if frame > 0x7fffffff {
                return Err(FlacError::InvalidFrameHeader);
            }
            BlockTime::FrameNumber(frame as u32)
        }
    };

    if read_8bit_bs {
        // 8 bit block size - 1 is stored.
        let bs = try!(crc_input.read_byte());
        block_size = bs as u16 + 1;
    }
    if read_16bit_bs {
        // 16-bit block size - 1 is stored. Note that the max block size that
        // can be indicated in the streaminfo block is a 16-bit number, so a
        // value of 0xffff would be invalid because it exceeds the max block
        // size, though this is not mentioned explicitly in the specification.
        let bs = try!(crc_input.read_be_u16());
        if bs == 0xffff { return Err(FlacError::InvalidBlockSize); }
        block_size = bs + 1;
    }

    if read_8bit_sr {
        let sr = try!(crc_input.read_byte());
        sample_rate = Some(sr as u32);
    }
    if read_16bit_sr {
        let sr = try!(crc_input.read_be_u16());
        sample_rate = Some(sr as u32);
    }
    if read_16bit_sr_ten {
        let sr_ten = try!(crc_input.read_be_u16());
        sample_rate = Some(sr_ten as u32 * 10);
    }

    // Next is an 8-bit CRC that is computed over the entire header so far.
    let computed_crc = crc_input.crc();
    let presumed_crc = try!(crc_input.read_byte());

    if computed_crc != presumed_crc {
        return Err(FlacError::FrameHeaderCrcMismatch);
    }

    let frame_header = FrameHeader {
       block_time: block_time,
       block_size: block_size,
       sample_rate: sample_rate,
       n_channels: n_channels,
       channel_mode: channel_mode,
       bits_per_sample: bits_per_sample
    };
    Ok(frame_header)
}

/// Reads frames from a stream and exposes them as an iterator.
///
/// TODO: for now, it is assumes that the reader starts at a frame header;
/// no searching for a sync code is performed at the moment.
pub struct FrameReader<'r> {
    input: &'r mut (Reader + 'r),
}

/// TODO
struct Frame;

/// Either a `Frame` or a `FlacError`.
pub type FrameResult = FlacResult<Frame>;

impl<'r> FrameReader<'r> {

    /// Creates a new frame reader that will yield at least one element.
    pub fn new(input: &'r mut Reader) -> FrameReader<'r> {
        FrameReader { input: input }
    }

    fn read_next(&mut self) -> FrameResult {
        let header = try!(read_frame_header(self.input));

        // TODO: remove this print.
        println!("Frame: bs = {}, sr = {}, n_ch = {}, cm = {}, bps = {}",
                 header.block_size,
                 header.sample_rate,
                 header.n_channels,
                 header.channel_mode,
                 header.bits_per_sample);

        // TODO: read the subframes and padding
        // TODO: read frame footer

        Ok(Frame)
    }
}

impl<'r> Iterator<FrameResult> for FrameReader<'r> {
    fn next(&mut self) -> Option<FrameResult> {
        // TODO: there needs to be a way to determine whether stream has ended.
        // In that case, we need to know the stream lengh, so we need to know
        // the streaminfo (which we might need anyway) ...
        Some(self.read_next())
    }

    // TODO: it would be possible to give quite an accurate size hint.
}
<|endoftext|>


<commit_before>use std::convert::TryFrom;

use blake2b_simd::{Params as Blake2bParams, State as Blake2b};
use blake2s_simd::{Params as Blake2sParams, State as Blake2s};
use digest::Digest;

use crate::digests::{wrap, Multihash, MultihashDigest, Multihasher};
use crate::errors::DecodeError;

#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_code {
    ($(
        #[$doc:meta]
        $name:ident => $code:expr,
    )*) => {
        /// The code of Multihash.
        #[derive(Clone, Copy, Debug, PartialEq, Eq)]
        pub enum Code {
            $(
                #[$doc]
                $name,
            )*
        }

        impl Code {
            /// Hash some input and return the raw binary digest.
            pub fn digest(&self, data: &[u8]) -> Multihash {
                match self {
                    $(Self::$name => $name::digest(data),)*
                }
            }
        }

        impl From<Code> for Box<dyn MultihashDigest<Code>> {
            fn from(code: Code) -> Self {
                match code {
                    $(Code::$name => Box::new($name::default()),)*
                }
            }
        }

        impl From<Code> for u64 {
            /// Return the code as integer value.
            fn from(code: Code) -> Self {
                match code {
                    $(Code::$name => $code,)*
                }
            }
        }

        impl TryFrom<u64> for Code {
            type Error = DecodeError;

            /// Return the `Code` based on the integer value. Error if no matching code exists.
            fn try_from(raw: u64) -> Result<Self, Self::Error> {
                match raw {
                    $($code => Ok(Self::$name),)*
                    _ => Err(DecodeError::UnknownCode),
                }
            }
        }
    };
}

#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! derive_digest {
    ($(
        #[$doc:meta]
        @sha $type:ty as $name:ident;
            @code_doc $code_doc:literal,
    )*) => {
        $(
            #[$doc]
            #[derive(Clone, Debug, Default)]
            pub struct $name($type);
            impl $name {
                #[doc = $code_doc]
                pub const CODE: Code = Code::$name;
                /// Hash some input and return the Multihash digest.
                #[inline]
                pub fn digest(data: &[u8]) -> Multihash {
                    let digest = <$type>::digest(&data);
                    wrap(Self::CODE, &digest)
                }
            }
            impl Multihasher<Code> for $name {
                const CODE: Code = Code::$name;
                #[inline]
                fn digest(data: &[u8]) -> Multihash {
                    Self::digest(data)
                }
            }
            impl MultihashDigest<Code> for $name {
                #[inline]
                fn code(&self) -> Code {
                    Self::CODE
                }
                #[inline]
                fn digest(&self, data: &[u8]) -> Multihash {
                    Self::digest(data)
                }
                #[inline]
                fn input(&mut self, data: &[u8]) {
                    self.0.input(data)
                }
                #[inline]
                fn result(self) -> Multihash {
                    wrap(Self::CODE, self.0.result().as_slice())
                }
                #[inline]
                fn result_reset(&mut self) -> Multihash {
                    wrap(Self::CODE, self.0.result_reset().as_slice())
                }
                #[inline]
                fn reset(&mut self) {
                    self.0.reset()
                }
            }
            impl ::std::io::Write for $name {
                #[inline]
                fn write(&mut self, buf: &[u8]) -> ::std::io::Result<usize> {
                    <$name as MultihashDigest<Code>>::input(self, buf);
                    Ok(buf.len())
                }
                #[inline]
                fn flush(&mut self) -> ::std::io::Result<()> {
                    Ok(())
                }
            }
        )*
    };
    ($(
        #[$doc:meta]
        @blake $type:ty | $params:ty as $name:ident $len:expr;
            @code_doc $code_doc:literal,
    )*) => {
        $(
            #[$doc]
            #[derive(Clone, Debug)]
            pub struct $name($type);
            impl $name {
                #[doc = $code_doc]
                pub const CODE: Code = Code::$name;
                /// Hash some input and return the Multihash digest.
                pub fn digest(data: &[u8]) -> Multihash {
                    let digest = <$params>::new().hash_length($len).hash(data);
                    wrap(Self::CODE, &digest.as_bytes())
                }
            }
            impl Default for $name {
                fn default() -> Self {
                    $name(<$params>::new().hash_length($len).to_state())
                }
            }
            impl Multihasher<Code> for $name {
                const CODE: Code = Code::$name;
                #[inline]
                fn digest(data: &[u8]) -> Multihash {
                    Self::digest(data)
                }
            }
            impl MultihashDigest<Code> for $name {
                #[inline]
                fn code(&self) -> Code {
                    Self::CODE
                }
                #[inline]
                fn digest(&self, data: &[u8]) -> Multihash {
                    Self::digest(data)
                }
                #[inline]
                fn input(&mut self, data: &[u8]) {
                    self.0.update(data);
                }
                #[inline]
                fn result(self) -> Multihash {
                    let digest = self.0.finalize();
                    wrap(Self::CODE, digest.as_bytes())
                }
                #[inline]
                fn result_reset(&mut self) -> Multihash {
                    let digest = self.0.finalize();
                    let hash = wrap(Self::CODE, digest.as_bytes());
                    self.reset();
                    hash
                }
                #[inline]
                fn reset(&mut self) {
                    self.0 = Self::default().0;
                }
            }
            impl ::std::io::Write for $name {
                #[inline]
                fn write(&mut self, buf: &[u8]) -> ::std::io::Result<usize> {
                    <$name as MultihashDigest<Code>>::input(self, buf);
                    Ok(buf.len())
                }
                #[inline]
                fn flush(&mut self) -> ::std::io::Result<()> {
                    self.0.finalize();
                    Ok(())
                }
            }
        )*
    };
}

impl_code! {
    /// Identity (Raw binary)
    Identity => 0x00,
    /// SHA-1 (20-byte hash size)
    Sha1 => 0x11,
    /// SHA-256 (32-byte hash size)
    Sha2_256 => 0x12,
    /// SHA-512 (64-byte hash size)
    Sha2_512 => 0x13,
    /// SHA3-224 (28-byte hash size)
    Sha3_224 => 0x17,
    /// SHA3-256 (32-byte hash size)
    Sha3_256 => 0x16,
    /// SHA3-384 (48-byte hash size)
    Sha3_384 => 0x15,
    /// SHA3-512 (64-byte hash size)
    Sha3_512 => 0x14,
    /// Keccak-224 (28-byte hash size)
    Keccak224 => 0x1a,
    /// Keccak-256 (32-byte hash size)
    Keccak256 => 0x1b,
    /// Keccak-384 (48-byte hash size)
    Keccak384 => 0x1c,
    /// Keccak-512 (64-byte hash size)
    Keccak512 => 0x1d,
    /// BLAKE2b-256 (32-byte hash size)
    Blake2b256 => 0xb220,
    /// BLAKE2b-512 (64-byte hash size)
    Blake2b512 => 0xb240,
    /// BLAKE2s-128 (16-byte hash size)
    Blake2s128 => 0xb250,
    /// BLAKE2s-256 (32-byte hash size)
    Blake2s256 => 0xb260,
}

/// The Identity hasher.
#[derive(Clone, Debug, Default)]
pub struct Identity(Vec<u8>);
impl Multihasher<Code> for Identity {
    const CODE: Code = Code::Identity;
    #[inline]
    fn digest(data: &[u8]) -> Multihash {
        Self::digest(data)
    }
}
impl MultihashDigest<Code> for Identity {
    #[inline]
    fn code(&self) -> Code {
        Self::CODE
    }
    #[inline]
    fn digest(&self, data: &[u8]) -> Multihash {
        Self::digest(data)
    }
    #[inline]
    fn input(&mut self, data: &[u8]) {
        if ((self.0.len() as u64) + (data.len() as u64)) >= u64::from(std::u32::MAX) {
            panic!("Input data for identity hash is too large, it needs to be less than 2^32.")
        }
        self.0.extend_from_slice(data)
    }
    #[inline]
    fn result(self) -> Multihash {
        wrap(Self::CODE, &self.0)
    }
    #[inline]
    fn result_reset(&mut self) -> Multihash {
        let hash = wrap(Self::CODE, &self.0);
        self.reset();
        hash
    }
    #[inline]
    fn reset(&mut self) {
        self.0.clear()
    }
}
impl Identity {
    /// The code of the Identity hasher, 0x00.
    pub const CODE: Code = Code::Identity;
    /// Hash some input and return the raw binary digest.
    pub fn digest(data: &[u8]) -> Multihash {
        if (data.len() as u64) >= u64::from(std::u32::MAX) {
            panic!("Input data for identity hash is too large, it needs to be less than 2^32.")
        }
        wrap(Self::CODE, data)
    }
}

derive_digest! {
    /// The SHA-1 hasher.
    @sha ::sha1::Sha1 as Sha1;
        @code_doc "The code of the SHA-1 hasher, 0x11.",
    /// The SHA2-256 hasher.
    @sha ::sha2::Sha256 as Sha2_256;
        @code_doc "The code of the SHA2-256 hasher, 0x12.",
    /// The SHA2-512 hasher.
    @sha ::sha2::Sha512 as Sha2_512;
        @code_doc "The code of the SHA2-512 hasher, 0x13.",
    /// The SHA3-224 hasher.
    @sha ::sha3::Sha3_224 as Sha3_224;
        @code_doc "The code of the SHA3-224 hasher, 0x17.",
    /// The SHA3-256 hasher.
    @sha ::sha3::Sha3_256 as Sha3_256;
        @code_doc "The code of the SHA3-256 hasher, 0x16.",
    /// The SHA3-384 hasher.
    @sha ::sha3::Sha3_384 as Sha3_384;
        @code_doc "The code of the SHA3-384 hasher, 0x15.",
    /// The SHA3-512 hasher.
    @sha ::sha3::Sha3_512 as Sha3_512;
        @code_doc "The code of the SHA3-512 hasher, 0x14.",
    /// The Keccak-224 hasher.
    @sha ::sha3::Keccak224 as Keccak224;
        @code_doc "The code of the Keccak-224 hasher, 0x1a.",
    /// The Keccak-256 hasher.
    @sha ::sha3::Keccak256 as Keccak256;
        @code_doc "The code of the Keccak-256 hasher, 0x1b.",
    /// The Keccak-384 hasher.
    @sha ::sha3::Keccak384 as Keccak384;
        @code_doc "The code of the Keccak-384 hasher, 0x1c.",
    /// The Keccak-512 hasher.
    @sha ::sha3::Keccak512 as Keccak512;
        @code_doc "The code of the Keccak-512 hasher, 0x1d.",
}
derive_digest! {
    /// The Blake2b-256 hasher.
    @blake Blake2b | Blake2bParams as Blake2b256 32;
        @code_doc "The code of the Blake2-256 hasher, 0xb220.",
    /// The Blake2b-512 hasher.
    @blake Blake2b | Blake2bParams as Blake2b512 64;
        @code_doc "The code of the Blake2-512 hasher, 0xb240.",
    /// The Blake2s-128 hasher.
    @blake Blake2s | Blake2sParams as Blake2s128 16;
        @code_doc "The code of the Blake2-128 hasher, 0xb250.",
    /// The Blake2s-256 hasher.
    @blake Blake2s | Blake2sParams as Blake2s256 32;
        @code_doc "The code of the Blake2-256 hasher, 0xb260.",
}
<commit_msg>feat: derive `PartialOrd`,`Ord` and `Hash` trait for `Code`<commit_after>use std::convert::TryFrom;

use blake2b_simd::{Params as Blake2bParams, State as Blake2b};
use blake2s_simd::{Params as Blake2sParams, State as Blake2s};
use digest::Digest;

use crate::digests::{wrap, Multihash, MultihashDigest, Multihasher};
use crate::errors::DecodeError;

#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_code {
    ($(
        #[$doc:meta]
        $name:ident => $code:expr,
    )*) => {
        /// The code of Multihash.
        #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
        pub enum Code {
            $(
                #[$doc]
                $name,
            )*
        }

        impl Code {
            /// Hash some input and return the raw binary digest.
            pub fn digest(&self, data: &[u8]) -> Multihash {
                match self {
                    $(Self::$name => $name::digest(data),)*
                }
            }
        }

        impl From<Code> for Box<dyn MultihashDigest<Code>> {
            fn from(code: Code) -> Self {
                match code {
                    $(Code::$name => Box::new($name::default()),)*
                }
            }
        }

        impl From<Code> for u64 {
            /// Return the code as integer value.
            fn from(code: Code) -> Self {
                match code {
                    $(Code::$name => $code,)*
                }
            }
        }

        impl TryFrom<u64> for Code {
            type Error = DecodeError;

            /// Return the `Code` based on the integer value. Error if no matching code exists.
            fn try_from(raw: u64) -> Result<Self, Self::Error> {
                match raw {
                    $($code => Ok(Self::$name),)*
                    _ => Err(DecodeError::UnknownCode),
                }
            }
        }
    };
}

#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! derive_digest {
    ($(
        #[$doc:meta]
        @sha $type:ty as $name:ident;
            @code_doc $code_doc:literal,
    )*) => {
        $(
            #[$doc]
            #[derive(Clone, Debug, Default)]
            pub struct $name($type);
            impl $name {
                #[doc = $code_doc]
                pub const CODE: Code = Code::$name;
                /// Hash some input and return the Multihash digest.
                #[inline]
                pub fn digest(data: &[u8]) -> Multihash {
                    let digest = <$type>::digest(&data);
                    wrap(Self::CODE, &digest)
                }
            }
            impl Multihasher<Code> for $name {
                const CODE: Code = Code::$name;
                #[inline]
                fn digest(data: &[u8]) -> Multihash {
                    Self::digest(data)
                }
            }
            impl MultihashDigest<Code> for $name {
                #[inline]
                fn code(&self) -> Code {
                    Self::CODE
                }
                #[inline]
                fn digest(&self, data: &[u8]) -> Multihash {
                    Self::digest(data)
                }
                #[inline]
                fn input(&mut self, data: &[u8]) {
                    self.0.input(data)
                }
                #[inline]
                fn result(self) -> Multihash {
                    wrap(Self::CODE, self.0.result().as_slice())
                }
                #[inline]
                fn result_reset(&mut self) -> Multihash {
                    wrap(Self::CODE, self.0.result_reset().as_slice())
                }
                #[inline]
                fn reset(&mut self) {
                    self.0.reset()
                }
            }
            impl ::std::io::Write for $name {
                #[inline]
                fn write(&mut self, buf: &[u8]) -> ::std::io::Result<usize> {
                    <$name as MultihashDigest<Code>>::input(self, buf);
                    Ok(buf.len())
                }
                #[inline]
                fn flush(&mut self) -> ::std::io::Result<()> {
                    Ok(())
                }
            }
        )*
    };
    ($(
        #[$doc:meta]
        @blake $type:ty | $params:ty as $name:ident $len:expr;
            @code_doc $code_doc:literal,
    )*) => {
        $(
            #[$doc]
            #[derive(Clone, Debug)]
            pub struct $name($type);
            impl $name {
                #[doc = $code_doc]
                pub const CODE: Code = Code::$name;
                /// Hash some input and return the Multihash digest.
                pub fn digest(data: &[u8]) -> Multihash {
                    let digest = <$params>::new().hash_length($len).hash(data);
                    wrap(Self::CODE, &digest.as_bytes())
                }
            }
            impl Default for $name {
                fn default() -> Self {
                    $name(<$params>::new().hash_length($len).to_state())
                }
            }
            impl Multihasher<Code> for $name {
                const CODE: Code = Code::$name;
                #[inline]
                fn digest(data: &[u8]) -> Multihash {
                    Self::digest(data)
                }
            }
            impl MultihashDigest<Code> for $name {
                #[inline]
                fn code(&self) -> Code {
                    Self::CODE
                }
                #[inline]
                fn digest(&self, data: &[u8]) -> Multihash {
                    Self::digest(data)
                }
                #[inline]
                fn input(&mut self, data: &[u8]) {
                    self.0.update(data);
                }
                #[inline]
                fn result(self) -> Multihash {
                    let digest = self.0.finalize();
                    wrap(Self::CODE, digest.as_bytes())
                }
                #[inline]
                fn result_reset(&mut self) -> Multihash {
                    let digest = self.0.finalize();
                    let hash = wrap(Self::CODE, digest.as_bytes());
                    self.reset();
                    hash
                }
                #[inline]
                fn reset(&mut self) {
                    self.0 = Self::default().0;
                }
            }
            impl ::std::io::Write for $name {
                #[inline]
                fn write(&mut self, buf: &[u8]) -> ::std::io::Result<usize> {
                    <$name as MultihashDigest<Code>>::input(self, buf);
                    Ok(buf.len())
                }
                #[inline]
                fn flush(&mut self) -> ::std::io::Result<()> {
                    self.0.finalize();
                    Ok(())
                }
            }
        )*
    };
}

impl_code! {
    /// Identity (Raw binary)
    Identity => 0x00,
    /// SHA-1 (20-byte hash size)
    Sha1 => 0x11,
    /// SHA-256 (32-byte hash size)
    Sha2_256 => 0x12,
    /// SHA-512 (64-byte hash size)
    Sha2_512 => 0x13,
    /// SHA3-224 (28-byte hash size)
    Sha3_224 => 0x17,
    /// SHA3-256 (32-byte hash size)
    Sha3_256 => 0x16,
    /// SHA3-384 (48-byte hash size)
    Sha3_384 => 0x15,
    /// SHA3-512 (64-byte hash size)
    Sha3_512 => 0x14,
    /// Keccak-224 (28-byte hash size)
    Keccak224 => 0x1a,
    /// Keccak-256 (32-byte hash size)
    Keccak256 => 0x1b,
    /// Keccak-384 (48-byte hash size)
    Keccak384 => 0x1c,
    /// Keccak-512 (64-byte hash size)
    Keccak512 => 0x1d,
    /// BLAKE2b-256 (32-byte hash size)
    Blake2b256 => 0xb220,
    /// BLAKE2b-512 (64-byte hash size)
    Blake2b512 => 0xb240,
    /// BLAKE2s-128 (16-byte hash size)
    Blake2s128 => 0xb250,
    /// BLAKE2s-256 (32-byte hash size)
    Blake2s256 => 0xb260,
}

/// The Identity hasher.
#[derive(Clone, Debug, Default)]
pub struct Identity(Vec<u8>);
impl Multihasher<Code> for Identity {
    const CODE: Code = Code::Identity;
    #[inline]
    fn digest(data: &[u8]) -> Multihash {
        Self::digest(data)
    }
}
impl MultihashDigest<Code> for Identity {
    #[inline]
    fn code(&self) -> Code {
        Self::CODE
    }
    #[inline]
    fn digest(&self, data: &[u8]) -> Multihash {
        Self::digest(data)
    }
    #[inline]
    fn input(&mut self, data: &[u8]) {
        if ((self.0.len() as u64) + (data.len() as u64)) >= u64::from(std::u32::MAX) {
            panic!("Input data for identity hash is too large, it needs to be less than 2^32.")
        }
        self.0.extend_from_slice(data)
    }
    #[inline]
    fn result(self) -> Multihash {
        wrap(Self::CODE, &self.0)
    }
    #[inline]
    fn result_reset(&mut self) -> Multihash {
        let hash = wrap(Self::CODE, &self.0);
        self.reset();
        hash
    }
    #[inline]
    fn reset(&mut self) {
        self.0.clear()
    }
}
impl Identity {
    /// The code of the Identity hasher, 0x00.
    pub const CODE: Code = Code::Identity;
    /// Hash some input and return the raw binary digest.
    pub fn digest(data: &[u8]) -> Multihash {
        if (data.len() as u64) >= u64::from(std::u32::MAX) {
            panic!("Input data for identity hash is too large, it needs to be less than 2^32.")
        }
        wrap(Self::CODE, data)
    }
}

derive_digest! {
    /// The SHA-1 hasher.
    @sha ::sha1::Sha1 as Sha1;
        @code_doc "The code of the SHA-1 hasher, 0x11.",
    /// The SHA2-256 hasher.
    @sha ::sha2::Sha256 as Sha2_256;
        @code_doc "The code of the SHA2-256 hasher, 0x12.",
    /// The SHA2-512 hasher.
    @sha ::sha2::Sha512 as Sha2_512;
        @code_doc "The code of the SHA2-512 hasher, 0x13.",
    /// The SHA3-224 hasher.
    @sha ::sha3::Sha3_224 as Sha3_224;
        @code_doc "The code of the SHA3-224 hasher, 0x17.",
    /// The SHA3-256 hasher.
    @sha ::sha3::Sha3_256 as Sha3_256;
        @code_doc "The code of the SHA3-256 hasher, 0x16.",
    /// The SHA3-384 hasher.
    @sha ::sha3::Sha3_384 as Sha3_384;
        @code_doc "The code of the SHA3-384 hasher, 0x15.",
    /// The SHA3-512 hasher.
    @sha ::sha3::Sha3_512 as Sha3_512;
        @code_doc "The code of the SHA3-512 hasher, 0x14.",
    /// The Keccak-224 hasher.
    @sha ::sha3::Keccak224 as Keccak224;
        @code_doc "The code of the Keccak-224 hasher, 0x1a.",
    /// The Keccak-256 hasher.
    @sha ::sha3::Keccak256 as Keccak256;
        @code_doc "The code of the Keccak-256 hasher, 0x1b.",
    /// The Keccak-384 hasher.
    @sha ::sha3::Keccak384 as Keccak384;
        @code_doc "The code of the Keccak-384 hasher, 0x1c.",
    /// The Keccak-512 hasher.
    @sha ::sha3::Keccak512 as Keccak512;
        @code_doc "The code of the Keccak-512 hasher, 0x1d.",
}
derive_digest! {
    /// The Blake2b-256 hasher.
    @blake Blake2b | Blake2bParams as Blake2b256 32;
        @code_doc "The code of the Blake2-256 hasher, 0xb220.",
    /// The Blake2b-512 hasher.
    @blake Blake2b | Blake2bParams as Blake2b512 64;
        @code_doc "The code of the Blake2-512 hasher, 0xb240.",
    /// The Blake2s-128 hasher.
    @blake Blake2s | Blake2sParams as Blake2s128 16;
        @code_doc "The code of the Blake2-128 hasher, 0xb250.",
    /// The Blake2s-256 hasher.
    @blake Blake2s | Blake2sParams as Blake2s256 32;
        @code_doc "The code of the Blake2-256 hasher, 0xb260.",
}
<|endoftext|>


<commit_before>//! Adapts the HTTP/1.1 implementation into the `HttpMessage` API.
use std::io::{self, Write, BufWriter, Read};
use std::net::Shutdown;

use method::{Method};
use header::{ContentLength, TransferEncoding};
use header::Encoding::Chunked;
use http::{HttpWriter, LINE_ENDING};
use http::HttpReader::{SizedReader, ChunkedReader, EofReader};
use http::HttpWriter::{ChunkedWriter, SizedWriter, EmptyWriter};
use buffer::BufReader;
use http::{self, HttpReader};

use message::{
    HttpMessage,
    RequestHead,
    ResponseHead,
};
use net::NetworkStream;
use header;
use version;

/// An implementation of the `HttpMessage` trait for HTTP/1.1.
#[derive(Debug)]
pub struct Http11Message {
    stream: Option<Box<NetworkStream + Send>>,
    writer: Option<HttpWriter<BufWriter<Box<NetworkStream + Send>>>>,
    reader: Option<HttpReader<BufReader<Box<NetworkStream + Send>>>>,
}

impl Write for Http11Message {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        match self.writer {
            None => Err(io::Error::new(io::ErrorKind::Other,
                                          "Not in a writable state")),
            Some(ref mut writer) => writer.write(buf),
        }
    }
    #[inline]
    fn flush(&mut self) -> io::Result<()> {
        match self.writer {
            None => Err(io::Error::new(io::ErrorKind::Other,
                                          "Not in a writable state")),
            Some(ref mut writer) => writer.flush(),
        }
    }
}

impl Read for Http11Message {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match self.reader {
            None => Err(io::Error::new(io::ErrorKind::Other,
                                          "Not in a readable state")),
            Some(ref mut reader) => reader.read(buf),
        }
    }
}

impl HttpMessage for Http11Message {
    fn set_outgoing(&mut self, mut head: RequestHead) -> ::Result<RequestHead> {
        if self.stream.is_none() {
            return Err(From::from(io::Error::new(
                        io::ErrorKind::Other,
                        "Message not idle, cannot start new outgoing")));
        }
        let mut stream = BufWriter::new(self.stream.take().unwrap());

        let mut uri = head.url.serialize_path().unwrap();
        if let Some(ref q) = head.url.query {
            uri.push('?');
            uri.push_str(&q[..]);
        }

        let version = version::HttpVersion::Http11;
        debug!("request line: {:?} {:?} {:?}", head.method, uri, version);
        try!(write!(&mut stream, "{} {} {}{}",
                    head.method, uri, version, LINE_ENDING));

        let stream = match head.method {
            Method::Get | Method::Head => {
                debug!("headers={:?}", head.headers);
                try!(write!(&mut stream, "{}{}", head.headers, LINE_ENDING));
                EmptyWriter(stream)
            },
            _ => {
                let mut chunked = true;
                let mut len = 0;

                match head.headers.get::<header::ContentLength>() {
                    Some(cl) => {
                        chunked = false;
                        len = **cl;
                    },
                    None => ()
                };

                // can't do in match above, thanks borrowck
                if chunked {
                    let encodings = match head.headers.get_mut::<header::TransferEncoding>() {
                        Some(&mut header::TransferEncoding(ref mut encodings)) => {
                            //TODO: check if chunked is already in encodings. use HashSet?
                            encodings.push(header::Encoding::Chunked);
                            false
                        },
                        None => true
                    };

                    if encodings {
                        head.headers.set::<header::TransferEncoding>(
                            header::TransferEncoding(vec![header::Encoding::Chunked]))
                    }
                }

                debug!("headers={:?}", head.headers);
                try!(write!(&mut stream, "{}{}", head.headers, LINE_ENDING));

                if chunked {
                    ChunkedWriter(stream)
                } else {
                    SizedWriter(stream, len)
                }
            }
        };

        self.writer = Some(stream);

        Ok(head)
    }

    fn get_incoming(&mut self) -> ::Result<ResponseHead> {
        try!(self.flush_outgoing());
        if self.stream.is_none() {
            // The message was already in the reading state...
            // TODO Decide what happens in case we try to get a new incoming at that point
            return Err(From::from(
                    io::Error::new(io::ErrorKind::Other,
                    "Read already in progress")));
        }

        let stream = self.stream.take().unwrap();
        let mut stream = BufReader::new(stream);

        let head = try!(http::parse_response(&mut stream));
        let raw_status = head.subject;
        let headers = head.headers;

        let body = if headers.has::<TransferEncoding>() {
            match headers.get::<TransferEncoding>() {
                Some(&TransferEncoding(ref codings)) => {
                    if codings.len() > 1 {
                        trace!("TODO: #2 handle other codings: {:?}", codings);
                    };

                    if codings.contains(&Chunked) {
                        ChunkedReader(stream, None)
                    } else {
                        trace!("not chuncked. read till eof");
                        EofReader(stream)
                    }
                }
                None => unreachable!()
            }
        } else if headers.has::<ContentLength>() {
            match headers.get::<ContentLength>() {
                Some(&ContentLength(len)) => SizedReader(stream, len),
                None => unreachable!()
            }
        } else {
            trace!("neither Transfer-Encoding nor Content-Length");
            EofReader(stream)
        };

        self.reader = Some(body);

        Ok(ResponseHead {
            headers: headers,
            raw_status: raw_status,
            version: head.version,
        })
    }

    fn close_connection(&mut self) -> ::Result<()> {
        try!(self.get_mut().close(Shutdown::Both));
        Ok(())
    }
}

impl Http11Message {
    /// Consumes the `Http11Message` and returns the underlying `NetworkStream`.
    pub fn into_inner(mut self) -> Box<NetworkStream + Send> {
        if self.stream.is_some() {
            self.stream.take().unwrap()
        } else if self.writer.is_some() {
            self.writer.take().unwrap().into_inner().into_inner().unwrap()
        } else if self.reader.is_some() {
            self.reader.take().unwrap().into_inner().into_inner()
        } else {
            panic!("Http11Message lost its underlying stream somehow");
        }
    }

    /// Gets a mutable reference to the underlying `NetworkStream`, regardless of the state of the
    /// `Http11Message`.
    pub fn get_mut(&mut self) -> &mut Box<NetworkStream + Send> {
        if self.stream.is_some() {
            self.stream.as_mut().unwrap()
        } else if self.writer.is_some() {
            self.writer.as_mut().unwrap().get_mut().get_mut()
        } else if self.reader.is_some() {
            self.reader.as_mut().unwrap().get_mut().get_mut()
        } else {
            panic!("Http11Message lost its underlying stream somehow");
        }
    }

    /// Creates a new `Http11Message` that will use the given `NetworkStream` for communicating to
    /// the peer.
    pub fn with_stream(stream: Box<NetworkStream + Send>) -> Http11Message {
        Http11Message {
            stream: Some(stream),
            writer: None,
            reader: None,
        }
    }

    /// Flushes the current outgoing content and moves the stream into the `stream` property.
    ///
    /// TODO It might be sensible to lift this up to the `HttpMessage` trait itself...
    pub fn flush_outgoing(&mut self) -> ::Result<()> {
        match self.writer {
            None => return Ok(()),
            Some(_) => {},
        };

        let writer = self.writer.take().unwrap();
        let raw = try!(writer.end()).into_inner().unwrap(); // end() already flushes
        self.stream = Some(raw);

        Ok(())
    }
}
<commit_msg>feat(client): implement Protocol trait for HTTP/1.1<commit_after>//! Adapts the HTTP/1.1 implementation into the `HttpMessage` API.
use std::io::{self, Write, BufWriter, Read};
use std::net::Shutdown;

use method::{Method};
use header::{ContentLength, TransferEncoding};
use header::Encoding::Chunked;

use net::{NetworkConnector, NetworkStream, ContextVerifier};
use http::{HttpWriter, LINE_ENDING};
use http::HttpReader::{SizedReader, ChunkedReader, EofReader};
use http::HttpWriter::{ChunkedWriter, SizedWriter, EmptyWriter};
use buffer::BufReader;
use http::{self, HttpReader};

use message::{
    Protocol,
    HttpMessage,
    RequestHead,
    ResponseHead,
};
use header;
use version;

/// An implementation of the `HttpMessage` trait for HTTP/1.1.
#[derive(Debug)]
pub struct Http11Message {
    stream: Option<Box<NetworkStream + Send>>,
    writer: Option<HttpWriter<BufWriter<Box<NetworkStream + Send>>>>,
    reader: Option<HttpReader<BufReader<Box<NetworkStream + Send>>>>,
}

impl Write for Http11Message {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        match self.writer {
            None => Err(io::Error::new(io::ErrorKind::Other,
                                          "Not in a writable state")),
            Some(ref mut writer) => writer.write(buf),
        }
    }
    #[inline]
    fn flush(&mut self) -> io::Result<()> {
        match self.writer {
            None => Err(io::Error::new(io::ErrorKind::Other,
                                          "Not in a writable state")),
            Some(ref mut writer) => writer.flush(),
        }
    }
}

impl Read for Http11Message {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match self.reader {
            None => Err(io::Error::new(io::ErrorKind::Other,
                                          "Not in a readable state")),
            Some(ref mut reader) => reader.read(buf),
        }
    }
}

impl HttpMessage for Http11Message {
    fn set_outgoing(&mut self, mut head: RequestHead) -> ::Result<RequestHead> {
        if self.stream.is_none() {
            return Err(From::from(io::Error::new(
                        io::ErrorKind::Other,
                        "Message not idle, cannot start new outgoing")));
        }
        let mut stream = BufWriter::new(self.stream.take().unwrap());

        let mut uri = head.url.serialize_path().unwrap();
        if let Some(ref q) = head.url.query {
            uri.push('?');
            uri.push_str(&q[..]);
        }

        let version = version::HttpVersion::Http11;
        debug!("request line: {:?} {:?} {:?}", head.method, uri, version);
        try!(write!(&mut stream, "{} {} {}{}",
                    head.method, uri, version, LINE_ENDING));

        let stream = match head.method {
            Method::Get | Method::Head => {
                debug!("headers={:?}", head.headers);
                try!(write!(&mut stream, "{}{}", head.headers, LINE_ENDING));
                EmptyWriter(stream)
            },
            _ => {
                let mut chunked = true;
                let mut len = 0;

                match head.headers.get::<header::ContentLength>() {
                    Some(cl) => {
                        chunked = false;
                        len = **cl;
                    },
                    None => ()
                };

                // can't do in match above, thanks borrowck
                if chunked {
                    let encodings = match head.headers.get_mut::<header::TransferEncoding>() {
                        Some(&mut header::TransferEncoding(ref mut encodings)) => {
                            //TODO: check if chunked is already in encodings. use HashSet?
                            encodings.push(header::Encoding::Chunked);
                            false
                        },
                        None => true
                    };

                    if encodings {
                        head.headers.set::<header::TransferEncoding>(
                            header::TransferEncoding(vec![header::Encoding::Chunked]))
                    }
                }

                debug!("headers={:?}", head.headers);
                try!(write!(&mut stream, "{}{}", head.headers, LINE_ENDING));

                if chunked {
                    ChunkedWriter(stream)
                } else {
                    SizedWriter(stream, len)
                }
            }
        };

        self.writer = Some(stream);

        Ok(head)
    }

    fn get_incoming(&mut self) -> ::Result<ResponseHead> {
        try!(self.flush_outgoing());
        if self.stream.is_none() {
            // The message was already in the reading state...
            // TODO Decide what happens in case we try to get a new incoming at that point
            return Err(From::from(
                    io::Error::new(io::ErrorKind::Other,
                    "Read already in progress")));
        }

        let stream = self.stream.take().unwrap();
        let mut stream = BufReader::new(stream);

        let head = try!(http::parse_response(&mut stream));
        let raw_status = head.subject;
        let headers = head.headers;

        let body = if headers.has::<TransferEncoding>() {
            match headers.get::<TransferEncoding>() {
                Some(&TransferEncoding(ref codings)) => {
                    if codings.len() > 1 {
                        trace!("TODO: #2 handle other codings: {:?}", codings);
                    };

                    if codings.contains(&Chunked) {
                        ChunkedReader(stream, None)
                    } else {
                        trace!("not chuncked. read till eof");
                        EofReader(stream)
                    }
                }
                None => unreachable!()
            }
        } else if headers.has::<ContentLength>() {
            match headers.get::<ContentLength>() {
                Some(&ContentLength(len)) => SizedReader(stream, len),
                None => unreachable!()
            }
        } else {
            trace!("neither Transfer-Encoding nor Content-Length");
            EofReader(stream)
        };

        self.reader = Some(body);

        Ok(ResponseHead {
            headers: headers,
            raw_status: raw_status,
            version: head.version,
        })
    }

    fn close_connection(&mut self) -> ::Result<()> {
        try!(self.get_mut().close(Shutdown::Both));
        Ok(())
    }
}

impl Http11Message {
    /// Consumes the `Http11Message` and returns the underlying `NetworkStream`.
    pub fn into_inner(mut self) -> Box<NetworkStream + Send> {
        if self.stream.is_some() {
            self.stream.take().unwrap()
        } else if self.writer.is_some() {
            self.writer.take().unwrap().into_inner().into_inner().unwrap()
        } else if self.reader.is_some() {
            self.reader.take().unwrap().into_inner().into_inner()
        } else {
            panic!("Http11Message lost its underlying stream somehow");
        }
    }

    /// Gets a mutable reference to the underlying `NetworkStream`, regardless of the state of the
    /// `Http11Message`.
    pub fn get_mut(&mut self) -> &mut Box<NetworkStream + Send> {
        if self.stream.is_some() {
            self.stream.as_mut().unwrap()
        } else if self.writer.is_some() {
            self.writer.as_mut().unwrap().get_mut().get_mut()
        } else if self.reader.is_some() {
            self.reader.as_mut().unwrap().get_mut().get_mut()
        } else {
            panic!("Http11Message lost its underlying stream somehow");
        }
    }

    /// Creates a new `Http11Message` that will use the given `NetworkStream` for communicating to
    /// the peer.
    pub fn with_stream(stream: Box<NetworkStream + Send>) -> Http11Message {
        Http11Message {
            stream: Some(stream),
            writer: None,
            reader: None,
        }
    }

    /// Flushes the current outgoing content and moves the stream into the `stream` property.
    ///
    /// TODO It might be sensible to lift this up to the `HttpMessage` trait itself...
    pub fn flush_outgoing(&mut self) -> ::Result<()> {
        match self.writer {
            None => return Ok(()),
            Some(_) => {},
        };

        let writer = self.writer.take().unwrap();
        let raw = try!(writer.end()).into_inner().unwrap(); // end() already flushes
        self.stream = Some(raw);

        Ok(())
    }
}

/// The `Protocol` implementation provides HTTP/1.1 messages.
pub struct Http11Protocol {
    connector: Connector,
}

impl Protocol for Http11Protocol {
    fn new_message(&self, host: &str, port: u16, scheme: &str) -> ::Result<Box<HttpMessage>> {
        let stream = try!(self.connector.connect(host, port, scheme)).into();

        Ok(Box::new(Http11Message::with_stream(stream)))
    }

    #[inline]
    fn set_ssl_verifier(&mut self, verifier: ContextVerifier) {
        self.connector.set_ssl_verifier(verifier);
    }
}

impl Http11Protocol {
    /// Creates a new `Http11Protocol` instance that will use the given `NetworkConnector` for
    /// establishing HTTP connections.
    pub fn with_connector<C, S>(c: C) -> Http11Protocol
            where C: NetworkConnector<Stream=S> + Send + 'static,
                  S: NetworkStream + Send {
        Http11Protocol {
            connector: Connector(Box::new(ConnAdapter(c))),
        }
    }
}

struct ConnAdapter<C: NetworkConnector + Send>(C);

impl<C: NetworkConnector<Stream=S> + Send, S: NetworkStream + Send> NetworkConnector for ConnAdapter<C> {
    type Stream = Box<NetworkStream + Send>;
    #[inline]
    fn connect(&self, host: &str, port: u16, scheme: &str)
        -> ::Result<Box<NetworkStream + Send>> {
        Ok(try!(self.0.connect(host, port, scheme)).into())
    }
    #[inline]
    fn set_ssl_verifier(&mut self, verifier: ContextVerifier) {
        self.0.set_ssl_verifier(verifier);
    }
}

struct Connector(Box<NetworkConnector<Stream=Box<NetworkStream + Send>> + Send>);

impl NetworkConnector for Connector {
    type Stream = Box<NetworkStream + Send>;
    #[inline]
    fn connect(&self, host: &str, port: u16, scheme: &str)
        -> ::Result<Box<NetworkStream + Send>> {
        Ok(try!(self.0.connect(host, port, scheme)).into())
    }
    #[inline]
    fn set_ssl_verifier(&mut self, verifier: ContextVerifier) {
        self.0.set_ssl_verifier(verifier);
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![feature(rustc_private)]
#![feature(str_strip)]

// FIXME: switch to something more ergonomic here, once available.
// (Currently there is no way to opt into sysroot crates without `extern crate`.)
#[allow(unused_extern_crates)]
extern crate rustc;
#[allow(unused_extern_crates)]
extern crate rustc_driver;
#[allow(unused_extern_crates)]
extern crate rustc_errors;
#[allow(unused_extern_crates)]
extern crate rustc_interface;

use rustc::ty::TyCtxt;
use rustc_interface::interface;
use rustc_tools_util::*;

use lazy_static::lazy_static;
use std::borrow::Cow;
use std::env;
use std::ops::Deref;
use std::panic;
use std::path::{Path, PathBuf};
use std::process::{exit, Command};

mod lintlist;

/// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If
/// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`.
fn arg_value<'a, T: Deref<Target = str>>(
    args: &'a [T],
    find_arg: &str,
    pred: impl Fn(&str) -> bool,
) -> Option<&'a str> {
    let mut args = args.iter().map(Deref::deref);
    while let Some(arg) = args.next() {
        let mut arg = arg.splitn(2, '=');
        if arg.next() != Some(find_arg) {
            continue;
        }

        match arg.next().or_else(|| args.next()) {
            Some(v) if pred(v) => return Some(v),
            _ => {},
        }
    }
    None
}

#[test]
fn test_arg_value() {
    let args = &["--bar=bar", "--foobar", "123", "--foo"];

    assert_eq!(arg_value(&[] as &[&str], "--foobar", |_| true), None);
    assert_eq!(arg_value(args, "--bar", |_| false), None);
    assert_eq!(arg_value(args, "--bar", |_| true), Some("bar"));
    assert_eq!(arg_value(args, "--bar", |p| p == "bar"), Some("bar"));
    assert_eq!(arg_value(args, "--bar", |p| p == "foo"), None);
    assert_eq!(arg_value(args, "--foobar", |p| p == "foo"), None);
    assert_eq!(arg_value(args, "--foobar", |p| p == "123"), Some("123"));
    assert_eq!(arg_value(args, "--foo", |_| true), None);
}

struct DefaultCallbacks;
impl rustc_driver::Callbacks for DefaultCallbacks {}

struct ClippyCallbacks;
impl rustc_driver::Callbacks for ClippyCallbacks {
    fn config(&mut self, config: &mut interface::Config) {
        let previous = config.register_lints.take();
        config.register_lints = Some(Box::new(move |sess, mut lint_store| {
            // technically we're ~guaranteed that this is none but might as well call anything that
            // is there already. Certainly it can't hurt.
            if let Some(previous) = &previous {
                (previous)(sess, lint_store);
            }

            let conf = clippy_lints::read_conf(&[], &sess);
            clippy_lints::register_plugins(&mut lint_store, &sess, &conf);
            clippy_lints::register_pre_expansion_lints(&mut lint_store, &conf);
            clippy_lints::register_renamed(&mut lint_store);
        }));

        // FIXME: #4825; This is required, because Clippy lints that are based on MIR have to be
        // run on the unoptimized MIR. On the other hand this results in some false negatives. If
        // MIR passes can be enabled / disabled separately, we should figure out, what passes to
        // use for Clippy.
        config.opts.debugging_opts.mir_opt_level = 0;
    }
}

#[allow(clippy::find_map, clippy::filter_map)]
fn describe_lints() {
    use lintlist::*;
    use std::collections::HashSet;

    println!(
        "
Available lint options:
    -W <foo>           Warn about <foo>
    -A <foo>           Allow <foo>
    -D <foo>           Deny <foo>
    -F <foo>           Forbid <foo> (deny <foo> and all attempts to override)

"
    );

    let lint_level = |lint: &Lint| {
        LINT_LEVELS
            .iter()
            .find(|level_mapping| level_mapping.0 == lint.group)
            .map(|(_, level)| match level {
                Level::Allow => "allow",
                Level::Warn => "warn",
                Level::Deny => "deny",
            })
            .unwrap()
    };

    let mut lints: Vec<_> = ALL_LINTS.iter().collect();
    // The sort doesn't case-fold but it's doubtful we care.
    lints.sort_by_cached_key(|x: &&Lint| (lint_level(x), x.name));

    let max_lint_name_len = lints
        .iter()
        .map(|lint| lint.name.len())
        .map(|len| len + "clippy::".len())
        .max()
        .unwrap_or(0);

    let padded = |x: &str| {
        let mut s = " ".repeat(max_lint_name_len - x.chars().count());
        s.push_str(x);
        s
    };

    let scoped = |x: &str| format!("clippy::{}", x);

    let lint_groups: HashSet<_> = lints.iter().map(|lint| lint.group).collect();

    println!("Lint checks provided by clippy:\n");
    println!("    {}  {:7.7}  meaning", padded("name"), "default");
    println!("    {}  {:7.7}  -------", padded("----"), "-------");

    let print_lints = |lints: &[&Lint]| {
        for lint in lints {
            let name = lint.name.replace("_", "-");
            println!(
                "    {}  {:7.7}  {}",
                padded(&scoped(&name)),
                lint_level(lint),
                lint.desc
            );
        }
        println!("\n");
    };

    print_lints(&lints);

    let max_group_name_len = std::cmp::max(
        "clippy::all".len(),
        lint_groups
            .iter()
            .map(|group| group.len())
            .map(|len| len + "clippy::".len())
            .max()
            .unwrap_or(0),
    );

    let padded_group = |x: &str| {
        let mut s = " ".repeat(max_group_name_len - x.chars().count());
        s.push_str(x);
        s
    };

    println!("Lint groups provided by clippy:\n");
    println!("    {}  sub-lints", padded_group("name"));
    println!("    {}  ---------", padded_group("----"));
    println!("    {}  the set of all clippy lints", padded_group("clippy::all"));

    let print_lint_groups = || {
        for group in lint_groups {
            let name = group.to_lowercase().replace("_", "-");
            let desc = lints
                .iter()
                .filter(|&lint| lint.group == group)
                .map(|lint| lint.name)
                .map(|name| name.replace("_", "-"))
                .collect::<Vec<String>>()
                .join(", ");
            println!("    {}  {}", padded_group(&scoped(&name)), desc);
        }
        println!("\n");
    };

    print_lint_groups();
}

fn display_help() {
    println!(
        "\
Checks a package to catch common mistakes and improve your Rust code.

Usage:
    cargo clippy [options] [--] [<opts>...]

Common options:
    -h, --help               Print this message
    -V, --version            Print version info and exit

Other options are the same as `cargo check`.

To allow or deny a lint from the command line you can use `cargo clippy --`
with:

    -W --warn OPT       Set lint warnings
    -A --allow OPT      Set lint allowed
    -D --deny OPT       Set lint denied
    -F --forbid OPT     Set lint forbidden

You can use tool lints to allow or deny lints from your code, eg.:

    #[allow(clippy::needless_lifetimes)]
"
    );
}

const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new";

lazy_static! {
    static ref ICE_HOOK: Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static> = {
        let hook = panic::take_hook();
        panic::set_hook(Box::new(|info| report_clippy_ice(info, BUG_REPORT_URL)));
        hook
    };
}

fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
    // Invoke our ICE handler, which prints the actual panic message and optionally a backtrace
    (*ICE_HOOK)(info);

    // Separate the output with an empty line
    eprintln!();

    let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(
        rustc_errors::ColorConfig::Auto,
        None,
        false,
        false,
        None,
        false,
    ));
    let handler = rustc_errors::Handler::with_emitter(true, None, emitter);

    // a .span_bug or .bug call has already printed what
    // it wants to print.
    if !info.payload().is::<rustc_errors::ExplicitBug>() {
        let d = rustc_errors::Diagnostic::new(rustc_errors::Level::Bug, "unexpected panic");
        handler.emit_diagnostic(&d);
    }

    let version_info = rustc_tools_util::get_version_info!();

    let xs: Vec<Cow<'static, str>> = vec![
        "the compiler unexpectedly panicked. this is a bug.".into(),
        format!("we would appreciate a bug report: {}", bug_report_url).into(),
        format!("Clippy version: {}", version_info).into(),
    ];

    for note in &xs {
        handler.note_without_error(&note);
    }

    // If backtraces are enabled, also print the query stack
    let backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0");

    if backtrace {
        TyCtxt::try_print_query_stack(&handler);
    }
}

pub fn main() {
    rustc_driver::init_rustc_env_logger();
    lazy_static::initialize(&ICE_HOOK);
    exit(
        rustc_driver::catch_fatal_errors(move || {
            let mut orig_args: Vec<String> = env::args().collect();

            if orig_args.iter().any(|a| a == "--version" || a == "-V") {
                let version_info = rustc_tools_util::get_version_info!();
                println!("{}", version_info);
                exit(0);
            }

            // Get the sysroot, looking from most specific to this invocation to the least:
            // - command line
            // - runtime environment
            //    - SYSROOT
            //    - RUSTUP_HOME, MULTIRUST_HOME, RUSTUP_TOOLCHAIN, MULTIRUST_TOOLCHAIN
            // - sysroot from rustc in the path
            // - compile-time environment
            let sys_root_arg = arg_value(&orig_args, "--sysroot", |_| true);
            let have_sys_root_arg = sys_root_arg.is_some();
            let sys_root = sys_root_arg
                .map(PathBuf::from)
                .or_else(|| std::env::var("SYSROOT").ok().map(PathBuf::from))
                .or_else(|| {
                    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
                    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
                    home.and_then(|home| {
                        toolchain.map(|toolchain| {
                            let mut path = PathBuf::from(home);
                            path.push("toolchains");
                            path.push(toolchain);
                            path
                        })
                    })
                })
                .or_else(|| {
                    Command::new("rustc")
                        .arg("--print")
                        .arg("sysroot")
                        .output()
                        .ok()
                        .and_then(|out| String::from_utf8(out.stdout).ok())
                        .map(|s| PathBuf::from(s.trim()))
                })
                .or_else(|| option_env!("SYSROOT").map(PathBuf::from))
                .map(|pb| pb.to_string_lossy().to_string())
                .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust");

            // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument.
            // We're invoking the compiler programmatically, so we ignore this/
            let wrapper_mode = orig_args.get(1).map(Path::new).and_then(Path::file_stem) == Some("rustc".as_ref());

            if wrapper_mode {
                // we still want to be able to invoke it normally though
                orig_args.remove(1);
            }

            if !wrapper_mode && (orig_args.iter().any(|a| a == "--help" || a == "-h") || orig_args.len() == 1) {
                display_help();
                exit(0);
            }

            let should_describe_lints = || {
                let args: Vec<_> = env::args().collect();
                args.windows(2).any(|args| {
                    args[1] == "help"
                        && match args[0].as_str() {
                            "-W" | "-A" | "-D" | "-F" => true,
                            _ => false,
                        }
                })
            };

            if !wrapper_mode && should_describe_lints() {
                describe_lints();
                exit(0);
            }

            // this conditional check for the --sysroot flag is there so users can call
            // `clippy_driver` directly
            // without having to pass --sysroot or anything
            let mut args: Vec<String> = orig_args.clone();
            if !have_sys_root_arg {
                args.extend(vec!["--sysroot".into(), sys_root]);
            };

            // this check ensures that dependencies are built but not linted and the final
            // crate is linted but not built
            let clippy_enabled = env::var("CLIPPY_TESTS").map_or(false, |val| val == "true")
                || arg_value(&orig_args, "--cap-lints", |val| val == "allow").is_none();

            if clippy_enabled {
                args.extend(vec!["--cfg".into(), r#"feature="cargo-clippy""#.into()]);
                if let Ok(extra_args) = env::var("CLIPPY_ARGS") {
                    args.extend(extra_args.split("__CLIPPY_HACKERY__").filter_map(|s| {
                        if s.is_empty() {
                            None
                        } else {
                            Some(s.to_string())
                        }
                    }));
                }
            }
            let mut clippy = ClippyCallbacks;
            let mut default = DefaultCallbacks;
            let callbacks: &mut (dyn rustc_driver::Callbacks + Send) =
                if clippy_enabled { &mut clippy } else { &mut default };
            rustc_driver::run_compiler(&args, callbacks, None, None)
        })
        .and_then(|result| result)
        .is_err() as i32,
    )
}
<commit_msg>Get {RUSTUP,MULTIRUST}_{HOME,TOOLCHAIN} from runtime environment<commit_after>#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![feature(rustc_private)]
#![feature(str_strip)]

// FIXME: switch to something more ergonomic here, once available.
// (Currently there is no way to opt into sysroot crates without `extern crate`.)
#[allow(unused_extern_crates)]
extern crate rustc;
#[allow(unused_extern_crates)]
extern crate rustc_driver;
#[allow(unused_extern_crates)]
extern crate rustc_errors;
#[allow(unused_extern_crates)]
extern crate rustc_interface;

use rustc::ty::TyCtxt;
use rustc_interface::interface;
use rustc_tools_util::*;

use lazy_static::lazy_static;
use std::borrow::Cow;
use std::env;
use std::ops::Deref;
use std::panic;
use std::path::{Path, PathBuf};
use std::process::{exit, Command};

mod lintlist;

/// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If
/// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`.
fn arg_value<'a, T: Deref<Target = str>>(
    args: &'a [T],
    find_arg: &str,
    pred: impl Fn(&str) -> bool,
) -> Option<&'a str> {
    let mut args = args.iter().map(Deref::deref);
    while let Some(arg) = args.next() {
        let mut arg = arg.splitn(2, '=');
        if arg.next() != Some(find_arg) {
            continue;
        }

        match arg.next().or_else(|| args.next()) {
            Some(v) if pred(v) => return Some(v),
            _ => {},
        }
    }
    None
}

#[test]
fn test_arg_value() {
    let args = &["--bar=bar", "--foobar", "123", "--foo"];

    assert_eq!(arg_value(&[] as &[&str], "--foobar", |_| true), None);
    assert_eq!(arg_value(args, "--bar", |_| false), None);
    assert_eq!(arg_value(args, "--bar", |_| true), Some("bar"));
    assert_eq!(arg_value(args, "--bar", |p| p == "bar"), Some("bar"));
    assert_eq!(arg_value(args, "--bar", |p| p == "foo"), None);
    assert_eq!(arg_value(args, "--foobar", |p| p == "foo"), None);
    assert_eq!(arg_value(args, "--foobar", |p| p == "123"), Some("123"));
    assert_eq!(arg_value(args, "--foo", |_| true), None);
}

struct DefaultCallbacks;
impl rustc_driver::Callbacks for DefaultCallbacks {}

struct ClippyCallbacks;
impl rustc_driver::Callbacks for ClippyCallbacks {
    fn config(&mut self, config: &mut interface::Config) {
        let previous = config.register_lints.take();
        config.register_lints = Some(Box::new(move |sess, mut lint_store| {
            // technically we're ~guaranteed that this is none but might as well call anything that
            // is there already. Certainly it can't hurt.
            if let Some(previous) = &previous {
                (previous)(sess, lint_store);
            }

            let conf = clippy_lints::read_conf(&[], &sess);
            clippy_lints::register_plugins(&mut lint_store, &sess, &conf);
            clippy_lints::register_pre_expansion_lints(&mut lint_store, &conf);
            clippy_lints::register_renamed(&mut lint_store);
        }));

        // FIXME: #4825; This is required, because Clippy lints that are based on MIR have to be
        // run on the unoptimized MIR. On the other hand this results in some false negatives. If
        // MIR passes can be enabled / disabled separately, we should figure out, what passes to
        // use for Clippy.
        config.opts.debugging_opts.mir_opt_level = 0;
    }
}

#[allow(clippy::find_map, clippy::filter_map)]
fn describe_lints() {
    use lintlist::*;
    use std::collections::HashSet;

    println!(
        "
Available lint options:
    -W <foo>           Warn about <foo>
    -A <foo>           Allow <foo>
    -D <foo>           Deny <foo>
    -F <foo>           Forbid <foo> (deny <foo> and all attempts to override)

"
    );

    let lint_level = |lint: &Lint| {
        LINT_LEVELS
            .iter()
            .find(|level_mapping| level_mapping.0 == lint.group)
            .map(|(_, level)| match level {
                Level::Allow => "allow",
                Level::Warn => "warn",
                Level::Deny => "deny",
            })
            .unwrap()
    };

    let mut lints: Vec<_> = ALL_LINTS.iter().collect();
    // The sort doesn't case-fold but it's doubtful we care.
    lints.sort_by_cached_key(|x: &&Lint| (lint_level(x), x.name));

    let max_lint_name_len = lints
        .iter()
        .map(|lint| lint.name.len())
        .map(|len| len + "clippy::".len())
        .max()
        .unwrap_or(0);

    let padded = |x: &str| {
        let mut s = " ".repeat(max_lint_name_len - x.chars().count());
        s.push_str(x);
        s
    };

    let scoped = |x: &str| format!("clippy::{}", x);

    let lint_groups: HashSet<_> = lints.iter().map(|lint| lint.group).collect();

    println!("Lint checks provided by clippy:\n");
    println!("    {}  {:7.7}  meaning", padded("name"), "default");
    println!("    {}  {:7.7}  -------", padded("----"), "-------");

    let print_lints = |lints: &[&Lint]| {
        for lint in lints {
            let name = lint.name.replace("_", "-");
            println!(
                "    {}  {:7.7}  {}",
                padded(&scoped(&name)),
                lint_level(lint),
                lint.desc
            );
        }
        println!("\n");
    };

    print_lints(&lints);

    let max_group_name_len = std::cmp::max(
        "clippy::all".len(),
        lint_groups
            .iter()
            .map(|group| group.len())
            .map(|len| len + "clippy::".len())
            .max()
            .unwrap_or(0),
    );

    let padded_group = |x: &str| {
        let mut s = " ".repeat(max_group_name_len - x.chars().count());
        s.push_str(x);
        s
    };

    println!("Lint groups provided by clippy:\n");
    println!("    {}  sub-lints", padded_group("name"));
    println!("    {}  ---------", padded_group("----"));
    println!("    {}  the set of all clippy lints", padded_group("clippy::all"));

    let print_lint_groups = || {
        for group in lint_groups {
            let name = group.to_lowercase().replace("_", "-");
            let desc = lints
                .iter()
                .filter(|&lint| lint.group == group)
                .map(|lint| lint.name)
                .map(|name| name.replace("_", "-"))
                .collect::<Vec<String>>()
                .join(", ");
            println!("    {}  {}", padded_group(&scoped(&name)), desc);
        }
        println!("\n");
    };

    print_lint_groups();
}

fn display_help() {
    println!(
        "\
Checks a package to catch common mistakes and improve your Rust code.

Usage:
    cargo clippy [options] [--] [<opts>...]

Common options:
    -h, --help               Print this message
    -V, --version            Print version info and exit

Other options are the same as `cargo check`.

To allow or deny a lint from the command line you can use `cargo clippy --`
with:

    -W --warn OPT       Set lint warnings
    -A --allow OPT      Set lint allowed
    -D --deny OPT       Set lint denied
    -F --forbid OPT     Set lint forbidden

You can use tool lints to allow or deny lints from your code, eg.:

    #[allow(clippy::needless_lifetimes)]
"
    );
}

const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new";

lazy_static! {
    static ref ICE_HOOK: Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static> = {
        let hook = panic::take_hook();
        panic::set_hook(Box::new(|info| report_clippy_ice(info, BUG_REPORT_URL)));
        hook
    };
}

fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
    // Invoke our ICE handler, which prints the actual panic message and optionally a backtrace
    (*ICE_HOOK)(info);

    // Separate the output with an empty line
    eprintln!();

    let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(
        rustc_errors::ColorConfig::Auto,
        None,
        false,
        false,
        None,
        false,
    ));
    let handler = rustc_errors::Handler::with_emitter(true, None, emitter);

    // a .span_bug or .bug call has already printed what
    // it wants to print.
    if !info.payload().is::<rustc_errors::ExplicitBug>() {
        let d = rustc_errors::Diagnostic::new(rustc_errors::Level::Bug, "unexpected panic");
        handler.emit_diagnostic(&d);
    }

    let version_info = rustc_tools_util::get_version_info!();

    let xs: Vec<Cow<'static, str>> = vec![
        "the compiler unexpectedly panicked. this is a bug.".into(),
        format!("we would appreciate a bug report: {}", bug_report_url).into(),
        format!("Clippy version: {}", version_info).into(),
    ];

    for note in &xs {
        handler.note_without_error(&note);
    }

    // If backtraces are enabled, also print the query stack
    let backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0");

    if backtrace {
        TyCtxt::try_print_query_stack(&handler);
    }
}

fn toolchain_path(home: Option<String>, toolchain: Option<String>) -> Option<PathBuf> {
    home.and_then(|home| {
        toolchain.map(|toolchain| {
            let mut path = PathBuf::from(home);
            path.push("toolchains");
            path.push(toolchain);
            path
        })
    })
}

pub fn main() {
    rustc_driver::init_rustc_env_logger();
    lazy_static::initialize(&ICE_HOOK);
    exit(
        rustc_driver::catch_fatal_errors(move || {
            let mut orig_args: Vec<String> = env::args().collect();

            if orig_args.iter().any(|a| a == "--version" || a == "-V") {
                let version_info = rustc_tools_util::get_version_info!();
                println!("{}", version_info);
                exit(0);
            }

            // Get the sysroot, looking from most specific to this invocation to the least:
            // - command line
            // - runtime environment
            //    - SYSROOT
            //    - RUSTUP_HOME, MULTIRUST_HOME, RUSTUP_TOOLCHAIN, MULTIRUST_TOOLCHAIN
            // - sysroot from rustc in the path
            // - compile-time environment
            //    - SYSROOT
            //    - RUSTUP_HOME, MULTIRUST_HOME, RUSTUP_TOOLCHAIN, MULTIRUST_TOOLCHAIN
            let sys_root_arg = arg_value(&orig_args, "--sysroot", |_| true);
            let have_sys_root_arg = sys_root_arg.is_some();
            let sys_root = sys_root_arg
                .map(PathBuf::from)
                .or_else(|| std::env::var("SYSROOT").ok().map(PathBuf::from))
                .or_else(|| {
                    let home = std::env::var("RUSTUP_HOME")
                        .or_else(|_| std::env::var("MULTIRUST_HOME"))
                        .ok();
                    let toolchain = std::env::var("RUSTUP_TOOLCHAIN")
                        .or_else(|_| std::env::var("MULTIRUST_TOOLCHAIN"))
                        .ok();
                    toolchain_path(home, toolchain)
                })
                .or_else(|| {
                    Command::new("rustc")
                        .arg("--print")
                        .arg("sysroot")
                        .output()
                        .ok()
                        .and_then(|out| String::from_utf8(out.stdout).ok())
                        .map(|s| PathBuf::from(s.trim()))
                })
                .or_else(|| option_env!("SYSROOT").map(PathBuf::from))
                .or_else(|| {
                    let home = option_env!("RUSTUP_HOME")
                        .or(option_env!("MULTIRUST_HOME"))
                        .map(ToString::to_string);
                    let toolchain = option_env!("RUSTUP_TOOLCHAIN")
                        .or(option_env!("MULTIRUST_TOOLCHAIN"))
                        .map(ToString::to_string);
                    toolchain_path(home, toolchain)
                })
                .map(|pb| pb.to_string_lossy().to_string())
                .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust");

            // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument.
            // We're invoking the compiler programmatically, so we ignore this/
            let wrapper_mode = orig_args.get(1).map(Path::new).and_then(Path::file_stem) == Some("rustc".as_ref());

            if wrapper_mode {
                // we still want to be able to invoke it normally though
                orig_args.remove(1);
            }

            if !wrapper_mode && (orig_args.iter().any(|a| a == "--help" || a == "-h") || orig_args.len() == 1) {
                display_help();
                exit(0);
            }

            let should_describe_lints = || {
                let args: Vec<_> = env::args().collect();
                args.windows(2).any(|args| {
                    args[1] == "help"
                        && match args[0].as_str() {
                            "-W" | "-A" | "-D" | "-F" => true,
                            _ => false,
                        }
                })
            };

            if !wrapper_mode && should_describe_lints() {
                describe_lints();
                exit(0);
            }

            // this conditional check for the --sysroot flag is there so users can call
            // `clippy_driver` directly
            // without having to pass --sysroot or anything
            let mut args: Vec<String> = orig_args.clone();
            if !have_sys_root_arg {
                args.extend(vec!["--sysroot".into(), sys_root]);
            };

            // this check ensures that dependencies are built but not linted and the final
            // crate is linted but not built
            let clippy_enabled = env::var("CLIPPY_TESTS").map_or(false, |val| val == "true")
                || arg_value(&orig_args, "--cap-lints", |val| val == "allow").is_none();

            if clippy_enabled {
                args.extend(vec!["--cfg".into(), r#"feature="cargo-clippy""#.into()]);
                if let Ok(extra_args) = env::var("CLIPPY_ARGS") {
                    args.extend(extra_args.split("__CLIPPY_HACKERY__").filter_map(|s| {
                        if s.is_empty() {
                            None
                        } else {
                            Some(s.to_string())
                        }
                    }));
                }
            }
            let mut clippy = ClippyCallbacks;
            let mut default = DefaultCallbacks;
            let callbacks: &mut (dyn rustc_driver::Callbacks + Send) =
                if clippy_enabled { &mut clippy } else { &mut default };
            rustc_driver::run_compiler(&args, callbacks, None, None)
        })
        .and_then(|result| result)
        .is_err() as i32,
    )
}
<|endoftext|>


<commit_before><commit_msg>added sigmoid function<commit_after><|endoftext|>