<commit_before>extern crate byteorder;
extern crate regex;
extern crate flate2;
extern crate getopts;
extern crate tempdir;
#[macro_use]
extern crate error_chain;

use std::fs::File;
use std::io;
use std::io::{BufReader, BufWriter};
use std::path::Path;
use std::env;
use std::process::exit;
use std::process::Command;

use getopts::Options;

use tempdir::TempDir;

pub mod data;
mod write;
mod read;
mod string_write;
mod string_read;
#[cfg(test)]
mod tests;

mod errors {
    error_chain!{
        foreign_links {
            Io(::std::io::Error);
            FromUtf8(::std::string::FromUtf8Error);
        }
    }
}
use errors::*;

fn main() {
    match run_cmdline() {
        Ok(ret) => {
            exit(ret);
        },
        Err(ref e) => {
            if let Some(backtrace) = e.backtrace() {
                eprintln!("{:?}", backtrace);
            }

            eprintln!("Error: {}", e);

            for e in e.iter().skip(1) {
                eprintln!("	caused by: {}", e);
            }

            eprintln!("For help, run with --help or read the manpage.");
            exit(1);
        },
    }
}

fn run_cmdline() -> Result<i32> {
    let args: Vec<String> = env::args().collect();

    let mut opts = Options::new();
    opts.optflagopt("e", "edit", "edit a NBT file with your $EDITOR.
    If [FILE] is specified, then that file is edited in place, but specifying --input and/or --output will override the input/output.
    If no file is specified, default to read from --input and writing to --output.", "FILE");
    opts.optflagopt("p", "print", "print NBT file to text format. Adding an argument to this is the same as specifying --input", "FILE");
    opts.optflagopt("r", "reverse", "reverse a file in text format to NBT format. Adding an argument to this is the same as specifying --input", "FILE");
    opts.optopt("i",
                "input",
                "specify the input file, defaults to stdin",
                "FILE");
    opts.optopt("o",
                "output",
                "specify the output file, defaults to stdout",
                "FILE");
    opts.optflag("h", "help", "print the help menu");
    opts.optflag("", "version", "print program version");

    let matches = opts.parse(&args[1..]).chain_err(|| "error parsing options")?;

    if matches.opt_present("h") {
        let brief = "Usage: nbted [options] FILE";
        print!("{}", opts.usage(&brief));
        println!("\nThe default action, taken if no action is explicitly selected, is to --edit.");
        println!("\nFor detailed usage information, read the manpage.");
        return Ok(0);
    }

    if matches.opt_present("version") {
        println!("{} {} {}",
                 env!("CARGO_PKG_NAME"),
                 env!("CARGO_PKG_VERSION"),
                 /* See build.rs for the git-revision.txt file */
                 include!(concat!(env!("OUT_DIR"), "/git-revision.txt")));
        println!("https://github.com/C4K3/nbted");
        return Ok(0);
    }

    let is_print: bool = matches.opt_present("print");
    let is_reverse: bool = matches.opt_present("reverse");
    let is_edit: bool = if matches.opt_present("edit") {
        true
    } else {
        /* If edit is not explicitly defined, it is the default action and is
         * selected if no other action is specified */
        (!(is_reverse || is_print))
    };

    /* Hopefully this is a simpler way of ensuring that only one action can be
     * taken than having a long logical expression */
    let mut action_count = 0;
    if is_print {
        action_count += 1;
    }
    if is_reverse {
        action_count += 1;
    }
    if is_edit {
        action_count += 1;
    }
    if action_count > 1 {
        bail!("You can only specify one action a time.");
    }

    /* Figure out the input file, by trying to read the arguments for all of
     * --input, --edit, --print and --reverse, prioritizing --input over the
     * other arguments, if none of the arguments are specified but there is a
     * free argument, use that, else we finally default to - (stdin) */
    let input = if let Some(x) = matches.opt_str("input") {
        x
    } else if let Some(x) = matches.opt_str("edit") {
        x
    } else if let Some(x) = matches.opt_str("print") {
        x
    } else if let Some(x) = matches.opt_str("reverse") {
        x
    } else if matches.free.len() == 1 {
        matches.free[0].clone()
    } else {
        /* stdin */
        "-".to_string()
    };

    let output = if let Some(x) = matches.opt_str("output") {
        x
    } else if let Some(x) = matches.opt_str("edit") {
        x
    } else if is_edit && matches.free.len() == 1 {
        /* Only want to default to the free argument if we're editing
         * (DO NOT WRITE BACK TO THE READ FILE UNLESS EDITING!) */
        matches.free[0].clone()
    } else {
        /* stdout */
        "-".to_string()
    };

    if matches.free.len() > 1 {
        bail!("nbted was given multiple arguments, but only supports editing one file at a time.");
    }

    if is_print {
        return print(&input, &output);
    } else if is_reverse {
        return reverse(&input, &output);
    } else if is_edit {
        return edit(&input, &output);
    } else {
        bail!("Internal error: No action selected. (Please report this.)");
    }
}

/// When the user wants to edit a specific file in place
fn edit(input: &str, output: &str) -> Result<i32> {

    /* First we read the NBT data from the input */
    let nbt = if input == "-" {
        // let mut f = BufReader::new(io::stdin());
        let f = io::stdin();
        let mut f = f.lock();
        read::read_file(&mut f).chain_err(|| "Unable to parse any NBT files from stdin")?
    } else {
        let path: &Path = Path::new(input);
        let f = File::open(path)
            .chain_err(|| format!("Unable to open file {}", input))?;
        let mut f = BufReader::new(f);

        read::read_file(&mut f).chain_err(
            || format!("Unable to parse {}, are you sure it's an NBT file?",
                       input))?
    };

    /* Then we create a temporary file and write the NBT data in text format
     * to the temporary file */
    let tmpdir = TempDir::new("nbted")
        .chain_err(|| "Unable to create temporary directory")?;

    let tmp = match Path::new(input).file_name() {
        Some(x) => {
            let mut x = x.to_os_string();
            x.push(".txt");
            x
        },
        None => bail!("Error reading file name"),
    };
    let tmp_path = tmpdir.path().join(tmp);

    {
        let mut f = File::create(&tmp_path)
            .chain_err(|| "Unable to create temporary file")?;

        string_write::write_file(&mut f, &nbt)
            .chain_err(|| "Unable to write temporary file")?;

        f.sync_all().chain_err(|| "Unable to synchronize file")?;
    }

    let new_nbt = {
        let mut new_nbt = open_editor(&tmp_path);

        while let Err(e) = new_nbt {
            eprintln!("Unable to parse edited file");
            for e in e.iter() {
                eprintln!("	caused by: {}", e);
            }
            eprintln!("Do you want to open the file for editing again? (y/N)");

            let mut line = String::new();
            io::stdin().read_line(&mut line)
                .chain_err(|| "Error reading from stdin. Nothing was changed")?;

            if line.trim() == "y" {
                new_nbt = open_editor(&tmp_path);
            } else {
                eprintln!("Exiting ... File is unchanged.");
                return Ok(0);
            }
        }

        new_nbt.expect("new_nbt was Error")
    };

    if nbt == new_nbt {
        eprintln!("No changes, will do nothing.");
        return Ok(0);
    }

    /* And finally we write the edited nbt (new_nbt) into the output file */
    if output == "-" {
        let f = io::stdout();
        let mut f = f.lock();
        match write::write_file(&mut f, &new_nbt) {
            Ok(()) => (),
            Err(_) => return Ok(1),
        }
    } else {
        let path: &Path = Path::new(output);
        let f = File::create(&path).chain_err(
            || format!("Unable to write to output NBT file {}. Nothing was changed",
                       output))?;
        let mut f = BufWriter::new(f);

        write::write_file(&mut f, &new_nbt).chain_err(
            || format!("Error writing NBT file {}. State of NBT file is unknown, consider restoring it from a backup.",
                       output))?;
    }

    eprintln!("File edited successfully.");
    Ok(0)
}

/// Open the user's $EDITOR on the temporary file, wait until the editor is
/// closed again, read the temporary file and attempt to parse it into NBT,
/// returning the result.
fn open_editor(tmp_path: &Path) -> Result<data::NBTFile> {
    let editor = match env::var("EDITOR") {
        Ok(x) => x,
        Err(_) => {
            match env::var("VISUAL") {
                Ok(x) => x,
                Err(_) => bail!("Unable to find $EDITOR"),
            }
        },
    };

    let mut cmd = Command::new(editor);
    cmd.arg(&tmp_path.as_os_str());
    let mut cmd = cmd.spawn().chain_err(|| "Error opening editor")?;

    match cmd.wait() {
        Ok(x) if x.success() => (),
        Ok(_) => bail!("Editor did not exit correctly"),
        Err(e) => {
            return Err(Error::with_chain(e, "Error executing editor"));
        },
    }

    /* Then we parse the text format in the temporary file into NBT */
    let mut f = File::open(&tmp_path).chain_err(
        || "Unable to read temporary file. Nothing was changed.")?;

    string_read::read_file(&mut f).map_err(|e| e.into())
}

/// When the user wants to print an NBT file to text format
fn print(input: &str, output: &str) -> Result<i32> {
    /* First we read a NBTFile from the input */
    let nbt = if input == "-" {
        let f = io::stdin();
        let mut f = f.lock();
        read::read_file(&mut f).chain_err(
            || format!("Unable to parse {}, are you sure it's an NBT file?",
                       input))?
    } else {
        let path: &Path = Path::new(input);
        let f = File::open(path).chain_err(
            || format!("Unable to open file {}", input))?;
        let mut f = BufReader::new(f);

        read::read_file(&mut f).chain_err(
            || format!("Unable to parse {}, are you sure it's an NBT file?",
                       input))?
    };

    /* Then we write the NBTFile to the output in text format */
    if output == "-" {
        let f = io::stdout();
        let mut f = f.lock();
        match string_write::write_file(&mut f, &nbt) {
            Ok(()) => (),
            Err(_) => return Ok(1),
        }
    } else {
        let path: &Path = Path::new(output);
        let f = File::create(&path).chain_err(
            || format!("Unable to write to output NBT file {}. Nothing was changed.",
                       output))?;
        let mut f = BufWriter::new(f);

        string_write::write_file(&mut f, &nbt).chain_err(
            || format!("Error writing NBT file {}. State of NBT file is unknown, consider restoring it from a backup.",
                       output))?;
    }

    Ok(0)
}

/// When the user wants to convert a text format file into an NBT file
fn reverse(input: &str, output: &str) -> Result<i32> {
    /* First we read the input file in the text format */
    let path: &Path = Path::new(input);
    let mut f = File::open(&path).chain_err(
        || format!("Unable to read text file {}",
                   input))?;

    let nbt = string_read::read_file(&mut f).chain_err(
        || format!("Unable to parse text file {}",
        input))?;

    /* Then we write the parsed NBT to the output file in NBT format */
    if output == "-" {
        let f = io::stdout();
        let mut f = f.lock();
        match write::write_file(&mut f, &nbt) {
            Ok(()) => (),
            Err(_) => return Ok(1),
        }
    } else {
        let path: &Path = Path::new(output);
        let f = File::create(&path).chain_err(
            || format!("Unable to write to output NBT file {}. Nothing was changed",
                       output))?;
        let mut f = BufWriter::new(f);

        write::write_file(&mut f, &nbt).chain_err(
            || format!("error writing to NBT FILE {}, state of NBT file is unknown, consider restoring it from a backup.",
                       output))?;
    }

    Ok(0)
}
<commit_msg>Add some comments for clarity<commit_after>extern crate byteorder;
extern crate regex;
extern crate flate2;
extern crate getopts;
extern crate tempdir;
#[macro_use]
extern crate error_chain;

use std::fs::File;
use std::io;
use std::io::{BufReader, BufWriter};
use std::path::Path;
use std::env;
use std::process::exit;
use std::process::Command;

use getopts::Options;

use tempdir::TempDir;

pub mod data;
mod write;
mod read;
mod string_write;
mod string_read;
#[cfg(test)]
mod tests;

mod errors {
    error_chain!{
        foreign_links {
            Io(::std::io::Error);
            FromUtf8(::std::string::FromUtf8Error);
        }
    }
}
use errors::*;

fn main() {
    match run_cmdline() {
        Ok(ret) => {
            exit(ret);
        },
        Err(ref e) => {
            if let Some(backtrace) = e.backtrace() {
                eprintln!("{:?}", backtrace);
            }

            eprintln!("Error: {}", e);

            for e in e.iter().skip(1) {
                eprintln!("	caused by: {}", e);
            }

            eprintln!("For help, run with --help or read the manpage.");
            exit(1);
        },
    }
}

/// Main entrypoint for program.
///
/// Returns an integer representing the program's exit status.
fn run_cmdline() -> Result<i32> {
    let args: Vec<String> = env::args().collect();

    let mut opts = Options::new();
    opts.optflagopt("e", "edit", "edit a NBT file with your $EDITOR.
    If [FILE] is specified, then that file is edited in place, but specifying --input and/or --output will override the input/output.
    If no file is specified, default to read from --input and writing to --output.", "FILE");
    opts.optflagopt("p", "print", "print NBT file to text format. Adding an argument to this is the same as specifying --input", "FILE");
    opts.optflagopt("r", "reverse", "reverse a file in text format to NBT format. Adding an argument to this is the same as specifying --input", "FILE");
    opts.optopt("i",
                "input",
                "specify the input file, defaults to stdin",
                "FILE");
    opts.optopt("o",
                "output",
                "specify the output file, defaults to stdout",
                "FILE");
    opts.optflag("h", "help", "print the help menu");
    opts.optflag("", "version", "print program version");

    let matches = opts.parse(&args[1..]).chain_err(|| "error parsing options")?;

    if matches.opt_present("h") {
        let brief = "Usage: nbted [options] FILE";
        print!("{}", opts.usage(&brief));
        println!("\nThe default action, taken if no action is explicitly selected, is to --edit.");
        println!("\nFor detailed usage information, read the manpage.");
        return Ok(0);
    }

    if matches.opt_present("version") {
        println!("{} {} {}",
                 env!("CARGO_PKG_NAME"),
                 env!("CARGO_PKG_VERSION"),
                 /* See build.rs for the git-revision.txt file */
                 include!(concat!(env!("OUT_DIR"), "/git-revision.txt")));
        println!("https://github.com/C4K3/nbted");
        return Ok(0);
    }

    let is_print: bool = matches.opt_present("print");
    let is_reverse: bool = matches.opt_present("reverse");
    let is_edit: bool = if matches.opt_present("edit") {
        true
    } else {
        /* If edit is not explicitly defined, it is the default action and is
         * selected if no other action is specified */
        (!(is_reverse || is_print))
    };

    /* Hopefully this is a simpler way of ensuring that only one action can be
     * taken than having a long logical expression */
    let mut action_count = 0;
    if is_print {
        action_count += 1;
    }
    if is_reverse {
        action_count += 1;
    }
    if is_edit {
        action_count += 1;
    }
    if action_count > 1 {
        bail!("You can only specify one action a time.");
    }

    /* Figure out the input file, by trying to read the arguments for all of
     * --input, --edit, --print and --reverse, prioritizing --input over the
     * other arguments, if none of the arguments are specified but there is a
     * free argument, use that, else we finally default to - (stdin) */
    let input = if let Some(x) = matches.opt_str("input") {
        x
    } else if let Some(x) = matches.opt_str("edit") {
        x
    } else if let Some(x) = matches.opt_str("print") {
        x
    } else if let Some(x) = matches.opt_str("reverse") {
        x
    } else if matches.free.len() == 1 {
        matches.free[0].clone()
    } else {
        /* stdin */
        "-".to_string()
    };

    let output = if let Some(x) = matches.opt_str("output") {
        x
    } else if let Some(x) = matches.opt_str("edit") {
        x
    } else if is_edit && matches.free.len() == 1 {
        /* Only want to default to the free argument if we're editing
         * (DO NOT WRITE BACK TO THE READ FILE UNLESS EDITING!) */
        matches.free[0].clone()
    } else {
        /* stdout */
        "-".to_string()
    };

    if matches.free.len() > 1 {
        bail!("nbted was given multiple arguments, but only supports editing one file at a time.");
    }

    if is_print {
        return print(&input, &output);
    } else if is_reverse {
        return reverse(&input, &output);
    } else if is_edit {
        return edit(&input, &output);
    } else {
        bail!("Internal error: No action selected. (Please report this.)");
    }
}

/// When the user wants to edit a specific file in place
///
/// Returns an integer representing the program's exit status.
fn edit(input: &str, output: &str) -> Result<i32> {

    /* First we read the NBT data from the input */
    let nbt = if input == "-" {
        // let mut f = BufReader::new(io::stdin());
        let f = io::stdin();
        let mut f = f.lock();
        read::read_file(&mut f).chain_err(|| "Unable to parse any NBT files from stdin")?
    } else {
        let path: &Path = Path::new(input);
        let f = File::open(path)
            .chain_err(|| format!("Unable to open file {}", input))?;
        let mut f = BufReader::new(f);

        read::read_file(&mut f).chain_err(
            || format!("Unable to parse {}, are you sure it's an NBT file?",
                       input))?
    };

    /* Then we create a temporary file and write the NBT data in text format
     * to the temporary file */
    let tmpdir = TempDir::new("nbted")
        .chain_err(|| "Unable to create temporary directory")?;

    let tmp = match Path::new(input).file_name() {
        Some(x) => {
            let mut x = x.to_os_string();
            x.push(".txt");
            x
        },
        None => bail!("Error reading file name"),
    };
    let tmp_path = tmpdir.path().join(tmp);

    {
        let mut f = File::create(&tmp_path)
            .chain_err(|| "Unable to create temporary file")?;

        string_write::write_file(&mut f, &nbt)
            .chain_err(|| "Unable to write temporary file")?;

        f.sync_all().chain_err(|| "Unable to synchronize file")?;
    }

    let new_nbt = {
        let mut new_nbt = open_editor(&tmp_path);

        while let Err(e) = new_nbt {
            eprintln!("Unable to parse edited file");
            for e in e.iter() {
                eprintln!("	caused by: {}", e);
            }
            eprintln!("Do you want to open the file for editing again? (y/N)");

            let mut line = String::new();
            io::stdin().read_line(&mut line)
                .chain_err(|| "Error reading from stdin. Nothing was changed")?;

            if line.trim() == "y" {
                new_nbt = open_editor(&tmp_path);
            } else {
                eprintln!("Exiting ... File is unchanged.");
                return Ok(0);
            }
        }

        new_nbt.expect("new_nbt was Error")
    };

    if nbt == new_nbt {
        eprintln!("No changes, will do nothing.");
        return Ok(0);
    }

    /* And finally we write the edited nbt (new_nbt) into the output file */
    if output == "-" {
        let f = io::stdout();
        let mut f = f.lock();
        /* If we get an error writing to stdout, we want to just silently exit
         * with exit code 1. (It can generally be assumed that nbted will not
         * error in serializing the data, so any error here would be because of
         * writing to stdout) */
        match write::write_file(&mut f, &new_nbt) {
            Ok(()) => (),
            Err(_) => return Ok(1),
        }
    } else {
        let path: &Path = Path::new(output);
        let f = File::create(&path).chain_err(
            || format!("Unable to write to output NBT file {}. Nothing was changed",
                       output))?;
        let mut f = BufWriter::new(f);

        write::write_file(&mut f, &new_nbt).chain_err(
            || format!("Error writing NBT file {}. State of NBT file is unknown, consider restoring it from a backup.",
                       output))?;
    }

    eprintln!("File edited successfully.");
    Ok(0)
}

/// Open the user's $EDITOR on the temporary file, wait until the editor is
/// closed again, read the temporary file and attempt to parse it into NBT,
/// returning the result.
fn open_editor(tmp_path: &Path) -> Result<data::NBTFile> {
    let editor = match env::var("EDITOR") {
        Ok(x) => x,
        Err(_) => {
            match env::var("VISUAL") {
                Ok(x) => x,
                Err(_) => bail!("Unable to find $EDITOR"),
            }
        },
    };

    let mut cmd = Command::new(editor);
    cmd.arg(&tmp_path.as_os_str());
    let mut cmd = cmd.spawn().chain_err(|| "Error opening editor")?;

    match cmd.wait() {
        Ok(x) if x.success() => (),
        Ok(_) => bail!("Editor did not exit correctly"),
        Err(e) => {
            return Err(Error::with_chain(e, "Error executing editor"));
        },
    }

    /* Then we parse the text format in the temporary file into NBT */
    let mut f = File::open(&tmp_path).chain_err(
        || "Unable to read temporary file. Nothing was changed.")?;

    string_read::read_file(&mut f).map_err(|e| e.into())
}

/// When the user wants to print an NBT file to text format
fn print(input: &str, output: &str) -> Result<i32> {
    /* First we read a NBTFile from the input */
    let nbt = if input == "-" {
        let f = io::stdin();
        let mut f = f.lock();
        read::read_file(&mut f).chain_err(
            || format!("Unable to parse {}, are you sure it's an NBT file?",
                       input))?
    } else {
        let path: &Path = Path::new(input);
        let f = File::open(path).chain_err(
            || format!("Unable to open file {}", input))?;
        let mut f = BufReader::new(f);

        read::read_file(&mut f).chain_err(
            || format!("Unable to parse {}, are you sure it's an NBT file?",
                       input))?
    };

    /* Then we write the NBTFile to the output in text format */
    if output == "-" {
        let f = io::stdout();
        let mut f = f.lock();
        /* If we get an error writing to stdout, we want to just silently exit
         * with exit code 1. (It can generally be assumed that nbted will not
         * error in serializing the data, so any error here would be because of
         * writing to stdout) */
        match string_write::write_file(&mut f, &nbt) {
            Ok(()) => (),
            Err(_) => return Ok(1),
        }
    } else {
        let path: &Path = Path::new(output);
        let f = File::create(&path).chain_err(
            || format!("Unable to write to output NBT file {}. Nothing was changed.",
                       output))?;
        let mut f = BufWriter::new(f);

        string_write::write_file(&mut f, &nbt).chain_err(
            || format!("Error writing NBT file {}. State of NBT file is unknown, consider restoring it from a backup.",
                       output))?;
    }

    Ok(0)
}

/// When the user wants to convert a text format file into an NBT file
///
/// Returns an integer representing the program's exit status.
fn reverse(input: &str, output: &str) -> Result<i32> {
    /* First we read the input file in the text format */
    let path: &Path = Path::new(input);
    let mut f = File::open(&path).chain_err(
        || format!("Unable to read text file {}",
                   input))?;

    let nbt = string_read::read_file(&mut f).chain_err(
        || format!("Unable to parse text file {}",
        input))?;

    /* Then we write the parsed NBT to the output file in NBT format */
    if output == "-" {
        let f = io::stdout();
        let mut f = f.lock();
        /* If we get an error writing to stdout, we want to just silently exit
         * with exit code 1. (It can generally be assumed that nbted will not
         * error in serializing the data, so any error here would be because of
         * writing to stdout) */
        match write::write_file(&mut f, &nbt) {
            Ok(()) => (),
            Err(_) => return Ok(1),
        }
    } else {
        let path: &Path = Path::new(output);
        let f = File::create(&path).chain_err(
            || format!("Unable to write to output NBT file {}. Nothing was changed",
                       output))?;
        let mut f = BufWriter::new(f);

        write::write_file(&mut f, &nbt).chain_err(
            || format!("error writing to NBT FILE {}, state of NBT file is unknown, consider restoring it from a backup.",
                       output))?;
    }

    Ok(0)
}
<|endoftext|>


<commit_before>use crate::nameserver::NameServerConfig;

pub fn name_server_configs() -> Vec<NameServerConfig> {
    vec![
        cloudflare::udp(),
        cloudflare::tcp(),
        cloudflare::https(),
        cloudflare::tls(),
        google::udp(),
        google::tcp(),
        opennic::udp(),
        opennic::tcp(),
        quad9::udp(),
        quad9::tcp(),
        quad9::tls(),
    ]
}

pub mod cloudflare {
    use std::net::Ipv4Addr;

    use crate::nameserver::NameServerConfig;

    static IPV4: Ipv4Addr = Ipv4Addr::new(1, 1, 1, 1);

    pub fn udp() -> NameServerConfig {
        NameServerConfig::udp_with_name((IPV4, 53), "Cloudflare".to_string())
    }

    pub fn tcp() -> NameServerConfig {
        NameServerConfig::tcp_with_name((IPV4, 53), "Cloudflare".to_string())
    }

    pub fn https() -> NameServerConfig {
        NameServerConfig::https_with_name((IPV4, 443), "cloudflare-dns.com", "Cloudflare".to_string())
    }

    pub fn tls() -> NameServerConfig {
        NameServerConfig::tls_with_name((IPV4, 853), "cloudflare-dns.com", "Cloudflare".to_string())
    }
}

pub mod google {
    use std::net::Ipv4Addr;

    use crate::nameserver::NameServerConfig;

    static IPV4: Ipv4Addr = Ipv4Addr::new(8, 8, 8, 8);

    pub fn udp() -> NameServerConfig {
        NameServerConfig::udp_with_name((IPV4, 53), "Google".to_string())
    }

    pub fn tcp() -> NameServerConfig {
        NameServerConfig::tcp_with_name((IPV4, 53), "Google".to_string())
    }

    pub fn https() -> NameServerConfig {
        NameServerConfig::https_with_name((IPV4, 443), "dns.google", "Cloudflare".to_string())
    }

    pub fn tls() -> NameServerConfig {
        NameServerConfig::tls_with_name((IPV4, 853), "dns.google", "Cloudflare".to_string())
    }
}

pub mod opennic {
    use std::net::Ipv4Addr;

    use crate::nameserver::NameServerConfig;

    static IPV4: Ipv4Addr = Ipv4Addr::new(185, 121, 177, 177);

    pub fn udp() -> NameServerConfig {
        NameServerConfig::udp_with_name((IPV4, 53), "OpenNIC".to_string())
    }

    pub fn tcp() -> NameServerConfig {
        NameServerConfig::tcp_with_name((IPV4, 53), "OpenNIC".to_string())
    }
}

pub mod quad9 {
    use std::net::Ipv4Addr;

    use crate::nameserver::NameServerConfig;

    static IPV4: Ipv4Addr = Ipv4Addr::new(9, 9, 9, 9);

    pub fn udp() -> NameServerConfig {
        NameServerConfig::udp_with_name((IPV4, 53), "Quad9".to_string())
    }

    pub fn tcp() -> NameServerConfig {
        NameServerConfig::tcp_with_name((IPV4, 53), "Quad9".to_string())
    }

    pub fn tls() -> NameServerConfig {
        NameServerConfig::tls_with_name((IPV4, 853), "cloudflare-dns.com", "Cloudflare".to_string())
    }
}
<commit_msg>Fix some typos and missing NS in predefined<commit_after>use crate::nameserver::NameServerConfig;

pub fn name_server_configs() -> Vec<NameServerConfig> {
    vec![
        cloudflare::udp(),
        cloudflare::tcp(),
        cloudflare::https(),
        cloudflare::tls(),
        google::udp(),
        google::tcp(),
        google::https(),
        google::tls(),
        opennic::udp(),
        opennic::tcp(),
        quad9::udp(),
        quad9::tcp(),
        quad9::https(),
        quad9::tls(),
    ]
}

pub mod cloudflare {
    use std::net::Ipv4Addr;

    use crate::nameserver::NameServerConfig;

    static IPV4: Ipv4Addr = Ipv4Addr::new(1, 1, 1, 1);

    pub fn udp() -> NameServerConfig {
        NameServerConfig::udp_with_name((IPV4, 53), "Cloudflare".to_string())
    }

    pub fn tcp() -> NameServerConfig {
        NameServerConfig::tcp_with_name((IPV4, 53), "Cloudflare".to_string())
    }

    pub fn https() -> NameServerConfig {
        NameServerConfig::https_with_name((IPV4, 443), "cloudflare-dns.com", "Cloudflare".to_string())
    }

    pub fn tls() -> NameServerConfig {
        NameServerConfig::tls_with_name((IPV4, 853), "cloudflare-dns.com", "Cloudflare".to_string())
    }
}

pub mod google {
    use std::net::Ipv4Addr;

    use crate::nameserver::NameServerConfig;

    static IPV4: Ipv4Addr = Ipv4Addr::new(8, 8, 8, 8);

    pub fn udp() -> NameServerConfig {
        NameServerConfig::udp_with_name((IPV4, 53), "Google".to_string())
    }

    pub fn tcp() -> NameServerConfig {
        NameServerConfig::tcp_with_name((IPV4, 53), "Google".to_string())
    }

    pub fn https() -> NameServerConfig {
        NameServerConfig::https_with_name((IPV4, 443), "dns.google", "Google".to_string())
    }

    pub fn tls() -> NameServerConfig {
        NameServerConfig::tls_with_name((IPV4, 853), "dns.google", "Google".to_string())
    }
}

pub mod opennic {
    use std::net::Ipv4Addr;

    use crate::nameserver::NameServerConfig;

    static IPV4: Ipv4Addr = Ipv4Addr::new(185, 121, 177, 177);

    pub fn udp() -> NameServerConfig {
        NameServerConfig::udp_with_name((IPV4, 53), "OpenNIC".to_string())
    }

    pub fn tcp() -> NameServerConfig {
        NameServerConfig::tcp_with_name((IPV4, 53), "OpenNIC".to_string())
    }
}

pub mod quad9 {
    use std::net::Ipv4Addr;

    use crate::nameserver::NameServerConfig;

    static IPV4: Ipv4Addr = Ipv4Addr::new(9, 9, 9, 9);

    pub fn udp() -> NameServerConfig {
        NameServerConfig::udp_with_name((IPV4, 53), "Quad9".to_string())
    }

    pub fn tcp() -> NameServerConfig {
        NameServerConfig::tcp_with_name((IPV4, 53), "Quad9".to_string())
    }

    pub fn https() -> NameServerConfig {
        NameServerConfig::https_with_name((IPV4, 443), "dns.quad9.net", "Quad9".to_string())
    }

    pub fn tls() -> NameServerConfig {
        NameServerConfig::tls_with_name((IPV4, 853), "dns.quad9.net", "Quad9".to_string())
    }
}
<|endoftext|>


<commit_before>use buffer::{Buffer, Direction, Mark};
use input::Input;
use uibuf::{UIBuffer, CharColor};
use frontends::Frontend;

/// A View is an abstract Window (into a Buffer).
///
/// It draws a portion of a Buffer to a UIBuffer which in turn is drawn to the
/// screen. It maintains the status bar for the current view, the "dirty status"
/// which is whether the buffer has been modified or not and a number of other
/// pieces of information.
pub struct View<'v> {
    pub buffer: Buffer,     //Text buffer
    top_line: Mark,         //First character of the top line to be displayed.
    left_col: uint,         //Index into the top line to set the left column to.
    cursor: Mark,           //Cursor displayed by this buffer.
    uibuf: UIBuffer,        //UIBuffer
}

impl<'v> View<'v> {

    //----- CONSTRUCTORS ---------------------------------------------------------------------------

    pub fn new(source: Input, width: uint, height: uint) -> View<'v> {
        let mut buffer = match source {
            Input::Filename(path) => {
                match path {
                    Some(s) => Buffer::new_from_file(Path::new(s)),
                    None    => Buffer::new(),
                }
            },
            Input::Stdin(reader) => {
                Buffer::new_from_reader(reader)
            },
        };

        // NOTE(greg): this may not play well with resizing
        let uibuf = UIBuffer::new(width, height);

        let cursor = Mark::Cursor(0);
        buffer.set_mark(cursor, 0);
        let top_line = Mark::DisplayMark(0);
        buffer.set_mark(top_line, 0);

        View {
            buffer: buffer,
            top_line: top_line,
            left_col: 0,
            cursor: cursor,
            uibuf: uibuf,
        }
    }

    pub fn get_height(&self) -> uint {
        // NOTE(greg): when the status bar needs to move up, this value should be changed
        self.uibuf.get_height() -1
    }

    pub fn get_width(&self) -> uint {
        self.uibuf.get_width()
    }

    //----- DRAWING METHODS ------------------------------------------------------------------------
    /// Clear the buffer
    ///
    /// Fills every cell in the UIBuffer with the space (' ') char.
    pub fn clear<T: Frontend>(&mut self, frontend: &mut T) {
        self.uibuf.fill(' ');
        self.uibuf.draw_everything(frontend);
    }

    pub fn draw<T: Frontend>(&mut self, frontend: &mut T) {
        for (index,line) in self.buffer
                                .lines_from(self.top_line)
                                .unwrap()
                                .take(self.get_height())
                                .enumerate() {
            draw_line(&mut self.uibuf, line, index, self.left_col);
            if index == self.get_height() { break; }
        }
        self.uibuf.draw_everything(frontend);
    }

    pub fn draw_status<T: Frontend>(&mut self, frontend: &mut T) {
        let buffer_status = self.buffer.status_text();
        let mut cursor_status = self.buffer.get_mark_coords(self.cursor).unwrap_or((0,0));
        cursor_status = (cursor_status.0 + 1, cursor_status.1 + 1);
        let status_text = format!("{} {}", buffer_status, cursor_status).into_bytes();
        let status_text_len = status_text.len();
        let width = self.get_width();
        let height = self.get_height();

        for index in range(0, width) {
            let mut ch: char = ' ';
            if index < status_text_len {
                ch = status_text[index] as char;
            }
            self.uibuf.update_cell(index, height, ch, CharColor::Black, CharColor::Blue);
        }

        self.uibuf.draw_range(frontend, height, height+1);
    }

    pub fn draw_cursor<T: Frontend>(&mut self, frontend: &mut T) {
        if let Some(top_line) = self.buffer.get_mark_coords(self.top_line) {
            if let Some((x, y)) = self.buffer.get_mark_coords(self.cursor) {
                frontend.draw_cursor(x as int, y as int - top_line.1 as int);
            }
        }
    }

    pub fn resize<T: Frontend>(&mut self, frontend: &mut T) {
        let width = self.uibuf.get_width();
        self.clear(frontend);
        self.uibuf = UIBuffer::new(width, 15);
    }

    //----- CURSOR METHODS -------------------------------------------------------------------------

    pub fn move_cursor(&mut self, direction: Direction) {
        self.buffer.shift_mark(self.cursor, direction);
        self.move_screen();
    }

    pub fn move_cursor_to_line_end(&mut self) {
        self.buffer.shift_mark(self.cursor, Direction::LineEnd);
        self.move_screen();
    }

    pub fn move_cursor_to_line_start(&mut self) {
        self.buffer.shift_mark(self.cursor, Direction::LineStart);
        self.move_screen();
    }

    //Update the top_line mark if necessary to keep the cursor on the screen.
    fn move_screen(&mut self) {
        if let (Some(cursor), Some(top_line)) = (self.buffer.get_mark_coords(self.cursor),
                                                 self.buffer.get_mark_coords(self.top_line)) {
            // FIXME
            // match cursor.0 as int - self.left_col as int {
            //     x if x < 0 => { self.left_col -= x as uint; }
            //     x if x > self.get_width() as int => { self.left_col += x as uint - self.get_width()}
            //     _ => { }
            // }

            let cursor_linenum = cursor.1 as int;
            let cursor_offset = cursor_linenum - top_line.1 as int;
            let height = self.get_height() as int;

            if cursor_offset >= (height - 5) {
                // moving down
                let times = cursor_offset - (height - 5) + 1;
                self.buffer.shift_mark(self.top_line, Direction::Down(times as uint));
            } else if cursor_offset < 5 {
                // moving up
                self.buffer.shift_mark(self.top_line, Direction::Up(1));
            }
        }
    }

    //----- TEXT EDIT METHODS ----------------------------------------------------------------------

    pub fn delete_char(&mut self, direction: Direction) {
        match direction {
            Direction::Left(1) if self.buffer.get_mark_idx(self.cursor) != Some(0) => {
                self.move_cursor(direction);
                self.buffer.remove_char(self.cursor);
            }
            Direction::Right(1) if self.buffer.get_mark_idx(self.cursor) != Some(self.buffer.len()) => {
                self.buffer.remove_char(self.cursor);
            }
            _ => {}
        }
    }

    pub fn insert_tab(&mut self) {
        // A tab is just 4 spaces
        for _ in range(0i, 4) {
            self.insert_char(' ');
        }
    }

    pub fn insert_char(&mut self, ch: char) {
        self.buffer.insert_char(self.cursor, ch as u8);
        self.move_cursor(Direction::Right(1))
    }

    pub fn undo(&mut self) {
        let point = if let Some(transaction) = self.buffer.undo() { transaction.end_point }
                    else { return; };
        self.buffer.set_mark(self.cursor, point);
        self.move_screen();
    }

    pub fn redo(&mut self) {
        let point = if let Some(transaction) = self.buffer.redo() { transaction.end_point }
                    else { return; };
        self.buffer.set_mark(self.cursor, point);
        self.move_screen();
    }

}

pub fn draw_line(buf: &mut UIBuffer, line: &[u8], idx: uint, left: uint) {
    let width = buf.get_width() - 1;
    let mut wide_chars = 0;
    for line_idx in range(left, left + width) {
        if line_idx < line.len() {
            match line[line_idx] {
                b'\t'   => {
                    let w = 4 - line_idx % 4;
                    for _ in range(0, w) {
                        buf.update_cell_content(line_idx + wide_chars - left, idx, ' ');
                    }
                }
                b'\n'   => buf.update_cell_content(line_idx + wide_chars - left, idx, ' '),
                _       => buf.update_cell_content(line_idx + wide_chars - left, idx,
                                                   line[line_idx] as char),
            }
            wide_chars += (line[line_idx] as char).width(false).unwrap_or(1) - 1;
        } else { buf.update_cell_content(line_idx + wide_chars - left, idx, ' '); }
    }
    if line.len() >= width {
        buf.update_cell_content(width + wide_chars, idx, '→');
    }

}

#[cfg(test)]
mod tests {

    use buffer::Direction;
    use view::View;
    use input::Input;

    fn setup_view<'v>(testcase: &'static str) -> View<'v> {
        let mut view = View::new(Input::Filename(None), 50, 50);
        for ch in testcase.chars() {
            view.insert_char(ch);
        }
        view.buffer.set_mark(view.cursor, 0);
        view
    }

    #[test]
    fn test_move_cursor_down() {
        let mut view = setup_view("test\nsecond");
        view.move_cursor(Direction::Down(1));
        assert_eq!(view.buffer.get_mark_coords(view.cursor).unwrap().1, 1);
        assert_eq!(view.buffer.lines_from(view.cursor).unwrap().next().unwrap(), b"second"[]);
    }

    #[test]
    fn test_move_cursor_up() {
        let mut view = setup_view("test\nsecond");
        view.move_cursor(Direction::Down(1));
        view.move_cursor(Direction::Up(1));
        assert_eq!(view.buffer.get_mark_coords(view.cursor).unwrap().1, 0);
        assert_eq!(view.buffer.lines_from(view.cursor).unwrap().next().unwrap(), b"test\n"[]);
    }

    #[test]
    fn test_insert_line() {
        let mut view = setup_view("test\nsecond");
        view.move_cursor(Direction::Right(1));
        view.insert_char('\n');

        assert_eq!(view.buffer.get_mark_coords(view.cursor).unwrap(), (0, 1))
    }

    #[test]
    fn test_insert_char() {
        let mut view = setup_view("test\nsecond");
        view.insert_char('t');

        assert_eq!(view.buffer.lines().next().unwrap(), b"ttest\n"[]);
    }

    #[test]
    fn test_delete_char_to_right() {
        let mut view = setup_view("test\nsecond");
        view.delete_char(Direction::Right(1));

        assert_eq!(view.buffer.lines().next().unwrap(), b"est\n"[]);
    }

    #[test]
    fn test_delete_char_to_left() {
        let mut view = setup_view("test\nsecond");
        view.move_cursor(Direction::Right(1));
        view.delete_char(Direction::Left(1));

        assert_eq!(view.buffer.lines().next().unwrap(), b"est\n"[]);
    }

    #[test]
    fn test_delete_char_at_start_of_line() {
        let mut view = setup_view("test\nsecond");
        view.move_cursor(Direction::Down(1));
        view.delete_char(Direction::Left(1));

        assert_eq!(view.buffer.lines().next().unwrap(), b"testsecond"[]);
    }

    #[test]
    fn test_delete_char_at_end_of_line() {
        let mut view = setup_view("test\nsecond");
        view.move_cursor(Direction::Right(4));
        view.delete_char(Direction::Right(1));

        assert_eq!(view.buffer.lines().next().unwrap(), b"testsecond"[]);
    }

    #[test]
    fn deleting_backward_at_start_of_first_line_does_nothing() {
        let mut view = setup_view("test\nsecond");
        view.delete_char(Direction::Left(1));

        let lines: Vec<&[u8]> = view.buffer.lines().collect();

        assert_eq!(lines.len(), 2);
        assert_eq!(view.buffer.lines().next().unwrap(), b"test\n");
    }
}
<commit_msg>Fixed some scrolling bugs.<commit_after>use buffer::{Buffer, Direction, Mark};
use input::Input;
use uibuf::{UIBuffer, CharColor};
use frontends::Frontend;

/// A View is an abstract Window (into a Buffer).
///
/// It draws a portion of a Buffer to a UIBuffer which in turn is drawn to the
/// screen. It maintains the status bar for the current view, the "dirty status"
/// which is whether the buffer has been modified or not and a number of other
/// pieces of information.
pub struct View<'v> {
    pub buffer: Buffer,     //Text buffer
    top_line: Mark,         //First character of the top line to be displayed.
    left_col: uint,         //Index into the top line to set the left column to.
    cursor: Mark,           //Cursor displayed by this buffer.
    uibuf: UIBuffer,        //UIBuffer
    threshold: uint,
}

impl<'v> View<'v> {

    //----- CONSTRUCTORS ---------------------------------------------------------------------------

    pub fn new(source: Input, width: uint, height: uint) -> View<'v> {
        let mut buffer = match source {
            Input::Filename(path) => {
                match path {
                    Some(s) => Buffer::new_from_file(Path::new(s)),
                    None    => Buffer::new(),
                }
            },
            Input::Stdin(reader) => {
                Buffer::new_from_reader(reader)
            },
        };

        // NOTE(greg): this may not play well with resizing
        let uibuf = UIBuffer::new(width, height);

        let cursor = Mark::Cursor(0);
        buffer.set_mark(cursor, 0);
        let top_line = Mark::DisplayMark(0);
        buffer.set_mark(top_line, 0);

        View {
            buffer: buffer,
            top_line: top_line,
            left_col: 0,
            cursor: cursor,
            uibuf: uibuf,
            threshold: 5,
        }
    }

    pub fn get_height(&self) -> uint {
        // NOTE(greg): when the status bar needs to move up, this value should be changed
        self.uibuf.get_height() -1
    }

    pub fn get_width(&self) -> uint {
        self.uibuf.get_width()
    }

    //----- DRAWING METHODS ------------------------------------------------------------------------
    /// Clear the buffer
    ///
    /// Fills every cell in the UIBuffer with the space (' ') char.
    pub fn clear<T: Frontend>(&mut self, frontend: &mut T) {
        self.uibuf.fill(' ');
        self.uibuf.draw_everything(frontend);
    }

    pub fn draw<T: Frontend>(&mut self, frontend: &mut T) {
        for (index,line) in self.buffer
                                .lines_from(self.top_line)
                                .unwrap()
                                .take(self.get_height())
                                .enumerate() {
            draw_line(&mut self.uibuf, line, index, self.left_col);
            if index == self.get_height() { break; }
        }
        self.uibuf.draw_everything(frontend);
    }

    pub fn draw_status<T: Frontend>(&mut self, frontend: &mut T) {
        let buffer_status = self.buffer.status_text();
        let mut cursor_status = self.buffer.get_mark_coords(self.cursor).unwrap_or((0,0));
        cursor_status = (cursor_status.0 + 1, cursor_status.1 + 1);
        let status_text = format!("{} {}", buffer_status, cursor_status).into_bytes();
        let status_text_len = status_text.len();
        let width = self.get_width();
        let height = self.get_height();

        for index in range(0, width) {
            let mut ch: char = ' ';
            if index < status_text_len {
                ch = status_text[index] as char;
            }
            self.uibuf.update_cell(index, height, ch, CharColor::Black, CharColor::Blue);
        }

        self.uibuf.draw_range(frontend, height, height+1);
    }

    pub fn draw_cursor<T: Frontend>(&mut self, frontend: &mut T) {
        if let Some(top_line) = self.buffer.get_mark_coords(self.top_line) {
            if let Some((x, y)) = self.buffer.get_mark_coords(self.cursor) {
                frontend.draw_cursor(x as int, y as int - top_line.1 as int);
            }
        }
    }

    pub fn resize<T: Frontend>(&mut self, frontend: &mut T) {
        let width = self.uibuf.get_width();
        self.clear(frontend);
        self.uibuf = UIBuffer::new(width, 15);
    }

    //----- CURSOR METHODS -------------------------------------------------------------------------

    pub fn move_cursor(&mut self, direction: Direction) {
        self.buffer.shift_mark(self.cursor, direction);
        self.move_screen();
    }

    pub fn move_cursor_to_line_end(&mut self) {
        self.buffer.shift_mark(self.cursor, Direction::LineEnd);
        self.move_screen();
    }

    pub fn move_cursor_to_line_start(&mut self) {
        self.buffer.shift_mark(self.cursor, Direction::LineStart);
        self.move_screen();
    }

    //Update the top_line mark if necessary to keep the cursor on the screen.
    fn move_screen(&mut self) {
        if let (Some(cursor), Some((_, top_line))) = (self.buffer.get_mark_coords(self.cursor),
                                                      self.buffer.get_mark_coords(self.top_line)) {

            let width  = (self.get_width()  - self.threshold) as int;
            let height = (self.get_height() - self.threshold) as int;

            //left-right shifting
            match cursor.0 as int - self.left_col as int {
                x_offset if x_offset < self.threshold as int && self.left_col > 0 => {
                    self.left_col -= (self.threshold as int - x_offset) as uint;
                }
                x_offset if x_offset >= width => {
                    self.left_col += (x_offset - width + 1) as uint;
                }
                _ => { }
            }

            //up-down shifting
            match cursor.1 as int - top_line as int {
                y_offset if y_offset < self.threshold as int && top_line > 0 => {
                    self.buffer.shift_mark(self.top_line,
                                           Direction::Up((self.threshold as int - y_offset) as uint));
                }
                y_offset if y_offset >= height => {
                    self.buffer.shift_mark(self.top_line,
                                           Direction::Down((y_offset - height + 1) as uint));
                }
                _ => { }
            }
        }
    }

    //----- TEXT EDIT METHODS ----------------------------------------------------------------------

    pub fn delete_char(&mut self, direction: Direction) {
        match direction {
            Direction::Left(1) if self.buffer.get_mark_idx(self.cursor) != Some(0) => {
                self.move_cursor(direction);
                self.buffer.remove_char(self.cursor);
            }
            Direction::Right(1) if self.buffer.get_mark_idx(self.cursor) != Some(self.buffer.len()) => {
                self.buffer.remove_char(self.cursor);
            }
            _ => {}
        }
    }

    pub fn insert_tab(&mut self) {
        // A tab is just 4 spaces
        for _ in range(0i, 4) {
            self.insert_char(' ');
        }
    }

    pub fn insert_char(&mut self, ch: char) {
        self.buffer.insert_char(self.cursor, ch as u8);
        self.move_cursor(Direction::Right(1))
    }

    pub fn undo(&mut self) {
        let point = if let Some(transaction) = self.buffer.undo() { transaction.end_point }
                    else { return; };
        self.buffer.set_mark(self.cursor, point);
        self.move_screen();
    }

    pub fn redo(&mut self) {
        let point = if let Some(transaction) = self.buffer.redo() { transaction.end_point }
                    else { return; };
        self.buffer.set_mark(self.cursor, point);
        self.move_screen();
    }

}

pub fn draw_line(buf: &mut UIBuffer, line: &[u8], idx: uint, left: uint) {
    let width = buf.get_width() - 1;
    let mut wide_chars = 0;
    for line_idx in range(left, left + width) {
        if line_idx < line.len() {
            match line[line_idx] {
                b'\t'   => {
                    let w = 4 - line_idx % 4;
                    for _ in range(0, w) {
                        buf.update_cell_content(line_idx + wide_chars - left, idx, ' ');
                    }
                }
                b'\n'   => buf.update_cell_content(line_idx + wide_chars - left, idx, ' '),
                _       => buf.update_cell_content(line_idx + wide_chars - left, idx,
                                                   line[line_idx] as char),
            }
            wide_chars += (line[line_idx] as char).width(false).unwrap_or(1) - 1;
        } else { buf.update_cell_content(line_idx + wide_chars - left, idx, ' '); }
    }
    if line.len() >= width {
        buf.update_cell_content(width + wide_chars, idx, '→');
    }

}

#[cfg(test)]
mod tests {

    use buffer::Direction;
    use view::View;
    use input::Input;

    fn setup_view<'v>(testcase: &'static str) -> View<'v> {
        let mut view = View::new(Input::Filename(None), 50, 50);
        for ch in testcase.chars() {
            view.insert_char(ch);
        }
        view.buffer.set_mark(view.cursor, 0);
        view
    }

    #[test]
    fn test_move_cursor_down() {
        let mut view = setup_view("test\nsecond");
        view.move_cursor(Direction::Down(1));
        assert_eq!(view.buffer.get_mark_coords(view.cursor).unwrap().1, 1);
        assert_eq!(view.buffer.lines_from(view.cursor).unwrap().next().unwrap(), b"second"[]);
    }

    #[test]
    fn test_move_cursor_up() {
        let mut view = setup_view("test\nsecond");
        view.move_cursor(Direction::Down(1));
        view.move_cursor(Direction::Up(1));
        assert_eq!(view.buffer.get_mark_coords(view.cursor).unwrap().1, 0);
        assert_eq!(view.buffer.lines_from(view.cursor).unwrap().next().unwrap(), b"test\n"[]);
    }

    #[test]
    fn test_insert_line() {
        let mut view = setup_view("test\nsecond");
        view.move_cursor(Direction::Right(1));
        view.insert_char('\n');

        assert_eq!(view.buffer.get_mark_coords(view.cursor).unwrap(), (0, 1))
    }

    #[test]
    fn test_insert_char() {
        let mut view = setup_view("test\nsecond");
        view.insert_char('t');

        assert_eq!(view.buffer.lines().next().unwrap(), b"ttest\n"[]);
    }

    #[test]
    fn test_delete_char_to_right() {
        let mut view = setup_view("test\nsecond");
        view.delete_char(Direction::Right(1));

        assert_eq!(view.buffer.lines().next().unwrap(), b"est\n"[]);
    }

    #[test]
    fn test_delete_char_to_left() {
        let mut view = setup_view("test\nsecond");
        view.move_cursor(Direction::Right(1));
        view.delete_char(Direction::Left(1));

        assert_eq!(view.buffer.lines().next().unwrap(), b"est\n"[]);
    }

    #[test]
    fn test_delete_char_at_start_of_line() {
        let mut view = setup_view("test\nsecond");
        view.move_cursor(Direction::Down(1));
        view.delete_char(Direction::Left(1));

        assert_eq!(view.buffer.lines().next().unwrap(), b"testsecond"[]);
    }

    #[test]
    fn test_delete_char_at_end_of_line() {
        let mut view = setup_view("test\nsecond");
        view.move_cursor(Direction::Right(4));
        view.delete_char(Direction::Right(1));

        assert_eq!(view.buffer.lines().next().unwrap(), b"testsecond"[]);
    }

    #[test]
    fn deleting_backward_at_start_of_first_line_does_nothing() {
        let mut view = setup_view("test\nsecond");
        view.delete_char(Direction::Left(1));

        let lines: Vec<&[u8]> = view.buffer.lines().collect();

        assert_eq!(lines.len(), 2);
        assert_eq!(view.buffer.lines().next().unwrap(), b"test\n");
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 Amanieu d'Antras
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

#[cfg(feature = "nightly")]
use std::sync::atomic::{AtomicU8, ATOMIC_U8_INIT, Ordering, fence};
#[cfg(feature = "nightly")]
type U8 = u8;
#[cfg(not(feature = "nightly"))]
use stable::{AtomicU8, ATOMIC_U8_INIT, Ordering, fence};
#[cfg(not(feature = "nightly"))]
type U8 = usize;
use std::mem;
use parking_lot_core::{self, SpinWait, DEFAULT_PARK_TOKEN, DEFAULT_UNPARK_TOKEN};
use util::UncheckedOptionExt;

const DONE_BIT: U8 = 1;
const POISON_BIT: U8 = 2;
const LOCKED_BIT: U8 = 4;
const PARKED_BIT: U8 = 8;

/// State yielded to the `call_once_force` method which can be used to query
/// whether the `Once` was previously poisoned or not.
pub struct OnceState(bool);

impl OnceState {
    /// Returns whether the associated `Once` has been poisoned.
    ///
    /// Once an initalization routine for a `Once` has panicked it will forever
    /// indicate to future forced initialization routines that it is poisoned.
    #[inline]
    pub fn poisoned(&self) -> bool {
        self.0
    }
}

/// A synchronization primitive which can be used to run a one-time
/// initialization. Useful for one-time initialization for globals, FFI or
/// related functionality.
///
/// # Differences from the standard library `Once`
///
/// - Only requires 1 byte of space, instead of 1 word.
/// - Not required to be `'static`.
/// - Relaxed memory barriers in the fast path, which can significantly improve
///   performance on some architectures.
/// - Efficient handling of micro-contention using adaptive spinning.
///
/// # Examples
///
/// ```
/// use parking_lot::{Once, ONCE_INIT};
///
/// static START: Once = ONCE_INIT;
///
/// START.call_once(|| {
///     // run initialization here
/// });
/// ```
pub struct Once(AtomicU8);

/// Initialization value for static `Once` values.
pub const ONCE_INIT: Once = Once(ATOMIC_U8_INIT);

impl Once {
    /// Creates a new `Once` value.
    #[cfg(feature = "nightly")]
    #[inline]
    pub const fn new() -> Once {
        Once(AtomicU8::new(0))
    }

    /// Creates a new `Once` value.
    #[cfg(not(feature = "nightly"))]
    #[inline]
    pub fn new() -> Once {
        Once(AtomicU8::new(0))
    }

    /// Performs an initialization routine once and only once. The given closure
    /// will be executed if this is the first time `call_once` has been called,
    /// and otherwise the routine will *not* be invoked.
    ///
    /// This method will block the calling thread if another initialization
    /// routine is currently running.
    ///
    /// When this function returns, it is guaranteed that some initialization
    /// has run and completed (it may not be the closure specified). It is also
    /// guaranteed that any memory writes performed by the executed closure can
    /// be reliably observed by other threads at this point (there is a
    /// happens-before relation between the closure and code executing after the
    /// return).
    ///
    /// # Examples
    ///
    /// ```
    /// use parking_lot::{Once, ONCE_INIT};
    ///
    /// static mut VAL: usize = 0;
    /// static INIT: Once = ONCE_INIT;
    ///
    /// // Accessing a `static mut` is unsafe much of the time, but if we do so
    /// // in a synchronized fashion (e.g. write once or read all) then we're
    /// // good to go!
    /// //
    /// // This function will only call `expensive_computation` once, and will
    /// // otherwise always return the value returned from the first invocation.
    /// fn get_cached_val() -> usize {
    ///     unsafe {
    ///         INIT.call_once(|| {
    ///             VAL = expensive_computation();
    ///         });
    ///         VAL
    ///     }
    /// }
    ///
    /// fn expensive_computation() -> usize {
    ///     // ...
    /// # 2
    /// }
    /// ```
    ///
    /// # Panics
    ///
    /// The closure `f` will only be executed once if this is called
    /// concurrently amongst many threads. If that closure panics, however, then
    /// it will *poison* this `Once` instance, causing all future invocations of
    /// `call_once` to also panic.
    #[inline]
    pub fn call_once<F>(&self, f: F)
        where F: FnOnce()
    {
        if self.0.load(Ordering::Acquire) == DONE_BIT {
            return;
        }

        let mut f = Some(f);
        self.call_once_slow(false, &mut |_| unsafe { f.take().unchecked_unwrap()() });
    }

    /// Performs the same function as `call_once` except ignores poisoning.
    ///
    /// If this `Once` has been poisoned (some initialization panicked) then
    /// this function will continue to attempt to call initialization functions
    /// until one of them doesn't panic.
    ///
    /// The closure `f` is yielded a structure which can be used to query the
    /// state of this `Once` (whether initialization has previously panicked or
    /// not).
    #[inline]
    pub fn call_once_force<F>(&self, f: F)
        where F: FnOnce(OnceState)
    {
        if self.0.load(Ordering::Acquire) == DONE_BIT {
            return;
        }

        let mut f = Some(f);
        self.call_once_slow(true,
                            &mut |state| unsafe {
                                f.take().unchecked_unwrap()(state)
                            });
    }

    // This is a non-generic function to reduce the monomorphization cost of
    // using `call_once` (this isn't exactly a trivial or small implementation).
    //
    // Additionally, this is tagged with `#[cold]` as it should indeed be cold
    // and it helps let LLVM know that calls to this function should be off the
    // fast path. Essentially, this should help generate more straight line code
    // in LLVM.
    //
    // Finally, this takes an `FnMut` instead of a `FnOnce` because there's
    // currently no way to take an `FnOnce` and call it via virtual dispatch
    // without some allocation overhead.
    #[cold]
    #[inline(never)]
    fn call_once_slow(&self, ignore_poison: bool, f: &mut FnMut(OnceState)) {
        let mut spinwait = SpinWait::new();
        let mut state = self.0.load(Ordering::Relaxed);
        loop {
            // If another thread called the closure, we're done
            if state & DONE_BIT != 0 {
                // An acquire fence is needed here since we didn't load the
                // state with Ordering::Acquire.
                fence(Ordering::Acquire);
                return;
            }

            // If the state has been poisoned and we aren't forcing, then panic
            if state & POISON_BIT != 0 && !ignore_poison {
                // Need the fence here as well for the same reason
                fence(Ordering::Acquire);
                panic!("Once instance has previously been poisoned");
            }

            // Grab the lock if it isn't locked, even if there is a queue on it.
            // We also clear the poison bit since we are going to try running
            // the closure again.
            if state & LOCKED_BIT == 0 {
                match self.0
                    .compare_exchange_weak(state,
                                           (state | LOCKED_BIT) & !POISON_BIT,
                                           Ordering::Acquire,
                                           Ordering::Relaxed) {
                    Ok(_) => break,
                    Err(x) => state = x,
                }
                continue;
            }

            // If there is no queue, try spinning a few times
            if state & PARKED_BIT == 0 && spinwait.spin() {
                state = self.0.load(Ordering::Relaxed);
                continue;
            }

            // Set the parked bit
            if state & PARKED_BIT == 0 {
                if let Err(x) = self.0.compare_exchange_weak(state,
                                                             state | PARKED_BIT,
                                                             Ordering::Relaxed,
                                                             Ordering::Relaxed) {
                    state = x;
                    continue;
                }
            }

            // Park our thread until we are woken up by the thread that owns the
            // lock.
            unsafe {
                let addr = self as *const _ as usize;
                let validate = || self.0.load(Ordering::Relaxed) == LOCKED_BIT | PARKED_BIT;
                let before_sleep = || {};
                let timed_out = |_, _| unreachable!();
                parking_lot_core::park(addr,
                                       validate,
                                       before_sleep,
                                       timed_out,
                                       DEFAULT_PARK_TOKEN,
                                       None);
            }

            // Loop back and check if the done bit was set
            spinwait.reset();
            state = self.0.load(Ordering::Relaxed);
        }

        struct PanicGuard<'a>(&'a Once);
        impl<'a> Drop for PanicGuard<'a> {
            fn drop(&mut self) {
                // Mark the state as poisoned, unlock it and unpark all threads.
                let once = self.0;
                let state = once.0.swap(POISON_BIT, Ordering::Release);
                if state & PARKED_BIT != 0 {
                    unsafe {
                        let addr = once as *const _ as usize;
                        parking_lot_core::unpark_all(addr, DEFAULT_UNPARK_TOKEN);
                    }
                }
            }
        }

        // At this point we have the lock, so run the closure. Make sure we
        // properly clean up if the closure panicks.
        let guard = PanicGuard(self);
        f(OnceState(state & POISON_BIT != 0));
        mem::forget(guard);

        // Now unlock the state, set the done bit and unpark all threads
        let state = self.0.swap(DONE_BIT, Ordering::Release);
        if state & PARKED_BIT != 0 {
            unsafe {
                let addr = self as *const _ as usize;
                parking_lot_core::unpark_all(addr, DEFAULT_UNPARK_TOKEN);
            }
        }
    }
}

impl Default for Once {
    #[inline]
    fn default() -> Once {
        Once::new()
    }
}

#[cfg(test)]
mod tests {
    #[cfg(feature = "nightly")]
    use std::panic;
    use std::sync::mpsc::channel;
    use std::thread;
    use {Once, ONCE_INIT};

    #[test]
    fn smoke_once() {
        static O: Once = ONCE_INIT;
        let mut a = 0;
        O.call_once(|| a += 1);
        assert_eq!(a, 1);
        O.call_once(|| a += 1);
        assert_eq!(a, 1);
    }

    #[test]
    fn stampede_once() {
        static O: Once = ONCE_INIT;
        static mut RUN: bool = false;

        let (tx, rx) = channel();
        for _ in 0..10 {
            let tx = tx.clone();
            thread::spawn(move || {
                for _ in 0..4 {
                    thread::yield_now()
                }
                unsafe {
                    O.call_once(|| {
                        assert!(!RUN);
                        RUN = true;
                    });
                    assert!(RUN);
                }
                tx.send(()).unwrap();
            });
        }

        unsafe {
            O.call_once(|| {
                assert!(!RUN);
                RUN = true;
            });
            assert!(RUN);
        }

        for _ in 0..10 {
            rx.recv().unwrap();
        }
    }

    #[cfg(feature = "nightly")]
    #[test]
    fn poison_bad() {
        static O: Once = ONCE_INIT;

        // poison the once
        let t = panic::catch_unwind(|| {
            O.call_once(|| panic!());
        });
        assert!(t.is_err());

        // poisoning propagates
        let t = panic::catch_unwind(|| {
            O.call_once(|| {});
        });
        assert!(t.is_err());

        // we can subvert poisoning, however
        let mut called = false;
        O.call_once_force(|p| {
            called = true;
            assert!(p.poisoned())
        });
        assert!(called);

        // once any success happens, we stop propagating the poison
        O.call_once(|| {});
    }

    #[cfg(feature = "nightly")]
    #[test]
    fn wait_for_force_to_finish() {
        static O: Once = ONCE_INIT;

        // poison the once
        let t = panic::catch_unwind(|| {
            O.call_once(|| panic!());
        });
        assert!(t.is_err());

        // make sure someone's waiting inside the once via a force
        let (tx1, rx1) = channel();
        let (tx2, rx2) = channel();
        let t1 = thread::spawn(move || {
            O.call_once_force(|p| {
                assert!(p.poisoned());
                tx1.send(()).unwrap();
                rx2.recv().unwrap();
            });
        });

        rx1.recv().unwrap();

        // put another waiter on the once
        let t2 = thread::spawn(|| {
            let mut called = false;
            O.call_once(|| {
                called = true;
            });
            assert!(!called);
        });

        tx2.send(()).unwrap();

        assert!(t1.join().is_ok());
        assert!(t2.join().is_ok());

    }
}
<commit_msg>Add Once::state()<commit_after>// Copyright 2016 Amanieu d'Antras
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

#[cfg(feature = "nightly")]
use std::sync::atomic::{AtomicU8, ATOMIC_U8_INIT, Ordering, fence};
#[cfg(feature = "nightly")]
type U8 = u8;
#[cfg(not(feature = "nightly"))]
use stable::{AtomicU8, ATOMIC_U8_INIT, Ordering, fence};
#[cfg(not(feature = "nightly"))]
type U8 = usize;
use std::mem;
use parking_lot_core::{self, SpinWait, DEFAULT_PARK_TOKEN, DEFAULT_UNPARK_TOKEN};
use util::UncheckedOptionExt;

const DONE_BIT: U8 = 1;
const POISON_BIT: U8 = 2;
const LOCKED_BIT: U8 = 4;
const PARKED_BIT: U8 = 8;

/// Current state of a `Once`.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum OnceState {
    /// A closure has not been executed yet
    New,

    /// A closure was executed but panicked.
    Poisoned,

    /// A thread is currently executing a closure.
    InProgress,

    /// A closure has completed sucessfully.
    Done,
}

impl OnceState {
    /// Returns whether the associated `Once` has been poisoned.
    ///
    /// Once an initalization routine for a `Once` has panicked it will forever
    /// indicate to future forced initialization routines that it is poisoned.
    #[inline]
    pub fn poisoned(&self) -> bool {
        match *self {
            OnceState::Poisoned => true,
            _ => false,
        }
    }

    /// Returns whether the associated `Once` has successfullly executed a
    /// closure.
    ///
    /// Note that you generally need an `Acquire` barrier after checking this to
    /// ensure that operations are correctly ordered with regards to a
    /// concurrently executing closure.
    #[inline]
    pub fn done(&self) -> bool {
        match *self {
            OnceState::Done => true,
            _ => false,
        }
    }
}

/// A synchronization primitive which can be used to run a one-time
/// initialization. Useful for one-time initialization for globals, FFI or
/// related functionality.
///
/// # Differences from the standard library `Once`
///
/// - Only requires 1 byte of space, instead of 1 word.
/// - Not required to be `'static`.
/// - Relaxed memory barriers in the fast path, which can significantly improve
///   performance on some architectures.
/// - Efficient handling of micro-contention using adaptive spinning.
///
/// # Examples
///
/// ```
/// use parking_lot::{Once, ONCE_INIT};
///
/// static START: Once = ONCE_INIT;
///
/// START.call_once(|| {
///     // run initialization here
/// });
/// ```
pub struct Once(AtomicU8);

/// Initialization value for static `Once` values.
pub const ONCE_INIT: Once = Once(ATOMIC_U8_INIT);

impl Once {
    /// Creates a new `Once` value.
    #[cfg(feature = "nightly")]
    #[inline]
    pub const fn new() -> Once {
        Once(AtomicU8::new(0))
    }

    /// Creates a new `Once` value.
    #[cfg(not(feature = "nightly"))]
    #[inline]
    pub fn new() -> Once {
        Once(AtomicU8::new(0))
    }

    /// Returns the current state of this `Once`.
    #[inline]
    pub fn state(&self) -> OnceState {
        let state = self.0.load(Ordering::Relaxed);
        if state & DONE_BIT != 0 {
            OnceState::Done
        } else if state & LOCKED_BIT != 0 {
            OnceState::InProgress
        } else if state & POISON_BIT != 0 {
            OnceState::Poisoned
        } else {
            OnceState::New
        }
    }

    /// Performs an initialization routine once and only once. The given closure
    /// will be executed if this is the first time `call_once` has been called,
    /// and otherwise the routine will *not* be invoked.
    ///
    /// This method will block the calling thread if another initialization
    /// routine is currently running.
    ///
    /// When this function returns, it is guaranteed that some initialization
    /// has run and completed (it may not be the closure specified). It is also
    /// guaranteed that any memory writes performed by the executed closure can
    /// be reliably observed by other threads at this point (there is a
    /// happens-before relation between the closure and code executing after the
    /// return).
    ///
    /// # Examples
    ///
    /// ```
    /// use parking_lot::{Once, ONCE_INIT};
    ///
    /// static mut VAL: usize = 0;
    /// static INIT: Once = ONCE_INIT;
    ///
    /// // Accessing a `static mut` is unsafe much of the time, but if we do so
    /// // in a synchronized fashion (e.g. write once or read all) then we're
    /// // good to go!
    /// //
    /// // This function will only call `expensive_computation` once, and will
    /// // otherwise always return the value returned from the first invocation.
    /// fn get_cached_val() -> usize {
    ///     unsafe {
    ///         INIT.call_once(|| {
    ///             VAL = expensive_computation();
    ///         });
    ///         VAL
    ///     }
    /// }
    ///
    /// fn expensive_computation() -> usize {
    ///     // ...
    /// # 2
    /// }
    /// ```
    ///
    /// # Panics
    ///
    /// The closure `f` will only be executed once if this is called
    /// concurrently amongst many threads. If that closure panics, however, then
    /// it will *poison* this `Once` instance, causing all future invocations of
    /// `call_once` to also panic.
    #[inline]
    pub fn call_once<F>(&self, f: F)
        where F: FnOnce()
    {
        if self.0.load(Ordering::Acquire) == DONE_BIT {
            return;
        }

        let mut f = Some(f);
        self.call_once_slow(false, &mut |_| unsafe { f.take().unchecked_unwrap()() });
    }

    /// Performs the same function as `call_once` except ignores poisoning.
    ///
    /// If this `Once` has been poisoned (some initialization panicked) then
    /// this function will continue to attempt to call initialization functions
    /// until one of them doesn't panic.
    ///
    /// The closure `f` is yielded a structure which can be used to query the
    /// state of this `Once` (whether initialization has previously panicked or
    /// not).
    #[inline]
    pub fn call_once_force<F>(&self, f: F)
        where F: FnOnce(OnceState)
    {
        if self.0.load(Ordering::Acquire) == DONE_BIT {
            return;
        }

        let mut f = Some(f);
        self.call_once_slow(true,
                            &mut |state| unsafe {
                                f.take().unchecked_unwrap()(state)
                            });
    }

    // This is a non-generic function to reduce the monomorphization cost of
    // using `call_once` (this isn't exactly a trivial or small implementation).
    //
    // Additionally, this is tagged with `#[cold]` as it should indeed be cold
    // and it helps let LLVM know that calls to this function should be off the
    // fast path. Essentially, this should help generate more straight line code
    // in LLVM.
    //
    // Finally, this takes an `FnMut` instead of a `FnOnce` because there's
    // currently no way to take an `FnOnce` and call it via virtual dispatch
    // without some allocation overhead.
    #[cold]
    #[inline(never)]
    fn call_once_slow(&self, ignore_poison: bool, f: &mut FnMut(OnceState)) {
        let mut spinwait = SpinWait::new();
        let mut state = self.0.load(Ordering::Relaxed);
        loop {
            // If another thread called the closure, we're done
            if state & DONE_BIT != 0 {
                // An acquire fence is needed here since we didn't load the
                // state with Ordering::Acquire.
                fence(Ordering::Acquire);
                return;
            }

            // If the state has been poisoned and we aren't forcing, then panic
            if state & POISON_BIT != 0 && !ignore_poison {
                // Need the fence here as well for the same reason
                fence(Ordering::Acquire);
                panic!("Once instance has previously been poisoned");
            }

            // Grab the lock if it isn't locked, even if there is a queue on it.
            // We also clear the poison bit since we are going to try running
            // the closure again.
            if state & LOCKED_BIT == 0 {
                match self.0
                    .compare_exchange_weak(state,
                                           (state | LOCKED_BIT) & !POISON_BIT,
                                           Ordering::Acquire,
                                           Ordering::Relaxed) {
                    Ok(_) => break,
                    Err(x) => state = x,
                }
                continue;
            }

            // If there is no queue, try spinning a few times
            if state & PARKED_BIT == 0 && spinwait.spin() {
                state = self.0.load(Ordering::Relaxed);
                continue;
            }

            // Set the parked bit
            if state & PARKED_BIT == 0 {
                if let Err(x) = self.0.compare_exchange_weak(state,
                                                             state | PARKED_BIT,
                                                             Ordering::Relaxed,
                                                             Ordering::Relaxed) {
                    state = x;
                    continue;
                }
            }

            // Park our thread until we are woken up by the thread that owns the
            // lock.
            unsafe {
                let addr = self as *const _ as usize;
                let validate = || self.0.load(Ordering::Relaxed) == LOCKED_BIT | PARKED_BIT;
                let before_sleep = || {};
                let timed_out = |_, _| unreachable!();
                parking_lot_core::park(addr,
                                       validate,
                                       before_sleep,
                                       timed_out,
                                       DEFAULT_PARK_TOKEN,
                                       None);
            }

            // Loop back and check if the done bit was set
            spinwait.reset();
            state = self.0.load(Ordering::Relaxed);
        }

        struct PanicGuard<'a>(&'a Once);
        impl<'a> Drop for PanicGuard<'a> {
            fn drop(&mut self) {
                // Mark the state as poisoned, unlock it and unpark all threads.
                let once = self.0;
                let state = once.0.swap(POISON_BIT, Ordering::Release);
                if state & PARKED_BIT != 0 {
                    unsafe {
                        let addr = once as *const _ as usize;
                        parking_lot_core::unpark_all(addr, DEFAULT_UNPARK_TOKEN);
                    }
                }
            }
        }

        // At this point we have the lock, so run the closure. Make sure we
        // properly clean up if the closure panicks.
        let guard = PanicGuard(self);
        let once_state = if state & POISON_BIT != 0 {
            OnceState::Poisoned
        } else {
            OnceState::New
        };
        f(once_state);
        mem::forget(guard);

        // Now unlock the state, set the done bit and unpark all threads
        let state = self.0.swap(DONE_BIT, Ordering::Release);
        if state & PARKED_BIT != 0 {
            unsafe {
                let addr = self as *const _ as usize;
                parking_lot_core::unpark_all(addr, DEFAULT_UNPARK_TOKEN);
            }
        }
    }
}

impl Default for Once {
    #[inline]
    fn default() -> Once {
        Once::new()
    }
}

#[cfg(test)]
mod tests {
    #[cfg(feature = "nightly")]
    use std::panic;
    use std::sync::mpsc::channel;
    use std::thread;
    use {Once, ONCE_INIT};

    #[test]
    fn smoke_once() {
        static O: Once = ONCE_INIT;
        let mut a = 0;
        O.call_once(|| a += 1);
        assert_eq!(a, 1);
        O.call_once(|| a += 1);
        assert_eq!(a, 1);
    }

    #[test]
    fn stampede_once() {
        static O: Once = ONCE_INIT;
        static mut RUN: bool = false;

        let (tx, rx) = channel();
        for _ in 0..10 {
            let tx = tx.clone();
            thread::spawn(move || {
                for _ in 0..4 {
                    thread::yield_now()
                }
                unsafe {
                    O.call_once(|| {
                        assert!(!RUN);
                        RUN = true;
                    });
                    assert!(RUN);
                }
                tx.send(()).unwrap();
            });
        }

        unsafe {
            O.call_once(|| {
                assert!(!RUN);
                RUN = true;
            });
            assert!(RUN);
        }

        for _ in 0..10 {
            rx.recv().unwrap();
        }
    }

    #[cfg(feature = "nightly")]
    #[test]
    fn poison_bad() {
        static O: Once = ONCE_INIT;

        // poison the once
        let t = panic::catch_unwind(|| {
            O.call_once(|| panic!());
        });
        assert!(t.is_err());

        // poisoning propagates
        let t = panic::catch_unwind(|| {
            O.call_once(|| {});
        });
        assert!(t.is_err());

        // we can subvert poisoning, however
        let mut called = false;
        O.call_once_force(|p| {
            called = true;
            assert!(p.poisoned())
        });
        assert!(called);

        // once any success happens, we stop propagating the poison
        O.call_once(|| {});
    }

    #[cfg(feature = "nightly")]
    #[test]
    fn wait_for_force_to_finish() {
        static O: Once = ONCE_INIT;

        // poison the once
        let t = panic::catch_unwind(|| {
            O.call_once(|| panic!());
        });
        assert!(t.is_err());

        // make sure someone's waiting inside the once via a force
        let (tx1, rx1) = channel();
        let (tx2, rx2) = channel();
        let t1 = thread::spawn(move || {
            O.call_once_force(|p| {
                assert!(p.poisoned());
                tx1.send(()).unwrap();
                rx2.recv().unwrap();
            });
        });

        rx1.recv().unwrap();

        // put another waiter on the once
        let t2 = thread::spawn(|| {
            let mut called = false;
            O.call_once(|| {
                called = true;
            });
            assert!(!called);
        });

        tx2.send(()).unwrap();

        assert!(t1.join().is_ok());
        assert!(t2.join().is_ok());

    }
}
<|endoftext|>


<commit_before>use libc::c_uint;
use ffi::prelude::LLVMPassManagerRef;
use ffi::{core, target};
use ffi::transforms::pass_manager_builder as builder;
use ffi::transforms::pass_manager_builder::LLVMPassManagerBuilderRef;
use module::Module;
use target::TargetData;

/// Runs transformations on bitcode
pub struct PassManager {
    manager: LLVMPassManagerRef
}
native_ref!(PassManager, manager: LLVMPassManagerRef);
impl PassManager {
    /// Create a new pass manager
    pub fn new() -> PassManager {
        unsafe { core::LLVMCreatePassManager() }.into()
    }
    /// Adds target data information to a pass manage
    pub fn add_target_data(&self, data: &TargetData) {
        unsafe { target::LLVMAddTargetData(data.into(), self.into()) }
    }
    /// Initializes, executes on the provided module, and finalizes all of the passes scheduled in the pass manage
    pub fn run(&self, module: &Module) -> Result<(), ()> {
        if unsafe { core::LLVMRunPassManager(self.into(), module.into()) } == 0 {
            Ok(())
        } else {
            Err(())
        }
    }
    /// Pupulate this pass manager with the options given in the builder
    pub fn populate(&self, builder: PassManagerBuilder) {
        unsafe { builder::LLVMPassManagerBuilderPopulateModulePassManager(builder.into(), self.into()) }
    }
}
impl Drop for PassManager {
    fn drop(&mut self) {
        unsafe { core::LLVMDisposePassManager(self.into()) }
    }
}
/// Defines the options that can be passed to `PassManager`
pub struct PassManagerBuilder {
    builder: LLVMPassManagerBuilderRef
}
native_ref!(PassManagerBuilder, builder: LLVMPassManagerBuilderRef);
impl PassManagerBuilder {
    /// Create a new pass manager builder
    pub fn new() -> PassManagerBuilder {
        unsafe { builder::LLVMPassManagerBuilderCreate().into() }
    }
    /// Set the optimisation level of the pass manager
    pub fn with_opt_level(self, level: usize) -> PassManagerBuilder {
        unsafe { builder::LLVMPassManagerBuilderSetOptLevel((&self).into(), level as c_uint) };
        self
    }
    /// Set the size level of the pass manager
    pub fn with_size_level(self, size: usize) -> PassManagerBuilder {
        unsafe { builder::LLVMPassManagerBuilderSetOptLevel((&self).into(), size as c_uint) };
        self
    }
    /// Use an inliner with threshold given
    ///
    /// This threshold should be the degree to which the inlining should be done
    pub fn with_inliner(self, threshold: usize) -> PassManagerBuilder {
        unsafe { builder::LLVMPassManagerBuilderUseInlinerWithThreshold((&self).into(), threshold as c_uint) };
        self
    }
}
impl Drop for PassManagerBuilder {
    fn drop(&mut self) {
        unsafe { builder::LLVMPassManagerBuilderDispose(self.into()) }
    }
}
<commit_msg>Make documentation clearer<commit_after>use libc::c_uint;
use ffi::prelude::LLVMPassManagerRef;
use ffi::{core, target};
use ffi::transforms::pass_manager_builder as builder;
use ffi::transforms::pass_manager_builder::LLVMPassManagerBuilderRef;
use module::Module;
use target::TargetData;

/// Runs transformations on bitcode
pub struct PassManager {
    manager: LLVMPassManagerRef
}
native_ref!(PassManager, manager: LLVMPassManagerRef);
impl PassManager {
    /// Create a new pass manager
    pub fn new() -> PassManager {
        unsafe { core::LLVMCreatePassManager() }.into()
    }
    /// Adds target data information to a pass manage
    pub fn add_target_data(&self, data: &TargetData) {
        unsafe { target::LLVMAddTargetData(data.into(), self.into()) }
    }
    /// Initializes, executes on the provided module, and finalizes all of the passes scheduled in the pass manage
    pub fn run(&self, module: &Module) -> Result<(), ()> {
        if unsafe { core::LLVMRunPassManager(self.into(), module.into()) } == 0 {
            Ok(())
        } else {
            Err(())
        }
    }
    /// Pupulate this pass manager with the options given in the builder
    pub fn populate(&self, builder: PassManagerBuilder) {
        unsafe { builder::LLVMPassManagerBuilderPopulateModulePassManager(builder.into(), self.into()) }
    }
}
impl Drop for PassManager {
    fn drop(&mut self) {
        unsafe { core::LLVMDisposePassManager(self.into()) }
    }
}
/// Sets up a standard optimization sequence for languages like C and C++, allowing some APIs to customize the pass sequence in various ways
pub struct PassManagerBuilder {
    builder: LLVMPassManagerBuilderRef
}
native_ref!(PassManagerBuilder, builder: LLVMPassManagerBuilderRef);
impl PassManagerBuilder {
    /// Create a new pass manager builder
    pub fn new() -> PassManagerBuilder {
        unsafe { builder::LLVMPassManagerBuilderCreate().into() }
    }
    /// Set the optimisation level of the pass manager
    ///
    ///  0 = -O0, 1 = -O1, 2 = -O2, 3 = -O3
    pub fn with_opt_level(self, level: usize) -> PassManagerBuilder {
        unsafe { builder::LLVMPassManagerBuilderSetOptLevel((&self).into(), level as c_uint) };
        self
    }
    /// Specify how much we're optimizing for size
    ///
    ///  0 = none, 1 = -Os, 2 = -Oz
    pub fn with_size_level(self, size: usize) -> PassManagerBuilder {
        unsafe { builder::LLVMPassManagerBuilderSetOptLevel((&self).into(), size as c_uint) };
        self
    }
    /// Use an inliner with threshold given
    ///
    /// This threshold should be the degree to which the inlining should be done
    pub fn with_inliner(self, threshold: usize) -> PassManagerBuilder {
        unsafe { builder::LLVMPassManagerBuilderUseInlinerWithThreshold((&self).into(), threshold as c_uint) };
        self
    }
}
impl Drop for PassManagerBuilder {
    fn drop(&mut self) {
        unsafe { builder::LLVMPassManagerBuilderDispose(self.into()) }
    }
}
<|endoftext|>


<commit_before>use super::field::Field;

pub struct Level {
    data: Vec<Vec<Field>>,
    width: usize,
    height: usize,
}

impl Level {
    pub fn with_size(x: usize, y: usize) -> Self {
        Level {
            data: vec![vec![Field::new(0); y]; x],
            width: x,
            height: y,
        }
    }

    pub fn get_width(&self) -> usize {
        self.width
    }

    pub fn get_height(&self) -> usize {
        self.height
    }

    pub fn get_data(&mut self) -> &mut Vec<Vec<Field>> {
        &mut self.data
    }

    pub fn get_field_at(&self, x: usize, y: usize) -> &Field {
        &self.data[x][y]
    }
}

impl Clone for Level {
    fn clone(&self) -> Self {
        let mut vec = vec![vec![Field::new(0); self.height]; self.width];
        for i in 0..self.width {
            for j in 0..self.height {
                vec[i][j] = self.data[i][j].clone();
            }
        }
        Level {
            data: vec,
            width: self.width,
            height: self.height,
        }
    }
}
<commit_msg>comments level<commit_after>use super::field::Field;

pub struct Level {
    // 2D-Array to maintain objects of the level
    data: Vec<Vec<Field>>,
    width: usize,
    height: usize,
}

impl Level {
    pub fn with_size(x: usize, y: usize) -> Self {
        Level {
            // Initialize 2D-Array with empty field-objects
            data: vec![vec![Field::new(0); y]; x],
            width: x,
            height: y,
        }
    }

    pub fn get_width(&self) -> usize {
        self.width
    }

    pub fn get_height(&self) -> usize {
        self.height
    }

    pub fn get_data(&mut self) -> &mut Vec<Vec<Field>> {
        //returns reference of field-objects
        &mut self.data
    }

    pub fn get_field_at(&self, x: usize, y: usize) -> &Field {
        // returns reference of field-object at specific index
        &self.data[x][y]
    }
}

// Clone level to save resources
impl Clone for Level {
    fn clone(&self) -> Self {
        let mut vec = vec![vec![Field::new(0); self.height]; self.width];
        for i in 0..self.width {
            for j in 0..self.height {
                vec[i][j] = self.data[i][j].clone();
            }
        }
        Level {
            data: vec,
            width: self.width,
            height: self.height,
        }
    }
}
<|endoftext|>