<commit_before>extern crate xml;

use std::collections::HashMap;
use std::str;

use xml::writer::{EmitterConfig, XmlEvent};

fn characters_to_xml(characters: HashMap<String, String>) -> String {
    let mut output: Vec<u8> = Vec::new();
    let mut writer = EmitterConfig::new()
        .perform_indent(true)
        .create_writer(&mut output);

    writer
        .write(XmlEvent::start_element("CharacterRemarks"))
        .unwrap();

    for (character, line) in &characters {
        let element = XmlEvent::start_element("Character").attr("name", character);
        writer.write(element).unwrap();
        writer.write(XmlEvent::characters(line)).unwrap();
        writer.write(XmlEvent::end_element()).unwrap();
    }

    writer.write(XmlEvent::end_element()).unwrap();
    str::from_utf8(&output).unwrap().to_string()
}

fn main() {
    let mut input = HashMap::new();
    input.insert(
        "April".to_string(),
        "Bubbly: I'm > Tam and <= Emily".to_string(),
    );
    input.insert(
        "Tam O'Shanter".to_string(),
        "Burns: \"When chapman billies leave the street ...\"".to_string(),
    );
    input.insert("Emily".to_string(), "Short & shrift".to_string());

    let output = characters_to_xml(input);

    println!("{}", output);
}
<commit_msg>Added tests<commit_after>extern crate xml;

use std::collections::HashMap;
use std::str;

use xml::writer::{EmitterConfig, XmlEvent};

fn characters_to_xml(characters: HashMap<String, String>) -> String {
    let mut output: Vec<u8> = Vec::new();
    let mut writer = EmitterConfig::new()
        .perform_indent(true)
        .create_writer(&mut output);

    writer
        .write(XmlEvent::start_element("CharacterRemarks"))
        .unwrap();

    for (character, line) in &characters {
        let element = XmlEvent::start_element("Character").attr("name", character);
        writer.write(element).unwrap();
        writer.write(XmlEvent::characters(line)).unwrap();
        writer.write(XmlEvent::end_element()).unwrap();
    }

    writer.write(XmlEvent::end_element()).unwrap();
    str::from_utf8(&output).unwrap().to_string()
}

fn main() {
    let mut input = HashMap::new();
    input.insert(
        "April".to_string(),
        "Bubbly: I'm > Tam and <= Emily".to_string(),
    );
    input.insert(
        "Tam O'Shanter".to_string(),
        "Burns: \"When chapman billies leave the street ...\"".to_string(),
    );
    input.insert("Emily".to_string(), "Short & shrift".to_string());

    let output = characters_to_xml(input);

    println!("{}", output);
    assert!(output.contains(
        "<Character name=\"Tam O'Shanter\">Burns: \"When chapman \
         billies leave the street ...\"</Character>"
    ));
    assert!(
        output.contains("<Character name=\"April\">Bubbly: I'm > Tam and <= Emily</Character>")
    );
    assert!(output.contains("<Character name=\"Emily\">Short & shrift</Character>"));
}
<|endoftext|>


<commit_before>extern crate time;
extern crate getopts;
extern crate tcc;

use std::os::args;
use time::{Timespec};
use getopts::{optopt,optflag,getopts,OptGroup,usage};

fn main() {
    // Get time right away so that printed time does not reflect
    // time spent parsing arguments and formatting
    let ts = tcc::timestamp_now();
    let t = tcc::Time::time_now(tcc::Yearbase(None));

    println!("The current timestamp: {}",ts);
    println!("The beginning timestamp: {}",tcc::timestamp_at(Timespec{sec: tcc::EPOCH, nsec: 0}));

    println!("The current time: {}",t);
    println!("The beginning time: {}",tcc::Time::time_at(Timespec{sec: tcc::EPOCH, nsec: 0},tcc::Yearbase(None)));

    // Get options from command line arguments in order to build Calendar
    let opts = &[
        optflag("h", "help", "print this help menu"),
        optopt("Y","year-base","Integer representing the year base","NUMBER"),
        optopt("Q","mod-quarter","Integer representing the datemod for quarters","NUMBER"),
        optopt("L","mod-luna","Integer representing the datemod for lunas","NUMBER"),
        optopt("W","mod-week","Integer representing the datemod for weeks","NUMBER"),
        optopt("D","mod-day","Integer representing the datemod for days","NUMBER"),
        optopt("R","mod-hour","Integer representing the datemod for hours","NUMBER"),
        optopt("M","mod-minute","Integer representing the datemod for minutes","NUMBER")
    ];

    let matches = match getopts(args().tail(), opts) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) }
    };

    if matches.opt_present("h") {
        print!("{}", usage("tcc-date", opts));
        println!("\nExample: tcc-date -h 5");
        return;
    }

    let mut c = tcc::Calendar::new().
                               force_year_sign(true).
                               month_delimiter('/').
                               designator_delimiter(None);

    println!("Calendar: {}",c);

}
<commit_msg>update usage of getopts crate<commit_after>extern crate time;
extern crate getopts;
extern crate tcc;

use time::{Timespec};
use getopts::Options;
use std::env;

fn print_usage(program: &str, opts: Options) {
    let brief = format!("Usage: {} [options]",program);
    print!("{}", opts.usage(&brief));
}

fn main() {
    // Get time right away so that printed time does not reflect
    // time spent parsing arguments and formatting
    let ts = tcc::timestamp_now();
    let t = tcc::Time::time_now(tcc::Yearbase(None));

    println!("The current timestamp: {}",ts);
    println!("The beginning timestamp: {}",tcc::timestamp_at(Timespec{sec: tcc::EPOCH, nsec: 0}));

    println!("The current time: {}",t);
    println!("The beginning time: {}",tcc::Time::time_at(Timespec{sec: tcc::EPOCH, nsec: 0},tcc::Yearbase(None)));

    // Get options from command line arguments in order to build Calendar
    let mut opts = Options::new();
    opts.optflag("h", "help", "print this help menu");
    opts.optopt("Y","year-base","Integer representing the year base","NUMBER");
    opts.optopt("Q","mod-quarter","Integer representing the datemod for quarters","NUMBER");
    opts.optopt("L","mod-luna","Integer representing the datemod for lunas","NUMBER");
    opts.optopt("W","mod-week","Integer representing the datemod for weeks","NUMBER");
    opts.optopt("D","mod-day","Integer representing the datemod for days","NUMBER");
    opts.optopt("R","mod-hour","Integer representing the datemod for hours","NUMBER");
    opts.optopt("M","mod-minute","Integer representing the datemod for minutes","NUMBER");

    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) }
    };

    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }

    let mut c = tcc::Calendar::new().
                               force_year_sign(true).
                               month_delimiter('/').
                               designator_delimiter(None);

    println!("Calendar: {}",c);

}
<|endoftext|>


<commit_before>use std::ascii::AsciiExt;

const SPACE: u8 = 0x20;

/// Reverse the contents of the input vector between `from` and `to`
/// inclusively.
#[inline]
fn reverse_vec(v: &mut [u8], from: usize, to: usize) {
    v[from..to].reverse();
}

/// Reverse the words in the input string. Words are defined as any characters
/// other than a space. Only ASCII input is acceptable.
///
/// # Examples
///
/// ```
/// use reversewords::ascii_reverse_words;
///
/// let mut s = "Hello from Rust!".to_string();
/// ascii_reverse_words(&mut s);
/// assert_eq!("Rust! from Hello", s)
/// ```
#[inline]
pub fn ascii_reverse_words(s: &mut String) {
    let len = s.len();
    if len == 0 {
        return;
    }

    if !s.is_ascii() {
        // Reversing non-ASCII strings is hard because you have to make sure
        // not to spit graphemes.
        panic!("Unexpected non-ASCII string: \"{}\"", s);
    }

    unsafe {
        let ref mut bytes = s.as_mut_vec();  // Unsafe.
        // Reverse the entire string. So:
        // "Hello from Rust!" => "!tsuR morf olleH"
        reverse_vec(bytes, 0, len);

        // Find each "word" (non-space) in `bytes` and reverse it. So
        // "!tsuR" => "Rust1".
        let mut left = 0;
        while left < len {
            if bytes[left] == SPACE {
                left += 1;
            } else {
                let mut right = left;
                while right < len && bytes[right] != SPACE {
                    right += 1;
                }
                reverse_vec(bytes, left, right);
                left = right;
            }
        }
    }
}

#[test]
fn ascii_hello_world() {
    let mut s = "Hello World".to_string();
    ascii_reverse_words(&mut s);
    assert_eq!("World Hello", s)
}

#[test]
fn ascii_empty() {
    let mut s = "".to_string();
    ascii_reverse_words(&mut s);
    assert_eq!("", s)
}

#[test]
fn ascii_single_space_only() {
    let mut s = " ".to_string();
    ascii_reverse_words(&mut s);
    assert_eq!(" ", s)
}

#[test]
fn ascii_multiple_spaces_only() {
    let mut s = "   ".to_string();
    ascii_reverse_words(&mut s);
    assert_eq!("   ", s)
}

#[test]
fn ascii_single_letter_only() {
    let mut s = "a".to_string();
    ascii_reverse_words(&mut s);
    assert_eq!("a", s)
}

#[test]
fn ascii_single_word_only() {
    let mut s = "Hello".to_string();
    ascii_reverse_words(&mut s);
    assert_eq!("Hello", s)
}

#[test]
fn ascii_space_and_word() {
    let mut s = " Hello".to_string();
    ascii_reverse_words(&mut s);
    assert_eq!("Hello ", s)
}

#[test]
fn ascii_space_word_space() {
    let mut s = " Hello  ".to_string();
    ascii_reverse_words(&mut s);
    assert_eq!("  Hello ", s)
}

#[test]
#[should_panic]
fn non_ascii() {
    let mut s = "Я люблю тебя.".to_string();
    ascii_reverse_words(&mut s);
}
<commit_msg>reversewords: inline reverse_vec<commit_after>use std::ascii::AsciiExt;

const SPACE: u8 = 0x20;

/// Reverse the words in the input string. Words are defined as any characters
/// other than a space. Only ASCII input is acceptable.
///
/// # Examples
///
/// ```
/// use reversewords::ascii_reverse_words;
///
/// let mut s = "Hello from Rust!".to_string();
/// ascii_reverse_words(&mut s);
/// assert_eq!("Rust! from Hello", s)
/// ```
#[inline]
pub fn ascii_reverse_words(s: &mut String) {
    let len = s.len();
    if len == 0 {
        return;
    }

    if !s.is_ascii() {
        // Reversing non-ASCII strings is hard because you have to make sure
        // not to spit graphemes.
        panic!("Unexpected non-ASCII string: \"{}\"", s);
    }

    unsafe {
        let ref mut bytes = s.as_mut_vec();  // Unsafe.
        // Reverse the entire string. So:
        // "Hello from Rust!" => "!tsuR morf olleH"
        bytes.reverse();

        // Find each "word" (non-space) in `bytes` and reverse it. So
        // "!tsuR" => "Rust1".
        let mut left = 0;
        while left < len {
            if bytes[left] == SPACE {
                left += 1;
            } else {
                let mut right = left;
                while right < len && bytes[right] != SPACE {
                    right += 1;
                }
                bytes[left..right].reverse();
                left = right;
            }
        }
    }
}

#[test]
fn ascii_hello_world() {
    let mut s = "Hello World".to_string();
    ascii_reverse_words(&mut s);
    assert_eq!("World Hello", s)
}

#[test]
fn ascii_empty() {
    let mut s = "".to_string();
    ascii_reverse_words(&mut s);
    assert_eq!("", s)
}

#[test]
fn ascii_single_space_only() {
    let mut s = " ".to_string();
    ascii_reverse_words(&mut s);
    assert_eq!(" ", s)
}

#[test]
fn ascii_multiple_spaces_only() {
    let mut s = "   ".to_string();
    ascii_reverse_words(&mut s);
    assert_eq!("   ", s)
}

#[test]
fn ascii_single_letter_only() {
    let mut s = "a".to_string();
    ascii_reverse_words(&mut s);
    assert_eq!("a", s)
}

#[test]
fn ascii_single_word_only() {
    let mut s = "Hello".to_string();
    ascii_reverse_words(&mut s);
    assert_eq!("Hello", s)
}

#[test]
fn ascii_space_and_word() {
    let mut s = " Hello".to_string();
    ascii_reverse_words(&mut s);
    assert_eq!("Hello ", s)
}

#[test]
fn ascii_space_word_space() {
    let mut s = " Hello  ".to_string();
    ascii_reverse_words(&mut s);
    assert_eq!("  Hello ", s)
}

#[test]
#[should_panic]
fn non_ascii() {
    let mut s = "Я люблю тебя.".to_string();
    ascii_reverse_words(&mut s);
}
<|endoftext|>


<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"]),
    ("coq", &["*.v"]),
    ("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*"]),
    ("dvc", &["Dvcfile", "*.dvc"]),
    ("ebuild", &["*.ebuild"]),
    ("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"]),
    ("meson", &["meson.build", "meson_options.txt"]),
    ("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"]),
    ("z", &["*.Z"]),
    ("zig", &["*.zig"]),
    ("zsh", &[
        ".zshenv", "zshenv",
        ".zlogin", "zlogin",
        ".zlogout", "zlogout",
        ".zprofile", "zprofile",
        ".zshrc", "zshrc",
        "*.zsh",
    ]),
    ("zstd", &["*.zst", "*.zstd"]),
];
<commit_msg>ignore/types: add racket<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"]),
    ("coq", &["*.v"]),
    ("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*"]),
    ("dvc", &["Dvcfile", "*.dvc"]),
    ("ebuild", &["*.ebuild"]),
    ("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"]),
    ("meson", &["meson.build", "meson_options.txt"]),
    ("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"]),
    ("racket", &["*.rkt"]),
    ("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"]),
    ("z", &["*.Z"]),
    ("zig", &["*.zig"]),
    ("zsh", &[
        ".zshenv", "zshenv",
        ".zlogin", "zlogin",
        ".zlogout", "zlogout",
        ".zprofile", "zprofile",
        ".zshrc", "zshrc",
        "*.zsh",
    ]),
    ("zstd", &["*.zst", "*.zstd"]),
];
<|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
//

use std::collections::HashMap;
use std::io::{Read, Write};
use std::path::PathBuf;

use serde_json;
use toml;

use error::StoreErrorKind as SEK;
use error::MapErrInto;
use super::Mapper;
use store::Result;
use store::Entry;
use storeid::StoreId;

use libimagerror::into::IntoError;

#[derive(Deserialize, Serialize)]
struct BackendEntry {
    header: serde_json::Value,
    content: String,
}

impl BackendEntry {

    fn to_string(self) -> Result<String> {
        toml::to_string(&self.header)
            .map_err_into(SEK::IoError)
            .map(|hdr| {
                format!("---\n{header}---\n{content}",
                        header  = hdr,
                        content = self.content)
            })
    }

}

#[derive(Deserialize, Serialize)]
struct Document {
    version: String,
    store: HashMap<PathBuf, BackendEntry>,
}

pub struct JsonMapper;

impl JsonMapper {

    pub fn new() -> JsonMapper {
        JsonMapper
    }

}

impl Mapper for JsonMapper {
    fn read_to_fs<R: Read>(&self, r: &mut R, hm: &mut HashMap<PathBuf, Entry>)   -> Result<()> {
        let mut document = {
            let mut s = String::new();
            try!(r.read_to_string(&mut s).map_err_into(SEK::IoError));
            let doc : Document = try!(serde_json::from_str(&s).map_err_into(SEK::IoError));
            doc
        };

        let _ = try!(::semver::Version::parse(&document.version)
            .map_err_into(SEK::VersionError)
            .and_then(|doc_vers| {
                // safe because cargo does not compile if crate version is not valid
                let crate_version = ::semver::Version::parse(version!()).unwrap();

                if doc_vers > crate_version {
                    Err(SEK::VersionError.into_error())
                } else {
                    Ok(())
                }
            }));

        for (key, val) in document.store.drain() {
            let res = val
                .to_string()
                .and_then(|vals| {
                    StoreId::new_baseless(key.clone())
                        .and_then(|id| Entry::from_str(id, &vals))
                        .map(|entry| hm.insert(key, entry))
                })
                .map(|_| ());

            let _ = try!(res);
        }

        Ok(())
    }

    fn fs_to_write<W: Write>(&self, hm: &mut HashMap<PathBuf, Entry>, out: &mut W) -> Result<()> {
        #[derive(Serialize)]
        struct BackendEntry {
            header: ::toml::Value,
            content: String,
        }

        impl BackendEntry {
            fn construct_from(e: Entry) -> BackendEntry {
                BackendEntry {
                    header:  e.get_header().clone(),
                    content: e.get_content().clone(),
                }
            }
        }

        #[derive(Serialize)]
        struct OutDocument {
            version: String,
            store: HashMap<PathBuf, BackendEntry>,
        }

        let mut store = HashMap::new();
        for (key, value) in hm.drain() {
            store.insert(key, BackendEntry::construct_from(value));
        }

        let doc = OutDocument {
            version: String::from(version!()),
            store:   store,
        };

        serde_json::to_string(&doc)
            .map_err_into(SEK::IoError)
            .and_then(|json| out.write(&json.into_bytes()).map_err_into(SEK::IoError))
            .and_then(|_| out.flush().map_err_into(SEK::IoError))
            .map(|_| ())
    }
}

#[cfg(test)]
mod test {
    use std::io::Cursor;

    use super::*;

    #[test]
    fn test_json_to_fs() {
        let json = r#"
        { "version": "0.3.0",
          "store": {
            "example": {
                "header": {
                    "imag": {
                        "version": "0.3.0"
                    }
                },
                "content": "test"
            }
          }
        }
        "#;
        let mut json = Cursor::new(String::from(json).into_bytes());
        let mapper   = JsonMapper::new();
        let mut hm   = HashMap::new();

        let io_res  = mapper.read_to_fs(&mut json, &mut hm);
        assert!(io_res.is_ok());

        assert_eq!(1, hm.len()); // we should have exactly one entry
    }

    #[test]
    fn test_fs_to_json() {
        let mapper                    = JsonMapper::new();
        let mut out : Cursor<Vec<u8>> = Cursor::new(vec![]);

        let mut hm = {
            let mut hm = HashMap::new();
            let content = r#"---
[imag]
version = "0.3.0"
---
hi there!"#;

            let id = PathBuf::from("example");
            let entry = Entry::from_str(id.clone(), content).unwrap();
            hm.insert(id, entry);
            hm
        };

        let io_res = mapper.fs_to_write(&mut hm, &mut out);
        assert!(io_res.is_ok());

        let example = r#"
        {
            "version": "0.3.0",
            "store": {
                "example": {
                    "header": {
                        "imag": {
                            "version": "0.3.0"
                        }
                    },
                    "content": "hi there!"
                }
            }
        }
        "#;

        let example_json : ::serde_json::Value = ::serde_json::from_str(example).unwrap();

        let output_json = String::from_utf8(out.into_inner()).unwrap();
        let output_json : ::serde_json::Value = ::serde_json::from_str(&output_json).unwrap();

        assert_eq!(example_json, output_json);
    }
}

<commit_msg>Add another JSON test for an empty JSON<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
//

use std::collections::HashMap;
use std::io::{Read, Write};
use std::path::PathBuf;

use serde_json;
use toml;

use error::StoreErrorKind as SEK;
use error::MapErrInto;
use super::Mapper;
use store::Result;
use store::Entry;
use storeid::StoreId;

use libimagerror::into::IntoError;

#[derive(Deserialize, Serialize)]
struct BackendEntry {
    header: serde_json::Value,
    content: String,
}

impl BackendEntry {

    fn to_string(self) -> Result<String> {
        toml::to_string(&self.header)
            .map_err_into(SEK::IoError)
            .map(|hdr| {
                format!("---\n{header}---\n{content}",
                        header  = hdr,
                        content = self.content)
            })
    }

}

#[derive(Deserialize, Serialize)]
struct Document {
    version: String,
    store: HashMap<PathBuf, BackendEntry>,
}

pub struct JsonMapper;

impl JsonMapper {

    pub fn new() -> JsonMapper {
        JsonMapper
    }

}

impl Mapper for JsonMapper {
    fn read_to_fs<R: Read>(&self, r: &mut R, hm: &mut HashMap<PathBuf, Entry>)   -> Result<()> {
        let mut document = {
            let mut s = String::new();
            try!(r.read_to_string(&mut s).map_err_into(SEK::IoError));
            let doc : Document = try!(serde_json::from_str(&s).map_err_into(SEK::IoError));
            doc
        };

        let _ = try!(::semver::Version::parse(&document.version)
            .map_err_into(SEK::VersionError)
            .and_then(|doc_vers| {
                // safe because cargo does not compile if crate version is not valid
                let crate_version = ::semver::Version::parse(version!()).unwrap();

                if doc_vers > crate_version {
                    Err(SEK::VersionError.into_error())
                } else {
                    Ok(())
                }
            }));

        for (key, val) in document.store.drain() {
            let res = val
                .to_string()
                .and_then(|vals| {
                    StoreId::new_baseless(key.clone())
                        .and_then(|id| Entry::from_str(id, &vals))
                        .map(|entry| hm.insert(key, entry))
                })
                .map(|_| ());

            let _ = try!(res);
        }

        Ok(())
    }

    fn fs_to_write<W: Write>(&self, hm: &mut HashMap<PathBuf, Entry>, out: &mut W) -> Result<()> {
        #[derive(Serialize)]
        struct BackendEntry {
            header: ::toml::Value,
            content: String,
        }

        impl BackendEntry {
            fn construct_from(e: Entry) -> BackendEntry {
                BackendEntry {
                    header:  e.get_header().clone(),
                    content: e.get_content().clone(),
                }
            }
        }

        #[derive(Serialize)]
        struct OutDocument {
            version: String,
            store: HashMap<PathBuf, BackendEntry>,
        }

        let mut store = HashMap::new();
        for (key, value) in hm.drain() {
            store.insert(key, BackendEntry::construct_from(value));
        }

        let doc = OutDocument {
            version: String::from(version!()),
            store:   store,
        };

        serde_json::to_string(&doc)
            .map_err_into(SEK::IoError)
            .and_then(|json| out.write(&json.into_bytes()).map_err_into(SEK::IoError))
            .and_then(|_| out.flush().map_err_into(SEK::IoError))
            .map(|_| ())
    }
}

#[cfg(test)]
mod test {
    use std::io::Cursor;

    use super::*;

    #[test]
    fn test_empty_json_to_fs() {
        let json = r#"{"version":"0.3.0","store":{}}"#;
        let mut json = Cursor::new(String::from(json).into_bytes());
        let mapper   = JsonMapper::new();
        let mut hm   = HashMap::new();

        let io_res  = mapper.read_to_fs(&mut json, &mut hm);
        assert!(io_res.is_ok());
        assert!(hm.is_empty());
    }

    #[test]
    fn test_json_to_fs() {
        let json = r#"
        { "version": "0.3.0",
          "store": {
            "example": {
                "header": {
                    "imag": {
                        "version": "0.3.0"
                    }
                },
                "content": "test"
            }
          }
        }
        "#;
        let mut json = Cursor::new(String::from(json).into_bytes());
        let mapper   = JsonMapper::new();
        let mut hm   = HashMap::new();

        let io_res  = mapper.read_to_fs(&mut json, &mut hm);
        assert!(io_res.is_ok());

        assert_eq!(1, hm.len()); // we should have exactly one entry
    }

    #[test]
    fn test_fs_to_json() {
        let mapper                    = JsonMapper::new();
        let mut out : Cursor<Vec<u8>> = Cursor::new(vec![]);

        let mut hm = {
            let mut hm = HashMap::new();
            let content = r#"---
[imag]
version = "0.3.0"
---
hi there!"#;

            let id = PathBuf::from("example");
            let entry = Entry::from_str(id.clone(), content).unwrap();
            hm.insert(id, entry);
            hm
        };

        let io_res = mapper.fs_to_write(&mut hm, &mut out);
        assert!(io_res.is_ok());

        let example = r#"
        {
            "version": "0.3.0",
            "store": {
                "example": {
                    "header": {
                        "imag": {
                            "version": "0.3.0"
                        }
                    },
                    "content": "hi there!"
                }
            }
        }
        "#;

        let example_json : ::serde_json::Value = ::serde_json::from_str(example).unwrap();

        let output_json = String::from_utf8(out.into_inner()).unwrap();
        let output_json : ::serde_json::Value = ::serde_json::from_str(&output_json).unwrap();

        assert_eq!(example_json, output_json);
    }
}

<|endoftext|>


<commit_before>use log::*;
use chrono::prelude::Local;

const THRESHOLD: LogLevelFilter = LogLevelFilter::Info;

pub struct SimpleLogger;

impl Log for SimpleLogger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= LogLevel::Info
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            let date = Local::now();
            let formatted_date = date.format("%Y-%m-%d %H:%M:%S%.3f");
            println!("{} {} {}: {}", formatted_date, record.level(), record.target(), record.args());
        }
    }
}

impl SimpleLogger {
    pub fn init() -> Result<(), SetLoggerError> {
        set_logger(|max_log_level| {
            max_log_level.set(THRESHOLD);
            Box::new(SimpleLogger)
        })
    }
}
<commit_msg>Fix logger threshold<commit_after>use log::*;
use chrono::prelude::Local;

const THRESHOLD: LogLevelFilter = LogLevelFilter::Debug;

pub struct SimpleLogger;

impl Log for SimpleLogger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= THRESHOLD
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            let date = Local::now();
            let formatted_date = date.format("%Y-%m-%d %H:%M:%S%.3f");
            println!("{} {} {}: {}", formatted_date, record.level(), record.target(), record.args());
        }
    }
}

impl SimpleLogger {
    pub fn init() -> Result<(), SetLoggerError> {
        set_logger(|max_log_level| {
            max_log_level.set(THRESHOLD);
            Box::new(SimpleLogger)
        })
    }
}
<|endoftext|>


<commit_before>//! # Advent of Code 2016 - Day 1
//!
//! This is my Rust solution to Day 1 of the Advent of Code 2016
//! "No Time for a Taxicab." Full details of the challenge can be
//! found on [the challenge page](page).
//!
//! [page]: http://adventofcode.com/2016/day/1

use std::str::FromStr;

/// The compass direction Santa's little helper is facing.
#[derive(Debug)]
pub enum Orientation {
    North,
    West,
    South,
    East,
}

impl Orientation {
    /// Returns the new orientation after turning left.
    pub fn left(self) -> Orientation {
        use Orientation::*;
        match self {
            North => West,
            West => South,
            South => East,
            East => North,
        }
    }

    /// Returns the new orientation after turning right.
    pub fn right(self) -> Orientation {
        use Orientation::*;
        match self {
            North => East,
            East => South,
            South => West,
            West => North,
        }
    }
}

/// The position and orientation of Santa's little helper in the city grid.
#[derive(Debug)]
pub struct Position {
    /// The East-West direction with East being positive.
    pub x: i64,
    /// The North-South direction with North being positive.
    pub y: i64,
    /// The direction Santa's little helper is facing.
    pub facing: Orientation,

}

impl Position {
    /// Puts a new Santa's little helper in the grid at position
    /// `(0, 0)` facing North.
    pub fn new() -> Position {
        Position {
            x: 0,
            y: 0,
            facing: Orientation::North,
        }
    }

    /// Follows one step of the Easter Bunny's instructions
    pub fn follow_instruction(self, instruction: Instruction) -> Position {
        self.turn(instruction.direction)
            .walk(instruction.amount)
    }

    fn walk(self, amount: i64) -> Position {
        use Orientation::*;

        let (new_x, new_y) = match self.facing {
            North => (self.x, self.y + amount),
            West => (self.x - amount, self.y),
            South => (self.x, self.y - amount),
            East => (self.x + amount, self.y),
        };

        Position {
            x: new_x,
            y: new_y,
            ..self
        }
    }

    fn turn(self, direction: TurnDirection) -> Position {
        match direction {
            TurnDirection::Left  => self.left(),
            TurnDirection::Right => self.right(),
        }
    }

    fn left(self) -> Position {
        Position { facing: self.facing.left(), ..self }
    }

    fn right(self) -> Position {
        Position { facing: self.facing.right(), ..self }
    }

    /// Calculates how many blocks away from the start that
    /// Santa's little helper has travelled.
    pub fn blocks_travelled(&self) -> i64 {
        self.x.abs() + self.y.abs()
    }
}

/// A direction to turn in from the Easter Bunny's instructions.
#[derive(Debug)]
enum TurnDirection {
    Left,
    Right,
}

/// One of the Easter Bunny's instructions on how to find his HQ.
#[derive(Debug)]
pub struct Instruction {
    amount: i64,
    direction: TurnDirection,
}

/// A parse error interpreting an Easter Bunny instruction.
#[derive(Debug)]
pub enum InstructionParseErr {
    /// The direction was not known.
    BadDirection,
    /// The move amount could not be parsed.
    BadAmount(std::num::ParseIntError),
    /// The input was malformed.
    BadInput,
}

impl FromStr for Instruction {
    type Err = InstructionParseErr;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let mut chars = s.chars();
        let dir = match chars.next() {
            Some('R') => Ok(TurnDirection::Right),
            Some('L') => Ok(TurnDirection::Left),
            Some(_)   => Err(InstructionParseErr::BadDirection),
            None      => Err(InstructionParseErr::BadInput),
        }?;

        let amount = chars.as_str()
            .parse::<i64>()
            .map_err(InstructionParseErr::BadAmount)?;

        Ok(Instruction {
            amount: amount,
            direction: dir,
        })
    }
}

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

    #[test]
    fn test_input_1() {
        let input_str = "R3, L2";
        let destination = process_input(input_str);

        assert!(destination.is_ok());
        assert_eq!(destination.unwrap().blocks_travelled(), 5);
    }

    #[test]
    fn test_input_2() {
        let input_str = "R2, R2, R2";
        let destination = process_input(input_str);

        assert!(destination.is_ok());
        assert_eq!(destination.unwrap().blocks_travelled(), 2);
    }

    #[test]
    fn test_input_3() {
        let input_str = "R5, L5, R5, R3";
        let destination = process_input(input_str);

        assert!(destination.is_ok());
        assert_eq!(destination.unwrap().blocks_travelled(), 12);
    }
}

/// Given an input string, calculates the final destination.
pub fn process_input(input_str: &str) -> Result<Position, InstructionParseErr> {
    input_str.split(", ")
        .map(|s| s.parse::<Instruction>())
        .fold(Ok(Position::new()),
              |pos_opt, instr_opt| {
                  match (pos_opt, instr_opt) {
                      (Ok(pos), Ok(instr)) => Ok(pos.follow_instruction(instr)),
                      (Err(a), _) => Err(a),
                      (_, Err(b)) => Err(b),
                  }
              })
}

fn main() {
    let challenge_input = "R2, L1, R2, R1, R1, L3, R3, L5, L5, L2, L1, R4, R1, R3, L5, L5, R3, L4, L4, R5, R4, R3, L1, L2, R5, R4, L2, R1, R4, R4, L2, L1, L1, R190, R3, L4, R52, R5, R3, L5, R3, R2, R1, L5, L5, L4, R2, L3, R3, L1, L3, R5, L3, L4, R3, R77, R3, L2, R189, R4, R2, L2, R2, L1, R5, R4, R4, R2, L2, L2, L5, L1, R1, R2, L3, L4, L5, R1, L1, L2, L2, R2, L3, R3, L4, L1, L5, L4, L4, R3, R5, L2, R4, R5, R3, L2, L2, L4, L2, R2, L5, L4, R3, R1, L2, R2, R4, L1, L4, L4, L2, R2, L4, L1, L1, R4, L1, L3, L2, L2, L5, R5, R2, R5, L1, L5, R2, R4, R4, L2, R5, L5, R5, R5, L4, R2, R1, R1, R3, L3, L3, L4, L3, L2, L2, L2, R2, L1, L3, R2, R5, R5, L4, R3, L3, L4, R2, L5, R5";

    let destination = process_input(challenge_input);

    println!("{:?}", destination);
    println!("{}", destination.unwrap().blocks_travelled());
}
<commit_msg>Added Day 01 - Part 2<commit_after>//! # Advent of Code 2016 - Day 1
//!
//! This is my Rust solution to Day 1 of the Advent of Code 2016
//! "No Time for a Taxicab." Full details of the challenge can be
//! found on [the challenge page][page].
//!
//! [page]: http://adventofcode.com/2016/day/1

use std::collections::HashMap;
use std::str::FromStr;

/// The compass direction Santa's little helper is facing.
#[derive(Debug)]
pub enum Orientation {
    North,
    West,
    South,
    East,
}

impl Orientation {
    /// Returns the new orientation after turning left.
    pub fn left(self) -> Orientation {
        use Orientation::*;
        match self {
            North => West,
            West => South,
            South => East,
            East => North,
        }
    }

    /// Returns the new orientation after turning right.
    pub fn right(self) -> Orientation {
        use Orientation::*;
        match self {
            North => East,
            East => South,
            South => West,
            West => North,
        }
    }
}

/// The position and orientation of Santa's little helper in the city grid.
#[derive(Debug)]
pub struct Position {
    /// The East-West direction with East being positive.
    pub x: i64,
    /// The North-South direction with North being positive.
    pub y: i64,
    /// The direction Santa's little helper is facing.
    pub facing: Orientation,

}

impl Position {
    /// Puts a new Santa's little helper in the grid at position
    /// `(0, 0)` facing North.
    pub fn new() -> Position {
        Position {
            x: 0,
            y: 0,
            facing: Orientation::North,
        }
    }

    /// Follows one step of the Easter Bunny's instructions
    pub fn follow_instruction(self, instruction: Instruction) -> Position {
        self.turn(instruction.direction)
            .walk(instruction.amount)
    }

    fn walk(self, amount: i64) -> Position {
        use Orientation::*;

        let (new_x, new_y) = match self.facing {
            North => (self.x, self.y + amount),
            West => (self.x - amount, self.y),
            South => (self.x, self.y - amount),
            East => (self.x + amount, self.y),
        };

        Position {
            x: new_x,
            y: new_y,
            ..self
        }
    }

    fn turn(self, direction: TurnDirection) -> Position {
        match direction {
            TurnDirection::Left  => self.left(),
            TurnDirection::Right => self.right(),
        }
    }

    fn left(self) -> Position {
        Position { facing: self.facing.left(), ..self }
    }

    fn right(self) -> Position {
        Position { facing: self.facing.right(), ..self }
    }

    /// Calculates how many blocks away from the start that
    /// Santa's little helper has travelled.
    pub fn blocks_travelled(&self) -> i64 {
        self.x.abs() + self.y.abs()
    }
}

/// A direction to turn in from the Easter Bunny's instructions.
#[derive(Debug)]
enum TurnDirection {
    Left,
    Right,
}

/// One of the Easter Bunny's instructions on how to find his HQ.
#[derive(Debug)]
pub struct Instruction {
    amount: i64,
    direction: TurnDirection,
}

/// A parse error interpreting an Easter Bunny instruction.
#[derive(Debug)]
pub enum InstructionParseErr {
    /// The direction was not known.
    BadDirection,
    /// The move amount could not be parsed.
    BadAmount(std::num::ParseIntError),
    /// The input was malformed.
    BadInput,
}

impl FromStr for Instruction {
    type Err = InstructionParseErr;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let mut chars = s.chars();
        let dir = match chars.next() {
            Some('R') => Ok(TurnDirection::Right),
            Some('L') => Ok(TurnDirection::Left),
            Some(_)   => Err(InstructionParseErr::BadDirection),
            None      => Err(InstructionParseErr::BadInput),
        }?;

        let amount = chars.as_str()
            .parse::<i64>()
            .map_err(InstructionParseErr::BadAmount)?;

        Ok(Instruction {
            amount: amount,
            direction: dir,
        })
    }
}

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

    #[test]
    fn test_input_1() {
        let input_str = "R3, L2";
        let destination = process_input(input_str);

        assert!(destination.is_ok());
        assert_eq!(destination.unwrap().blocks_travelled(), 5);
    }

    #[test]
    fn test_input_2() {
        let input_str = "R2, R2, R2";
        let destination = process_input(input_str);

        assert!(destination.is_ok());
        assert_eq!(destination.unwrap().blocks_travelled(), 2);
    }

    #[test]
    fn test_input_3() {
        let input_str = "R5, L5, R5, R3";
        let destination = process_input(input_str);

        assert!(destination.is_ok());
        assert_eq!(destination.unwrap().blocks_travelled(), 12);
    }
}

/// Given an input string, calculates the final destination.
pub fn process_input(input_str: &str) -> Result<Position, InstructionParseErr> {
    input_str.split(", ")
        .map(|s| s.parse::<Instruction>())
        .fold(Ok(Position::new()),
              |pos_opt, instr_opt| {
                  match (pos_opt, instr_opt) {
                      (Ok(pos), Ok(instr)) => Ok(pos.follow_instruction(instr)),
                      (Err(a), _) => Err(a),
                      (_, Err(b)) => Err(b),
                  }
              })
}

/// Calculates the location of the Easter Bunny's HQ, which is the first
/// intersection visited twice when following the instructions.
pub fn find_bunny_hq(input_str: &str) -> Result<(i64, i64), InstructionParseErr> {
    let instructions = input_str.split(", ")
        .map(|s| s.parse::<Instruction>())
        .collect::<Result<Vec<Instruction>, InstructionParseErr>>()?;

    // Construct a map to hold all the locations that we have visited
    let mut visited = HashMap::new();
    let mut posn = Position::new();
    visited.insert((0, 0), 1);

    for instr in instructions {
        posn = posn.turn(instr.direction);
        for _ in 1 .. (instr.amount + 1) {
            posn = posn.walk(1);
            if visited.get(&(posn.x, posn.y)).is_some() {
                return Ok((posn.x, posn.y))
            } else {
                visited.insert((posn.x, posn.y), 1);
            }

        }
    }

    Ok((std::i64::MAX, std::i64::MAX))
}

fn main() {
    let challenge_input = "R2, L1, R2, R1, R1, L3, R3, L5, L5, L2, L1, R4, R1, R3, L5, L5, R3, L4, L4, R5, R4, R3, L1, L2, R5, R4, L2, R1, R4, R4, L2, L1, L1, R190, R3, L4, R52, R5, R3, L5, R3, R2, R1, L5, L5, L4, R2, L3, R3, L1, L3, R5, L3, L4, R3, R77, R3, L2, R189, R4, R2, L2, R2, L1, R5, R4, R4, R2, L2, L2, L5, L1, R1, R2, L3, L4, L5, R1, L1, L2, L2, R2, L3, R3, L4, L1, L5, L4, L4, R3, R5, L2, R4, R5, R3, L2, L2, L4, L2, R2, L5, L4, R3, R1, L2, R2, R4, L1, L4, L4, L2, R2, L4, L1, L1, R4, L1, L3, L2, L2, L5, R5, R2, R5, L1, L5, R2, R4, R4, L2, R5, L5, R5, R5, L4, R2, R1, R1, R3, L3, L3, L4, L3, L2, L2, L2, R2, L1, L3, R2, R5, R5, L4, R3, L3, L4, R2, L5, R5";

    let destination = process_input(challenge_input).expect("Failed to process instructions");
    let bunny_hq = find_bunny_hq(challenge_input).expect("Failed to process instructions");

    println!("Final location = ({}, {}), facing {:?}",
             destination.x,
             destination.y,
             destination.facing);
    println!("Distance from the start = {}\n", destination.blocks_travelled());
    println!("First place visited twice = ({}, {})", bunny_hq.0, bunny_hq.1);
    println!("Distance from the start = {}", bunny_hq.0.abs() + bunny_hq.1.abs());
}
<|endoftext|>


<commit_before>use std::net::TcpStream;
use std::str;
use std::io::{self, BufReader, Write};

fn main () {
    let mut stream = TcpStream::connect("127.0.0.1:8888").expect("Could not connect to server");

    loop {
        let mut input = String::new();
        let mut buffer: Vec<u8> = Vec::new();
        io::stdin().read_line(&mut input).expect("Failed to read from stdin");
        stream.write(input.as_bytes()).expect("Failed to write to server");
        let mut reader = BufReader::new(&stream);
        reader.read_until(b'\n', &mut buffer).expect("Could not read into buffer");
        print!("{}", str::from_utf8(&buffer).expect("Could not write buffer as string"));

    }
}
<commit_msg>Fixed error in rust tcp client<commit_after>use std::net::TcpStream;
use std::str;
use std::io::{self, BufReader, Write};
use std::io::BufRead;

fn main () {
    let mut stream = TcpStream::connect("127.0.0.1:8888").expect("Could not connect to server");

    loop {
        let mut input = String::new();
        let mut buffer: Vec<u8> = Vec::new();
        io::stdin().read_line(&mut input).expect("Failed to read from stdin");
        stream.write(input.as_bytes()).expect("Failed to write to server");
        let mut reader = BufReader::new(&stream);
        reader.read_until(b'\n', &mut buffer).expect("Could not read into buffer");
        print!("{}", str::from_utf8(&buffer).expect("Could not write buffer as string"));

    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::{Read, Write};
use std::path::Path;
use std::process::Command;

fn main() {
    if !Path::new("jsonnet/.git").exists() {
        let _ = Command::new("git")
            .args(&["submodule", "update", "--init"])
            .status();
    }

    let dir = Path::new("jsonnet");

    let embedded = ["std"];
    for f in &embedded {
        let output = dir.join("core").join(format!("{}.jsonnet.h", f));
        if output.exists() {
            continue;
        }
        let input = dir.join("stdlib").join(format!("{}.jsonnet", f));
        println!("embedding: {:?} -> {:?}", input, output);
        let in_f = File::open(input).unwrap();
        let mut out_f = File::create(&output).unwrap();
        for b in in_f.bytes() {
            write!(&mut out_f, "{},", b.unwrap()).unwrap();
        }
        writeln!(&mut out_f, "0").unwrap();
    }

    let jsonnet_core = [
        "desugarer.cpp",
        "formatter.cpp",
        "lexer.cpp",
        "libjsonnet.cpp",
        "parser.cpp",
        "pass.cpp",
        "static_analysis.cpp",
        "string_utils.cpp",
        "vm.cpp",
    ];

    let mut c = cc::Build::new();
    c.cpp(true)
        .flag("-std=c++0x")
        .include(dir.join("include"))
        .include(dir.join("third_party/md5"));

    for f in &jsonnet_core {
        c.file(dir.join("core").join(f));
    }

    c.file(dir.join("third_party/md5/md5.cpp"));

    c.compile("libjsonnet.a")
}
<commit_msg>Write generated std.jsonnet.h to OUT_DIR<commit_after>use std::env;
use std::error::Error;
use std::fs::{create_dir_all, File};
use std::io::{Read, Write};
use std::path::{Path, PathBuf};
use std::process::Command;

fn main() -> Result<(), Box<dyn Error>> {
    if !Path::new("jsonnet/.git").exists() {
        let _ = Command::new("git")
            .args(&["submodule", "update", "--init"])
            .status();
    }

    let dir = Path::new("jsonnet");
    let out_dir = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR undefined"));

    let embedded = ["std"];
    for f in &embedded {
        let output = out_dir.join("include").join(format!("{}.jsonnet.h", f));
        let input = dir.join("stdlib").join(format!("{}.jsonnet", f));
        println!("embedding: {:?} -> {:?}", input, output);
        create_dir_all(output.parent().unwrap())?;
        let in_f = File::open(input)?;
        let mut out_f = File::create(&output)?;
        for b in in_f.bytes() {
            write!(&mut out_f, "{},", b?)?;
        }
        writeln!(&mut out_f, "0")?;
    }

    let jsonnet_core = [
        "desugarer.cpp",
        "formatter.cpp",
        "lexer.cpp",
        "libjsonnet.cpp",
        "parser.cpp",
        "pass.cpp",
        "static_analysis.cpp",
        "string_utils.cpp",
        "vm.cpp",
    ];

    let mut c = cc::Build::new();
    c.cpp(true)
        .flag_if_supported("-std=c++0x")
        .include(out_dir.join("include"))
        .include(dir.join("include"))
        .include(dir.join("third_party/md5"));

    for f in &jsonnet_core {
        c.file(dir.join("core").join(f));
    }

    c.file(dir.join("third_party/md5/md5.cpp"));

    c.compile("libjsonnet.a");

    Ok(())
}
<|endoftext|>


<commit_before>use gettextrs::gettext;
use glib;
use gtk;
use gtk::prelude::*;

use std::{
    collections::HashSet,
    path::{Path, PathBuf},
    rc::Rc,
    sync::{Arc, RwLock},
};

use crate::{
    application::CommandLineArguments,
    media::{MediaEvent, PlaybackPipeline},
    metadata,
    metadata::{Format, MediaInfo},
};

use super::{UIController, UIEventSender};

const PROGRESS_TIMER_PERIOD: u32 = 250; // 250 ms

pub enum ProcessingType {
    Async(glib::Receiver<MediaEvent>),
    Sync,
}

#[derive(Debug, PartialEq)]
pub enum ProcessingState {
    AllComplete(String),
    Cancelled,
    ConfirmedOutputTo(Rc<Path>),
    SkipCurrent,
    DoneWithCurrent,
    PendingAsyncMediaEvent,
    Start,
    WouldOutputTo(Rc<Path>),
}

pub trait MediaProcessor {
    fn init(&mut self) -> ProcessingType;
    fn next(&mut self) -> Result<ProcessingState, String>;
    fn process(&mut self, path: &Path) -> Result<ProcessingState, String>;
    fn handle_media_event(&mut self, event: MediaEvent) -> Result<ProcessingState, String>;
    fn report_progress(&self) -> Option<f64>;
}

pub trait OutputControllerImpl {
    const BTN_NAME: &'static str;
    const LIST_NAME: &'static str;
    const PROGRESS_BAR_NAME: &'static str;
}

pub struct OutputMediaFileInfo {
    pub format: Format,
    pub path: PathBuf,
    pub extension: String,
    pub stream_ids: Arc<RwLock<HashSet<String>>>,
}

impl OutputMediaFileInfo {
    pub fn new(format: Format, src_info: &MediaInfo) -> Self {
        let (stream_ids, content) = src_info.streams.get_ids_to_export(format);
        let extension = metadata::Factory::get_extension(format, content).to_owned();

        OutputMediaFileInfo {
            path: src_info.path.with_extension(&extension),
            extension,
            format,
            stream_ids: Arc::new(RwLock::new(stream_ids)),
        }
    }
}

type OverwriteResponseCb = Fn(gtk::ResponseType, &Rc<Path>);

pub struct OutputBaseController<Impl> {
    impl_: Impl,
    ui_event: UIEventSender,

    progress_bar: gtk::ProgressBar,
    list: gtk::ListBox,
    pub(super) btn: gtk::Button,

    perspective_selector: gtk::MenuButton,
    open_btn: gtk::Button,
    chapter_grid: gtk::Grid,

    playback_pipeline: Option<PlaybackPipeline>,

    pub(super) media_event_handler: Option<Rc<Fn(MediaEvent)>>,
    media_event_handler_src: Option<glib::SourceId>,

    pub(super) progress_updater: Option<Rc<Fn()>>,
    progress_timer_src: Option<glib::SourceId>,

    pub(super) overwrite_response_cb: Option<Rc<OverwriteResponseCb>>,
    overwrite_all: bool,
}

impl<Impl> OutputBaseController<Impl>
where
    Impl: OutputControllerImpl + MediaProcessor + UIController + 'static,
{
    pub fn new_base(impl_: Impl, builder: &gtk::Builder, ui_event_sender: UIEventSender) -> Self {
        OutputBaseController {
            impl_,
            ui_event: ui_event_sender,

            btn: builder.get_object(Impl::BTN_NAME).unwrap(),
            list: builder.get_object(Impl::LIST_NAME).unwrap(),
            progress_bar: builder.get_object(Impl::PROGRESS_BAR_NAME).unwrap(),

            perspective_selector: builder.get_object("perspective-menu-btn").unwrap(),
            open_btn: builder.get_object("open-btn").unwrap(),
            chapter_grid: builder.get_object("info-chapter_list-grid").unwrap(),

            playback_pipeline: None,

            media_event_handler: None,
            media_event_handler_src: None,

            progress_updater: None,
            progress_timer_src: None,

            overwrite_response_cb: None,
            overwrite_all: false,
        }
    }

    #[allow(clippy::redundant_closure)]
    fn attach_media_event_handler(&mut self, receiver: glib::Receiver<MediaEvent>) {
        debug_assert!(self.media_event_handler_src.is_none());

        let media_event_handler = Rc::clone(self.media_event_handler.as_ref().unwrap());
        self.media_event_handler_src = Some(receiver.attach(None, move |event| {
            media_event_handler(event);
            // will be removed in `OutputBaseController::switch_to_available`
            glib::Continue(true)
        }));
    }

    fn remove_media_event_handler(&mut self) {
        if let Some(src) = self.media_event_handler_src.take() {
            let _res = glib::Source::remove(src);
        }
    }

    pub fn handle_media_event(&mut self, event: MediaEvent) {
        let res = self.impl_.handle_media_event(event);
        self.handle_processing_states(res);
    }

    fn register_progress_timer(&mut self) {
        if self.progress_timer_src.is_none() {
            let progress_updater = Rc::clone(self.progress_updater.as_ref().unwrap());
            self.progress_timer_src =
                Some(glib::timeout_add_local(PROGRESS_TIMER_PERIOD, move || {
                    progress_updater();
                    glib::Continue(true)
                }));
        }
    }

    fn remove_progress_timer(&mut self) {
        if let Some(src) = self.progress_timer_src.take() {
            let _res = glib::Source::remove(src);
        }
    }

    pub fn update_progress(&self) {
        if let Some(progress) = self.impl_.report_progress() {
            self.progress_bar.set_fraction(progress);
        }
    }

    pub fn have_pipeline(&mut self, playback_pipeline: PlaybackPipeline) {
        self.playback_pipeline = Some(playback_pipeline);
    }

    fn ask_overwrite_question(&mut self, path: &Rc<Path>) {
        self.remove_progress_timer();
        self.ui_event.reset_cursor();

        let filename = path.file_name().expect("no `filename` in `path`");
        let filename = filename
            .to_str()
            .expect("can't get printable `str` from `filename`");
        let question = gettext("{output_file}\nalready exists. Overwrite?").replacen(
            "{output_file}",
            filename,
            1,
        );

        let path_cb = Rc::clone(path);
        let overwrite_response_cb = Rc::clone(self.overwrite_response_cb.as_ref().unwrap());
        self.ui_event.ask_question(
            question,
            Rc::new(move |response_type| overwrite_response_cb(response_type, &path_cb)),
        );
    }

    pub fn handle_overwrite_response(&mut self, response_type: gtk::ResponseType, path: &Rc<Path>) {
        let next_state = match response_type {
            gtk::ResponseType::Apply => {
                // This one is used for "Yes to all"
                self.overwrite_all = true;
                ProcessingState::ConfirmedOutputTo(Rc::clone(path))
            }
            gtk::ResponseType::Cancel => ProcessingState::Cancelled,
            gtk::ResponseType::No => ProcessingState::SkipCurrent,
            gtk::ResponseType::Yes => ProcessingState::ConfirmedOutputTo(Rc::clone(path)),
            other => unimplemented!(
                "Response type {:?} in OutputBaseController::handle_overwrite_response",
                other,
            ),
        };

        if next_state != ProcessingState::Cancelled {
            self.ui_event.set_cursor_waiting();
            self.register_progress_timer();
        }

        self.handle_processing_states(Ok(next_state));
    }

    fn switch_to_busy(&self) {
        self.list.set_sensitive(false);
        self.btn.set_sensitive(false);

        self.perspective_selector.set_sensitive(false);
        self.open_btn.set_sensitive(false);
        self.chapter_grid.set_sensitive(false);

        self.ui_event.set_cursor_waiting();
    }

    fn switch_to_available(&mut self) {
        self.remove_media_event_handler();
        self.remove_progress_timer();

        self.progress_bar.set_fraction(0f64);
        self.list.set_sensitive(true);
        self.btn.set_sensitive(true);

        self.perspective_selector.set_sensitive(true);
        self.open_btn.set_sensitive(true);
        self.chapter_grid.set_sensitive(true);

        let playback_pipeline = self.playback_pipeline.take().expect(concat!(
            "OutputBaseController: `playback_pipeline` is already taken in ",
            "`switch_to_available`",
        ));
        self.ui_event.hand_back_pipeline(playback_pipeline);
        self.ui_event.reset_cursor();
    }

    pub fn handle_processing_states(&mut self, mut res: Result<ProcessingState, String>) {
        loop {
            match res {
                Ok(ProcessingState::AllComplete(msg)) => {
                    self.switch_to_available();
                    self.ui_event.show_info(msg);
                    break;
                }
                Ok(ProcessingState::Cancelled) => {
                    self.switch_to_available();
                    self.ui_event.show_info(gettext("Operation cancelled"));
                    break;
                }
                Ok(ProcessingState::ConfirmedOutputTo(path)) => {
                    res = self.impl_.process(path.as_ref());
                    if res == Ok(ProcessingState::PendingAsyncMediaEvent) {
                        // Next state handled asynchronously in media event handler
                        break;
                    }
                }
                Ok(ProcessingState::DoneWithCurrent) => {
                    res = self.impl_.next();
                }
                Ok(ProcessingState::PendingAsyncMediaEvent) => {
                    // Next state handled asynchronously in media event handler
                    break;
                }
                Ok(ProcessingState::Start) => {
                    self.switch_to_busy();
                    self.overwrite_all = false;

                    match self.impl_.init() {
                        ProcessingType::Sync => (),
                        ProcessingType::Async(receiver) => {
                            self.attach_media_event_handler(receiver);
                            self.register_progress_timer();
                        }
                    }

                    res = self.impl_.next();
                }
                Ok(ProcessingState::SkipCurrent) => {
                    res = match self.impl_.next() {
                        Ok(state) => match state {
                            ProcessingState::AllComplete(_) => {
                                // Don't display the success message when the user decided
                                // to skip (not overwrite) last part as it seems missleading
                                self.switch_to_available();
                                break;
                            }
                            other => Ok(other),
                        },
                        Err(err) => Err(err),
                    };
                }
                Ok(ProcessingState::WouldOutputTo(path)) => {
                    if !self.overwrite_all && path.exists() {
                        self.ask_overwrite_question(&path);
                        // Pending user response
                        // Next steps handled asynchronously (see closure above)
                        break;
                    } else {
                        // handle processing in next iteration
                        res = Ok(ProcessingState::ConfirmedOutputTo(path));
                    }
                }
                Err(err) => {
                    self.switch_to_available();
                    self.ui_event.show_error(err);
                    break;
                }
            }
        }
    }
}

impl<Impl> UIController for OutputBaseController<Impl>
where
    Impl: OutputControllerImpl + MediaProcessor + UIController + 'static,
{
    fn setup(&mut self, args: &CommandLineArguments) {
        self.btn.set_sensitive(false);
        self.impl_.setup(args);
    }

    fn new_media(&mut self, pipeline: &PlaybackPipeline) {
        self.btn.set_sensitive(true);
        self.impl_.new_media(pipeline);
    }

    fn cleanup(&mut self) {
        self.progress_bar.set_fraction(0f64);
        self.btn.set_sensitive(false);
        self.overwrite_all = false;
        self.impl_.cleanup();
    }

    fn streams_changed(&mut self, info: &MediaInfo) {
        self.impl_.streams_changed(info);
    }
}
<commit_msg>InfoBar question: don't show "Operation Cancelled"<commit_after>use gettextrs::gettext;
use glib;
use gtk;
use gtk::prelude::*;

use std::{
    collections::HashSet,
    path::{Path, PathBuf},
    rc::Rc,
    sync::{Arc, RwLock},
};

use crate::{
    application::CommandLineArguments,
    media::{MediaEvent, PlaybackPipeline},
    metadata,
    metadata::{Format, MediaInfo},
};

use super::{UIController, UIEventSender};

const PROGRESS_TIMER_PERIOD: u32 = 250; // 250 ms

pub enum ProcessingType {
    Async(glib::Receiver<MediaEvent>),
    Sync,
}

#[derive(Debug, PartialEq)]
pub enum ProcessingState {
    AllComplete(String),
    Cancelled,
    ConfirmedOutputTo(Rc<Path>),
    SkipCurrent,
    DoneWithCurrent,
    PendingAsyncMediaEvent,
    Start,
    WouldOutputTo(Rc<Path>),
}

pub trait MediaProcessor {
    fn init(&mut self) -> ProcessingType;
    fn next(&mut self) -> Result<ProcessingState, String>;
    fn process(&mut self, path: &Path) -> Result<ProcessingState, String>;
    fn handle_media_event(&mut self, event: MediaEvent) -> Result<ProcessingState, String>;
    fn report_progress(&self) -> Option<f64>;
}

pub trait OutputControllerImpl {
    const BTN_NAME: &'static str;
    const LIST_NAME: &'static str;
    const PROGRESS_BAR_NAME: &'static str;
}

pub struct OutputMediaFileInfo {
    pub format: Format,
    pub path: PathBuf,
    pub extension: String,
    pub stream_ids: Arc<RwLock<HashSet<String>>>,
}

impl OutputMediaFileInfo {
    pub fn new(format: Format, src_info: &MediaInfo) -> Self {
        let (stream_ids, content) = src_info.streams.get_ids_to_export(format);
        let extension = metadata::Factory::get_extension(format, content).to_owned();

        OutputMediaFileInfo {
            path: src_info.path.with_extension(&extension),
            extension,
            format,
            stream_ids: Arc::new(RwLock::new(stream_ids)),
        }
    }
}

type OverwriteResponseCb = Fn(gtk::ResponseType, &Rc<Path>);

pub struct OutputBaseController<Impl> {
    impl_: Impl,
    ui_event: UIEventSender,

    progress_bar: gtk::ProgressBar,
    list: gtk::ListBox,
    pub(super) btn: gtk::Button,

    perspective_selector: gtk::MenuButton,
    open_btn: gtk::Button,
    chapter_grid: gtk::Grid,

    playback_pipeline: Option<PlaybackPipeline>,

    pub(super) media_event_handler: Option<Rc<Fn(MediaEvent)>>,
    media_event_handler_src: Option<glib::SourceId>,

    pub(super) progress_updater: Option<Rc<Fn()>>,
    progress_timer_src: Option<glib::SourceId>,

    pub(super) overwrite_response_cb: Option<Rc<OverwriteResponseCb>>,
    overwrite_all: bool,
}

impl<Impl> OutputBaseController<Impl>
where
    Impl: OutputControllerImpl + MediaProcessor + UIController + 'static,
{
    pub fn new_base(impl_: Impl, builder: &gtk::Builder, ui_event_sender: UIEventSender) -> Self {
        OutputBaseController {
            impl_,
            ui_event: ui_event_sender,

            btn: builder.get_object(Impl::BTN_NAME).unwrap(),
            list: builder.get_object(Impl::LIST_NAME).unwrap(),
            progress_bar: builder.get_object(Impl::PROGRESS_BAR_NAME).unwrap(),

            perspective_selector: builder.get_object("perspective-menu-btn").unwrap(),
            open_btn: builder.get_object("open-btn").unwrap(),
            chapter_grid: builder.get_object("info-chapter_list-grid").unwrap(),

            playback_pipeline: None,

            media_event_handler: None,
            media_event_handler_src: None,

            progress_updater: None,
            progress_timer_src: None,

            overwrite_response_cb: None,
            overwrite_all: false,
        }
    }

    #[allow(clippy::redundant_closure)]
    fn attach_media_event_handler(&mut self, receiver: glib::Receiver<MediaEvent>) {
        debug_assert!(self.media_event_handler_src.is_none());

        let media_event_handler = Rc::clone(self.media_event_handler.as_ref().unwrap());
        self.media_event_handler_src = Some(receiver.attach(None, move |event| {
            media_event_handler(event);
            // will be removed in `OutputBaseController::switch_to_available`
            glib::Continue(true)
        }));
    }

    fn remove_media_event_handler(&mut self) {
        if let Some(src) = self.media_event_handler_src.take() {
            let _res = glib::Source::remove(src);
        }
    }

    pub fn handle_media_event(&mut self, event: MediaEvent) {
        let res = self.impl_.handle_media_event(event);
        self.handle_processing_states(res);
    }

    fn register_progress_timer(&mut self) {
        if self.progress_timer_src.is_none() {
            let progress_updater = Rc::clone(self.progress_updater.as_ref().unwrap());
            self.progress_timer_src =
                Some(glib::timeout_add_local(PROGRESS_TIMER_PERIOD, move || {
                    progress_updater();
                    glib::Continue(true)
                }));
        }
    }

    fn remove_progress_timer(&mut self) {
        if let Some(src) = self.progress_timer_src.take() {
            let _res = glib::Source::remove(src);
        }
    }

    pub fn update_progress(&self) {
        if let Some(progress) = self.impl_.report_progress() {
            self.progress_bar.set_fraction(progress);
        }
    }

    pub fn have_pipeline(&mut self, playback_pipeline: PlaybackPipeline) {
        self.playback_pipeline = Some(playback_pipeline);
    }

    fn ask_overwrite_question(&mut self, path: &Rc<Path>) {
        self.remove_progress_timer();
        self.ui_event.reset_cursor();

        let filename = path.file_name().expect("no `filename` in `path`");
        let filename = filename
            .to_str()
            .expect("can't get printable `str` from `filename`");
        let question = gettext("{output_file}\nalready exists. Overwrite?").replacen(
            "{output_file}",
            filename,
            1,
        );

        let path_cb = Rc::clone(path);
        let overwrite_response_cb = Rc::clone(self.overwrite_response_cb.as_ref().unwrap());
        self.ui_event.ask_question(
            question,
            Rc::new(move |response_type| overwrite_response_cb(response_type, &path_cb)),
        );
    }

    pub fn handle_overwrite_response(&mut self, response_type: gtk::ResponseType, path: &Rc<Path>) {
        let next_state = match response_type {
            gtk::ResponseType::Apply => {
                // This one is used for "Yes to all"
                self.overwrite_all = true;
                ProcessingState::ConfirmedOutputTo(Rc::clone(path))
            }
            gtk::ResponseType::Cancel => ProcessingState::Cancelled,
            gtk::ResponseType::No => ProcessingState::SkipCurrent,
            gtk::ResponseType::Yes => ProcessingState::ConfirmedOutputTo(Rc::clone(path)),
            other => unimplemented!(
                "Response type {:?} in OutputBaseController::handle_overwrite_response",
                other,
            ),
        };

        if next_state != ProcessingState::Cancelled {
            self.ui_event.set_cursor_waiting();
            self.register_progress_timer();
        }

        self.handle_processing_states(Ok(next_state));
    }

    fn switch_to_busy(&self) {
        self.list.set_sensitive(false);
        self.btn.set_sensitive(false);

        self.perspective_selector.set_sensitive(false);
        self.open_btn.set_sensitive(false);
        self.chapter_grid.set_sensitive(false);

        self.ui_event.set_cursor_waiting();
    }

    fn switch_to_available(&mut self) {
        self.remove_media_event_handler();
        self.remove_progress_timer();

        self.progress_bar.set_fraction(0f64);
        self.list.set_sensitive(true);
        self.btn.set_sensitive(true);

        self.perspective_selector.set_sensitive(true);
        self.open_btn.set_sensitive(true);
        self.chapter_grid.set_sensitive(true);

        let playback_pipeline = self.playback_pipeline.take().expect(concat!(
            "OutputBaseController: `playback_pipeline` is already taken in ",
            "`switch_to_available`",
        ));
        self.ui_event.hand_back_pipeline(playback_pipeline);
        self.ui_event.reset_cursor();
    }

    pub fn handle_processing_states(&mut self, mut res: Result<ProcessingState, String>) {
        loop {
            match res {
                Ok(ProcessingState::AllComplete(msg)) => {
                    self.switch_to_available();
                    self.ui_event.show_info(msg);
                    break;
                }
                Ok(ProcessingState::Cancelled) => {
                    self.switch_to_available();
                    break;
                }
                Ok(ProcessingState::ConfirmedOutputTo(path)) => {
                    res = self.impl_.process(path.as_ref());
                    if res == Ok(ProcessingState::PendingAsyncMediaEvent) {
                        // Next state handled asynchronously in media event handler
                        break;
                    }
                }
                Ok(ProcessingState::DoneWithCurrent) => {
                    res = self.impl_.next();
                }
                Ok(ProcessingState::PendingAsyncMediaEvent) => {
                    // Next state handled asynchronously in media event handler
                    break;
                }
                Ok(ProcessingState::Start) => {
                    self.switch_to_busy();
                    self.overwrite_all = false;

                    match self.impl_.init() {
                        ProcessingType::Sync => (),
                        ProcessingType::Async(receiver) => {
                            self.attach_media_event_handler(receiver);
                            self.register_progress_timer();
                        }
                    }

                    res = self.impl_.next();
                }
                Ok(ProcessingState::SkipCurrent) => {
                    res = match self.impl_.next() {
                        Ok(state) => match state {
                            ProcessingState::AllComplete(_) => {
                                // Don't display the success message when the user decided
                                // to skip (not overwrite) last part as it seems missleading
                                self.switch_to_available();
                                break;
                            }
                            other => Ok(other),
                        },
                        Err(err) => Err(err),
                    };
                }
                Ok(ProcessingState::WouldOutputTo(path)) => {
                    if !self.overwrite_all && path.exists() {
                        self.ask_overwrite_question(&path);
                        // Pending user response
                        // Next steps handled asynchronously (see closure above)
                        break;
                    } else {
                        // handle processing in next iteration
                        res = Ok(ProcessingState::ConfirmedOutputTo(path));
                    }
                }
                Err(err) => {
                    self.switch_to_available();
                    self.ui_event.show_error(err);
                    break;
                }
            }
        }
    }
}

impl<Impl> UIController for OutputBaseController<Impl>
where
    Impl: OutputControllerImpl + MediaProcessor + UIController + 'static,
{
    fn setup(&mut self, args: &CommandLineArguments) {
        self.btn.set_sensitive(false);
        self.impl_.setup(args);
    }

    fn new_media(&mut self, pipeline: &PlaybackPipeline) {
        self.btn.set_sensitive(true);
        self.impl_.new_media(pipeline);
    }

    fn cleanup(&mut self) {
        self.progress_bar.set_fraction(0f64);
        self.btn.set_sensitive(false);
        self.overwrite_all = false;
        self.impl_.cleanup();
    }

    fn streams_changed(&mut self, info: &MediaInfo) {
        self.impl_.streams_changed(info);
    }
}
<|endoftext|>