<commit_before>mod crc;
#[macro_use]
mod macros;
mod types;

pub use self::crc::{crc8, crc16};
pub use self::types::{ErrorKind, ByteStream, ReadStream};

use nom::{self, IResult};
use metadata::{Metadata, metadata_parser};

use std::ops::{Add, AddAssign, BitAnd, BitOr, Mul, Sub, Shl, ShlAssign, Shr};
use std::io;

/// An interface for parsing through some type of producer to a byte stream.
///
/// External parsers get passed in and consumes the bytes held internally
/// and outputs the `Result` of that parser.
pub trait StreamProducer {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T, ErrorKind>;
}

/// An abstraction trait for keeping different sized integers.
pub trait Sample: PartialEq + Eq + Sized + Clone + Copy +
                  Add<Output = Self> + AddAssign +
                  BitAnd<Self, Output = Self> + BitOr<Self, Output = Self> +
                  Mul<Output = Self> + Shl<u32, Output = Self>  +
                  ShlAssign<u32> + Shr<u32, Output = Self> +
                  Shr<i8, Output = Self> + Shr<i32, Output = Self> +
                  Sub<Output = Self> {
  /// The normal size for the current a `Sample`.
  type Normal;

  /// The size, in bits, for the `Sample::Normal`.
  fn size() -> usize;

  /// The size, in bits, for the `Sample`.
  fn size_extended() -> usize;

  /// Convert the extended `Sample` to the normal.
  fn to_normal(sample: Self) -> Option<Self::Normal>;

  /// Convert an i8 into a `Sample`.
  fn from_i8(sample: i8) -> Self;

  /// Convert an i16 into a `Sample`.
  fn from_i16(sample: i16) -> Self;

  /// Convert an i32 into a `Sample`.
  ///
  /// With `Sample` sometimes being smaller than a i32, there is a chance
  /// for this function to return an incorrect number. So when the number is
  /// larger of smaller than the current `Sample`, it returns `None`
  /// otherwise `Some(sample)`.
  fn from_i32(sample: i32) -> Option<Self>;

  /// Convert an i32 into a `Sample`.
  fn from_i32_lossy(sample: i32) -> Self;
}

/// A trait for defining the size of a sample.
pub trait SampleSize {
  /// The internal integer size used with `Stream::iter`.
  ///
  /// Rather than making the user of `Stream::iter` will remember what the
  /// extended size of the output sample will be, this is to map to the
  /// value based on the current integer size used.
  type Extended: Sample;
}

impl SampleSize for i8 {
  type Extended = i16;
}

impl SampleSize for i16 {
  type Extended = i32;
}

impl SampleSize for i32 {
  type Extended = i64;
}

pub trait WriteExtension: io::Write {
  fn write_u8(&mut self, number: u8) -> io::Result<()>;

  fn write_be_u16(&mut self, number: u16) -> io::Result<()>;
  fn write_le_u16(&mut self, number: u16) -> io::Result<()>;

  fn write_be_u24(&mut self, number: u32) -> io::Result<()>;
  fn write_le_u24(&mut self, number: u32) -> io::Result<()>;

  fn write_be_u32(&mut self, number: u32) -> io::Result<()>;
  fn write_le_u32(&mut self, number: u32) -> io::Result<()>;

  fn write_be_u64(&mut self, number: u64) -> io::Result<()>;
  fn write_le_u64(&mut self, number: u64) -> io::Result<()>;
}

impl<Write> WriteExtension for Write where Write: io::Write {
  fn write_u8(&mut self, number: u8) -> io::Result<()> {
    self.write_all(&[number])
  }

  fn write_be_u16(&mut self, number: u16) -> io::Result<()> {
    let mut buffer = [0; 2];

    buffer[0] = (number >> 8) as u8;
    buffer[1] = number as u8;

    self.write_all(&buffer)
  }

  fn write_le_u16(&mut self, number: u16) -> io::Result<()> {
    let mut buffer = [0; 2];

    buffer[2] = number as u8;
    buffer[1] = (number >> 8) as u8;

    self.write_all(&buffer)
  }

  fn write_be_u24(&mut self, number: u32) -> io::Result<()> {
    let mut buffer = [0; 3];

    buffer[0] = (number >> 16) as u8;
    buffer[1] = (number >> 8) as u8;
    buffer[2] = number as u8;

    self.write_all(&buffer)
  }

  fn write_le_u24(&mut self, number: u32) -> io::Result<()> {
    let mut buffer = [0; 3];

    buffer[0] = number as u8;
    buffer[1] = (number >> 8) as u8;
    buffer[2] = (number >> 16) as u8;

    self.write_all(&buffer)
  }

  fn write_be_u32(&mut self, number: u32) -> io::Result<()> {
    let mut buffer = [0; 4];

    buffer[0] = (number >> 24) as u8;
    buffer[1] = (number >> 16) as u8;
    buffer[2] = (number >> 8) as u8;
    buffer[3] = number as u8;

    self.write_all(&buffer)
  }

  fn write_le_u32(&mut self, number: u32) -> io::Result<()> {
    let mut buffer = [0; 4];

    buffer[0] = number as u8;
    buffer[1] = (number >> 8) as u8;
    buffer[2] = (number >> 16) as u8;
    buffer[3] = (number >> 24) as u8;

    self.write_all(&buffer)
  }

  fn write_be_u64(&mut self, number: u64) -> io::Result<()> {
    let mut buffer = [0; 8];

    buffer[0] = (number >> 56) as u8;
    buffer[1] = (number >> 48) as u8;
    buffer[2] = (number >> 40) as u8;
    buffer[3] = (number >> 32) as u8;
    buffer[4] = (number >> 24) as u8;
    buffer[5] = (number >> 16) as u8;
    buffer[6] = (number >> 8) as u8;
    buffer[7] = number as u8;

    self.write_all(&buffer)
  }

  fn write_le_u64(&mut self, number: u64) -> io::Result<()> {
    let mut buffer = [0; 8];

    buffer[0] = number as u8;
    buffer[1] = (number >> 8) as u8;
    buffer[2] = (number >> 16) as u8;
    buffer[3] = (number >> 24) as u8;
    buffer[4] = (number >> 32) as u8;
    buffer[5] = (number >> 40) as u8;
    buffer[6] = (number >> 48) as u8;
    buffer[7] = (number >> 56) as u8;

    self.write_all(&buffer)
  }
}

// Convert one to four byte slices into an unsigned 32-bit number.
//
// NOTE: This assumes big-endian since most numbers in the FLAC binary are
// that endianness.
#[inline]
pub fn to_u32(bytes: &[u8]) -> u32 {
  let length = bytes.len();

  debug_assert!(length <= 4);

  (0..length).fold(0, |result, i|
    result + ((bytes[i] as u32) << ((length - 1 - i) * 8))
  )
}

// Extends a signed value of a specific bit size to a larger bit size.
//
// NOTE: This assumes that the larger bit size will be 32 bit since that is
// the largest sample size supported in FLAC.
pub fn extend_sign(value: u32, bit_count: usize) -> i32 {
  if bit_count >= 32 || value < (1 << (bit_count - 1)) {
    value as i32
  } else {
    (value as i32).wrapping_sub(1 << bit_count)
  }
}

// Bit shifted version for two to the power of a given exponent.
#[inline]
pub fn power_of_two(exponent: u32) -> u32 {
  debug_assert!(exponent <= 31);

  1 << exponent
}

#[derive(PartialEq, Eq)]
enum ParserState {
  Header,
  StreamInfo,
  Metadata
}

fn parser<'a>(input: &'a [u8], state: &mut ParserState)
              -> IResult<&'a [u8], Metadata, ErrorKind> {
  let mut slice = input;
  let error     = nom::Err::Code(nom::ErrorKind::Custom(ErrorKind::Unknown));

  if *state == ParserState::Header {
    let (i, _) = try_parser! {
      to_custom_error!(slice, tag!("fLaC"), HeaderParser)
    };

    slice  = i;
    *state = ParserState::StreamInfo;
  }

  match *state {
    ParserState::StreamInfo => {
      let (i, block) = try_parse!(slice, metadata_parser);

      if block.is_stream_info() {
        *state = ParserState::Metadata;

        IResult::Done(i, block)
      } else {
        IResult::Error(error)
      }
    }
    ParserState::Metadata   => metadata_parser(slice),
    _                       => IResult::Error(error),
  }
}

pub fn many_metadata<S, F>(stream: &mut S, mut f: F) -> Result<(), ErrorKind>
 where S: StreamProducer,
       F: FnMut(Metadata) {
  let mut state  = ParserState::Header;
  let mut result = Ok(());

  loop {
    match stream.parse(|i| parser(i, &mut state)) {
      Ok(block)                => {
        let is_last = block.is_last();

        f(block);

        if is_last {
          break;
        }
      }
      Err(ErrorKind::Continue) => continue,
      Err(e)                   => {
        result = Err(e);

        break;
      }
    }
  }

  result
}

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

  #[test]
  #[should_panic]
  fn test_panic_to_u32() {
    to_u32(&[0x00, 0x00, 0x00, 0x00, 0x00]);
  }

  #[test]
  fn test_to_u32() {
    let bytes = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];

    assert_eq!(to_u32(&bytes[0..1]), 0x00000001);
    assert_eq!(to_u32(&bytes[3..5]), 0x00006789);
    assert_eq!(to_u32(&bytes[1..4]), 0x00234567);
    assert_eq!(to_u32(&bytes[4..]), 0x89abcdef);
  }

  #[test]
  fn test_extend_sign() {
    assert_eq!(extend_sign(32, 6), -32);
    assert_eq!(extend_sign(31, 6), 31);
    assert_eq!(extend_sign(128, 8), -128);
    assert_eq!(extend_sign(127, 8), 127);

    assert_eq!(extend_sign(2048, 12), -2048);
    assert_eq!(extend_sign(2047, 12), 2047);
    assert_eq!(extend_sign(32768, 16), -32768);
    assert_eq!(extend_sign(32767, 16), 32767);

    assert_eq!(extend_sign(8388608, 24), -8388608);
    assert_eq!(extend_sign(8388607, 24), 8388607);
    assert_eq!(extend_sign(2147483648, 32), -2147483648);
    assert_eq!(extend_sign(2147483647, 32), 2147483647);
  }

  #[test]
  #[should_panic]
  fn test_panic_power_of_two() {
    power_of_two(32);
  }

  #[test]
  fn test_power_of_two() {
    assert_eq!(power_of_two(0), 1);
    assert_eq!(power_of_two(1), 2);
    assert_eq!(power_of_two(2), 4);
    assert_eq!(power_of_two(10), 1024);
    assert_eq!(power_of_two(31), 2147483648);
  }

  #[test]
  fn test_write_u8() {
    let mut buffer = [0; 1];

    assert!((&mut buffer[..]).write_u8(0xa0).is_ok());
    assert_eq!(buffer, [0xa0]);

    assert!((&mut buffer[..]).write_u8(0xff).is_ok());
    assert_eq!(buffer, [0xff]);

    assert!((&mut buffer[..]).write_u8(0x10).is_ok());
    assert_eq!(buffer, [0x10]);
  }

  #[test]
  fn test_write_le_u16() {
    let mut buffer = [0; 2];

    assert!((&mut buffer[..]).write_le_u16(0xabcd).is_ok());
    assert_eq!(buffer, [0xcd, 0xab]);

    assert!((&mut buffer[..]).write_le_u16(0xff00).is_ok());
    assert_eq!(buffer, [0x00, 0xff]);

    assert!((&mut buffer[..]).write_le_u16(0x5e9a).is_ok());
    assert_eq!(buffer, [0x9a, 0x5e]);
  }

  #[test]
  fn test_write_be_u16() {
    let mut buffer = [0; 2];

    assert!((&mut buffer[..]).write_be_u16(0xabcd).is_ok());
    assert_eq!(buffer, [0xab, 0xcd]);

    assert!((&mut buffer[..]).write_be_u16(0xff00).is_ok());
    assert_eq!(buffer, [0xff, 0x00]);

    assert!((&mut buffer[..]).write_be_u16(0x5e9a).is_ok());
    assert_eq!(buffer, [0x5e, 0x9a]);
  }
}
<commit_msg>Fix bound check fail for write_le_u16<commit_after>mod crc;
#[macro_use]
mod macros;
mod types;

pub use self::crc::{crc8, crc16};
pub use self::types::{ErrorKind, ByteStream, ReadStream};

use nom::{self, IResult};
use metadata::{Metadata, metadata_parser};

use std::ops::{Add, AddAssign, BitAnd, BitOr, Mul, Sub, Shl, ShlAssign, Shr};
use std::io;

/// An interface for parsing through some type of producer to a byte stream.
///
/// External parsers get passed in and consumes the bytes held internally
/// and outputs the `Result` of that parser.
pub trait StreamProducer {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T, ErrorKind>;
}

/// An abstraction trait for keeping different sized integers.
pub trait Sample: PartialEq + Eq + Sized + Clone + Copy +
                  Add<Output = Self> + AddAssign +
                  BitAnd<Self, Output = Self> + BitOr<Self, Output = Self> +
                  Mul<Output = Self> + Shl<u32, Output = Self>  +
                  ShlAssign<u32> + Shr<u32, Output = Self> +
                  Shr<i8, Output = Self> + Shr<i32, Output = Self> +
                  Sub<Output = Self> {
  /// The normal size for the current a `Sample`.
  type Normal;

  /// The size, in bits, for the `Sample::Normal`.
  fn size() -> usize;

  /// The size, in bits, for the `Sample`.
  fn size_extended() -> usize;

  /// Convert the extended `Sample` to the normal.
  fn to_normal(sample: Self) -> Option<Self::Normal>;

  /// Convert an i8 into a `Sample`.
  fn from_i8(sample: i8) -> Self;

  /// Convert an i16 into a `Sample`.
  fn from_i16(sample: i16) -> Self;

  /// Convert an i32 into a `Sample`.
  ///
  /// With `Sample` sometimes being smaller than a i32, there is a chance
  /// for this function to return an incorrect number. So when the number is
  /// larger of smaller than the current `Sample`, it returns `None`
  /// otherwise `Some(sample)`.
  fn from_i32(sample: i32) -> Option<Self>;

  /// Convert an i32 into a `Sample`.
  fn from_i32_lossy(sample: i32) -> Self;
}

/// A trait for defining the size of a sample.
pub trait SampleSize {
  /// The internal integer size used with `Stream::iter`.
  ///
  /// Rather than making the user of `Stream::iter` will remember what the
  /// extended size of the output sample will be, this is to map to the
  /// value based on the current integer size used.
  type Extended: Sample;
}

impl SampleSize for i8 {
  type Extended = i16;
}

impl SampleSize for i16 {
  type Extended = i32;
}

impl SampleSize for i32 {
  type Extended = i64;
}

pub trait WriteExtension: io::Write {
  fn write_u8(&mut self, number: u8) -> io::Result<()>;

  fn write_be_u16(&mut self, number: u16) -> io::Result<()>;
  fn write_le_u16(&mut self, number: u16) -> io::Result<()>;

  fn write_be_u24(&mut self, number: u32) -> io::Result<()>;
  fn write_le_u24(&mut self, number: u32) -> io::Result<()>;

  fn write_be_u32(&mut self, number: u32) -> io::Result<()>;
  fn write_le_u32(&mut self, number: u32) -> io::Result<()>;

  fn write_be_u64(&mut self, number: u64) -> io::Result<()>;
  fn write_le_u64(&mut self, number: u64) -> io::Result<()>;
}

impl<Write> WriteExtension for Write where Write: io::Write {
  fn write_u8(&mut self, number: u8) -> io::Result<()> {
    self.write_all(&[number])
  }

  fn write_be_u16(&mut self, number: u16) -> io::Result<()> {
    let mut buffer = [0; 2];

    buffer[0] = (number >> 8) as u8;
    buffer[1] = number as u8;

    self.write_all(&buffer)
  }

  fn write_le_u16(&mut self, number: u16) -> io::Result<()> {
    let mut buffer = [0; 2];

    buffer[0] = number as u8;
    buffer[1] = (number >> 8) as u8;

    self.write_all(&buffer)
  }

  fn write_be_u24(&mut self, number: u32) -> io::Result<()> {
    let mut buffer = [0; 3];

    buffer[0] = (number >> 16) as u8;
    buffer[1] = (number >> 8) as u8;
    buffer[2] = number as u8;

    self.write_all(&buffer)
  }

  fn write_le_u24(&mut self, number: u32) -> io::Result<()> {
    let mut buffer = [0; 3];

    buffer[0] = number as u8;
    buffer[1] = (number >> 8) as u8;
    buffer[2] = (number >> 16) as u8;

    self.write_all(&buffer)
  }

  fn write_be_u32(&mut self, number: u32) -> io::Result<()> {
    let mut buffer = [0; 4];

    buffer[0] = (number >> 24) as u8;
    buffer[1] = (number >> 16) as u8;
    buffer[2] = (number >> 8) as u8;
    buffer[3] = number as u8;

    self.write_all(&buffer)
  }

  fn write_le_u32(&mut self, number: u32) -> io::Result<()> {
    let mut buffer = [0; 4];

    buffer[0] = number as u8;
    buffer[1] = (number >> 8) as u8;
    buffer[2] = (number >> 16) as u8;
    buffer[3] = (number >> 24) as u8;

    self.write_all(&buffer)
  }

  fn write_be_u64(&mut self, number: u64) -> io::Result<()> {
    let mut buffer = [0; 8];

    buffer[0] = (number >> 56) as u8;
    buffer[1] = (number >> 48) as u8;
    buffer[2] = (number >> 40) as u8;
    buffer[3] = (number >> 32) as u8;
    buffer[4] = (number >> 24) as u8;
    buffer[5] = (number >> 16) as u8;
    buffer[6] = (number >> 8) as u8;
    buffer[7] = number as u8;

    self.write_all(&buffer)
  }

  fn write_le_u64(&mut self, number: u64) -> io::Result<()> {
    let mut buffer = [0; 8];

    buffer[0] = number as u8;
    buffer[1] = (number >> 8) as u8;
    buffer[2] = (number >> 16) as u8;
    buffer[3] = (number >> 24) as u8;
    buffer[4] = (number >> 32) as u8;
    buffer[5] = (number >> 40) as u8;
    buffer[6] = (number >> 48) as u8;
    buffer[7] = (number >> 56) as u8;

    self.write_all(&buffer)
  }
}

// Convert one to four byte slices into an unsigned 32-bit number.
//
// NOTE: This assumes big-endian since most numbers in the FLAC binary are
// that endianness.
#[inline]
pub fn to_u32(bytes: &[u8]) -> u32 {
  let length = bytes.len();

  debug_assert!(length <= 4);

  (0..length).fold(0, |result, i|
    result + ((bytes[i] as u32) << ((length - 1 - i) * 8))
  )
}

// Extends a signed value of a specific bit size to a larger bit size.
//
// NOTE: This assumes that the larger bit size will be 32 bit since that is
// the largest sample size supported in FLAC.
pub fn extend_sign(value: u32, bit_count: usize) -> i32 {
  if bit_count >= 32 || value < (1 << (bit_count - 1)) {
    value as i32
  } else {
    (value as i32).wrapping_sub(1 << bit_count)
  }
}

// Bit shifted version for two to the power of a given exponent.
#[inline]
pub fn power_of_two(exponent: u32) -> u32 {
  debug_assert!(exponent <= 31);

  1 << exponent
}

#[derive(PartialEq, Eq)]
enum ParserState {
  Header,
  StreamInfo,
  Metadata
}

fn parser<'a>(input: &'a [u8], state: &mut ParserState)
              -> IResult<&'a [u8], Metadata, ErrorKind> {
  let mut slice = input;
  let error     = nom::Err::Code(nom::ErrorKind::Custom(ErrorKind::Unknown));

  if *state == ParserState::Header {
    let (i, _) = try_parser! {
      to_custom_error!(slice, tag!("fLaC"), HeaderParser)
    };

    slice  = i;
    *state = ParserState::StreamInfo;
  }

  match *state {
    ParserState::StreamInfo => {
      let (i, block) = try_parse!(slice, metadata_parser);

      if block.is_stream_info() {
        *state = ParserState::Metadata;

        IResult::Done(i, block)
      } else {
        IResult::Error(error)
      }
    }
    ParserState::Metadata   => metadata_parser(slice),
    _                       => IResult::Error(error),
  }
}

pub fn many_metadata<S, F>(stream: &mut S, mut f: F) -> Result<(), ErrorKind>
 where S: StreamProducer,
       F: FnMut(Metadata) {
  let mut state  = ParserState::Header;
  let mut result = Ok(());

  loop {
    match stream.parse(|i| parser(i, &mut state)) {
      Ok(block)                => {
        let is_last = block.is_last();

        f(block);

        if is_last {
          break;
        }
      }
      Err(ErrorKind::Continue) => continue,
      Err(e)                   => {
        result = Err(e);

        break;
      }
    }
  }

  result
}

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

  #[test]
  #[should_panic]
  fn test_panic_to_u32() {
    to_u32(&[0x00, 0x00, 0x00, 0x00, 0x00]);
  }

  #[test]
  fn test_to_u32() {
    let bytes = [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef];

    assert_eq!(to_u32(&bytes[0..1]), 0x00000001);
    assert_eq!(to_u32(&bytes[3..5]), 0x00006789);
    assert_eq!(to_u32(&bytes[1..4]), 0x00234567);
    assert_eq!(to_u32(&bytes[4..]), 0x89abcdef);
  }

  #[test]
  fn test_extend_sign() {
    assert_eq!(extend_sign(32, 6), -32);
    assert_eq!(extend_sign(31, 6), 31);
    assert_eq!(extend_sign(128, 8), -128);
    assert_eq!(extend_sign(127, 8), 127);

    assert_eq!(extend_sign(2048, 12), -2048);
    assert_eq!(extend_sign(2047, 12), 2047);
    assert_eq!(extend_sign(32768, 16), -32768);
    assert_eq!(extend_sign(32767, 16), 32767);

    assert_eq!(extend_sign(8388608, 24), -8388608);
    assert_eq!(extend_sign(8388607, 24), 8388607);
    assert_eq!(extend_sign(2147483648, 32), -2147483648);
    assert_eq!(extend_sign(2147483647, 32), 2147483647);
  }

  #[test]
  #[should_panic]
  fn test_panic_power_of_two() {
    power_of_two(32);
  }

  #[test]
  fn test_power_of_two() {
    assert_eq!(power_of_two(0), 1);
    assert_eq!(power_of_two(1), 2);
    assert_eq!(power_of_two(2), 4);
    assert_eq!(power_of_two(10), 1024);
    assert_eq!(power_of_two(31), 2147483648);
  }

  #[test]
  fn test_write_u8() {
    let mut buffer = [0; 1];

    assert!((&mut buffer[..]).write_u8(0xa0).is_ok());
    assert_eq!(buffer, [0xa0]);

    assert!((&mut buffer[..]).write_u8(0xff).is_ok());
    assert_eq!(buffer, [0xff]);

    assert!((&mut buffer[..]).write_u8(0x10).is_ok());
    assert_eq!(buffer, [0x10]);
  }

  #[test]
  fn test_write_le_u16() {
    let mut buffer = [0; 2];

    assert!((&mut buffer[..]).write_le_u16(0xabcd).is_ok());
    assert_eq!(buffer, [0xcd, 0xab]);

    assert!((&mut buffer[..]).write_le_u16(0xff00).is_ok());
    assert_eq!(buffer, [0x00, 0xff]);

    assert!((&mut buffer[..]).write_le_u16(0x5e9a).is_ok());
    assert_eq!(buffer, [0x9a, 0x5e]);
  }

  #[test]
  fn test_write_be_u16() {
    let mut buffer = [0; 2];

    assert!((&mut buffer[..]).write_be_u16(0xabcd).is_ok());
    assert_eq!(buffer, [0xab, 0xcd]);

    assert!((&mut buffer[..]).write_be_u16(0xff00).is_ok());
    assert_eq!(buffer, [0xff, 0x00]);

    assert!((&mut buffer[..]).write_be_u16(0x5e9a).is_ok());
    assert_eq!(buffer, [0x5e, 0x9a]);
  }
}
<|endoftext|>


<commit_before>/*
Attrs module handles annotation attributes in more user friendly values than MetaItems.
Attrs can generate source code of data from instance.
 */
//use syntax::attr::AttrMetaMethods;
use std::collections;
use std::fmt;
use syntax::ast;

// Attr is recursive structure how to represent annotation values in somehow more friendly than MetaItems.
// Attr has implements trait fmt::Display in that way that it can generate source code from instance.
#[derive(Debug)]
pub enum Attr {
	ListAttr(String, Vec<Attr>),
	NamedAttr(String, Box<Attr>),
	StringAttr(String),
}

impl fmt::Display for Attr {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		match self {
			&Attr::StringAttr(ref s) => write!(f, "attrs:Attr::Attr(\"{}\".to_string())", s),
			&Attr::NamedAttr(ref n, ref v) => {
				write!(f, "attrs:Attr::NamedAttr(\"{}\".to_string(), Box::new({}))", n, v)
			}
			&Attr::ListAttr(ref n, ref v) => {
				let mut items = vec![];
				for i in v.iter() {
					items.push(format!("{}", i))
				}
				write!(f, "attrs:Attr::ListAttr(\"{}\".to_string(), vec![{}])", n, items.join(", "))
			}
		}
    }
}

// Errors that can occur at reading from meta attributes and applying for callback closure.
pub enum AttrError {
	UnknownAttr(String),
	UnusedAttr,
}

// implement Display trait to nice error messages
impl fmt::Display for AttrError {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		match self {
			UnknownAttr => write!(f, "unknown attribute"),
			UnusedAttr => write!(f, "unused attribute"),
		}
    }
}

/*
Attributes struct to hold all attributes
 */
#[derive(Debug)]
pub struct Attrs(collections::HashMap<String, Attr>);

/*
Attrs is a set of all attributes for given column.
 */
impl Attrs {

	// Create new instance of Attrs
	pub fn new() -> Attrs {
		Attrs(collections::HashMap::new())
	}

	// insert new attribute
	pub fn insert(&mut self, name: &String, attr:Attr) -> &Self {
		self.0.insert((*name).clone(), attr);
		self
	}

	// read meta item and populate attributes
	// closure is callback function that can correct these attributes to valid values, or
	// refuse attribute at all.
	pub fn read_meta_item<F>(&mut self, _mi:&ast::MetaItem, _closure: F) -> Result<Attrs, AttrError>
		where F: Fn(String, Result<Attr, AttrError>) -> Result<Attr, AttrError>
	{

		Err(AttrError::UnknownAttr)
	}

}

/*
@TODO: Implement fmt::Display trait that will similarly to Attr generate source code representation of data it holds.
 */
impl fmt::Display for Attrs {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "attrs:Attrs")
    }
}

#[test]
fn attrs() {
}

<commit_msg>Updates in attrs, updated docs, cleanup in attrs<commit_after>/*
Attrs module handles annotation attributes in more user friendly values than MetaItems.
Attrs can generate source code of data from instance.
 */
//use syntax::attr::AttrMetaMethods;
use std::collections;
use std::fmt;
use syntax::ast;

// Attr is recursive structure how to represent annotation values in somehow more friendly than MetaItems.
// Attr has implements trait fmt::Display in that way that it can generate source code from instance.
#[derive(Debug)]
pub enum Attr {
	ListAttr(String, Vec<Attr>),
	NamedAttr(String, Box<Attr>),
	StringAttr(String),
}

impl fmt::Display for Attr {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		match self {
			&Attr::StringAttr(ref s) => write!(f, "attrs:Attr::Attr(\"{}\".to_string())", s),
			&Attr::NamedAttr(ref n, ref v) => {
				write!(f, "attrs:Attr::NamedAttr(\"{}\".to_string(), Box::new({}))", n, v)
			}
			&Attr::ListAttr(ref n, ref v) => {
				let mut items = vec![];
				for i in v.iter() {
					items.push(format!("{}", i))
				}
				write!(f, "attrs:Attr::ListAttr(\"{}\".to_string(), vec![{}])", n, items.join(", "))
			}
		}
    }
}

// Errors that can occur at reading from meta attributes and applying for callback closure.
pub enum AttrError {
	UnknownAttr,
	UnusedAttr,
}

// implement Display trait to nice error messages
impl fmt::Display for AttrError {

	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		match self {
			&AttrError::UnknownAttr => write!(f, "unknown attribute"),
			&AttrError::UnusedAttr => write!(f, "unused attribute"),
		}
    }

}

/*
Attributes struct to hold all attributes
 */
#[derive(Debug)]
pub struct Attrs(collections::HashMap<String, Attr>);

/*
Attrs is a set of all attributes for given column.
 */
impl Attrs {

	// Create new instance of Attrs
	pub fn new() -> Attrs {
		Attrs(collections::HashMap::new())
	}

	// insert new attribute
	pub fn insert(&mut self, name: &String, attr:Attr) -> &Self {
		self.0.insert((*name).clone(), attr);
		self
	}

	// read meta item and populate attributes
	// closure is callback function that can correct these attributes to valid values, or
	// refuse attribute at all.
	pub fn read_meta_item<F>(&mut self, _mi:&ast::MetaItem, _closure: F) -> Result<Attrs, AttrError>
		where F: Fn(String, Result<Attr, AttrError>) -> Result<Attr, AttrError>
	{

		Err(AttrError::UnknownAttr)
	}

}

/*
@TODO: Implement fmt::Display trait that will similarly to Attr generate source code representation of data it holds.
 */
impl fmt::Display for Attrs {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		write!(f, "attrs:Attrs")
    }
}

#[test]
fn attrs() {
}

<|endoftext|>


<commit_before>//! Lenny Face Generator (づσ.σ)づ .
//!
//! This module maintains a set of hardcoded components for [Lenny Faces]. Generate as many of them
//! as you need.
//!
//! [Lenny Faces]: <http://knowyourmeme.com/memes/lenny-face>
//!
//! Source: <https://github.com/Twentysix26/Red-Cogs>

use rand::random;

static EARS: &'static [(&'static str, &'static str)] = include!("lenny_ears.inc");
static EYES: &'static [(&'static str, &'static str)] = include!("lenny_eyes.inc");
static MOUTHS: &'static [&'static str] = include!("lenny_mouths.inc");

/// Generate a new Lenny Face.
pub fn gen() -> String {
    let (l_ear, r_ear) = EARS[random::<usize>() % EARS.len()];
    let (l_eye, r_eye) = EYES[random::<usize>() % EYES.len()];
    let mouth = &MOUTHS[random::<usize>() % MOUTHS.len()];
    format!("{}{}{}{}{}", l_ear, l_eye, mouth, r_eye, r_ear)
}

/// (╯°□°）╯︵ ┻━┻
pub fn fliptable() -> String {
    "(╯°□°）╯︵ ┻━┻".to_owned()
}

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

    #[test]
    fn generate() {
        println!("{}", gen());
    }
}
<commit_msg>Utils: The additional pylons you need<commit_after>//! Lenny Face Generator (づσ.σ)づ .
//!
//! This module maintains a set of hardcoded components for [Lenny Faces]. Generate as many of them
//! as you need.
//!
//! [Lenny Faces]: <http://knowyourmeme.com/memes/lenny-face>
//!
//! Source: <https://github.com/Twentysix26/Red-Cogs>

use rand::random;

static EARS: &'static [(&'static str, &'static str)] = include!("lenny_ears.inc");
static EYES: &'static [(&'static str, &'static str)] = include!("lenny_eyes.inc");
static MOUTHS: &'static [&'static str] = include!("lenny_mouths.inc");

/// Generate a new Lenny Face.
pub fn gen() -> String {
    let (l_ear, r_ear) = EARS[random::<usize>() % EARS.len()];
    let (l_eye, r_eye) = EYES[random::<usize>() % EYES.len()];
    let mouth = &MOUTHS[random::<usize>() % MOUTHS.len()];
    format!("{}{}{}{}{}", l_ear, l_eye, mouth, r_eye, r_ear)
}

/// (╯°□°）╯︵ ┻━┻
pub fn fliptable() -> &'static str {
    "(╯°□°）╯︵ ┻━┻"
}

/// > The Overmind has come to destroy all that we hold dear and assimilate us into itself. And I
/// > say to thee, this shall not come to pass! Aiur shall not fall! Executor, I stand ready!
/// >
/// > -- Tassadar
pub fn pylons() -> &'static str {
    r#" /\                                         /\
{==} You Must Construct Additional Pylons! {==}
 \/                                         \/"#
}

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

    #[test]
    fn generate() {
        println!("{}", gen());
    }

    #[test]
    fn polyons() {
        println!("{}", pylons());
    }
}
<|endoftext|>


<commit_before>// DOCS

#![feature(plugin,core,collections,std_misc)]
#![plugin(peg_syntax_ext)]

use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::borrow::ToOwned;
use std::str::FromStr;
use std::fmt;
use std::error::Error;

pub struct Property {
    /// Parameters.
    pub params: HashMap<String, String>,

    /// Value as unparsed string.
    pub raw_value: String,

    /// Property group. E.g. a contentline like `foo.FN:Markus` would result in the group being
    /// `"foo"`.
    pub prop_group: Option<String>
}

impl Property {
    /// Create property from unescaped string.
    pub fn new(value: &str) -> Property {
        Property {
            params: HashMap::new(),
            raw_value: escape_chars(value),
            prop_group: None
        }
    }

    /// Get value as unescaped string.
    pub fn value_as_string(&self) -> String {
        unescape_chars(self.raw_value.as_slice())
    }
}

pub struct Component {
    /// The name of the component, such as `VCARD` or `VEVENT`.
    pub name: String,

    /// The component's properties.
    pub props: HashMap<String, Vec<Property>>,

    /// The component's child- or sub-components.
    pub subcomponents: Vec<Component>
}

impl Component {
    pub fn new(name: &str) -> Component {
        Component {
            name: name.to_string(),
            props: HashMap::new(),
            subcomponents: vec![]
        }
    }

    /// Retrieve one property (from many) by key. Returns `None` if nothing is found.
    pub fn single_prop(&self, key: &str) -> Option<&Property> {
        match self.props.get(key) {
            Some(x) => {
                match x.len() {
                    1 => Some(&x[0]),
                    _ => None
                }
            },
            None => None
        }
    }

    /// Retrieve a mutable vector of properties for this key. Creates one (and inserts it into the
    /// component) if none exists.
    pub fn all_props_mut(&mut self, key: &str) -> &mut Vec<Property> {
        match self.props.entry(String::from_str(key)) {
            Occupied(values) => values.into_mut(),
            Vacant(values) => values.insert(vec![])
        }
    }

    /// Retrieve properties by key. Returns an empty slice if key doesn't exist.
    pub fn all_props(&self, key: &str) -> &[Property] {
        static EMPTY: &'static [Property] = &[];
        match self.props.get(key) {
            Some(values) => values.as_slice(),
            None => EMPTY
        }
    }
}

impl FromStr for Component {
    type Err = String;

    /// Same as `vobject::parse_component`, but without the error messages.
    fn from_str(s: &str) -> Result<Component, String> {
        match parse_component(s) {
            Ok(x) => Ok(x),
            Err(e) => Err(e.into_string())
        }
    }
}

/// Parse a component. The error value is a human-readable message.
pub fn parse_component(s: &str) -> ParseResult<Component> {
    // XXX: The unfolding should be worked into the PEG
    // See feature request: https://github.com/kevinmehall/rust-peg/issues/26
    let unfolded = unfold_lines(s);
    match parser::component(unfolded.as_slice()) {
        Ok(x) => Ok(x),
        Err(e) => Err(ParseError::from_peg_error(e))
    }
}

/// Write a component. The error value is a human-readable message.
pub fn write_component(c: &Component) -> String {
    fn inner(buf: &mut String, c: &Component) {
        buf.push_str("BEGIN:");
        buf.push_str(c.name.as_slice());&
        buf.push_str("\r\n");

        for (prop_name, props) in c.props.iter() {
            for prop in props.iter() {
                match prop.prop_group {
                    Some(ref x) => { buf.push_str(x.as_slice()); buf.push('.'); },
                    None => ()
                };
                buf.push_str(prop_name.as_slice());
                for (param_key, param_value) in prop.params.iter() {
                    buf.push(';');
                    buf.push_str(param_key.as_slice());
                    buf.push('=');
                    buf.push_str(param_value.as_slice());
                };
                buf.push(':');
                buf.push_str(fold_line(prop.raw_value.as_slice()).as_slice());
                buf.push_str("\r\n");
            };
        };

        for subcomponent in c.subcomponents.iter() {
            inner(buf, subcomponent);
        };

        buf.push_str("END:");
        buf.push_str(c.name.as_slice());
        buf.push_str("\r\n");
    }

    let mut buf = String::new();
    inner(&mut buf, c);
    buf
}

/// Escape text for a VObject property value.
pub fn escape_chars(s: &str) -> String {
    // Order matters! Lifted from icalendar.parser
    // https://github.com/collective/icalendar/
    s
        .replace("\\N", "\n")
        .replace("\\", "\\\\")
        .replace(";", "\\;")
        .replace(",", "\\,")
        .replace("\r\n", "\\n")
        .replace("\n", "\\n")
}

/// Unescape text from a VObject property value.
pub fn unescape_chars(s: &str) -> String {
    // Order matters! Lifted from icalendar.parser
    // https://github.com/collective/icalendar/
    s
        .replace("\\N", "\\n")
        .replace("\r\n", "\n")
        .replace("\\n", "\n")
        .replace("\\,", ",")
        .replace("\\;", ";")
        .replace("\\\\", "\\")
}

/// Unfold contentline.
pub fn unfold_lines(s: &str) -> String {
    s
        .replace("\r\n ", "").replace("\r\n\t", "")
        .replace("\n ", "").replace("\n\t", "")
        .replace("\r ", "").replace("\r\t", "")
}

/// Fold contentline to 75 chars. This function assumes the input to be unfolded, which means no
/// '\n' or '\r' in it.
pub fn fold_line(s: &str) -> String {
    let mut rv = String::new();
    for (i, c) in s.chars().enumerate() {
        rv.push(c);
        if i != 0 && i % 75 == 0 {
            rv.push_str("\r\n ");
        };
    };
    rv
}

#[derive(PartialEq, Eq, Debug)]
pub struct ParseError {
    desc: String,
    orig: Option<parser::ParseError>
}

pub type ParseResult<T> = Result<T, ParseError>;

impl Error for ParseError {
    fn description(&self) -> &str {
        self.desc.as_slice()
    }

    fn cause(&self) -> Option<&Error> {
        match self.parser_error() {
            Some(x) => Some(&*x),
            None => None
        }
    }
}

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

impl ParseError {
    pub fn new(desc: String, cause: Option<parser::ParseError>) -> Self {
        ParseError {
            desc: desc,
            orig: cause
        }
    }

    pub fn from_peg_error(e: parser::ParseError) -> Self {
        ParseError {
            desc: stringify!(e).to_owned(),
            orig: Some(e)
        }
    }

    pub fn into_string(self) -> String {
        self.desc
    }

    /// Access the underlying parser error.
    pub fn parser_error(&self) -> Option<&parser::ParseError> {
        self.orig.as_ref()
    }

    /// The line where the error occured.
    ///
    /// The value might be warped because content lines are unfolded before the parser keeps track
    /// of line numbers.
    pub fn line(&self) -> Option<&usize> {
        match self.parser_error() {
            Some(e) => Some(&e.line),
            None => None
        }
    }

    /// The column where the error occured.
    ///
    /// The value might be warped because content lines are unfolded before the parser keeps track
    /// of line numbers.
    pub fn column(&self) -> Option<&usize> {
        match self.parser_error() {
            Some(e) => Some(&e.column),
            None => None
        }
    }
}

peg! parser(r#"
use super::{Component,Property};
use std::collections::HashMap;

components -> Vec<Component>
    = cs:component ** eols __ { cs }

    #[pub]
    component -> Component
        = name:component_begin
          ps:props
          cs:components
          component_end {
            let mut rv = Component::new(name);
            rv.subcomponents = cs;

            for (k, v) in ps.into_iter() {
                rv.all_props_mut(k).push(v);
            };

            rv
        }

    component_begin -> &'input str
        = "BEGIN:" v:value __ { v }

    component_end -> &'input str
        = "END:" v:value __ { v }

props -> Vec<(&'input str, Property)>
    = ps:prop ++ eols __ { ps }

    prop -> (&'input str, Property)
        = !"BEGIN:" !"END:" g:group? k:name p:params ":" v:value {
            (k, Property { params: p, raw_value: v.to_string(), prop_group: g })
        }

    group -> String
        = g:group_name "." { g.to_string() }

        group_name -> &'input str
            = group_char+ { match_str }

    name -> &'input str
        = iana_token+ { match_str }

    params -> HashMap<String, String>
        = ps:(";" p:param {p})* {
            let mut rv: HashMap<String, String> = HashMap::with_capacity(ps.len());
            rv.extend(ps.into_iter().map(|(k, v)| (k.to_string(), v.to_string())));
            rv
        }

        param -> (&'input str, &'input str)
            // FIXME: Doesn't handle comma-separated values
            = k:param_name v:("=" v:param_value { v })? {
                (k, match v {
                    Some(x) => x,
                    None => ""
                })
            }

        param_name -> &'input str
            = iana_token+ { match_str }

        param_value -> &'input str
            = x:(quoted_string / param_text) { x }

        param_text -> &'input str
            = safe_char* { match_str }

    value -> &'input str
        = value_char+ { match_str }

quoted_string -> &'input str
    = dquote x:quoted_content dquote { x }

quoted_content -> &'input str
    = qsafe_char* { match_str }

iana_token = ([a-zA-Z0-9] / "-")+
group_char = ([a-zA-Z0-9] / "-")
qsafe_char = !dquote !ctl value_char
safe_char = !";" !":" qsafe_char

value_char = !eol .

eol = "\r\n" / "\n" / "\r"
dquote = "\""
eols = eol+

// Taken from vCard. vCalendar's is a subset. Together with the definition of "qsafe_char" this
// might reject a bunch of valid iCalendars, but I can't imagine one.
ctl = [\u{00}-\u{1F}] / "\u{7F}"

whitespace = " " / "\t"
__ = (eol / whitespace)*

"#);
<commit_msg>Avoid stringify<commit_after>// DOCS

#![feature(plugin,core,collections,std_misc)]
#![plugin(peg_syntax_ext)]

use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::borrow::ToOwned;
use std::str::FromStr;
use std::fmt;
use std::error::Error;

pub struct Property {
    /// Parameters.
    pub params: HashMap<String, String>,

    /// Value as unparsed string.
    pub raw_value: String,

    /// Property group. E.g. a contentline like `foo.FN:Markus` would result in the group being
    /// `"foo"`.
    pub prop_group: Option<String>
}

impl Property {
    /// Create property from unescaped string.
    pub fn new(value: &str) -> Property {
        Property {
            params: HashMap::new(),
            raw_value: escape_chars(value),
            prop_group: None
        }
    }

    /// Get value as unescaped string.
    pub fn value_as_string(&self) -> String {
        unescape_chars(self.raw_value.as_slice())
    }
}

pub struct Component {
    /// The name of the component, such as `VCARD` or `VEVENT`.
    pub name: String,

    /// The component's properties.
    pub props: HashMap<String, Vec<Property>>,

    /// The component's child- or sub-components.
    pub subcomponents: Vec<Component>
}

impl Component {
    pub fn new(name: &str) -> Component {
        Component {
            name: name.to_string(),
            props: HashMap::new(),
            subcomponents: vec![]
        }
    }

    /// Retrieve one property (from many) by key. Returns `None` if nothing is found.
    pub fn single_prop(&self, key: &str) -> Option<&Property> {
        match self.props.get(key) {
            Some(x) => {
                match x.len() {
                    1 => Some(&x[0]),
                    _ => None
                }
            },
            None => None
        }
    }

    /// Retrieve a mutable vector of properties for this key. Creates one (and inserts it into the
    /// component) if none exists.
    pub fn all_props_mut(&mut self, key: &str) -> &mut Vec<Property> {
        match self.props.entry(String::from_str(key)) {
            Occupied(values) => values.into_mut(),
            Vacant(values) => values.insert(vec![])
        }
    }

    /// Retrieve properties by key. Returns an empty slice if key doesn't exist.
    pub fn all_props(&self, key: &str) -> &[Property] {
        static EMPTY: &'static [Property] = &[];
        match self.props.get(key) {
            Some(values) => values.as_slice(),
            None => EMPTY
        }
    }
}

impl FromStr for Component {
    type Err = String;

    /// Same as `vobject::parse_component`, but without the error messages.
    fn from_str(s: &str) -> Result<Component, String> {
        match parse_component(s) {
            Ok(x) => Ok(x),
            Err(e) => Err(e.into_string())
        }
    }
}

/// Parse a component. The error value is a human-readable message.
pub fn parse_component(s: &str) -> ParseResult<Component> {
    // XXX: The unfolding should be worked into the PEG
    // See feature request: https://github.com/kevinmehall/rust-peg/issues/26
    let unfolded = unfold_lines(s);
    match parser::component(unfolded.as_slice()) {
        Ok(x) => Ok(x),
        Err(e) => Err(ParseError::from_peg_error(e))
    }
}

/// Write a component. The error value is a human-readable message.
pub fn write_component(c: &Component) -> String {
    fn inner(buf: &mut String, c: &Component) {
        buf.push_str("BEGIN:");
        buf.push_str(c.name.as_slice());&
        buf.push_str("\r\n");

        for (prop_name, props) in c.props.iter() {
            for prop in props.iter() {
                match prop.prop_group {
                    Some(ref x) => { buf.push_str(x.as_slice()); buf.push('.'); },
                    None => ()
                };
                buf.push_str(prop_name.as_slice());
                for (param_key, param_value) in prop.params.iter() {
                    buf.push(';');
                    buf.push_str(param_key.as_slice());
                    buf.push('=');
                    buf.push_str(param_value.as_slice());
                };
                buf.push(':');
                buf.push_str(fold_line(prop.raw_value.as_slice()).as_slice());
                buf.push_str("\r\n");
            };
        };

        for subcomponent in c.subcomponents.iter() {
            inner(buf, subcomponent);
        };

        buf.push_str("END:");
        buf.push_str(c.name.as_slice());
        buf.push_str("\r\n");
    }

    let mut buf = String::new();
    inner(&mut buf, c);
    buf
}

/// Escape text for a VObject property value.
pub fn escape_chars(s: &str) -> String {
    // Order matters! Lifted from icalendar.parser
    // https://github.com/collective/icalendar/
    s
        .replace("\\N", "\n")
        .replace("\\", "\\\\")
        .replace(";", "\\;")
        .replace(",", "\\,")
        .replace("\r\n", "\\n")
        .replace("\n", "\\n")
}

/// Unescape text from a VObject property value.
pub fn unescape_chars(s: &str) -> String {
    // Order matters! Lifted from icalendar.parser
    // https://github.com/collective/icalendar/
    s
        .replace("\\N", "\\n")
        .replace("\r\n", "\n")
        .replace("\\n", "\n")
        .replace("\\,", ",")
        .replace("\\;", ";")
        .replace("\\\\", "\\")
}

/// Unfold contentline.
pub fn unfold_lines(s: &str) -> String {
    s
        .replace("\r\n ", "").replace("\r\n\t", "")
        .replace("\n ", "").replace("\n\t", "")
        .replace("\r ", "").replace("\r\t", "")
}

/// Fold contentline to 75 chars. This function assumes the input to be unfolded, which means no
/// '\n' or '\r' in it.
pub fn fold_line(s: &str) -> String {
    let mut rv = String::new();
    for (i, c) in s.chars().enumerate() {
        rv.push(c);
        if i != 0 && i % 75 == 0 {
            rv.push_str("\r\n ");
        };
    };
    rv
}

#[derive(PartialEq, Eq, Debug)]
pub struct ParseError {
    desc: String,
    orig: Option<parser::ParseError>
}

pub type ParseResult<T> = Result<T, ParseError>;

impl Error for ParseError {
    fn description(&self) -> &str {
        self.desc.as_slice()
    }

    fn cause(&self) -> Option<&Error> {
        match self.parser_error() {
            Some(x) => Some(&*x),
            None => None
        }
    }
}

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

impl ParseError {
    pub fn new(desc: String, cause: Option<parser::ParseError>) -> Self {
        ParseError {
            desc: desc,
            orig: cause
        }
    }

    pub fn from_peg_error(e: parser::ParseError) -> Self {
        ParseError {
            desc: format!("{}", e).to_owned(),
            orig: Some(e)
        }
    }

    pub fn into_string(self) -> String {
        self.desc
    }

    /// Access the underlying parser error.
    pub fn parser_error(&self) -> Option<&parser::ParseError> {
        self.orig.as_ref()
    }

    /// The line where the error occured.
    ///
    /// The value might be warped because content lines are unfolded before the parser keeps track
    /// of line numbers.
    pub fn line(&self) -> Option<&usize> {
        match self.parser_error() {
            Some(e) => Some(&e.line),
            None => None
        }
    }

    /// The column where the error occured.
    ///
    /// The value might be warped because content lines are unfolded before the parser keeps track
    /// of line numbers.
    pub fn column(&self) -> Option<&usize> {
        match self.parser_error() {
            Some(e) => Some(&e.column),
            None => None
        }
    }
}

peg! parser(r#"
use super::{Component,Property};
use std::collections::HashMap;

components -> Vec<Component>
    = cs:component ** eols __ { cs }

    #[pub]
    component -> Component
        = name:component_begin
          ps:props
          cs:components
          component_end {
            let mut rv = Component::new(name);
            rv.subcomponents = cs;

            for (k, v) in ps.into_iter() {
                rv.all_props_mut(k).push(v);
            };

            rv
        }

    component_begin -> &'input str
        = "BEGIN:" v:value __ { v }

    component_end -> &'input str
        = "END:" v:value __ { v }

props -> Vec<(&'input str, Property)>
    = ps:prop ++ eols __ { ps }

    prop -> (&'input str, Property)
        = !"BEGIN:" !"END:" g:group? k:name p:params ":" v:value {
            (k, Property { params: p, raw_value: v.to_string(), prop_group: g })
        }

    group -> String
        = g:group_name "." { g.to_string() }

        group_name -> &'input str
            = group_char+ { match_str }

    name -> &'input str
        = iana_token+ { match_str }

    params -> HashMap<String, String>
        = ps:(";" p:param {p})* {
            let mut rv: HashMap<String, String> = HashMap::with_capacity(ps.len());
            rv.extend(ps.into_iter().map(|(k, v)| (k.to_string(), v.to_string())));
            rv
        }

        param -> (&'input str, &'input str)
            // FIXME: Doesn't handle comma-separated values
            = k:param_name v:("=" v:param_value { v })? {
                (k, match v {
                    Some(x) => x,
                    None => ""
                })
            }

        param_name -> &'input str
            = iana_token+ { match_str }

        param_value -> &'input str
            = x:(quoted_string / param_text) { x }

        param_text -> &'input str
            = safe_char* { match_str }

    value -> &'input str
        = value_char+ { match_str }

quoted_string -> &'input str
    = dquote x:quoted_content dquote { x }

quoted_content -> &'input str
    = qsafe_char* { match_str }

iana_token = ([a-zA-Z0-9] / "-")+
group_char = ([a-zA-Z0-9] / "-")
qsafe_char = !dquote !ctl value_char
safe_char = !";" !":" qsafe_char

value_char = !eol .

eol = "\r\n" / "\n" / "\r"
dquote = "\""
eols = eol+

// Taken from vCard. vCalendar's is a subset. Together with the definition of "qsafe_char" this
// might reject a bunch of valid iCalendars, but I can't imagine one.
ctl = [\u{00}-\u{1F}] / "\u{7F}"

whitespace = " " / "\t"
__ = (eol / whitespace)*

"#);
<|endoftext|>


<commit_before>//! Mergesort algorithm.
//!
//! The `efficient` module contains the efficient sorting algorithm "Mergesort".
//!
//! Source: https://en.wikipedia.org/wiki/Merge_sort

extern crate libc;

use std::slice;

/// Mergesort
///
/// # Details
///
///
///
/// # Scaling
///
///
///
/// # Optimizations
///
///
///
/// # Notes
///
/// The type T of the vector elements to sort _must_ implement the `PartialOrd` trait so the
/// compiler knows how to compare the elements and sort them.
///
/// # Examples
///
/// ```
/// let mut data: Vec<i32> = vec![4, 2, 3, 1, 5];
/// sorting::efficientsorts::merge::sort(&mut data);
/// assert_eq!(vec![1, 2, 3, 4, 5], data);
/// ```
///
pub fn sort<T: PartialOrd+Clone>(input: &mut [T]) {
    let n = input.len();

    if n <= 1 {
        // return;
    } else if n == 2 {
        if input.first() > input.last() {
            input.swap(0, 1);
        }
    } else {
        assert!(n > 2);

        // The subvectors of input are now sorted. Merge them into temporary buffer.
        let mut tmp: Vec<T> = Vec::with_capacity(n);

        {
        let n2 = n / 2;
        let (mut split_left, mut split_right) = input.split_at_mut(n2);

        // Recursively call the function on slices of the vector.
        sort(&mut split_left);
        sort(&mut split_right);

        let mut split_left  = split_left.to_vec();
        let mut split_right = split_right.to_vec();

        for _ in 0..n {
            let len_left  = split_left.len();
            let len_right = split_right.len();

            if len_left != 0 && len_right != 0 {
                let take_left: bool = split_left.first() < split_right.first();
                if take_left {
                    tmp.push(split_left.remove(0));
                } else {
                    tmp.push(split_right.remove(0));
                }
            } else if len_left == 0 {
                // Left is now empty
                assert!(len_left  == 0);
                assert!(len_right != 0);
                tmp.push(split_right.remove(0));
            } else {
                // Right is now empty
                assert!(len_left  != 0);
                assert!(len_right == 0);
                tmp.push(split_left.remove(0));
            }
        }
        }

        // Copy content of "tmp" back into "input" vector.
        assert_eq!(tmp.len(), n);
        // input = &mut tmp[..];
        for k in 0..n {
            input[k] = tmp[k].clone();
        }
    }
}

#[no_mangle]
pub extern "C" fn ffi_mergesort_i8(array_pointer: *const libc::int8_t, n: libc::size_t) {
    assert!(!array_pointer.is_null());
    assert!(n != 0);
    let mut to_sort = unsafe {
        slice::from_raw_parts_mut(array_pointer as *mut i8, n as usize)
    };
    sort(&mut to_sort);
}
#[no_mangle]
pub extern "C" fn ffi_mergesort_i16(array_pointer: *const libc::int16_t, n: libc::size_t) {
    assert!(!array_pointer.is_null());
    assert!(n != 0);
    let mut to_sort = unsafe {
        slice::from_raw_parts_mut(array_pointer as *mut i16, n as usize)
    };
    sort(&mut to_sort);
}
#[no_mangle]
pub extern "C" fn ffi_mergesort_i32(array_pointer: *const libc::int32_t, n: libc::size_t) {
    assert!(!array_pointer.is_null());
    assert!(n != 0);
    let mut to_sort = unsafe {
        slice::from_raw_parts_mut(array_pointer as *mut i32, n as usize)
    };
    sort(&mut to_sort);
}
#[no_mangle]
pub extern "C" fn ffi_mergesort_i64(array_pointer: *const libc::int64_t, n: libc::size_t) {
    assert!(!array_pointer.is_null());
    assert!(n != 0);
    let mut to_sort = unsafe {
        slice::from_raw_parts_mut(array_pointer as *mut i64, n as usize)
    };
    sort(&mut to_sort);
}

#[no_mangle]
pub extern "C" fn ffi_mergesort_u8(array_pointer: *const libc::uint8_t, n: libc::size_t) {
    assert!(!array_pointer.is_null());
    assert!(n != 0);
    let mut to_sort = unsafe {
        slice::from_raw_parts_mut(array_pointer as *mut u8, n as usize)
    };
    sort(&mut to_sort);
}
#[no_mangle]
pub extern "C" fn ffi_mergesort_u16(array_pointer: *const libc::uint16_t, n: libc::size_t) {
    assert!(!array_pointer.is_null());
    assert!(n != 0);
    let mut to_sort = unsafe {
        slice::from_raw_parts_mut(array_pointer as *mut u16, n as usize)
    };
    sort(&mut to_sort);
}
#[no_mangle]
pub extern "C" fn ffi_mergesort_u32(array_pointer: *const libc::uint32_t, n: libc::size_t) {
    assert!(!array_pointer.is_null());
    assert!(n != 0);
    let mut to_sort = unsafe {
        slice::from_raw_parts_mut(array_pointer as *mut u32, n as usize)
    };
    sort(&mut to_sort);
}
#[no_mangle]
pub extern "C" fn ffi_mergesort_u64(array_pointer: *const libc::uint64_t, n: libc::size_t) {
    assert!(!array_pointer.is_null());
    assert!(n != 0);
    let mut to_sort = unsafe {
        slice::from_raw_parts_mut(array_pointer as *mut u64, n as usize)
    };
    sort(&mut to_sort);
}

#[no_mangle]
pub extern "C" fn ffi_mergesort_f32(array_pointer: *const libc::c_void, n: libc::size_t) {
    assert!(!array_pointer.is_null());
    assert!(n != 0);
    let mut to_sort = unsafe {
        slice::from_raw_parts_mut(array_pointer as *mut f32, n as usize)
    };
    sort(&mut to_sort);
}
#[no_mangle]
pub extern "C" fn ffi_mergesort_f64(array_pointer: *const libc::c_void, n: libc::size_t) {
    assert!(!array_pointer.is_null());
    assert!(n != 0);
    let mut to_sort = unsafe {
        slice::from_raw_parts_mut(array_pointer as *mut f64, n as usize)
    };
    sort(&mut to_sort);
}
<commit_msg>Use debug_assert instead of assert.<commit_after>//! Mergesort algorithm.
//!
//! The `efficient` module contains the efficient sorting algorithm "Mergesort".
//!
//! Source: https://en.wikipedia.org/wiki/Merge_sort

extern crate libc;

use std::slice;

/// Mergesort
///
/// # Details
///
///
///
/// # Scaling
///
///
///
/// # Optimizations
///
///
///
/// # Notes
///
/// The type T of the vector elements to sort _must_ implement the `PartialOrd` trait so the
/// compiler knows how to compare the elements and sort them.
///
/// # Examples
///
/// ```
/// let mut data: Vec<i32> = vec![4, 2, 3, 1, 5];
/// sorting::efficientsorts::merge::sort(&mut data);
/// assert_eq!(vec![1, 2, 3, 4, 5], data);
/// ```
///
pub fn sort<T: PartialOrd+Clone>(input: &mut [T]) {
    let n = input.len();

    if n <= 1 {
        // return;
    } else if n == 2 {
        if input.first() > input.last() {
            input.swap(0, 1);
        }
    } else {
        assert!(n > 2);

        // The subvectors of input are now sorted. Merge them into temporary buffer.
        let mut tmp: Vec<T> = Vec::with_capacity(n);

        {
        let n2 = n / 2;
        let (mut split_left, mut split_right) = input.split_at_mut(n2);

        // Recursively call the function on slices of the vector.
        sort(&mut split_left);
        sort(&mut split_right);

        let mut split_left  = split_left.to_vec();
        let mut split_right = split_right.to_vec();

        for _ in 0..n {
            let len_left  = split_left.len();
            let len_right = split_right.len();

            if len_left != 0 && len_right != 0 {
                let take_left: bool = split_left.first() < split_right.first();
                if take_left {
                    tmp.push(split_left.remove(0));
                } else {
                    tmp.push(split_right.remove(0));
                }
            } else if len_left == 0 {
                // Left is now empty
                debug_assert!(len_left  == 0);
                debug_assert!(len_right != 0);
                tmp.push(split_right.remove(0));
            } else {
                // Right is now empty
                debug_assert!(len_left  != 0);
                debug_assert!(len_right == 0);
                tmp.push(split_left.remove(0));
            }
        }
        }

        // Copy content of "tmp" back into "input" vector.
        assert_eq!(tmp.len(), n);
        // input = &mut tmp[..];
        for k in 0..n {
            input[k] = tmp[k].clone();
        }
    }
}

#[no_mangle]
pub extern "C" fn ffi_mergesort_i8(array_pointer: *const libc::int8_t, n: libc::size_t) {
    assert!(!array_pointer.is_null());
    assert!(n != 0);
    let mut to_sort = unsafe {
        slice::from_raw_parts_mut(array_pointer as *mut i8, n as usize)
    };
    sort(&mut to_sort);
}
#[no_mangle]
pub extern "C" fn ffi_mergesort_i16(array_pointer: *const libc::int16_t, n: libc::size_t) {
    assert!(!array_pointer.is_null());
    assert!(n != 0);
    let mut to_sort = unsafe {
        slice::from_raw_parts_mut(array_pointer as *mut i16, n as usize)
    };
    sort(&mut to_sort);
}
#[no_mangle]
pub extern "C" fn ffi_mergesort_i32(array_pointer: *const libc::int32_t, n: libc::size_t) {
    assert!(!array_pointer.is_null());
    assert!(n != 0);
    let mut to_sort = unsafe {
        slice::from_raw_parts_mut(array_pointer as *mut i32, n as usize)
    };
    sort(&mut to_sort);
}
#[no_mangle]
pub extern "C" fn ffi_mergesort_i64(array_pointer: *const libc::int64_t, n: libc::size_t) {
    assert!(!array_pointer.is_null());
    assert!(n != 0);
    let mut to_sort = unsafe {
        slice::from_raw_parts_mut(array_pointer as *mut i64, n as usize)
    };
    sort(&mut to_sort);
}

#[no_mangle]
pub extern "C" fn ffi_mergesort_u8(array_pointer: *const libc::uint8_t, n: libc::size_t) {
    assert!(!array_pointer.is_null());
    assert!(n != 0);
    let mut to_sort = unsafe {
        slice::from_raw_parts_mut(array_pointer as *mut u8, n as usize)
    };
    sort(&mut to_sort);
}
#[no_mangle]
pub extern "C" fn ffi_mergesort_u16(array_pointer: *const libc::uint16_t, n: libc::size_t) {
    assert!(!array_pointer.is_null());
    assert!(n != 0);
    let mut to_sort = unsafe {
        slice::from_raw_parts_mut(array_pointer as *mut u16, n as usize)
    };
    sort(&mut to_sort);
}
#[no_mangle]
pub extern "C" fn ffi_mergesort_u32(array_pointer: *const libc::uint32_t, n: libc::size_t) {
    assert!(!array_pointer.is_null());
    assert!(n != 0);
    let mut to_sort = unsafe {
        slice::from_raw_parts_mut(array_pointer as *mut u32, n as usize)
    };
    sort(&mut to_sort);
}
#[no_mangle]
pub extern "C" fn ffi_mergesort_u64(array_pointer: *const libc::uint64_t, n: libc::size_t) {
    assert!(!array_pointer.is_null());
    assert!(n != 0);
    let mut to_sort = unsafe {
        slice::from_raw_parts_mut(array_pointer as *mut u64, n as usize)
    };
    sort(&mut to_sort);
}

#[no_mangle]
pub extern "C" fn ffi_mergesort_f32(array_pointer: *const libc::c_void, n: libc::size_t) {
    assert!(!array_pointer.is_null());
    assert!(n != 0);
    let mut to_sort = unsafe {
        slice::from_raw_parts_mut(array_pointer as *mut f32, n as usize)
    };
    sort(&mut to_sort);
}
#[no_mangle]
pub extern "C" fn ffi_mergesort_f64(array_pointer: *const libc::c_void, n: libc::size_t) {
    assert!(!array_pointer.is_null());
    assert!(n != 0);
    let mut to_sort = unsafe {
        slice::from_raw_parts_mut(array_pointer as *mut f64, n as usize)
    };
    sort(&mut to_sort);
}
<|endoftext|>


<commit_before>//! `ResponseError` trait and foreign impls.

use std::{
    error::Error as StdError,
    fmt,
    io::{self, Write as _},
};

use actix_http::{body::AnyBody, header, Response, StatusCode};
use bytes::BytesMut;

use crate::error::{downcast_dyn, downcast_get_type_id};
use crate::{helpers, HttpResponse};

/// Errors that can generate responses.
// TODO: add std::error::Error bound when replacement for Box<dyn Error> is found
pub trait ResponseError: fmt::Debug + fmt::Display {
    /// Returns appropriate status code for error.
    ///
    /// A 500 Internal Server Error is used by default. If [error_response](Self::error_response) is
    /// also implemented and does not call `self.status_code()`, then this will not be used.
    fn status_code(&self) -> StatusCode {
        StatusCode::INTERNAL_SERVER_ERROR
    }

    /// Creates full response for error.
    ///
    /// By default, the generated response uses a 500 Internal Server Error status code, a
    /// `Content-Type` of `text/plain`, and the body is set to `Self`'s `Display` impl.
    fn error_response(&self) -> HttpResponse {
        let mut res = HttpResponse::new(self.status_code());

        let mut buf = BytesMut::new();
        let _ = write!(helpers::MutWriter(&mut buf), "{}", self);

        res.headers_mut().insert(
            header::CONTENT_TYPE,
            header::HeaderValue::from_static("text/plain; charset=utf-8"),
        );

        res.set_body(AnyBody::from(buf))
    }

    downcast_get_type_id!();
}

downcast_dyn!(ResponseError);

impl ResponseError for Box<dyn StdError + 'static> {}

#[cfg(feature = "openssl")]
impl ResponseError for actix_tls::accept::openssl::SslError {}

impl ResponseError for serde::de::value::Error {
    fn status_code(&self) -> StatusCode {
        StatusCode::BAD_REQUEST
    }
}

impl ResponseError for std::str::Utf8Error {
    fn status_code(&self) -> StatusCode {
        StatusCode::BAD_REQUEST
    }
}

impl ResponseError for std::io::Error {
    fn status_code(&self) -> StatusCode {
        // TODO: decide if these errors should consider not found or permission errors
        match self.kind() {
            io::ErrorKind::NotFound => StatusCode::NOT_FOUND,
            io::ErrorKind::PermissionDenied => StatusCode::FORBIDDEN,
            _ => StatusCode::INTERNAL_SERVER_ERROR,
        }
    }
}

impl ResponseError for actix_http::error::HttpError {}

impl ResponseError for actix_http::Error {
    fn status_code(&self) -> StatusCode {
        // TODO: map error kinds to status code better
        StatusCode::INTERNAL_SERVER_ERROR
    }

    fn error_response(&self) -> HttpResponse {
        HttpResponse::new(self.status_code()).set_body(self.to_string().into())
    }
}

impl ResponseError for actix_http::header::InvalidHeaderValue {
    fn status_code(&self) -> StatusCode {
        StatusCode::BAD_REQUEST
    }
}

impl ResponseError for actix_http::error::ParseError {
    fn status_code(&self) -> StatusCode {
        StatusCode::BAD_REQUEST
    }
}

impl ResponseError for actix_http::error::BlockingError {}

impl ResponseError for actix_http::error::PayloadError {
    fn status_code(&self) -> StatusCode {
        match *self {
            actix_http::error::PayloadError::Overflow => StatusCode::PAYLOAD_TOO_LARGE,
            _ => StatusCode::BAD_REQUEST,
        }
    }
}

impl ResponseError for actix_http::ws::ProtocolError {}

impl ResponseError for actix_http::error::ContentTypeError {
    fn status_code(&self) -> StatusCode {
        StatusCode::BAD_REQUEST
    }
}

impl ResponseError for actix_http::ws::HandshakeError {
    fn error_response(&self) -> HttpResponse {
        Response::from(self).into()
    }
}

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

    #[test]
    fn test_error_casting() {
        use actix_http::error::{ContentTypeError, PayloadError};

        let err = PayloadError::Overflow;
        let resp_err: &dyn ResponseError = &err;

        let err = resp_err.downcast_ref::<PayloadError>().unwrap();
        assert_eq!(err.to_string(), "Payload reached size limit.");

        let not_err = resp_err.downcast_ref::<ContentTypeError>();
        assert!(not_err.is_none());
    }
}
<commit_msg>re-add serde error impls<commit_after>//! `ResponseError` trait and foreign impls.

use std::{
    error::Error as StdError,
    fmt,
    io::{self, Write as _},
};

use actix_http::{body::AnyBody, header, Response, StatusCode};
use bytes::BytesMut;

use crate::error::{downcast_dyn, downcast_get_type_id};
use crate::{helpers, HttpResponse};

/// Errors that can generate responses.
// TODO: add std::error::Error bound when replacement for Box<dyn Error> is found
pub trait ResponseError: fmt::Debug + fmt::Display {
    /// Returns appropriate status code for error.
    ///
    /// A 500 Internal Server Error is used by default. If [error_response](Self::error_response) is
    /// also implemented and does not call `self.status_code()`, then this will not be used.
    fn status_code(&self) -> StatusCode {
        StatusCode::INTERNAL_SERVER_ERROR
    }

    /// Creates full response for error.
    ///
    /// By default, the generated response uses a 500 Internal Server Error status code, a
    /// `Content-Type` of `text/plain`, and the body is set to `Self`'s `Display` impl.
    fn error_response(&self) -> HttpResponse {
        let mut res = HttpResponse::new(self.status_code());

        let mut buf = BytesMut::new();
        let _ = write!(helpers::MutWriter(&mut buf), "{}", self);

        res.headers_mut().insert(
            header::CONTENT_TYPE,
            header::HeaderValue::from_static("text/plain; charset=utf-8"),
        );

        res.set_body(AnyBody::from(buf))
    }

    downcast_get_type_id!();
}

downcast_dyn!(ResponseError);

impl ResponseError for Box<dyn StdError + 'static> {}

#[cfg(feature = "openssl")]
impl ResponseError for actix_tls::accept::openssl::SslError {}

impl ResponseError for serde::de::value::Error {
    fn status_code(&self) -> StatusCode {
        StatusCode::BAD_REQUEST
    }
}

impl ResponseError for serde_json::Error {}

impl ResponseError for serde_urlencoded::ser::Error {}

impl ResponseError for std::str::Utf8Error {
    fn status_code(&self) -> StatusCode {
        StatusCode::BAD_REQUEST
    }
}

impl ResponseError for std::io::Error {
    fn status_code(&self) -> StatusCode {
        // TODO: decide if these errors should consider not found or permission errors
        match self.kind() {
            io::ErrorKind::NotFound => StatusCode::NOT_FOUND,
            io::ErrorKind::PermissionDenied => StatusCode::FORBIDDEN,
            _ => StatusCode::INTERNAL_SERVER_ERROR,
        }
    }
}

impl ResponseError for actix_http::error::HttpError {}

impl ResponseError for actix_http::Error {
    fn status_code(&self) -> StatusCode {
        // TODO: map error kinds to status code better
        StatusCode::INTERNAL_SERVER_ERROR
    }

    fn error_response(&self) -> HttpResponse {
        HttpResponse::new(self.status_code()).set_body(self.to_string().into())
    }
}

impl ResponseError for actix_http::header::InvalidHeaderValue {
    fn status_code(&self) -> StatusCode {
        StatusCode::BAD_REQUEST
    }
}

impl ResponseError for actix_http::error::ParseError {
    fn status_code(&self) -> StatusCode {
        StatusCode::BAD_REQUEST
    }
}

impl ResponseError for actix_http::error::BlockingError {}

impl ResponseError for actix_http::error::PayloadError {
    fn status_code(&self) -> StatusCode {
        match *self {
            actix_http::error::PayloadError::Overflow => StatusCode::PAYLOAD_TOO_LARGE,
            _ => StatusCode::BAD_REQUEST,
        }
    }
}

impl ResponseError for actix_http::ws::ProtocolError {}

impl ResponseError for actix_http::error::ContentTypeError {
    fn status_code(&self) -> StatusCode {
        StatusCode::BAD_REQUEST
    }
}

impl ResponseError for actix_http::ws::HandshakeError {
    fn error_response(&self) -> HttpResponse {
        Response::from(self).into()
    }
}

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

    #[test]
    fn test_error_casting() {
        use actix_http::error::{ContentTypeError, PayloadError};

        let err = PayloadError::Overflow;
        let resp_err: &dyn ResponseError = &err;

        let err = resp_err.downcast_ref::<PayloadError>().unwrap();
        assert_eq!(err.to_string(), "Payload reached size limit.");

        let not_err = resp_err.downcast_ref::<ContentTypeError>();
        assert!(not_err.is_none());
    }
}
<|endoftext|>


<commit_before>use super::*;

pub struct PriceFilter {
    pub locale: String,
}

impl PriceFilter {
    fn currencies(&self) -> &'static str {
        "$¢£¤¥֏؋৲৳৻૱௹฿₠₡₢₣₤₥₦₧₨₩₪₫€₭₮₯₰₱₲₳₴₵₶₷₸₹₺₽﹩＄￠￡￥￦"
    }
}

impl LinterFilter for PriceFilter {
    fn locales(&self) -> Vec<&'static str> {
        vec!("de", "es", "fr")
    }

    fn message(&self) -> &'static str {
        match &self.locale as &str {
            "de" | "es" | "fr" => "The currency sign should be written after the amount and a non-breaking space.",
            _ => "",
        }
    }

    fn regex_pattern(&self) -> String {
        match &self.locale as &str {
            // Matches one of the following:
            // - digits followed by a character (or none) other than a non-breaking space followed
            //   by any of currencies() return values (ex: `120€` or `120 $`);
            // - any of currencies() return values followed by any whitespace character (or not)
            //   followed by digits (ex: `€120` or `$ 120`).
            "de" | "es" | "fr" => format!("([\\d]+[^ ]?[{}]{{1}}|[{}]{{1}}[\\s]?[\\d]+)", self.currencies(), self.currencies()),
            _ => "".to_string(),
        }
    }
}

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

    struct ExpectedWarning {
        locale: &'static str,
        text: &'static str,
        start: usize,
        end: usize,
    }

    fn expected_warnings() -> Vec<ExpectedWarning> {
        vec!(
            ExpectedWarning { locale: "de", text: "€120", start: 0, end: 6},
            ExpectedWarning { locale: "de", text: "120 €", start: 0, end: 7},
            ExpectedWarning { locale: "de", text: "120€", start: 0, end: 6},

            ExpectedWarning { locale: "es", text: "€120", start: 0, end: 6},
            ExpectedWarning { locale: "es", text: "120 €", start: 0, end: 7},
            ExpectedWarning { locale: "es", text: "120€", start: 0, end: 6},

            ExpectedWarning { locale: "fr", text: "€120", start: 0, end: 6},
            ExpectedWarning { locale: "fr", text: "120 €", start: 0, end: 7},
            ExpectedWarning { locale: "fr", text: "120€", start: 0, end: 6}
        )
    }

    #[test]
    fn test_filters_when_warnings() {
        for expected_warning in expected_warnings() {
            let filter = PriceFilter { locale: expected_warning.locale.to_string() };

            let result = filter.check(expected_warning.text);

            assert!(result.is_err());

            let warnings = result.err().unwrap();

            assert_eq!(1, warnings.len());
            assert_eq!(expected_warning.start, warnings[0].start);
            assert_eq!(expected_warning.end, warnings[0].end);
        }
    }

    #[test]
    fn test_filter_when_de_and_no_warnings() {
        let filter = PriceFilter { locale: "de".to_string() };

        let result = filter.check("120 €");

        assert_eq!(false, result.is_err());
        assert_eq!((), result.unwrap());
    }

    #[test]
    fn test_filter_when_es_and_no_warnings() {
        let filter = PriceFilter { locale: "es".to_string() };

        let result = filter.check("120 €");

        assert_eq!(false, result.is_err());
        assert_eq!((), result.unwrap());
    }

    #[test]
    fn test_filter_when_fr_and_no_warnings() {
        let filter = PriceFilter { locale: "fr".to_string() };

        let result = filter.check("120 €");

        assert_eq!(false, result.is_err());
        assert_eq!((), result.unwrap());
    }
}

<commit_msg>Add English in PriceFilter<commit_after>use super::*;

pub struct PriceFilter {
    pub locale: String,
}

impl PriceFilter {
    fn currencies(&self) -> &'static str {
        "$¢£¤¥֏؋৲৳৻૱௹฿₠₡₢₣₤₥₦₧₨₩₪₫€₭₮₯₰₱₲₳₴₵₶₷₸₹₺₽﹩＄￠￡￥￦"
    }
}

impl LinterFilter for PriceFilter {
    fn locales(&self) -> Vec<&'static str> {
        vec!("de", "en", "es", "fr")
    }

    fn message(&self) -> &'static str {
        match &self.locale as &str {
            "de" | "es" | "fr" => "The currency sign should be written after the amount and a non-breaking space.",
            "en" => "The currency sign should be written before the amount without space.",
            _ => "",
        }
    }

    fn regex_pattern(&self) -> String {
        match &self.locale as &str {
            // Matches one of the following:
            // - digits followed by a character (or none) other than a non-breaking space followed
            //   by any of currencies() return values (ex: `120€` or `120 $`);
            // - any of currencies() return values followed by any whitespace character (or not)
            //   followed by digits (ex: `€120` or `$ 120`).
            "de" | "es" | "fr" => format!("([\\d]+[^ ]?[{}]{{1}}|[{}]{{1}}[\\s]?[\\d]+)", self.currencies(), self.currencies()),

            // Matches one of the following:
            // - digits followed by any whitespace character (or not) followed by any of
            //   currencies() return values (ex: `120€` or `120 €`)
            // - any of currencies() return values followed by any whitespace character followed by
            //   digits (ex: `€ 120` or `$ 120`).
            "en" => format!("([\\d]+[\\s]?[{}]{{1}}|[{}]{{1}}[\\s][\\d]+)", self.currencies(), self.currencies()),

            _ => "".to_string(),
        }
    }
}

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

    struct ExpectedWarning {
        locale: &'static str,
        text: &'static str,
        start: usize,
        end: usize,
    }

    fn expected_warnings() -> Vec<ExpectedWarning> {
        vec!(
            ExpectedWarning { locale: "de", text: "€120", start: 0, end: 6},
            ExpectedWarning { locale: "de", text: "120 €", start: 0, end: 7},
            ExpectedWarning { locale: "de", text: "120€", start: 0, end: 6},

            ExpectedWarning { locale: "en", text: "120 €", start: 0, end: 7},
            ExpectedWarning { locale: "en", text: "120 €", start: 0, end: 8},
            ExpectedWarning { locale: "en", text: "120€", start: 0, end: 6},
            ExpectedWarning { locale: "en", text: "€ 120", start: 0, end: 7},
            ExpectedWarning { locale: "en", text: "€ 120", start: 0, end: 8},

            ExpectedWarning { locale: "es", text: "€120", start: 0, end: 6},
            ExpectedWarning { locale: "es", text: "120 €", start: 0, end: 7},
            ExpectedWarning { locale: "es", text: "120€", start: 0, end: 6},

            ExpectedWarning { locale: "fr", text: "€120", start: 0, end: 6},
            ExpectedWarning { locale: "fr", text: "120 €", start: 0, end: 7},
            ExpectedWarning { locale: "fr", text: "120€", start: 0, end: 6}
        )
    }

    #[test]
    fn test_filters_when_warnings() {
        for expected_warning in expected_warnings() {
            let filter = PriceFilter { locale: expected_warning.locale.to_string() };

            let result = filter.check(expected_warning.text);

            assert!(result.is_err());

            let warnings = result.err().unwrap();

            assert_eq!(1, warnings.len());
            assert_eq!(expected_warning.start, warnings[0].start);
            assert_eq!(expected_warning.end, warnings[0].end);
        }
    }

    #[test]
    fn test_filter_when_de_and_no_warnings() {
        let filter = PriceFilter { locale: "de".to_string() };

        let result = filter.check("120 €");

        assert_eq!(false, result.is_err());
        assert_eq!((), result.unwrap());
    }

    #[test]
    fn test_filter_when_en_and_no_warnings() {
        let filter = PriceFilter { locale: "en".to_string() };

        let result = filter.check("€120");

        assert_eq!(false, result.is_err());
        assert_eq!((), result.unwrap());
    }

    #[test]
    fn test_filter_when_es_and_no_warnings() {
        let filter = PriceFilter { locale: "es".to_string() };

        let result = filter.check("120 €");

        assert_eq!(false, result.is_err());
        assert_eq!((), result.unwrap());
    }

    #[test]
    fn test_filter_when_fr_and_no_warnings() {
        let filter = PriceFilter { locale: "fr".to_string() };

        let result = filter.check("120 €");

        assert_eq!(false, result.is_err());
        assert_eq!((), result.unwrap());
    }
}

<|endoftext|>


<commit_before>// Copyright 2015-2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Inspired by Paul Woolcock's cargo-fmt (https://github.com/pwoolcoc/cargo-fmt/)

#![cfg(not(test))]
#![deny(warnings)]

extern crate cargo_metadata;
extern crate getopts;
extern crate serde_json as json;

use std::env;
use std::fs;
use std::hash::{Hash, Hasher};
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::process::{Command, ExitStatus};
use std::str;
use std::collections::HashSet;
use std::iter::FromIterator;

use getopts::{Matches, Options};

fn main() {
    let exit_status = execute();
    std::io::stdout().flush().unwrap();
    std::process::exit(exit_status);
}

const SUCCESS: i32 = 0;
const FAILURE: i32 = 1;

fn execute() -> i32 {
    let mut opts = getopts::Options::new();
    opts.optflag("h", "help", "show this message");
    opts.optflag("q", "quiet", "no output printed to stdout");
    opts.optflag("v", "verbose", "use verbose output");
    opts.optmulti(
        "p",
        "package",
        "specify package to format (only usable in workspaces)",
        "<package>",
    );
    opts.optflag("", "version", "print rustfmt version and exit");
    opts.optflag("", "all", "format all packages (only usable in workspaces)");

    // If there is any invalid argument passed to `cargo fmt`, return without formatting.
    let mut is_package_arg = false;
    for arg in env::args().skip(2).take_while(|a| a != "--") {
        if arg.starts_with('-') {
            is_package_arg = arg.starts_with("--package");
        } else if !is_package_arg {
            print_usage_to_stderr(&opts, &format!("Invalid argument: `{}`.", arg));
            return FAILURE;
        } else {
            is_package_arg = false;
        }
    }

    let matches = match opts.parse(env::args().skip(1).take_while(|a| a != "--")) {
        Ok(m) => m,
        Err(e) => {
            print_usage_to_stderr(&opts, &e.to_string());
            return FAILURE;
        }
    };

    let verbosity = match (matches.opt_present("v"), matches.opt_present("q")) {
        (false, false) => Verbosity::Normal,
        (false, true) => Verbosity::Quiet,
        (true, false) => Verbosity::Verbose,
        (true, true) => {
            print_usage_to_stderr(&opts, "quiet mode and verbose mode are not compatible");
            return FAILURE;
        }
    };

    if matches.opt_present("h") {
        print_usage_to_stdout(&opts, "");
        return SUCCESS;
    }

    if matches.opt_present("version") {
        return handle_command_status(get_version(), &opts);
    }

    let strategy = CargoFmtStrategy::from_matches(&matches);
    handle_command_status(format_crate(verbosity, &strategy), &opts)
}

macro_rules! print_usage {
    ($print:ident, $opts:ident, $reason:expr) => ({
        let msg = format!("{}\nusage: cargo fmt [options]", $reason);
        $print!(
            "{}\nThis utility formats all bin and lib files of the current crate using rustfmt. \
             Arguments after `--` are passed to rustfmt.",
            $opts.usage(&msg)
        );
    })
}

fn print_usage_to_stdout(opts: &Options, reason: &str) {
    print_usage!(println, opts, reason);
}

fn print_usage_to_stderr(opts: &Options, reason: &str) {
    print_usage!(eprintln, opts, reason);
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Verbosity {
    Verbose,
    Normal,
    Quiet,
}

fn handle_command_status(status: Result<ExitStatus, io::Error>, opts: &getopts::Options) -> i32 {
    match status {
        Err(e) => {
            print_usage_to_stderr(&opts, &e.to_string());
            FAILURE
        }
        Ok(status) => {
            if status.success() {
                SUCCESS
            } else {
                status.code().unwrap_or(FAILURE)
            }
        }
    }
}

fn get_version() -> Result<ExitStatus, io::Error> {
    let mut command = Command::new("rustfmt")
        .args(vec!["--version"])
        .spawn()
        .map_err(|e| match e.kind() {
            io::ErrorKind::NotFound => io::Error::new(
                io::ErrorKind::Other,
                "Could not run rustfmt, please make sure it is in your PATH.",
            ),
            _ => e,
        })?;

    command.wait()
}

fn format_crate(
    verbosity: Verbosity,
    strategy: &CargoFmtStrategy,
) -> Result<ExitStatus, io::Error> {
    let rustfmt_args = get_fmt_args();
    let targets = if rustfmt_args.iter().any(|s| s == "--dump-default-config") {
        HashSet::new()
    } else {
        get_targets(strategy)?
    };

    // Currently only bin and lib files get formatted
    let files: Vec<_> = targets
        .into_iter()
        .inspect(|t| {
            if verbosity == Verbosity::Verbose {
                println!("[{}] {:?}", t.kind, t.path)
            }
        })
        .map(|t| t.path)
        .collect();

    format_files(&files, &rustfmt_args, verbosity)
}

fn get_fmt_args() -> Vec<String> {
    // All arguments after -- are passed to rustfmt
    env::args().skip_while(|a| a != "--").skip(1).collect()
}

/// Target uses a `path` field for equality and hashing.
#[derive(Debug)]
pub struct Target {
    /// A path to the main source file of the target.
    path: PathBuf,
    /// A kind of target (e.g. lib, bin, example, ...).
    kind: String,
}

impl Target {
    pub fn from_target(target: &cargo_metadata::Target) -> Self {
        let path = PathBuf::from(&target.src_path);
        let canonicalized = fs::canonicalize(&path).unwrap_or(path);

        Target {
            path: canonicalized,
            kind: target.kind[0].clone(),
        }
    }
}

impl PartialEq for Target {
    fn eq(&self, other: &Target) -> bool {
        self.path == other.path
    }
}

impl Eq for Target {}

impl Hash for Target {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.path.hash(state);
    }
}

#[derive(Debug, PartialEq, Eq)]
pub enum CargoFmtStrategy {
    /// Format every packages and dependencies.
    All,
    /// Format pacakges that are specified by the command line argument.
    Some(Vec<String>),
    /// Format the root packages only.
    Root,
}

impl CargoFmtStrategy {
    pub fn from_matches(matches: &Matches) -> CargoFmtStrategy {
        match (matches.opt_present("all"), matches.opt_present("p")) {
            (false, false) => CargoFmtStrategy::Root,
            (true, _) => CargoFmtStrategy::All,
            (false, true) => CargoFmtStrategy::Some(matches.opt_strs("p")),
        }
    }
}

/// Based on the specified `CargoFmtStrategy`, returns a set of main source files.
fn get_targets(strategy: &CargoFmtStrategy) -> Result<HashSet<Target>, io::Error> {
    let mut targets = HashSet::new();

    match *strategy {
        CargoFmtStrategy::Root => get_targets_root_only(&mut targets)?,
        CargoFmtStrategy::All => get_targets_recursive(None, &mut targets, &mut HashSet::new())?,
        CargoFmtStrategy::Some(ref hitlist) => get_targets_with_hitlist(hitlist, &mut targets)?,
    }

    if targets.is_empty() {
        Err(io::Error::new(
            io::ErrorKind::Other,
            "Failed to find targets".to_owned(),
        ))
    } else {
        Ok(targets)
    }
}

fn get_targets_root_only(targets: &mut HashSet<Target>) -> Result<(), io::Error> {
    let metadata = get_cargo_metadata(None)?;

    for package in metadata.packages {
        for target in package.targets {
            if target.name == package.name {
                targets.insert(Target::from_target(&target));
            }
        }
    }

    Ok(())
}

fn get_targets_recursive(
    manifest_path: Option<&Path>,
    mut targets: &mut HashSet<Target>,
    visited: &mut HashSet<String>,
) -> Result<(), io::Error> {
    let metadata = get_cargo_metadata(manifest_path)?;

    for package in metadata.packages {
        add_targets(&package.targets, &mut targets);

        // Look for local dependencies.
        for dependency in package.dependencies {
            if dependency.source.is_some() || visited.contains(&dependency.name) {
                continue;
            }

            let mut manifest_path = PathBuf::from(&package.manifest_path);

            manifest_path.pop();
            manifest_path.push(&dependency.name);
            manifest_path.push("Cargo.toml");

            if manifest_path.exists() {
                visited.insert(dependency.name);
                get_targets_recursive(Some(&manifest_path), &mut targets, visited)?;
            }
        }
    }

    Ok(())
}

fn get_targets_with_hitlist(
    hitlist: &[String],
    targets: &mut HashSet<Target>,
) -> Result<(), io::Error> {
    let metadata = get_cargo_metadata(None)?;

    let mut workspace_hitlist: HashSet<&String> = HashSet::from_iter(hitlist);

    for package in metadata.packages {
        if workspace_hitlist.remove(&package.name) {
            for target in package.targets {
                targets.insert(Target::from_target(&target));
            }
        }
    }

    if workspace_hitlist.is_empty() {
        Ok(())
    } else {
        let package = workspace_hitlist.iter().next().unwrap();
        Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            format!("package `{}` is not a member of the workspace", package),
        ))
    }
}

fn add_targets(target_paths: &[cargo_metadata::Target], targets: &mut HashSet<Target>) {
    for target in target_paths {
        targets.insert(Target::from_target(target));
    }
}

fn format_files(
    files: &[PathBuf],
    fmt_args: &[String],
    verbosity: Verbosity,
) -> Result<ExitStatus, io::Error> {
    let stdout = if verbosity == Verbosity::Quiet {
        std::process::Stdio::null()
    } else {
        std::process::Stdio::inherit()
    };

    if verbosity == Verbosity::Verbose {
        print!("rustfmt");
        for a in fmt_args {
            print!(" {}", a);
        }
        for f in files {
            print!(" {}", f.display());
        }
        println!();
    }

    let mut command = Command::new("rustfmt")
        .stdout(stdout)
        .args(files)
        .args(fmt_args)
        .spawn()
        .map_err(|e| match e.kind() {
            io::ErrorKind::NotFound => io::Error::new(
                io::ErrorKind::Other,
                "Could not run rustfmt, please make sure it is in your PATH.",
            ),
            _ => e,
        })?;

    command.wait()
}

fn get_cargo_metadata(manifest_path: Option<&Path>) -> Result<cargo_metadata::Metadata, io::Error> {
    match cargo_metadata::metadata(manifest_path) {
        Ok(metadata) => Ok(metadata),
        Err(..) => Err(io::Error::new(
            io::ErrorKind::Other,
            "`cargo manifest` failed.",
        )),
    }
}
<commit_msg>Using common execute rustfmt function<commit_after>// Copyright 2015-2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Inspired by Paul Woolcock's cargo-fmt (https://github.com/pwoolcoc/cargo-fmt/)

#![cfg(not(test))]
#![deny(warnings)]

extern crate cargo_metadata;
extern crate getopts;
extern crate serde_json as json;

use std::env;
use std::fs;
use std::hash::{Hash, Hasher};
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::process::{Command, ExitStatus};
use std::str;
use std::collections::HashSet;
use std::iter::FromIterator;

use getopts::{Matches, Options};

fn main() {
    let exit_status = execute();
    std::io::stdout().flush().unwrap();
    std::process::exit(exit_status);
}

const SUCCESS: i32 = 0;
const FAILURE: i32 = 1;

fn execute() -> i32 {
    let mut opts = getopts::Options::new();
    opts.optflag("h", "help", "show this message");
    opts.optflag("q", "quiet", "no output printed to stdout");
    opts.optflag("v", "verbose", "use verbose output");
    opts.optmulti(
        "p",
        "package",
        "specify package to format (only usable in workspaces)",
        "<package>",
    );
    opts.optflag("", "version", "print rustfmt version and exit");
    opts.optflag("", "all", "format all packages (only usable in workspaces)");

    // If there is any invalid argument passed to `cargo fmt`, return without formatting.
    let mut is_package_arg = false;
    for arg in env::args().skip(2).take_while(|a| a != "--") {
        if arg.starts_with('-') {
            is_package_arg = arg.starts_with("--package");
        } else if !is_package_arg {
            print_usage_to_stderr(&opts, &format!("Invalid argument: `{}`.", arg));
            return FAILURE;
        } else {
            is_package_arg = false;
        }
    }

    let matches = match opts.parse(env::args().skip(1).take_while(|a| a != "--")) {
        Ok(m) => m,
        Err(e) => {
            print_usage_to_stderr(&opts, &e.to_string());
            return FAILURE;
        }
    };

    let verbosity = match (matches.opt_present("v"), matches.opt_present("q")) {
        (false, false) => Verbosity::Normal,
        (false, true) => Verbosity::Quiet,
        (true, false) => Verbosity::Verbose,
        (true, true) => {
            print_usage_to_stderr(&opts, "quiet mode and verbose mode are not compatible");
            return FAILURE;
        }
    };

    if matches.opt_present("h") {
        print_usage_to_stdout(&opts, "");
        return SUCCESS;
    }

    if matches.opt_present("version") {
        return handle_command_status(get_version(verbosity), &opts);
    }

    let strategy = CargoFmtStrategy::from_matches(&matches);
    handle_command_status(format_crate(verbosity, &strategy), &opts)
}

macro_rules! print_usage {
    ($print:ident, $opts:ident, $reason:expr) => ({
        let msg = format!("{}\nusage: cargo fmt [options]", $reason);
        $print!(
            "{}\nThis utility formats all bin and lib files of the current crate using rustfmt. \
             Arguments after `--` are passed to rustfmt.",
            $opts.usage(&msg)
        );
    })
}

fn print_usage_to_stdout(opts: &Options, reason: &str) {
    print_usage!(println, opts, reason);
}

fn print_usage_to_stderr(opts: &Options, reason: &str) {
    print_usage!(eprintln, opts, reason);
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Verbosity {
    Verbose,
    Normal,
    Quiet,
}

fn handle_command_status(status: Result<ExitStatus, io::Error>, opts: &getopts::Options) -> i32 {
    match status {
        Err(e) => {
            print_usage_to_stderr(&opts, &e.to_string());
            FAILURE
        }
        Ok(status) => {
            if status.success() {
                SUCCESS
            } else {
                status.code().unwrap_or(FAILURE)
            }
        }
    }
}

fn get_version(verbosity: Verbosity) -> Result<ExitStatus, io::Error> {
    run_rustfmt(&vec![], &vec![String::from("--version")], verbosity)
}

fn format_crate(
    verbosity: Verbosity,
    strategy: &CargoFmtStrategy,
) -> Result<ExitStatus, io::Error> {
    let rustfmt_args = get_fmt_args();
    let targets = if rustfmt_args.iter().any(|s| s == "--dump-default-config") {
        HashSet::new()
    } else {
        get_targets(strategy)?
    };

    // Currently only bin and lib files get formatted
    let files: Vec<_> = targets
        .into_iter()
        .inspect(|t| {
            if verbosity == Verbosity::Verbose {
                println!("[{}] {:?}", t.kind, t.path)
            }
        })
        .map(|t| t.path)
        .collect();

    run_rustfmt(&files, &rustfmt_args, verbosity)
}

fn get_fmt_args() -> Vec<String> {
    // All arguments after -- are passed to rustfmt
    env::args().skip_while(|a| a != "--").skip(1).collect()
}

/// Target uses a `path` field for equality and hashing.
#[derive(Debug)]
pub struct Target {
    /// A path to the main source file of the target.
    path: PathBuf,
    /// A kind of target (e.g. lib, bin, example, ...).
    kind: String,
}

impl Target {
    pub fn from_target(target: &cargo_metadata::Target) -> Self {
        let path = PathBuf::from(&target.src_path);
        let canonicalized = fs::canonicalize(&path).unwrap_or(path);

        Target {
            path: canonicalized,
            kind: target.kind[0].clone(),
        }
    }
}

impl PartialEq for Target {
    fn eq(&self, other: &Target) -> bool {
        self.path == other.path
    }
}

impl Eq for Target {}

impl Hash for Target {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.path.hash(state);
    }
}

#[derive(Debug, PartialEq, Eq)]
pub enum CargoFmtStrategy {
    /// Format every packages and dependencies.
    All,
    /// Format pacakges that are specified by the command line argument.
    Some(Vec<String>),
    /// Format the root packages only.
    Root,
}

impl CargoFmtStrategy {
    pub fn from_matches(matches: &Matches) -> CargoFmtStrategy {
        match (matches.opt_present("all"), matches.opt_present("p")) {
            (false, false) => CargoFmtStrategy::Root,
            (true, _) => CargoFmtStrategy::All,
            (false, true) => CargoFmtStrategy::Some(matches.opt_strs("p")),
        }
    }
}

/// Based on the specified `CargoFmtStrategy`, returns a set of main source files.
fn get_targets(strategy: &CargoFmtStrategy) -> Result<HashSet<Target>, io::Error> {
    let mut targets = HashSet::new();

    match *strategy {
        CargoFmtStrategy::Root => get_targets_root_only(&mut targets)?,
        CargoFmtStrategy::All => get_targets_recursive(None, &mut targets, &mut HashSet::new())?,
        CargoFmtStrategy::Some(ref hitlist) => get_targets_with_hitlist(hitlist, &mut targets)?,
    }

    if targets.is_empty() {
        Err(io::Error::new(
            io::ErrorKind::Other,
            "Failed to find targets".to_owned(),
        ))
    } else {
        Ok(targets)
    }
}

fn get_targets_root_only(targets: &mut HashSet<Target>) -> Result<(), io::Error> {
    let metadata = get_cargo_metadata(None)?;

    for package in metadata.packages {
        for target in package.targets {
            if target.name == package.name {
                targets.insert(Target::from_target(&target));
            }
        }
    }

    Ok(())
}

fn get_targets_recursive(
    manifest_path: Option<&Path>,
    mut targets: &mut HashSet<Target>,
    visited: &mut HashSet<String>,
) -> Result<(), io::Error> {
    let metadata = get_cargo_metadata(manifest_path)?;

    for package in metadata.packages {
        add_targets(&package.targets, &mut targets);

        // Look for local dependencies.
        for dependency in package.dependencies {
            if dependency.source.is_some() || visited.contains(&dependency.name) {
                continue;
            }

            let mut manifest_path = PathBuf::from(&package.manifest_path);

            manifest_path.pop();
            manifest_path.push(&dependency.name);
            manifest_path.push("Cargo.toml");

            if manifest_path.exists() {
                visited.insert(dependency.name);
                get_targets_recursive(Some(&manifest_path), &mut targets, visited)?;
            }
        }
    }

    Ok(())
}

fn get_targets_with_hitlist(
    hitlist: &[String],
    targets: &mut HashSet<Target>,
) -> Result<(), io::Error> {
    let metadata = get_cargo_metadata(None)?;

    let mut workspace_hitlist: HashSet<&String> = HashSet::from_iter(hitlist);

    for package in metadata.packages {
        if workspace_hitlist.remove(&package.name) {
            for target in package.targets {
                targets.insert(Target::from_target(&target));
            }
        }
    }

    if workspace_hitlist.is_empty() {
        Ok(())
    } else {
        let package = workspace_hitlist.iter().next().unwrap();
        Err(io::Error::new(
            io::ErrorKind::InvalidInput,
            format!("package `{}` is not a member of the workspace", package),
        ))
    }
}

fn add_targets(target_paths: &[cargo_metadata::Target], targets: &mut HashSet<Target>) {
    for target in target_paths {
        targets.insert(Target::from_target(target));
    }
}

fn run_rustfmt(
    files: &[PathBuf],
    fmt_args: &[String],
    verbosity: Verbosity,
) -> Result<ExitStatus, io::Error> {
    let stdout = if verbosity == Verbosity::Quiet {
        std::process::Stdio::null()
    } else {
        std::process::Stdio::inherit()
    };

    if verbosity == Verbosity::Verbose {
        print!("rustfmt");
        for a in fmt_args {
            print!(" {}", a);
        }
        for f in files {
            print!(" {}", f.display());
        }
        println!();
    }

    let mut command = Command::new("rustfmt")
        .stdout(stdout)
        .args(files)
        .args(fmt_args)
        .spawn()
        .map_err(|e| match e.kind() {
            io::ErrorKind::NotFound => io::Error::new(
                io::ErrorKind::Other,
                "Could not run rustfmt, please make sure it is in your PATH.",
            ),
            _ => e,
        })?;

    command.wait()
}

fn get_cargo_metadata(manifest_path: Option<&Path>) -> Result<cargo_metadata::Metadata, io::Error> {
    match cargo_metadata::metadata(manifest_path) {
        Ok(metadata) => Ok(metadata),
        Err(..) => Err(io::Error::new(
            io::ErrorKind::Other,
            "`cargo manifest` failed.",
        )),
    }
}
<|endoftext|>