<commit_before>use super::ActionType;

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MessageAction;

impl MessageAction {
    pub fn new() -> MessageAction {
        MessageAction
    }
}

impl From<MessageAction> for super::ActionType {
    fn from(action: MessageAction) -> super::ActionType {
        super::ActionType::Message(action)
    }
}

mod deser {

use super::MessageAction;
use serde;
use serde::de::Deserialize;

impl serde::Deserialize for MessageAction {
    fn deserialize<D>(deserializer: &mut D) -> Result<MessageAction, D::Error>
        where D: serde::de::Deserializer
    {
        deserializer.visit_unit_struct("MessageAction", MessageActionVisitor)
    }
}

struct MessageActionVisitor;

impl serde::de::Visitor for MessageActionVisitor {
    type Value = MessageAction;
    fn visit_unit<E>(&mut self) -> Result<Self::Value, E>
        where E: serde::de::Error {
        Ok(MessageAction)
    }
}
}
<commit_msg>src: remove unused but checked in files<commit_after><|endoftext|>


<commit_before>pub mod bitbucket;
pub mod gist;
pub mod hastebin;
pub mod pastebin;
pub mod pastie;
pub mod sprunge;

use bins::error::*;
use bins::network::download::Downloader;
use bins::network::upload::Uploader;
use bins::network;
use bins::{self, Bins, PasteFile};
use hyper::Url;
use linked_hash_map::LinkedHashMap;
use std::collections::HashMap;
use std::iter::repeat;

pub struct Index {
  pub files: LinkedHashMap<String, Url>
}

impl Index {
  fn repeat_str(string: &str, count: usize) -> String {
    repeat(string).take(count).collect()
  }

  pub fn to_string(&self) -> String {
    let header = format!("{} files", self.files.len());
    let separator = Self::repeat_str("-", header.len());
    let mut body = String::from("");
    for (i, (name, url)) in self.files.iter().enumerate() {
      let number = i + 1;
      body.push_str(&format!("{number}. {name}: {url}\n",
                             number = number,
                             name = name,
                             url = url));
    }
    format!("{}\n{}\n\n{}", header, separator, body)
  }

  pub fn parse<S: Into<String>>(string: S) -> Result<Index> {
    let string = string.into();
    let lines: Vec<&str> = string.split('\n').collect();
    if lines.len() < 4 {
      return Err(ErrorKind::InvalidIndexError.into());
    }
    let mut split = lines.iter().skip(3).filter(|s| !s.trim().is_empty()).map(|s| s.split(": ")).collect::<Vec<_>>();
    let names: Vec<String> = some_or_err!(split.iter_mut()
                                            .map(|s| {
                                              s.nth(0)
                                                .map(|n| n.split(' ').skip(1).collect::<Vec<&str>>().join(" "))
                                            })
                                            .collect(),
                                          ErrorKind::InvalidIndexError.into());
    let url_strings: Vec<String> = some_or_err!(split.iter_mut().map(|s| s.nth(0).map(|s| s.to_owned())).collect(),
                                                ErrorKind::InvalidIndexError.into());
    let urls: Vec<Url> = try!(url_strings.into_iter().map(network::parse_url).collect());
    let urls: LinkedHashMap<String, Url> = names.into_iter().zip(urls.into_iter()).collect();
    Ok(Index { files: urls })
  }
}

pub struct RemotePasteFile {
  pub name: String,
  pub url: Url,
  pub contents: Option<String>
}

/// Produce information about HTML content from URLs to HTML content.
pub trait ProduceInfo {
  fn produce_info(&self, bins: &Bins, url: &Url) -> Result<Vec<RemotePasteFile>>;

  fn produce_info_all(&self, bins: &Bins, urls: Vec<&Url>) -> Result<Vec<RemotePasteFile>> {
    let info: Vec<Vec<RemotePasteFile>> = try!(urls.iter().map(|u| self.produce_info(bins, u)).collect());
    Ok(info.into_iter().flat_map(|v| v).collect())
  }
}

impl<T> ProduceInfo for T
  where T: GenerateIndex + ConvertUrlsToRawUrls + Downloader
{
  fn produce_info(&self, bins: &Bins, url: &Url) -> Result<Vec<RemotePasteFile>> {
    let raw_url = try!(self.convert_url_to_raw_url(bins, url));
    let mut res = try!(self.download(&bins, &raw_url));
    let content = try!(network::read_response(&mut res));
    let index = Index::parse(content.clone());
    let mut urls: Vec<RemotePasteFile> = Vec::new();
    match index {
      Ok(ref i) => {
        for (name, url) in i.files.clone().into_iter() {
          urls.push(RemotePasteFile {
            name: name.clone(),
            url: url.clone(),
            contents: None
          });
        }
      }
      Err(ref e) => {
        if let ErrorKind::InvalidIndexError = *e.kind() {} else {
          return Err(e.to_string().into());
        }
        let url = url.clone();
        let name = some_or_err!(url.path_segments().and_then(|s| s.last()),
                                "paste url was a root url".into());
        urls.push(RemotePasteFile {
          name: name.to_owned(),
          url: url.clone(),
          contents: Some(content)
        });
      }
    }
    Ok(urls)
  }
}

/// Produce information about raw content from URLs to HTML content.
pub trait ProduceRawInfo {
  fn produce_raw_info(&self, bins: &Bins, url: &Url) -> Result<Vec<RemotePasteFile>>;

  fn produce_raw_info_all(&self, bins: &Bins, urls: Vec<&Url>) -> Result<Vec<RemotePasteFile>> {
    let info: Vec<Vec<RemotePasteFile>> = try!(urls.iter().map(|u| self.produce_raw_info(bins, u)).collect());
    Ok(info.into_iter().flat_map(|v| v).collect())
  }
}

impl<T> ProduceRawInfo for T
  where T: ConvertUrlsToRawUrls + Downloader + UsesIndices + ProduceInfo
{
  fn produce_raw_info(&self, bins: &Bins, url: &Url) -> Result<Vec<RemotePasteFile>> {
    let info = try!(self.produce_info(bins, url));
    info.into_iter()
      .map(|r| {
        let raw_url = try!(self.convert_url_to_raw_url(bins, &r.url));
        Ok(RemotePasteFile { url: raw_url, ..r })
      })
      .collect()
  }
}

pub trait ConvertUrlsToRawUrls {
  fn convert_url_to_raw_url(&self, bins: &Bins, url: &Url) -> Result<Url>;

  fn convert_urls_to_raw_urls(&self, bins: &Bins, urls: Vec<&Url>) -> Result<Vec<Url>> {
    urls.iter().map(|u| self.convert_url_to_raw_url(bins, u)).collect()
  }
}

/// Produce raw content from a URL to HTML content.
pub trait ProduceRawContent: ProduceRawInfo + ProduceInfo + Downloader {
  fn produce_raw_contents(&self, bins: &Bins, url: &Url) -> Result<String> {
    let raw_info = if bins.arguments.urls {
      try!(self.produce_info(bins, url))
    } else {
      try!(self.produce_raw_info(bins, url))
    };
    let raw_info: Vec<RemotePasteFile> = if raw_info.len() > 1 {
      if !bins.arguments.files.is_empty() {
        let mut map: HashMap<String, RemotePasteFile> =
          raw_info.into_iter().map(|r| (r.name.to_lowercase(), r)).collect();
        try!(bins.arguments
          .files
          .iter()
          .map(|s| map.remove(&s.to_lowercase()).ok_or(format!("file {} not found", s)))
          .collect())
      } else if let Some(ref range) = bins.arguments.range {
        let mut numbered_info: HashMap<usize, RemotePasteFile> = raw_info.into_iter()
          .enumerate()
          .collect();
        try!(range.clone()
          .into_iter()
          .map(|n| numbered_info.remove(&n).ok_or(format!("file {} not found", n)))
          .collect())
      } else if bins.arguments.all {
        raw_info
      } else {
        let names = raw_info.into_iter().map(|r| String::from("  ") + &r.name).collect::<Vec<_>>().join("\n");
        return Err(format!("paste had multiple files, but no behavior was specified on the command \
                            line\n\navailable files:\n{}",
                           names)
          .into());
      }
    } else {
      raw_info
    };
    if bins.arguments.raw_urls || bins.arguments.urls {
      return Ok(raw_info.into_iter().map(|r| r.url.as_str().to_owned()).collect::<Vec<_>>().join("\n"));
    }
    let names: Vec<String> = raw_info.iter().map(|p| p.name.clone()).collect();
    let all_contents: Vec<String> = try!(raw_info.iter()
      .map(|p| {
        match p.contents.clone() {
          Some(contents) => Ok(contents),
          None => self.download(&bins, &p.url).and_then(|mut r| network::read_response(&mut r)),
        }
      })
      .collect());
    let files: LinkedHashMap<String, String> = names.into_iter().zip(all_contents.into_iter()).collect();
    Ok(files.into_iter()
      .map(|(name, content)| {
        PasteFile {
          name: name.clone(),
          data: if bins.arguments.number_lines {
            number_lines(content.clone())
          } else {
            content.clone()
          }
        }
      })
      .collect::<Vec<PasteFile>>()
      .join())
  }
}

fn number_lines(string: String) -> String {
  let lines: Vec<&str> = string.split('\n').collect();
  let num_lines = lines.len();
  let zeroes: String = repeat(" ").take(num_lines.to_string().len()).collect();
  lines.into_iter()
    .enumerate()
    .map(|(i, l)| {
      let i = i + 1;
      format!("{}{}  {}",
              &zeroes[0..zeroes.len() - i.to_string().len()],
              i,
              l)
    })
    .collect::<Vec<_>>()
    .join("\n")
}

/// Produce a URL to HTML content from raw content.
pub trait UploadContent: Uploader {
  fn upload_paste(&self, bins: &Bins, content: PasteFile) -> Result<Url>;
}

impl<T> UploadContent for T
  where T: UploadUrl + Uploader
{
  fn upload_paste(&self, bins: &Bins, content: PasteFile) -> Result<Url> {
    let url = try!(network::parse_url(self.get_upload_url()));
    let mut response = try!(self.upload(&url, bins, &content));
    network::parse_url(try!(network::read_response(&mut response)))
  }
}

/// Produce a URL to HTML content from a batch of raw content.
pub trait UploadBatchContent: UploadContent {
  fn upload_all(&self, bins: &Bins, content: Vec<PasteFile>) -> Result<Url>;
}

impl<T> UploadBatchContent for T
  where T: GenerateIndex + UploadContent
{
  fn upload_all(&self, bins: &Bins, content: Vec<PasteFile>) -> Result<Url> {
    let index = try!(self.generate_index(bins, content));
    self.upload_paste(bins,
                      PasteFile {
                        name: "index.md".to_owned(),
                        data: index.to_string()
                      })
  }
}

pub trait UsesIndices {}

/// Generate an index for multiple files.
pub trait GenerateIndex {
  fn generate_index(&self, bins: &Bins, content: Vec<PasteFile>) -> Result<Index>;
}

impl<T> GenerateIndex for T
  where T: UploadContent + UsesIndices
{
  fn generate_index(&self, bins: &Bins, content: Vec<PasteFile>) -> Result<Index> {
    let names: Vec<String> = (&content).into_iter().map(|p| p.name.clone()).collect();
    let urls: Vec<Url> = try!(content.into_iter().map(|p| self.upload_paste(bins, p)).collect());
    let uploads: LinkedHashMap<String, Url> = names.into_iter().zip(urls.into_iter()).collect();
    Ok(Index { files: uploads })
  }
}

pub trait UploadUrl {
  fn get_upload_url(&self) -> &str;
}

pub trait VerifyUrl {
  fn segments(&self, url: &Url) -> Vec<String> {
    let segments = match url.path_segments() {
      Some(s) => s,
      None => return Vec::new(),
    };
    segments.filter(|s| !s.is_empty()).map(|s| s.to_owned()).collect::<Vec<_>>()
  }

  fn verify_url(&self, url: &Url) -> bool;
}

/// A bin, which can upload content in raw form and download content in raw and HTML form.
pub trait Bin: Sync + ProduceInfo + ProduceRawContent + UploadBatchContent + VerifyUrl {
  fn get_name(&self) -> &str;

  fn get_domain(&self) -> &str;
}

trait Join {
  fn join(&self) -> String;
}

impl Join for Vec<PasteFile> {
  fn join(&self) -> String {
    if self.len() == 1 {
      self.get(0).expect("len() == 1, but no first element").data.clone()
    } else {
      self.into_iter().map(|p| format!("--- {} ---\n\n{}", p.name, p.data)).collect::<Vec<String>>().join("\n\n")
    }
  }
}

lazy_static! {
  pub static ref BINS: Vec<Box<Bin>> = {
      vec![
        Box::new(bins::Gist::new()),
        Box::new(bins::Bitbucket::new()),
        Box::new(bins::Sprunge::new()),
        Box::new(bins::Hastebin::new()),
        Box::new(bins::Pastebin::new()),
        Box::new(bins::Pastie::new())
      ]
  };
}

pub fn get_bin_names<'a>() -> Vec<&'a str> {
  BINS.iter().map(|e| e.get_name()).collect()
}

pub fn get_bin_by_name(name: &str) -> Option<&Box<Bin>> {
  BINS.iter().find(|e| e.get_name().to_lowercase() == name.to_lowercase())
}

pub fn get_bin_by_domain(domain: &str) -> Option<&Box<Bin>> {
  BINS.iter().find(|e| e.get_domain().to_lowercase() == domain.to_lowercase())
}
<commit_msg>fix: use different file separator and fewer newlines<commit_after>pub mod bitbucket;
pub mod gist;
pub mod hastebin;
pub mod pastebin;
pub mod pastie;
pub mod sprunge;

use bins::error::*;
use bins::network::download::Downloader;
use bins::network::upload::Uploader;
use bins::network;
use bins::{self, Bins, PasteFile};
use hyper::Url;
use linked_hash_map::LinkedHashMap;
use std::collections::HashMap;
use std::iter::repeat;

pub struct Index {
  pub files: LinkedHashMap<String, Url>
}

impl Index {
  fn repeat_str(string: &str, count: usize) -> String {
    repeat(string).take(count).collect()
  }

  pub fn to_string(&self) -> String {
    let header = format!("{} files", self.files.len());
    let separator = Self::repeat_str("-", header.len());
    let mut body = String::from("");
    for (i, (name, url)) in self.files.iter().enumerate() {
      let number = i + 1;
      body.push_str(&format!("{number}. {name}: {url}\n",
                             number = number,
                             name = name,
                             url = url));
    }
    format!("{}\n{}\n\n{}", header, separator, body)
  }

  pub fn parse<S: Into<String>>(string: S) -> Result<Index> {
    let string = string.into();
    let lines: Vec<&str> = string.split('\n').collect();
    if lines.len() < 4 {
      return Err(ErrorKind::InvalidIndexError.into());
    }
    let mut split = lines.iter().skip(3).filter(|s| !s.trim().is_empty()).map(|s| s.split(": ")).collect::<Vec<_>>();
    let names: Vec<String> = some_or_err!(split.iter_mut()
                                            .map(|s| {
                                              s.nth(0)
                                                .map(|n| n.split(' ').skip(1).collect::<Vec<&str>>().join(" "))
                                            })
                                            .collect(),
                                          ErrorKind::InvalidIndexError.into());
    let url_strings: Vec<String> = some_or_err!(split.iter_mut().map(|s| s.nth(0).map(|s| s.to_owned())).collect(),
                                                ErrorKind::InvalidIndexError.into());
    let urls: Vec<Url> = try!(url_strings.into_iter().map(network::parse_url).collect());
    let urls: LinkedHashMap<String, Url> = names.into_iter().zip(urls.into_iter()).collect();
    Ok(Index { files: urls })
  }
}

pub struct RemotePasteFile {
  pub name: String,
  pub url: Url,
  pub contents: Option<String>
}

/// Produce information about HTML content from URLs to HTML content.
pub trait ProduceInfo {
  fn produce_info(&self, bins: &Bins, url: &Url) -> Result<Vec<RemotePasteFile>>;

  fn produce_info_all(&self, bins: &Bins, urls: Vec<&Url>) -> Result<Vec<RemotePasteFile>> {
    let info: Vec<Vec<RemotePasteFile>> = try!(urls.iter().map(|u| self.produce_info(bins, u)).collect());
    Ok(info.into_iter().flat_map(|v| v).collect())
  }
}

impl<T> ProduceInfo for T
  where T: GenerateIndex + ConvertUrlsToRawUrls + Downloader
{
  fn produce_info(&self, bins: &Bins, url: &Url) -> Result<Vec<RemotePasteFile>> {
    let raw_url = try!(self.convert_url_to_raw_url(bins, url));
    let mut res = try!(self.download(&bins, &raw_url));
    let content = try!(network::read_response(&mut res));
    let index = Index::parse(content.clone());
    let mut urls: Vec<RemotePasteFile> = Vec::new();
    match index {
      Ok(ref i) => {
        for (name, url) in i.files.clone().into_iter() {
          urls.push(RemotePasteFile {
            name: name.clone(),
            url: url.clone(),
            contents: None
          });
        }
      }
      Err(ref e) => {
        if let ErrorKind::InvalidIndexError = *e.kind() {} else {
          return Err(e.to_string().into());
        }
        let url = url.clone();
        let name = some_or_err!(url.path_segments().and_then(|s| s.last()),
                                "paste url was a root url".into());
        urls.push(RemotePasteFile {
          name: name.to_owned(),
          url: url.clone(),
          contents: Some(content)
        });
      }
    }
    Ok(urls)
  }
}

/// Produce information about raw content from URLs to HTML content.
pub trait ProduceRawInfo {
  fn produce_raw_info(&self, bins: &Bins, url: &Url) -> Result<Vec<RemotePasteFile>>;

  fn produce_raw_info_all(&self, bins: &Bins, urls: Vec<&Url>) -> Result<Vec<RemotePasteFile>> {
    let info: Vec<Vec<RemotePasteFile>> = try!(urls.iter().map(|u| self.produce_raw_info(bins, u)).collect());
    Ok(info.into_iter().flat_map(|v| v).collect())
  }
}

impl<T> ProduceRawInfo for T
  where T: ConvertUrlsToRawUrls + Downloader + UsesIndices + ProduceInfo
{
  fn produce_raw_info(&self, bins: &Bins, url: &Url) -> Result<Vec<RemotePasteFile>> {
    let info = try!(self.produce_info(bins, url));
    info.into_iter()
      .map(|r| {
        let raw_url = try!(self.convert_url_to_raw_url(bins, &r.url));
        Ok(RemotePasteFile { url: raw_url, ..r })
      })
      .collect()
  }
}

pub trait ConvertUrlsToRawUrls {
  fn convert_url_to_raw_url(&self, bins: &Bins, url: &Url) -> Result<Url>;

  fn convert_urls_to_raw_urls(&self, bins: &Bins, urls: Vec<&Url>) -> Result<Vec<Url>> {
    urls.iter().map(|u| self.convert_url_to_raw_url(bins, u)).collect()
  }
}

/// Produce raw content from a URL to HTML content.
pub trait ProduceRawContent: ProduceRawInfo + ProduceInfo + Downloader {
  fn produce_raw_contents(&self, bins: &Bins, url: &Url) -> Result<String> {
    let raw_info = if bins.arguments.urls {
      try!(self.produce_info(bins, url))
    } else {
      try!(self.produce_raw_info(bins, url))
    };
    let raw_info: Vec<RemotePasteFile> = if raw_info.len() > 1 {
      if !bins.arguments.files.is_empty() {
        let mut map: HashMap<String, RemotePasteFile> =
          raw_info.into_iter().map(|r| (r.name.to_lowercase(), r)).collect();
        try!(bins.arguments
          .files
          .iter()
          .map(|s| map.remove(&s.to_lowercase()).ok_or(format!("file {} not found", s)))
          .collect())
      } else if let Some(ref range) = bins.arguments.range {
        let mut numbered_info: HashMap<usize, RemotePasteFile> = raw_info.into_iter()
          .enumerate()
          .collect();
        try!(range.clone()
          .into_iter()
          .map(|n| numbered_info.remove(&n).ok_or(format!("file {} not found", n)))
          .collect())
      } else if bins.arguments.all {
        raw_info
      } else {
        let names = raw_info.into_iter().map(|r| String::from("  ") + &r.name).collect::<Vec<_>>().join("\n");
        return Err(format!("paste had multiple files, but no behavior was specified on the command \
                            line\n\navailable files:\n{}",
                           names)
          .into());
      }
    } else {
      raw_info
    };
    if bins.arguments.raw_urls || bins.arguments.urls {
      return Ok(raw_info.into_iter().map(|r| r.url.as_str().to_owned()).collect::<Vec<_>>().join("\n"));
    }
    let names: Vec<String> = raw_info.iter().map(|p| p.name.clone()).collect();
    let all_contents: Vec<String> = try!(raw_info.iter()
      .map(|p| {
        match p.contents.clone() {
          Some(contents) => Ok(contents),
          None => self.download(&bins, &p.url).and_then(|mut r| network::read_response(&mut r)),
        }
      })
      .collect());
    let files: LinkedHashMap<String, String> = names.into_iter().zip(all_contents.into_iter()).collect();
    Ok(files.into_iter()
      .map(|(name, content)| {
        PasteFile {
          name: name.clone(),
          data: if bins.arguments.number_lines {
            number_lines(content.clone())
          } else {
            content.clone()
          }
        }
      })
      .collect::<Vec<PasteFile>>()
      .join())
  }
}

fn number_lines(string: String) -> String {
  let lines: Vec<&str> = string.split('\n').collect();
  let num_lines = lines.len();
  let zeroes: String = repeat(" ").take(num_lines.to_string().len()).collect();
  lines.into_iter()
    .enumerate()
    .map(|(i, l)| {
      let i = i + 1;
      format!("{}{}  {}",
              &zeroes[0..zeroes.len() - i.to_string().len()],
              i,
              l)
    })
    .collect::<Vec<_>>()
    .join("\n")
}

/// Produce a URL to HTML content from raw content.
pub trait UploadContent: Uploader {
  fn upload_paste(&self, bins: &Bins, content: PasteFile) -> Result<Url>;
}

impl<T> UploadContent for T
  where T: UploadUrl + Uploader
{
  fn upload_paste(&self, bins: &Bins, content: PasteFile) -> Result<Url> {
    let url = try!(network::parse_url(self.get_upload_url()));
    let mut response = try!(self.upload(&url, bins, &content));
    network::parse_url(try!(network::read_response(&mut response)))
  }
}

/// Produce a URL to HTML content from a batch of raw content.
pub trait UploadBatchContent: UploadContent {
  fn upload_all(&self, bins: &Bins, content: Vec<PasteFile>) -> Result<Url>;
}

impl<T> UploadBatchContent for T
  where T: GenerateIndex + UploadContent
{
  fn upload_all(&self, bins: &Bins, content: Vec<PasteFile>) -> Result<Url> {
    let index = try!(self.generate_index(bins, content));
    self.upload_paste(bins,
                      PasteFile {
                        name: "index.md".to_owned(),
                        data: index.to_string()
                      })
  }
}

pub trait UsesIndices {}

/// Generate an index for multiple files.
pub trait GenerateIndex {
  fn generate_index(&self, bins: &Bins, content: Vec<PasteFile>) -> Result<Index>;
}

impl<T> GenerateIndex for T
  where T: UploadContent + UsesIndices
{
  fn generate_index(&self, bins: &Bins, content: Vec<PasteFile>) -> Result<Index> {
    let names: Vec<String> = (&content).into_iter().map(|p| p.name.clone()).collect();
    let urls: Vec<Url> = try!(content.into_iter().map(|p| self.upload_paste(bins, p)).collect());
    let uploads: LinkedHashMap<String, Url> = names.into_iter().zip(urls.into_iter()).collect();
    Ok(Index { files: uploads })
  }
}

pub trait UploadUrl {
  fn get_upload_url(&self) -> &str;
}

pub trait VerifyUrl {
  fn segments(&self, url: &Url) -> Vec<String> {
    let segments = match url.path_segments() {
      Some(s) => s,
      None => return Vec::new(),
    };
    segments.filter(|s| !s.is_empty()).map(|s| s.to_owned()).collect::<Vec<_>>()
  }

  fn verify_url(&self, url: &Url) -> bool;
}

/// A bin, which can upload content in raw form and download content in raw and HTML form.
pub trait Bin: Sync + ProduceInfo + ProduceRawContent + UploadBatchContent + VerifyUrl {
  fn get_name(&self) -> &str;

  fn get_domain(&self) -> &str;
}

trait Join {
  fn join(&self) -> String;
}

impl Join for Vec<PasteFile> {
  fn join(&self) -> String {
    if self.len() == 1 {
      self.get(0).expect("len() == 1, but no first element").data.clone()
    } else {
      self.into_iter().map(|p| format!("==> {} <==\n{}", p.name, p.data)).collect::<Vec<String>>().join("\n")
    }
  }
}

lazy_static! {
  pub static ref BINS: Vec<Box<Bin>> = {
      vec![
        Box::new(bins::Gist::new()),
        Box::new(bins::Bitbucket::new()),
        Box::new(bins::Sprunge::new()),
        Box::new(bins::Hastebin::new()),
        Box::new(bins::Pastebin::new()),
        Box::new(bins::Pastie::new())
      ]
  };
}

pub fn get_bin_names<'a>() -> Vec<&'a str> {
  BINS.iter().map(|e| e.get_name()).collect()
}

pub fn get_bin_by_name(name: &str) -> Option<&Box<Bin>> {
  BINS.iter().find(|e| e.get_name().to_lowercase() == name.to_lowercase())
}

pub fn get_bin_by_domain(domain: &str) -> Option<&Box<Bin>> {
  BINS.iter().find(|e| e.get_domain().to_lowercase() == domain.to_lowercase())
}
<|endoftext|>


<commit_before>use std::net::{
    IpAddr,
    Ipv4Addr,
    Ipv6Addr,
    SocketAddr,
};
use std::sync::mpsc;
use c_ares;

use error::Error;
use host::HostResults;
use nameinfo::NameInfoResult;
use resolver::{
    Options,
    Resolver,
};

/// A blocking DNS resolver.
pub struct BlockingResolver {
    inner: Resolver,
}

impl BlockingResolver {
    /// Create a new `BlockingResolver`, using default `Options`.
    pub fn new() -> Result<BlockingResolver, Error> {
        let options = Options::default();
        Self::with_options(options)
    }

    /// Create a new `BlockingResolver`, with the given `Options`.
    pub fn with_options(options: Options) -> Result<BlockingResolver, Error> {
        let inner = Resolver::with_options(options)?;
        let resolver = BlockingResolver {
            inner: inner,
        };
        Ok(resolver)
    }

    /// Set the list of servers to contact, instead of the servers specified
    /// in resolv.conf or the local named.
    ///
    /// String format is `host[:port]`.  IPv6 addresses with ports require
    /// square brackets eg `[2001:4860:4860::8888]:53`.
    pub fn set_servers(
        &mut self,
        servers: &[&str]) -> Result<&mut Self, c_ares::Error> {
        self.inner.set_servers(servers)?;
        Ok(self)
    }

    /// Set the local IPv4 address from which to make queries.
    pub fn set_local_ipv4(&mut self, ipv4: &Ipv4Addr) -> &mut Self {
        self.inner.set_local_ipv4(ipv4);
        self
    }

    /// Set the local IPv6 address from which to make queries.
    pub fn set_local_ipv6(&mut self, ipv6: &Ipv6Addr) -> &mut Self {
        self.inner.set_local_ipv6(ipv6);
        self
    }

    /// Set the local device from which to make queries.
    pub fn set_local_device(&mut self, device: &str) -> &mut Self {
        self.inner.set_local_device(device);
        self
    }

    /// Look up the A records associated with `name`.
    pub fn query_a(&self, name: &str) -> c_ares::Result<c_ares::AResults> {
        let (tx, rx) = mpsc::channel();
        self.inner.query_a(name, move |result| {
            tx.send(result).unwrap()
        });
        rx.recv().unwrap()
    }

    /// Search for the A records associated with `name`.
    pub fn search_a(&self, name: &str) -> c_ares::Result<c_ares::AResults> {
        let (tx, rx) = mpsc::channel();
        self.inner.search_a(name, move |result| {
            tx.send(result).unwrap()
        });
        rx.recv().unwrap()
    }

    /// Look up the AAAA records associated with `name`.
    pub fn query_aaaa(&self, name: &str)  -> c_ares::Result<c_ares::AAAAResults> {
        let (tx, rx) = mpsc::channel();
        self.inner.query_aaaa(name, move |result| {
            tx.send(result).unwrap()
        });
        rx.recv().unwrap()
    }

    /// Search for the AAAA records associated with `name`.
    pub fn search_aaaa(&self, name: &str) -> c_ares::Result<c_ares::AAAAResults> {
        let (tx, rx) = mpsc::channel();
        self.inner.search_aaaa(name, move |result| {
            tx.send(result).unwrap()
        });
        rx.recv().unwrap()
    }

    /// Look up the CNAME records associated with `name`.
    pub fn query_cname(&self, name: &str)
        -> c_ares::Result<c_ares::CNameResults> {
        let (tx, rx) = mpsc::channel();
        self.inner.query_cname(name, move |result| {
            tx.send(result).unwrap()
        });
        rx.recv().unwrap()
    }

    /// Search for the CNAME records associated with `name`.
    pub fn search_cname(&self, name: &str)
        -> c_ares::Result<c_ares::CNameResults> {
        let (tx, rx) = mpsc::channel();
        self.inner.search_cname(name, move |result| {
            tx.send(result).unwrap()
        });
        rx.recv().unwrap()
    }

    /// Look up the MX records associated with `name`.
    pub fn query_mx(&self, name: &str) -> c_ares::Result<c_ares::MXResults> {
        let (tx, rx) = mpsc::channel();
        self.inner.query_mx(name, move |result| {
            tx.send(result).unwrap()
        });
        rx.recv().unwrap()
    }

    /// Search for the MX records associated with `name`.
    pub fn search_mx(&self, name: &str) -> c_ares::Result<c_ares::MXResults> {
        let (tx, rx) = mpsc::channel();
        self.inner.search_mx(name, move |result| {
            tx.send(result).unwrap()
        });
        rx.recv().unwrap()
    }

    /// Look up the NAPTR records associated with `name`.
    pub fn query_naptr(&self, name: &str)
        -> c_ares::Result<c_ares::NAPTRResults> {
        let (tx, rx) = mpsc::channel();
        self.inner.query_naptr(name, move |result| {
            tx.send(result).unwrap()
        });
        rx.recv().unwrap()
    }

    /// Search for the NAPTR records associated with `name`.
    pub fn search_naptr(&self, name: &str)
        -> c_ares::Result<c_ares::NAPTRResults> {
        let (tx, rx) = mpsc::channel();
        self.inner.search_naptr(name, move |result| {
            tx.send(result).unwrap()
        });
        rx.recv().unwrap()
    }

    /// Look up the NS records associated with `name`.
    pub fn query_ns(&self, name: &str) -> c_ares::Result<c_ares::NSResults> {
        let (tx, rx) = mpsc::channel();
        self.inner.query_ns(name, move |result| {
            tx.send(result).unwrap()
        });
        rx.recv().unwrap()
    }

    /// Search for the NS records associated with `name`.
    pub fn search_ns(&self, name: &str) -> c_ares::Result<c_ares::NSResults> {
        let (tx, rx) = mpsc::channel();
        self.inner.search_ns(name, move |result| {
            tx.send(result).unwrap()
        });
        rx.recv().unwrap()
    }

    /// Look up the PTR records associated with `name`.
    pub fn query_ptr(&self, name: &str) -> c_ares::Result<c_ares::PTRResults> {
        let (tx, rx) = mpsc::channel();
        self.inner.query_ptr(name, move |result| {
            tx.send(result).unwrap()
        });
        rx.recv().unwrap()
    }

    /// Search for the PTR records associated with `name`.
    pub fn search_ptr(&self, name: &str) -> c_ares::Result<c_ares::PTRResults> {
        let (tx, rx) = mpsc::channel();
        self.inner.search_ptr(name, move |result| {
            tx.send(result).unwrap()
        });
        rx.recv().unwrap()
    }

    /// Look up the SOA records associated with `name`.
    pub fn query_soa(&self, name: &str) -> c_ares::Result<c_ares::SOAResult> {
        let (tx, rx) = mpsc::channel();
        self.inner.query_soa(name, move |result| {
            tx.send(result).unwrap()
        });
        rx.recv().unwrap()
    }

    /// Search for the SOA records associated with `name`.
    pub fn search_soa(&self, name: &str) -> c_ares::Result<c_ares::SOAResult> {
        let (tx, rx) = mpsc::channel();
        self.inner.search_soa(name, move |result| {
            tx.send(result).unwrap()
        });
        rx.recv().unwrap()
    }

    /// Look up the SRV records associated with `name`.
    pub fn query_srv(&self, name: &str) -> c_ares::Result<c_ares::SRVResults> {
        let (tx, rx) = mpsc::channel();
        self.inner.query_srv(name, move |result| {
            tx.send(result).unwrap()
        });
        rx.recv().unwrap()
    }

    /// Search for the SRV records associated with `name`.
    pub fn search_srv(&self, name: &str) -> c_ares::Result<c_ares::SRVResults> {
        let (tx, rx) = mpsc::channel();
        self.inner.search_srv(name, move |result| {
            tx.send(result).unwrap()
        });
        rx.recv().unwrap()
    }

    /// Look up the TXT records associated with `name`.
    pub fn query_txt(&self, name: &str) -> c_ares::Result<c_ares::TXTResults> {
        let (tx, rx) = mpsc::channel();
        self.inner.query_txt(name, move |result| {
            tx.send(result).unwrap()
        });
        rx.recv().unwrap()
    }

    /// Search for the TXT records associated with `name`.
    pub fn search_txt(&self, name: &str) -> c_ares::Result<c_ares::TXTResults> {
        let (tx, rx) = mpsc::channel();
        self.inner.search_txt(name, move |result| {
            tx.send(result).unwrap()
        });
        rx.recv().unwrap()
    }

    /// Perform a host query by address.
    ///
    /// This method is one of the very few places where this library performs
    /// strictly more allocation than the underlying `c-ares` code.  If this is
    /// a problem for you, you should prefer to use the analogous method on the
    /// `Resolver`.
    pub fn get_host_by_address(&self, address: &IpAddr)
        -> c_ares::Result<HostResults> {
        let (tx, rx) = mpsc::channel();
        self.inner.get_host_by_address(address, move |result| {
            tx.send(result.map(|h| h.into())).unwrap()
        });
        rx.recv().unwrap()
    }

    /// Perform a host query by name.
    ///
    /// This method is one of the very few places where this library performs
    /// strictly more allocation than the underlying `c-ares` code.  If this is
    /// a problem for you, you should prefer to use the analogous method on the
    /// `Resolver`.
    pub fn get_host_by_name(&self, name: &str, family: c_ares::AddressFamily)
        -> c_ares::Result<HostResults> {
        let (tx, rx) = mpsc::channel();
        self.inner.get_host_by_name(name, family, move |result| {
            tx.send(result.map(|h| h.into())).unwrap()
        });
        rx.recv().unwrap()
    }

    /// Address-to-nodename translation in protocol-independent manner.
    ///
    /// This method is one of the very few places where this library performs
    /// strictly more allocation than the underlying `c-ares` code.  If this is
    /// a problem for you, you should prefer to use the analogous method on the
    /// `Resolver`.
    pub fn get_name_info<F>(
        &self,
        address: &SocketAddr,
        flags: c_ares::NIFlags)
        -> c_ares::Result<NameInfoResult> {
        let (tx, rx) = mpsc::channel();
        self.inner.get_name_info(address, flags, move |result| {
            tx.send(result.map(|n| n.into())).unwrap()
        });
        rx.recv().unwrap()
    }

    /// Initiate a single-question DNS query for `name`.  The class and type of
    /// the query are per the provided parameters, taking values as defined in
    /// `arpa/nameser.h`.
    ///
    /// This method is one of the very few places where this library performs
    /// strictly more allocation than the underlying `c-ares` code.  If this is
    /// a problem for you, you should prefer to use the analogous method on the
    /// `Resolver`.
    ///
    /// This method is provided so that users can query DNS types for which
    /// `c-ares` does not provide a parser; or in case a third-party parser is
    /// preferred.  Usually, if a suitable `query_xxx()` is available, that
    /// should be used.
    pub fn query(&self, name: &str, dns_class: u16, query_type: u16)
        -> c_ares::Result<Vec<u8>> {
        let (tx, rx) = mpsc::channel();
        self.inner.query(name, dns_class, query_type, move |result| {
            tx.send(result.map(|bs| bs.to_owned())).unwrap()
        });
        rx.recv().unwrap()
    }

    /// Initiate a series of single-question DNS queries for `name`.  The
    /// class and type of the query are per the provided parameters, taking
    /// values as defined in `arpa/nameser.h`.
    ///
    /// This method is one of the very few places where this library performs
    /// strictly more allocation than the underlying `c-ares` code.  If this is
    /// a problem for you, you should prefer to use the analogous method on the
    /// `Resolver`.
    ///
    /// This method is provided so that users can search DNS types for which
    /// `c-ares` does not provide a parser; or in case a third-party parser is
    /// preferred.  Usually, if a suitable `search_xxx()` is available, that
    /// should be used.
    pub fn search(&self, name: &str, dns_class: u16, query_type: u16)
        -> c_ares::Result<Vec<u8>> {
        let (tx, rx) = mpsc::channel();
        self.inner.search(name, dns_class, query_type, move |result| {
            tx.send(result.map(|bs| bs.to_owned())).unwrap()
        });
        rx.recv().unwrap()
    }
}
<commit_msg>macro away some repetition<commit_after>use std::net::{
    IpAddr,
    Ipv4Addr,
    Ipv6Addr,
    SocketAddr,
};
use std::sync::mpsc;
use c_ares;

use error::Error;
use host::HostResults;
use nameinfo::NameInfoResult;
use resolver::{
    Options,
    Resolver,
};

/// A blocking DNS resolver.
pub struct BlockingResolver {
    inner: Resolver,
}

// Most query implementations follow the same pattern: call through to the
// `Resolver`, arranging that the callback sends the result down a channel.
macro_rules! blockify {
    ($resolver:expr, $query:ident, $question:expr) => {
        {
            let (tx, rx) = mpsc::channel();
            $resolver.$query($question, move |result| {
                tx.send(result).unwrap()
            });
            rx.recv().unwrap()
        }
    }
}

impl BlockingResolver {
    /// Create a new `BlockingResolver`, using default `Options`.
    pub fn new() -> Result<BlockingResolver, Error> {
        let options = Options::default();
        Self::with_options(options)
    }

    /// Create a new `BlockingResolver`, with the given `Options`.
    pub fn with_options(options: Options) -> Result<BlockingResolver, Error> {
        let inner = Resolver::with_options(options)?;
        let resolver = BlockingResolver {
            inner: inner,
        };
        Ok(resolver)
    }

    /// Set the list of servers to contact, instead of the servers specified
    /// in resolv.conf or the local named.
    ///
    /// String format is `host[:port]`.  IPv6 addresses with ports require
    /// square brackets eg `[2001:4860:4860::8888]:53`.
    pub fn set_servers(
        &mut self,
        servers: &[&str]) -> Result<&mut Self, c_ares::Error> {
        self.inner.set_servers(servers)?;
        Ok(self)
    }

    /// Set the local IPv4 address from which to make queries.
    pub fn set_local_ipv4(&mut self, ipv4: &Ipv4Addr) -> &mut Self {
        self.inner.set_local_ipv4(ipv4);
        self
    }

    /// Set the local IPv6 address from which to make queries.
    pub fn set_local_ipv6(&mut self, ipv6: &Ipv6Addr) -> &mut Self {
        self.inner.set_local_ipv6(ipv6);
        self
    }

    /// Set the local device from which to make queries.
    pub fn set_local_device(&mut self, device: &str) -> &mut Self {
        self.inner.set_local_device(device);
        self
    }

    /// Look up the A records associated with `name`.
    pub fn query_a(&self, name: &str) -> c_ares::Result<c_ares::AResults> {
        blockify!(self.inner, query_a, name)
    }

    /// Search for the A records associated with `name`.
    pub fn search_a(&self, name: &str) -> c_ares::Result<c_ares::AResults> {
        blockify!(self.inner, search_a, name)
    }

    /// Look up the AAAA records associated with `name`.
    pub fn query_aaaa(&self, name: &str)
        -> c_ares::Result<c_ares::AAAAResults>
    {
        blockify!(self.inner, query_aaaa, name)
    }

    /// Search for the AAAA records associated with `name`.
    pub fn search_aaaa(&self, name: &str)
        -> c_ares::Result<c_ares::AAAAResults> {
        blockify!(self.inner, search_aaaa, name)
    }

    /// Look up the CNAME records associated with `name`.
    pub fn query_cname(&self, name: &str)
        -> c_ares::Result<c_ares::CNameResults>
    {
        blockify!(self.inner, query_cname, name)
    }

    /// Search for the CNAME records associated with `name`.
    pub fn search_cname(&self, name: &str)
        -> c_ares::Result<c_ares::CNameResults>
    {
        blockify!(self.inner, search_cname, name)
    }

    /// Look up the MX records associated with `name`.
    pub fn query_mx(&self, name: &str) -> c_ares::Result<c_ares::MXResults> {
        blockify!(self.inner, query_mx, name)
    }

    /// Search for the MX records associated with `name`.
    pub fn search_mx(&self, name: &str) -> c_ares::Result<c_ares::MXResults> {
        blockify!(self.inner, search_mx, name)
    }

    /// Look up the NAPTR records associated with `name`.
    pub fn query_naptr(&self, name: &str)
        -> c_ares::Result<c_ares::NAPTRResults>
    {
        blockify!(self.inner, query_naptr, name)
    }

    /// Search for the NAPTR records associated with `name`.
    pub fn search_naptr(&self, name: &str)
        -> c_ares::Result<c_ares::NAPTRResults>
    {
        blockify!(self.inner, search_naptr, name)
    }

    /// Look up the NS records associated with `name`.
    pub fn query_ns(&self, name: &str) -> c_ares::Result<c_ares::NSResults> {
        blockify!(self.inner, query_ns, name)
    }

    /// Search for the NS records associated with `name`.
    pub fn search_ns(&self, name: &str) -> c_ares::Result<c_ares::NSResults> {
        blockify!(self.inner, search_ns, name)
    }

    /// Look up the PTR records associated with `name`.
    pub fn query_ptr(&self, name: &str) -> c_ares::Result<c_ares::PTRResults> {
        blockify!(self.inner, query_ptr, name)
    }

    /// Search for the PTR records associated with `name`.
    pub fn search_ptr(&self, name: &str)
        -> c_ares::Result<c_ares::PTRResults>
    {
        blockify!(self.inner, search_ptr, name)
    }

    /// Look up the SOA records associated with `name`.
    pub fn query_soa(&self, name: &str) -> c_ares::Result<c_ares::SOAResult> {
        blockify!(self.inner, query_soa, name)
    }

    /// Search for the SOA records associated with `name`.
    pub fn search_soa(&self, name: &str) -> c_ares::Result<c_ares::SOAResult> {
        blockify!(self.inner, search_soa, name)
    }

    /// Look up the SRV records associated with `name`.
    pub fn query_srv(&self, name: &str) -> c_ares::Result<c_ares::SRVResults> {
        blockify!(self.inner, query_srv, name)
    }

    /// Search for the SRV records associated with `name`.
    pub fn search_srv(&self, name: &str)
        -> c_ares::Result<c_ares::SRVResults>
    {
        blockify!(self.inner, search_srv, name)
    }

    /// Look up the TXT records associated with `name`.
    pub fn query_txt(&self, name: &str) -> c_ares::Result<c_ares::TXTResults> {
        blockify!(self.inner, query_txt, name)
    }

    /// Search for the TXT records associated with `name`.
    pub fn search_txt(&self, name: &str)
        -> c_ares::Result<c_ares::TXTResults>
    {
        blockify!(self.inner, search_txt, name)
    }

    /// Perform a host query by address.
    ///
    /// This method is one of the very few places where this library performs
    /// strictly more allocation than the underlying `c-ares` code.  If this is
    /// a problem for you, you should prefer to use the analogous method on the
    /// `Resolver`.
    pub fn get_host_by_address(&self, address: &IpAddr)
        -> c_ares::Result<HostResults> {
        let (tx, rx) = mpsc::channel();
        self.inner.get_host_by_address(address, move |result| {
            tx.send(result.map(|h| h.into())).unwrap()
        });
        rx.recv().unwrap()
    }

    /// Perform a host query by name.
    ///
    /// This method is one of the very few places where this library performs
    /// strictly more allocation than the underlying `c-ares` code.  If this is
    /// a problem for you, you should prefer to use the analogous method on the
    /// `Resolver`.
    pub fn get_host_by_name(&self, name: &str, family: c_ares::AddressFamily)
        -> c_ares::Result<HostResults> {
        let (tx, rx) = mpsc::channel();
        self.inner.get_host_by_name(name, family, move |result| {
            tx.send(result.map(|h| h.into())).unwrap()
        });
        rx.recv().unwrap()
    }

    /// Address-to-nodename translation in protocol-independent manner.
    ///
    /// This method is one of the very few places where this library performs
    /// strictly more allocation than the underlying `c-ares` code.  If this is
    /// a problem for you, you should prefer to use the analogous method on the
    /// `Resolver`.
    pub fn get_name_info<F>(
        &self,
        address: &SocketAddr,
        flags: c_ares::NIFlags)
        -> c_ares::Result<NameInfoResult> {
        let (tx, rx) = mpsc::channel();
        self.inner.get_name_info(address, flags, move |result| {
            tx.send(result.map(|n| n.into())).unwrap()
        });
        rx.recv().unwrap()
    }

    /// Initiate a single-question DNS query for `name`.  The class and type of
    /// the query are per the provided parameters, taking values as defined in
    /// `arpa/nameser.h`.
    ///
    /// This method is one of the very few places where this library performs
    /// strictly more allocation than the underlying `c-ares` code.  If this is
    /// a problem for you, you should prefer to use the analogous method on the
    /// `Resolver`.
    ///
    /// This method is provided so that users can query DNS types for which
    /// `c-ares` does not provide a parser; or in case a third-party parser is
    /// preferred.  Usually, if a suitable `query_xxx()` is available, that
    /// should be used.
    pub fn query(&self, name: &str, dns_class: u16, query_type: u16)
        -> c_ares::Result<Vec<u8>> {
        let (tx, rx) = mpsc::channel();
        self.inner.query(name, dns_class, query_type, move |result| {
            tx.send(result.map(|bs| bs.to_owned())).unwrap()
        });
        rx.recv().unwrap()
    }

    /// Initiate a series of single-question DNS queries for `name`.  The
    /// class and type of the query are per the provided parameters, taking
    /// values as defined in `arpa/nameser.h`.
    ///
    /// This method is one of the very few places where this library performs
    /// strictly more allocation than the underlying `c-ares` code.  If this is
    /// a problem for you, you should prefer to use the analogous method on the
    /// `Resolver`.
    ///
    /// This method is provided so that users can search DNS types for which
    /// `c-ares` does not provide a parser; or in case a third-party parser is
    /// preferred.  Usually, if a suitable `search_xxx()` is available, that
    /// should be used.
    pub fn search(&self, name: &str, dns_class: u16, query_type: u16)
        -> c_ares::Result<Vec<u8>> {
        let (tx, rx) = mpsc::channel();
        self.inner.search(name, dns_class, query_type, move |result| {
            tx.send(result.map(|bs| bs.to_owned())).unwrap()
        });
        rx.recv().unwrap()
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

// Copyright (c) 2016, Stepan Koltsov
//
// 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::HashMap;

use protobuf;
use protobuf::compiler_plugin;
use protobuf::code_writer::CodeWriter;
use protobuf::descriptor::*;
use protobuf::descriptorx::*;

use super::util::{MethodType, fq_grpc, to_snake_case};

struct MethodGen<'a> {
    proto: &'a MethodDescriptorProto,
    service_name: String,
    service_path: String,
    root_scope: &'a RootScope<'a>,
}

impl<'a> MethodGen<'a> {
    fn new(proto: &'a MethodDescriptorProto,
           service_name: String,
           service_path: String,
           root_scope: &'a RootScope<'a>)
           -> MethodGen<'a> {
        MethodGen {
            proto: proto,
            service_name: service_name,
            service_path: service_path,
            root_scope: root_scope,
        }
    }

    fn input(&self) -> String {
        format!("super::{}",
                self.root_scope
                    .find_message(self.proto.get_input_type())
                    .rust_fq_name())
    }

    fn output(&self) -> String {
        format!("super::{}",
                self.root_scope
                    .find_message(self.proto.get_output_type())
                    .rust_fq_name())
    }

    fn method_type(&self) -> (MethodType, String) {
        match (self.proto.get_client_streaming(), self.proto.get_server_streaming()) {
            (false, false) => (MethodType::Unary, fq_grpc("MethodType::Unary")),
            (true, false) => (MethodType::ClientStreaming, fq_grpc("MethodType::ClientStreaming")),
            (false, true) => (MethodType::ServerStreaming, fq_grpc("MethodType::ServerStreaming")),
            (true, true) => (MethodType::Duplex, fq_grpc("MethodType::Duplex")),
        }
    }

    fn service_name(&self) -> String {
        to_snake_case(&self.service_name)
    }

    fn name(&self) -> String {
        to_snake_case(self.proto.get_name())
    }

    fn fq_name(&self) -> String {
        format!("\"{}/{}\"", self.service_path, &self.proto.get_name())
    }

    fn const_method_name(&self) -> String {
        format!("METHOD_{}_{}",
                self.service_name().to_uppercase(),
                self.name().to_uppercase())
    }

    fn write_definition(&self, w: &mut CodeWriter) {
        w.block(&format!("const {}: {} = {} {{",
                         self.const_method_name(),
                         fq_grpc("Method"),
                         fq_grpc("Method")),
                &format!("}};"),
                |w| {
                    w.field_entry("ty", &self.method_type().1);
                    w.field_entry("name", &self.fq_name());
                });
    }

    // Method signatures
    fn unary(&self, method_name: &str) -> String {
        format!("{}(&self, req: {}) -> {}<{}>",
                method_name,
                self.input(),
                fq_grpc("Result"),
                self.output())
    }

    fn unary_opt(&self, method_name: &str) -> String {
        format!("{}_opt(&self, req: {}, opt: {}) -> {}<{}>",
                method_name,
                self.input(),
                fq_grpc("CallOption"),
                fq_grpc("Result"),
                self.output())
    }

    fn unary_async(&self, method_name: &str) -> String {
        format!("{}_async(&self, req: {}) -> {}<{}>",
                method_name,
                self.input(),
                fq_grpc("UnaryCallHandler"),
                self.output())
    }

    fn unary_async_opt(&self, method_name: &str) -> String {
        format!("{}_async_opt(&self, req: {}, opt: {}) -> {}<{}>",
                method_name,
                self.input(),
                fq_grpc("CallOption"),
                fq_grpc("UnaryCallHandler"),
                self.output())
    }

    fn client_streaming(&self, method_name: &str) -> String {
        format!("{}(&self) -> {}<{}, {}>",
                method_name,
                fq_grpc("ClientStreamingCallHandler"),
                self.input(),
                self.output())
    }

    fn client_streaming_opt(&self, method_name: &str) -> String {
        format!("{}_opt(&self, opt: {}) -> {}<{}, {}>",
                method_name,
                fq_grpc("CallOption"),
                fq_grpc("ClientStreamingCallHandler"),
                self.input(),
                self.output())
    }

    fn server_streaming(&self, method_name: &str) -> String {
        format!("{}(&self, req: {}) -> {}<{}>",
                method_name,
                self.input(),
                fq_grpc("ServerStreamingCallHandler"),
                self.output())
    }

    fn server_streaming_opt(&self, method_name: &str) -> String {
        format!("{}_opt(&self, req: {}, opt: {}) -> {}<{}>",
                method_name,
                self.input(),
                fq_grpc("CallOption"),
                fq_grpc("ServerStreamingCallHandler"),
                self.output())
    }

    fn duplex_streaming(&self, method_name: &str) -> String {
        format!("{}(&self) -> {}<{}, {}>",
                method_name,
                fq_grpc("DuplexCallHandler"),
                self.input(),
                self.output())
    }

    fn duplex_streaming_opt(&self, method_name: &str) -> String {
        format!("{}_opt(&self, opt: {}) -> {}<{}, {}>",
                method_name,
                fq_grpc("CallOption"),
                fq_grpc("DuplexCallHandler"),
                self.input(),
                self.output())
    }

    fn write_client(&self, w: &mut CodeWriter) {
        let method_name = self.name();
        match self.method_type().0 {
            // Unary
            MethodType::Unary => {
                w.pub_fn(&self.unary_opt(&method_name), |w| {
                    w.write_line(&format!("self.client.unary_call(&{}, req, opt)",
                                          self.const_method_name()));
                });
                w.write_line("");

                w.pub_fn(&self.unary(&method_name), |w| {
                    w.write_line(&format!("self.{}_opt(req, {})",
                                          method_name,
                                          fq_grpc("CallOption::default()")));
                });
                w.write_line("");

                w.pub_fn(&self.unary_async_opt(&method_name), |w| {
                    w.write_line(&format!("self.client.unary_call_async(&{}, req, opt)",
                                          self.const_method_name()));
                });
                w.write_line("");

                w.pub_fn(&self.unary_async(&method_name), |w| {
                    w.write_line(&format!("self.{}_async_opt(req, {})",
                                          method_name,
                                          fq_grpc("CallOption::default()")));
                });
            }

            // Client streaming
            MethodType::ClientStreaming => {
                w.pub_fn(&self.client_streaming_opt(&method_name), |w| {
                    w.write_line(&format!("self.client.client_streaming(&{}, opt)",
                                          self.const_method_name()));
                });
                w.write_line("");

                w.pub_fn(&self.client_streaming(&method_name), |w| {
                    w.write_line(&format!("self.{}_opt({})",
                                          method_name,
                                          fq_grpc("CallOption::default()")));
                });
            }

            // Server streaming
            MethodType::ServerStreaming => {
                w.pub_fn(&self.server_streaming_opt(&method_name), |w| {
                    w.write_line(&format!("self.client.server_streaming(&{}, req, opt)",
                                          self.const_method_name()));
                });
                w.write_line("");

                w.pub_fn(&self.server_streaming(&method_name), |w| {
                    w.write_line(&format!("self.{}_opt(req, {})",
                                          method_name,
                                          fq_grpc("CallOption::default()")));
                });
            }

            // Duplex streaming
            MethodType::Duplex => {
                w.pub_fn(&self.duplex_streaming_opt(&method_name), |w| {
                    w.write_line(&format!("self.client.duplex_streaming(&{}, opt)",
                                          self.const_method_name()));
                });
                w.write_line("");

                w.pub_fn(&self.duplex_streaming(&method_name), |w| {
                    w.write_line(&format!("self.{}_opt({})",
                                          method_name,
                                          fq_grpc("CallOption::default()")));
                });
            }
        };
    }

    fn write_service(&self, w: &mut CodeWriter) {
        let (req, resp) = match self.method_type().0 {
            MethodType::Unary => ("", "UnarySink"),
            MethodType::ClientStreaming => ("RequestStream", "ClientStreamingSink"),
            MethodType::ServerStreaming => ("", "ServerStreamingSink"),
            MethodType::Duplex => ("RequestStream", "DuplexSink"),
        };
        let req = if req.is_empty() {
            self.input()
        } else {
            format!("{}<{}>", fq_grpc(req), self.input())
        };
        let sig = format!("{}(&self, ctx: {}, req: {}, resp: {}<{}>)",
                          self.name(),
                          fq_grpc("RpcContext"),
                          req,
                          fq_grpc(resp),
                          self.output());
        w.fn_def(&sig);
    }

    fn write_bind(&self, w: &mut CodeWriter) {
        let add = match self.method_type().0 {
            MethodType::Unary => "add_unary_handler",
            MethodType::ClientStreaming => "add_client_streaming_handler",
            MethodType::ServerStreaming => "add_server_streaming_handler",
            MethodType::Duplex => "add_duplex_streaming_handler",
        };
        w.block(&format!("builder = builder.{}(&{}, move |ctx, req, resp| {{",
                         add,
                         self.const_method_name()),
                "});",
                |w| { w.write_line(&format!("instance.{}(ctx, req, resp)", self.name())); });
    }
}

struct ServiceGen<'a> {
    proto: &'a ServiceDescriptorProto,
    methods: Vec<MethodGen<'a>>,
}

impl<'a> ServiceGen<'a> {
    fn new(proto: &'a ServiceDescriptorProto,
           file: &FileDescriptorProto,
           root_scope: &'a RootScope)
           -> ServiceGen<'a> {
        let service_path = if file.get_package().is_empty() {
            format!("/{}", proto.get_name())
        } else {
            format!("/{}.{}", file.get_package(), proto.get_name())
        };
        let methods = proto
            .get_method()
            .into_iter()
            .map(|m| {
                     MethodGen::new(m,
                                    proto.get_name().to_string(),
                                    service_path.clone(),
                                    root_scope)
                 })
            .collect();

        ServiceGen {
            proto: proto,
            methods: methods,
        }
    }

    fn service_name(&self) -> &str {
        self.proto.get_name()
    }

    fn client_name(&self) -> String {
        format!("{}Client", self.service_name())
    }

    fn write_client(&self, w: &mut CodeWriter) {
        w.pub_struct(&self.client_name(),
                     |w| { w.field_decl("client", "::grpc::Client"); });

        w.write_line("");

        w.impl_self_block(&self.client_name(), |w| {
            w.pub_fn("new(channel: ::grpc::Channel) -> Self", |w| {
                w.expr_block(&self.client_name(),
                             |w| { w.field_entry("client", "::grpc::Client::new(channel)"); });
            });

            for method in &self.methods {
                w.write_line("");
                method.write_client(w);
            }
        });
    }

    fn write_server(&self, w: &mut CodeWriter) {
        w.pub_trait(&self.service_name(), |w| for method in &self.methods {
            method.write_service(w);
        });

        w.write_line("");

        w.pub_fn(&format!("create_{}<S: {} + Send + Clone + 'static>(s: S) -> {}",
                          to_snake_case(self.service_name()),
                          self.service_name(),
                          fq_grpc("Service")),
                 |w| {
                     w.write_line("let mut builder = ::grpc::ServiceBuilder::new();");
                     for method in &self.methods {
                         w.write_line("let instance = s.clone();");
                         method.write_bind(w);
                     }
                     w.write_line("builder.build()");
                 });
    }

    fn write_method_definitions(&self, w: &mut CodeWriter) {
        for (i, method) in self.methods.iter().enumerate() {
            if i != 0 {
                w.write_line("");
            }

            method.write_definition(w);
        }
    }

    fn write(&self, w: &mut CodeWriter) {
        self.write_method_definitions(w);
        w.write_line("");
        self.write_client(w);
        w.write_line("");
        self.write_server(w);
    }
}

fn gen_file(file: &FileDescriptorProto,
            root_scope: &RootScope)
            -> Option<compiler_plugin::GenResult> {
    if file.get_service().is_empty() {
        return None;
    }

    let base = protobuf::descriptorx::proto_path_to_rust_mod(file.get_name());

    let mut v = Vec::new();
    {
        let mut w = CodeWriter::new(&mut v);
        w.write_generated();

        for service in file.get_service() {
            w.write_line("");
            ServiceGen::new(service, file, root_scope).write(&mut w);
        }
    }

    Some(compiler_plugin::GenResult {
             name: base + "_grpc.rs",
             content: v,
         })
}

pub fn gen(file_descriptors: &[FileDescriptorProto],
           files_to_generate: &[String])
           -> Vec<compiler_plugin::GenResult> {
    let files_map: HashMap<&str, &FileDescriptorProto> = file_descriptors
        .iter()
        .map(|f| (f.get_name(), f))
        .collect();

    let root_scope = RootScope { file_descriptors: file_descriptors };

    let mut results = Vec::new();

    for file_name in files_to_generate {
        let file = files_map[&file_name[..]];

        if file.get_service().is_empty() {
            continue;
        }

        results.extend(gen_file(file, &root_scope).into_iter());
    }

    results
}

pub fn protoc_gen_grpc_rust_main() {
    compiler_plugin::plugin_main(gen);
}
<commit_msg>compiler: update argument names. (#21)<commit_after>// Copyright 2017 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

// Copyright (c) 2016, Stepan Koltsov
//
// 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::HashMap;

use protobuf;
use protobuf::compiler_plugin;
use protobuf::code_writer::CodeWriter;
use protobuf::descriptor::*;
use protobuf::descriptorx::*;

use super::util::{MethodType, fq_grpc, to_snake_case};

struct MethodGen<'a> {
    proto: &'a MethodDescriptorProto,
    service_name: String,
    service_path: String,
    root_scope: &'a RootScope<'a>,
}

impl<'a> MethodGen<'a> {
    fn new(proto: &'a MethodDescriptorProto,
           service_name: String,
           service_path: String,
           root_scope: &'a RootScope<'a>)
           -> MethodGen<'a> {
        MethodGen {
            proto: proto,
            service_name: service_name,
            service_path: service_path,
            root_scope: root_scope,
        }
    }

    fn input(&self) -> String {
        format!("super::{}",
                self.root_scope
                    .find_message(self.proto.get_input_type())
                    .rust_fq_name())
    }

    fn output(&self) -> String {
        format!("super::{}",
                self.root_scope
                    .find_message(self.proto.get_output_type())
                    .rust_fq_name())
    }

    fn method_type(&self) -> (MethodType, String) {
        match (self.proto.get_client_streaming(), self.proto.get_server_streaming()) {
            (false, false) => (MethodType::Unary, fq_grpc("MethodType::Unary")),
            (true, false) => (MethodType::ClientStreaming, fq_grpc("MethodType::ClientStreaming")),
            (false, true) => (MethodType::ServerStreaming, fq_grpc("MethodType::ServerStreaming")),
            (true, true) => (MethodType::Duplex, fq_grpc("MethodType::Duplex")),
        }
    }

    fn service_name(&self) -> String {
        to_snake_case(&self.service_name)
    }

    fn name(&self) -> String {
        to_snake_case(self.proto.get_name())
    }

    fn fq_name(&self) -> String {
        format!("\"{}/{}\"", self.service_path, &self.proto.get_name())
    }

    fn const_method_name(&self) -> String {
        format!("METHOD_{}_{}",
                self.service_name().to_uppercase(),
                self.name().to_uppercase())
    }

    fn write_definition(&self, w: &mut CodeWriter) {
        w.block(&format!("const {}: {} = {} {{",
                         self.const_method_name(),
                         fq_grpc("Method"),
                         fq_grpc("Method")),
                &format!("}};"),
                |w| {
                    w.field_entry("ty", &self.method_type().1);
                    w.field_entry("name", &self.fq_name());
                });
    }

    // Method signatures
    fn unary(&self, method_name: &str) -> String {
        format!("{}(&self, req: {}) -> {}<{}>",
                method_name,
                self.input(),
                fq_grpc("Result"),
                self.output())
    }

    fn unary_opt(&self, method_name: &str) -> String {
        format!("{}_opt(&self, req: {}, opt: {}) -> {}<{}>",
                method_name,
                self.input(),
                fq_grpc("CallOption"),
                fq_grpc("Result"),
                self.output())
    }

    fn unary_async(&self, method_name: &str) -> String {
        format!("{}_async(&self, req: {}) -> {}<{}>",
                method_name,
                self.input(),
                fq_grpc("UnaryCallHandler"),
                self.output())
    }

    fn unary_async_opt(&self, method_name: &str) -> String {
        format!("{}_async_opt(&self, req: {}, opt: {}) -> {}<{}>",
                method_name,
                self.input(),
                fq_grpc("CallOption"),
                fq_grpc("UnaryCallHandler"),
                self.output())
    }

    fn client_streaming(&self, method_name: &str) -> String {
        format!("{}(&self) -> {}<{}, {}>",
                method_name,
                fq_grpc("ClientStreamingCallHandler"),
                self.input(),
                self.output())
    }

    fn client_streaming_opt(&self, method_name: &str) -> String {
        format!("{}_opt(&self, opt: {}) -> {}<{}, {}>",
                method_name,
                fq_grpc("CallOption"),
                fq_grpc("ClientStreamingCallHandler"),
                self.input(),
                self.output())
    }

    fn server_streaming(&self, method_name: &str) -> String {
        format!("{}(&self, req: {}) -> {}<{}>",
                method_name,
                self.input(),
                fq_grpc("ServerStreamingCallHandler"),
                self.output())
    }

    fn server_streaming_opt(&self, method_name: &str) -> String {
        format!("{}_opt(&self, req: {}, opt: {}) -> {}<{}>",
                method_name,
                self.input(),
                fq_grpc("CallOption"),
                fq_grpc("ServerStreamingCallHandler"),
                self.output())
    }

    fn duplex_streaming(&self, method_name: &str) -> String {
        format!("{}(&self) -> {}<{}, {}>",
                method_name,
                fq_grpc("DuplexCallHandler"),
                self.input(),
                self.output())
    }

    fn duplex_streaming_opt(&self, method_name: &str) -> String {
        format!("{}_opt(&self, opt: {}) -> {}<{}, {}>",
                method_name,
                fq_grpc("CallOption"),
                fq_grpc("DuplexCallHandler"),
                self.input(),
                self.output())
    }

    fn write_client(&self, w: &mut CodeWriter) {
        let method_name = self.name();
        match self.method_type().0 {
            // Unary
            MethodType::Unary => {
                w.pub_fn(&self.unary_opt(&method_name), |w| {
                    w.write_line(&format!("self.client.unary_call(&{}, req, opt)",
                                          self.const_method_name()));
                });
                w.write_line("");

                w.pub_fn(&self.unary(&method_name), |w| {
                    w.write_line(&format!("self.{}_opt(req, {})",
                                          method_name,
                                          fq_grpc("CallOption::default()")));
                });
                w.write_line("");

                w.pub_fn(&self.unary_async_opt(&method_name), |w| {
                    w.write_line(&format!("self.client.unary_call_async(&{}, req, opt)",
                                          self.const_method_name()));
                });
                w.write_line("");

                w.pub_fn(&self.unary_async(&method_name), |w| {
                    w.write_line(&format!("self.{}_async_opt(req, {})",
                                          method_name,
                                          fq_grpc("CallOption::default()")));
                });
            }

            // Client streaming
            MethodType::ClientStreaming => {
                w.pub_fn(&self.client_streaming_opt(&method_name), |w| {
                    w.write_line(&format!("self.client.client_streaming(&{}, opt)",
                                          self.const_method_name()));
                });
                w.write_line("");

                w.pub_fn(&self.client_streaming(&method_name), |w| {
                    w.write_line(&format!("self.{}_opt({})",
                                          method_name,
                                          fq_grpc("CallOption::default()")));
                });
            }

            // Server streaming
            MethodType::ServerStreaming => {
                w.pub_fn(&self.server_streaming_opt(&method_name), |w| {
                    w.write_line(&format!("self.client.server_streaming(&{}, req, opt)",
                                          self.const_method_name()));
                });
                w.write_line("");

                w.pub_fn(&self.server_streaming(&method_name), |w| {
                    w.write_line(&format!("self.{}_opt(req, {})",
                                          method_name,
                                          fq_grpc("CallOption::default()")));
                });
            }

            // Duplex streaming
            MethodType::Duplex => {
                w.pub_fn(&self.duplex_streaming_opt(&method_name), |w| {
                    w.write_line(&format!("self.client.duplex_streaming(&{}, opt)",
                                          self.const_method_name()));
                });
                w.write_line("");

                w.pub_fn(&self.duplex_streaming(&method_name), |w| {
                    w.write_line(&format!("self.{}_opt({})",
                                          method_name,
                                          fq_grpc("CallOption::default()")));
                });
            }
        };
    }

    fn write_service(&self, w: &mut CodeWriter) {
        let req_stream_type = format!("{}<{}>", fq_grpc("RequestStream"), self.input());
        let (req, req_type, resp_type) = match self.method_type().0 {
            MethodType::Unary => ("req", self.input(), "UnarySink"),
            MethodType::ClientStreaming => ("stream", req_stream_type, "ClientStreamingSink"),
            MethodType::ServerStreaming => ("req", self.input(), "ServerStreamSink"),
            MethodType::Duplex => ("stream", req_stream_type, "DuplexSink"),
        };
        let sig = format!("{}(&self, ctx: {}, {}: {}, sink: {}<{}>)",
                          self.name(),
                          fq_grpc("RpcContext"),
                          req,
                          req_type,
                          fq_grpc(resp_type),
                          self.output());
        w.fn_def(&sig);
    }

    fn write_bind(&self, w: &mut CodeWriter) {
        let add = match self.method_type().0 {
            MethodType::Unary => "add_unary_handler",
            MethodType::ClientStreaming => "add_client_streaming_handler",
            MethodType::ServerStreaming => "add_server_streaming_handler",
            MethodType::Duplex => "add_duplex_streaming_handler",
        };
        w.block(&format!("builder = builder.{}(&{}, move |ctx, req, resp| {{",
                         add,
                         self.const_method_name()),
                "});",
                |w| { w.write_line(&format!("instance.{}(ctx, req, resp)", self.name())); });
    }
}

struct ServiceGen<'a> {
    proto: &'a ServiceDescriptorProto,
    methods: Vec<MethodGen<'a>>,
}

impl<'a> ServiceGen<'a> {
    fn new(proto: &'a ServiceDescriptorProto,
           file: &FileDescriptorProto,
           root_scope: &'a RootScope)
           -> ServiceGen<'a> {
        let service_path = if file.get_package().is_empty() {
            format!("/{}", proto.get_name())
        } else {
            format!("/{}.{}", file.get_package(), proto.get_name())
        };
        let methods = proto
            .get_method()
            .into_iter()
            .map(|m| {
                     MethodGen::new(m,
                                    proto.get_name().to_string(),
                                    service_path.clone(),
                                    root_scope)
                 })
            .collect();

        ServiceGen {
            proto: proto,
            methods: methods,
        }
    }

    fn service_name(&self) -> &str {
        self.proto.get_name()
    }

    fn client_name(&self) -> String {
        format!("{}Client", self.service_name())
    }

    fn write_client(&self, w: &mut CodeWriter) {
        w.pub_struct(&self.client_name(),
                     |w| { w.field_decl("client", "::grpc::Client"); });

        w.write_line("");

        w.impl_self_block(&self.client_name(), |w| {
            w.pub_fn("new(channel: ::grpc::Channel) -> Self", |w| {
                w.expr_block(&self.client_name(),
                             |w| { w.field_entry("client", "::grpc::Client::new(channel)"); });
            });

            for method in &self.methods {
                w.write_line("");
                method.write_client(w);
            }
        });
    }

    fn write_server(&self, w: &mut CodeWriter) {
        w.pub_trait(&self.service_name(), |w| for method in &self.methods {
            method.write_service(w);
        });

        w.write_line("");

        w.pub_fn(&format!("create_{}<S: {} + Send + Clone + 'static>(s: S) -> {}",
                          to_snake_case(self.service_name()),
                          self.service_name(),
                          fq_grpc("Service")),
                 |w| {
                     w.write_line("let mut builder = ::grpc::ServiceBuilder::new();");
                     for method in &self.methods {
                         w.write_line("let instance = s.clone();");
                         method.write_bind(w);
                     }
                     w.write_line("builder.build()");
                 });
    }

    fn write_method_definitions(&self, w: &mut CodeWriter) {
        for (i, method) in self.methods.iter().enumerate() {
            if i != 0 {
                w.write_line("");
            }

            method.write_definition(w);
        }
    }

    fn write(&self, w: &mut CodeWriter) {
        self.write_method_definitions(w);
        w.write_line("");
        self.write_client(w);
        w.write_line("");
        self.write_server(w);
    }
}

fn gen_file(file: &FileDescriptorProto,
            root_scope: &RootScope)
            -> Option<compiler_plugin::GenResult> {
    if file.get_service().is_empty() {
        return None;
    }

    let base = protobuf::descriptorx::proto_path_to_rust_mod(file.get_name());

    let mut v = Vec::new();
    {
        let mut w = CodeWriter::new(&mut v);
        w.write_generated();

        for service in file.get_service() {
            w.write_line("");
            ServiceGen::new(service, file, root_scope).write(&mut w);
        }
    }

    Some(compiler_plugin::GenResult {
             name: base + "_grpc.rs",
             content: v,
         })
}

pub fn gen(file_descriptors: &[FileDescriptorProto],
           files_to_generate: &[String])
           -> Vec<compiler_plugin::GenResult> {
    let files_map: HashMap<&str, &FileDescriptorProto> = file_descriptors
        .iter()
        .map(|f| (f.get_name(), f))
        .collect();

    let root_scope = RootScope { file_descriptors: file_descriptors };

    let mut results = Vec::new();

    for file_name in files_to_generate {
        let file = files_map[&file_name[..]];

        if file.get_service().is_empty() {
            continue;
        }

        results.extend(gen_file(file, &root_scope).into_iter());
    }

    results
}

pub fn protoc_gen_grpc_rust_main() {
    compiler_plugin::plugin_main(gen);
}
<|endoftext|>


<commit_before>#![recursion_limit="128"]
#![cfg_attr(feature = "cargo-clippy", allow(cyclomatic_complexity, trivial_regex))]
use std::io::stderr;
use std::io::Write;
use std::collections::HashMap;

extern crate bam2bedgraph;
use bam2bedgraph::errors::*;
use bam2bedgraph::indexed_annotation::IndexedAnnotation;

extern crate bio;

extern crate structopt;
#[macro_use]
extern crate structopt_derive;
use structopt::StructOpt;

#[derive(StructOpt, Debug)]
#[structopt(name = "cassette_lengths", about = "Histogram of cassette exon lengths within the intron of tr of another gene")]
struct Options {
    // input files
    #[structopt(long="overlapping_genes", help = "Only show cassettes which overlap other genes?")]
    overlapping_genes: bool,
    // input files
    #[structopt(long="gff", help = "A genome annotation file in gff3 format", name="ANNOT_GFF_FILE")]
    annotfile_gff: Option<String>,
}

fn run() -> Result<()> {
    let options = Options::from_args();
    let annot = IndexedAnnotation::from_gff(
        &options.annotfile_gff.r()?,
        &None,
        &None)?;
    println!("row\tgene_name\tother_gene_name\tcassette_location\tcassette_length");
    for (row, record) in annot.rows.iter().enumerate() {
        if let Some(exon_type) = record.attributes.get("exon_type") {
            if exon_type == "cassette" && record.feature_type == "exon" {
                if let Some(record_gene_name) = record.attributes.get("gene_name") {
                    let mut other_genes = HashMap::<String,u64>::new();
                    for overlap_row in annot.tree[&record.seqname].find(record.start-1..record.end) {
                        let overlaps = &annot.rows[*overlap_row.data()];
                        if overlaps.strand == record.strand &&
                            (overlaps.feature_type == "gene" || overlaps.feature_type == "exon")
                        {
                            if let Some(overlaps_gene_name) = overlaps.attributes.get("gene_name") {
                                if overlaps_gene_name != record_gene_name &&
                                    &format!("{}.reannot", overlaps_gene_name) != record_gene_name
                                {
                                    if overlaps.feature_type == "exon" {
                                        *other_genes.entry(overlaps_gene_name.clone()).or_insert(0) += 1;
                                    }
                                    else {
                                        other_genes.entry(overlaps_gene_name.clone()).or_insert(0);
                                    }
                                }
                            }
                        }
                    }
                    let mut overlapping_genes = Vec::<String>::new();
                    for (gene_name,overlapping_exons) in other_genes {
                        if overlapping_exons == 0 {
                            overlapping_genes.push(gene_name.clone());
                        }
                    }
                    if options.overlapping_genes && !overlapping_genes.is_empty() {
                        println!("{}\t{}\t{}\t{}:{}..{}:{}\t{}",
                            row,
                            record_gene_name,
                            overlapping_genes.join(","),
                            record.seqname,
                            record.start,
                            record.end,
                            record.strand,
                            record.end-record.start+1);
                    }
                }
            }
        }
    }

    Ok(())
}

fn main() {
    std::env::set_var("RUST_BACKTRACE", "full");
    if let Err(ref e) = run() {
        writeln!(stderr(), "error: {}", e).unwrap();
        for e in e.iter().skip(1) {
            writeln!(stderr(), "caused by: {}", e).unwrap();
        }
        if let Some(backtrace) = e.backtrace() {
            writeln!(stderr(), "backtrace: {:?}", backtrace).unwrap();
        }
        ::std::process::exit(1);
    }
}
<commit_msg>add --overlapping_genes flag<commit_after>#![recursion_limit="128"]
#![cfg_attr(feature = "cargo-clippy", allow(cyclomatic_complexity, trivial_regex))]
use std::io::stderr;
use std::io::Write;
use std::collections::HashMap;

extern crate bam2bedgraph;
use bam2bedgraph::errors::*;
use bam2bedgraph::indexed_annotation::IndexedAnnotation;

extern crate bio;

extern crate structopt;
#[macro_use]
extern crate structopt_derive;
use structopt::StructOpt;

#[derive(StructOpt, Debug)]
#[structopt(name = "cassette_lengths", about = "Histogram of cassette exon lengths within the intron of tr of another gene")]
struct Options {
    // input files
    #[structopt(long="overlapping_genes", help = "Only show cassettes which overlap other genes?")]
    overlapping_genes: bool,
    // input files
    #[structopt(long="gff", help = "A genome annotation file in gff3 format", name="ANNOT_GFF_FILE")]
    annotfile_gff: Option<String>,
}

fn run() -> Result<()> {
    let options = Options::from_args();
    let annot = IndexedAnnotation::from_gff(
        &options.annotfile_gff.r()?,
        &None,
        &None)?;
    println!("row\tgene_name\tother_gene_name\tcassette_location\tcassette_length");
    for (row, record) in annot.rows.iter().enumerate() {
        if let Some(exon_type) = record.attributes.get("exon_type") {
            if exon_type == "cassette" && record.feature_type == "exon" {
                if let Some(record_gene_name) = record.attributes.get("gene_name") {
                    let mut other_genes = HashMap::<String,u64>::new();
                    for overlap_row in annot.tree[&record.seqname].find(record.start-1..record.end) {
                        let overlaps = &annot.rows[*overlap_row.data()];
                        if overlaps.strand == record.strand &&
                            (overlaps.feature_type == "gene" || overlaps.feature_type == "exon")
                        {
                            if let Some(overlaps_gene_name) = overlaps.attributes.get("gene_name") {
                                if overlaps_gene_name != record_gene_name &&
                                    &format!("{}.reannot", overlaps_gene_name) != record_gene_name
                                {
                                    if overlaps.feature_type == "exon" {
                                        *other_genes.entry(overlaps_gene_name.clone()).or_insert(0) += 1;
                                    }
                                    else {
                                        other_genes.entry(overlaps_gene_name.clone()).or_insert(0);
                                    }
                                }
                            }
                        }
                    }
                    let mut overlapping_genes = Vec::<String>::new();
                    for (gene_name,overlapping_exons) in other_genes {
                        if overlapping_exons == 0 {
                            overlapping_genes.push(gene_name.clone());
                        }
                    }
                    if !options.overlapping_genes || !overlapping_genes.is_empty() {
                        println!("{}\t{}\t{}\t{}:{}..{}:{}\t{}",
                            row,
                            record_gene_name,
                            overlapping_genes.join(","),
                            record.seqname,
                            record.start,
                            record.end,
                            record.strand,
                            record.end-record.start+1);
                    }
                }
            }
        }
    }

    Ok(())
}

fn main() {
    std::env::set_var("RUST_BACKTRACE", "full");
    if let Err(ref e) = run() {
        writeln!(stderr(), "error: {}", e).unwrap();
        for e in e.iter().skip(1) {
            writeln!(stderr(), "caused by: {}", e).unwrap();
        }
        if let Some(backtrace) = e.backtrace() {
            writeln!(stderr(), "backtrace: {:?}", backtrace).unwrap();
        }
        ::std::process::exit(1);
    }
}
<|endoftext|>