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

//! Script to check the validity of `href` links in our HTML documentation.
//!
//! In the past we've been quite error prone to writing in broken links as most
//! of them are manually rather than automatically added. As files move over
//! time or apis change old links become stale or broken. The purpose of this
//! script is to check all relative links in our documentation to make sure they
//! actually point to a valid place.
//!
//! Currently this doesn't actually do any HTML parsing or anything fancy like
//! that, it just has a simple "regex" to search for `href` and `id` tags.
//! These values are then translated to file URLs if possible and then the
//! destination is asserted to exist.
//!
//! A few whitelisted exceptions are allowed as there's known bugs in rustdoc,
//! but this should catch the majority of "broken link" cases.

use std::env;
use std::fs::File;
use std::io::prelude::*;
use std::path::{Path, PathBuf, Component};
use std::collections::{HashMap, HashSet};
use std::collections::hash_map::Entry;

use Redirect::*;

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

fn main() {
    let docs = env::args_os().nth(1).unwrap();
    let docs = env::current_dir().unwrap().join(docs);
    let mut errors = false;
    walk(&mut HashMap::new(), &docs, &docs, &mut errors);
    if errors {
        panic!("found some broken links");
    }
}

#[derive(Debug)]
pub enum LoadError {
    IOError(std::io::Error),
    BrokenRedirect(PathBuf, std::io::Error),
    IsRedirect,
}

enum Redirect {
    SkipRedirect,
    FromRedirect(bool),
}

struct FileEntry {
    source: String,
    ids: HashSet<String>,
}

type Cache = HashMap<PathBuf, FileEntry>;

fn small_url_encode(s: &str) -> String {
    s.replace("<", "%3C")
     .replace(">", "%3E")
     .replace(" ", "%20")
     .replace("?", "%3F")
     .replace("'", "%27")
     .replace("&", "%26")
     .replace(",", "%2C")
     .replace(":", "%3A")
     .replace(";", "%3B")
     .replace("[", "%5B")
     .replace("]", "%5D")
     .replace("\"", "%22")
}

impl FileEntry {
    fn parse_ids(&mut self, file: &Path, contents: &str, errors: &mut bool) {
        if self.ids.is_empty() {
            with_attrs_in_source(contents, " id", |fragment, i, _| {
                let frag = fragment.trim_left_matches("#").to_owned();
                let encoded = small_url_encode(&frag);
                if !self.ids.insert(frag) {
                    *errors = true;
                    println!("{}:{}: id is not unique: `{}`", file.display(), i, fragment);
                }
                // Just in case, we also add the encoded id.
                self.ids.insert(encoded);
            });
        }
    }
}

fn walk(cache: &mut Cache, root: &Path, dir: &Path, errors: &mut bool) {
    for entry in t!(dir.read_dir()).map(|e| t!(e)) {
        let path = entry.path();
        let kind = t!(entry.file_type());
        if kind.is_dir() {
            walk(cache, root, &path, errors);
        } else {
            let pretty_path = check(cache, root, &path, errors);
            if let Some(pretty_path) = pretty_path {
                let entry = cache.get_mut(&pretty_path).unwrap();
                // we don't need the source anymore,
                // so drop to reduce memory-usage
                entry.source = String::new();
            }
        }
    }
}

fn check(cache: &mut Cache,
         root: &Path,
         file: &Path,
         errors: &mut bool)
         -> Option<PathBuf> {
    // Ignore none HTML files.
    if file.extension().and_then(|s| s.to_str()) != Some("html") {
        return None;
    }

    // Unfortunately we're not 100% full of valid links today to we need a few
    // whitelists to get this past `make check` today.
    // FIXME(#32129)
    if file.ends_with("std/string/struct.String.html") ||
       file.ends_with("interpret/struct.ImmTy.html") ||
       file.ends_with("symbol/struct.InternedString.html") ||
       file.ends_with("ast/struct.ThinVec.html") ||
       file.ends_with("util/struct.ThinVec.html") ||
       file.ends_with("util/struct.RcSlice.html") ||
       file.ends_with("layout/struct.TyLayout.html") ||
       file.ends_with("humantime/struct.Timestamp.html") ||
       file.ends_with("log/index.html") ||
       file.ends_with("ty/struct.Slice.html") ||
       file.ends_with("ty/enum.Attributes.html") ||
       file.ends_with("ty/struct.SymbolName.html") {
        return None;
    }
    // FIXME(#32553)
    if file.ends_with("string/struct.String.html") {
        return None;
    }
    // FIXME(#32130)
    if file.ends_with("btree_set/struct.BTreeSet.html") ||
       file.ends_with("struct.BTreeSet.html") ||
       file.ends_with("btree_map/struct.BTreeMap.html") ||
       file.ends_with("hash_map/struct.HashMap.html") ||
       file.ends_with("hash_set/struct.HashSet.html") ||
       file.ends_with("sync/struct.Lrc.html") ||
       file.ends_with("sync/struct.RwLock.html") {
        return None;
    }

    let res = load_file(cache, root, file, SkipRedirect);
    let (pretty_file, contents) = match res {
        Ok(res) => res,
        Err(_) => return None,
    };
    {
        cache.get_mut(&pretty_file)
             .unwrap()
             .parse_ids(&pretty_file, &contents, errors);
    }

    // Search for anything that's the regex 'href[ ]*=[ ]*".*?"'
    with_attrs_in_source(&contents, " href", |url, i, base| {
        // Ignore external URLs
        if url.starts_with("http:") || url.starts_with("https:") ||
           url.starts_with("javascript:") || url.starts_with("ftp:") ||
           url.starts_with("irc:") || url.starts_with("data:") {
            return;
        }
        let mut parts = url.splitn(2, "#");
        let url = parts.next().unwrap();
        let fragment = parts.next();
        let mut parts = url.splitn(2, "?");
        let url = parts.next().unwrap();

        // Once we've plucked out the URL, parse it using our base url and
        // then try to extract a file path.
        let mut path = file.to_path_buf();
        if !base.is_empty() || !url.is_empty() {
            path.pop();
            for part in Path::new(base).join(url).components() {
                match part {
                    Component::Prefix(_) |
                    Component::RootDir => {
                        // Avoid absolute paths as they make the docs not
                        // relocatable by making assumptions on where the docs
                        // are hosted relative to the site root.
                        *errors = true;
                        println!("{}:{}: absolute path - {}",
                                 pretty_file.display(),
                                 i + 1,
                                 Path::new(base).join(url).display());
                        return;
                    }
                    Component::CurDir => {}
                    Component::ParentDir => { path.pop(); }
                    Component::Normal(s) => { path.push(s); }
                }
            }
        }

        // Alright, if we've found a file name then this file had better
        // exist! If it doesn't then we register and print an error.
        if path.exists() {
            if path.is_dir() {
                // Links to directories show as directory listings when viewing
                // the docs offline so it's best to avoid them.
                *errors = true;
                let pretty_path = path.strip_prefix(root).unwrap_or(&path);
                println!("{}:{}: directory link - {}",
                         pretty_file.display(),
                         i + 1,
                         pretty_path.display());
                return;
            }
            if let Some(extension) = path.extension() {
                // Ignore none HTML files.
                if extension != "html" {
                    return;
                }
            }
            let res = load_file(cache, root, &path, FromRedirect(false));
            let (pretty_path, contents) = match res {
                Ok(res) => res,
                Err(LoadError::IOError(err)) => {
                    panic!("error loading {}: {}", path.display(), err);
                }
                Err(LoadError::BrokenRedirect(target, _)) => {
                    *errors = true;
                    println!("{}:{}: broken redirect to {}",
                             pretty_file.display(),
                             i + 1,
                             target.display());
                    return;
                }
                Err(LoadError::IsRedirect) => unreachable!(),
            };

            if let Some(ref fragment) = fragment {
                // Fragments like `#1-6` are most likely line numbers to be
                // interpreted by javascript, so we're ignoring these
                if fragment.splitn(2, '-')
                           .all(|f| f.chars().all(|c| c.is_numeric())) {
                    return;
                }

                // These appear to be broken in mdbook right now?
                if fragment.starts_with("-") {
                    return;
                }

                let entry = &mut cache.get_mut(&pretty_path).unwrap();
                entry.parse_ids(&pretty_path, &contents, errors);

                if !entry.ids.contains(*fragment) {
                    *errors = true;
                    print!("{}:{}: broken link fragment ",
                           pretty_file.display(),
                           i + 1);
                    println!("`#{}` pointing to `{}`", fragment, pretty_path.display());
                };
            }
        } else {
            *errors = true;
            print!("{}:{}: broken link - ", pretty_file.display(), i + 1);
            let pretty_path = path.strip_prefix(root).unwrap_or(&path);
            println!("{}", pretty_path.display());
        }
    });
    Some(pretty_file)
}

fn load_file(cache: &mut Cache,
             root: &Path,
             file: &Path,
             redirect: Redirect)
             -> Result<(PathBuf, String), LoadError> {
    let mut contents = String::new();
    let pretty_file = PathBuf::from(file.strip_prefix(root).unwrap_or(&file));

    let maybe_redirect = match cache.entry(pretty_file.clone()) {
        Entry::Occupied(entry) => {
            contents = entry.get().source.clone();
            None
        }
        Entry::Vacant(entry) => {
            let mut fp = File::open(file).map_err(|err| {
                if let FromRedirect(true) = redirect {
                    LoadError::BrokenRedirect(file.to_path_buf(), err)
                } else {
                    LoadError::IOError(err)
                }
            })?;
            fp.read_to_string(&mut contents).map_err(|err| LoadError::IOError(err))?;

            let maybe = maybe_redirect(&contents);
            if maybe.is_some() {
                if let SkipRedirect = redirect {
                    return Err(LoadError::IsRedirect);
                }
            } else {
                entry.insert(FileEntry {
                    source: contents.clone(),
                    ids: HashSet::new(),
                });
            }
            maybe
        }
    };
    match maybe_redirect.map(|url| file.parent().unwrap().join(url)) {
        Some(redirect_file) => {
            load_file(cache, root, &redirect_file, FromRedirect(true))
        }
        None => Ok((pretty_file, contents)),
    }
}

fn maybe_redirect(source: &str) -> Option<String> {
    const REDIRECT: &'static str = "
Redirecting to  l,
        None => return None,
    };

    redirect_line.find(REDIRECT).map(|i| {
        let rest = &redirect_line[(i + REDIRECT.len() + 1)..];
        let pos_quote = rest.find('"').unwrap();
        rest[..pos_quote].to_owned()
    })
}

fn with_attrs_in_source<F: FnMut(&str, usize, &str)>(contents: &str, attr: &str, mut f: F) {
    let mut base = "";
    for (i, mut line) in contents.lines().enumerate() {
        while let Some(j) = line.find(attr) {
            let rest = &line[j + attr.len()..];
            // The base tag should always be the first link in the document so
            // we can get away with using one pass.
            let is_base = line[..j].ends_with("<base");
            line = rest;
            let pos_equals = match rest.find("=") {
                Some(i) => i,
                None => continue,
            };
            if rest[..pos_equals].trim_left_matches(" ") != "" {
                continue;
            }

            let rest = &rest[pos_equals + 1..];

            let pos_quote = match rest.find(&['"', '\''][..]) {
                Some(i) => i,
                None => continue,
            };
            let quote_delim = rest.as_bytes()[pos_quote] as char;

            if rest[..pos_quote].trim_left_matches(" ") != "" {
                continue;
            }
            let rest = &rest[pos_quote + 1..];
            let url = match rest.find(quote_delim) {
                Some(i) => &rest[..i],
                None => continue,
            };
            if is_base {
                base = url;
                continue;
            }
            f(url, i, base)
        }
    }
}
<commit_msg>Rollup merge of #56360 - alexcrichton:linkchecker-omg, r=pietroalbini<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Script to check the validity of `href` links in our HTML documentation.
//!
//! In the past we've been quite error prone to writing in broken links as most
//! of them are manually rather than automatically added. As files move over
//! time or apis change old links become stale or broken. The purpose of this
//! script is to check all relative links in our documentation to make sure they
//! actually point to a valid place.
//!
//! Currently this doesn't actually do any HTML parsing or anything fancy like
//! that, it just has a simple "regex" to search for `href` and `id` tags.
//! These values are then translated to file URLs if possible and then the
//! destination is asserted to exist.
//!
//! A few whitelisted exceptions are allowed as there's known bugs in rustdoc,
//! but this should catch the majority of "broken link" cases.

use std::collections::hash_map::Entry;
use std::collections::{HashMap, HashSet};
use std::env;
use std::fs;
use std::path::{Path, PathBuf, Component};
use std::rc::Rc;

use Redirect::*;

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

fn main() {
    let docs = env::args_os().nth(1).unwrap();
    let docs = env::current_dir().unwrap().join(docs);
    let mut errors = false;
    walk(&mut HashMap::new(), &docs, &docs, &mut errors);
    if errors {
        panic!("found some broken links");
    }
}

#[derive(Debug)]
pub enum LoadError {
    IOError(std::io::Error),
    BrokenRedirect(PathBuf, std::io::Error),
    IsRedirect,
}

enum Redirect {
    SkipRedirect,
    FromRedirect(bool),
}

struct FileEntry {
    source: Rc<String>,
    ids: HashSet<String>,
}

type Cache = HashMap<PathBuf, FileEntry>;

fn small_url_encode(s: &str) -> String {
    s.replace("<", "%3C")
     .replace(">", "%3E")
     .replace(" ", "%20")
     .replace("?", "%3F")
     .replace("'", "%27")
     .replace("&", "%26")
     .replace(",", "%2C")
     .replace(":", "%3A")
     .replace(";", "%3B")
     .replace("[", "%5B")
     .replace("]", "%5D")
     .replace("\"", "%22")
}

impl FileEntry {
    fn parse_ids(&mut self, file: &Path, contents: &str, errors: &mut bool) {
        if self.ids.is_empty() {
            with_attrs_in_source(contents, " id", |fragment, i, _| {
                let frag = fragment.trim_left_matches("#").to_owned();
                let encoded = small_url_encode(&frag);
                if !self.ids.insert(frag) {
                    *errors = true;
                    println!("{}:{}: id is not unique: `{}`", file.display(), i, fragment);
                }
                // Just in case, we also add the encoded id.
                self.ids.insert(encoded);
            });
        }
    }
}

fn walk(cache: &mut Cache, root: &Path, dir: &Path, errors: &mut bool) {
    for entry in t!(dir.read_dir()).map(|e| t!(e)) {
        let path = entry.path();
        let kind = t!(entry.file_type());
        if kind.is_dir() {
            walk(cache, root, &path, errors);
        } else {
            let pretty_path = check(cache, root, &path, errors);
            if let Some(pretty_path) = pretty_path {
                let entry = cache.get_mut(&pretty_path).unwrap();
                // we don't need the source anymore,
                // so drop to reduce memory-usage
                entry.source = Rc::new(String::new());
            }
        }
    }
}

fn check(cache: &mut Cache,
         root: &Path,
         file: &Path,
         errors: &mut bool)
         -> Option<PathBuf> {
    // Ignore none HTML files.
    if file.extension().and_then(|s| s.to_str()) != Some("html") {
        return None;
    }

    // Unfortunately we're not 100% full of valid links today to we need a few
    // whitelists to get this past `make check` today.
    // FIXME(#32129)
    if file.ends_with("std/string/struct.String.html") ||
       file.ends_with("interpret/struct.ImmTy.html") ||
       file.ends_with("symbol/struct.InternedString.html") ||
       file.ends_with("ast/struct.ThinVec.html") ||
       file.ends_with("util/struct.ThinVec.html") ||
       file.ends_with("util/struct.RcSlice.html") ||
       file.ends_with("layout/struct.TyLayout.html") ||
       file.ends_with("humantime/struct.Timestamp.html") ||
       file.ends_with("log/index.html") ||
       file.ends_with("ty/struct.Slice.html") ||
       file.ends_with("ty/enum.Attributes.html") ||
       file.ends_with("ty/struct.SymbolName.html") {
        return None;
    }
    // FIXME(#32553)
    if file.ends_with("string/struct.String.html") {
        return None;
    }
    // FIXME(#32130)
    if file.ends_with("btree_set/struct.BTreeSet.html") ||
       file.ends_with("struct.BTreeSet.html") ||
       file.ends_with("btree_map/struct.BTreeMap.html") ||
       file.ends_with("hash_map/struct.HashMap.html") ||
       file.ends_with("hash_set/struct.HashSet.html") ||
       file.ends_with("sync/struct.Lrc.html") ||
       file.ends_with("sync/struct.RwLock.html") {
        return None;
    }

    let res = load_file(cache, root, file, SkipRedirect);
    let (pretty_file, contents) = match res {
        Ok(res) => res,
        Err(_) => return None,
    };
    {
        cache.get_mut(&pretty_file)
             .unwrap()
             .parse_ids(&pretty_file, &contents, errors);
    }

    // Search for anything that's the regex 'href[ ]*=[ ]*".*?"'
    with_attrs_in_source(&contents, " href", |url, i, base| {
        // Ignore external URLs
        if url.starts_with("http:") || url.starts_with("https:") ||
           url.starts_with("javascript:") || url.starts_with("ftp:") ||
           url.starts_with("irc:") || url.starts_with("data:") {
            return;
        }
        let mut parts = url.splitn(2, "#");
        let url = parts.next().unwrap();
        let fragment = parts.next();
        let mut parts = url.splitn(2, "?");
        let url = parts.next().unwrap();

        // Once we've plucked out the URL, parse it using our base url and
        // then try to extract a file path.
        let mut path = file.to_path_buf();
        if !base.is_empty() || !url.is_empty() {
            path.pop();
            for part in Path::new(base).join(url).components() {
                match part {
                    Component::Prefix(_) |
                    Component::RootDir => {
                        // Avoid absolute paths as they make the docs not
                        // relocatable by making assumptions on where the docs
                        // are hosted relative to the site root.
                        *errors = true;
                        println!("{}:{}: absolute path - {}",
                                 pretty_file.display(),
                                 i + 1,
                                 Path::new(base).join(url).display());
                        return;
                    }
                    Component::CurDir => {}
                    Component::ParentDir => { path.pop(); }
                    Component::Normal(s) => { path.push(s); }
                }
            }
        }

        // Alright, if we've found a file name then this file had better
        // exist! If it doesn't then we register and print an error.
        if path.exists() {
            if path.is_dir() {
                // Links to directories show as directory listings when viewing
                // the docs offline so it's best to avoid them.
                *errors = true;
                let pretty_path = path.strip_prefix(root).unwrap_or(&path);
                println!("{}:{}: directory link - {}",
                         pretty_file.display(),
                         i + 1,
                         pretty_path.display());
                return;
            }
            if let Some(extension) = path.extension() {
                // Ignore none HTML files.
                if extension != "html" {
                    return;
                }
            }
            let res = load_file(cache, root, &path, FromRedirect(false));
            let (pretty_path, contents) = match res {
                Ok(res) => res,
                Err(LoadError::IOError(err)) => {
                    panic!("error loading {}: {}", path.display(), err);
                }
                Err(LoadError::BrokenRedirect(target, _)) => {
                    *errors = true;
                    println!("{}:{}: broken redirect to {}",
                             pretty_file.display(),
                             i + 1,
                             target.display());
                    return;
                }
                Err(LoadError::IsRedirect) => unreachable!(),
            };

            if let Some(ref fragment) = fragment {
                // Fragments like `#1-6` are most likely line numbers to be
                // interpreted by javascript, so we're ignoring these
                if fragment.splitn(2, '-')
                           .all(|f| f.chars().all(|c| c.is_numeric())) {
                    return;
                }

                // These appear to be broken in mdbook right now?
                if fragment.starts_with("-") {
                    return;
                }

                let entry = &mut cache.get_mut(&pretty_path).unwrap();
                entry.parse_ids(&pretty_path, &contents, errors);

                if !entry.ids.contains(*fragment) {
                    *errors = true;
                    print!("{}:{}: broken link fragment ",
                           pretty_file.display(),
                           i + 1);
                    println!("`#{}` pointing to `{}`", fragment, pretty_path.display());
                };
            }
        } else {
            *errors = true;
            print!("{}:{}: broken link - ", pretty_file.display(), i + 1);
            let pretty_path = path.strip_prefix(root).unwrap_or(&path);
            println!("{}", pretty_path.display());
        }
    });
    Some(pretty_file)
}

fn load_file(cache: &mut Cache,
             root: &Path,
             file: &Path,
             redirect: Redirect)
             -> Result<(PathBuf, Rc<String>), LoadError> {
    let pretty_file = PathBuf::from(file.strip_prefix(root).unwrap_or(&file));

    let (maybe_redirect, contents) = match cache.entry(pretty_file.clone()) {
        Entry::Occupied(entry) => {
            (None, entry.get().source.clone())
        }
        Entry::Vacant(entry) => {
            let contents = match fs::read_to_string(file) {
                Ok(s) => Rc::new(s),
                Err(err) => {
                    return Err(if let FromRedirect(true) = redirect {
                        LoadError::BrokenRedirect(file.to_path_buf(), err)
                    } else {
                        LoadError::IOError(err)
                    })
                }
            };

            let maybe = maybe_redirect(&contents);
            if maybe.is_some() {
                if let SkipRedirect = redirect {
                    return Err(LoadError::IsRedirect);
                }
            } else {
                entry.insert(FileEntry {
                    source: contents.clone(),
                    ids: HashSet::new(),
                });
            }
            (maybe, contents)
        }
    };
    match maybe_redirect.map(|url| file.parent().unwrap().join(url)) {
        Some(redirect_file) => {
            load_file(cache, root, &redirect_file, FromRedirect(true))
        }
        None => Ok((pretty_file, contents)),
    }
}

fn maybe_redirect(source: &str) -> Option<String> {
    const REDIRECT: &'static str = "
Redirecting to  l,
        None => return None,
    };

    redirect_line.find(REDIRECT).map(|i| {
        let rest = &redirect_line[(i + REDIRECT.len() + 1)..];
        let pos_quote = rest.find('"').unwrap();
        rest[..pos_quote].to_owned()
    })
}

fn with_attrs_in_source<F: FnMut(&str, usize, &str)>(contents: &str, attr: &str, mut f: F) {
    let mut base = "";
    for (i, mut line) in contents.lines().enumerate() {
        while let Some(j) = line.find(attr) {
            let rest = &line[j + attr.len()..];
            // The base tag should always be the first link in the document so
            // we can get away with using one pass.
            let is_base = line[..j].ends_with("<base");
            line = rest;
            let pos_equals = match rest.find("=") {
                Some(i) => i,
                None => continue,
            };
            if rest[..pos_equals].trim_left_matches(" ") != "" {
                continue;
            }

            let rest = &rest[pos_equals + 1..];

            let pos_quote = match rest.find(&['"', '\''][..]) {
                Some(i) => i,
                None => continue,
            };
            let quote_delim = rest.as_bytes()[pos_quote] as char;

            if rest[..pos_quote].trim_left_matches(" ") != "" {
                continue;
            }
            let rest = &rest[pos_quote + 1..];
            let url = match rest.find(quote_delim) {
                Some(i) => &rest[..i],
                None => continue,
            };
            if is_base {
                base = url;
                continue;
            }
            f(url, i, base)
        }
    }
}
<|endoftext|>


<commit_before>use crate::borrow_check::place_ext::PlaceExt;
use crate::borrow_check::nll::ToRegionVid;
use crate::dataflow::indexes::BorrowIndex;
use crate::dataflow::move_paths::MoveData;
use rustc::mir::traversal;
use rustc::mir::visit::{
    PlaceContext, Visitor, NonUseContext, MutatingUseContext, NonMutatingUseContext
};
use rustc::mir::{self, Location, Mir, Local};
use rustc::ty::{RegionVid, TyCtxt};
use rustc::util::nodemap::{FxHashMap, FxHashSet};
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::bit_set::BitSet;
use std::fmt;
use std::ops::Index;

crate struct BorrowSet<'tcx> {
    /// The fundamental map relating bitvector indexes to the borrows
    /// in the MIR.
    crate borrows: IndexVec<BorrowIndex, BorrowData<'tcx>>,

    /// Each borrow is also uniquely identified in the MIR by the
    /// `Location` of the assignment statement in which it appears on
    /// the right hand side; we map each such location to the
    /// corresponding `BorrowIndex`.
    crate location_map: FxHashMap<Location, BorrowIndex>,

    /// Locations which activate borrows.
    /// NOTE: a given location may activate more than one borrow in the future
    /// when more general two-phase borrow support is introduced, but for now we
    /// only need to store one borrow index.
    crate activation_map: FxHashMap<Location, Vec<BorrowIndex>>,

    /// Map from local to all the borrows on that local.
    crate local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,

    crate locals_state_at_exit: LocalsStateAtExit,
}

impl<'tcx> Index<BorrowIndex> for BorrowSet<'tcx> {
    type Output = BorrowData<'tcx>;

    fn index(&self, index: BorrowIndex) -> &BorrowData<'tcx> {
        &self.borrows[index]
    }
}

/// Location where a two-phase borrow is activated, if a borrow
/// is in fact a two-phase borrow.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
crate enum TwoPhaseActivation {
    NotTwoPhase,
    NotActivated,
    ActivatedAt(Location),
}

#[derive(Debug)]
crate struct BorrowData<'tcx> {
    /// Location where the borrow reservation starts.
    /// In many cases, this will be equal to the activation location but not always.
    crate reserve_location: Location,
    /// Location where the borrow is activated.
    crate activation_location: TwoPhaseActivation,
    /// What kind of borrow this is
    crate kind: mir::BorrowKind,
    /// The region for which this borrow is live
    crate region: RegionVid,
    /// Place from which we are borrowing
    crate borrowed_place: mir::Place<'tcx>,
    /// Place to which the borrow was stored
    crate assigned_place: mir::Place<'tcx>,
}

impl<'tcx> fmt::Display for BorrowData<'tcx> {
    fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result {
        let kind = match self.kind {
            mir::BorrowKind::Shared => "",
            mir::BorrowKind::Shallow => "shallow ",
            mir::BorrowKind::Unique => "uniq ",
            mir::BorrowKind::Mut { .. } => "mut ",
        };
        write!(w, "&{:?} {}{:?}", self.region, kind, self.borrowed_place)
    }
}

crate enum LocalsStateAtExit {
    AllAreInvalidated,
    SomeAreInvalidated { has_storage_dead_or_moved: BitSet<Local> }
}

impl LocalsStateAtExit {
    fn build(
        locals_are_invalidated_at_exit: bool,
        mir: &Mir<'tcx>,
        move_data: &MoveData<'tcx>
    ) -> Self {
        struct HasStorageDead(BitSet<Local>);

        impl<'tcx> Visitor<'tcx> for HasStorageDead {
            fn visit_local(&mut self, local: &Local, ctx: PlaceContext<'tcx>, _: Location) {
                if ctx == PlaceContext::NonUse(NonUseContext::StorageDead) {
                    self.0.insert(*local);
                }
            }
        }

        if locals_are_invalidated_at_exit {
            LocalsStateAtExit::AllAreInvalidated
        } else {
            let mut has_storage_dead = HasStorageDead(BitSet::new_empty(mir.local_decls.len()));
            has_storage_dead.visit_mir(mir);
            let mut has_storage_dead_or_moved = has_storage_dead.0;
            for move_out in &move_data.moves {
                if let Some(index) = move_data.base_local(move_out.path) {
                    has_storage_dead_or_moved.insert(index);

                }
            }
            LocalsStateAtExit::SomeAreInvalidated{ has_storage_dead_or_moved }
        }
    }
}

impl<'tcx> BorrowSet<'tcx> {
    pub fn build(
        tcx: TyCtxt<'_, '_, 'tcx>,
        mir: &Mir<'tcx>,
        locals_are_invalidated_at_exit: bool,
        move_data: &MoveData<'tcx>
    ) -> Self {

        let mut visitor = GatherBorrows {
            tcx,
            mir,
            idx_vec: IndexVec::new(),
            location_map: Default::default(),
            activation_map: Default::default(),
            local_map: Default::default(),
            pending_activations: Default::default(),
            locals_state_at_exit:
                LocalsStateAtExit::build(locals_are_invalidated_at_exit, mir, move_data),
        };

        for (block, block_data) in traversal::preorder(mir) {
            visitor.visit_basic_block_data(block, block_data);
        }

        BorrowSet {
            borrows: visitor.idx_vec,
            location_map: visitor.location_map,
            activation_map: visitor.activation_map,
            local_map: visitor.local_map,
            locals_state_at_exit: visitor.locals_state_at_exit,
        }
    }

    crate fn activations_at_location(&self, location: Location) -> &[BorrowIndex] {
        self.activation_map
            .get(&location)
            .map(|activations| &activations[..])
            .unwrap_or(&[])
    }
}

struct GatherBorrows<'a, 'gcx: 'tcx, 'tcx: 'a> {
    tcx: TyCtxt<'a, 'gcx, 'tcx>,
    mir: &'a Mir<'tcx>,
    idx_vec: IndexVec<BorrowIndex, BorrowData<'tcx>>,
    location_map: FxHashMap<Location, BorrowIndex>,
    activation_map: FxHashMap<Location, Vec<BorrowIndex>>,
    local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,

    /// When we encounter a 2-phase borrow statement, it will always
    /// be assigning into a temporary TEMP:
    ///
    ///    TEMP = &foo
    ///
    /// We add TEMP into this map with `b`, where `b` is the index of
    /// the borrow. When we find a later use of this activation, we
    /// remove from the map (and add to the "tombstone" set below).
    pending_activations: FxHashMap<mir::Local, BorrowIndex>,

    locals_state_at_exit: LocalsStateAtExit,
}

impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> {
    fn visit_assign(
        &mut self,
        block: mir::BasicBlock,
        assigned_place: &mir::Place<'tcx>,
        rvalue: &mir::Rvalue<'tcx>,
        location: mir::Location,
    ) {
        if let mir::Rvalue::Ref(region, kind, ref borrowed_place) = *rvalue {
            if borrowed_place.ignore_borrow(
                self.tcx, self.mir, &self.locals_state_at_exit) {
                return;
            }

            let region = region.to_region_vid();

            let borrow = BorrowData {
                kind,
                region,
                reserve_location: location,
                activation_location: TwoPhaseActivation::NotTwoPhase,
                borrowed_place: borrowed_place.clone(),
                assigned_place: assigned_place.clone(),
            };
            let idx = self.idx_vec.push(borrow);
            self.location_map.insert(location, idx);

            self.insert_as_pending_if_two_phase(location, &assigned_place, kind, idx);

            if let Some(local) = borrowed_place.root_local() {
                self.local_map.entry(local).or_default().insert(idx);
            }
        }

        self.super_assign(block, assigned_place, rvalue, location)
    }

    fn visit_local(
        &mut self,
        temp: &Local,
        context: PlaceContext<'tcx>,
        location: Location,
    ) {
        if !context.is_use() {
            return;
        }

        // We found a use of some temporary TMP
        // check whether we (earlier) saw a 2-phase borrow like
        //
        //     TMP = &mut place
        if let Some(&borrow_index) = self.pending_activations.get(temp) {
            let borrow_data = &mut self.idx_vec[borrow_index];

            // Watch out: the use of TMP in the borrow itself
            // doesn't count as an activation. =)
            if borrow_data.reserve_location == location &&
                context == PlaceContext::MutatingUse(MutatingUseContext::Store)
            {
                return;
            }

            if let TwoPhaseActivation::ActivatedAt(other_location) =
                    borrow_data.activation_location {
                span_bug!(
                    self.mir.source_info(location).span,
                    "found two uses for 2-phase borrow temporary {:?}: \
                     {:?} and {:?}",
                    temp,
                    location,
                    other_location,
                );
            }

            // Otherwise, this is the unique later use
            // that we expect.
            borrow_data.activation_location = match context {
                // The use of TMP in a shared borrow does not
                // count as an actual activation.
                PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow(..)) |
                PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow(..)) =>
                    TwoPhaseActivation::NotActivated,
                _ => {
                    // Double check: This borrow is indeed a two-phase borrow (that is,
                    // we are 'transitioning' from `NotActivated` to `ActivatedAt`) and
                    // we've not found any other activations (checked above).
                    assert_eq!(
                        borrow_data.activation_location,
                        TwoPhaseActivation::NotActivated,
                        "never found an activation for this borrow!",
                    );

                    self.activation_map
                        .entry(location)
                        .or_default()
                        .push(borrow_index);
                    TwoPhaseActivation::ActivatedAt(location)
                }
            };
        }
    }

    fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: mir::Location) {
        if let mir::Rvalue::Ref(region, kind, ref place) = *rvalue {
            // double-check that we already registered a BorrowData for this

            let borrow_index = self.location_map[&location];
            let borrow_data = &self.idx_vec[borrow_index];
            assert_eq!(borrow_data.reserve_location, location);
            assert_eq!(borrow_data.kind, kind);
            assert_eq!(borrow_data.region, region.to_region_vid());
            assert_eq!(borrow_data.borrowed_place, *place);
        }

        return self.super_rvalue(rvalue, location);
    }

    fn visit_statement(
        &mut self,
        block: mir::BasicBlock,
        statement: &mir::Statement<'tcx>,
        location: Location,
    ) {
        return self.super_statement(block, statement, location);
    }
}

impl<'a, 'gcx, 'tcx> GatherBorrows<'a, 'gcx, 'tcx> {
    /// Returns `true` if the borrow represented by `kind` is
    /// allowed to be split into separate Reservation and
    /// Activation phases.
    fn allow_two_phase_borrow(&self, kind: mir::BorrowKind) -> bool {
        self.tcx.two_phase_borrows()
            && (kind.allows_two_phase_borrow()
                || self.tcx.sess.opts.debugging_opts.two_phase_beyond_autoref)
    }

    /// If this is a two-phase borrow, then we will record it
    /// as "pending" until we find the activating use.
    fn insert_as_pending_if_two_phase(
        &mut self,
        start_location: Location,
        assigned_place: &mir::Place<'tcx>,
        kind: mir::BorrowKind,
        borrow_index: BorrowIndex,
    ) {
        debug!(
            "Borrows::insert_as_pending_if_two_phase({:?}, {:?}, {:?})",
            start_location, assigned_place, borrow_index,
        );

        if !self.allow_two_phase_borrow(kind) {
            debug!("  -> {:?}", start_location);
            return;
        }

        // When we encounter a 2-phase borrow statement, it will always
        // be assigning into a temporary TEMP:
        //
        //    TEMP = &foo
        //
        // so extract `temp`.
        let temp = if let &mir::Place::Local(temp) = assigned_place {
            temp
        } else {
            span_bug!(
                self.mir.source_info(start_location).span,
                "expected 2-phase borrow to assign to a local, not `{:?}`",
                assigned_place,
            );
        };

        // Consider the borrow not activated to start. When we find an activation, we'll update
        // this field.
        {
            let borrow_data = &mut self.idx_vec[borrow_index];
            borrow_data.activation_location = TwoPhaseActivation::NotActivated;
        }

        // Insert `temp` into the list of pending activations. From
        // now on, we'll be on the lookout for a use of it. Note that
        // we are guaranteed that this use will come after the
        // assignment.
        let old_value = self.pending_activations.insert(temp, borrow_index);
        if let Some(old_index) = old_value {
            span_bug!(self.mir.source_info(start_location).span,
                      "found already pending activation for temp: {:?} \
                       at borrow_index: {:?} with associated data {:?}",
                      temp, old_index, self.idx_vec[old_index]);
        }
    }
}
<commit_msg>Activate two phase borrows on all uses<commit_after>use crate::borrow_check::place_ext::PlaceExt;
use crate::borrow_check::nll::ToRegionVid;
use crate::dataflow::indexes::BorrowIndex;
use crate::dataflow::move_paths::MoveData;
use rustc::mir::traversal;
use rustc::mir::visit::{PlaceContext, Visitor, NonUseContext, MutatingUseContext};
use rustc::mir::{self, Location, Mir, Local};
use rustc::ty::{RegionVid, TyCtxt};
use rustc::util::nodemap::{FxHashMap, FxHashSet};
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::bit_set::BitSet;
use std::fmt;
use std::ops::Index;

crate struct BorrowSet<'tcx> {
    /// The fundamental map relating bitvector indexes to the borrows
    /// in the MIR.
    crate borrows: IndexVec<BorrowIndex, BorrowData<'tcx>>,

    /// Each borrow is also uniquely identified in the MIR by the
    /// `Location` of the assignment statement in which it appears on
    /// the right hand side; we map each such location to the
    /// corresponding `BorrowIndex`.
    crate location_map: FxHashMap<Location, BorrowIndex>,

    /// Locations which activate borrows.
    /// NOTE: a given location may activate more than one borrow in the future
    /// when more general two-phase borrow support is introduced, but for now we
    /// only need to store one borrow index.
    crate activation_map: FxHashMap<Location, Vec<BorrowIndex>>,

    /// Map from local to all the borrows on that local.
    crate local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,

    crate locals_state_at_exit: LocalsStateAtExit,
}

impl<'tcx> Index<BorrowIndex> for BorrowSet<'tcx> {
    type Output = BorrowData<'tcx>;

    fn index(&self, index: BorrowIndex) -> &BorrowData<'tcx> {
        &self.borrows[index]
    }
}

/// Location where a two-phase borrow is activated, if a borrow
/// is in fact a two-phase borrow.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
crate enum TwoPhaseActivation {
    NotTwoPhase,
    NotActivated,
    ActivatedAt(Location),
}

#[derive(Debug)]
crate struct BorrowData<'tcx> {
    /// Location where the borrow reservation starts.
    /// In many cases, this will be equal to the activation location but not always.
    crate reserve_location: Location,
    /// Location where the borrow is activated.
    crate activation_location: TwoPhaseActivation,
    /// What kind of borrow this is
    crate kind: mir::BorrowKind,
    /// The region for which this borrow is live
    crate region: RegionVid,
    /// Place from which we are borrowing
    crate borrowed_place: mir::Place<'tcx>,
    /// Place to which the borrow was stored
    crate assigned_place: mir::Place<'tcx>,
}

impl<'tcx> fmt::Display for BorrowData<'tcx> {
    fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result {
        let kind = match self.kind {
            mir::BorrowKind::Shared => "",
            mir::BorrowKind::Shallow => "shallow ",
            mir::BorrowKind::Unique => "uniq ",
            mir::BorrowKind::Mut { .. } => "mut ",
        };
        write!(w, "&{:?} {}{:?}", self.region, kind, self.borrowed_place)
    }
}

crate enum LocalsStateAtExit {
    AllAreInvalidated,
    SomeAreInvalidated { has_storage_dead_or_moved: BitSet<Local> }
}

impl LocalsStateAtExit {
    fn build(
        locals_are_invalidated_at_exit: bool,
        mir: &Mir<'tcx>,
        move_data: &MoveData<'tcx>
    ) -> Self {
        struct HasStorageDead(BitSet<Local>);

        impl<'tcx> Visitor<'tcx> for HasStorageDead {
            fn visit_local(&mut self, local: &Local, ctx: PlaceContext<'tcx>, _: Location) {
                if ctx == PlaceContext::NonUse(NonUseContext::StorageDead) {
                    self.0.insert(*local);
                }
            }
        }

        if locals_are_invalidated_at_exit {
            LocalsStateAtExit::AllAreInvalidated
        } else {
            let mut has_storage_dead = HasStorageDead(BitSet::new_empty(mir.local_decls.len()));
            has_storage_dead.visit_mir(mir);
            let mut has_storage_dead_or_moved = has_storage_dead.0;
            for move_out in &move_data.moves {
                if let Some(index) = move_data.base_local(move_out.path) {
                    has_storage_dead_or_moved.insert(index);

                }
            }
            LocalsStateAtExit::SomeAreInvalidated{ has_storage_dead_or_moved }
        }
    }
}

impl<'tcx> BorrowSet<'tcx> {
    pub fn build(
        tcx: TyCtxt<'_, '_, 'tcx>,
        mir: &Mir<'tcx>,
        locals_are_invalidated_at_exit: bool,
        move_data: &MoveData<'tcx>
    ) -> Self {

        let mut visitor = GatherBorrows {
            tcx,
            mir,
            idx_vec: IndexVec::new(),
            location_map: Default::default(),
            activation_map: Default::default(),
            local_map: Default::default(),
            pending_activations: Default::default(),
            locals_state_at_exit:
                LocalsStateAtExit::build(locals_are_invalidated_at_exit, mir, move_data),
        };

        for (block, block_data) in traversal::preorder(mir) {
            visitor.visit_basic_block_data(block, block_data);
        }

        BorrowSet {
            borrows: visitor.idx_vec,
            location_map: visitor.location_map,
            activation_map: visitor.activation_map,
            local_map: visitor.local_map,
            locals_state_at_exit: visitor.locals_state_at_exit,
        }
    }

    crate fn activations_at_location(&self, location: Location) -> &[BorrowIndex] {
        self.activation_map
            .get(&location)
            .map(|activations| &activations[..])
            .unwrap_or(&[])
    }
}

struct GatherBorrows<'a, 'gcx: 'tcx, 'tcx: 'a> {
    tcx: TyCtxt<'a, 'gcx, 'tcx>,
    mir: &'a Mir<'tcx>,
    idx_vec: IndexVec<BorrowIndex, BorrowData<'tcx>>,
    location_map: FxHashMap<Location, BorrowIndex>,
    activation_map: FxHashMap<Location, Vec<BorrowIndex>>,
    local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,

    /// When we encounter a 2-phase borrow statement, it will always
    /// be assigning into a temporary TEMP:
    ///
    ///    TEMP = &foo
    ///
    /// We add TEMP into this map with `b`, where `b` is the index of
    /// the borrow. When we find a later use of this activation, we
    /// remove from the map (and add to the "tombstone" set below).
    pending_activations: FxHashMap<mir::Local, BorrowIndex>,

    locals_state_at_exit: LocalsStateAtExit,
}

impl<'a, 'gcx, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'gcx, 'tcx> {
    fn visit_assign(
        &mut self,
        block: mir::BasicBlock,
        assigned_place: &mir::Place<'tcx>,
        rvalue: &mir::Rvalue<'tcx>,
        location: mir::Location,
    ) {
        if let mir::Rvalue::Ref(region, kind, ref borrowed_place) = *rvalue {
            if borrowed_place.ignore_borrow(
                self.tcx, self.mir, &self.locals_state_at_exit) {
                return;
            }

            let region = region.to_region_vid();

            let borrow = BorrowData {
                kind,
                region,
                reserve_location: location,
                activation_location: TwoPhaseActivation::NotTwoPhase,
                borrowed_place: borrowed_place.clone(),
                assigned_place: assigned_place.clone(),
            };
            let idx = self.idx_vec.push(borrow);
            self.location_map.insert(location, idx);

            self.insert_as_pending_if_two_phase(location, &assigned_place, kind, idx);

            if let Some(local) = borrowed_place.root_local() {
                self.local_map.entry(local).or_default().insert(idx);
            }
        }

        self.super_assign(block, assigned_place, rvalue, location)
    }

    fn visit_local(
        &mut self,
        temp: &Local,
        context: PlaceContext<'tcx>,
        location: Location,
    ) {
        if !context.is_use() {
            return;
        }

        // We found a use of some temporary TMP
        // check whether we (earlier) saw a 2-phase borrow like
        //
        //     TMP = &mut place
        if let Some(&borrow_index) = self.pending_activations.get(temp) {
            let borrow_data = &mut self.idx_vec[borrow_index];

            // Watch out: the use of TMP in the borrow itself
            // doesn't count as an activation. =)
            if borrow_data.reserve_location == location &&
                context == PlaceContext::MutatingUse(MutatingUseContext::Store)
            {
                return;
            }

            if let TwoPhaseActivation::ActivatedAt(other_location) =
                    borrow_data.activation_location {
                span_bug!(
                    self.mir.source_info(location).span,
                    "found two uses for 2-phase borrow temporary {:?}: \
                     {:?} and {:?}",
                    temp,
                    location,
                    other_location,
                );
            }

            // Otherwise, this is the unique later use that we expect.
            // Double check: This borrow is indeed a two-phase borrow (that is,
            // we are 'transitioning' from `NotActivated` to `ActivatedAt`) and
            // we've not found any other activations (checked above).
            assert_eq!(
                borrow_data.activation_location,
                TwoPhaseActivation::NotActivated,
                "never found an activation for this borrow!",
            );
            self.activation_map
                .entry(location)
                .or_default()
                .push(borrow_index);

            borrow_data.activation_location = TwoPhaseActivation::ActivatedAt(location);
        }
    }

    fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: mir::Location) {
        if let mir::Rvalue::Ref(region, kind, ref place) = *rvalue {
            // double-check that we already registered a BorrowData for this

            let borrow_index = self.location_map[&location];
            let borrow_data = &self.idx_vec[borrow_index];
            assert_eq!(borrow_data.reserve_location, location);
            assert_eq!(borrow_data.kind, kind);
            assert_eq!(borrow_data.region, region.to_region_vid());
            assert_eq!(borrow_data.borrowed_place, *place);
        }

        return self.super_rvalue(rvalue, location);
    }

    fn visit_statement(
        &mut self,
        block: mir::BasicBlock,
        statement: &mir::Statement<'tcx>,
        location: Location,
    ) {
        return self.super_statement(block, statement, location);
    }
}

impl<'a, 'gcx, 'tcx> GatherBorrows<'a, 'gcx, 'tcx> {
    /// Returns `true` if the borrow represented by `kind` is
    /// allowed to be split into separate Reservation and
    /// Activation phases.
    fn allow_two_phase_borrow(&self, kind: mir::BorrowKind) -> bool {
        self.tcx.two_phase_borrows()
            && (kind.allows_two_phase_borrow()
                || self.tcx.sess.opts.debugging_opts.two_phase_beyond_autoref)
    }

    /// If this is a two-phase borrow, then we will record it
    /// as "pending" until we find the activating use.
    fn insert_as_pending_if_two_phase(
        &mut self,
        start_location: Location,
        assigned_place: &mir::Place<'tcx>,
        kind: mir::BorrowKind,
        borrow_index: BorrowIndex,
    ) {
        debug!(
            "Borrows::insert_as_pending_if_two_phase({:?}, {:?}, {:?})",
            start_location, assigned_place, borrow_index,
        );

        if !self.allow_two_phase_borrow(kind) {
            debug!("  -> {:?}", start_location);
            return;
        }

        // When we encounter a 2-phase borrow statement, it will always
        // be assigning into a temporary TEMP:
        //
        //    TEMP = &foo
        //
        // so extract `temp`.
        let temp = if let &mir::Place::Local(temp) = assigned_place {
            temp
        } else {
            span_bug!(
                self.mir.source_info(start_location).span,
                "expected 2-phase borrow to assign to a local, not `{:?}`",
                assigned_place,
            );
        };

        // Consider the borrow not activated to start. When we find an activation, we'll update
        // this field.
        {
            let borrow_data = &mut self.idx_vec[borrow_index];
            borrow_data.activation_location = TwoPhaseActivation::NotActivated;
        }

        // Insert `temp` into the list of pending activations. From
        // now on, we'll be on the lookout for a use of it. Note that
        // we are guaranteed that this use will come after the
        // assignment.
        let old_value = self.pending_activations.insert(temp, borrow_index);
        if let Some(old_index) = old_value {
            span_bug!(self.mir.source_info(start_location).span,
                      "found already pending activation for temp: {:?} \
                       at borrow_index: {:?} with associated data {:?}",
                      temp, old_index, self.idx_vec[old_index]);
        }
    }
}
<|endoftext|>


<commit_before>//! Definitions for l4re-uclibc on 64bit systems

pub type blkcnt_t = i64;
pub type blksize_t = i64;
pub type clock_t = i64;
pub type c_char = u8;
pub type c_long = i64;
pub type c_ulong = u64;
pub type fsblkcnt_t = ::c_ulong;
pub type fsfilcnt_t = ::c_ulong;
pub type fsword_t = ::c_long;
pub type ino_t = ::c_ulong;
pub type nlink_t = ::c_uint;
pub type off_t = ::c_long;
pub type rlim_t = c_ulong;
pub type rlim64_t = u64;
pub type suseconds_t = ::c_long;
pub type time_t = ::c_int;
pub type wchar_t = ::c_int;

// ToDo, used?
//pub type d_ino = ::c_ulong;
pub type nfds_t = ::c_ulong;

s! {
    pub struct ipc_perm {
        pub __key: ::key_t,
        pub uid: ::uid_t,
        pub gid: ::gid_t,
        pub cuid: ::uid_t,
        pub cgid: ::gid_t,
        pub mode: ::c_ushort, // read / write
        __pad1: ::c_ushort,
        pub __seq: ::c_ushort,
        __pad2: ::c_ushort,
        __unused1: ::c_ulong,
        __unused2: ::c_ulong
    }

    pub struct siginfo_t {
        si_signo: ::c_int, // signal number
        si_errno: ::c_int, // if not zero: error value of signal, see errno.h
        si_code: ::c_int,  // signal code
        pub _pad: [::c_int; 28], // unported union
        _align: [usize; 0],
    }

    pub struct shmid_ds {
        pub shm_perm: ::ipc_perm,
        pub shm_segsz: ::size_t, // segment size in bytes
        pub shm_atime: ::time_t, // time of last shmat()
        pub shm_dtime: ::time_t,
        pub shm_ctime: ::time_t,
        pub shm_cpid: ::pid_t,
        pub shm_lpid: ::pid_t,
        pub shm_nattch: ::shmatt_t,
        __unused1: ::c_ulong,
        __unused2: ::c_ulong
    }

    pub struct msqid_ds {
        pub msg_perm: ::ipc_perm,
        pub msg_stime: ::time_t,
        pub msg_rtime: ::time_t,
        pub msg_ctime: ::time_t,
        __msg_cbytes: ::c_ulong,
        pub msg_qnum: ::msgqnum_t,
        pub msg_qbytes: ::msglen_t,
        pub msg_lspid: ::pid_t,
        pub msg_lrpid: ::pid_t,
        __ignored1: ::c_ulong,
        __ignored2: ::c_ulong,
    }

    pub struct sockaddr {
        pub sa_family: ::sa_family_t,
        pub sa_data: [::c_char; 14],
    }

    pub struct sockaddr_in {
        pub sin_family: ::sa_family_t,
        pub sin_port: ::in_port_t,
        pub sin_addr: ::in_addr,
        pub sin_zero: [u8; 8],
    }

    pub struct sockaddr_in6 {
        pub sin6_family: ::sa_family_t,
        pub sin6_port: ::in_port_t,
        pub sin6_flowinfo: u32,
        pub sin6_addr: ::in6_addr,
        pub sin6_scope_id: u32,
    }

    // ------------------------------------------------------------
    // definitions below are *unverified* and might **break** the software
//    pub struct in_addr {
//        pub s_addr: in_addr_t,
//    }
//
//    pub struct in6_addr {
//        pub s6_addr: [u8; 16],
//        __align: [u32; 0],
//    }

    pub struct stat { // ToDo
        pub st_dev: ::c_ulong,
        st_pad1: [::c_long; 2],
        pub st_ino: ::ino_t,
        pub st_mode: ::mode_t,
        pub st_nlink: ::nlink_t,
        pub st_uid: ::uid_t,
        pub st_gid: ::gid_t,
        pub st_rdev: u64,
        pub st_pad2: [u64; 1],
        pub st_size: off_t,
        st_pad3: ::c_long,
        pub st_atime: ::time_t,
        pub st_atime_nsec: ::c_long,
        pub st_mtime: ::time_t,
        pub st_mtime_nsec: ::c_long,
        pub st_ctime: ::time_t,
        pub st_ctime_nsec: ::c_long,
        pub st_blksize: ::blksize_t,
        st_pad4: ::c_long,
        pub st_blocks: ::blkcnt_t,
        st_pad5: [::c_long; 7],
    }

    pub struct statvfs { // ToDo: broken
        pub f_bsize: ::c_ulong,
        pub f_frsize: ::c_ulong,
        pub f_blocks: ::fsblkcnt_t,
        pub f_bfree: ::fsblkcnt_t,
        pub f_bavail: ::fsblkcnt_t,
        pub f_files: ::fsfilcnt_t,
        pub f_ffree: ::fsfilcnt_t,
        pub f_favail: ::fsfilcnt_t,
        #[cfg(target_endian = "little")]
        pub f_fsid: ::c_ulong,
        #[cfg(target_pointer_width = "32")]
        __f_unused: ::c_int,
        #[cfg(target_endian = "big")]
        pub f_fsid: ::c_ulong,
        pub f_flag: ::c_ulong,
        pub f_namemax: ::c_ulong,
        __f_spare: [::c_int; 6],
    }

    pub struct dirent { // Todo
        pub d_ino: ::ino64_t,
        pub d_off: ::off64_t,
        d_reclen: u16,
        pub d_type: u8,
        pub d_name: [i8; 256],
    }

    pub struct dirent64 { //
        pub d_ino: ::ino64_t,
        pub d_off: ::off64_t,
        pub d_reclen: u16,
        pub d_type: u8,
        pub d_name: [i8; 256],
    }

    pub struct pthread_attr_t { // ToDo
        __size: [u64; 7]
    }

    pub struct sigaction { // TODO!!
        pub sa_sigaction: ::sighandler_t,
        pub sa_mask: ::sigset_t,
        #[cfg(target_arch = "sparc64")]
        __reserved0: ::c_int,
        pub sa_flags: ::c_int,
        _restorer: *mut ::c_void,
    }

    pub struct stack_t { // ToDo
        pub ss_sp: *mut ::c_void,
        pub ss_flags: ::c_int,
        pub ss_size: ::size_t
    }

    pub struct statfs { // ToDo
        pub f_type: fsword_t,
        pub f_bsize: fsword_t,
        pub f_blocks: ::fsblkcnt_t,
        pub f_bfree: ::fsblkcnt_t,
        pub f_bavail: ::fsblkcnt_t,
        pub f_files: ::fsfilcnt_t,
        pub f_ffree: ::fsfilcnt_t,
        pub f_fsid: ::fsid_t,
        pub f_namelen: fsword_t,
        pub f_frsize: fsword_t,
        f_spare: [fsword_t; 5],
    }

    pub struct msghdr { // ToDo
        pub msg_name: *mut ::c_void,
        pub msg_namelen: ::socklen_t,
        pub msg_iov: *mut ::iovec,
        pub msg_iovlen: ::size_t,
        pub msg_control: *mut ::c_void,
        pub msg_controllen: ::size_t,
        pub msg_flags: ::c_int,
    }

    pub struct termios { // ToDo
        pub c_iflag: ::tcflag_t,
        pub c_oflag: ::tcflag_t,
        pub c_cflag: ::tcflag_t,
        pub c_lflag: ::tcflag_t,
        pub c_line: ::cc_t,
        pub c_cc: [::cc_t; ::NCCS],
    }

    pub struct sem_t { // ToDo
        #[cfg(target_pointer_width = "32")]
        __size: [::c_char; 16],
        #[cfg(target_pointer_width = "64")]
        __size: [::c_char; 32],
        __align: [::c_long; 0],
    }

    pub struct pthread_mutex_t { // ToDo
        #[cfg(any(target_arch = "mips", target_arch = "arm",
                  target_arch = "powerpc"))]
        __align: [::c_long; 0],
        #[cfg(not(any(target_arch = "mips", target_arch = "arm",
                      target_arch = "powerpc")))]
        __align: [::c_longlong; 0],
        size: [u8; __SIZEOF_PTHREAD_MUTEX_T],
    }

    pub struct pthread_mutexattr_t { // ToDo
        #[cfg(any(target_arch = "x86_64", target_arch = "powerpc64",
                  target_arch = "mips64", target_arch = "s390x",
                  target_arch = "sparc64"))]
        __align: [::c_int; 0],
        #[cfg(not(any(target_arch = "x86_64", target_arch = "powerpc64",
                      target_arch = "mips64", target_arch = "s390x",
                      target_arch = "sparc64")))]
        __align: [::c_long; 0],
        size: [u8; __SIZEOF_PTHREAD_MUTEXATTR_T],
    }

    pub struct pthread_cond_t { // ToDo
        __align: [::c_longlong; 0],
        size: [u8; __SIZEOF_PTHREAD_COND_T],
    }

    pub struct pthread_condattr_t { // ToDo
        __align: [::c_int; 0],
        size: [u8; __SIZEOF_PTHREAD_CONDATTR_T],
    }

    pub struct pthread_rwlock_t { // ToDo
        #[cfg(any(target_arch = "mips", target_arch = "arm",
                  target_arch = "powerpc"))]
        __align: [::c_long; 0],
        #[cfg(not(any(target_arch = "mips", target_arch = "arm",
                      target_arch = "powerpc")))]
        __align: [::c_longlong; 0],
        size: [u8; __SIZEOF_PTHREAD_RWLOCK_T],
    }

    pub struct sigset_t { // ToDo
        __val: [::c_ulong; 16],
    }

    pub struct sysinfo { // ToDo
        pub uptime: ::c_long,
        pub loads: [::c_ulong; 3],
        pub totalram: ::c_ulong,
        pub freeram: ::c_ulong,
        pub sharedram: ::c_ulong,
        pub bufferram: ::c_ulong,
        pub totalswap: ::c_ulong,
        pub freeswap: ::c_ulong,
        pub procs: ::c_ushort,
        pub pad: ::c_ushort,
        pub totalhigh: ::c_ulong,
        pub freehigh: ::c_ulong,
        pub mem_unit: ::c_uint,
        pub _f: [::c_char; 0],
    }

    pub struct glob_t { // ToDo
        pub gl_pathc: ::size_t,
        pub gl_pathv: *mut *mut c_char,
        pub gl_offs: ::size_t,
        pub gl_flags: ::c_int,
        __unused1: *mut ::c_void,
        __unused2: *mut ::c_void,
        __unused3: *mut ::c_void,
        __unused4: *mut ::c_void,
        __unused5: *mut ::c_void,
    }

    pub struct stat64 { // ToDo
        pub st_dev: ::dev_t,
        pub st_ino: ::ino64_t,
        pub st_nlink: ::nlink_t,
        pub st_mode: ::mode_t,
        pub st_uid: ::uid_t,
        pub st_gid: ::gid_t,
        __pad0: ::c_int,
        pub st_rdev: ::dev_t,
        pub st_size: ::off_t,
        pub st_blksize: ::blksize_t,
        pub st_blocks: ::blkcnt64_t,
        pub st_atime: ::time_t,
        pub st_atime_nsec: ::c_long,
        pub st_mtime: ::time_t,
        pub st_mtime_nsec: ::c_long,
        pub st_ctime: ::time_t,
        pub st_ctime_nsec: ::c_long,
        __reserved: [::c_long; 3],
    }

    pub struct rlimit64 { // ToDo
        pub rlim_cur: rlim64_t,
        pub rlim_max: rlim64_t,
    }

    pub struct cpu_set_t { // ToDo
        #[cfg(target_pointer_width = "32")]
        bits: [u32; 32],
        #[cfg(target_pointer_width = "64")]
        bits: [u64; 16],
    }

    pub struct timespec { // ToDo
        tv_sec: time_t, // seconds
        tv_nsec: ::c_ulong, // nanoseconds
    }

    pub struct fsid_t { // ToDo
        __val: [::c_int; 2],
    }
}

// constants
pub const O_CLOEXEC: ::c_int = 0x80000;
pub const O_DIRECTORY: ::c_int = 0200000;
pub const NCCS: usize = 32;
pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 40;
pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4;
pub const PTHREAD_MUTEX_NORMAL: ::c_int = 0;
pub const PTHREAD_MUTEX_RECURSIVE: ::c_int = 1;
pub const PTHREAD_MUTEX_ERRORCHECK: ::c_int = 2;
pub const PTHREAD_MUTEX_DEFAULT: ::c_int = PTHREAD_MUTEX_NORMAL;
pub const RLIM_INFINITY: u64 = 0xffffffffffffffff;
pub const __SIZEOF_PTHREAD_COND_T: usize = 48;
pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4;
pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56;

extern {
    pub fn memalign(align: ::size_t, size: ::size_t) -> *mut ::c_void;
}
<commit_msg>Improve types for uclibc/x86_64<commit_after>//! Definitions for l4re-uclibc on 64bit systems

pub type blkcnt_t = i64;
pub type blksize_t = i64;
pub type clock_t = i64;
pub type c_char = u8;
pub type c_long = i64;
pub type c_ulong = u64;
pub type fsblkcnt_t = ::c_ulong;
pub type fsfilcnt_t = ::c_ulong;
pub type fsword_t = ::c_long;
pub type ino_t = ::c_ulong;
pub type nlink_t = ::c_uint;
pub type off_t = ::c_long;
pub type rlim_t = c_ulong;
pub type rlim64_t = u64;
pub type suseconds_t = ::c_long;
pub type time_t = ::c_int;
pub type wchar_t = ::c_int;

// ToDo, used?
//pub type d_ino = ::c_ulong;
pub type nfds_t = ::c_ulong;

// L4Re specifics
// Some of these aren't actually part of the libc, but of l4sys, but since libc
// depends on l4sys on this platform, we should dump the few important
// definitions here.
pub type l4_umword_t = ::c_ulong; // Unsigned machine word.

s! {
    pub struct dirent {
        pub d_ino: ::ino64_t,
        pub d_off: ::off64_t,
        pub d_reclen: u16,
        pub d_type: u8,
        pub d_name: [::c_char; 256],
    }

    pub struct dirent64 {
        pub d_ino: ::ino64_t,
        pub d_off: ::off64_t,
        pub d_reclen: u16,
        pub d_type: u8,
        pub d_name: [::c_char; 256],
    }

    pub struct ipc_perm {
        pub __key: ::key_t,
        pub uid: ::uid_t,
        pub gid: ::gid_t,
        pub cuid: ::uid_t,
        pub cgid: ::gid_t,
        pub mode: ::c_ushort, // read / write
        __pad1: ::c_ushort,
        pub __seq: ::c_ushort,
        __pad2: ::c_ushort,
        __unused1: ::c_ulong,
        __unused2: ::c_ulong
    }

    /// CPU sets.
    pub struct l4_sched_cpu_set_t {
        // from the L4Re docs
        /// Combination of granularity and offset.
        ///
        /// The granularity defines how many CPUs each bit in map describes.
        /// The offset is the numer of the first CPU described by the first
        /// bit in the bitmap.
        /// offset must be a multiple of 2^graularity.
        ///
        /// | MSB              |                 LSB |
        /// | ---------------- | ------------------- |
        /// | 8bit granularity | 24bit offset ..     |
        gran_offset: l4_umword_t ,
        /// Bitmap of CPUs.
        map: l4_umword_t ,
    }

    pub struct pthread_attr_t {
        __detachstate: ::c_int,
        __schedpolicy: ::c_int,
        __schedparam: __sched_param,
        __inheritsched: ::c_int,
        __scope: ::c_int,
        __guardsize: ::size_t,
        __stackaddr_set: ::c_int,
        __stackaddr: *mut ::c_void, // better don't use it
        __stacksize: ::size_t,
        // L4Re specifics
        affinity: l4_sched_cpu_set_t,
        create_flags: ::c_uint,
    }

    pub struct __sched_param {
        __sched_priority: ::c_int,
    }

    pub struct siginfo_t {
        si_signo: ::c_int, // signal number
        si_errno: ::c_int, // if not zero: error value of signal, see errno.h
        si_code: ::c_int,  // signal code
        pub _pad: [::c_int; 28], // unported union
        _align: [usize; 0],
    }

    pub struct shmid_ds {
        pub shm_perm: ::ipc_perm,
        pub shm_segsz: ::size_t, // segment size in bytes
        pub shm_atime: ::time_t, // time of last shmat()
        pub shm_dtime: ::time_t,
        pub shm_ctime: ::time_t,
        pub shm_cpid: ::pid_t,
        pub shm_lpid: ::pid_t,
        pub shm_nattch: ::shmatt_t,
        __unused1: ::c_ulong,
        __unused2: ::c_ulong
    }

    pub struct msqid_ds {
        pub msg_perm: ::ipc_perm,
        pub msg_stime: ::time_t,
        pub msg_rtime: ::time_t,
        pub msg_ctime: ::time_t,
        __msg_cbytes: ::c_ulong,
        pub msg_qnum: ::msgqnum_t,
        pub msg_qbytes: ::msglen_t,
        pub msg_lspid: ::pid_t,
        pub msg_lrpid: ::pid_t,
        __ignored1: ::c_ulong,
        __ignored2: ::c_ulong,
    }

    pub struct sockaddr {
        pub sa_family: ::sa_family_t,
        pub sa_data: [::c_char; 14],
    }

    pub struct sockaddr_in {
        pub sin_family: ::sa_family_t,
        pub sin_port: ::in_port_t,
        pub sin_addr: ::in_addr,
        pub sin_zero: [u8; 8],
    }

    pub struct sockaddr_in6 {
        pub sin6_family: ::sa_family_t,
        pub sin6_port: ::in_port_t,
        pub sin6_flowinfo: u32,
        pub sin6_addr: ::in6_addr,
        pub sin6_scope_id: u32,
    }

    // ------------------------------------------------------------
    // definitions below are *unverified* and might **break** the software
//    pub struct in_addr {
//        pub s_addr: in_addr_t,
//    }
//
//    pub struct in6_addr {
//        pub s6_addr: [u8; 16],
//        __align: [u32; 0],
//    }

    pub struct stat { // ToDo
        pub st_dev: ::c_ulong,
        st_pad1: [::c_long; 2],
        pub st_ino: ::ino_t,
        pub st_mode: ::mode_t,
        pub st_nlink: ::nlink_t,
        pub st_uid: ::uid_t,
        pub st_gid: ::gid_t,
        pub st_rdev: u64,
        pub st_pad2: [u64; 1],
        pub st_size: off_t,
        st_pad3: ::c_long,
        pub st_atime: ::time_t,
        pub st_atime_nsec: ::c_long,
        pub st_mtime: ::time_t,
        pub st_mtime_nsec: ::c_long,
        pub st_ctime: ::time_t,
        pub st_ctime_nsec: ::c_long,
        pub st_blksize: ::blksize_t,
        st_pad4: ::c_long,
        pub st_blocks: ::blkcnt_t,
        st_pad5: [::c_long; 7],
    }

    pub struct statvfs { // ToDo: broken
        pub f_bsize: ::c_ulong,
        pub f_frsize: ::c_ulong,
        pub f_blocks: ::fsblkcnt_t,
        pub f_bfree: ::fsblkcnt_t,
        pub f_bavail: ::fsblkcnt_t,
        pub f_files: ::fsfilcnt_t,
        pub f_ffree: ::fsfilcnt_t,
        pub f_favail: ::fsfilcnt_t,
        #[cfg(target_endian = "little")]
        pub f_fsid: ::c_ulong,
        #[cfg(target_pointer_width = "32")]
        __f_unused: ::c_int,
        #[cfg(target_endian = "big")]
        pub f_fsid: ::c_ulong,
        pub f_flag: ::c_ulong,
        pub f_namemax: ::c_ulong,
        __f_spare: [::c_int; 6],
    }

    pub struct sigaction { // TODO!!
        pub sa_sigaction: ::sighandler_t,
        pub sa_mask: ::sigset_t,
        #[cfg(target_arch = "sparc64")]
        __reserved0: ::c_int,
        pub sa_flags: ::c_int,
        _restorer: *mut ::c_void,
    }

    pub struct stack_t { // ToDo
        pub ss_sp: *mut ::c_void,
        pub ss_flags: ::c_int,
        pub ss_size: ::size_t
    }

    pub struct statfs { // ToDo
        pub f_type: fsword_t,
        pub f_bsize: fsword_t,
        pub f_blocks: ::fsblkcnt_t,
        pub f_bfree: ::fsblkcnt_t,
        pub f_bavail: ::fsblkcnt_t,
        pub f_files: ::fsfilcnt_t,
        pub f_ffree: ::fsfilcnt_t,
        pub f_fsid: ::fsid_t,
        pub f_namelen: fsword_t,
        pub f_frsize: fsword_t,
        f_spare: [fsword_t; 5],
    }

    pub struct msghdr { // ToDo
        pub msg_name: *mut ::c_void,
        pub msg_namelen: ::socklen_t,
        pub msg_iov: *mut ::iovec,
        pub msg_iovlen: ::size_t,
        pub msg_control: *mut ::c_void,
        pub msg_controllen: ::size_t,
        pub msg_flags: ::c_int,
    }

    pub struct termios { // ToDo
        pub c_iflag: ::tcflag_t,
        pub c_oflag: ::tcflag_t,
        pub c_cflag: ::tcflag_t,
        pub c_lflag: ::tcflag_t,
        pub c_line: ::cc_t,
        pub c_cc: [::cc_t; ::NCCS],
    }

    pub struct sem_t { // ToDo
        #[cfg(target_pointer_width = "32")]
        __size: [::c_char; 16],
        #[cfg(target_pointer_width = "64")]
        __size: [::c_char; 32],
        __align: [::c_long; 0],
    }

    pub struct pthread_mutex_t { // ToDo
        #[cfg(any(target_arch = "mips", target_arch = "arm",
                  target_arch = "powerpc"))]
        __align: [::c_long; 0],
        #[cfg(not(any(target_arch = "mips", target_arch = "arm",
                      target_arch = "powerpc")))]
        __align: [::c_longlong; 0],
        size: [u8; __SIZEOF_PTHREAD_MUTEX_T],
    }

    pub struct pthread_mutexattr_t { // ToDo
        #[cfg(any(target_arch = "x86_64", target_arch = "powerpc64",
                  target_arch = "mips64", target_arch = "s390x",
                  target_arch = "sparc64"))]
        __align: [::c_int; 0],
        #[cfg(not(any(target_arch = "x86_64", target_arch = "powerpc64",
                      target_arch = "mips64", target_arch = "s390x",
                      target_arch = "sparc64")))]
        __align: [::c_long; 0],
        size: [u8; __SIZEOF_PTHREAD_MUTEXATTR_T],
    }

    pub struct pthread_cond_t { // ToDo
        __align: [::c_longlong; 0],
        size: [u8; __SIZEOF_PTHREAD_COND_T],
    }

    pub struct pthread_condattr_t { // ToDo
        __align: [::c_int; 0],
        size: [u8; __SIZEOF_PTHREAD_CONDATTR_T],
    }

    pub struct pthread_rwlock_t { // ToDo
        #[cfg(any(target_arch = "mips", target_arch = "arm",
                  target_arch = "powerpc"))]
        __align: [::c_long; 0],
        #[cfg(not(any(target_arch = "mips", target_arch = "arm",
                      target_arch = "powerpc")))]
        __align: [::c_longlong; 0],
        size: [u8; __SIZEOF_PTHREAD_RWLOCK_T],
    }

    pub struct sigset_t { // ToDo
        __val: [::c_ulong; 16],
    }

    pub struct sysinfo { // ToDo
        pub uptime: ::c_long,
        pub loads: [::c_ulong; 3],
        pub totalram: ::c_ulong,
        pub freeram: ::c_ulong,
        pub sharedram: ::c_ulong,
        pub bufferram: ::c_ulong,
        pub totalswap: ::c_ulong,
        pub freeswap: ::c_ulong,
        pub procs: ::c_ushort,
        pub pad: ::c_ushort,
        pub totalhigh: ::c_ulong,
        pub freehigh: ::c_ulong,
        pub mem_unit: ::c_uint,
        pub _f: [::c_char; 0],
    }

    pub struct glob_t { // ToDo
        pub gl_pathc: ::size_t,
        pub gl_pathv: *mut *mut c_char,
        pub gl_offs: ::size_t,
        pub gl_flags: ::c_int,
        __unused1: *mut ::c_void,
        __unused2: *mut ::c_void,
        __unused3: *mut ::c_void,
        __unused4: *mut ::c_void,
        __unused5: *mut ::c_void,
    }

    pub struct stat64 { // ToDo
        pub st_dev: ::dev_t,
        pub st_ino: ::ino64_t,
        pub st_nlink: ::nlink_t,
        pub st_mode: ::mode_t,
        pub st_uid: ::uid_t,
        pub st_gid: ::gid_t,
        __pad0: ::c_int,
        pub st_rdev: ::dev_t,
        pub st_size: ::off_t,
        pub st_blksize: ::blksize_t,
        pub st_blocks: ::blkcnt64_t,
        pub st_atime: ::time_t,
        pub st_atime_nsec: ::c_long,
        pub st_mtime: ::time_t,
        pub st_mtime_nsec: ::c_long,
        pub st_ctime: ::time_t,
        pub st_ctime_nsec: ::c_long,
        __reserved: [::c_long; 3],
    }

    pub struct rlimit64 { // ToDo
        pub rlim_cur: rlim64_t,
        pub rlim_max: rlim64_t,
    }

    pub struct cpu_set_t { // ToDo
        #[cfg(target_pointer_width = "32")]
        bits: [u32; 32],
        #[cfg(target_pointer_width = "64")]
        bits: [u64; 16],
    }

    pub struct timespec { // ToDo
        tv_sec: time_t, // seconds
        tv_nsec: ::c_ulong, // nanoseconds
    }

    pub struct fsid_t { // ToDo
        __val: [::c_int; 2],
    }
}

// constants
pub const O_CLOEXEC: ::c_int = 0x80000;
pub const O_DIRECTORY: ::c_int = 0200000;
pub const NCCS: usize = 32;
pub const __SIZEOF_PTHREAD_MUTEX_T: usize = 40;
pub const __SIZEOF_PTHREAD_MUTEXATTR_T: usize = 4;
pub const PTHREAD_MUTEX_NORMAL: ::c_int = 0;
pub const PTHREAD_MUTEX_RECURSIVE: ::c_int = 1;
pub const PTHREAD_MUTEX_ERRORCHECK: ::c_int = 2;
pub const PTHREAD_MUTEX_DEFAULT: ::c_int = PTHREAD_MUTEX_NORMAL;
pub const RLIM_INFINITY: u64 = 0xffffffffffffffff;
pub const __SIZEOF_PTHREAD_COND_T: usize = 48;
pub const __SIZEOF_PTHREAD_CONDATTR_T: usize = 4;
pub const __SIZEOF_PTHREAD_RWLOCK_T: usize = 56;

extern {
    pub fn memalign(align: ::size_t, size: ::size_t) -> *mut ::c_void;
}
<|endoftext|>


<commit_before>/// Generates a variation of the suffix array for fast codepoint name searching
/// by substring.
///
/// https://en.wikipedia.org/wiki/Suffix_array (note: Wikipedia uses 1-based
/// indexing but here we will use 0-based for implementation parity)
///
/// Suffix arrays provide fast substring lookup into a string by allowing one
/// to binary search for any suffix in said string, however for our purposes
/// we need to search multiple strings (each Unicode character name), matching
/// all codepoints whose names contain said substring. To achieve this we
/// concatenate all the names together, storing the codepoint alongside the
/// indexes.
///
/// For example the imaginary codepoints "one" as \x01 and "five" as \x05 would
/// be joined to form S = "one$five$". '$' is a sentinel character that is
/// lexicographically smaller than all other characters, in the implementation
/// a newline character is used to make the generated file look nicer.
///
/// Because no pattern contains the sentinel, the suffix "ne$five$" is
/// equivalent to "ne$", we also omit suffixes that begin with a sentinel, e.g.
/// "$five$" (i = 3) or "$" (i = 8) to save some bytes.
///
/// Starting with the suffixes of S
///
/// | Suffix | i | c |
/// | ------ | - | - |
/// | one$   | 0 | 1 |
/// | ne$    | 1 | 1 |
/// | e$     | 2 | 1 |
/// | five$  | 4 | 5 |
/// | ive$   | 5 | 5 |
/// | ve$    | 6 | 5 |
/// | e$     | 7 | 5 |
///
/// They are then sorted lexicographically by suffix to become
///
/// | Suffix | i | c |
/// | ------ | - | - |
/// | e$     | 2 | 1 |
/// | e$     | 7 | 5 |
/// | five$  | 4 | 5 |
/// | ive$   | 5 | 5 |
/// | ne$    | 1 | 1 |
/// | one$   | 0 | 1 |
/// | ve$    | 6 | 5 |
///
/// Since we don't need to know where in the combined string our suffix is, only
/// which codepoint it corresponds to we can join the entries for "e$", losing
/// the information that there is a suffix at index 7. This costs a few bytes
/// per entry since the codepoint array is now an array of arrays, however since
/// there are around 18x fewer entries in total for this dataset the trade-off
/// is well worth it.
///
/// After removing duplicates and the temporary suffixes the remaining data is:
///
/// - The combined string S = "one$five$",
/// - The suffix array A,
/// - The corresponding codepoints C
///
/// | i | A[i] | C[i] |
/// | - | ---- | ---- |
/// | 0 |    2 | 1, 5 |
/// | 1 |    4 |    5 |
/// | 2 |    5 |    5 |
/// | 3 |    1 |    1 |
/// | 4 |    0 |    1 |
/// | 5 |    6 |    5 |
///
/// This is the final table that we will use to search for name matches. The
/// suffix for each entry at i can be enumerated by iterating through the string
/// S beginning at index A[i].
///
/// | i | S[A[i]..] | A[i] | C[i] |
/// | - | -------   | ---- | ---- |
/// | 0 | e$five$   |    2 | 1, 5 |
/// | 1 | five$     |    4 |    5 |
/// | 2 | ive$      |    5 |    5 |
/// | 3 | ne$five$  |    1 |    1 |
/// | 4 | one$five$ |    0 |    1 |
/// | 5 | ve$       |    6 |    5 |
///
/// To find all the matches we have to find all the suffixes that begin with the
/// input pattern. Since the table is sorted these suffixes are all contiguous,
/// to locate them we perform two binary searches. One search to find the first
/// matching suffix and for the last.
///
/// https://en.wikipedia.org/wiki/Suffix_array#Applications
///
/// With the range of suffixes found the list of codepoints can be enumerated
/// for the interval C[first..last].
///
/// # Extra
///
/// Not shown is a further optimisation where each Unicode character name is
/// split into individual words, e.g. "DIGIT ONE" adds "DIGIT$" and "ONE$" to
/// the table separately. This allows us to deduplicate the many occurrences of
/// words such as "LETTER" that appear in the middle of names. This reduction
/// makes both the tables A and C smaller as well as the combined string S,
/// drastically reducing the space requirement.
///
/// This means that multiword searches will no longer work directly since no
/// suffixes contain spaces. Instead we also split the input pattern into words
/// and search individually once for each word. Each word gives us a set of
/// codepoints, the final result in the union of all word subresults.
///
/// For example "LATIN LETTER" is split into patterns "LATIN" and "LETTER",
/// the final result is codepoints that match both "LATIN" and "LETTER". This
/// means that word order of the input pattern no longer has an effect on the
/// result, allowing "LATIN LETTER" to match "LATIN SMALL LETTER A".
///
/// Additionally, a small extra saving can be had by removing duplicate
/// codepoints for a single suffix.  For example in "LEFT SQUARE BRACKET" when
/// split into words "LEFT$", "SQUARE$" and "BRACKET$" the suffix "T$" appears
/// twice. The "T$" suffix is already deduplicated however the codepoint for
/// LEFT SQUARE BRACKET will appear twice in C[i], this is simply removed.

// TODO:
// - investigate LEB128 encoding, potential savings for codepoints array
// - investigate fm-index/wavelet-trees

extern crate leb128;
extern crate ucd_raw;

use std::collections::HashMap;
use std::fs::File;
use std::io::BufWriter;
use std::time::Instant;
use ucd_raw::Character;
use ucd_raw::CHARACTERS;

#[derive(Debug)]
struct TempSuffix<'a> {
    suffix: &'a str,
    index: usize,
    codepoints: Vec<u32>,
}

fn char_iter() -> impl Iterator<Item = &'static Character> {
    CHARACTERS
        .iter()
        .filter(|character| match character.codepoint {
            0x03400...0x04DB5 => false,
            0x04E00...0x09FEA => false,
            0x20000...0x2A6D6 => false,
            0x2A700...0x2B734 => false,
            0x2B740...0x2B81D => false,
            0x2B820...0x2CEA1 => false,
            0x2CEB0...0x2EBE0 => false,
            0x17000...0x187EC => false,
            0x1B170...0x1B2FB => false,
            0x0F900...0x0FA6D => false,
            0x0FA70...0x0FAD9 => false,
            0x2F800...0x2FA1D => false,
            _ => true,
        })
}

fn suffixes<'a>(string: &'a str) -> impl Iterator<Item = (usize, &'a str)> {
    (0..string.len()).map(move |i| &string[i..]).enumerate()
}

fn main() {
    println!("indexing {} codepoints...", char_iter().count());

    let start = Instant::now();

    let mut combined = String::new();
    let mut visited_words = HashMap::new();
    let mut temp_suffixes = Vec::new();

    let out = File::create("utf/src/generated.bin").unwrap();
    let mut out = BufWriter::new(out);

    for character in char_iter() {
        for word in character.name.split_whitespace() {
            let mut start;

            if visited_words.contains_key(word) {
                start = visited_words[word];
            } else {
                start = combined.len();

                visited_words.insert(word, start);
                combined.push_str(word);
                combined.push('\n');
            }

            for (offset, suffix) in suffixes(word) {
                temp_suffixes.push(TempSuffix {
                    suffix,
                    index: start + offset,
                    codepoints: vec![character.codepoint],
                });
            }
        }
    }

    temp_suffixes.sort_unstable_by_key(|temp_suffix| temp_suffix.suffix);

    println!("length before dedup: {}", temp_suffixes.len());

    temp_suffixes.dedup_by(|a, b| {
        let equal = a.suffix == b.suffix;

        if equal {
            b.codepoints.extend_from_slice(&a.codepoints);
        }

        equal
    });

    for suffix in &mut temp_suffixes {
        suffix.codepoints.sort_unstable();
        suffix.codepoints.dedup();
    }

    println!("after: {}", temp_suffixes.len());

    for suffix in temp_suffixes {
        leb128::write::unsigned(&mut out, suffix.index as u64).unwrap();
        leb128::write::unsigned(&mut out, suffix.codepoints.len() as u64).unwrap();

        let mut last = 0;
        for codepoint in suffix.codepoints {
            let delta = codepoint - last;
            last = codepoint;

            leb128::write::unsigned(&mut out, delta as u64).unwrap();
        }
    }

    println!("Generated in {:?}", start.elapsed());
}
<commit_msg>Write combined string to file<commit_after>/// Generates a variation of the suffix array for fast codepoint name searching
/// by substring.
///
/// https://en.wikipedia.org/wiki/Suffix_array (note: Wikipedia uses 1-based
/// indexing but here we will use 0-based for implementation parity)
///
/// Suffix arrays provide fast substring lookup into a string by allowing one
/// to binary search for any suffix in said string, however for our purposes
/// we need to search multiple strings (each Unicode character name), matching
/// all codepoints whose names contain said substring. To achieve this we
/// concatenate all the names together, storing the codepoint alongside the
/// indexes.
///
/// For example the imaginary codepoints "one" as \x01 and "five" as \x05 would
/// be joined to form S = "one$five$". '$' is a sentinel character that is
/// lexicographically smaller than all other characters, in the implementation
/// a newline character is used to make the generated file look nicer.
///
/// Because no pattern contains the sentinel, the suffix "ne$five$" is
/// equivalent to "ne$", we also omit suffixes that begin with a sentinel, e.g.
/// "$five$" (i = 3) or "$" (i = 8) to save some bytes.
///
/// Starting with the suffixes of S
///
/// | Suffix | i | c |
/// | ------ | - | - |
/// | one$   | 0 | 1 |
/// | ne$    | 1 | 1 |
/// | e$     | 2 | 1 |
/// | five$  | 4 | 5 |
/// | ive$   | 5 | 5 |
/// | ve$    | 6 | 5 |
/// | e$     | 7 | 5 |
///
/// They are then sorted lexicographically by suffix to become
///
/// | Suffix | i | c |
/// | ------ | - | - |
/// | e$     | 2 | 1 |
/// | e$     | 7 | 5 |
/// | five$  | 4 | 5 |
/// | ive$   | 5 | 5 |
/// | ne$    | 1 | 1 |
/// | one$   | 0 | 1 |
/// | ve$    | 6 | 5 |
///
/// Since we don't need to know where in the combined string our suffix is, only
/// which codepoint it corresponds to we can join the entries for "e$", losing
/// the information that there is a suffix at index 7. This costs a few bytes
/// per entry since the codepoint array is now an array of arrays, however since
/// there are around 18x fewer entries in total for this dataset the trade-off
/// is well worth it.
///
/// After removing duplicates and the temporary suffixes the remaining data is:
///
/// - The combined string S = "one$five$",
/// - The suffix array A,
/// - The corresponding codepoints C
///
/// | i | A[i] | C[i] |
/// | - | ---- | ---- |
/// | 0 |    2 | 1, 5 |
/// | 1 |    4 |    5 |
/// | 2 |    5 |    5 |
/// | 3 |    1 |    1 |
/// | 4 |    0 |    1 |
/// | 5 |    6 |    5 |
///
/// This is the final table that we will use to search for name matches. The
/// suffix for each entry at i can be enumerated by iterating through the string
/// S beginning at index A[i].
///
/// | i | S[A[i]..] | A[i] | C[i] |
/// | - | -------   | ---- | ---- |
/// | 0 | e$five$   |    2 | 1, 5 |
/// | 1 | five$     |    4 |    5 |
/// | 2 | ive$      |    5 |    5 |
/// | 3 | ne$five$  |    1 |    1 |
/// | 4 | one$five$ |    0 |    1 |
/// | 5 | ve$       |    6 |    5 |
///
/// To find all the matches we have to find all the suffixes that begin with the
/// input pattern. Since the table is sorted these suffixes are all contiguous,
/// to locate them we perform two binary searches. One search to find the first
/// matching suffix and for the last.
///
/// https://en.wikipedia.org/wiki/Suffix_array#Applications
///
/// With the range of suffixes found the list of codepoints can be enumerated
/// for the interval C[first..last].
///
/// # Extra
///
/// Not shown is a further optimisation where each Unicode character name is
/// split into individual words, e.g. "DIGIT ONE" adds "DIGIT$" and "ONE$" to
/// the table separately. This allows us to deduplicate the many occurrences of
/// words such as "LETTER" that appear in the middle of names. This reduction
/// makes both the tables A and C smaller as well as the combined string S,
/// drastically reducing the space requirement.
///
/// This means that multiword searches will no longer work directly since no
/// suffixes contain spaces. Instead we also split the input pattern into words
/// and search individually once for each word. Each word gives us a set of
/// codepoints, the final result in the union of all word subresults.
///
/// For example "LATIN LETTER" is split into patterns "LATIN" and "LETTER",
/// the final result is codepoints that match both "LATIN" and "LETTER". This
/// means that word order of the input pattern no longer has an effect on the
/// result, allowing "LATIN LETTER" to match "LATIN SMALL LETTER A".
///
/// Additionally, a small extra saving can be had by removing duplicate
/// codepoints for a single suffix.  For example in "LEFT SQUARE BRACKET" when
/// split into words "LEFT$", "SQUARE$" and "BRACKET$" the suffix "T$" appears
/// twice. The "T$" suffix is already deduplicated however the codepoint for
/// LEFT SQUARE BRACKET will appear twice in C[i], this is simply removed.
extern crate leb128;
extern crate ucd_raw;

use std::collections::HashMap;
use std::fs::File;
use std::io::BufWriter;
use std::io::Write;
use std::path::Path;
use std::time::Instant;
use ucd_raw::Character;
use ucd_raw::CHARACTERS;

#[derive(Debug)]
struct TempSuffix<'a> {
    suffix: &'a str,
    index: usize,
    codepoints: Vec<u32>,
}

fn out_file<P: AsRef<Path>>(path: P) -> BufWriter<File> {
    let file = File::create(path).unwrap();

    BufWriter::new(file)
}

fn char_iter() -> impl Iterator<Item = &'static Character> {
    CHARACTERS
        .iter()
        .filter(|character| match character.codepoint {
            0x03400...0x04DB5 => false,
            0x04E00...0x09FEA => false,
            0x20000...0x2A6D6 => false,
            0x2A700...0x2B734 => false,
            0x2B740...0x2B81D => false,
            0x2B820...0x2CEA1 => false,
            0x2CEB0...0x2EBE0 => false,
            0x17000...0x187EC => false,
            0x1B170...0x1B2FB => false,
            0x0F900...0x0FA6D => false,
            0x0FA70...0x0FAD9 => false,
            0x2F800...0x2FA1D => false,
            _ => true,
        })
}

fn suffixes<'a>(string: &'a str) -> impl Iterator<Item = (usize, &'a str)> {
    (0..string.len()).map(move |i| &string[i..]).enumerate()
}

fn main() {
    println!("indexing {} codepoints...", char_iter().count());

    let start = Instant::now();

    let mut combined = String::new();
    let mut visited_words = HashMap::new();
    let mut temp_suffixes = Vec::new();

    let mut combined_out = out_file("utf/src/generated.combined");
    let mut leb_out = out_file("utf/src/generated.leb");

    for character in char_iter() {
        for word in character.name.split_whitespace() {
            let mut start;

            if visited_words.contains_key(word) {
                start = visited_words[word];
            } else {
                start = combined.len();

                visited_words.insert(word, start);
                combined.push_str(word);
                combined.push('\n');
            }

            for (offset, suffix) in suffixes(word) {
                temp_suffixes.push(TempSuffix {
                    suffix,
                    index: start + offset,
                    codepoints: vec![character.codepoint],
                });
            }
        }
    }

    temp_suffixes.sort_unstable_by_key(|temp_suffix| temp_suffix.suffix);

    println!("length before dedup: {}", temp_suffixes.len());

    temp_suffixes.dedup_by(|a, b| {
        let equal = a.suffix == b.suffix;

        if equal {
            b.codepoints.extend_from_slice(&a.codepoints);
        }

        equal
    });

    for suffix in &mut temp_suffixes {
        suffix.codepoints.sort_unstable();
        suffix.codepoints.dedup();
    }

    println!("after: {}", temp_suffixes.len());

    for suffix in temp_suffixes {
        leb128::write::unsigned(&mut leb_out, suffix.index as u64).unwrap();
        leb128::write::unsigned(&mut leb_out, suffix.codepoints.len() as u64).unwrap();

        let mut last = 0;
        for codepoint in suffix.codepoints {
            let delta = codepoint - last;
            last = codepoint;

            leb128::write::unsigned(&mut leb_out, delta as u64).unwrap();
        }
    }

    combined_out.write_all(combined.as_bytes()).unwrap();

    println!("Generated in {:?}", start.elapsed());
}
<|endoftext|>


<commit_before>#![feature(global_allocator, allocator_api, heap_api)]

#![feature(integer_atomics)]
#![feature(ascii_ctype)]
// `error_chain!` can recurse deeply
#![recursion_limit = "1024"]

//hexadecimal colors aren't numbers
#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))]

//
//use std::heap::{Alloc, System, Layout, AllocErr};
//
//struct MyAllocator;
//
//unsafe impl<'a> Alloc for &'a MyAllocator {
//    unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
//        System.alloc(layout)
//    }
//
//    unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
//        System.dealloc(ptr, layout)
//    }
//}

#[global_allocator]
static GLOBAL: ::std::heap::System = ::std::heap::System;

#[macro_use]
extern crate error_chain;

#[macro_use]
extern crate lazy_static;

extern crate rand;
extern crate reqwest;
extern crate hyper_native_tls;
extern crate regex;
extern crate hyper;
extern crate blake2_rfc;
extern crate twox_hash;
extern crate chrono;
extern crate zip;
//extern crate serde;
//extern crate serde_json;
extern crate backtrace;
extern crate num;
extern crate base64;
extern crate sha2;
extern crate unicase;
extern crate app_dirs;
extern crate chashmap;
extern crate parking_lot;
extern crate time;
extern crate uuid;
extern crate lockless;
extern crate smallvec;
#[cfg(test)]
extern crate mockito;

extern crate digest;

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
extern crate openssl;
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
extern crate hyper_openssl;

pub mod identifier_styles;
pub mod preludes;
pub mod filesystem;
pub mod fetching;
pub mod caching;
pub mod hashing;
pub mod process_testing;
pub mod process_capture;
pub mod colors;
pub mod debug;
pub mod licensing;
pub mod pollster;
pub mod util;

pub mod timeywimey{
    pub fn time_bucket(seconds_per_bucket: u64, bucket_count: u64) -> u64{
        ::std::time::SystemTime::now().duration_since(::std::time::UNIX_EPOCH).unwrap().as_secs() / seconds_per_bucket % bucket_count
    }
    pub use chrono::prelude::Utc;
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}

// We'll put our errors in an `errors` module, and other modules in
// this crate will `use errors::*;` to get access to everything
// `error_chain!` creates.
#[allow(unused_doc_comment)]
mod errors {
    // Create the Error, ErrorKind, ResultExt, and Result types

    error_chain! {

        errors{
           LicenseCorrupted(msg: String) {
                description("Please verify/reinstall license; license corrupt.")
                display("Please verify/reinstall license; license corrupt: {}", msg)
           }
           RsaDecryptInputLargerThanModulus
        }

    }
}

#[test]
fn test_file_macro_for_this_build(){
    assert!(file!().starts_with(env!("CARGO_PKG_NAME")))
}

<commit_msg>Update alloc for compatibility with stable Rust<commit_after>#![feature(global_allocator, alloc_system, allocator_api)]

#![feature(integer_atomics)]
#![feature(ascii_ctype)]
// `error_chain!` can recurse deeply
#![recursion_limit = "1024"]

//hexadecimal colors aren't numbers
#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))]

//
//use std::heap::{Alloc, System, Layout, AllocErr};
//
//struct MyAllocator;
//
//unsafe impl<'a> Alloc for &'a MyAllocator {
//    unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
//        System.alloc(layout)
//    }
//
//    unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
//        System.dealloc(ptr, layout)
//    }
//}

extern crate alloc_system;

#[global_allocator]
static GLOBAL: alloc_system::System = alloc_system::System;

#[macro_use]
extern crate error_chain;

#[macro_use]
extern crate lazy_static;

extern crate rand;
extern crate reqwest;
extern crate hyper_native_tls;
extern crate regex;
extern crate hyper;
extern crate blake2_rfc;
extern crate twox_hash;
extern crate chrono;
extern crate zip;
//extern crate serde;
//extern crate serde_json;
extern crate backtrace;
extern crate num;
extern crate base64;
extern crate sha2;
extern crate unicase;
extern crate app_dirs;
extern crate chashmap;
extern crate parking_lot;
extern crate time;
extern crate uuid;
extern crate lockless;
extern crate smallvec;
#[cfg(test)]
extern crate mockito;

extern crate digest;

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
extern crate openssl;
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
extern crate hyper_openssl;

pub mod identifier_styles;
pub mod preludes;
pub mod filesystem;
pub mod fetching;
pub mod caching;
pub mod hashing;
pub mod process_testing;
pub mod process_capture;
pub mod colors;
pub mod debug;
pub mod licensing;
pub mod pollster;
pub mod util;

pub mod timeywimey{
    pub fn time_bucket(seconds_per_bucket: u64, bucket_count: u64) -> u64{
        ::std::time::SystemTime::now().duration_since(::std::time::UNIX_EPOCH).unwrap().as_secs() / seconds_per_bucket % bucket_count
    }
    pub use chrono::prelude::Utc;
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}

// We'll put our errors in an `errors` module, and other modules in
// this crate will `use errors::*;` to get access to everything
// `error_chain!` creates.
#[allow(unused_doc_comment)]
mod errors {
    // Create the Error, ErrorKind, ResultExt, and Result types

    error_chain! {

        errors{
           LicenseCorrupted(msg: String) {
                description("Please verify/reinstall license; license corrupt.")
                display("Please verify/reinstall license; license corrupt: {}", msg)
           }
           RsaDecryptInputLargerThanModulus
        }

    }
}

#[test]
fn test_file_macro_for_this_build(){
    assert!(file!().starts_with(env!("CARGO_PKG_NAME")))
}

<|endoftext|>