<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#[macro_use]
extern crate clap;
#[macro_use]
extern crate derive_error;
extern crate resvg;
extern crate svgdom;
extern crate fern;
extern crate log;
extern crate time;

use std::str::FromStr;
use std::fs;
use std::fmt;
use std::path;
use std::io::{
    self,
    Write,
};

use clap::{
    App,
    Arg,
    ArgMatches,
};

use resvg::{
    FitTo,
    Options,
    NodeExt,
    RectExt,
    Render,
};
use resvg::tree::prelude::*;

use svgdom::{
    ChainedErrorExt,
    WriteBuffer,
};

struct Args {
    in_svg: path::PathBuf,
    out_png: Option<path::PathBuf>,
    backend: Box<Render>,
    #[allow(dead_code)]
    backend_name: String,
    query_all: bool,
    export_id: Option<String>,
    dump: Option<path::PathBuf>,
    pretend: bool,
    perf: bool,
}

#[derive(Error, Debug)]
enum Error {
    #[error(msg_embedded, no_from, non_std)]
    InvalidId(String),
    Resvg(resvg::Error),
    Io(io::Error),
}

fn main() {
    #[cfg(all(not(feature = "cairo-backend"), not(feature = "qt-backend")))]
    {
        eprintln!("Error: rendersvg has been build without any backend.");
        return;
    }

    if let Err(e) = process() {
        match e {
            Error::InvalidId(ref id) => {
                eprintln!("Error: Input file does not contain ID {:?}.", id);
            }
            Error::Resvg(ref e) => eprintln!("{}.", e.full_chain()),
            Error::Io(ref e) => eprintln!("Error: {}.", e),
        }

        std::process::exit(1);
    }
}

fn process() -> Result<(), Error> {
    let (args, opt) = parse_args();

    // Do not print warning during the ID querying.
    //
    // Some crates still can print to stdout/stderr, but we can't do anything about it.
    if !args.query_all {
        fern::Dispatch::new()
            .format(log_format)
            .level(log::LevelFilter::Warn)
            .chain(std::io::stderr())
            .apply().unwrap();
    }

    macro_rules! timed {
        ($name:expr, $task:expr) => { run_task(args.perf, $name, || $task) };
    }

    // Load file.
    let rtree = {
        let data = timed!("File loading", resvg::load_file(&args.in_svg))?;
        let mut dom = timed!("Parsing", resvg::parse_dom(&data))?;
        timed!("Preprocessing", resvg::preprocess_dom(&mut dom, &opt))?;
        timed!("Conversion", resvg::convert_dom_to_rtree(&dom, &opt))?
    };

    // We have to init only Qt backend.
    #[cfg(feature = "qt-backend")]
    let _resvg = timed!("Backend init", init_qt_gui(&rtree, &args));

    if args.query_all {
        query_all(&rtree, &args, &opt);
        return Ok(());
    }

    if let Some(ref dump_path) = args.dump {
        dump_svg(&rtree, dump_path)?;
    }

    if args.pretend {
        return Ok(());
    }

    // Render.
    if let Some(ref out_png) = args.out_png {
        let img = if let Some(ref id) = args.export_id {
            if let Some(node) = rtree.root().descendants().find(|n| n.svg_id() == id) {
                timed!("Rendering", args.backend.render_node_to_image(node, &opt))
            } else {
                return Err(Error::InvalidId(id.clone()));
            }
        } else {
            timed!("Rendering", args.backend.render_to_image(&rtree, &opt))
        }?;

        timed!("Saving", img.save(out_png));
    };

    Ok(())
}

// Qt backend initialization is pretty slow
// and needed only for files with text nodes.
// So we skip it file doesn't have one.
#[cfg(feature = "qt-backend")]
fn init_qt_gui(
    rtree: &tree::RenderTree,
    args: &Args,
) -> Option<resvg::InitObject> {
    if args.backend_name != "qt" {
        return None;
    }

    // Check that rtree has any text nodes.
    let has_text = rtree.root().descendants().any(|n|
        if let &tree::NodeKind::Text { .. } = n.value() { true } else { false }
    );

    if has_text {
        // Init Qt backend.
        Some(resvg::init())
    } else {
        None
    }
}

fn query_all(
    rtree: &tree::RenderTree,
    args: &Args,
    opt: &Options,
) {
    let mut count = 0;
    for node in rtree.root().descendants() {
        if rtree.is_in_defs(node) {
            continue;
        }

        if node.svg_id().is_empty() {
            continue;
        }

        count += 1;

        fn round_len(v: f64) -> f64 {
            (v * 1000.0).round() / 1000.0
        }

        if let Some(bbox) = args.backend.calc_node_bbox(node, &opt) {
            println!("{},{},{},{},{}", node.svg_id(),
                     round_len(bbox.x()), round_len(bbox.y()),
                     round_len(bbox.width()), round_len(bbox.height()));
        }
    }

    if count == 0 {
        eprintln!("Error: The file has no valid ID's.");
    }
}

fn run_task<P, T>(perf: bool, title: &str, p: P) -> T
    where P: FnOnce() -> T
{
    if perf {
        let start = time::precise_time_ns();
        let res = p();
        let end = time::precise_time_ns();
        println!("{}: {:.2}ms", title, (end - start) as f64 / 1_000_000.0);
        res
    } else {
        p()
    }
}

fn parse_args() -> (Args, Options) {
    let app = prepare_app();
    let args = match app.get_matches_safe() {
        Ok(a) => a,
        Err(mut e) => {
            // change case before printing an error
            if e.message.starts_with("error:") {
                e.message = e.message.replace("error:", "Error:");
            }
            e.exit();
        }
    };

    let app_args = fill_args(&args);
    let opt = fill_options(&args, &app_args);
    (app_args, opt)
}

fn prepare_app<'a, 'b>() -> App<'a, 'b> {
    App::new("rendersvg")
        .version(env!("CARGO_PKG_VERSION"))
        .arg(Arg::with_name("in-svg")
            .help("Input file")
            .required(true)
            .index(1)
            .validator(is_svg))
        .arg(Arg::with_name("out-png")
            .help("Output file")
            .required_unless_one(&["query-all"])
            .index(2)
            .validator(is_png))
        .arg(Arg::with_name("dpi")
            .long("dpi")
            .help("Sets the resolution [72..4000]")
            .value_name("DPI")
            .default_value("96")
            .validator(is_dpi))
        .arg(Arg::with_name("width")
            .short("w")
            .long("width")
            .value_name("LENGTH")
            .help("Sets the width in pixels")
            .conflicts_with_all(&["height", "zoom"])
            .validator(is_length))
        .arg(Arg::with_name("height")
            .short("h")
            .long("height")
            .value_name("LENGTH")
            .help("Sets the height in pixels")
            .conflicts_with_all(&["width", "zoom"])
            .validator(is_length))
        .arg(Arg::with_name("zoom")
            .short("z")
            .long("zoom")
            .value_name("ZOOM")
            .help("Zooms the image by a factor")
            .conflicts_with_all(&["width", "height"])
            .validator(is_zoom))
        .arg(Arg::with_name("background")
            .long("background")
            .value_name("COLOR")
            .help("Sets the background color")
            .validator(is_color))
        .arg(Arg::with_name("backend")
            .long("backend")
            .help("Sets the rendering backend.\nHas no effect if built with only one backend")
            .takes_value(true)
            .default_value(default_backend())
            .possible_values(&backends()))
        .arg(Arg::with_name("query-all")
            .long("query-all")
            .help("Queries all valid SVG ids with bounding boxes"))
        .arg(Arg::with_name("export-id")
            .long("export-id")
            .help("Renders an object only with a specified ID")
            .value_name("ID"))
        .arg(Arg::with_name("dump-svg")
            .long("dump-svg")
            .help("Saves a preprocessed SVG to the selected file")
            .value_name("PATH"))
        .arg(Arg::with_name("pretend")
            .long("pretend")
            .help("Does all the steps except rendering"))
        .arg(Arg::with_name("perf")
            .long("perf")
            .help("Prints performance stats"))
}

fn backends() -> Vec<&'static str> {
    let mut list = Vec::new();

    #[cfg(feature = "cairo-backend")]
    {
        list.push("cairo");
    }

    #[cfg(feature = "qt-backend")]
    {
        list.push("qt");
    }

    list
}

#[allow(unreachable_code)]
fn default_backend() -> &'static str {
    #[cfg(feature = "cairo-backend")]
    {
        return "cairo"
    }

    #[cfg(feature = "qt-backend")]
    {
        return "qt"
    }

    unreachable!();
}

// TODO: simplify is_* methods
fn is_svg(val: String) -> Result<(), String> {
    let val = val.to_lowercase();
    if val.ends_with(".svg") || val.ends_with(".svgz") {
        Ok(())
    } else {
        Err(String::from("The input file format must be SVG(Z)."))
    }
}

fn is_png(val: String) -> Result<(), String> {
    if val.ends_with(".png") || val.ends_with(".PNG") {
        Ok(())
    } else {
        Err(String::from("The output file format must be PNG."))
    }
}

fn is_dpi(val: String) -> Result<(), String> {
    let n = match val.parse::<u32>() {
        Ok(v) => v,
        Err(e) => return Err(format!("{}", e)),
    };

    if n >= 72 && n <= 4000 {
        Ok(())
    } else {
        Err(String::from("Invalid DPI value."))
    }
}

fn is_length(val: String) -> Result<(), String> {
    let n = match val.parse::<u32>() {
        Ok(v) => v,
        Err(e) => return Err(format!("{}", e)),
    };

    if n > 0 {
        Ok(())
    } else {
        Err(String::from("Invalid length value."))
    }
}

fn is_zoom(val: String) -> Result<(), String> {
    let n = match val.parse::<f32>() {
        Ok(v) => v,
        Err(e) => return Err(format!("{}", e)),
    };

    if n > 0.0 {
        Ok(())
    } else {
        Err(String::from("Invalid zoom value."))
    }
}

fn is_color(val: String) -> Result<(), String> {
    match svgdom::Color::from_str(&val) {
        Ok(_) => Ok(()),
        Err(_) => Err("Invalid color.".into()),
    }
}

fn fill_args(args: &ArgMatches) -> Args {
    let in_svg  = args.value_of("in-svg").unwrap().into();
    let out_png = if args.is_present("out-png") {
        Some(args.value_of("out-png").unwrap().into())
    } else {
        None
    };

    let dump = if args.is_present("dump-svg") {
        Some(args.value_of("dump-svg").unwrap().into())
    } else {
        None
    };

    let export_id = if args.is_present("export-id") {
        Some(args.value_of("export-id").unwrap().into())
    } else {
        None
    };

    let backend_name = args.value_of("backend").unwrap().to_string();
    let backend: Box<Render> = match backend_name.as_str() {
        #[cfg(feature = "cairo-backend")]
        "cairo" => Box::new(resvg::render_cairo::Backend),
        #[cfg(feature = "qt-backend")]
        "qt" => Box::new(resvg::render_qt::Backend),
        _ => unreachable!(),
    };

    Args {
        in_svg,
        out_png,
        backend,
        backend_name,
        query_all: args.is_present("query-all"),
        export_id,
        dump,
        pretend: args.is_present("pretend"),
        perf: args.is_present("perf"),
    }
}

fn fill_options(args: &ArgMatches, app_args: &Args) -> Options {
    let mut fit_to = FitTo::Original;
    if args.is_present("width") {
        fit_to = FitTo::Width(value_t!(args.value_of("width"), u32).unwrap());
    } else if args.is_present("height") {
        fit_to = FitTo::Height(value_t!(args.value_of("height"), u32).unwrap());
    } else if args.is_present("zoom") {
        fit_to = FitTo::Zoom(value_t!(args.value_of("zoom"), f32).unwrap());
    }

    let mut background = None;
    if args.is_present("background") {
        let s = args.value_of("background").unwrap();
        background = Some(svgdom::Color::from_str(s).unwrap());
    }

    // We don't have to keep named groups when we don't need them
    // because it will slow down rendering.
    let keep_named_groups = app_args.query_all || app_args.export_id.is_some();

    Options {
        path: Some(args.value_of("in-svg").unwrap().into()),
        dpi: value_t!(args.value_of("dpi"), u16).unwrap() as f64,
        fit_to,
        background,
        keep_named_groups,
    }
}

fn dump_svg(rtree: &tree::RenderTree, path: &path::Path) -> Result<(), io::Error> {
    let mut f = fs::File::create(path)?;

    let opt = svgdom::WriteOptions {
        indent: svgdom::Indent::Spaces(2),
        attributes_indent: svgdom::Indent::Spaces(3),
        write_hidden_attributes: true,
        attributes_order: svgdom::AttributesOrder::Specification,
        .. svgdom::WriteOptions::default()
    };

    let svgdoc = rtree.to_svgdom();

    let mut out = Vec::new();
    svgdoc.write_buf_opt(&opt, &mut out);
    f.write_all(&out)?;

    Ok(())
}

fn log_format(
    out: fern::FormatCallback,
    message: &fmt::Arguments,
    record: &log::Record,
) {
    let lvl = match record.level() {
        log::Level::Error => "Error",
        log::Level::Warn  => "Warning",
        log::Level::Info  => "Info",
        log::Level::Debug => "Debug",
        log::Level::Trace => "Trace",
    };

    out.finish(format_args!(
        "{} (in {}:{}): {}",
        lvl,
        record.target(),
        record.line().unwrap_or(0),
        message
    ))
}
<commit_msg>Added --quiet flag for rendersvg.<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#[macro_use]
extern crate clap;
#[macro_use]
extern crate derive_error;
extern crate resvg;
extern crate svgdom;
extern crate fern;
extern crate log;
extern crate time;

use std::str::FromStr;
use std::fs;
use std::fmt;
use std::path;
use std::io::{
    self,
    Write,
};

use clap::{
    App,
    Arg,
    ArgMatches,
};

use resvg::{
    FitTo,
    Options,
    NodeExt,
    RectExt,
    Render,
};
use resvg::tree::prelude::*;

use svgdom::{
    ChainedErrorExt,
    WriteBuffer,
};

struct Args {
    in_svg: path::PathBuf,
    out_png: Option<path::PathBuf>,
    backend: Box<Render>,
    #[allow(dead_code)]
    backend_name: String,
    query_all: bool,
    export_id: Option<String>,
    dump: Option<path::PathBuf>,
    pretend: bool,
    perf: bool,
    quiet: bool,
}

#[derive(Error, Debug)]
enum Error {
    #[error(msg_embedded, no_from, non_std)]
    InvalidId(String),
    Resvg(resvg::Error),
    Io(io::Error),
}

fn main() {
    #[cfg(all(not(feature = "cairo-backend"), not(feature = "qt-backend")))]
    {
        eprintln!("Error: rendersvg has been build without any backend.");
        return;
    }

    if let Err(e) = process() {
        match e {
            Error::InvalidId(ref id) => {
                eprintln!("Error: Input file does not contain ID {:?}.", id);
            }
            Error::Resvg(ref e) => eprintln!("{}.", e.full_chain()),
            Error::Io(ref e) => eprintln!("Error: {}.", e),
        }

        std::process::exit(1);
    }
}

fn process() -> Result<(), Error> {
    let (args, opt) = parse_args();

    // Do not print warning during the ID querying.
    //
    // Some crates still can print to stdout/stderr, but we can't do anything about it.
    if !(args.query_all || args.quiet) {
        fern::Dispatch::new()
            .format(log_format)
            .level(log::LevelFilter::Warn)
            .chain(std::io::stderr())
            .apply().unwrap();
    }

    macro_rules! timed {
        ($name:expr, $task:expr) => { run_task(args.perf, $name, || $task) };
    }

    // Load file.
    let rtree = {
        let data = timed!("File loading", resvg::load_file(&args.in_svg))?;
        let mut dom = timed!("Parsing", resvg::parse_dom(&data))?;
        timed!("Preprocessing", resvg::preprocess_dom(&mut dom, &opt))?;
        timed!("Conversion", resvg::convert_dom_to_rtree(&dom, &opt))?
    };

    // We have to init only Qt backend.
    #[cfg(feature = "qt-backend")]
    let _resvg = timed!("Backend init", init_qt_gui(&rtree, &args));

    if args.query_all {
        query_all(&rtree, &args, &opt);
        return Ok(());
    }

    if let Some(ref dump_path) = args.dump {
        dump_svg(&rtree, dump_path)?;
    }

    if args.pretend {
        return Ok(());
    }

    // Render.
    if let Some(ref out_png) = args.out_png {
        let img = if let Some(ref id) = args.export_id {
            if let Some(node) = rtree.root().descendants().find(|n| n.svg_id() == id) {
                timed!("Rendering", args.backend.render_node_to_image(node, &opt))
            } else {
                return Err(Error::InvalidId(id.clone()));
            }
        } else {
            timed!("Rendering", args.backend.render_to_image(&rtree, &opt))
        }?;

        timed!("Saving", img.save(out_png));
    };

    Ok(())
}

// Qt backend initialization is pretty slow
// and needed only for files with text nodes.
// So we skip it file doesn't have one.
#[cfg(feature = "qt-backend")]
fn init_qt_gui(
    rtree: &tree::RenderTree,
    args: &Args,
) -> Option<resvg::InitObject> {
    if args.backend_name != "qt" {
        return None;
    }

    // Check that rtree has any text nodes.
    let has_text = rtree.root().descendants().any(|n|
        if let &tree::NodeKind::Text { .. } = n.value() { true } else { false }
    );

    if has_text {
        // Init Qt backend.
        Some(resvg::init())
    } else {
        None
    }
}

fn query_all(
    rtree: &tree::RenderTree,
    args: &Args,
    opt: &Options,
) {
    let mut count = 0;
    for node in rtree.root().descendants() {
        if rtree.is_in_defs(node) {
            continue;
        }

        if node.svg_id().is_empty() {
            continue;
        }

        count += 1;

        fn round_len(v: f64) -> f64 {
            (v * 1000.0).round() / 1000.0
        }

        if let Some(bbox) = args.backend.calc_node_bbox(node, &opt) {
            println!("{},{},{},{},{}", node.svg_id(),
                     round_len(bbox.x()), round_len(bbox.y()),
                     round_len(bbox.width()), round_len(bbox.height()));
        }
    }

    if count == 0 {
        eprintln!("Error: The file has no valid ID's.");
    }
}

fn run_task<P, T>(perf: bool, title: &str, p: P) -> T
    where P: FnOnce() -> T
{
    if perf {
        let start = time::precise_time_ns();
        let res = p();
        let end = time::precise_time_ns();
        println!("{}: {:.2}ms", title, (end - start) as f64 / 1_000_000.0);
        res
    } else {
        p()
    }
}

fn parse_args() -> (Args, Options) {
    let app = prepare_app();
    let args = match app.get_matches_safe() {
        Ok(a) => a,
        Err(mut e) => {
            // change case before printing an error
            if e.message.starts_with("error:") {
                e.message = e.message.replace("error:", "Error:");
            }
            e.exit();
        }
    };

    let app_args = fill_args(&args);
    let opt = fill_options(&args, &app_args);
    (app_args, opt)
}

fn prepare_app<'a, 'b>() -> App<'a, 'b> {
    App::new("rendersvg")
        .version(env!("CARGO_PKG_VERSION"))
        .arg(Arg::with_name("in-svg")
            .help("Input file")
            .required(true)
            .index(1)
            .validator(is_svg))
        .arg(Arg::with_name("out-png")
            .help("Output file")
            .required_unless_one(&["query-all"])
            .index(2)
            .validator(is_png))
        .arg(Arg::with_name("dpi")
            .long("dpi")
            .help("Sets the resolution [72..4000]")
            .value_name("DPI")
            .default_value("96")
            .validator(is_dpi))
        .arg(Arg::with_name("width")
            .short("w")
            .long("width")
            .value_name("LENGTH")
            .help("Sets the width in pixels")
            .conflicts_with_all(&["height", "zoom"])
            .validator(is_length))
        .arg(Arg::with_name("height")
            .short("h")
            .long("height")
            .value_name("LENGTH")
            .help("Sets the height in pixels")
            .conflicts_with_all(&["width", "zoom"])
            .validator(is_length))
        .arg(Arg::with_name("zoom")
            .short("z")
            .long("zoom")
            .value_name("ZOOM")
            .help("Zooms the image by a factor")
            .conflicts_with_all(&["width", "height"])
            .validator(is_zoom))
        .arg(Arg::with_name("background")
            .long("background")
            .value_name("COLOR")
            .help("Sets the background color")
            .validator(is_color))
        .arg(Arg::with_name("backend")
            .long("backend")
            .help("Sets the rendering backend.\nHas no effect if built with only one backend")
            .takes_value(true)
            .default_value(default_backend())
            .possible_values(&backends()))
        .arg(Arg::with_name("query-all")
            .long("query-all")
            .help("Queries all valid SVG ids with bounding boxes"))
        .arg(Arg::with_name("export-id")
            .long("export-id")
            .help("Renders an object only with a specified ID")
            .value_name("ID"))
        .arg(Arg::with_name("dump-svg")
            .long("dump-svg")
            .help("Saves a preprocessed SVG to the selected file")
            .value_name("PATH"))
        .arg(Arg::with_name("pretend")
            .long("pretend")
            .help("Does all the steps except rendering"))
        .arg(Arg::with_name("perf")
            .long("perf")
            .help("Prints performance stats"))
        .arg(Arg::with_name("quiet")
            .long("quiet")
            .help("Disables warnings"))
}

fn backends() -> Vec<&'static str> {
    let mut list = Vec::new();

    #[cfg(feature = "cairo-backend")]
    {
        list.push("cairo");
    }

    #[cfg(feature = "qt-backend")]
    {
        list.push("qt");
    }

    list
}

#[allow(unreachable_code)]
fn default_backend() -> &'static str {
    #[cfg(feature = "cairo-backend")]
    {
        return "cairo"
    }

    #[cfg(feature = "qt-backend")]
    {
        return "qt"
    }

    unreachable!();
}

// TODO: simplify is_* methods
fn is_svg(val: String) -> Result<(), String> {
    let val = val.to_lowercase();
    if val.ends_with(".svg") || val.ends_with(".svgz") {
        Ok(())
    } else {
        Err(String::from("The input file format must be SVG(Z)."))
    }
}

fn is_png(val: String) -> Result<(), String> {
    if val.ends_with(".png") || val.ends_with(".PNG") {
        Ok(())
    } else {
        Err(String::from("The output file format must be PNG."))
    }
}

fn is_dpi(val: String) -> Result<(), String> {
    let n = match val.parse::<u32>() {
        Ok(v) => v,
        Err(e) => return Err(format!("{}", e)),
    };

    if n >= 72 && n <= 4000 {
        Ok(())
    } else {
        Err(String::from("Invalid DPI value."))
    }
}

fn is_length(val: String) -> Result<(), String> {
    let n = match val.parse::<u32>() {
        Ok(v) => v,
        Err(e) => return Err(format!("{}", e)),
    };

    if n > 0 {
        Ok(())
    } else {
        Err(String::from("Invalid length value."))
    }
}

fn is_zoom(val: String) -> Result<(), String> {
    let n = match val.parse::<f32>() {
        Ok(v) => v,
        Err(e) => return Err(format!("{}", e)),
    };

    if n > 0.0 {
        Ok(())
    } else {
        Err(String::from("Invalid zoom value."))
    }
}

fn is_color(val: String) -> Result<(), String> {
    match svgdom::Color::from_str(&val) {
        Ok(_) => Ok(()),
        Err(_) => Err("Invalid color.".into()),
    }
}

fn fill_args(args: &ArgMatches) -> Args {
    let in_svg  = args.value_of("in-svg").unwrap().into();
    let out_png = if args.is_present("out-png") {
        Some(args.value_of("out-png").unwrap().into())
    } else {
        None
    };

    let dump = if args.is_present("dump-svg") {
        Some(args.value_of("dump-svg").unwrap().into())
    } else {
        None
    };

    let export_id = if args.is_present("export-id") {
        Some(args.value_of("export-id").unwrap().into())
    } else {
        None
    };

    let backend_name = args.value_of("backend").unwrap().to_string();
    let backend: Box<Render> = match backend_name.as_str() {
        #[cfg(feature = "cairo-backend")]
        "cairo" => Box::new(resvg::render_cairo::Backend),
        #[cfg(feature = "qt-backend")]
        "qt" => Box::new(resvg::render_qt::Backend),
        _ => unreachable!(),
    };

    Args {
        in_svg,
        out_png,
        backend,
        backend_name,
        query_all: args.is_present("query-all"),
        export_id,
        dump,
        pretend: args.is_present("pretend"),
        perf: args.is_present("perf"),
        quiet: args.is_present("quiet"),
    }
}

fn fill_options(args: &ArgMatches, app_args: &Args) -> Options {
    let mut fit_to = FitTo::Original;
    if args.is_present("width") {
        fit_to = FitTo::Width(value_t!(args.value_of("width"), u32).unwrap());
    } else if args.is_present("height") {
        fit_to = FitTo::Height(value_t!(args.value_of("height"), u32).unwrap());
    } else if args.is_present("zoom") {
        fit_to = FitTo::Zoom(value_t!(args.value_of("zoom"), f32).unwrap());
    }

    let mut background = None;
    if args.is_present("background") {
        let s = args.value_of("background").unwrap();
        background = Some(svgdom::Color::from_str(s).unwrap());
    }

    // We don't have to keep named groups when we don't need them
    // because it will slow down rendering.
    let keep_named_groups = app_args.query_all || app_args.export_id.is_some();

    Options {
        path: Some(args.value_of("in-svg").unwrap().into()),
        dpi: value_t!(args.value_of("dpi"), u16).unwrap() as f64,
        fit_to,
        background,
        keep_named_groups,
    }
}

fn dump_svg(rtree: &tree::RenderTree, path: &path::Path) -> Result<(), io::Error> {
    let mut f = fs::File::create(path)?;

    let opt = svgdom::WriteOptions {
        indent: svgdom::Indent::Spaces(2),
        attributes_indent: svgdom::Indent::Spaces(3),
        write_hidden_attributes: true,
        attributes_order: svgdom::AttributesOrder::Specification,
        .. svgdom::WriteOptions::default()
    };

    let svgdoc = rtree.to_svgdom();

    let mut out = Vec::new();
    svgdoc.write_buf_opt(&opt, &mut out);
    f.write_all(&out)?;

    Ok(())
}

fn log_format(
    out: fern::FormatCallback,
    message: &fmt::Arguments,
    record: &log::Record,
) {
    let lvl = match record.level() {
        log::Level::Error => "Error",
        log::Level::Warn  => "Warning",
        log::Level::Info  => "Info",
        log::Level::Debug => "Debug",
        log::Level::Trace => "Trace",
    };

    out.finish(format_args!(
        "{} (in {}:{}): {}",
        lvl,
        record.target(),
        record.line().unwrap_or(0),
        message
    ))
}
<|endoftext|>


<commit_before>// compile-flags: -Zunleash-the-miri-inside-of-you
// ignore-x86 FIXME: missing sysroot spans (#53081)
#![deny(const_err)]

use std::mem::ManuallyDrop;

fn main() {}

static TEST_OK: () = {
    let v: Vec<i32> = Vec::new();
    let _v = ManuallyDrop::new(v);
};

// Make sure we catch executing bad drop functions.
// The actual error is located in `real_drop_in_place` so we can't capture it with the
// error annotations here.
static TEST_BAD: () = {
    let _v: Vec<i32> = Vec::new();
    //~^ WARN skipping const check
};
<commit_msg>use error-pattern<commit_after>// compile-flags: -Zunleash-the-miri-inside-of-you
// ignore-x86 FIXME: missing sysroot spans (#53081)
// error-pattern: calling non-const function `<std::vec::Vec<i32> as std::ops::Drop>::drop`
#![deny(const_err)]

use std::mem::ManuallyDrop;

fn main() {}

static TEST_OK: () = {
    let v: Vec<i32> = Vec::new();
    let _v = ManuallyDrop::new(v);
};

// Make sure we catch executing bad drop functions.
// The actual error is tested by the error-pattern above.
static TEST_BAD: () = {
    let _v: Vec<i32> = Vec::new();
    //~^ WARN skipping const check
};
<|endoftext|>


<commit_before>use std::cmp::Ordering::*;

#[derive(Debug)]
pub struct BST<T> {
    nodes: Vec<Node<T>>,
    root: Option<Ptr>,
}

#[derive(Debug, Clone, Copy)]
struct Ptr(usize);

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
enum Color {Red, Black}

#[derive(Debug)]
struct Node<T> {
    elem: T,
    color: Color,
    left: Option<Ptr>,
    right: Option<Ptr>,
}

impl<T: Ord> Node<T> {
    fn new(elem: T, color: Color) -> Self {
        Node { elem: elem, color: color, left: None, right: None }
    }
}

impl<T: Ord> BST<T> {
    fn deref(&self, i: &Ptr) -> &Node<T> {
        &self.nodes[i.0]
    }

    fn deref_mut(&mut self, i: &Ptr) -> &mut Node<T> {
        &mut self.nodes[i.0]
    }

    pub fn new() -> Self {
        BST{ nodes: Vec::new(), root: None }
    }

    pub fn singleton(elem: T) -> Self {
        BST{ nodes: vec![Node::new(elem, Color::Black)], root: Some(Ptr(0))}
    }

    fn member_impl(&self, ptr: &Option<Ptr>, elem: &T) -> bool {
        match *ptr {
            None => false,
            Some(ref ptr) => {
                let node = self.deref(ptr);
                match node.elem.cmp(elem) {
                    Less => self.member_impl(&node.right, elem),
                    Greater => self.member_impl(&node.left, elem),
                    Equal => true,
                }
            }
        }
    }

    pub fn member(&self, elem: &T) -> bool {
        self.member_impl(&self.root, elem)
    }

    fn is_red(&self, ptr: &Option<Ptr>) -> bool {
        ptr.as_ref().map_or(false, |p| self.deref(p).color == Color::Red)
    }

    fn rotate_left(&mut self, h: Ptr) -> Ptr {
        let x : Ptr = {self.deref(&h).right.expect("rotate left on node whose left child is nil")};
        self.deref_mut(&h).right = {self.deref(&x).left};
        self.deref_mut(&x).left = Some(h);
        self.deref_mut(&x).color = {self.deref(&h).color};
        self.deref_mut(&h).color = Color::Red;
        x
        // Note to self: the braces on the right of the assignment are to limit
        // the scope of the immutable borrow, because we are immediately
        // borrowing again mutably.
    }

    fn rotate_right(&mut self, h: Ptr) -> Ptr {
        let x : Ptr = {self.deref(&h).left.expect("rotate right on node whose left child is nil")};
        self.deref_mut(&h).left = {self.deref(&x).right};
        self.deref_mut(&x).right = Some(h);
        self.deref_mut(&x).color = {self.deref(&h).color};
        self.deref_mut(&h).color = Color::Red;
        x
    }

    fn move_red_up(&mut self, h: Ptr) {
        self.deref_mut(&h).color = Color::Red;
        let left : Ptr = {self.deref(&h).left.expect("move red up on node whose left child is nil")};
        self.deref_mut(&left).color = Color::Black;
        let right: Ptr = {self.deref(&h).right.expect("move red up on node whose right child is nil")};
        self.deref_mut(&right).color = Color::Black;
    }

    fn insert_impl(&mut self, node: Option<Ptr>, elem: T) -> Ptr {
        match node {
            None => {
                self.nodes.push(Node::new(elem, Color::Red));
                Ptr(self.nodes.len() - 1)
            },
            Some(mut node) => {
                match self.deref(&node).elem.cmp(&elem) {
                    Less => {
                        let right : Option<Ptr> = self.deref(&node).right;
                        let new_right : Ptr = self.insert_impl(right, elem);
                        self.deref_mut(&node).right = Some(new_right);
                    },
                    Greater => {
                        let left : Option<Ptr> = self.deref(&node).left;
                        let new_left : Ptr = self.insert_impl(left, elem);
                        self.deref_mut(&node).left = Some(new_left);
                    },
                    Equal => self.deref_mut(&node).elem = elem,
                }

                if self.is_red(&self.deref(&node).right) && !self.is_red(&self.deref(&node).left) {
                    node = self.rotate_left(node);
                }
                if self.is_red(&self.deref(&node).left) && self.is_red(&self.deref(&self.deref(&node).left.unwrap()).left) {
                    node = self.rotate_right(node);
                }
                if self.is_red(&self.deref(&node).left) && self.is_red(&self.deref(&node).right) {
                    self.move_red_up(node);
                }

                node
            }
        }
    }

    pub fn insert(&mut self, elem: T) {
        let old_root : Option<Ptr> = self.root;
        let new_root : Ptr = self.insert_impl(old_root, elem);
        self.root = Some(new_root);
        self.deref_mut(&new_root).color = Color::Black;
    }

    fn print_structure_inner(&self, node: Option<Ptr>) {
        match node {
            None => print!("[missing]"),
            Some(node_id) => {
                print!("{{ node ");
                let node = self.deref(&node_id);
                if let Color::Red = node.color {
                    print!("[draw=red]");
                }
                print!("{{{:?}}} ", node_id.0); // Prints order of insertion
                if let Color::Red = node.color {
                    print!("edge from parent[red]");
                }
                print!(" child ");
                self.print_structure_inner(node.left);
                print!(" child ");
                self.print_structure_inner(node.right);
                print!(" }}");
            }
        }
    }

    pub fn print_structure(&self) {
        match self.root {
            None => (),
            Some(ref node_id) => {
                println!("%% Put these in your preamble\n\
                          \\usepackage{{tikz}}\n\
                          \\usetikzlibrary{{graphdrawing}}\n\
                          \\usegdlibrary{{trees}}\n\
                          \\definecolor{{red}}{{RGB}}{{171,50,37}}\n\n\
                          %% Put these in the document body\n\
                          \\tikz [binary tree layout, nodes={{draw,circle}}, font=\\sffamily, semithick] \
                          \\node");
                let node = self.deref(&node_id);
                print!("{{{:?}}} child ", node_id.0); // Prints order of insertion
                self.print_structure_inner(node.left);
                print!(" child ");
                self.print_structure_inner(node.right);
                println!(";");
            }
        }
    }
}

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

    #[test]
    fn it_works() {
        let e: BST<i32> = BST::new();
        let s = BST::singleton(2);

        assert_eq!(false, e.member(&1));
        assert_eq!(false, e.member(&2));
        assert_eq!(false, e.member(&3));

        assert_eq!(false, s.member(&1));
        assert_eq!(true, s.member(&2));
        assert_eq!(false, s.member(&3));

        let mut s = s;
        s.insert(1);
        assert_eq!(true, s.member(&1));
        assert_eq!(true, s.member(&2));
        assert_eq!(false, s.member(&3));

        s.insert(4);
        assert_eq!(true, s.member(&1));
        assert_eq!(true, s.member(&2));
        assert_eq!(false, s.member(&3));
        assert_eq!(true, s.member(&4));

        {
            let mut thousand : BST<i32> = BST::new();
            for i in 0..1000 {
                thousand.insert(i);
            }
            for i in 0..1000 {
                assert_eq!(true, thousand.member(&i));
            }
            assert_eq!(false, thousand.member(&1000));
        }

        {
            let mut thousand : BST<i32> = BST::new();
            for i in 0..1000 {
                if i % 2 == 0 {
                    thousand.insert(i);
                }
            }
            for i in 0..1000 {
                assert_eq!(i % 2 == 0, thousand.member(&i));
            }
            for i in 0..1000 {
                if i % 2 == 1 {
                    thousand.insert(i);
                }
            }
            for i in 0..1000 {
                assert_eq!(true, thousand.member(&i));
            }
        }

        {
            let mut ex : BST<i32> = BST::new();
            for c in 0..64 {
                ex.insert(c);
                ex.print_structure();
                println!("");
            }
        }

        {
            let mut ex : BST<i32> = BST::new();
            let v: [i32; 20] = [14, 9, 12, 6, 2, 10, 1, 18, 16, 5, 8, 17, 13, 3, 11, 15, 7, 19, 4, 20];
            for c in &v {
                ex.insert(*c);
                ex.print_structure();
                println!("");
            }
        }
    }
}
<commit_msg>Remove unnecessary Eq trait on Color<commit_after>use std::cmp::Ordering::*;

#[derive(Debug)]
pub struct BST<T> {
    nodes: Vec<Node<T>>,
    root: Option<Ptr>,
}

#[derive(Debug, Clone, Copy)]
struct Ptr(usize);

#[derive(Debug, Clone, Copy)]
enum Color {Red, Black}

#[derive(Debug)]
struct Node<T> {
    elem: T,
    color: Color,
    left: Option<Ptr>,
    right: Option<Ptr>,
}

impl<T: Ord> Node<T> {
    fn new(elem: T, color: Color) -> Self {
        Node { elem: elem, color: color, left: None, right: None }
    }
}

impl<T: Ord> BST<T> {
    fn deref(&self, i: &Ptr) -> &Node<T> {
        &self.nodes[i.0]
    }

    fn deref_mut(&mut self, i: &Ptr) -> &mut Node<T> {
        &mut self.nodes[i.0]
    }

    pub fn new() -> Self {
        BST{ nodes: Vec::new(), root: None }
    }

    pub fn singleton(elem: T) -> Self {
        BST{ nodes: vec![Node::new(elem, Color::Black)], root: Some(Ptr(0))}
    }

    fn member_impl(&self, ptr: &Option<Ptr>, elem: &T) -> bool {
        match *ptr {
            None => false,
            Some(ref ptr) => {
                let node = self.deref(ptr);
                match node.elem.cmp(elem) {
                    Less => self.member_impl(&node.right, elem),
                    Greater => self.member_impl(&node.left, elem),
                    Equal => true,
                }
            }
        }
    }

    pub fn member(&self, elem: &T) -> bool {
        self.member_impl(&self.root, elem)
    }

    fn is_red(&self, ptr: &Option<Ptr>) -> bool {
        ptr.as_ref().map_or(false, |p| if let Color::Red = self.deref(p).color { true } else { false })
    }

    fn rotate_left(&mut self, h: Ptr) -> Ptr {
        let x : Ptr = {self.deref(&h).right.expect("rotate left on node whose left child is nil")};
        self.deref_mut(&h).right = {self.deref(&x).left};
        self.deref_mut(&x).left = Some(h);
        self.deref_mut(&x).color = {self.deref(&h).color};
        self.deref_mut(&h).color = Color::Red;
        x
        // Note to self: the braces on the right of the assignment are to limit
        // the scope of the immutable borrow, because we are immediately
        // borrowing again mutably.
    }

    fn rotate_right(&mut self, h: Ptr) -> Ptr {
        let x : Ptr = {self.deref(&h).left.expect("rotate right on node whose left child is nil")};
        self.deref_mut(&h).left = {self.deref(&x).right};
        self.deref_mut(&x).right = Some(h);
        self.deref_mut(&x).color = {self.deref(&h).color};
        self.deref_mut(&h).color = Color::Red;
        x
    }

    fn move_red_up(&mut self, h: Ptr) {
        self.deref_mut(&h).color = Color::Red;
        let left : Ptr = {self.deref(&h).left.expect("move red up on node whose left child is nil")};
        self.deref_mut(&left).color = Color::Black;
        let right: Ptr = {self.deref(&h).right.expect("move red up on node whose right child is nil")};
        self.deref_mut(&right).color = Color::Black;
    }

    fn insert_impl(&mut self, node: Option<Ptr>, elem: T) -> Ptr {
        match node {
            None => {
                self.nodes.push(Node::new(elem, Color::Red));
                Ptr(self.nodes.len() - 1)
            },
            Some(mut node) => {
                match self.deref(&node).elem.cmp(&elem) {
                    Less => {
                        let right : Option<Ptr> = self.deref(&node).right;
                        let new_right : Ptr = self.insert_impl(right, elem);
                        self.deref_mut(&node).right = Some(new_right);
                    },
                    Greater => {
                        let left : Option<Ptr> = self.deref(&node).left;
                        let new_left : Ptr = self.insert_impl(left, elem);
                        self.deref_mut(&node).left = Some(new_left);
                    },
                    Equal => self.deref_mut(&node).elem = elem,
                }

                if self.is_red(&self.deref(&node).right) && !self.is_red(&self.deref(&node).left) {
                    node = self.rotate_left(node);
                }
                if self.is_red(&self.deref(&node).left) && self.is_red(&self.deref(&self.deref(&node).left.unwrap()).left) {
                    node = self.rotate_right(node);
                }
                if self.is_red(&self.deref(&node).left) && self.is_red(&self.deref(&node).right) {
                    self.move_red_up(node);
                }

                node
            }
        }
    }

    pub fn insert(&mut self, elem: T) {
        let old_root : Option<Ptr> = self.root;
        let new_root : Ptr = self.insert_impl(old_root, elem);
        self.root = Some(new_root);
        self.deref_mut(&new_root).color = Color::Black;
    }

    fn print_structure_inner(&self, node: Option<Ptr>) {
        match node {
            None => print!("[missing]"),
            Some(node_id) => {
                print!("{{ node ");
                let node = self.deref(&node_id);
                if let Color::Red = node.color {
                    print!("[draw=red]");
                }
                print!("{{{:?}}} ", node_id.0); // Prints order of insertion
                if let Color::Red = node.color {
                    print!("edge from parent[red]");
                }
                print!(" child ");
                self.print_structure_inner(node.left);
                print!(" child ");
                self.print_structure_inner(node.right);
                print!(" }}");
            }
        }
    }

    pub fn print_structure(&self) {
        match self.root {
            None => (),
            Some(ref node_id) => {
                println!("%% Put these in your preamble\n\
                          \\usepackage{{tikz}}\n\
                          \\usetikzlibrary{{graphdrawing}}\n\
                          \\usegdlibrary{{trees}}\n\
                          \\definecolor{{red}}{{RGB}}{{171,50,37}}\n\n\
                          %% Put these in the document body\n\
                          \\tikz [binary tree layout, nodes={{draw,circle}}, font=\\sffamily, semithick] \
                          \\node");
                let node = self.deref(&node_id);
                print!("{{{:?}}} child ", node_id.0); // Prints order of insertion
                self.print_structure_inner(node.left);
                print!(" child ");
                self.print_structure_inner(node.right);
                println!(";");
            }
        }
    }
}

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

    #[test]
    fn it_works() {
        let e: BST<i32> = BST::new();
        let s = BST::singleton(2);

        assert_eq!(false, e.member(&1));
        assert_eq!(false, e.member(&2));
        assert_eq!(false, e.member(&3));

        assert_eq!(false, s.member(&1));
        assert_eq!(true, s.member(&2));
        assert_eq!(false, s.member(&3));

        let mut s = s;
        s.insert(1);
        assert_eq!(true, s.member(&1));
        assert_eq!(true, s.member(&2));
        assert_eq!(false, s.member(&3));

        s.insert(4);
        assert_eq!(true, s.member(&1));
        assert_eq!(true, s.member(&2));
        assert_eq!(false, s.member(&3));
        assert_eq!(true, s.member(&4));

        {
            let mut thousand : BST<i32> = BST::new();
            for i in 0..1000 {
                thousand.insert(i);
            }
            for i in 0..1000 {
                assert_eq!(true, thousand.member(&i));
            }
            assert_eq!(false, thousand.member(&1000));
        }

        {
            let mut thousand : BST<i32> = BST::new();
            for i in 0..1000 {
                if i % 2 == 0 {
                    thousand.insert(i);
                }
            }
            for i in 0..1000 {
                assert_eq!(i % 2 == 0, thousand.member(&i));
            }
            for i in 0..1000 {
                if i % 2 == 1 {
                    thousand.insert(i);
                }
            }
            for i in 0..1000 {
                assert_eq!(true, thousand.member(&i));
            }
        }

        {
            let mut ex : BST<i32> = BST::new();
            for c in 0..64 {
                ex.insert(c);
                ex.print_structure();
                println!("");
            }
        }

        {
            let mut ex : BST<i32> = BST::new();
            let v: [i32; 20] = [14, 9, 12, 6, 2, 10, 1, 18, 16, 5, 8, 17, 13, 3, 11, 15, 7, 19, 4, 20];
            for c in &v {
                ex.insert(*c);
                ex.print_structure();
                println!("");
            }
        }
    }
}
<|endoftext|>


<commit_before>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use std::ops::{Range, Index};

/// Implementation of a `Stack` which maintains an log of `StackOp`s in order to rewind the stack
/// to a previous state.
#[derive(Debug)]
pub struct Stack<T: Clone> {
    ops: Vec<StackOp<T>>,
    cache: Vec<T>,
    snapshots: Vec<usize>
}

impl<T: Clone> Stack<T> {
    /// Creates a new `Stack`.
    pub fn new() -> Self {
        Stack {
            ops: vec![],
            cache: vec![],
            snapshots: vec![]
        }
    }

    /// Returns `true` if the stack is currently empty.
    #[allow(dead_code)]
    pub fn is_empty(&self) -> bool {
        self.cache.is_empty()
    }

    /// Returns the top-most `&T` in the `Stack`.
    pub fn peek(&self) -> Option<&T> {
        self.cache.last()
    }

    /// Pushes a `T` onto the `Stack`.
    pub fn push(&mut self, elem: T) {
        self.ops.push(StackOp::Push(elem.clone()));
        self.cache.push(elem);
    }

    /// Pops the top-most `T` from the `Stack`.
    pub fn pop(&mut self) -> Option<T> {
        let popped = self.cache.pop();
        if let Some(ref val) = popped {
            self.ops.push(StackOp::Pop(val.clone()));
        }
        popped
    }

    /// Returns an iterator to the current state of the cache in lifo order (top to bottom).
    #[allow(dead_code)]
    pub fn iter(&self) -> impl Iterator<Item = &T> {
        self.cache.iter().rev()
    }

    /// Returns the size of the stack
    pub fn len(&self) -> usize {
        self.cache.len()
    }

    /// Takes a snapshot of the current `Stack`.
    pub fn snapshot(&mut self) {
        self.snapshots.push(self.ops.len());
    }

    /// Rewinds the `Stack` to the most recent `snapshot()`. If no `snapshot()` has been taken, this
    /// function return the stack to its initial state.
    pub fn restore(&mut self) {
        match self.snapshots.pop() {
            Some(ops_index) => {
                self.rewind_to(ops_index);
                self.ops.truncate(ops_index);
            },
            None => {
                self.cache.clear();
                self.ops.clear();
            }
        }
    }

    // Rewind the stack to a particular index
    fn rewind_to(&mut self, index: usize) {
        let ops_to_rewind = &self.ops[index..];
        for op in ops_to_rewind.iter().rev() {
            match *op {
                StackOp::Push(_) => {
                    self.cache.pop();
                }
                StackOp::Pop(ref elem) => {
                    self.cache.push(elem.clone());
                }
            }
        }
    }
}

impl<T: Clone> Index<Range<usize>> for Stack<T> {
    type Output = [T];

    fn index(&self, range: Range<usize>) -> &[T] {
        self.cache.index(range)
    }
}

#[derive(Debug)]
enum StackOp<T> {
    Push(T),
    Pop(T)
}

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

    #[test]
    fn snapshot_with_empty() {
        let mut stack = Stack::new();

        stack.snapshot();
        // []
        assert!(stack.is_empty());
        // [0]
        stack.push(0);
        stack.restore();
        assert!(stack.is_empty());
    }

    #[test]
    fn snapshot_twice() {
        let mut stack = Stack::new();

        stack.push(0);

        stack.snapshot();
        stack.snapshot();
        stack.restore();
        stack.restore();

        assert_eq!(stack.iter().collect::<Vec<&i32>>(), vec![&0]);
    }

    #[test]
    fn iter() {
        let mut stack = Stack::new();

        stack.push(0);
        stack.push(1);
        stack.push(2);

        assert_eq!(stack.iter().collect::<Vec<&i32>>(), vec![&2, &1, &0]);
    }

    #[test]
    fn stack_ops() {
        let mut stack = Stack::new();

        // []
        assert!(stack.is_empty());
        assert_eq!(stack.peek(), None);
        assert_eq!(stack.pop(), None);

        // [0]
        stack.push(0);
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&0));

        // [0, 1]
        stack.push(1);
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&1));

        // [0]
        assert_eq!(stack.pop(), Some(1));
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&0));

        // [0, 2]
        stack.push(2);
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&2));

        // [0, 2, 3]
        stack.push(3);
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&3));

        // Take a snapshot of the current stack
        // [0, 2, 3]
        stack.snapshot();

        // [0, 2]
        assert_eq!(stack.pop(), Some(3));
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&2));

        // Take a snapshot of the current stack
        // [0, 2]
        stack.snapshot();

        // [0]
        assert_eq!(stack.pop(), Some(2));
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&0));

        // []
        assert_eq!(stack.pop(), Some(0));
        assert!(stack.is_empty());

        // Test backtracking
        // [0, 2]
        stack.restore();
        assert_eq!(stack.pop(), Some(2));
        assert_eq!(stack.pop(), Some(0));
        assert_eq!(stack.pop(), None);

        // Test backtracking
        // [0, 2, 3]
        stack.restore();
        assert_eq!(stack.pop(), Some(3));
        assert_eq!(stack.pop(), Some(2));
        assert_eq!(stack.pop(), Some(0));
        assert_eq!(stack.pop(), None);
    }
}
<commit_msg>removed unused iter function<commit_after>// pest. The Elegant Parser
// Copyright (c) 2018 Dragoș Tiselice
//
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use std::ops::{ Range, Index };

/// Implementation of a `Stack` which maintains an log of `StackOp`s in order to rewind the stack
/// to a previous state.
#[derive(Debug)]
pub struct Stack<T: Clone> {
    ops: Vec<StackOp<T>>,
    cache: Vec<T>,
    snapshots: Vec<usize>
}

impl<T: Clone> Stack<T> {
    /// Creates a new `Stack`.
    pub fn new() -> Self {
        Stack {
            ops: vec![],
            cache: vec![],
            snapshots: vec![]
        }
    }

    /// Returns `true` if the stack is currently empty.
    #[allow(dead_code)]
    pub fn is_empty(&self) -> bool {
        self.cache.is_empty()
    }

    /// Returns the top-most `&T` in the `Stack`.
    pub fn peek(&self) -> Option<&T> {
        self.cache.last()
    }

    /// Pushes a `T` onto the `Stack`.
    pub fn push(&mut self, elem: T) {
        self.ops.push(StackOp::Push(elem.clone()));
        self.cache.push(elem);
    }

    /// Pops the top-most `T` from the `Stack`.
    pub fn pop(&mut self) -> Option<T> {
        let popped = self.cache.pop();
        if let Some(ref val) = popped {
            self.ops.push(StackOp::Pop(val.clone()));
        }
        popped
    }

    /// Returns the size of the stack
    pub fn len(&self) -> usize {
        self.cache.len()
    }

    /// Takes a snapshot of the current `Stack`.
    pub fn snapshot(&mut self) {
        self.snapshots.push(self.ops.len());
    }

    /// Rewinds the `Stack` to the most recent `snapshot()`. If no `snapshot()` has been taken, this
    /// function return the stack to its initial state.
    pub fn restore(&mut self) {
        match self.snapshots.pop() {
            Some(ops_index) => {
                self.rewind_to(ops_index);
                self.ops.truncate(ops_index);
            },
            None => {
                self.cache.clear();
                self.ops.clear();
            }
        }
    }

    // Rewind the stack to a particular index
    fn rewind_to(&mut self, index: usize) {
        let ops_to_rewind = &self.ops[index..];
        for op in ops_to_rewind.iter().rev() {
            match *op {
                StackOp::Push(_) => {
                    self.cache.pop();
                }
                StackOp::Pop(ref elem) => {
                    self.cache.push(elem.clone());
                }
            }
        }
    }
}

impl<T: Clone> Index<Range<usize>> for Stack<T> {
    type Output = [T];

    fn index(&self, range: Range<usize>) -> &[T] {
        self.cache.index(range)
    }
}

#[derive(Debug)]
enum StackOp<T> {
    Push(T),
    Pop(T)
}

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

    #[test]
    fn snapshot_with_empty() {
        let mut stack = Stack::new();

        stack.snapshot();
        // []
        assert!(stack.is_empty());
        // [0]
        stack.push(0);
        stack.restore();
        assert!(stack.is_empty());
    }

    #[test]
    fn snapshot_twice() {
        let mut stack = Stack::new();

        stack.push(0);

        stack.snapshot();
        stack.snapshot();
        stack.restore();
        stack.restore();

        assert_eq!(stack.iter().collect::<Vec<&i32>>(), vec![&0]);
    }

    #[test]
    fn stack_ops() {
        let mut stack = Stack::new();

        // []
        assert!(stack.is_empty());
        assert_eq!(stack.peek(), None);
        assert_eq!(stack.pop(), None);

        // [0]
        stack.push(0);
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&0));

        // [0, 1]
        stack.push(1);
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&1));

        // [0]
        assert_eq!(stack.pop(), Some(1));
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&0));

        // [0, 2]
        stack.push(2);
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&2));

        // [0, 2, 3]
        stack.push(3);
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&3));

        // Take a snapshot of the current stack
        // [0, 2, 3]
        stack.snapshot();

        // [0, 2]
        assert_eq!(stack.pop(), Some(3));
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&2));

        // Take a snapshot of the current stack
        // [0, 2]
        stack.snapshot();

        // [0]
        assert_eq!(stack.pop(), Some(2));
        assert!(!stack.is_empty());
        assert_eq!(stack.peek(), Some(&0));

        // []
        assert_eq!(stack.pop(), Some(0));
        assert!(stack.is_empty());

        // Test backtracking
        // [0, 2]
        stack.restore();
        assert_eq!(stack.pop(), Some(2));
        assert_eq!(stack.pop(), Some(0));
        assert_eq!(stack.pop(), None);

        // Test backtracking
        // [0, 2, 3]
        stack.restore();
        assert_eq!(stack.pop(), Some(3));
        assert_eq!(stack.pop(), Some(2));
        assert_eq!(stack.pop(), Some(0));
        assert_eq!(stack.pop(), None);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    block_storage::BlockReader, state_replication::TxnManager, util::time_service::TimeService,
};
use anyhow::{bail, ensure, format_err, Context};
use consensus_types::{
    block::Block,
    block_data::BlockData,
    common::{Author, Round},
    quorum_cert::QuorumCert,
};

use diem_infallible::Mutex;
use std::sync::Arc;

#[cfg(test)]
#[path = "proposal_generator_test.rs"]
mod proposal_generator_test;

/// ProposalGenerator is responsible for generating the proposed block on demand: it's typically
/// used by a validator that believes it's a valid candidate for serving as a proposer at a given
/// round.
/// ProposalGenerator is the one choosing the branch to extend:
/// - round is given by the caller (typically determined by RoundState).
/// The transactions for the proposed block are delivered by TxnManager.
///
/// TxnManager should be aware of the pending transactions in the branch that it is extending,
/// such that it will filter them out to avoid transaction duplication.
pub struct ProposalGenerator {
    // The account address of this validator
    author: Author,
    // Block store is queried both for finding the branch to extend and for generating the
    // proposed block.
    block_store: Arc<dyn BlockReader + Send + Sync>,
    // Transaction manager is delivering the transactions.
    txn_manager: Arc<dyn TxnManager>,
    // Time service to generate block timestamps
    time_service: Arc<dyn TimeService>,
    // Max number of transactions to be added to a proposed block.
    max_block_size: u64,
    // Last round that a proposal was generated
    last_round_generated: Mutex<Round>,
}

impl ProposalGenerator {
    pub fn new(
        author: Author,
        block_store: Arc<dyn BlockReader + Send + Sync>,
        txn_manager: Arc<dyn TxnManager>,
        time_service: Arc<dyn TimeService>,
        max_block_size: u64,
    ) -> Self {
        Self {
            author,
            block_store,
            txn_manager,
            time_service,
            max_block_size,
            last_round_generated: Mutex::new(0),
        }
    }

    pub fn author(&self) -> Author {
        self.author
    }

    /// Creates a NIL block proposal extending the highest certified block from the block store.
    pub fn generate_nil_block(&self, round: Round) -> anyhow::Result<Block> {
        let hqc = self.ensure_highest_quorum_cert(round)?;
        Ok(Block::new_nil(round, hqc.as_ref().clone()))
    }

    /// The function generates a new proposal block: the returned future is fulfilled when the
    /// payload is delivered by the TxnManager implementation.  At most one proposal can be
    /// generated per round (no proposal equivocation allowed).
    /// Errors returned by the TxnManager implementation are propagated to the caller.
    /// The logic for choosing the branch to extend is as follows:
    /// 1. The function gets the highest head of a one-chain from block tree.
    /// The new proposal must extend hqc to ensure optimistic responsiveness.
    /// 2. The round is provided by the caller.
    /// 3. In case a given round is not greater than the calculated parent, return an OldRound
    /// error.
    pub async fn generate_proposal(&mut self, round: Round) -> anyhow::Result<BlockData> {
        {
            let mut last_round_generated = self.last_round_generated.lock();
            if *last_round_generated < round {
                *last_round_generated = round;
            } else {
                bail!("Already proposed in the round {}", round);
            }
        }

        let hqc = self.ensure_highest_quorum_cert(round)?;

        let (payload, timestamp) = if hqc.certified_block().has_reconfiguration() {
            // Reconfiguration rule - we propose empty blocks with parents' timestamp
            // after reconfiguration until it's committed
            (vec![], hqc.certified_block().timestamp_usecs())
        } else {
            // One needs to hold the blocks with the references to the payloads while get_block is
            // being executed: pending blocks vector keeps all the pending ancestors of the extended branch.
            let pending_blocks = self
                .block_store
                .path_from_root(hqc.certified_block().id())
                .ok_or_else(|| format_err!("HQC {} already pruned", hqc.certified_block().id()))?;

            // Exclude all the pending transactions: these are all the ancestors of
            // parent (including) up to the root (excluding).
            let exclude_payload: Vec<&Vec<_>> = pending_blocks
                .iter()
                .flat_map(|block| block.payload())
                .collect();

            // All proposed blocks in a branch are guaranteed to have increasing timestamps
            // since their predecessor block will not be added to the BlockStore until
            // the local time exceeds it.
            let timestamp = self.time_service.get_current_timestamp();

            let payload = self
                .txn_manager
                .pull_txns(self.max_block_size, exclude_payload)
                .await
                .context("Fail to retrieve txn")?;

            (payload, timestamp.as_micros() as u64)
        };

        // create block proposal
        Ok(BlockData::new_proposal(
            payload,
            self.author,
            round,
            timestamp,
            hqc.as_ref().clone(),
        ))
    }

    fn ensure_highest_quorum_cert(&self, round: Round) -> anyhow::Result<Arc<QuorumCert>> {
        let hqc = self.block_store.highest_quorum_cert();
        ensure!(
            hqc.certified_block().round() < round,
            "Given round {} is lower than hqc round {}",
            round,
            hqc.certified_block().round()
        );
        ensure!(
            !hqc.ends_epoch(),
            "The epoch has already ended,a proposal is not allowed to generated"
        );

        Ok(hqc)
    }
}
<commit_msg>[consensus] avoid mempool long poll if root block has user txns<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    block_storage::BlockReader, state_replication::TxnManager, util::time_service::TimeService,
};
use anyhow::{bail, ensure, format_err, Context};
use consensus_types::{
    block::Block,
    block_data::BlockData,
    common::{Author, Round},
    quorum_cert::QuorumCert,
};

use diem_infallible::Mutex;
use std::sync::Arc;

#[cfg(test)]
#[path = "proposal_generator_test.rs"]
mod proposal_generator_test;

/// ProposalGenerator is responsible for generating the proposed block on demand: it's typically
/// used by a validator that believes it's a valid candidate for serving as a proposer at a given
/// round.
/// ProposalGenerator is the one choosing the branch to extend:
/// - round is given by the caller (typically determined by RoundState).
/// The transactions for the proposed block are delivered by TxnManager.
///
/// TxnManager should be aware of the pending transactions in the branch that it is extending,
/// such that it will filter them out to avoid transaction duplication.
pub struct ProposalGenerator {
    // The account address of this validator
    author: Author,
    // Block store is queried both for finding the branch to extend and for generating the
    // proposed block.
    block_store: Arc<dyn BlockReader + Send + Sync>,
    // Transaction manager is delivering the transactions.
    txn_manager: Arc<dyn TxnManager>,
    // Time service to generate block timestamps
    time_service: Arc<dyn TimeService>,
    // Max number of transactions to be added to a proposed block.
    max_block_size: u64,
    // Last round that a proposal was generated
    last_round_generated: Mutex<Round>,
}

impl ProposalGenerator {
    pub fn new(
        author: Author,
        block_store: Arc<dyn BlockReader + Send + Sync>,
        txn_manager: Arc<dyn TxnManager>,
        time_service: Arc<dyn TimeService>,
        max_block_size: u64,
    ) -> Self {
        Self {
            author,
            block_store,
            txn_manager,
            time_service,
            max_block_size,
            last_round_generated: Mutex::new(0),
        }
    }

    pub fn author(&self) -> Author {
        self.author
    }

    /// Creates a NIL block proposal extending the highest certified block from the block store.
    pub fn generate_nil_block(&self, round: Round) -> anyhow::Result<Block> {
        let hqc = self.ensure_highest_quorum_cert(round)?;
        Ok(Block::new_nil(round, hqc.as_ref().clone()))
    }

    /// The function generates a new proposal block: the returned future is fulfilled when the
    /// payload is delivered by the TxnManager implementation.  At most one proposal can be
    /// generated per round (no proposal equivocation allowed).
    /// Errors returned by the TxnManager implementation are propagated to the caller.
    /// The logic for choosing the branch to extend is as follows:
    /// 1. The function gets the highest head of a one-chain from block tree.
    /// The new proposal must extend hqc to ensure optimistic responsiveness.
    /// 2. The round is provided by the caller.
    /// 3. In case a given round is not greater than the calculated parent, return an OldRound
    /// error.
    pub async fn generate_proposal(&mut self, round: Round) -> anyhow::Result<BlockData> {
        {
            let mut last_round_generated = self.last_round_generated.lock();
            if *last_round_generated < round {
                *last_round_generated = round;
            } else {
                bail!("Already proposed in the round {}", round);
            }
        }

        let hqc = self.ensure_highest_quorum_cert(round)?;

        let (payload, timestamp) = if hqc.certified_block().has_reconfiguration() {
            // Reconfiguration rule - we propose empty blocks with parents' timestamp
            // after reconfiguration until it's committed
            (vec![], hqc.certified_block().timestamp_usecs())
        } else {
            // One needs to hold the blocks with the references to the payloads while get_block is
            // being executed: pending blocks vector keeps all the pending ancestors of the extended branch.
            let mut pending_blocks = self
                .block_store
                .path_from_root(hqc.certified_block().id())
                .ok_or_else(|| format_err!("HQC {} already pruned", hqc.certified_block().id()))?;
            // Avoid txn manager long poll it the root block has txns, so that the leader can
            // deliver the commit proof to others without delay.
            pending_blocks.push(self.block_store.root());

            // Exclude all the pending transactions: these are all the ancestors of
            // parent (including) up to the root (including).
            let exclude_payload: Vec<&Vec<_>> = pending_blocks
                .iter()
                .flat_map(|block| block.payload())
                .collect();

            // All proposed blocks in a branch are guaranteed to have increasing timestamps
            // since their predecessor block will not be added to the BlockStore until
            // the local time exceeds it.
            let timestamp = self.time_service.get_current_timestamp();

            let payload = self
                .txn_manager
                .pull_txns(self.max_block_size, exclude_payload)
                .await
                .context("Fail to retrieve txn")?;

            (payload, timestamp.as_micros() as u64)
        };

        // create block proposal
        Ok(BlockData::new_proposal(
            payload,
            self.author,
            round,
            timestamp,
            hqc.as_ref().clone(),
        ))
    }

    fn ensure_highest_quorum_cert(&self, round: Round) -> anyhow::Result<Arc<QuorumCert>> {
        let hqc = self.block_store.highest_quorum_cert();
        ensure!(
            hqc.certified_block().round() < round,
            "Given round {} is lower than hqc round {}",
            round,
            hqc.certified_block().round()
        );
        ensure!(
            !hqc.ends_epoch(),
            "The epoch has already ended,a proposal is not allowed to generated"
        );

        Ok(hqc)
    }
}
<|endoftext|>


<commit_before>println!("Hello from included file!");
<commit_msg>fix incomplete include<commit_after>println!("Hello from included file!")
<|endoftext|>


<commit_before>#![crate_id(name="cat", vers="1.0.0", author="Seldaek")]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Jordi Boggiano <j.boggiano@seld.be>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/* last synced with: cat (GNU coreutils) 8.13 */

extern crate getopts;

use std::os;
use std::io::{print, File};
use std::io::stdio::{stdout_raw, stdin_raw, stderr};
use std::io::{IoResult};
use std::ptr::{copy_nonoverlapping_memory};

#[allow(dead_code)]
fn main() { os::set_exit_status(uumain(os::args())); }

pub fn uumain(args: Vec<String>) -> int {
    let program = args.get(0).as_slice();
    let opts = [
        getopts::optflag("A", "show-all", "equivalent to -vET"),
        getopts::optflag("b", "number-nonblank",
                         "number nonempty output lines, overrides -n"),
        getopts::optflag("e", "", "equivalent to -vE"),
        getopts::optflag("E", "show-ends", "display $ at end of each line"),
        getopts::optflag("n", "number", "number all output lines"),
        getopts::optflag("s", "squeeze-blank", "suppress repeated empty output lines"),
        getopts::optflag("t", "", "equivalent to -vT"),
        getopts::optflag("T", "show-tabs", "display TAB characters as ^I"),
        getopts::optflag("v", "show-nonprinting",
                         "use ^ and M- notation, except for LF (\\n) and TAB (\\t)"),
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit"),
    ];
    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(f) => fail!("Invalid options\n{}", f)
    };
    if matches.opt_present("help") {
        println!("cat 1.0.0");
        println!("");
        println!("Usage:");
        println!("  {0:s} [OPTION]... [FILE]...", program);
        println!("");
        print(getopts::usage("Concatenate FILE(s), or standard input, to \
                             standard output.", opts).as_slice());
        println!("");
        println!("With no FILE, or when FILE is -, read standard input.");
        return 0;
    }
    if matches.opt_present("version") {
        println!("cat 1.0.0");
        return 0;
    }

    let mut number_mode = NumberNone;
    if matches.opt_present("n") {
        number_mode = NumberAll;
    }
    if matches.opt_present("b") {
        number_mode = NumberNonEmpty;
    }
    let show_nonprint = matches.opts_present(["A".to_string(), "e".to_string(),
                                              "t".to_string(), "v".to_string()]);
    let show_ends = matches.opts_present(["E".to_string(), "A".to_string(),
                                          "e".to_string()]);
    let show_tabs = matches.opts_present(["A".to_string(), "T".to_string(),
                                          "t".to_string()]);
    let squeeze_blank = matches.opt_present("s");
    let mut files = matches.free;
    if files.is_empty() {
        files.push("-".to_string());
    }

    exec(files, number_mode, show_nonprint, show_ends, show_tabs, squeeze_blank);

    0
}

#[deriving(Eq, PartialEq)]
enum NumberingMode {
    NumberNone,
    NumberNonEmpty,
    NumberAll,
}

fn write_lines(files: Vec<String>, number: NumberingMode, squeeze_blank: bool,
               show_ends: bool) {

    let mut line_counter: uint = 1;

    for path in files.iter() {
        let (mut reader, interactive) = match open(path.as_slice()) {
            Some(f) => f,
            None => continue,
        };

        let mut in_buf  = [0, .. 1024 * 31];
        let mut out_buf = [0, .. 1024 * 64];
        let mut writer = UnsafeWriter::new(out_buf.as_mut_slice(), stdout_raw());
        let mut at_line_start = true;
        loop {
            let n = match reader.read(in_buf) {
                Ok(n) if n != 0 => n,
                _ => break,
            };
            let in_buf = in_buf.slice_to(n);
            let mut buf_pos = range(0, n);
            loop {
                writer.possibly_flush();
                let pos = match buf_pos.next() {
                    Some(p) => p,
                    None => break,
                };
                if in_buf[pos] == '\n' as u8 {
                    if !at_line_start || !squeeze_blank {
                        if at_line_start && number == NumberAll {
                            (write!(&mut writer, "{0:6u}\t", line_counter)).unwrap();
                            line_counter += 1;
                        }
                        if show_ends {
                            writer.write_u8('$' as u8).unwrap();
                        }
                        writer.write_u8('\n' as u8).unwrap();
                        if interactive {
                            writer.flush().unwrap();
                        }
                    }
                    at_line_start = true;
                    continue;
                }
                if at_line_start && number != NumberNone {
                    (write!(&mut writer, "{0:6u}\t", line_counter)).unwrap();
                    line_counter += 1;
                }
                match in_buf.tailn(pos).iter().position(|c| *c == '\n' as u8) {
                    Some(p) => {
                        writer.write(in_buf.slice(pos, pos + p)).unwrap();
                        if show_ends {
                            writer.write_u8('$' as u8).unwrap();
                        }
                        writer.write_u8('\n' as u8).unwrap();
                        if interactive {
                            writer.flush().unwrap();
                        }
                        buf_pos = range(pos + p + 1, n);
                        at_line_start = true;
                    },
                    None => {
                        writer.write(in_buf.tailn(pos)).unwrap();
                        at_line_start = false;
                        break;
                    }
                };
            }
        }
    }
}

fn write_bytes(files: Vec<String>, number: NumberingMode, squeeze_blank: bool,
               show_ends: bool, show_nonprint: bool, show_tabs: bool) {

    let mut line_counter: uint = 1;

    for path in files.iter() {
        let (mut reader, interactive) = match open(path.as_slice()) {
            Some(f) => f,
            None => continue,
        };

        // Flush all 1024 iterations.
        let mut flush_counter = range(0, 1024);

        let mut in_buf  = [0, .. 1024 * 32];
        let mut out_buf = [0, .. 1024 * 64];
        let mut writer = UnsafeWriter::new(out_buf.as_mut_slice(), stdout_raw());
        let mut at_line_start = true;
        loop {
            let n = match reader.read(in_buf) {
                Ok(n) if n != 0 => n,
                _ => break,
            };
            for &byte in in_buf.slice_to(n).iter() {
                if flush_counter.next().is_none() {
                    writer.possibly_flush();
                    flush_counter = range(0, 1024);
                }
                if byte == '\n' as u8 {
                    if !at_line_start || !squeeze_blank {
                        if at_line_start && number == NumberAll {
                            (write!(&mut writer, "{0:6u}\t", line_counter)).unwrap();
                            line_counter += 1;
                        }
                        if show_ends {
                            writer.write_u8('$' as u8).unwrap();
                        }
                        writer.write_u8('\n' as u8).unwrap();
                        if interactive {
                            writer.flush().unwrap();
                        }
                    }
                    at_line_start = true;
                    continue;
                }
                if at_line_start && number != NumberNone {
                    (write!(&mut writer, "{0:6u}\t", line_counter)).unwrap();
                    line_counter += 1;
                    at_line_start = false;
                }
                // This code is slow because of the many branches. cat in glibc avoids
                // this by having the whole loop inside show_nonprint.
                if byte == '\t' as u8 {
                    if show_tabs {
                        writer.write_str("^I")
                    } else {
                        writer.write_u8(byte)
                    }
                } else if show_nonprint {
                    let byte = match byte {
                        128 .. 255 => {
                            writer.write_str("M-").unwrap();
                            byte - 128
                        },
                        _ => byte,
                    };
                    match byte {
                        0 .. 31 => writer.write(['^' as u8, byte + 64]),
                        127     => writer.write(['^' as u8, byte - 64]),
                        _       => writer.write_u8(byte),
                    }
                } else {
                    writer.write_u8(byte)
                }.unwrap();
            }
        }
    }
}

fn write_fast(files: Vec<String>) {
    let mut writer = stdout_raw();
    let mut in_buf = [0, .. 1024 * 64];

    for path in files.iter() {
        let (mut reader, _) = match open(path.as_slice()) {
            Some(x) => x,
            None => continue,
        };

        loop {
            match reader.read(in_buf) {
                Ok(n) if n != 0 => {
                    // This interface is completely broken.
                    writer.write(in_buf.slice_to(n)).unwrap();
                },
                _ => break
            }
        }
    }
}

fn exec(files: Vec<String>, number: NumberingMode, show_nonprint: bool,
        show_ends: bool, show_tabs: bool, squeeze_blank: bool) {

    if show_nonprint || show_tabs {
        write_bytes(files, number, squeeze_blank, show_ends, show_nonprint, show_tabs);
    } else if number != NumberNone || squeeze_blank || show_ends {
        write_lines(files, number, squeeze_blank, show_ends);
    } else {
        write_fast(files);
    }
}

fn open(path: &str) -> Option<(Box<Reader>, bool)> {
    if path == "-" {
        let stdin = stdin_raw();
        let interactive = stdin.isatty();
        return Some((box stdin as Box<Reader>, interactive));
    }

    match File::open(&std::path::Path::new(path)) {
        Ok(f) => Some((box f as Box<Reader>, false)),
        Err(e) => {
            (writeln!(stderr(), "cat: {0:s}: {1:s}", path, e.to_str())).unwrap();
            None
        },
    }
}

struct UnsafeWriter<'a, W> {
    inner: W,
    buf: &'a mut [u8],
    pos: uint,
    threshold: uint,
}

impl<'a, W: Writer> UnsafeWriter<'a, W> {
    fn new(buf: &'a mut [u8], inner: W) -> UnsafeWriter<'a, W> {
        let threshold = buf.len()/2;
        UnsafeWriter {
            inner: inner,
            buf: buf,
            pos: 0,
            threshold: threshold,
        }
    }

    fn flush_buf(&mut self) -> IoResult<()> {
        if self.pos != 0 {
            let ret = self.inner.write(self.buf.slice_to(self.pos));
            self.pos = 0;
            ret
        } else {
            Ok(())
        }
    }

    fn possibly_flush(&mut self) {
        if self.pos > self.threshold {
            self.inner.write(self.buf.slice_to(self.pos)).unwrap();
            self.pos = 0;
        }
    }
}

#[inline(never)]
fn fail() -> ! {
    fail!("assertion failed");
}

impl<'a, W: Writer> Writer for UnsafeWriter<'a, W> {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        let dst = self.buf.mut_slice_from(self.pos);
        if buf.len() > dst.len() {
            fail();
        }
        unsafe {
            copy_nonoverlapping_memory(dst.as_mut_ptr(), buf.as_ptr(), buf.len())
        }
        self.pos += buf.len();
        Ok(())
    }

    fn flush(&mut self) -> IoResult<()> {
        self.flush_buf().and_then(|()| self.inner.flush())
    }
}

#[unsafe_destructor]
impl<'a, W: Writer> Drop for UnsafeWriter<'a, W> {
    fn drop(&mut self) {
        let _ = self.flush_buf();
    }
}

/* vim: set ai ts=4 sw=4 sts=4 et : */
<commit_msg>cat: fix build<commit_after>#![crate_id(name="cat", vers="1.0.0", author="Seldaek")]
#![feature(unsafe_destructor)]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Jordi Boggiano <j.boggiano@seld.be>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

/* last synced with: cat (GNU coreutils) 8.13 */

extern crate getopts;

use std::os;
use std::io::{print, File};
use std::io::stdio::{stdout_raw, stdin_raw, stderr};
use std::io::{IoResult};
use std::ptr::{copy_nonoverlapping_memory};

#[allow(dead_code)]
fn main() { os::set_exit_status(uumain(os::args())); }

pub fn uumain(args: Vec<String>) -> int {
    let program = args.get(0).as_slice();
    let opts = [
        getopts::optflag("A", "show-all", "equivalent to -vET"),
        getopts::optflag("b", "number-nonblank",
                         "number nonempty output lines, overrides -n"),
        getopts::optflag("e", "", "equivalent to -vE"),
        getopts::optflag("E", "show-ends", "display $ at end of each line"),
        getopts::optflag("n", "number", "number all output lines"),
        getopts::optflag("s", "squeeze-blank", "suppress repeated empty output lines"),
        getopts::optflag("t", "", "equivalent to -vT"),
        getopts::optflag("T", "show-tabs", "display TAB characters as ^I"),
        getopts::optflag("v", "show-nonprinting",
                         "use ^ and M- notation, except for LF (\\n) and TAB (\\t)"),
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit"),
    ];
    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(f) => fail!("Invalid options\n{}", f)
    };
    if matches.opt_present("help") {
        println!("cat 1.0.0");
        println!("");
        println!("Usage:");
        println!("  {0:s} [OPTION]... [FILE]...", program);
        println!("");
        print(getopts::usage("Concatenate FILE(s), or standard input, to \
                             standard output.", opts).as_slice());
        println!("");
        println!("With no FILE, or when FILE is -, read standard input.");
        return 0;
    }
    if matches.opt_present("version") {
        println!("cat 1.0.0");
        return 0;
    }

    let mut number_mode = NumberNone;
    if matches.opt_present("n") {
        number_mode = NumberAll;
    }
    if matches.opt_present("b") {
        number_mode = NumberNonEmpty;
    }
    let show_nonprint = matches.opts_present(["A".to_string(), "e".to_string(),
                                              "t".to_string(), "v".to_string()]);
    let show_ends = matches.opts_present(["E".to_string(), "A".to_string(),
                                          "e".to_string()]);
    let show_tabs = matches.opts_present(["A".to_string(), "T".to_string(),
                                          "t".to_string()]);
    let squeeze_blank = matches.opt_present("s");
    let mut files = matches.free;
    if files.is_empty() {
        files.push("-".to_string());
    }

    exec(files, number_mode, show_nonprint, show_ends, show_tabs, squeeze_blank);

    0
}

#[deriving(Eq, PartialEq)]
enum NumberingMode {
    NumberNone,
    NumberNonEmpty,
    NumberAll,
}

fn write_lines(files: Vec<String>, number: NumberingMode, squeeze_blank: bool,
               show_ends: bool) {

    let mut line_counter: uint = 1;

    for path in files.iter() {
        let (mut reader, interactive) = match open(path.as_slice()) {
            Some(f) => f,
            None => continue,
        };

        let mut in_buf  = [0, .. 1024 * 31];
        let mut out_buf = [0, .. 1024 * 64];
        let mut writer = UnsafeWriter::new(out_buf.as_mut_slice(), stdout_raw());
        let mut at_line_start = true;
        loop {
            let n = match reader.read(in_buf) {
                Ok(n) if n != 0 => n,
                _ => break,
            };
            let in_buf = in_buf.slice_to(n);
            let mut buf_pos = range(0, n);
            loop {
                writer.possibly_flush();
                let pos = match buf_pos.next() {
                    Some(p) => p,
                    None => break,
                };
                if in_buf[pos] == '\n' as u8 {
                    if !at_line_start || !squeeze_blank {
                        if at_line_start && number == NumberAll {
                            (write!(&mut writer, "{0:6u}\t", line_counter)).unwrap();
                            line_counter += 1;
                        }
                        if show_ends {
                            writer.write_u8('$' as u8).unwrap();
                        }
                        writer.write_u8('\n' as u8).unwrap();
                        if interactive {
                            writer.flush().unwrap();
                        }
                    }
                    at_line_start = true;
                    continue;
                }
                if at_line_start && number != NumberNone {
                    (write!(&mut writer, "{0:6u}\t", line_counter)).unwrap();
                    line_counter += 1;
                }
                match in_buf.tailn(pos).iter().position(|c| *c == '\n' as u8) {
                    Some(p) => {
                        writer.write(in_buf.slice(pos, pos + p)).unwrap();
                        if show_ends {
                            writer.write_u8('$' as u8).unwrap();
                        }
                        writer.write_u8('\n' as u8).unwrap();
                        if interactive {
                            writer.flush().unwrap();
                        }
                        buf_pos = range(pos + p + 1, n);
                        at_line_start = true;
                    },
                    None => {
                        writer.write(in_buf.tailn(pos)).unwrap();
                        at_line_start = false;
                        break;
                    }
                };
            }
        }
    }
}

fn write_bytes(files: Vec<String>, number: NumberingMode, squeeze_blank: bool,
               show_ends: bool, show_nonprint: bool, show_tabs: bool) {

    let mut line_counter: uint = 1;

    for path in files.iter() {
        let (mut reader, interactive) = match open(path.as_slice()) {
            Some(f) => f,
            None => continue,
        };

        // Flush all 1024 iterations.
        let mut flush_counter = range(0, 1024);

        let mut in_buf  = [0, .. 1024 * 32];
        let mut out_buf = [0, .. 1024 * 64];
        let mut writer = UnsafeWriter::new(out_buf.as_mut_slice(), stdout_raw());
        let mut at_line_start = true;
        loop {
            let n = match reader.read(in_buf) {
                Ok(n) if n != 0 => n,
                _ => break,
            };
            for &byte in in_buf.slice_to(n).iter() {
                if flush_counter.next().is_none() {
                    writer.possibly_flush();
                    flush_counter = range(0, 1024);
                }
                if byte == '\n' as u8 {
                    if !at_line_start || !squeeze_blank {
                        if at_line_start && number == NumberAll {
                            (write!(&mut writer, "{0:6u}\t", line_counter)).unwrap();
                            line_counter += 1;
                        }
                        if show_ends {
                            writer.write_u8('$' as u8).unwrap();
                        }
                        writer.write_u8('\n' as u8).unwrap();
                        if interactive {
                            writer.flush().unwrap();
                        }
                    }
                    at_line_start = true;
                    continue;
                }
                if at_line_start && number != NumberNone {
                    (write!(&mut writer, "{0:6u}\t", line_counter)).unwrap();
                    line_counter += 1;
                    at_line_start = false;
                }
                // This code is slow because of the many branches. cat in glibc avoids
                // this by having the whole loop inside show_nonprint.
                if byte == '\t' as u8 {
                    if show_tabs {
                        writer.write_str("^I")
                    } else {
                        writer.write_u8(byte)
                    }
                } else if show_nonprint {
                    let byte = match byte {
                        128 .. 255 => {
                            writer.write_str("M-").unwrap();
                            byte - 128
                        },
                        _ => byte,
                    };
                    match byte {
                        0 .. 31 => writer.write(['^' as u8, byte + 64]),
                        127     => writer.write(['^' as u8, byte - 64]),
                        _       => writer.write_u8(byte),
                    }
                } else {
                    writer.write_u8(byte)
                }.unwrap();
            }
        }
    }
}

fn write_fast(files: Vec<String>) {
    let mut writer = stdout_raw();
    let mut in_buf = [0, .. 1024 * 64];

    for path in files.iter() {
        let (mut reader, _) = match open(path.as_slice()) {
            Some(x) => x,
            None => continue,
        };

        loop {
            match reader.read(in_buf) {
                Ok(n) if n != 0 => {
                    // This interface is completely broken.
                    writer.write(in_buf.slice_to(n)).unwrap();
                },
                _ => break
            }
        }
    }
}

fn exec(files: Vec<String>, number: NumberingMode, show_nonprint: bool,
        show_ends: bool, show_tabs: bool, squeeze_blank: bool) {

    if show_nonprint || show_tabs {
        write_bytes(files, number, squeeze_blank, show_ends, show_nonprint, show_tabs);
    } else if number != NumberNone || squeeze_blank || show_ends {
        write_lines(files, number, squeeze_blank, show_ends);
    } else {
        write_fast(files);
    }
}

fn open(path: &str) -> Option<(Box<Reader>, bool)> {
    if path == "-" {
        let stdin = stdin_raw();
        let interactive = stdin.isatty();
        return Some((box stdin as Box<Reader>, interactive));
    }

    match File::open(&std::path::Path::new(path)) {
        Ok(f) => Some((box f as Box<Reader>, false)),
        Err(e) => {
            (writeln!(stderr(), "cat: {0:s}: {1:s}", path, e.to_str())).unwrap();
            None
        },
    }
}

struct UnsafeWriter<'a, W> {
    inner: W,
    buf: &'a mut [u8],
    pos: uint,
    threshold: uint,
}

impl<'a, W: Writer> UnsafeWriter<'a, W> {
    fn new(buf: &'a mut [u8], inner: W) -> UnsafeWriter<'a, W> {
        let threshold = buf.len()/2;
        UnsafeWriter {
            inner: inner,
            buf: buf,
            pos: 0,
            threshold: threshold,
        }
    }

    fn flush_buf(&mut self) -> IoResult<()> {
        if self.pos != 0 {
            let ret = self.inner.write(self.buf.slice_to(self.pos));
            self.pos = 0;
            ret
        } else {
            Ok(())
        }
    }

    fn possibly_flush(&mut self) {
        if self.pos > self.threshold {
            self.inner.write(self.buf.slice_to(self.pos)).unwrap();
            self.pos = 0;
        }
    }
}

#[inline(never)]
fn fail() -> ! {
    fail!("assertion failed");
}

impl<'a, W: Writer> Writer for UnsafeWriter<'a, W> {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        let dst = self.buf.mut_slice_from(self.pos);
        if buf.len() > dst.len() {
            fail();
        }
        unsafe {
            copy_nonoverlapping_memory(dst.as_mut_ptr(), buf.as_ptr(), buf.len())
        }
        self.pos += buf.len();
        Ok(())
    }

    fn flush(&mut self) -> IoResult<()> {
        self.flush_buf().and_then(|()| self.inner.flush())
    }
}

#[unsafe_destructor]
impl<'a, W: Writer> Drop for UnsafeWriter<'a, W> {
    fn drop(&mut self) {
        let _ = self.flush_buf();
    }
}

/* vim: set ai ts=4 sw=4 sts=4 et : */
<|endoftext|>


<commit_before>use std::char;

pub enum TokenType {
    ILLEGAL,
    EOF,
    IDENT,
    INT,
    ASSIGN,
    PLUS,
    MINUS,
    COMMA,
    SEMICOLON,
    LPAREN,
    RPAREN,
    LBRACE,
    RBRACE,
    FUNCTION,
    LET,
}

pub enum Value {
    Int(String),
    Str(String),
}

pub struct Token {
    pub token_type: TokenType,
    pub value: Option<Value>,
}

impl TokenType {
    pub fn from_string(s: String) -> TokenType {
        match s.as_ref() {
            "\n" => TokenType::EOF,
            "let" => TokenType::LET,
            "+" => TokenType::PLUS,
            "-" => TokenType::MINUS,
            "," => TokenType::COMMA,
            ";" => TokenType::SEMICOLON,
            "(" => TokenType::LPAREN,
            ")" => TokenType::RPAREN,
            "{" => TokenType::LBRACE,
            "}" => TokenType::RBRACE,
            "func" => TokenType::FUNCTION,
            _ => TokenType::ILLEGAL
        }
    }
}

pub struct Parser<'a> {
    pub tokens: &'a [Token]
}

impl<'a> Parser<'a> {
    pub fn parse(&self) {
        return ();
    }
}

pub struct Lexer<'a> {
    pub input: String,
    pub position: usize,
    pub read_position: usize,
    pub ch: &'a mut char
}

impl<'a> Lexer<'a> {
    pub fn new(input: String, c: &'a mut char) -> Lexer<'a> {
        return Lexer {
            input: input,
            position: 0,
            read_position: 0,
            ch: c
        };
    }

    pub fn read_char(&'a mut self) -> char {
        if self.read_position >= self.input.len() {
            return '0';
        } else {
            let c = self.input.chars().nth(self.read_position).unwrap();
            self.position = self.read_position;
            self.read_position += 1;
            return c;
        }
    }

    pub fn next_token(&'a mut self) -> Token {
        let token_type = TokenType::from_string(self.ch.to_string());
        let c = self.read_char();
        return Token {
            token_type: token_type,
            value: Some(Value::Str(c.to_string()))
        };
    }

    pub fn peek_char(&self) -> char {
        if self.read_position >= self.input.len() {
            return '0';
        } else {
            return self.input.chars().nth(self.read_position).unwrap();
        }
    }
}

#[test]
fn next_token() {
    let input = String::from("=+(){},;");
    let tests = [
        (TokenType::ASSIGN, "="),
        (TokenType::PLUS, "+"),
        (TokenType::LPAREN, "("),
        (TokenType::RPAREN, ")"),
        (TokenType::LBRACE, "{"),
        (TokenType::RBRACE, "}"),
        (TokenType::COMMA, ","),
        (TokenType::SEMICOLON, ";"),
        (TokenType::EOF, ""),
    ];
}
<commit_msg>edit code<commit_after>use std::char;

pub enum TokenType {
    ILLEGAL,
    EOF,
    IDENT,
    INT,
    ASSIGN,
    PLUS,
    MINUS,
    COMMA,
    SEMICOLON,
    LPAREN,
    RPAREN,
    LBRACE,
    RBRACE,
    FUNCTION,
    LET,
}

pub enum Value {
    Int(String),
    Str(String),
}

pub struct Token {
    pub token_type: TokenType,
    pub value: Option<Value>,
}

impl TokenType {
    pub fn from_string(s: String) -> TokenType {
        match s.as_ref() {
            "\n" => TokenType::EOF,
            "let" => TokenType::LET,
            "+" => TokenType::PLUS,
            "-" => TokenType::MINUS,
            "," => TokenType::COMMA,
            ";" => TokenType::SEMICOLON,
            "(" => TokenType::LPAREN,
            ")" => TokenType::RPAREN,
            "{" => TokenType::LBRACE,
            "}" => TokenType::RBRACE,
            "func" => TokenType::FUNCTION,
            _ => TokenType::ILLEGAL
        }
    }
}

pub struct Parser<'a> {
    pub tokens: &'a [Token]
}

impl<'a> Parser<'a> {
    pub fn parse(&self) {
        return ();
    }
}

pub struct Lexer<'a> {
    pub input: String,
    pub position: usize,
    pub read_position: usize,
    pub ch: &'a mut char
}

impl<'a> Lexer<'a> {
    pub fn new(input: String, c: &'a mut char) -> Lexer<'a> {
        return Lexer {
            input: input,
            position: 0,
            read_position: 0,
            ch: c
        };
    }

    pub fn read_char(&'a mut self) -> char {
        if self.read_position >= self.input.len() {
            return '0';
        } else {
            let c = self.input.chars().nth(self.read_position).unwrap();
            self.position = self.read_position;
            self.read_position += 1;
            return c;
        }
    }

    pub fn next_token(&'a mut self) -> Token {
        let token_type = TokenType::from_string(self.ch.to_string());
        let c = self.read_char();
        return Token {
            token_type: token_type,
            value: Some(Value::Str(c.to_string()))
        };
    }

    pub fn peek_char(&self) -> char {
        if self.read_position >= self.input.len() {
            return '0';
        } else {
            return self.input.chars().nth(self.read_position).unwrap();
        }
    }
}

#[test]
fn next_token() {
    let input = String::from("=+(){},;");
    let tests = [
        (TokenType::ASSIGN, "="),
        (TokenType::PLUS, "+"),
        (TokenType::LPAREN, "("),
        (TokenType::RPAREN, ")"),
        (TokenType::LBRACE, "{"),
        (TokenType::RBRACE, "}"),
        (TokenType::COMMA, ","),
        (TokenType::SEMICOLON, ";"),
        (TokenType::EOF, ""),
    ];
    let l = &mut Lexer::new(input, ' ');
    for e in tests.into_iter() {
        let t = l.next_token();
        assert_eq!(t.token_type, e.1);
    }
}
<|endoftext|>