<commit_before>use super::dibits;

/// P25 baud rate is 4800 symbols/sec = 9600 bits/sec.
const BAUD: usize = 4800;

/// Yields a series of scaled impulses vs time corresponding to given dibits.
pub struct C4FMImpulse<T: Iterator<Item = dibits::Dibit>> {
    /// The dibit source to iterate over.
    src: T,
    /// Number of samples per impulse/symbol period.
    samples_per_impulse: usize,
    /// Current global sample index.
    sample: usize,
}

impl<T: Iterator<Item = dibits::Dibit>> C4FMImpulse<T> {
    /// Construct a new `C4FMImpulse<T>` from the given source and sample rate.
    pub fn new(src: T, sample_rate: usize) -> C4FMImpulse<T> {
        // Fractional samples aren't supported.
        assert!(sample_rate % BAUD == 0);

        C4FMImpulse {
            src: src,
            samples_per_impulse: sample_rate / BAUD,
            sample: 0,
        }
    }
}

impl<T: Iterator<Item = dibits::Dibit>> Iterator for C4FMImpulse<T> {
    type Item = f64;

    fn next(&mut self) -> Option<Self::Item> {
        // Store current sample and move to the next.
        let s = self.sample;
        self.sample += 1;

        // Impulse is only output at the beginning of a symbol period.
        if s % self.samples_per_impulse != 0 {
            return Some(0.0);
        }

        // Map the current dibit to a scaled impulse.
        if let Some(dibit) = self.src.next() {
            match dibit {
                dibits::Dibit(0b01) => Some(1800.0),
                dibits::Dibit(0b00) => Some(600.0),
                dibits::Dibit(0b10) => Some(-600.0),
                dibits::Dibit(0b11) => Some(-1800.0),
                _ => panic!("invalid dibit encountered"),
            }
        } else {
            None
        }
    }
}

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

        const BITS: &'static [u8] = &[
            0b00011011,
        ];

        let d = dibits::Dibits::new(BITS.iter().cloned());
        let mut imp = C4FMImpulse::new(d, 9600);

        assert!(imp.next().unwrap() == 600.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 1800.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == -600.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == -1800.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().is_none());
    }
}
<commit_msg>Add C4FMDeviationDibits iterator<commit_after>use super::dibits;

/// P25 baud rate is 4800 symbols/sec = 9600 bits/sec.
const BAUD: usize = 4800;

/// Yields a series of scaled impulses vs time corresponding to given dibits.
pub struct C4FMImpulse<T: Iterator<Item = dibits::Dibit>> {
    /// The dibit source to iterate over.
    src: T,
    /// Number of samples per impulse/symbol period.
    samples_per_impulse: usize,
    /// Current global sample index.
    sample: usize,
}

impl<T: Iterator<Item = dibits::Dibit>> C4FMImpulse<T> {
    /// Construct a new `C4FMImpulse<T>` from the given source and sample rate.
    pub fn new(src: T, sample_rate: usize) -> C4FMImpulse<T> {
        // Fractional samples aren't supported.
        assert!(sample_rate % BAUD == 0);

        C4FMImpulse {
            src: src,
            samples_per_impulse: sample_rate / BAUD,
            sample: 0,
        }
    }
}

impl<T: Iterator<Item = dibits::Dibit>> Iterator for C4FMImpulse<T> {
    type Item = f64;

    fn next(&mut self) -> Option<Self::Item> {
        // Store current sample and move to the next.
        let s = self.sample;
        self.sample += 1;

        // Impulse is only output at the beginning of a symbol period.
        if s % self.samples_per_impulse != 0 {
            return Some(0.0);
        }

        // Map the current dibit to a scaled impulse.
        if let Some(dibit) = self.src.next() {
            match dibit {
                dibits::Dibit(0b01) => Some(1800.0),
                dibits::Dibit(0b00) => Some(600.0),
                dibits::Dibit(0b10) => Some(-600.0),
                dibits::Dibit(0b11) => Some(-1800.0),
                _ => panic!("invalid dibit encountered"),
            }
        } else {
            None
        }
    }
}

/// Generates the alternating series of dibits used for the C4FM deviation test. The
/// resulting filtered waveform approximates a 1200Hz sine wave.
pub struct C4FMDeviationDibits {
    /// Used to alternate dibits.
    idx: usize,
}

impl C4FMDeviationDibits {
    /// Construct a new `C4FMDeviationDibits`.
    pub fn new() -> C4FMDeviationDibits {
        C4FMDeviationDibits {
            idx: 0,
        }
    }
}

impl Iterator for C4FMDeviationDibits {
    type Item = dibits::Dibit;

    fn next(&mut self) -> Option<Self::Item> {
        let idx = self.idx;

        self.idx += 1;
        self.idx %= 4;

        Some(if idx < 2 {
            dibits::Dibit(0b01)
        } else {
            dibits::Dibit(0b11)
        })
    }
}

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

    #[test]
    fn test_impulses() {
        const BITS: &'static [u8] = &[
            0b00011011,
        ];

        let d = dibits::Dibits::new(BITS.iter().cloned());
        let mut imp = C4FMImpulse::new(d, 9600);

        assert!(imp.next().unwrap() == 600.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == 1800.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == -600.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().unwrap() == -1800.0);
        assert!(imp.next().unwrap() == 0.0);
        assert!(imp.next().is_none());
    }

    #[test]
    fn test_deviation() {
        let mut d = C4FMDeviationDibits::new();

        assert!(d.next().unwrap().0 == 0b01);
        assert!(d.next().unwrap().0 == 0b01);
        assert!(d.next().unwrap().0 == 0b11);
        assert!(d.next().unwrap().0 == 0b11);
        assert!(d.next().unwrap().0 == 0b01);
        assert!(d.next().unwrap().0 == 0b01);
        assert!(d.next().unwrap().0 == 0b11);
        assert!(d.next().unwrap().0 == 0b11);
    }
}
<|endoftext|>


<commit_before>use std::io::buffered::BufferedStream;
use std::io::net::ip::SocketAddr;
use std::io::net::tcp::TcpStream;
use std::io::Stream;
use std::vec::bytes::push_bytes;
use std::vec;
use std::str::from_utf8;

pub enum Result {
  Nil,
  Int(int),
  Data(~[u8]),
  List(~[Result]),
  Error(~str),
  Status(~str),
  ProtocolError(&'static str)
}

fn read_char<T: Stream>(io: &mut BufferedStream<T>) -> Option<char> {
  match io.read_byte() {
    Some(ch) => Some(ch as char),
    None     => None
  }
}

fn parse_data<T: Stream>(len: uint, io: &mut BufferedStream<T>) -> Result {
  let res =
    if (len > 0) {
      let bytes = io.read_bytes(len);
      if bytes.len() != len {
        return ProtocolError("Invalid number of bytes")
      } else {
        Data(bytes)
      }
    } else {
      Data(~[])
    };

  if (read_char(io) != Some('\r')) {
    return ProtocolError("Carriage return expected"); // TODO: ignore
  }

  if (read_char(io) != Some('\n')) {
    return ProtocolError("Newline expected");
  }

  return res;
}

fn parse_list<T: Stream>(len: uint, io: &mut BufferedStream<T>) -> Result {
  let mut list: ~[Result] = vec::with_capacity(len);

  for _ in range(0, len) {
    match parse(io) {
      ProtocolError(err) => {
        return ProtocolError(err);
      }
      other => {
        list.push(other);
      }
    }
  }

  List(list)
}

fn parse_int_line<T: Stream>(io: &mut BufferedStream<T>) -> Option<int> {
  let mut i: int = 0;
  let mut digits: uint = 0;
  let mut negative: bool = false;

  loop {
    match read_char(io) {
      None => { return None }
      Some(ch) => {
        match ch {
          '0' .. '9' => {
            digits += 1;
            i = (i * 10) + (ch as int - '0' as int);
          }
          '-' => {
            if negative { return None }
            negative = true
          }
          '\r' => {
            if read_char(io) != Some('\n') { return None }
            break
          }
          '\n' => { break }
          _ => { return None }
        }
      }
    }
  }

  if digits == 0 { return None }

  if negative { Some(-i) }
  else { Some(i) }
}

fn parse_n<T: Stream>(io: &mut BufferedStream<T>, f: |uint, &mut BufferedStream<T>| -> Result) -> Result {
  match parse_int_line(io) {
    Some(-1) => Nil,
    Some(len) if len >= 0 => f(len as uint, io),
    _ => ProtocolError("Invalid number")
  }
}

fn parse_status<T: Stream>(io: &mut BufferedStream<T>) -> Result {
  match io.read_line() {
    Some(line) => Status(line),
    None       => ProtocolError("Invalid status line")
  }
}

fn parse_error<T: Stream>(io: &mut BufferedStream<T>) -> Result {
  match io.read_line() {
    Some(line) => Error(line),
    None       => ProtocolError("Invalid error line")
  }
}

pub fn parse<T: Stream>(io: &mut BufferedStream<T>) -> Result {
  match read_char(io) {
    Some('$') => parse_n(io, parse_data),
    Some('*') => parse_n(io, parse_list),
    Some('+') => parse_status(io),
    Some('-') => parse_error(io),
    Some(':') => {
      match parse_int_line(io) {
        Some(i) => Int(i),
        None => ProtocolError("Invalid number")
      }
    },
    Some(_)   => ProtocolError("Invalid character"),
    None      => ProtocolError("Invalid EOF")
  }
}

pub struct CommandWriter {
  buf: ~[u8]
}

impl CommandWriter {
  pub fn new() -> CommandWriter {
    CommandWriter { buf: ~[] }
  }

  pub fn args<'a>(&'a mut self, n: uint) -> &'a mut CommandWriter {
    self.write_char('*');
    self.write_uint(n);
    self.write_crnl();
    self
  }

  pub fn arg_bin<'a>(&'a mut self, arg: &[u8]) -> &'a mut CommandWriter {
    self.write_char('$');
    self.write_uint(arg.len());
    self.write_crnl();
    self.write(arg);
    self.write_crnl();
    self
  }

  pub fn nil(&mut self) {
    self.write_str("$-1");
    self.write_crnl();
  }

  pub fn arg_str<'a>(&'a mut self, arg: &str) -> &'a mut CommandWriter {
    self.write_char('$');
    self.write_uint(arg.len());
    self.write_crnl();
    self.write_str(arg);
    self.write_crnl();
    self
  }

  pub fn error(&mut self, err: &str) {
    self.write_char('-');
    self.write_str(err);
    self.write_crnl();
  }

  pub fn status(&mut self, status: &str) {
    self.write_char('+');
    self.write_str(status);
    self.write_crnl();
  }

  fn write_crnl(&mut self) {
    self.write_char('\r');
    self.write_char('\n');
  }

  fn write_uint(&mut self, n: uint) {
    if n < 10 {
      self.write_byte('0' as u8 + (n as u8));
    }
    else {
      push_bytes(&mut self.buf, n.to_str().into_bytes());
    }
  }

  fn write_str(&mut self, s: &str) {
    push_bytes(&mut self.buf, s.as_bytes());
  }

  fn write(&mut self, s: &[u8]) {
    push_bytes(&mut self.buf, s);
  }

  fn write_char(&mut self, s: char) {
    self.buf.push(s as u8);
  }

  fn write_byte(&mut self, b: u8) {
    self.buf.push(b);
  }

  pub fn with_buf<T>(&self, f: |&[u8]| -> T) -> T {
    f(self.buf.as_slice())
  }
}

fn execute<T: Stream>(cmd: &[u8], io: &mut BufferedStream<T>) -> Result {
  io.write(cmd);
  io.flush();
  parse(io)
}

pub struct Client<T> {
  priv io: BufferedStream<T>
}

impl Client<TcpStream> {
  pub fn new(sock_addr: &str) -> Client<TcpStream> {
    let addr = from_str::<SocketAddr>(sock_addr).unwrap();
    let tcp_stream = TcpStream::connect(addr).unwrap();
    Client::new_from_stream(tcp_stream)
  }
}

impl<T: Stream> Client<T> {
  pub fn new_from_stream(io: T) -> Client<T> {
    Client { io: BufferedStream::new(io) }
  }

  pub fn get(&mut self, key: &str) -> Result {
    let mut cwr = CommandWriter::new();
    cwr.args(2).
        arg_str("GET").
        arg_str(key).
        with_buf(|cmd| execute(cmd, &mut self.io))
  }

  pub fn get_str(&mut self, key: &str) -> Option<~str> {
    match self.get(key) {
      Nil => None,
      Int(i) => Some(i.to_str()),
      Data(ref bytes) => Some(from_utf8(*bytes).to_owned()),
      _ => fail!("Invalid result type from Redis")
    }
  }

  pub fn get_int(&mut self, key: &str) -> Option<int> {
    match self.get(key) {
      Nil => None,
      Data(ref bytes) => from_str(from_utf8(*bytes)), // XXX
      _ => fail!("Invalid result type from Redis")
    }
  }

  pub fn set(&mut self, key: &str, val: &str) -> Result {
    let mut cwr = CommandWriter::new();
    cwr.args(3).
        arg_str("SET").
        arg_str(key).
        arg_str(val).
        with_buf(|cmd| execute(cmd, &mut self.io))
  }

  pub fn set_int(&mut self, key: &str, val: int) -> Result {
    self.set(key, val.to_str())
  }

  pub fn incr(&mut self, key: &str) -> int {
    let mut cwr = CommandWriter::new();
    let res = cwr.args(2).
        arg_str("INCR").
        arg_str(key).
        with_buf(|cmd| execute(cmd, &mut self.io));
    match res {
      Int(i) => i,
      _ => fail!()
    }
  }
}
<commit_msg>Use i64 instead of int<commit_after>use std::io::buffered::BufferedStream;
use std::io::net::ip::SocketAddr;
use std::io::net::tcp::TcpStream;
use std::io::Stream;
use std::vec::bytes::push_bytes;
use std::vec;
use std::str::from_utf8;

pub enum Result {
  Nil,
  Int(i64),
  Data(~[u8]),
  List(~[Result]),
  Error(~str),
  Status(~str),
  ProtocolError(&'static str)
}

fn read_char<T: Stream>(io: &mut BufferedStream<T>) -> Option<char> {
  match io.read_byte() {
    Some(ch) => Some(ch as char),
    None     => None
  }
}

fn parse_data<T: Stream>(len: uint, io: &mut BufferedStream<T>) -> Result {
  let res =
    if (len > 0) {
      let bytes = io.read_bytes(len);
      if bytes.len() != len {
        return ProtocolError("Invalid number of bytes")
      } else {
        Data(bytes)
      }
    } else {
      Data(~[])
    };

  if (read_char(io) != Some('\r')) {
    return ProtocolError("Carriage return expected"); // TODO: ignore
  }

  if (read_char(io) != Some('\n')) {
    return ProtocolError("Newline expected");
  }

  return res;
}

fn parse_list<T: Stream>(len: uint, io: &mut BufferedStream<T>) -> Result {
  let mut list: ~[Result] = vec::with_capacity(len);

  for _ in range(0, len) {
    match parse(io) {
      ProtocolError(err) => {
        return ProtocolError(err);
      }
      other => {
        list.push(other);
      }
    }
  }

  List(list)
}

fn parse_int_line<T: Stream>(io: &mut BufferedStream<T>) -> Option<i64> {
  let mut i: i64 = 0;
  let mut digits: uint = 0;
  let mut negative: bool = false;

  loop {
    match read_char(io) {
      None => { return None }
      Some(ch) => {
        match ch {
          '0' .. '9' => {
            digits += 1;
            i = (i * 10) + (ch as i64 - '0' as i64);
          }
          '-' => {
            if negative { return None }
            negative = true
          }
          '\r' => {
            if read_char(io) != Some('\n') { return None }
            break
          }
          '\n' => { break }
          _ => { return None }
        }
      }
    }
  }

  if digits == 0 { return None }

  if negative { Some(-i) }
  else { Some(i) }
}

fn parse_n<T: Stream>(io: &mut BufferedStream<T>, f: |uint, &mut BufferedStream<T>| -> Result) -> Result {
  match parse_int_line(io) {
    Some(-1) => Nil,
    Some(len) if len >= 0 => f(len as uint, io), // XXX: i64 might be larger than uint
    _ => ProtocolError("Invalid number")
  }
}

fn parse_status<T: Stream>(io: &mut BufferedStream<T>) -> Result {
  match io.read_line() {
    Some(line) => Status(line),
    None       => ProtocolError("Invalid status line")
  }
}

fn parse_error<T: Stream>(io: &mut BufferedStream<T>) -> Result {
  match io.read_line() {
    Some(line) => Error(line),
    None       => ProtocolError("Invalid error line")
  }
}

pub fn parse<T: Stream>(io: &mut BufferedStream<T>) -> Result {
  match read_char(io) {
    Some('$') => parse_n(io, parse_data),
    Some('*') => parse_n(io, parse_list),
    Some('+') => parse_status(io),
    Some('-') => parse_error(io),
    Some(':') => {
      match parse_int_line(io) {
        Some(i) => Int(i),
        None => ProtocolError("Invalid number")
      }
    },
    Some(_)   => ProtocolError("Invalid character"),
    None      => ProtocolError("Invalid EOF")
  }
}

pub struct CommandWriter {
  buf: ~[u8]
}

impl CommandWriter {
  pub fn new() -> CommandWriter {
    CommandWriter { buf: ~[] }
  }

  pub fn args<'a>(&'a mut self, n: uint) -> &'a mut CommandWriter {
    self.write_char('*');
    self.write_uint(n);
    self.write_crnl();
    self
  }

  pub fn arg_bin<'a>(&'a mut self, arg: &[u8]) -> &'a mut CommandWriter {
    self.write_char('$');
    self.write_uint(arg.len());
    self.write_crnl();
    self.write(arg);
    self.write_crnl();
    self
  }

  pub fn nil(&mut self) {
    self.write_str("$-1");
    self.write_crnl();
  }

  pub fn arg_str<'a>(&'a mut self, arg: &str) -> &'a mut CommandWriter {
    self.write_char('$');
    self.write_uint(arg.len());
    self.write_crnl();
    self.write_str(arg);
    self.write_crnl();
    self
  }

  pub fn error(&mut self, err: &str) {
    self.write_char('-');
    self.write_str(err);
    self.write_crnl();
  }

  pub fn status(&mut self, status: &str) {
    self.write_char('+');
    self.write_str(status);
    self.write_crnl();
  }

  fn write_crnl(&mut self) {
    self.write_char('\r');
    self.write_char('\n');
  }

  fn write_uint(&mut self, n: uint) {
    if n < 10 {
      self.write_byte('0' as u8 + (n as u8));
    }
    else {
      push_bytes(&mut self.buf, n.to_str().into_bytes()); // XXX: Optimize
    }
  }

  fn write_str(&mut self, s: &str) {
    push_bytes(&mut self.buf, s.as_bytes());
  }

  fn write(&mut self, s: &[u8]) {
    push_bytes(&mut self.buf, s);
  }

  fn write_char(&mut self, s: char) {
    self.buf.push(s as u8);
  }

  fn write_byte(&mut self, b: u8) {
    self.buf.push(b);
  }

  pub fn with_buf<T>(&self, f: |&[u8]| -> T) -> T {
    f(self.buf.as_slice())
  }
}

fn execute<T: Stream>(cmd: &[u8], io: &mut BufferedStream<T>) -> Result {
  io.write(cmd);
  io.flush();
  parse(io)
}

pub struct Client<T> {
  priv io: BufferedStream<T>
}

impl Client<TcpStream> {
  pub fn new(sock_addr: &str) -> Client<TcpStream> {
    let addr = from_str::<SocketAddr>(sock_addr).unwrap();
    let tcp_stream = TcpStream::connect(addr).unwrap();
    Client::new_from_stream(tcp_stream)
  }
}

impl<T: Stream> Client<T> {
  pub fn new_from_stream(io: T) -> Client<T> {
    Client { io: BufferedStream::new(io) }
  }

  pub fn get(&mut self, key: &str) -> Result {
    let mut cwr = CommandWriter::new();
    cwr.args(2).
        arg_str("GET").
        arg_str(key).
        with_buf(|cmd| execute(cmd, &mut self.io))
  }

  pub fn get_str(&mut self, key: &str) -> Option<~str> {
    match self.get(key) {
      Nil => None,
      Int(i) => Some(i.to_str()),
      Data(ref bytes) => Some(from_utf8(*bytes).to_owned()),
      _ => fail!("Invalid result type from Redis")
    }
  }

  pub fn get_int(&mut self, key: &str) -> Option<i64> {
    match self.get(key) {
      Nil => None,
      Data(ref bytes) => from_str(from_utf8(*bytes)), // XXX
      _ => fail!("Invalid result type from Redis")
    }
  }

  pub fn set(&mut self, key: &str, val: &str) -> Result {
    let mut cwr = CommandWriter::new();
    cwr.args(3).
        arg_str("SET").
        arg_str(key).
        arg_str(val).
        with_buf(|cmd| execute(cmd, &mut self.io))
  }

  pub fn set_int(&mut self, key: &str, val: i64) -> Result {
    self.set(key, val.to_str())
  }

  pub fn incr(&mut self, key: &str) -> i64 {
    let mut cwr = CommandWriter::new();
    let res = cwr.args(2).
        arg_str("INCR").
        arg_str(key).
        with_buf(|cmd| execute(cmd, &mut self.io));
    match res {
      Int(i) => i,
      _ => fail!()
    }
  }
}
<|endoftext|>


<commit_before>// Format validated types representing lexical tokens defined in
// RFC 5322 (as well as some referred from RFC 5234)
// in order to support SMTP (RFC 5321)

// Macro for defining sequences of characters within a character class
macro_rules! def_cclass {
    ( $typ:ident, $test:ident) => {
        #[derive(Debug, Clone, PartialEq)]
        pub struct $typ(pub Vec<u8>);
        impl Parsable for $typ {
            fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
                let mut pos: usize = 0;
                let mut output: Vec<u8> = Vec::new();
                while pos < input.len() && $test(input[pos]) {
                    output.push(input[pos]);
                    pos += 1;
                }
                if output.len() > 0 {
                    Ok( ($typ(output), &input[pos..]) )
                }
                else {
                    if pos >= input.len() { Err( ParseError::Eof ) }
                    else { Err( ParseError::NotFound ) }
                }
            }
        }
        impl Streamable for $typ {
            fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
                Ok(try!(w.write(&self.0[..])))
            }
        }
    };
}

// Macro for assigning the returned remaining input of a parse function to an existing
// variable
macro_rules! parse {
    ($pth:ident, $rem:ident) => {
        {
            $pth::parse($rem).map(|(value, r)| { $rem = r; value })
        }
    };
}

macro_rules! req {
    ($rem:ident, $bytes:expr, $input:ident) => {
        let len: usize = $bytes.len();
        if $rem.len() < len {
            return Err(ParseError::Eof);
        }
        if &$rem[0..len] != $bytes {
            return Err(ParseError::Expected($bytes.to_vec()));
        }
        $rem = &$rem[len..];
    };
}

pub mod error;
pub use self::error::ParseError;
pub mod types;
pub mod headers;

use std::io::Write;
use std::io::Error as IoError;
use self::headers::{Return, Received};
use self::headers::{ResentDate, ResentFrom, ResentSender, ResentTo, ResentCc, ResentBcc,
                    ResentMessageId};
use self::headers::{OrigDate, From, Sender, ReplyTo, To, Cc, Bcc, MessageId, InReplyTo,
                    References, Subject, Comments, Keywords, OptionalField};

pub trait Parsable: Sized {
    /// Parse the object off of the beginning of the `input`.  If found, returns Some object,
    /// and a slice containing the remainer of the input.
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError>;
}

pub trait Streamable {
    /// Serializes and sends the content out to `w`, returning the number of bytes written.
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError>;
}

// 3.6.7
// trace           =   [return]
//                     1*received
#[derive(Debug, Clone, PartialEq)]
pub struct Trace {
    return_path: Option<Return>,
    received: Vec<Received>
}
impl Parsable for Trace {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        let mut rem = input;
        let maybe_return = parse!(Return, rem).ok();
        let mut received: Vec<Received> = Vec::new();
        while let Ok(r) = parse!(Received, rem) {
            received.push(r);
        }
        if received.len() < 1 { return Err(ParseError::NotFound); }
        Ok((Trace {
            return_path: maybe_return,
            received: received,
        }, rem))
    }
}
impl Streamable for Trace {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        let mut count: usize = 0;
        if let Some(ref rp) = self.return_path {
            count += try!(rp.stream(w));
        }
        for r in &self.received {
            count += try!(r.stream(w));
        }
        Ok(count)
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum ResentField {
    Date(ResentDate),
    From(ResentFrom),
    Sender(ResentSender),
    To(ResentTo),
    Cc(ResentCc),
    Bcc(ResentBcc),
    MessageId(ResentMessageId),
}
impl Parsable for ResentField {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        let mut rem = input;
        if let Ok(x) = parse!(ResentDate, rem) {
            return Ok((ResentField::Date(x), rem));
        }
        if let Ok(x) = parse!(ResentFrom, rem) {
            return Ok((ResentField::From(x), rem));
        }
        if let Ok(x) = parse!(ResentSender, rem) {
            return Ok((ResentField::Sender(x), rem));
        }
        if let Ok(x) = parse!(ResentTo, rem) {
            return Ok((ResentField::To(x), rem));
        }
        if let Ok(x) = parse!(ResentCc, rem) {
            return Ok((ResentField::Cc(x), rem));
        }
        if let Ok(x) = parse!(ResentBcc, rem) {
            return Ok((ResentField::Bcc(x), rem));
        }
        if let Ok(x) = parse!(ResentMessageId, rem) {
            return Ok((ResentField::MessageId(x), rem));
        }
        Err(ParseError::NotFound)
    }
}
impl Streamable for ResentField {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        match *self {
            ResentField::Date(ref x) => x.stream(w),
            ResentField::From(ref x) => x.stream(w),
            ResentField::Sender(ref x) => x.stream(w),
            ResentField::To(ref x) => x.stream(w),
            ResentField::Cc(ref x) => x.stream(w),
            ResentField::Bcc(ref x) => x.stream(w),
            ResentField::MessageId(ref x) => x.stream(w),
        }
    }
}

// 3.6
// a sub part of the Fields definition
#[derive(Debug, Clone, PartialEq)]
pub enum Field {
    OrigDate(OrigDate),
    From(From),
    Sender(Sender),
    ReplyTo(ReplyTo),
    To(To),
    Cc(Cc),
    Bcc(Bcc),
    MessageId(MessageId),
    InReplyTo(InReplyTo),
    References(References),
    Subject(Subject),
    Comments(Comments),
    Keywords(Keywords),
    OptionalField(OptionalField),
}
impl Parsable for Field {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        let mut rem = input;
        if let Ok(x) = parse!(OrigDate, rem) {
            return Ok((Field::OrigDate(x), rem));
        }
        if let Ok(x) = parse!(From, rem) {
            return Ok((Field::From(x), rem));
        }
        if let Ok(x) = parse!(Sender, rem) {
            return Ok((Field::Sender(x), rem));
        }
        if let Ok(x) = parse!(ReplyTo, rem) {
            return Ok((Field::ReplyTo(x), rem));
        }
        if let Ok(x) = parse!(To, rem) {
            return Ok((Field::To(x), rem));
        }
        if let Ok(x) = parse!(Cc, rem) {
            return Ok((Field::Cc(x), rem));
        }
        if let Ok(x) = parse!(Bcc, rem) {
            return Ok((Field::Bcc(x), rem));
        }
        if let Ok(x) = parse!(MessageId, rem) {
            return Ok((Field::MessageId(x), rem));
        }
        if let Ok(x) = parse!(InReplyTo, rem) {
            return Ok((Field::InReplyTo(x), rem));
        }
        if let Ok(x) = parse!(References, rem) {
            return Ok((Field::References(x), rem));
        }
        if let Ok(x) = parse!(Subject, rem) {
            return Ok((Field::Subject(x), rem));
        }
        if let Ok(x) = parse!(Comments, rem) {
            return Ok((Field::Comments(x), rem));
        }
        if let Ok(x) = parse!(Keywords, rem) {
            return Ok((Field::Keywords(x), rem));
        }
        if let Ok(x) = parse!(OptionalField, rem) {
            return Ok((Field::OptionalField(x), rem));
        }
        Err(ParseError::NotFound)
    }
}
impl Streamable for Field {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        match *self {
            Field::OrigDate(ref x) => x.stream(w),
            Field::From(ref x) => x.stream(w),
            Field::Sender(ref x) => x.stream(w),
            Field::ReplyTo(ref x) => x.stream(w),
            Field::To(ref x) => x.stream(w),
            Field::Cc(ref x) => x.stream(w),
            Field::Bcc(ref x) => x.stream(w),
            Field::MessageId(ref x) => x.stream(w),
            Field::InReplyTo(ref x) => x.stream(w),
            Field::References(ref x) => x.stream(w),
            Field::Subject(ref x) => x.stream(w),
            Field::Comments(ref x) => x.stream(w),
            Field::Keywords(ref x) => x.stream(w),
            Field::OptionalField(ref x) => x.stream(w),
        }
    }
}

// 3.6
// a sub part of the Fields definition
#[derive(Debug, Clone, PartialEq)]
pub struct ResentTraceBlock {
    pub trace: Trace,
    pub resent_fields: Vec<ResentField>,
}
impl Parsable for ResentTraceBlock {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        let mut rem = input;
        if let Ok(t) = parse!(Trace, rem) {
            let mut fields: Vec<ResentField> = Vec::new();
            while let Ok(f) = parse!(ResentField, rem) {
                fields.push(f);
            }
            if fields.len() == 0 {
                Err(ParseError::ExpectedType("Resent Field"))
            } else {
                Ok((ResentTraceBlock {
                    trace: t,
                    resent_fields: fields
                }, rem))
            }
        } else {
            Err(ParseError::NotFound)
        }
    }
}
impl Streamable for ResentTraceBlock {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        let mut count: usize = 0;
        count += try!(self.trace.stream(w));
        for field in &self.resent_fields {
            count += try!(field.stream(w));
        }
        Ok(count)
    }
}

// 3.6
// a sub part of the Fields definition
#[derive(Debug, Clone, PartialEq)]
pub struct OptTraceBlock {
    pub trace: Trace,
    pub opt_fields: Vec<OptionalField>,
}
impl Parsable for OptTraceBlock {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        let mut rem = input;
        if let Ok(t) = parse!(Trace, rem) {
            let mut fields: Vec<OptionalField> = Vec::new();
            while let Ok(f) = parse!(OptionalField, rem) {
                fields.push(f);
            }
            if fields.len() == 0 {
                Err(ParseError::ExpectedType("Optional Field"))
            } else {
                Ok((OptTraceBlock {
                    trace: t,
                    opt_fields: fields
                }, rem))
            }
        } else {
            Err(ParseError::NotFound)
        }
    }
}
impl Streamable for OptTraceBlock {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        let mut count: usize = 0;
        count += try!(self.trace.stream(w));
        for field in &self.opt_fields {
            count += try!(field.stream(w));
        }
        Ok(count)
    }
}

// 3.6
// a sub part of the Fields definition
#[derive(Debug, Clone, PartialEq)]
pub enum TraceBlock {
    Resent(ResentTraceBlock),
    Opt(OptTraceBlock),
}
impl Parsable for TraceBlock {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        let mut rem = input;
        if let Ok(block) = parse!(ResentTraceBlock, rem) {
            Ok((TraceBlock::Resent(block), rem))
        }
        else if let Ok(block) = parse!(OptTraceBlock, rem) {
            Ok((TraceBlock::Opt(block), rem))
        }
        else {
            Err(ParseError::NotFound)
        }
    }
}
impl Streamable for TraceBlock {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        match *self {
            TraceBlock::Resent(ref block) => block.stream(w),
            TraceBlock::Opt(ref block) => block.stream(w),
        }
    }
}

// 3.6
// fields          =   *(trace
//                       *optional-field /
//                       *(resent-date /
//                        resent-from /
//                        resent-sender /
//                        resent-to /
//                        resent-cc /
//                        resent-bcc /
//                        resent-msg-id))
//                     *(orig-date /
//                     from /
//                     sender /
//                     reply-to /
//                     to /
//                     cc /
//                     bcc /
//                     message-id /
//                     in-reply-to /
//                     references /
//                     subject /
//                     comments /
//                     keywords /
//                     optional-field)
#[derive(Debug, Clone, PartialEq)]
pub struct Fields {
    pub trace_blocks: Vec<TraceBlock>,
    pub fields: Vec<Field>,
}
impl Parsable for Fields {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        let mut rem = input;
        let mut trace_blocks: Vec<TraceBlock> = Vec::new();
        while let Ok(tb) = parse!(TraceBlock, rem) {
            trace_blocks.push(tb);
        }
        let mut fields: Vec<Field> = Vec::new();
        while let Ok(f) = parse!(Field, rem) {
            fields.push(f);
        }
        Ok((Fields {
            trace_blocks: trace_blocks,
            fields: fields,
        }, rem))
    }
}
impl Streamable for Fields {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        let mut count: usize = 0;
        for tb in &self.trace_blocks {
            count += try!(tb.stream(w));
        }
        for f in &self.fields {
            count += try!(f.stream(w));
        }
        Ok(count)
    }
}
<commit_msg>rfc5322: 3.5, text<commit_after>// Format validated types representing lexical tokens defined in
// RFC 5322 (as well as some referred from RFC 5234)
// in order to support SMTP (RFC 5321)

// Macro for defining sequences of characters within a character class
macro_rules! def_cclass {
    ( $typ:ident, $test:ident) => {
        #[derive(Debug, Clone, PartialEq)]
        pub struct $typ(pub Vec<u8>);
        impl Parsable for $typ {
            fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
                let mut pos: usize = 0;
                let mut output: Vec<u8> = Vec::new();
                while pos < input.len() && $test(input[pos]) {
                    output.push(input[pos]);
                    pos += 1;
                }
                if output.len() > 0 {
                    Ok( ($typ(output), &input[pos..]) )
                }
                else {
                    if pos >= input.len() { Err( ParseError::Eof ) }
                    else { Err( ParseError::NotFound ) }
                }
            }
        }
        impl Streamable for $typ {
            fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
                Ok(try!(w.write(&self.0[..])))
            }
        }
    };
}

// Macro for assigning the returned remaining input of a parse function to an existing
// variable
macro_rules! parse {
    ($pth:ident, $rem:ident) => {
        {
            $pth::parse($rem).map(|(value, r)| { $rem = r; value })
        }
    };
}

macro_rules! req {
    ($rem:ident, $bytes:expr, $input:ident) => {
        let len: usize = $bytes.len();
        if $rem.len() < len {
            return Err(ParseError::Eof);
        }
        if &$rem[0..len] != $bytes {
            return Err(ParseError::Expected($bytes.to_vec()));
        }
        $rem = &$rem[len..];
    };
}

pub mod error;
pub use self::error::ParseError;
pub mod types;
pub mod headers;

use std::io::Write;
use std::io::Error as IoError;
use self::headers::{Return, Received};
use self::headers::{ResentDate, ResentFrom, ResentSender, ResentTo, ResentCc, ResentBcc,
                    ResentMessageId};
use self::headers::{OrigDate, From, Sender, ReplyTo, To, Cc, Bcc, MessageId, InReplyTo,
                    References, Subject, Comments, Keywords, OptionalField};

pub trait Parsable: Sized {
    /// Parse the object off of the beginning of the `input`.  If found, returns Some object,
    /// and a slice containing the remainer of the input.
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError>;
}

pub trait Streamable {
    /// Serializes and sends the content out to `w`, returning the number of bytes written.
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError>;
}

// 3.6.7
// trace           =   [return]
//                     1*received
#[derive(Debug, Clone, PartialEq)]
pub struct Trace {
    return_path: Option<Return>,
    received: Vec<Received>
}
impl Parsable for Trace {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        let mut rem = input;
        let maybe_return = parse!(Return, rem).ok();
        let mut received: Vec<Received> = Vec::new();
        while let Ok(r) = parse!(Received, rem) {
            received.push(r);
        }
        if received.len() < 1 { return Err(ParseError::NotFound); }
        Ok((Trace {
            return_path: maybe_return,
            received: received,
        }, rem))
    }
}
impl Streamable for Trace {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        let mut count: usize = 0;
        if let Some(ref rp) = self.return_path {
            count += try!(rp.stream(w));
        }
        for r in &self.received {
            count += try!(r.stream(w));
        }
        Ok(count)
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum ResentField {
    Date(ResentDate),
    From(ResentFrom),
    Sender(ResentSender),
    To(ResentTo),
    Cc(ResentCc),
    Bcc(ResentBcc),
    MessageId(ResentMessageId),
}
impl Parsable for ResentField {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        let mut rem = input;
        if let Ok(x) = parse!(ResentDate, rem) {
            return Ok((ResentField::Date(x), rem));
        }
        if let Ok(x) = parse!(ResentFrom, rem) {
            return Ok((ResentField::From(x), rem));
        }
        if let Ok(x) = parse!(ResentSender, rem) {
            return Ok((ResentField::Sender(x), rem));
        }
        if let Ok(x) = parse!(ResentTo, rem) {
            return Ok((ResentField::To(x), rem));
        }
        if let Ok(x) = parse!(ResentCc, rem) {
            return Ok((ResentField::Cc(x), rem));
        }
        if let Ok(x) = parse!(ResentBcc, rem) {
            return Ok((ResentField::Bcc(x), rem));
        }
        if let Ok(x) = parse!(ResentMessageId, rem) {
            return Ok((ResentField::MessageId(x), rem));
        }
        Err(ParseError::NotFound)
    }
}
impl Streamable for ResentField {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        match *self {
            ResentField::Date(ref x) => x.stream(w),
            ResentField::From(ref x) => x.stream(w),
            ResentField::Sender(ref x) => x.stream(w),
            ResentField::To(ref x) => x.stream(w),
            ResentField::Cc(ref x) => x.stream(w),
            ResentField::Bcc(ref x) => x.stream(w),
            ResentField::MessageId(ref x) => x.stream(w),
        }
    }
}

// 3.6
// a sub part of the Fields definition
#[derive(Debug, Clone, PartialEq)]
pub enum Field {
    OrigDate(OrigDate),
    From(From),
    Sender(Sender),
    ReplyTo(ReplyTo),
    To(To),
    Cc(Cc),
    Bcc(Bcc),
    MessageId(MessageId),
    InReplyTo(InReplyTo),
    References(References),
    Subject(Subject),
    Comments(Comments),
    Keywords(Keywords),
    OptionalField(OptionalField),
}
impl Parsable for Field {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        let mut rem = input;
        if let Ok(x) = parse!(OrigDate, rem) {
            return Ok((Field::OrigDate(x), rem));
        }
        if let Ok(x) = parse!(From, rem) {
            return Ok((Field::From(x), rem));
        }
        if let Ok(x) = parse!(Sender, rem) {
            return Ok((Field::Sender(x), rem));
        }
        if let Ok(x) = parse!(ReplyTo, rem) {
            return Ok((Field::ReplyTo(x), rem));
        }
        if let Ok(x) = parse!(To, rem) {
            return Ok((Field::To(x), rem));
        }
        if let Ok(x) = parse!(Cc, rem) {
            return Ok((Field::Cc(x), rem));
        }
        if let Ok(x) = parse!(Bcc, rem) {
            return Ok((Field::Bcc(x), rem));
        }
        if let Ok(x) = parse!(MessageId, rem) {
            return Ok((Field::MessageId(x), rem));
        }
        if let Ok(x) = parse!(InReplyTo, rem) {
            return Ok((Field::InReplyTo(x), rem));
        }
        if let Ok(x) = parse!(References, rem) {
            return Ok((Field::References(x), rem));
        }
        if let Ok(x) = parse!(Subject, rem) {
            return Ok((Field::Subject(x), rem));
        }
        if let Ok(x) = parse!(Comments, rem) {
            return Ok((Field::Comments(x), rem));
        }
        if let Ok(x) = parse!(Keywords, rem) {
            return Ok((Field::Keywords(x), rem));
        }
        if let Ok(x) = parse!(OptionalField, rem) {
            return Ok((Field::OptionalField(x), rem));
        }
        Err(ParseError::NotFound)
    }
}
impl Streamable for Field {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        match *self {
            Field::OrigDate(ref x) => x.stream(w),
            Field::From(ref x) => x.stream(w),
            Field::Sender(ref x) => x.stream(w),
            Field::ReplyTo(ref x) => x.stream(w),
            Field::To(ref x) => x.stream(w),
            Field::Cc(ref x) => x.stream(w),
            Field::Bcc(ref x) => x.stream(w),
            Field::MessageId(ref x) => x.stream(w),
            Field::InReplyTo(ref x) => x.stream(w),
            Field::References(ref x) => x.stream(w),
            Field::Subject(ref x) => x.stream(w),
            Field::Comments(ref x) => x.stream(w),
            Field::Keywords(ref x) => x.stream(w),
            Field::OptionalField(ref x) => x.stream(w),
        }
    }
}

// 3.6
// a sub part of the Fields definition
#[derive(Debug, Clone, PartialEq)]
pub struct ResentTraceBlock {
    pub trace: Trace,
    pub resent_fields: Vec<ResentField>,
}
impl Parsable for ResentTraceBlock {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        let mut rem = input;
        if let Ok(t) = parse!(Trace, rem) {
            let mut fields: Vec<ResentField> = Vec::new();
            while let Ok(f) = parse!(ResentField, rem) {
                fields.push(f);
            }
            if fields.len() == 0 {
                Err(ParseError::ExpectedType("Resent Field"))
            } else {
                Ok((ResentTraceBlock {
                    trace: t,
                    resent_fields: fields
                }, rem))
            }
        } else {
            Err(ParseError::NotFound)
        }
    }
}
impl Streamable for ResentTraceBlock {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        let mut count: usize = 0;
        count += try!(self.trace.stream(w));
        for field in &self.resent_fields {
            count += try!(field.stream(w));
        }
        Ok(count)
    }
}

// 3.6
// a sub part of the Fields definition
#[derive(Debug, Clone, PartialEq)]
pub struct OptTraceBlock {
    pub trace: Trace,
    pub opt_fields: Vec<OptionalField>,
}
impl Parsable for OptTraceBlock {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        let mut rem = input;
        if let Ok(t) = parse!(Trace, rem) {
            let mut fields: Vec<OptionalField> = Vec::new();
            while let Ok(f) = parse!(OptionalField, rem) {
                fields.push(f);
            }
            if fields.len() == 0 {
                Err(ParseError::ExpectedType("Optional Field"))
            } else {
                Ok((OptTraceBlock {
                    trace: t,
                    opt_fields: fields
                }, rem))
            }
        } else {
            Err(ParseError::NotFound)
        }
    }
}
impl Streamable for OptTraceBlock {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        let mut count: usize = 0;
        count += try!(self.trace.stream(w));
        for field in &self.opt_fields {
            count += try!(field.stream(w));
        }
        Ok(count)
    }
}

// 3.6
// a sub part of the Fields definition
#[derive(Debug, Clone, PartialEq)]
pub enum TraceBlock {
    Resent(ResentTraceBlock),
    Opt(OptTraceBlock),
}
impl Parsable for TraceBlock {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        let mut rem = input;
        if let Ok(block) = parse!(ResentTraceBlock, rem) {
            Ok((TraceBlock::Resent(block), rem))
        }
        else if let Ok(block) = parse!(OptTraceBlock, rem) {
            Ok((TraceBlock::Opt(block), rem))
        }
        else {
            Err(ParseError::NotFound)
        }
    }
}
impl Streamable for TraceBlock {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        match *self {
            TraceBlock::Resent(ref block) => block.stream(w),
            TraceBlock::Opt(ref block) => block.stream(w),
        }
    }
}

// 3.6
// fields          =   *(trace
//                       *optional-field /
//                       *(resent-date /
//                        resent-from /
//                        resent-sender /
//                        resent-to /
//                        resent-cc /
//                        resent-bcc /
//                        resent-msg-id))
//                     *(orig-date /
//                     from /
//                     sender /
//                     reply-to /
//                     to /
//                     cc /
//                     bcc /
//                     message-id /
//                     in-reply-to /
//                     references /
//                     subject /
//                     comments /
//                     keywords /
//                     optional-field)
#[derive(Debug, Clone, PartialEq)]
pub struct Fields {
    pub trace_blocks: Vec<TraceBlock>,
    pub fields: Vec<Field>,
}
impl Parsable for Fields {
    fn parse(input: &[u8]) -> Result<(Self, &[u8]), ParseError> {
        let mut rem = input;
        let mut trace_blocks: Vec<TraceBlock> = Vec::new();
        while let Ok(tb) = parse!(TraceBlock, rem) {
            trace_blocks.push(tb);
        }
        let mut fields: Vec<Field> = Vec::new();
        while let Ok(f) = parse!(Field, rem) {
            fields.push(f);
        }
        Ok((Fields {
            trace_blocks: trace_blocks,
            fields: fields,
        }, rem))
    }
}
impl Streamable for Fields {
    fn stream<W: Write>(&self, w: &mut W) -> Result<usize, IoError> {
        let mut count: usize = 0;
        for tb in &self.trace_blocks {
            count += try!(tb.stream(w));
        }
        for f in &self.fields {
            count += try!(f.stream(w));
        }
        Ok(count)
    }
}

// 3.5
// text            =   %d1-9 /            ; Characters excluding CR
//                     %d11 /             ;  and LF
//                     %d12 /
//                     %d14-127
#[inline]
pub fn is_text(c: u8) -> bool {
    (c>=1 && c<=9) || c==11 || c==12 || (c>=14 && c<=127)
}
def_cclass!(Text, is_text);
<|endoftext|>


<commit_before>#[crate_type = "rlib"];

use std::{iter, vec};

pub static EXPECTED_ANSWER: &'static str = "18407904";

// [定理]
// a + b = c のとき、
// GCD(a, b) = 1 => GCD(a, c) = GCD(b, c) = 1
//
// [証明]
// まず、GCD(a, b) = 1 => GCD(a, c) = 1 を示す。
// GCD(a, b) のとき、GCD(a, c) = k > 1 であると仮定すると、
// 整数 n, m を用いて a = kn, c = km と表すことができる。
// b = c - a = km - kn = k(m, n) より、GCD(a, b) >= k となり矛盾。
// よって、GCD(a, c) = 1 である。
//
// 次に、GCD(a, b) = 1 => GCD(b, c) = 1 を示す。
// GCD(a, b) = 1 のとき、GCD(b, c) = k > 1 であると仮定すると、
// 整数 n, m を用いて b = kn, c = km と表すことができる。
// ここで、a = c - b = km - kn = k(m - n) より、 GCD(a, b) >= k となり矛盾。
// よって、GCD(b, c) = 1 である。

#[deriving(Eq)]
struct Rad(uint, ~[uint]);

fn create_rad_vec(n_limit: uint) -> ~[Rad] {
    let mut rad_vec = vec::from_fn(n_limit, |_| Rad(1, ~[]));
    for p in range(2, rad_vec.len()) {
        let Rad(n, _) = rad_vec[p];
        if n != 1 { continue }

        for np in iter::count(p, p).take_while(|&np| np < n_limit) {
            let Rad(ref mut n, ref mut facts) = rad_vec[np];
            (*n) *= p;
            facts.push(p);
        }
    }
    rad_vec
}

fn rad_has_union(&Rad(_, ref a): &Rad, &Rad(_, ref b): &Rad) -> bool {
    let mut i_a = 0;
    let mut i_b = 0;

    loop {
        if i_a >= a.len() || i_b >= b.len() { return false }
        match a[i_a].cmp(&b[i_b]) {
            Equal   => return true,
            Less    => i_a += 1,
            Greater => i_b += 1
        }
    }
}

fn abc_hits_c_sum(c_limit: uint) -> uint {
    let rad_vec = create_rad_vec(c_limit);
    let mut c_sum = 0;

    for c in range(3, c_limit) {
        let Rad(rad_c, _) = rad_vec[c];
        if rad_c == c { continue } // if rad(c) == c, rad(ab) must be 1. this doesn't satisfy condition 2.

        // if a == 1, GCD(a, b) == GCD(b, c) == GCD(c, a) == 1 is always satisfied.
        {
            let Rad(rad_b, _) = rad_vec[c - 1];
            if rad_b * rad_c < c { c_sum += c; }
        }

        // if c is even, a and b must be odd
        if c.is_even() {
            for a in iter::range_step(3, (c + 1) / 2, 2) {
                let b = c - a;
                let Rad(rad_a, _) = rad_vec[a];
                let Rad(rad_b, _) = rad_vec[b];
                let rad_abc = rad_a * rad_b * rad_c;
                if rad_abc >= c || rad_has_union(&rad_vec[a], &rad_vec[c]) { continue; }
                c_sum += c;
            }
        } else {
            for a in range(2, (c + 1) / 2) {
                let b = c - a;
                let Rad(rad_a, _) = rad_vec[a];
                let Rad(rad_b, _) = rad_vec[b];
                let rad_abc = rad_a * rad_b * rad_c;
                if rad_abc >= c || rad_has_union(&rad_vec[a], &rad_vec[c]) { continue; }
                c_sum += c;
            }
        }
    }

    c_sum
}

pub fn solve() -> ~str { abc_hits_c_sum(120000).to_str() }

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

    #[test]
    fn create_rad_vec() {
        let rad_vec = ~[
            Rad(1, ~[]), Rad(1, ~[]), Rad(2, ~[2]), Rad(3, ~[3]), Rad(2, ~[2]), Rad(5, ~[5]),
            Rad(6, ~[2, 3]), Rad(7, ~[7]), Rad(2, ~[2]), Rad(3, ~[3])];
        assert_eq!(rad_vec, super::create_rad_vec(10))
    }

    #[test]
    fn rad_has_union() {
        assert!(super::rad_has_union(&Rad(2, ~[2]), &Rad(2, ~[2])));
        assert!(!super::rad_has_union(&Rad(2, ~[2]), &Rad(3, ~[4])));

        assert!(super::rad_has_union(&Rad(3, ~[3]), &Rad(6, ~[2, 3])));
        assert!(super::rad_has_union(&Rad(15, ~[3, 5]), &Rad(10, ~[2, 5])));

        assert!(!super::rad_has_union(&Rad(30, ~[2, 3, 5]), &Rad(1001, ~[7, 11, 13])));
    }

    #[test]
    fn abc_hits_c_sum() {
        assert_eq!(12523, super::abc_hits_c_sum(1000));
    }
}
<commit_msg>More optimization #127<commit_after>#[crate_type = "rlib"];

use std::{iter, vec};

pub static EXPECTED_ANSWER: &'static str = "18407904";

// [定理]
// a + b = c のとき、
// GCD(a, b) = 1 => GCD(a, c) = GCD(b, c) = 1
//
// [証明]
// まず、GCD(a, b) = 1 => GCD(a, c) = 1 を示す。
// GCD(a, b) のとき、GCD(a, c) = k > 1 であると仮定すると、
// 整数 n, m を用いて a = kn, c = km と表すことができる。
// b = c - a = km - kn = k(m, n) より、GCD(a, b) >= k となり矛盾。
// よって、GCD(a, c) = 1 である。
//
// 次に、GCD(a, b) = 1 => GCD(b, c) = 1 を示す。
// GCD(a, b) = 1 のとき、GCD(b, c) = k > 1 であると仮定すると、
// 整数 n, m を用いて b = kn, c = km と表すことができる。
// ここで、a = c - b = km - kn = k(m - n) より、 GCD(a, b) >= k となり矛盾。
// よって、GCD(b, c) = 1 である。

#[deriving(Eq, Clone, TotalEq, TotalOrd)]
struct Rad(uint, uint, ~[uint]); // (n, rad, facts)

fn create_rad_vec(n_limit: uint) -> ~[Rad] {
    let mut rad_vec = vec::from_fn(n_limit, |i| Rad(1, i, ~[]));
    for p in range(2, rad_vec.len()) {
        let Rad(rad_p, _, _) = rad_vec[p];
        if rad_p != 1 { continue }

        for kp in iter::count(p, p).take_while(|&kp| kp < n_limit) {
            let Rad(ref mut rad_kp, _, ref mut facts) = rad_vec[kp];
            (*rad_kp) *= p;
            facts.push(p);
        }
    }
    rad_vec
}

fn rad_has_union(a: &[uint], b: &[uint]) -> bool {
    let mut i_a = 0;
    let mut i_b = 0;

    loop {
        if i_a >= a.len() || i_b >= b.len() { return false }
        match a[i_a].cmp(&b[i_b]) {
            Equal   => return true,
            Less    => i_a += 1,
            Greater => i_b += 1
        }
    }
}

fn abc_hits_c_sum(c_limit: uint) -> uint {
    let rad_vec = create_rad_vec(c_limit);
    let mut sorted_rad_vec = rad_vec.tail().to_owned(); // drop a == 0 element
    sorted_rad_vec.sort();

    let mut c_sum = 0;

    for c in range(3, c_limit) {
        let Rad(rad_c, _, ref c_facts) = rad_vec[c];
        if rad_c == c { continue } // if rad(c) == c, rad(ab) must be 1. this doesn't satisfy condition 2.

        for &Rad(rad_a, a, ref a_facts) in sorted_rad_vec.iter() {
            if rad_a >= c / rad_c { break }
            if a >= (c + 1) / 2 { continue }

            let Rad(rad_b, _, _) = rad_vec[c - a];
            let rad_abc = rad_a * rad_b * rad_c;
            if rad_abc >= c || (a != 1 && rad_has_union(*c_facts, *a_facts)) { continue; }
            c_sum += c;
        }
    }

    c_sum
}

pub fn solve() -> ~str { abc_hits_c_sum(120000).to_str() }

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

    #[test]
    fn create_rad_vec() {
        let rad_vec = ~[
            Rad(1, 0, ~[]), Rad(1, 1, ~[]), Rad(2, 2, ~[2]), Rad(3, 3, ~[3]), Rad(2, 4, ~[2]), Rad(5, 5, ~[5]),
            Rad(6, 6, ~[2, 3]), Rad(7, 7, ~[7]), Rad(2, 8, ~[2]), Rad(3, 9, ~[3])];
        assert_eq!(rad_vec, super::create_rad_vec(10))
    }

    #[test]
    fn rad_has_union() {
        assert!(super::rad_has_union(&[2], &[2]));
        assert!(!super::rad_has_union(&[2], &[4]));

        assert!(super::rad_has_union(&[3], &[2, 3]));
        assert!(super::rad_has_union(&[3, 5], &[2, 5]));

        assert!(!super::rad_has_union(&[2, 3, 5], &[7, 11, 13]));
    }

    #[test]
    fn abc_hits_c_sum() {
        assert_eq!(12523, super::abc_hits_c_sum(1000));
    }
}
<|endoftext|>


<commit_before>use internal::ColorComponent;
use can::{
    CanColor,
    CanRectangle,
    CanSourceRectangle,
    CanTransform,
};
use has::{
    HasColor,
    HasRectangle,
    HasSourceRectangle,
    HasTransform,
};
use std::num::Float;
use vecmath::{
    hsv,
    margin_rectangle,
    multiply,
    orient,
    relative_rectangle,
    relative_source_rectangle,
    rotate_radians,
    scale,
    shear,
    translate,
    Scalar,
    Vec2d,
};

/// Implemented by contexts that contains color.
pub trait RelativeColor {
    /// Multiplies with red, green, blue and alpha values.
    fn mul_rgba(
        &self,
        r: ColorComponent,
        g: ColorComponent,
        b: ColorComponent,
        a: ColorComponent
    ) -> Self;

    /// Mixes the current color with white.
    ///
    /// 0 is black and 1 is white.
    #[inline(always)]
    fn tint(&self, f: ColorComponent) -> Self {
        self.mul_rgba(f, f, f, 1.0)
    }

    /// Mixes the current color with black.
    ///
    /// 0 is white and 1 is black.
    #[inline(always)]
    fn shade(&self, f: ColorComponent) -> Self {
        let f = 1.0 - f;
        self.mul_rgba(f, f, f, 1.0)
    }

    /// Rotates hue by degrees.
    #[inline(always)]
    fn hue_deg(&self, angle: ColorComponent) -> Self {
        let pi: ColorComponent = Float::pi();
        self.hue_rad(angle * pi / 180.0)
    }

    /// Rotates hue by radians.
    fn hue_rad(&self, angle: ColorComponent) -> Self;
}

impl<T: HasColor + CanColor> RelativeColor for T {
    #[inline(always)]
    fn mul_rgba(
        &self,
        r: ColorComponent,
        g: ColorComponent,
        b: ColorComponent,
        a: ColorComponent
    ) -> T {
        let color = self.get_color();
        self.color([color[0] * r, color[1] * g, color[2] * b, color[3] * a])
    }

    #[inline(always)]
    fn hue_rad(&self, angle: ColorComponent) -> T {
        self.color(hsv(self.get_color(), angle, 1.0, 1.0))
    }
}

/// Should be implemented by contexts that have rectangle information.
pub trait RelativeRectangle {
    /// Shrinks the current rectangle equally by all sides.
    fn margin(&self, m: Scalar) -> Self;

    /// Expands the current rectangle equally by all sides.
    #[inline(always)]
    fn expand(&self, m: Scalar) -> Self {
        self.margin(-m)
    }

    /// Moves to a relative rectangle using the current rectangle as tile.
    fn rel(&self, x: Scalar, y: Scalar) -> Self;
}

impl<T: HasRectangle + CanRectangle>
RelativeRectangle for T {
    #[inline(always)]
    fn margin(&self, m: Scalar) -> T {
        self.rectangle(margin_rectangle(self.get_rectangle(), m))
    }

    #[inline(always)]
    fn rel(&self, x: Scalar, y: Scalar) -> T {
        self.rectangle(relative_rectangle(self.get_rectangle(), [x, y]))
    }
}

/// Should be implemented by contexts that
/// have source rectangle information.
pub trait RelativeSourceRectangle {
    /// Adds a source rectangle.
    fn src_rect(&self, x: i32, y: i32, w: i32, h: i32) -> Self;

    /// Moves to a relative source rectangle using
    /// the current source rectangle as tile.
    fn src_rel(&self, x: i32, y: i32) -> Self;

    /// Flips the source rectangle horizontally.
    fn src_flip_h(&self) -> Self;

    /// Flips the source rectangle vertically.
    fn src_flip_v(&self) -> Self;

    /// Flips the source rectangle horizontally and vertically.
    fn src_flip_hv(&self) -> Self;
}

impl<T: HasSourceRectangle
      + CanSourceRectangle,
> RelativeSourceRectangle for T {
    #[inline(always)]
    fn src_rel(&self, x: i32, y: i32) -> T {
        self.source_rectangle(
            relative_source_rectangle(self.get_source_rectangle(), x, y)
        )
    }

    #[inline(always)]
    fn src_rect(&self, x: i32, y: i32, w: i32, h: i32) -> T {
        self.source_rectangle([x, y, w, h])
    }

    #[inline(always)]
    fn src_flip_h(&self) -> T {
        let source_rect = self.get_source_rectangle();
        self.source_rectangle([
            source_rect[0] + source_rect[2],
            source_rect[1],
            -source_rect[2],
            source_rect[3]
        ])
    }

    #[inline(always)]
    fn src_flip_v(&self) -> T {
        let source_rect = self.get_source_rectangle();
        self.source_rectangle([
            source_rect[0],
            source_rect[1] + source_rect[3],
            source_rect[2],
            -source_rect[3]
        ])
    }

    #[inline(always)]
    fn src_flip_hv(&self) -> T {
        let source_rect = self.get_source_rectangle();
        self.source_rectangle([
            source_rect[0] + source_rect[2],
            source_rect[1] + source_rect[3],
            -source_rect[2],
            -source_rect[3]
        ])
    }
}

/// Implemented by contexts that can transform.
pub trait RelativeTransform2d {
    /// Translate x an y in local coordinates.
    fn trans(&self, x: Scalar, y: Scalar) -> Self;

    /// Rotates degrees in local coordinates.
    #[inline(always)]
    fn rot_deg(&self, angle: Scalar) -> Self {
        let pi: Scalar = Float::pi();
        self.rot_rad(angle * pi / 180.0)
    }

    /// Rotate radians in local coordinates.
    fn rot_rad(&self, angle: Scalar) -> Self;

    /// Orients x axis to look at point locally.
    ///
    /// Leaves x axis unchanged if the point to
    /// look at is the origin.
    fn orient(&self, x: Scalar, y: Scalar) -> Self;

    /// Scales in local coordinates.
    fn scale(&self, sx: Scalar, sy: Scalar) -> Self;

    /// Scales in both directions in local coordinates.
    #[inline(always)]
    fn zoom(&self, s: Scalar) -> Self {
        self.scale(s, s)
    }

    /// Flips vertically in local coordinates.
    #[inline(always)]
    fn flip_v(&self) -> Self {
        self.scale(1.0, -1.0)
    }

    /// Flips horizontally in local coordinates.
    #[inline(always)]
    fn flip_h(&self) -> Self {
        self.scale(-1.0, 1.0)
    }

    /// Flips horizontally and vertically in local coordinates.
    #[inline(always)]
    fn flip_hv(&self) -> Self {
        self.scale(-1.0, -1.0)
    }

    /// Shears in local coordinates.
    fn shear(&self, v: Vec2d) -> Self;
}

impl<T: HasTransform + CanTransform
> RelativeTransform2d for T {
    #[inline(always)]
    fn trans(&self, x: Scalar, y: Scalar) -> T {
        let trans = translate([x, y]);
        self.transform(multiply(self.get_transform(), trans))
    }

    #[inline(always)]
    fn rot_rad(&self, angle: Scalar) -> T {
        let rot = rotate_radians(angle);
        self.transform(multiply(self.get_transform(), rot))
    }

    #[inline(always)]
    fn orient(&self, x: Scalar, y: Scalar) -> T {
        let orient = orient(x, y);
        self.transform(multiply(self.get_transform(), orient))
    }

    #[inline(always)]
    fn scale(&self, sx: Scalar, sy: Scalar) -> T {
        let scale = scale(sx, sy);
        self.transform(multiply(self.get_transform(), scale))
    }

    #[inline(always)]
    fn shear(&self, v: Vec2d) -> T {
        let shear = shear(v);
        self.transform(multiply(self.get_transform(), shear))
    }
}
<commit_msg>Made `Relative` traits inherit `Has` and `Can`<commit_after>use internal::ColorComponent;
use can::{
    CanColor,
    CanRectangle,
    CanSourceRectangle,
    CanTransform,
};
use has::{
    HasColor,
    HasRectangle,
    HasSourceRectangle,
    HasTransform,
};
use std::num::Float;
use vecmath::{
    hsv,
    margin_rectangle,
    multiply,
    orient,
    relative_rectangle,
    relative_source_rectangle,
    rotate_radians,
    scale,
    shear,
    translate,
    Scalar,
    Vec2d,
};

/// Implemented by contexts that contains color.
pub trait RelativeColor: HasColor + CanColor {
    /// Multiplies with red, green, blue and alpha values.
    #[inline(always)]
    fn mul_rgba(
        &self,
        r: ColorComponent,
        g: ColorComponent,
        b: ColorComponent,
        a: ColorComponent
    ) -> Self {
        let color = self.get_color();
        self.color([color[0] * r, color[1] * g, color[2] * b, color[3] * a])
    }

    /// Mixes the current color with white.
    ///
    /// 0 is black and 1 is white.
    #[inline(always)]
    fn tint(&self, f: ColorComponent) -> Self {
        self.mul_rgba(f, f, f, 1.0)
    }

    /// Mixes the current color with black.
    ///
    /// 0 is white and 1 is black.
    #[inline(always)]
    fn shade(&self, f: ColorComponent) -> Self {
        let f = 1.0 - f;
        self.mul_rgba(f, f, f, 1.0)
    }

    /// Rotates hue by degrees.
    #[inline(always)]
    fn hue_deg(&self, angle: ColorComponent) -> Self {
        let pi: ColorComponent = Float::pi();
        self.hue_rad(angle * pi / 180.0)
    }

    /// Rotates hue by radians.
    #[inline(always)]
    fn hue_rad(&self, angle: ColorComponent) -> Self {
        self.color(hsv(self.get_color(), angle, 1.0, 1.0))
    }
}

impl<T: HasColor + CanColor> RelativeColor for T {}

/// Should be implemented by contexts that have rectangle information.
pub trait RelativeRectangle: HasRectangle + CanRectangle {
    /// Shrinks the current rectangle equally by all sides.
    #[inline(always)]
    fn margin(&self, m: Scalar) -> Self {
        self.rectangle(margin_rectangle(self.get_rectangle(), m))
    }

    /// Expands the current rectangle equally by all sides.
    #[inline(always)]
    fn expand(&self, m: Scalar) -> Self {
        self.margin(-m)
    }

    /// Moves to a relative rectangle using the current rectangle as tile.
    #[inline(always)]
    fn rel(&self, x: Scalar, y: Scalar) -> Self {
        self.rectangle(relative_rectangle(self.get_rectangle(), [x, y]))
    }
}

impl<T: HasRectangle + CanRectangle> RelativeRectangle for T {}

/// Should be implemented by contexts that
/// have source rectangle information.
pub trait RelativeSourceRectangle: HasSourceRectangle + CanSourceRectangle {
    /// Adds a source rectangle.
    #[inline(always)]
    fn src_rect(&self, x: i32, y: i32, w: i32, h: i32) -> Self {
        self.source_rectangle([x, y, w, h])
    }

    /// Moves to a relative source rectangle using
    /// the current source rectangle as tile.
    #[inline(always)]
    fn src_rel(&self, x: i32, y: i32) -> Self {
        self.source_rectangle(
            relative_source_rectangle(self.get_source_rectangle(), x, y)
        )
    }

    /// Flips the source rectangle horizontally.
    #[inline(always)]
    fn src_flip_h(&self) -> Self {
        let source_rect = self.get_source_rectangle();
        self.source_rectangle([
            source_rect[0] + source_rect[2],
            source_rect[1],
            -source_rect[2],
            source_rect[3]
        ])
    }

    /// Flips the source rectangle vertically.
    #[inline(always)]
    fn src_flip_v(&self) -> Self {
        let source_rect = self.get_source_rectangle();
        self.source_rectangle([
            source_rect[0],
            source_rect[1] + source_rect[3],
            source_rect[2],
            -source_rect[3]
        ])
    }

    /// Flips the source rectangle horizontally and vertically.
    #[inline(always)]
    fn src_flip_hv(&self) -> Self {
        let source_rect = self.get_source_rectangle();
        self.source_rectangle([
            source_rect[0] + source_rect[2],
            source_rect[1] + source_rect[3],
            -source_rect[2],
            -source_rect[3]
        ])
    }
}

impl<T: HasSourceRectangle
      + CanSourceRectangle,
> RelativeSourceRectangle for T {}

/// Implemented by contexts that can transform.
pub trait RelativeTransform2d: HasTransform + CanTransform {
    /// Translate x an y in local coordinates.
    #[inline(always)]
    fn trans(&self, x: Scalar, y: Scalar) -> Self {
        let trans = translate([x, y]);
        self.transform(multiply(self.get_transform(), trans))
    }

    /// Rotates degrees in local coordinates.
    #[inline(always)]
    fn rot_deg(&self, angle: Scalar) -> Self {
        let pi: Scalar = Float::pi();
        self.rot_rad(angle * pi / 180.0)
    }

    /// Rotate radians in local coordinates.
    #[inline(always)]
    fn rot_rad(&self, angle: Scalar) -> Self {
        let rot = rotate_radians(angle);
        self.transform(multiply(self.get_transform(), rot))
    }

    /// Orients x axis to look at point locally.
    ///
    /// Leaves x axis unchanged if the point to
    /// look at is the origin.
    #[inline(always)]
    fn orient(&self, x: Scalar, y: Scalar) -> Self {
        let orient = orient(x, y);
        self.transform(multiply(self.get_transform(), orient))
    }

    /// Scales in local coordinates.
    #[inline(always)]
    fn scale(&self, sx: Scalar, sy: Scalar) -> Self {
        let scale = scale(sx, sy);
        self.transform(multiply(self.get_transform(), scale))
    }

    /// Scales in both directions in local coordinates.
    #[inline(always)]
    fn zoom(&self, s: Scalar) -> Self {
        self.scale(s, s)
    }

    /// Flips vertically in local coordinates.
    #[inline(always)]
    fn flip_v(&self) -> Self {
        self.scale(1.0, -1.0)
    }

    /// Flips horizontally in local coordinates.
    #[inline(always)]
    fn flip_h(&self) -> Self {
        self.scale(-1.0, 1.0)
    }

    /// Flips horizontally and vertically in local coordinates.
    #[inline(always)]
    fn flip_hv(&self) -> Self {
        self.scale(-1.0, -1.0)
    }

    /// Shears in local coordinates.
    #[inline(always)]
    fn shear(&self, v: Vec2d) -> Self {
        let shear = shear(v);
        self.transform(multiply(self.get_transform(), shear))
    }
}

impl<T: HasTransform + CanTransform> RelativeTransform2d for T {}

<|endoftext|>


<commit_before>use std::boxed::FnBox;
use std::thread::{self, spawn};
use std::sync::mpsc::{channel, Sender, SendError, Receiver, TryRecvError};
use std::error::Error;
use std::fmt;

trait Runner {
    fn run(self: Box<Self>);
}

impl <F: FnBox()> Runner for F {
    fn run(self: Box<F>) {
        self.call_box(())
    }
}

/// Type used by ThreadPool to run closures, etc. on the spawned threads.
pub type Proc<'a> = Box<Runner + Send + 'a>;

/// Used to interact with the spawned threads returned by the ThreadPool.
///
/// See documentation for ThreadPool for more information.
pub struct Thread {
    inner: ThreadInner,
}

struct ThreadInner {
    sender: Sender<Proc<'static>>,
    result: Receiver<thread::Result<()>>,
}

impl Thread {
    fn new(sender: Sender<Proc<'static>>, result: Receiver<thread::Result<()>>) -> Thread {
        Thread {
            inner: ThreadInner {
                       sender: sender,
                       result: result,
                   },
        }
    }

    /// Sends the runnable object to a spawned thread to be run.
    pub fn start(&self, f: Proc<'static>) -> Result<(), SendError<Proc<'static>>> {
        self.inner.sender.send(f)
    }

    /// Blocks on the result of the started Proc.
    ///
    /// Do not use if no Proc is being run!
    pub fn join(&self) -> thread::Result<()> {
        self.inner.result.recv().expect("Could not get result")
    }
}

/// The ThreadPool that manages the state of the threads and spawns new ones.
///
/// ```
/// #![feature(box_syntax)]
/// #![feature(result_expect)]
/// use std::sync::mpsc::channel;
/// use ferrous_threads::thread_pool::ThreadPool;
///
/// let mut pool = ThreadPool::new(1, 2);
/// let thread = pool.thread().unwrap();
///
/// let (sn, rc) = channel();
/// thread.start(box move || { sn.send(9u8).unwrap();}).expect("Could not send Proc");
/// assert!(thread.join().is_ok());
/// assert!(rc.recv().unwrap() == 9u8);
/// ```
///
/// When requesting a thread, this pool will either return a unused thread that has already been
/// spawned, spin up a new thread, or return an error if the maximum number of threads has been
/// reached.
pub struct ThreadPool {
    free_sender: Sender<Thread>, // Keep this to spawn new threads
    free_threads: Receiver<Thread>, // Threads will send themselves when they are free.
    active_threads: usize,
    max_threads: usize,
}

fn spawn_thread(free: Sender<Thread>) {
        spawn(move || {
            let sentinel = Sentinel::new(free.clone());
            ThreadRunner::new(free).run();
            sentinel.done();
        });
}

impl ThreadPool {
    pub fn new(init_threads: usize, max_threads: usize) -> ThreadPool {
        let (sn, rc) = channel();
        let mut thrs = Vec::new();
        for _i in 0..init_threads {
            spawn_thread(sn.clone());
            let thr = rc.recv().expect("Could not receive initial thread");
            thrs.push(thr);
        }

        for t in thrs.into_iter() {
            sn.send(t).expect("Could not reinsert threads");
        }

        ThreadPool {
            free_sender: sn,
            free_threads: rc,
            active_threads: init_threads,
            max_threads: max_threads
        }
    }

    /// Returns a handle to a spawned thread or an error if there are no more threads available.
    pub fn thread(&mut self) -> Result<Thread, ThreadError> {
        let mut res = self.free_threads.try_recv();
        if res.is_err() {
            thread::yield_now();
            res = self.free_threads.try_recv();
        }

        match res {
            Ok(thr) => Ok(thr),
            Err(TryRecvError::Empty) => {
                if self.active_threads >= self.max_threads {
                    Err(ThreadError)
                } else {
                    self.active_threads += 1;
                    spawn_thread(self.free_sender.clone());
                    let thr = self.free_threads.recv().expect("Could not receive thread");
                    Ok(thr)
                }
            }
            Err(TryRecvError::Disconnected) => panic!("channel closed"),
        }
    }
}

/// Error type used by the ThreadPool
#[derive(Debug, Clone)]
pub struct ThreadError;

impl Error for ThreadError {
    fn description(&self) -> &str {
        "Could not make any more threads."
    }
}

impl fmt::Display for ThreadError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        "Could not make any more threads.".fmt(f)
    }
}

struct Sentinel {
    free_threads: Sender<Thread>,
    active: bool,
}

// Idea taken from https://github.com/rust-lang/threadpool/blob/b9416b4cb591a3ac8bac8efef19e5cbf5e212a9d/src/lib.rs#L40
impl Sentinel {
    fn new(free_threads: Sender<Thread>) -> Sentinel {
        Sentinel {
            free_threads: free_threads,
            active: true,
        }
    }

    // Cancel and destroy this sentinel.
    fn done(mut self) {
        self.active = false;
    }
}

impl Drop for Sentinel {
    fn drop(&mut self) {
        if self.active {
            // Spawn new thread and remove old one.
            spawn_thread(self.free_threads.clone());
        }
    }
}

struct ThreadRunner {
    free_chan: Sender<Thread>, // ThreadRunner will send its Thread when it is ready to do work
}

impl ThreadRunner {
    pub fn new(free_chan: Sender<Thread>) -> ThreadRunner {
        ThreadRunner {
            free_chan: free_chan,
        }
    }

    fn run(self) {
        loop {
            let (thr, jobs) = channel();
            let (res_sender, res_recver) = channel();
            let thread = Thread::new(thr, res_recver);

            let res = self.free_chan.send(thread);
            if res.is_err() {
                // ThreadPool has disconnected
                return
            }
            let res = jobs.recv();
            if res.is_err() {
                // Thread has disconnected
                return
            }
            let job = res.unwrap();
            let res = thread::catch_panic(move || { job.run(); });
            let res = res_sender.send(res);
            if res.is_err() {
                // Thread has disconnected
                return
            }
        }
    }
}

#[cfg(test)]
mod test {
    use std::thread;
    use std::sync::mpsc::{channel};
    use thread_pool::{ThreadPool, Runner};

    #[test]
    fn test_runable() {
        let (sn, rc) = channel::<u8>();
        let f = box move || {
            sn.send(0u8).unwrap();
        };
        f.run();
        assert!(rc.recv().unwrap() == 0);
    }

    #[test]
    fn test_thread_pool_thread_and_start() {
        let (sn, rc) = channel::<u8>();
        let (init, max) = (1, 2);
        let mut pool = ThreadPool::new(init, max);

        let f = box move || {
            sn.send(0u8).unwrap();
        };

        let thr1 = pool.thread();
        let _thr2 = pool.thread();
        let thr3 = pool.thread();
        assert!(thr3.is_err());

        assert!(thr1.is_ok());
        let thr1 = thr1.ok().unwrap();

        let res = thr1.start(f);
        assert!(res.is_ok());

        assert!(rc.recv().unwrap() == 0);
    }

    #[test]
    fn test_thread_pool_join() {
        let (sn1, rc1) = channel::<u8>();
        let (init, max) = (1, 2);
        let mut pool = ThreadPool::new(init, max);

        let f1 = box move || {
            sn1.send(0u8).unwrap();
        };

        let f2 = box move || {
            panic!();
        };

        // Initial thread.
        let thr1 = pool.thread();
        // Start a new one.
        let thr2 = pool.thread();

        assert!(thr1.is_ok());
        let thr1 = thr1.ok().unwrap();

        assert!(thr2.is_ok());
        let thr2 = thr2.ok().unwrap();

        let res = thr1.start(f1);
        assert!(res.is_ok());
        let res = thr2.start(f2);
        assert!(res.is_ok());
        let res = thr1.join();
        assert!(res.is_ok());
        assert!(rc1.recv().unwrap() == 0);

        let res = thr2.join();
        assert!(res.is_err());
    }

    #[test]
    fn test_thread_pool_max_threads_panic() {
        let (sn1, rc1) = channel::<u8>();
        let (sn3, rc3) = channel::<u8>();
        let (init, max) = (1, 2);
        let mut pool = ThreadPool::new(init, max);

        let f1 = box move || {
            sn1.send(0u8).unwrap();
        };

        let f3 = box move || {
            sn3.send(0u8).unwrap();
        };

        let f2 = box move || {
            panic!();
        };

        // Initial thread.
        let thr1 = pool.thread();
        // Start a new one.
        let thr2 = pool.thread();
        let thr1 = thr1.ok().unwrap();
        let thr2 = thr2.ok().unwrap();

        let res = thr2.start(f2);
        assert!(res.is_ok());
        let res = thr2.join();
        assert!(res.is_err());

        thread::sleep_ms(100);

        let thr3 = pool.thread();
        // Can still get thread after panic
        assert!(thr3.is_ok());
        let thr3 = thr3.ok().unwrap();
        let res = thr3.start(f3);
        assert!(res.is_ok());
        let res = thr3.join();
        assert!(res.is_ok());
        assert!(rc3.recv().unwrap() == 0);

        let res = thr1.start(f1);
        assert!(res.is_ok());
        let res = thr1.join();
        assert!(res.is_ok());
        assert!(rc1.recv().unwrap() == 0);
    }
}
<commit_msg>Add module documentation to thread_pool<commit_after>//! This module contains an implementation of a thread pool that will automatically spin up a
//! configurable amount of OS threads on start-up, and will only allow a configurable amount of
//! total OS threads.
//!
//! ```
//! #![feature(box_syntax)]
//! #![feature(result_expect)]
//! use std::sync::mpsc::channel;
//! use ferrous_threads::thread_pool::ThreadPool;
//!
//! let mut pool = ThreadPool::new(1, 2);
//! let thread = pool.thread().unwrap();
//!
//! let (sn, rc) = channel();
//! thread.start(box move || { sn.send(9u8).unwrap();}).expect("Could not send Proc");
//! assert!(thread.join().is_ok());
//! assert!(rc.recv().unwrap() == 9u8);
//! ```
//!
//! If a job running on a thread panics, the pool will detect this and spawn a new thread to take
//! the place of the old one. The user of the pool is able to detect this error condition through
//! the result returned on join().
//!
//! ```
//! #![feature(box_syntax)]
//! #![feature(result_expect)]
//! use std::sync::mpsc::channel;
//! use ferrous_threads::thread_pool::ThreadPool;
//!
//! let mut pool = ThreadPool::new(1, 2);
//! let _ = pool.thread().unwrap();
//! let thread = pool.thread().unwrap();
//!
//! thread.start(box move || { panic!();}).expect("Could not send Proc");
//! assert!(thread.join().is_err());
//! ```

use std::boxed::FnBox;
use std::thread::{self, spawn};
use std::sync::mpsc::{channel, Sender, SendError, Receiver, TryRecvError};
use std::error::Error;
use std::fmt;

trait Runner {
    fn run(self: Box<Self>);
}

impl <F: FnBox()> Runner for F {
    fn run(self: Box<F>) {
        self.call_box(())
    }
}

/// Type used by ThreadPool to run closures, etc. on the spawned threads.
pub type Proc<'a> = Box<Runner + Send + 'a>;

/// Used to interact with the spawned threads returned by the ThreadPool.
///
/// See documentation for ThreadPool for more information.
pub struct Thread {
    inner: ThreadInner,
}

struct ThreadInner {
    sender: Sender<Proc<'static>>,
    result: Receiver<thread::Result<()>>,
}

impl Thread {
    fn new(sender: Sender<Proc<'static>>, result: Receiver<thread::Result<()>>) -> Thread {
        Thread {
            inner: ThreadInner {
                       sender: sender,
                       result: result,
                   },
        }
    }

    /// Sends the runnable object to a spawned thread to be run.
    pub fn start(&self, f: Proc<'static>) -> Result<(), SendError<Proc<'static>>> {
        self.inner.sender.send(f)
    }

    /// Blocks on the result of the started Proc.
    ///
    /// Do not use if no Proc is being run!
    pub fn join(&self) -> thread::Result<()> {
        self.inner.result.recv().expect("Could not get result")
    }
}

/// The ThreadPool that manages the state of the threads and spawns new ones.
///
/// When requesting a thread, this pool will either return a unused thread that has already been
/// spawned, spin up a new thread, or return an error if the maximum number of threads has been
/// reached.
pub struct ThreadPool {
    free_sender: Sender<Thread>, // Keep this to spawn new threads
    free_threads: Receiver<Thread>, // Threads will send themselves when they are free.
    active_threads: usize,
    max_threads: usize,
}

fn spawn_thread(free: Sender<Thread>) {
        spawn(move || {
            let sentinel = Sentinel::new(free.clone());
            ThreadRunner::new(free).run();
            sentinel.done();
        });
}

impl ThreadPool {
    pub fn new(init_threads: usize, max_threads: usize) -> ThreadPool {
        let (sn, rc) = channel();
        let mut thrs = Vec::new();
        for _i in 0..init_threads {
            spawn_thread(sn.clone());
            let thr = rc.recv().expect("Could not receive initial thread");
            thrs.push(thr);
        }

        for t in thrs.into_iter() {
            sn.send(t).expect("Could not reinsert threads");
        }

        ThreadPool {
            free_sender: sn,
            free_threads: rc,
            active_threads: init_threads,
            max_threads: max_threads
        }
    }

    /// Returns a handle to a spawned thread or an error if there are no more threads available.
    pub fn thread(&mut self) -> Result<Thread, ThreadError> {
        let mut res = self.free_threads.try_recv();
        if res.is_err() {
            thread::yield_now();
            res = self.free_threads.try_recv();
        }

        match res {
            Ok(thr) => Ok(thr),
            Err(TryRecvError::Empty) => {
                if self.active_threads >= self.max_threads {
                    Err(ThreadError)
                } else {
                    self.active_threads += 1;
                    spawn_thread(self.free_sender.clone());
                    let thr = self.free_threads.recv().expect("Could not receive thread");
                    Ok(thr)
                }
            }
            Err(TryRecvError::Disconnected) => panic!("channel closed"),
        }
    }
}

/// Error type used by the ThreadPool
#[derive(Debug, Clone)]
pub struct ThreadError;

impl Error for ThreadError {
    fn description(&self) -> &str {
        "Could not make any more threads."
    }
}

impl fmt::Display for ThreadError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        "Could not make any more threads.".fmt(f)
    }
}

struct Sentinel {
    free_threads: Sender<Thread>,
    active: bool,
}

// Idea taken from https://github.com/rust-lang/threadpool/blob/b9416b4cb591a3ac8bac8efef19e5cbf5e212a9d/src/lib.rs#L40
impl Sentinel {
    fn new(free_threads: Sender<Thread>) -> Sentinel {
        Sentinel {
            free_threads: free_threads,
            active: true,
        }
    }

    // Cancel and destroy this sentinel.
    fn done(mut self) {
        self.active = false;
    }
}

impl Drop for Sentinel {
    fn drop(&mut self) {
        if self.active {
            // Spawn new thread and remove old one.
            spawn_thread(self.free_threads.clone());
        }
    }
}

struct ThreadRunner {
    free_chan: Sender<Thread>, // ThreadRunner will send its Thread when it is ready to do work
}

impl ThreadRunner {
    pub fn new(free_chan: Sender<Thread>) -> ThreadRunner {
        ThreadRunner {
            free_chan: free_chan,
        }
    }

    fn run(self) {
        loop {
            let (thr, jobs) = channel();
            let (res_sender, res_recver) = channel();
            let thread = Thread::new(thr, res_recver);

            let res = self.free_chan.send(thread);
            if res.is_err() {
                // ThreadPool has disconnected
                return
            }
            let res = jobs.recv();
            if res.is_err() {
                // Thread has disconnected
                return
            }
            let job = res.unwrap();
            let res = thread::catch_panic(move || { job.run(); });
            let res = res_sender.send(res);
            if res.is_err() {
                // Thread has disconnected
                return
            }
        }
    }
}

#[cfg(test)]
mod test {
    use std::thread;
    use std::sync::mpsc::{channel};
    use thread_pool::{ThreadPool, Runner};

    #[test]
    fn test_runable() {
        let (sn, rc) = channel::<u8>();
        let f = box move || {
            sn.send(0u8).unwrap();
        };
        f.run();
        assert!(rc.recv().unwrap() == 0);
    }

    #[test]
    fn test_thread_pool_thread_and_start() {
        let (sn, rc) = channel::<u8>();
        let (init, max) = (1, 2);
        let mut pool = ThreadPool::new(init, max);

        let f = box move || {
            sn.send(0u8).unwrap();
        };

        let thr1 = pool.thread();
        let _thr2 = pool.thread();
        let thr3 = pool.thread();
        assert!(thr3.is_err());

        assert!(thr1.is_ok());
        let thr1 = thr1.ok().unwrap();

        let res = thr1.start(f);
        assert!(res.is_ok());

        assert!(rc.recv().unwrap() == 0);
    }

    #[test]
    fn test_thread_pool_join() {
        let (sn1, rc1) = channel::<u8>();
        let (init, max) = (1, 2);
        let mut pool = ThreadPool::new(init, max);

        let f1 = box move || {
            sn1.send(0u8).unwrap();
        };

        let f2 = box move || {
            panic!();
        };

        // Initial thread.
        let thr1 = pool.thread();
        // Start a new one.
        let thr2 = pool.thread();

        assert!(thr1.is_ok());
        let thr1 = thr1.ok().unwrap();

        assert!(thr2.is_ok());
        let thr2 = thr2.ok().unwrap();

        let res = thr1.start(f1);
        assert!(res.is_ok());
        let res = thr2.start(f2);
        assert!(res.is_ok());
        let res = thr1.join();
        assert!(res.is_ok());
        assert!(rc1.recv().unwrap() == 0);

        let res = thr2.join();
        assert!(res.is_err());
    }

    #[test]
    fn test_thread_pool_max_threads_panic() {
        let (sn1, rc1) = channel::<u8>();
        let (sn3, rc3) = channel::<u8>();
        let (init, max) = (1, 2);
        let mut pool = ThreadPool::new(init, max);

        let f1 = box move || {
            sn1.send(0u8).unwrap();
        };

        let f3 = box move || {
            sn3.send(0u8).unwrap();
        };

        let f2 = box move || {
            panic!();
        };

        // Initial thread.
        let thr1 = pool.thread();
        // Start a new one.
        let thr2 = pool.thread();
        let thr1 = thr1.ok().unwrap();
        let thr2 = thr2.ok().unwrap();

        let res = thr2.start(f2);
        assert!(res.is_ok());
        let res = thr2.join();
        assert!(res.is_err());

        thread::sleep_ms(100);

        let thr3 = pool.thread();
        // Can still get thread after panic
        assert!(thr3.is_ok());
        let thr3 = thr3.ok().unwrap();
        let res = thr3.start(f3);
        assert!(res.is_ok());
        let res = thr3.join();
        assert!(res.is_ok());
        assert!(rc3.recv().unwrap() == 0);

        let res = thr1.start(f1);
        assert!(res.is_ok());
        let res = thr1.join();
        assert!(res.is_ok());
        assert!(rc1.recv().unwrap() == 0);
    }
}
<|endoftext|>


<commit_before>//! The tmux config data we want

use std::collections::HashMap;
use std::str::FromStr;

#[derive(Debug, Clone)]
pub struct Config {
    pub base_index: usize,
    pub pane_base_index: usize
}

impl Config {
    pub fn from_string(options: String) -> Config {
        let lines = options.lines();
        let mut config: HashMap<&str, &str> = HashMap::new();

        for line in lines {
            let opt: Vec<&str> = line.split(" ").collect();
            config.insert(opt[0], opt[1]);
        }

        Config {
            base_index: usize::from_str(config.get("base-index").unwrap_or(&"0")).unwrap(),
            pane_base_index: usize::from_str(config.get("pane-base-index").unwrap_or(&"0")).unwrap()
        }
    }
}

#[test]
fn expect_base_index_0() {
    let output = "some-stuff false\nbase-index 0\nother-thing true".to_string();
    let config = Config::from_string(output);
    assert_eq!(config.base_index, 0)
}

#[test]
fn expect_base_index_5() {
    let output = "some-stuff false\nbase-index 5\nother-thing true".to_string();
    let config = Config::from_string(output);
    assert_eq!(config.base_index, 5)
}

#[test]
fn expect_missing_base_index_0() {
    let output = "some-stuff false".to_string();
    let config = Config::from_string(output);
    assert_eq!(config.base_index, 0)
}

#[test]
fn expect_pane_base_index_0() {
    let output = "some-stuff false\npane-base-index 0\nother-thing true".to_string();
    let config = Config::from_string(output);
    assert_eq!(config.pane_base_index, 0)
}

#[test]
fn expect_pane_base_index_5() {
    let output = "some-stuff false\npane-base-index 5\nother-thing true".to_string();
    let config = Config::from_string(output);
    assert_eq!(config.pane_base_index, 5)
}

#[test]
fn expect_missing_pane_base_index_0() {
    let output = "some-stuff false".to_string();
    let config = Config::from_string(output);
    assert_eq!(config.pane_base_index, 0)
}
<commit_msg>doc(tmux/config.rs): Add inline docs for Config<commit_after>//! The tmux config data we want
/// This assists in the parsing and accessibility of a users tmux configuration
/// options. Once the data is parsed we move it into a config struct for easy
/// access.

use std::collections::HashMap;
use std::str::FromStr;

/// A simple struct for accessing parsed config options we want to know about.
#[derive(Debug, Clone)]
pub struct Config {
    pub base_index: usize,
    pub pane_base_index: usize
}

/// The parser of config options. A string of output is passed in. It's simple
/// key value pairs in the format of `key value\n`
impl Config {
    pub fn from_string(options: String) -> Config {
        let lines = options.lines();
        let mut config: HashMap<&str, &str> = HashMap::new();

        for line in lines {
            let opt: Vec<&str> = line.split(" ").collect();
            config.insert(opt[0], opt[1]);
        }

        Config {
            base_index: usize::from_str(config.get("base-index").unwrap_or(&"0")).unwrap(),
            pane_base_index: usize::from_str(config.get("pane-base-index").unwrap_or(&"0")).unwrap()
        }
    }
}

#[test]
fn expect_base_index_0() {
    let output = "some-stuff false\nbase-index 0\nother-thing true".to_string();
    let config = Config::from_string(output);
    assert_eq!(config.base_index, 0)
}

#[test]
fn expect_base_index_5() {
    let output = "some-stuff false\nbase-index 5\nother-thing true".to_string();
    let config = Config::from_string(output);
    assert_eq!(config.base_index, 5)
}

#[test]
fn expect_missing_base_index_0() {
    let output = "some-stuff false".to_string();
    let config = Config::from_string(output);
    assert_eq!(config.base_index, 0)
}

#[test]
fn expect_pane_base_index_0() {
    let output = "some-stuff false\npane-base-index 0\nother-thing true".to_string();
    let config = Config::from_string(output);
    assert_eq!(config.pane_base_index, 0)
}

#[test]
fn expect_pane_base_index_5() {
    let output = "some-stuff false\npane-base-index 5\nother-thing true".to_string();
    let config = Config::from_string(output);
    assert_eq!(config.pane_base_index, 5)
}

#[test]
fn expect_missing_pane_base_index_0() {
    let output = "some-stuff false".to_string();
    let config = Config::from_string(output);
    assert_eq!(config.pane_base_index, 0)
}
<|endoftext|>


<commit_before>//! lint on `use`ing all variants of an enum

use rustc::hir::*;
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use syntax::ast::NodeId;
use syntax::codemap::Span;
use utils::span_lint;

/// **What it does:** Checks for `use Enum::*`.
///
/// **Why is this bad?** It is usually better style to use the prefixed name of
/// an enumeration variant, rather than importing variants.
///
/// **Known problems:** Old-style enumerations that prefix the variants are
/// still around.
///
/// **Example:**
/// ```rust
/// use std::cmp::Ordering::*;
/// ```
declare_lint! {
    pub ENUM_GLOB_USE,
    Allow,
    "use items that import all variants of an enum"
}

pub struct EnumGlobUse;

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

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EnumGlobUse {
    fn check_mod(&mut self, cx: &LateContext<'a, 'tcx>, m: &'tcx Mod, _: Span, _: NodeId) {
        // only check top level `use` statements
        for item in &m.item_ids {
            self.lint_item(cx, cx.tcx.hir.expect_item(item.id));
        }
    }
}

impl EnumGlobUse {
    fn lint_item(&self, cx: &LateContext, item: &Item) {
        if item.vis == Visibility::Public {
            return; // re-exports are fine
        }
        if let ItemUse(ref path, UseKind::Glob) = item.node {
            // FIXME: ask jseyfried why the qpath.def for `use std::cmp::Ordering::*;`
            // extracted through `ItemUse(ref qpath, UseKind::Glob)` is a `Mod` and not an
            // `Enum`
            // if let Def::Enum(_) = path.def {
            if path.segments
                .last()
                .and_then(|seg| seg.name.as_str().chars().next())
                .map_or(false, char::is_uppercase)
            {
                span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants");
            }
        }
    }
}
<commit_msg>Add known false positive for enum_glob_use<commit_after>//! lint on `use`ing all variants of an enum

use rustc::hir::*;
use rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
use syntax::ast::NodeId;
use syntax::codemap::Span;
use utils::span_lint;

/// **What it does:** Checks for `use Enum::*`.
///
/// **Why is this bad?** It is usually better style to use the prefixed name of
/// an enumeration variant, rather than importing variants.
///
/// **Known problems:** Old-style enumerations that prefix the variants are
/// still around. May cause problems with modules that are not snake_case (see
/// [#2397](https://github.com/rust-lang-nursery/rust-clippy/issues/2397))
///
/// **Example:**
/// ```rust
/// use std::cmp::Ordering::*;
/// ```
declare_lint! {
    pub ENUM_GLOB_USE,
    Allow,
    "use items that import all variants of an enum"
}

pub struct EnumGlobUse;

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

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for EnumGlobUse {
    fn check_mod(&mut self, cx: &LateContext<'a, 'tcx>, m: &'tcx Mod, _: Span, _: NodeId) {
        // only check top level `use` statements
        for item in &m.item_ids {
            self.lint_item(cx, cx.tcx.hir.expect_item(item.id));
        }
    }
}

impl EnumGlobUse {
    fn lint_item(&self, cx: &LateContext, item: &Item) {
        if item.vis == Visibility::Public {
            return; // re-exports are fine
        }
        if let ItemUse(ref path, UseKind::Glob) = item.node {
            // FIXME: ask jseyfried why the qpath.def for `use std::cmp::Ordering::*;`
            // extracted through `ItemUse(ref qpath, UseKind::Glob)` is a `Mod` and not an
            // `Enum`
            // if let Def::Enum(_) = path.def {
            if path.segments
                .last()
                .and_then(|seg| seg.name.as_str().chars().next())
                .map_or(false, char::is_uppercase)
            {
                span_lint(cx, ENUM_GLOB_USE, item.span, "don't use glob imports for enum variants");
            }
        }
    }
}
<|endoftext|>