<commit_before>/// This list represents the default file types that ripgrep ships with. In
/// general, any file format is fair game, although it should generally be
/// limited to reasonably popular open formats. For other cases, you can add
/// types to each invocation of ripgrep with the '--type-add' flag.
///
/// If you would like to add or improve this list, please file a PR:
/// https://github.com/BurntSushi/ripgrep
///
/// Please try to keep this list sorted lexicographically and wrapped to 79
/// columns (inclusive).
#[rustfmt::skip]
pub const DEFAULT_TYPES: &[(&str, &[&str])] = &[
    ("agda", &["*.agda", "*.lagda"]),
    ("aidl", &["*.aidl"]),
    ("amake", &["*.mk", "*.bp"]),
    ("asciidoc", &["*.adoc", "*.asc", "*.asciidoc"]),
    ("asm", &["*.asm", "*.s", "*.S"]),
    ("asp", &[
        "*.aspx", "*.aspx.cs", "*.aspx.cs", "*.ascx", "*.ascx.cs", "*.ascx.vb",
    ]),
    ("ats", &["*.ats", "*.dats", "*.sats", "*.hats"]),
    ("avro", &["*.avdl", "*.avpr", "*.avsc"]),
    ("awk", &["*.awk"]),
    ("bazel", &["*.bzl", "WORKSPACE", "BUILD", "BUILD.bazel"]),
    ("bitbake", &["*.bb", "*.bbappend", "*.bbclass", "*.conf", "*.inc"]),
    ("brotli", &["*.br"]),
    ("buildstream", &["*.bst"]),
    ("bzip2", &["*.bz2", "*.tbz2"]),
    ("c", &["*.[chH]", "*.[chH].in", "*.cats"]),
    ("cabal", &["*.cabal"]),
    ("cbor", &["*.cbor"]),
    ("ceylon", &["*.ceylon"]),
    ("clojure", &["*.clj", "*.cljc", "*.cljs", "*.cljx"]),
    ("cmake", &["*.cmake", "CMakeLists.txt"]),
    ("coffeescript", &["*.coffee"]),
    ("config", &["*.cfg", "*.conf", "*.config", "*.ini"]),
    ("cpp", &[
        "*.[ChH]", "*.cc", "*.[ch]pp", "*.[ch]xx", "*.hh",  "*.inl",
        "*.[ChH].in", "*.cc.in", "*.[ch]pp.in", "*.[ch]xx.in", "*.hh.in",
    ]),
    ("creole", &["*.creole"]),
    ("crystal", &["Projectfile", "*.cr"]),
    ("cs", &["*.cs"]),
    ("csharp", &["*.cs"]),
    ("cshtml", &["*.cshtml"]),
    ("css", &["*.css", "*.scss"]),
    ("csv", &["*.csv"]),
    ("cython", &["*.pyx", "*.pxi", "*.pxd"]),
    ("d", &["*.d"]),
    ("dart", &["*.dart"]),
    ("dhall", &["*.dhall"]),
    ("diff", &["*.patch", "*.diff"]),
    ("docker", &["*Dockerfile*"]),
    ("edn", &["*.edn"]),
    ("elisp", &["*.el"]),
    ("elixir", &["*.ex", "*.eex", "*.exs"]),
    ("elm", &["*.elm"]),
    ("erb", &["*.erb"]),
    ("erlang", &["*.erl", "*.hrl"]),
    ("fidl", &["*.fidl"]),
    ("fish", &["*.fish"]),
    ("fortran", &[
        "*.f", "*.F", "*.f77", "*.F77", "*.pfo",
        "*.f90", "*.F90", "*.f95", "*.F95",
    ]),
    ("fsharp", &["*.fs", "*.fsx", "*.fsi"]),
    ("gap", &["*.g", "*.gap", "*.gi", "*.gd", "*.tst"]),
    ("gn", &["*.gn", "*.gni"]),
    ("go", &["*.go"]),
    ("gradle", &["*.gradle"]),
    ("groovy", &["*.groovy", "*.gradle"]),
    ("gzip", &["*.gz", "*.tgz"]),
    ("h", &["*.h", "*.hpp"]),
    ("haml", &["*.haml"]),
    ("haskell", &["*.hs", "*.lhs", "*.cpphs", "*.c2hs", "*.hsc"]),
    ("hbs", &["*.hbs"]),
    ("hs", &["*.hs", "*.lhs"]),
    ("html", &["*.htm", "*.html", "*.ejs"]),
    ("idris", &["*.idr", "*.lidr"]),
    ("java", &["*.java", "*.jsp", "*.jspx", "*.properties"]),
    ("jinja", &["*.j2", "*.jinja", "*.jinja2"]),
    ("jl", &["*.jl"]),
    ("js", &["*.js", "*.jsx", "*.vue"]),
    ("json", &["*.json", "composer.lock"]),
    ("jsonl", &["*.jsonl"]),
    ("julia", &["*.jl"]),
    ("jupyter", &["*.ipynb", "*.jpynb"]),
    ("kotlin", &["*.kt", "*.kts"]),
    ("less", &["*.less"]),
    ("license", &[
        // General
        "COPYING", "COPYING[.-]*",
        "COPYRIGHT", "COPYRIGHT[.-]*",
        "EULA", "EULA[.-]*",
        "licen[cs]e", "licen[cs]e.*",
        "LICEN[CS]E", "LICEN[CS]E[.-]*", "*[.-]LICEN[CS]E*",
        "NOTICE", "NOTICE[.-]*",
        "PATENTS", "PATENTS[.-]*",
        "UNLICEN[CS]E", "UNLICEN[CS]E[.-]*",
        // GPL (gpl.txt, etc.)
        "agpl[.-]*",
        "gpl[.-]*",
        "lgpl[.-]*",
        // Other license-specific (APACHE-2.0.txt, etc.)
        "AGPL-*[0-9]*",
        "APACHE-*[0-9]*",
        "BSD-*[0-9]*",
        "CC-BY-*",
        "GFDL-*[0-9]*",
        "GNU-*[0-9]*",
        "GPL-*[0-9]*",
        "LGPL-*[0-9]*",
        "MIT-*[0-9]*",
        "MPL-*[0-9]*",
        "OFL-*[0-9]*",
    ]),
    ("lisp", &["*.el", "*.jl", "*.lisp", "*.lsp", "*.sc", "*.scm"]),
    ("lock", &["*.lock", "package-lock.json"]),
    ("log", &["*.log"]),
    ("lua", &["*.lua"]),
    ("lz4", &["*.lz4"]),
    ("lzma", &["*.lzma"]),
    ("m4", &["*.ac", "*.m4"]),
    ("make", &[
        "[Gg][Nn][Uu]makefile", "[Mm]akefile",
        "[Gg][Nn][Uu]makefile.am", "[Mm]akefile.am",
        "[Gg][Nn][Uu]makefile.in", "[Mm]akefile.in",
        "*.mk", "*.mak"
    ]),
    ("mako", &["*.mako", "*.mao"]),
    ("man", &["*.[0-9lnpx]", "*.[0-9][cEFMmpSx]"]),
    ("markdown", &["*.markdown", "*.md", "*.mdown", "*.mkdn"]),
    ("matlab", &["*.m"]),
    ("md", &["*.markdown", "*.md", "*.mdown", "*.mkdn"]),
    ("mk", &["mkfile"]),
    ("ml", &["*.ml"]),
    ("msbuild", &[
        "*.csproj", "*.fsproj", "*.vcxproj", "*.proj", "*.props", "*.targets",
    ]),
    ("nim", &["*.nim", "*.nimf", "*.nimble", "*.nims"]),
    ("nix", &["*.nix"]),
    ("objc", &["*.h", "*.m"]),
    ("objcpp", &["*.h", "*.mm"]),
    ("ocaml", &["*.ml", "*.mli", "*.mll", "*.mly"]),
    ("org", &["*.org", "*.org_archive"]),
    ("pascal", &["*.pas", "*.dpr", "*.lpr", "*.pp", "*.inc"]),
    ("pdf", &["*.pdf"]),
    ("perl", &["*.perl", "*.pl", "*.PL", "*.plh", "*.plx", "*.pm", "*.t"]),
    ("php", &["*.php", "*.php3", "*.php4", "*.php5", "*.phtml"]),
    ("pod", &["*.pod"]),
    ("postscript", &["*.eps", "*.ps"]),
    ("protobuf", &["*.proto"]),
    ("ps", &["*.cdxml", "*.ps1", "*.ps1xml", "*.psd1", "*.psm1"]),
    ("puppet", &["*.erb", "*.pp", "*.rb"]),
    ("purs", &["*.purs"]),
    ("py", &["*.py"]),
    ("qmake", &["*.pro", "*.pri", "*.prf"]),
    ("qml", &["*.qml"]),
    ("r", &["*.R", "*.r", "*.Rmd", "*.Rnw"]),
    ("rdoc", &["*.rdoc"]),
    ("readme", &["README*", "*README"]),
    ("robot", &["*.robot"]),
    ("rst", &["*.rst"]),
    ("ruby", &["Gemfile", "*.gemspec", ".irbrc", "Rakefile", "*.rb"]),
    ("rust", &["*.rs"]),
    ("sass", &["*.sass", "*.scss"]),
    ("scala", &["*.scala", "*.sbt"]),
    ("sh", &[
        // Portable/misc. init files
        ".login", ".logout", ".profile", "profile",
        // bash-specific init files
        ".bash_login", "bash_login",
        ".bash_logout", "bash_logout",
        ".bash_profile", "bash_profile",
        ".bashrc", "bashrc", "*.bashrc",
        // csh-specific init files
        ".cshrc", "*.cshrc",
        // ksh-specific init files
        ".kshrc", "*.kshrc",
        // tcsh-specific init files
        ".tcshrc",
        // zsh-specific init files
        ".zshenv", "zshenv",
        ".zlogin", "zlogin",
        ".zlogout", "zlogout",
        ".zprofile", "zprofile",
        ".zshrc", "zshrc",
        // Extensions
        "*.bash", "*.csh", "*.ksh", "*.sh", "*.tcsh", "*.zsh",
    ]),
    ("slim", &["*.skim", "*.slim", "*.slime"]),
    ("smarty", &["*.tpl"]),
    ("sml", &["*.sml", "*.sig"]),
    ("soy", &["*.soy"]),
    ("spark", &["*.spark"]),
    ("spec", &["*.spec"]),
    ("sql", &["*.sql", "*.psql"]),
    ("stylus", &["*.styl"]),
    ("sv", &["*.v", "*.vg", "*.sv", "*.svh", "*.h"]),
    ("svg", &["*.svg"]),
    ("swift", &["*.swift"]),
    ("swig", &["*.def", "*.i"]),
    ("systemd", &[
        "*.automount", "*.conf", "*.device", "*.link", "*.mount", "*.path",
        "*.scope", "*.service", "*.slice", "*.socket", "*.swap", "*.target",
        "*.timer",
    ]),
    ("taskpaper", &["*.taskpaper"]),
    ("tcl", &["*.tcl"]),
    ("tex", &["*.tex", "*.ltx", "*.cls", "*.sty", "*.bib", "*.dtx", "*.ins"]),
    ("textile", &["*.textile"]),
    ("tf", &["*.tf"]),
    ("thrift", &["*.thrift"]),
    ("toml", &["*.toml", "Cargo.lock"]),
    ("ts", &["*.ts", "*.tsx"]),
    ("twig", &["*.twig"]),
    ("txt", &["*.txt"]),
    ("typoscript", &["*.typoscript", "*.ts"]),
    ("vala", &["*.vala"]),
    ("vb", &["*.vb"]),
    ("verilog", &["*.v", "*.vh", "*.sv", "*.svh"]),
    ("vhdl", &["*.vhd", "*.vhdl"]),
    ("vim", &["*.vim"]),
    ("vimscript", &["*.vim"]),
    ("webidl", &["*.idl", "*.webidl", "*.widl"]),
    ("wiki", &["*.mediawiki", "*.wiki"]),
    ("xml", &[
        "*.xml", "*.xml.dist", "*.dtd", "*.xsl", "*.xslt", "*.xsd", "*.xjb",
        "*.rng", "*.sch", "*.xhtml",
    ]),
    ("xz", &["*.xz", "*.txz"]),
    ("yacc", &["*.y"]),
    ("yaml", &["*.yaml", "*.yml"]),
    ("zig", &["*.zig"]),
    ("zsh", &[
        ".zshenv", "zshenv",
        ".zlogin", "zlogin",
        ".zlogout", "zlogout",
        ".zprofile", "zprofile",
        ".zshrc", "zshrc",
        "*.zsh",
    ]),
    ("zstd", &["*.zst", "*.zstd"]),
];
<commit_msg>ignore/types: add K type<commit_after>/// This list represents the default file types that ripgrep ships with. In
/// general, any file format is fair game, although it should generally be
/// limited to reasonably popular open formats. For other cases, you can add
/// types to each invocation of ripgrep with the '--type-add' flag.
///
/// If you would like to add or improve this list, please file a PR:
/// https://github.com/BurntSushi/ripgrep
///
/// Please try to keep this list sorted lexicographically and wrapped to 79
/// columns (inclusive).
#[rustfmt::skip]
pub const DEFAULT_TYPES: &[(&str, &[&str])] = &[
    ("agda", &["*.agda", "*.lagda"]),
    ("aidl", &["*.aidl"]),
    ("amake", &["*.mk", "*.bp"]),
    ("asciidoc", &["*.adoc", "*.asc", "*.asciidoc"]),
    ("asm", &["*.asm", "*.s", "*.S"]),
    ("asp", &[
        "*.aspx", "*.aspx.cs", "*.aspx.cs", "*.ascx", "*.ascx.cs", "*.ascx.vb",
    ]),
    ("ats", &["*.ats", "*.dats", "*.sats", "*.hats"]),
    ("avro", &["*.avdl", "*.avpr", "*.avsc"]),
    ("awk", &["*.awk"]),
    ("bazel", &["*.bzl", "WORKSPACE", "BUILD", "BUILD.bazel"]),
    ("bitbake", &["*.bb", "*.bbappend", "*.bbclass", "*.conf", "*.inc"]),
    ("brotli", &["*.br"]),
    ("buildstream", &["*.bst"]),
    ("bzip2", &["*.bz2", "*.tbz2"]),
    ("c", &["*.[chH]", "*.[chH].in", "*.cats"]),
    ("cabal", &["*.cabal"]),
    ("cbor", &["*.cbor"]),
    ("ceylon", &["*.ceylon"]),
    ("clojure", &["*.clj", "*.cljc", "*.cljs", "*.cljx"]),
    ("cmake", &["*.cmake", "CMakeLists.txt"]),
    ("coffeescript", &["*.coffee"]),
    ("config", &["*.cfg", "*.conf", "*.config", "*.ini"]),
    ("cpp", &[
        "*.[ChH]", "*.cc", "*.[ch]pp", "*.[ch]xx", "*.hh",  "*.inl",
        "*.[ChH].in", "*.cc.in", "*.[ch]pp.in", "*.[ch]xx.in", "*.hh.in",
    ]),
    ("creole", &["*.creole"]),
    ("crystal", &["Projectfile", "*.cr"]),
    ("cs", &["*.cs"]),
    ("csharp", &["*.cs"]),
    ("cshtml", &["*.cshtml"]),
    ("css", &["*.css", "*.scss"]),
    ("csv", &["*.csv"]),
    ("cython", &["*.pyx", "*.pxi", "*.pxd"]),
    ("d", &["*.d"]),
    ("dart", &["*.dart"]),
    ("dhall", &["*.dhall"]),
    ("diff", &["*.patch", "*.diff"]),
    ("docker", &["*Dockerfile*"]),
    ("edn", &["*.edn"]),
    ("elisp", &["*.el"]),
    ("elixir", &["*.ex", "*.eex", "*.exs"]),
    ("elm", &["*.elm"]),
    ("erb", &["*.erb"]),
    ("erlang", &["*.erl", "*.hrl"]),
    ("fidl", &["*.fidl"]),
    ("fish", &["*.fish"]),
    ("fortran", &[
        "*.f", "*.F", "*.f77", "*.F77", "*.pfo",
        "*.f90", "*.F90", "*.f95", "*.F95",
    ]),
    ("fsharp", &["*.fs", "*.fsx", "*.fsi"]),
    ("gap", &["*.g", "*.gap", "*.gi", "*.gd", "*.tst"]),
    ("gn", &["*.gn", "*.gni"]),
    ("go", &["*.go"]),
    ("gradle", &["*.gradle"]),
    ("groovy", &["*.groovy", "*.gradle"]),
    ("gzip", &["*.gz", "*.tgz"]),
    ("h", &["*.h", "*.hpp"]),
    ("haml", &["*.haml"]),
    ("haskell", &["*.hs", "*.lhs", "*.cpphs", "*.c2hs", "*.hsc"]),
    ("hbs", &["*.hbs"]),
    ("hs", &["*.hs", "*.lhs"]),
    ("html", &["*.htm", "*.html", "*.ejs"]),
    ("idris", &["*.idr", "*.lidr"]),
    ("java", &["*.java", "*.jsp", "*.jspx", "*.properties"]),
    ("jinja", &["*.j2", "*.jinja", "*.jinja2"]),
    ("jl", &["*.jl"]),
    ("js", &["*.js", "*.jsx", "*.vue"]),
    ("json", &["*.json", "composer.lock"]),
    ("jsonl", &["*.jsonl"]),
    ("julia", &["*.jl"]),
    ("jupyter", &["*.ipynb", "*.jpynb"]),
    ("k", &["*.k"]),
    ("kotlin", &["*.kt", "*.kts"]),
    ("less", &["*.less"]),
    ("license", &[
        // General
        "COPYING", "COPYING[.-]*",
        "COPYRIGHT", "COPYRIGHT[.-]*",
        "EULA", "EULA[.-]*",
        "licen[cs]e", "licen[cs]e.*",
        "LICEN[CS]E", "LICEN[CS]E[.-]*", "*[.-]LICEN[CS]E*",
        "NOTICE", "NOTICE[.-]*",
        "PATENTS", "PATENTS[.-]*",
        "UNLICEN[CS]E", "UNLICEN[CS]E[.-]*",
        // GPL (gpl.txt, etc.)
        "agpl[.-]*",
        "gpl[.-]*",
        "lgpl[.-]*",
        // Other license-specific (APACHE-2.0.txt, etc.)
        "AGPL-*[0-9]*",
        "APACHE-*[0-9]*",
        "BSD-*[0-9]*",
        "CC-BY-*",
        "GFDL-*[0-9]*",
        "GNU-*[0-9]*",
        "GPL-*[0-9]*",
        "LGPL-*[0-9]*",
        "MIT-*[0-9]*",
        "MPL-*[0-9]*",
        "OFL-*[0-9]*",
    ]),
    ("lisp", &["*.el", "*.jl", "*.lisp", "*.lsp", "*.sc", "*.scm"]),
    ("lock", &["*.lock", "package-lock.json"]),
    ("log", &["*.log"]),
    ("lua", &["*.lua"]),
    ("lz4", &["*.lz4"]),
    ("lzma", &["*.lzma"]),
    ("m4", &["*.ac", "*.m4"]),
    ("make", &[
        "[Gg][Nn][Uu]makefile", "[Mm]akefile",
        "[Gg][Nn][Uu]makefile.am", "[Mm]akefile.am",
        "[Gg][Nn][Uu]makefile.in", "[Mm]akefile.in",
        "*.mk", "*.mak"
    ]),
    ("mako", &["*.mako", "*.mao"]),
    ("man", &["*.[0-9lnpx]", "*.[0-9][cEFMmpSx]"]),
    ("markdown", &["*.markdown", "*.md", "*.mdown", "*.mkdn"]),
    ("matlab", &["*.m"]),
    ("md", &["*.markdown", "*.md", "*.mdown", "*.mkdn"]),
    ("mk", &["mkfile"]),
    ("ml", &["*.ml"]),
    ("msbuild", &[
        "*.csproj", "*.fsproj", "*.vcxproj", "*.proj", "*.props", "*.targets",
    ]),
    ("nim", &["*.nim", "*.nimf", "*.nimble", "*.nims"]),
    ("nix", &["*.nix"]),
    ("objc", &["*.h", "*.m"]),
    ("objcpp", &["*.h", "*.mm"]),
    ("ocaml", &["*.ml", "*.mli", "*.mll", "*.mly"]),
    ("org", &["*.org", "*.org_archive"]),
    ("pascal", &["*.pas", "*.dpr", "*.lpr", "*.pp", "*.inc"]),
    ("pdf", &["*.pdf"]),
    ("perl", &["*.perl", "*.pl", "*.PL", "*.plh", "*.plx", "*.pm", "*.t"]),
    ("php", &["*.php", "*.php3", "*.php4", "*.php5", "*.phtml"]),
    ("pod", &["*.pod"]),
    ("postscript", &["*.eps", "*.ps"]),
    ("protobuf", &["*.proto"]),
    ("ps", &["*.cdxml", "*.ps1", "*.ps1xml", "*.psd1", "*.psm1"]),
    ("puppet", &["*.erb", "*.pp", "*.rb"]),
    ("purs", &["*.purs"]),
    ("py", &["*.py"]),
    ("qmake", &["*.pro", "*.pri", "*.prf"]),
    ("qml", &["*.qml"]),
    ("r", &["*.R", "*.r", "*.Rmd", "*.Rnw"]),
    ("rdoc", &["*.rdoc"]),
    ("readme", &["README*", "*README"]),
    ("robot", &["*.robot"]),
    ("rst", &["*.rst"]),
    ("ruby", &["Gemfile", "*.gemspec", ".irbrc", "Rakefile", "*.rb"]),
    ("rust", &["*.rs"]),
    ("sass", &["*.sass", "*.scss"]),
    ("scala", &["*.scala", "*.sbt"]),
    ("sh", &[
        // Portable/misc. init files
        ".login", ".logout", ".profile", "profile",
        // bash-specific init files
        ".bash_login", "bash_login",
        ".bash_logout", "bash_logout",
        ".bash_profile", "bash_profile",
        ".bashrc", "bashrc", "*.bashrc",
        // csh-specific init files
        ".cshrc", "*.cshrc",
        // ksh-specific init files
        ".kshrc", "*.kshrc",
        // tcsh-specific init files
        ".tcshrc",
        // zsh-specific init files
        ".zshenv", "zshenv",
        ".zlogin", "zlogin",
        ".zlogout", "zlogout",
        ".zprofile", "zprofile",
        ".zshrc", "zshrc",
        // Extensions
        "*.bash", "*.csh", "*.ksh", "*.sh", "*.tcsh", "*.zsh",
    ]),
    ("slim", &["*.skim", "*.slim", "*.slime"]),
    ("smarty", &["*.tpl"]),
    ("sml", &["*.sml", "*.sig"]),
    ("soy", &["*.soy"]),
    ("spark", &["*.spark"]),
    ("spec", &["*.spec"]),
    ("sql", &["*.sql", "*.psql"]),
    ("stylus", &["*.styl"]),
    ("sv", &["*.v", "*.vg", "*.sv", "*.svh", "*.h"]),
    ("svg", &["*.svg"]),
    ("swift", &["*.swift"]),
    ("swig", &["*.def", "*.i"]),
    ("systemd", &[
        "*.automount", "*.conf", "*.device", "*.link", "*.mount", "*.path",
        "*.scope", "*.service", "*.slice", "*.socket", "*.swap", "*.target",
        "*.timer",
    ]),
    ("taskpaper", &["*.taskpaper"]),
    ("tcl", &["*.tcl"]),
    ("tex", &["*.tex", "*.ltx", "*.cls", "*.sty", "*.bib", "*.dtx", "*.ins"]),
    ("textile", &["*.textile"]),
    ("tf", &["*.tf"]),
    ("thrift", &["*.thrift"]),
    ("toml", &["*.toml", "Cargo.lock"]),
    ("ts", &["*.ts", "*.tsx"]),
    ("twig", &["*.twig"]),
    ("txt", &["*.txt"]),
    ("typoscript", &["*.typoscript", "*.ts"]),
    ("vala", &["*.vala"]),
    ("vb", &["*.vb"]),
    ("verilog", &["*.v", "*.vh", "*.sv", "*.svh"]),
    ("vhdl", &["*.vhd", "*.vhdl"]),
    ("vim", &["*.vim"]),
    ("vimscript", &["*.vim"]),
    ("webidl", &["*.idl", "*.webidl", "*.widl"]),
    ("wiki", &["*.mediawiki", "*.wiki"]),
    ("xml", &[
        "*.xml", "*.xml.dist", "*.dtd", "*.xsl", "*.xslt", "*.xsd", "*.xjb",
        "*.rng", "*.sch", "*.xhtml",
    ]),
    ("xz", &["*.xz", "*.txz"]),
    ("yacc", &["*.y"]),
    ("yaml", &["*.yaml", "*.yml"]),
    ("zig", &["*.zig"]),
    ("zsh", &[
        ".zshenv", "zshenv",
        ".zlogin", "zlogin",
        ".zlogout", "zlogout",
        ".zprofile", "zprofile",
        ".zshrc", "zshrc",
        "*.zsh",
    ]),
    ("zstd", &["*.zst", "*.zstd"]),
];
<|endoftext|>


<commit_before>/// Lookup hir elements using positions in the source code. This is a lossy
/// transformation: in general, a single source might correspond to several
/// modules, functions, etc, due to macros, cfgs and `#[path=]` attributes on
/// modules.
///
/// So, this modules should not be used during hir construction, it exists
/// purely for "IDE needs".
use std::sync::Arc;

use ra_db::{FileId, FilePosition};
use ra_syntax::{
    SyntaxNode, AstPtr, TextUnit,
    ast::{self, AstNode, NameOwner},
    algo::find_node_at_offset,
};

use crate::{
    HirDatabase, Function, Struct, Enum, Const, Static, Either, DefWithBody,
    AsName, Module, HirFileId, Crate, Trait, Resolver,
    ids::LocationCtx,
    expr, AstId
};

/// Locates the module by `FileId`. Picks topmost module in the file.
pub fn module_from_file_id(db: &impl HirDatabase, file_id: FileId) -> Option<Module> {
    module_from_source(db, file_id.into(), None)
}

/// Locates the child module by `mod child;` declaration.
pub fn module_from_declaration(
    db: &impl HirDatabase,
    file_id: FileId,
    decl: &ast::Module,
) -> Option<Module> {
    let parent_module = module_from_file_id(db, file_id);
    let child_name = decl.name();
    match (parent_module, child_name) {
        (Some(parent_module), Some(child_name)) => parent_module.child(db, &child_name.as_name()),
        _ => None,
    }
}

/// Locates the module by position in the source code.
pub fn module_from_position(db: &impl HirDatabase, position: FilePosition) -> Option<Module> {
    let file = db.parse(position.file_id);
    match find_node_at_offset::<ast::Module>(file.syntax(), position.offset) {
        Some(m) if !m.has_semi() => module_from_inline(db, position.file_id.into(), m),
        _ => module_from_file_id(db, position.file_id.into()),
    }
}

fn module_from_inline(
    db: &impl HirDatabase,
    file_id: FileId,
    module: &ast::Module,
) -> Option<Module> {
    assert!(!module.has_semi());
    let file_id = file_id.into();
    let ast_id_map = db.ast_id_map(file_id);
    let item_id = ast_id_map.ast_id(module).with_file_id(file_id);
    module_from_source(db, file_id, Some(item_id))
}

/// Locates the module by child syntax element within the module
pub fn module_from_child_node(
    db: &impl HirDatabase,
    file_id: FileId,
    child: &SyntaxNode,
) -> Option<Module> {
    if let Some(m) = child.ancestors().filter_map(ast::Module::cast).find(|it| !it.has_semi()) {
        module_from_inline(db, file_id.into(), m)
    } else {
        module_from_file_id(db, file_id.into())
    }
}

fn module_from_source(
    db: &impl HirDatabase,
    file_id: HirFileId,
    decl_id: Option<AstId<ast::Module>>,
) -> Option<Module> {
    let source_root_id = db.file_source_root(file_id.as_original_file());
    db.source_root_crates(source_root_id).iter().map(|&crate_id| Crate { crate_id }).find_map(
        |krate| {
            let def_map = db.crate_def_map(krate);
            let module_id = def_map.find_module_by_source(file_id, decl_id)?;
            Some(Module { krate, module_id })
        },
    )
}

pub fn const_from_source(
    db: &impl HirDatabase,
    file_id: FileId,
    const_def: &ast::ConstDef,
) -> Option<Const> {
    let module = module_from_child_node(db, file_id, const_def.syntax())?;
    let res = const_from_module(db, module, const_def);
    Some(res)
}

pub fn const_from_module(
    db: &impl HirDatabase,
    module: Module,
    const_def: &ast::ConstDef,
) -> Const {
    let (file_id, _) = module.definition_source(db);
    let file_id = file_id.into();
    let ctx = LocationCtx::new(db, module, file_id);
    Const { id: ctx.to_def(const_def) }
}

pub fn function_from_position(db: &impl HirDatabase, position: FilePosition) -> Option<Function> {
    let file = db.parse(position.file_id);
    let fn_def = find_node_at_offset::<ast::FnDef>(file.syntax(), position.offset)?;
    function_from_source(db, position.file_id, fn_def)
}

pub fn function_from_source(
    db: &impl HirDatabase,
    file_id: FileId,
    fn_def: &ast::FnDef,
) -> Option<Function> {
    let module = module_from_child_node(db, file_id, fn_def.syntax())?;
    let res = function_from_module(db, module, fn_def);
    Some(res)
}

pub fn function_from_module(
    db: &impl HirDatabase,
    module: Module,
    fn_def: &ast::FnDef,
) -> Function {
    let (file_id, _) = module.definition_source(db);
    let file_id = file_id.into();
    let ctx = LocationCtx::new(db, module, file_id);
    Function { id: ctx.to_def(fn_def) }
}

pub fn function_from_child_node(
    db: &impl HirDatabase,
    file_id: FileId,
    node: &SyntaxNode,
) -> Option<Function> {
    let fn_def = node.ancestors().find_map(ast::FnDef::cast)?;
    function_from_source(db, file_id, fn_def)
}

pub fn struct_from_module(
    db: &impl HirDatabase,
    module: Module,
    struct_def: &ast::StructDef,
) -> Struct {
    let (file_id, _) = module.definition_source(db);
    let file_id = file_id.into();
    let ctx = LocationCtx::new(db, module, file_id);
    Struct { id: ctx.to_def(struct_def) }
}

pub fn static_from_source(
    db: &impl HirDatabase,
    file_id: FileId,
    static_def: &ast::StaticDef,
) -> Option<Static> {
    let module = module_from_child_node(db, file_id, static_def.syntax())?;
    let res = static_from_module(db, module, static_def);
    Some(res)
}

pub fn static_from_module(
    db: &impl HirDatabase,
    module: Module,
    static_def: &ast::StaticDef,
) -> Static {
    let (file_id, _) = module.definition_source(db);
    let file_id = file_id.into();
    let ctx = LocationCtx::new(db, module, file_id);
    Static { id: ctx.to_def(static_def) }
}

pub fn enum_from_module(db: &impl HirDatabase, module: Module, enum_def: &ast::EnumDef) -> Enum {
    let (file_id, _) = module.definition_source(db);
    let file_id = file_id.into();
    let ctx = LocationCtx::new(db, module, file_id);
    Enum { id: ctx.to_def(enum_def) }
}

pub fn trait_from_module(
    db: &impl HirDatabase,
    module: Module,
    trait_def: &ast::TraitDef,
) -> Trait {
    let (file_id, _) = module.definition_source(db);
    let file_id = file_id.into();
    let ctx = LocationCtx::new(db, module, file_id);
    Trait { id: ctx.to_def(trait_def) }
}

fn resolver_for_node(
    db: &impl HirDatabase,
    file_id: FileId,
    node: &SyntaxNode,
    offset: Option<TextUnit>,
) -> Resolver {
    node.ancestors()
        .find_map(|node| {
            if ast::Expr::cast(node).is_some() || ast::Block::cast(node).is_some() {
                if let Some(func) = function_from_child_node(db, file_id, node) {
                    let scopes = func.scopes(db);
                    let scope = match offset {
                        None => scopes.scope_for(&node),
                        Some(offset) => scopes.scope_for_offset(offset),
                    };
                    Some(expr::resolver_for_scope(func.body(db), db, scope))
                } else {
                    // FIXME const/static/array length
                    None
                }
            } else {
                try_get_resolver_for_node(db, file_id, node)
            }
        })
        .unwrap_or_default()
}

fn try_get_resolver_for_node(
    db: &impl HirDatabase,
    file_id: FileId,
    node: &SyntaxNode,
) -> Option<Resolver> {
    if let Some(module) = ast::Module::cast(node) {
        Some(module_from_declaration(db, file_id, module)?.resolver(db))
    } else if let Some(_) = ast::SourceFile::cast(node) {
        Some(module_from_source(db, file_id.into(), None)?.resolver(db))
    } else if let Some(s) = ast::StructDef::cast(node) {
        let module = module_from_child_node(db, file_id, s.syntax())?;
        Some(struct_from_module(db, module, s).resolver(db))
    } else if let Some(e) = ast::EnumDef::cast(node) {
        let module = module_from_child_node(db, file_id, e.syntax())?;
        Some(enum_from_module(db, module, e).resolver(db))
    } else if let Some(f) = ast::FnDef::cast(node) {
        function_from_source(db, file_id, f).map(|f| f.resolver(db))
    } else {
        // FIXME add missing cases
        None
    }
}

/// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of
/// original source files. It should not be used inside the HIR itself.
#[derive(Debug)]
pub struct SourceAnalyzer {
    resolver: Resolver,
    body_source_map: Option<Arc<crate::expr::BodySourceMap>>,
    infer: Option<Arc<crate::ty::InferenceResult>>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PathResolution {
    /// An item
    Def(crate::ModuleDef),
    /// A local binding (only value namespace)
    LocalBinding(Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>),
    /// A generic parameter
    GenericParam(u32),
    SelfType(crate::ImplBlock),
    AssocItem(crate::ImplItem),
}

impl SourceAnalyzer {
    pub fn new(
        db: &impl HirDatabase,
        file_id: FileId,
        node: &SyntaxNode,
        offset: Option<TextUnit>,
    ) -> SourceAnalyzer {
        let def_with_body = node.ancestors().find_map(|node| {
            if let Some(src) = ast::FnDef::cast(node) {
                return function_from_source(db, file_id, src).map(DefWithBody::from);
            }
            if let Some(src) = ast::StaticDef::cast(node) {
                return static_from_source(db, file_id, src).map(DefWithBody::from);
            }
            if let Some(src) = ast::ConstDef::cast(node) {
                return const_from_source(db, file_id, src).map(DefWithBody::from);
            }
            None
        });
        SourceAnalyzer {
            resolver: resolver_for_node(db, file_id, node, offset),
            body_source_map: def_with_body.map(|it| it.body_source_map(db)),
            infer: def_with_body.map(|it| it.infer(db)),
        }
    }

    pub fn resolver(&self) -> &Resolver {
        &self.resolver
    }

    pub fn type_of(&self, _db: &impl HirDatabase, expr: &ast::Expr) -> Option<crate::Ty> {
        let expr_id = self.body_source_map.as_ref()?.node_expr(expr)?;
        Some(self.infer.as_ref()?[expr_id].clone())
    }

    pub fn type_of_pat(&self, _db: &impl HirDatabase, pat: &ast::Pat) -> Option<crate::Ty> {
        let pat_id = self.body_source_map.as_ref()?.node_pat(pat)?;
        Some(self.infer.as_ref()?[pat_id].clone())
    }

    pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> {
        let expr_id = self.body_source_map.as_ref()?.node_expr(call.into())?;
        self.infer.as_ref()?.method_resolution(expr_id)
    }

    pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<crate::StructField> {
        let expr_id = self.body_source_map.as_ref()?.node_expr(field.into())?;
        self.infer.as_ref()?.field_resolution(expr_id)
    }

    pub fn resolve_path(&self, db: &impl HirDatabase, path: &ast::Path) -> Option<PathResolution> {
        if let Some(path_expr) = path.syntax().parent().and_then(ast::PathExpr::cast) {
            let expr_id = self.body_source_map.as_ref()?.node_expr(path_expr.into())?;
            if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_expr(expr_id) {
                return Some(PathResolution::AssocItem(assoc));
            }
        }
        if let Some(path_pat) = path.syntax().parent().and_then(ast::PathPat::cast) {
            let pat_id = self.body_source_map.as_ref()?.node_pat(path_pat.into())?;
            if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_pat(pat_id) {
                return Some(PathResolution::AssocItem(assoc));
            }
        }
        let hir_path = crate::Path::from_ast(path)?;
        let res = self.resolver.resolve_path(db, &hir_path);
        let res = res.clone().take_types().or_else(|| res.take_values())?;
        let res = match res {
            crate::Resolution::Def(it) => PathResolution::Def(it),
            crate::Resolution::LocalBinding(it) => {
                PathResolution::LocalBinding(self.body_source_map.as_ref()?.pat_syntax(it)?)
            }
            crate::Resolution::GenericParam(it) => PathResolution::GenericParam(it),
            crate::Resolution::SelfType(it) => PathResolution::SelfType(it),
        };
        Some(res)
    }

    #[cfg(test)]
    pub(crate) fn body_source_map(&self) -> Arc<crate::expr::BodySourceMap> {
        self.body_source_map.clone().unwrap()
    }

    #[cfg(test)]
    pub(crate) fn inference_result(&self) -> Arc<crate::ty::InferenceResult> {
        self.infer.clone().unwrap()
    }
}
<commit_msg>simplify<commit_after>/// Lookup hir elements using positions in the source code. This is a lossy
/// transformation: in general, a single source might correspond to several
/// modules, functions, etc, due to macros, cfgs and `#[path=]` attributes on
/// modules.
///
/// So, this modules should not be used during hir construction, it exists
/// purely for "IDE needs".
use std::sync::Arc;

use ra_db::{FileId, FilePosition};
use ra_syntax::{
    SyntaxNode, AstPtr, TextUnit,
    ast::{self, AstNode, NameOwner},
    algo::find_node_at_offset,
};

use crate::{
    HirDatabase, Function, Struct, Enum, Const, Static, Either, DefWithBody,
    AsName, Module, HirFileId, Crate, Trait, Resolver,
    ids::LocationCtx,
    expr, AstId
};

/// Locates the module by `FileId`. Picks topmost module in the file.
pub fn module_from_file_id(db: &impl HirDatabase, file_id: FileId) -> Option<Module> {
    module_from_source(db, file_id.into(), None)
}

/// Locates the child module by `mod child;` declaration.
pub fn module_from_declaration(
    db: &impl HirDatabase,
    file_id: FileId,
    decl: &ast::Module,
) -> Option<Module> {
    let parent_module = module_from_file_id(db, file_id);
    let child_name = decl.name();
    match (parent_module, child_name) {
        (Some(parent_module), Some(child_name)) => parent_module.child(db, &child_name.as_name()),
        _ => None,
    }
}

/// Locates the module by position in the source code.
pub fn module_from_position(db: &impl HirDatabase, position: FilePosition) -> Option<Module> {
    let file = db.parse(position.file_id);
    match find_node_at_offset::<ast::Module>(file.syntax(), position.offset) {
        Some(m) if !m.has_semi() => module_from_inline(db, position.file_id.into(), m),
        _ => module_from_file_id(db, position.file_id.into()),
    }
}

fn module_from_inline(
    db: &impl HirDatabase,
    file_id: FileId,
    module: &ast::Module,
) -> Option<Module> {
    assert!(!module.has_semi());
    let file_id = file_id.into();
    let ast_id_map = db.ast_id_map(file_id);
    let item_id = ast_id_map.ast_id(module).with_file_id(file_id);
    module_from_source(db, file_id, Some(item_id))
}

/// Locates the module by child syntax element within the module
pub fn module_from_child_node(
    db: &impl HirDatabase,
    file_id: FileId,
    child: &SyntaxNode,
) -> Option<Module> {
    if let Some(m) = child.ancestors().filter_map(ast::Module::cast).find(|it| !it.has_semi()) {
        module_from_inline(db, file_id.into(), m)
    } else {
        module_from_file_id(db, file_id.into())
    }
}

fn module_from_source(
    db: &impl HirDatabase,
    file_id: HirFileId,
    decl_id: Option<AstId<ast::Module>>,
) -> Option<Module> {
    let source_root_id = db.file_source_root(file_id.as_original_file());
    db.source_root_crates(source_root_id).iter().map(|&crate_id| Crate { crate_id }).find_map(
        |krate| {
            let def_map = db.crate_def_map(krate);
            let module_id = def_map.find_module_by_source(file_id, decl_id)?;
            Some(Module { krate, module_id })
        },
    )
}

pub fn function_from_position(db: &impl HirDatabase, position: FilePosition) -> Option<Function> {
    let file = db.parse(position.file_id);
    let fn_def = find_node_at_offset::<ast::FnDef>(file.syntax(), position.offset)?;
    function_from_source(db, position.file_id, fn_def)
}

pub fn function_from_source(
    db: &impl HirDatabase,
    file_id: FileId,
    fn_def: &ast::FnDef,
) -> Option<Function> {
    let module = module_from_child_node(db, file_id, fn_def.syntax())?;
    let res = function_from_module(db, module, fn_def);
    Some(res)
}

pub fn function_from_module(
    db: &impl HirDatabase,
    module: Module,
    fn_def: &ast::FnDef,
) -> Function {
    let (file_id, _) = module.definition_source(db);
    let file_id = file_id.into();
    let ctx = LocationCtx::new(db, module, file_id);
    Function { id: ctx.to_def(fn_def) }
}

pub fn function_from_child_node(
    db: &impl HirDatabase,
    file_id: FileId,
    node: &SyntaxNode,
) -> Option<Function> {
    let fn_def = node.ancestors().find_map(ast::FnDef::cast)?;
    function_from_source(db, file_id, fn_def)
}

pub fn struct_from_module(
    db: &impl HirDatabase,
    module: Module,
    struct_def: &ast::StructDef,
) -> Struct {
    let (file_id, _) = module.definition_source(db);
    let file_id = file_id.into();
    let ctx = LocationCtx::new(db, module, file_id);
    Struct { id: ctx.to_def(struct_def) }
}

pub fn enum_from_module(db: &impl HirDatabase, module: Module, enum_def: &ast::EnumDef) -> Enum {
    let (file_id, _) = module.definition_source(db);
    let file_id = file_id.into();
    let ctx = LocationCtx::new(db, module, file_id);
    Enum { id: ctx.to_def(enum_def) }
}

pub fn trait_from_module(
    db: &impl HirDatabase,
    module: Module,
    trait_def: &ast::TraitDef,
) -> Trait {
    let (file_id, _) = module.definition_source(db);
    let file_id = file_id.into();
    let ctx = LocationCtx::new(db, module, file_id);
    Trait { id: ctx.to_def(trait_def) }
}

fn resolver_for_node(
    db: &impl HirDatabase,
    file_id: FileId,
    node: &SyntaxNode,
    offset: Option<TextUnit>,
) -> Resolver {
    node.ancestors()
        .find_map(|node| {
            if ast::Expr::cast(node).is_some() || ast::Block::cast(node).is_some() {
                if let Some(func) = function_from_child_node(db, file_id, node) {
                    let scopes = func.scopes(db);
                    let scope = match offset {
                        None => scopes.scope_for(&node),
                        Some(offset) => scopes.scope_for_offset(offset),
                    };
                    Some(expr::resolver_for_scope(func.body(db), db, scope))
                } else {
                    // FIXME const/static/array length
                    None
                }
            } else {
                try_get_resolver_for_node(db, file_id, node)
            }
        })
        .unwrap_or_default()
}

fn try_get_resolver_for_node(
    db: &impl HirDatabase,
    file_id: FileId,
    node: &SyntaxNode,
) -> Option<Resolver> {
    if let Some(module) = ast::Module::cast(node) {
        Some(module_from_declaration(db, file_id, module)?.resolver(db))
    } else if let Some(_) = ast::SourceFile::cast(node) {
        Some(module_from_source(db, file_id.into(), None)?.resolver(db))
    } else if let Some(s) = ast::StructDef::cast(node) {
        let module = module_from_child_node(db, file_id, s.syntax())?;
        Some(struct_from_module(db, module, s).resolver(db))
    } else if let Some(e) = ast::EnumDef::cast(node) {
        let module = module_from_child_node(db, file_id, e.syntax())?;
        Some(enum_from_module(db, module, e).resolver(db))
    } else if let Some(f) = ast::FnDef::cast(node) {
        function_from_source(db, file_id, f).map(|f| f.resolver(db))
    } else {
        // FIXME add missing cases
        None
    }
}

pub fn def_with_body_from_child_node(
    db: &impl HirDatabase,
    file_id: FileId,
    node: &SyntaxNode,
) -> Option<DefWithBody> {
    let module = module_from_child_node(db, file_id, node)?;
    let ctx = LocationCtx::new(db, module, file_id.into());
    node.ancestors().find_map(|node| {
        if let Some(def) = ast::FnDef::cast(node) {
            return Some(Function { id: ctx.to_def(def) }.into());
        }
        if let Some(def) = ast::ConstDef::cast(node) {
            return Some(Const { id: ctx.to_def(def) }.into());
        }
        if let Some(def) = ast::StaticDef::cast(node) {
            return Some(Static { id: ctx.to_def(def) }.into());
        }
        None
    })
}

/// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of
/// original source files. It should not be used inside the HIR itself.
#[derive(Debug)]
pub struct SourceAnalyzer {
    resolver: Resolver,
    body_source_map: Option<Arc<crate::expr::BodySourceMap>>,
    infer: Option<Arc<crate::ty::InferenceResult>>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PathResolution {
    /// An item
    Def(crate::ModuleDef),
    /// A local binding (only value namespace)
    LocalBinding(Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>),
    /// A generic parameter
    GenericParam(u32),
    SelfType(crate::ImplBlock),
    AssocItem(crate::ImplItem),
}

impl SourceAnalyzer {
    pub fn new(
        db: &impl HirDatabase,
        file_id: FileId,
        node: &SyntaxNode,
        offset: Option<TextUnit>,
    ) -> SourceAnalyzer {
        let def_with_body = def_with_body_from_child_node(db, file_id, node);
        SourceAnalyzer {
            resolver: resolver_for_node(db, file_id, node, offset),
            body_source_map: def_with_body.map(|it| it.body_source_map(db)),
            infer: def_with_body.map(|it| it.infer(db)),
        }
    }

    pub fn resolver(&self) -> &Resolver {
        &self.resolver
    }

    pub fn type_of(&self, _db: &impl HirDatabase, expr: &ast::Expr) -> Option<crate::Ty> {
        let expr_id = self.body_source_map.as_ref()?.node_expr(expr)?;
        Some(self.infer.as_ref()?[expr_id].clone())
    }

    pub fn type_of_pat(&self, _db: &impl HirDatabase, pat: &ast::Pat) -> Option<crate::Ty> {
        let pat_id = self.body_source_map.as_ref()?.node_pat(pat)?;
        Some(self.infer.as_ref()?[pat_id].clone())
    }

    pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<Function> {
        let expr_id = self.body_source_map.as_ref()?.node_expr(call.into())?;
        self.infer.as_ref()?.method_resolution(expr_id)
    }

    pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option<crate::StructField> {
        let expr_id = self.body_source_map.as_ref()?.node_expr(field.into())?;
        self.infer.as_ref()?.field_resolution(expr_id)
    }

    pub fn resolve_path(&self, db: &impl HirDatabase, path: &ast::Path) -> Option<PathResolution> {
        if let Some(path_expr) = path.syntax().parent().and_then(ast::PathExpr::cast) {
            let expr_id = self.body_source_map.as_ref()?.node_expr(path_expr.into())?;
            if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_expr(expr_id) {
                return Some(PathResolution::AssocItem(assoc));
            }
        }
        if let Some(path_pat) = path.syntax().parent().and_then(ast::PathPat::cast) {
            let pat_id = self.body_source_map.as_ref()?.node_pat(path_pat.into())?;
            if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_pat(pat_id) {
                return Some(PathResolution::AssocItem(assoc));
            }
        }
        let hir_path = crate::Path::from_ast(path)?;
        let res = self.resolver.resolve_path(db, &hir_path);
        let res = res.clone().take_types().or_else(|| res.take_values())?;
        let res = match res {
            crate::Resolution::Def(it) => PathResolution::Def(it),
            crate::Resolution::LocalBinding(it) => {
                PathResolution::LocalBinding(self.body_source_map.as_ref()?.pat_syntax(it)?)
            }
            crate::Resolution::GenericParam(it) => PathResolution::GenericParam(it),
            crate::Resolution::SelfType(it) => PathResolution::SelfType(it),
        };
        Some(res)
    }

    #[cfg(test)]
    pub(crate) fn body_source_map(&self) -> Arc<crate::expr::BodySourceMap> {
        self.body_source_map.clone().unwrap()
    }

    #[cfg(test)]
    pub(crate) fn inference_result(&self) -> Arc<crate::ty::InferenceResult> {
        self.infer.clone().unwrap()
    }
}
<|endoftext|>


<commit_before>extern crate clingo;

use clingo::*;

fn main() {

    // create a number, identifier (function without arguments), and a function symbol
    let number_symbol = clingo_symbol::create_number(42);
    let identifier_symbol = clingo_symbol::create_id("x", true).unwrap();

    let function_args = &[number_symbol, identifier_symbol];
    let function_symbol = clingo_symbol::create_function("x", function_args, true).unwrap();
    let symbols = [number_symbol, identifier_symbol, function_symbol];

    // print the symbols along with their hash values
    for &symbol in &symbols {
        let atom_string = safe_clingo_symbol_to_string(symbol).unwrap();
        println!(
            "the hash of {} is {}",
            atom_string.to_str().unwrap(),
            safe_clingo_symbol_hash(symbol)
        );
    }

    // retrieve argument symbols of a symbol
    let symbols2 = safe_clingo_symbol_arguments(function_symbol).unwrap();

    // equal to comparison
    for symbol in symbols2 {
        let equal = safe_clingo_symbol_is_equal_to(symbols[0], symbol);

        let atom_string1 = safe_clingo_symbol_to_string(symbols[0]).unwrap();
        let atom_string2 = safe_clingo_symbol_to_string(symbol).unwrap();
        if equal {
            println!(
                "{} is equal {}",
                atom_string1.to_str().unwrap(),
                atom_string2.to_str().unwrap()
            );
        } else {
            println!(
                "{} is not equal {}",
                atom_string1.to_str().unwrap(),
                atom_string2.to_str().unwrap()
            );
        }
    }

    // less than comparison
    let less = safe_clingo_symbol_is_less_than(symbols[0], symbols[1]);
    let atom_string1 = safe_clingo_symbol_to_string(symbols[0]).unwrap();
    let atom_string2 = safe_clingo_symbol_to_string(symbols[1]).unwrap();
    if less {
        println!(
            "{} is less than {}",
            atom_string1.to_str().unwrap(),
            atom_string2.to_str().unwrap()
        );
    } else {
        println!(
            "{} is not less than {}",
            atom_string1.to_str().unwrap(),
            atom_string2.to_str().unwrap()
        );
    }
}
<commit_msg>fix output<commit_after>extern crate clingo;

use clingo::*;

fn main() {

    // create a number, identifier (function without arguments), and a function symbol
    let number_symbol = clingo_symbol::create_number(42);
    let identifier_symbol = clingo_symbol::create_id("x", true).unwrap();

    let function_args = &[number_symbol, identifier_symbol];
    let function_symbol = clingo_symbol::create_function("x", function_args, true).unwrap();
    let symbols = [number_symbol, identifier_symbol, function_symbol];

    // print the symbols along with their hash values
    for &symbol in &symbols {
        let atom_string = safe_clingo_symbol_to_string(symbol).unwrap();
        println!(
            "the hash of {} is {}",
            atom_string.to_str().unwrap(),
            safe_clingo_symbol_hash(symbol)
        );
    }

    // retrieve argument symbols of a symbol
    let symbols2 = safe_clingo_symbol_arguments(function_symbol).unwrap();

    // equal to comparison
    for symbol in symbols2 {
        let equal = safe_clingo_symbol_is_equal_to(symbols[0], symbol);

        let atom_string1 = safe_clingo_symbol_to_string(symbols[0]).unwrap();
        let atom_string2 = safe_clingo_symbol_to_string(symbol).unwrap();
        if equal {
            println!(
                "{} is equal to {}",
                atom_string1.to_str().unwrap(),
                atom_string2.to_str().unwrap()
            );
        } else {
            println!(
                "{} is not equal to {}",
                atom_string1.to_str().unwrap(),
                atom_string2.to_str().unwrap()
            );
        }
    }

    // less than comparison
    let less = safe_clingo_symbol_is_less_than(symbols[0], symbols[1]);
    let atom_string1 = safe_clingo_symbol_to_string(symbols[0]).unwrap();
    let atom_string2 = safe_clingo_symbol_to_string(symbols[1]).unwrap();
    if less {
        println!(
            "{} is less than {}",
            atom_string1.to_str().unwrap(),
            atom_string2.to_str().unwrap()
        );
    } else {
        println!(
            "{} is not less than {}",
            atom_string1.to_str().unwrap(),
            atom_string2.to_str().unwrap()
        );
    }
}
<|endoftext|>


<commit_before>#![feature(specialization)]
#![feature(conservative_impl_trait)]
#![feature(cfg_target_feature)]
#![feature(asm)]

#![allow(unused_imports)]

extern crate core;
extern crate typenum;
extern crate momms;

use std::time::{Instant};
use typenum::{U1, B0, UInt, Unsigned};

use momms::kern::{KernelNM,KernelMN};
use momms::matrix::{Scalar, Mat, ColumnPanelMatrix, RowPanelMatrix, Matrix, Hierarch};
use momms::composables::{GemmNode, AlgorithmStep, PartM, PartN, PartK, PackA, PackB, SpawnThreads, ParallelM, ParallelN, TheRest};
use momms::thread_comm::ThreadInfo;
use momms::util;

fn test_algorithm<T: Scalar, Mr: Unsigned, Nr: Unsigned, Kc:Unsigned, CLRS: Unsigned, CLCS: Unsigned,
    S: GemmNode<T, Hierarch<T, Mr, Kc, U1, Mr>, Hierarch<T, Kc, Nr, Nr, U1>, Hierarch<T, Mr, Nr, CLRS, CLCS>>>
    ( m:usize, n: usize, k: usize, algo: &mut S, flusher: &mut Vec<f64>, n_reps: usize ) -> (f64, T)
{
    let algo_desc = S::hierarchy_description();
    let mut best_time: f64 = 9999999999.0;
    let mut worst_err: T = T::zero();

    for _ in 0..n_reps {
        //Create matrices.
        let mut a : Hierarch<T, Mr, Kc, U1, Mr> = Hierarch::new(m, k, &algo_desc, AlgorithmStep::M{bsz: 0}, AlgorithmStep::K{bsz: 0});
        let mut b : Hierarch<T, Kc, Nr, Nr, U1> = Hierarch::new(k, n, &algo_desc, AlgorithmStep::K{bsz: 0}, AlgorithmStep::N{bsz: 0});
        let mut c : Hierarch<T, Mr, Nr, CLRS, CLCS> = Hierarch::new(m, n, &algo_desc, AlgorithmStep::M{bsz: 0}, AlgorithmStep::N{bsz: 0});

        //Fill the matrices
        a.fill_rand(); c.fill_zero(); b.fill_rand();

        //Read a buffer so that A, B, and C are cold in cache.
        for i in flusher.iter_mut() { *i += 1.0; }

        //Time and run algorithm
        let start = Instant::now();
        unsafe{ algo.run( &mut a, &mut b, &mut c, &ThreadInfo::single_thread() ); }
        best_time = best_time.min(util::dur_seconds(start));
        let err = util::test_c_eq_a_b( &mut a, &mut b, &mut c);
        worst_err = worst_err.max(err);
    }
    (best_time, worst_err)
}

fn test(m_selector: isize, n_selector: isize, k_selector: isize) {
    //Goto's algorithm
    type U3000 = UInt<UInt<typenum::U750, B0>, B0>;
    type Nc = U3000;
    type Kc = typenum::U192;
    type Mc = typenum::U120;
    type Mr = typenum::U4;
    type Nr = typenum::U12;

    type Goto<T,MTA,MTB,MTC>
        = SpawnThreads<T, MTA, MTB, MTC,
          PartN<T, MTA, MTB, MTC, Nc,
          PartK<T, MTA, MTB, MTC, Kc,
          PartM<T, MTA, MTB, MTC, Mc,
          ParallelN<T, MTA, MTB, MTC, Nr, TheRest,
          KernelNM<T, MTA, MTB, MTC, Nr, Mr>>>>>>;

    type RootS3 = typenum::U768;
    //Resident A algorithm
    type NcL2 = typenum::U120;
    type L3A<T,MTA,MTB,MTC>
        = SpawnThreads<T, MTA, MTB, MTC,
          PartM<T, MTA, MTB, MTC, RootS3,
          PartK<T, MTA, MTB, MTC, RootS3,
          PartN<T, MTA, MTB, MTC, NcL2,
          PartK<T, MTA, MTB, MTC, Kc,
          ParallelM<T, MTA, MTB, MTC, Nr, TheRest, //This algorithm uses a 12x4 ukernel instead of 4x12 like the other two
          KernelMN<T, MTA, MTB, MTC, Nr, Mr>>>>>>>;

    //Resident B algorithm
    type McL2 = typenum::U120;
    type L3B<T,MTA,MTB,MTC>
        = SpawnThreads<T, MTA, MTB, MTC,
          PartN<T, MTA, MTB, MTC, RootS3,
          PartK<T, MTA, MTB, MTC, RootS3,
          PartM<T, MTA, MTB, MTC, McL2,
          PartK<T, MTA, MTB, MTC, Kc,
          ParallelN<T, MTA, MTB, MTC, Nr, TheRest,
          KernelNM<T, MTA, MTB, MTC, Nr, Mr>>>>>>>;

    type L3CNc = typenum::U780;
    type L3CKc = typenum::U156;
    type L3CMc = typenum::U156;
    //Resident C algorithm
    type L3C<T,MTA,MTB,MTC>
        = SpawnThreads<T, MTA, MTB, MTC,
          PartN<T, MTA, MTB, MTC, L3CNc,
          PartM<T, MTA, MTB, MTC, L3CKc,
          PartK<T, MTA, MTB, MTC, L3CKc,
          PartM<T, MTA, MTB, MTC, L3CMc,
          ParallelN<T, MTA, MTB, MTC, Nr, TheRest,
          KernelNM<T, MTA, MTB, MTC, Nr, Mr>>>>>>>;

    //We can use the same matrix type for all three algorithms
    type HierA<T> = Hierarch<T, Mr, Kc, U1, Mr>;
    type HierB<T> = Hierarch<T, Kc, Nr, Nr, U1>;
    type HierC<T> = Hierarch<T, Mr, Nr, Nr, U1>;

    type HierAL3a<T> = Hierarch<T, Nr, Kc, U1, Nr>;
    type HierBL3a<T> = Hierarch<T, Kc, Mr, Mr, U1>;
    type HierCL3a<T> = Hierarch<T, Nr, Mr, U1, Nr>;

    type HierAL3c<T> = Hierarch<T, Mr, L3CKc, U1, Mr>;
    type HierBL3c<T> = Hierarch<T, L3CKc, Nr, Nr, U1>;
    type HierCL3c<T> = Hierarch<T, Mr, Nr, Nr, U1>;

    let mut goto = <Goto<f64, HierA<f64>, HierB<f64>, HierC<f64>>>::new();
    let mut l3a = <L3A<f64, HierAL3a<f64>, HierBL3a<f64>, HierCL3a<f64>>>::new();
    let mut l3b = <L3B<f64, HierA<f64>, HierB<f64>, HierC<f64>>>::new();
    let mut l3c = <L3C<f64, HierAL3c<f64>, HierBL3c<f64>, HierCL3c<f64>>>::new();

    goto.set_n_threads(4);
    l3a.set_n_threads(4);
    l3b.set_n_threads(4);
    l3c.set_n_threads(4);

    let flusher_len = 2*1024*1024; //16MB
    let mut flusher : Vec<f64> = Vec::with_capacity(flusher_len);
    for _ in 0..flusher_len {
        flusher.push(0.0);
    }

    println!("m\tn\tk\t{: <13}{: <13}{: <13}{: <13}{: <15}{: <15}{: <15}{: <15}", "goto", "l3a", "l3b", "l3c", "goto", "l3a", "l3b", "l3c");
    for index in 01..81 {
        let size = index*50;
//        let (m, n, k) = (size, size, size);
        let m = if m_selector < 0 { size * isize::abs(m_selector) } else { m_selector } as usize;
        let n = if n_selector < 0 { size * isize::abs(n_selector) } else { n_selector } as usize;
        let k = if k_selector < 0 { size * isize::abs(k_selector) } else { k_selector } as usize;

        let n_reps = 5;
        let (goto_time, goto_err) = test_algorithm(m, n, k, &mut goto, &mut flusher, n_reps);
        let (l3a_time, l3a_err) = test_algorithm(m, n, k, &mut l3a, &mut flusher, n_reps);
        let (l3b_time, l3b_err) = test_algorithm(m, n, k, &mut l3b, &mut flusher, n_reps);
        let (l3c_time, l3c_err) = test_algorithm(m, n, k, &mut l3c, &mut flusher, n_reps);

        println!("{}\t{}\t{}\t{}{}{}{}{}{}{}{}",
                 m, n, k,
                 format!("{: <13.5}", util::gflops(m,n,k,goto_time)),
                 format!("{: <13.5}", util::gflops(m,n,k,l3a_time)),
                 format!("{: <13.5}", util::gflops(m,n,k,l3b_time)),
                 format!("{: <13.5}", util::gflops(m,n,k,l3c_time)),
                 format!("{: <15.5e}", goto_err.sqrt()),
                 format!("{: <15.5e}", l3a_err.sqrt()),
                 format!("{: <15.5e}", l3b_err.sqrt()),
                 format!("{: <15.5e}", l3c_err.sqrt()));
    }

    let mut sum = 0.0;
    for a in flusher.iter() {
        sum += *a;
    }
    println!("Flush value {}", sum);
}

fn main() {
    //Best for Resident A
    test(768,-1,768);
    //Best for Resident B
    test(-1,768,768);
    //Best for Resident C
    test(768,768,-1);
}
<commit_msg>Fix l3_shapes blocksize<commit_after>#![feature(specialization)]
#![feature(conservative_impl_trait)]
#![feature(cfg_target_feature)]
#![feature(asm)]

#![allow(unused_imports)]

extern crate core;
extern crate typenum;
extern crate momms;

use std::time::{Instant};
use typenum::{U1, B0, UInt, Unsigned};

use momms::kern::{KernelNM,KernelMN};
use momms::matrix::{Scalar, Mat, ColumnPanelMatrix, RowPanelMatrix, Matrix, Hierarch};
use momms::composables::{GemmNode, AlgorithmStep, PartM, PartN, PartK, PackA, PackB, SpawnThreads, ParallelM, ParallelN, TheRest};
use momms::thread_comm::ThreadInfo;
use momms::util;

fn test_algorithm<T: Scalar, Mr: Unsigned, Nr: Unsigned, Kc:Unsigned, CLRS: Unsigned, CLCS: Unsigned,
    S: GemmNode<T, Hierarch<T, Mr, Kc, U1, Mr>, Hierarch<T, Kc, Nr, Nr, U1>, Hierarch<T, Mr, Nr, CLRS, CLCS>>>
    ( m:usize, n: usize, k: usize, algo: &mut S, flusher: &mut Vec<f64>, n_reps: usize ) -> (f64, T)
{
    let algo_desc = S::hierarchy_description();
    let mut best_time: f64 = 9999999999.0;
    let mut worst_err: T = T::zero();

    for _ in 0..n_reps {
        //Create matrices.
        let mut a : Hierarch<T, Mr, Kc, U1, Mr> = Hierarch::new(m, k, &algo_desc, AlgorithmStep::M{bsz: 0}, AlgorithmStep::K{bsz: 0});
        let mut b : Hierarch<T, Kc, Nr, Nr, U1> = Hierarch::new(k, n, &algo_desc, AlgorithmStep::K{bsz: 0}, AlgorithmStep::N{bsz: 0});
        let mut c : Hierarch<T, Mr, Nr, CLRS, CLCS> = Hierarch::new(m, n, &algo_desc, AlgorithmStep::M{bsz: 0}, AlgorithmStep::N{bsz: 0});

        //Fill the matrices
        a.fill_rand(); c.fill_zero(); b.fill_rand();

        //Read a buffer so that A, B, and C are cold in cache.
        for i in flusher.iter_mut() { *i += 1.0; }

        //Time and run algorithm
        let start = Instant::now();
        unsafe{ algo.run( &mut a, &mut b, &mut c, &ThreadInfo::single_thread() ); }
        best_time = best_time.min(util::dur_seconds(start));
        let err = util::test_c_eq_a_b( &mut a, &mut b, &mut c);
        worst_err = worst_err.max(err);
    }
    (best_time, worst_err)
}

fn test(m_selector: isize, n_selector: isize, k_selector: isize) {
    //Goto's algorithm
    type U3000 = UInt<UInt<typenum::U750, B0>, B0>;
    type Nc = U3000;
    type Kc = typenum::U192;
    type Mc = typenum::U120;
    type Mr = typenum::U4;
    type Nr = typenum::U12;

    type Goto<T,MTA,MTB,MTC>
        = SpawnThreads<T, MTA, MTB, MTC,
          PartN<T, MTA, MTB, MTC, Nc,
          PartK<T, MTA, MTB, MTC, Kc,
          PartM<T, MTA, MTB, MTC, Mc,
          ParallelN<T, MTA, MTB, MTC, Nr, TheRest,
          KernelNM<T, MTA, MTB, MTC, Nr, Mr>>>>>>;

    type RootS3 = typenum::U768;
    //Resident A algorithm
    type NcL2 = typenum::U120;
    type L3A<T,MTA,MTB,MTC>
        = SpawnThreads<T, MTA, MTB, MTC,
          PartM<T, MTA, MTB, MTC, RootS3,
          PartK<T, MTA, MTB, MTC, RootS3,
          PartN<T, MTA, MTB, MTC, NcL2,
          PartK<T, MTA, MTB, MTC, Kc,
          ParallelM<T, MTA, MTB, MTC, Nr, TheRest, //This algorithm uses a 12x4 ukernel instead of 4x12 like the other two
          KernelMN<T, MTA, MTB, MTC, Nr, Mr>>>>>>>;

    //Resident B algorithm
    type McL2 = typenum::U120;
    type L3B<T,MTA,MTB,MTC>
        = SpawnThreads<T, MTA, MTB, MTC,
          PartN<T, MTA, MTB, MTC, RootS3,
          PartK<T, MTA, MTB, MTC, RootS3,
          PartM<T, MTA, MTB, MTC, McL2,
          PartK<T, MTA, MTB, MTC, Kc,
          ParallelN<T, MTA, MTB, MTC, Nr, TheRest,
          KernelNM<T, MTA, MTB, MTC, Nr, Mr>>>>>>>;

    type L3CNc = typenum::U780;
    type L3CMc = typenum::U780;
    type L3CKc = typenum::U156;
    type L3CMc = typenum::U156;
    //Resident C algorithm
    type L3C<T,MTA,MTB,MTC>
        = SpawnThreads<T, MTA, MTB, MTC,
          PartN<T, MTA, MTB, MTC, L3CNc,
          PartM<T, MTA, MTB, MTC, L3CMc,
          PartK<T, MTA, MTB, MTC, L3CKc,
          PartM<T, MTA, MTB, MTC, L3CMc,
          ParallelN<T, MTA, MTB, MTC, Nr, TheRest,
          KernelNM<T, MTA, MTB, MTC, Nr, Mr>>>>>>>;

    //We can use the same matrix type for all three algorithms
    type HierA<T> = Hierarch<T, Mr, Kc, U1, Mr>;
    type HierB<T> = Hierarch<T, Kc, Nr, Nr, U1>;
    type HierC<T> = Hierarch<T, Mr, Nr, Nr, U1>;

    type HierAL3a<T> = Hierarch<T, Nr, Kc, U1, Nr>;
    type HierBL3a<T> = Hierarch<T, Kc, Mr, Mr, U1>;
    type HierCL3a<T> = Hierarch<T, Nr, Mr, U1, Nr>;

    type HierAL3c<T> = Hierarch<T, Mr, L3CKc, U1, Mr>;
    type HierBL3c<T> = Hierarch<T, L3CKc, Nr, Nr, U1>;
    type HierCL3c<T> = Hierarch<T, Mr, Nr, Nr, U1>;

    let mut goto = <Goto<f64, HierA<f64>, HierB<f64>, HierC<f64>>>::new();
    let mut l3a = <L3A<f64, HierAL3a<f64>, HierBL3a<f64>, HierCL3a<f64>>>::new();
    let mut l3b = <L3B<f64, HierA<f64>, HierB<f64>, HierC<f64>>>::new();
    let mut l3c = <L3C<f64, HierAL3c<f64>, HierBL3c<f64>, HierCL3c<f64>>>::new();

    goto.set_n_threads(4);
    l3a.set_n_threads(4);
    l3b.set_n_threads(4);
    l3c.set_n_threads(4);

    let flusher_len = 2*1024*1024; //16MB
    let mut flusher : Vec<f64> = Vec::with_capacity(flusher_len);
    for _ in 0..flusher_len {
        flusher.push(0.0);
    }

    println!("m\tn\tk\t{: <13}{: <13}{: <13}{: <13}{: <15}{: <15}{: <15}{: <15}", "goto", "l3a", "l3b", "l3c", "goto", "l3a", "l3b", "l3c");
    for index in 01..81 {
        let size = index*50;
//        let (m, n, k) = (size, size, size);
        let m = if m_selector < 0 { size * isize::abs(m_selector) } else { m_selector } as usize;
        let n = if n_selector < 0 { size * isize::abs(n_selector) } else { n_selector } as usize;
        let k = if k_selector < 0 { size * isize::abs(k_selector) } else { k_selector } as usize;

        let n_reps = 5;
        let (goto_time, goto_err) = test_algorithm(m, n, k, &mut goto, &mut flusher, n_reps);
        let (l3a_time, l3a_err) = test_algorithm(m, n, k, &mut l3a, &mut flusher, n_reps);
        let (l3b_time, l3b_err) = test_algorithm(m, n, k, &mut l3b, &mut flusher, n_reps);
        let (l3c_time, l3c_err) = test_algorithm(m, n, k, &mut l3c, &mut flusher, n_reps);

        println!("{}\t{}\t{}\t{}{}{}{}{}{}{}{}",
                 m, n, k,
                 format!("{: <13.5}", util::gflops(m,n,k,goto_time)),
                 format!("{: <13.5}", util::gflops(m,n,k,l3a_time)),
                 format!("{: <13.5}", util::gflops(m,n,k,l3b_time)),
                 format!("{: <13.5}", util::gflops(m,n,k,l3c_time)),
                 format!("{: <15.5e}", goto_err.sqrt()),
                 format!("{: <15.5e}", l3a_err.sqrt()),
                 format!("{: <15.5e}", l3b_err.sqrt()),
                 format!("{: <15.5e}", l3c_err.sqrt()));
    }

    let mut sum = 0.0;
    for a in flusher.iter() {
        sum += *a;
    }
    println!("Flush value {}", sum);
}

fn main() {
    //Best for Resident A
    test(768,-1,768);
    //Best for Resident B
    test(-1,768,768);
    //Best for Resident C
    test(768,768,-1);
}
<|endoftext|>


<commit_before>/*!
Errors and error handling

This mostly concerns converting to and from the main error type defined
in this crate: [`Error`](enum.Error.html)
*/

use std::ffi::{IntoStringError, NulError};
use std::io;
use std::ops::Range;
use std::str::Utf8Error;
use std::string::FromUtf8Error;
use std::sync;
use stringutils::status_to_string;

/// Enumeration of all error types
#[derive(Debug)]
pub enum Error {
    /// Internal Fits errors
    Fits(FitsError),

    /// Invalid index error
    Index(IndexError),

    /// Generic errors from simple strings
    Message(String),

    /// String conversion errors
    Null(NulError),

    /// UTF-8 conversion errors
    Utf8(Utf8Error),

    /// IO errors
    Io(io::Error),

    /// String conversion errors
    IntoString(IntoStringError),

    /// File path already exists
    ExistingFile(String),

    /// Error unlocking a mutex
    UnlockError,
}

/// Error raised when the user requests invalid indexes for data
#[derive(Debug, PartialEq, Eq)]
pub struct IndexError {
    /// Error message
    pub message: String,

    /// The range requested by the user
    pub given: Range<usize>,
}

/// Handy error type for use internally
pub type Result<T> = ::std::result::Result<T, Error>;

impl ::std::convert::From<FitsError> for Error {
    fn from(error: FitsError) -> Self {
        Error::Fits(error)
    }
}

impl ::std::convert::From<IndexError> for Error {
    fn from(error: IndexError) -> Self {
        Error::Index(error)
    }
}

impl<'a> ::std::convert::From<&'a str> for Error {
    fn from(error: &'a str) -> Self {
        Error::Message(error.to_string())
    }
}

impl ::std::convert::From<NulError> for Error {
    fn from(error: NulError) -> Self {
        Error::Null(error)
    }
}

impl ::std::convert::From<FromUtf8Error> for Error {
    fn from(error: FromUtf8Error) -> Self {
        Error::Utf8(error.utf8_error())
    }
}

impl ::std::convert::From<Utf8Error> for Error {
    fn from(error: Utf8Error) -> Self {
        Error::Utf8(error)
    }
}

impl ::std::convert::From<Box<dyn (::std::error::Error)>> for Error {
    fn from(error: Box<dyn (::std::error::Error)>) -> Self {
        let description = error.description();
        let message = match error.source() {
            Some(msg) => format!("Error: {} caused by {}", description, msg),
            None => format!("Error: {}", description),
        };
        Error::Message(message)
    }
}

impl ::std::convert::From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Error::Io(e)
    }
}

impl ::std::convert::From<IntoStringError> for Error {
    fn from(e: IntoStringError) -> Self {
        Error::IntoString(e)
    }
}

use fitsfile::FitsFile;
type PoisonError<'a> = sync::PoisonError<sync::MutexGuard<'a, FitsFile>>;

impl<'a> ::std::convert::From<PoisonError<'a>> for Error {
    fn from(_e: PoisonError) -> Self {
        Error::UnlockError
    }
}

impl ::std::fmt::Display for Error {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> {
        match *self {
            Error::Fits(ref e) => write!(f, "Fits error: {:?}", e),
            Error::Message(ref s) => write!(f, "Error: {}", s),
            Error::Null(ref e) => e.fmt(f),
            Error::Utf8(ref e) => e.fmt(f),
            Error::Index(ref e) => write!(f, "Error: {:?}", e),
            Error::Io(ref e) => e.fmt(f),
            Error::IntoString(ref e) => e.fmt(f),
            Error::ExistingFile(ref filename) => write!(f, "File {} already exists", filename),
            Error::UnlockError => write!(f, "Invalid concurrent access to fits file"),
        }
    }
}

impl ::std::error::Error for Error {
    fn description(&self) -> &str {
        "fitsio error"
    }
}

/**
Error type

`cfitsio` passes errors through integer status codes. This struct wraps this and its associated
error message.
*/
#[derive(Debug, PartialEq, Eq)]
pub struct FitsError {
    /// `cfitsio` error code
    pub status: i32,
    /// `cfitsio` message for error code
    pub message: String,
}

/// Function for chaining result types
pub fn check_status(status: i32) -> Result<()> {
    match status {
        0 => Ok(()),
        _ => Err(Error::Fits(FitsError {
            status,
            message: status_to_string(status)?.expect("guaranteed to be Some"),
        })),
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_check_status_ok() {
        assert!(check_status(0).is_ok());
    }

    #[test]
    fn test_check_status_ok_with_value() {
        assert_eq!(check_status(0).map(|_| 10i32).unwrap(), 10i32);
    }

    #[test]
    fn test_check_status_with_err() {
        assert!(check_status(105).map(|_| 10i32).is_err());
    }
}
<commit_msg>Compiler warns about deprecated Error::description<commit_after>/*!
Errors and error handling

This mostly concerns converting to and from the main error type defined
in this crate: [`Error`](enum.Error.html)
*/

use std::ffi::{IntoStringError, NulError};
use std::io;
use std::ops::Range;
use std::str::Utf8Error;
use std::string::FromUtf8Error;
use std::sync;
use stringutils::status_to_string;

/// Enumeration of all error types
#[derive(Debug)]
pub enum Error {
    /// Internal Fits errors
    Fits(FitsError),

    /// Invalid index error
    Index(IndexError),

    /// Generic errors from simple strings
    Message(String),

    /// String conversion errors
    Null(NulError),

    /// UTF-8 conversion errors
    Utf8(Utf8Error),

    /// IO errors
    Io(io::Error),

    /// String conversion errors
    IntoString(IntoStringError),

    /// File path already exists
    ExistingFile(String),

    /// Error unlocking a mutex
    UnlockError,
}

/// Error raised when the user requests invalid indexes for data
#[derive(Debug, PartialEq, Eq)]
pub struct IndexError {
    /// Error message
    pub message: String,

    /// The range requested by the user
    pub given: Range<usize>,
}

/// Handy error type for use internally
pub type Result<T> = ::std::result::Result<T, Error>;

impl ::std::convert::From<FitsError> for Error {
    fn from(error: FitsError) -> Self {
        Error::Fits(error)
    }
}

impl ::std::convert::From<IndexError> for Error {
    fn from(error: IndexError) -> Self {
        Error::Index(error)
    }
}

impl<'a> ::std::convert::From<&'a str> for Error {
    fn from(error: &'a str) -> Self {
        Error::Message(error.to_string())
    }
}

impl ::std::convert::From<NulError> for Error {
    fn from(error: NulError) -> Self {
        Error::Null(error)
    }
}

impl ::std::convert::From<FromUtf8Error> for Error {
    fn from(error: FromUtf8Error) -> Self {
        Error::Utf8(error.utf8_error())
    }
}

impl ::std::convert::From<Utf8Error> for Error {
    fn from(error: Utf8Error) -> Self {
        Error::Utf8(error)
    }
}

impl ::std::convert::From<Box<dyn (::std::error::Error)>> for Error {
    fn from(error: Box<dyn (::std::error::Error)>) -> Self {
        let message = match error.source() {
            Some(msg) => format!("Error: {} caused by {}", error, msg),
            None => format!("Error: {}", error),
        };
        Error::Message(message)
    }
}

impl ::std::convert::From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Error::Io(e)
    }
}

impl ::std::convert::From<IntoStringError> for Error {
    fn from(e: IntoStringError) -> Self {
        Error::IntoString(e)
    }
}

use fitsfile::FitsFile;
type PoisonError<'a> = sync::PoisonError<sync::MutexGuard<'a, FitsFile>>;

impl<'a> ::std::convert::From<PoisonError<'a>> for Error {
    fn from(_e: PoisonError) -> Self {
        Error::UnlockError
    }
}

impl ::std::fmt::Display for Error {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> {
        match *self {
            Error::Fits(ref e) => write!(f, "Fits error: {:?}", e),
            Error::Message(ref s) => write!(f, "Error: {}", s),
            Error::Null(ref e) => e.fmt(f),
            Error::Utf8(ref e) => e.fmt(f),
            Error::Index(ref e) => write!(f, "Error: {:?}", e),
            Error::Io(ref e) => e.fmt(f),
            Error::IntoString(ref e) => e.fmt(f),
            Error::ExistingFile(ref filename) => write!(f, "File {} already exists", filename),
            Error::UnlockError => write!(f, "Invalid concurrent access to fits file"),
        }
    }
}

impl ::std::error::Error for Error {
    fn description(&self) -> &str {
        "fitsio error"
    }
}

/**
Error type

`cfitsio` passes errors through integer status codes. This struct wraps this and its associated
error message.
*/
#[derive(Debug, PartialEq, Eq)]
pub struct FitsError {
    /// `cfitsio` error code
    pub status: i32,
    /// `cfitsio` message for error code
    pub message: String,
}

/// Function for chaining result types
pub fn check_status(status: i32) -> Result<()> {
    match status {
        0 => Ok(()),
        _ => Err(Error::Fits(FitsError {
            status,
            message: status_to_string(status)?.expect("guaranteed to be Some"),
        })),
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_check_status_ok() {
        assert!(check_status(0).is_ok());
    }

    #[test]
    fn test_check_status_ok_with_value() {
        assert_eq!(check_status(0).map(|_| 10i32).unwrap(), 10i32);
    }

    #[test]
    fn test_check_status_with_err() {
        assert!(check_status(105).map(|_| 10i32).is_err());
    }
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

#[macro_export]
macro_rules! generate_error_imports {
    () => {
        use std::error::Error;
        use std::fmt::Error as FmtError;
        use std::fmt::{Display, Formatter};

        use $crate::into::IntoError;
    }
}

#[macro_export]
macro_rules! generate_error_module {
    ( $exprs:item ) => {
        pub mod error {
            generate_error_imports!();
            $exprs
        }
    }
}

#[macro_export]
macro_rules! generate_custom_error_types {
    {
        $name: ident,
        $kindname: ident,
        $customMemberTypeName: ident,
        $($kind:ident => $string:expr),*
    } => {
        #[derive(Clone, Copy, Debug, PartialEq)]
        pub enum $kindname {
            $( $kind ),*
        }

        impl Display for $kindname {

            fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
                let s = match *self {
                    $( $kindname::$kind => $string ),*
                };
                try!(write!(fmt, "{}", s));
                Ok(())
            }

        }

        impl IntoError for $kindname {
            type Target = $name;

            fn into_error(self) -> Self::Target {
                $name::new(self, None)
            }

            fn into_error_with_cause(self, cause: Box<Error>) -> Self::Target {
                $name::new(self, Some(cause))
            }

        }

        #[derive(Debug)]
        pub struct $name {
            err_type: $kindname,
            cause: Option<Box<Error>>,
            custom_data: Option<$customMemberTypeName>,
        }

        impl $name {

            pub fn new(errtype: $kindname, cause: Option<Box<Error>>) -> $name {
                $name {
                    err_type: errtype,
                    cause: cause,
                    custom_data: None,
                }
            }

            #[allow(dead_code)]
            pub fn err_type(&self) -> $kindname {
                self.err_type
            }

            #[allow(dead_code)]
            pub fn with_custom_data(mut self, custom: $customMemberTypeName) -> $name {
                self.custom_data = Some(custom);
                self
            }

        }

        impl Into<$name> for $kindname {

            fn into(self) -> $name {
                $name::new(self, None)
            }

        }

        impl Display for $name {

            fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
                try!(write!(fmt, "[{}]", self.err_type));
                Ok(())
            }

        }

        impl Error for $name {

            fn description(&self) -> &str {
                match self.err_type {
                    $( $kindname::$kind => $string ),*
                }
            }

            fn cause(&self) -> Option<&Error> {
                self.cause.as_ref().map(|e| &**e)
            }

        }

    }
}

#[macro_export]
macro_rules! generate_result_helper {
    (
        $name: ident,
        $kindname: ident
    ) => {
        /// Trait to replace
        ///
        /// ```ignore
        /// foo.map_err(Box::new).map_err(|e| SomeType::SomeErrorKind.into_error_with_cause(e))
        /// // or:
        /// foo.map_err(|e| SomeType::SomeErrorKind.into_error_with_cause(Box::new(e)))
        /// ```
        ///
        /// with much nicer
        ///
        /// ```ignore
        /// foo.map_err_into(SomeType::SomeErrorKind)
        /// ```
        ///
        pub trait MapErrInto<T> {
            fn map_err_into(self, error_kind: $kindname) -> Result<T, $name>;
        }

        impl<T, E: Error + 'static> MapErrInto<T> for Result<T, E> {

            fn map_err_into(self, error_kind: $kindname) -> Result<T, $name> {
                self.map_err(Box::new)
                    .map_err(|e| error_kind.into_error_with_cause(e))
            }

        }
    }
}

#[macro_export]
macro_rules! generate_option_helper {
    (
        $name: ident,
        $kindname: ident
    ) => {
        /// Trait to replace
        ///
        /// ```ignore
        /// foo.ok_or(SomeType::SomeErrorKind.into_error())
        /// ```
        ///
        /// with
        ///
        /// ```ignore
        /// foo.ok_or_errkind(SomeType::SomeErrorKind)
        /// ```
        pub trait OkOrErr<T> {
            fn ok_or_errkind(self, kind: $kindname) -> Result<T, $name>;
        }

        impl<T> OkOrErr<T> for Option<T> {

            fn ok_or_errkind(self, kind: $kindname) -> Result<T, $name> {
                self.ok_or(kind.into_error())
            }

        }
    }
}

#[macro_export]
macro_rules! generate_error_types {
    (
        $name: ident,
        $kindname: ident,
        $($kind:ident => $string:expr),*
    ) => {
        #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Copy)]
        pub struct SomeNotExistingTypeWithATypeNameNoOneWillEverChoose {}
        generate_custom_error_types!($name, $kindname,
                                     SomeNotExistingTypeWithATypeNameNoOneWillEverChoose,
                                     $($kind => $string),*);

        generate_result_helper!($name, $kindname);
        generate_option_helper!($name, $kindname);
    }
}

#[cfg(test)]
mod test {

    generate_error_module!(
        generate_error_types!(TestError, TestErrorKind,
            TestErrorKindA => "testerrorkind a",
            TestErrorKindB => "testerrorkind B");
    );

    #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Copy)]
    pub struct CustomData {
        pub test: i32,
        pub othr: i64,
    }

    generate_error_imports!();

    #[allow(dead_code)]
    generate_custom_error_types!(CustomTestError, CustomTestErrorKind,
        CustomData,
        CustomErrorKindA => "customerrorkind a",
        CustomErrorKindB => "customerrorkind B");

    // Allow dead code here.
    // We wrote this to show that custom test types can be implemented.
    #[allow(dead_code)]
    impl CustomTestError {
        pub fn test(&self) -> i32 {
            match self.custom_data {
                Some(t) => t.test,
                None => 0,
            }
        }

        pub fn bar(&self) -> i64 {
            match self.custom_data {
                Some(t) => t.othr,
                None => 0,
            }
        }
    }

    #[test]
    fn test_a() {
        use self::error::{TestError, TestErrorKind};

        let kind = TestErrorKind::TestErrorKindA;
        assert_eq!(String::from("testerrorkind a"), format!("{}", kind));

        let e = TestError::new(kind, None);
        assert_eq!(String::from("[testerrorkind a]"), format!("{}", e));
    }

    #[test]
    fn test_b() {
        use self::error::{TestError, TestErrorKind};

        let kind = TestErrorKind::TestErrorKindB;
        assert_eq!(String::from("testerrorkind B"), format!("{}", kind));

        let e = TestError::new(kind, None);
        assert_eq!(String::from("[testerrorkind B]"), format!("{}", e));

    }

    #[test]
    fn test_ab() {
        use std::error::Error;
        use self::error::{TestError, TestErrorKind};

        let kinda = TestErrorKind::TestErrorKindA;
        let kindb = TestErrorKind::TestErrorKindB;
        assert_eq!(String::from("testerrorkind a"), format!("{}", kinda));
        assert_eq!(String::from("testerrorkind B"), format!("{}", kindb));

        let e = TestError::new(kinda, Some(Box::new(TestError::new(kindb, None))));
        assert_eq!(String::from("[testerrorkind a]"), format!("{}", e));
        assert_eq!(TestErrorKind::TestErrorKindA, e.err_type());
        assert_eq!(String::from("[testerrorkind B]"), format!("{}", e.cause().unwrap()));
    }

    pub mod anothererrormod {
        generate_error_imports!();
        generate_error_types!(TestError, TestErrorKind,
            TestErrorKindA => "testerrorkind a",
            TestErrorKindB => "testerrorkind B");
    }

    #[test]
    fn test_other_a() {
        use self::anothererrormod::{TestError, TestErrorKind};

        let kind = TestErrorKind::TestErrorKindA;
        assert_eq!(String::from("testerrorkind a"), format!("{}", kind));

        let e = TestError::new(kind, None);
        assert_eq!(String::from("[testerrorkind a]"), format!("{}", e));
    }

    #[test]
    fn test_other_b() {
        use self::anothererrormod::{TestError, TestErrorKind};

        let kind = TestErrorKind::TestErrorKindB;
        assert_eq!(String::from("testerrorkind B"), format!("{}", kind));

        let e = TestError::new(kind, None);
        assert_eq!(String::from("[testerrorkind B]"), format!("{}", e));

    }

    #[test]
    fn test_other_ab() {
        use std::error::Error;
        use self::anothererrormod::{TestError, TestErrorKind};

        let kinda = TestErrorKind::TestErrorKindA;
        let kindb = TestErrorKind::TestErrorKindB;
        assert_eq!(String::from("testerrorkind a"), format!("{}", kinda));
        assert_eq!(String::from("testerrorkind B"), format!("{}", kindb));

        let e = TestError::new(kinda, Some(Box::new(TestError::new(kindb, None))));
        assert_eq!(String::from("[testerrorkind a]"), format!("{}", e));
        assert_eq!(TestErrorKind::TestErrorKindA, e.err_type());
        assert_eq!(String::from("[testerrorkind B]"), format!("{}", e.cause().unwrap()));
    }

    #[test]
    fn test_error_kind_mapping() {
        use std::io::{Error, ErrorKind};
        use self::error::MapErrInto;
        use self::error::TestErrorKind;

        let err : Result<(), _> = Err(Error::new(ErrorKind::Other, ""));
        let err : Result<(), _> = err.map_err_into(TestErrorKind::TestErrorKindA);

        assert!(err.is_err());
        let err = err.unwrap_err();

        match err.err_type() {
            TestErrorKind::TestErrorKindA => assert!(true),
            _ => assert!(false),
        }
    }

    #[test]
    fn test_error_kind_double_mapping() {
        use std::io::{Error, ErrorKind};
        use self::error::MapErrInto;
        use self::error::TestErrorKind;

        let err : Result<(), _> = Err(Error::new(ErrorKind::Other, ""));
        let err : Result<(), _> = err.map_err_into(TestErrorKind::TestErrorKindA)
                                     .map_err_into(TestErrorKind::TestErrorKindB);

        assert!(err.is_err());
        let err = err.unwrap_err();
        match err.err_type() {
            TestErrorKind::TestErrorKindB => assert!(true),
            _ => assert!(false),
        }

        // not sure how to test that the inner error is of TestErrorKindA, actually...
        match err.cause() {
            Some(_) => assert!(true),
            None    => assert!(false),
        }

    }

    #[test]
    fn test_error_option_good() {
        use self::error::OkOrErr;
        use self::error::TestErrorKind;

        let something = Some(1);
        match something.ok_or_errkind(TestErrorKind::TestErrorKindA) {
            Ok(1) => assert!(true),
            _     => assert!(false),
        }
    }

    #[test]
    fn test_error_option_bad() {
        use self::error::OkOrErr;
        use self::error::TestErrorKind;

        let something : Option<i32> = None;
        match something.ok_or_errkind(TestErrorKind::TestErrorKindA) {
            Ok(_)  => assert!(false),
            Err(_) => assert!(true),
        }
    }

}
<commit_msg>Allow dead code in the whole test module<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

#[macro_export]
macro_rules! generate_error_imports {
    () => {
        use std::error::Error;
        use std::fmt::Error as FmtError;
        use std::fmt::{Display, Formatter};

        use $crate::into::IntoError;
    }
}

#[macro_export]
macro_rules! generate_error_module {
    ( $exprs:item ) => {
        pub mod error {
            generate_error_imports!();
            $exprs
        }
    }
}

#[macro_export]
macro_rules! generate_custom_error_types {
    {
        $name: ident,
        $kindname: ident,
        $customMemberTypeName: ident,
        $($kind:ident => $string:expr),*
    } => {
        #[derive(Clone, Copy, Debug, PartialEq)]
        pub enum $kindname {
            $( $kind ),*
        }

        impl Display for $kindname {

            fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
                let s = match *self {
                    $( $kindname::$kind => $string ),*
                };
                try!(write!(fmt, "{}", s));
                Ok(())
            }

        }

        impl IntoError for $kindname {
            type Target = $name;

            fn into_error(self) -> Self::Target {
                $name::new(self, None)
            }

            fn into_error_with_cause(self, cause: Box<Error>) -> Self::Target {
                $name::new(self, Some(cause))
            }

        }

        #[derive(Debug)]
        pub struct $name {
            err_type: $kindname,
            cause: Option<Box<Error>>,
            custom_data: Option<$customMemberTypeName>,
        }

        impl $name {

            pub fn new(errtype: $kindname, cause: Option<Box<Error>>) -> $name {
                $name {
                    err_type: errtype,
                    cause: cause,
                    custom_data: None,
                }
            }

            #[allow(dead_code)]
            pub fn err_type(&self) -> $kindname {
                self.err_type
            }

            #[allow(dead_code)]
            pub fn with_custom_data(mut self, custom: $customMemberTypeName) -> $name {
                self.custom_data = Some(custom);
                self
            }

        }

        impl Into<$name> for $kindname {

            fn into(self) -> $name {
                $name::new(self, None)
            }

        }

        impl Display for $name {

            fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
                try!(write!(fmt, "[{}]", self.err_type));
                Ok(())
            }

        }

        impl Error for $name {

            fn description(&self) -> &str {
                match self.err_type {
                    $( $kindname::$kind => $string ),*
                }
            }

            fn cause(&self) -> Option<&Error> {
                self.cause.as_ref().map(|e| &**e)
            }

        }

    }
}

#[macro_export]
macro_rules! generate_result_helper {
    (
        $name: ident,
        $kindname: ident
    ) => {
        /// Trait to replace
        ///
        /// ```ignore
        /// foo.map_err(Box::new).map_err(|e| SomeType::SomeErrorKind.into_error_with_cause(e))
        /// // or:
        /// foo.map_err(|e| SomeType::SomeErrorKind.into_error_with_cause(Box::new(e)))
        /// ```
        ///
        /// with much nicer
        ///
        /// ```ignore
        /// foo.map_err_into(SomeType::SomeErrorKind)
        /// ```
        ///
        pub trait MapErrInto<T> {
            fn map_err_into(self, error_kind: $kindname) -> Result<T, $name>;
        }

        impl<T, E: Error + 'static> MapErrInto<T> for Result<T, E> {

            fn map_err_into(self, error_kind: $kindname) -> Result<T, $name> {
                self.map_err(Box::new)
                    .map_err(|e| error_kind.into_error_with_cause(e))
            }

        }
    }
}

#[macro_export]
macro_rules! generate_option_helper {
    (
        $name: ident,
        $kindname: ident
    ) => {
        /// Trait to replace
        ///
        /// ```ignore
        /// foo.ok_or(SomeType::SomeErrorKind.into_error())
        /// ```
        ///
        /// with
        ///
        /// ```ignore
        /// foo.ok_or_errkind(SomeType::SomeErrorKind)
        /// ```
        pub trait OkOrErr<T> {
            fn ok_or_errkind(self, kind: $kindname) -> Result<T, $name>;
        }

        impl<T> OkOrErr<T> for Option<T> {

            fn ok_or_errkind(self, kind: $kindname) -> Result<T, $name> {
                self.ok_or(kind.into_error())
            }

        }
    }
}

#[macro_export]
macro_rules! generate_error_types {
    (
        $name: ident,
        $kindname: ident,
        $($kind:ident => $string:expr),*
    ) => {
        #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Copy)]
        pub struct SomeNotExistingTypeWithATypeNameNoOneWillEverChoose {}
        generate_custom_error_types!($name, $kindname,
                                     SomeNotExistingTypeWithATypeNameNoOneWillEverChoose,
                                     $($kind => $string),*);

        generate_result_helper!($name, $kindname);
        generate_option_helper!($name, $kindname);
    }
}

#[cfg(test)]
#[allow(dead_code)]
mod test {

    generate_error_module!(
        generate_error_types!(TestError, TestErrorKind,
            TestErrorKindA => "testerrorkind a",
            TestErrorKindB => "testerrorkind B");
    );

    #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Copy)]
    pub struct CustomData {
        pub test: i32,
        pub othr: i64,
    }

    generate_error_imports!();

    #[allow(dead_code)]
    generate_custom_error_types!(CustomTestError, CustomTestErrorKind,
        CustomData,
        CustomErrorKindA => "customerrorkind a",
        CustomErrorKindB => "customerrorkind B");

    // Allow dead code here.
    // We wrote this to show that custom test types can be implemented.
    #[allow(dead_code)]
    impl CustomTestError {
        pub fn test(&self) -> i32 {
            match self.custom_data {
                Some(t) => t.test,
                None => 0,
            }
        }

        pub fn bar(&self) -> i64 {
            match self.custom_data {
                Some(t) => t.othr,
                None => 0,
            }
        }
    }

    #[test]
    fn test_a() {
        use self::error::{TestError, TestErrorKind};

        let kind = TestErrorKind::TestErrorKindA;
        assert_eq!(String::from("testerrorkind a"), format!("{}", kind));

        let e = TestError::new(kind, None);
        assert_eq!(String::from("[testerrorkind a]"), format!("{}", e));
    }

    #[test]
    fn test_b() {
        use self::error::{TestError, TestErrorKind};

        let kind = TestErrorKind::TestErrorKindB;
        assert_eq!(String::from("testerrorkind B"), format!("{}", kind));

        let e = TestError::new(kind, None);
        assert_eq!(String::from("[testerrorkind B]"), format!("{}", e));

    }

    #[test]
    fn test_ab() {
        use std::error::Error;
        use self::error::{TestError, TestErrorKind};

        let kinda = TestErrorKind::TestErrorKindA;
        let kindb = TestErrorKind::TestErrorKindB;
        assert_eq!(String::from("testerrorkind a"), format!("{}", kinda));
        assert_eq!(String::from("testerrorkind B"), format!("{}", kindb));

        let e = TestError::new(kinda, Some(Box::new(TestError::new(kindb, None))));
        assert_eq!(String::from("[testerrorkind a]"), format!("{}", e));
        assert_eq!(TestErrorKind::TestErrorKindA, e.err_type());
        assert_eq!(String::from("[testerrorkind B]"), format!("{}", e.cause().unwrap()));
    }

    pub mod anothererrormod {
        generate_error_imports!();
        generate_error_types!(TestError, TestErrorKind,
            TestErrorKindA => "testerrorkind a",
            TestErrorKindB => "testerrorkind B");
    }

    #[test]
    fn test_other_a() {
        use self::anothererrormod::{TestError, TestErrorKind};

        let kind = TestErrorKind::TestErrorKindA;
        assert_eq!(String::from("testerrorkind a"), format!("{}", kind));

        let e = TestError::new(kind, None);
        assert_eq!(String::from("[testerrorkind a]"), format!("{}", e));
    }

    #[test]
    fn test_other_b() {
        use self::anothererrormod::{TestError, TestErrorKind};

        let kind = TestErrorKind::TestErrorKindB;
        assert_eq!(String::from("testerrorkind B"), format!("{}", kind));

        let e = TestError::new(kind, None);
        assert_eq!(String::from("[testerrorkind B]"), format!("{}", e));

    }

    #[test]
    fn test_other_ab() {
        use std::error::Error;
        use self::anothererrormod::{TestError, TestErrorKind};

        let kinda = TestErrorKind::TestErrorKindA;
        let kindb = TestErrorKind::TestErrorKindB;
        assert_eq!(String::from("testerrorkind a"), format!("{}", kinda));
        assert_eq!(String::from("testerrorkind B"), format!("{}", kindb));

        let e = TestError::new(kinda, Some(Box::new(TestError::new(kindb, None))));
        assert_eq!(String::from("[testerrorkind a]"), format!("{}", e));
        assert_eq!(TestErrorKind::TestErrorKindA, e.err_type());
        assert_eq!(String::from("[testerrorkind B]"), format!("{}", e.cause().unwrap()));
    }

    #[test]
    fn test_error_kind_mapping() {
        use std::io::{Error, ErrorKind};
        use self::error::MapErrInto;
        use self::error::TestErrorKind;

        let err : Result<(), _> = Err(Error::new(ErrorKind::Other, ""));
        let err : Result<(), _> = err.map_err_into(TestErrorKind::TestErrorKindA);

        assert!(err.is_err());
        let err = err.unwrap_err();

        match err.err_type() {
            TestErrorKind::TestErrorKindA => assert!(true),
            _ => assert!(false),
        }
    }

    #[test]
    fn test_error_kind_double_mapping() {
        use std::io::{Error, ErrorKind};
        use self::error::MapErrInto;
        use self::error::TestErrorKind;

        let err : Result<(), _> = Err(Error::new(ErrorKind::Other, ""));
        let err : Result<(), _> = err.map_err_into(TestErrorKind::TestErrorKindA)
                                     .map_err_into(TestErrorKind::TestErrorKindB);

        assert!(err.is_err());
        let err = err.unwrap_err();
        match err.err_type() {
            TestErrorKind::TestErrorKindB => assert!(true),
            _ => assert!(false),
        }

        // not sure how to test that the inner error is of TestErrorKindA, actually...
        match err.cause() {
            Some(_) => assert!(true),
            None    => assert!(false),
        }

    }

    #[test]
    fn test_error_option_good() {
        use self::error::OkOrErr;
        use self::error::TestErrorKind;

        let something = Some(1);
        match something.ok_or_errkind(TestErrorKind::TestErrorKindA) {
            Ok(1) => assert!(true),
            _     => assert!(false),
        }
    }

    #[test]
    fn test_error_option_bad() {
        use self::error::OkOrErr;
        use self::error::TestErrorKind;

        let something : Option<i32> = None;
        match something.ok_or_errkind(TestErrorKind::TestErrorKindA) {
            Ok(_)  => assert!(false),
            Err(_) => assert!(true),
        }
    }

}
<|endoftext|>