<commit_before>/// low level wrapper for the state machine, encoding and decoding from lapin-async
use lapin_async::connection::*;
use lapin_async::format::frame::*;

use nom::{IResult,Offset};
use cookie_factory::GenError;
use bytes::BytesMut;
use std::iter::repeat;
use std::io::{self,Error,ErrorKind};
use std::time::Duration;
use futures::{Async,Poll,Sink,Stream,StartSend,Future};
use tokio_io::{AsyncRead,AsyncWrite};
use tokio_io::codec::{Decoder,Encoder,Framed};
use tokio_timer::{Interval,Timer};
use client::ConnectionOptions;

/// implements tokio-io's Decoder and Encoder
pub struct AMQPCodec;

impl Decoder for AMQPCodec {
    type Item = Frame;
    type Error = io::Error;

    fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Frame>, io::Error> {
        let (consumed, f) = match frame(buf) {
          IResult::Incomplete(_) => {
            return Ok(None)
          },
          IResult::Error(e) => {
            return Err(io::Error::new(io::ErrorKind::Other, format!("parse error: {:?}", e)))
          },
          IResult::Done(i, frame) => {
            (buf.offset(i), frame)
          }
        };

        trace!("decoded frame: {:?}", f);

        buf.split_to(consumed);

        Ok(Some(f))
    }
}

impl Encoder for AMQPCodec {
    type Item = Frame;
    type Error = io::Error;

    fn encode(&mut self, frame: Frame, buf: &mut BytesMut) -> Result<(), Self::Error> {
      let length = buf.len();
      if length < 8192 {
        //reserve more capacity and intialize it
        buf.extend(repeat(0).take(8192 - length));
      }
      trace!("will encode and write frame: {:?}", frame);

      loop {
        let gen_res = match &frame {
          &Frame::ProtocolHeader => {
            gen_protocol_header((buf, 0)).map(|tup| tup.1)
          },
          &Frame::Heartbeat(_) => {
            gen_heartbeat_frame((buf, 0)).map(|tup| tup.1)
          },
          &Frame::Method(channel, ref method) => {
            gen_method_frame((buf, 0), channel, method).map(|tup| tup.1)
          },
          &Frame::Header(channel_id, class_id, ref header) => {
            gen_content_header_frame((buf, 0), channel_id, class_id, header.body_size, &header.properties).map(|tup| tup.1)
          },
          &Frame::Body(channel_id, ref data) => {
            gen_content_body_frame((buf, 0), channel_id, data).map(|tup| tup.1)
          }
        };

        match gen_res {
          Ok(sz) => {
            buf.truncate(sz);
            trace!("serialized frame: {} bytes", sz);
            return Ok(());
          },
          Err(e) => {
            error!("error generating frame: {:?}", e);
            match e {
              GenError::BufferTooSmall(sz) => {
                buf.extend(repeat(0).take(sz - length));
                //return Err(Error::new(ErrorKind::InvalidData, "send buffer too small"));
              },
              GenError::InvalidOffset | GenError::CustomError(_) | GenError::NotYetImplemented => {
                return Err(Error::new(ErrorKind::InvalidData, "could not generate"));
              }
            }
          }
        }
      }
    }
}

/// Wrappers over a `Framed` stream using `AMQPCodec` and lapin-async's `Connection`
pub struct AMQPTransport<T> {
  pub upstream: Framed<T,AMQPCodec>,
  pub heartbeat: Interval,
  pub conn: Connection,
}

impl<T> AMQPTransport<T>
   where T: AsyncRead+AsyncWrite,
         T: 'static               {

  /// starts the connection process
  ///
  /// returns a future of a `AMQPTransport` that is connected
  pub fn connect(upstream: Framed<T,AMQPCodec>, options: &ConnectionOptions) -> Box<Future<Item = AMQPTransport<T>, Error = io::Error>> {
    let mut conn = Connection::new();
    conn.set_credentials(&options.username, &options.password);
    conn.set_vhost(&options.vhost);
    conn.set_heartbeat(options.heartbeat);
    conn.connect();

    let mut t = AMQPTransport {
      upstream:  upstream,
      heartbeat: Timer::default().interval(Duration::from_secs(conn.configuration.heartbeat as u64)),
      conn:      conn,
    };

    t.send_and_handle_frames();
    t.poll_children();

    let mut connector = AMQPTransportConnector {
      transport: Some(t)
    };

    trace!("pre-poll");
    connector.poll();
    trace!("post-poll");

    Box::new(connector)
  }

  fn poll_heartbeat(&mut self) {
    if let Ok(Async::Ready(_)) = self.heartbeat.poll() {
      debug!("Heartbeat");
      self.start_send(Frame::Heartbeat(0));
      self.poll_complete();
    }
  }

  fn poll_upstream(&mut self) -> Poll<Option<()>, io::Error> {
    let value = match self.upstream.poll() {
      Ok(Async::Ready(t)) => t,
      Ok(Async::NotReady) => {
        trace!("NotReady");
        return Ok(Async::NotReady);
      },
      Err(e) => {
        error!("upstream poll got error: {:?}", e);
        return Err(From::from(e));
      },
    };

    if let Some(frame) = value {
      trace!("got frame: {:?}", frame);
      self.conn.handle_frame(frame);
      self.send_frames();
      self.upstream.poll_complete();
      Ok(Async::Ready(Some(())))
    } else {
      error!("did not get a frame");
      Ok(Async::Ready(None))
    }
  }

  pub fn poll_children(&mut self) {
    self.poll_heartbeat();
    let value = match self.upstream.poll() {
      Ok(Async::Ready(t)) => t,
      Ok(Async::NotReady) => {
        trace!("NotReady");
        return;
      },
      Err(e) => {
        error!("upstream poll got error: {:?}", e);
        return;
      },
    };

    match value {
      Some(frame) => {
        trace!("got frame: {:?}", frame);
        self.conn.handle_frame(frame);
        self.send_frames();
        self.upstream.poll_complete();
      },
      e => {
        error!("did not get a frame? -> {:?}", e);
      }
    }
  }

  pub fn send_and_handle_frames(&mut self) {
    self.send_frames();
    self.handle_frames();
  }

  pub fn send_frames(&mut self) {
    //FIXME: find a way to use a future here
    while let Some(f) = self.conn.next_frame() {
      self.upstream.start_send(f);
      self.upstream.poll_complete();
    }
    //self.upstream.poll_complete();
  }

  pub fn handle_frames(&mut self) {
    loop {
      match self.poll() {
        Ok(Async::Ready(Some(frame))) => {
          trace!("handle frames: AMQPTransport received frame: {:?}", frame);
          self.conn.handle_frame(frame);
        },
        Ok(Async::Ready(None)) => {
          trace!("handle frames: upstream poll gave Ready(None)");
          break;
        },
        Ok(Async::NotReady) => {
          trace!("handle frames: upstream poll gave NotReady");
          self.poll_children();
          break;
        },
        Err(e) => {
          error!("handle frames: upstream poll got error: {:?}", e);
          break;
        },
      };
    }
  }
}

/// implements a future of `AMQPTransport`
///
/// this structure is used to perform the AMQP handshake and provide
/// a connected transport afterwards
pub struct AMQPTransportConnector<T> {
  pub transport: Option<AMQPTransport<T>>,
}

impl<T> Future for AMQPTransportConnector<T>
    where T: AsyncRead + AsyncWrite,
          T: 'static {

  type Item  = AMQPTransport<T>;
  type Error = io::Error;

  fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
    debug!("AMQPTransportConnector poll transport is none? {}", self.transport.is_none());
    let mut transport = self.transport.take().unwrap();

    //we might have received a frame before here
    transport.handle_frames();
    transport.send_frames();

    debug!("conn state: {:?}", transport.conn.state);
    if transport.conn.state == ConnectionState::Connected {
      debug!("already connected");
      return Ok(Async::Ready(transport))
    }

    trace!("waiting before poll");
    transport.poll_heartbeat();
    let value = match transport.upstream.poll() {
      Ok(Async::Ready(t)) => t,
      Ok(Async::NotReady) => {
        trace!("upstream poll gave NotReady");
        self.transport = Some(transport);
        return Ok(Async::NotReady);
      },
      Err(e) => {
        error!("upstream poll got error: {:?}", e);
        return Err(From::from(e));
      },
    };

    match value {
      Some(frame) => {
        trace!("got frame: {:?}", frame);
        transport.conn.handle_frame(frame);
        transport.send_frames();
        transport.upstream.poll_complete();
        if transport.conn.state == ConnectionState::Connected {
          return Ok(Async::Ready(transport))
        } else {
          transport.poll_children();
          self.transport = Some(transport);
          return Ok(Async::NotReady)
        }
      },
      e => {
        error!("did not get a frame? -> {:?}", e);
        self.transport = Some(transport);
        return Ok(Async::NotReady)
      }
    }
  }
}

impl<T> Stream for AMQPTransport<T>
    where T: AsyncRead + AsyncWrite,
          T: 'static {
    type Item = Frame;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Option<Frame>, io::Error> {
        self.poll_heartbeat();

        trace!("stream poll");
        // and Async::NotReady.
        match try_ready!(self.upstream.poll()) {
            Some(frame) => {
              debug!("AMQPTransport received frame: {:?}", frame);
              //try!(self.poll_complete());
              return Ok(Async::Ready(Some(frame)))
            },
            None => {
              trace!("AMQPTransport returned NotReady");
              return Ok(Async::NotReady)
            }
        }
    }
}

impl<T> Sink for AMQPTransport<T>
    where T: AsyncWrite {
    type SinkItem = Frame;
    type SinkError = io::Error;

    fn start_send(&mut self, item: Frame) -> StartSend<Frame, io::Error> {
        trace!("sink start send");
        self.upstream.start_send(item)
    }

    fn poll_complete(&mut self) -> Poll<(), io::Error> {
        trace!("sink poll_complete");
        self.upstream.poll_complete()
    }
}

<commit_msg>futures: use poll_upstream in poll_children<commit_after>/// low level wrapper for the state machine, encoding and decoding from lapin-async
use lapin_async::connection::*;
use lapin_async::format::frame::*;

use nom::{IResult,Offset};
use cookie_factory::GenError;
use bytes::BytesMut;
use std::iter::repeat;
use std::io::{self,Error,ErrorKind};
use std::time::Duration;
use futures::{Async,Poll,Sink,Stream,StartSend,Future};
use tokio_io::{AsyncRead,AsyncWrite};
use tokio_io::codec::{Decoder,Encoder,Framed};
use tokio_timer::{Interval,Timer};
use client::ConnectionOptions;

/// implements tokio-io's Decoder and Encoder
pub struct AMQPCodec;

impl Decoder for AMQPCodec {
    type Item = Frame;
    type Error = io::Error;

    fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<Frame>, io::Error> {
        let (consumed, f) = match frame(buf) {
          IResult::Incomplete(_) => {
            return Ok(None)
          },
          IResult::Error(e) => {
            return Err(io::Error::new(io::ErrorKind::Other, format!("parse error: {:?}", e)))
          },
          IResult::Done(i, frame) => {
            (buf.offset(i), frame)
          }
        };

        trace!("decoded frame: {:?}", f);

        buf.split_to(consumed);

        Ok(Some(f))
    }
}

impl Encoder for AMQPCodec {
    type Item = Frame;
    type Error = io::Error;

    fn encode(&mut self, frame: Frame, buf: &mut BytesMut) -> Result<(), Self::Error> {
      let length = buf.len();
      if length < 8192 {
        //reserve more capacity and intialize it
        buf.extend(repeat(0).take(8192 - length));
      }
      trace!("will encode and write frame: {:?}", frame);

      loop {
        let gen_res = match &frame {
          &Frame::ProtocolHeader => {
            gen_protocol_header((buf, 0)).map(|tup| tup.1)
          },
          &Frame::Heartbeat(_) => {
            gen_heartbeat_frame((buf, 0)).map(|tup| tup.1)
          },
          &Frame::Method(channel, ref method) => {
            gen_method_frame((buf, 0), channel, method).map(|tup| tup.1)
          },
          &Frame::Header(channel_id, class_id, ref header) => {
            gen_content_header_frame((buf, 0), channel_id, class_id, header.body_size, &header.properties).map(|tup| tup.1)
          },
          &Frame::Body(channel_id, ref data) => {
            gen_content_body_frame((buf, 0), channel_id, data).map(|tup| tup.1)
          }
        };

        match gen_res {
          Ok(sz) => {
            buf.truncate(sz);
            trace!("serialized frame: {} bytes", sz);
            return Ok(());
          },
          Err(e) => {
            error!("error generating frame: {:?}", e);
            match e {
              GenError::BufferTooSmall(sz) => {
                buf.extend(repeat(0).take(sz - length));
                //return Err(Error::new(ErrorKind::InvalidData, "send buffer too small"));
              },
              GenError::InvalidOffset | GenError::CustomError(_) | GenError::NotYetImplemented => {
                return Err(Error::new(ErrorKind::InvalidData, "could not generate"));
              }
            }
          }
        }
      }
    }
}

/// Wrappers over a `Framed` stream using `AMQPCodec` and lapin-async's `Connection`
pub struct AMQPTransport<T> {
  pub upstream: Framed<T,AMQPCodec>,
  pub heartbeat: Interval,
  pub conn: Connection,
}

impl<T> AMQPTransport<T>
   where T: AsyncRead+AsyncWrite,
         T: 'static               {

  /// starts the connection process
  ///
  /// returns a future of a `AMQPTransport` that is connected
  pub fn connect(upstream: Framed<T,AMQPCodec>, options: &ConnectionOptions) -> Box<Future<Item = AMQPTransport<T>, Error = io::Error>> {
    let mut conn = Connection::new();
    conn.set_credentials(&options.username, &options.password);
    conn.set_vhost(&options.vhost);
    conn.set_heartbeat(options.heartbeat);
    conn.connect();

    let mut t = AMQPTransport {
      upstream:  upstream,
      heartbeat: Timer::default().interval(Duration::from_secs(conn.configuration.heartbeat as u64)),
      conn:      conn,
    };

    t.send_and_handle_frames();
    t.poll_children();

    let mut connector = AMQPTransportConnector {
      transport: Some(t)
    };

    trace!("pre-poll");
    connector.poll();
    trace!("post-poll");

    Box::new(connector)
  }

  fn poll_heartbeat(&mut self) {
    if let Ok(Async::Ready(_)) = self.heartbeat.poll() {
      debug!("Heartbeat");
      self.start_send(Frame::Heartbeat(0));
      self.poll_complete();
    }
  }

  fn poll_upstream(&mut self) -> Poll<Option<()>, io::Error> {
    let value = match self.upstream.poll() {
      Ok(Async::Ready(t)) => t,
      Ok(Async::NotReady) => {
        trace!("NotReady");
        return Ok(Async::NotReady);
      },
      Err(e) => {
        error!("upstream poll got error: {:?}", e);
        return Err(From::from(e));
      },
    };

    if let Some(frame) = value {
      trace!("got frame: {:?}", frame);
      self.conn.handle_frame(frame);
      self.send_frames();
      self.upstream.poll_complete();
      Ok(Async::Ready(Some(())))
    } else {
      error!("did not get a frame");
      Ok(Async::Ready(None))
    }
  }

  pub fn poll_children(&mut self) {
    self.poll_heartbeat();
    self.poll_upstream();
  }

  pub fn send_and_handle_frames(&mut self) {
    self.send_frames();
    self.handle_frames();
  }

  pub fn send_frames(&mut self) {
    //FIXME: find a way to use a future here
    while let Some(f) = self.conn.next_frame() {
      self.upstream.start_send(f);
      self.upstream.poll_complete();
    }
    //self.upstream.poll_complete();
  }

  pub fn handle_frames(&mut self) {
    loop {
      match self.poll() {
        Ok(Async::Ready(Some(frame))) => {
          trace!("handle frames: AMQPTransport received frame: {:?}", frame);
          self.conn.handle_frame(frame);
        },
        Ok(Async::Ready(None)) => {
          trace!("handle frames: upstream poll gave Ready(None)");
          break;
        },
        Ok(Async::NotReady) => {
          trace!("handle frames: upstream poll gave NotReady");
          self.poll_children();
          break;
        },
        Err(e) => {
          error!("handle frames: upstream poll got error: {:?}", e);
          break;
        },
      };
    }
  }
}

/// implements a future of `AMQPTransport`
///
/// this structure is used to perform the AMQP handshake and provide
/// a connected transport afterwards
pub struct AMQPTransportConnector<T> {
  pub transport: Option<AMQPTransport<T>>,
}

impl<T> Future for AMQPTransportConnector<T>
    where T: AsyncRead + AsyncWrite,
          T: 'static {

  type Item  = AMQPTransport<T>;
  type Error = io::Error;

  fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
    debug!("AMQPTransportConnector poll transport is none? {}", self.transport.is_none());
    let mut transport = self.transport.take().unwrap();

    //we might have received a frame before here
    transport.handle_frames();
    transport.send_frames();

    debug!("conn state: {:?}", transport.conn.state);
    if transport.conn.state == ConnectionState::Connected {
      debug!("already connected");
      return Ok(Async::Ready(transport))
    }

    trace!("waiting before poll");
    transport.poll_heartbeat();
    let value = match transport.upstream.poll() {
      Ok(Async::Ready(t)) => t,
      Ok(Async::NotReady) => {
        trace!("upstream poll gave NotReady");
        self.transport = Some(transport);
        return Ok(Async::NotReady);
      },
      Err(e) => {
        error!("upstream poll got error: {:?}", e);
        return Err(From::from(e));
      },
    };

    match value {
      Some(frame) => {
        trace!("got frame: {:?}", frame);
        transport.conn.handle_frame(frame);
        transport.send_frames();
        transport.upstream.poll_complete();
        if transport.conn.state == ConnectionState::Connected {
          return Ok(Async::Ready(transport))
        } else {
          transport.poll_children();
          self.transport = Some(transport);
          return Ok(Async::NotReady)
        }
      },
      e => {
        error!("did not get a frame? -> {:?}", e);
        self.transport = Some(transport);
        return Ok(Async::NotReady)
      }
    }
  }
}

impl<T> Stream for AMQPTransport<T>
    where T: AsyncRead + AsyncWrite,
          T: 'static {
    type Item = Frame;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Option<Frame>, io::Error> {
        self.poll_heartbeat();

        trace!("stream poll");
        // and Async::NotReady.
        match try_ready!(self.upstream.poll()) {
            Some(frame) => {
              debug!("AMQPTransport received frame: {:?}", frame);
              //try!(self.poll_complete());
              return Ok(Async::Ready(Some(frame)))
            },
            None => {
              trace!("AMQPTransport returned NotReady");
              return Ok(Async::NotReady)
            }
        }
    }
}

impl<T> Sink for AMQPTransport<T>
    where T: AsyncWrite {
    type SinkItem = Frame;
    type SinkError = io::Error;

    fn start_send(&mut self, item: Frame) -> StartSend<Frame, io::Error> {
        trace!("sink start send");
        self.upstream.start_send(item)
    }

    fn poll_complete(&mut self) -> Poll<(), io::Error> {
        trace!("sink poll_complete");
        self.upstream.poll_complete()
    }
}

<|endoftext|>


<commit_before>use super::errors::*;

static C_PRE: &'static str = "const char data[] = {";
static C_SEPERATOR: &'static str = ",";
static C_POST: &'static str = "};";

static CPP_PRE: &'static str = "const char data[] = {";
static CPP_SEPERATOR: &'static str = ",";
static CPP_POST: &'static str = "};";

static PYTHON_PRE: &'static str = "data = [";
static PYTHON_SEPERATOR: &'static str = ",";
static PYTHON_POST: &'static str = "]";

static RUST_PRE: &'static str = "let data = [";
static RUST_SEPERATOR: &'static str = ",";
static RUST_POST: &'static str = "];";

trait Render {
    fn render(&self, data: &[u8]) -> String;
}

pub enum Language {
    C,
    Cpp,
    Rust,
    Python,
}

struct Template {
    prefix: String,
    separator: String,
    suffix: String,
    bytes_per_line: usize,
}

impl Template {
    fn new(lang: Language) -> Template {
        match lang {
            Language::C => {
                Template {
                    prefix: C_PRE.to_string(),
                    separator: C_SEPERATOR.to_string(),
                    suffix: C_POST.to_string(),
                    bytes_per_line: 16,
                }
            }
            Language::Cpp => {
                Template {
                    prefix: CPP_PRE.to_string(),
                    separator: CPP_SEPERATOR.to_string(),
                    suffix: CPP_POST.to_string(),
                    bytes_per_line: 16,
                }
            }
            Language::Python => {
                Template {
                    prefix: PYTHON_PRE.to_string(),
                    separator: PYTHON_SEPERATOR.to_string(),
                    suffix: PYTHON_POST.to_string(),
                    bytes_per_line: 16,
                }
            }
            Language::Rust => {
                Template {
                    prefix: RUST_PRE.to_string(),
                    separator: RUST_SEPERATOR.to_string(),
                    suffix: RUST_POST.to_string(),
                    bytes_per_line: 16,
                }
            }
        }
    }
}

impl Render for Template {
    fn render(&self, data: &[u8]) -> String {
        let mut output = String::new();
        output = output + &self.prefix;
        for element in data.iter().enumerate() {
            let (index, byte) = element;
            if data.len() - 1 == index {
                output = output + &format!("{}", byte);
            } else {
                output = output + &format!("{}{} ", byte, self.separator);
                if (index + 1) % self.bytes_per_line == 0 {
                    output = output + &"\n";
                }
            }
        }
        output = output + &self.suffix;
        output
    }
}

mod test {
    use super::*;

    #[test]
    fn render_basic_c_template() {
        let data = [0, 1, 2, 3, 4, 5];
        let template = Template::new(Language::C);
        let expected_result = "const char data[] = {0, 1, 2, 3, 4, 5};";
        assert_eq!(template.render(&data), expected_result);
    }

    #[test]
    fn render_c_template_with_large_data() {
        let data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
                    22, 23, 24, 25, 26];
        let template = Template::new(Language::C);
        let expected_result = "const char data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, \n16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26};";
        assert_eq!(template.render(&data), expected_result);
    }

    #[test]
    fn render_basic_cplusplus_template() {
        let data = [0, 1, 2, 3, 4, 5];
        let template = Template::new(Language::Cpp);
        let expected_result = "const char data[] = {0, 1, 2, 3, 4, 5};";
        assert_eq!(template.render(&data), expected_result);
    }

    #[test]
    fn render_cplusplus_template_with_large_data() {
        let data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
                    22, 23, 24, 25, 26];
        let template = Template::new(Language::Cpp);
        let expected_result = "const char data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, \n16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26};";
        assert_eq!(template.render(&data), expected_result);
    }

    #[test]
    fn render_basic_python_template() {
        let data = [0, 1, 2, 3, 4, 5];
        let template = Template::new(Language::Python);
        let expected_result = "data = [0, 1, 2, 3, 4, 5]";
        assert_eq!(template.render(&data), expected_result);
    }

    #[test]
    fn render_python_template_with_large_data() {
        let data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
                    22, 23, 24, 25, 26];
        let template = Template::new(Language::Python);
        let expected_result = "data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, \n16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26]";
        assert_eq!(template.render(&data), expected_result);
    }

    #[test]
    fn render_basic_rust_template() {
        let data = [0, 1, 2, 3, 4, 5];
        let template = Template::new(Language::Rust);
        let expected_result = "let data = [0, 1, 2, 3, 4, 5];";
        assert_eq!(template.render(&data), expected_result);
    }

    #[test]
    fn render_rust_template_with_large_data() {
        let data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
                    22, 23, 24, 25, 26];
        let template = Template::new(Language::Rust);
        let expected_result = "let data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, \n16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26];";
        assert_eq!(template.render(&data), expected_result);
    }
}
<commit_msg>Adjust visibility in generate module<commit_after>use super::errors::*;

static C_PRE: &'static str = "const char data[] = {";
static C_SEPERATOR: &'static str = ",";
static C_POST: &'static str = "};";

static CPP_PRE: &'static str = "const char data[] = {";
static CPP_SEPERATOR: &'static str = ",";
static CPP_POST: &'static str = "};";

static PYTHON_PRE: &'static str = "data = [";
static PYTHON_SEPERATOR: &'static str = ",";
static PYTHON_POST: &'static str = "]";

static RUST_PRE: &'static str = "let data = [";
static RUST_SEPERATOR: &'static str = ",";
static RUST_POST: &'static str = "];";

pub trait Render {
    fn render(&self, data: &[u8]) -> String;
}

pub enum Language {
    C,
    Cpp,
    Rust,
    Python,
}

pub struct Template {
    prefix: String,
    separator: String,
    suffix: String,
    bytes_per_line: usize,
}

impl Template {
    pub fn new(lang: Language) -> Template {
        match lang {
            Language::C => {
                Template {
                    prefix: C_PRE.to_string(),
                    separator: C_SEPERATOR.to_string(),
                    suffix: C_POST.to_string(),
                    bytes_per_line: 16,
                }
            }
            Language::Cpp => {
                Template {
                    prefix: CPP_PRE.to_string(),
                    separator: CPP_SEPERATOR.to_string(),
                    suffix: CPP_POST.to_string(),
                    bytes_per_line: 16,
                }
            }
            Language::Python => {
                Template {
                    prefix: PYTHON_PRE.to_string(),
                    separator: PYTHON_SEPERATOR.to_string(),
                    suffix: PYTHON_POST.to_string(),
                    bytes_per_line: 16,
                }
            }
            Language::Rust => {
                Template {
                    prefix: RUST_PRE.to_string(),
                    separator: RUST_SEPERATOR.to_string(),
                    suffix: RUST_POST.to_string(),
                    bytes_per_line: 16,
                }
            }
        }
    }
}

impl Render for Template {
    fn render(&self, data: &[u8]) -> String {
        let mut output = String::new();
        output = output + &self.prefix;
        for element in data.iter().enumerate() {
            let (index, byte) = element;
            if data.len() - 1 == index {
                output = output + &format!("{}", byte);
            } else {
                output = output + &format!("{}{} ", byte, self.separator);
                if (index + 1) % self.bytes_per_line == 0 {
                    output = output + &"\n";
                }
            }
        }
        output = output + &self.suffix;
        output
    }
}

mod test {
    use super::*;

    #[test]
    fn render_basic_c_template() {
        let data = [0, 1, 2, 3, 4, 5];
        let template = Template::new(Language::C);
        let expected_result = "const char data[] = {0, 1, 2, 3, 4, 5};";
        assert_eq!(template.render(&data), expected_result);
    }

    #[test]
    fn render_c_template_with_large_data() {
        let data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
                    22, 23, 24, 25, 26];
        let template = Template::new(Language::C);
        let expected_result = "const char data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, \n16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26};";
        assert_eq!(template.render(&data), expected_result);
    }

    #[test]
    fn render_basic_cplusplus_template() {
        let data = [0, 1, 2, 3, 4, 5];
        let template = Template::new(Language::Cpp);
        let expected_result = "const char data[] = {0, 1, 2, 3, 4, 5};";
        assert_eq!(template.render(&data), expected_result);
    }

    #[test]
    fn render_cplusplus_template_with_large_data() {
        let data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
                    22, 23, 24, 25, 26];
        let template = Template::new(Language::Cpp);
        let expected_result = "const char data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, \n16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26};";
        assert_eq!(template.render(&data), expected_result);
    }

    #[test]
    fn render_basic_python_template() {
        let data = [0, 1, 2, 3, 4, 5];
        let template = Template::new(Language::Python);
        let expected_result = "data = [0, 1, 2, 3, 4, 5]";
        assert_eq!(template.render(&data), expected_result);
    }

    #[test]
    fn render_python_template_with_large_data() {
        let data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
                    22, 23, 24, 25, 26];
        let template = Template::new(Language::Python);
        let expected_result = "data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, \n16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26]";
        assert_eq!(template.render(&data), expected_result);
    }

    #[test]
    fn render_basic_rust_template() {
        let data = [0, 1, 2, 3, 4, 5];
        let template = Template::new(Language::Rust);
        let expected_result = "let data = [0, 1, 2, 3, 4, 5];";
        assert_eq!(template.render(&data), expected_result);
    }

    #[test]
    fn render_rust_template_with_large_data() {
        let data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
                    22, 23, 24, 25, 26];
        let template = Template::new(Language::Rust);
        let expected_result = "let data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, \n16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26];";
        assert_eq!(template.render(&data), expected_result);
    }
}
<|endoftext|>


<commit_before>extern crate cargo;
extern crate reqwest;
#[macro_use]
extern crate lazy_static;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;
extern crate toml;

use std::collections::{BTreeMap, BTreeSet, HashSet};
use std::collections::btree_map::Entry;
use std::fs::File;
use std::io::{Read, Write};

use cargo::core::{Dependency, Source, SourceId, Summary};
use cargo::core::registry::PackageRegistry;
use cargo::core::resolver::{self, Method, Resolve};
use cargo::sources::RegistrySource;
use cargo::util::Config;

/// The list of crates from crates.io
#[derive(Debug, Deserialize)]
struct TopCrates {
    crates: Vec<Crate>,
}

/// A single crate from crates.io
#[derive(Debug, Deserialize)]
struct OneCrate {
    #[serde(rename="crate")]
    krate: Crate,
}

/// The shared description of a crate
#[derive(Debug, Deserialize)]
struct Crate {
    #[serde(rename="id")]
    name: String,
}

/// A Cargo.toml file.
#[derive(Serialize)]
struct TomlManifest {
    package: Package,
    profile: Profiles,
    dependencies: BTreeMap<String, String>,
}

/// Header of Cargo.toml file.
#[derive(Serialize)]
struct Package {
    name: String,
    version: String,
    authors: Vec<String>,
}

/// A mapping of a crates name to its identifier used in source code
#[derive(Debug, Serialize)]
struct CrateInformation {
    name: String,
    version: String,
    id: String,
}

/// Hand-curated changes to the crate list
#[derive(Debug, Deserialize)]
struct Modifications {
    #[serde(default)]
    blacklist: Vec<String>,
    #[serde(default)]
    additions: BTreeSet<String>,
}

/// A profile section in a Cargo.toml file
#[derive(Serialize)]
#[serde(rename_all="kebab-case")]
struct Profile {
    codegen_units: u32,
    incremental: bool,
}

/// Available profile types
#[derive(Serialize)]
struct Profiles {
    dev: Profile,
    release: Profile,
}

impl Modifications {
    fn blacklisted(&self, name: &str) -> bool {
        self.blacklist.iter().any(|n| n == name)
    }
}

lazy_static! {
    static ref MODIFICATIONS: Modifications = {
        let mut f = File::open("crate-modifications.toml")
            .expect("unable to open crate modifications file");

        let mut d = Vec::new();
        f.read_to_end(&mut d)
            .expect("unable to read crate modifications file");

        toml::from_slice(&d)
            .expect("unable to parse crate modifications file")
    };
}

impl TopCrates {
    /// List top 100 crates by number of downloads on crates.io.
    fn download() -> TopCrates {
        let resp =
            reqwest::get("https://crates.io/api/v1/crates?page=1&per_page=100&sort=downloads")
            .expect("Could not fetch top crates");
        assert!(resp.status().is_success());

        serde_json::from_reader(resp).expect("Invalid JSON")
    }

    /// Add crates that have been hand-picked
    fn add_curated_crates(&mut self) {
        self.crates.extend({
            MODIFICATIONS
                .additions
                .iter()
                .cloned()
                .map(|name| Crate { name })
        });
    }
}

fn decide_features(summary: &Summary) -> Method<'static> {
    // Enable `playground` feature if present.
    if summary.features().contains_key("playground") {
        // Would put this in a lazy_static, but its type is Vec<InternedString>
        // and InternedString is not publicly nameable.
        let features = Method::split_features(&["playground".to_owned()]);

        Method::Required {
            dev_deps: false,
            features: Box::leak(Box::new(features)),
            uses_default_features: false,
            all_features: false,
        }
    } else {
        Method::Required {
            dev_deps: false,
            features: &[],
            uses_default_features: true,
            all_features: false,
        }
    }
}

fn unique_latest_crates(resolve: Resolve) -> BTreeMap<String, String> {
    let mut uniqs = BTreeMap::new();
    for pkg in resolve.iter() {
        if MODIFICATIONS.blacklisted(pkg.name().as_str()) {
            continue;
        }

        match uniqs.entry(pkg.name()) {
            Entry::Vacant(entry) => {
                // First time seeing this package.
                entry.insert(pkg.version());
            }
            Entry::Occupied(mut entry) => {
                // Seen before, keep the newest version.
                if &pkg.version() > entry.get() {
                    entry.insert(pkg.version());
                }
            }
        }
    }

    uniqs.into_iter()
         .map(|(name, version)| (name.to_string(), version.to_string()))
         .collect()
}

fn write_manifest(manifest: TomlManifest, path: &str) {
    let mut f = File::create(path).expect("Unable to create Cargo.toml");
    let content = toml::to_vec(&manifest).expect("Couldn't serialize TOML");
    f.write_all(&content).expect("Couldn't write Cargo.toml");
}

fn main() {
    // Setup to interact with cargo.
    let config = Config::default().expect("Unable to create default Cargo config");
    let crates_io = SourceId::crates_io(&config).expect("Unable to create crates.io source ID");
    let mut source = RegistrySource::remote(&crates_io, &config);
    source.update().expect("Unable to update registry");

    let mut top = TopCrates::download();
    top.add_curated_crates();

    // Find the newest (non-prerelease, non-yanked) versions of all
    // the interesting crates.
    let mut summaries = Vec::new();
    for Crate { ref name } in top.crates {
        if MODIFICATIONS.blacklisted(name) {
            continue;
        }

        // Query the registry for a summary of this crate.
        // Usefully, this doesn't seem to include yanked versions
        let dep = Dependency::parse_no_deprecated(name, None, &crates_io)
            .unwrap_or_else(|e| panic!("Unable to parse dependency for {}: {}", name, e));

        let matches = source.query_vec(&dep).unwrap_or_else(|e| {
            panic!("Unable to query registry for {}: {}", name, e);
        });

        // Find the newest non-prelease version
        let summary = matches.into_iter()
            .filter(|summary| !summary.version().is_prerelease())
            .max_by_key(|summary| summary.version().clone())
            .unwrap_or_else(|| panic!("Registry has no viable versions of {}", name));

        // Add a dependency on this crate.
        let method = decide_features(&summary);
        summaries.push((summary, method));
    }

    // Resolve transitive dependencies.
    let mut registry = PackageRegistry::new(&config)
        .expect("Unable to create package registry");
    registry.lock_patches();
    let try_to_use = HashSet::new();
    let res = resolver::resolve(&summaries, &[], &mut registry, &try_to_use, None, true)
        .expect("Unable to resolve dependencies");

    // Construct playground's Cargo.toml.
    let unique_latest_crates = unique_latest_crates(res);
    let manifest = TomlManifest {
        package: Package {
            name: "playground".to_owned(),
            version: "0.0.1".to_owned(),
            authors: vec!["The Rust Playground".to_owned()],
        },
        profile: Profiles {
            dev: Profile { codegen_units: 1, incremental: false },
            release: Profile { codegen_units: 1, incremental: false },
        },
        dependencies: unique_latest_crates.clone(),
    };

    // Write manifest file.
    let cargo_toml = "../compiler/base/Cargo.toml";
    write_manifest(manifest, cargo_toml);
    println!("wrote {}", cargo_toml);

    let mut infos = Vec::new();

    for (name, version) in unique_latest_crates {
        let pkgid = cargo::core::PackageId::new(&name, &version, &crates_io)
            .unwrap_or_else(|e| panic!("Unable to build PackageId for {} {}: {}", name, version, e));

        let pkg = source.download(&pkgid)
            .unwrap_or_else(|e| panic!("Unable to download {} {}: {}", name, version, e));

        for target in pkg.targets() {
            if let cargo::core::TargetKind::Lib(_) = *target.kind() {
                infos.push(CrateInformation {
                    name: name.clone(),
                    version: version.clone(),
                    id: target.crate_name()
                })
            }
        }
    }

    let path = "../compiler/base/crate-information.json";
    let mut f = File::create(path)
        .unwrap_or_else(|e| panic!("Unable to create {}: {}", path, e));
    serde_json::to_writer_pretty(&mut f, &infos)
        .unwrap_or_else(|e| panic!("Unable to write {}: {}", path, e));
    println!("Wrote {}", path);
}
<commit_msg>Implement playground-specific custom metadata to control enabled features<commit_after>extern crate cargo;
extern crate reqwest;
#[macro_use]
extern crate lazy_static;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;
extern crate toml;

use std::collections::{BTreeMap, BTreeSet, HashSet};
use std::collections::btree_map::Entry;
use std::fs::File;
use std::io::{Read, Write};

use cargo::core::{Dependency, Package, Source, SourceId, Summary};
use cargo::core::registry::PackageRegistry;
use cargo::core::resolver::{self, Method, Resolve};
use cargo::sources::RegistrySource;
use cargo::util::Config;

/// The list of crates from crates.io
#[derive(Debug, Deserialize)]
struct TopCrates {
    crates: Vec<Crate>,
}

/// A single crate from crates.io
#[derive(Debug, Deserialize)]
struct OneCrate {
    #[serde(rename="crate")]
    krate: Crate,
}

/// The shared description of a crate
#[derive(Debug, Deserialize)]
struct Crate {
    #[serde(rename="id")]
    name: String,
}

/// A Cargo.toml file.
#[derive(Serialize)]
struct TomlManifest {
    package: TomlPackage,
    profile: Profiles,
    #[serde(serialize_with = "toml::ser::tables_last")]
    dependencies: BTreeMap<String, DependencySpec>,
}

/// Header of Cargo.toml file.
#[derive(Serialize)]
struct TomlPackage {
    name: String,
    version: String,
    authors: Vec<String>,
}

/// A mapping of a crates name to its identifier used in source code
#[derive(Debug, Serialize)]
struct CrateInformation {
    name: String,
    version: String,
    id: String,
}

/// Hand-curated changes to the crate list
#[derive(Debug, Deserialize)]
struct Modifications {
    #[serde(default)]
    blacklist: Vec<String>,
    #[serde(default)]
    additions: BTreeSet<String>,
}

/// A profile section in a Cargo.toml file
#[derive(Serialize)]
#[serde(rename_all="kebab-case")]
struct Profile {
    codegen_units: u32,
    incremental: bool,
}

/// Available profile types
#[derive(Serialize)]
struct Profiles {
    dev: Profile,
    release: Profile,
}

/// `"1.0.0"` or `{ version = "1.0.0", features = ["..."] }`
#[derive(Serialize, Clone)]
#[serde(untagged)]
enum DependencySpec {
    String(String),
    #[serde(rename_all = "kebab-case")]
    Explicit {
        version: String,
        #[serde(skip_serializing_if = "Vec::is_empty")]
        features: Vec<String>,
        #[serde(skip_serializing_if = "is_true")]
        default_features: bool,
    }
}

impl DependencySpec {
    fn version(&self) -> String {
        match *self {
            DependencySpec::String(ref version) |
            DependencySpec::Explicit { ref version, .. } => version.clone(),
        }
    }
}

fn is_true(b: &bool) -> bool {
    *b
}

impl Modifications {
    fn blacklisted(&self, name: &str) -> bool {
        self.blacklist.iter().any(|n| n == name)
    }
}

lazy_static! {
    static ref MODIFICATIONS: Modifications = {
        let mut f = File::open("crate-modifications.toml")
            .expect("unable to open crate modifications file");

        let mut d = Vec::new();
        f.read_to_end(&mut d)
            .expect("unable to read crate modifications file");

        toml::from_slice(&d)
            .expect("unable to parse crate modifications file")
    };
}

impl TopCrates {
    /// List top 100 crates by number of downloads on crates.io.
    fn download() -> TopCrates {
        let resp =
            reqwest::get("https://crates.io/api/v1/crates?page=1&per_page=100&sort=downloads")
            .expect("Could not fetch top crates");
        assert!(resp.status().is_success());

        serde_json::from_reader(resp).expect("Invalid JSON")
    }

    /// Add crates that have been hand-picked
    fn add_curated_crates(&mut self) {
        self.crates.extend({
            MODIFICATIONS
                .additions
                .iter()
                .cloned()
                .map(|name| Crate { name })
        });
    }
}

fn decide_features(summary: &Summary) -> Method<'static> {
    // Enable `playground` feature if present.
    if summary.features().contains_key("playground") {
        // Would put this in a lazy_static, but its type is Vec<InternedString>
        // and InternedString is not publicly nameable.
        let features = Method::split_features(&["playground".to_owned()]);

        Method::Required {
            dev_deps: false,
            features: Box::leak(Box::new(features)),
            uses_default_features: false,
            all_features: false,
        }
    } else {
        Method::Required {
            dev_deps: false,
            features: &[],
            uses_default_features: true,
            all_features: false,
        }
    }
}

fn unique_latest_crates(resolve: Resolve) -> BTreeMap<String, DependencySpec> {
    let mut uniqs = BTreeMap::new();
    for pkg in resolve.iter() {
        if MODIFICATIONS.blacklisted(pkg.name().as_str()) {
            continue;
        }

        match uniqs.entry(pkg.name()) {
            Entry::Vacant(entry) => {
                // First time seeing this package.
                entry.insert(pkg.version());
            }
            Entry::Occupied(mut entry) => {
                // Seen before, keep the newest version.
                if &pkg.version() > entry.get() {
                    entry.insert(pkg.version());
                }
            }
        }
    }

    uniqs.into_iter()
         .map(|(name, version)| (
             name.to_string(),
             DependencySpec::String(version.to_string()),
         ))
         .collect()
}

/// Updates `dep` to include features specified by the custom metadata of `pkg`.
///
/// Our custom metadata format looks like:
///
///     [package.metadata.playground]
///     default-features = true
///     features = ["std", "extra-traits"]
///     all-features = false
///
/// All fields are optional.
fn fill_playground_metadata_features(dep: &mut DependencySpec, pkg: &Package) {
    let custom_metadata = match pkg.manifest().custom_metadata() {
        Some(custom_metadata) => custom_metadata,
        None => return,
    };

    let playground_metadata = match custom_metadata.get("playground") {
        Some(playground_metadata) => playground_metadata,
        None => return,
    };

    #[derive(Deserialize)]
    #[serde(default, rename_all = "kebab-case")]
    struct Metadata {
        features: Vec<String>,
        default_features: bool,
        all_features: bool,
    }

    impl Default for Metadata {
        fn default() -> Self {
            Metadata {
                features: Vec::new(),
                default_features: true,
                all_features: false,
            }
        }
    }

    let metadata = match playground_metadata.clone().try_into::<Metadata>() {
        Ok(metadata) => metadata,
        Err(err) => {
            eprintln!(
                "Failed to parse custom metadata for {} {}: {}",
                pkg.name(), pkg.version(), err);
            return;
        }
    };

    // If `all-features` is set then we ignore `features`.
    let summary = pkg.summary();
    let mut enabled_features: BTreeSet<String> = if metadata.all_features {
        summary.features().keys().cloned().collect()
    } else {
        metadata.features.into_iter().collect()
    };

    // If not opting out of default features, remove default features from the
    // explicit features list. This avoids ongoing spurious diffs in our
    // generated Cargo.toml as default features are added to a library.
    if metadata.default_features {
        if let Some(default_feature_names) = summary.features().get("default") {
            enabled_features.remove("default");
            for feature in default_feature_names {
                enabled_features.remove(&feature.to_string(summary));
            }
        }
    }

    if !enabled_features.is_empty() || !metadata.default_features {
        *dep = DependencySpec::Explicit {
            version: dep.version(),
            features: enabled_features.into_iter().collect(),
            default_features: metadata.default_features,
        };
    }
}

fn write_manifest(manifest: TomlManifest, path: &str) {
    let mut f = File::create(path).expect("Unable to create Cargo.toml");
    let content = toml::to_vec(&manifest).expect("Couldn't serialize TOML");
    f.write_all(&content).expect("Couldn't write Cargo.toml");
}

fn main() {
    // Setup to interact with cargo.
    let config = Config::default().expect("Unable to create default Cargo config");
    let crates_io = SourceId::crates_io(&config).expect("Unable to create crates.io source ID");
    let mut source = RegistrySource::remote(&crates_io, &config);
    source.update().expect("Unable to update registry");

    let mut top = TopCrates::download();
    top.add_curated_crates();

    // Find the newest (non-prerelease, non-yanked) versions of all
    // the interesting crates.
    let mut summaries = Vec::new();
    for Crate { ref name } in top.crates {
        if MODIFICATIONS.blacklisted(name) {
            continue;
        }

        // Query the registry for a summary of this crate.
        // Usefully, this doesn't seem to include yanked versions
        let dep = Dependency::parse_no_deprecated(name, None, &crates_io)
            .unwrap_or_else(|e| panic!("Unable to parse dependency for {}: {}", name, e));

        let matches = source.query_vec(&dep).unwrap_or_else(|e| {
            panic!("Unable to query registry for {}: {}", name, e);
        });

        // Find the newest non-prelease version
        let summary = matches.into_iter()
            .filter(|summary| !summary.version().is_prerelease())
            .max_by_key(|summary| summary.version().clone())
            .unwrap_or_else(|| panic!("Registry has no viable versions of {}", name));

        // Add a dependency on this crate.
        let method = decide_features(&summary);
        summaries.push((summary, method));
    }

    // Resolve transitive dependencies.
    let mut registry = PackageRegistry::new(&config)
        .expect("Unable to create package registry");
    registry.lock_patches();
    let try_to_use = HashSet::new();
    let res = resolver::resolve(&summaries, &[], &mut registry, &try_to_use, None, true)
        .expect("Unable to resolve dependencies");

    // Construct playground's Cargo.toml.
    let mut unique_latest_crates = unique_latest_crates(res);

    let mut infos = Vec::new();

    for (name, spec) in &mut unique_latest_crates {
        let version = spec.version();

        let pkgid = cargo::core::PackageId::new(&name, &version, &crates_io)
            .unwrap_or_else(|e| panic!("Unable to build PackageId for {} {}: {}", name, version, e));

        let pkg = source.download(&pkgid)
            .unwrap_or_else(|e| panic!("Unable to download {} {}: {}", name, version, e));

        for target in pkg.targets() {
            if let cargo::core::TargetKind::Lib(_) = *target.kind() {
                infos.push(CrateInformation {
                    name: name.clone(),
                    version: version.clone(),
                    id: target.crate_name()
                })
            }
        }

        fill_playground_metadata_features(spec, &pkg);
    }

    let manifest = TomlManifest {
        package: TomlPackage {
            name: "playground".to_owned(),
            version: "0.0.1".to_owned(),
            authors: vec!["The Rust Playground".to_owned()],
        },
        profile: Profiles {
            dev: Profile { codegen_units: 1, incremental: false },
            release: Profile { codegen_units: 1, incremental: false },
        },
        dependencies: unique_latest_crates,
    };

    // Write manifest file.
    let cargo_toml = "../compiler/base/Cargo.toml";
    write_manifest(manifest, cargo_toml);
    println!("wrote {}", cargo_toml);

    let path = "../compiler/base/crate-information.json";
    let mut f = File::create(path)
        .unwrap_or_else(|e| panic!("Unable to create {}: {}", path, e));
    serde_json::to_writer_pretty(&mut f, &infos)
        .unwrap_or_else(|e| panic!("Unable to write {}: {}", path, e));
    println!("Wrote {}", path);
}
<|endoftext|>


<commit_before>//! Checks for usage of  `&Vec[_]` and `&String`.

use crate::utils::ptr::get_spans;
use crate::utils::{
    is_allowed, is_type_diagnostic_item, match_qpath, match_type, paths, snippet_opt, span_lint, span_lint_and_sugg,
    span_lint_and_then, walk_ptrs_hir_ty,
};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{
    BinOpKind, BodyId, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, HirId, ImplItem, ImplItemKind, Item, ItemKind,
    Lifetime, MutTy, Mutability, Node, PathSegment, QPath, TraitFn, TraitItem, TraitItemKind, Ty, TyKind,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
use rustc_span::MultiSpan;
use std::borrow::Cow;

declare_clippy_lint! {
    /// **What it does:** This lint checks for function arguments of type `&String`
    /// or `&Vec` unless the references are mutable. It will also suggest you
    /// replace `.clone()` calls with the appropriate `.to_owned()`/`to_string()`
    /// calls.
    ///
    /// **Why is this bad?** Requiring the argument to be of the specific size
    /// makes the function less useful for no benefit; slices in the form of `&[T]`
    /// or `&str` usually suffice and can be obtained from other types, too.
    ///
    /// **Known problems:** The lint does not follow data. So if you have an
    /// argument `x` and write `let y = x; y.clone()` the lint will not suggest
    /// changing that `.clone()` to `.to_owned()`.
    ///
    /// Other functions called from this function taking a `&String` or `&Vec`
    /// argument may also fail to compile if you change the argument. Applying
    /// this lint on them will fix the problem, but they may be in other crates.
    ///
    /// Also there may be `fn(&Vec)`-typed references pointing to your function.
    /// If you have them, you will get a compiler error after applying this lint's
    /// suggestions. You then have the choice to undo your changes or change the
    /// type of the reference.
    ///
    /// Note that if the function is part of your public interface, there may be
    /// other crates referencing it you may not be aware. Carefully deprecate the
    /// function before applying the lint suggestions in this case.
    ///
    /// **Example:**
    /// ```ignore
    /// // Bad
    /// fn foo(&Vec<u32>) { .. }
    ///
    /// // Good
    /// fn foo(&[u32]) { .. }
    /// ```
    pub PTR_ARG,
    style,
    "fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively"
}

declare_clippy_lint! {
    /// **What it does:** This lint checks for equality comparisons with `ptr::null`
    ///
    /// **Why is this bad?** It's easier and more readable to use the inherent
    /// `.is_null()`
    /// method instead
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```ignore
    /// // Bad
    /// if x == ptr::null {
    ///     ..
    /// }
    ///
    /// // Good
    /// if x.is_null() {
    ///     ..
    /// }
    /// ```
    pub CMP_NULL,
    style,
    "comparing a pointer to a null pointer, suggesting to use `.is_null()` instead."
}

declare_clippy_lint! {
    /// **What it does:** This lint checks for functions that take immutable
    /// references and return mutable ones.
    ///
    /// **Why is this bad?** This is trivially unsound, as one can create two
    /// mutable references from the same (immutable!) source.
    /// This [error](https://github.com/rust-lang/rust/issues/39465)
    /// actually lead to an interim Rust release 1.15.1.
    ///
    /// **Known problems:** To be on the conservative side, if there's at least one
    /// mutable reference with the output lifetime, this lint will not trigger.
    /// In practice, this case is unlikely anyway.
    ///
    /// **Example:**
    /// ```ignore
    /// fn foo(&Foo) -> &mut Bar { .. }
    /// ```
    pub MUT_FROM_REF,
    correctness,
    "fns that create mutable refs from immutable ref args"
}

declare_lint_pass!(Ptr => [PTR_ARG, CMP_NULL, MUT_FROM_REF]);

impl<'tcx> LateLintPass<'tcx> for Ptr {
    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
        if let ItemKind::Fn(ref sig, _, body_id) = item.kind {
            check_fn(cx, &sig.decl, item.hir_id, Some(body_id));
        }
    }

    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
        if let ImplItemKind::Fn(ref sig, body_id) = item.kind {
            let parent_item = cx.tcx.hir().get_parent_item(item.hir_id);
            if let Some(Node::Item(it)) = cx.tcx.hir().find(parent_item) {
                if let ItemKind::Impl { of_trait: Some(_), .. } = it.kind {
                    return; // ignore trait impls
                }
            }
            check_fn(cx, &sig.decl, item.hir_id, Some(body_id));
        }
    }

    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
        if let TraitItemKind::Fn(ref sig, ref trait_method) = item.kind {
            let body_id = if let TraitFn::Provided(b) = *trait_method {
                Some(b)
            } else {
                None
            };
            check_fn(cx, &sig.decl, item.hir_id, body_id);
        }
    }

    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
        if let ExprKind::Binary(ref op, ref l, ref r) = expr.kind {
            if (op.node == BinOpKind::Eq || op.node == BinOpKind::Ne) && (is_null_path(l) || is_null_path(r)) {
                span_lint(
                    cx,
                    CMP_NULL,
                    expr.span,
                    "comparing with null is better expressed by the `.is_null()` method",
                );
            }
        }
    }
}

#[allow(clippy::too_many_lines)]
fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: Option<BodyId>) {
    let fn_def_id = cx.tcx.hir().local_def_id(fn_id);
    let sig = cx.tcx.fn_sig(fn_def_id);
    let fn_ty = sig.skip_binder();
    let body = opt_body_id.map(|id| cx.tcx.hir().body(id));

    for (idx, (arg, ty)) in decl.inputs.iter().zip(fn_ty.inputs()).enumerate() {
        // Honor the allow attribute on parameters. See issue 5644.
        if let Some(body) = &body {
            if is_allowed(cx, PTR_ARG, body.params[idx].hir_id) {
                continue;
            }
        }

        if let ty::Ref(_, ty, Mutability::Not) = ty.kind {
            if is_type_diagnostic_item(cx, ty, sym!(vec_type)) {
                let mut ty_snippet = None;
                if_chain! {
                    if let TyKind::Path(QPath::Resolved(_, ref path)) = walk_ptrs_hir_ty(arg).kind;
                    if let Some(&PathSegment{args: Some(ref parameters), ..}) = path.segments.last();
                    then {
                        let types: Vec<_> = parameters.args.iter().filter_map(|arg| match arg {
                            GenericArg::Type(ty) => Some(ty),
                            _ => None,
                        }).collect();
                        if types.len() == 1 {
                            ty_snippet = snippet_opt(cx, types[0].span);
                        }
                    }
                };
                if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_owned()")]) {
                    span_lint_and_then(
                        cx,
                        PTR_ARG,
                        arg.span,
                        "writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used \
                         with non-Vec-based slices.",
                        |diag| {
                            if let Some(ref snippet) = ty_snippet {
                                diag.span_suggestion(
                                    arg.span,
                                    "change this to",
                                    format!("&[{}]", snippet),
                                    Applicability::Unspecified,
                                );
                            }
                            for (clonespan, suggestion) in spans {
                                diag.span_suggestion(
                                    clonespan,
                                    &snippet_opt(cx, clonespan).map_or("change the call to".into(), |x| {
                                        Cow::Owned(format!("change `{}` to", x))
                                    }),
                                    suggestion.into(),
                                    Applicability::Unspecified,
                                );
                            }
                        },
                    );
                }
            } else if is_type_diagnostic_item(cx, ty, sym!(string_type)) {
                if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_string()"), ("as_str", "")]) {
                    span_lint_and_then(
                        cx,
                        PTR_ARG,
                        arg.span,
                        "writing `&String` instead of `&str` involves a new object where a slice will do.",
                        |diag| {
                            diag.span_suggestion(arg.span, "change this to", "&str".into(), Applicability::Unspecified);
                            for (clonespan, suggestion) in spans {
                                diag.span_suggestion_short(
                                    clonespan,
                                    &snippet_opt(cx, clonespan).map_or("change the call to".into(), |x| {
                                        Cow::Owned(format!("change `{}` to", x))
                                    }),
                                    suggestion.into(),
                                    Applicability::Unspecified,
                                );
                            }
                        },
                    );
                }
            } else if match_type(cx, ty, &paths::COW) {
                if_chain! {
                    if let TyKind::Rptr(_, MutTy { ref ty, ..} ) = arg.kind;
                    if let TyKind::Path(ref path) = ty.kind;
                    if let QPath::Resolved(None, ref pp) = *path;
                    if let [ref bx] = *pp.segments;
                    if let Some(ref params) = bx.args;
                    if !params.parenthesized;
                    if let Some(inner) = params.args.iter().find_map(|arg| match arg {
                        GenericArg::Type(ty) => Some(ty),
                        _ => None,
                    });
                    then {
                        let replacement = snippet_opt(cx, inner.span);
                        if let Some(r) = replacement {
                            span_lint_and_sugg(
                                cx,
                                PTR_ARG,
                                arg.span,
                                "using a reference to `Cow` is not recommended.",
                                "change this to",
                                "&".to_owned() + &r,
                                Applicability::Unspecified,
                            );
                        }
                    }
                }
            }
        }
    }

    if let FnRetTy::Return(ref ty) = decl.output {
        if let Some((out, Mutability::Mut, _)) = get_rptr_lm(ty) {
            let mut immutables = vec![];
            for (_, ref mutbl, ref argspan) in decl
                .inputs
                .iter()
                .filter_map(|ty| get_rptr_lm(ty))
                .filter(|&(lt, _, _)| lt.name == out.name)
            {
                if *mutbl == Mutability::Mut {
                    return;
                }
                immutables.push(*argspan);
            }
            if immutables.is_empty() {
                return;
            }
            span_lint_and_then(
                cx,
                MUT_FROM_REF,
                ty.span,
                "mutable borrow from immutable input(s)",
                |diag| {
                    let ms = MultiSpan::from_spans(immutables);
                    diag.span_note(ms, "immutable borrow here");
                },
            );
        }
    }
}

fn get_rptr_lm<'tcx>(ty: &'tcx Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, Span)> {
    if let TyKind::Rptr(ref lt, ref m) = ty.kind {
        Some((lt, m.mutbl, ty.span))
    } else {
        None
    }
}

fn is_null_path(expr: &Expr<'_>) -> bool {
    if let ExprKind::Call(ref pathexp, ref args) = expr.kind {
        if args.is_empty() {
            if let ExprKind::Path(ref path) = pathexp.kind {
                return match_qpath(path, &paths::PTR_NULL) || match_qpath(path, &paths::PTR_NULL_MUT);
            }
        }
    }
    false
}
<commit_msg>Auto merge of #5885 - Ryan1729:patch-2, r=flip1995<commit_after>//! Checks for usage of  `&Vec[_]` and `&String`.

use crate::utils::ptr::get_spans;
use crate::utils::{
    is_allowed, is_type_diagnostic_item, match_qpath, match_type, paths, snippet_opt, span_lint, span_lint_and_sugg,
    span_lint_and_then, walk_ptrs_hir_ty,
};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{
    BinOpKind, BodyId, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, HirId, ImplItem, ImplItemKind, Item, ItemKind,
    Lifetime, MutTy, Mutability, Node, PathSegment, QPath, TraitFn, TraitItem, TraitItemKind, Ty, TyKind,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
use rustc_span::MultiSpan;
use std::borrow::Cow;

declare_clippy_lint! {
    /// **What it does:** This lint checks for function arguments of type `&String`
    /// or `&Vec` unless the references are mutable. It will also suggest you
    /// replace `.clone()` calls with the appropriate `.to_owned()`/`to_string()`
    /// calls.
    ///
    /// **Why is this bad?** Requiring the argument to be of the specific size
    /// makes the function less useful for no benefit; slices in the form of `&[T]`
    /// or `&str` usually suffice and can be obtained from other types, too.
    ///
    /// **Known problems:** The lint does not follow data. So if you have an
    /// argument `x` and write `let y = x; y.clone()` the lint will not suggest
    /// changing that `.clone()` to `.to_owned()`.
    ///
    /// Other functions called from this function taking a `&String` or `&Vec`
    /// argument may also fail to compile if you change the argument. Applying
    /// this lint on them will fix the problem, but they may be in other crates.
    ///
    /// One notable example of a function that may cause issues, and which cannot
    /// easily be changed due to being in the standard library is `Vec::contains`.
    /// when called on a `Vec<Vec<T>>`. If a `&Vec` is passed to that method then
    /// it will compile, but if a `&[T]` is passed then it will not compile.
    ///
    /// ```ignore
    /// fn cannot_take_a_slice(v: &Vec<u8>) -> bool {
    ///     let vec_of_vecs: Vec<Vec<u8>> = some_other_fn();
    ///
    ///     vec_of_vecs.contains(v)
    /// }
    /// ```
    ///
    /// Also there may be `fn(&Vec)`-typed references pointing to your function.
    /// If you have them, you will get a compiler error after applying this lint's
    /// suggestions. You then have the choice to undo your changes or change the
    /// type of the reference.
    ///
    /// Note that if the function is part of your public interface, there may be
    /// other crates referencing it, of which you may not be aware. Carefully
    /// deprecate the function before applying the lint suggestions in this case.
    ///
    /// **Example:**
    /// ```ignore
    /// // Bad
    /// fn foo(&Vec<u32>) { .. }
    ///
    /// // Good
    /// fn foo(&[u32]) { .. }
    /// ```
    pub PTR_ARG,
    style,
    "fn arguments of the type `&Vec<...>` or `&String`, suggesting to use `&[...]` or `&str` instead, respectively"
}

declare_clippy_lint! {
    /// **What it does:** This lint checks for equality comparisons with `ptr::null`
    ///
    /// **Why is this bad?** It's easier and more readable to use the inherent
    /// `.is_null()`
    /// method instead
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```ignore
    /// // Bad
    /// if x == ptr::null {
    ///     ..
    /// }
    ///
    /// // Good
    /// if x.is_null() {
    ///     ..
    /// }
    /// ```
    pub CMP_NULL,
    style,
    "comparing a pointer to a null pointer, suggesting to use `.is_null()` instead."
}

declare_clippy_lint! {
    /// **What it does:** This lint checks for functions that take immutable
    /// references and return mutable ones.
    ///
    /// **Why is this bad?** This is trivially unsound, as one can create two
    /// mutable references from the same (immutable!) source.
    /// This [error](https://github.com/rust-lang/rust/issues/39465)
    /// actually lead to an interim Rust release 1.15.1.
    ///
    /// **Known problems:** To be on the conservative side, if there's at least one
    /// mutable reference with the output lifetime, this lint will not trigger.
    /// In practice, this case is unlikely anyway.
    ///
    /// **Example:**
    /// ```ignore
    /// fn foo(&Foo) -> &mut Bar { .. }
    /// ```
    pub MUT_FROM_REF,
    correctness,
    "fns that create mutable refs from immutable ref args"
}

declare_lint_pass!(Ptr => [PTR_ARG, CMP_NULL, MUT_FROM_REF]);

impl<'tcx> LateLintPass<'tcx> for Ptr {
    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
        if let ItemKind::Fn(ref sig, _, body_id) = item.kind {
            check_fn(cx, &sig.decl, item.hir_id, Some(body_id));
        }
    }

    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
        if let ImplItemKind::Fn(ref sig, body_id) = item.kind {
            let parent_item = cx.tcx.hir().get_parent_item(item.hir_id);
            if let Some(Node::Item(it)) = cx.tcx.hir().find(parent_item) {
                if let ItemKind::Impl { of_trait: Some(_), .. } = it.kind {
                    return; // ignore trait impls
                }
            }
            check_fn(cx, &sig.decl, item.hir_id, Some(body_id));
        }
    }

    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
        if let TraitItemKind::Fn(ref sig, ref trait_method) = item.kind {
            let body_id = if let TraitFn::Provided(b) = *trait_method {
                Some(b)
            } else {
                None
            };
            check_fn(cx, &sig.decl, item.hir_id, body_id);
        }
    }

    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
        if let ExprKind::Binary(ref op, ref l, ref r) = expr.kind {
            if (op.node == BinOpKind::Eq || op.node == BinOpKind::Ne) && (is_null_path(l) || is_null_path(r)) {
                span_lint(
                    cx,
                    CMP_NULL,
                    expr.span,
                    "comparing with null is better expressed by the `.is_null()` method",
                );
            }
        }
    }
}

#[allow(clippy::too_many_lines)]
fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_id: HirId, opt_body_id: Option<BodyId>) {
    let fn_def_id = cx.tcx.hir().local_def_id(fn_id);
    let sig = cx.tcx.fn_sig(fn_def_id);
    let fn_ty = sig.skip_binder();
    let body = opt_body_id.map(|id| cx.tcx.hir().body(id));

    for (idx, (arg, ty)) in decl.inputs.iter().zip(fn_ty.inputs()).enumerate() {
        // Honor the allow attribute on parameters. See issue 5644.
        if let Some(body) = &body {
            if is_allowed(cx, PTR_ARG, body.params[idx].hir_id) {
                continue;
            }
        }

        if let ty::Ref(_, ty, Mutability::Not) = ty.kind {
            if is_type_diagnostic_item(cx, ty, sym!(vec_type)) {
                let mut ty_snippet = None;
                if_chain! {
                    if let TyKind::Path(QPath::Resolved(_, ref path)) = walk_ptrs_hir_ty(arg).kind;
                    if let Some(&PathSegment{args: Some(ref parameters), ..}) = path.segments.last();
                    then {
                        let types: Vec<_> = parameters.args.iter().filter_map(|arg| match arg {
                            GenericArg::Type(ty) => Some(ty),
                            _ => None,
                        }).collect();
                        if types.len() == 1 {
                            ty_snippet = snippet_opt(cx, types[0].span);
                        }
                    }
                };
                if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_owned()")]) {
                    span_lint_and_then(
                        cx,
                        PTR_ARG,
                        arg.span,
                        "writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used \
                         with non-Vec-based slices.",
                        |diag| {
                            if let Some(ref snippet) = ty_snippet {
                                diag.span_suggestion(
                                    arg.span,
                                    "change this to",
                                    format!("&[{}]", snippet),
                                    Applicability::Unspecified,
                                );
                            }
                            for (clonespan, suggestion) in spans {
                                diag.span_suggestion(
                                    clonespan,
                                    &snippet_opt(cx, clonespan).map_or("change the call to".into(), |x| {
                                        Cow::Owned(format!("change `{}` to", x))
                                    }),
                                    suggestion.into(),
                                    Applicability::Unspecified,
                                );
                            }
                        },
                    );
                }
            } else if is_type_diagnostic_item(cx, ty, sym!(string_type)) {
                if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_string()"), ("as_str", "")]) {
                    span_lint_and_then(
                        cx,
                        PTR_ARG,
                        arg.span,
                        "writing `&String` instead of `&str` involves a new object where a slice will do.",
                        |diag| {
                            diag.span_suggestion(arg.span, "change this to", "&str".into(), Applicability::Unspecified);
                            for (clonespan, suggestion) in spans {
                                diag.span_suggestion_short(
                                    clonespan,
                                    &snippet_opt(cx, clonespan).map_or("change the call to".into(), |x| {
                                        Cow::Owned(format!("change `{}` to", x))
                                    }),
                                    suggestion.into(),
                                    Applicability::Unspecified,
                                );
                            }
                        },
                    );
                }
            } else if match_type(cx, ty, &paths::COW) {
                if_chain! {
                    if let TyKind::Rptr(_, MutTy { ref ty, ..} ) = arg.kind;
                    if let TyKind::Path(ref path) = ty.kind;
                    if let QPath::Resolved(None, ref pp) = *path;
                    if let [ref bx] = *pp.segments;
                    if let Some(ref params) = bx.args;
                    if !params.parenthesized;
                    if let Some(inner) = params.args.iter().find_map(|arg| match arg {
                        GenericArg::Type(ty) => Some(ty),
                        _ => None,
                    });
                    then {
                        let replacement = snippet_opt(cx, inner.span);
                        if let Some(r) = replacement {
                            span_lint_and_sugg(
                                cx,
                                PTR_ARG,
                                arg.span,
                                "using a reference to `Cow` is not recommended.",
                                "change this to",
                                "&".to_owned() + &r,
                                Applicability::Unspecified,
                            );
                        }
                    }
                }
            }
        }
    }

    if let FnRetTy::Return(ref ty) = decl.output {
        if let Some((out, Mutability::Mut, _)) = get_rptr_lm(ty) {
            let mut immutables = vec![];
            for (_, ref mutbl, ref argspan) in decl
                .inputs
                .iter()
                .filter_map(|ty| get_rptr_lm(ty))
                .filter(|&(lt, _, _)| lt.name == out.name)
            {
                if *mutbl == Mutability::Mut {
                    return;
                }
                immutables.push(*argspan);
            }
            if immutables.is_empty() {
                return;
            }
            span_lint_and_then(
                cx,
                MUT_FROM_REF,
                ty.span,
                "mutable borrow from immutable input(s)",
                |diag| {
                    let ms = MultiSpan::from_spans(immutables);
                    diag.span_note(ms, "immutable borrow here");
                },
            );
        }
    }
}

fn get_rptr_lm<'tcx>(ty: &'tcx Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, Span)> {
    if let TyKind::Rptr(ref lt, ref m) = ty.kind {
        Some((lt, m.mutbl, ty.span))
    } else {
        None
    }
}

fn is_null_path(expr: &Expr<'_>) -> bool {
    if let ExprKind::Call(ref pathexp, ref args) = expr.kind {
        if args.is_empty() {
            if let ExprKind::Path(ref path) = pathexp.kind {
                return match_qpath(path, &paths::PTR_NULL) || match_qpath(path, &paths::PTR_NULL_MUT);
            }
        }
    }
    false
}
<|endoftext|>