<commit_before>// This file is part of the uutils coreutils package.
//
// (c) Nick Platt <platt.nicholas@gmail.com>
// (c) Jian Zeng <anonymousknight96 AT gmail.com>
//
// For the full copyright and license information, please view the LICENSE file
// that was distributed with this source code.

// spell-checker:ignore (ToDO) filetime strptime utcoff strs datetime MMDDhhmm

pub extern crate filetime;

#[macro_use]
extern crate uucore;

use clap::{crate_version, App, Arg, ArgGroup};
use filetime::*;
use std::fs::{self, File};
use std::io::Error;
use std::path::Path;
use std::process;

static ABOUT: &str = "Update the access and modification times of each FILE to the current time.";
pub mod options {
    // Both SOURCES and sources are needed as we need to be able to refer to the ArgGroup.
    pub static SOURCES: &str = "sources";
    pub mod sources {
        pub static DATE: &str = "date";
        pub static REFERENCE: &str = "reference";
        pub static CURRENT: &str = "current";
    }
    pub static ACCESS: &str = "access";
    pub static MODIFICATION: &str = "modification";
    pub static NO_CREATE: &str = "no-create";
    pub static NO_DEREF: &str = "no-dereference";
    pub static TIME: &str = "time";
}

static ARG_FILES: &str = "files";

fn to_local(mut tm: time::Tm) -> time::Tm {
    tm.tm_utcoff = time::now().tm_utcoff;
    tm
}

fn local_tm_to_filetime(tm: time::Tm) -> FileTime {
    let ts = tm.to_timespec();
    FileTime::from_unix_time(ts.sec as i64, ts.nsec as u32)
}

fn get_usage() -> String {
    format!("{0} [OPTION]... [USER]", executable!())
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let usage = get_usage();

    let matches = uu_app().usage(&usage[..]).get_matches_from(args);

    let files: Vec<String> = matches
        .values_of(ARG_FILES)
        .map(|v| v.map(ToString::to_string).collect())
        .unwrap_or_default();

    let (mut atime, mut mtime) = if matches.is_present(options::sources::REFERENCE) {
        stat(
            matches.value_of(options::sources::REFERENCE).unwrap(),
            !matches.is_present(options::NO_DEREF),
        )
    } else if matches.is_present(options::sources::DATE)
        || matches.is_present(options::sources::CURRENT)
    {
        let timestamp = if matches.is_present(options::sources::DATE) {
            parse_date(matches.value_of(options::sources::DATE).unwrap())
        } else {
            parse_timestamp(matches.value_of(options::sources::CURRENT).unwrap())
        };
        (timestamp, timestamp)
    } else {
        let now = local_tm_to_filetime(time::now());
        (now, now)
    };

    let mut error_code = 0;

    for filename in &files {
        let path = &filename[..];

        if !Path::new(path).exists() {
            // no-dereference included here for compatibility
            if matches.is_present(options::NO_CREATE) || matches.is_present(options::NO_DEREF) {
                continue;
            }

            if let Err(e) = File::create(path) {
                match e.kind() {
                    std::io::ErrorKind::NotFound => {
                        show_error!("cannot touch '{}': {}", path, "No such file or directory")
                    }
                    std::io::ErrorKind::PermissionDenied => {
                        show_error!("cannot touch '{}': {}", path, "Permission denied")
                    }
                    _ => show_error!("cannot touch '{}': {}", path, e),
                }
                error_code = 1;
                continue;
            };

            // Minor optimization: if no reference time was specified, we're done.
            if !matches.is_present(options::SOURCES) {
                continue;
            }
        }

        // If changing "only" atime or mtime, grab the existing value of the other.
        // Note that "-a" and "-m" may be passed together; this is not an xor.
        if matches.is_present(options::ACCESS)
            || matches.is_present(options::MODIFICATION)
            || matches.is_present(options::TIME)
        {
            let st = stat(path, !matches.is_present(options::NO_DEREF));
            let time = matches.value_of(options::TIME).unwrap_or("");

            if !(matches.is_present(options::ACCESS)
                || time.contains(&"access".to_owned())
                || time.contains(&"atime".to_owned())
                || time.contains(&"use".to_owned()))
            {
                atime = st.0;
            }

            if !(matches.is_present(options::MODIFICATION)
                || time.contains(&"modify".to_owned())
                || time.contains(&"mtime".to_owned()))
            {
                mtime = st.1;
            }
        }

        if matches.is_present(options::NO_DEREF) {
            if let Err(e) = set_symlink_file_times(path, atime, mtime) {
                // we found an error, it should fail in any case
                error_code = 1;
                if e.kind() == std::io::ErrorKind::PermissionDenied {
                    // GNU compatibility (not-owner.sh)
                    show_error!("setting times of '{}': {}", path, "Permission denied");
                } else {
                    show_error!("setting times of '{}': {}", path, e);
                }
            }
        } else if let Err(e) = filetime::set_file_times(path, atime, mtime) {
            // we found an error, it should fail in any case
            error_code = 1;

            if e.kind() == std::io::ErrorKind::PermissionDenied {
                // GNU compatibility (not-owner.sh)
                show_error!("setting times of '{}': {}", path, "Permission denied");
            } else {
                show_error!("setting times of '{}': {}", path, e);
            }
        }
    }
    error_code
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(executable!())
        .version(crate_version!())
        .about(ABOUT)
        .arg(
            Arg::with_name(options::ACCESS)
                .short("a")
                .help("change only the access time"),
        )
        .arg(
            Arg::with_name(options::sources::CURRENT)
                .short("t")
                .help("use [[CC]YY]MMDDhhmm[.ss] instead of the current time")
                .value_name("STAMP")
                .takes_value(true),
        )
        .arg(
            Arg::with_name(options::sources::DATE)
                .short("d")
                .long(options::sources::DATE)
                .help("parse argument and use it instead of current time")
                .value_name("STRING"),
        )
        .arg(
            Arg::with_name(options::MODIFICATION)
                .short("m")
                .help("change only the modification time"),
        )
        .arg(
            Arg::with_name(options::NO_CREATE)
                .short("c")
                .long(options::NO_CREATE)
                .help("do not create any files"),
        )
        .arg(
            Arg::with_name(options::NO_DEREF)
                .short("h")
                .long(options::NO_DEREF)
                .help(
                    "affect each symbolic link instead of any referenced file \
                     (only for systems that can change the timestamps of a symlink)",
                ),
        )
        .arg(
            Arg::with_name(options::sources::REFERENCE)
                .short("r")
                .long(options::sources::REFERENCE)
                .help("use this file's times instead of the current time")
                .value_name("FILE"),
        )
        .arg(
            Arg::with_name(options::TIME)
                .long(options::TIME)
                .help(
                    "change only the specified time: \"access\", \"atime\", or \
                     \"use\" are equivalent to -a; \"modify\" or \"mtime\" are \
                     equivalent to -m",
                )
                .value_name("WORD")
                .possible_values(&["access", "atime", "use"])
                .takes_value(true),
        )
        .arg(
            Arg::with_name(ARG_FILES)
                .multiple(true)
                .takes_value(true)
                .min_values(1),
        )
        .group(ArgGroup::with_name(options::SOURCES).args(&[
            options::sources::CURRENT,
            options::sources::DATE,
            options::sources::REFERENCE,
        ]))
}

fn stat(path: &str, follow: bool) -> (FileTime, FileTime) {
    let metadata = if follow {
        fs::symlink_metadata(path)
    } else {
        fs::metadata(path)
    };

    match metadata {
        Ok(m) => (
            FileTime::from_last_access_time(&m),
            FileTime::from_last_modification_time(&m),
        ),
        Err(_) => crash!(
            1,
            "failed to get attributes of '{}': {}",
            path,
            Error::last_os_error()
        ),
    }
}

fn parse_date(str: &str) -> FileTime {
    // This isn't actually compatible with GNU touch, but there doesn't seem to
    // be any simple specification for what format this parameter allows and I'm
    // not about to implement GNU parse_datetime.
    // http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob_plain;f=lib/parse-datetime.y
    let formats = vec!["%c", "%F"];
    for f in formats {
        if let Ok(tm) = time::strptime(str, f) {
            return local_tm_to_filetime(to_local(tm));
        }
    }
    if let Ok(tm) = time::strptime(str, "@%s") {
        // Don't convert to local time in this case - seconds since epoch are not time-zone dependent
        return local_tm_to_filetime(tm);
    }
    show_error!("Unable to parse date: {}\n", str);
    process::exit(1);
}

fn parse_timestamp(s: &str) -> FileTime {
    let now = time::now();
    let (format, ts) = match s.chars().count() {
        15 => ("%Y%m%d%H%M.%S", s.to_owned()),
        12 => ("%Y%m%d%H%M", s.to_owned()),
        13 => ("%y%m%d%H%M.%S", s.to_owned()),
        10 => ("%y%m%d%H%M", s.to_owned()),
        11 => ("%Y%m%d%H%M.%S", format!("{}{}", now.tm_year + 1900, s)),
        8 => ("%Y%m%d%H%M", format!("{}{}", now.tm_year + 1900, s)),
        _ => panic!("Unknown timestamp format"),
    };

    match time::strptime(&ts, format) {
        Ok(tm) => {
            let mut local = to_local(tm);
            local.tm_isdst = -1;
            let ft = local_tm_to_filetime(local);

            // We have to check that ft is valid time. Due to daylight saving
            // time switch, local time can jump from 1:59 AM to 3:00 AM,
            // in which case any time between 2:00 AM and 2:59 AM is not valid.
            // Convert back to local time and see if we got the same value back.
            let ts = time::Timespec {
                sec: ft.unix_seconds(),
                nsec: 0,
            };
            let tm2 = time::at(ts);
            if tm.tm_hour != tm2.tm_hour {
                show_error!("invalid date format {}", s);
                process::exit(1);
            }

            ft
        }
        Err(e) => panic!("Unable to parse timestamp\n{}", e),
    }
}
<commit_msg>touch: adapt to standardized error handling<commit_after>// This file is part of the uutils coreutils package.
//
// (c) Nick Platt <platt.nicholas@gmail.com>
// (c) Jian Zeng <anonymousknight96 AT gmail.com>
//
// For the full copyright and license information, please view the LICENSE file
// that was distributed with this source code.

// spell-checker:ignore (ToDO) filetime strptime utcoff strs datetime MMDDhhmm

pub extern crate filetime;

#[macro_use]
extern crate uucore;

use clap::{crate_version, App, Arg, ArgGroup};
use filetime::*;
use std::fs::{self, File};
use std::path::Path;
use uucore::error::{FromIo, UResult, USimpleError};

static ABOUT: &str = "Update the access and modification times of each FILE to the current time.";
pub mod options {
    // Both SOURCES and sources are needed as we need to be able to refer to the ArgGroup.
    pub static SOURCES: &str = "sources";
    pub mod sources {
        pub static DATE: &str = "date";
        pub static REFERENCE: &str = "reference";
        pub static CURRENT: &str = "current";
    }
    pub static ACCESS: &str = "access";
    pub static MODIFICATION: &str = "modification";
    pub static NO_CREATE: &str = "no-create";
    pub static NO_DEREF: &str = "no-dereference";
    pub static TIME: &str = "time";
}

static ARG_FILES: &str = "files";

fn to_local(mut tm: time::Tm) -> time::Tm {
    tm.tm_utcoff = time::now().tm_utcoff;
    tm
}

fn local_tm_to_filetime(tm: time::Tm) -> FileTime {
    let ts = tm.to_timespec();
    FileTime::from_unix_time(ts.sec as i64, ts.nsec as u32)
}

fn get_usage() -> String {
    format!("{0} [OPTION]... [USER]", executable!())
}

#[uucore_procs::gen_uumain]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let usage = get_usage();

    let matches = uu_app().usage(&usage[..]).get_matches_from(args);

    let files = matches.values_of_os(ARG_FILES).unwrap();

    let (mut atime, mut mtime) =
        if let Some(reference) = matches.value_of_os(options::sources::REFERENCE) {
            stat(Path::new(reference), !matches.is_present(options::NO_DEREF))?
        } else {
            let timestamp = if let Some(date) = matches.value_of(options::sources::DATE) {
                parse_date(date)?
            } else if let Some(current) = matches.value_of(options::sources::CURRENT) {
                parse_timestamp(current)?
            } else {
                local_tm_to_filetime(time::now())
            };
            (timestamp, timestamp)
        };

    for filename in files {
        let path = Path::new(filename);
        if !path.exists() {
            // no-dereference included here for compatibility
            if matches.is_present(options::NO_CREATE) || matches.is_present(options::NO_DEREF) {
                continue;
            }

            if let Err(e) = File::create(path) {
                show!(e.map_err_context(|| format!("cannot touch '{}'", path.display())));
                continue;
            };

            // Minor optimization: if no reference time was specified, we're done.
            if !matches.is_present(options::SOURCES) {
                continue;
            }
        }

        // If changing "only" atime or mtime, grab the existing value of the other.
        // Note that "-a" and "-m" may be passed together; this is not an xor.
        if matches.is_present(options::ACCESS)
            || matches.is_present(options::MODIFICATION)
            || matches.is_present(options::TIME)
        {
            let st = stat(path, !matches.is_present(options::NO_DEREF))?;
            let time = matches.value_of(options::TIME).unwrap_or("");

            if !(matches.is_present(options::ACCESS)
                || time.contains(&"access".to_owned())
                || time.contains(&"atime".to_owned())
                || time.contains(&"use".to_owned()))
            {
                atime = st.0;
            }

            if !(matches.is_present(options::MODIFICATION)
                || time.contains(&"modify".to_owned())
                || time.contains(&"mtime".to_owned()))
            {
                mtime = st.1;
            }
        }

        if matches.is_present(options::NO_DEREF) {
            set_symlink_file_times(path, atime, mtime)
        } else {
            filetime::set_file_times(path, atime, mtime)
        }
        .map_err_context(|| format!("setting times of '{}'", path.display()))?;
    }

    Ok(())
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(executable!())
        .version(crate_version!())
        .about(ABOUT)
        .arg(
            Arg::with_name(options::ACCESS)
                .short("a")
                .help("change only the access time"),
        )
        .arg(
            Arg::with_name(options::sources::CURRENT)
                .short("t")
                .help("use [[CC]YY]MMDDhhmm[.ss] instead of the current time")
                .value_name("STAMP")
                .takes_value(true),
        )
        .arg(
            Arg::with_name(options::sources::DATE)
                .short("d")
                .long(options::sources::DATE)
                .help("parse argument and use it instead of current time")
                .value_name("STRING"),
        )
        .arg(
            Arg::with_name(options::MODIFICATION)
                .short("m")
                .help("change only the modification time"),
        )
        .arg(
            Arg::with_name(options::NO_CREATE)
                .short("c")
                .long(options::NO_CREATE)
                .help("do not create any files"),
        )
        .arg(
            Arg::with_name(options::NO_DEREF)
                .short("h")
                .long(options::NO_DEREF)
                .help(
                    "affect each symbolic link instead of any referenced file \
                     (only for systems that can change the timestamps of a symlink)",
                ),
        )
        .arg(
            Arg::with_name(options::sources::REFERENCE)
                .short("r")
                .long(options::sources::REFERENCE)
                .help("use this file's times instead of the current time")
                .value_name("FILE"),
        )
        .arg(
            Arg::with_name(options::TIME)
                .long(options::TIME)
                .help(
                    "change only the specified time: \"access\", \"atime\", or \
                     \"use\" are equivalent to -a; \"modify\" or \"mtime\" are \
                     equivalent to -m",
                )
                .value_name("WORD")
                .possible_values(&["access", "atime", "use"])
                .takes_value(true),
        )
        .arg(
            Arg::with_name(ARG_FILES)
                .multiple(true)
                .takes_value(true)
                .min_values(1),
        )
        .group(ArgGroup::with_name(options::SOURCES).args(&[
            options::sources::CURRENT,
            options::sources::DATE,
            options::sources::REFERENCE,
        ]))
}

fn stat(path: &Path, follow: bool) -> UResult<(FileTime, FileTime)> {
    let metadata = if follow {
        fs::symlink_metadata(path)
    } else {
        fs::metadata(path)
    }
    .map_err_context(|| format!("failed to get attributes of '{}'", path.display()))?;

    Ok((
        FileTime::from_last_access_time(&metadata),
        FileTime::from_last_modification_time(&metadata),
    ))
}

fn parse_date(str: &str) -> UResult<FileTime> {
    // This isn't actually compatible with GNU touch, but there doesn't seem to
    // be any simple specification for what format this parameter allows and I'm
    // not about to implement GNU parse_datetime.
    // http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob_plain;f=lib/parse-datetime.y
    let formats = vec!["%c", "%F"];
    for f in formats {
        if let Ok(tm) = time::strptime(str, f) {
            return Ok(local_tm_to_filetime(to_local(tm)));
        }
    }

    if let Ok(tm) = time::strptime(str, "@%s") {
        // Don't convert to local time in this case - seconds since epoch are not time-zone dependent
        return Ok(local_tm_to_filetime(tm));
    }

    Err(USimpleError::new(
        1,
        format!("Unable to parse date: {}", str),
    ))
}

fn parse_timestamp(s: &str) -> UResult<FileTime> {
    let now = time::now();
    let (format, ts) = match s.chars().count() {
        15 => ("%Y%m%d%H%M.%S", s.to_owned()),
        12 => ("%Y%m%d%H%M", s.to_owned()),
        13 => ("%y%m%d%H%M.%S", s.to_owned()),
        10 => ("%y%m%d%H%M", s.to_owned()),
        11 => ("%Y%m%d%H%M.%S", format!("{}{}", now.tm_year + 1900, s)),
        8 => ("%Y%m%d%H%M", format!("{}{}", now.tm_year + 1900, s)),
        _ => return Err(USimpleError::new(1, format!("invalid date format '{}'", s))),
    };

    let tm = time::strptime(&ts, format)
        .map_err(|_| USimpleError::new(1, format!("invalid date format '{}'", s)))?;

    let mut local = to_local(tm);
    local.tm_isdst = -1;
    let ft = local_tm_to_filetime(local);

    // We have to check that ft is valid time. Due to daylight saving
    // time switch, local time can jump from 1:59 AM to 3:00 AM,
    // in which case any time between 2:00 AM and 2:59 AM is not valid.
    // Convert back to local time and see if we got the same value back.
    let ts = time::Timespec {
        sec: ft.unix_seconds(),
        nsec: 0,
    };
    let tm2 = time::at(ts);
    if tm.tm_hour != tm2.tm_hour {
        return Err(USimpleError::new(1, format!("invalid date format '{}'", s)));
    }

    Ok(ft)
}
<|endoftext|>


<commit_before>extern crate rand;

use std::io::prelude::*;
use std::fs::File;
use std::io::BufWriter;
use std::f32;
use rand::Rng;

// Terminals
#[allow(unused_variables)]
fn expr_x(x:f32, y:f32) -> f32 {
    return x;
}

#[allow(unused_variables)]
fn expr_y(x:f32, y:f32) -> f32 {
    return y;
}

// Single

fn expr_sin(e: f32) -> f32 {
    return f32::sin(f32::consts::PI * e);
}

fn expr_cos(e: f32) -> f32 {
    return f32::cos(f32::consts::PI * e);
}

fn expr_negate(e: f32) -> f32 {
    return -e;
}

fn expr_sqrt(e: f32) -> f32 {
    if e < 0.0 {
        return -f32::sqrt(-e);
    } else {
        return f32::sqrt(e);
    }
}

// Double

fn expr_arith_mean(e1: f32, e2: f32) -> f32 {
    return (e1 + e2) / 2.0;
}

fn expr_geo_mean(e1: f32, e2: f32) -> f32 {
    return expr_sqrt(e1 * e2);
}

fn expr_mult(e1: f32, e2: f32) -> f32 {
    return e1*e2;
}

fn expr_max(e1: f32, e2: f32) -> f32 {
    if e1 > e2 {
        return e1;
    } else {
        return e2;
    }
}

fn expr_min(e1: f32, e2: f32) -> f32 {
    if e1 > e2 {
        return e2;
    } else {
        return e1;
    }
}

type ExprTerminal = fn(f32, f32) -> f32;
type ExprSingle = fn(f32) -> f32;
type ExprDouble = fn(f32, f32) -> f32;

enum Expression {
    Terminal {
        expr: ExprTerminal
    },
    Single {
        expr: ExprSingle,
        e : Box<Expression>
    },
    Double {
        expr: ExprDouble,
        e1 : Box<Expression>,
        e2 : Box<Expression>
    }
}

fn build_expression(depth: i32, rng: &mut rand::ThreadRng) -> Box<Expression> {
    let terminals: [ExprTerminal; 2] = [expr_x, expr_y];
    let singles: [ExprSingle; 4] = [expr_sin, expr_cos, expr_negate, expr_sqrt];
    let doubles: [ExprDouble; 5] = [expr_arith_mean, expr_geo_mean, expr_mult, expr_min, expr_max];
    if depth == 1 {
        let f = terminals[rng.gen_range(0, 2)];
        let e = Box::new(Expression::Terminal { expr: f });
        return e;
    } else {
        let i = rng.gen_range(0, 4 + 5);
        if i < 4 {
            let e1 = build_expression(depth - 1, rng);
            let e = Box::new(Expression::Single { expr: singles[i], e: e1 });
            return e;
        } else {
            let e1 = build_expression(depth - 1, rng);
            let e2 = build_expression(depth - 1, rng);
            let e = Box::new(Expression::Double { expr: doubles[i - 4], e1: e1, e2: e2 });
            return e;
        }
    }
}

fn eval_expression(expression: &Box<Expression>, x: f32, y: f32) -> f32 {
    return match **expression {
        Expression::Terminal { expr }  => expr(x,y),
        Expression::Single {expr, ref e} => expr(eval_expression(e, x, y)),
        Expression::Double {expr, ref e1, ref e2} => expr(eval_expression(e1, x, y), eval_expression(e2, x, y))
    }
}

fn emit_greyscale(scale: i32, expr: Box<Expression>) {
    let size: usize = 2*(scale as usize) + 1;
    let mut output = BufWriter::new(File::create("test.pgm").unwrap());
    // So apparently the size of arrays in rust have to be a compile time
    // constant at the moment. Hardcode the value because whatever.
    write!(output, "P5 {} {} 255\n", size, size).unwrap();
    for xi in -scale .. (scale + 1) {
        for yi in -scale .. (scale + 1) {
            let x = xi as f32 / scale as f32;
            let y = yi as f32 / scale as f32;
            let intensity = (127.5 + 127.5*eval_expression(&expr, x, y)/2.0) as u8;
            let buf: [u8; 1] = [intensity];
            output.write(&buf).unwrap();
        }
    }
}

fn main() {
    let mut rng : rand::ThreadRng = rand::thread_rng();
    let expr = build_expression(15, &mut rng);
    emit_greyscale(150, expr);
}
<commit_msg>Change parameters from Box<T> to T&.<commit_after>extern crate rand;

use std::io::prelude::*;
use std::fs::File;
use std::io::BufWriter;
use std::f32;
use rand::Rng;

// Terminals
#[allow(unused_variables)]
fn expr_x(x:f32, y:f32) -> f32 {
    return x;
}

#[allow(unused_variables)]
fn expr_y(x:f32, y:f32) -> f32 {
    return y;
}

// Single

fn expr_sin(e: f32) -> f32 {
    return f32::sin(f32::consts::PI * e);
}

fn expr_cos(e: f32) -> f32 {
    return f32::cos(f32::consts::PI * e);
}

fn expr_negate(e: f32) -> f32 {
    return -e;
}

fn expr_sqrt(e: f32) -> f32 {
    if e < 0.0 {
        return -f32::sqrt(-e);
    } else {
        return f32::sqrt(e);
    }
}

// Double

fn expr_arith_mean(e1: f32, e2: f32) -> f32 {
    return (e1 + e2) / 2.0;
}

fn expr_geo_mean(e1: f32, e2: f32) -> f32 {
    return expr_sqrt(e1 * e2);
}

fn expr_mult(e1: f32, e2: f32) -> f32 {
    return e1*e2;
}

fn expr_max(e1: f32, e2: f32) -> f32 {
    if e1 > e2 {
        return e1;
    } else {
        return e2;
    }
}

fn expr_min(e1: f32, e2: f32) -> f32 {
    if e1 > e2 {
        return e2;
    } else {
        return e1;
    }
}

type ExprTerminal = fn(f32, f32) -> f32;
type ExprSingle = fn(f32) -> f32;
type ExprDouble = fn(f32, f32) -> f32;

enum Expression {
    Terminal {
        expr: ExprTerminal
    },
    Single {
        expr: ExprSingle,
        e : Box<Expression>
    },
    Double {
        expr: ExprDouble,
        e1 : Box<Expression>,
        e2 : Box<Expression>
    }
}

fn build_expression(depth: i32, rng: &mut rand::ThreadRng) -> Box<Expression> {
    let terminals: [ExprTerminal; 2] = [expr_x, expr_y];
    let singles: [ExprSingle; 4] = [expr_sin, expr_cos, expr_negate, expr_sqrt];
    let doubles: [ExprDouble; 5] = [expr_arith_mean, expr_geo_mean, expr_mult, expr_min, expr_max];
    if depth == 1 {
        let f = terminals[rng.gen_range(0, 2)];
        let e = Box::new(Expression::Terminal { expr: f });
        return e;
    } else {
        let i = rng.gen_range(0, 4 + 5);
        if i < 4 {
            let e1 = build_expression(depth - 1, rng);
            let e = Box::new(Expression::Single { expr: singles[i], e: e1 });
            return e;
        } else {
            let e1 = build_expression(depth - 1, rng);
            let e2 = build_expression(depth - 1, rng);
            let e = Box::new(Expression::Double { expr: doubles[i - 4], e1: e1, e2: e2 });
            return e;
        }
    }
}

fn eval_expression(expression: &Expression, x: f32, y: f32) -> f32 {
    return match *expression {
        Expression::Terminal { expr }  => expr(x,y),
        Expression::Single {expr, ref e} => expr(eval_expression((*e).as_ref(), x, y)),
        Expression::Double {expr, ref e1, ref e2} => expr(eval_expression((*e1).as_ref(), x, y), eval_expression((*e2).as_ref(), x, y))
    }
}

fn emit_greyscale(scale: i32, expr: &Expression) {
    let size: usize = 2*(scale as usize) + 1;
    let mut output = BufWriter::new(File::create("test.pgm").unwrap());
    // So apparently the size of arrays in rust have to be a compile time
    // constant at the moment. Hardcode the value because whatever.
    write!(output, "P5 {} {} 255\n", size, size).unwrap();
    for xi in -scale .. (scale + 1) {
        for yi in -scale .. (scale + 1) {
            let x = xi as f32 / scale as f32;
            let y = yi as f32 / scale as f32;
            let intensity = (127.5 + 127.5*eval_expression(&expr, x, y)/2.0) as u8;
            let buf: [u8; 1] = [intensity];
            output.write(&buf).unwrap();
        }
    }
}

fn main() {
    let mut rng : rand::ThreadRng = rand::thread_rng();
    let expr = build_expression(15, &mut rng);
    emit_greyscale(150, expr.as_ref());
}
<|endoftext|>


<commit_before>use ::alsa::PollDescriptors;
use ::alsa::mixer::{Mixer, SelemId, SelemChannelId};
use ::alsa::ctl::Ctl;

use format::data::Format;
use widget::base::Sender;

use std::sync::{Arc, RwLock};
use std::thread;
use std::ffi::CString;

use libc::{pollfd, poll}; // TODO use mio/epoll?

use super::{VolumeBackend, VolumeState};

pub struct ALSA {
    last_value: Arc<RwLock<Format>>,
}

impl ALSA {
    pub fn new() -> ALSA {
        ALSA {
            last_value: Arc::new(RwLock::new(Format::Str("".to_owned()))),
        }
    }

    fn get_volume_state() -> VolumeState {
        let mixer = Mixer::new("default", false).unwrap();
        let selem_id = SelemId::new("Master", 0);
        let selem = mixer.find_selem(&selem_id).unwrap();
        let (min, max) = selem.get_playback_volume_range();
        let volume = selem.get_playback_volume(SelemChannelId::FrontLeft).unwrap();
        let switch = selem.get_playback_switch(SelemChannelId::FrontLeft).unwrap();
        VolumeState {
            volume: (volume as f64 / (max - min) as f64) as f32,
            muted: switch == 0,
        }
    }
}

impl<F> VolumeBackend<F> for ALSA
    where F: Fn(VolumeState) -> Format + Sync + Send + 'static {

    fn current_value(&self) -> Format {
        (*self.last_value).read().unwrap().clone()
    }

    fn spawn_notifier(&mut self, tx: Sender<()>, updater: Arc<Box<F>>) {
        let ctl = Ctl::open(CString::new("default").unwrap().as_ref(), false).unwrap();
        ctl.subscribe_events(true).unwrap();

        let mut fds = Vec::<pollfd>::with_capacity(ctl.count());
        fds.resize(ctl.count(), pollfd {fd: 0, events: 0, revents: 0});
        let filled = ctl.fill(&mut fds).unwrap();
        assert!(filled == ctl.count());

        let last_value = self.last_value.clone();
        thread::spawn(move || {
            loop {
                unsafe {
                    let err = poll(fds.as_mut_ptr(), fds.len() as u64, -1);
                    // TODO check error
                }

                match ctl.read() {
                    Ok(Some(_)) => {
                        let state = ALSA::get_volume_state();

                        let mut writer = last_value.write().unwrap();
                        *writer = (*updater)(state);
                        let _ = tx.send(());
                    },
                    _ => continue
                }
            }
        });
    }
}

pub fn default_volume() -> FreeBSDSound {
    ALSA::new()
}
<commit_msg>fix an incorrect return type on `default_volume`<commit_after>use ::alsa::PollDescriptors;
use ::alsa::mixer::{Mixer, SelemId, SelemChannelId};
use ::alsa::ctl::Ctl;

use format::data::Format;
use widget::base::Sender;

use std::sync::{Arc, RwLock};
use std::thread;
use std::ffi::CString;

use libc::{pollfd, poll}; // TODO use mio/epoll?

use super::{VolumeBackend, VolumeState};

pub struct ALSA {
    last_value: Arc<RwLock<Format>>,
}

impl ALSA {
    pub fn new() -> ALSA {
        ALSA {
            last_value: Arc::new(RwLock::new(Format::Str("".to_owned()))),
        }
    }

    fn get_volume_state() -> VolumeState {
        let mixer = Mixer::new("default", false).unwrap();
        let selem_id = SelemId::new("Master", 0);
        let selem = mixer.find_selem(&selem_id).unwrap();
        let (min, max) = selem.get_playback_volume_range();
        let volume = selem.get_playback_volume(SelemChannelId::FrontLeft).unwrap();
        let switch = selem.get_playback_switch(SelemChannelId::FrontLeft).unwrap();
        VolumeState {
            volume: (volume as f64 / (max - min) as f64) as f32,
            muted: switch == 0,
        }
    }
}

impl<F> VolumeBackend<F> for ALSA
    where F: Fn(VolumeState) -> Format + Sync + Send + 'static {

    fn current_value(&self) -> Format {
        (*self.last_value).read().unwrap().clone()
    }

    fn spawn_notifier(&mut self, tx: Sender<()>, updater: Arc<Box<F>>) {
        let ctl = Ctl::open(CString::new("default").unwrap().as_ref(), false).unwrap();
        ctl.subscribe_events(true).unwrap();

        let mut fds = Vec::<pollfd>::with_capacity(ctl.count());
        fds.resize(ctl.count(), pollfd {fd: 0, events: 0, revents: 0});
        let filled = ctl.fill(&mut fds).unwrap();
        assert!(filled == ctl.count());

        let last_value = self.last_value.clone();
        thread::spawn(move || {
            loop {
                unsafe {
                    let err = poll(fds.as_mut_ptr(), fds.len() as u64, -1);
                    // TODO check error
                }

                match ctl.read() {
                    Ok(Some(_)) => {
                        let state = ALSA::get_volume_state();

                        let mut writer = last_value.write().unwrap();
                        *writer = (*updater)(state);
                        let _ = tx.send(());
                    },
                    _ => continue
                }
            }
        });
    }
}

pub fn default_volume() -> ALSA {
    ALSA::new()
}
<|endoftext|>


<commit_before>// Copyright 2013-2015, The Rust-GNOME Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use glib::{Value, Type};
use glib::translate::{FromGlibPtr, ToGlibPtr, from_glib};
use ffi;
use {TreeIter, TreePath};
use libc::c_void;
use glib;

pub struct TreeModel {
    pointer: *mut ffi::C_GtkTreeModel
}

impl TreeModel {
    pub fn get_flags(&self) -> ::TreeModelFlags {
        unsafe { ffi::gtk_tree_model_get_flags(self.pointer) }
    }

    pub fn get_n_columns(&self) -> i32 {
        unsafe { ffi::gtk_tree_model_get_n_columns(self.pointer) }
    }

    pub fn get_column_type(&self, index_: i32) -> Type {
        unsafe { from_glib(ffi::gtk_tree_model_get_column_type(self.pointer, index_)) }
    }

    pub fn get_iter(&self, iter: &mut TreeIter, path: &TreePath) -> bool {
        match unsafe { ffi::gtk_tree_model_get_iter(self.pointer, iter.unwrap_pointer(), path.unwrap_pointer()) } {
            0 => false,
            _ => true
        }
    }

    pub fn get_iter_from_string(&self, iter: &mut TreeIter, path_string: &str) -> bool {
        match unsafe { ffi::gtk_tree_model_get_iter_from_string(self.pointer, iter.unwrap_pointer(), path_string.borrow_to_glib().0) } {
                0 => false,
                _ => true
            }
    }

    pub fn get_iter_first(&self, iter: &mut TreeIter) -> bool {
        match unsafe { ffi::gtk_tree_model_get_iter_first(self.pointer, iter.unwrap_pointer()) } {
            0 => false,
            _ => true
        }
    }

    pub fn get_path(&self, iter: &TreeIter) -> Option<TreePath> {
        let tmp_pointer = unsafe { ffi::gtk_tree_model_get_path(self.pointer, iter.unwrap_pointer()) };

        if tmp_pointer.is_null() {
            None
        } else {
            Some(TreePath::wrap_pointer(tmp_pointer))
        }
    }

    pub fn get_value(&self, iter: &TreeIter, column: i32) -> Value {
        unsafe {
            let mut value = Value::new();
            ffi::gtk_tree_model_get_value(self.pointer, iter.unwrap_pointer(), column,
                value.as_mut_ptr());
            value
        }
    }

    pub fn iter_next(&self, iter: &mut TreeIter) -> bool {
        match unsafe { ffi::gtk_tree_model_iter_next(self.pointer, iter.unwrap_pointer()) } {
            0 => false,
            _ => true
        }
    }

    pub fn iter_previous(&self, iter: &mut TreeIter) -> bool {
        match unsafe { ffi::gtk_tree_model_iter_previous(self.pointer, iter.unwrap_pointer()) } {
            0 => false,
            _ => true
        }
    }

    pub fn iter_children(&self, iter: &mut TreeIter, parent: Option<&TreeIter>) -> bool {
        match unsafe {
            ffi::gtk_tree_model_iter_children(self.pointer,
                                              iter.unwrap_pointer(),
                                              if parent.is_none() { ::std::ptr::null_mut() } else { parent.unwrap().unwrap_pointer() })
        } {
            0 => false,
            _ => true
        }
    }

    pub fn iter_has_child(&self, iter: &TreeIter) -> bool {
        match unsafe { ffi::gtk_tree_model_iter_has_child(self.pointer, iter.unwrap_pointer()) } {
            0 => false,
            _ => true
        }
    }

    pub fn iter_n_children(&self, iter: &TreeIter) -> i32 {
        unsafe { ffi::gtk_tree_model_iter_n_children(self.pointer, iter.unwrap_pointer()) }
    }

    pub fn iter_nth_child(&self, iter: &mut TreeIter, parent: Option<&TreeIter>, n: i32) -> bool {
        match unsafe {
            ffi::gtk_tree_model_iter_nth_child(self.pointer,
                                               iter.unwrap_pointer(),
                                               if parent.is_none() { ::std::ptr::null_mut() } else { parent.unwrap().unwrap_pointer() },
                                               n)
        } {
            0 => false,
            _ => true
        }
    }

    pub fn iter_parent(&self, iter: &mut TreeIter, child: &TreeIter) -> bool {
        match unsafe { ffi::gtk_tree_model_iter_parent(self.pointer, iter.unwrap_pointer(), child.unwrap_pointer()) } {
            0 => false,
            _ => true
        }
    }

    pub fn get_string_from_iter(&self, iter: &TreeIter) -> Option<String> {
        unsafe {
            FromGlibPtr::take(
                ffi::gtk_tree_model_get_string_from_iter(self.pointer,
                                                         iter.unwrap_pointer()))
        }
    }

    pub fn row_changed(&self, path: &TreePath, iter: &TreeIter) {
        unsafe { ffi::gtk_tree_model_row_changed(self.pointer, path.unwrap_pointer(), iter.unwrap_pointer()) }
    }

    pub fn row_inserted(&self, path: &TreePath, iter: &TreeIter) {
        unsafe { ffi::gtk_tree_model_row_inserted(self.pointer, path.unwrap_pointer(), iter.unwrap_pointer()) }
    }

    pub fn row_has_child_toggled(&self, path: &TreePath, iter: &TreeIter) {
        unsafe { ffi::gtk_tree_model_row_has_child_toggled(self.pointer, path.unwrap_pointer(), iter.unwrap_pointer()) }
    }

    pub fn row_deleted(&self, path: &TreePath) {
        unsafe { ffi::gtk_tree_model_row_deleted(self.pointer, path.unwrap_pointer()) }
    }

    pub fn rows_reordered(&self, path: &TreePath, iter: Option<&TreeIter>, new_order: &mut [i32]) {
        unsafe {
            ffi::gtk_tree_model_rows_reordered(self.pointer,
                                               path.unwrap_pointer(),
                                               if iter.is_none() { ::std::ptr::null_mut() } else { iter.unwrap().unwrap_pointer() },
                                               new_order.as_mut_ptr())
        }
    }

    pub fn ref_node(&self, iter: &TreeIter) {
        unsafe { ffi::gtk_tree_model_ref_node(self.pointer, iter.unwrap_pointer()) }
    }

    pub fn unref_node(&self, iter: &TreeIter) {
        unsafe { ffi::gtk_tree_model_unref_node(self.pointer, iter.unwrap_pointer()) }
    }

    pub fn foreach<T>(&self, func: fn(&mut TreeModel, &mut TreePath, &mut TreeIter, data: &mut T) -> bool, user_data: &mut T) {
        let t = &(func, user_data);
        let ca = t as *const (fn(&mut TreeModel, &mut TreePath, &mut TreeIter, data: &mut T) -> bool, &mut T);

        unsafe { ffi::gtk_tree_model_foreach(self.pointer, my_fn as ffi::gpointer, ca as ffi::gpointer) }
    }

    #[doc(hidden)]
    pub fn unwrap_pointer(&self) -> *mut ffi::C_GtkTreeModel {
        self.pointer
    }

    #[doc(hidden)]
    pub fn wrap_pointer(c_treemodel: *mut ffi::C_GtkTreeModel) -> TreeModel {
        TreeModel {
            pointer: c_treemodel
        }
    }
}

fn my_fn(model: *mut ffi::C_GtkTreeModel, path: *mut ffi::C_GtkTreePath, iter: *mut ffi::C_GtkTreeIter,
    data: &mut (fn(&mut TreeModel, &mut TreePath, &mut TreeIter, data: *mut c_void) -> bool, &mut c_void)) -> ffi::Gboolean {
    glib::to_gboolean(data.0(&mut TreeModel::wrap_pointer(model), &mut TreePath::wrap_pointer(path), &mut TreeIter::wrap_pointer(iter), data.1))
}

impl_drop!(TreeModel, GTK_TREE_MODEL);<commit_msg>Update iter_n_children<commit_after>// Copyright 2013-2015, The Rust-GNOME Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use glib::{Value, Type};
use glib::translate::{FromGlibPtr, ToGlibPtr, from_glib};
use ffi;
use {TreeIter, TreePath};
use libc::c_void;
use glib;

pub struct TreeModel {
    pointer: *mut ffi::C_GtkTreeModel
}

impl TreeModel {
    pub fn get_flags(&self) -> ::TreeModelFlags {
        unsafe { ffi::gtk_tree_model_get_flags(self.pointer) }
    }

    pub fn get_n_columns(&self) -> i32 {
        unsafe { ffi::gtk_tree_model_get_n_columns(self.pointer) }
    }

    pub fn get_column_type(&self, index_: i32) -> Type {
        unsafe { from_glib(ffi::gtk_tree_model_get_column_type(self.pointer, index_)) }
    }

    pub fn get_iter(&self, iter: &mut TreeIter, path: &TreePath) -> bool {
        match unsafe { ffi::gtk_tree_model_get_iter(self.pointer, iter.unwrap_pointer(), path.unwrap_pointer()) } {
            0 => false,
            _ => true
        }
    }

    pub fn get_iter_from_string(&self, iter: &mut TreeIter, path_string: &str) -> bool {
        match unsafe { ffi::gtk_tree_model_get_iter_from_string(self.pointer, iter.unwrap_pointer(), path_string.borrow_to_glib().0) } {
                0 => false,
                _ => true
            }
    }

    pub fn get_iter_first(&self, iter: &mut TreeIter) -> bool {
        match unsafe { ffi::gtk_tree_model_get_iter_first(self.pointer, iter.unwrap_pointer()) } {
            0 => false,
            _ => true
        }
    }

    pub fn get_path(&self, iter: &TreeIter) -> Option<TreePath> {
        let tmp_pointer = unsafe { ffi::gtk_tree_model_get_path(self.pointer, iter.unwrap_pointer()) };

        if tmp_pointer.is_null() {
            None
        } else {
            Some(TreePath::wrap_pointer(tmp_pointer))
        }
    }

    pub fn get_value(&self, iter: &TreeIter, column: i32) -> Value {
        unsafe {
            let mut value = Value::new();
            ffi::gtk_tree_model_get_value(self.pointer, iter.unwrap_pointer(), column,
                value.as_mut_ptr());
            value
        }
    }

    pub fn iter_next(&self, iter: &mut TreeIter) -> bool {
        match unsafe { ffi::gtk_tree_model_iter_next(self.pointer, iter.unwrap_pointer()) } {
            0 => false,
            _ => true
        }
    }

    pub fn iter_previous(&self, iter: &mut TreeIter) -> bool {
        match unsafe { ffi::gtk_tree_model_iter_previous(self.pointer, iter.unwrap_pointer()) } {
            0 => false,
            _ => true
        }
    }

    pub fn iter_children(&self, iter: &mut TreeIter, parent: Option<&TreeIter>) -> bool {
        match unsafe {
            ffi::gtk_tree_model_iter_children(self.pointer,
                                              iter.unwrap_pointer(),
                                              if parent.is_none() { ::std::ptr::null_mut() } else { parent.unwrap().unwrap_pointer() })
        } {
            0 => false,
            _ => true
        }
    }

    pub fn iter_has_child(&self, iter: &TreeIter) -> bool {
        match unsafe { ffi::gtk_tree_model_iter_has_child(self.pointer, iter.unwrap_pointer()) } {
            0 => false,
            _ => true
        }
    }

    pub fn iter_n_children(&self, iter: Option<&TreeIter>) -> i32 {
        unsafe { ffi::gtk_tree_model_iter_n_children(self.pointer, match iter {
                Some(i) => i.unwrap_pointer(),
                None => ::std::ptr::null_mut()
            }) }
    }

    pub fn iter_nth_child(&self, iter: &mut TreeIter, parent: Option<&TreeIter>, n: i32) -> bool {
        match unsafe {
            ffi::gtk_tree_model_iter_nth_child(self.pointer,
                iter.unwrap_pointer(),
                match parent {
                    Some(p) => p.unwrap_pointer(),
                    None => ::std::ptr::null_mut()
                },
                n)
        } {
            0 => false,
            _ => true
        }
    }

    pub fn iter_parent(&self, iter: &mut TreeIter, child: &TreeIter) -> bool {
        match unsafe { ffi::gtk_tree_model_iter_parent(self.pointer, iter.unwrap_pointer(), child.unwrap_pointer()) } {
            0 => false,
            _ => true
        }
    }

    pub fn get_string_from_iter(&self, iter: &TreeIter) -> Option<String> {
        unsafe {
            FromGlibPtr::take(
                ffi::gtk_tree_model_get_string_from_iter(self.pointer,
                                                         iter.unwrap_pointer()))
        }
    }

    pub fn row_changed(&self, path: &TreePath, iter: &TreeIter) {
        unsafe { ffi::gtk_tree_model_row_changed(self.pointer, path.unwrap_pointer(), iter.unwrap_pointer()) }
    }

    pub fn row_inserted(&self, path: &TreePath, iter: &TreeIter) {
        unsafe { ffi::gtk_tree_model_row_inserted(self.pointer, path.unwrap_pointer(), iter.unwrap_pointer()) }
    }

    pub fn row_has_child_toggled(&self, path: &TreePath, iter: &TreeIter) {
        unsafe { ffi::gtk_tree_model_row_has_child_toggled(self.pointer, path.unwrap_pointer(), iter.unwrap_pointer()) }
    }

    pub fn row_deleted(&self, path: &TreePath) {
        unsafe { ffi::gtk_tree_model_row_deleted(self.pointer, path.unwrap_pointer()) }
    }

    pub fn rows_reordered(&self, path: &TreePath, iter: Option<&TreeIter>, new_order: &mut [i32]) {
        unsafe {
            ffi::gtk_tree_model_rows_reordered(self.pointer,
                                               path.unwrap_pointer(),
                                               if iter.is_none() { ::std::ptr::null_mut() } else { iter.unwrap().unwrap_pointer() },
                                               new_order.as_mut_ptr())
        }
    }

    pub fn ref_node(&self, iter: &TreeIter) {
        unsafe { ffi::gtk_tree_model_ref_node(self.pointer, iter.unwrap_pointer()) }
    }

    pub fn unref_node(&self, iter: &TreeIter) {
        unsafe { ffi::gtk_tree_model_unref_node(self.pointer, iter.unwrap_pointer()) }
    }

    pub fn foreach<T>(&self, func: fn(&mut TreeModel, &mut TreePath, &mut TreeIter, data: &mut T) -> bool, user_data: &mut T) {
        let t = &(func, user_data);
        let ca = t as *const (fn(&mut TreeModel, &mut TreePath, &mut TreeIter, data: &mut T) -> bool, &mut T);

        unsafe { ffi::gtk_tree_model_foreach(self.pointer, my_fn as ffi::gpointer, ca as ffi::gpointer) }
    }

    #[doc(hidden)]
    pub fn unwrap_pointer(&self) -> *mut ffi::C_GtkTreeModel {
        self.pointer
    }

    #[doc(hidden)]
    pub fn wrap_pointer(c_treemodel: *mut ffi::C_GtkTreeModel) -> TreeModel {
        TreeModel {
            pointer: c_treemodel
        }
    }
}

fn my_fn(model: *mut ffi::C_GtkTreeModel, path: *mut ffi::C_GtkTreePath, iter: *mut ffi::C_GtkTreeIter,
    data: &mut (fn(&mut TreeModel, &mut TreePath, &mut TreeIter, data: *mut c_void) -> bool, &mut c_void)) -> ffi::Gboolean {
    glib::to_gboolean(data.0(&mut TreeModel::wrap_pointer(model), &mut TreePath::wrap_pointer(path), &mut TreeIter::wrap_pointer(iter), data.1))
}

impl_drop!(TreeModel, GTK_TREE_MODEL);<|endoftext|>


<commit_before>mod progress;

use self::progress::Progress;
use anyhow::Result;
use flate2::read::GzDecoder;
use std::fs;
use std::path::Path;
use tar::Archive;
use walkdir::DirEntry;

const REVISION: &str = "ac2d9fc509e36d1b32513744adf58c34bcc4f43c";

#[rustfmt::skip]
static EXCLUDE: &[&str] = &[
    // NEEDS CATEGORIZATION
    "library/alloc/src/borrow.rs",
    "src/test/ui/parser/macro-braces-dot-question.rs",
    "src/test/ui/rfc-2632-const-trait-impl/inherent-impl-const-bounds.rs",

    // TODO: impl ~const T {}
    // https://github.com/dtolnay/syn/issues/1051
    "src/test/ui/rfc-2632-const-trait-impl/syntax.rs",

    // TODO: ~const in where-clause
    // https://github.com/dtolnay/syn/issues/1051
    "src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-run.rs",
    "src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs",

    // Compile-fail expr parameter in const generic position: f::<1 + 2>()
    "src/test/ui/const-generics/early/closing-args-token.rs",
    "src/test/ui/const-generics/early/const-expression-parameter.rs",

    // Deprecated anonymous parameter syntax in traits
    "src/test/ui/issues/issue-13105.rs",
    "src/test/ui/issues/issue-13775.rs",
    "src/test/ui/issues/issue-34074.rs",
    "src/test/ui/proc-macro/trait-fn-args-2015.rs",
    "src/tools/rustfmt/tests/source/trait.rs",
    "src/tools/rustfmt/tests/target/trait.rs",

    // Excessive nesting
    "src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs",

    // Testing rustfmt on invalid syntax
    "src/tools/rustfmt/tests/coverage/target/comments.rs",
    "src/tools/rustfmt/tests/parser/issue-4126/invalid.rs",
    "src/tools/rustfmt/tests/parser/issue_4418.rs",
    "src/tools/rustfmt/tests/parser/unclosed-delims/issue_4466.rs",
    "src/tools/rustfmt/tests/source/configs/disable_all_formatting/true.rs",
    "src/tools/rustfmt/tests/source/configs/spaces_around_ranges/false.rs",
    "src/tools/rustfmt/tests/source/configs/spaces_around_ranges/true.rs",
    "src/tools/rustfmt/tests/source/type.rs",
    "src/tools/rustfmt/tests/target/configs/spaces_around_ranges/false.rs",
    "src/tools/rustfmt/tests/target/configs/spaces_around_ranges/true.rs",
    "src/tools/rustfmt/tests/target/type.rs",

    // Not actually test cases
    "src/test/rustdoc-ui/test-compile-fail2.rs",
    "src/test/rustdoc-ui/test-compile-fail3.rs",
    "src/test/ui/include-single-expr-helper.rs",
    "src/test/ui/include-single-expr-helper-1.rs",
    "src/test/ui/json-bom-plus-crlf-multifile-aux.rs",
    "src/test/ui/lint/expansion-time-include.rs",
    "src/test/ui/macros/auxiliary/macro-comma-support.rs",
    "src/test/ui/macros/auxiliary/macro-include-items-expr.rs",
    "src/test/ui/parser/auxiliary/issue-21146-inc.rs",
];

pub fn base_dir_filter(entry: &DirEntry) -> bool {
    let path = entry.path();
    if path.is_dir() {
        return true; // otherwise walkdir does not visit the files
    }
    if path.extension().map(|e| e != "rs").unwrap_or(true) {
        return false;
    }

    let mut path_string = path.to_string_lossy();
    if cfg!(windows) {
        path_string = path_string.replace('\\', "/").into();
    }
    let path = if let Some(path) = path_string.strip_prefix("tests/rust/") {
        path
    } else {
        panic!("unexpected path in Rust dist: {}", path_string);
    };

    if path.starts_with("src/test/compile-fail") || path.starts_with("src/test/rustfix") {
        return false;
    }

    if path.starts_with("src/test/ui") {
        let stderr_path = entry.path().with_extension("stderr");
        if stderr_path.exists() {
            // Expected to fail in some way
            return false;
        }
    }

    !EXCLUDE.contains(&path)
}

#[allow(dead_code)]
pub fn edition(path: &Path) -> &'static str {
    if path.ends_with("dyn-2015-no-warnings-without-lints.rs") {
        "2015"
    } else {
        "2018"
    }
}

pub fn clone_rust() {
    let needs_clone = match fs::read_to_string("tests/rust/COMMIT") {
        Err(_) => true,
        Ok(contents) => contents.trim() != REVISION,
    };
    if needs_clone {
        download_and_unpack().unwrap();
    }
    let mut missing = String::new();
    let test_src = Path::new("tests/rust");
    for exclude in EXCLUDE {
        if !test_src.join(exclude).exists() {
            missing += "\ntests/rust/";
            missing += exclude;
        }
    }
    if !missing.is_empty() {
        panic!("excluded test file does not exist:{}\n", missing);
    }
}

fn download_and_unpack() -> Result<()> {
    let url = format!(
        "https://github.com/rust-lang/rust/archive/{}.tar.gz",
        REVISION
    );
    let response = reqwest::blocking::get(&url)?.error_for_status()?;
    let progress = Progress::new(response);
    let decoder = GzDecoder::new(progress);
    let mut archive = Archive::new(decoder);
    let prefix = format!("rust-{}", REVISION);

    let tests_rust = Path::new("tests/rust");
    if tests_rust.exists() {
        fs::remove_dir_all(tests_rust)?;
    }

    for entry in archive.entries()? {
        let mut entry = entry?;
        let path = entry.path()?;
        if path == Path::new("pax_global_header") {
            continue;
        }
        let relative = path.strip_prefix(&prefix)?;
        let out = tests_rust.join(relative);
        entry.unpack(&out)?;
    }

    fs::write("tests/rust/COMMIT", REVISION)?;
    Ok(())
}
<commit_msg>Categorize new test suite parse failures<commit_after>mod progress;

use self::progress::Progress;
use anyhow::Result;
use flate2::read::GzDecoder;
use std::fs;
use std::path::Path;
use tar::Archive;
use walkdir::DirEntry;

const REVISION: &str = "ac2d9fc509e36d1b32513744adf58c34bcc4f43c";

#[rustfmt::skip]
static EXCLUDE: &[&str] = &[
    // TODO: dot after curly braced macro call: macro!{...}.field
    // https://github.com/dtolnay/syn/issues/1068
    "src/test/ui/parser/macro-braces-dot-question.rs",

    // TODO: impl ~const T {}
    // https://github.com/dtolnay/syn/issues/1051
    "src/test/ui/rfc-2632-const-trait-impl/syntax.rs",

    // TODO: ~const in where-clause
    // https://github.com/dtolnay/syn/issues/1051
    "library/alloc/src/borrow.rs",
    "src/test/ui/rfc-2632-const-trait-impl/inherent-impl-const-bounds.rs",
    "src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-run.rs",
    "src/test/ui/rfc-2632-const-trait-impl/trait-where-clause-self-referential.rs",

    // Compile-fail expr parameter in const generic position: f::<1 + 2>()
    "src/test/ui/const-generics/early/closing-args-token.rs",
    "src/test/ui/const-generics/early/const-expression-parameter.rs",

    // Deprecated anonymous parameter syntax in traits
    "src/test/ui/issues/issue-13105.rs",
    "src/test/ui/issues/issue-13775.rs",
    "src/test/ui/issues/issue-34074.rs",
    "src/test/ui/proc-macro/trait-fn-args-2015.rs",
    "src/tools/rustfmt/tests/source/trait.rs",
    "src/tools/rustfmt/tests/target/trait.rs",

    // Excessive nesting
    "src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs",

    // Testing rustfmt on invalid syntax
    "src/tools/rustfmt/tests/coverage/target/comments.rs",
    "src/tools/rustfmt/tests/parser/issue-4126/invalid.rs",
    "src/tools/rustfmt/tests/parser/issue_4418.rs",
    "src/tools/rustfmt/tests/parser/unclosed-delims/issue_4466.rs",
    "src/tools/rustfmt/tests/source/configs/disable_all_formatting/true.rs",
    "src/tools/rustfmt/tests/source/configs/spaces_around_ranges/false.rs",
    "src/tools/rustfmt/tests/source/configs/spaces_around_ranges/true.rs",
    "src/tools/rustfmt/tests/source/type.rs",
    "src/tools/rustfmt/tests/target/configs/spaces_around_ranges/false.rs",
    "src/tools/rustfmt/tests/target/configs/spaces_around_ranges/true.rs",
    "src/tools/rustfmt/tests/target/type.rs",

    // Not actually test cases
    "src/test/rustdoc-ui/test-compile-fail2.rs",
    "src/test/rustdoc-ui/test-compile-fail3.rs",
    "src/test/ui/include-single-expr-helper.rs",
    "src/test/ui/include-single-expr-helper-1.rs",
    "src/test/ui/json-bom-plus-crlf-multifile-aux.rs",
    "src/test/ui/lint/expansion-time-include.rs",
    "src/test/ui/macros/auxiliary/macro-comma-support.rs",
    "src/test/ui/macros/auxiliary/macro-include-items-expr.rs",
    "src/test/ui/parser/auxiliary/issue-21146-inc.rs",
];

pub fn base_dir_filter(entry: &DirEntry) -> bool {
    let path = entry.path();
    if path.is_dir() {
        return true; // otherwise walkdir does not visit the files
    }
    if path.extension().map(|e| e != "rs").unwrap_or(true) {
        return false;
    }

    let mut path_string = path.to_string_lossy();
    if cfg!(windows) {
        path_string = path_string.replace('\\', "/").into();
    }
    let path = if let Some(path) = path_string.strip_prefix("tests/rust/") {
        path
    } else {
        panic!("unexpected path in Rust dist: {}", path_string);
    };

    if path.starts_with("src/test/compile-fail") || path.starts_with("src/test/rustfix") {
        return false;
    }

    if path.starts_with("src/test/ui") {
        let stderr_path = entry.path().with_extension("stderr");
        if stderr_path.exists() {
            // Expected to fail in some way
            return false;
        }
    }

    !EXCLUDE.contains(&path)
}

#[allow(dead_code)]
pub fn edition(path: &Path) -> &'static str {
    if path.ends_with("dyn-2015-no-warnings-without-lints.rs") {
        "2015"
    } else {
        "2018"
    }
}

pub fn clone_rust() {
    let needs_clone = match fs::read_to_string("tests/rust/COMMIT") {
        Err(_) => true,
        Ok(contents) => contents.trim() != REVISION,
    };
    if needs_clone {
        download_and_unpack().unwrap();
    }
    let mut missing = String::new();
    let test_src = Path::new("tests/rust");
    for exclude in EXCLUDE {
        if !test_src.join(exclude).exists() {
            missing += "\ntests/rust/";
            missing += exclude;
        }
    }
    if !missing.is_empty() {
        panic!("excluded test file does not exist:{}\n", missing);
    }
}

fn download_and_unpack() -> Result<()> {
    let url = format!(
        "https://github.com/rust-lang/rust/archive/{}.tar.gz",
        REVISION
    );
    let response = reqwest::blocking::get(&url)?.error_for_status()?;
    let progress = Progress::new(response);
    let decoder = GzDecoder::new(progress);
    let mut archive = Archive::new(decoder);
    let prefix = format!("rust-{}", REVISION);

    let tests_rust = Path::new("tests/rust");
    if tests_rust.exists() {
        fs::remove_dir_all(tests_rust)?;
    }

    for entry in archive.entries()? {
        let mut entry = entry?;
        let path = entry.path()?;
        if path == Path::new("pax_global_header") {
            continue;
        }
        let relative = path.strip_prefix(&prefix)?;
        let out = tests_rust.join(relative);
        entry.unpack(&out)?;
    }

    fs::write("tests/rust/COMMIT", REVISION)?;
    Ok(())
}
<|endoftext|>


<commit_before>use anyhow::Result;
use flate2::read::GzDecoder;
use std::fs;
use std::path::Path;
use tar::Archive;
use walkdir::DirEntry;

static REVISION: &'static str = "7979016aff545f7b41cc517031026020b340989d";

pub fn base_dir_filter(entry: &DirEntry) -> bool {
    let path = entry.path();
    if path.is_dir() {
        return true; // otherwise walkdir does not visit the files
    }
    if path.extension().map(|e| e != "rs").unwrap_or(true) {
        return false;
    }
    let path_string = path.to_string_lossy();
    let path_string = if cfg!(windows) {
        path_string.replace('\\', "/").into()
    } else {
        path_string
    };
    // TODO assert that parsing fails on the parse-fail cases
    if path_string.starts_with("tests/rust/src/test/parse-fail")
        || path_string.starts_with("tests/rust/src/test/compile-fail")
        || path_string.starts_with("tests/rust/src/test/rustfix")
    {
        return false;
    }

    if path_string.starts_with("tests/rust/src/test/ui") {
        let stderr_path = path.with_extension("stderr");
        if stderr_path.exists() {
            // Expected to fail in some way
            return false;
        }
    }

    match path_string.as_ref() {
        // Deprecated placement syntax
        "tests/rust/src/test/ui/obsolete-in-place/bad.rs" |
        // Deprecated anonymous parameter syntax in traits
        "tests/rust/src/test/ui/error-codes/e0119/auxiliary/issue-23563-a.rs" |
        "tests/rust/src/test/ui/issues/issue-13105.rs" |
        "tests/rust/src/test/ui/issues/issue-13775.rs" |
        "tests/rust/src/test/ui/issues/issue-34074.rs" |
        // Deprecated await macro syntax
        "tests/rust/src/test/ui/async-await/await-macro.rs" |
        // 2015-style dyn that libsyntax rejects
        "tests/rust/src/test/ui/dyn-keyword/dyn-2015-no-warnings-without-lints.rs" |
        // not actually test cases
        "tests/rust/src/test/ui/include-single-expr-helper.rs" |
        "tests/rust/src/test/ui/include-single-expr-helper-1.rs" |
        "tests/rust/src/test/ui/issues/auxiliary/issue-21146-inc.rs" |
        "tests/rust/src/test/ui/macros/auxiliary/macro-comma-support.rs" |
        "tests/rust/src/test/ui/macros/auxiliary/macro-include-items-expr.rs" => false,
        _ => true,
    }
}

pub fn clone_rust() {
    let needs_clone = match fs::read_to_string("tests/rust/COMMIT") {
        Err(_) => true,
        Ok(contents) => contents.trim() != REVISION,
    };
    if needs_clone {
        download_and_unpack().unwrap();
    }
}

fn download_and_unpack() -> Result<()> {
    let url = format!(
        "https://github.com/rust-lang/rust/archive/{}.tar.gz",
        REVISION
    );
    let request = reqwest::blocking::get(&url)?;
    let decoder = GzDecoder::new(request);
    let mut archive = Archive::new(decoder);
    let prefix = format!("rust-{}", REVISION);

    let tests_rust = Path::new("tests/rust");
    if tests_rust.exists() {
        fs::remove_dir_all(tests_rust)?;
    }

    for entry in archive.entries()? {
        let mut entry = entry?;
        let path = entry.path()?;
        if path == Path::new("pax_global_header") {
            continue;
        }
        let relative = path.strip_prefix(&prefix)?;
        let out = tests_rust.join(relative);
        entry.unpack(&out)?;
    }

    fs::write("tests/rust/COMMIT", REVISION)?;
    Ok(())
}
<commit_msg>Remove unneeded lifetime from static in test<commit_after>use anyhow::Result;
use flate2::read::GzDecoder;
use std::fs;
use std::path::Path;
use tar::Archive;
use walkdir::DirEntry;

const REVISION: &str = "7979016aff545f7b41cc517031026020b340989d";

pub fn base_dir_filter(entry: &DirEntry) -> bool {
    let path = entry.path();
    if path.is_dir() {
        return true; // otherwise walkdir does not visit the files
    }
    if path.extension().map(|e| e != "rs").unwrap_or(true) {
        return false;
    }
    let path_string = path.to_string_lossy();
    let path_string = if cfg!(windows) {
        path_string.replace('\\', "/").into()
    } else {
        path_string
    };
    // TODO assert that parsing fails on the parse-fail cases
    if path_string.starts_with("tests/rust/src/test/parse-fail")
        || path_string.starts_with("tests/rust/src/test/compile-fail")
        || path_string.starts_with("tests/rust/src/test/rustfix")
    {
        return false;
    }

    if path_string.starts_with("tests/rust/src/test/ui") {
        let stderr_path = path.with_extension("stderr");
        if stderr_path.exists() {
            // Expected to fail in some way
            return false;
        }
    }

    match path_string.as_ref() {
        // Deprecated placement syntax
        "tests/rust/src/test/ui/obsolete-in-place/bad.rs" |
        // Deprecated anonymous parameter syntax in traits
        "tests/rust/src/test/ui/error-codes/e0119/auxiliary/issue-23563-a.rs" |
        "tests/rust/src/test/ui/issues/issue-13105.rs" |
        "tests/rust/src/test/ui/issues/issue-13775.rs" |
        "tests/rust/src/test/ui/issues/issue-34074.rs" |
        // Deprecated await macro syntax
        "tests/rust/src/test/ui/async-await/await-macro.rs" |
        // 2015-style dyn that libsyntax rejects
        "tests/rust/src/test/ui/dyn-keyword/dyn-2015-no-warnings-without-lints.rs" |
        // not actually test cases
        "tests/rust/src/test/ui/include-single-expr-helper.rs" |
        "tests/rust/src/test/ui/include-single-expr-helper-1.rs" |
        "tests/rust/src/test/ui/issues/auxiliary/issue-21146-inc.rs" |
        "tests/rust/src/test/ui/macros/auxiliary/macro-comma-support.rs" |
        "tests/rust/src/test/ui/macros/auxiliary/macro-include-items-expr.rs" => false,
        _ => true,
    }
}

pub fn clone_rust() {
    let needs_clone = match fs::read_to_string("tests/rust/COMMIT") {
        Err(_) => true,
        Ok(contents) => contents.trim() != REVISION,
    };
    if needs_clone {
        download_and_unpack().unwrap();
    }
}

fn download_and_unpack() -> Result<()> {
    let url = format!(
        "https://github.com/rust-lang/rust/archive/{}.tar.gz",
        REVISION
    );
    let request = reqwest::blocking::get(&url)?;
    let decoder = GzDecoder::new(request);
    let mut archive = Archive::new(decoder);
    let prefix = format!("rust-{}", REVISION);

    let tests_rust = Path::new("tests/rust");
    if tests_rust.exists() {
        fs::remove_dir_all(tests_rust)?;
    }

    for entry in archive.entries()? {
        let mut entry = entry?;
        let path = entry.path()?;
        if path == Path::new("pax_global_header") {
            continue;
        }
        let relative = path.strip_prefix(&prefix)?;
        let out = tests_rust.join(relative);
        entry.unpack(&out)?;
    }

    fs::write("tests/rust/COMMIT", REVISION)?;
    Ok(())
}
<|endoftext|>


<commit_before>//! Tools for handling XML from AWS with helper functions for testing.
//!
//! Wraps an XML stack via traits.
//! Also provides a method of supplying an XML stack from a file for testing purposes.

use std::collections::HashMap;
use std::io;
use std::iter::Peekable;
use std::num::ParseIntError;
use xml;
use xml::reader::{EventReader, Events, ParserConfig, XmlEvent};
use xml::writer::EventWriter;

use crate::{error::RusotoError, request::HttpResponse};

/// generic Error for XML parsing
#[derive(Debug)]
pub struct XmlParseError(pub String);

impl XmlParseError {
    pub fn new(msg: &str) -> XmlParseError {
        XmlParseError(msg.to_string())
    }
}

/// syntactic sugar for the XML event stack we pass around
pub type XmlStack<'a> = Peekable<Events<&'a [u8]>>;

/// Peek at next items in the XML stack
pub trait Peek {
    fn peek(&mut self) -> Option<&Result<XmlEvent, xml::reader::Error>>;
}

/// Move to the next part of the XML stack
pub trait Next {
    fn next(&mut self) -> Option<Result<XmlEvent, xml::reader::Error>>;
}

/// Wraps the Hyper Response type
pub struct XmlResponse<'b> {
    xml_stack: Peekable<Events<&'b [u8]>>, // refactor to use XmlStack type?
}

impl<'b> XmlResponse<'b> {
    pub fn new(stack: Peekable<Events<&'b [u8]>>) -> XmlResponse {
        XmlResponse { xml_stack: stack }
    }
}

impl<'b> Peek for XmlResponse<'b> {
    fn peek(&mut self) -> Option<&Result<XmlEvent, xml::reader::Error>> {
        while let Some(&Ok(XmlEvent::Whitespace(_))) = self.xml_stack.peek() {
            self.xml_stack.next();
        }
        self.xml_stack.peek()
    }
}

impl<'b> Next for XmlResponse<'b> {
    fn next(&mut self) -> Option<Result<XmlEvent, xml::reader::Error>> {
        let mut maybe_event;
        loop {
            maybe_event = self.xml_stack.next();
            match maybe_event {
                Some(Ok(XmlEvent::Whitespace(_))) => {}
                _ => break,
            }
        }
        maybe_event
    }
}

impl From<ParseIntError> for XmlParseError {
    fn from(_e: ParseIntError) -> XmlParseError {
        XmlParseError::new("ParseIntError")
    }
}

/// return a string field with the right name or throw a parse error
pub fn string_field<T: Peek + Next>(name: &str, stack: &mut T) -> Result<String, XmlParseError> {
    start_element(name, stack)?;
    let value = characters(stack)?;
    end_element(name, stack)?;
    Ok(value)
}

pub fn write_characters_element<W>(
    writer: &mut EventWriter<W>,
    name: &str,
    value_str: &str,
) -> Result<(), xml::writer::Error>
where
    W: io::Write,
{
    writer.write(xml::writer::XmlEvent::start_element(name))?;
    writer.write(xml::writer::XmlEvent::characters(value_str))?;
    writer.write(xml::writer::XmlEvent::end_element())
}

/// return some XML Characters
pub fn characters<T: Peek + Next>(stack: &mut T) -> Result<String, XmlParseError> {
    {
        // Lexical lifetime
        // Check to see if the next element is an end tag.
        // If it is, return an empty string.
        let current = stack.peek();
        if let Some(&Ok(XmlEvent::EndElement { .. })) = current {
            return Ok("".to_string());
        }
    }
    if let Some(Ok(XmlEvent::Characters(data))) = stack.next() {
        Ok(data)
    } else {
        Err(XmlParseError::new("Expected characters"))
    }
}

/// get the name of the current element in the stack.  throw a parse error if it's not a `StartElement`
pub fn peek_at_name<T: Peek + Next>(stack: &mut T) -> Result<String, XmlParseError> {
    let current = stack.peek();
    if let Some(&Ok(XmlEvent::StartElement { ref name, .. })) = current {
        Ok(name.local_name.to_string())
    } else {
        Ok("".to_string())
    }
}

/// consume a `StartElement` with a specific name or throw an `XmlParseError`
pub fn start_element<T: Peek + Next>(
    element_name: &str,
    stack: &mut T,
) -> Result<HashMap<String, String>, XmlParseError> {
    let next = stack.next();

    if let Some(Ok(XmlEvent::StartElement {
        name, attributes, ..
    })) = next
    {
        if name.local_name == element_name {
            let mut attr_map = HashMap::new();
            for attr in attributes {
                attr_map.insert(attr.name.local_name, attr.value);
            }
            Ok(attr_map)
        } else {
            Err(XmlParseError::new(&format!(
                "START Expected {} got {}",
                element_name, name.local_name
            )))
        }
    } else {
        Err(XmlParseError::new(&format!(
            "Expected StartElement {} got {:#?}",
            element_name, next
        )))
    }
}

/// consume an `EndElement` with a specific name or throw an `XmlParseError`
pub fn end_element<T: Peek + Next>(element_name: &str, stack: &mut T) -> Result<(), XmlParseError> {
    let next = stack.next();
    if let Some(Ok(XmlEvent::EndElement { name, .. })) = next {
        if name.local_name == element_name {
            Ok(())
        } else {
            Err(XmlParseError::new(&format!(
                "END Expected {} got {}",
                element_name, name.local_name
            )))
        }
    } else {
        Err(XmlParseError::new(&format!(
            "Expected EndElement {} got {:?}",
            element_name, next
        )))
    }
}

/// skip a tag and all its children
pub fn skip_tree<T: Peek + Next>(stack: &mut T) {
    let mut deep: usize = 0;

    loop {
        match stack.next() {
            None => break,
            Some(Ok(XmlEvent::StartElement { .. })) => deep += 1,
            Some(Ok(XmlEvent::EndElement { .. })) => {
                if deep > 1 {
                    deep -= 1;
                } else {
                    break;
                }
            }
            _ => (),
        }
    }
}

/// skip all elements until a start element is encountered
///
/// Errors and end-of-stream are ignored.
pub fn find_start_element<T: Peek + Next>(stack: &mut T) {
    loop {
        match stack.peek() {
            Some(&Ok(XmlEvent::StartElement { .. })) => break,
            Some(&Ok(_)) => {
                stack.next().unwrap().unwrap();
            }
            Some(&Err(_)) => break,
            None => break,
        }
    }
}

enum DeserializerNext {
    Close,
    Skip,
    Element(String),
}

pub fn deserialize_elements<T, S, F>(
    tag_name: &str,
    stack: &mut T,
    mut handle_element: F,
) -> Result<S, XmlParseError>
where
    T: Peek + Next,
    S: Default,
    F: FnMut(&str, &mut T, &mut S) -> Result<(), XmlParseError>,
{
    let mut obj = S::default();

    start_element(tag_name, stack)?;

    loop {
        let next_event = match stack.peek() {
            Some(&Ok(XmlEvent::EndElement { .. })) => DeserializerNext::Close,
            Some(&Ok(XmlEvent::StartElement { ref name, .. })) => {
                DeserializerNext::Element(name.local_name.to_owned())
            }
            _ => DeserializerNext::Skip,
        };

        match next_event {
            DeserializerNext::Element(name) => {
                handle_element(&name[..], stack, &mut obj)?;
            }
            DeserializerNext::Close => break,
            DeserializerNext::Skip => {
                stack.next();
            }
        }
    }

    end_element(tag_name, stack)?;

    Ok(obj)
}

pub async fn parse_response<T, E>(
    response: &mut HttpResponse,
    deserialize: fn(&str, &mut XmlResponse<'_>) -> Result<T, XmlParseError>,
) -> Result<T, RusotoError<E>>
where
    T: Default,
{
    let xml_response = response.buffer().await.map_err(RusotoError::HttpDispatch)?;
    if xml_response.body.is_empty() {
        Ok(T::default())
    } else {
        let reader = EventReader::new_with_config(
            xml_response.body.as_ref(),
            ParserConfig::new().trim_whitespace(false),
        );
        let mut stack = XmlResponse::new(reader.into_iter().peekable());
        let _start_document = stack.next();
        let actual_tag_name = peek_at_name(&mut stack)?;
        Ok(deserialize(&actual_tag_name, &mut stack)?)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::fs::File;
    use std::io::Read;

    #[test]
    fn peek_at_name_happy_path() {
        let mut file = File::open("test_resources/list_queues_with_queue.xml").unwrap();
        let mut body = String::new();
        let _size = file.read_to_string(&mut body);
        let my_parser = EventReader::new(body.as_bytes());
        let my_stack = my_parser.into_iter().peekable();
        let mut reader = XmlResponse::new(my_stack);

        loop {
            reader.next();
            match peek_at_name(&mut reader) {
                Ok(data) => {
                    if data == "QueueUrl" {
                        return;
                    }
                }
                Err(_) => panic!("Couldn't peek at name"),
            }
        }
    }

    #[test]
    fn start_element_happy_path() {
        let mut file = File::open("test_resources/list_queues_with_queue.xml").unwrap();
        let mut body = String::new();
        let _size = file.read_to_string(&mut body);
        let my_parser = EventReader::new(body.as_bytes());
        let my_stack = my_parser.into_iter().peekable();
        let mut reader = XmlResponse::new(my_stack);

        // skip two leading fields since we ignore them (xml declaration, return type declaration)
        reader.next();
        reader.next();

        match start_element("ListQueuesResult", &mut reader) {
            Ok(_) => (),
            Err(_) => panic!("Couldn't find start element"),
        }
    }

    #[test]
    fn string_field_happy_path() {
        let mut file = File::open("test_resources/list_queues_with_queue.xml").unwrap();
        let mut body = String::new();
        let _size = file.read_to_string(&mut body);
        let my_parser = EventReader::new(body.as_bytes());
        let my_stack = my_parser.into_iter().peekable();
        let mut reader = XmlResponse::new(my_stack);

        // skip two leading fields since we ignore them (xml declaration, return type declaration)
        reader.next();
        reader.next();

        reader.next(); // reader now at ListQueuesResult

        // now we're set up to use string:
        let my_chars = string_field("QueueUrl", &mut reader).unwrap();
        assert_eq!(
            my_chars,
            "https://sqs.us-east-1.amazonaws.com/347452556413/testqueue"
        )
    }

    #[test]
    fn end_element_happy_path() {
        let mut file = File::open("test_resources/list_queues_with_queue.xml").unwrap();
        let mut body = String::new();
        let _size = file.read_to_string(&mut body);
        let my_parser = EventReader::new(body.as_bytes());
        let my_stack = my_parser.into_iter().peekable();
        let mut reader = XmlResponse::new(my_stack);

        // skip two leading fields since we ignore them (xml declaration, return type declaration)
        reader.next();
        reader.next();

        // TODO: this is fragile and not good: do some looping to find end element?
        // But need to do it without being dependent on peek_at_name.
        reader.next();
        reader.next();
        reader.next();
        reader.next();

        match end_element("ListQueuesResult", &mut reader) {
            Ok(_) => (),
            Err(_) => panic!("Couldn't find end element"),
        }
    }

    #[test]
    fn test_find_start_element() {
        let body = include_bytes!("../../../test_resources/list_queues_with_queue.xml");
        let parser = EventReader::new(&body[..]);
        let stack = parser.into_iter().peekable();
        let mut reader = XmlResponse::new(stack);

        // skip first two elements
        find_start_element(&mut reader);
        assert_eq!(peek_at_name(&mut reader).unwrap(), "ListQueuesResponse");

        // already at start element
        find_start_element(&mut reader);
        assert_eq!(peek_at_name(&mut reader).unwrap(), "ListQueuesResponse");
    }
}
<commit_msg>Simplify deserialize_elements<commit_after>//! Tools for handling XML from AWS with helper functions for testing.
//!
//! Wraps an XML stack via traits.
//! Also provides a method of supplying an XML stack from a file for testing purposes.

use std::collections::HashMap;
use std::io;
use std::iter::Peekable;
use std::num::ParseIntError;
use xml;
use xml::reader::{EventReader, Events, ParserConfig, XmlEvent};
use xml::writer::EventWriter;

use crate::{error::RusotoError, request::HttpResponse};

/// generic Error for XML parsing
#[derive(Debug)]
pub struct XmlParseError(pub String);

impl XmlParseError {
    pub fn new(msg: &str) -> XmlParseError {
        XmlParseError(msg.to_string())
    }
}

/// syntactic sugar for the XML event stack we pass around
pub type XmlStack<'a> = Peekable<Events<&'a [u8]>>;

/// Peek at next items in the XML stack
pub trait Peek {
    fn peek(&mut self) -> Option<&Result<XmlEvent, xml::reader::Error>>;
}

/// Move to the next part of the XML stack
pub trait Next {
    fn next(&mut self) -> Option<Result<XmlEvent, xml::reader::Error>>;
}

/// Wraps the Hyper Response type
pub struct XmlResponse<'b> {
    xml_stack: Peekable<Events<&'b [u8]>>, // refactor to use XmlStack type?
}

impl<'b> XmlResponse<'b> {
    pub fn new(stack: Peekable<Events<&'b [u8]>>) -> XmlResponse {
        XmlResponse { xml_stack: stack }
    }
}

impl<'b> Peek for XmlResponse<'b> {
    fn peek(&mut self) -> Option<&Result<XmlEvent, xml::reader::Error>> {
        while let Some(&Ok(XmlEvent::Whitespace(_))) = self.xml_stack.peek() {
            self.xml_stack.next();
        }
        self.xml_stack.peek()
    }
}

impl<'b> Next for XmlResponse<'b> {
    fn next(&mut self) -> Option<Result<XmlEvent, xml::reader::Error>> {
        let mut maybe_event;
        loop {
            maybe_event = self.xml_stack.next();
            match maybe_event {
                Some(Ok(XmlEvent::Whitespace(_))) => {}
                _ => break,
            }
        }
        maybe_event
    }
}

impl From<ParseIntError> for XmlParseError {
    fn from(_e: ParseIntError) -> XmlParseError {
        XmlParseError::new("ParseIntError")
    }
}

/// return a string field with the right name or throw a parse error
pub fn string_field<T: Peek + Next>(name: &str, stack: &mut T) -> Result<String, XmlParseError> {
    start_element(name, stack)?;
    let value = characters(stack)?;
    end_element(name, stack)?;
    Ok(value)
}

pub fn write_characters_element<W>(
    writer: &mut EventWriter<W>,
    name: &str,
    value_str: &str,
) -> Result<(), xml::writer::Error>
where
    W: io::Write,
{
    writer.write(xml::writer::XmlEvent::start_element(name))?;
    writer.write(xml::writer::XmlEvent::characters(value_str))?;
    writer.write(xml::writer::XmlEvent::end_element())
}

/// return some XML Characters
pub fn characters<T: Peek + Next>(stack: &mut T) -> Result<String, XmlParseError> {
    {
        // Lexical lifetime
        // Check to see if the next element is an end tag.
        // If it is, return an empty string.
        let current = stack.peek();
        if let Some(&Ok(XmlEvent::EndElement { .. })) = current {
            return Ok("".to_string());
        }
    }
    if let Some(Ok(XmlEvent::Characters(data))) = stack.next() {
        Ok(data)
    } else {
        Err(XmlParseError::new("Expected characters"))
    }
}

/// get the name of the current element in the stack.  throw a parse error if it's not a `StartElement`
pub fn peek_at_name<T: Peek + Next>(stack: &mut T) -> Result<String, XmlParseError> {
    let current = stack.peek();
    if let Some(&Ok(XmlEvent::StartElement { ref name, .. })) = current {
        Ok(name.local_name.to_string())
    } else {
        Ok("".to_string())
    }
}

/// consume a `StartElement` with a specific name or throw an `XmlParseError`
pub fn start_element<T: Peek + Next>(
    element_name: &str,
    stack: &mut T,
) -> Result<HashMap<String, String>, XmlParseError> {
    let next = stack.next();

    if let Some(Ok(XmlEvent::StartElement {
        name, attributes, ..
    })) = next
    {
        if name.local_name == element_name {
            let mut attr_map = HashMap::new();
            for attr in attributes {
                attr_map.insert(attr.name.local_name, attr.value);
            }
            Ok(attr_map)
        } else {
            Err(XmlParseError::new(&format!(
                "START Expected {} got {}",
                element_name, name.local_name
            )))
        }
    } else {
        Err(XmlParseError::new(&format!(
            "Expected StartElement {} got {:#?}",
            element_name, next
        )))
    }
}

/// consume an `EndElement` with a specific name or throw an `XmlParseError`
pub fn end_element<T: Peek + Next>(element_name: &str, stack: &mut T) -> Result<(), XmlParseError> {
    let next = stack.next();
    if let Some(Ok(XmlEvent::EndElement { name, .. })) = next {
        if name.local_name == element_name {
            Ok(())
        } else {
            Err(XmlParseError::new(&format!(
                "END Expected {} got {}",
                element_name, name.local_name
            )))
        }
    } else {
        Err(XmlParseError::new(&format!(
            "Expected EndElement {} got {:?}",
            element_name, next
        )))
    }
}

/// skip a tag and all its children
pub fn skip_tree<T: Peek + Next>(stack: &mut T) {
    let mut deep: usize = 0;

    loop {
        match stack.next() {
            None => break,
            Some(Ok(XmlEvent::StartElement { .. })) => deep += 1,
            Some(Ok(XmlEvent::EndElement { .. })) => {
                if deep > 1 {
                    deep -= 1;
                } else {
                    break;
                }
            }
            _ => (),
        }
    }
}

/// skip all elements until a start element is encountered
///
/// Errors and end-of-stream are ignored.
pub fn find_start_element<T: Peek + Next>(stack: &mut T) {
    loop {
        match stack.peek() {
            Some(&Ok(XmlEvent::StartElement { .. })) => break,
            Some(&Ok(_)) => {
                stack.next().unwrap().unwrap();
            }
            Some(&Err(_)) => break,
            None => break,
        }
    }
}

pub fn deserialize_elements<T, S, F>(
    tag_name: &str,
    stack: &mut T,
    mut handle_element: F,
) -> Result<S, XmlParseError>
where
    T: Peek + Next,
    S: Default,
    F: FnMut(&str, &mut T, &mut S) -> Result<(), XmlParseError>,
{
    let mut obj = S::default();

    start_element(tag_name, stack)?;

    loop {
        match stack.peek() {
            Some(&Ok(XmlEvent::EndElement { .. })) => break,
            Some(&Ok(XmlEvent::StartElement { ref name, .. })) => {
                let local_name = name.local_name.to_owned();
                handle_element(&local_name, stack, &mut obj)?;
            }
            _ => {
                stack.next();
            }
        }
    }

    end_element(tag_name, stack)?;

    Ok(obj)
}

pub async fn parse_response<T, E>(
    response: &mut HttpResponse,
    deserialize: fn(&str, &mut XmlResponse<'_>) -> Result<T, XmlParseError>,
) -> Result<T, RusotoError<E>>
where
    T: Default,
{
    let xml_response = response.buffer().await.map_err(RusotoError::HttpDispatch)?;
    if xml_response.body.is_empty() {
        Ok(T::default())
    } else {
        let reader = EventReader::new_with_config(
            xml_response.body.as_ref(),
            ParserConfig::new().trim_whitespace(false),
        );
        let mut stack = XmlResponse::new(reader.into_iter().peekable());
        let _start_document = stack.next();
        let actual_tag_name = peek_at_name(&mut stack)?;
        Ok(deserialize(&actual_tag_name, &mut stack)?)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::fs::File;
    use std::io::Read;

    #[test]
    fn peek_at_name_happy_path() {
        let mut file = File::open("test_resources/list_queues_with_queue.xml").unwrap();
        let mut body = String::new();
        let _size = file.read_to_string(&mut body);
        let my_parser = EventReader::new(body.as_bytes());
        let my_stack = my_parser.into_iter().peekable();
        let mut reader = XmlResponse::new(my_stack);

        loop {
            reader.next();
            match peek_at_name(&mut reader) {
                Ok(data) => {
                    if data == "QueueUrl" {
                        return;
                    }
                }
                Err(_) => panic!("Couldn't peek at name"),
            }
        }
    }

    #[test]
    fn start_element_happy_path() {
        let mut file = File::open("test_resources/list_queues_with_queue.xml").unwrap();
        let mut body = String::new();
        let _size = file.read_to_string(&mut body);
        let my_parser = EventReader::new(body.as_bytes());
        let my_stack = my_parser.into_iter().peekable();
        let mut reader = XmlResponse::new(my_stack);

        // skip two leading fields since we ignore them (xml declaration, return type declaration)
        reader.next();
        reader.next();

        match start_element("ListQueuesResult", &mut reader) {
            Ok(_) => (),
            Err(_) => panic!("Couldn't find start element"),
        }
    }

    #[test]
    fn string_field_happy_path() {
        let mut file = File::open("test_resources/list_queues_with_queue.xml").unwrap();
        let mut body = String::new();
        let _size = file.read_to_string(&mut body);
        let my_parser = EventReader::new(body.as_bytes());
        let my_stack = my_parser.into_iter().peekable();
        let mut reader = XmlResponse::new(my_stack);

        // skip two leading fields since we ignore them (xml declaration, return type declaration)
        reader.next();
        reader.next();

        reader.next(); // reader now at ListQueuesResult

        // now we're set up to use string:
        let my_chars = string_field("QueueUrl", &mut reader).unwrap();
        assert_eq!(
            my_chars,
            "https://sqs.us-east-1.amazonaws.com/347452556413/testqueue"
        )
    }

    #[test]
    fn end_element_happy_path() {
        let mut file = File::open("test_resources/list_queues_with_queue.xml").unwrap();
        let mut body = String::new();
        let _size = file.read_to_string(&mut body);
        let my_parser = EventReader::new(body.as_bytes());
        let my_stack = my_parser.into_iter().peekable();
        let mut reader = XmlResponse::new(my_stack);

        // skip two leading fields since we ignore them (xml declaration, return type declaration)
        reader.next();
        reader.next();

        // TODO: this is fragile and not good: do some looping to find end element?
        // But need to do it without being dependent on peek_at_name.
        reader.next();
        reader.next();
        reader.next();
        reader.next();

        match end_element("ListQueuesResult", &mut reader) {
            Ok(_) => (),
            Err(_) => panic!("Couldn't find end element"),
        }
    }

    #[test]
    fn test_find_start_element() {
        let body = include_bytes!("../../../test_resources/list_queues_with_queue.xml");
        let parser = EventReader::new(&body[..]);
        let stack = parser.into_iter().peekable();
        let mut reader = XmlResponse::new(stack);

        // skip first two elements
        find_start_element(&mut reader);
        assert_eq!(peek_at_name(&mut reader).unwrap(), "ListQueuesResponse");

        // already at start element
        find_start_element(&mut reader);
        assert_eq!(peek_at_name(&mut reader).unwrap(), "ListQueuesResponse");
    }
}
<|endoftext|>


<commit_before>#![feature(step_by)]

extern crate sdl2;
extern crate sdl2_gfx;

use sdl2_gfx::primitives::DrawRenderer;
use sdl2::pixels::Color;
use sdl2::event::Event;
use std::time::Duration;

mod primitives;
mod circle;

use circle::*;
use primitives::*;

const WIDTH: u32 = 1600;
const HEIGHT: u32 = 800;

fn main() {
    // Initialize SDL2
    let sdl_context   = sdl2::init().unwrap();
    let video_context = sdl_context.video().unwrap();

    // Create window
    let window = video_context.window("Graphics Task 1", WIDTH, HEIGHT)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    // Get renderer binded to window
    let mut renderer = window.renderer().build().unwrap();

    // Create FPS manager to precisely control inter-frames delays
    let mut fps_manager = sdl2_gfx::framerate::FPSManager::new();
    fps_manager.set_framerate(10).unwrap();

    // Set draw color and clear the screen
    renderer.set_draw_color(Color::RGB(0, 0, 0));
    renderer.clear();
    renderer.present();

    // Get event pump
    let mut events = sdl_context.event_pump().unwrap();

    // Set first circle center and radius
    let startx1 = (WIDTH / 100 * 25) as f32;
    let startx2 = (WIDTH / 100 * 75) as f32;
    let starty  = (HEIGHT / 2)       as f32;

    // Set result text coordinates
    let textx = (WIDTH - 200) as i16;
    let texty = 10;
    // Create circles
    let mut bresenham_circles = Vec::with_capacity(200);
    let mut builtin_circles   = Vec::with_capacity(200);

    for r in (4..).step_by(2).take(198) {
        bresenham_circles.push(
            Circle::new(
                Point2D::new(startx1, starty),
                r,
                Color::RGB(0, 255, 0)
            )
        );

        builtin_circles.push(
            Circle::new(
                Point2D::new(startx2, starty),
                r,
                Color::RGB(255, 0, 0)
            )
        );
    }

    // Start main loop
    'main:
    loop {
        // If exit event passed, break the loop
        for event in events.poll_iter() {
            match event {
                Event::Quit {..} => break 'main,
                _ => ()
            }
        }

        // Clear render buffer
        renderer.set_draw_color(Color::RGB(0, 0, 0));
        renderer.clear();

        // Plot circles
        let builtin_duration = stopwatch(|| {
            for c in &builtin_circles {
                c.draw_builtin_circle(&renderer);
            }
        });

        let bresenham_duration = stopwatch(|| {
            for c in &bresenham_circles {
                c.draw(&renderer);
            }
        });

        let faster = if bresenham_duration.subsec_nanos() > builtin_duration.subsec_nanos() {
            "BUILTIN"
        } else {
            "MY IMPLEMENTATION"
        };

        // Draw results
        renderer.string(
            textx,
            texty,
            &format!("Bresenham: {} ms", bresenham_duration.subsec_nanos() / 1000_000),
            Color::RGB(255, 255, 255)
        ).unwrap();

        renderer.string(
            textx,
            texty + 15,
            &format!("Builtin:   {} ms", builtin_duration.subsec_nanos() / 1000_000),
            Color::RGB(255, 255, 255)
        ).unwrap();

        renderer.string(
            textx,
            texty + 30,
            &format!("Faster: {}", faster),
            Color::RGB(255, 255, 255)
        ).unwrap();

        // Present render buffer
        renderer.present();

        // Sleep until the next frame should be rendered
        fps_manager.delay();
    }
}

fn stopwatch<F>(mut closure: F) -> Duration
    where F: FnMut() {
    use std::time::SystemTime;
    let before_time = SystemTime::now();
    closure();
    let after_time  = SystemTime::now();
    after_time.duration_since(before_time).unwrap()
}
<commit_msg>Using average time in comparison<commit_after>#![feature(step_by)]

extern crate sdl2;
extern crate sdl2_gfx;

use sdl2_gfx::primitives::DrawRenderer;
use sdl2::pixels::Color;
use sdl2::event::Event;
use std::time::Duration;

mod primitives;
mod circle;

use circle::*;
use primitives::*;

const WIDTH: u32 = 1600;
const HEIGHT: u32 = 800;

fn main() {
    // Initialize SDL2
    let sdl_context   = sdl2::init().unwrap();
    let video_context = sdl_context.video().unwrap();

    // Create window
    let window = video_context.window("Graphics Task 1", WIDTH, HEIGHT)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    // Get renderer binded to window
    let mut renderer = window.renderer().build().unwrap();

    // Create FPS manager to precisely control inter-frames delays
    let mut fps_manager = sdl2_gfx::framerate::FPSManager::new();
    fps_manager.set_framerate(30).unwrap();

    // Set draw color and clear the screen
    renderer.set_draw_color(Color::RGB(0, 0, 0));
    renderer.clear();
    renderer.present();

    // Get event pump
    let mut events = sdl_context.event_pump().unwrap();

    // Set first circle center and radius
    let startx1 = (WIDTH / 100 * 25) as f32;
    let startx2 = (WIDTH / 100 * 75) as f32;
    let starty  = (HEIGHT / 2)       as f32;

    // Create circles
    let mut bresenham_circles = Vec::with_capacity(200);
    let mut builtin_circles   = Vec::with_capacity(200);

    for r in (4..).step_by(4).take(100) {
        bresenham_circles.push(
            Circle::new(
                Point2D::new(startx1, starty),
                r,
                Color::RGB(0, 255, 0)
            )
        );

        builtin_circles.push(
            Circle::new(
                Point2D::new(startx2, starty),
                r,
                Color::RGB(255, 0, 0)
            )
        );
    }

    let cache_size = 30;
    let mut bresenham_cache = [0; 30];
    let mut builtin_cache   = [0; 30];
    let mut frame_counter   = 0;

    // Start main loop
    'main:
    loop {
        // If exit event passed, break the loop
        for event in events.poll_iter() {
            match event {
                Event::Quit {..} => break 'main,
                _ => ()
            }
        }

        // Clear render buffer
        renderer.set_draw_color(Color::RGB(0, 0, 0));
        renderer.clear();

        // Plot circles
        let (d1, d2) = draw_circles(&bresenham_circles, &builtin_circles, &renderer);

        bresenham_cache[frame_counter % 30] = d1;
        builtin_cache[frame_counter % 30] = d2;

        // Calculate average time
        let bresenham_avg = bresenham_cache.iter().fold(0, |sum, &val| {sum + val}) / cache_size;
        let builtin_avg   = builtin_cache.iter().fold(0, |sum, &val| {sum + val}) / cache_size;

        // Draw text
        draw_text(bresenham_avg, builtin_avg, &renderer);

        // Present render buffer
        renderer.present();

        // Sleep until the next frame should be rendered
        fps_manager.delay();
        frame_counter += 1;
    }
}

fn draw_circles(bresenham: &Vec<Circle>, builtin: &Vec<Circle>,
            renderer: &sdl2::render::Renderer) -> (u32, u32) {
    // Plot circles
    let builtin_duration = stopwatch(|| {
        for c in builtin {
            c.draw_builtin_circle(&renderer);
        }
    });

    let bresenham_duration = stopwatch(|| {
        for c in bresenham {
            c.draw(&renderer);
        }
    });

    (bresenham_duration.subsec_nanos(), builtin_duration.subsec_nanos())
}

fn draw_text(bresenham: u32, builtin: u32, renderer: &sdl2::render::Renderer) {
    let faster = if bresenham > builtin {
        "BUILTIN"
    } else {
        "MY IMPLEMENTATION"
    };

    let x = WIDTH as i16 - 300;
    let y = 10;

    // Draw results
    renderer.string(
        x,
        y,
        &format!("Bresenham: {} ms", bresenham / 1000_000),
        Color::RGB(255, 255, 255)
    ).unwrap();

    renderer.string(
        x,
        y + 20,
        &format!("Builtin:   {} ms", builtin / 1000_000),
        Color::RGB(255, 255, 255)
    ).unwrap();

    renderer.string(
        x,
        y + 40,
        &format!("Faster: {}", faster),
        Color::RGB(255, 255, 255)
    ).unwrap();
}

fn stopwatch<F>(mut closure: F) -> Duration
    where F: FnMut() {
    use std::time::SystemTime;
    let before_time = SystemTime::now();
    closure();
    let after_time  = SystemTime::now();
    after_time.duration_since(before_time).unwrap()
}
<|endoftext|>