<commit_before>use bins::error::*;
use bins::Bins;
use bins::configuration::BinsConfiguration;
use bins::engines;
use bins::FlexibleRange;
use bins::network;
use clap::{App, Arg, ArgGroup};
use hyper::Url;
use std::path::Path;
use std::process;

pub struct Arguments {
  pub all: bool,
  pub auth: bool,
  pub bin: Option<String>,
  pub copy: bool,
  pub files: Vec<String>,
  pub force: bool,
  pub input: Option<String>,
  pub json: bool,
  pub message: Option<String>,
  pub name: Option<String>,
  pub number_lines: bool,
  pub output: Option<String>,
  pub private: bool,
  pub range: Option<FlexibleRange>,
  pub raw_urls: bool,
  pub server: Option<Url>,
  pub urls: bool,
  pub write: bool
}

include!(concat!(env!("OUT_DIR"), "/git_short_tag.rs"));

fn get_name() -> String {
  option_env!("CARGO_PKG_NAME").unwrap_or("unknown_name").to_owned()
}

fn get_version() -> String {
  let version = option_env!("CARGO_PKG_VERSION").unwrap_or("unknown_version").to_owned();
  let git_tag = git_short_tag();
  format!("{}{}", version, git_tag)
}

fn get_feature_info() -> Option<String> {
  let mut features = Vec::new();
  if cfg!(feature = "clipboard_support") {
    features.push("clipboard_support");
  }
  if cfg!(feature = "file_type_checking") {
    features.push("file_type_checking");
  }
  if features.is_empty() {
    None
  } else {
    Some(format!("features: {}", features.join(", ")))
  }
}

cfg_if! {
  if #[cfg(feature = "clipboard_support")] {
    fn get_clipboard_args<'a, 'b>() -> Vec<Arg<'a, 'b>> {
      vec![Arg::with_name("copy")
             .short("C")
             .long("copy")
             .help("copies the output of the command to the clipboard without a newline")
             .conflicts_with("no-copy"),
           Arg::with_name("no-copy")
             .short("c")
             .long("no-copy")
             .help("does not copy the output of the command to the clipboard")]
    }
  } else {
    fn get_clipboard_args<'a, 'b>() -> Vec<Arg<'a, 'b>> {
      Vec::new()
    }
  }
}

pub fn get_arguments(config: &BinsConfiguration) -> Result<Arguments> {
  let mut arguments = Arguments {
    all: false,
    auth: config.get_defaults_auth(),
    bin: config.get_defaults_bin().map(|s| s.to_owned()),
    copy: config.get_defaults_copy(),
    files: Vec::new(),
    force: false,
    input: None,
    json: false,
    message: None,
    name: None,
    number_lines: false,
    output: None,
    private: config.get_defaults_private(),
    range: None,
    raw_urls: false,
    server: None,
    urls: false,
    write: false
  };
  let name = get_name();
  let version = get_version();
  let feature_info = get_feature_info();
  let combined_version = match feature_info {
    Some(i) => format!("{}\n{}", version, i),
    None => version
  };
  let mut app = App::new(name.as_ref())
    .version(combined_version.as_ref())
    .about("A tool for pasting from the terminal")
    .arg(Arg::with_name("files")
      .help("files to paste")
      .takes_value(true)
      .multiple(true))
    .arg(Arg::with_name("message")
      .short("m")
      .long("message")
      .help("message to paste")
      .use_delimiter(false)
      .takes_value(true)
      .value_name("string"))
    .arg(Arg::with_name("private")
      .short("p")
      .long("private")
      .help("if the paste should be private")
      .conflicts_with("public"))
    .arg(Arg::with_name("public")
      .short("P")
      .long("public")
      .help("if the paste should be public"))
    .arg(Arg::with_name("auth")
      .short("a")
      .long("auth")
      .help("if authentication (like api keys and tokens) should be used")
      .conflicts_with("anon"))
    .arg(Arg::with_name("anon")
      .short("A")
      .long("anon")
      .help("if pastes should be posted without authentication"))
    .arg(Arg::with_name("bin")
      .short("b")
      .long("bin")
      .help("bin to use when uploading")
      .takes_value(true)
      .possible_values(&*engines::get_bin_names()))
    .arg(Arg::with_name("service")
      .short("s")
      .long("service")
      .help("legacy flag included for backwards compatibility. use --bin, as this will be removed in 2.0.0")
      .takes_value(true)
      .possible_values(&*engines::get_bin_names()))
    .group(ArgGroup::with_name("bin_or_service")
      .args(&["bin", "service"])
      .required(arguments.bin.is_none()))
    .arg(Arg::with_name("list-bins")
      .short("l")
      .long("list-bins")
      .help("lists available bins and exits")
      .conflicts_with_all(&["files", "message", "private", "public", "auth", "anon", "bin_or_service", "input"]))
    .arg(Arg::with_name("list-services")
      .long("list-services")
      .help("legacy flag included for backwards compatibility. use --list-bins, as this will be removed in 2.0.0")
      .conflicts_with_all(&["files", "message", "private", "public", "auth", "anon", "bin_or_service", "input"]))
    .group(ArgGroup::with_name("list-bins_or_list-services").args(&["list-bins", "list-services"]))
    .arg(Arg::with_name("input")
      .short("i")
      .long("input")
      .help("displays raw contents of input paste")
      .takes_value(true)
      .value_name("url")
      .conflicts_with_all(&["auth", "anon", "public", "private", "message", "bin_or_service"]))
    .arg(Arg::with_name("range")
      .short("n")
      .long("range")
      .help("chooses the files to get in input mode, starting from 0 (e.g. \"0\", \"0,1\", \"0-2\", \"2-0,3\")")
      .takes_value(true)
      .value_name("range")
      .use_delimiter(false)
      .requires("input")
      .conflicts_with("files"))
    .arg(Arg::with_name("all")
      .short("L")
      .long("all")
      .help("gets all files in input mode")
      .requires("input")
      .conflicts_with_all(&["files", "range"]))
    .arg(Arg::with_name("raw-urls")
      .short("r")
      .long("raw-urls")
      .help("gets the raw urls instead of the content in input mode")
      .requires("input"))
    .arg(Arg::with_name("urls")
      .short("u")
      .long("urls")
      .help("gets the urls instead of the content in input mode")
      .requires("input")
      .conflicts_with("raw-urls"))
    .arg(Arg::with_name("server")
      .short("S")
      .long("server")
      .help("specifies the server to use for the service (only support on hastebin)")
      .takes_value(true)
      .value_name("server_url"))
    .arg(Arg::with_name("name")
      .short("N")
      .long("name")
      .help("specifies a file name for --message or stdin")
      .takes_value(true)
      .value_name("name")
      .conflicts_with("files"))
    .arg(Arg::with_name("force")
      .short("f")
      .long("force")
      .help("overrides warnings about file type or size when uploading")
      .conflicts_with("input"))
    .arg(Arg::with_name("number_lines")
      .short("e")
      .long("number-lines")
      .help("display line numbers for each file in input mode")
      .requires("input"))
    .arg(Arg::with_name("write")
      .short("w")
      .long("write")
      .help("writes pastes to files in input mode")
      .requires("input"))
    .arg(Arg::with_name("output")
      .short("o")
      .long("output")
      .help("specifies where to save files in write mode")
      .takes_value(true)
      .value_name("dir")
      .requires("write"))
    .arg(Arg::with_name("json")
      .short("j")
      .long("json")
      .help("output a json object instead of normal values")
      .conflicts_with_all(&["write", "urls", "raw-urls"]));
  for arg in get_clipboard_args() {
    app = app.arg(arg);
  }
  let res = app.get_matches();
  if res.is_present("list-bins_or_list-services") {
    println!("{}", engines::get_bin_names().join("\n"));
    process::exit(0);
  }
  if let Some(files) = res.values_of("files") {
    arguments.files = files.map(|s| s.to_owned()).collect();
  }
  if let Some(message) = res.value_of("message") {
    arguments.message = Some(message.to_owned());
  }
  if let Some(bin) = res.value_of("bin_or_service") {
    arguments.bin = Some(bin.to_owned());
  }
  if let Some(input) = res.value_of("input") {
    arguments.input = Some(input.to_owned());
  }
  if let Some(range) = res.value_of("range") {
    arguments.range = Some(try!(FlexibleRange::parse(range)));
  }
  if let Some(server) = res.value_of("server") {
    if let Some(ref bin) = arguments.bin {
      if bin.to_lowercase() != "hastebin" {
        return Err("--server may only be used if --service is hastebin".into());
      }
    }
    arguments.server = Some(try!(network::parse_url(server).chain_err(|| "invalid --server")));
  }
  if let Some(name) = res.value_of("name") {
    let name = try!(Bins::sanitize_path(Path::new(name)));
    arguments.name = Some(name.to_owned());
  }
  if let Some(output) = res.value_of("output") {
    arguments.output = Some(output.to_owned());
  }
  arguments.all = res.is_present("all");
  arguments.force = res.is_present("force");
  arguments.json = res.is_present("json");
  arguments.number_lines = res.is_present("number_lines");
  arguments.raw_urls = res.is_present("raw-urls");
  arguments.urls = res.is_present("urls");
  arguments.write = res.is_present("write");
  if res.is_present("private") {
    arguments.private = true;
  } else if res.is_present("public") {
    arguments.private = false;
  }
  if res.is_present("anon") {
    arguments.auth = false;
  } else if res.is_present("auth") {
    arguments.auth = true;
  }
  if res.is_present("copy") {
    arguments.copy = true;
  } else if res.is_present("no-copy") {
    arguments.copy = false;
  }
  Ok(arguments)
}
<commit_msg>refactor(arguments): don't use cfg_if where not necessary<commit_after>use bins::error::*;
use bins::Bins;
use bins::configuration::BinsConfiguration;
use bins::engines;
use bins::FlexibleRange;
use bins::network;
use clap::{App, Arg, ArgGroup};
use hyper::Url;
use std::path::Path;
use std::process;

pub struct Arguments {
  pub all: bool,
  pub auth: bool,
  pub bin: Option<String>,
  pub copy: bool,
  pub files: Vec<String>,
  pub force: bool,
  pub input: Option<String>,
  pub json: bool,
  pub message: Option<String>,
  pub name: Option<String>,
  pub number_lines: bool,
  pub output: Option<String>,
  pub private: bool,
  pub range: Option<FlexibleRange>,
  pub raw_urls: bool,
  pub server: Option<Url>,
  pub urls: bool,
  pub write: bool
}

include!(concat!(env!("OUT_DIR"), "/git_short_tag.rs"));

fn get_name() -> String {
  option_env!("CARGO_PKG_NAME").unwrap_or("unknown_name").to_owned()
}

fn get_version() -> String {
  let version = option_env!("CARGO_PKG_VERSION").unwrap_or("unknown_version").to_owned();
  let git_tag = git_short_tag();
  format!("{}{}", version, git_tag)
}

fn get_feature_info() -> Option<String> {
  let mut features = Vec::new();
  if cfg!(feature = "clipboard_support") {
    features.push("clipboard_support");
  }
  if cfg!(feature = "file_type_checking") {
    features.push("file_type_checking");
  }
  if features.is_empty() {
    None
  } else {
    Some(format!("features: {}", features.join(", ")))
  }
}

fn get_feature_args<'a, 'b>() -> Vec<Arg<'a, 'b>> {
  let mut args = Vec::new();
  if cfg!(feature = "clipboard_support") {
    args.push(Arg::with_name("copy")
      .short("C")
      .long("copy")
      .help("copies the output of the command to the clipboard without a newline")
      .conflicts_with("no-copy"));
    args.push(Arg::with_name("no-copy")
      .short("c")
      .long("no-copy")
      .help("does not copy the output of the command to the clipboard"));
  }
  args
}

pub fn get_arguments(config: &BinsConfiguration) -> Result<Arguments> {
  let mut arguments = Arguments {
    all: false,
    auth: config.get_defaults_auth(),
    bin: config.get_defaults_bin().map(|s| s.to_owned()),
    copy: config.get_defaults_copy(),
    files: Vec::new(),
    force: false,
    input: None,
    json: false,
    message: None,
    name: None,
    number_lines: false,
    output: None,
    private: config.get_defaults_private(),
    range: None,
    raw_urls: false,
    server: None,
    urls: false,
    write: false
  };
  let name = get_name();
  let version = get_version();
  let feature_info = get_feature_info();
  let combined_version = match feature_info {
    Some(i) => format!("{}\n{}", version, i),
    None => version
  };
  let mut app = App::new(name.as_ref())
    .version(combined_version.as_ref())
    .about("A tool for pasting from the terminal")
    .arg(Arg::with_name("files")
      .help("files to paste")
      .takes_value(true)
      .multiple(true))
    .arg(Arg::with_name("message")
      .short("m")
      .long("message")
      .help("message to paste")
      .use_delimiter(false)
      .takes_value(true)
      .value_name("string"))
    .arg(Arg::with_name("private")
      .short("p")
      .long("private")
      .help("if the paste should be private")
      .conflicts_with("public"))
    .arg(Arg::with_name("public")
      .short("P")
      .long("public")
      .help("if the paste should be public"))
    .arg(Arg::with_name("auth")
      .short("a")
      .long("auth")
      .help("if authentication (like api keys and tokens) should be used")
      .conflicts_with("anon"))
    .arg(Arg::with_name("anon")
      .short("A")
      .long("anon")
      .help("if pastes should be posted without authentication"))
    .arg(Arg::with_name("bin")
      .short("b")
      .long("bin")
      .help("bin to use when uploading")
      .takes_value(true)
      .possible_values(&*engines::get_bin_names()))
    .arg(Arg::with_name("service")
      .short("s")
      .long("service")
      .help("legacy flag included for backwards compatibility. use --bin, as this will be removed in 2.0.0")
      .takes_value(true)
      .possible_values(&*engines::get_bin_names()))
    .group(ArgGroup::with_name("bin_or_service")
      .args(&["bin", "service"])
      .required(arguments.bin.is_none()))
    .arg(Arg::with_name("list-bins")
      .short("l")
      .long("list-bins")
      .help("lists available bins and exits")
      .conflicts_with_all(&["files", "message", "private", "public", "auth", "anon", "bin_or_service", "input"]))
    .arg(Arg::with_name("list-services")
      .long("list-services")
      .help("legacy flag included for backwards compatibility. use --list-bins, as this will be removed in 2.0.0")
      .conflicts_with_all(&["files", "message", "private", "public", "auth", "anon", "bin_or_service", "input"]))
    .group(ArgGroup::with_name("list-bins_or_list-services").args(&["list-bins", "list-services"]))
    .arg(Arg::with_name("input")
      .short("i")
      .long("input")
      .help("displays raw contents of input paste")
      .takes_value(true)
      .value_name("url")
      .conflicts_with_all(&["auth", "anon", "public", "private", "message", "bin_or_service"]))
    .arg(Arg::with_name("range")
      .short("n")
      .long("range")
      .help("chooses the files to get in input mode, starting from 0 (e.g. \"0\", \"0,1\", \"0-2\", \"2-0,3\")")
      .takes_value(true)
      .value_name("range")
      .use_delimiter(false)
      .requires("input")
      .conflicts_with("files"))
    .arg(Arg::with_name("all")
      .short("L")
      .long("all")
      .help("gets all files in input mode")
      .requires("input")
      .conflicts_with_all(&["files", "range"]))
    .arg(Arg::with_name("raw-urls")
      .short("r")
      .long("raw-urls")
      .help("gets the raw urls instead of the content in input mode")
      .requires("input"))
    .arg(Arg::with_name("urls")
      .short("u")
      .long("urls")
      .help("gets the urls instead of the content in input mode")
      .requires("input")
      .conflicts_with("raw-urls"))
    .arg(Arg::with_name("server")
      .short("S")
      .long("server")
      .help("specifies the server to use for the service (only support on hastebin)")
      .takes_value(true)
      .value_name("server_url"))
    .arg(Arg::with_name("name")
      .short("N")
      .long("name")
      .help("specifies a file name for --message or stdin")
      .takes_value(true)
      .value_name("name")
      .conflicts_with("files"))
    .arg(Arg::with_name("force")
      .short("f")
      .long("force")
      .help("overrides warnings about file type or size when uploading")
      .conflicts_with("input"))
    .arg(Arg::with_name("number_lines")
      .short("e")
      .long("number-lines")
      .help("display line numbers for each file in input mode")
      .requires("input"))
    .arg(Arg::with_name("write")
      .short("w")
      .long("write")
      .help("writes pastes to files in input mode")
      .requires("input"))
    .arg(Arg::with_name("output")
      .short("o")
      .long("output")
      .help("specifies where to save files in write mode")
      .takes_value(true)
      .value_name("dir")
      .requires("write"))
    .arg(Arg::with_name("json")
      .short("j")
      .long("json")
      .help("output a json object instead of normal values")
      .conflicts_with_all(&["write", "urls", "raw-urls"]));
  for arg in get_feature_args() {
    app = app.arg(arg);
  }
  let res = app.get_matches();
  if res.is_present("list-bins_or_list-services") {
    println!("{}", engines::get_bin_names().join("\n"));
    process::exit(0);
  }
  if let Some(files) = res.values_of("files") {
    arguments.files = files.map(|s| s.to_owned()).collect();
  }
  if let Some(message) = res.value_of("message") {
    arguments.message = Some(message.to_owned());
  }
  if let Some(bin) = res.value_of("bin_or_service") {
    arguments.bin = Some(bin.to_owned());
  }
  if let Some(input) = res.value_of("input") {
    arguments.input = Some(input.to_owned());
  }
  if let Some(range) = res.value_of("range") {
    arguments.range = Some(try!(FlexibleRange::parse(range)));
  }
  if let Some(server) = res.value_of("server") {
    if let Some(ref bin) = arguments.bin {
      if bin.to_lowercase() != "hastebin" {
        return Err("--server may only be used if --service is hastebin".into());
      }
    }
    arguments.server = Some(try!(network::parse_url(server).chain_err(|| "invalid --server")));
  }
  if let Some(name) = res.value_of("name") {
    let name = try!(Bins::sanitize_path(Path::new(name)));
    arguments.name = Some(name.to_owned());
  }
  if let Some(output) = res.value_of("output") {
    arguments.output = Some(output.to_owned());
  }
  arguments.all = res.is_present("all");
  arguments.force = res.is_present("force");
  arguments.json = res.is_present("json");
  arguments.number_lines = res.is_present("number_lines");
  arguments.raw_urls = res.is_present("raw-urls");
  arguments.urls = res.is_present("urls");
  arguments.write = res.is_present("write");
  if res.is_present("private") {
    arguments.private = true;
  } else if res.is_present("public") {
    arguments.private = false;
  }
  if res.is_present("anon") {
    arguments.auth = false;
  } else if res.is_present("auth") {
    arguments.auth = true;
  }
  if res.is_present("copy") {
    arguments.copy = true;
  } else if res.is_present("no-copy") {
    arguments.copy = false;
  }
  Ok(arguments)
}
<|endoftext|>


<commit_before>use std::sync::Arc;

use gluon::{
    self,
    base::{ast::OwnedExpr, fnv::FnvMap, metadata::Metadata, symbol::Symbol, types::ArcType},
    compiler_pipeline::TypecheckValue,
    import::Importer,
    query::AsyncCompilation,
    Error as GluonError, ModuleCompiler, Thread, ThreadExt,
};

use {futures::prelude::*, tokio::sync::Mutex, url::Url};

use crate::{name::module_name_to_file_, text_edit::TextChanges};

pub(crate) struct Module {
    pub source: Arc<gluon::base::source::FileMap>,
    pub expr: Arc<OwnedExpr<Symbol>>,
    pub metadata: Arc<Metadata>,
    pub uri: Url,
}

pub struct State {
    pub uri: Url,
    pub version: Option<i64>,
    pub text_changes: TextChanges,
}

impl State {
    pub(crate) fn empty(uri: Url) -> State {
        State {
            uri,
            version: None,
            text_changes: TextChanges::new(),
        }
    }
}

pub(crate) async fn get_module(
    thread: &Thread,
    module: &str,
) -> gluon::Result<(
    Arc<gluon::base::source::FileMap>,
    TypecheckValue<Arc<OwnedExpr<Symbol>>>,
)> {
    let mut db = thread.get_database();
    let m = db
        .typechecked_source_module(module.into(), None)
        .await
        .or_else(|err| err.value.ok_or(err.error))?;

    let _ = db.module_type(module.into(), None).await;
    let _ = db.module_metadata(module.into(), None).await;

    Ok((db.get_filemap(module).expect("Filemap"), m))
}

#[derive(Clone)]
pub(crate) struct CheckImporter(pub(crate) Arc<Mutex<FnvMap<String, State>>>);
impl CheckImporter {
    pub(crate) fn new() -> CheckImporter {
        CheckImporter(Arc::new(Mutex::new(FnvMap::default())))
    }

    pub(crate) async fn module(&self, thread: &Thread, module: &str) -> Option<Module> {
        let (source, value) = get_module(thread, module)
            .await
            .map_err(|err| {
                dbg!(&err);
                err
            })
            .ok()?;

        let uri = {
            let map = self.0.lock().await;
            map.get(module)?.uri.clone()
        };

        Some(Module {
            source,
            expr: value.expr.clone(),
            metadata: value.metadata.clone(),
            uri,
        })
    }

    pub(crate) async fn modules(&self, thread: &Thread) -> impl Iterator<Item = Module> {
        let uris = self
            .0
            .lock()
            .await
            .iter()
            .map(|(module, s)| (module.clone(), s.uri.clone()))
            .collect::<Vec<_>>();

        futures::stream::iter(uris)
            .filter_map(|(module, uri)| async move {
                let (source, value) = get_module(thread, &module).await.ok()?;
                Some(Module {
                    source,
                    expr: value.expr.clone(),
                    metadata: value.metadata.clone(),
                    uri,
                })
            })
            .collect::<Vec<_>>()
            .await
            .into_iter()
    }
}

#[async_trait::async_trait]
impl Importer for CheckImporter {
    async fn import(
        &self,
        compiler: &mut ModuleCompiler<'_, '_>,
        _: &Thread,
        module_name: &str,
    ) -> Result<ArcType, (Option<ArcType>, GluonError)> {
        let typ = compiler
            .database
            .module_type(module_name.into(), None)
            .await
            .map_err(|err| (err.value, err.error))?;
        compiler
            .database
            .module_metadata(module_name.into(), None)
            .await
            .map_err(|err| (None, err.error))?;

        self.0.lock().await.insert(
            module_name.into(),
            State {
                uri: module_name_to_file_(module_name)
                    .map_err(|err| (None, GluonError::from(err.to_string())))?,
                version: None,
                text_changes: TextChanges::new(),
            },
        );

        Ok(typ)
    }
}
<commit_msg>Use SalvageResult<commit_after>use std::sync::Arc;

use gluon::{
    self,
    base::{ast::OwnedExpr, fnv::FnvMap, metadata::Metadata, symbol::Symbol, types::ArcType},
    compiler_pipeline::{SalvageResult, TypecheckValue},
    import::Importer,
    query::AsyncCompilation,
    Error as GluonError, ModuleCompiler, Thread, ThreadExt,
};

use {futures::prelude::*, tokio::sync::Mutex, url::Url};

use crate::{name::module_name_to_file_, text_edit::TextChanges};

pub(crate) struct Module {
    pub source: Arc<gluon::base::source::FileMap>,
    pub expr: Arc<OwnedExpr<Symbol>>,
    pub metadata: Arc<Metadata>,
    pub uri: Url,
}

pub struct State {
    pub uri: Url,
    pub version: Option<i64>,
    pub text_changes: TextChanges,
}

impl State {
    pub(crate) fn empty(uri: Url) -> State {
        State {
            uri,
            version: None,
            text_changes: TextChanges::new(),
        }
    }
}

pub(crate) async fn get_module(
    thread: &Thread,
    module: &str,
) -> gluon::Result<(
    Arc<gluon::base::source::FileMap>,
    TypecheckValue<Arc<OwnedExpr<Symbol>>>,
)> {
    let mut db = thread.get_database();
    let m = db
        .typechecked_source_module(module.into(), None)
        .await
        .or_else(|err| err.value.ok_or(err.error))?;

    let _ = db.module_type(module.into(), None).await;
    let _ = db.module_metadata(module.into(), None).await;

    Ok((db.get_filemap(module).expect("Filemap"), m))
}

#[derive(Clone)]
pub(crate) struct CheckImporter(pub(crate) Arc<Mutex<FnvMap<String, State>>>);
impl CheckImporter {
    pub(crate) fn new() -> CheckImporter {
        CheckImporter(Arc::new(Mutex::new(FnvMap::default())))
    }

    pub(crate) async fn module(&self, thread: &Thread, module: &str) -> Option<Module> {
        let (source, value) = get_module(thread, module)
            .await
            .map_err(|err| {
                dbg!(&err);
                err
            })
            .ok()?;

        let uri = {
            let map = self.0.lock().await;
            map.get(module)?.uri.clone()
        };

        Some(Module {
            source,
            expr: value.expr.clone(),
            metadata: value.metadata.clone(),
            uri,
        })
    }

    pub(crate) async fn modules(&self, thread: &Thread) -> impl Iterator<Item = Module> {
        let uris = self
            .0
            .lock()
            .await
            .iter()
            .map(|(module, s)| (module.clone(), s.uri.clone()))
            .collect::<Vec<_>>();

        futures::stream::iter(uris)
            .filter_map(|(module, uri)| async move {
                let (source, value) = get_module(thread, &module).await.ok()?;
                Some(Module {
                    source,
                    expr: value.expr.clone(),
                    metadata: value.metadata.clone(),
                    uri,
                })
            })
            .collect::<Vec<_>>()
            .await
            .into_iter()
    }
}

#[async_trait::async_trait]
impl Importer for CheckImporter {
    async fn import(
        &self,
        compiler: &mut ModuleCompiler<'_, '_>,
        _: &Thread,
        module_name: &str,
    ) -> SalvageResult<ArcType> {
        compiler
            .database
            .module_metadata(module_name.into(), None)
            .await
            .or_else(|err| err.get_value())?;
        let typ = compiler
            .database
            .module_type(module_name.into(), None)
            .await
            .or_else(|err| err.get_value())?;

        self.0.lock().await.insert(
            module_name.into(),
            State {
                uri: module_name_to_file_(module_name)
                    .map_err(|err| GluonError::from(err.to_string()))?,
                version: None,
                text_changes: TextChanges::new(),
            },
        );

        Ok(typ)
    }
}
<|endoftext|>


<commit_before>use std::fs;
use std::path::Path;

use kuchiki::traits::*;
use hyper::{Client, Url};
use hyper::client::Response;
use hyper::Result as HyperResult;
use util;

pub fn versions() {
    let groonga_versioned_dir = util::obtain_groonga_versioned_path();
    let paths = fs::read_dir(&Path::new(&groonga_versioned_dir)).unwrap();

    let names = paths.filter_map(|entry| {
            entry.ok().and_then(|e| {
                e.path()
                    .file_name()
                    .and_then(|n| n.to_str().map(|s| String::from(s)))
            })
        })
        .collect::<Vec<String>>();

    println!("Installed Groonga:");
    println!("\tsystem");
    for entry in names {
        println!("\t{}", entry);
    }
}

pub struct MaybeProxyUrl {
    pub url: Url,
}

impl<'a> IntoResponse for MaybeProxyUrl {
    fn into_response(self) -> HyperResult<Response> {
        extern crate env_proxy;
        let maybe_proxy = env_proxy::for_url(&self.url);

        let client = match maybe_proxy {
            None => Client::new(),
            Some(host_port) => Client::with_http_proxy(host_port.0, host_port.1),
        };
        client.get(self.url).send()
    }
}
<commit_msg>command common: Remove a needless newline<commit_after>use std::fs;
use std::path::Path;

use kuchiki::traits::*;
use hyper::{Client, Url};
use hyper::client::Response;
use hyper::Result as HyperResult;
use util;

pub fn versions() {
    let groonga_versioned_dir = util::obtain_groonga_versioned_path();
    let paths = fs::read_dir(&Path::new(&groonga_versioned_dir)).unwrap();

    let names = paths.filter_map(|entry| {
            entry.ok().and_then(|e| {
                e.path()
                    .file_name()
                    .and_then(|n| n.to_str().map(|s| String::from(s)))
            })
        })
        .collect::<Vec<String>>();

    println!("Installed Groonga:");
    println!("\tsystem");
    for entry in names {
        println!("\t{}", entry);
    }
}

pub struct MaybeProxyUrl {
    pub url: Url,
}

impl<'a> IntoResponse for MaybeProxyUrl {
    fn into_response(self) -> HyperResult<Response> {
        extern crate env_proxy;
        let maybe_proxy = env_proxy::for_url(&self.url);

        let client = match maybe_proxy {
            None => Client::new(),
            Some(host_port) => Client::with_http_proxy(host_port.0, host_port.1),
        };
        client.get(self.url).send()
    }
}
<|endoftext|>


<commit_before>extern crate mime = "mime-types";
extern crate conduit;

use std::fmt::Show;
use std::collections::HashMap;
use std::io::fs::File;
use std::io::util::NullReader;
use conduit::{Request, Response, Handler};

pub struct Static {
    path: Path,
    types: mime::Types
}

impl Static {
    pub fn new(path: Path) -> Static {
        Static {
            path: path,
            types: mime::Types::new()
                .ok().expect("Couldn't load mime-types")
        }
    }
}

impl Handler for Static {
    fn call(&self, request: &mut Request) -> Result<Response, Box<Show>> {
        let request_path = request.path().slice_from(1);
        let path = self.path.join(request_path);

        if !self.path.is_ancestor_of(&path) {
            return Ok(Response {
                status: (404, "Not Found"),
                headers: HashMap::new(),
                body: box NullReader
            })
        }

        let mime = self.types.mime_for_path(&path);
        let mut file = match File::open(&path) {
            Ok(f) => f,
            Err(..) => {
                return Ok(Response {
                    status: (404, "Not Found"),
                    headers: HashMap::new(),
                    body: box NullReader,
                })
            }
        };
        let stat = try!(file.stat().map_err(|e| box e as Box<Show>));

        let mut headers = HashMap::new();
        headers.insert("Content-Type".to_str(), vec![mime.to_str()]);
        headers.insert("Content-Length".to_str(), vec![stat.size.to_str()]);

        Ok(Response {
            status: (200, "OK"),
            headers: headers,
            body: box file as Box<Reader + Send>
        })
    }
}

#[cfg(test)]
mod tests {
    extern crate test = "conduit-test";

    use std::io::{fs, File, TempDir, UserRWX};

    use conduit;
    use conduit::Handler;
    use Static;

    #[test]
    fn test_static() {
        let td = TempDir::new("conduit-static").unwrap();
        let root = td.path();
        let handler = Static::new(root.clone());
        File::create(&root.join("Cargo.toml")).write(b"[package]").unwrap();
        let mut req = test::MockRequest::new(conduit::Get, "/Cargo.toml");
        let mut res = handler.call(&mut req).ok().expect("No response");
        let body = res.body.read_to_str().ok().expect("No body");
        assert_eq!(body.as_slice(), "[package]");
        assert_eq!(res.headers.find_equiv(&"Content-Type"),
                   Some(&vec!("text/plain".to_str())));
        assert_eq!(res.headers.find_equiv(&"Content-Length"),
                   Some(&vec!["9".to_str()]));
    }

    #[test]
    fn test_mime_types() {
        let td = TempDir::new("conduit-static").unwrap();
        let root = td.path();
        fs::mkdir(&root.join("src"), UserRWX).unwrap();
        File::create(&root.join("src/fixture.css")).unwrap();

        let handler = Static::new(root.clone());
        let mut req = test::MockRequest::new(conduit::Get, "/src/fixture.css");
        let res = handler.call(&mut req).ok().expect("No response");
        assert_eq!(res.headers.find_equiv(&"Content-Type"),
                   Some(&vec!("text/css".to_str())));
        assert_eq!(res.headers.find_equiv(&"Content-Length"),
                   Some(&vec!["0".to_str()]));
    }

    #[test]
    fn test_missing() {
        let td = TempDir::new("conduit-static").unwrap();
        let root = td.path();

        let handler = Static::new(root.clone());
        let mut req = test::MockRequest::new(conduit::Get, "/nope");
        let res = handler.call(&mut req).ok().expect("No response");
        assert_eq!(res.status.val0(), 404);
    }
}
<commit_msg>Add a Last-Modified header<commit_after>extern crate conduit;
extern crate mime = "mime-types";
extern crate time;

use std::fmt::Show;
use std::collections::HashMap;
use std::io::fs::File;
use std::io::util::NullReader;
use conduit::{Request, Response, Handler};

pub struct Static {
    path: Path,
    types: mime::Types
}

impl Static {
    pub fn new(path: Path) -> Static {
        Static {
            path: path,
            types: mime::Types::new()
                .ok().expect("Couldn't load mime-types")
        }
    }
}

impl Handler for Static {
    fn call(&self, request: &mut Request) -> Result<Response, Box<Show>> {
        let request_path = request.path().slice_from(1);
        let path = self.path.join(request_path);

        if !self.path.is_ancestor_of(&path) {
            return Ok(Response {
                status: (404, "Not Found"),
                headers: HashMap::new(),
                body: box NullReader
            })
        }

        let mime = self.types.mime_for_path(&path);
        let mut file = match File::open(&path) {
            Ok(f) => f,
            Err(..) => {
                return Ok(Response {
                    status: (404, "Not Found"),
                    headers: HashMap::new(),
                    body: box NullReader,
                })
            }
        };
        let stat = try!(file.stat().map_err(|e| box e as Box<Show>));
        let ts = time::Timespec {
            sec: (stat.modified as i64) / 1000,
            nsec: ((stat.modified as i32) % 1000) * 1000
        };
        let tm = time::at(ts).to_utc();

        let mut headers = HashMap::new();
        headers.insert("Content-Type".to_str(), vec![mime.to_str()]);
        headers.insert("Content-Length".to_str(), vec![stat.size.to_str()]);
        headers.insert("Last-Modified".to_str(),
                       vec![tm.strftime("%a, %d %b %Y %T GMT")]);

        Ok(Response {
            status: (200, "OK"),
            headers: headers,
            body: box file as Box<Reader + Send>
        })
    }
}

#[cfg(test)]
mod tests {
    extern crate test = "conduit-test";

    use std::io::{fs, File, TempDir, UserRWX};

    use conduit;
    use conduit::Handler;
    use Static;

    #[test]
    fn test_static() {
        let td = TempDir::new("conduit-static").unwrap();
        let root = td.path();
        let handler = Static::new(root.clone());
        File::create(&root.join("Cargo.toml")).write(b"[package]").unwrap();
        let mut req = test::MockRequest::new(conduit::Get, "/Cargo.toml");
        let mut res = handler.call(&mut req).ok().expect("No response");
        let body = res.body.read_to_str().ok().expect("No body");
        assert_eq!(body.as_slice(), "[package]");
        assert_eq!(res.headers.find_equiv(&"Content-Type"),
                   Some(&vec!("text/plain".to_str())));
        assert_eq!(res.headers.find_equiv(&"Content-Length"),
                   Some(&vec!["9".to_str()]));
    }

    #[test]
    fn test_mime_types() {
        let td = TempDir::new("conduit-static").unwrap();
        let root = td.path();
        fs::mkdir(&root.join("src"), UserRWX).unwrap();
        File::create(&root.join("src/fixture.css")).unwrap();

        let handler = Static::new(root.clone());
        let mut req = test::MockRequest::new(conduit::Get, "/src/fixture.css");
        let res = handler.call(&mut req).ok().expect("No response");
        assert_eq!(res.headers.find_equiv(&"Content-Type"),
                   Some(&vec!("text/css".to_str())));
        assert_eq!(res.headers.find_equiv(&"Content-Length"),
                   Some(&vec!["0".to_str()]));
    }

    #[test]
    fn test_missing() {
        let td = TempDir::new("conduit-static").unwrap();
        let root = td.path();

        let handler = Static::new(root.clone());
        let mut req = test::MockRequest::new(conduit::Get, "/nope");
        let res = handler.call(&mut req).ok().expect("No response");
        assert_eq!(res.status.val0(), 404);
    }

    #[test]
    fn last_modified() {
        let td = TempDir::new("conduit-static").unwrap();
        let root = td.path();
        File::create(&root.join("test")).unwrap();
        let handler = Static::new(root.clone());
        let mut req = test::MockRequest::new(conduit::Get, "/test");
        let res = handler.call(&mut req).ok().expect("No response");
        assert_eq!(res.status.val0(), 200);
        assert!(res.headers.find_equiv(&"Last-Modified").is_some());
    }
}
<|endoftext|>


<commit_before>use crate::hir;
use crate::ty::{self, Region, TyCtxt};
use crate::hir::Node;
use crate::middle::resolve_lifetime as rl;
use crate::hir::intravisit::{self, NestedVisitorMap, Visitor};
use crate::infer::error_reporting::nice_region_error::NiceRegionError;

impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
    /// This function calls the `visit_ty` method for the parameters
    /// corresponding to the anonymous regions. The `nested_visitor.found_type`
    /// contains the anonymous type.
    ///
    /// # Arguments
    /// region - the anonymous region corresponding to the anon_anon conflict
    /// br - the bound region corresponding to the above region which is of type `BrAnon(_)`
    ///
    /// # Example
    /// ```
    /// fn foo(x: &mut Vec<&u8>, y: &u8)
    ///    { x.push(y); }
    /// ```
    /// The function returns the nested type corresponding to the anonymous region
    /// for e.g., `&u8` and Vec<`&u8`.
    pub(super) fn find_anon_type(
        &self,
        region: Region<'tcx>,
        br: &ty::BoundRegion,
    ) -> Option<(&hir::Ty, &hir::FnDecl)> {
        if let Some(anon_reg) = self.tcx().is_suitable_region(region) {
            let def_id = anon_reg.def_id;
            if let Some(hir_id) = self.tcx().hir().as_local_hir_id(def_id) {
                let fndecl = match self.tcx().hir().get(hir_id) {
                    Node::Item(&hir::Item {
                        node: hir::ItemKind::Fn(ref fndecl, ..),
                        ..
                    }) => &fndecl,
                    Node::TraitItem(&hir::TraitItem {
                        node: hir::TraitItemKind::Method(ref m, ..),
                        ..
                    })
                    | Node::ImplItem(&hir::ImplItem {
                        node: hir::ImplItemKind::Method(ref m, ..),
                        ..
                    }) => &m.decl,
                    _ => return None,
                };

                return fndecl
                    .inputs
                    .iter()
                    .filter_map(|arg| self.find_component_for_bound_region(arg, br))
                    .next()
                    .map(|ty| (ty, &**fndecl));
            }
        }
        None
    }

    // This method creates a FindNestedTypeVisitor which returns the type corresponding
    // to the anonymous region.
    fn find_component_for_bound_region(
        &self,
        arg: &'tcx hir::Ty,
        br: &ty::BoundRegion,
    ) -> Option<(&'tcx hir::Ty)> {
        let mut nested_visitor = FindNestedTypeVisitor {
            tcx: self.tcx(),
            bound_region: *br,
            found_type: None,
            current_index: ty::INNERMOST,
        };
        nested_visitor.visit_ty(arg);
        nested_visitor.found_type
    }
}

// The FindNestedTypeVisitor captures the corresponding `hir::Ty` of the
// anonymous region. The example above would lead to a conflict between
// the two anonymous lifetimes for &u8 in x and y respectively. This visitor
// would be invoked twice, once for each lifetime, and would
// walk the types like &mut Vec<&u8> and &u8 looking for the HIR
// where that lifetime appears. This allows us to highlight the
// specific part of the type in the error message.
struct FindNestedTypeVisitor<'tcx> {
    tcx: TyCtxt<'tcx>,
    // The bound_region corresponding to the Refree(freeregion)
    // associated with the anonymous region we are looking for.
    bound_region: ty::BoundRegion,
    // The type where the anonymous lifetime appears
    // for e.g., Vec<`&u8`> and <`&u8`>
    found_type: Option<&'tcx hir::Ty>,
    current_index: ty::DebruijnIndex,
}

impl Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::OnlyBodies(&self.tcx.hir())
    }

    fn visit_ty(&mut self, arg: &'tcx hir::Ty) {
        match arg.node {
            hir::TyKind::BareFn(_) => {
                self.current_index.shift_in(1);
                intravisit::walk_ty(self, arg);
                self.current_index.shift_out(1);
                return;
            }

            hir::TyKind::TraitObject(ref bounds, _) => for bound in bounds {
                self.current_index.shift_in(1);
                self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
                self.current_index.shift_out(1);
            },

            hir::TyKind::Rptr(ref lifetime, _) => {
                // the lifetime of the TyRptr
                let hir_id = lifetime.hir_id;
                match (self.tcx.named_region(hir_id), self.bound_region) {
                    // Find the index of the anonymous region that was part of the
                    // error. We will then search the function parameters for a bound
                    // region at the right depth with the same index
                    (
                        Some(rl::Region::LateBoundAnon(debruijn_index, anon_index)),
                        ty::BrAnon(br_index),
                    ) => {
                        debug!(
                            "LateBoundAnon depth = {:?} anon_index = {:?} br_index={:?}",
                            debruijn_index,
                            anon_index,
                            br_index
                        );
                        if debruijn_index == self.current_index && anon_index == br_index {
                            self.found_type = Some(arg);
                            return; // we can stop visiting now
                        }
                    }

                    // Find the index of the named region that was part of the
                    // error. We will then search the function parameters for a bound
                    // region at the right depth with the same index
                    (Some(rl::Region::EarlyBound(_, id, _)), ty::BrNamed(def_id, _)) => {
                        debug!("EarlyBound id={:?} def_id={:?}", id, def_id);
                        if id == def_id {
                            self.found_type = Some(arg);
                            return; // we can stop visiting now
                        }
                    }

                    // Find the index of the named region that was part of the
                    // error. We will then search the function parameters for a bound
                    // region at the right depth with the same index
                    (
                        Some(rl::Region::LateBound(debruijn_index, id, _)),
                        ty::BrNamed(def_id, _),
                    ) => {
                        debug!(
                            "FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}",
                            debruijn_index
                        );
                        debug!("LateBound id={:?} def_id={:?}", id, def_id);
                        if debruijn_index == self.current_index && id == def_id {
                            self.found_type = Some(arg);
                            return; // we can stop visiting now
                        }
                    }

                    (Some(rl::Region::Static), _)
                    | (Some(rl::Region::Free(_, _)), _)
                    | (Some(rl::Region::EarlyBound(_, _, _)), _)
                    | (Some(rl::Region::LateBound(_, _, _)), _)
                    | (Some(rl::Region::LateBoundAnon(_, _)), _)
                    | (None, _) => {
                        debug!("no arg found");
                    }
                }
            }
            // Checks if it is of type `hir::TyKind::Path` which corresponds to a struct.
            hir::TyKind::Path(_) => {
                let subvisitor = &mut TyPathVisitor {
                    tcx: self.tcx,
                    found_it: false,
                    bound_region: self.bound_region,
                    current_index: self.current_index,
                };
                intravisit::walk_ty(subvisitor, arg); // call walk_ty; as visit_ty is empty,
                                                      // this will visit only outermost type
                if subvisitor.found_it {
                    self.found_type = Some(arg);
                }
            }
            _ => {}
        }
        // walk the embedded contents: e.g., if we are visiting `Vec<&Foo>`,
        // go on to visit `&Foo`
        intravisit::walk_ty(self, arg);
    }
}

// The visitor captures the corresponding `hir::Ty` of the anonymous region
// in the case of structs ie. `hir::TyKind::Path`.
// This visitor would be invoked for each lifetime corresponding to a struct,
// and would walk the types like Vec<Ref> in the above example and Ref looking for the HIR
// where that lifetime appears. This allows us to highlight the
// specific part of the type in the error message.
struct TyPathVisitor<'tcx> {
    tcx: TyCtxt<'tcx>,
    found_it: bool,
    bound_region: ty::BoundRegion,
    current_index: ty::DebruijnIndex,
}

impl Visitor<'tcx> for TyPathVisitor<'tcx> {
    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::OnlyBodies(&self.tcx.hir())
    }

    fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) {
        match (self.tcx.named_region(lifetime.hir_id), self.bound_region) {
            // the lifetime of the TyPath!
            (Some(rl::Region::LateBoundAnon(debruijn_index, anon_index)), ty::BrAnon(br_index)) => {
                if debruijn_index == self.current_index && anon_index == br_index {
                    self.found_it = true;
                    return;
                }
            }

            (Some(rl::Region::EarlyBound(_, id, _)), ty::BrNamed(def_id, _)) => {
                debug!(
                    "EarlyBound self.infcx.tcx.hir().local_def_id_from_node_id(id)={:?} \
                     def_id={:?}",
                    id,
                    def_id
                );
                if id == def_id {
                    self.found_it = true;
                    return; // we can stop visiting now
                }
            }

            (Some(rl::Region::LateBound(debruijn_index, id, _)), ty::BrNamed(def_id, _)) => {
                debug!(
                    "FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}",
                    debruijn_index,
                );
                debug!("id={:?}", id);
                debug!("def_id={:?}", def_id);
                if debruijn_index == self.current_index && id == def_id {
                    self.found_it = true;
                    return; // we can stop visiting now
                }
            }

            (Some(rl::Region::Static), _)
            | (Some(rl::Region::EarlyBound(_, _, _)), _)
            | (Some(rl::Region::LateBound(_, _, _)), _)
            | (Some(rl::Region::LateBoundAnon(_, _)), _)
            | (Some(rl::Region::Free(_, _)), _)
            | (None, _) => {
                debug!("no arg found");
            }
        }
    }

    fn visit_ty(&mut self, arg: &'tcx hir::Ty) {
        // ignore nested types
        //
        // If you have a type like `Foo<'a, &Ty>` we
        // are only interested in the immediate lifetimes ('a).
        //
        // Making `visit_ty` empty will ignore the `&Ty` embedded
        // inside, it will get reached by the outer visitor.
        debug!("`Ty` corresponding to a struct is {:?}", arg);
    }
}
<commit_msg>infer: fix a Region-related debug message<commit_after>use crate::hir;
use crate::ty::{self, Region, TyCtxt};
use crate::hir::Node;
use crate::middle::resolve_lifetime as rl;
use crate::hir::intravisit::{self, NestedVisitorMap, Visitor};
use crate::infer::error_reporting::nice_region_error::NiceRegionError;

impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
    /// This function calls the `visit_ty` method for the parameters
    /// corresponding to the anonymous regions. The `nested_visitor.found_type`
    /// contains the anonymous type.
    ///
    /// # Arguments
    /// region - the anonymous region corresponding to the anon_anon conflict
    /// br - the bound region corresponding to the above region which is of type `BrAnon(_)`
    ///
    /// # Example
    /// ```
    /// fn foo(x: &mut Vec<&u8>, y: &u8)
    ///    { x.push(y); }
    /// ```
    /// The function returns the nested type corresponding to the anonymous region
    /// for e.g., `&u8` and Vec<`&u8`.
    pub(super) fn find_anon_type(
        &self,
        region: Region<'tcx>,
        br: &ty::BoundRegion,
    ) -> Option<(&hir::Ty, &hir::FnDecl)> {
        if let Some(anon_reg) = self.tcx().is_suitable_region(region) {
            let def_id = anon_reg.def_id;
            if let Some(hir_id) = self.tcx().hir().as_local_hir_id(def_id) {
                let fndecl = match self.tcx().hir().get(hir_id) {
                    Node::Item(&hir::Item {
                        node: hir::ItemKind::Fn(ref fndecl, ..),
                        ..
                    }) => &fndecl,
                    Node::TraitItem(&hir::TraitItem {
                        node: hir::TraitItemKind::Method(ref m, ..),
                        ..
                    })
                    | Node::ImplItem(&hir::ImplItem {
                        node: hir::ImplItemKind::Method(ref m, ..),
                        ..
                    }) => &m.decl,
                    _ => return None,
                };

                return fndecl
                    .inputs
                    .iter()
                    .filter_map(|arg| self.find_component_for_bound_region(arg, br))
                    .next()
                    .map(|ty| (ty, &**fndecl));
            }
        }
        None
    }

    // This method creates a FindNestedTypeVisitor which returns the type corresponding
    // to the anonymous region.
    fn find_component_for_bound_region(
        &self,
        arg: &'tcx hir::Ty,
        br: &ty::BoundRegion,
    ) -> Option<(&'tcx hir::Ty)> {
        let mut nested_visitor = FindNestedTypeVisitor {
            tcx: self.tcx(),
            bound_region: *br,
            found_type: None,
            current_index: ty::INNERMOST,
        };
        nested_visitor.visit_ty(arg);
        nested_visitor.found_type
    }
}

// The FindNestedTypeVisitor captures the corresponding `hir::Ty` of the
// anonymous region. The example above would lead to a conflict between
// the two anonymous lifetimes for &u8 in x and y respectively. This visitor
// would be invoked twice, once for each lifetime, and would
// walk the types like &mut Vec<&u8> and &u8 looking for the HIR
// where that lifetime appears. This allows us to highlight the
// specific part of the type in the error message.
struct FindNestedTypeVisitor<'tcx> {
    tcx: TyCtxt<'tcx>,
    // The bound_region corresponding to the Refree(freeregion)
    // associated with the anonymous region we are looking for.
    bound_region: ty::BoundRegion,
    // The type where the anonymous lifetime appears
    // for e.g., Vec<`&u8`> and <`&u8`>
    found_type: Option<&'tcx hir::Ty>,
    current_index: ty::DebruijnIndex,
}

impl Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::OnlyBodies(&self.tcx.hir())
    }

    fn visit_ty(&mut self, arg: &'tcx hir::Ty) {
        match arg.node {
            hir::TyKind::BareFn(_) => {
                self.current_index.shift_in(1);
                intravisit::walk_ty(self, arg);
                self.current_index.shift_out(1);
                return;
            }

            hir::TyKind::TraitObject(ref bounds, _) => for bound in bounds {
                self.current_index.shift_in(1);
                self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None);
                self.current_index.shift_out(1);
            },

            hir::TyKind::Rptr(ref lifetime, _) => {
                // the lifetime of the TyRptr
                let hir_id = lifetime.hir_id;
                match (self.tcx.named_region(hir_id), self.bound_region) {
                    // Find the index of the anonymous region that was part of the
                    // error. We will then search the function parameters for a bound
                    // region at the right depth with the same index
                    (
                        Some(rl::Region::LateBoundAnon(debruijn_index, anon_index)),
                        ty::BrAnon(br_index),
                    ) => {
                        debug!(
                            "LateBoundAnon depth = {:?} anon_index = {:?} br_index={:?}",
                            debruijn_index,
                            anon_index,
                            br_index
                        );
                        if debruijn_index == self.current_index && anon_index == br_index {
                            self.found_type = Some(arg);
                            return; // we can stop visiting now
                        }
                    }

                    // Find the index of the named region that was part of the
                    // error. We will then search the function parameters for a bound
                    // region at the right depth with the same index
                    (Some(rl::Region::EarlyBound(_, id, _)), ty::BrNamed(def_id, _)) => {
                        debug!("EarlyBound id={:?} def_id={:?}", id, def_id);
                        if id == def_id {
                            self.found_type = Some(arg);
                            return; // we can stop visiting now
                        }
                    }

                    // Find the index of the named region that was part of the
                    // error. We will then search the function parameters for a bound
                    // region at the right depth with the same index
                    (
                        Some(rl::Region::LateBound(debruijn_index, id, _)),
                        ty::BrNamed(def_id, _),
                    ) => {
                        debug!(
                            "FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}",
                            debruijn_index
                        );
                        debug!("LateBound id={:?} def_id={:?}", id, def_id);
                        if debruijn_index == self.current_index && id == def_id {
                            self.found_type = Some(arg);
                            return; // we can stop visiting now
                        }
                    }

                    (Some(rl::Region::Static), _)
                    | (Some(rl::Region::Free(_, _)), _)
                    | (Some(rl::Region::EarlyBound(_, _, _)), _)
                    | (Some(rl::Region::LateBound(_, _, _)), _)
                    | (Some(rl::Region::LateBoundAnon(_, _)), _)
                    | (None, _) => {
                        debug!("no arg found");
                    }
                }
            }
            // Checks if it is of type `hir::TyKind::Path` which corresponds to a struct.
            hir::TyKind::Path(_) => {
                let subvisitor = &mut TyPathVisitor {
                    tcx: self.tcx,
                    found_it: false,
                    bound_region: self.bound_region,
                    current_index: self.current_index,
                };
                intravisit::walk_ty(subvisitor, arg); // call walk_ty; as visit_ty is empty,
                                                      // this will visit only outermost type
                if subvisitor.found_it {
                    self.found_type = Some(arg);
                }
            }
            _ => {}
        }
        // walk the embedded contents: e.g., if we are visiting `Vec<&Foo>`,
        // go on to visit `&Foo`
        intravisit::walk_ty(self, arg);
    }
}

// The visitor captures the corresponding `hir::Ty` of the anonymous region
// in the case of structs ie. `hir::TyKind::Path`.
// This visitor would be invoked for each lifetime corresponding to a struct,
// and would walk the types like Vec<Ref> in the above example and Ref looking for the HIR
// where that lifetime appears. This allows us to highlight the
// specific part of the type in the error message.
struct TyPathVisitor<'tcx> {
    tcx: TyCtxt<'tcx>,
    found_it: bool,
    bound_region: ty::BoundRegion,
    current_index: ty::DebruijnIndex,
}

impl Visitor<'tcx> for TyPathVisitor<'tcx> {
    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
        NestedVisitorMap::OnlyBodies(&self.tcx.hir())
    }

    fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) {
        match (self.tcx.named_region(lifetime.hir_id), self.bound_region) {
            // the lifetime of the TyPath!
            (Some(rl::Region::LateBoundAnon(debruijn_index, anon_index)), ty::BrAnon(br_index)) => {
                if debruijn_index == self.current_index && anon_index == br_index {
                    self.found_it = true;
                    return;
                }
            }

            (Some(rl::Region::EarlyBound(_, id, _)), ty::BrNamed(def_id, _)) => {
                debug!("EarlyBound id={:?} def_id={:?}", id, def_id);
                if id == def_id {
                    self.found_it = true;
                    return; // we can stop visiting now
                }
            }

            (Some(rl::Region::LateBound(debruijn_index, id, _)), ty::BrNamed(def_id, _)) => {
                debug!(
                    "FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}",
                    debruijn_index,
                );
                debug!("id={:?}", id);
                debug!("def_id={:?}", def_id);
                if debruijn_index == self.current_index && id == def_id {
                    self.found_it = true;
                    return; // we can stop visiting now
                }
            }

            (Some(rl::Region::Static), _)
            | (Some(rl::Region::EarlyBound(_, _, _)), _)
            | (Some(rl::Region::LateBound(_, _, _)), _)
            | (Some(rl::Region::LateBoundAnon(_, _)), _)
            | (Some(rl::Region::Free(_, _)), _)
            | (None, _) => {
                debug!("no arg found");
            }
        }
    }

    fn visit_ty(&mut self, arg: &'tcx hir::Ty) {
        // ignore nested types
        //
        // If you have a type like `Foo<'a, &Ty>` we
        // are only interested in the immediate lifetimes ('a).
        //
        // Making `visit_ty` empty will ignore the `&Ty` embedded
        // inside, it will get reached by the outer visitor.
        debug!("`Ty` corresponding to a struct is {:?}", arg);
    }
}
<|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/.

//! udev-related methods
use std::{
    collections::HashMap,
    fs,
    path::{Path, PathBuf},
};

use libudev;

use crate::stratis::StratisResult;

/// Takes a libudev device entry and returns the properties as a HashMap.
fn device_as_map(device: &libudev::Device) -> HashMap<String, String> {
    let rc: HashMap<_, _> = device
        .properties()
        .map(|i| {
            (
                String::from(i.name().to_string_lossy()),
                String::from(i.value().to_string_lossy()),
            )
        })
        .collect();
    rc
}

/// Common function used to retrieve the udev db entry for a block device as a HashMap when found
pub fn get_udev_block_device(
    dev_node_search: &Path,
) -> StratisResult<Option<HashMap<String, String>>> {
    let context = libudev::Context::new()?;
    let mut enumerator = libudev::Enumerator::new(&context)?;
    enumerator.match_subsystem("block")?;

    // Get canonical form to ensure we do correct lookup in udev db
    let canonical = fs::canonicalize(dev_node_search)?;

    let result = enumerator
        .scan_devices()?
        .filter(|dev| dev.is_initialized())
        .find(|x| x.devnode().map_or(false, |d| canonical == d))
        .map(|dev| device_as_map(&dev));
    Ok(result)
}

/// Lookup the WWN from the udev db using the device node eg. /dev/sda
pub fn hw_lookup(dev_node_search: &Path) -> StratisResult<Option<String>> {
    let dev = get_udev_block_device(dev_node_search)?;
    Ok(dev.and_then(|dev| dev.get("ID_WWN").cloned()))
}

/// Collect paths for all the block devices which are not individual multipath paths and which
/// appear to be empty from a udev perspective.
pub fn get_all_empty_devices() -> StratisResult<Vec<PathBuf>> {
    let context = libudev::Context::new()?;
    let mut enumerator = libudev::Enumerator::new(&context)?;
    enumerator.match_subsystem("block")?;

    Ok(enumerator
        .scan_devices()?
        .filter(|dev| dev.is_initialized())
        .filter(|dev| {
            dev.property_value("DM_MULTIPATH_DEVICE_PATH")
                .map_or(true, |v| v != "1")
                && !((dev.property_value("ID_PART_TABLE_TYPE").is_some()
                    && dev.property_value("ID_PART_ENTRY_DISK").is_none())
                    || dev.property_value("ID_FS_USAGE").is_some())
        })
        .filter_map(|i| i.devnode().map(|d| d.into()))
        .collect())
}
<commit_msg>Make a udev enumerator for matching block devices<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/.

//! udev-related methods
use std::{
    collections::HashMap,
    fs,
    path::{Path, PathBuf},
};

use libudev;

use crate::stratis::StratisResult;

/// Make an enumerator for enumerating block devices. Return an error if there
/// was any udev-related error.
fn block_enumerator(context: &libudev::Context) -> libudev::Result<libudev::Enumerator> {
    let mut enumerator = libudev::Enumerator::new(context)?;
    enumerator.match_subsystem("block")?;
    Ok(enumerator)
}

/// Takes a libudev device entry and returns the properties as a HashMap.
fn device_as_map(device: &libudev::Device) -> HashMap<String, String> {
    let rc: HashMap<_, _> = device
        .properties()
        .map(|i| {
            (
                String::from(i.name().to_string_lossy()),
                String::from(i.value().to_string_lossy()),
            )
        })
        .collect();
    rc
}

/// Common function used to retrieve the udev db entry for a block device as a HashMap when found
pub fn get_udev_block_device(
    dev_node_search: &Path,
) -> StratisResult<Option<HashMap<String, String>>> {
    let context = libudev::Context::new()?;
    let mut enumerator = block_enumerator(&context)?;

    // Get canonical form to ensure we do correct lookup in udev db
    let canonical = fs::canonicalize(dev_node_search)?;

    let result = enumerator
        .scan_devices()?
        .filter(|dev| dev.is_initialized())
        .find(|x| x.devnode().map_or(false, |d| canonical == d))
        .map(|dev| device_as_map(&dev));
    Ok(result)
}

/// Lookup the WWN from the udev db using the device node eg. /dev/sda
pub fn hw_lookup(dev_node_search: &Path) -> StratisResult<Option<String>> {
    let dev = get_udev_block_device(dev_node_search)?;
    Ok(dev.and_then(|dev| dev.get("ID_WWN").cloned()))
}

/// Collect paths for all the block devices which are not individual multipath paths and which
/// appear to be empty from a udev perspective.
pub fn get_all_empty_devices() -> StratisResult<Vec<PathBuf>> {
    let context = libudev::Context::new()?;
    let mut enumerator = block_enumerator(&context)?;

    Ok(enumerator
        .scan_devices()?
        .filter(|dev| dev.is_initialized())
        .filter(|dev| {
            dev.property_value("DM_MULTIPATH_DEVICE_PATH")
                .map_or(true, |v| v != "1")
                && !((dev.property_value("ID_PART_TABLE_TYPE").is_some()
                    && dev.property_value("ID_PART_ENTRY_DISK").is_none())
                    || dev.property_value("ID_FS_USAGE").is_some())
        })
        .filter_map(|i| i.devnode().map(|d| d.into()))
        .collect())
}
<|endoftext|>


<commit_before>use display_delegate::display;
use lifetime_remover::remove_lifetimes_from_path;
use quote::{ToTokens};
use std::fmt::{Error, Formatter};
use syn::{self, ArgCaptured, FnArg, Ident, Pat, PatIdent, PathSegment, Stmt};
use syn::punctuated::Punctuated;
use syn::token::{Comma, Colon2};

const ARGS_REPLACEMENT_TUPLE_NAME: &str  = "__mocktopus_args_replacement_tuple__";
const MOCKTOPUS_EXTERN_CRATE_NAME: &str = "__mocktopus_extern_crate_inside_header__";

macro_rules! error_msg {
    ($msg:expr) => { concat!("Mocktopus internal error: ", $msg) }
}

pub enum FnHeaderBuilder<'a> {
    StaticFn,
    StructImpl,
    TraitDefault,
    TraitImpl(&'a Punctuated<PathSegment, Colon2>),
}

impl<'a> FnHeaderBuilder<'a> {
    pub fn build(&self, fn_ident: &Ident, fn_args: &Punctuated<FnArg, Comma>) -> Stmt {
        let header_str = format!(
r#"{{
    extern crate mocktopus as {mocktopus_crate};
    match ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe (
            || {mocktopus_crate}::mocking::Mockable::call_mock(&{full_fn_name}, {args_tuple}))) {{
        Ok({mocktopus_crate}::mocking::MockResult::Continue({args_replacement_tuple})) => {args_replacement},
        Ok({mocktopus_crate}::mocking::MockResult::Return(result)) => return result,
        Err(unwind) => {{
            {args_forget}
            ::std::panic::resume_unwind(unwind);
        }}
    }}
}}"#,
            mocktopus_crate         = MOCKTOPUS_EXTERN_CRATE_NAME,
            full_fn_name            = display(|f| write_full_fn_name(f, self, fn_ident)),
            args_tuple              = display(|f| write_args_tuple(f, fn_args)),
            args_replacement_tuple  = ARGS_REPLACEMENT_TUPLE_NAME,
            args_replacement        = display(|f| write_args_replacement(f, fn_args)),
            args_forget             = display(|f| write_args_forget(f, fn_args)));
        syn::parse_str(&header_str).expect(error_msg!("generated header unparsable"))
    }
}

fn write_full_fn_name(f: &mut Formatter, builder: &FnHeaderBuilder, fn_ident: &Ident) -> Result<(), Error> {
    match *builder {
        FnHeaderBuilder::StaticFn => (),
        FnHeaderBuilder::StructImpl |
        FnHeaderBuilder::TraitDefault => write!(f, "Self::")?,
        FnHeaderBuilder::TraitImpl(ref path) => write!(f, "<Self as {}>::", display(|f| write_trait_path(f, path)))?,
    }
    write!(f, "{}", fn_ident.as_ref())
}

fn write_trait_path<T: ToTokens + Clone>(f: &mut Formatter, trait_path: &Punctuated<PathSegment, T>) -> Result<(), Error> {
    let mut trait_path_without_lifetimes = trait_path.clone();
    remove_lifetimes_from_path(&mut trait_path_without_lifetimes);
    write!(f, "{}", trait_path_without_lifetimes.into_tokens())
}

fn write_args_tuple<T>(f: &mut Formatter, fn_args: &Punctuated<FnArg, T>) -> Result<(), Error> {
    if fn_args.is_empty() {
        return write!(f, "()");
    }
    write!(f, "unsafe {{ (")?;
    for fn_arg_name in iter_fn_arg_names(fn_args) {
        write!(f, "::std::mem::replace({}::mocking_utils::as_mut(&{}), ::std::mem::uninitialized()), ",
               MOCKTOPUS_EXTERN_CRATE_NAME, fn_arg_name)?;
    }
    write!(f, ") }}")
}

fn write_args_replacement<T>(f: &mut Formatter, fn_args: &Punctuated<FnArg, T>) -> Result<(), Error> {
    if fn_args.is_empty() {
        return writeln!(f, "()");
    }
    writeln!(f, "unsafe {{")?;
    for (fn_arg_index, fn_arg_name) in iter_fn_arg_names(fn_args).enumerate() {
        writeln!(f, "::std::mem::replace({}::mocking_utils::as_mut(&{}), {}.{});",
                 MOCKTOPUS_EXTERN_CRATE_NAME, fn_arg_name, ARGS_REPLACEMENT_TUPLE_NAME, fn_arg_index)?;
    }
    writeln!(f, "}}")
}

fn write_args_forget<T>(f: &mut Formatter, fn_args: &Punctuated<FnArg, T>) -> Result<(), Error> {
    for fn_arg_name in iter_fn_arg_names(fn_args) {
        writeln!(f, "::std::mem::forget({});", fn_arg_name)?;
    }
    Ok(())
}

pub fn iter_fn_arg_names<'a, T>(input_args: &'a Punctuated<FnArg, T>) -> impl Iterator<Item = &'a str> {
    input_args.iter()
        .map(|fn_arg| match *fn_arg {
            FnArg::SelfRef(_) | FnArg::SelfValue(_) => "self",
            FnArg::Captured(
                ArgCaptured {
                    pat: Pat::Ident(
                        PatIdent {
                            ref ident,
                            subpat: None,
                            ..
                        }
                    ),
                    ..
                }
            ) => ident.as_ref(),
            _ => panic!("{}: '{}'", error_msg!("invalid fn arg type"), fn_arg.clone().into_tokens()),
        })
}
<commit_msg>Clean up header builder<commit_after>use display_delegate::display;
use lifetime_remover::remove_lifetimes_from_path;
use quote::{ToTokens};
use std::fmt::{Error, Formatter};
use syn::{self, ArgCaptured, FnArg, Ident, Pat, PatIdent, PathSegment, Stmt};
use syn::punctuated::Punctuated;
use syn::token::{Comma, Colon2};

const MOCKTOPUS_CRATE_NAME:     &str = "__mocktopus_crate__";
const ARGS_TO_CONTINUE_NAME:    &str = "__mocktopus_args_to_continue__";
const UNWIND_DATA_NAME:         &str = "__mocktopus_unwind_data__";

macro_rules! error_msg {
    ($msg:expr) => { concat!("Mocktopus internal error: ", $msg) }
}

pub enum FnHeaderBuilder<'a> {
    StaticFn,
    StructImpl,
    TraitDefault,
    TraitImpl(&'a Punctuated<PathSegment, Colon2>),
}

impl<'a> FnHeaderBuilder<'a> {
    pub fn build(&self, fn_ident: &Ident, fn_args: &Punctuated<FnArg, Comma>) -> Stmt {
        let header_str = format!(
r#"{{
    extern crate mocktopus as {mocktopus};
    match ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe (
            || {mocktopus}::mocking::Mockable::call_mock(&{full_fn_name}, {extract_args}))) {{
        Ok({mocktopus}::mocking::MockResult::Continue({args_to_continue})) => {restore_args},
        Ok({mocktopus}::mocking::MockResult::Return(result)) => return result,
        Err({unwind}) => {{
            {forget_args}
            ::std::panic::resume_unwind({unwind});
        }}
    }}
}}"#,
            mocktopus           = MOCKTOPUS_CRATE_NAME,
            full_fn_name        = display(|f| write_full_fn_name(f, self, fn_ident)),
            extract_args        = display(|f| write_extract_args(f, fn_args)),
            args_to_continue    = ARGS_TO_CONTINUE_NAME,
            restore_args        = display(|f| write_restore_args(f, fn_args)),
            forget_args         = display(|f| write_forget_args(f, fn_args)),
            unwind              = UNWIND_DATA_NAME);
        syn::parse_str(&header_str)
            .unwrap_or_else(|e| panic!("{}\ndetails: {}\nheader:\n{}",
                                       error_msg!("generated header unparsable"), e, &header_str))
    }
}

fn write_full_fn_name(f: &mut Formatter, builder: &FnHeaderBuilder, fn_ident: &Ident) -> Result<(), Error> {
    match *builder {
        FnHeaderBuilder::StaticFn               => (),
        FnHeaderBuilder::StructImpl |
        FnHeaderBuilder::TraitDefault           => write!(f, "Self::")?,
        FnHeaderBuilder::TraitImpl(ref path)    => write!(f, "<Self as {}>::", display(|f| write_trait_path(f, path)))?,
    }
    write!(f, "{}", fn_ident.as_ref())
}

fn write_trait_path<T: ToTokens + Clone>(f: &mut Formatter, trait_path: &Punctuated<PathSegment, T>) -> Result<(), Error> {
    let mut trait_path_without_lifetimes = trait_path.clone();
    remove_lifetimes_from_path(&mut trait_path_without_lifetimes);
    write!(f, "{}", trait_path_without_lifetimes.into_tokens())
}

fn write_extract_args<T>(f: &mut Formatter, fn_args: &Punctuated<FnArg, T>) -> Result<(), Error> {
    if fn_args.is_empty() {
        return write!(f, "()");
    }
    write!(f, "unsafe {{ (")?;
    for fn_arg_name in iter_fn_arg_names(fn_args) {
        write!(f, "::std::mem::replace({}::mocking_utils::as_mut(&{}), ::std::mem::uninitialized()), ",
               MOCKTOPUS_CRATE_NAME, fn_arg_name)?;
    }
    write!(f, ") }}")
}

fn write_restore_args<T>(f: &mut Formatter, fn_args: &Punctuated<FnArg, T>) -> Result<(), Error> {
    if fn_args.is_empty() {
        return writeln!(f, "()");
    }
    writeln!(f, "unsafe {{")?;
    for (fn_arg_index, fn_arg_name) in iter_fn_arg_names(fn_args).enumerate() {
        writeln!(f, "::std::mem::replace({}::mocking_utils::as_mut(&{}), {}.{});",
                 MOCKTOPUS_CRATE_NAME, fn_arg_name, ARGS_TO_CONTINUE_NAME, fn_arg_index)?;
    }
    writeln!(f, "}}")
}

fn write_forget_args<T>(f: &mut Formatter, fn_args: &Punctuated<FnArg, T>) -> Result<(), Error> {
    for fn_arg_name in iter_fn_arg_names(fn_args) {
        writeln!(f, "::std::mem::forget({});", fn_arg_name)?;
    }
    Ok(())
}

fn iter_fn_arg_names<'a, T>(input_args: &'a Punctuated<FnArg, T>) -> impl Iterator<Item = &'a str> {
    input_args.iter()
        .map(|fn_arg| match *fn_arg {
            FnArg::SelfRef(_) | FnArg::SelfValue(_) => "self",
            FnArg::Captured(
                ArgCaptured {
                    pat: Pat::Ident(
                        PatIdent {
                            ref ident,
                            subpat: None,
                            ..
                        }
                    ),
                    ..
                }
            ) => ident.as_ref(),
            _ => panic!("{}: '{}'", error_msg!("invalid fn arg type"), fn_arg.clone().into_tokens()),
        })
}
<|endoftext|>


<commit_before>// Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
//
// 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.

use std::ptr;
use std::mem;
use mopa;

use glib_ffi;
use gobject_ffi;
use gst_ffi;
use gst_base_ffi;

use glib;
use glib::translate::*;
use gst;
use gst::prelude::*;
use gst_base;
use gst_base::prelude::*;

use object::*;
use element::*;

pub trait BaseSrcImpl<T: BaseSrc>
    : mopa::Any + ObjectImpl<T> + ElementImpl<T> + Send + Sync + 'static {
    fn start(&self, _element: &T) -> bool {
        true
    }
    fn stop(&self, _element: &T) -> bool {
        true
    }
    fn is_seekable(&self, _element: &T) -> bool {
        false
    }
    fn get_size(&self, _element: &T) -> Option<u64> {
        None
    }
    fn fill(
        &self,
        element: &T,
        offset: u64,
        length: u32,
        buffer: &mut gst::BufferRef,
    ) -> gst::FlowReturn;
    fn do_seek(&self, element: &T, segment: &mut gst::Segment) -> bool {
        element.parent_do_seek(segment)
    }
    fn query(&self, element: &T, query: &mut gst::QueryRef) -> bool {
        element.parent_query(query)
    }
    fn event(&self, element: &T, event: &gst::Event) -> bool {
        element.parent_event(event)
    }
}

mopafy_object_impl!(BaseSrc, BaseSrcImpl);

pub unsafe trait BaseSrc
    : IsA<gst::Element> + IsA<gst_base::BaseSrc> + ObjectType {
    fn parent_do_seek(&self, segment: &mut gst::Segment) -> bool {
        unsafe {
            let klass = self.get_class();
            let parent_klass = (*klass).get_parent_class() as *const gst_base_ffi::GstBaseSrcClass;
            (*parent_klass)
                .do_seek
                .map(|f| {
                    from_glib(f(self.to_glib_none().0, segment.to_glib_none_mut().0))
                })
                .unwrap_or(false)
        }
    }

    fn parent_query(&self, query: &mut gst::QueryRef) -> bool {
        unsafe {
            let klass = self.get_class();
            let parent_klass = (*klass).get_parent_class() as *const gst_base_ffi::GstBaseSrcClass;
            (*parent_klass)
                .query
                .map(|f| from_glib(f(self.to_glib_none().0, query.as_mut_ptr())))
                .unwrap_or(false)
        }
    }

    fn parent_event(&self, event: &gst::Event) -> bool {
        unsafe {
            let klass = self.get_class();
            let parent_klass = (*klass).get_parent_class() as *const gst_base_ffi::GstBaseSrcClass;
            (*parent_klass)
                .event
                .map(|f| {
                    from_glib(f(self.to_glib_none().0, event.to_glib_none().0))
                })
                .unwrap_or(false)
        }
    }
}

pub unsafe trait BaseSrcClass<T: BaseSrc>
where
    T::ImplType: BaseSrcImpl<T>,
{
    fn override_vfuncs(&mut self, _: &ClassInitToken) {
        unsafe {
            let klass = &mut *(self as *const Self as *mut gst_base_ffi::GstBaseSrcClass);
            klass.start = Some(base_src_start::<T>);
            klass.stop = Some(base_src_stop::<T>);
            klass.is_seekable = Some(base_src_is_seekable::<T>);
            klass.get_size = Some(base_src_get_size::<T>);
            klass.fill = Some(base_src_fill::<T>);
            klass.do_seek = Some(base_src_do_seek::<T>);
            klass.query = Some(base_src_query::<T>);
            klass.event = Some(base_src_event::<T>);
        }
    }
}

glib_wrapper! {
    pub struct RsBaseSrc(Object<InstanceStruct<RsBaseSrc>>): [gst_base::BaseSrc => gst_base_ffi::GstBaseSrc,
                                                              gst::Element => gst_ffi::GstElement,
                                                              gst::Object => gst_ffi::GstObject];

    match fn {
        get_type => || get_type::<RsBaseSrc>(),
    }
}

// FIXME: This is wrong: it must be a basesrc but also backed by ObjectType<T>
unsafe impl<T: IsA<gst::Element> + IsA<gst_base::BaseSrc> + ObjectType> BaseSrc for T {}
pub type RsBaseSrcClass = ClassStruct<RsBaseSrc>;

// FIXME: Boilerplate
unsafe impl BaseSrcClass<RsBaseSrc> for RsBaseSrcClass {}
unsafe impl ElementClass<RsBaseSrc> for RsBaseSrcClass {}

#[macro_export]
macro_rules! box_base_src_impl(
    ($name:ident) => {
        box_element_impl!($name);

        impl<T: BaseSrc> BaseSrcImpl<T> for Box<$name<T>> {
            fn start(&self, element: &T) -> bool {
                let imp: &$name<T> = self.as_ref();
                imp.start(element)
            }

            fn stop(&self, element: &T) -> bool {
                let imp: &$name<T> = self.as_ref();
                imp.stop(element)
            }

            fn is_seekable(&self, element: &T) -> bool {
                let imp: &$name<T> = self.as_ref();
                imp.is_seekable(element)
            }

            fn get_size(&self, element: &T) -> Option<u64> {
                let imp: &$name<T> = self.as_ref();
                imp.get_size(element)
            }

            fn fill(
                &self,
                element: &T,
                offset: u64,
                length: u32,
                buffer: &mut gst::BufferRef,
            ) -> gst::FlowReturn {
                let imp: &$name<T> = self.as_ref();
                imp.fill(element, offset, length, buffer)
            }

            fn do_seek(&self, element: &T, segment: &mut gst::Segment) -> bool {
                let imp: &$name<T> = self.as_ref();
                imp.do_seek(element, segment)
            }

            fn query(&self, element: &T, query: &mut gst::QueryRef) -> bool {
                let imp: &$name<T> = self.as_ref();
                imp.query(element, query)
            }
            fn event(&self, element: &T, event: &gst::Event) -> bool {
                let imp: &$name<T> = self.as_ref();
                imp.event(element, event)
            }
        }
    };
);
box_base_src_impl!(BaseSrcImpl);

impl ObjectType for RsBaseSrc {
    const NAME: &'static str = "RsBaseSrc";
    type GlibType = gst_base_ffi::GstBaseSrc;
    type GlibClassType = gst_base_ffi::GstBaseSrcClass;
    type ImplType = Box<BaseSrcImpl<Self>>;

    fn glib_type() -> glib::Type {
        unsafe { from_glib(gst_base_ffi::gst_base_src_get_type()) }
    }

    fn class_init(token: &ClassInitToken, klass: &mut RsBaseSrcClass) {
        ElementClass::override_vfuncs(klass, token);
        BaseSrcClass::override_vfuncs(klass, token);
    }

    object_type_fns!();
}

unsafe extern "C" fn base_src_start<T: BaseSrc>(
    ptr: *mut gst_base_ffi::GstBaseSrc,
) -> glib_ffi::gboolean
where
    T::ImplType: BaseSrcImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;

    panic_to_error!(&wrap, &element.panicked, false, { imp.start(&wrap) }).to_glib()
}

unsafe extern "C" fn base_src_stop<T: BaseSrc>(
    ptr: *mut gst_base_ffi::GstBaseSrc,
) -> glib_ffi::gboolean
where
    T::ImplType: BaseSrcImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;

    panic_to_error!(&wrap, &element.panicked, false, { imp.stop(&wrap) }).to_glib()
}

unsafe extern "C" fn base_src_is_seekable<T: BaseSrc>(
    ptr: *mut gst_base_ffi::GstBaseSrc,
) -> glib_ffi::gboolean
where
    T::ImplType: BaseSrcImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;

    panic_to_error!(&wrap, &element.panicked, false, { imp.is_seekable(&wrap) }).to_glib()
}

unsafe extern "C" fn base_src_get_size<T: BaseSrc>(
    ptr: *mut gst_base_ffi::GstBaseSrc,
    size: *mut u64,
) -> glib_ffi::gboolean
where
    T::ImplType: BaseSrcImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;

    panic_to_error!(&wrap, &element.panicked, false, {
        match imp.get_size(&wrap) {
            Some(s) => {
                *size = s;
                true
            }
            None => false,
        }
    }).to_glib()
}

unsafe extern "C" fn base_src_fill<T: BaseSrc>(
    ptr: *mut gst_base_ffi::GstBaseSrc,
    offset: u64,
    length: u32,
    buffer: *mut gst_ffi::GstBuffer,
) -> gst_ffi::GstFlowReturn
where
    T::ImplType: BaseSrcImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;
    let buffer = gst::BufferRef::from_mut_ptr(buffer);

    panic_to_error!(&wrap, &element.panicked, gst::FlowReturn::Error, {
        imp.fill(&wrap, offset, length, buffer)
    }).to_glib()
}

unsafe extern "C" fn base_src_do_seek<T: BaseSrc>(
    ptr: *mut gst_base_ffi::GstBaseSrc,
    segment: *mut gst_ffi::GstSegment,
) -> glib_ffi::gboolean
where
    T::ImplType: BaseSrcImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;

    panic_to_error!(&wrap, &element.panicked, false, {
        imp.do_seek(&wrap, &mut from_glib_borrow(segment))
    }).to_glib()
}

unsafe extern "C" fn base_src_query<T: BaseSrc>(
    ptr: *mut gst_base_ffi::GstBaseSrc,
    query_ptr: *mut gst_ffi::GstQuery,
) -> glib_ffi::gboolean
where
    T::ImplType: BaseSrcImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;
    let query = gst::QueryRef::from_mut_ptr(query_ptr);

    panic_to_error!(&wrap, &element.panicked, false, { imp.query(&wrap, query) }).to_glib()
}

unsafe extern "C" fn base_src_event<T: BaseSrc>(
    ptr: *mut gst_base_ffi::GstBaseSrc,
    event_ptr: *mut gst_ffi::GstEvent,
) -> glib_ffi::gboolean
where
    T::ImplType: BaseSrcImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;

    panic_to_error!(&wrap, &element.panicked, false, {
        imp.event(&wrap, &from_glib_none(event_ptr))
    }).to_glib()
}
<commit_msg>Remove obsolete FIXME comment<commit_after>// Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
//
// 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.

use std::ptr;
use std::mem;
use mopa;

use glib_ffi;
use gobject_ffi;
use gst_ffi;
use gst_base_ffi;

use glib;
use glib::translate::*;
use gst;
use gst::prelude::*;
use gst_base;
use gst_base::prelude::*;

use object::*;
use element::*;

pub trait BaseSrcImpl<T: BaseSrc>
    : mopa::Any + ObjectImpl<T> + ElementImpl<T> + Send + Sync + 'static {
    fn start(&self, _element: &T) -> bool {
        true
    }
    fn stop(&self, _element: &T) -> bool {
        true
    }
    fn is_seekable(&self, _element: &T) -> bool {
        false
    }
    fn get_size(&self, _element: &T) -> Option<u64> {
        None
    }
    fn fill(
        &self,
        element: &T,
        offset: u64,
        length: u32,
        buffer: &mut gst::BufferRef,
    ) -> gst::FlowReturn;
    fn do_seek(&self, element: &T, segment: &mut gst::Segment) -> bool {
        element.parent_do_seek(segment)
    }
    fn query(&self, element: &T, query: &mut gst::QueryRef) -> bool {
        element.parent_query(query)
    }
    fn event(&self, element: &T, event: &gst::Event) -> bool {
        element.parent_event(event)
    }
}

mopafy_object_impl!(BaseSrc, BaseSrcImpl);

pub unsafe trait BaseSrc
    : IsA<gst::Element> + IsA<gst_base::BaseSrc> + ObjectType {
    fn parent_do_seek(&self, segment: &mut gst::Segment) -> bool {
        unsafe {
            let klass = self.get_class();
            let parent_klass = (*klass).get_parent_class() as *const gst_base_ffi::GstBaseSrcClass;
            (*parent_klass)
                .do_seek
                .map(|f| {
                    from_glib(f(self.to_glib_none().0, segment.to_glib_none_mut().0))
                })
                .unwrap_or(false)
        }
    }

    fn parent_query(&self, query: &mut gst::QueryRef) -> bool {
        unsafe {
            let klass = self.get_class();
            let parent_klass = (*klass).get_parent_class() as *const gst_base_ffi::GstBaseSrcClass;
            (*parent_klass)
                .query
                .map(|f| from_glib(f(self.to_glib_none().0, query.as_mut_ptr())))
                .unwrap_or(false)
        }
    }

    fn parent_event(&self, event: &gst::Event) -> bool {
        unsafe {
            let klass = self.get_class();
            let parent_klass = (*klass).get_parent_class() as *const gst_base_ffi::GstBaseSrcClass;
            (*parent_klass)
                .event
                .map(|f| {
                    from_glib(f(self.to_glib_none().0, event.to_glib_none().0))
                })
                .unwrap_or(false)
        }
    }
}

pub unsafe trait BaseSrcClass<T: BaseSrc>
where
    T::ImplType: BaseSrcImpl<T>,
{
    fn override_vfuncs(&mut self, _: &ClassInitToken) {
        unsafe {
            let klass = &mut *(self as *const Self as *mut gst_base_ffi::GstBaseSrcClass);
            klass.start = Some(base_src_start::<T>);
            klass.stop = Some(base_src_stop::<T>);
            klass.is_seekable = Some(base_src_is_seekable::<T>);
            klass.get_size = Some(base_src_get_size::<T>);
            klass.fill = Some(base_src_fill::<T>);
            klass.do_seek = Some(base_src_do_seek::<T>);
            klass.query = Some(base_src_query::<T>);
            klass.event = Some(base_src_event::<T>);
        }
    }
}

glib_wrapper! {
    pub struct RsBaseSrc(Object<InstanceStruct<RsBaseSrc>>): [gst_base::BaseSrc => gst_base_ffi::GstBaseSrc,
                                                              gst::Element => gst_ffi::GstElement,
                                                              gst::Object => gst_ffi::GstObject];

    match fn {
        get_type => || get_type::<RsBaseSrc>(),
    }
}

unsafe impl<T: IsA<gst::Element> + IsA<gst_base::BaseSrc> + ObjectType> BaseSrc for T {}
pub type RsBaseSrcClass = ClassStruct<RsBaseSrc>;

// FIXME: Boilerplate
unsafe impl BaseSrcClass<RsBaseSrc> for RsBaseSrcClass {}
unsafe impl ElementClass<RsBaseSrc> for RsBaseSrcClass {}

#[macro_export]
macro_rules! box_base_src_impl(
    ($name:ident) => {
        box_element_impl!($name);

        impl<T: BaseSrc> BaseSrcImpl<T> for Box<$name<T>> {
            fn start(&self, element: &T) -> bool {
                let imp: &$name<T> = self.as_ref();
                imp.start(element)
            }

            fn stop(&self, element: &T) -> bool {
                let imp: &$name<T> = self.as_ref();
                imp.stop(element)
            }

            fn is_seekable(&self, element: &T) -> bool {
                let imp: &$name<T> = self.as_ref();
                imp.is_seekable(element)
            }

            fn get_size(&self, element: &T) -> Option<u64> {
                let imp: &$name<T> = self.as_ref();
                imp.get_size(element)
            }

            fn fill(
                &self,
                element: &T,
                offset: u64,
                length: u32,
                buffer: &mut gst::BufferRef,
            ) -> gst::FlowReturn {
                let imp: &$name<T> = self.as_ref();
                imp.fill(element, offset, length, buffer)
            }

            fn do_seek(&self, element: &T, segment: &mut gst::Segment) -> bool {
                let imp: &$name<T> = self.as_ref();
                imp.do_seek(element, segment)
            }

            fn query(&self, element: &T, query: &mut gst::QueryRef) -> bool {
                let imp: &$name<T> = self.as_ref();
                imp.query(element, query)
            }
            fn event(&self, element: &T, event: &gst::Event) -> bool {
                let imp: &$name<T> = self.as_ref();
                imp.event(element, event)
            }
        }
    };
);
box_base_src_impl!(BaseSrcImpl);

impl ObjectType for RsBaseSrc {
    const NAME: &'static str = "RsBaseSrc";
    type GlibType = gst_base_ffi::GstBaseSrc;
    type GlibClassType = gst_base_ffi::GstBaseSrcClass;
    type ImplType = Box<BaseSrcImpl<Self>>;

    fn glib_type() -> glib::Type {
        unsafe { from_glib(gst_base_ffi::gst_base_src_get_type()) }
    }

    fn class_init(token: &ClassInitToken, klass: &mut RsBaseSrcClass) {
        ElementClass::override_vfuncs(klass, token);
        BaseSrcClass::override_vfuncs(klass, token);
    }

    object_type_fns!();
}

unsafe extern "C" fn base_src_start<T: BaseSrc>(
    ptr: *mut gst_base_ffi::GstBaseSrc,
) -> glib_ffi::gboolean
where
    T::ImplType: BaseSrcImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;

    panic_to_error!(&wrap, &element.panicked, false, { imp.start(&wrap) }).to_glib()
}

unsafe extern "C" fn base_src_stop<T: BaseSrc>(
    ptr: *mut gst_base_ffi::GstBaseSrc,
) -> glib_ffi::gboolean
where
    T::ImplType: BaseSrcImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;

    panic_to_error!(&wrap, &element.panicked, false, { imp.stop(&wrap) }).to_glib()
}

unsafe extern "C" fn base_src_is_seekable<T: BaseSrc>(
    ptr: *mut gst_base_ffi::GstBaseSrc,
) -> glib_ffi::gboolean
where
    T::ImplType: BaseSrcImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;

    panic_to_error!(&wrap, &element.panicked, false, { imp.is_seekable(&wrap) }).to_glib()
}

unsafe extern "C" fn base_src_get_size<T: BaseSrc>(
    ptr: *mut gst_base_ffi::GstBaseSrc,
    size: *mut u64,
) -> glib_ffi::gboolean
where
    T::ImplType: BaseSrcImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;

    panic_to_error!(&wrap, &element.panicked, false, {
        match imp.get_size(&wrap) {
            Some(s) => {
                *size = s;
                true
            }
            None => false,
        }
    }).to_glib()
}

unsafe extern "C" fn base_src_fill<T: BaseSrc>(
    ptr: *mut gst_base_ffi::GstBaseSrc,
    offset: u64,
    length: u32,
    buffer: *mut gst_ffi::GstBuffer,
) -> gst_ffi::GstFlowReturn
where
    T::ImplType: BaseSrcImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;
    let buffer = gst::BufferRef::from_mut_ptr(buffer);

    panic_to_error!(&wrap, &element.panicked, gst::FlowReturn::Error, {
        imp.fill(&wrap, offset, length, buffer)
    }).to_glib()
}

unsafe extern "C" fn base_src_do_seek<T: BaseSrc>(
    ptr: *mut gst_base_ffi::GstBaseSrc,
    segment: *mut gst_ffi::GstSegment,
) -> glib_ffi::gboolean
where
    T::ImplType: BaseSrcImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;

    panic_to_error!(&wrap, &element.panicked, false, {
        imp.do_seek(&wrap, &mut from_glib_borrow(segment))
    }).to_glib()
}

unsafe extern "C" fn base_src_query<T: BaseSrc>(
    ptr: *mut gst_base_ffi::GstBaseSrc,
    query_ptr: *mut gst_ffi::GstQuery,
) -> glib_ffi::gboolean
where
    T::ImplType: BaseSrcImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;
    let query = gst::QueryRef::from_mut_ptr(query_ptr);

    panic_to_error!(&wrap, &element.panicked, false, { imp.query(&wrap, query) }).to_glib()
}

unsafe extern "C" fn base_src_event<T: BaseSrc>(
    ptr: *mut gst_base_ffi::GstBaseSrc,
    event_ptr: *mut gst_ffi::GstEvent,
) -> glib_ffi::gboolean
where
    T::ImplType: BaseSrcImpl<T>,
{
    callback_guard!();
    floating_reference_guard!(ptr);
    let element = &*(ptr as *mut InstanceStruct<T>);
    let wrap: T = from_glib_borrow(ptr as *mut InstanceStruct<T>);
    let imp = &*element.imp;

    panic_to_error!(&wrap, &element.panicked, false, {
        imp.event(&wrap, &from_glib_none(event_ptr))
    }).to_glib()
}
<|endoftext|>