<commit_before>use std::str;
use std::thread;
use std::sync::Mutex;
use std::cell::RefCell;
use std::time::{Duration,Instant};
use std::iter::repeat;
use std::collections::BTreeMap;
use std::collections::VecDeque;
use std::fmt::Arguments;
use std::net::SocketAddr;
use mio::net::UdpSocket;
use std::io::{self,BufWriter,Write,Error,ErrorKind};
use nom::HexDisplay;
use hdrhistogram::Histogram;
use sozu_command::buffer::Buffer;
use sozu_command::messages::{FilteredData,MetricsData,Percentiles,BackendMetricsData,FilteredTimeSerie};

use super::{Subscriber,MetricData,StoredMetricData};

#[derive(Debug,Clone,PartialEq)]
pub struct MetricLine {
  label:      &'static str,
  app_id:     Option<String>,
  backend_id: Option<String>,
  /// in milliseconds
  duration:   usize,
}

pub struct MetricSocket {
  pub addr:   SocketAddr,
  pub socket: UdpSocket,
}

impl Write for MetricSocket {
  fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
    self.socket.send_to(buf, &self.addr)
  }

  fn flush(&mut self) -> io::Result<()> {
    Ok(())
  }
}

pub struct NetworkDrain {
  queue:              VecDeque<MetricLine>,
  buffer:             Buffer,
  pub prefix:         String,
  pub remote:         BufWriter<MetricSocket>,
  is_writable:        bool,
  data:               BTreeMap<String, StoredMetricData>,
  /// (app_id, key) -> metric
  app_data:           BTreeMap<(String, String), StoredMetricData>,
  /// (app_id, backend_id, key) -> metric
  backend_data:       BTreeMap<(String, String, String), StoredMetricData>,
  pub use_tagged_metrics: bool,
  pub origin:         String,
  created:            Instant,
}

impl NetworkDrain {
  pub fn new(prefix: String, socket: UdpSocket, addr: SocketAddr) -> Self {
    NetworkDrain {
      queue:  VecDeque::new(),
      buffer: Buffer::with_capacity(2048),
      prefix: prefix,
      remote: BufWriter::new(MetricSocket {
        addr, socket
      }),
      is_writable: true,
      data: BTreeMap::new(),
      app_data: BTreeMap::new(),
      backend_data: BTreeMap::new(),
      use_tagged_metrics: false,
      origin: String::from("x"),
      created: Instant::now(),
    }
  }

  pub fn writable(&mut self) {
    self.is_writable = true;
  }

  pub fn send_data(&mut self) {
    let now  = Instant::now();
    let secs = Duration::new(2, 0);

    if self.is_writable {
    for (ref key, ref mut stored_metric) in self.data.iter_mut().filter(|&(_, ref value)| now.duration_since(value.last_sent) > secs) {
      //info!("will write {} -> {:#?}", key, stored_metric);
      let res = match stored_metric.data {
        MetricData::Gauge(value) => {
          if self.use_tagged_metrics {
            self.remote.write_fmt(format_args!("{}.{},origin={}:{}|g\n", self.prefix, key, self.origin, value))
          } else {
            self.remote.write_fmt(format_args!("{}.{}.{}:{}|g\n", self.prefix, self.origin, key, value))
          }
        },
        MetricData::Count(value) => {
          if value == 0 {
            stored_metric.last_sent = now;
          }

          let res = if self.use_tagged_metrics {
            self.remote.write_fmt(format_args!("{}.{},origin={}:{}|c\n", self.prefix, key, self.origin, value))
          } else {
            self.remote.write_fmt(format_args!("{}.{}.{}:{}|c\n", self.prefix, self.origin, key, value))
          };

          if res.is_ok() {
            stored_metric.data = MetricData::Count(0);
          }

          res
        },
        _ => {Ok(())}
      };

      match res {
        Ok(()) => {
          stored_metric.last_sent = now;
        },
        Err(e) => match e.kind() {
          ErrorKind::WriteZero => {
            self.remote.flush();
          },
          ErrorKind::WouldBlock => {
            error!("WouldBlock while writing global metrics to socket");
            self.is_writable = false;
            break;
          },
          e => {
            error!("metrics socket write error={:?}", e);
            break;
          },
        }
      }
    }
    }

    self.remote.flush();

    if self.is_writable {
    for (ref key, ref mut stored_metric) in self.app_data.iter_mut().filter(|&(_, ref value)| now.duration_since(value.last_sent) > secs) {
      //info!("will write {} -> {:#?}", key, stored_metric);
      let res = match stored_metric.data {
        MetricData::Gauge(value) => {
          if self.use_tagged_metrics {
            self.remote.write_fmt(format_args!("{}.app.{},origin={},app_id={}:{}|g\n", self.prefix, key.1, self.origin, key.0, value))
          } else {
            self.remote.write_fmt(format_args!("{}.{}.app.{}.{}:{}|g\n", self.prefix, self.origin, key.0, key.1, value))
          }
        },
        MetricData::Count(value) => {
          if value == 0 {
            stored_metric.last_sent = now;
          }

          let res = if self.use_tagged_metrics {
            self.remote.write_fmt(format_args!("{}.app.{},origin={},app_id={}:{}|c\n", self.prefix, key.1, self.origin, key.0, value))
          } else {
            self.remote.write_fmt(format_args!("{}.{}.app.{}.{}:{}|c\n", self.prefix, self.origin, key.0, key.1, value))
          };

          if res.is_ok() {
            stored_metric.data = MetricData::Count(0);
          }

          res
        },
        _ => {Ok(())}
      };

      match res {
        Ok(()) => {
          stored_metric.last_sent = now;
        },
        Err(e) => match e.kind() {
          ErrorKind::WriteZero => {
            self.remote.flush();
          },
          ErrorKind::WouldBlock => {
            error!("WouldBlock while writing app metrics to socket");
            self.is_writable = false;
            break;
          },
          e => {
            error!("metrics socket write error={:?}", e);
            break;
          },
        }
      }
    }
    }

    self.remote.flush();

    if self.is_writable {
    for (ref key, ref mut stored_metric) in self.backend_data.iter_mut().filter(|&(_, ref value)| now.duration_since(value.last_sent) > secs) {
      //info!("will write {} -> {:#?}", key, stored_metric);
      let res = match stored_metric.data {
        MetricData::Gauge(value) => {
          if self.use_tagged_metrics {
            self.remote.write_fmt(format_args!("{}.backend.{},origin={},app_id={},backend_id={}:{}|g\n", self.prefix, key.2, self.origin, key.0, key.1, value))
          } else {
            self.remote.write_fmt(format_args!("{}.{}.app.{}.backend.{}.{}:{}|g\n", self.prefix, self.origin, key.0, key.1, key.2, value))
          }
        },
        MetricData::Count(value) => {
          if value == 0 {
            stored_metric.last_sent = now;
          }

          let res = if self.use_tagged_metrics {
            self.remote.write_fmt(format_args!("{}.app.{},origin={},app_id={},backend_id={}:{}|c\n", self.prefix, key.2, self.origin, key.0, key.1, value))
          } else {
            self.remote.write_fmt(format_args!("{}.{}.app.{}.backend.{}.{}:{}|c\n", self.prefix, self.origin, key.0, key.1, key.2, value))
          };

          if res.is_ok() {
            stored_metric.data = MetricData::Count(0);
          }

          res
        },
        _ => {Ok(())}
      };

      match res {
        Ok(()) => {
          stored_metric.last_sent = now;
        },
        Err(e) => match e.kind() {
          ErrorKind::WriteZero => {
            self.remote.flush();
          },
          ErrorKind::WouldBlock => {
            error!("WouldBlock while writing backend metrics to socket");
            self.is_writable = false;
            break;
          },
          e => {
            error!("metrics socket write error={:?}", e);
            break;
          },
        }
      }
    }
    }
    self.remote.flush();

    if self.is_writable {
    for metric in self.queue.drain(..) {
       let res = match (metric.app_id, metric.backend_id) {
        (Some(app_id), Some(backend_id)) => {
          if self.use_tagged_metrics {
            self.buffer.write_fmt(format_args!("{}.backend.{},origin={},app_id={},backend_id={}:{}|ms\n", self.prefix, metric.label,
              self.origin, app_id, backend_id, metric.duration))
          } else {
            self.buffer.write_fmt(format_args!("{}.{}.app.{}.backend.{}.{}:{}|ms\n", self.prefix, self.origin, app_id, backend_id,
              metric.label, metric.duration))
          }
        },
        (Some(app_id), None) => {
          if self.use_tagged_metrics {
            self.buffer.write_fmt(format_args!("{}.app.{},origin={},app_id={}:{}|ms\n", self.prefix, metric.label,
              self.origin, app_id, metric.duration))
          } else {
            self.buffer.write_fmt(format_args!("{}.{}.app.{}.{}:{}|ms\n", self.prefix, self.origin, app_id,
              metric.label, metric.duration))
          }
        },
        (None, None) => {
          if self.use_tagged_metrics {
            self.buffer.write_fmt(format_args!("{}.{},origin={},:{}|ms\n", self.prefix, metric.label,
              self.origin, metric.duration))
          } else {
            self.buffer.write_fmt(format_args!("{}.{}.{}:{}|ms\n", self.prefix, self.origin,
              metric.label, metric.duration))
          }
        },
        _ => { Ok(()) }
      };

      match res {
        Ok(()) => {
        },
        Err(e) => match e.kind() {
          ErrorKind::WriteZero => {
            self.remote.flush();
          },
          ErrorKind::WouldBlock => {
            error!("WouldBlock while writing timing metrics to socket");
            self.is_writable = false;
            break;
          },
          e => {
            error!("metrics socket write error={:?}", e);
            break;
          },
        }
      }
    }
    self.remote.flush();
    }
  }
}

impl Subscriber for NetworkDrain {
  fn receive_metric(&mut self, key: &'static str, app_id: Option<&str>, backend_id: Option<&str>, metric: MetricData) {
    if metric.is_time() {
      if let MetricData::Time(millis) = metric {
        self.queue.push_back(MetricLine {
          label: key,
          app_id: app_id.map(|s| s.to_string()),
          backend_id: backend_id.map(|s| s.to_string()),
          duration: millis,
        });
      }
    } else {
      if let Some(id) = app_id {
        if let Some(bid) = backend_id {
          let k = (String::from(id), String::from(bid), String::from(key));
          if !self.backend_data.contains_key(&k) {
            self.backend_data.insert(
              k,
              StoredMetricData::new(self.created, metric)
            );
          } else {
            self.backend_data.get_mut(&k).map(|stored_metric| {
              stored_metric.data.update(key, metric);
            });
          }
        } else {
          let k = (String::from(id), String::from(key));
          if !self.app_data.contains_key(&k) {
            self.app_data.insert(
              k,
              StoredMetricData::new(self.created, metric)
            );
          } else {
            self.app_data.get_mut(&k).map(|stored_metric| {
              stored_metric.data.update(key, metric);
            });
          }
        }
      } else {
        if !self.data.contains_key(key) {
          self.data.insert(
            String::from(key),
            StoredMetricData::new(self.created, metric)
          );
        } else {
          self.data.get_mut(key).map(|stored_metric| {
            stored_metric.data.update(key, metric);
          });
        }
      }
    }
  }
}

<commit_msg>add the version as label to the metrics<commit_after>use std::str;
use std::thread;
use std::sync::Mutex;
use std::cell::RefCell;
use std::time::{Duration,Instant};
use std::iter::repeat;
use std::collections::BTreeMap;
use std::collections::VecDeque;
use std::fmt::Arguments;
use std::net::SocketAddr;
use mio::net::UdpSocket;
use std::io::{self,BufWriter,Write,Error,ErrorKind};
use nom::HexDisplay;
use hdrhistogram::Histogram;
use sozu_command::buffer::Buffer;
use sozu_command::messages::{FilteredData,MetricsData,Percentiles,BackendMetricsData,FilteredTimeSerie};

use super::{Subscriber,MetricData,StoredMetricData};

const VERSION: &'static str = env!("CARGO_PKG_VERSION");

#[derive(Debug,Clone,PartialEq)]
pub struct MetricLine {
  label:      &'static str,
  app_id:     Option<String>,
  backend_id: Option<String>,
  /// in milliseconds
  duration:   usize,
}

pub struct MetricSocket {
  pub addr:   SocketAddr,
  pub socket: UdpSocket,
}

impl Write for MetricSocket {
  fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
    self.socket.send_to(buf, &self.addr)
  }

  fn flush(&mut self) -> io::Result<()> {
    Ok(())
  }
}

pub struct NetworkDrain {
  queue:              VecDeque<MetricLine>,
  buffer:             Buffer,
  pub prefix:         String,
  pub remote:         BufWriter<MetricSocket>,
  is_writable:        bool,
  data:               BTreeMap<String, StoredMetricData>,
  /// (app_id, key) -> metric
  app_data:           BTreeMap<(String, String), StoredMetricData>,
  /// (app_id, backend_id, key) -> metric
  backend_data:       BTreeMap<(String, String, String), StoredMetricData>,
  pub use_tagged_metrics: bool,
  pub origin:         String,
  created:            Instant,
}

impl NetworkDrain {
  pub fn new(prefix: String, socket: UdpSocket, addr: SocketAddr) -> Self {
    NetworkDrain {
      queue:  VecDeque::new(),
      buffer: Buffer::with_capacity(2048),
      prefix: prefix,
      remote: BufWriter::new(MetricSocket {
        addr, socket
      }),
      is_writable: true,
      data: BTreeMap::new(),
      app_data: BTreeMap::new(),
      backend_data: BTreeMap::new(),
      use_tagged_metrics: false,
      origin: String::from("x"),
      created: Instant::now(),
    }
  }

  pub fn writable(&mut self) {
    self.is_writable = true;
  }

  pub fn send_data(&mut self) {
    let now  = Instant::now();
    let secs = Duration::new(2, 0);

    if self.is_writable {
    for (ref key, ref mut stored_metric) in self.data.iter_mut().filter(|&(_, ref value)| now.duration_since(value.last_sent) > secs) {
      //info!("will write {} -> {:#?}", key, stored_metric);
      let res = match stored_metric.data {
        MetricData::Gauge(value) => {
          if self.use_tagged_metrics {
            self.remote.write_fmt(format_args!("{}.{},origin={},version={}:{}|g\n", self.prefix, key, self.origin, VERSION, value))
          } else {
            self.remote.write_fmt(format_args!("{}.{}.{}:{}|g\n", self.prefix, self.origin, key, value))
          }
        },
        MetricData::Count(value) => {
          if value == 0 {
            stored_metric.last_sent = now;
          }

          let res = if self.use_tagged_metrics {
            self.remote.write_fmt(format_args!("{}.{},origin={},version={}:{}|c\n", self.prefix, key, self.origin, VERSION, value))
          } else {
            self.remote.write_fmt(format_args!("{}.{}.{}:{}|c\n", self.prefix, self.origin, key, value))
          };

          if res.is_ok() {
            stored_metric.data = MetricData::Count(0);
          }

          res
        },
        _ => {Ok(())}
      };

      match res {
        Ok(()) => {
          stored_metric.last_sent = now;
        },
        Err(e) => match e.kind() {
          ErrorKind::WriteZero => {
            self.remote.flush();
          },
          ErrorKind::WouldBlock => {
            error!("WouldBlock while writing global metrics to socket");
            self.is_writable = false;
            break;
          },
          e => {
            error!("metrics socket write error={:?}", e);
            break;
          },
        }
      }
    }
    }

    self.remote.flush();

    if self.is_writable {
    for (ref key, ref mut stored_metric) in self.app_data.iter_mut().filter(|&(_, ref value)| now.duration_since(value.last_sent) > secs) {
      //info!("will write {} -> {:#?}", key, stored_metric);
      let res = match stored_metric.data {
        MetricData::Gauge(value) => {
          if self.use_tagged_metrics {
            self.remote.write_fmt(format_args!("{}.app.{},origin={},version={},app_id={}:{}|g\n",
              self.prefix, key.1, self.origin, VERSION, key.0, value))
          } else {
            self.remote.write_fmt(format_args!("{}.{}.app.{}.{}:{}|g\n", self.prefix, self.origin, key.0, key.1, value))
          }
        },
        MetricData::Count(value) => {
          if value == 0 {
            stored_metric.last_sent = now;
          }

          let res = if self.use_tagged_metrics {
            self.remote.write_fmt(format_args!("{}.app.{},origin={},version={},app_id={}:{}|c\n",
              self.prefix, key.1, self.origin, VERSION, key.0, value))
          } else {
            self.remote.write_fmt(format_args!("{}.{}.app.{}.{}:{}|c\n", self.prefix, self.origin, key.0, key.1, value))
          };

          if res.is_ok() {
            stored_metric.data = MetricData::Count(0);
          }

          res
        },
        _ => {Ok(())}
      };

      match res {
        Ok(()) => {
          stored_metric.last_sent = now;
        },
        Err(e) => match e.kind() {
          ErrorKind::WriteZero => {
            self.remote.flush();
          },
          ErrorKind::WouldBlock => {
            error!("WouldBlock while writing app metrics to socket");
            self.is_writable = false;
            break;
          },
          e => {
            error!("metrics socket write error={:?}", e);
            break;
          },
        }
      }
    }
    }

    self.remote.flush();

    if self.is_writable {
    for (ref key, ref mut stored_metric) in self.backend_data.iter_mut().filter(|&(_, ref value)| now.duration_since(value.last_sent) > secs) {
      //info!("will write {} -> {:#?}", key, stored_metric);
      let res = match stored_metric.data {
        MetricData::Gauge(value) => {
          if self.use_tagged_metrics {
            self.remote.write_fmt(format_args!("{}.backend.{},origin={},version={},app_id={},backend_id={}:{}|g\n",
              self.prefix, key.2, self.origin, VERSION, key.0, key.1, value))
          } else {
            self.remote.write_fmt(format_args!("{}.{}.app.{}.backend.{}.{}:{}|g\n", self.prefix, self.origin, key.0, key.1, key.2, value))
          }
        },
        MetricData::Count(value) => {
          if value == 0 {
            stored_metric.last_sent = now;
          }

          let res = if self.use_tagged_metrics {
            self.remote.write_fmt(format_args!("{}.app.{},origin={},version={},app_id={},backend_id={}:{}|c\n",
              self.prefix, key.2, self.origin, VERSION, key.0, key.1, value))
          } else {
            self.remote.write_fmt(format_args!("{}.{}.app.{}.backend.{}.{}:{}|c\n", self.prefix, self.origin, key.0, key.1, key.2, value))
          };

          if res.is_ok() {
            stored_metric.data = MetricData::Count(0);
          }

          res
        },
        _ => {Ok(())}
      };

      match res {
        Ok(()) => {
          stored_metric.last_sent = now;
        },
        Err(e) => match e.kind() {
          ErrorKind::WriteZero => {
            self.remote.flush();
          },
          ErrorKind::WouldBlock => {
            error!("WouldBlock while writing backend metrics to socket");
            self.is_writable = false;
            break;
          },
          e => {
            error!("metrics socket write error={:?}", e);
            break;
          },
        }
      }
    }
    }
    self.remote.flush();

    if self.is_writable {
    for metric in self.queue.drain(..) {
       let res = match (metric.app_id, metric.backend_id) {
        (Some(app_id), Some(backend_id)) => {
          if self.use_tagged_metrics {
            self.buffer.write_fmt(format_args!("{}.backend.{},origin={},version={},app_id={},backend_id={}:{}|ms\n",
              self.prefix, metric.label, self.origin, VERSION, app_id, backend_id, metric.duration))
          } else {
            self.buffer.write_fmt(format_args!("{}.{}.app.{}.backend.{}.{}:{}|ms\n", self.prefix, self.origin, app_id, backend_id,
              metric.label, metric.duration))
          }
        },
        (Some(app_id), None) => {
          if self.use_tagged_metrics {
            self.buffer.write_fmt(format_args!("{}.app.{},origin={},version={},app_id={}:{}|ms\n",
              self.prefix, metric.label, self.origin, VERSION, app_id, metric.duration))
          } else {
            self.buffer.write_fmt(format_args!("{}.{}.app.{}.{}:{}|ms\n", self.prefix, self.origin, app_id,
              metric.label, metric.duration))
          }
        },
        (None, None) => {
          if self.use_tagged_metrics {
            self.buffer.write_fmt(format_args!("{}.{},origin={},version={}:{}|ms\n",
              self.prefix, metric.label, self.origin, VERSION, metric.duration))
          } else {
            self.buffer.write_fmt(format_args!("{}.{}.{}:{}|ms\n", self.prefix, self.origin,
              metric.label, metric.duration))
          }
        },
        _ => { Ok(()) }
      };

      match res {
        Ok(()) => {
        },
        Err(e) => match e.kind() {
          ErrorKind::WriteZero => {
            self.remote.flush();
          },
          ErrorKind::WouldBlock => {
            error!("WouldBlock while writing timing metrics to socket");
            self.is_writable = false;
            break;
          },
          e => {
            error!("metrics socket write error={:?}", e);
            break;
          },
        }
      }
    }
    self.remote.flush();
    }
  }
}

impl Subscriber for NetworkDrain {
  fn receive_metric(&mut self, key: &'static str, app_id: Option<&str>, backend_id: Option<&str>, metric: MetricData) {
    if metric.is_time() {
      if let MetricData::Time(millis) = metric {
        self.queue.push_back(MetricLine {
          label: key,
          app_id: app_id.map(|s| s.to_string()),
          backend_id: backend_id.map(|s| s.to_string()),
          duration: millis,
        });
      }
    } else {
      if let Some(id) = app_id {
        if let Some(bid) = backend_id {
          let k = (String::from(id), String::from(bid), String::from(key));
          if !self.backend_data.contains_key(&k) {
            self.backend_data.insert(
              k,
              StoredMetricData::new(self.created, metric)
            );
          } else {
            self.backend_data.get_mut(&k).map(|stored_metric| {
              stored_metric.data.update(key, metric);
            });
          }
        } else {
          let k = (String::from(id), String::from(key));
          if !self.app_data.contains_key(&k) {
            self.app_data.insert(
              k,
              StoredMetricData::new(self.created, metric)
            );
          } else {
            self.app_data.get_mut(&k).map(|stored_metric| {
              stored_metric.data.update(key, metric);
            });
          }
        }
      } else {
        if !self.data.contains_key(key) {
          self.data.insert(
            String::from(key),
            StoredMetricData::new(self.created, metric)
          );
        } else {
          self.data.get_mut(key).map(|stored_metric| {
            stored_metric.data.update(key, metric);
          });
        }
      }
    }
  }
}

<|endoftext|>


<commit_before>//! Test Driven Learning Project.
//! Desenvolva TDD e programação com TDD e programação!
//! Módulo novice.
//!
//! The MIT License (MIT)
//!
//! Copyright (c) 2016 Paulo Henrique Rodrigues Pinheiro <paulo@sysincloud.it>
//!
//! Permission is hereby granted, free of charge, to any person obtaining a copy
//! of this software and associated documentation files (the "Software"), to deal
//! in the Software without restriction, including without limitation the rights
//! to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//! copies of the Software, and to permit persons to whom the Software is
//! furnished to do so, subject to the following conditions:
//!
//! The above copyright notice and this permission notice shall be included in all
//! copies or substantial portions of the Software.
//!
//! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//! IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//! FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//! AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//! LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//! OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//! SOFTWARE.

use std::collections::HashSet;

/// A função `negue` deve receber um valor boleano (verdadeiro ou falso) e
/// retornar a negação desse valor.
///
/// # Examples
///
/// ```
/// extern crate rust;
/// assert_eq!(true, rust::problems::negue(false));
/// assert_eq!(false, rust::problems::negue(true));
/// ```
pub fn negue(value:bool) -> bool {
    !value
}

/// A função `diga_ola` deve ser escrita de tal forma que receba como
/// parâmetro um argumento *string*. Deve retornar a *string* "Olá, ", seguida
/// do argumento recebido, mais um ponto final. A *string* recebida deve estar
/// limpa, ou seja, sem caracteres de espaço no começo ou no fim. Se a *string*
/// estiver vazia, retorna apenas "Olá!"
///
/// # Examples
///
/// ```
/// extern crate rust;
///
/// assert_eq!("Olá!", rust::problems::diga_ola(""));
/// assert_eq!("Olá!", rust::problems::diga_ola("    "));
/// assert_eq!("Olá, Paulo.", rust::problems::diga_ola("Paulo"));
/// assert_eq!("Olá, Paulo.", rust::problems::diga_ola("  Paulo  "));
/// assert_eq!("Olá, Paulo Henrique.", rust::problems::diga_ola("  Paulo Henrique  "));
/// ```
pub fn diga_ola(nome:&str) -> String {
    let nome_limpo = nome.trim();

    if nome_limpo.is_empty() {
        return "Olá!".to_string();
    }

    format!("Olá, {}.", &nome_limpo)
}

/// A função `lista_numeros_pares` deve receber um parâmetro numérico
/// inteiro que determina quantos números pares devem estar em um array que
/// será o retorno da função.
///
/// Examples
///
/// ```
/// extern crate rust;
///
/// assert_eq!(0, rust::problems::lista_numeros_pares(0).len());
/// assert_eq!(vec![2], rust::problems::lista_numeros_pares(1));
/// assert_eq!(vec![2, 4, 6, 8], rust::problems::lista_numeros_pares(4));
/// assert_eq!(vec![2, 4, 6, 8, 10], rust::problems::lista_numeros_pares(5));
/// assert_eq!(0, rust::problems::lista_numeros_pares(-1).len());
/// ```
pub fn lista_numeros_pares(quantos:i32) -> Vec<i32> {
    (1..quantos+1).map(|x| x*2).collect::<Vec<i32>>()
}

/// A função `lista_multiplos` deve receber dois parâmetros numéricos
/// inteiros e retornar uma lista de números inteiros. O tamanho da lista é
/// determinado pelo primeiro parâmetro, e o número base será o segundo
/// parâmetro.
///
/// Examples
///
/// ```
/// extern crate rust;
///
/// assert_eq!(0, rust::problems::lista_multiplos(0, 10).len());
/// assert_eq!(0, rust::problems::lista_multiplos(-1, 10).len());
/// assert_eq!(vec![-3, -2, -1], rust::problems::lista_multiplos(3, -1));
/// assert_eq!(0, rust::problems::lista_multiplos(3, 0).len());
/// assert_eq!(vec![10, 20, 30], rust::problems::lista_multiplos(3, 10));
/// ```
pub fn lista_multiplos(quantos:i32, base:i32) -> Vec<i32> {
    if base == 0 {
        return vec![];
    }

    let mut response = (1..quantos+1).map(|x| x*base).collect::<Vec<i32>>();

    if base < 1 {
        response.reverse();
    }

    response
}

/// A função `soma` deve receber um *array* de números inteiros, e retornar
/// a sua soma. Se a lista for vazia, deve retornar zero.
///
/// Examples
///
/// ```
/// extern crate rust;
///
/// assert_eq!(0, rust::problems::soma(vec![]));
/// assert_eq!(1, rust::problems::soma(vec![1]));
/// assert_eq!(3, rust::problems::soma(vec![1, 2]));
/// ```
pub fn soma(lista:Vec<i32>) -> i32 {
    lista.iter().fold(0, |result, x| result + x)
}

/// A função `subtracao` deve receber um *array* de números inteiros, e
/// retornar a subtração de todos os elementos em sequência. Por exemplo,
/// subtracao([3,2,1]) deve retornar 0, e subtracao([10,2,3]) deve retornar 5.
/// Se a lista for vazia, deve retornar zero.
///
/// Examples
///
/// ```
/// extern crate rust;
///
/// assert_eq!(0, rust::problems::subtracao(vec![3, 2, 1]));
/// assert_eq!(5, rust::problems::subtracao(vec![10, 2, 3]));
/// assert_eq!(0, rust::problems::subtracao(vec![]));
/// assert_eq!(-1, rust::problems::subtracao(vec![1, 2]));
/// assert_eq!(4, rust::problems::subtracao(vec![-1, -2, -3]));
/// assert_eq!(3, rust::problems::subtracao(vec![9, 3, 2, 1]));
/// ```
pub fn subtracao(lista:Vec<i32>) -> i32 {
    if lista.len() < 1 {
        return 0;
    }

    lista[1..lista.len()].iter().fold(lista[0], |result, x| result - x)
}

/// A função `multiplicação` deve receber um *array* de números inteiros, e
/// retornar o seu produto. Se a lista for vazia, deve retornar zero.
///
/// Examples
///
/// ```
/// extern crate rust;
///
/// assert_eq!(6, rust::problems::multiplicacao(vec![1, 2, 3]));
/// assert_eq!(0, rust::problems::multiplicacao(vec![]));
/// assert_eq!(-8, rust::problems::multiplicacao(vec![-2, 1, 4]));
/// assert_eq!(8, rust::problems::multiplicacao(vec![-2, -1, 4]));
pub fn multiplicacao(lista:Vec<i32>) -> i32 {
    if lista.len() < 1 {
        return 0;
    }

    lista.iter().fold(1, |result, x| result * x)
}

/// A função `divisao` deve receber um *array* de números inteiros, e
/// retornar o resultado da sequência de divisões por cada elemento. Por
/// exemplo, divisão([16, 4, 2]) deve retornar 2, e divisão([100,2,10]) deve
/// retornar 5. Se a lista for vazia, deve retornar zero.
///
/// Examples
///
/// ```
/// extern crate rust;
///
/// assert_eq!(2, rust::problems::divisao(vec![5, 2]));
/// assert_eq!(0, rust::problems::divisao(vec![]));
/// assert_eq!(0, rust::problems::divisao(vec![0]));
/// assert_eq!(2, rust::problems::divisao(vec![16, 4, 2]));
/// assert_eq!(5, rust::problems::divisao(vec![100, 2, 10]));
/// assert_eq!(0, rust::problems::divisao(vec![0, 1]));
/// //assert_eq!(0, rust::problems::divisao(vec![1, 0]));
pub fn divisao(lista:Vec<i32>) ->i32 {
    if lista.len() < 1 {
        return 0;
    }

    lista[1..lista.len()].iter().fold(lista[0], |result, x| result / x)
}

/// A função `maior` deve receber um *array* de números inteiros e retornar
/// qual é o maior deles.
///
/// Examples
///
/// ```
/// extern crate rust;
///
/// assert_eq!(100, rust::problems::maior(vec![0, 1 ,100]));
/// assert_eq!(0, rust::problems::maior(vec![0]));
pub fn maior(lista:Vec<i32>)-> i32 {
    lista.iter().fold(lista[0], |result, x| if *x > result {*x} else {result})
}

/// A função `intersecao` deve receber dois *arrays* contendo números
/// inteiros, e retornar a interseção entre os conjuntos, ou seja, um *array*
/// que contenha apenas os números que estejam contidos nos dois *arrays*
/// passados para a função.
///
/// Examples
///
/// ```
/// assert_eq!(0, rust::problems::intersecao(vec![], vec![]).len());
/// assert_eq!(0, rust::problems::intersecao(vec![1, 2], vec![3, 4]).len());
/// assert_eq!(vec![2], rust::problems::intersecao(vec![1, 2], vec![2, 3]));
pub fn intersecao(a:Vec<i32>, b:Vec<i32>) -> Vec<i32> {
    let _a:HashSet<i32> = a.iter().cloned().collect();
    let _b:HashSet<i32> = b.iter().cloned().collect();

    _a.intersection(&_b).cloned().collect::<Vec<i32>>()
}
<commit_msg>Utiliza o metodo para ver se o vetor esta vazio.<commit_after>//! Test Driven Learning Project.
//! Desenvolva TDD e programação com TDD e programação!
//! Módulo novice.
//!
//! The MIT License (MIT)
//!
//! Copyright (c) 2016 Paulo Henrique Rodrigues Pinheiro <paulo@sysincloud.it>
//!
//! Permission is hereby granted, free of charge, to any person obtaining a copy
//! of this software and associated documentation files (the "Software"), to deal
//! in the Software without restriction, including without limitation the rights
//! to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//! copies of the Software, and to permit persons to whom the Software is
//! furnished to do so, subject to the following conditions:
//!
//! The above copyright notice and this permission notice shall be included in all
//! copies or substantial portions of the Software.
//!
//! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//! IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//! FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//! AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//! LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//! OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//! SOFTWARE.

use std::collections::HashSet;

/// A função `negue` deve receber um valor boleano (verdadeiro ou falso) e
/// retornar a negação desse valor.
///
/// # Examples
///
/// ```
/// extern crate rust;
/// assert_eq!(true, rust::problems::negue(false));
/// assert_eq!(false, rust::problems::negue(true));
/// ```
pub fn negue(value:bool) -> bool {
    !value
}

/// A função `diga_ola` deve ser escrita de tal forma que receba como
/// parâmetro um argumento *string*. Deve retornar a *string* "Olá, ", seguida
/// do argumento recebido, mais um ponto final. A *string* recebida deve estar
/// limpa, ou seja, sem caracteres de espaço no começo ou no fim. Se a *string*
/// estiver vazia, retorna apenas "Olá!"
///
/// # Examples
///
/// ```
/// extern crate rust;
///
/// assert_eq!("Olá!", rust::problems::diga_ola(""));
/// assert_eq!("Olá!", rust::problems::diga_ola("    "));
/// assert_eq!("Olá, Paulo.", rust::problems::diga_ola("Paulo"));
/// assert_eq!("Olá, Paulo.", rust::problems::diga_ola("  Paulo  "));
/// assert_eq!("Olá, Paulo Henrique.", rust::problems::diga_ola("  Paulo Henrique  "));
/// ```
pub fn diga_ola(nome:&str) -> String {
    let nome_limpo = nome.trim();

    if nome_limpo.is_empty() {
        return "Olá!".to_string();
    }

    format!("Olá, {}.", &nome_limpo)
}

/// A função `lista_numeros_pares` deve receber um parâmetro numérico
/// inteiro que determina quantos números pares devem estar em um array que
/// será o retorno da função.
///
/// Examples
///
/// ```
/// extern crate rust;
///
/// assert_eq!(0, rust::problems::lista_numeros_pares(0).len());
/// assert_eq!(vec![2], rust::problems::lista_numeros_pares(1));
/// assert_eq!(vec![2, 4, 6, 8], rust::problems::lista_numeros_pares(4));
/// assert_eq!(vec![2, 4, 6, 8, 10], rust::problems::lista_numeros_pares(5));
/// assert_eq!(0, rust::problems::lista_numeros_pares(-1).len());
/// ```
pub fn lista_numeros_pares(quantos:i32) -> Vec<i32> {
    (1..quantos+1).map(|x| x*2).collect::<Vec<i32>>()
}

/// A função `lista_multiplos` deve receber dois parâmetros numéricos
/// inteiros e retornar uma lista de números inteiros. O tamanho da lista é
/// determinado pelo primeiro parâmetro, e o número base será o segundo
/// parâmetro.
///
/// Examples
///
/// ```
/// extern crate rust;
///
/// assert_eq!(0, rust::problems::lista_multiplos(0, 10).len());
/// assert_eq!(0, rust::problems::lista_multiplos(-1, 10).len());
/// assert_eq!(vec![-3, -2, -1], rust::problems::lista_multiplos(3, -1));
/// assert_eq!(0, rust::problems::lista_multiplos(3, 0).len());
/// assert_eq!(vec![10, 20, 30], rust::problems::lista_multiplos(3, 10));
/// ```
pub fn lista_multiplos(quantos:i32, base:i32) -> Vec<i32> {
    if base == 0 {
        return vec![];
    }

    let mut response = (1..quantos+1).map(|x| x*base).collect::<Vec<i32>>();

    if base < 1 {
        response.reverse();
    }

    response
}

/// A função `soma` deve receber um *array* de números inteiros, e retornar
/// a sua soma. Se a lista for vazia, deve retornar zero.
///
/// Examples
///
/// ```
/// extern crate rust;
///
/// assert_eq!(0, rust::problems::soma(vec![]));
/// assert_eq!(1, rust::problems::soma(vec![1]));
/// assert_eq!(3, rust::problems::soma(vec![1, 2]));
/// ```
pub fn soma(lista:Vec<i32>) -> i32 {
    lista.iter().fold(0, |result, x| result + x)
}

/// A função `subtracao` deve receber um *array* de números inteiros, e
/// retornar a subtração de todos os elementos em sequência. Por exemplo,
/// subtracao([3,2,1]) deve retornar 0, e subtracao([10,2,3]) deve retornar 5.
/// Se a lista for vazia, deve retornar zero.
///
/// Examples
///
/// ```
/// extern crate rust;
///
/// assert_eq!(0, rust::problems::subtracao(vec![3, 2, 1]));
/// assert_eq!(5, rust::problems::subtracao(vec![10, 2, 3]));
/// assert_eq!(0, rust::problems::subtracao(vec![]));
/// assert_eq!(-1, rust::problems::subtracao(vec![1, 2]));
/// assert_eq!(4, rust::problems::subtracao(vec![-1, -2, -3]));
/// assert_eq!(3, rust::problems::subtracao(vec![9, 3, 2, 1]));
/// ```
pub fn subtracao(lista:Vec<i32>) -> i32 {
    if lista.is_empty() {
        return 0;
    }

    lista[1..lista.len()].iter().fold(lista[0], |result, x| result - x)
}

/// A função `multiplicação` deve receber um *array* de números inteiros, e
/// retornar o seu produto. Se a lista for vazia, deve retornar zero.
///
/// Examples
///
/// ```
/// extern crate rust;
///
/// assert_eq!(6, rust::problems::multiplicacao(vec![1, 2, 3]));
/// assert_eq!(0, rust::problems::multiplicacao(vec![]));
/// assert_eq!(-8, rust::problems::multiplicacao(vec![-2, 1, 4]));
/// assert_eq!(8, rust::problems::multiplicacao(vec![-2, -1, 4]));
pub fn multiplicacao(lista:Vec<i32>) -> i32 {
    if lista.is_empty() {
        return 0;
    }

    lista.iter().fold(1, |result, x| result * x)
}

/// A função `divisao` deve receber um *array* de números inteiros, e
/// retornar o resultado da sequência de divisões por cada elemento. Por
/// exemplo, divisão([16, 4, 2]) deve retornar 2, e divisão([100,2,10]) deve
/// retornar 5. Se a lista for vazia, deve retornar zero.
///
/// Examples
///
/// ```
/// extern crate rust;
///
/// assert_eq!(2, rust::problems::divisao(vec![5, 2]));
/// assert_eq!(0, rust::problems::divisao(vec![]));
/// assert_eq!(0, rust::problems::divisao(vec![0]));
/// assert_eq!(2, rust::problems::divisao(vec![16, 4, 2]));
/// assert_eq!(5, rust::problems::divisao(vec![100, 2, 10]));
/// assert_eq!(0, rust::problems::divisao(vec![0, 1]));
/// //assert_eq!(0, rust::problems::divisao(vec![1, 0]));
pub fn divisao(lista:Vec<i32>) ->i32 {
    if lista.is_empty() {
        return 0;
    }

    lista[1..lista.len()].iter().fold(lista[0], |result, x| result / x)
}

/// A função `maior` deve receber um *array* de números inteiros e retornar
/// qual é o maior deles.
///
/// Examples
///
/// ```
/// extern crate rust;
///
/// assert_eq!(100, rust::problems::maior(vec![0, 1 ,100]));
/// assert_eq!(0, rust::problems::maior(vec![0]));
pub fn maior(lista:Vec<i32>)-> i32 {
    lista.iter().fold(lista[0], |result, x| if *x > result {*x} else {result})
}

/// A função `intersecao` deve receber dois *arrays* contendo números
/// inteiros, e retornar a interseção entre os conjuntos, ou seja, um *array*
/// que contenha apenas os números que estejam contidos nos dois *arrays*
/// passados para a função.
///
/// Examples
///
/// ```
/// assert_eq!(0, rust::problems::intersecao(vec![], vec![]).len());
/// assert_eq!(0, rust::problems::intersecao(vec![1, 2], vec![3, 4]).len());
/// assert_eq!(vec![2], rust::problems::intersecao(vec![1, 2], vec![2, 3]));
pub fn intersecao(a:Vec<i32>, b:Vec<i32>) -> Vec<i32> {
    let _a:HashSet<i32> = a.iter().cloned().collect();
    let _b:HashSet<i32> = b.iter().cloned().collect();

    _a.intersection(&_b).cloned().collect::<Vec<i32>>()
}
<|endoftext|>


<commit_before>// compile-flags: -O
// only-x86_64

#![crate_type = "lib"]

// CHECK-LABEL: @slice_reverse_u8
#[no_mangle]
pub fn slice_reverse_u8(slice: &mut [u8]) {
    // CHECK-NOT: panic_bounds_check
    // CHECK-NOT: slice_end_index_len_fail
    // CHECK: shufflevector <{{[0-9]+}} x i8>
    // CHECK-NOT: panic_bounds_check
    // CHECK-NOT: slice_end_index_len_fail
    slice.reverse();
}

// CHECK-LABEL: @slice_reverse_i32
#[no_mangle]
pub fn slice_reverse_i32(slice: &mut [i32]) {
    // CHECK-NOT: panic_bounds_check
    // CHECK-NOT: slice_end_index_len_fail
    // CHECK: shufflevector <{{[0-9]+}} x i32>
    // CHECK-NOT: panic_bounds_check
    // CHECK-NOT: slice_end_index_len_fail
    slice.reverse();
}
<commit_msg>Don't run the codegen test when `debug_assert` is enabled<commit_after>// compile-flags: -O
// only-x86_64
// ignore-debug: the debug assertions in from_raw_parts get in the way

#![crate_type = "lib"]

// CHECK-LABEL: @slice_reverse_u8
#[no_mangle]
pub fn slice_reverse_u8(slice: &mut [u8]) {
    // CHECK-NOT: panic_bounds_check
    // CHECK-NOT: slice_end_index_len_fail
    // CHECK: shufflevector <{{[0-9]+}} x i8>
    // CHECK-NOT: panic_bounds_check
    // CHECK-NOT: slice_end_index_len_fail
    slice.reverse();
}

// CHECK-LABEL: @slice_reverse_i32
#[no_mangle]
pub fn slice_reverse_i32(slice: &mut [i32]) {
    // CHECK-NOT: panic_bounds_check
    // CHECK-NOT: slice_end_index_len_fail
    // CHECK: shufflevector <{{[0-9]+}} x i32>
    // CHECK-NOT: panic_bounds_check
    // CHECK-NOT: slice_end_index_len_fail
    slice.reverse();
}
<|endoftext|>


<commit_before>use ::inflector::Inflector;
use ::quote::Tokens;
use ::syn::Ident;
use ::yaml_rust::Yaml;

use infer::datatype;
use infer::Error;

type StructBoundArgImpl = Result<
    (Tokens, Tokens, Tokens, Tokens),
    Box<Error + Send + Sync>
>;

fn ident(param: &str) -> Ident {
    Ident::new(param.to_snake_case())
}

pub(super) fn infer_v3(struct_ident: &Ident, schema: &Yaml) -> StructBoundArgImpl {
    let mut idents: Vec<Ident> = Vec::new();
    let mut types: Vec<Tokens> = Vec::new();
    let mut name_strs: Vec<Tokens> = Vec::new();
    let mut accessors: Vec<Tokens> = Vec::new();

    for schema in schema.as_vec().unwrap() {
        let name = schema["name"].as_str()
            .expect("Parameter name must be a string.");
        let field = ident(name);
        let (param_type, _) = datatype::infer_v3(&schema["schema"])?;
        let mandate: Tokens;

        if let Some(true) = schema["required"].as_bool() {
            mandate = quote!(tapioca::datatype::Required);
        } else {
            mandate = quote!(tapioca::datatype::Optional);
        }

        idents.push(ident(name));
        types.push(quote!{ #mandate<#param_type> });
        name_strs.push(quote!{ #name });
        accessors.push(quote!{ query_parameters.#field });
    }

    Ok((
        quote! {
            pub struct #struct_ident {
                #(pub #idents: #types),*
            }
        },
        quote! {},
        quote! { query_parameters: &#struct_ident },
        quote! {
            url.query_pairs_mut()
                .clear()
                #(.append_pair(
                    #name_strs,
                    #accessors.unwrap_or("").to_string().as_str()
                ))*
                ;
        }
    ))
}
<commit_msg>Fix construction of query string<commit_after>use ::inflector::Inflector;
use ::quote::Tokens;
use ::syn::Ident;
use ::yaml_rust::Yaml;

use infer::datatype;
use infer::Error;

type StructBoundArgImpl = Result<
    (Tokens, Tokens, Tokens, Tokens),
    Box<Error + Send + Sync>
>;

fn ident(param: &str) -> Ident {
    Ident::new(param.to_snake_case())
}

pub(super) fn infer_v3(struct_ident: &Ident, schema: &Yaml) -> StructBoundArgImpl {
    let mut idents: Vec<Ident> = Vec::new();
    let mut types: Vec<Tokens> = Vec::new();
    let mut name_strs: Vec<Tokens> = Vec::new();
    let mut accessors: Vec<Tokens> = Vec::new();

    for schema in schema.as_vec().unwrap() {
        let name = schema["name"].as_str()
            .expect("Parameter name must be a string.");
        let field = ident(name);
        let (param_type, _) = datatype::infer_v3(&schema["schema"])?;
        let mandate: Tokens;

        if let Some(true) = schema["required"].as_bool() {
            mandate = quote!(tapioca::datatype::Required);
            accessors.push(quote!{ query_parameters.#field.to_string() });
        } else {
            mandate = quote!(tapioca::datatype::Optional);
            accessors.push(quote!{
                query_parameters.#field
                    .map(|p| p.to_string())
                    .unwrap_or("".to_owned())
            });
        }

        idents.push(ident(name));
        types.push(quote!{ #mandate<#param_type> });
        name_strs.push(quote!{ #name });
    }

    Ok((
        quote! {
            pub struct #struct_ident {
                #(pub #idents: #types),*
            }
        },
        quote! {},
        quote! { query_parameters: &#struct_ident },
        quote! {
            url.query_pairs_mut()
                .clear()
                #(.append_pair(#name_strs, #accessors.as_str()))*
                ;
        }
    ))
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Necessary types for [grid](https://drafts.csswg.org/css-grid/).

use cssparser::{Parser, Token};
use parser::{Parse, ParserContext};
use std::ascii::AsciiExt;
use std::fmt;
use style_traits::ToCss;
use values::{CSSFloat, HasViewportPercentage};
use values::computed::{ComputedValueAsSpecified, Context, ToComputedValue};
use values::specified::LengthOrPercentage;

#[derive(PartialEq, Clone, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A `<grid-line>` type.
///
/// https://drafts.csswg.org/css-grid/#typedef-grid-row-start-grid-line
#[allow(missing_docs)]
pub struct GridLine {
    /// Flag to check whether it's a `span` keyword.
    pub is_span: bool,
    /// A custom identifier for named lines.
    ///
    /// https://drafts.csswg.org/css-grid/#grid-placement-slot
    pub ident: Option<String>,
    /// Denotes the nth grid line from grid item's placement.
    pub integer: Option<i32>,
}

impl Default for GridLine {
    fn default() -> Self {
        GridLine {
            is_span: false,
            ident: None,
            integer: None,
        }
    }
}

impl ToCss for GridLine {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        if !self.is_span && self.ident.is_none() && self.integer.is_none() {
            return dest.write_str("auto")
        }

        if self.is_span {
            try!(dest.write_str("span"));
        }

        if let Some(i) = self.integer {
            try!(write!(dest, " {}", i));
        }

        if let Some(ref s) = self.ident {
            try!(write!(dest, " {}", s));
        }

        Ok(())
    }
}

impl Parse for GridLine {
    fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
        let mut grid_line = Default::default();
        if input.try(|i| i.expect_ident_matching("auto")).is_ok() {
            return Ok(grid_line)
        }

        for _ in 0..3 {     // Maximum possible entities for <grid-line>
            if input.try(|i| i.expect_ident_matching("span")).is_ok() {
                if grid_line.is_span {
                    return Err(())
                }
                grid_line.is_span = true;
            } else if let Ok(i) = input.try(|i| i.expect_integer()) {
                if i == 0 || grid_line.integer.is_some() {
                    return Err(())
                }
                grid_line.integer = Some(i);
            } else if let Ok(name) = input.try(|i| i.expect_ident()) {
                if grid_line.ident.is_some() {
                    return Err(())
                }
                grid_line.ident = Some(name.into_owned());
            } else {
                break
            }
        }

        if grid_line.is_span {
            if let Some(i) = grid_line.integer {
                if i < 0 {      // disallow negative integers for grid spans
                    return Err(())
                }
            } else {
                grid_line.integer = Some(1);
            }
        }

        Ok(grid_line)
    }
}

impl ComputedValueAsSpecified for GridLine {}
no_viewport_percentage!(GridLine);

define_css_keyword_enum!{ TrackKeyword:
    "auto" => Auto,
    "max-content" => MaxContent,
    "min-content" => MinContent
}

#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A track breadth for explicit grid track sizing. It's generic solely to
/// avoid re-implementing it for the computed type.
///
/// https://drafts.csswg.org/css-grid/#typedef-track-breadth
pub enum TrackBreadth<L> {
    /// The generic type is almost always a non-negative `<length-percentage>`
    Breadth(L),
    /// A flex fraction specified in `fr` units.
    Flex(CSSFloat),
    /// One of the track-sizing keywords (`auto`, `min-content`, `max-content`)
    Keyword(TrackKeyword),
}

/// Parse a single flexible length.
pub fn parse_flex(input: &mut Parser) -> Result<CSSFloat, ()> {
    match try!(input.next()) {
        Token::Dimension(ref value, ref unit) if unit.eq_ignore_ascii_case("fr") && value.value.is_sign_positive()
            => Ok(value.value),
        _ => Err(()),
    }
}

impl Parse for TrackBreadth<LengthOrPercentage> {
    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
        if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
            return Ok(TrackBreadth::Breadth(lop))
        }

        if let Ok(f) = input.try(parse_flex) {
            return Ok(TrackBreadth::Flex(f))
        }

        TrackKeyword::parse(input).map(TrackBreadth::Keyword)
    }
}

impl<L: ToCss> ToCss for TrackBreadth<L> {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        match *self {
            TrackBreadth::Breadth(ref lop) => lop.to_css(dest),
            TrackBreadth::Flex(ref value) => write!(dest, "{}fr", value),
            TrackBreadth::Keyword(ref k) => k.to_css(dest),
        }
    }
}

impl HasViewportPercentage for TrackBreadth<LengthOrPercentage> {
    #[inline]
    fn has_viewport_percentage(&self) -> bool {
        if let TrackBreadth::Breadth(ref lop) = *self {
            lop.has_viewport_percentage()
        } else {
            false
        }
    }
}

impl<L: ToComputedValue> ToComputedValue for TrackBreadth<L> {
    type ComputedValue = TrackBreadth<L::ComputedValue>;

    #[inline]
    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
        match *self {
            TrackBreadth::Breadth(ref lop) => TrackBreadth::Breadth(lop.to_computed_value(context)),
            TrackBreadth::Flex(fr) => TrackBreadth::Flex(fr),
            TrackBreadth::Keyword(k) => TrackBreadth::Keyword(k),
        }
    }

    #[inline]
    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
        match *computed {
            TrackBreadth::Breadth(ref lop) =>
                TrackBreadth::Breadth(ToComputedValue::from_computed_value(lop)),
            TrackBreadth::Flex(fr) => TrackBreadth::Flex(fr),
            TrackBreadth::Keyword(k) => TrackBreadth::Keyword(k),
        }
    }
}

#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A `<track-size>` type for explicit grid track sizing. Like `<track-breadth>`, this is
/// generic only to avoid code bloat. It only takes `<length-percentage>`
///
/// https://drafts.csswg.org/css-grid/#typedef-track-size
pub enum TrackSize<L> {
    /// A flexible `<track-breadth>`
    Breadth(TrackBreadth<L>),
    /// A `minmax` function for a range over an inflexible `<track-breadth>`
    /// and a flexible `<track-breadth>`
    ///
    /// https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-minmax
    MinMax(TrackBreadth<L>, TrackBreadth<L>),
    /// A `fit-content` function.
    ///
    /// https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-fit-content
    FitContent(L),
}

impl<L> Default for TrackSize<L> {
    fn default() -> Self {
        TrackSize::Breadth(TrackBreadth::Keyword(TrackKeyword::Auto))
    }
}

impl Parse for TrackSize<LengthOrPercentage> {
    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
        if let Ok(b) = input.try(|i| TrackBreadth::parse(context, i)) {
            return Ok(TrackSize::Breadth(b))
        }

        if input.try(|i| i.expect_function_matching("minmax")).is_ok() {
            return input.parse_nested_block(|input| {
                let inflexible_breadth =
                    match input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
                        Ok(lop) => TrackBreadth::Breadth(lop),
                        Err(..) => {
                            let keyword = try!(TrackKeyword::parse(input));
                            TrackBreadth::Keyword(keyword)
                        }
                    };

                try!(input.expect_comma());
                Ok(TrackSize::MinMax(inflexible_breadth, try!(TrackBreadth::parse(context, input))))
            });
        }

        try!(input.expect_function_matching("fit-content"));
        // FIXME(emilio): This needs a parse_nested_block, doesn't it?
        Ok(try!(LengthOrPercentage::parse(context, input).map(TrackSize::FitContent)))
    }
}

impl<L: ToCss> ToCss for TrackSize<L> {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        match *self {
            TrackSize::Breadth(ref b) => b.to_css(dest),
            TrackSize::MinMax(ref infexible, ref flexible) => {
                try!(dest.write_str("minmax("));
                try!(infexible.to_css(dest));
                try!(dest.write_str(","));
                try!(flexible.to_css(dest));
                dest.write_str(")")
            },
            TrackSize::FitContent(ref lop) => {
                try!(dest.write_str("fit-content("));
                try!(lop.to_css(dest));
                dest.write_str(")")
            },
        }
    }
}

impl HasViewportPercentage for TrackSize<LengthOrPercentage> {
    #[inline]
    fn has_viewport_percentage(&self) -> bool {
        match *self {
            TrackSize::Breadth(ref b) => b.has_viewport_percentage(),
            TrackSize::MinMax(ref inf_b, ref b) => inf_b.has_viewport_percentage() || b.has_viewport_percentage(),
            TrackSize::FitContent(ref lop) => lop.has_viewport_percentage(),
        }
    }
}

impl<L: ToComputedValue> ToComputedValue for TrackSize<L> {
    type ComputedValue = TrackSize<L::ComputedValue>;

    #[inline]
    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
        match *self {
            TrackSize::Breadth(ref b) => TrackSize::Breadth(b.to_computed_value(context)),
            TrackSize::MinMax(ref b_1, ref b_2) =>
                TrackSize::MinMax(b_1.to_computed_value(context), b_2.to_computed_value(context)),
            TrackSize::FitContent(ref lop) => TrackSize::FitContent(lop.to_computed_value(context)),
        }
    }

    #[inline]
    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
        match *computed {
            TrackSize::Breadth(ref b) =>
                TrackSize::Breadth(ToComputedValue::from_computed_value(b)),
            TrackSize::MinMax(ref b_1, ref b_2) =>
                TrackSize::MinMax(ToComputedValue::from_computed_value(b_1),
                                  ToComputedValue::from_computed_value(b_2)),
            TrackSize::FitContent(ref lop) =>
                TrackSize::FitContent(ToComputedValue::from_computed_value(lop)),
        }
    }
}
<commit_msg>Add function to parse <line-names><commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Necessary types for [grid](https://drafts.csswg.org/css-grid/).

use cssparser::{Parser, Token};
use parser::{Parse, ParserContext};
use std::ascii::AsciiExt;
use std::fmt;
use style_traits::ToCss;
use values::{CSSFloat, CustomIdent, HasViewportPercentage};
use values::computed::{ComputedValueAsSpecified, Context, ToComputedValue};
use values::specified::LengthOrPercentage;

#[derive(PartialEq, Clone, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A `<grid-line>` type.
///
/// https://drafts.csswg.org/css-grid/#typedef-grid-row-start-grid-line
pub struct GridLine {
    /// Flag to check whether it's a `span` keyword.
    pub is_span: bool,
    /// A custom identifier for named lines.
    ///
    /// https://drafts.csswg.org/css-grid/#grid-placement-slot
    pub ident: Option<String>,
    /// Denotes the nth grid line from grid item's placement.
    pub integer: Option<i32>,
}

impl Default for GridLine {
    fn default() -> Self {
        GridLine {
            is_span: false,
            ident: None,
            integer: None,
        }
    }
}

impl ToCss for GridLine {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        if !self.is_span && self.ident.is_none() && self.integer.is_none() {
            return dest.write_str("auto")
        }

        if self.is_span {
            try!(dest.write_str("span"));
        }

        if let Some(i) = self.integer {
            try!(write!(dest, " {}", i));
        }

        if let Some(ref s) = self.ident {
            try!(write!(dest, " {}", s));
        }

        Ok(())
    }
}

impl Parse for GridLine {
    fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
        let mut grid_line = Default::default();
        if input.try(|i| i.expect_ident_matching("auto")).is_ok() {
            return Ok(grid_line)
        }

        for _ in 0..3 {     // Maximum possible entities for <grid-line>
            if input.try(|i| i.expect_ident_matching("span")).is_ok() {
                if grid_line.is_span {
                    return Err(())
                }
                grid_line.is_span = true;
            } else if let Ok(i) = input.try(|i| i.expect_integer()) {
                if i == 0 || grid_line.integer.is_some() {
                    return Err(())
                }
                grid_line.integer = Some(i);
            } else if let Ok(name) = input.try(|i| i.expect_ident()) {
                if grid_line.ident.is_some() {
                    return Err(())
                }
                grid_line.ident = Some(name.into_owned());
            } else {
                break
            }
        }

        if grid_line.is_span {
            if let Some(i) = grid_line.integer {
                if i < 0 {      // disallow negative integers for grid spans
                    return Err(())
                }
            } else {
                grid_line.integer = Some(1);
            }
        }

        Ok(grid_line)
    }
}

impl ComputedValueAsSpecified for GridLine {}
no_viewport_percentage!(GridLine);

define_css_keyword_enum!{ TrackKeyword:
    "auto" => Auto,
    "max-content" => MaxContent,
    "min-content" => MinContent
}

#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A track breadth for explicit grid track sizing. It's generic solely to
/// avoid re-implementing it for the computed type.
///
/// https://drafts.csswg.org/css-grid/#typedef-track-breadth
pub enum TrackBreadth<L> {
    /// The generic type is almost always a non-negative `<length-percentage>`
    Breadth(L),
    /// A flex fraction specified in `fr` units.
    Flex(CSSFloat),
    /// One of the track-sizing keywords (`auto`, `min-content`, `max-content`)
    Keyword(TrackKeyword),
}

/// Parse a single flexible length.
pub fn parse_flex(input: &mut Parser) -> Result<CSSFloat, ()> {
    match try!(input.next()) {
        Token::Dimension(ref value, ref unit) if unit.eq_ignore_ascii_case("fr") && value.value.is_sign_positive()
            => Ok(value.value),
        _ => Err(()),
    }
}

impl Parse for TrackBreadth<LengthOrPercentage> {
    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
        if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
            return Ok(TrackBreadth::Breadth(lop))
        }

        if let Ok(f) = input.try(parse_flex) {
            return Ok(TrackBreadth::Flex(f))
        }

        TrackKeyword::parse(input).map(TrackBreadth::Keyword)
    }
}

impl<L: ToCss> ToCss for TrackBreadth<L> {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        match *self {
            TrackBreadth::Breadth(ref lop) => lop.to_css(dest),
            TrackBreadth::Flex(ref value) => write!(dest, "{}fr", value),
            TrackBreadth::Keyword(ref k) => k.to_css(dest),
        }
    }
}

impl HasViewportPercentage for TrackBreadth<LengthOrPercentage> {
    #[inline]
    fn has_viewport_percentage(&self) -> bool {
        if let TrackBreadth::Breadth(ref lop) = *self {
            lop.has_viewport_percentage()
        } else {
            false
        }
    }
}

impl<L: ToComputedValue> ToComputedValue for TrackBreadth<L> {
    type ComputedValue = TrackBreadth<L::ComputedValue>;

    #[inline]
    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
        match *self {
            TrackBreadth::Breadth(ref lop) => TrackBreadth::Breadth(lop.to_computed_value(context)),
            TrackBreadth::Flex(fr) => TrackBreadth::Flex(fr),
            TrackBreadth::Keyword(k) => TrackBreadth::Keyword(k),
        }
    }

    #[inline]
    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
        match *computed {
            TrackBreadth::Breadth(ref lop) =>
                TrackBreadth::Breadth(ToComputedValue::from_computed_value(lop)),
            TrackBreadth::Flex(fr) => TrackBreadth::Flex(fr),
            TrackBreadth::Keyword(k) => TrackBreadth::Keyword(k),
        }
    }
}

#[derive(Clone, PartialEq, Debug)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A `<track-size>` type for explicit grid track sizing. Like `<track-breadth>`, this is
/// generic only to avoid code bloat. It only takes `<length-percentage>`
///
/// https://drafts.csswg.org/css-grid/#typedef-track-size
pub enum TrackSize<L> {
    /// A flexible `<track-breadth>`
    Breadth(TrackBreadth<L>),
    /// A `minmax` function for a range over an inflexible `<track-breadth>`
    /// and a flexible `<track-breadth>`
    ///
    /// https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-minmax
    MinMax(TrackBreadth<L>, TrackBreadth<L>),
    /// A `fit-content` function.
    ///
    /// https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-fit-content
    FitContent(L),
}

impl<L> Default for TrackSize<L> {
    fn default() -> Self {
        TrackSize::Breadth(TrackBreadth::Keyword(TrackKeyword::Auto))
    }
}

impl Parse for TrackSize<LengthOrPercentage> {
    fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
        if let Ok(b) = input.try(|i| TrackBreadth::parse(context, i)) {
            return Ok(TrackSize::Breadth(b))
        }

        if input.try(|i| i.expect_function_matching("minmax")).is_ok() {
            return input.parse_nested_block(|input| {
                let inflexible_breadth =
                    match input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
                        Ok(lop) => TrackBreadth::Breadth(lop),
                        Err(..) => {
                            let keyword = try!(TrackKeyword::parse(input));
                            TrackBreadth::Keyword(keyword)
                        }
                    };

                try!(input.expect_comma());
                Ok(TrackSize::MinMax(inflexible_breadth, try!(TrackBreadth::parse(context, input))))
            });
        }

        try!(input.expect_function_matching("fit-content"));
        // FIXME(emilio): This needs a parse_nested_block, doesn't it?
        Ok(try!(LengthOrPercentage::parse(context, input).map(TrackSize::FitContent)))
    }
}

impl<L: ToCss> ToCss for TrackSize<L> {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
        match *self {
            TrackSize::Breadth(ref b) => b.to_css(dest),
            TrackSize::MinMax(ref infexible, ref flexible) => {
                try!(dest.write_str("minmax("));
                try!(infexible.to_css(dest));
                try!(dest.write_str(","));
                try!(flexible.to_css(dest));
                dest.write_str(")")
            },
            TrackSize::FitContent(ref lop) => {
                try!(dest.write_str("fit-content("));
                try!(lop.to_css(dest));
                dest.write_str(")")
            },
        }
    }
}

impl HasViewportPercentage for TrackSize<LengthOrPercentage> {
    #[inline]
    fn has_viewport_percentage(&self) -> bool {
        match *self {
            TrackSize::Breadth(ref b) => b.has_viewport_percentage(),
            TrackSize::MinMax(ref inf_b, ref b) => inf_b.has_viewport_percentage() || b.has_viewport_percentage(),
            TrackSize::FitContent(ref lop) => lop.has_viewport_percentage(),
        }
    }
}

impl<L: ToComputedValue> ToComputedValue for TrackSize<L> {
    type ComputedValue = TrackSize<L::ComputedValue>;

    #[inline]
    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
        match *self {
            TrackSize::Breadth(ref b) => TrackSize::Breadth(b.to_computed_value(context)),
            TrackSize::MinMax(ref b_1, ref b_2) =>
                TrackSize::MinMax(b_1.to_computed_value(context), b_2.to_computed_value(context)),
            TrackSize::FitContent(ref lop) => TrackSize::FitContent(lop.to_computed_value(context)),
        }
    }

    #[inline]
    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
        match *computed {
            TrackSize::Breadth(ref b) =>
                TrackSize::Breadth(ToComputedValue::from_computed_value(b)),
            TrackSize::MinMax(ref b_1, ref b_2) =>
                TrackSize::MinMax(ToComputedValue::from_computed_value(b_1),
                                  ToComputedValue::from_computed_value(b_2)),
            TrackSize::FitContent(ref lop) =>
                TrackSize::FitContent(ToComputedValue::from_computed_value(lop)),
        }
    }
}

/// Parse the grid line names into a vector of owned strings.
///
/// https://drafts.csswg.org/css-grid/#typedef-line-names
pub fn parse_line_names(input: &mut Parser) -> Result<Vec<String>, ()> {
    input.expect_square_bracket_block()?;
    input.parse_nested_block(|input| {
        let mut values = vec![];
        while let Ok(ident) = input.try(|i| i.expect_ident()) {
            if CustomIdent::from_ident((&*ident).into(), &["span"]).is_err() {
                return Err(())
            }

            values.push(ident.into_owned());
        }

        Ok(values)
    })
}
<|endoftext|>


<commit_before>//! Library used by tidy and other tools.
//!
//! This library contains the tidy lints and exposes it
//! to be used by tools.

use std::fs::File;
use std::io::Read;
use walkdir::{DirEntry, WalkDir};

use std::path::Path;

macro_rules! t {
    ($e:expr, $p:expr) => {
        match $e {
            Ok(e) => e,
            Err(e) => panic!("{} failed on {} with {}", stringify!($e), ($p).display(), e),
        }
    };

    ($e:expr) => {
        match $e {
            Ok(e) => e,
            Err(e) => panic!("{} failed with {}", stringify!($e), e),
        }
    };
}

macro_rules! tidy_error {
    ($bad:expr, $fmt:expr) => ({
        *$bad = true;
        eprintln!("tidy error: {}", $fmt);
    });
    ($bad:expr, $fmt:expr, $($arg:tt)*) => ({
        *$bad = true;
        eprint!("tidy error: ");
        eprintln!($fmt, $($arg)*);
    });
}

pub mod bins;
pub mod debug_artifacts;
pub mod deps;
pub mod edition;
pub mod error_codes_check;
pub mod errors;
pub mod extdeps;
pub mod features;
pub mod pal;
pub mod style;
pub mod ui_tests;
pub mod unit_tests;
pub mod unstable_book;

fn filter_dirs(path: &Path) -> bool {
    let skip = [
        "compiler/rustc_codegen_cranelift",
        "src/llvm-project",
        "library/backtrace",
        "library/stdarch",
        "src/tools/cargo",
        "src/tools/clippy",
        "src/tools/miri",
        "src/tools/rls",
        "src/tools/rust-analyzer",
        "src/tools/rust-installer",
        "src/tools/rustfmt",
        "src/doc/book",
        // Filter RLS output directories
        "target/rls",
    ];
    skip.iter().any(|p| path.ends_with(p))
}

fn walk_many(
    paths: &[&Path],
    skip: &mut dyn FnMut(&Path) -> bool,
    f: &mut dyn FnMut(&DirEntry, &str),
) {
    for path in paths {
        walk(path, skip, f);
    }
}

fn walk(path: &Path, skip: &mut dyn FnMut(&Path) -> bool, f: &mut dyn FnMut(&DirEntry, &str)) {
    let mut contents = String::new();
    walk_no_read(path, skip, &mut |entry| {
        contents.clear();
        if t!(File::open(entry.path()), entry.path()).read_to_string(&mut contents).is_err() {
            contents.clear();
        }
        f(&entry, &contents);
    });
}

fn walk_no_read(path: &Path, skip: &mut dyn FnMut(&Path) -> bool, f: &mut dyn FnMut(&DirEntry)) {
    let walker = WalkDir::new(path).into_iter().filter_entry(|e| !skip(e.path()));
    for entry in walker {
        if let Ok(entry) = entry {
            if entry.file_type().is_dir() {
                continue;
            }
            f(&entry);
        }
    }
}
<commit_msg>don't try to visit probe file<commit_after>//! Library used by tidy and other tools.
//!
//! This library contains the tidy lints and exposes it
//! to be used by tools.

use std::fs::File;
use std::io::Read;
use walkdir::{DirEntry, WalkDir};

use std::path::Path;

macro_rules! t {
    ($e:expr, $p:expr) => {
        match $e {
            Ok(e) => e,
            Err(e) => panic!("{} failed on {} with {}", stringify!($e), ($p).display(), e),
        }
    };

    ($e:expr) => {
        match $e {
            Ok(e) => e,
            Err(e) => panic!("{} failed with {}", stringify!($e), e),
        }
    };
}

macro_rules! tidy_error {
    ($bad:expr, $fmt:expr) => ({
        *$bad = true;
        eprintln!("tidy error: {}", $fmt);
    });
    ($bad:expr, $fmt:expr, $($arg:tt)*) => ({
        *$bad = true;
        eprint!("tidy error: ");
        eprintln!($fmt, $($arg)*);
    });
}

pub mod bins;
pub mod debug_artifacts;
pub mod deps;
pub mod edition;
pub mod error_codes_check;
pub mod errors;
pub mod extdeps;
pub mod features;
pub mod pal;
pub mod style;
pub mod ui_tests;
pub mod unit_tests;
pub mod unstable_book;

fn filter_dirs(path: &Path) -> bool {
    let skip = [
        "tidy-test-file",
        "compiler/rustc_codegen_cranelift",
        "src/llvm-project",
        "library/backtrace",
        "library/stdarch",
        "src/tools/cargo",
        "src/tools/clippy",
        "src/tools/miri",
        "src/tools/rls",
        "src/tools/rust-analyzer",
        "src/tools/rust-installer",
        "src/tools/rustfmt",
        "src/doc/book",
        // Filter RLS output directories
        "target/rls",
    ];
    skip.iter().any(|p| path.ends_with(p))
}

fn walk_many(
    paths: &[&Path],
    skip: &mut dyn FnMut(&Path) -> bool,
    f: &mut dyn FnMut(&DirEntry, &str),
) {
    for path in paths {
        walk(path, skip, f);
    }
}

fn walk(path: &Path, skip: &mut dyn FnMut(&Path) -> bool, f: &mut dyn FnMut(&DirEntry, &str)) {
    let mut contents = String::new();
    walk_no_read(path, skip, &mut |entry| {
        contents.clear();
        if t!(File::open(entry.path()), entry.path()).read_to_string(&mut contents).is_err() {
            contents.clear();
        }
        f(&entry, &contents);
    });
}

fn walk_no_read(path: &Path, skip: &mut dyn FnMut(&Path) -> bool, f: &mut dyn FnMut(&DirEntry)) {
    let walker = WalkDir::new(path).into_iter().filter_entry(|e| !skip(e.path()));
    for entry in walker {
        if let Ok(entry) = entry {
            if entry.file_type().is_dir() {
                continue;
            }
            f(&entry);
        }
    }
}
<|endoftext|>


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

//! Tidy check to enforce rules about platform-specific code in std
//!
//! This is intended to maintain existing standards of code
//! organization in hopes that the standard library will continue to
//! be refactored to isolate platform-specific bits, making porting
//! easier; where "standard library" roughly means "all the
//! dependencies of the std and test crates".
//!
//! This generally means placing restrictions on where `cfg(unix)`,
//! `cfg(windows)`, `cfg(target_os)` and `cfg(target_env)` may appear,
//! the basic objective being to isolate platform-specific code to the
//! platform-specific `std::sys` modules, and to the allocation,
//! unwinding, and libc crates.
//!
//! Following are the basic rules, though there are currently
//! exceptions:
//!
//! - core may not have platform-specific code
//! - libcompiler_builtins may have platform-specific code
//! - liballoc_system may have platform-specific code
//! - liballoc_jemalloc may have platform-specific code
//! - libpanic_abort may have platform-specific code
//! - libpanic_unwind may have platform-specific code
//! - libunwind may have platform-specific code
//! - other crates in the std facade may not
//! - std may have platform-specific code in the following places
//!   - sys/unix/
//!   - sys/windows/
//!   - os/
//!
//! `std/sys_common` should _not_ contain platform-specific code.
//! Finally, because std contains tests with platform-specific
//! `ignore` attributes, once the parser encounters `mod tests`,
//! platform-specific cfgs are allowed. Not sure yet how to deal with
//! this in the long term.

use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::iter::Iterator;

// Paths that may contain platform-specific code
const EXCEPTION_PATHS: &'static [&'static str] = &[
    // std crates
    "src/liballoc_jemalloc",
    "src/liballoc_system",
    "src/libcompiler_builtins",
    "src/liblibc",
    "src/libpanic_abort",
    "src/libpanic_unwind",
    "src/libunwind",
    "src/libstd/sys/", // Platform-specific code for std lives here.
                       // This has the trailing slash so that sys_common is not excepted.
    "src/libstd/os", // Platform-specific public interfaces
    "src/rtstartup", // Not sure what to do about this. magic stuff for mingw

    // temporary exceptions
    "src/libstd/lib.rs", // FIXME(#44217)
    "src/libstd/path.rs",
    "src/libstd/f32.rs",
    "src/libstd/f64.rs",
    "src/libstd/sys_common/mod.rs",
    "src/libstd/sys_common/net.rs",
    "src/libterm", // Not sure how to make this crate portable, but test needs it
    "src/libtest", // Probably should defer to unstable std::sys APIs

    // std testing crates, ok for now at least
    "src/libcore/tests",
    "src/liballoc/tests/lib.rs",

    // non-std crates
    "src/test",
    "src/tools",
    "src/librustc",
    "src/librustdoc",
    "src/libsyntax",
    "src/bootstrap",
];

pub fn check(path: &Path, bad: &mut bool) {
    let ref mut contents = String::new();
    // Sanity check that the complex parsing here works
    let ref mut saw_target_arch = false;
    let ref mut saw_cfg_bang = false;
    super::walk(path, &mut super::filter_dirs, &mut |file| {
        let filestr = file.to_string_lossy().replace("\\", "/");
        if !filestr.ends_with(".rs") { return }

        let is_exception_path = EXCEPTION_PATHS.iter().any(|s| filestr.contains(&**s));
        if is_exception_path { return }

        check_cfgs(contents, &file, bad, saw_target_arch, saw_cfg_bang);
    });

    assert!(*saw_target_arch);
    assert!(*saw_cfg_bang);
}

fn check_cfgs(contents: &mut String, file: &Path,
              bad: &mut bool, saw_target_arch: &mut bool, saw_cfg_bang: &mut bool) {
    contents.truncate(0);
    t!(t!(File::open(file), file).read_to_string(contents));

    // For now it's ok to have platform-specific code after 'mod tests'.
    let mod_tests_idx = find_test_mod(contents);
    let contents = &contents[..mod_tests_idx];
    // Pull out all "cfg(...)" and "cfg!(...)" strings
    let cfgs = parse_cfgs(contents);

    let mut line_numbers: Option<Vec<usize>> = None;
    let mut err = |idx: usize, cfg: &str| {
        if line_numbers.is_none() {
            line_numbers = Some(contents.match_indices('\n').map(|(i, _)| i).collect());
        }
        let line_numbers = line_numbers.as_ref().expect("");
        let line = match line_numbers.binary_search(&idx) {
            Ok(_) => unreachable!(),
            Err(i) => i + 1
        };
        tidy_error!(bad, "{}:{}: platform-specific cfg: {}", file.display(), line, cfg);
    };

    for (idx, cfg) in cfgs.into_iter() {
        // Sanity check that the parsing here works
        if !*saw_target_arch && cfg.contains("target_arch") { *saw_target_arch = true }
        if !*saw_cfg_bang && cfg.contains("cfg!") { *saw_cfg_bang = true }

        let contains_platform_specific_cfg =
            cfg.contains("target_os")
            || cfg.contains("target_env")
            || cfg.contains("target_vendor")
            || cfg.contains("unix")
            || cfg.contains("windows");

        if !contains_platform_specific_cfg { continue }

        let preceeded_by_doc_comment = {
            let pre_contents = &contents[..idx];
            let pre_newline = pre_contents.rfind('\n');
            let pre_doc_comment = pre_contents.rfind("///");
            match (pre_newline, pre_doc_comment) {
                (Some(n), Some(c)) => n < c,
                (None, Some(_)) => true,
                (_, None) => false,
            }
        };

        if preceeded_by_doc_comment { continue }

        err(idx, cfg);
    }
}

fn find_test_mod(contents: &str) -> usize {
    if let Some(mod_tests_idx) = contents.find("mod tests") {
        // Also capture a previos line indicating "mod tests" in cfg-ed out
        let prev_newline_idx = contents[..mod_tests_idx].rfind('\n').unwrap_or(mod_tests_idx);
        let prev_newline_idx = contents[..prev_newline_idx].rfind('\n');
        if let Some(nl) = prev_newline_idx {
            let prev_line = &contents[nl + 1 .. mod_tests_idx];
            let emcc_cfg = "cfg(all(test, not(target_os";
            if prev_line.contains(emcc_cfg) {
                nl
            } else {
                mod_tests_idx
            }
        } else {
            mod_tests_idx
        }
    } else {
        contents.len()
    }
}

fn parse_cfgs<'a>(contents: &'a str) -> Vec<(usize, &'a str)> {
    let candidate_cfgs = contents.match_indices("cfg");
    let candidate_cfg_idxs = candidate_cfgs.map(|(i, _)| i);
    // This is puling out the indexes of all "cfg" strings
    // that appear to be tokens succeeded by a paren.
    let cfgs = candidate_cfg_idxs.filter(|i| {
        let pre_idx = i.saturating_sub(*i);
        let succeeds_non_ident = !contents.as_bytes().get(pre_idx)
            .cloned()
            .map(char::from)
            .map(char::is_alphanumeric)
            .unwrap_or(false);
        let contents_after = &contents[*i..];
        let first_paren = contents_after.find('(');
        let paren_idx = first_paren.map(|ip| i + ip);
        let preceeds_whitespace_and_paren = paren_idx.map(|ip| {
            let maybe_space = &contents[*i + "cfg".len() .. ip];
            maybe_space.chars().all(|c| char::is_whitespace(c) || c == '!')
        }).unwrap_or(false);

        succeeds_non_ident && preceeds_whitespace_and_paren
    });

    cfgs.map(|i| {
        let mut depth = 0;
        let contents_from = &contents[i..];
        for (j, byte) in contents_from.bytes().enumerate() {
            match byte {
                b'(' => {
                    depth += 1;
                }
                b')' => {
                    depth -= 1;
                    if depth == 0 {
                        return (i, &contents_from[.. j + 1]);
                    }
                }
                _ => { }
            }
        }

        unreachable!()
    }).collect()
}
<commit_msg>Extend tidy to allow conditionalizing tests for multiple targets.<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Tidy check to enforce rules about platform-specific code in std
//!
//! This is intended to maintain existing standards of code
//! organization in hopes that the standard library will continue to
//! be refactored to isolate platform-specific bits, making porting
//! easier; where "standard library" roughly means "all the
//! dependencies of the std and test crates".
//!
//! This generally means placing restrictions on where `cfg(unix)`,
//! `cfg(windows)`, `cfg(target_os)` and `cfg(target_env)` may appear,
//! the basic objective being to isolate platform-specific code to the
//! platform-specific `std::sys` modules, and to the allocation,
//! unwinding, and libc crates.
//!
//! Following are the basic rules, though there are currently
//! exceptions:
//!
//! - core may not have platform-specific code
//! - libcompiler_builtins may have platform-specific code
//! - liballoc_system may have platform-specific code
//! - liballoc_jemalloc may have platform-specific code
//! - libpanic_abort may have platform-specific code
//! - libpanic_unwind may have platform-specific code
//! - libunwind may have platform-specific code
//! - other crates in the std facade may not
//! - std may have platform-specific code in the following places
//!   - sys/unix/
//!   - sys/windows/
//!   - os/
//!
//! `std/sys_common` should _not_ contain platform-specific code.
//! Finally, because std contains tests with platform-specific
//! `ignore` attributes, once the parser encounters `mod tests`,
//! platform-specific cfgs are allowed. Not sure yet how to deal with
//! this in the long term.

use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::iter::Iterator;

// Paths that may contain platform-specific code
const EXCEPTION_PATHS: &'static [&'static str] = &[
    // std crates
    "src/liballoc_jemalloc",
    "src/liballoc_system",
    "src/libcompiler_builtins",
    "src/liblibc",
    "src/libpanic_abort",
    "src/libpanic_unwind",
    "src/libunwind",
    "src/libstd/sys/", // Platform-specific code for std lives here.
                       // This has the trailing slash so that sys_common is not excepted.
    "src/libstd/os", // Platform-specific public interfaces
    "src/rtstartup", // Not sure what to do about this. magic stuff for mingw

    // temporary exceptions
    "src/libstd/lib.rs", // FIXME(#44217)
    "src/libstd/path.rs",
    "src/libstd/f32.rs",
    "src/libstd/f64.rs",
    "src/libstd/sys_common/mod.rs",
    "src/libstd/sys_common/net.rs",
    "src/libterm", // Not sure how to make this crate portable, but test needs it
    "src/libtest", // Probably should defer to unstable std::sys APIs

    // std testing crates, ok for now at least
    "src/libcore/tests",
    "src/liballoc/tests/lib.rs",

    // non-std crates
    "src/test",
    "src/tools",
    "src/librustc",
    "src/librustdoc",
    "src/libsyntax",
    "src/bootstrap",
];

pub fn check(path: &Path, bad: &mut bool) {
    let ref mut contents = String::new();
    // Sanity check that the complex parsing here works
    let ref mut saw_target_arch = false;
    let ref mut saw_cfg_bang = false;
    super::walk(path, &mut super::filter_dirs, &mut |file| {
        let filestr = file.to_string_lossy().replace("\\", "/");
        if !filestr.ends_with(".rs") { return }

        let is_exception_path = EXCEPTION_PATHS.iter().any(|s| filestr.contains(&**s));
        if is_exception_path { return }

        check_cfgs(contents, &file, bad, saw_target_arch, saw_cfg_bang);
    });

    assert!(*saw_target_arch);
    assert!(*saw_cfg_bang);
}

fn check_cfgs(contents: &mut String, file: &Path,
              bad: &mut bool, saw_target_arch: &mut bool, saw_cfg_bang: &mut bool) {
    contents.truncate(0);
    t!(t!(File::open(file), file).read_to_string(contents));

    // For now it's ok to have platform-specific code after 'mod tests'.
    let mod_tests_idx = find_test_mod(contents);
    let contents = &contents[..mod_tests_idx];
    // Pull out all "cfg(...)" and "cfg!(...)" strings
    let cfgs = parse_cfgs(contents);

    let mut line_numbers: Option<Vec<usize>> = None;
    let mut err = |idx: usize, cfg: &str| {
        if line_numbers.is_none() {
            line_numbers = Some(contents.match_indices('\n').map(|(i, _)| i).collect());
        }
        let line_numbers = line_numbers.as_ref().expect("");
        let line = match line_numbers.binary_search(&idx) {
            Ok(_) => unreachable!(),
            Err(i) => i + 1
        };
        tidy_error!(bad, "{}:{}: platform-specific cfg: {}", file.display(), line, cfg);
    };

    for (idx, cfg) in cfgs.into_iter() {
        // Sanity check that the parsing here works
        if !*saw_target_arch && cfg.contains("target_arch") { *saw_target_arch = true }
        if !*saw_cfg_bang && cfg.contains("cfg!") { *saw_cfg_bang = true }

        let contains_platform_specific_cfg =
            cfg.contains("target_os")
            || cfg.contains("target_env")
            || cfg.contains("target_vendor")
            || cfg.contains("unix")
            || cfg.contains("windows");

        if !contains_platform_specific_cfg { continue }

        let preceeded_by_doc_comment = {
            let pre_contents = &contents[..idx];
            let pre_newline = pre_contents.rfind('\n');
            let pre_doc_comment = pre_contents.rfind("///");
            match (pre_newline, pre_doc_comment) {
                (Some(n), Some(c)) => n < c,
                (None, Some(_)) => true,
                (_, None) => false,
            }
        };

        if preceeded_by_doc_comment { continue }

        err(idx, cfg);
    }
}

fn find_test_mod(contents: &str) -> usize {
    if let Some(mod_tests_idx) = contents.find("mod tests") {
        // Also capture a previos line indicating "mod tests" in cfg-ed out
        let prev_newline_idx = contents[..mod_tests_idx].rfind('\n').unwrap_or(mod_tests_idx);
        let prev_newline_idx = contents[..prev_newline_idx].rfind('\n');
        if let Some(nl) = prev_newline_idx {
            let prev_line = &contents[nl + 1 .. mod_tests_idx];
            if prev_line.contains("cfg(all(test, not(target_os")
                || prev_line.contains("cfg(all(test, not(any(target_os") {
                nl
            } else {
                mod_tests_idx
            }
        } else {
            mod_tests_idx
        }
    } else {
        contents.len()
    }
}

fn parse_cfgs<'a>(contents: &'a str) -> Vec<(usize, &'a str)> {
    let candidate_cfgs = contents.match_indices("cfg");
    let candidate_cfg_idxs = candidate_cfgs.map(|(i, _)| i);
    // This is puling out the indexes of all "cfg" strings
    // that appear to be tokens succeeded by a paren.
    let cfgs = candidate_cfg_idxs.filter(|i| {
        let pre_idx = i.saturating_sub(*i);
        let succeeds_non_ident = !contents.as_bytes().get(pre_idx)
            .cloned()
            .map(char::from)
            .map(char::is_alphanumeric)
            .unwrap_or(false);
        let contents_after = &contents[*i..];
        let first_paren = contents_after.find('(');
        let paren_idx = first_paren.map(|ip| i + ip);
        let preceeds_whitespace_and_paren = paren_idx.map(|ip| {
            let maybe_space = &contents[*i + "cfg".len() .. ip];
            maybe_space.chars().all(|c| char::is_whitespace(c) || c == '!')
        }).unwrap_or(false);

        succeeds_non_ident && preceeds_whitespace_and_paren
    });

    cfgs.map(|i| {
        let mut depth = 0;
        let contents_from = &contents[i..];
        for (j, byte) in contents_from.bytes().enumerate() {
            match byte {
                b'(' => {
                    depth += 1;
                }
                b')' => {
                    depth -= 1;
                    if depth == 0 {
                        return (i, &contents_from[.. j + 1]);
                    }
                }
                _ => { }
            }
        }

        unreachable!()
    }).collect()
}
<|endoftext|>


<commit_before>use ra_syntax::{
    TextUnit, AstNode, SyntaxKind::COLONCOLON,
    ast,
    algo::generate,
};

use crate::assists::{AssistCtx, Assist};

pub fn split_import(ctx: AssistCtx) -> Option<Assist> {
    let colon_colon = ctx
        .leaf_at_offset()
        .find(|leaf| leaf.kind() == COLONCOLON)?;
    let path = colon_colon.parent().and_then(ast::Path::cast)?;
    let top_path = generate(Some(path), |it| it.parent_path()).last()?;

    let use_tree = top_path.syntax().ancestors().find_map(ast::UseTree::cast);
    if use_tree.is_none() {
        return None;
    }

    let l_curly = colon_colon.range().end();
    let r_curly = top_path.syntax().range().end();

    ctx.build("split import", |edit| {
        edit.insert(l_curly, "{");
        edit.insert(r_curly, "}");
        edit.set_cursor(l_curly + TextUnit::of_str("{"));
    })
}

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

    #[test]
    fn test_split_import() {
        check_assist(
            split_import,
            "use crate::<|>db::RootDatabase;",
            "use crate::{<|>db::RootDatabase};",
        )
    }
}
<commit_msg>split_import intention correctly works with use trees<commit_after>use ra_syntax::{
    TextUnit, AstNode, SyntaxKind::COLONCOLON,
    ast,
    algo::generate,
};

use crate::assists::{AssistCtx, Assist};

pub fn split_import(ctx: AssistCtx) -> Option<Assist> {
    let colon_colon = ctx
        .leaf_at_offset()
        .find(|leaf| leaf.kind() == COLONCOLON)?;
    let path = colon_colon.parent().and_then(ast::Path::cast)?;
    let top_path = generate(Some(path), |it| it.parent_path()).last()?;

    let use_tree = top_path.syntax().ancestors().find_map(ast::UseTree::cast);
    if use_tree.is_none() {
        return None;
    }

    let l_curly = colon_colon.range().end();
    let r_curly = match top_path.syntax().parent().and_then(ast::UseTree::cast) {
        Some(tree) => tree.syntax().range().end(),
        None => top_path.syntax().range().end(),
    };

    ctx.build("split import", |edit| {
        edit.insert(l_curly, "{");
        edit.insert(r_curly, "}");
        edit.set_cursor(l_curly + TextUnit::of_str("{"));
    })
}

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

    #[test]
    fn test_split_import() {
        check_assist(
            split_import,
            "use crate::<|>db::RootDatabase;",
            "use crate::{<|>db::RootDatabase};",
        )
    }

    #[test]
    fn split_import_works_with_trees() {
        check_assist(
            split_import,
            "use algo:<|>:visitor::{Visitor, visit}",
            "use algo::{<|>visitor::{Visitor, visit}}",
        )
    }
}
<|endoftext|>