<commit_before>use crate::core::shell::Verbosity;
use crate::core::{GitReference, Workspace};
use crate::ops;
use crate::sources::path::PathSource;
use crate::util::Sha256;
use crate::util::{paths, CargoResult, CargoResultExt, Config};
use anyhow::bail;
use serde::Serialize;
use std::collections::HashSet;
use std::collections::{BTreeMap, BTreeSet, HashMap};
use std::fs;
use std::path::{Path, PathBuf};

pub struct VendorOptions<'a> {
    pub no_delete: bool,
    pub versioned_dirs: bool,
    pub destination: &'a Path,
    pub extra: Vec<PathBuf>,
}

pub fn vendor(ws: &Workspace<'_>, opts: &VendorOptions<'_>) -> CargoResult<()> {
    let config = ws.config();
    let mut extra_workspaces = Vec::new();
    for extra in opts.extra.iter() {
        let extra = config.cwd().join(extra);
        let ws = Workspace::new(&extra, config)?;
        extra_workspaces.push(ws);
    }
    let workspaces = extra_workspaces.iter().chain(Some(ws)).collect::<Vec<_>>();
    let vendor_config =
        sync(config, &workspaces, opts).chain_err(|| "failed to sync".to_string())?;

    if config.shell().verbosity() != Verbosity::Quiet {
        crate::drop_eprint!(
            config,
            "To use vendored sources, add this to your .cargo/config for this project:\n\n"
        );
        crate::drop_print!(config, "{}", &toml::to_string(&vendor_config).unwrap());
    }

    Ok(())
}

#[derive(Serialize)]
struct VendorConfig {
    source: BTreeMap<String, VendorSource>,
}

#[derive(Serialize)]
#[serde(rename_all = "lowercase", untagged)]
enum VendorSource {
    Directory {
        directory: PathBuf,
    },
    Registry {
        registry: Option<String>,
        #[serde(rename = "replace-with")]
        replace_with: String,
    },
    Git {
        git: String,
        branch: Option<String>,
        tag: Option<String>,
        rev: Option<String>,
        #[serde(rename = "replace-with")]
        replace_with: String,
    },
}

fn sync(
    config: &Config,
    workspaces: &[&Workspace<'_>],
    opts: &VendorOptions<'_>,
) -> CargoResult<VendorConfig> {
    let canonical_destination = opts.destination.canonicalize();
    let canonical_destination = canonical_destination
        .as_ref()
        .map(|p| &**p)
        .unwrap_or(opts.destination);

    paths::create_dir_all(&canonical_destination)?;
    let mut to_remove = HashSet::new();
    if !opts.no_delete {
        for entry in canonical_destination.read_dir()? {
            let entry = entry?;
            if !entry
                .file_name()
                .to_str()
                .map_or(false, |s| s.starts_with('.'))
            {
                to_remove.insert(entry.path());
            }
        }
    }

    // First up attempt to work around rust-lang/cargo#5956. Apparently build
    // artifacts sprout up in Cargo's global cache for whatever reason, although
    // it's unsure what tool is causing these issues at this time. For now we
    // apply a heavy-hammer approach which is to delete Cargo's unpacked version
    // of each crate to start off with. After we do this we'll re-resolve and
    // redownload again, which should trigger Cargo to re-extract all the
    // crates.
    //
    // Note that errors are largely ignored here as this is a best-effort
    // attempt. If anything fails here we basically just move on to the next
    // crate to work with.
    for ws in workspaces {
        let (packages, resolve) =
            ops::resolve_ws(ws).chain_err(|| "failed to load pkg lockfile")?;

        packages
            .get_many(resolve.iter())
            .chain_err(|| "failed to download packages")?;

        for pkg in resolve.iter() {
            // Don't delete actual source code!
            if pkg.source_id().is_path() {
                if let Ok(path) = pkg.source_id().url().to_file_path() {
                    if let Ok(path) = path.canonicalize() {
                        to_remove.remove(&path);
                    }
                }
                continue;
            }
            if pkg.source_id().is_git() {
                continue;
            }
            if let Ok(pkg) = packages.get_one(pkg) {
                drop(fs::remove_dir_all(pkg.manifest_path().parent().unwrap()));
            }
        }
    }

    let mut checksums = HashMap::new();
    let mut ids = BTreeMap::new();

    // Next up let's actually download all crates and start storing internal
    // tables about them.
    for ws in workspaces {
        let (packages, resolve) =
            ops::resolve_ws(ws).chain_err(|| "failed to load pkg lockfile")?;

        packages
            .get_many(resolve.iter())
            .chain_err(|| "failed to download packages")?;

        for pkg in resolve.iter() {
            // No need to vendor path crates since they're already in the
            // repository
            if pkg.source_id().is_path() {
                continue;
            }
            ids.insert(
                pkg,
                packages
                    .get_one(pkg)
                    .chain_err(|| "failed to fetch package")?
                    .clone(),
            );

            checksums.insert(pkg, resolve.checksums().get(&pkg).cloned());
        }
    }

    let mut versions = HashMap::new();
    for id in ids.keys() {
        let map = versions.entry(id.name()).or_insert_with(BTreeMap::default);
        if let Some(prev) = map.get(&id.version()) {
            bail!(
                "found duplicate version of package `{} v{}` \
                 vendored from two sources:\n\
                 \n\
                 \tsource 1: {}\n\
                 \tsource 2: {}",
                id.name(),
                id.version(),
                prev,
                id.source_id()
            );
        }
        map.insert(id.version(), id.source_id());
    }

    let mut sources = BTreeSet::new();
    for (id, pkg) in ids.iter() {
        // Next up, copy it to the vendor directory
        let src = pkg
            .manifest_path()
            .parent()
            .expect("manifest_path should point to a file");
        let max_version = *versions[&id.name()].iter().rev().next().unwrap().0;
        let dir_has_version_suffix = opts.versioned_dirs || id.version() != max_version;
        let dst_name = if dir_has_version_suffix {
            // Eg vendor/futures-0.1.13
            format!("{}-{}", id.name(), id.version())
        } else {
            // Eg vendor/futures
            id.name().to_string()
        };

        sources.insert(id.source_id());
        let dst = canonical_destination.join(&dst_name);
        to_remove.remove(&dst);
        let cksum = dst.join(".cargo-checksum.json");
        if dir_has_version_suffix && cksum.exists() {
            // Always re-copy directory without version suffix in case the version changed
            continue;
        }

        config.shell().status(
            "Vendoring",
            &format!("{} ({}) to {}", id, src.to_string_lossy(), dst.display()),
        )?;

        let _ = fs::remove_dir_all(&dst);
        let pathsource = PathSource::new(src, id.source_id(), config);
        let paths = pathsource.list_files(pkg)?;
        let mut map = BTreeMap::new();
        cp_sources(src, &paths, &dst, &mut map)
            .chain_err(|| format!("failed to copy over vendored sources for: {}", id))?;

        // Finally, emit the metadata about this package
        let json = serde_json::json!({
            "package": checksums.get(id),
            "files": map,
        });

        paths::write(&cksum, json.to_string())?;
    }

    for path in to_remove {
        if path.is_dir() {
            paths::remove_dir_all(&path)?;
        } else {
            paths::remove_file(&path)?;
        }
    }

    // add our vendored source
    let mut config = BTreeMap::new();

    let merged_source_name = "vendored-sources";
    config.insert(
        merged_source_name.to_string(),
        VendorSource::Directory {
            directory: opts.destination.to_path_buf(),
        },
    );

    // replace original sources with vendor
    for source_id in sources {
        let name = if source_id.is_default_registry() {
            "crates-io".to_string()
        } else {
            source_id.url().to_string()
        };

        let source = if source_id.is_default_registry() {
            VendorSource::Registry {
                registry: None,
                replace_with: merged_source_name.to_string(),
            }
        } else if source_id.is_remote_registry() {
            let registry = source_id.url().to_string();
            VendorSource::Registry {
                registry: Some(registry),
                replace_with: merged_source_name.to_string(),
            }
        } else if source_id.is_git() {
            let mut branch = None;
            let mut tag = None;
            let mut rev = None;
            if let Some(reference) = source_id.git_reference() {
                match *reference {
                    GitReference::Branch(ref b) => branch = Some(b.clone()),
                    GitReference::Tag(ref t) => tag = Some(t.clone()),
                    GitReference::Rev(ref r) => rev = Some(r.clone()),
                    GitReference::DefaultBranch => {}
                }
            }
            VendorSource::Git {
                git: source_id.url().to_string(),
                branch,
                tag,
                rev,
                replace_with: merged_source_name.to_string(),
            }
        } else {
            panic!("Invalid source ID: {}", source_id)
        };
        config.insert(name, source);
    }

    Ok(VendorConfig { source: config })
}

fn cp_sources(
    src: &Path,
    paths: &[PathBuf],
    dst: &Path,
    cksums: &mut BTreeMap<String, String>,
) -> CargoResult<()> {
    for p in paths {
        let relative = p.strip_prefix(&src).unwrap();

        match relative.to_str() {
            // Skip git config files as they're not relevant to builds most of
            // the time and if we respect them (e.g.  in git) then it'll
            // probably mess with the checksums when a vendor dir is checked
            // into someone else's source control
            Some(".gitattributes") | Some(".gitignore") | Some(".git") => continue,

            // Temporary Cargo files
            Some(".cargo-ok") => continue,

            // Skip patch-style orig/rej files. Published crates on crates.io
            // have `Cargo.toml.orig` which we don't want to use here and
            // otherwise these are rarely used as part of the build process.
            Some(filename) => {
                if filename.ends_with(".orig") || filename.ends_with(".rej") {
                    continue;
                }
            }
            _ => {}
        };

        // Join pathname components individually to make sure that the joined
        // path uses the correct directory separators everywhere, since
        // `relative` may use Unix-style and `dst` may require Windows-style
        // backslashes.
        let dst = relative
            .iter()
            .fold(dst.to_owned(), |acc, component| acc.join(&component));

        paths::create_dir_all(dst.parent().unwrap())?;

        paths::copy(&p, &dst)?;
        let cksum = Sha256::new().update_path(dst)?.finish_hex();
        cksums.insert(relative.to_str().unwrap().replace("\\", "/"), cksum);
    }
    Ok(())
}
<commit_msg>vendor: correct the path to cargo config <commit_after>use crate::core::shell::Verbosity;
use crate::core::{GitReference, Workspace};
use crate::ops;
use crate::sources::path::PathSource;
use crate::util::Sha256;
use crate::util::{paths, CargoResult, CargoResultExt, Config};
use anyhow::bail;
use serde::Serialize;
use std::collections::HashSet;
use std::collections::{BTreeMap, BTreeSet, HashMap};
use std::fs;
use std::path::{Path, PathBuf};

pub struct VendorOptions<'a> {
    pub no_delete: bool,
    pub versioned_dirs: bool,
    pub destination: &'a Path,
    pub extra: Vec<PathBuf>,
}

pub fn vendor(ws: &Workspace<'_>, opts: &VendorOptions<'_>) -> CargoResult<()> {
    let config = ws.config();
    let mut extra_workspaces = Vec::new();
    for extra in opts.extra.iter() {
        let extra = config.cwd().join(extra);
        let ws = Workspace::new(&extra, config)?;
        extra_workspaces.push(ws);
    }
    let workspaces = extra_workspaces.iter().chain(Some(ws)).collect::<Vec<_>>();
    let vendor_config =
        sync(config, &workspaces, opts).chain_err(|| "failed to sync".to_string())?;

    if config.shell().verbosity() != Verbosity::Quiet {
        crate::drop_eprint!(
            config,
            "To use vendored sources, add this to your .cargo/config.toml for this project:\n\n"
        );
        crate::drop_print!(config, "{}", &toml::to_string(&vendor_config).unwrap());
    }

    Ok(())
}

#[derive(Serialize)]
struct VendorConfig {
    source: BTreeMap<String, VendorSource>,
}

#[derive(Serialize)]
#[serde(rename_all = "lowercase", untagged)]
enum VendorSource {
    Directory {
        directory: PathBuf,
    },
    Registry {
        registry: Option<String>,
        #[serde(rename = "replace-with")]
        replace_with: String,
    },
    Git {
        git: String,
        branch: Option<String>,
        tag: Option<String>,
        rev: Option<String>,
        #[serde(rename = "replace-with")]
        replace_with: String,
    },
}

fn sync(
    config: &Config,
    workspaces: &[&Workspace<'_>],
    opts: &VendorOptions<'_>,
) -> CargoResult<VendorConfig> {
    let canonical_destination = opts.destination.canonicalize();
    let canonical_destination = canonical_destination
        .as_ref()
        .map(|p| &**p)
        .unwrap_or(opts.destination);

    paths::create_dir_all(&canonical_destination)?;
    let mut to_remove = HashSet::new();
    if !opts.no_delete {
        for entry in canonical_destination.read_dir()? {
            let entry = entry?;
            if !entry
                .file_name()
                .to_str()
                .map_or(false, |s| s.starts_with('.'))
            {
                to_remove.insert(entry.path());
            }
        }
    }

    // First up attempt to work around rust-lang/cargo#5956. Apparently build
    // artifacts sprout up in Cargo's global cache for whatever reason, although
    // it's unsure what tool is causing these issues at this time. For now we
    // apply a heavy-hammer approach which is to delete Cargo's unpacked version
    // of each crate to start off with. After we do this we'll re-resolve and
    // redownload again, which should trigger Cargo to re-extract all the
    // crates.
    //
    // Note that errors are largely ignored here as this is a best-effort
    // attempt. If anything fails here we basically just move on to the next
    // crate to work with.
    for ws in workspaces {
        let (packages, resolve) =
            ops::resolve_ws(ws).chain_err(|| "failed to load pkg lockfile")?;

        packages
            .get_many(resolve.iter())
            .chain_err(|| "failed to download packages")?;

        for pkg in resolve.iter() {
            // Don't delete actual source code!
            if pkg.source_id().is_path() {
                if let Ok(path) = pkg.source_id().url().to_file_path() {
                    if let Ok(path) = path.canonicalize() {
                        to_remove.remove(&path);
                    }
                }
                continue;
            }
            if pkg.source_id().is_git() {
                continue;
            }
            if let Ok(pkg) = packages.get_one(pkg) {
                drop(fs::remove_dir_all(pkg.manifest_path().parent().unwrap()));
            }
        }
    }

    let mut checksums = HashMap::new();
    let mut ids = BTreeMap::new();

    // Next up let's actually download all crates and start storing internal
    // tables about them.
    for ws in workspaces {
        let (packages, resolve) =
            ops::resolve_ws(ws).chain_err(|| "failed to load pkg lockfile")?;

        packages
            .get_many(resolve.iter())
            .chain_err(|| "failed to download packages")?;

        for pkg in resolve.iter() {
            // No need to vendor path crates since they're already in the
            // repository
            if pkg.source_id().is_path() {
                continue;
            }
            ids.insert(
                pkg,
                packages
                    .get_one(pkg)
                    .chain_err(|| "failed to fetch package")?
                    .clone(),
            );

            checksums.insert(pkg, resolve.checksums().get(&pkg).cloned());
        }
    }

    let mut versions = HashMap::new();
    for id in ids.keys() {
        let map = versions.entry(id.name()).or_insert_with(BTreeMap::default);
        if let Some(prev) = map.get(&id.version()) {
            bail!(
                "found duplicate version of package `{} v{}` \
                 vendored from two sources:\n\
                 \n\
                 \tsource 1: {}\n\
                 \tsource 2: {}",
                id.name(),
                id.version(),
                prev,
                id.source_id()
            );
        }
        map.insert(id.version(), id.source_id());
    }

    let mut sources = BTreeSet::new();
    for (id, pkg) in ids.iter() {
        // Next up, copy it to the vendor directory
        let src = pkg
            .manifest_path()
            .parent()
            .expect("manifest_path should point to a file");
        let max_version = *versions[&id.name()].iter().rev().next().unwrap().0;
        let dir_has_version_suffix = opts.versioned_dirs || id.version() != max_version;
        let dst_name = if dir_has_version_suffix {
            // Eg vendor/futures-0.1.13
            format!("{}-{}", id.name(), id.version())
        } else {
            // Eg vendor/futures
            id.name().to_string()
        };

        sources.insert(id.source_id());
        let dst = canonical_destination.join(&dst_name);
        to_remove.remove(&dst);
        let cksum = dst.join(".cargo-checksum.json");
        if dir_has_version_suffix && cksum.exists() {
            // Always re-copy directory without version suffix in case the version changed
            continue;
        }

        config.shell().status(
            "Vendoring",
            &format!("{} ({}) to {}", id, src.to_string_lossy(), dst.display()),
        )?;

        let _ = fs::remove_dir_all(&dst);
        let pathsource = PathSource::new(src, id.source_id(), config);
        let paths = pathsource.list_files(pkg)?;
        let mut map = BTreeMap::new();
        cp_sources(src, &paths, &dst, &mut map)
            .chain_err(|| format!("failed to copy over vendored sources for: {}", id))?;

        // Finally, emit the metadata about this package
        let json = serde_json::json!({
            "package": checksums.get(id),
            "files": map,
        });

        paths::write(&cksum, json.to_string())?;
    }

    for path in to_remove {
        if path.is_dir() {
            paths::remove_dir_all(&path)?;
        } else {
            paths::remove_file(&path)?;
        }
    }

    // add our vendored source
    let mut config = BTreeMap::new();

    let merged_source_name = "vendored-sources";
    config.insert(
        merged_source_name.to_string(),
        VendorSource::Directory {
            directory: opts.destination.to_path_buf(),
        },
    );

    // replace original sources with vendor
    for source_id in sources {
        let name = if source_id.is_default_registry() {
            "crates-io".to_string()
        } else {
            source_id.url().to_string()
        };

        let source = if source_id.is_default_registry() {
            VendorSource::Registry {
                registry: None,
                replace_with: merged_source_name.to_string(),
            }
        } else if source_id.is_remote_registry() {
            let registry = source_id.url().to_string();
            VendorSource::Registry {
                registry: Some(registry),
                replace_with: merged_source_name.to_string(),
            }
        } else if source_id.is_git() {
            let mut branch = None;
            let mut tag = None;
            let mut rev = None;
            if let Some(reference) = source_id.git_reference() {
                match *reference {
                    GitReference::Branch(ref b) => branch = Some(b.clone()),
                    GitReference::Tag(ref t) => tag = Some(t.clone()),
                    GitReference::Rev(ref r) => rev = Some(r.clone()),
                    GitReference::DefaultBranch => {}
                }
            }
            VendorSource::Git {
                git: source_id.url().to_string(),
                branch,
                tag,
                rev,
                replace_with: merged_source_name.to_string(),
            }
        } else {
            panic!("Invalid source ID: {}", source_id)
        };
        config.insert(name, source);
    }

    Ok(VendorConfig { source: config })
}

fn cp_sources(
    src: &Path,
    paths: &[PathBuf],
    dst: &Path,
    cksums: &mut BTreeMap<String, String>,
) -> CargoResult<()> {
    for p in paths {
        let relative = p.strip_prefix(&src).unwrap();

        match relative.to_str() {
            // Skip git config files as they're not relevant to builds most of
            // the time and if we respect them (e.g.  in git) then it'll
            // probably mess with the checksums when a vendor dir is checked
            // into someone else's source control
            Some(".gitattributes") | Some(".gitignore") | Some(".git") => continue,

            // Temporary Cargo files
            Some(".cargo-ok") => continue,

            // Skip patch-style orig/rej files. Published crates on crates.io
            // have `Cargo.toml.orig` which we don't want to use here and
            // otherwise these are rarely used as part of the build process.
            Some(filename) => {
                if filename.ends_with(".orig") || filename.ends_with(".rej") {
                    continue;
                }
            }
            _ => {}
        };

        // Join pathname components individually to make sure that the joined
        // path uses the correct directory separators everywhere, since
        // `relative` may use Unix-style and `dst` may require Windows-style
        // backslashes.
        let dst = relative
            .iter()
            .fold(dst.to_owned(), |acc, component| acc.join(&component));

        paths::create_dir_all(dst.parent().unwrap())?;

        paths::copy(&p, &dst)?;
        let cksum = Sha256::new().update_path(dst)?.finish_hex();
        cksums.insert(relative.to_str().unwrap().replace("\\", "/"), cksum);
    }
    Ok(())
}
<|endoftext|>


<commit_before>use super::{
    function_body_chunk,
    general::{
        cfg_condition, cfg_deprecated, doc_hidden, not_version_condition, version_condition,
    },
    parameter::ToParameter,
    return_value::{out_parameters_as_return, ToReturnValue},
};
use crate::{
    analysis::{
        self,
        bounds::{Bound, Bounds},
        functions::Visibility,
        namespaces,
    },
    chunk::{ffi_function_todo, Chunk},
    env::Env,
    library,
    writer::{primitives::tabs, ToCode},
};
use log::warn;
use std::{
    fmt,
    io::{Result, Write},
    result::Result as StdResult,
};

pub fn generate(
    w: &mut dyn Write,
    env: &Env,
    analysis: &analysis::functions::Info,
    in_trait: bool,
    only_declaration: bool,
    indent: usize,
) -> Result<()> {
    if analysis.is_async_finish(env) {
        return Ok(());
    }

    let mut commented = false;
    let mut comment_prefix = "";
    let mut pub_prefix = if in_trait { "" } else { "pub " };

    match analysis.visibility {
        Visibility::Public => {}
        Visibility::Comment => {
            commented = true;
            comment_prefix = "//";
        }
        Visibility::Private => {
            if in_trait {
                warn!(
                    "Generating trait method for private function {}",
                    analysis.glib_name
                );
            } else {
                pub_prefix = "";
            }
        }
        Visibility::Hidden => return Ok(()),
    }
    let declaration = declaration(env, analysis);
    let suffix = if only_declaration { ";" } else { " {" };

    writeln!(w)?;
    if !in_trait || only_declaration {
        cfg_deprecated(w, env, analysis.deprecated_version, commented, indent)?;
    }
    cfg_condition(w, &analysis.cfg_condition, commented, indent)?;
    version_condition(w, env, analysis.version, commented, indent)?;
    not_version_condition(w, analysis.not_version, commented, indent)?;
    doc_hidden(w, analysis.doc_hidden, comment_prefix, indent)?;
    writeln!(
        w,
        "{}{}{}{}{}",
        tabs(indent),
        comment_prefix,
        pub_prefix,
        declaration,
        suffix,
    )?;

    if !only_declaration {
        let body = body_chunk(env, analysis).to_code(env);
        for s in body {
            writeln!(w, "{}{}", tabs(indent), s)?;
        }
    }

    if analysis.async_future.is_some() {
        let declaration = declaration_futures(env, analysis);
        let suffix = if only_declaration { ";" } else { " {" };

        writeln!(w)?;
        if !in_trait || only_declaration {
            cfg_deprecated(w, env, analysis.deprecated_version, commented, indent)?;
        }

        writeln!(
            w,
            "{}{}#[cfg(feature = \"futures\")]",
            tabs(indent),
            comment_prefix
        )?;
        cfg_condition(w, &analysis.cfg_condition, commented, indent)?;
        version_condition(w, env, analysis.version, commented, indent)?;
        not_version_condition(w, analysis.not_version, commented, indent)?;
        doc_hidden(w, analysis.doc_hidden, comment_prefix, indent)?;
        writeln!(
            w,
            "{}{}{}{}{}",
            tabs(indent),
            comment_prefix,
            pub_prefix,
            declaration,
            suffix
        )?;

        if !only_declaration {
            let body = body_chunk_futures(env, analysis).unwrap();
            for s in body.lines() {
                if !s.is_empty() {
                    writeln!(w, "{}{}{}", tabs(indent + 1), comment_prefix, s)?;
                } else {
                    writeln!(w)?;
                }
            }
            writeln!(w, "{}{}}}", tabs(indent), comment_prefix)?;
        }
    }

    Ok(())
}

pub fn declaration(env: &Env, analysis: &analysis::functions::Info) -> String {
    let outs_as_return = !analysis.outs.is_empty();
    let return_str = if outs_as_return {
        out_parameters_as_return(env, analysis)
    } else if analysis.ret.bool_return_is_error.is_some() {
        if env.namespaces.glib_ns_id == namespaces::MAIN {
            " -> Result<(), error::BoolError>".into()
        } else {
            " -> Result<(), glib::error::BoolError>".into()
        }
    } else {
        analysis.ret.to_return_value(env, false)
    };
    let mut param_str = String::with_capacity(100);

    let (bounds, _) = bounds(&analysis.bounds, &[], false, false);

    for par in analysis.parameters.rust_parameters.iter() {
        if !param_str.is_empty() {
            param_str.push_str(", ")
        }
        let c_par = &analysis.parameters.c_parameters[par.ind_c];
        let s = c_par.to_parameter(env, &analysis.bounds);
        param_str.push_str(&s);
    }

    format!(
        "fn {}{}({}){}",
        analysis.name, bounds, param_str, return_str,
    )
}

pub fn declaration_futures(env: &Env, analysis: &analysis::functions::Info) -> String {
    let async_future = analysis.async_future.as_ref().unwrap();

    let return_str = format!(
        " -> Box_<future::Future<Output = Result<{}, {}>> + std::marker::Unpin>",
        async_future.success_parameters, async_future.error_parameters
    );

    let mut param_str = String::with_capacity(100);

    let mut skipped = 0;
    let mut skipped_bounds = vec![];
    for (pos, par) in analysis.parameters.rust_parameters.iter().enumerate() {
        let c_par = &analysis.parameters.c_parameters[par.ind_c];

        if c_par.name == "callback" || c_par.name == "cancellable" {
            skipped += 1;
            if let Some((t, _)) = analysis.bounds.get_parameter_alias_info(&c_par.name) {
                skipped_bounds.push(t);
                if let Some(p) = analysis.bounds.get_base_alias(t) {
                    skipped_bounds.push(p);
                }
            }
            continue;
        }

        if pos - skipped > 0 {
            param_str.push_str(", ")
        }

        let s = c_par.to_parameter(env, &analysis.bounds);
        param_str.push_str(&s);
    }

    let (bounds, _) = bounds(&analysis.bounds, skipped_bounds.as_ref(), true, false);

    format!(
        "fn {}{}({}){}",
        async_future.name, bounds, param_str, return_str,
    )
}

pub fn bound_to_string(bound: &Bound, r#async: bool) -> String {
    use crate::analysis::bounds::BoundType::*;

    match bound.bound_type {
        NoWrapper => format!("{}: {}", bound.alias, bound.type_str),
        IsA(Some(lifetime)) => format!(
            "{}: IsA<{}> + {}",
            bound.alias,
            bound.type_str,
            if r#async {
                "Clone + 'static".into()
            } else {
                format!("'{}", lifetime)
            }
        ),
        IsA(None) => format!(
            "{}: IsA<{}>{}",
            bound.alias,
            bound.type_str,
            if r#async { " + Clone + 'static" } else { "" }
        ),
        // This case should normally never happened
        AsRef(Some(_ /*lifetime*/)) => {
            unreachable!();
            // format!("{}: AsRef<{}> + '{}", bound.alias, bound.type_str, lifetime)
        }
        AsRef(None) => format!("{}: AsRef<{}>", bound.alias, bound.type_str),
    }
}

pub fn bounds(
    bounds: &Bounds,
    skip: &[char],
    r#async: bool,
    filter_callback_modified: bool,
) -> (String, Vec<String>) {
    use crate::analysis::bounds::BoundType::*;

    if bounds.is_empty() {
        return (String::new(), Vec::new());
    }

    let skip_lifetimes = bounds
        .iter()
        .filter(|bound| skip.contains(&bound.alias))
        .filter_map(|bound| match bound.bound_type {
            IsA(Some(lifetime)) | AsRef(Some(lifetime)) => Some(lifetime),
            _ => None,
        })
        .collect::<Vec<_>>();

    let strs: Vec<String> = bounds
        .iter_lifetimes()
        .filter(|s| !skip_lifetimes.contains(s))
        .map(|s| format!("'{}", s))
        .chain(
            bounds
                .iter()
                .filter(|bound| {
                    !skip.contains(&bound.alias)
                        && (!filter_callback_modified || !bound.callback_modified)
                })
                .map(|b| bound_to_string(b, r#async)),
        )
        .collect();

    if strs.is_empty() {
        (String::new(), Vec::new())
    } else {
        let bounds = bounds
            .iter_lifetimes()
            .filter(|s| !skip_lifetimes.contains(s))
            .map(|s| format!("'{}", s))
            .chain(
                bounds
                    .iter()
                    .filter(|bound| {
                        !skip.contains(&bound.alias)
                            && (!filter_callback_modified || !bound.callback_modified)
                    })
                    .map(|b| b.alias.to_string()),
            )
            .collect::<Vec<_>>();
        (format!("<{}>", strs.join(", ")), bounds)
    }
}

pub fn body_chunk(env: &Env, analysis: &analysis::functions::Info) -> Chunk {
    if analysis.visibility == Visibility::Comment {
        return ffi_function_todo(env, &analysis.glib_name);
    }

    let outs_as_return = !analysis.outs.is_empty();

    let mut builder = function_body_chunk::Builder::new();
    builder
        .glib_name(&format!(
            "{}::{}",
            env.main_sys_crate_name(),
            analysis.glib_name
        ))
        .assertion(analysis.assertion)
        .ret(&analysis.ret)
        .transformations(&analysis.parameters.transformations)
        .outs_mode(analysis.outs.mode);

    if analysis.r#async {
        if let Some(ref trampoline) = analysis.trampoline {
            builder.async_trampoline(trampoline);
        } else {
            warn!(
                "Async function {} has no associated _finish function",
                analysis.name
            );
        }
    } else {
        for trampoline in analysis.callbacks.iter() {
            builder.callback(trampoline);
        }
        for trampoline in analysis.destroys.iter() {
            builder.destroy(trampoline);
        }
    }

    for par in &analysis.parameters.c_parameters {
        if outs_as_return && analysis.outs.iter().any(|p| p.name == par.name) {
            builder.out_parameter(env, par);
        } else {
            builder.parameter();
        }
    }

    let (bounds, bounds_names) = bounds(&analysis.bounds, &[], false, true);

    builder.generate(env, bounds, bounds_names.join(", "))
}

pub fn body_chunk_futures(
    env: &Env,
    analysis: &analysis::functions::Info,
) -> StdResult<String, fmt::Error> {
    use crate::analysis::ref_mode::RefMode;
    use std::fmt::Write;

    let async_future = analysis.async_future.as_ref().unwrap();

    let mut body = String::new();

    if env.config.library_name != "Gio" {
        writeln!(body, "use gio::GioFuture;")?;
    } else {
        writeln!(body, "use GioFuture;")?;
    }
    writeln!(body, "use fragile::Fragile;")?;
    writeln!(body)?;

    let skip = if async_future.is_method { 1 } else { 0 };

    // Skip the instance parameter
    for par in analysis.parameters.rust_parameters.iter().skip(skip) {
        if par.name == "cancellable" || par.name == "callback" {
            continue;
        }

        let c_par = &analysis.parameters.c_parameters[par.ind_c];

        let type_ = env.type_(par.typ);
        let is_str = if let library::Type::Fundamental(library::Fundamental::Utf8) = *type_ {
            true
        } else {
            false
        };

        if *c_par.nullable {
            writeln!(
                body,
                "let {} = {}.map(ToOwned::to_owned);",
                par.name, par.name
            )?;
        } else if is_str {
            writeln!(body, "let {} = String::from({});", par.name, par.name)?;
        } else if c_par.ref_mode != RefMode::None {
            writeln!(body, "let {} = {}.clone();", par.name, par.name)?;
        }
    }

    if async_future.is_method {
        writeln!(body, "GioFuture::new(self, move |obj, send| {{")?;
    } else {
        writeln!(body, "GioFuture::new(&(), move |_obj, send| {{")?;
    }

    if env.config.library_name != "Gio" {
        writeln!(body, "\tlet cancellable = gio::Cancellable::new();")?;
    } else {
        writeln!(body, "\tlet cancellable = Cancellable::new();")?;
    }
    writeln!(body, "\tlet send = Fragile::new(send);")?;

    if async_future.is_method {
        writeln!(body, "\tobj.{}(", analysis.name)?;
    } else if analysis.type_name.is_ok() {
        writeln!(body, "\tSelf::{}(", analysis.name)?;
    } else {
        writeln!(body, "\t{}(", analysis.name)?;
    }

    // Skip the instance parameter
    for par in analysis.parameters.rust_parameters.iter().skip(skip) {
        if par.name == "cancellable" {
            writeln!(body, "\t\tSome(&cancellable),")?;
        } else if par.name == "callback" {
            continue;
        } else {
            let c_par = &analysis.parameters.c_parameters[par.ind_c];

            if *c_par.nullable {
                writeln!(
                    body,
                    "\t\t{}.as_ref().map(::std::borrow::Borrow::borrow),",
                    par.name
                )?;
            } else if c_par.ref_mode != RefMode::None {
                writeln!(body, "\t\t&{},", par.name)?;
            } else {
                writeln!(body, "\t\t{},", par.name)?;
            }
        }
    }

    writeln!(body, "\t\tmove |res| {{")?;
    writeln!(body, "\t\t\tlet _ = send.into_inner().send(res);")?;
    writeln!(body, "\t\t}},")?;
    writeln!(body, "\t);")?;
    writeln!(body)?;
    writeln!(body, "\tcancellable")?;
    writeln!(body, "}})")?;

    Ok(body)
}
<commit_msg>Fix trait object warning for futures<commit_after>use super::{
    function_body_chunk,
    general::{
        cfg_condition, cfg_deprecated, doc_hidden, not_version_condition, version_condition,
    },
    parameter::ToParameter,
    return_value::{out_parameters_as_return, ToReturnValue},
};
use crate::{
    analysis::{
        self,
        bounds::{Bound, Bounds},
        functions::Visibility,
        namespaces,
    },
    chunk::{ffi_function_todo, Chunk},
    env::Env,
    library,
    writer::{primitives::tabs, ToCode},
};
use log::warn;
use std::{
    fmt,
    io::{Result, Write},
    result::Result as StdResult,
};

pub fn generate(
    w: &mut dyn Write,
    env: &Env,
    analysis: &analysis::functions::Info,
    in_trait: bool,
    only_declaration: bool,
    indent: usize,
) -> Result<()> {
    if analysis.is_async_finish(env) {
        return Ok(());
    }

    let mut commented = false;
    let mut comment_prefix = "";
    let mut pub_prefix = if in_trait { "" } else { "pub " };

    match analysis.visibility {
        Visibility::Public => {}
        Visibility::Comment => {
            commented = true;
            comment_prefix = "//";
        }
        Visibility::Private => {
            if in_trait {
                warn!(
                    "Generating trait method for private function {}",
                    analysis.glib_name
                );
            } else {
                pub_prefix = "";
            }
        }
        Visibility::Hidden => return Ok(()),
    }
    let declaration = declaration(env, analysis);
    let suffix = if only_declaration { ";" } else { " {" };

    writeln!(w)?;
    if !in_trait || only_declaration {
        cfg_deprecated(w, env, analysis.deprecated_version, commented, indent)?;
    }
    cfg_condition(w, &analysis.cfg_condition, commented, indent)?;
    version_condition(w, env, analysis.version, commented, indent)?;
    not_version_condition(w, analysis.not_version, commented, indent)?;
    doc_hidden(w, analysis.doc_hidden, comment_prefix, indent)?;
    writeln!(
        w,
        "{}{}{}{}{}",
        tabs(indent),
        comment_prefix,
        pub_prefix,
        declaration,
        suffix,
    )?;

    if !only_declaration {
        let body = body_chunk(env, analysis).to_code(env);
        for s in body {
            writeln!(w, "{}{}", tabs(indent), s)?;
        }
    }

    if analysis.async_future.is_some() {
        let declaration = declaration_futures(env, analysis);
        let suffix = if only_declaration { ";" } else { " {" };

        writeln!(w)?;
        if !in_trait || only_declaration {
            cfg_deprecated(w, env, analysis.deprecated_version, commented, indent)?;
        }

        writeln!(
            w,
            "{}{}#[cfg(feature = \"futures\")]",
            tabs(indent),
            comment_prefix
        )?;
        cfg_condition(w, &analysis.cfg_condition, commented, indent)?;
        version_condition(w, env, analysis.version, commented, indent)?;
        not_version_condition(w, analysis.not_version, commented, indent)?;
        doc_hidden(w, analysis.doc_hidden, comment_prefix, indent)?;
        writeln!(
            w,
            "{}{}{}{}{}",
            tabs(indent),
            comment_prefix,
            pub_prefix,
            declaration,
            suffix
        )?;

        if !only_declaration {
            let body = body_chunk_futures(env, analysis).unwrap();
            for s in body.lines() {
                if !s.is_empty() {
                    writeln!(w, "{}{}{}", tabs(indent + 1), comment_prefix, s)?;
                } else {
                    writeln!(w)?;
                }
            }
            writeln!(w, "{}{}}}", tabs(indent), comment_prefix)?;
        }
    }

    Ok(())
}

pub fn declaration(env: &Env, analysis: &analysis::functions::Info) -> String {
    let outs_as_return = !analysis.outs.is_empty();
    let return_str = if outs_as_return {
        out_parameters_as_return(env, analysis)
    } else if analysis.ret.bool_return_is_error.is_some() {
        if env.namespaces.glib_ns_id == namespaces::MAIN {
            " -> Result<(), error::BoolError>".into()
        } else {
            " -> Result<(), glib::error::BoolError>".into()
        }
    } else {
        analysis.ret.to_return_value(env, false)
    };
    let mut param_str = String::with_capacity(100);

    let (bounds, _) = bounds(&analysis.bounds, &[], false, false);

    for par in analysis.parameters.rust_parameters.iter() {
        if !param_str.is_empty() {
            param_str.push_str(", ")
        }
        let c_par = &analysis.parameters.c_parameters[par.ind_c];
        let s = c_par.to_parameter(env, &analysis.bounds);
        param_str.push_str(&s);
    }

    format!(
        "fn {}{}({}){}",
        analysis.name, bounds, param_str, return_str,
    )
}

pub fn declaration_futures(env: &Env, analysis: &analysis::functions::Info) -> String {
    let async_future = analysis.async_future.as_ref().unwrap();

    let return_str = format!(
        " -> Box_<dyn future::Future<Output = Result<{}, {}>> + std::marker::Unpin>",
        async_future.success_parameters, async_future.error_parameters
    );

    let mut param_str = String::with_capacity(100);

    let mut skipped = 0;
    let mut skipped_bounds = vec![];
    for (pos, par) in analysis.parameters.rust_parameters.iter().enumerate() {
        let c_par = &analysis.parameters.c_parameters[par.ind_c];

        if c_par.name == "callback" || c_par.name == "cancellable" {
            skipped += 1;
            if let Some((t, _)) = analysis.bounds.get_parameter_alias_info(&c_par.name) {
                skipped_bounds.push(t);
                if let Some(p) = analysis.bounds.get_base_alias(t) {
                    skipped_bounds.push(p);
                }
            }
            continue;
        }

        if pos - skipped > 0 {
            param_str.push_str(", ")
        }

        let s = c_par.to_parameter(env, &analysis.bounds);
        param_str.push_str(&s);
    }

    let (bounds, _) = bounds(&analysis.bounds, skipped_bounds.as_ref(), true, false);

    format!(
        "fn {}{}({}){}",
        async_future.name, bounds, param_str, return_str,
    )
}

pub fn bound_to_string(bound: &Bound, r#async: bool) -> String {
    use crate::analysis::bounds::BoundType::*;

    match bound.bound_type {
        NoWrapper => format!("{}: {}", bound.alias, bound.type_str),
        IsA(Some(lifetime)) => format!(
            "{}: IsA<{}> + {}",
            bound.alias,
            bound.type_str,
            if r#async {
                "Clone + 'static".into()
            } else {
                format!("'{}", lifetime)
            }
        ),
        IsA(None) => format!(
            "{}: IsA<{}>{}",
            bound.alias,
            bound.type_str,
            if r#async { " + Clone + 'static" } else { "" }
        ),
        // This case should normally never happened
        AsRef(Some(_ /*lifetime*/)) => {
            unreachable!();
            // format!("{}: AsRef<{}> + '{}", bound.alias, bound.type_str, lifetime)
        }
        AsRef(None) => format!("{}: AsRef<{}>", bound.alias, bound.type_str),
    }
}

pub fn bounds(
    bounds: &Bounds,
    skip: &[char],
    r#async: bool,
    filter_callback_modified: bool,
) -> (String, Vec<String>) {
    use crate::analysis::bounds::BoundType::*;

    if bounds.is_empty() {
        return (String::new(), Vec::new());
    }

    let skip_lifetimes = bounds
        .iter()
        .filter(|bound| skip.contains(&bound.alias))
        .filter_map(|bound| match bound.bound_type {
            IsA(Some(lifetime)) | AsRef(Some(lifetime)) => Some(lifetime),
            _ => None,
        })
        .collect::<Vec<_>>();

    let strs: Vec<String> = bounds
        .iter_lifetimes()
        .filter(|s| !skip_lifetimes.contains(s))
        .map(|s| format!("'{}", s))
        .chain(
            bounds
                .iter()
                .filter(|bound| {
                    !skip.contains(&bound.alias)
                        && (!filter_callback_modified || !bound.callback_modified)
                })
                .map(|b| bound_to_string(b, r#async)),
        )
        .collect();

    if strs.is_empty() {
        (String::new(), Vec::new())
    } else {
        let bounds = bounds
            .iter_lifetimes()
            .filter(|s| !skip_lifetimes.contains(s))
            .map(|s| format!("'{}", s))
            .chain(
                bounds
                    .iter()
                    .filter(|bound| {
                        !skip.contains(&bound.alias)
                            && (!filter_callback_modified || !bound.callback_modified)
                    })
                    .map(|b| b.alias.to_string()),
            )
            .collect::<Vec<_>>();
        (format!("<{}>", strs.join(", ")), bounds)
    }
}

pub fn body_chunk(env: &Env, analysis: &analysis::functions::Info) -> Chunk {
    if analysis.visibility == Visibility::Comment {
        return ffi_function_todo(env, &analysis.glib_name);
    }

    let outs_as_return = !analysis.outs.is_empty();

    let mut builder = function_body_chunk::Builder::new();
    builder
        .glib_name(&format!(
            "{}::{}",
            env.main_sys_crate_name(),
            analysis.glib_name
        ))
        .assertion(analysis.assertion)
        .ret(&analysis.ret)
        .transformations(&analysis.parameters.transformations)
        .outs_mode(analysis.outs.mode);

    if analysis.r#async {
        if let Some(ref trampoline) = analysis.trampoline {
            builder.async_trampoline(trampoline);
        } else {
            warn!(
                "Async function {} has no associated _finish function",
                analysis.name
            );
        }
    } else {
        for trampoline in analysis.callbacks.iter() {
            builder.callback(trampoline);
        }
        for trampoline in analysis.destroys.iter() {
            builder.destroy(trampoline);
        }
    }

    for par in &analysis.parameters.c_parameters {
        if outs_as_return && analysis.outs.iter().any(|p| p.name == par.name) {
            builder.out_parameter(env, par);
        } else {
            builder.parameter();
        }
    }

    let (bounds, bounds_names) = bounds(&analysis.bounds, &[], false, true);

    builder.generate(env, bounds, bounds_names.join(", "))
}

pub fn body_chunk_futures(
    env: &Env,
    analysis: &analysis::functions::Info,
) -> StdResult<String, fmt::Error> {
    use crate::analysis::ref_mode::RefMode;
    use std::fmt::Write;

    let async_future = analysis.async_future.as_ref().unwrap();

    let mut body = String::new();

    if env.config.library_name != "Gio" {
        writeln!(body, "use gio::GioFuture;")?;
    } else {
        writeln!(body, "use GioFuture;")?;
    }
    writeln!(body, "use fragile::Fragile;")?;
    writeln!(body)?;

    let skip = if async_future.is_method { 1 } else { 0 };

    // Skip the instance parameter
    for par in analysis.parameters.rust_parameters.iter().skip(skip) {
        if par.name == "cancellable" || par.name == "callback" {
            continue;
        }

        let c_par = &analysis.parameters.c_parameters[par.ind_c];

        let type_ = env.type_(par.typ);
        let is_str = if let library::Type::Fundamental(library::Fundamental::Utf8) = *type_ {
            true
        } else {
            false
        };

        if *c_par.nullable {
            writeln!(
                body,
                "let {} = {}.map(ToOwned::to_owned);",
                par.name, par.name
            )?;
        } else if is_str {
            writeln!(body, "let {} = String::from({});", par.name, par.name)?;
        } else if c_par.ref_mode != RefMode::None {
            writeln!(body, "let {} = {}.clone();", par.name, par.name)?;
        }
    }

    if async_future.is_method {
        writeln!(body, "GioFuture::new(self, move |obj, send| {{")?;
    } else {
        writeln!(body, "GioFuture::new(&(), move |_obj, send| {{")?;
    }

    if env.config.library_name != "Gio" {
        writeln!(body, "\tlet cancellable = gio::Cancellable::new();")?;
    } else {
        writeln!(body, "\tlet cancellable = Cancellable::new();")?;
    }
    writeln!(body, "\tlet send = Fragile::new(send);")?;

    if async_future.is_method {
        writeln!(body, "\tobj.{}(", analysis.name)?;
    } else if analysis.type_name.is_ok() {
        writeln!(body, "\tSelf::{}(", analysis.name)?;
    } else {
        writeln!(body, "\t{}(", analysis.name)?;
    }

    // Skip the instance parameter
    for par in analysis.parameters.rust_parameters.iter().skip(skip) {
        if par.name == "cancellable" {
            writeln!(body, "\t\tSome(&cancellable),")?;
        } else if par.name == "callback" {
            continue;
        } else {
            let c_par = &analysis.parameters.c_parameters[par.ind_c];

            if *c_par.nullable {
                writeln!(
                    body,
                    "\t\t{}.as_ref().map(::std::borrow::Borrow::borrow),",
                    par.name
                )?;
            } else if c_par.ref_mode != RefMode::None {
                writeln!(body, "\t\t&{},", par.name)?;
            } else {
                writeln!(body, "\t\t{},", par.name)?;
            }
        }
    }

    writeln!(body, "\t\tmove |res| {{")?;
    writeln!(body, "\t\t\tlet _ = send.into_inner().send(res);")?;
    writeln!(body, "\t\t}},")?;
    writeln!(body, "\t);")?;
    writeln!(body)?;
    writeln!(body, "\tcancellable")?;
    writeln!(body, "}})")?;

    Ok(body)
}
<|endoftext|>


<commit_before>use std::iter::Peekable;

use ::Data;
use collection::{close_under_lub, LeastUpperBound, Lookup};
use collection::compact::Compact;

use iterators::merge::{Merge, MergeIterator};
use iterators::coalesce::{Coalesce, CoalesceIterator};

// Test implementation which uses references rather than clones

pub trait Traceable where for<'a> &'a Self: TraceRef<'a, Self::Key, Self::Index, Self::Value> {

    type Key: Data+Ord+'static;
    type Index: LeastUpperBound+'static;
    type Value: Data+Ord+'static;

    // type PartKey: Unsigned;    // the keys are partitioned and likely ordered by this unsigned integer

    // // indicates the part for a key
    // fn part(&self, key: &Self::Key) -> Self::PartKey;

    // TODO : Should probably allow the trace to determine how it receives data.
    // TODO : Radix sorting and such might live in the trace, rather than in `Arrange`.
    /// Introduces differences in `accumulation` at `time`.
    fn set_difference(&mut self, time: Self::Index, accumulation: Compact<Self::Key, Self::Value>);

    /// Method whose only role is to provide the lifetime to the `Trace` trait.
    fn trace<'a>(&'a self, key: &Self::Key) -> <&'a Self as TraceRef<'a,Self::Key,Self::Index,Self::Value>>::TIterator {
        TraceRef::<'a,Self::Key,Self::Index,Self::Value>::trace(self, key)
    }

    /// Enumerates updates for a specified key and time.
    fn get_difference<'a>(&'a self, key: &Self::Key, time: &Self::Index)
        -> Option<<&'a Self as TraceRef<'a,Self::Key,Self::Index,Self::Value>>::VIterator> {
        self.trace(key)
            .filter(|x| x.0 == time)
            .map(|x| x.1)
            .next()
    }

    /// Accumulates differences for `key` at times less than or equal to `time`.
    ///
    /// The `&mut self` argument allows the trace to use stashed storage for a merge.
    fn get_collection<'a>(&'a mut self, key: &Self::Key, time: &Self::Index)
        -> CollectionIterator<<&'a Self as TraceRef<'a,Self::Key,Self::Index,Self::Value>>::VIterator> {
        self.trace(key)
            .into_iter()
            .filter(|x| x.0 <= time)
            .map(|x| x.1)
            .merge()
            .coalesce()
            .peekable()
    }

    // TODO : Make sure the right assumptions are made about contents of stash.
    fn interesting_times<'a>(&'a self, key: &Self::Key, time: &Self::Index, stash: &mut Vec<Self::Index>) {
        // add all times, but filter a bit if possible
        for iter in self.trace(key) {
            let lub = iter.0.least_upper_bound(time);
            if !stash.contains(&lub) {
                stash.push(lub);
            }
        }
        close_under_lub(stash);
    }
}

pub trait TraceRef<'a,K,T:'a,V:'a> {
    type VIterator: Iterator<Item=(&'a V, i32)>+'a;
    type TIterator: Iterator<Item=(&'a T, Self::VIterator)>+'a;
    fn trace(self, key: &K) -> Self::TIterator;
}

pub type CollectionIterator<VIterator> = Peekable<CoalesceIterator<MergeIterator<VIterator>>>;

impl<K,V,L,T> Traceable for Trace<K, T, V, L> where K: Data+Ord+'static, V: Data+Ord+'static, L: Lookup<K, Offset>+'static, T: LeastUpperBound+'static {
    type Key = K;
    type Index = T;
    type Value = V;

    fn set_difference(&mut self, time: T, accumulation: Compact<K, V>) {

        // extract the relevant fields
        let keys = accumulation.keys;
        let cnts = accumulation.cnts;
        let vals = accumulation.vals;

        // index of the self.times entry we are about to insert
        let time_index = self.times.len();

        // counters for offsets in vals and wgts
        let mut vals_offset = 0;

        self.links.reserve(keys.len());

        // for each key and count ...
        for (key, cnt) in keys.into_iter().zip(cnts.into_iter()) {

            // prepare a new head cursor, and recover whatever is currently there.
            let next_position = Offset::new(self.links.len());
            let prev_position = self.keys.entry_or_insert(key, || next_position);

            // if we inserted a previously absent key
            if &prev_position.val() == &next_position.val() {
                // add the appropriate entry with no next pointer
                self.links.push(ListEntry {
                    time: time_index as u32,
                    vals: vals_offset,
                    next: None
                });
            }
            // we haven't yet installed next_position, so do that too
            else {
                // add the appropriate entry
                self.links.push(ListEntry {
                    time: time_index as u32,
                    vals: vals_offset,
                    next: Some(*prev_position)
                });
                *prev_position = next_position;
            }

            // advance offsets.
            vals_offset += cnt;
        }

        // add the values and weights to the list of timed differences.
        self.times.push(TimeEntry { time: time, vals: vals });
    }
}

impl<'a,K,V,L,T> TraceRef<'a,K,T,V> for &'a Trace<K,T,V,L> where K: Data+Ord+'a, V: Data+Ord+'a, L: Lookup<K, Offset>+'a, T: LeastUpperBound+'a {
    type VIterator = DifferenceIterator<'a, V>;
    type TIterator = TraceIterator<'a,K,T,V,L>;
    fn trace(self, key: &K) -> Self::TIterator {
        TraceIterator {
            trace: self,
            next0: self.keys.get_ref(key).map(|&x|x),
        }
    }
}

/// Enumerates the elements of a collection for a given key at a given time.
///
/// A collection iterator is only provided for non-empty sets, so one can call `peek.unwrap()` on
/// the iterator without worrying about panicing.
// pub type CollectionIterator<'a, V> = Peekable<CoalesceIterator<MergeUsingIterator<'a, DifferenceIterator<'a, V>>>>;

#[derive(Copy, Clone, Debug)]
pub struct Offset {
    dataz: u32,
}

impl Offset {
    #[inline(always)]
    fn new(offset: usize) -> Offset {
        assert!(offset < ((!0u32) as usize)); // note strict inequality
        Offset { dataz: (!0u32) - offset as u32 }
    }
    #[inline(always)]
    fn val(&self) -> usize { ((!0u32) - self.dataz) as usize }
}

/// A map from keys to time-indexed collection differences.
///
/// A `Trace` is morally equivalent to a `Map<K, Vec<(T, Vec<(V,i32)>)>`.
/// It uses an implementor `L` of the `Lookup<K, Offset>` trait to map keys to an `Offset`, a
/// position in member `self.links` of the head of the linked list for the key.
///
/// The entries in `self.links` form a linked list, where each element contains an index into
/// `self.times` indicating a time, and an offset in the associated vector in `self.times[index]`.
/// Finally, the `self.links` entry contains an optional `Offset` to the next element in the list.
/// Entries are added to `self.links` sequentially, so that one can determine not only where some
/// differences begin, but also where they end, by looking at the next entry in `self.lists`.
///
/// Elements of `self.times` correspond to distinct logical times, and the full set of differences
/// received at each.

struct ListEntry {
    time: u32,
    vals: u32,
    next: Option<Offset>,
}

struct TimeEntry<T, V> {
    time: T,
    vals: Vec<(V, i32)>,
}

/// A collection of values indexed by `key` and `time`.
pub struct Trace<K, T, V, L> {
    phantom:    ::std::marker::PhantomData<K>,
    links:      Vec<ListEntry>,
    times:      Vec<TimeEntry<T, V>>,
    pub keys:       L,
}

impl<K, V, L, T> Trace<K, T, V, L> where K: Ord, V: Ord, L: Lookup<K, Offset>, T: LeastUpperBound {
    #[inline]
    fn get_range<'a>(&'a self, position: Offset) -> DifferenceIterator<'a, V> {

        let time = self.links[position.val()].time as usize;
        let vals_lower = self.links[position.val()].vals as usize;

        // upper limit can be read if next link exists and of the same index. else, is last elt.
        let vals_upper = if (position.val() + 1) < self.links.len()
                                        && time == self.links[position.val() + 1].time as usize {

            self.links[position.val() + 1].vals as usize
        }
        else {
            self.times[time].vals.len()
        };

        DifferenceIterator::new(&self.times[time].vals[vals_lower..vals_upper])
    }
}

impl<K: Eq, L: Lookup<K, Offset>, T, V> Trace<K, T, V, L> {
    pub fn new(l: L) -> Trace<K, T, V, L> {
        // println!("allocating trace");
        Trace {
            phantom: ::std::marker::PhantomData,
            links:   Vec::new(),
            times:   Vec::new(),
            keys:    l,
        }
    }
}

/// Enumerates pairs of time `&T` and `DifferenceIterator<V>` of `(&V, i32)` elements.
#[derive(Clone)]
pub struct TraceIterator<'a, K: Eq+'a, T: 'a, V: 'a, L: Lookup<K, Offset>+'a> {
    trace: &'a Trace<K, T, V, L>,
    next0: Option<Offset>,
}

impl<'a, K, T, V, L> Iterator for TraceIterator<'a, K, T, V, L>
where K:  Ord+'a,
      T: LeastUpperBound+'a,
      V: Ord+'a,
      L: Lookup<K, Offset>+'a {
    type Item = (&'a T, DifferenceIterator<'a, V>);

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.next0.map(|position| {
            let time_index = self.trace.links[position.val()].time as usize;
            let result = (&self.trace.times[time_index].time, self.trace.get_range(position));
            self.next0 = self.trace.links[position.val()].next;
            result
        })
    }
}

/// Enumerates `(&V,i32)` elements of a difference.
pub struct DifferenceIterator<'a, V: 'a> {
    vals: &'a [(V,i32)],
    next: usize,            // index of next entry in vals,
}

impl<'a, V: 'a> DifferenceIterator<'a, V> {
    fn new(vals: &'a [(V, i32)]) -> DifferenceIterator<'a, V> {
        DifferenceIterator {
            vals: vals,
            next: 0,
        }
    }
}

impl<'a, V: 'a> Clone for DifferenceIterator<'a, V> {
    fn clone(&self) -> Self {
        DifferenceIterator {
            vals: self.vals,
            next: self.next,
        }
    }
}

impl<'a, V: 'a> Iterator for DifferenceIterator<'a, V> {
    type Item = (&'a V, i32);

    #[inline]
    fn next(&mut self) -> Option<(&'a V, i32)> {
        if self.next < self.vals.len() {
            self.next += 1;
            Some((&self.vals[self.next - 1].0, self.vals[self.next - 1].1))
        }
        else {
            None
        }
    }
}
<commit_msg>about to break things<commit_after>use std::iter::Peekable;

use ::Data;
use collection::{close_under_lub, LeastUpperBound, Lookup};
use collection::compact::Compact;

use iterators::merge::{Merge, MergeIterator};
use iterators::coalesce::{Coalesce, CoalesceIterator};

// TODO : Consider adding 'a parameter here; removing TraceRef.

pub trait Traceable where for<'a> &'a Self: TraceRef<'a, Self::Key, Self::Index, Self::Value> {

    type Key: Data+Ord+'static;
    type Index: LeastUpperBound+'static;
    type Value: Data+Ord+'static;

    // type PartKey: Unsigned;                              // the keys are partitioned and likely ordered by this unsigned integer
    // fn part(&self, key: &Self::Key) -> Self::PartKey;    // indicates the part for a key

    // TODO : Should probably allow the trace to determine how it receives data.
    // TODO : Radix sorting and such might live in the trace, rather than in `Arrange`.
    /// Introduces differences in `accumulation` at `time`.
    fn set_difference(&mut self, time: Self::Index, accumulation: Compact<Self::Key, Self::Value>);

    /// Method whose only role is to provide the lifetime to the `Trace` trait.
    fn trace<'a>(&'a self, key: &Self::Key) -> <&'a Self as TraceRef<'a,Self::Key,Self::Index,Self::Value>>::TIterator {
        TraceRef::<'a,Self::Key,Self::Index,Self::Value>::trace(self, key)
    }

    /// Enumerates updates for a specified key and time.
    fn get_difference<'a>(&'a self, key: &Self::Key, time: &Self::Index)
        -> Option<<&'a Self as TraceRef<'a,Self::Key,Self::Index,Self::Value>>::VIterator> {
        self.trace(key)
            .filter(|x| x.0 == time)
            .map(|x| x.1)
            .next()
    }

    /// Accumulates differences for `key` at times less than or equal to `time`.
    ///
    /// The `&mut self` argument allows the trace to use stashed storage for a merge.
    fn get_collection<'a>(&'a mut self, key: &Self::Key, time: &Self::Index)
        -> CollectionIterator<<&'a Self as TraceRef<'a,Self::Key,Self::Index,Self::Value>>::VIterator> {
        self.trace(key)
            .into_iter()
            .filter(|x| x.0 <= time)
            .map(|x| x.1)
            .merge()
            .coalesce()
            .peekable()
    }

    // TODO : Make sure the right assumptions are made about contents of stash.
    fn interesting_times<'a>(&'a self, key: &Self::Key, time: &Self::Index, stash: &mut Vec<Self::Index>) {
        // add all times, but filter a bit if possible
        for iter in self.trace(key) {
            let lub = iter.0.least_upper_bound(time);
            if !stash.contains(&lub) {
                stash.push(lub);
            }
        }
        close_under_lub(stash);
    }
}

pub trait TraceRef<'a,K,T:'a,V:'a> {
    type VIterator: Iterator<Item=(&'a V, i32)>+'a;
    type TIterator: Iterator<Item=(&'a T, Self::VIterator)>+'a;
    fn trace(self, key: &K) -> Self::TIterator;
}

pub type CollectionIterator<VIterator> = Peekable<CoalesceIterator<MergeIterator<VIterator>>>;

impl<K,V,L,T> Traceable for Trace<K, T, V, L> where K: Data+Ord+'static, V: Data+Ord+'static, L: Lookup<K, Offset>+'static, T: LeastUpperBound+'static {
    type Key = K;
    type Index = T;
    type Value = V;

    fn set_difference(&mut self, time: T, accumulation: Compact<K, V>) {

        // extract the relevant fields
        let keys = accumulation.keys;
        let cnts = accumulation.cnts;
        let vals = accumulation.vals;

        // index of the self.times entry we are about to insert
        let time_index = self.times.len();

        // counters for offsets in vals and wgts
        let mut vals_offset = 0;

        self.links.reserve(keys.len());

        // for each key and count ...
        for (key, cnt) in keys.into_iter().zip(cnts.into_iter()) {

            // prepare a new head cursor, and recover whatever is currently there.
            let next_position = Offset::new(self.links.len());
            let prev_position = self.keys.entry_or_insert(key, || next_position);

            // if we inserted a previously absent key
            if &prev_position.val() == &next_position.val() {
                // add the appropriate entry with no next pointer
                self.links.push(ListEntry {
                    time: time_index as u32,
                    vals: vals_offset,
                    next: None
                });
            }
            // we haven't yet installed next_position, so do that too
            else {
                // add the appropriate entry
                self.links.push(ListEntry {
                    time: time_index as u32,
                    vals: vals_offset,
                    next: Some(*prev_position)
                });
                *prev_position = next_position;
            }

            // advance offsets.
            vals_offset += cnt;
        }

        // add the values and weights to the list of timed differences.
        self.times.push(TimeEntry { time: time, vals: vals });
    }
}

impl<'a,K,V,L,T> TraceRef<'a,K,T,V> for &'a Trace<K,T,V,L> where K: Data+Ord+'a, V: Data+Ord+'a, L: Lookup<K, Offset>+'a, T: LeastUpperBound+'a {
    type VIterator = DifferenceIterator<'a, V>;
    type TIterator = TraceIterator<'a,K,T,V,L>;
    fn trace(self, key: &K) -> Self::TIterator {
        TraceIterator {
            trace: self,
            next0: self.keys.get_ref(key).map(|&x|x),
        }
    }
}

/// Enumerates the elements of a collection for a given key at a given time.
///
/// A collection iterator is only provided for non-empty sets, so one can call `peek.unwrap()` on
/// the iterator without worrying about panicing.
// pub type CollectionIterator<'a, V> = Peekable<CoalesceIterator<MergeUsingIterator<'a, DifferenceIterator<'a, V>>>>;

#[derive(Copy, Clone, Debug)]
pub struct Offset {
    dataz: u32,
}

impl Offset {
    #[inline(always)]
    fn new(offset: usize) -> Offset {
        assert!(offset < ((!0u32) as usize)); // note strict inequality
        Offset { dataz: (!0u32) - offset as u32 }
    }
    #[inline(always)]
    fn val(&self) -> usize { ((!0u32) - self.dataz) as usize }
}

/// A map from keys to time-indexed collection differences.
///
/// A `Trace` is morally equivalent to a `Map<K, Vec<(T, Vec<(V,i32)>)>`.
/// It uses an implementor `L` of the `Lookup<K, Offset>` trait to map keys to an `Offset`, a
/// position in member `self.links` of the head of the linked list for the key.
///
/// The entries in `self.links` form a linked list, where each element contains an index into
/// `self.times` indicating a time, and an offset in the associated vector in `self.times[index]`.
/// Finally, the `self.links` entry contains an optional `Offset` to the next element in the list.
/// Entries are added to `self.links` sequentially, so that one can determine not only where some
/// differences begin, but also where they end, by looking at the next entry in `self.lists`.
///
/// Elements of `self.times` correspond to distinct logical times, and the full set of differences
/// received at each.

struct ListEntry {
    time: u32,
    vals: u32,
    next: Option<Offset>,
}

struct TimeEntry<T, V> {
    time: T,
    vals: Vec<(V, i32)>,
}

/// A collection of values indexed by `key` and `time`.
pub struct Trace<K, T, V, L> {
    phantom:    ::std::marker::PhantomData<K>,
    links:      Vec<ListEntry>,
    times:      Vec<TimeEntry<T, V>>,
    pub keys:       L,
}

impl<K, V, L, T> Trace<K, T, V, L> where K: Ord, V: Ord, L: Lookup<K, Offset>, T: LeastUpperBound {
    #[inline]
    fn get_range<'a>(&'a self, position: Offset) -> DifferenceIterator<'a, V> {

        let time = self.links[position.val()].time as usize;
        let vals_lower = self.links[position.val()].vals as usize;

        // upper limit can be read if next link exists and of the same index. else, is last elt.
        let vals_upper = if (position.val() + 1) < self.links.len()
                                        && time == self.links[position.val() + 1].time as usize {

            self.links[position.val() + 1].vals as usize
        }
        else {
            self.times[time].vals.len()
        };

        DifferenceIterator::new(&self.times[time].vals[vals_lower..vals_upper])
    }
}

impl<K: Eq, L: Lookup<K, Offset>, T, V> Trace<K, T, V, L> {
    pub fn new(l: L) -> Trace<K, T, V, L> {
        // println!("allocating trace");
        Trace {
            phantom: ::std::marker::PhantomData,
            links:   Vec::new(),
            times:   Vec::new(),
            keys:    l,
        }
    }
}

/// Enumerates pairs of time `&T` and `DifferenceIterator<V>` of `(&V, i32)` elements.
#[derive(Clone)]
pub struct TraceIterator<'a, K: Eq+'a, T: 'a, V: 'a, L: Lookup<K, Offset>+'a> {
    trace: &'a Trace<K, T, V, L>,
    next0: Option<Offset>,
}

impl<'a, K, T, V, L> Iterator for TraceIterator<'a, K, T, V, L>
where K:  Ord+'a,
      T: LeastUpperBound+'a,
      V: Ord+'a,
      L: Lookup<K, Offset>+'a {
    type Item = (&'a T, DifferenceIterator<'a, V>);

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.next0.map(|position| {
            let time_index = self.trace.links[position.val()].time as usize;
            let result = (&self.trace.times[time_index].time, self.trace.get_range(position));
            self.next0 = self.trace.links[position.val()].next;
            result
        })
    }
}

/// Enumerates `(&V,i32)` elements of a difference.
///
/// Morally equivalent to a `&[(V,i32)]` slice iterator, except returns a `(&V,i32)` rather than a `&(V,i32)`.
/// This is important for consolidate and merge, though they could probably be changed.
pub struct DifferenceIterator<'a, V: 'a> {
    vals: &'a [(V,i32)],
    next: usize,            // index of next entry in vals,
}

impl<'a, V: 'a> DifferenceIterator<'a, V> {
    fn new(vals: &'a [(V, i32)]) -> DifferenceIterator<'a, V> {
        DifferenceIterator {
            vals: vals,
            next: 0,
        }
    }
}

impl<'a, V: 'a> Clone for DifferenceIterator<'a, V> {
    fn clone(&self) -> Self {
        DifferenceIterator {
            vals: self.vals,
            next: self.next,
        }
    }
}

impl<'a, V: 'a> Iterator for DifferenceIterator<'a, V> {
    type Item = (&'a V, i32);

    #[inline]
    fn next(&mut self) -> Option<(&'a V, i32)> {
        if self.next < self.vals.len() {
            self.next += 1;
            Some((&self.vals[self.next - 1].0, self.vals[self.next - 1].1))
        }
        else {
            None
        }
    }
}
<|endoftext|>


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

// Test that `?` macro Kleene operator can not be used when the `macro_at_most_once_rep` feature
// gate is not used.

macro_rules! m { ($(a)?) => {} }
//~^ ERROR Using the `?` macro Kleene operator for "at most one" repetition is unstable

fn main() {
    m!();
}
<commit_msg>Update feature gate test<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Test that `?` macro Kleene operator can not be used when the `macro_at_most_once_rep` feature
// gate is not used.

macro_rules! m { ($(a)?) => {} }
//~^ ERROR Using the `?` macro Kleene operator for "at most one" repetition is unstable (see issue #48075)

fn main() {
    m!();
}
<|endoftext|>


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

// run-pass
// This is meant to be a comprehensive test of invocations with/without
// trailing commas (or other, similar optionally-trailing separators).
// Every macro is accounted for, even those not tested in this file.
// (There will be a note indicating why).

// std and core are both tested because they may contain separate
// implementations for some macro_rules! macros as an implementation
// detail.

// ignore-pretty issue #37195

// compile-flags: --test -C debug_assertions=yes
// revisions: std core

#![cfg_attr(core, no_std)]

#![feature(concat_idents)]

#[cfg(std)] use std::fmt;
#[cfg(core)] use core::fmt;

#[test]
fn assert() {
    assert!(true);
    assert!(true,);
    assert!(true, "hello");
    assert!(true, "hello",);
    assert!(true, "hello {}", "world");
    assert!(true, "hello {}", "world",);
}

#[test]
fn assert_eq() {
    assert_eq!(1, 1);
    assert_eq!(1, 1,);
    assert_eq!(1, 1, "hello");
    assert_eq!(1, 1, "hello",);
    assert_eq!(1, 1, "hello {}", "world");
    assert_eq!(1, 1, "hello {}", "world",);
}

#[test]
fn assert_ne() {
    assert_ne!(1, 2);
    assert_ne!(1, 2,);
    assert_ne!(1, 2, "hello");
    assert_ne!(1, 2, "hello",);
    assert_ne!(1, 2, "hello {}", "world");
    assert_ne!(1, 2, "hello {}", "world",);
}

#[test]
fn cfg() {
    cfg!(pants);
    cfg!(pants,);
    cfg!(pants = "pants");
    cfg!(pants = "pants",);
    cfg!(all(pants));
    cfg!(all(pants),);
    cfg!(all(pants,));
    cfg!(all(pants,),);
}

#[test]
fn column() {
    column!();
}

// compile_error! is in a companion to this test in compile-fail

#[test]
fn concat() {
    concat!();
    concat!("hello");
    concat!("hello",);
    concat!("hello", " world");
    concat!("hello", " world",);
}

#[test]
fn concat_idents() {
    fn foo() {}
    fn foobar() {}

    concat_idents!(foo)();
    concat_idents!(foo,)();
    concat_idents!(foo, bar)();
    concat_idents!(foo, bar,)();
}

#[test]
fn debug_assert() {
    debug_assert!(true);
    debug_assert!(true, );
    debug_assert!(true, "hello");
    debug_assert!(true, "hello",);
    debug_assert!(true, "hello {}", "world");
    debug_assert!(true, "hello {}", "world",);
}

#[test]
fn debug_assert_eq() {
    debug_assert_eq!(1, 1);
    debug_assert_eq!(1, 1,);
    debug_assert_eq!(1, 1, "hello");
    debug_assert_eq!(1, 1, "hello",);
    debug_assert_eq!(1, 1, "hello {}", "world");
    debug_assert_eq!(1, 1, "hello {}", "world",);
}

#[test]
fn debug_assert_ne() {
    debug_assert_ne!(1, 2);
    debug_assert_ne!(1, 2,);
    debug_assert_ne!(1, 2, "hello");
    debug_assert_ne!(1, 2, "hello",);
    debug_assert_ne!(1, 2, "hello {}", "world");
    debug_assert_ne!(1, 2, "hello {}", "world",);
}

#[test]
fn env() {
    env!("PATH");
    env!("PATH",);
    env!("PATH", "not found");
    env!("PATH", "not found",);
}

#[cfg(std)]
#[test]
fn eprint() {
    eprint!("hello");
    eprint!("hello",);
    eprint!("hello {}", "world");
    eprint!("hello {}", "world",);
}

#[cfg(std)]
#[test]
fn eprintln() {
    eprintln!();
    eprintln!("hello");
    eprintln!("hello",);
    eprintln!("hello {}", "world");
    eprintln!("hello {}", "world",);
}

#[test]
fn file() {
    file!();
}

#[cfg(std)]
#[test]
fn format() {
    format!("hello");
    format!("hello",);
    format!("hello {}", "world");
    format!("hello {}", "world",);
}

#[test]
fn format_args() {
    format_args!("hello");
    format_args!("hello",);
    format_args!("hello {}", "world");
    format_args!("hello {}", "world",);
}

#[test]
fn include() {
    include!("auxiliary/macro-comma-support.rs");
    include!("auxiliary/macro-comma-support.rs",);
}

#[test]
fn include_bytes() {
    include_bytes!("auxiliary/macro-comma-support.rs");
    include_bytes!("auxiliary/macro-comma-support.rs",);
}

#[test]
fn include_str() {
    include_str!("auxiliary/macro-comma-support.rs");
    include_str!("auxiliary/macro-comma-support.rs",);
}

#[test]
fn line() {
    line!();
}

#[test]
fn module_path() {
    module_path!();
}

#[test]
fn option_env() {
    option_env!("PATH");
    option_env!("PATH",);
}

#[test]
fn panic() {
    // prevent 'unreachable code' warnings
    let falsum = || false;

    if falsum() { panic!(); }
    if falsum() { panic!("hello"); }
    if falsum() { panic!("hello",); }
    if falsum() { panic!("hello {}", "world"); }
    if falsum() { panic!("hello {}", "world",); }
}

#[cfg(std)]
#[test]
fn print() {
    print!("hello");
    print!("hello",);
    print!("hello {}", "world");
    print!("hello {}", "world",);
}

#[cfg(std)]
#[test]
fn println() {
    println!();
    println!("hello");
    println!("hello",);
    println!("hello {}", "world");
    println!("hello {}", "world",);
}

// select! is too troublesome and unlikely to be stabilized

// stringify! is N/A

#[cfg(std)]
#[test]
fn thread_local() {
    // this has an optional trailing *semicolon*
    thread_local! {
        #[allow(unused)] pub static A: () = ()
    }

    thread_local! {
        #[allow(unused)] pub static AA: () = ();
    }

    thread_local! {
        #[allow(unused)] pub static AAA: () = ();
        #[allow(unused)] pub static AAAA: () = ()
    }

    thread_local! {
        #[allow(unused)] pub static AAAAG: () = ();
        #[allow(unused)] pub static AAAAGH: () = ();
    }
}

#[test]
fn try() {
    fn inner() -> Result<(), ()> {
        try!(Ok(()));
        try!(Ok(()),);
        Ok(())
    }

    inner().unwrap();
}

#[test]
fn unimplemented() {
    // prevent 'unreachable code' warnings
    let falsum = || false;

    if falsum() { unimplemented!(); }
    if falsum() { unimplemented!("hello"); }
    if falsum() { unimplemented!("hello",); }
    if falsum() { unimplemented!("hello {}", "world"); }
    if falsum() { unimplemented!("hello {}", "world",); }
}

#[test]
fn unreachable() {
    // prevent 'unreachable code' warnings
    let falsum = || false;

    if falsum() { unreachable!(); }
    if falsum() { unreachable!("hello"); }
    if falsum() { unreachable!("hello",); }
    if falsum() { unreachable!("hello {}", "world"); }
    if falsum() { unreachable!("hello {}", "world",); }
}

#[cfg(std)]
#[test]
fn vec() {
    let _: Vec<()> = vec![];
    vec![0];
    vec![0,];
    vec![0, 1];
    vec![0, 1,];
}

// give a test body access to a fmt::Formatter, which seems
// to be the easiest way to use 'write!' on core.
macro_rules! test_with_formatter {
    (
        #[test]
        fn $fname:ident($f:ident: &mut fmt::Formatter) $block:block
    ) => {
        #[test]
        fn $fname() {
            struct Struct;
            impl fmt::Display for Struct {
                fn fmt(&self, $f: &mut fmt::Formatter) -> fmt::Result {
                    Ok($block)
                }
            }

            // suppress "unused"
            assert!(true, "{}", Struct);
        }
    };
}

test_with_formatter! {
    #[test]
    fn write(f: &mut fmt::Formatter) {
        write!(f, "hello");
        write!(f, "hello",);
        write!(f, "hello {}", "world");
        write!(f, "hello {}", "world",);
    }
}

test_with_formatter! {
    #[test]
    fn writeln(f: &mut fmt::Formatter) {
        writeln!(f);
        writeln!(f,);
        writeln!(f, "hello");
        writeln!(f, "hello",);
        writeln!(f, "hello {}", "world");
        writeln!(f, "hello {}", "world",);
    }
}
<commit_msg>Partially revert 674a5db "Fix undesirable fallout [from macro modularization]"<commit_after>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// run-pass
// This is meant to be a comprehensive test of invocations with/without
// trailing commas (or other, similar optionally-trailing separators).
// Every macro is accounted for, even those not tested in this file.
// (There will be a note indicating why).

// std and core are both tested because they may contain separate
// implementations for some macro_rules! macros as an implementation
// detail.

// ignore-pretty issue #37195

// compile-flags: --test -C debug_assertions=yes
// revisions: std core

#![cfg_attr(core, no_std)]

#![feature(concat_idents)]

#[cfg(std)] use std::fmt;
#[cfg(core)] use core::fmt;

#[test]
fn assert() {
    assert!(true);
    assert!(true,);
    assert!(true, "hello");
    assert!(true, "hello",);
    assert!(true, "hello {}", "world");
    assert!(true, "hello {}", "world",);
}

#[test]
fn assert_eq() {
    assert_eq!(1, 1);
    assert_eq!(1, 1,);
    assert_eq!(1, 1, "hello");
    assert_eq!(1, 1, "hello",);
    assert_eq!(1, 1, "hello {}", "world");
    assert_eq!(1, 1, "hello {}", "world",);
}

#[test]
fn assert_ne() {
    assert_ne!(1, 2);
    assert_ne!(1, 2,);
    assert_ne!(1, 2, "hello");
    assert_ne!(1, 2, "hello",);
    assert_ne!(1, 2, "hello {}", "world");
    assert_ne!(1, 2, "hello {}", "world",);
}

#[test]
fn cfg() {
    let _ = cfg!(pants);
    let _ = cfg!(pants,);
    let _ = cfg!(pants = "pants");
    let _ = cfg!(pants = "pants",);
    let _ = cfg!(all(pants));
    let _ = cfg!(all(pants),);
    let _ = cfg!(all(pants,));
    let _ = cfg!(all(pants,),);
}

#[test]
fn column() {
    let _ = column!();
}

// compile_error! is in a companion to this test in compile-fail

#[test]
fn concat() {
    let _ = concat!();
    let _ = concat!("hello");
    let _ = concat!("hello",);
    let _ = concat!("hello", " world");
    let _ = concat!("hello", " world",);
}

#[test]
fn concat_idents() {
    fn foo() {}
    fn foobar() {}

    concat_idents!(foo)();
    concat_idents!(foo,)();
    concat_idents!(foo, bar)();
    concat_idents!(foo, bar,)();
}

#[test]
fn debug_assert() {
    debug_assert!(true);
    debug_assert!(true, );
    debug_assert!(true, "hello");
    debug_assert!(true, "hello",);
    debug_assert!(true, "hello {}", "world");
    debug_assert!(true, "hello {}", "world",);
}

#[test]
fn debug_assert_eq() {
    debug_assert_eq!(1, 1);
    debug_assert_eq!(1, 1,);
    debug_assert_eq!(1, 1, "hello");
    debug_assert_eq!(1, 1, "hello",);
    debug_assert_eq!(1, 1, "hello {}", "world");
    debug_assert_eq!(1, 1, "hello {}", "world",);
}

#[test]
fn debug_assert_ne() {
    debug_assert_ne!(1, 2);
    debug_assert_ne!(1, 2,);
    debug_assert_ne!(1, 2, "hello");
    debug_assert_ne!(1, 2, "hello",);
    debug_assert_ne!(1, 2, "hello {}", "world");
    debug_assert_ne!(1, 2, "hello {}", "world",);
}

#[test]
fn env() {
    let _ = env!("PATH");
    let _ = env!("PATH",);
    let _ = env!("PATH", "not found");
    let _ = env!("PATH", "not found",);
}

#[cfg(std)]
#[test]
fn eprint() {
    eprint!("hello");
    eprint!("hello",);
    eprint!("hello {}", "world");
    eprint!("hello {}", "world",);
}

#[cfg(std)]
#[test]
fn eprintln() {
    eprintln!();
    eprintln!("hello");
    eprintln!("hello",);
    eprintln!("hello {}", "world");
    eprintln!("hello {}", "world",);
}

#[test]
fn file() {
    let _ = file!();
}

#[cfg(std)]
#[test]
fn format() {
    let _ = format!("hello");
    let _ = format!("hello",);
    let _ = format!("hello {}", "world");
    let _ = format!("hello {}", "world",);
}

#[test]
fn format_args() {
    let _ = format_args!("hello");
    let _ = format_args!("hello",);
    let _ = format_args!("hello {}", "world");
    let _ = format_args!("hello {}", "world",);
}

#[test]
fn include() {
    let _ = include!("auxiliary/macro-comma-support.rs");
    let _ = include!("auxiliary/macro-comma-support.rs",);
}

#[test]
fn include_bytes() {
    let _ = include_bytes!("auxiliary/macro-comma-support.rs");
    let _ = include_bytes!("auxiliary/macro-comma-support.rs",);
}

#[test]
fn include_str() {
    let _ = include_str!("auxiliary/macro-comma-support.rs");
    let _ = include_str!("auxiliary/macro-comma-support.rs",);
}

#[test]
fn line() {
    let _ = line!();
}

#[test]
fn module_path() {
    let _ = module_path!();
}

#[test]
fn option_env() {
    let _ = option_env!("PATH");
    let _ = option_env!("PATH",);
}

#[test]
fn panic() {
    // prevent 'unreachable code' warnings
    let falsum = || false;

    if falsum() { panic!(); }
    if falsum() { panic!("hello"); }
    if falsum() { panic!("hello",); }
    if falsum() { panic!("hello {}", "world"); }
    if falsum() { panic!("hello {}", "world",); }
}

#[cfg(std)]
#[test]
fn print() {
    print!("hello");
    print!("hello",);
    print!("hello {}", "world");
    print!("hello {}", "world",);
}

#[cfg(std)]
#[test]
fn println() {
    println!();
    println!("hello");
    println!("hello",);
    println!("hello {}", "world");
    println!("hello {}", "world",);
}

// select! is too troublesome and unlikely to be stabilized

// stringify! is N/A

#[cfg(std)]
#[test]
fn thread_local() {
    // this has an optional trailing *semicolon*
    thread_local! {
        #[allow(unused)] pub static A: () = ()
    }

    thread_local! {
        #[allow(unused)] pub static AA: () = ();
    }

    thread_local! {
        #[allow(unused)] pub static AAA: () = ();
        #[allow(unused)] pub static AAAA: () = ()
    }

    thread_local! {
        #[allow(unused)] pub static AAAAG: () = ();
        #[allow(unused)] pub static AAAAGH: () = ();
    }
}

#[test]
fn try() {
    fn inner() -> Result<(), ()> {
        try!(Ok(()));
        try!(Ok(()),);
        Ok(())
    }

    inner().unwrap();
}

#[test]
fn unimplemented() {
    // prevent 'unreachable code' warnings
    let falsum = || false;

    if falsum() { unimplemented!(); }
    if falsum() { unimplemented!("hello"); }
    if falsum() { unimplemented!("hello",); }
    if falsum() { unimplemented!("hello {}", "world"); }
    if falsum() { unimplemented!("hello {}", "world",); }
}

#[test]
fn unreachable() {
    // prevent 'unreachable code' warnings
    let falsum = || false;

    if falsum() { unreachable!(); }
    if falsum() { unreachable!("hello"); }
    if falsum() { unreachable!("hello",); }
    if falsum() { unreachable!("hello {}", "world"); }
    if falsum() { unreachable!("hello {}", "world",); }
}

#[cfg(std)]
#[test]
fn vec() {
    let _: Vec<()> = vec![];
    let _ = vec![0];
    let _ = vec![0,];
    let _ = vec![0, 1];
    let _ = vec![0, 1,];
}

// give a test body access to a fmt::Formatter, which seems
// to be the easiest way to use 'write!' on core.
macro_rules! test_with_formatter {
    (
        #[test]
        fn $fname:ident($f:ident: &mut fmt::Formatter) $block:block
    ) => {
        #[test]
        fn $fname() {
            struct Struct;
            impl fmt::Display for Struct {
                fn fmt(&self, $f: &mut fmt::Formatter) -> fmt::Result {
                    Ok($block)
                }
            }

            // suppress "unused"
            assert!(true, "{}", Struct);
        }
    };
}

test_with_formatter! {
    #[test]
    fn write(f: &mut fmt::Formatter) {
        let _ = write!(f, "hello");
        let _ = write!(f, "hello",);
        let _ = write!(f, "hello {}", "world");
        let _ = write!(f, "hello {}", "world",);
    }
}

test_with_formatter! {
    #[test]
    fn writeln(f: &mut fmt::Formatter) {
        let _ = writeln!(f);
        let _ = writeln!(f,);
        let _ = writeln!(f, "hello");
        let _ = writeln!(f, "hello",);
        let _ = writeln!(f, "hello {}", "world");
        let _ = writeln!(f, "hello {}", "world",);
    }
}
<|endoftext|>


<commit_before><commit_msg>explain reasoning for ignoring captures in lookarounds<commit_after><|endoftext|>