<commit_before>//! FIXME: write short doc here

use std::{ffi::OsStr, ops, path::Path, process::Command};

use anyhow::{Context, Result};
use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId};
use paths::{AbsPath, AbsPathBuf};
use ra_arena::{Arena, Idx};
use ra_db::Edition;
use rustc_hash::FxHashMap;

/// `CargoWorkspace` represents the logical structure of, well, a Cargo
/// workspace. It pretty closely mirrors `cargo metadata` output.
///
/// Note that internally, rust analyzer uses a different structure:
/// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates,
/// while this knows about `Packages` & `Targets`: purely cargo-related
/// concepts.
///
/// We use absolute paths here, `cargo metadata` guarantees to always produce
/// abs paths.
#[derive(Debug, Clone)]
pub struct CargoWorkspace {
    packages: Arena<PackageData>,
    targets: Arena<TargetData>,
    workspace_root: AbsPathBuf,
}

impl ops::Index<Package> for CargoWorkspace {
    type Output = PackageData;
    fn index(&self, index: Package) -> &PackageData {
        &self.packages[index]
    }
}

impl ops::Index<Target> for CargoWorkspace {
    type Output = TargetData;
    fn index(&self, index: Target) -> &TargetData {
        &self.targets[index]
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CargoConfig {
    /// Do not activate the `default` feature.
    pub no_default_features: bool,

    /// Activate all available features
    pub all_features: bool,

    /// List of features to activate.
    /// This will be ignored if `cargo_all_features` is true.
    pub features: Vec<String>,

    /// Runs cargo check on launch to figure out the correct values of OUT_DIR
    pub load_out_dirs_from_check: bool,

    /// rustc target
    pub target: Option<String>,
}

impl Default for CargoConfig {
    fn default() -> Self {
        CargoConfig {
            no_default_features: false,
            all_features: false,
            features: Vec::new(),
            load_out_dirs_from_check: false,
            target: None,
        }
    }
}

pub type Package = Idx<PackageData>;

pub type Target = Idx<TargetData>;

#[derive(Debug, Clone)]
pub struct PackageData {
    pub version: String,
    pub name: String,
    pub manifest: AbsPathBuf,
    pub targets: Vec<Target>,
    pub is_member: bool,
    pub dependencies: Vec<PackageDependency>,
    pub edition: Edition,
    pub features: Vec<String>,
    pub cfgs: Vec<String>,
    pub out_dir: Option<AbsPathBuf>,
    pub proc_macro_dylib_path: Option<AbsPathBuf>,
}

#[derive(Debug, Clone)]
pub struct PackageDependency {
    pub pkg: Package,
    pub name: String,
}

#[derive(Debug, Clone)]
pub struct TargetData {
    pub package: Package,
    pub name: String,
    pub root: AbsPathBuf,
    pub kind: TargetKind,
    pub is_proc_macro: bool,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TargetKind {
    Bin,
    /// Any kind of Cargo lib crate-type (dylib, rlib, proc-macro, ...).
    Lib,
    Example,
    Test,
    Bench,
    Other,
}

impl TargetKind {
    fn new(kinds: &[String]) -> TargetKind {
        for kind in kinds {
            return match kind.as_str() {
                "bin" => TargetKind::Bin,
                "test" => TargetKind::Test,
                "bench" => TargetKind::Bench,
                "example" => TargetKind::Example,
                "proc-macro" => TargetKind::Lib,
                _ if kind.contains("lib") => TargetKind::Lib,
                _ => continue,
            };
        }
        TargetKind::Other
    }
}

impl PackageData {
    pub fn root(&self) -> &AbsPath {
        self.manifest.parent().unwrap()
    }
}

impl CargoWorkspace {
    pub fn from_cargo_metadata(
        cargo_toml: &Path,
        cargo_features: &CargoConfig,
    ) -> Result<CargoWorkspace> {
        let mut meta = MetadataCommand::new();
        meta.cargo_path(ra_toolchain::cargo());
        meta.manifest_path(cargo_toml);
        if cargo_features.all_features {
            meta.features(CargoOpt::AllFeatures);
        } else if cargo_features.no_default_features {
            // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
            // https://github.com/oli-obk/cargo_metadata/issues/79
            meta.features(CargoOpt::NoDefaultFeatures);
        } else if !cargo_features.features.is_empty() {
            meta.features(CargoOpt::SomeFeatures(cargo_features.features.clone()));
        }
        if let Some(parent) = cargo_toml.parent() {
            meta.current_dir(parent);
        }
        if let Some(target) = cargo_features.target.as_ref() {
            meta.other_options(vec![String::from("--filter-platform"), target.clone()]);
        }
        let meta = meta.exec().with_context(|| {
            format!("Failed to run `cargo metadata --manifest-path {}`", cargo_toml.display())
        })?;

        let mut out_dir_by_id = FxHashMap::default();
        let mut cfgs = FxHashMap::default();
        let mut proc_macro_dylib_paths = FxHashMap::default();
        if cargo_features.load_out_dirs_from_check {
            let resources = load_extern_resources(cargo_toml, cargo_features)?;
            out_dir_by_id = resources.out_dirs;
            cfgs = resources.cfgs;
            proc_macro_dylib_paths = resources.proc_dylib_paths;
        }

        let mut pkg_by_id = FxHashMap::default();
        let mut packages = Arena::default();
        let mut targets = Arena::default();

        let ws_members = &meta.workspace_members;

        for meta_pkg in meta.packages {
            let cargo_metadata::Package { id, edition, name, manifest_path, version, .. } =
                meta_pkg;
            let is_member = ws_members.contains(&id);
            let edition = edition
                .parse::<Edition>()
                .with_context(|| format!("Failed to parse edition {}", edition))?;
            let pkg = packages.alloc(PackageData {
                name,
                version: version.to_string(),
                manifest: AbsPathBuf::assert(manifest_path),
                targets: Vec::new(),
                is_member,
                edition,
                dependencies: Vec::new(),
                features: Vec::new(),
                cfgs: cfgs.get(&id).cloned().unwrap_or_default(),
                out_dir: out_dir_by_id.get(&id).cloned(),
                proc_macro_dylib_path: proc_macro_dylib_paths.get(&id).cloned(),
            });
            let pkg_data = &mut packages[pkg];
            pkg_by_id.insert(id, pkg);
            for meta_tgt in meta_pkg.targets {
                let is_proc_macro = meta_tgt.kind.as_slice() == ["proc-macro"];
                let tgt = targets.alloc(TargetData {
                    package: pkg,
                    name: meta_tgt.name,
                    root: AbsPathBuf::assert(meta_tgt.src_path.clone()),
                    kind: TargetKind::new(meta_tgt.kind.as_slice()),
                    is_proc_macro,
                });
                pkg_data.targets.push(tgt);
            }
        }
        let resolve = meta.resolve.expect("metadata executed with deps");
        for node in resolve.nodes {
            let source = match pkg_by_id.get(&node.id) {
                Some(&src) => src,
                // FIXME: replace this and a similar branch below with `.unwrap`, once
                // https://github.com/rust-lang/cargo/issues/7841
                // is fixed and hits stable (around 1.43-is probably?).
                None => {
                    log::error!("Node id do not match in cargo metadata, ignoring {}", node.id);
                    continue;
                }
            };
            for dep_node in node.deps {
                let pkg = match pkg_by_id.get(&dep_node.pkg) {
                    Some(&pkg) => pkg,
                    None => {
                        log::error!(
                            "Dep node id do not match in cargo metadata, ignoring {}",
                            dep_node.pkg
                        );
                        continue;
                    }
                };
                let dep = PackageDependency { name: dep_node.name, pkg };
                packages[source].dependencies.push(dep);
            }
            packages[source].features.extend(node.features);
        }

        let workspace_root = AbsPathBuf::assert(meta.workspace_root);
        Ok(CargoWorkspace { packages, targets, workspace_root: workspace_root })
    }

    pub fn packages<'a>(&'a self) -> impl Iterator<Item = Package> + ExactSizeIterator + 'a {
        self.packages.iter().map(|(id, _pkg)| id)
    }

    pub fn target_by_root(&self, root: &AbsPath) -> Option<Target> {
        self.packages()
            .filter_map(|pkg| self[pkg].targets.iter().find(|&&it| &self[it].root == root))
            .next()
            .copied()
    }

    pub fn workspace_root(&self) -> &AbsPath {
        &self.workspace_root
    }

    pub fn package_flag(&self, package: &PackageData) -> String {
        if self.is_unique(&*package.name) {
            package.name.clone()
        } else {
            format!("{}:{}", package.name, package.version)
        }
    }

    fn is_unique(&self, name: &str) -> bool {
        self.packages.iter().filter(|(_, v)| v.name == name).count() == 1
    }
}

#[derive(Debug, Clone, Default)]
pub struct ExternResources {
    out_dirs: FxHashMap<PackageId, AbsPathBuf>,
    proc_dylib_paths: FxHashMap<PackageId, AbsPathBuf>,
    cfgs: FxHashMap<PackageId, Vec<String>>,
}

pub fn load_extern_resources(
    cargo_toml: &Path,
    cargo_features: &CargoConfig,
) -> Result<ExternResources> {
    let mut cmd = Command::new(ra_toolchain::cargo());
    cmd.args(&["check", "--message-format=json", "--manifest-path"]).arg(cargo_toml);
    if cargo_features.all_features {
        cmd.arg("--all-features");
    } else if cargo_features.no_default_features {
        // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
        // https://github.com/oli-obk/cargo_metadata/issues/79
        cmd.arg("--no-default-features");
    } else {
        cmd.args(&cargo_features.features);
    }

    let output = cmd.output()?;

    let mut res = ExternResources::default();

    for message in cargo_metadata::Message::parse_stream(output.stdout.as_slice()) {
        if let Ok(message) = message {
            match message {
                Message::BuildScriptExecuted(BuildScript { package_id, out_dir, cfgs, .. }) => {
                    let out_dir = AbsPathBuf::assert(out_dir);
                    res.out_dirs.insert(package_id.clone(), out_dir);
                    res.cfgs.insert(package_id, cfgs);
                }
                Message::CompilerArtifact(message) => {
                    if message.target.kind.contains(&"proc-macro".to_string()) {
                        let package_id = message.package_id;
                        // Skip rmeta file
                        if let Some(filename) = message.filenames.iter().find(|name| is_dylib(name))
                        {
                            let filename = AbsPathBuf::assert(filename.clone());
                            res.proc_dylib_paths.insert(package_id, filename);
                        }
                    }
                }
                Message::CompilerMessage(_) => (),
                Message::Unknown => (),
                Message::BuildFinished(_) => {}
                Message::TextLine(_) => {}
            }
        }
    }
    Ok(res)
}

// FIXME: File a better way to know if it is a dylib
fn is_dylib(path: &Path) -> bool {
    match path.extension().and_then(OsStr::to_str).map(|it| it.to_string().to_lowercase()) {
        None => false,
        Some(ext) => matches!(ext.as_str(), "dll" | "dylib" | "so"),
    }
}
<commit_msg>Don't crash on empty out_dirs with older cargos<commit_after>//! FIXME: write short doc here

use std::{
    ffi::OsStr,
    ops,
    path::{Path, PathBuf},
    process::Command,
};

use anyhow::{Context, Result};
use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId};
use paths::{AbsPath, AbsPathBuf};
use ra_arena::{Arena, Idx};
use ra_db::Edition;
use rustc_hash::FxHashMap;

/// `CargoWorkspace` represents the logical structure of, well, a Cargo
/// workspace. It pretty closely mirrors `cargo metadata` output.
///
/// Note that internally, rust analyzer uses a different structure:
/// `CrateGraph`. `CrateGraph` is lower-level: it knows only about the crates,
/// while this knows about `Packages` & `Targets`: purely cargo-related
/// concepts.
///
/// We use absolute paths here, `cargo metadata` guarantees to always produce
/// abs paths.
#[derive(Debug, Clone)]
pub struct CargoWorkspace {
    packages: Arena<PackageData>,
    targets: Arena<TargetData>,
    workspace_root: AbsPathBuf,
}

impl ops::Index<Package> for CargoWorkspace {
    type Output = PackageData;
    fn index(&self, index: Package) -> &PackageData {
        &self.packages[index]
    }
}

impl ops::Index<Target> for CargoWorkspace {
    type Output = TargetData;
    fn index(&self, index: Target) -> &TargetData {
        &self.targets[index]
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CargoConfig {
    /// Do not activate the `default` feature.
    pub no_default_features: bool,

    /// Activate all available features
    pub all_features: bool,

    /// List of features to activate.
    /// This will be ignored if `cargo_all_features` is true.
    pub features: Vec<String>,

    /// Runs cargo check on launch to figure out the correct values of OUT_DIR
    pub load_out_dirs_from_check: bool,

    /// rustc target
    pub target: Option<String>,
}

impl Default for CargoConfig {
    fn default() -> Self {
        CargoConfig {
            no_default_features: false,
            all_features: false,
            features: Vec::new(),
            load_out_dirs_from_check: false,
            target: None,
        }
    }
}

pub type Package = Idx<PackageData>;

pub type Target = Idx<TargetData>;

#[derive(Debug, Clone)]
pub struct PackageData {
    pub version: String,
    pub name: String,
    pub manifest: AbsPathBuf,
    pub targets: Vec<Target>,
    pub is_member: bool,
    pub dependencies: Vec<PackageDependency>,
    pub edition: Edition,
    pub features: Vec<String>,
    pub cfgs: Vec<String>,
    pub out_dir: Option<AbsPathBuf>,
    pub proc_macro_dylib_path: Option<AbsPathBuf>,
}

#[derive(Debug, Clone)]
pub struct PackageDependency {
    pub pkg: Package,
    pub name: String,
}

#[derive(Debug, Clone)]
pub struct TargetData {
    pub package: Package,
    pub name: String,
    pub root: AbsPathBuf,
    pub kind: TargetKind,
    pub is_proc_macro: bool,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TargetKind {
    Bin,
    /// Any kind of Cargo lib crate-type (dylib, rlib, proc-macro, ...).
    Lib,
    Example,
    Test,
    Bench,
    Other,
}

impl TargetKind {
    fn new(kinds: &[String]) -> TargetKind {
        for kind in kinds {
            return match kind.as_str() {
                "bin" => TargetKind::Bin,
                "test" => TargetKind::Test,
                "bench" => TargetKind::Bench,
                "example" => TargetKind::Example,
                "proc-macro" => TargetKind::Lib,
                _ if kind.contains("lib") => TargetKind::Lib,
                _ => continue,
            };
        }
        TargetKind::Other
    }
}

impl PackageData {
    pub fn root(&self) -> &AbsPath {
        self.manifest.parent().unwrap()
    }
}

impl CargoWorkspace {
    pub fn from_cargo_metadata(
        cargo_toml: &Path,
        cargo_features: &CargoConfig,
    ) -> Result<CargoWorkspace> {
        let mut meta = MetadataCommand::new();
        meta.cargo_path(ra_toolchain::cargo());
        meta.manifest_path(cargo_toml);
        if cargo_features.all_features {
            meta.features(CargoOpt::AllFeatures);
        } else if cargo_features.no_default_features {
            // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
            // https://github.com/oli-obk/cargo_metadata/issues/79
            meta.features(CargoOpt::NoDefaultFeatures);
        } else if !cargo_features.features.is_empty() {
            meta.features(CargoOpt::SomeFeatures(cargo_features.features.clone()));
        }
        if let Some(parent) = cargo_toml.parent() {
            meta.current_dir(parent);
        }
        if let Some(target) = cargo_features.target.as_ref() {
            meta.other_options(vec![String::from("--filter-platform"), target.clone()]);
        }
        let meta = meta.exec().with_context(|| {
            format!("Failed to run `cargo metadata --manifest-path {}`", cargo_toml.display())
        })?;

        let mut out_dir_by_id = FxHashMap::default();
        let mut cfgs = FxHashMap::default();
        let mut proc_macro_dylib_paths = FxHashMap::default();
        if cargo_features.load_out_dirs_from_check {
            let resources = load_extern_resources(cargo_toml, cargo_features)?;
            out_dir_by_id = resources.out_dirs;
            cfgs = resources.cfgs;
            proc_macro_dylib_paths = resources.proc_dylib_paths;
        }

        let mut pkg_by_id = FxHashMap::default();
        let mut packages = Arena::default();
        let mut targets = Arena::default();

        let ws_members = &meta.workspace_members;

        for meta_pkg in meta.packages {
            let cargo_metadata::Package { id, edition, name, manifest_path, version, .. } =
                meta_pkg;
            let is_member = ws_members.contains(&id);
            let edition = edition
                .parse::<Edition>()
                .with_context(|| format!("Failed to parse edition {}", edition))?;
            let pkg = packages.alloc(PackageData {
                name,
                version: version.to_string(),
                manifest: AbsPathBuf::assert(manifest_path),
                targets: Vec::new(),
                is_member,
                edition,
                dependencies: Vec::new(),
                features: Vec::new(),
                cfgs: cfgs.get(&id).cloned().unwrap_or_default(),
                out_dir: out_dir_by_id.get(&id).cloned(),
                proc_macro_dylib_path: proc_macro_dylib_paths.get(&id).cloned(),
            });
            let pkg_data = &mut packages[pkg];
            pkg_by_id.insert(id, pkg);
            for meta_tgt in meta_pkg.targets {
                let is_proc_macro = meta_tgt.kind.as_slice() == ["proc-macro"];
                let tgt = targets.alloc(TargetData {
                    package: pkg,
                    name: meta_tgt.name,
                    root: AbsPathBuf::assert(meta_tgt.src_path.clone()),
                    kind: TargetKind::new(meta_tgt.kind.as_slice()),
                    is_proc_macro,
                });
                pkg_data.targets.push(tgt);
            }
        }
        let resolve = meta.resolve.expect("metadata executed with deps");
        for node in resolve.nodes {
            let source = match pkg_by_id.get(&node.id) {
                Some(&src) => src,
                // FIXME: replace this and a similar branch below with `.unwrap`, once
                // https://github.com/rust-lang/cargo/issues/7841
                // is fixed and hits stable (around 1.43-is probably?).
                None => {
                    log::error!("Node id do not match in cargo metadata, ignoring {}", node.id);
                    continue;
                }
            };
            for dep_node in node.deps {
                let pkg = match pkg_by_id.get(&dep_node.pkg) {
                    Some(&pkg) => pkg,
                    None => {
                        log::error!(
                            "Dep node id do not match in cargo metadata, ignoring {}",
                            dep_node.pkg
                        );
                        continue;
                    }
                };
                let dep = PackageDependency { name: dep_node.name, pkg };
                packages[source].dependencies.push(dep);
            }
            packages[source].features.extend(node.features);
        }

        let workspace_root = AbsPathBuf::assert(meta.workspace_root);
        Ok(CargoWorkspace { packages, targets, workspace_root: workspace_root })
    }

    pub fn packages<'a>(&'a self) -> impl Iterator<Item = Package> + ExactSizeIterator + 'a {
        self.packages.iter().map(|(id, _pkg)| id)
    }

    pub fn target_by_root(&self, root: &AbsPath) -> Option<Target> {
        self.packages()
            .filter_map(|pkg| self[pkg].targets.iter().find(|&&it| &self[it].root == root))
            .next()
            .copied()
    }

    pub fn workspace_root(&self) -> &AbsPath {
        &self.workspace_root
    }

    pub fn package_flag(&self, package: &PackageData) -> String {
        if self.is_unique(&*package.name) {
            package.name.clone()
        } else {
            format!("{}:{}", package.name, package.version)
        }
    }

    fn is_unique(&self, name: &str) -> bool {
        self.packages.iter().filter(|(_, v)| v.name == name).count() == 1
    }
}

#[derive(Debug, Clone, Default)]
pub struct ExternResources {
    out_dirs: FxHashMap<PackageId, AbsPathBuf>,
    proc_dylib_paths: FxHashMap<PackageId, AbsPathBuf>,
    cfgs: FxHashMap<PackageId, Vec<String>>,
}

pub fn load_extern_resources(
    cargo_toml: &Path,
    cargo_features: &CargoConfig,
) -> Result<ExternResources> {
    let mut cmd = Command::new(ra_toolchain::cargo());
    cmd.args(&["check", "--message-format=json", "--manifest-path"]).arg(cargo_toml);
    if cargo_features.all_features {
        cmd.arg("--all-features");
    } else if cargo_features.no_default_features {
        // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
        // https://github.com/oli-obk/cargo_metadata/issues/79
        cmd.arg("--no-default-features");
    } else {
        cmd.args(&cargo_features.features);
    }

    let output = cmd.output()?;

    let mut res = ExternResources::default();

    for message in cargo_metadata::Message::parse_stream(output.stdout.as_slice()) {
        if let Ok(message) = message {
            match message {
                Message::BuildScriptExecuted(BuildScript { package_id, out_dir, cfgs, .. }) => {
                    // cargo_metadata crate returns default (empty) path for
                    // older cargos, which is not absolute, so work around that.
                    if out_dir != PathBuf::default() {
                        let out_dir = AbsPathBuf::assert(out_dir);
                        res.out_dirs.insert(package_id.clone(), out_dir);
                        res.cfgs.insert(package_id, cfgs);
                    }
                }
                Message::CompilerArtifact(message) => {
                    if message.target.kind.contains(&"proc-macro".to_string()) {
                        let package_id = message.package_id;
                        // Skip rmeta file
                        if let Some(filename) = message.filenames.iter().find(|name| is_dylib(name))
                        {
                            let filename = AbsPathBuf::assert(filename.clone());
                            res.proc_dylib_paths.insert(package_id, filename);
                        }
                    }
                }
                Message::CompilerMessage(_) => (),
                Message::Unknown => (),
                Message::BuildFinished(_) => {}
                Message::TextLine(_) => {}
            }
        }
    }
    Ok(res)
}

// FIXME: File a better way to know if it is a dylib
fn is_dylib(path: &Path) -> bool {
    match path.extension().and_then(OsStr::to_str).map(|it| it.to_string().to_lowercase()) {
        None => false,
        Some(ext) => matches!(ext.as_str(), "dll" | "dylib" | "so"),
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]
use std::io::{self, Cursor};
use std::mem;
use std::path::Path;
use std::pin::Pin;
use std::task::{Context, Poll};

use futures::{Stream, TryStreamExt};
use reqwest::r#async::{Body, Client, Decoder};
use tokio_fs::File;
use tokio::io::AsyncRead;

use failure::Fail;

#[derive(Debug, Fail)]
pub enum Error {
    #[fail(display = "Io Error")]
    Io(#[fail(cause)] std::io::Error),
    #[fail(display = "Reqwest error")]
    Reqwest(#[fail(cause)] reqwest::Error),
}

unsafe impl Send for Error {}
unsafe impl Sync for Error {}

struct AsyncReadWrapper<T> {
    inner: T,
}

impl<T> AsyncReadWrapper<T> {
    fn inner(self: Pin<&mut Self>) -> Pin<&mut T> {
        unsafe {
            Pin::map_unchecked_mut(self, |x| &mut x.inner)
        }
    }
}

impl<T> Stream for AsyncReadWrapper<T>
    where T: AsyncRead
{
    type Item = Result<hyper::Chunk, failure::Compat<Error>>;
    fn poll_next(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Option<Self::Item>> {
        let mut buf = vec![];
        loop {
            let mut read_buf = vec![];
            match self.as_mut().inner().as_mut().poll_read(cx, &mut read_buf) {
                Poll::Pending => {
                    if buf.is_empty() {
                        return Poll::Pending;
                    } else {
                        return Poll::Ready(Some(Ok(buf.into())));
                    }
                }
                Poll::Ready(Err(e)) => {
                    return Poll::Ready(Some(Err(Error::Io(e).compat())))
                },
                Poll::Ready(Ok(n)) => {
                    buf.extend_from_slice(&read_buf[..n]);
                    if buf.is_empty() && n == 0 {
                        return Poll::Ready(None);
                    } else {
                        return Poll::Ready(Some(Ok(buf.into())));
                    }
                }
            }
        }
    }
}

async fn post<P>(path: P) -> Result<(), Error>
where
    P: AsRef<Path> + Send + Unpin + 'static,
{
    let source = File::open(path)
        .await.map_err(Error::Io)?;
    let wrapper = AsyncReadWrapper { inner: source };
    let mut res = Client::new()
        .post("https://httpbin.org/post")
        .body(Body::wrap_stream(wrapper))
        .send()
        .await.map_err(Error::Reqwest)?;

    println!("{}", res.status());

    let body = mem::replace(res.body_mut(), Decoder::empty());
    let body: Result<_, _> = body.try_concat().await;

    let mut body = Cursor::new(body.map_err(Error::Reqwest)?);
    io::copy(&mut body, &mut io::stdout()).map_err(Error::Io)?;

    Ok(())
}

#[tokio::main]
async fn main() -> Result<(), Error> {
    let path = concat!(env!("CARGO_MANIFEST_DIR"), "/LICENSE-APACHE");
    post(path).await
}<commit_msg>Remove disabled examples<commit_after><|endoftext|>


<commit_before>extern crate pkg_config;

use std::process::Command;
use std::fs;
use std::path::Path;
use std::env;
use std::path::PathBuf;

fn main() {
    let wcd = env::current_dir().unwrap();
    let build = PathBuf::from(&wcd.join("ext/libqmlrswrapper/build"));
    let _ = fs::create_dir_all(&build);

    /*
     * Support Qt installed via the Ports system on BSD-like systems.
     *
     * The native libs are in `/usr/local/lib`, which is not linked against by default.
     * This means that either the user or every package has to add this if they want to link
     * against something that is not part of the core distribution in `/usr/lib`.
     *
     * See https://wiki.freebsd.org/WarnerLosh/UsrLocal for the line of reasoning & how this will
     * change in the future.
     */
    if cfg!(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd",
                target_os = "dragonfly", target_os = "bitrig")) {
        println!("cargo:rustc-link-search=native=/usr/local/lib");
    }

    /*
     * Prameters for supporting QT on OS X installed via homebres
     *
     * Because QT5 conflicts with QT4 the homebrew package manager won't link
     * the QT5 package into the default search paths for libraries, to deal
     * with this we need to give pkg-config and cmake a nudge in the right
     * direction.
     */
    if cfg!(target_os = "macos") {
        // Point at homebrew's QT5 install location, this will likely fail if
        // another package manager was used.
        let qt5_lib_path = Path::new("/usr/local/opt/qt5/lib");

        if Path::exists(qt5_lib_path) {
            // First nudge cmake in the direction of the .cmake files added by
            // homebrew. This clobbers the existing value if present, it's
            // unlikely to be present though.
            env::set_var("CMAKE_PREFIX_PATH", qt5_lib_path.join("cmake"));

            // Nudge pkg-config in the direction of the brewed QT to ensure the
            // correct compiler flags get found for the project.
            env::set_var("PKG_CONFIG_PATH", qt5_lib_path.join("pkgconfig"));
        } else {
            panic!("The QT5 was not found at the expected location ({}) please install it via homebrew.", qt5_lib_path.display());
        }
    }

    let mut myargs = vec![];
    if cfg!(windows) {
        let is_msys = env::var("MSYSTEM").is_ok();

        if is_msys {
            myargs.push("-GMSYS Makefiles");
        } else {
            myargs.push("-GVisual Studio 12 2013 Win64");
        }

        myargs.push("..");
    } else {
        myargs.push("..");
    }

    let cmake_output = Command::new("cmake").args(&myargs).current_dir(&build).output().unwrap_or_else(|e| {
        panic!("Failed to run cmake: {}", e);
    });
    let cmake_stderr = String::from_utf8(cmake_output.stderr).unwrap();
    if !cmake_stderr.is_empty() {
        panic!("cmake produced stderr: {}", cmake_stderr);
    }

    Command::new("cmake")
        .args(&vec!["--build","."])
        .current_dir(&build)
        .status().and_then(|x| Ok(x.success()) ).unwrap_or_else(|e| {
            panic!("Failed to run build: {}", e);
        });

    println!("cargo:rustc-link-lib=static=qmlrswrapper");

    if cfg!(windows) {
        println!("cargo:rustc-link-search=native={}\\system32",env::var("WINDIR").unwrap());
        println!("cargo:rustc-link-search=native={}\\Debug",build.display());
        println!("cargo:rustc-link-search=native={}\\lib",env::var("QTDIR").unwrap());

        println!("cargo:rustc-link-lib=dylib=Qt5Core");
        println!("cargo:rustc-link-lib=dylib=Qt5Gui");
        println!("cargo:rustc-link-lib=dylib=Qt5Qml");
        println!("cargo:rustc-link-lib=dylib=Qt5Quick");
    } else {
        println!("cargo:rustc-link-search=native={}{}",build.display(),if cfg!(windows) { "\\Debug" } else { "" });
        println!("cargo:rustc-link-lib=dylib=stdc++");
        pkg_config::find_library("Qt5Core Qt5Gui Qt5Qml Qt5Quick").unwrap();
    }
}
<commit_msg>Determine Qt5 path from QTDIR env vars, if set, on OS X<commit_after>extern crate pkg_config;

use std::process::Command;
use std::fs;
use std::path::Path;
use std::env;
use std::env::consts;
use std::path::PathBuf;

fn main() {
    let wcd = env::current_dir().unwrap();
    let build = PathBuf::from(&wcd.join("ext/libqmlrswrapper/build"));
    let _ = fs::create_dir_all(&build);

    /*
     * Support Qt installed via the Ports system on BSD-like systems.
     *
     * The native libs are in `/usr/local/lib`, which is not linked against by default.
     * This means that either the user or every package has to add this if they want to link
     * against something that is not part of the core distribution in `/usr/lib`.
     *
     * See https://wiki.freebsd.org/WarnerLosh/UsrLocal for the line of reasoning & how this will
     * change in the future.
     */
    if cfg!(any(target_os = "freebsd", target_os = "openbsd", target_os = "netbsd",
                target_os = "dragonfly", target_os = "bitrig")) {
        println!("cargo:rustc-link-search=native=/usr/local/lib");
    }

    /*
     * Parameters for supporting QT on OS X
     *
     * Because QT5 conflicts with QT4 the homebrew package manager won't link
     * the QT5 package into the default search paths for libraries, to deal
     * with this we need to give pkg-config and cmake a nudge in the right
     * direction.
     */
    if cfg!(target_os = "macos") {
        // We use the QTDIR or QTDIR64 env variables to find the location of
        // Qt5. If these are not set, we use the default homebrew install
        // location.
        let qtdir_variable = match consts::ARCH {
            "x86_64" => "QTDIR64",
            _ => "QTDIR",
        };
        let mut qt5_lib_path = PathBuf::new();
        qt5_lib_path.push(env::var(qtdir_variable).unwrap_or(String::from("/usr/local/opt/qt5")));
        qt5_lib_path.push(Path::new("lib"));

        if qt5_lib_path.exists() {
            // First nudge cmake in the direction of the .cmake files added by
            // homebrew. This clobbers the existing value if present, it's
            // unlikely to be present though.
            env::set_var("CMAKE_PREFIX_PATH", qt5_lib_path.join("cmake"));

            // Nudge pkg-config in the direction of the brewed QT to ensure the
            // correct compiler flags get found for the project.
            env::set_var("PKG_CONFIG_PATH", qt5_lib_path.join("pkgconfig"));
        } else {
            panic!("QT5 was not found at the expected location ({}) please install it via homebrew, or set the {} env variable.",
                qt5_lib_path.display(), qtdir_variable);
        }
    }

    let mut myargs = vec![];
    if cfg!(windows) {
        let is_msys = env::var("MSYSTEM").is_ok();

        if is_msys {
            myargs.push("-GMSYS Makefiles");
        } else {
            myargs.push("-GVisual Studio 12 2013 Win64");
        }

        myargs.push("..");
    } else {
        myargs.push("..");
    }

    let cmake_output = Command::new("cmake").args(&myargs).current_dir(&build).output().unwrap_or_else(|e| {
        panic!("Failed to run cmake: {}", e);
    });
    let cmake_stderr = String::from_utf8(cmake_output.stderr).unwrap();
    if !cmake_stderr.is_empty() {
        panic!("cmake produced stderr: {}", cmake_stderr);
    }

    Command::new("cmake")
        .args(&vec!["--build","."])
        .current_dir(&build)
        .status().and_then(|x| Ok(x.success()) ).unwrap_or_else(|e| {
            panic!("Failed to run build: {}", e);
        });

    println!("cargo:rustc-link-lib=static=qmlrswrapper");

    if cfg!(windows) {
        println!("cargo:rustc-link-search=native={}\\system32",env::var("WINDIR").unwrap());
        println!("cargo:rustc-link-search=native={}\\Debug",build.display());
        println!("cargo:rustc-link-search=native={}\\lib",env::var("QTDIR").unwrap());

        println!("cargo:rustc-link-lib=dylib=Qt5Core");
        println!("cargo:rustc-link-lib=dylib=Qt5Gui");
        println!("cargo:rustc-link-lib=dylib=Qt5Qml");
        println!("cargo:rustc-link-lib=dylib=Qt5Quick");
    } else {
        println!("cargo:rustc-link-search=native={}{}",build.display(),if cfg!(windows) { "\\Debug" } else { "" });
        println!("cargo:rustc-link-lib=dylib=stdc++");
        pkg_config::find_library("Qt5Core Qt5Gui Qt5Qml Qt5Quick").unwrap();
    }
}
<|endoftext|>


<commit_before>extern crate amq_protocol_codegen;
extern crate amq_protocol_types;
extern crate handlebars;
extern crate serde_json;

use amq_protocol_codegen::*;
use amq_protocol_types::*;
use handlebars::{Handlebars,Helper,HelperDef,RenderContext,RenderError};

use std::collections::BTreeMap;
use std::env;
use std::fs::File;
use std::io::{Read, Write};
use std::path::Path;
use std::ascii::AsciiExt;

fn main() {
    let out_dir      = env::var("OUT_DIR").expect("OUT_DIR is not defined");
    let dest_path    = Path::new(&out_dir).join("generated.rs");
    let dest_path2   = Path::new(&out_dir).join("api.rs");
    let mut f        = File::create(&dest_path).expect("Failed to create generated.rs");
    let mut f2       = File::create(&dest_path2).expect("Failed to create api.rs");
    let mut full_tpl = String::new();
    let mut api_tpl = String::new();
    std::fs::File::open("templates/main.rs").expect("Failed to open main template").read_to_string(&mut full_tpl).expect("Failed to read main template");
    std::fs::File::open("templates/api.rs").expect("Failed to open main template").read_to_string(&mut api_tpl).expect("Failed to read main template");

    let mut handlebars = Handlebars::new();
    let mut data = BTreeMap::new();

    handlebars.register_escape_fn(handlebars::no_escape);
    handlebars.register_helper("snake", Box::new(snake_helper));
    handlebars.register_helper("camel", Box::new(camel_helper));
    handlebars.register_helper("map_type", Box::new(map_type_helper));
    handlebars.register_helper("map_parser", Box::new(map_parser_helper));
    handlebars.register_helper("map_generator", Box::new(map_generator_helper));

    handlebars.register_template_string("full", full_tpl).expect("Failed to register full template");
    handlebars.register_template_string("api", api_tpl).expect("Failed to register api template");

    let specs     = AMQProtocolDefinition::load();
    data.insert("specs".to_string(), specs);
    writeln!(f, "{}", handlebars.render("full", &data).expect("Failed to render full template"));
    writeln!(f2, "{}", handlebars.render("api", &data).expect("Failed to render full template"));

    //writeln!(f, "{}", specs.codegen_full(&full_tpl)).expect("Failed to generate generated.rs");
}

fn camel_name(name: &str) -> String {
    let mut new_word: bool = true;
    name.chars().fold("".to_string(), |mut result, ch| {
        if ch == '-' || ch == '_' || ch == ' ' {
            new_word = true;
            result
        } else {
            result.push(if new_word { ch.to_ascii_uppercase() } else { ch.to_ascii_lowercase() });
            new_word = false;
            result
        }
    })
}

fn snake_name(name: &str) -> String {
    match name {
        "type"   => "amqp_type".to_string(),
        "return" => "amqp_return".to_string(),
        name     => name.replace("-", "_"),
    }
}

fn camel_helper (h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
    // just for example, add error check for unwrap
    let param = h.param(0).unwrap().value().as_str().unwrap();
    let rendered = camel_name(param);
    try!(rc.writer.write(rendered.into_bytes().as_ref()));
    Ok(())
}

fn snake_helper (h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
    // just for example, add error check for unwrap
    let param = h.param(0).unwrap().value().as_str().unwrap();
    let rendered = snake_name(param);
    try!(rc.writer.write(rendered.into_bytes().as_ref()));
    Ok(())
}

fn map_type_helper(h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
  println!("val1: {:?}", h.param(0));
  let val = h.param(0).unwrap().value().clone();
  let arg:AMQPArgument = serde_json::from_value(val.clone()).unwrap();

  let rendered = match arg.amqp_type {
    Some(ty) => ty.to_string(),
    None     => {
      let data:  serde_json::Map<String,  serde_json::Value> = serde_json::from_value(rc.context().data().clone()).unwrap();
      let specs: serde_json::Map<String, serde_json::Value> =  serde_json::from_value(data.get("specs").unwrap().clone()).unwrap();
      let domains: Vec<AMQPDomain> =  serde_json::from_value(specs.get("domains").unwrap().clone()).unwrap();

      let lookup_domain = arg.domain.clone().unwrap();
      let res = domains.iter().find(|d| d.name == lookup_domain).map(|d| d.amqp_type.to_string()).unwrap();
      println!("key {} => domain gave type: {}", arg.name, res);
      res
    },
  };
  try!(rc.writer.write(rendered.as_bytes()));

  Ok(())
}

fn map_parser_helper(h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
  println!("val1: {:?}", h.param(0));
  let val = h.param(0).unwrap().value().clone();
  let arg:AMQPArgument = serde_json::from_value(val).unwrap();

  let rendered = match arg.amqp_type {
    Some(AMQPType::Boolean)        => "map!(be_u8, |u| u != 0)",
    Some(AMQPType::ShortShortInt)  => "be_i8",
    Some(AMQPType::ShortShortUInt) => "be_u8",
    Some(AMQPType::ShortInt)       => "be_i16",
    Some(AMQPType::ShortUInt)      => "be_u16",
    Some(AMQPType::LongInt)        => "be_i32",
    Some(AMQPType::LongUInt)       => "be_u32",
    Some(AMQPType::LongLongInt)    => "be_i64",
    Some(AMQPType::LongLongUInt)   => "be_u64",
    Some(AMQPType::ShortString)    => "map!(short_string, |s:&str| s.to_string())",
    Some(AMQPType::LongString)     => "map!(long_string,  |s:&str| s.to_string())",
    Some(AMQPType::FieldTable)     => "field_table",
    Some(AMQPType::Timestamp)      => "be_u64",
    Some(_)                        => unimplemented!(),
    None                           => {
      let data:  serde_json::Map<String, serde_json::Value> = serde_json::from_value(rc.context().data().clone()).unwrap();
      let specs: serde_json::Map<String, serde_json::Value> =  serde_json::from_value(data.get("specs").unwrap().clone()).unwrap();
      let domains: Vec<AMQPDomain> =  serde_json::from_value(specs.get("domains").unwrap().clone()).unwrap();

      let lookup_domain = arg.domain.clone().unwrap();
      domains.iter().find(|d| d.name == lookup_domain).map(|d| match d.amqp_type {
        AMQPType::Boolean        => "map!(be_u8, |u| u != 0)",
        AMQPType::ShortShortInt  => "be_i8",
        AMQPType::ShortShortUInt => "be_u8",
        AMQPType::ShortInt       => "be_i16",
        AMQPType::ShortUInt      => "be_u16",
        AMQPType::LongInt        => "be_i32",
        AMQPType::LongUInt       => "be_u32",
        AMQPType::LongLongInt    => "be_i64",
        AMQPType::LongLongUInt   => "be_u64",
        AMQPType::ShortString    => "map!(short_string, |s:&str| s.to_string())",
        AMQPType::LongString     => "map!(long_string,  |s:&str| s.to_string())",
        AMQPType::FieldTable     => "field_table",
        AMQPType::Timestamp      => "be_u64",
        _                        => unimplemented!(),
      }).unwrap()
    }
  };
  try!(rc.writer.write(rendered.as_bytes()));

  Ok(())
}

fn map_generator_helper(h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
  println!("val1: {:?}", h.param(0));
  let val = h.param(0).unwrap().value().clone();
  let arg:AMQPArgument = serde_json::from_value(val).unwrap();

  let rendered = match arg.amqp_type {
    Some(AMQPType::Boolean)        => "gen_bool",
    Some(AMQPType::ShortShortInt)  => "gen_be_i8",
    Some(AMQPType::ShortShortUInt) => "gen_be_u8",
    Some(AMQPType::ShortInt)       => "gen_be_i16",
    Some(AMQPType::ShortUInt)      => "gen_be_u16",
    Some(AMQPType::LongInt)        => "gen_be_i32",
    Some(AMQPType::LongUInt)       => "gen_be_u32",
    Some(AMQPType::LongLongInt)    => "gen_be_i64",
    Some(AMQPType::LongLongUInt)   => "gen_be_u64",
    Some(AMQPType::ShortString)    => "gen_short_string",
    Some(AMQPType::LongString)     => "gen_long_string",
    Some(AMQPType::FieldTable)     => "gen_field_table",
    Some(AMQPType::Timestamp)      => "gen_be_u64",
    Some(_)                        => unimplemented!(),
    None                           => {
      let data:  serde_json::Map<String,  serde_json::Value> = serde_json::from_value(rc.context().data().clone()).unwrap();
      let specs: serde_json::Map<String, serde_json::Value> =  serde_json::from_value(data.get("specs").unwrap().clone()).unwrap();
      let domains: Vec<AMQPDomain> =  serde_json::from_value(specs.get("domains").unwrap().clone()).unwrap();

      let lookup_domain = arg.domain.clone().unwrap();
      domains.iter().find(|d| d.name == lookup_domain).map(|d| match d.amqp_type {
        AMQPType::Boolean        => "gen_bool",
        AMQPType::ShortShortInt  => "gen_be_u8",
        AMQPType::ShortShortUInt => "gen_be_u8",
        AMQPType::ShortInt       => "gen_be_u16",
        AMQPType::ShortUInt      => "gen_be_u16",
        AMQPType::LongInt        => "gen_be_u32",
        AMQPType::LongUInt       => "gen_be_u32",
        AMQPType::LongLongInt    => "gen_be_u64",
        AMQPType::LongLongUInt   => "gen_be_u64",
        AMQPType::ShortString    => "gen_short_string",
        AMQPType::LongString     => "gen_long_string",
        AMQPType::FieldTable     => "gen_field_table",
        AMQPType::Timestamp      => "gen_be_u64",
        _                        => unimplemented!(),
      }).unwrap()
    }
  };
  try!(rc.writer.write(rendered.as_bytes()));

  Ok(())
}
<commit_msg>build: use snake_helper and camel_helper from amq_protocol_codegen<commit_after>extern crate amq_protocol_codegen;
extern crate amq_protocol_types;
extern crate handlebars;
extern crate serde_json;

use amq_protocol_codegen::*;
use amq_protocol_types::*;
use handlebars::{Handlebars,Helper,HelperDef,RenderContext,RenderError};

use std::collections::BTreeMap;
use std::env;
use std::fs::File;
use std::io::{Read, Write};
use std::path::Path;
use std::ascii::AsciiExt;

fn main() {
    let out_dir      = env::var("OUT_DIR").expect("OUT_DIR is not defined");
    let dest_path    = Path::new(&out_dir).join("generated.rs");
    let dest_path2   = Path::new(&out_dir).join("api.rs");
    let mut f        = File::create(&dest_path).expect("Failed to create generated.rs");
    let mut f2       = File::create(&dest_path2).expect("Failed to create api.rs");
    let mut full_tpl = String::new();
    let mut api_tpl = String::new();
    std::fs::File::open("templates/main.rs").expect("Failed to open main template").read_to_string(&mut full_tpl).expect("Failed to read main template");
    std::fs::File::open("templates/api.rs").expect("Failed to open main template").read_to_string(&mut api_tpl).expect("Failed to read main template");

    let mut handlebars = Handlebars::new();
    let mut data = BTreeMap::new();

    handlebars.register_escape_fn(handlebars::no_escape);
    handlebars.register_helper("snake", Box::new(snake_helper));
    handlebars.register_helper("camel", Box::new(camel_helper));
    handlebars.register_helper("map_type", Box::new(map_type_helper));
    handlebars.register_helper("map_parser", Box::new(map_parser_helper));
    handlebars.register_helper("map_generator", Box::new(map_generator_helper));

    handlebars.register_template_string("full", full_tpl).expect("Failed to register full template");
    handlebars.register_template_string("api", api_tpl).expect("Failed to register api template");

    let specs     = AMQProtocolDefinition::load();
    data.insert("specs".to_string(), specs);
    writeln!(f, "{}", handlebars.render("full", &data).expect("Failed to render full template"));
    writeln!(f2, "{}", handlebars.render("api", &data).expect("Failed to render full template"));

    //writeln!(f, "{}", specs.codegen_full(&full_tpl)).expect("Failed to generate generated.rs");
}

fn map_type_helper(h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
  println!("val1: {:?}", h.param(0));
  let val = h.param(0).unwrap().value().clone();
  let arg:AMQPArgument = serde_json::from_value(val.clone()).unwrap();

  let rendered = match arg.amqp_type {
    Some(ty) => ty.to_string(),
    None     => {
      let data:  serde_json::Map<String,  serde_json::Value> = serde_json::from_value(rc.context().data().clone()).unwrap();
      let specs: serde_json::Map<String, serde_json::Value> =  serde_json::from_value(data.get("specs").unwrap().clone()).unwrap();
      let domains: Vec<AMQPDomain> =  serde_json::from_value(specs.get("domains").unwrap().clone()).unwrap();

      let lookup_domain = arg.domain.clone().unwrap();
      let res = domains.iter().find(|d| d.name == lookup_domain).map(|d| d.amqp_type.to_string()).unwrap();
      println!("key {} => domain gave type: {}", arg.name, res);
      res
    },
  };
  try!(rc.writer.write(rendered.as_bytes()));

  Ok(())
}

fn map_parser_helper(h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
  println!("val1: {:?}", h.param(0));
  let val = h.param(0).unwrap().value().clone();
  let arg:AMQPArgument = serde_json::from_value(val).unwrap();

  let rendered = match arg.amqp_type {
    Some(AMQPType::Boolean)        => "map!(be_u8, |u| u != 0)",
    Some(AMQPType::ShortShortInt)  => "be_i8",
    Some(AMQPType::ShortShortUInt) => "be_u8",
    Some(AMQPType::ShortInt)       => "be_i16",
    Some(AMQPType::ShortUInt)      => "be_u16",
    Some(AMQPType::LongInt)        => "be_i32",
    Some(AMQPType::LongUInt)       => "be_u32",
    Some(AMQPType::LongLongInt)    => "be_i64",
    Some(AMQPType::LongLongUInt)   => "be_u64",
    Some(AMQPType::ShortString)    => "map!(short_string, |s:&str| s.to_string())",
    Some(AMQPType::LongString)     => "map!(long_string,  |s:&str| s.to_string())",
    Some(AMQPType::FieldTable)     => "field_table",
    Some(AMQPType::Timestamp)      => "be_u64",
    Some(_)                        => unimplemented!(),
    None                           => {
      let data:  serde_json::Map<String, serde_json::Value> = serde_json::from_value(rc.context().data().clone()).unwrap();
      let specs: serde_json::Map<String, serde_json::Value> =  serde_json::from_value(data.get("specs").unwrap().clone()).unwrap();
      let domains: Vec<AMQPDomain> =  serde_json::from_value(specs.get("domains").unwrap().clone()).unwrap();

      let lookup_domain = arg.domain.clone().unwrap();
      domains.iter().find(|d| d.name == lookup_domain).map(|d| match d.amqp_type {
        AMQPType::Boolean        => "map!(be_u8, |u| u != 0)",
        AMQPType::ShortShortInt  => "be_i8",
        AMQPType::ShortShortUInt => "be_u8",
        AMQPType::ShortInt       => "be_i16",
        AMQPType::ShortUInt      => "be_u16",
        AMQPType::LongInt        => "be_i32",
        AMQPType::LongUInt       => "be_u32",
        AMQPType::LongLongInt    => "be_i64",
        AMQPType::LongLongUInt   => "be_u64",
        AMQPType::ShortString    => "map!(short_string, |s:&str| s.to_string())",
        AMQPType::LongString     => "map!(long_string,  |s:&str| s.to_string())",
        AMQPType::FieldTable     => "field_table",
        AMQPType::Timestamp      => "be_u64",
        _                        => unimplemented!(),
      }).unwrap()
    }
  };
  try!(rc.writer.write(rendered.as_bytes()));

  Ok(())
}

fn map_generator_helper(h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
  println!("val1: {:?}", h.param(0));
  let val = h.param(0).unwrap().value().clone();
  let arg:AMQPArgument = serde_json::from_value(val).unwrap();

  let rendered = match arg.amqp_type {
    Some(AMQPType::Boolean)        => "gen_bool",
    Some(AMQPType::ShortShortInt)  => "gen_be_i8",
    Some(AMQPType::ShortShortUInt) => "gen_be_u8",
    Some(AMQPType::ShortInt)       => "gen_be_i16",
    Some(AMQPType::ShortUInt)      => "gen_be_u16",
    Some(AMQPType::LongInt)        => "gen_be_i32",
    Some(AMQPType::LongUInt)       => "gen_be_u32",
    Some(AMQPType::LongLongInt)    => "gen_be_i64",
    Some(AMQPType::LongLongUInt)   => "gen_be_u64",
    Some(AMQPType::ShortString)    => "gen_short_string",
    Some(AMQPType::LongString)     => "gen_long_string",
    Some(AMQPType::FieldTable)     => "gen_field_table",
    Some(AMQPType::Timestamp)      => "gen_be_u64",
    Some(_)                        => unimplemented!(),
    None                           => {
      let data:  serde_json::Map<String,  serde_json::Value> = serde_json::from_value(rc.context().data().clone()).unwrap();
      let specs: serde_json::Map<String, serde_json::Value> =  serde_json::from_value(data.get("specs").unwrap().clone()).unwrap();
      let domains: Vec<AMQPDomain> =  serde_json::from_value(specs.get("domains").unwrap().clone()).unwrap();

      let lookup_domain = arg.domain.clone().unwrap();
      domains.iter().find(|d| d.name == lookup_domain).map(|d| match d.amqp_type {
        AMQPType::Boolean        => "gen_bool",
        AMQPType::ShortShortInt  => "gen_be_u8",
        AMQPType::ShortShortUInt => "gen_be_u8",
        AMQPType::ShortInt       => "gen_be_u16",
        AMQPType::ShortUInt      => "gen_be_u16",
        AMQPType::LongInt        => "gen_be_u32",
        AMQPType::LongUInt       => "gen_be_u32",
        AMQPType::LongLongInt    => "gen_be_u64",
        AMQPType::LongLongUInt   => "gen_be_u64",
        AMQPType::ShortString    => "gen_short_string",
        AMQPType::LongString     => "gen_long_string",
        AMQPType::FieldTable     => "gen_field_table",
        AMQPType::Timestamp      => "gen_be_u64",
        _                        => unimplemented!(),
      }).unwrap()
    }
  };
  try!(rc.writer.write(rendered.as_bytes()));

  Ok(())
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2020, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

#![allow(clippy::print_literal)]
#![allow(clippy::unused_io_amount)]

use rustc_version::{version, Version};
#[allow(unused_imports)]
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::exit;

#[allow(dead_code)]
fn rerun_dir<P: AsRef<Path>>(dir: P) {
  for entry in fs::read_dir(dir).unwrap() {
    let entry = entry.unwrap();
    let path = entry.path();
    println!("cargo:rerun-if-changed={}", path.to_string_lossy());

    if path.is_dir() {
      rerun_dir(path);
    }
  }
}

#[allow(dead_code)]
fn hash_changed(
  files: &[&str], out_dir: &str, config: &Path,
) -> Option<([u8; 8], PathBuf)> {
  use std::collections::hash_map::DefaultHasher;
  use std::hash::Hasher;
  use std::io::Read;

  let mut hasher = DefaultHasher::new();

  let paths = files.iter().map(Path::new).chain(std::iter::once(config));

  for path in paths {
    if let Ok(mut f) = std::fs::File::open(path) {
      let mut buf = Vec::new();
      f.read_to_end(&mut buf).unwrap();

      hasher.write(&buf);
    } else {
      panic!("Cannot open {}", path.display());
    }
  }

  let hash = hasher.finish().to_be_bytes();

  let hash_path = Path::new(&out_dir).join("asm.hash");

  if let Ok(old_hash) = std::fs::read(&hash_path) {
    if old_hash == hash {
      return None;
    }
  }

  Some((hash, hash_path))
}

#[cfg(feature = "asm")]
fn build_nasm_files() {
  use std::fs::File;
  use std::io::Write;
  let out_dir = env::var("OUT_DIR").unwrap();

  let dest_path = Path::new(&out_dir).join("config.asm");
  let mut config_file = File::create(&dest_path).unwrap();
  config_file.write(b"	%define private_prefix rav1e\n").unwrap();
  config_file.write(b"	%define ARCH_X86_32 0\n").unwrap();
  config_file.write(b" %define ARCH_X86_64 1\n").unwrap();
  config_file.write(b"	%define PIC 1\n").unwrap();
  config_file.write(b" %define STACK_ALIGNMENT 16\n").unwrap();
  config_file.write(b" %define HAVE_AVX512ICL 1\n").unwrap();
  if env::var("CARGO_CFG_TARGET_VENDOR").unwrap() == "apple" {
    config_file.write(b" %define PREFIX 1\n").unwrap();
  }

  let asm_files = &[
    "src/x86/ipred_avx2.asm",
    "src/x86/ipred_sse.asm",
    "src/x86/ipred16_avx2.asm",
    "src/x86/itx_avx2.asm",
    "src/x86/itx_sse.asm",
    "src/x86/itx16_avx2.asm",
    "src/x86/looprestoration_avx2.asm",
    "src/x86/looprestoration16_avx2.asm",
    "src/x86/mc_avx2.asm",
    "src/x86/mc16_avx2.asm",
    "src/x86/mc_avx512.asm",
    "src/x86/mc_sse.asm",
    "src/x86/me.asm",
    "src/x86/sad_sse2.asm",
    "src/x86/sad_avx.asm",
    "src/x86/satd.asm",
    "src/x86/sse.asm",
    "src/x86/cdef_rav1e.asm",
    "src/x86/cdef_sse.asm",
    "src/x86/cdef16_avx2.asm",
    "src/x86/cdef16_sse.asm",
    "src/x86/tables.asm",
  ];

  if let Some((hash, hash_path)) =
    hash_changed(asm_files, &out_dir, &dest_path)
  {
    let mut config_include_arg = String::from("-I");
    config_include_arg.push_str(&out_dir);
    config_include_arg.push('/');
    let mut nasm = nasm_rs::Build::new();
    for file in asm_files {
      nasm.file(file);
    }
    nasm.flag(&config_include_arg);
    nasm.flag("-Isrc/");
    let obj = nasm.compile_objects().expect(
      "NASM build failed. Make sure you have nasm installed. https://nasm.us",
    );
    // cc is better at finding the correct archiver
    let mut cc = cc::Build::new();
    for o in obj {
      cc.object(o);
    }
    cc.compile("rav1easm");

    std::fs::write(hash_path, &hash[..]).unwrap();
  } else {
    println!("cargo:rustc-link-search={}", out_dir);
  }
  println!("cargo:rustc-link-lib=static=rav1easm");
  rerun_dir("src/x86");
  rerun_dir("src/ext/x86");
}

#[cfg(feature = "asm")]
fn build_asm_files() {
  use std::fs::File;
  use std::io::Write;
  let out_dir = env::var("OUT_DIR").unwrap();

  let dest_path = Path::new(&out_dir).join("config.h");
  let mut config_file = File::create(&dest_path).unwrap();
  if env::var("CARGO_CFG_TARGET_VENDOR").unwrap() == "apple" {
    config_file.write(b" #define PREFIX 1\n").unwrap();
  }
  config_file.write(b" #define PRIVATE_PREFIX rav1e_\n").unwrap();
  config_file.write(b" #define ARCH_AARCH64 1\n").unwrap();
  config_file.write(b" #define ARCH_ARM 0\n").unwrap();
  config_file.write(b" #define CONFIG_LOG 1 \n").unwrap();
  config_file.write(b" #define HAVE_ASM 1\n").unwrap();
  config_file.sync_all().unwrap();

  let asm_files = &[
    "src/arm/64/cdef.S",
    "src/arm/64/cdef16.S",
    "src/arm/64/mc.S",
    "src/arm/64/mc16.S",
    "src/arm/64/itx.S",
    "src/arm/64/itx16.S",
    "src/arm/64/ipred.S",
    "src/arm/64/ipred16.S",
    "src/arm/64/sad.S",
    "src/arm/tables.S",
  ];

  if let Some((hash, hash_path)) =
    hash_changed(asm_files, &out_dir, &dest_path)
  {
    cc::Build::new()
      .files(asm_files)
      .include(".")
      .include(&out_dir)
      .compile("rav1e-aarch64");

    std::fs::write(hash_path, &hash[..]).unwrap();
  } else {
    println!("cargo:rustc-link-search={}", out_dir);
    println!("cargo:rustc-link-lib=static=rav1e-aarch64");
  }
  rerun_dir("src/arm");
}

fn rustc_version_check() {
  // This should match the version in the CI
  // Make sure to updated README.md when this changes.
  const REQUIRED_VERSION: &str = "1.51.0";
  if version().unwrap() < Version::parse(REQUIRED_VERSION).unwrap() {
    eprintln!("rav1e requires rustc >= {}.", REQUIRED_VERSION);
    exit(1);
  }
}

#[cfg(feature = "asm")]
fn is_nasm_new_enough(
  min_version: Option<(u8, u8, u8)>, nasm_path: &Path,
) -> Result<(), String> {
  match get_output(std::process::Command::new(nasm_path).arg("-v")) {
    Ok(version) => {
      if version.contains("NASM version 0.") {
        Err(version)
      } else if let Some((major, minor, micro)) = min_version {
        let ver = parse_nasm_version(&version)?;
        eprintln!("{:?} {:?} {:?}", min_version, version, ver);
        if major > ver.0
          || (major == ver.0 && minor > ver.1)
          || (major == ver.0 && minor == ver.1 && micro > ver.2)
        {
          Err(version)
        } else {
          Ok(())
        }
      } else {
        Ok(())
      }
    }
    Err(err) => Err(err),
  }
}

#[cfg(feature = "asm")]
fn parse_nasm_version(version_string: &str) -> Result<(u8, u8, u8), String> {
  // Rust regex lib doesn't support empty expressions in alterations,
  // so workaround the other way
  let regex1 =
    regex::Regex::new(r"(?:NASM version )?(\d+)\.(\d+)\.(\d+)").unwrap();
  if let Some(captures) = regex1.captures(version_string) {
    Ok((
      captures[1].parse().expect("Invalid version component"),
      captures[2].parse().expect("Invalid version component"),
      captures[3].parse().expect("Invalid version component"),
    ))
  } else {
    let regex2 = regex::Regex::new(r"(?:NASM version )?(\d+)\.(\d+)").unwrap();
    let captures = regex2
      .captures(version_string)
      .ok_or_else(|| "Unable to parse NASM version string".to_string())?;
    Ok((
      captures[1].parse().expect("Invalid version component"),
      captures[2].parse().expect("Invalid version component"),
      0,
    ))
  }
}

#[test]
fn test_parse_nasm_version() {
  let ver_str = "NASM version 2.14.02 compiled on Jan 22 2019";
  assert_eq!((2, 14, 2), parse_nasm_version(ver_str));
  let ver_str = "NASM version 2.14 compiled on Jan 22 2019";
  assert_eq!((2, 14, 0), parse_nasm_version(ver_str));
}

#[cfg(feature = "asm")]
fn nasm_version_check() -> std::path::PathBuf {
  let nasm_path = std::path::PathBuf::from("nasm");
  match is_nasm_new_enough(Some((2, 14, 0)), &nasm_path) {
    Ok(_) => nasm_path,
    Err(version) => {
      panic!("This version of NASM is too old: {}", version);
    }
  }
}

#[cfg(feature = "asm")]
fn get_output(cmd: &mut std::process::Command) -> Result<String, String> {
  let out = cmd.output().map_err(|e| e.to_string())?;
  if out.status.success() {
    Ok(String::from_utf8_lossy(&out.stdout).to_string())
  } else {
    Err(String::from_utf8_lossy(&out.stderr).to_string())
  }
}

#[allow(unused_variables)]
fn main() {
  rustc_version_check();

  let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
  let os = env::var("CARGO_CFG_TARGET_OS").unwrap();
  // let env = env::var("CARGO_CFG_TARGET_ENV").unwrap();

  #[cfg(feature = "asm")]
  {
    if arch == "x86_64" {
      println!("cargo:rustc-cfg={}", "nasm_x86_64");
      nasm_version_check();
      build_nasm_files()
    }
    if arch == "aarch64" {
      println!("cargo:rustc-cfg={}", "asm_neon");
      build_asm_files()
    }
  }

  if os == "windows" && cfg!(feature = "decode_test") {
    panic!("Unsupported feature on this platform!");
  }

  vergen::generate_cargo_keys(vergen::ConstantsFlags::all())
    .expect("Unable to generate the cargo keys!");

  println!("cargo:rustc-env=PROFILE={}", env::var("PROFILE").unwrap());
}
<commit_msg>Add build.rs to the asm freshness hash<commit_after>// Copyright (c) 2017-2020, The rav1e contributors. All rights reserved
//
// This source code is subject to the terms of the BSD 2 Clause License and
// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
// was not distributed with this source code in the LICENSE file, you can
// obtain it at www.aomedia.org/license/software. If the Alliance for Open
// Media Patent License 1.0 was not distributed with this source code in the
// PATENTS file, you can obtain it at www.aomedia.org/license/patent.

#![allow(clippy::print_literal)]
#![allow(clippy::unused_io_amount)]

use rustc_version::{version, Version};
#[allow(unused_imports)]
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::exit;

#[allow(dead_code)]
fn rerun_dir<P: AsRef<Path>>(dir: P) {
  for entry in fs::read_dir(dir).unwrap() {
    let entry = entry.unwrap();
    let path = entry.path();
    println!("cargo:rerun-if-changed={}", path.to_string_lossy());

    if path.is_dir() {
      rerun_dir(path);
    }
  }
}

#[allow(dead_code)]
fn hash_changed(
  files: &[&str], out_dir: &str, config: &Path,
) -> Option<([u8; 8], PathBuf)> {
  use std::collections::hash_map::DefaultHasher;
  use std::hash::Hasher;
  use std::io::Read;

  let mut hasher = DefaultHasher::new();

  let paths = files
    .iter()
    .map(Path::new)
    .chain(std::iter::once(config))
    .chain(std::iter::once(Path::new("build.rs")));

  for path in paths {
    if let Ok(mut f) = std::fs::File::open(path) {
      let mut buf = Vec::new();
      f.read_to_end(&mut buf).unwrap();

      hasher.write(&buf);
    } else {
      panic!("Cannot open {}", path.display());
    }
  }

  let hash = hasher.finish().to_be_bytes();

  let hash_path = Path::new(&out_dir).join("asm.hash");

  if let Ok(old_hash) = std::fs::read(&hash_path) {
    if old_hash == hash {
      return None;
    }
  }

  Some((hash, hash_path))
}

#[cfg(feature = "asm")]
fn build_nasm_files() {
  use std::fs::File;
  use std::io::Write;
  let out_dir = env::var("OUT_DIR").unwrap();

  let dest_path = Path::new(&out_dir).join("config.asm");
  let mut config_file = File::create(&dest_path).unwrap();
  config_file.write(b"	%define private_prefix rav1e\n").unwrap();
  config_file.write(b"	%define ARCH_X86_32 0\n").unwrap();
  config_file.write(b" %define ARCH_X86_64 1\n").unwrap();
  config_file.write(b"	%define PIC 1\n").unwrap();
  config_file.write(b" %define STACK_ALIGNMENT 16\n").unwrap();
  config_file.write(b" %define HAVE_AVX512ICL 1\n").unwrap();
  if env::var("CARGO_CFG_TARGET_VENDOR").unwrap() == "apple" {
    config_file.write(b" %define PREFIX 1\n").unwrap();
  }

  let asm_files = &[
    "src/x86/ipred_avx2.asm",
    "src/x86/ipred_sse.asm",
    "src/x86/ipred16_avx2.asm",
    "src/x86/itx_avx2.asm",
    "src/x86/itx_sse.asm",
    "src/x86/itx16_avx2.asm",
    "src/x86/looprestoration_avx2.asm",
    "src/x86/looprestoration16_avx2.asm",
    "src/x86/mc_avx2.asm",
    "src/x86/mc16_avx2.asm",
    "src/x86/mc_avx512.asm",
    "src/x86/mc_sse.asm",
    "src/x86/me.asm",
    "src/x86/sad_sse2.asm",
    "src/x86/sad_avx.asm",
    "src/x86/satd.asm",
    "src/x86/sse.asm",
    "src/x86/cdef_rav1e.asm",
    "src/x86/cdef_sse.asm",
    "src/x86/cdef16_avx2.asm",
    "src/x86/cdef16_sse.asm",
    "src/x86/tables.asm",
  ];

  if let Some((hash, hash_path)) =
    hash_changed(asm_files, &out_dir, &dest_path)
  {
    let mut config_include_arg = String::from("-I");
    config_include_arg.push_str(&out_dir);
    config_include_arg.push('/');
    let mut nasm = nasm_rs::Build::new();
    for file in asm_files {
      nasm.file(file);
    }
    nasm.flag(&config_include_arg);
    nasm.flag("-Isrc/");
    let obj = nasm.compile_objects().expect(
      "NASM build failed. Make sure you have nasm installed. https://nasm.us",
    );
    // cc is better at finding the correct archiver
    let mut cc = cc::Build::new();
    for o in obj {
      cc.object(o);
    }
    cc.compile("rav1easm");

    std::fs::write(hash_path, &hash[..]).unwrap();
  } else {
    println!("cargo:rustc-link-search={}", out_dir);
  }
  println!("cargo:rustc-link-lib=static=rav1easm");
  rerun_dir("src/x86");
  rerun_dir("src/ext/x86");
}

#[cfg(feature = "asm")]
fn build_asm_files() {
  use std::fs::File;
  use std::io::Write;
  let out_dir = env::var("OUT_DIR").unwrap();

  let dest_path = Path::new(&out_dir).join("config.h");
  let mut config_file = File::create(&dest_path).unwrap();
  if env::var("CARGO_CFG_TARGET_VENDOR").unwrap() == "apple" {
    config_file.write(b" #define PREFIX 1\n").unwrap();
  }
  config_file.write(b" #define PRIVATE_PREFIX rav1e_\n").unwrap();
  config_file.write(b" #define ARCH_AARCH64 1\n").unwrap();
  config_file.write(b" #define ARCH_ARM 0\n").unwrap();
  config_file.write(b" #define CONFIG_LOG 1 \n").unwrap();
  config_file.write(b" #define HAVE_ASM 1\n").unwrap();
  config_file.sync_all().unwrap();

  let asm_files = &[
    "src/arm/64/cdef.S",
    "src/arm/64/cdef16.S",
    "src/arm/64/mc.S",
    "src/arm/64/mc16.S",
    "src/arm/64/itx.S",
    "src/arm/64/itx16.S",
    "src/arm/64/ipred.S",
    "src/arm/64/ipred16.S",
    "src/arm/64/sad.S",
    "src/arm/tables.S",
  ];

  if let Some((hash, hash_path)) =
    hash_changed(asm_files, &out_dir, &dest_path)
  {
    cc::Build::new()
      .files(asm_files)
      .include(".")
      .include(&out_dir)
      .compile("rav1e-aarch64");

    std::fs::write(hash_path, &hash[..]).unwrap();
  } else {
    println!("cargo:rustc-link-search={}", out_dir);
    println!("cargo:rustc-link-lib=static=rav1e-aarch64");
  }
  rerun_dir("src/arm");
}

fn rustc_version_check() {
  // This should match the version in the CI
  // Make sure to updated README.md when this changes.
  const REQUIRED_VERSION: &str = "1.51.0";
  if version().unwrap() < Version::parse(REQUIRED_VERSION).unwrap() {
    eprintln!("rav1e requires rustc >= {}.", REQUIRED_VERSION);
    exit(1);
  }
}

#[cfg(feature = "asm")]
fn is_nasm_new_enough(
  min_version: Option<(u8, u8, u8)>, nasm_path: &Path,
) -> Result<(), String> {
  match get_output(std::process::Command::new(nasm_path).arg("-v")) {
    Ok(version) => {
      if version.contains("NASM version 0.") {
        Err(version)
      } else if let Some((major, minor, micro)) = min_version {
        let ver = parse_nasm_version(&version)?;
        eprintln!("{:?} {:?} {:?}", min_version, version, ver);
        if major > ver.0
          || (major == ver.0 && minor > ver.1)
          || (major == ver.0 && minor == ver.1 && micro > ver.2)
        {
          Err(version)
        } else {
          Ok(())
        }
      } else {
        Ok(())
      }
    }
    Err(err) => Err(err),
  }
}

#[cfg(feature = "asm")]
fn parse_nasm_version(version_string: &str) -> Result<(u8, u8, u8), String> {
  // Rust regex lib doesn't support empty expressions in alterations,
  // so workaround the other way
  let regex1 =
    regex::Regex::new(r"(?:NASM version )?(\d+)\.(\d+)\.(\d+)").unwrap();
  if let Some(captures) = regex1.captures(version_string) {
    Ok((
      captures[1].parse().expect("Invalid version component"),
      captures[2].parse().expect("Invalid version component"),
      captures[3].parse().expect("Invalid version component"),
    ))
  } else {
    let regex2 = regex::Regex::new(r"(?:NASM version )?(\d+)\.(\d+)").unwrap();
    let captures = regex2
      .captures(version_string)
      .ok_or_else(|| "Unable to parse NASM version string".to_string())?;
    Ok((
      captures[1].parse().expect("Invalid version component"),
      captures[2].parse().expect("Invalid version component"),
      0,
    ))
  }
}

#[test]
fn test_parse_nasm_version() {
  let ver_str = "NASM version 2.14.02 compiled on Jan 22 2019";
  assert_eq!((2, 14, 2), parse_nasm_version(ver_str));
  let ver_str = "NASM version 2.14 compiled on Jan 22 2019";
  assert_eq!((2, 14, 0), parse_nasm_version(ver_str));
}

#[cfg(feature = "asm")]
fn nasm_version_check() -> std::path::PathBuf {
  let nasm_path = std::path::PathBuf::from("nasm");
  match is_nasm_new_enough(Some((2, 14, 0)), &nasm_path) {
    Ok(_) => nasm_path,
    Err(version) => {
      panic!("This version of NASM is too old: {}", version);
    }
  }
}

#[cfg(feature = "asm")]
fn get_output(cmd: &mut std::process::Command) -> Result<String, String> {
  let out = cmd.output().map_err(|e| e.to_string())?;
  if out.status.success() {
    Ok(String::from_utf8_lossy(&out.stdout).to_string())
  } else {
    Err(String::from_utf8_lossy(&out.stderr).to_string())
  }
}

#[allow(unused_variables)]
fn main() {
  rustc_version_check();

  let arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
  let os = env::var("CARGO_CFG_TARGET_OS").unwrap();
  // let env = env::var("CARGO_CFG_TARGET_ENV").unwrap();

  #[cfg(feature = "asm")]
  {
    if arch == "x86_64" {
      println!("cargo:rustc-cfg={}", "nasm_x86_64");
      nasm_version_check();
      build_nasm_files()
    }
    if arch == "aarch64" {
      println!("cargo:rustc-cfg={}", "asm_neon");
      build_asm_files()
    }
  }

  if os == "windows" && cfg!(feature = "decode_test") {
    panic!("Unsupported feature on this platform!");
  }

  vergen::generate_cargo_keys(vergen::ConstantsFlags::all())
    .expect("Unable to generate the cargo keys!");

  println!("cargo:rustc-env=PROFILE={}", env::var("PROFILE").unwrap());
}
<|endoftext|>


<commit_before>use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;

pub fn main() {
    if let Ok(profile) = env::var("PROFILE") {
        println!("cargo:rustc-cfg=build={:?}", profile);
    }

    let feature_prefix = "CARGO_FEATURE_";
    let out_dir = env::var("OUT_DIR").unwrap();

    let mut crates = Vec::new();
    for (key, val) in env::vars() {
        if val == "1" && key.starts_with(feature_prefix) {
            let krate = key[feature_prefix.len()..].to_lowercase();
            match krate.as_ref() {
                "default" | "macos" | "unix" | "windows" => continue,
                "nightly" | "test_unimplemented" => continue,
                s if s.starts_with("feat_") => continue,
                _ => {}
            }
            crates.push(krate.to_string());
        }
    }
    crates.sort();

    let mut cf = File::create(Path::new(&out_dir).join("uutils_crates.rs")).unwrap();
    let mut mf = File::create(Path::new(&out_dir).join("uutils_map.rs")).unwrap();

    mf.write_all(
        "
    type UtilityMap = HashMap<&'static str, fn(Vec<String>) -> i32>;

    fn util_map() -> UtilityMap {
    let mut map: UtilityMap = HashMap::new();\n"
            .as_bytes(),
    )
    .unwrap();

    for krate in crates {
        cf.write_all(format!("extern crate uu_{krate};\n", krate = krate).as_bytes())
            .unwrap();

        match krate.as_ref() {
            "hashsum" => {
                mf.write_all(
                    "map.insert(\"hashsum\", uu_hashsum::uumain);
                              map.insert(\"md5sum\", uu_hashsum::uumain);
                              map.insert(\"sha1sum\", uu_hashsum::uumain);
                              map.insert(\"sha224sum\", uu_hashsum::uumain);
                              map.insert(\"sha256sum\", uu_hashsum::uumain);
                              map.insert(\"sha384sum\", uu_hashsum::uumain);
                              map.insert(\"sha512sum\", uu_hashsum::uumain);
                              map.insert(\"sha3sum\", uu_hashsum::uumain);
                              map.insert(\"sha3-224sum\", uu_hashsum::uumain);
                              map.insert(\"sha3-256sum\", uu_hashsum::uumain);
                              map.insert(\"sha3-384sum\", uu_hashsum::uumain);
                              map.insert(\"sha3-512sum\", uu_hashsum::uumain);
                              map.insert(\"shake128sum\", uu_hashsum::uumain);
                              map.insert(\"shake256sum\", uu_hashsum::uumain);\n"
                        .as_bytes(),
                )
                .unwrap();
            }
            _ => mf
                .write_all(
                    format!(
                        "map.insert(\"{krate}\", uu_{krate}::uumain);\n",
                        krate = krate
                    )
                    .as_bytes(),
                )
                .unwrap(),
        }
    }

    mf.write_all("map\n}\n".as_bytes()).unwrap();

    cf.flush().unwrap();
    mf.flush().unwrap();
}
<commit_msg>refactor/polish ~ fix `cargo clippy` complaints (string_lit_as_bytes)<commit_after>use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;

pub fn main() {
    if let Ok(profile) = env::var("PROFILE") {
        println!("cargo:rustc-cfg=build={:?}", profile);
    }

    let feature_prefix = "CARGO_FEATURE_";
    let out_dir = env::var("OUT_DIR").unwrap();

    let mut crates = Vec::new();
    for (key, val) in env::vars() {
        if val == "1" && key.starts_with(feature_prefix) {
            let krate = key[feature_prefix.len()..].to_lowercase();
            match krate.as_ref() {
                "default" | "macos" | "unix" | "windows" => continue,
                "nightly" | "test_unimplemented" => continue,
                s if s.starts_with("feat_") => continue,
                _ => {}
            }
            crates.push(krate.to_string());
        }
    }
    crates.sort();

    let mut cf = File::create(Path::new(&out_dir).join("uutils_crates.rs")).unwrap();
    let mut mf = File::create(Path::new(&out_dir).join("uutils_map.rs")).unwrap();

    mf.write_all(
        "
    type UtilityMap = HashMap<&'static str, fn(Vec<String>) -> i32>;

    fn util_map() -> UtilityMap {
    let mut map: UtilityMap = HashMap::new();\n"
            .as_bytes(),
    )
    .unwrap();

    for krate in crates {
        cf.write_all(format!("extern crate uu_{krate};\n", krate = krate).as_bytes())
            .unwrap();

        match krate.as_ref() {
            "hashsum" => {
                mf.write_all(
                    "map.insert(\"hashsum\", uu_hashsum::uumain);
                              map.insert(\"md5sum\", uu_hashsum::uumain);
                              map.insert(\"sha1sum\", uu_hashsum::uumain);
                              map.insert(\"sha224sum\", uu_hashsum::uumain);
                              map.insert(\"sha256sum\", uu_hashsum::uumain);
                              map.insert(\"sha384sum\", uu_hashsum::uumain);
                              map.insert(\"sha512sum\", uu_hashsum::uumain);
                              map.insert(\"sha3sum\", uu_hashsum::uumain);
                              map.insert(\"sha3-224sum\", uu_hashsum::uumain);
                              map.insert(\"sha3-256sum\", uu_hashsum::uumain);
                              map.insert(\"sha3-384sum\", uu_hashsum::uumain);
                              map.insert(\"sha3-512sum\", uu_hashsum::uumain);
                              map.insert(\"shake128sum\", uu_hashsum::uumain);
                              map.insert(\"shake256sum\", uu_hashsum::uumain);\n"
                        .as_bytes(),
                )
                .unwrap();
            }
            _ => mf
                .write_all(
                    format!(
                        "map.insert(\"{krate}\", uu_{krate}::uumain);\n",
                        krate = krate
                    )
                    .as_bytes(),
                )
                .unwrap(),
        }
    }

    mf.write_all(b"map\n}\n").unwrap();

    cf.flush().unwrap();
    mf.flush().unwrap();
}
<|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/. */

extern crate cc;

use std::env;
use std::path::PathBuf;

fn main() {
    let mut build = cc::Build::new();
    let outdir = env::var("DEP_MOZJS_OUTDIR").unwrap();
    let include_path: PathBuf = [&outdir, "dist", "include"].iter().collect();

    build
        .file("src/jsglue.cpp")
        .include(include_path);
    if env::var("CARGO_FEATURE_DEBUGMOZJS").is_ok() {
        build.define("DEBUG", "");
        build.define("_DEBUG", "");

        if cfg!(target_os = "windows") {
            build.flag("-MDd");
            build.flag("-Od");
        } else {
            build.flag("-g");
            build.flag("-O0");
        }
    } else if cfg!(target_os = "windows") {
        build.flag("-MD");
    }

    build.flag_if_supported("-Wno-c++0x-extensions");
    build.flag_if_supported("-Wno-return-type-c-linkage");
    build.flag_if_supported("-Wno-invalid-offsetof");
    build.flag_if_supported("-Wno-unused-parameter");

    let confdefs_path: PathBuf = [&outdir, "js", "src", "js-confdefs.h"].iter().collect();
    if cfg!(target_os = "windows") {
        build.flag(&format!("-FI{}", confdefs_path.to_string_lossy()));
        build.define("WIN32", "");
        build.flag("-Zi");
        build.flag("-GR-");
    } else {
        build.flag("-fPIC");
        build.flag("-fno-rtti");
        build.flag("-std=c++11");
        build.define("JS_NO_JSVAL_JSID_STRUCT_TYPES", "");
        build.flag("-include");
        build.flag(&confdefs_path.to_string_lossy());
    }

    build.compile("jsglue");
    println!("cargo:rerun-if-changed=src/jsglue.cpp");
}
<commit_msg>Auto merge of #427 - asajeffrey:build-rs-set-cpp-flag, r=jdm<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/. */

extern crate cc;

use std::env;
use std::path::PathBuf;

fn main() {
    let mut build = cc::Build::new();
    let outdir = env::var("DEP_MOZJS_OUTDIR").unwrap();
    let include_path: PathBuf = [&outdir, "dist", "include"].iter().collect();

    build.cpp(true)
        .file("src/jsglue.cpp")
        .include(include_path);
    if env::var("CARGO_FEATURE_DEBUGMOZJS").is_ok() {
        build.define("DEBUG", "");
        build.define("_DEBUG", "");

        if cfg!(target_os = "windows") {
            build.flag("-MDd");
            build.flag("-Od");
        } else {
            build.flag("-g");
            build.flag("-O0");
        }
    } else if cfg!(target_os = "windows") {
        build.flag("-MD");
    }

    build.flag_if_supported("-Wno-c++0x-extensions");
    build.flag_if_supported("-Wno-return-type-c-linkage");
    build.flag_if_supported("-Wno-invalid-offsetof");
    build.flag_if_supported("-Wno-unused-parameter");

    let confdefs_path: PathBuf = [&outdir, "js", "src", "js-confdefs.h"].iter().collect();
    if cfg!(target_os = "windows") {
        build.flag(&format!("-FI{}", confdefs_path.to_string_lossy()));
        build.define("WIN32", "");
        build.flag("-Zi");
        build.flag("-GR-");
    } else {
        build.flag("-fPIC");
        build.flag("-fno-rtti");
        build.flag("-std=c++11");
        build.define("JS_NO_JSVAL_JSID_STRUCT_TYPES", "");
        build.flag("-include");
        build.flag(&confdefs_path.to_string_lossy());
    }

    build.compile("jsglue");
    println!("cargo:rerun-if-changed=src/jsglue.cpp");
}
<|endoftext|>


<commit_before>use std::io::{Command, File, Truncate, Write};
use std::os;

fn main()
{
    let dir = Path::new(os::getenv("OUT_DIR").unwrap());
    let out_file = dir.join("codegen");
    Command::new("gcc").arg("src/codegen/type_size.c")
                       .arg("-o")
                       .arg(out_file.as_vec())
                       .status()
                       .unwrap();
    let code = Command::new(out_file.as_vec()).output().unwrap();
    if !code.status.success() {
        panic!("{}", String::from_utf8_lossy(code.error.as_slice()));
    }
    let mut f = File::open_mode(&Path::new("src/type_size.rs"), Truncate, Write);
    f.write(code.output.as_slice()).unwrap();
}
<commit_msg>Allow unstable items in the build script<commit_after>#![allow(unstable)]

use std::io::{Command, File, Truncate, Write};
use std::os;

fn main()
{
    let dir = Path::new(os::getenv("OUT_DIR").unwrap());
    let out_file = dir.join("codegen");
    Command::new("gcc").arg("src/codegen/type_size.c")
                       .arg("-o")
                       .arg(out_file.as_vec())
                       .status()
                       .unwrap();
    let code = Command::new(out_file.as_vec()).output().unwrap();
    if !code.status.success() {
        panic!("{}", String::from_utf8_lossy(code.error.as_slice()));
    }
    let mut f = File::open_mode(&Path::new("src/type_size.rs"), Truncate, Write);
    f.write(code.output.as_slice()).unwrap();
}
<|endoftext|>


<commit_before>use flate2::{Compression, GzBuilder};
use std::ffi::OsStr;
use std::fs;
use std::path::Path;

fn main() {
    compress_man();
}

fn compress_man() {
    let out_path = Path::new(&std::env::var("OUT_DIR").unwrap()).join("man.tgz");
    let dst = fs::File::create(out_path).unwrap();
    let encoder = GzBuilder::new()
        .filename("man.tar")
        .write(dst, Compression::best());
    let mut ar = tar::Builder::new(encoder);

    let mut add_files = |dir, extension| {
        for entry in fs::read_dir(dir).unwrap() {
            let path = entry.unwrap().path();
            if path.extension() != Some(extension) {
                continue;
            }
            println!("cargo:rerun-if-changed={}", path.display());
            ar.append_path_with_name(&path, path.file_name().unwrap())
                .unwrap();
        }
    };

    add_files(Path::new("src/etc/man"), OsStr::new("1"));
    add_files(Path::new("src/doc/man/generated_txt"), OsStr::new("txt"));
    let encoder = ar.into_inner().unwrap();
    encoder.finish().unwrap();
}
<commit_msg>Build manpage archive deterministically<commit_after>use flate2::{Compression, GzBuilder};
use std::ffi::OsStr;
use std::fs;
use std::path::Path;

fn main() {
    compress_man();
}

fn compress_man() {
    let out_path = Path::new(&std::env::var("OUT_DIR").unwrap()).join("man.tgz");
    let dst = fs::File::create(out_path).unwrap();
    let encoder = GzBuilder::new()
        .filename("man.tar")
        .write(dst, Compression::best());
    let mut ar = tar::Builder::new(encoder);
    ar.mode(tar::HeaderMode::Deterministic);

    let mut add_files = |dir, extension| {
        let mut files = fs::read_dir(dir)
            .unwrap()
            .map(|e| e.unwrap().path())
            .collect::<Vec<_>>();
        files.sort();
        for path in files {
            if path.extension() != Some(extension) {
                continue;
            }
            println!("cargo:rerun-if-changed={}", path.display());
            ar.append_path_with_name(&path, path.file_name().unwrap())
                .unwrap();
        }
    };

    add_files(Path::new("src/etc/man"), OsStr::new("1"));
    add_files(Path::new("src/doc/man/generated_txt"), OsStr::new("txt"));
    let encoder = ar.into_inner().unwrap();
    encoder.finish().unwrap();
}
<|endoftext|>


<commit_before>// min-version: 1.44.0
// max-version: 1.54.0

// === LLDB TESTS ==================================================================================

// lldb-command:run

// lldb-command:print os_string
// lldbr-check:[...]os_string = "A∆й中" [...]
// lldbg-check:[...]$0 = "A∆й中" [...]
// lldb-command:print empty_os_string
// lldbr-check:[...]empty_os_string = "" [...]
// lldbg-check:[...]$1 = "" [...]
// lldb-command:print c_string1
// lldbr-check:[...]c_string1 = "A∆й中" [...]
// TODO: investigate why `lldbg-check` fails
// lldb-command:print path_buf
// lldbr-check:[...]path_buf = "/a/b/∂" [...]
// lldbg-check:[...]$3 = "/a/b/∂" [...]
// lldb-command:print empty_path_buf
// lldbr-check:[...]empty_path_buf = "" [...]
// lldbg-check:[...]$4 = "" [...]
// lldb-command:print os_str1
// lldbr-check:[...]os_str1 = [...] "A∆й中"
// TODO: investigate why `lldbg-check` fails
// lldb-command:print os_str2
// lldbr-check:[...]os_str2 = [...] "A∆й中"
// TODO: investigate why `lldbg-check` fails
// lldb-command:print empty_os_str
// lldbr-check:[...]empty_os_str = [...] ""
// TODO: investigate why `lldbg-check` fails
// lldb-command:print path1
// lldbr-check:[...]path1 = [...] "/a/b/∂"
// TODO: investigate why `lldbg-check` fails
// lldb-command:print empty_path
// lldbr-check:[...]empty_path = [...] ""
// TODO: investigate why `lldbg-check` fails
// lldb-command:print c_str1
// lldbr-check:[...]c_str1 = [...] "abcd"
// TODO: investigate why `lldbg-check` fails

// === GDB TESTS ==================================================================================

// gdb-command:run

// gdb-command:print os_string
// gdb-check:[...]$1 = "A∆й中"
// gdb-command:print empty_os_string
// gdb-check:[...]$2 = ""

use std::ffi::{CStr, CString, OsStr, OsString};
use std::ops::DerefMut;
use std::path::{Path, PathBuf};

fn main() {
    let mut os_string = OsString::from("A∆й中");
    let empty_os_string = OsString::from("");
    let c_string1 = CString::new("A∆й中").unwrap();
    let path_buf = PathBuf::from("/a/b/∂");
    let empty_path_buf = PathBuf::from("");
    let os_str1 = OsStr::new("A∆й中");
    let os_str2 = os_string.deref_mut();
    let empty_os_str = OsStr::new("");
    let path1 = Path::new("/a/b/∂");
    let empty_path = Path::new("");
    let c_str1 = CStr::from_bytes_with_nul(b"abcd\0").unwrap();
    print!(""); // #break
}
<commit_msg>#7779: Enable FFI strings pretty-printers tests<commit_after>// min-version: 1.60.0

// === LLDB TESTS ==================================================================================

// lldb-command:run

// lldb-command:print os_string
// lldbr-check:[...]os_string = "abc" [...]
// lldbg-check:[...]$0 = "abc" [...]

// lldb-command:print os_string_empty
// lldbr-check:[...]os_string_empty = "" [...]
// lldbg-check:[...]$1 = "" [...]

// lldb-command:print os_string_unicode
// lldbr-check:[...]os_string_unicode = "A∆й中" [...]
// TODO: support WTF-8 on Windows

// lldb-command:print os_str
// lldbr-check:[...]os_str = "abc" { data_ptr = [...] length = 3 }
// TODO: support `ref$<...>` and `ref_mut$<...>` type wrappings on Windows

// lldb-command:print os_str_empty
// lldbr-check:[...]os_str_empty = "" { data_ptr = [...] length = 0 }
// TODO: support `ref$<...>` and `ref_mut$<...>` type wrappings on Windows

// lldb-command:print os_str_unicode
// lldbr-check:[...]os_str_unicode = "A∆й中" { data_ptr = [...] length = 9 }
// TODO: support `ref$<...>` and `ref_mut$<...>` type wrappings and WTF-8 on Windows

// lldb-command:print c_string
// lldbr-check:[...]c_string = "abc" [...]
// MSVC LLDB without Rust support fails to print `CString` in the console (but CLion renders it fine)

// lldb-command:print c_string_empty
// lldbr-check:[...]c_string_empty = "" [...]
// MSVC LLDB without Rust support fails to print `CString` in the console (but CLion renders it fine)

// lldb-command:print c_string_unicode
// lldbr-check:[...]c_string_unicode = "A∆й中" [...]
// MSVC LLDB without Rust support fails to print `CString` in the console (but CLion renders it fine)

// lldb-command:print c_str
// lldbr-check:[...]c_str = "abcd" { data_ptr = [...] length = 5 }
// TODO: support `ref$<...>` and `ref_mut$<...>` type wrappings on Windows

// lldb-command:print c_str_empty
// lldbr-check:[...]c_str_empty = "" { data_ptr = [...] length = 1 }
// TODO: support `ref$<...>` and `ref_mut$<...>` type wrappings on Windows

// lldb-command:print c_str_unicode
// lldbr-check:[...]c_str_unicode = "A∆й中" { data_ptr = [...] length = 10 }
// TODO: support `ref$<...>` and `ref_mut$<...>` type wrappings on Windows

// lldb-command:print path_buf
// lldbr-check:[...]path_buf = "/a/b/c" [...]
// lldbg-check:[...]$12 = "/a/b/c" [...]

// lldb-command:print path_buf_empty
// lldbr-check:[...]path_buf_empty = "" [...]
// lldbg-check:[...]$13 = "" [...]

// lldb-command:print path_buf_unicode
// lldbr-check:[...]path_buf_unicode = "/a/b/∂" [...]
// TODO: support WTF-8 on Windows

// lldb-command:print path
// lldbr-check:[...]path = "/a/b/c" { data_ptr = [...] length = 6 }
// TODO: support `ref$<...>` and `ref_mut$<...>` type wrappings on Windows

// lldb-command:print path_empty
// lldbr-check:[...]path_empty = "" { data_ptr = [...] length = 0 }
// TODO: support `ref$<...>` and `ref_mut$<...>` type wrappings on Windows

// lldb-command:print path_unicode
// lldbr-check:[...]path_unicode = "/a/b/∂" { data_ptr = [...] length = 8 }
// TODO: support `ref$<...>` and `ref_mut$<...>` type wrappings on Windows

// === GDB TESTS ==================================================================================

// gdb-command:run

// gdb-command:print os_string
// gdb-check:[...]$1 = "abc"
// gdb-command:print os_string_empty
// gdb-check:[...]$2 = ""
// gdb-command:print os_string_unicode
// gdb-check:[...]$3 = "A∆й中"

use std::ffi::{CStr, CString, OsStr, OsString};
use std::ops::DerefMut;
use std::path::{Path, PathBuf};

fn main() {
    let mut os_string = OsString::from("abc");
    let os_string_empty = OsString::from("");
    let mut os_string_unicode = OsString::from("A∆й中");

    let os_str = os_string.deref_mut();
    let os_str_empty = OsStr::new("");
    let os_str_unicode = os_string_unicode.deref_mut();

    let c_string = CString::new("abc").unwrap();
    let c_string_empty = CString::new("").unwrap();
    let c_string_unicode = CString::new("A∆й中").unwrap();

    let c_str = CStr::from_bytes_with_nul(b"abcd\0").unwrap();
    let c_str_empty = CStr::from_bytes_with_nul(b"\0").unwrap();
    let c_str_unicode = CStr::from_bytes_with_nul(b"A\xE2\x88\x86\xD0\xB9\xE4\xB8\xAD\0").unwrap();

    let path_buf = PathBuf::from("/a/b/c");
    let path_buf_empty = PathBuf::from("");
    let path_buf_unicode = PathBuf::from("/a/b/∂");

    let path = Path::new("/a/b/c");
    let path_empty = Path::new("");
    let path_unicode = Path::new("/a/b/∂");

    print!(""); // #break
}
<|endoftext|>