<commit_before>use std::env;
use std::ffi::{OsStr, OsString};
use std::fs::{self, File, OpenOptions};
use std::io;
use std::io::prelude::*;
use std::path::{Component, Path, PathBuf};

use filetime::FileTime;

use util::{internal, CargoResult};
use util::errors::{CargoError, CargoResultExt, Internal};

pub fn join_paths<T: AsRef<OsStr>>(paths: &[T], env: &str) -> CargoResult<OsString> {
    let err = match env::join_paths(paths.iter()) {
        Ok(paths) => return Ok(paths),
        Err(e) => e,
    };
    let paths = paths.iter().map(Path::new).collect::<Vec<_>>();
    let err = CargoError::from(err);
    let explain = Internal::new(format_err!("failed to join path array: {:?}", paths));
    let err = CargoError::from(err.context(explain));
    let more_explain = format!(
        "failed to join search paths together\n\
         Does ${} have an unterminated quote character?",
        env
    );
    Err(err.context(more_explain).into())
}

pub fn dylib_path_envvar() -> &'static str {
    if cfg!(windows) {
        "PATH"
    } else if cfg!(target_os = "macos") {
        "DYLD_LIBRARY_PATH"
    } else {
        "LD_LIBRARY_PATH"
    }
}

pub fn dylib_path() -> Vec<PathBuf> {
    match env::var_os(dylib_path_envvar()) {
        Some(var) => env::split_paths(&var).collect(),
        None => Vec::new(),
    }
}

pub fn normalize_path(path: &Path) -> PathBuf {
    let mut components = path.components().peekable();
    let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() {
        components.next();
        PathBuf::from(c.as_os_str())
    } else {
        PathBuf::new()
    };

    for component in components {
        match component {
            Component::Prefix(..) => unreachable!(),
            Component::RootDir => {
                ret.push(component.as_os_str());
            }
            Component::CurDir => {}
            Component::ParentDir => {
                ret.pop();
            }
            Component::Normal(c) => {
                ret.push(c);
            }
        }
    }
    ret
}

pub fn without_prefix<'a>(long_path: &'a Path, prefix: &'a Path) -> Option<&'a Path> {
    let mut a = long_path.components();
    let mut b = prefix.components();
    loop {
        match b.next() {
            Some(y) => match a.next() {
                Some(x) if x == y => continue,
                _ => return None,
            },
            None => return Some(a.as_path()),
        }
    }
}

pub fn resolve_executable(exec: &Path) -> CargoResult<PathBuf> {
    if exec.components().count() == 1 {
        let paths = env::var_os("PATH").ok_or(format_err!("no PATH"))?;
        for path in env::split_paths(&paths) {
            let candidate = PathBuf::from(path).join(&exec);
            if candidate.is_file() {
                // PATH may have a component like "." in it, so we still need to
                // canonicalize.
                return Ok(candidate.canonicalize()?);
            }
        }

        bail!("no executable for `{}` found in PATH", exec.display())
    } else {
        Ok(exec.canonicalize()?)
    }
}

pub fn read(path: &Path) -> CargoResult<String> {
    match String::from_utf8(read_bytes(path)?) {
        Ok(s) => Ok(s),
        Err(_) => bail!("path at `{}` was not valid utf-8", path.display()),
    }
}

pub fn read_bytes(path: &Path) -> CargoResult<Vec<u8>> {
    let res = (|| -> CargoResult<_> {
        let mut ret = Vec::new();
        let mut f = File::open(path)?;
        if let Ok(m) = f.metadata() {
            ret.reserve(m.len() as usize + 1);
        }
        f.read_to_end(&mut ret)?;
        Ok(ret)
    })()
        .chain_err(|| format!("failed to read `{}`", path.display()))?;
    Ok(res)
}

pub fn write(path: &Path, contents: &[u8]) -> CargoResult<()> {
    (|| -> CargoResult<()> {
        let mut f = File::create(path)?;
        f.write_all(contents)?;
        Ok(())
    })()
        .chain_err(|| format!("failed to write `{}`", path.display()))?;
    Ok(())
}

pub fn append(path: &Path, contents: &[u8]) -> CargoResult<()> {
    (|| -> CargoResult<()> {
        let mut f = OpenOptions::new()
            .write(true)
            .append(true)
            .create(true)
            .open(path)?;

        f.write_all(contents)?;
        Ok(())
    })()
        .chain_err(|| internal(format!("failed to write `{}`", path.display())))?;
    Ok(())
}

pub fn mtime(path: &Path) -> CargoResult<FileTime> {
    let meta =
        fs::metadata(path).chain_err(|| internal(format!("failed to stat `{}`", path.display())))?;
    Ok(FileTime::from_last_modification_time(&meta))
}

#[cfg(unix)]
pub fn path2bytes(path: &Path) -> CargoResult<&[u8]> {
    use std::os::unix::prelude::*;
    Ok(path.as_os_str().as_bytes())
}
#[cfg(windows)]
pub fn path2bytes(path: &Path) -> CargoResult<&[u8]> {
    match path.as_os_str().to_str() {
        Some(s) => Ok(s.as_bytes()),
        None => Err(format_err!("invalid non-unicode path: {}", path.display())),
    }
}

#[cfg(unix)]
pub fn bytes2path(bytes: &[u8]) -> CargoResult<PathBuf> {
    use std::os::unix::prelude::*;
    use std::ffi::OsStr;
    Ok(PathBuf::from(OsStr::from_bytes(bytes)))
}
#[cfg(windows)]
pub fn bytes2path(bytes: &[u8]) -> CargoResult<PathBuf> {
    use std::str;
    match str::from_utf8(bytes) {
        Ok(s) => Ok(PathBuf::from(s)),
        Err(..) => Err(format_err!("invalid non-unicode path")),
    }
}

pub fn ancestors(path: &Path) -> PathAncestors {
    PathAncestors::new(path)
}

pub struct PathAncestors<'a> {
    current: Option<&'a Path>,
    stop_at: Option<PathBuf>,
}

impl<'a> PathAncestors<'a> {
    fn new(path: &Path) -> PathAncestors {
        PathAncestors {
            current: Some(path),
            //HACK: avoid reading `~/.cargo/config` when testing Cargo itself.
            stop_at: env::var("__CARGO_TEST_ROOT").ok().map(PathBuf::from),
        }
    }
}

impl<'a> Iterator for PathAncestors<'a> {
    type Item = &'a Path;

    fn next(&mut self) -> Option<&'a Path> {
        if let Some(path) = self.current {
            self.current = path.parent();

            if let Some(ref stop_at) = self.stop_at {
                if path == stop_at {
                    self.current = None;
                }
            }

            Some(path)
        } else {
            None
        }
    }
}

pub fn remove_dir_all<P: AsRef<Path>>(p: P) -> CargoResult<()> {
    _remove_dir_all(p.as_ref())
}

fn _remove_dir_all(p: &Path) -> CargoResult<()> {
    if p.symlink_metadata()?.file_type().is_symlink() {
        return remove_file(p);
    }
    let entries = p.read_dir()
        .chain_err(|| format!("failed to read directory `{}`", p.display()))?;
    for entry in entries {
        let entry = entry?;
        let path = entry.path();
        if entry.file_type()?.is_dir() {
            remove_dir_all(&path)?;
        } else {
            remove_file(&path)?;
        }
    }
    remove_dir(&p)
}

pub fn remove_dir<P: AsRef<Path>>(p: P) -> CargoResult<()> {
    _remove_dir(p.as_ref())
}

fn _remove_dir(p: &Path) -> CargoResult<()> {
    fs::remove_dir(p).chain_err(|| format!("failed to remove directory `{}`", p.display()))?;
    Ok(())
}

pub fn remove_file<P: AsRef<Path>>(p: P) -> CargoResult<()> {
    _remove_file(p.as_ref())
}

fn _remove_file(p: &Path) -> CargoResult<()> {
    let mut err = match fs::remove_file(p) {
        Ok(()) => return Ok(()),
        Err(e) => e,
    };

    if err.kind() == io::ErrorKind::PermissionDenied && set_not_readonly(p).unwrap_or(false) {
        match fs::remove_file(p) {
            Ok(()) => return Ok(()),
            Err(e) => err = e,
        }
    }

    Err(err).chain_err(|| format!("failed to remove file `{}`", p.display()))?;
    Ok(())
}

fn set_not_readonly(p: &Path) -> io::Result<bool> {
    let mut perms = p.metadata()?.permissions();
    if !perms.readonly() {
        return Ok(false);
    }
    perms.set_readonly(false);
    fs::set_permissions(p, perms)?;
    Ok(true)
}
<commit_msg>Correctly resolve executables in paths on windows<commit_after>use std::env;
use std::ffi::{OsStr, OsString};
use std::fs::{self, File, OpenOptions};
use std::io;
use std::io::prelude::*;
use std::path::{Component, Path, PathBuf};
use std::iter;

use filetime::FileTime;

use util::{internal, CargoResult};
use util::errors::{CargoError, CargoResultExt, Internal};

pub fn join_paths<T: AsRef<OsStr>>(paths: &[T], env: &str) -> CargoResult<OsString> {
    let err = match env::join_paths(paths.iter()) {
        Ok(paths) => return Ok(paths),
        Err(e) => e,
    };
    let paths = paths.iter().map(Path::new).collect::<Vec<_>>();
    let err = CargoError::from(err);
    let explain = Internal::new(format_err!("failed to join path array: {:?}", paths));
    let err = CargoError::from(err.context(explain));
    let more_explain = format!(
        "failed to join search paths together\n\
         Does ${} have an unterminated quote character?",
        env
    );
    Err(err.context(more_explain).into())
}

pub fn dylib_path_envvar() -> &'static str {
    if cfg!(windows) {
        "PATH"
    } else if cfg!(target_os = "macos") {
        "DYLD_LIBRARY_PATH"
    } else {
        "LD_LIBRARY_PATH"
    }
}

pub fn dylib_path() -> Vec<PathBuf> {
    match env::var_os(dylib_path_envvar()) {
        Some(var) => env::split_paths(&var).collect(),
        None => Vec::new(),
    }
}

pub fn normalize_path(path: &Path) -> PathBuf {
    let mut components = path.components().peekable();
    let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() {
        components.next();
        PathBuf::from(c.as_os_str())
    } else {
        PathBuf::new()
    };

    for component in components {
        match component {
            Component::Prefix(..) => unreachable!(),
            Component::RootDir => {
                ret.push(component.as_os_str());
            }
            Component::CurDir => {}
            Component::ParentDir => {
                ret.pop();
            }
            Component::Normal(c) => {
                ret.push(c);
            }
        }
    }
    ret
}

pub fn without_prefix<'a>(long_path: &'a Path, prefix: &'a Path) -> Option<&'a Path> {
    let mut a = long_path.components();
    let mut b = prefix.components();
    loop {
        match b.next() {
            Some(y) => match a.next() {
                Some(x) if x == y => continue,
                _ => return None,
            },
            None => return Some(a.as_path()),
        }
    }
}

pub fn resolve_executable(exec: &Path) -> CargoResult<PathBuf> {
    if exec.components().count() == 1 {
        let paths = env::var_os("PATH").ok_or(format_err!("no PATH"))?;
        let candidates = env::split_paths(&paths).flat_map(|path| {
            let candidate = PathBuf::from(path).join(&exec);
            let with_exe = if env::consts::EXE_EXTENSION == "" {
                None
            } else {
                Some(candidate.with_extension(env::consts::EXE_EXTENSION))
            };
            iter::once(candidate).chain(with_exe)
        });
        for candidate in candidates {
            if candidate.is_file() {
                // PATH may have a component like "." in it, so we still need to
                // canonicalize.
                return Ok(candidate.canonicalize()?);
            }
        }

        bail!("no executable for `{}` found in PATH", exec.display())
    } else {
        Ok(exec.canonicalize()?)
    }
}

pub fn read(path: &Path) -> CargoResult<String> {
    match String::from_utf8(read_bytes(path)?) {
        Ok(s) => Ok(s),
        Err(_) => bail!("path at `{}` was not valid utf-8", path.display()),
    }
}

pub fn read_bytes(path: &Path) -> CargoResult<Vec<u8>> {
    let res = (|| -> CargoResult<_> {
        let mut ret = Vec::new();
        let mut f = File::open(path)?;
        if let Ok(m) = f.metadata() {
            ret.reserve(m.len() as usize + 1);
        }
        f.read_to_end(&mut ret)?;
        Ok(ret)
    })()
        .chain_err(|| format!("failed to read `{}`", path.display()))?;
    Ok(res)
}

pub fn write(path: &Path, contents: &[u8]) -> CargoResult<()> {
    (|| -> CargoResult<()> {
        let mut f = File::create(path)?;
        f.write_all(contents)?;
        Ok(())
    })()
        .chain_err(|| format!("failed to write `{}`", path.display()))?;
    Ok(())
}

pub fn append(path: &Path, contents: &[u8]) -> CargoResult<()> {
    (|| -> CargoResult<()> {
        let mut f = OpenOptions::new()
            .write(true)
            .append(true)
            .create(true)
            .open(path)?;

        f.write_all(contents)?;
        Ok(())
    })()
        .chain_err(|| internal(format!("failed to write `{}`", path.display())))?;
    Ok(())
}

pub fn mtime(path: &Path) -> CargoResult<FileTime> {
    let meta =
        fs::metadata(path).chain_err(|| internal(format!("failed to stat `{}`", path.display())))?;
    Ok(FileTime::from_last_modification_time(&meta))
}

#[cfg(unix)]
pub fn path2bytes(path: &Path) -> CargoResult<&[u8]> {
    use std::os::unix::prelude::*;
    Ok(path.as_os_str().as_bytes())
}
#[cfg(windows)]
pub fn path2bytes(path: &Path) -> CargoResult<&[u8]> {
    match path.as_os_str().to_str() {
        Some(s) => Ok(s.as_bytes()),
        None => Err(format_err!("invalid non-unicode path: {}", path.display())),
    }
}

#[cfg(unix)]
pub fn bytes2path(bytes: &[u8]) -> CargoResult<PathBuf> {
    use std::os::unix::prelude::*;
    use std::ffi::OsStr;
    Ok(PathBuf::from(OsStr::from_bytes(bytes)))
}
#[cfg(windows)]
pub fn bytes2path(bytes: &[u8]) -> CargoResult<PathBuf> {
    use std::str;
    match str::from_utf8(bytes) {
        Ok(s) => Ok(PathBuf::from(s)),
        Err(..) => Err(format_err!("invalid non-unicode path")),
    }
}

pub fn ancestors(path: &Path) -> PathAncestors {
    PathAncestors::new(path)
}

pub struct PathAncestors<'a> {
    current: Option<&'a Path>,
    stop_at: Option<PathBuf>,
}

impl<'a> PathAncestors<'a> {
    fn new(path: &Path) -> PathAncestors {
        PathAncestors {
            current: Some(path),
            //HACK: avoid reading `~/.cargo/config` when testing Cargo itself.
            stop_at: env::var("__CARGO_TEST_ROOT").ok().map(PathBuf::from),
        }
    }
}

impl<'a> Iterator for PathAncestors<'a> {
    type Item = &'a Path;

    fn next(&mut self) -> Option<&'a Path> {
        if let Some(path) = self.current {
            self.current = path.parent();

            if let Some(ref stop_at) = self.stop_at {
                if path == stop_at {
                    self.current = None;
                }
            }

            Some(path)
        } else {
            None
        }
    }
}

pub fn remove_dir_all<P: AsRef<Path>>(p: P) -> CargoResult<()> {
    _remove_dir_all(p.as_ref())
}

fn _remove_dir_all(p: &Path) -> CargoResult<()> {
    if p.symlink_metadata()?.file_type().is_symlink() {
        return remove_file(p);
    }
    let entries = p.read_dir()
        .chain_err(|| format!("failed to read directory `{}`", p.display()))?;
    for entry in entries {
        let entry = entry?;
        let path = entry.path();
        if entry.file_type()?.is_dir() {
            remove_dir_all(&path)?;
        } else {
            remove_file(&path)?;
        }
    }
    remove_dir(&p)
}

pub fn remove_dir<P: AsRef<Path>>(p: P) -> CargoResult<()> {
    _remove_dir(p.as_ref())
}

fn _remove_dir(p: &Path) -> CargoResult<()> {
    fs::remove_dir(p).chain_err(|| format!("failed to remove directory `{}`", p.display()))?;
    Ok(())
}

pub fn remove_file<P: AsRef<Path>>(p: P) -> CargoResult<()> {
    _remove_file(p.as_ref())
}

fn _remove_file(p: &Path) -> CargoResult<()> {
    let mut err = match fs::remove_file(p) {
        Ok(()) => return Ok(()),
        Err(e) => e,
    };

    if err.kind() == io::ErrorKind::PermissionDenied && set_not_readonly(p).unwrap_or(false) {
        match fs::remove_file(p) {
            Ok(()) => return Ok(()),
            Err(e) => err = e,
        }
    }

    Err(err).chain_err(|| format!("failed to remove file `{}`", p.display()))?;
    Ok(())
}

fn set_not_readonly(p: &Path) -> io::Result<bool> {
    let mut perms = p.metadata()?.permissions();
    if !perms.readonly() {
        return Ok(false);
    }
    perms.set_readonly(false);
    fs::set_permissions(p, perms)?;
    Ok(true)
}
<|endoftext|>


<commit_before>#![recursion_limit = "128"]

extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;

use std::iter;

use proc_macro::TokenStream;
use syn::{Body, Ident, Variant, VariantData};
use quote::Tokens;

fn generate_enum_code(name: &Ident, variants: &[Variant]) -> Tokens {
    let mut enum_count = 0usize;
    for &Variant {
             ref data,
             ref discriminant,
             ..
         } in variants {
        if data != &VariantData::Unit {
            panic!("#[derive(EnumMap)] requires C style style enum");
        }
        if discriminant.is_some() {
            panic!("#[derive(EnumMap)] doesn't currently support discriminants");
        }
        enum_count += 1;
    }

    let variant_a = variants.iter().map(|variant| &variant.ident);
    let variant_b = variants.iter().map(|variant| &variant.ident);
    let repeat_name_a = iter::repeat(name).take(variants.len());
    let repeat_name_b = repeat_name_a.clone();
    let counter = 0..variants.len();

    quote! {
        impl<V> ::enum_map::Internal<V> for #name {
            type Array = [V; #enum_count];
            fn slice(array: &Self::Array) -> &[V] {
                array
            }
            fn slice_mut(array: &mut Self::Array) -> &mut [V] {
                array
            }
            fn from_usize(value: usize) -> Self {
                match value {
                    #(
                        #counter => #repeat_name_a::#variant_a,
                    )*
                    _ => unreachable!()
                }
            }
            fn to_usize(self) -> usize {
                self as usize
            }
            fn from_function<F: Fn(Self) -> V>(f: F) -> Self::Array {
                [#(
                    f(#repeat_name_b::#variant_b),
                )*]
            }
        }
    }
}

#[proc_macro_derive(EnumMap)]
pub fn derive_enum_map(input: TokenStream) -> TokenStream {
    let input = syn::parse_macro_input(&input.to_string()).unwrap();
    match input.body {
            Body::Enum(ref variants) => generate_enum_code(&input.ident, variants),
            _ => panic!("#[derive(EnumMap)] is only defined for enums"),
        }
        .parse()
        .unwrap()
}
<commit_msg>Document why the documentation of enum-map-derive is missing<commit_after>//! Procedural macro implementing `#[derive(EnumMap)]`
//!
//! This is supposed to used with `enum-map` crate, which provides the
//! actual usage documentation.

#![recursion_limit = "128"]

extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;

use std::iter;

use proc_macro::TokenStream;
use syn::{Body, Ident, Variant, VariantData};
use quote::Tokens;

fn generate_enum_code(name: &Ident, variants: &[Variant]) -> Tokens {
    let mut enum_count = 0usize;
    for &Variant {
             ref data,
             ref discriminant,
             ..
         } in variants {
        if data != &VariantData::Unit {
            panic!("#[derive(EnumMap)] requires C style style enum");
        }
        if discriminant.is_some() {
            panic!("#[derive(EnumMap)] doesn't currently support discriminants");
        }
        enum_count += 1;
    }

    let variant_a = variants.iter().map(|variant| &variant.ident);
    let variant_b = variants.iter().map(|variant| &variant.ident);
    let repeat_name_a = iter::repeat(name).take(variants.len());
    let repeat_name_b = repeat_name_a.clone();
    let counter = 0..variants.len();

    quote! {
        impl<V> ::enum_map::Internal<V> for #name {
            type Array = [V; #enum_count];
            fn slice(array: &Self::Array) -> &[V] {
                array
            }
            fn slice_mut(array: &mut Self::Array) -> &mut [V] {
                array
            }
            fn from_usize(value: usize) -> Self {
                match value {
                    #(
                        #counter => #repeat_name_a::#variant_a,
                    )*
                    _ => unreachable!()
                }
            }
            fn to_usize(self) -> usize {
                self as usize
            }
            fn from_function<F: Fn(Self) -> V>(f: F) -> Self::Array {
                [#(
                    f(#repeat_name_b::#variant_b),
                )*]
            }
        }
    }
}

#[proc_macro_derive(EnumMap)]
pub fn derive_enum_map(input: TokenStream) -> TokenStream {
    let input = syn::parse_macro_input(&input.to_string()).unwrap();
    match input.body {
            Body::Enum(ref variants) => generate_enum_code(&input.ident, variants),
            _ => panic!("#[derive(EnumMap)] is only defined for enums"),
        }
        .parse()
        .unwrap()
}
<|endoftext|>


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

#[macro_use]
extern crate uucore;

use uu_base32::base_common;
pub use uu_base32::uu_app;

use uucore::encoding::Format;

use std::io::{stdin, Read};

static ABOUT: &str = "
 With no FILE, or when FILE is -, read standard input.

 The data are encoded as described for the base64 alphabet in RFC
 3548. When decoding, the input may contain newlines in addition
 to the bytes of the formal base64 alphabet. Use --ignore-garbage
 to attempt to recover from any other non-alphabet bytes in the
 encoded stream.
";
static VERSION: &str = env!("CARGO_PKG_VERSION");

static BASE_CMD_PARSE_ERROR: i32 = 1;

fn usage() -> String {
    format!("{0} [OPTION]... [FILE]", uucore::execution_phrase())
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let format = Format::Base64;
    let usage = usage();
    let name = uucore::util_name();
    let config_result: Result<base_common::Config, String> =
        base_common::parse_base_cmd_args(args, name, VERSION, ABOUT, &usage);
    let config = config_result.unwrap_or_else(|s| crash!(BASE_CMD_PARSE_ERROR, "{}", s));

    // Create a reference to stdin so we can return a locked stdin from
    // parse_base_cmd_args
    let stdin_raw = stdin();
    let mut input: Box<dyn Read> = base_common::get_input(&config, &stdin_raw);

    base_common::handle_input(
        &mut input,
        format,
        config.wrap_cols,
        config.ignore_garbage,
        config.decode,
        name,
    );

    0
}
<commit_msg>base64: use UResult<commit_after>// This file is part of the uutils coreutils package.
//
// (c) Jordy Dickinson <jordy.dickinson@gmail.com>
// (c) Jian Zeng <anonymousknight96@gmail.com>
//
// For the full copyright and license information, please view the LICENSE file
// that was distributed with this source code.

#[macro_use]
extern crate uucore;

use uu_base32::base_common;
pub use uu_base32::uu_app;

use uucore::{encoding::Format, error::UResult};

use std::io::{stdin, Read};

static ABOUT: &str = "
 With no FILE, or when FILE is -, read standard input.

 The data are encoded as described for the base64 alphabet in RFC
 3548. When decoding, the input may contain newlines in addition
 to the bytes of the formal base64 alphabet. Use --ignore-garbage
 to attempt to recover from any other non-alphabet bytes in the
 encoded stream.
";

fn usage() -> String {
    format!("{0} [OPTION]... [FILE]", uucore::execution_phrase())
}

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

    let config: base_common::Config = base_common::parse_base_cmd_args(args, ABOUT, &usage)?;

    // Create a reference to stdin so we can return a locked stdin from
    // parse_base_cmd_args
    let stdin_raw = stdin();
    let mut input: Box<dyn Read> = base_common::get_input(&config, &stdin_raw)?;

    base_common::handle_input(
        &mut input,
        format,
        config.wrap_cols,
        config.ignore_garbage,
        config.decode,
    )
}
<|endoftext|>


<commit_before>// * This file is part of the uutils coreutils package.
// *
// * (c) 2020 nicoo <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

extern crate rand;

use std::cell::RefCell;
use std::fmt;

use crate::numeric::{Arithmetic, Montgomery};
use crate::{miller_rabin, rho, table};

type Exponent = u8;

#[derive(Clone, Debug)]
struct Decomposition(Vec<(u64, Exponent)>);

impl Decomposition {
    fn one() -> Decomposition {
        Decomposition(Vec::new())
    }

    fn add(&mut self, factor: u64, exp: Exponent) {
        debug_assert!(exp > 0);

        if let Some((_, e)) = self.0.iter_mut().find(|(f, _)| *f == factor) {
            *e += exp;
        } else {
            self.0.push((factor, exp))
        }
    }

    #[cfg(test)]
    fn product(&self) -> u64 {
        self.0
            .iter()
            .fold(1, |acc, (p, exp)| acc * p.pow(*exp as u32))
    }

    fn get(&self, p: u64) -> Option<&(u64, u8)> {
        self.0.iter().find(|(q, _)| *q == p)
    }
}

impl PartialEq for Decomposition {
    fn eq(&self, other: &Decomposition) -> bool {
        for p in &self.0 {
            if other.get(p.0) != Some(p) {
                return false;
            }
        }

        for p in &other.0 {
            if self.get(p.0) != Some(p) {
                return false;
            }
        }

        true
    }
}
impl Eq for Decomposition {}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Factors(RefCell<Decomposition>);

impl Factors {
    pub fn one() -> Factors {
        Factors(RefCell::new(Decomposition::one()))
    }

    pub fn add(&mut self, prime: u64, exp: Exponent) {
        debug_assert!(miller_rabin::is_prime(prime));
        self.0.borrow_mut().add(prime, exp)
    }

    pub fn push(&mut self, prime: u64) {
        self.add(prime, 1)
    }

    #[cfg(test)]
    fn product(&self) -> u64 {
        self.0.borrow().product()
    }
}

impl fmt::Display for Factors {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let v = &mut (self.0).borrow_mut().0;
        v.sort_unstable();

        for (p, exp) in v.iter() {
            for _ in 0..*exp {
                write!(f, " {}", p)?
            }
        }

        Ok(())
    }
}

fn _factor<A: Arithmetic + miller_rabin::Basis>(num: u64, f: Factors) -> Factors {
    use miller_rabin::Result::*;

    // Shadow the name, so the recursion automatically goes from “Big” arithmetic to small.
    let _factor = |n, f| {
        if n < (1 << 32) {
            _factor::<Montgomery<u32>>(n, f)
        } else {
            _factor::<A>(n, f)
        }
    };

    if num == 1 {
        return f;
    }

    let n = A::new(num);
    let divisor = match miller_rabin::test::<A>(n) {
        Prime => {
            let mut r = f;
            r.push(num);
            return r;
        }

        Composite(d) => d,
        Pseudoprime => rho::find_divisor::<A>(n),
    };

    let f = _factor(divisor, f);
    _factor(num / divisor, f)
}

pub fn factor(mut n: u64) -> Factors {
    let mut factors = Factors::one();

    if n < 2 {
        return factors;
    }

    let z = n.trailing_zeros();
    if z > 0 {
        factors.add(2, z as Exponent);
        n >>= z;
    }

    if n == 1 {
        return factors;
    }

    let (factors, n) = table::factor(n, factors);

    if n < (1 << 32) {
        _factor::<Montgomery<u32>>(n, factors)
    } else {
        _factor::<Montgomery<u64>>(n, factors)
    }
}

#[cfg(test)]
mod tests {
    use super::{factor, Factors};
    use quickcheck::quickcheck;

    #[test]
    fn factor_recombines_small() {
        assert!((1..10_000)
            .map(|i| 2 * i + 1)
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_overflowing() {
        assert!((0..250)
            .map(|i| 2 * i + 2u64.pow(32) + 1)
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_strong_pseudoprime() {
        // This is a strong pseudoprime (wrt. miller_rabin::BASIS)
        //  and triggered a bug in rho::factor's codepath handling
        //  miller_rabbin::Result::Composite
        let pseudoprime = 17179869183;
        for _ in 0..20 {
            // Repeat the test 20 times, as it only fails some fraction
            // of the time.
            assert!(factor(pseudoprime).product() == pseudoprime);
        }
    }

    quickcheck! {
        fn factor_recombines(i: u64) -> bool {
            i == 0 || factor(i).product() == i
        }

        fn recombines_factors(f: Factors) -> bool {
            assert_eq!(factor(f.product()), f);
            true
        }
    }
}

#[cfg(test)]
impl quickcheck::Arbitrary for Factors {
    fn arbitrary<G: quickcheck::Gen>(gen: &mut G) -> Self {
        use rand::Rng;
        let mut f = Factors::one();
        let mut g = 1u64;
        let mut n = u64::MAX;

        // Adam Kalai's algorithm for generating uniformly-distributed
        // integers and their factorisation.
        //
        // See Generating Random Factored Numbers, Easily, J. Cryptology (2003)
        'attempt: loop {
            while n > 1 {
                n = gen.gen_range(1, n);
                if miller_rabin::is_prime(n) {
                    if let Some(h) = g.checked_mul(n) {
                        f.push(n);
                        g = h;
                    } else {
                        // We are overflowing u64, retry
                        continue 'attempt;
                    }
                }
            }

            return f;
        }
    }
}
<commit_msg>factor: Introduce a type alias for exponents<commit_after>// * This file is part of the uutils coreutils package.
// *
// * (c) 2020 nicoo <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

extern crate rand;

use std::cell::RefCell;
use std::fmt;

use crate::numeric::{Arithmetic, Montgomery};
use crate::{miller_rabin, rho, table};

type Exponent = u8;

#[derive(Clone, Debug)]
struct Decomposition(Vec<(u64, Exponent)>);

impl Decomposition {
    fn one() -> Decomposition {
        Decomposition(Vec::new())
    }

    fn add(&mut self, factor: u64, exp: Exponent) {
        debug_assert!(exp > 0);

        if let Some((_, e)) = self.0.iter_mut().find(|(f, _)| *f == factor) {
            *e += exp;
        } else {
            self.0.push((factor, exp))
        }
    }

    #[cfg(test)]
    fn product(&self) -> u64 {
        self.0
            .iter()
            .fold(1, |acc, (p, exp)| acc * p.pow(*exp as u32))
    }

    fn get(&self, p: u64) -> Option<&(u64, u8)> {
        self.0.iter().find(|(q, _)| *q == p)
    }
}

impl PartialEq for Decomposition {
    fn eq(&self, other: &Decomposition) -> bool {
        for p in &self.0 {
            if other.get(p.0) != Some(p) {
                return false;
            }
        }

        for p in &other.0 {
            if self.get(p.0) != Some(p) {
                return false;
            }
        }

        true
    }
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Factors {
    f: BTreeMap<u64, Exponent>,
}
impl Eq for Decomposition {}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Factors(RefCell<Decomposition>);

impl Factors {
    pub fn one() -> Factors {
        Factors(RefCell::new(Decomposition::one()))
    }

    pub fn add(&mut self, prime: u64, exp: Exponent) {
        debug_assert!(miller_rabin::is_prime(prime));
        self.0.borrow_mut().add(prime, exp)
    }

    pub fn push(&mut self, prime: u64) {
        self.add(prime, 1)
    }

    #[cfg(test)]
    fn product(&self) -> u64 {
        self.0.borrow().product()
    }
}

impl fmt::Display for Factors {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let v = &mut (self.0).borrow_mut().0;
        v.sort_unstable();

        for (p, exp) in v.iter() {
            for _ in 0..*exp {
                write!(f, " {}", p)?
            }
        }

        Ok(())
    }
}

fn _factor<A: Arithmetic + miller_rabin::Basis>(num: u64, f: Factors) -> Factors {
    use miller_rabin::Result::*;

    // Shadow the name, so the recursion automatically goes from “Big” arithmetic to small.
    let _factor = |n, f| {
        if n < (1 << 32) {
            _factor::<Montgomery<u32>>(n, f)
        } else {
            _factor::<A>(n, f)
        }
    };

    if num == 1 {
        return f;
    }

    let n = A::new(num);
    let divisor = match miller_rabin::test::<A>(n) {
        Prime => {
            let mut r = f;
            r.push(num);
            return r;
        }

        Composite(d) => d,
        Pseudoprime => rho::find_divisor::<A>(n),
    };

    let f = _factor(divisor, f);
    _factor(num / divisor, f)
}

pub fn factor(mut n: u64) -> Factors {
    let mut factors = Factors::one();

    if n < 2 {
        return factors;
    }

    let z = n.trailing_zeros();
    if z > 0 {
        factors.add(2, z as Exponent);
        n >>= z;
    }

    if n == 1 {
        return factors;
    }

    let (factors, n) = table::factor(n, factors);

    if n < (1 << 32) {
        _factor::<Montgomery<u32>>(n, factors)
    } else {
        _factor::<Montgomery<u64>>(n, factors)
    }
}

#[cfg(test)]
mod tests {
    use super::{factor, Factors};
    use quickcheck::quickcheck;

    #[test]
    fn factor_recombines_small() {
        assert!((1..10_000)
            .map(|i| 2 * i + 1)
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_overflowing() {
        assert!((0..250)
            .map(|i| 2 * i + 2u64.pow(32) + 1)
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_strong_pseudoprime() {
        // This is a strong pseudoprime (wrt. miller_rabin::BASIS)
        //  and triggered a bug in rho::factor's codepath handling
        //  miller_rabbin::Result::Composite
        let pseudoprime = 17179869183;
        for _ in 0..20 {
            // Repeat the test 20 times, as it only fails some fraction
            // of the time.
            assert!(factor(pseudoprime).product() == pseudoprime);
        }
    }

    quickcheck! {
        fn factor_recombines(i: u64) -> bool {
            i == 0 || factor(i).product() == i
        }

        fn recombines_factors(f: Factors) -> bool {
            assert_eq!(factor(f.product()), f);
            true
        }
    }
}

#[cfg(test)]
impl quickcheck::Arbitrary for Factors {
    fn arbitrary<G: quickcheck::Gen>(gen: &mut G) -> Self {
        use rand::Rng;
        let mut f = Factors::one();
        let mut g = 1u64;
        let mut n = u64::MAX;

        // Adam Kalai's algorithm for generating uniformly-distributed
        // integers and their factorisation.
        //
        // See Generating Random Factored Numbers, Easily, J. Cryptology (2003)
        'attempt: loop {
            while n > 1 {
                n = gen.gen_range(1, n);
                if miller_rabin::is_prime(n) {
                    if let Some(h) = g.checked_mul(n) {
                        f.push(n);
                        g = h;
                    } else {
                        // We are overflowing u64, retry
                        continue 'attempt;
                    }
                }
            }

            return f;
        }
    }
}
<|endoftext|>


<commit_before>//! Basic hello world example.

use cgmath;
use ggez;

use ggez::event;
use ggez::graphics;
use ggez::{Context, GameResult};
use std::env;
use std::path;

// First we make a structure to contain the game's state
struct MainState {
    frames: usize,
    text: graphics::Text,
}

impl MainState {
    fn new(ctx: &mut Context) -> GameResult<MainState> {
        // The ttf file will be in your resources directory. Later, we
        // will mount that directory so we can omit it in the path here.
        let font = graphics::Font::new(ctx, "/DejaVuSerif.ttf")?;
        let text = graphics::Text::new(("Hello world!", font, 48.0));

        let s = MainState { frames: 0, text };
        Ok(s)
    }
}

// Then we implement the `ggez:event::EventHandler` trait on it, which
// requires callbacks for updating and drawing the game state each frame.
//
// The `EventHandler` trait also contains callbacks for event handling
// that you can override if you wish, but the defaults are fine.
impl event::EventHandler for MainState {
    fn update(&mut self, _ctx: &mut Context) -> GameResult {
        Ok(())
    }

    fn draw(&mut self, ctx: &mut Context) -> GameResult {
        graphics::clear(ctx, [0.1, 0.2, 0.3, 1.0].into());

        // Drawables are drawn from their top-left corner.
        let offset = self.frames as f32 / 10.0;
        let dest_point = cgmath::Point2::new(offset, offset);
        graphics::draw(ctx, &self.text, (dest_point,))?;
        graphics::present(ctx)?;

        self.frames += 1;
        if (self.frames % 100) == 0 {
            println!("FPS: {}", ggez::timer::fps(ctx));
        }

        Ok(())
    }
}

// Now our main function, which does three things:
//
// * First, create a new `ggez::ContextBuilder`
// object which contains configuration info on things such
// as screen resolution and window title.
// * Second, create a `ggez::game::Game` object which will
// do the work of creating our MainState and running our game.
// * Then, just call `game.run()` which runs the `Game` mainloop.
pub fn main() -> GameResult {
    // We add the CARGO_MANIFEST_DIR/resources to the resource paths
    // so that ggez will look in our cargo project directory for files.
    let resource_dir = if let Ok(manifest_dir) = env::var("CARGO_MANIFEST_DIR") {
        let mut path = path::PathBuf::from(manifest_dir);
        path.push("resources");
        path
    } else {
        path::PathBuf::from("./resources")
    };

    let cb = ggez::ContextBuilder::new("helloworld", "ggez").add_resource_path(resource_dir);
    let (ctx, event_loop) = &mut cb.build()?;

    let state = &mut MainState::new(ctx)?;
    event::run(ctx, event_loop, state)
}
<commit_msg>02_hello_world.rs<commit_after>//! Basic hello world example.

use cgmath;
use ggez;

use ggez::event;
use ggez::graphics;
use ggez::{Context, GameResult};
use std::env;
use std::path;

// First we make a structure to contain the game's state
struct MainState {
    frames: usize,
    text: graphics::Text,
}

impl MainState {
    fn new(ctx: &mut Context) -> GameResult<MainState> {
        // The ttf file will be in your resources directory. Later, we
        // will mount that directory so we can omit it in the path here.
        let font = graphics::Font::new(ctx, "/DejaVuSerif.ttf")?;
        let text = graphics::Text::new(("Hello world!", font, 48.0));

        let s = MainState { frames: 0, text };
        Ok(s)
    }
}

// Then we implement the `ggez:event::EventHandler` trait on it, which
// requires callbacks for updating and drawing the game state each frame.
//
// The `EventHandler` trait also contains callbacks for event handling
// that you can override if you wish, but the defaults are fine.
impl event::EventHandler for MainState {
    fn update(&mut self, _ctx: &mut Context) -> GameResult {
        Ok(())
    }

    fn draw(&mut self, ctx: &mut Context) -> GameResult {
        graphics::clear(ctx, [0.1, 0.2, 0.3, 1.0].into());

        // Drawables are drawn from their top-left corner.
        let offset = self.frames as f32 / 10.0;
        let dest_point = mint::Point2 {
            x: (offset),
            y: (offset),
        };
        graphics::draw(ctx, &self.text, (dest_point,))?;
        graphics::present(ctx)?;

        self.frames += 1;
        if (self.frames % 100) == 0 {
            println!("FPS: {}", ggez::timer::fps(ctx));
        }

        Ok(())
    }
}

// Now our main function, which does three things:
//
// * First, create a new `ggez::ContextBuilder`
// object which contains configuration info on things such
// as screen resolution and window title.
// * Second, create a `ggez::game::Game` object which will
// do the work of creating our MainState and running our game.
// * Then, just call `game.run()` which runs the `Game` mainloop.
pub fn main() -> GameResult {
    // We add the CARGO_MANIFEST_DIR/resources to the resource paths
    // so that ggez will look in our cargo project directory for files.
    let resource_dir = if let Ok(manifest_dir) = env::var("CARGO_MANIFEST_DIR") {
        let mut path = path::PathBuf::from(manifest_dir);
        path.push("resources");
        path
    } else {
        path::PathBuf::from("./resources")
    };

    let cb = ggez::ContextBuilder::new("helloworld", "ggez").add_resource_path(resource_dir);
    let (ctx, event_loop) = &mut cb.build()?;

    let state = &mut MainState::new(ctx)?;
    event::run(ctx, event_loop, state)
}
<|endoftext|>


<commit_before>use regex::Regex;

#[derive(Eq, PartialEq, Debug, Clone, Copy)]
pub enum FileType {
    FullSig,
    NewSig,
    Inc,
    Full
}

#[derive(Eq, PartialEq, Debug)]
pub struct FileName {
    pub file_type : FileType,
    pub manifest : bool,
    pub volume_number : i32,
    pub time : String,
    pub start_time : String,
    pub end_time : String,
    pub compressed : bool,
    pub encrypted : bool,
    pub partial : bool
}

impl FileName {
    /// Builder pattern for FileName
    pub fn new() -> Self {
        FileName{
            file_type : FileType::Full,
            manifest : false,
            volume_number : 0,
            time : String::new(),
            start_time : String::new(),
            end_time : String::new(),
            compressed : false,
            encrypted : false,
            partial : false}
    }
}

gen_setters!(FileName,
    file_type : FileType,
    manifest : bool,
    volume_number : i32,
    time : String,
    start_time : String,
    end_time : String,
    compressed : bool,
    encrypted : bool,
    partial : bool
);

pub struct FileNameInfo<'a> {
    pub file_name : &'a str,
    pub info : FileName
}

impl<'a> FileNameInfo<'a> {
    pub fn new(name : &'a str, info : FileName) -> Self {
        FileNameInfo {
            file_name : &name,
            info : info
        }
    }
}

pub struct FileNameParser {
    full_vol_re : Regex,
    full_manifest_re : Regex,
    inc_vol_re : Regex,
    inc_manifest_re : Regex,
    full_sig_re : Regex,
    new_sig_re : Regex
}

impl FileNameParser {
    pub fn new() -> Self {
        FileNameParser {
            full_vol_re : Regex::new(r"^duplicity-full\.(?P<time>.*?)\.vol(?P<num>[0-9]+)\.difftar(?P<partial>(\.part))?($|\.)").unwrap(),
            full_manifest_re : Regex::new(r"^duplicity-full\.(?P<time>.*?)\.manifest(?P<partial>(\.part))?($|\.)").unwrap(),
            inc_vol_re : Regex::new(r"^duplicity-inc\.(?P<start_time>.*?)\.to\.(?P<end_time>.*?)\.vol(?P<num>[0-9]+)\.difftar($|\.)").unwrap(),
            inc_manifest_re : Regex::new(r"^duplicity-inc\.(?P<start_time>.*?)\.to\.(?P<end_time>.*?)\.manifest(?P<partial>(\.part))?(\.|$)").unwrap(),
            full_sig_re : Regex::new(r"^duplicity-full-signatures\.(?P<time>.*?)\.sigtar(?P<partial>(\.part))?(\.|$)").unwrap(),
            new_sig_re : Regex::new(r"^duplicity-new-signatures\.(?P<start_time>.*?)\.to\.(?P<end_time>.*?)\.sigtar(?P<partial>(\.part))?(\.|$)").unwrap(),
        }
    }

    pub fn parse(&self, filename : &str) -> Option<FileName> {
        use std::ascii::AsciiExt;

        let lower_fname = filename.to_ascii_lowercase();
        let mut opt_result = self.check_full(&lower_fname)
            .or(self.check_inc(&lower_fname))
            .or(self.check_sig(&lower_fname));

        // write encrypted and compressed properties
        // independently of which type of file is
        if let Some(ref mut result) = opt_result {
            result.compressed = self.is_compressed(lower_fname.as_ref());
            result.encrypted = self.is_encrypted(lower_fname.as_ref());
        }
        opt_result
    }

    fn check_full(&self, filename : &str) -> Option<FileName> {
        if let Some(captures) = self.full_vol_re.captures(filename) {
            let time = captures.name("time").unwrap();
            // TODO: str2time
            let vol_num = try_opt!(self.get_vol_num(captures.name("num").unwrap()));
            return Some(FileName::new().file_type(FileType::Full)
                        .volume_number(vol_num)
                        .time(time.to_owned()));
        }
        if let Some(captures) = self.full_manifest_re.captures(filename) {
            let time = captures.name("time").unwrap();
            // TODO: str2time
            return Some(FileName::new().file_type(FileType::Full)
                        .manifest(true)
                        .time(time.to_owned())
                        .partial(captures.name("partial").is_some()));
        }
        return None;
    }

    fn check_inc(&self, filename : &str) -> Option<FileName> {
        if let Some(captures) = self.inc_vol_re.captures(filename) {
            let start_time = captures.name("start_time").unwrap();
            let end_time = captures.name("end_time").unwrap();
            // TODO: str2time
            let vol_num = try_opt!(self.get_vol_num(captures.name("num").unwrap()));
            return Some(FileName::new().file_type(FileType::Inc)
                        .start_time(start_time.to_owned())
                        .end_time(end_time.to_owned())
                        .volume_number(vol_num));
        }
        if let Some(captures) = self.inc_manifest_re.captures(filename) {
            let start_time = captures.name("start_time").unwrap();
            let end_time = captures.name("end_time").unwrap();
            // TODO: str2time
            return Some(FileName::new().file_type(FileType::Inc)
                        .start_time(start_time.to_owned())
                        .end_time(end_time.to_owned())
                        .manifest(true)
                        .partial(captures.name("partial").is_some()));
        }
        return None;
    }

    fn check_sig(&self, filename : &str) -> Option<FileName> {
        if let Some(captures) = self.full_sig_re.captures(filename) {
            let time = captures.name("time").unwrap();
            // TODO: str2time
            return Some(FileName::new().file_type(FileType::FullSig)
                        .time(time.to_owned())
                        .partial(captures.name("partial").is_some()));
        }
        if let Some(captures) = self.new_sig_re.captures(filename) {
            let start_time = captures.name("start_time").unwrap();
            let end_time = captures.name("end_time").unwrap();
            // TODO: str2time
            return Some(FileName::new().file_type(FileType::NewSig)
                        .start_time(start_time.to_owned())
                        .end_time(end_time.to_owned())
                        .partial(captures.name("partial").is_some()));
        }
        return None;
    }

    fn get_vol_num(&self, s : &str) -> Option<i32> {
        s.parse::<i32>().ok()
    }

    fn is_encrypted(&self, s : &str) -> bool {
        s.ends_with(".gpg") || s.ends_with(".g")
    }

    fn is_compressed(&self, s : &str) -> bool {
        s.ends_with(".gz") || s.ends_with(".z")
    }
}

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

    #[test]
    fn parser_test() {
        let parser = FileNameParser::new();
        // invalid
        assert_eq!(parser.parse("invalid"), None);
        // full
        assert_eq!(parser.parse("duplicity-full.20150617T182545Z.vol1.difftar.gz"),
                   Some(FileName{file_type : FileType::Full,
                                 manifest : false,
                                 volume_number : 1,
                                 time : "20150617t182545z".to_owned(),
                                 start_time : String::new(),
                                 end_time : String::new(),
                                 compressed : true,
                                 encrypted: false,
                                 partial : false}));
        assert_eq!(parser.parse("duplicity-full.20150617T182545Z.manifest"),
                   Some(FileName{file_type : FileType::Full,
                                 manifest : true,
                                 volume_number : 0,
                                 time : "20150617t182545z".to_owned(),
                                 start_time : String::new(),
                                 end_time : String::new(),
                                 compressed : false,
                                 encrypted: false,
                                 partial : false}));
        // inc
        assert_eq!(parser.parse("duplicity-inc.20150617T182629Z.to.20150617T182650Z.vol1.difftar.gz"),
                   Some(FileName{file_type : FileType::Inc,
                                 manifest : false,
                                 volume_number : 1,
                                 time : String::new(),
                                 start_time : "20150617t182629z".to_owned(),
                                 end_time : "20150617t182650z".to_owned(),
                                 compressed : true,
                                 encrypted: false,
                                 partial : false}));
        assert_eq!(parser.parse("duplicity-inc.20150617T182545Z.to.20150617T182629Z.manifest"),
                   Some(FileName{file_type : FileType::Inc,
                                 manifest : true,
                                 volume_number : 0,
                                 time : String::new(),
                                 start_time : "20150617t182545z".to_owned(),
                                 end_time : "20150617t182629z".to_owned(),
                                 compressed : false,
                                 encrypted: false,
                                 partial : false}));
        // new sig
        assert_eq!(parser.parse("duplicity-new-signatures.20150617T182545Z.to.20150617T182629Z.sigtar.gz"),
                   Some(FileName{file_type : FileType::NewSig,
                                 manifest : false,
                                 volume_number : 0,
                                 time : String::new(),
                                 start_time : "20150617t182545z".to_owned(),
                                 end_time : "20150617t182629z".to_owned(),
                                 compressed : true,
                                 encrypted: false,
                                 partial : false}));
        // full sig
        assert_eq!(parser.parse("duplicity-full-signatures.20150617T182545Z.sigtar.gz"),
                   Some(FileName{file_type : FileType::FullSig,
                                 manifest : false,
                                 volume_number : 0,
                                 time : "20150617t182545z".to_owned(),
                                 start_time : String::new(),
                                 end_time : String::new(),
                                 compressed : true,
                                 encrypted: false,
                                 partial : false}));
    }

    #[test]
    fn time_test() {
        let result = ::time::strptime("20150617t182545Z", "%Y%m%dt%H%M%S%Z").unwrap();
        println!("{}", ::time::strftime("%a %d/%m/%Y %H:%M:%S", &result).unwrap());
    }
}
<commit_msg>More testing on time<commit_after>use regex::Regex;

#[derive(Eq, PartialEq, Debug, Clone, Copy)]
pub enum FileType {
    FullSig,
    NewSig,
    Inc,
    Full
}

#[derive(Eq, PartialEq, Debug)]
pub struct FileName {
    pub file_type : FileType,
    pub manifest : bool,
    pub volume_number : i32,
    pub time : String,
    pub start_time : String,
    pub end_time : String,
    pub compressed : bool,
    pub encrypted : bool,
    pub partial : bool
}

impl FileName {
    /// Builder pattern for FileName
    pub fn new() -> Self {
        FileName{
            file_type : FileType::Full,
            manifest : false,
            volume_number : 0,
            time : String::new(),
            start_time : String::new(),
            end_time : String::new(),
            compressed : false,
            encrypted : false,
            partial : false}
    }
}

gen_setters!(FileName,
    file_type : FileType,
    manifest : bool,
    volume_number : i32,
    time : String,
    start_time : String,
    end_time : String,
    compressed : bool,
    encrypted : bool,
    partial : bool
);

pub struct FileNameInfo<'a> {
    pub file_name : &'a str,
    pub info : FileName
}

impl<'a> FileNameInfo<'a> {
    pub fn new(name : &'a str, info : FileName) -> Self {
        FileNameInfo {
            file_name : &name,
            info : info
        }
    }
}

pub struct FileNameParser {
    full_vol_re : Regex,
    full_manifest_re : Regex,
    inc_vol_re : Regex,
    inc_manifest_re : Regex,
    full_sig_re : Regex,
    new_sig_re : Regex
}

impl FileNameParser {
    pub fn new() -> Self {
        FileNameParser {
            full_vol_re : Regex::new(r"^duplicity-full\.(?P<time>.*?)\.vol(?P<num>[0-9]+)\.difftar(?P<partial>(\.part))?($|\.)").unwrap(),
            full_manifest_re : Regex::new(r"^duplicity-full\.(?P<time>.*?)\.manifest(?P<partial>(\.part))?($|\.)").unwrap(),
            inc_vol_re : Regex::new(r"^duplicity-inc\.(?P<start_time>.*?)\.to\.(?P<end_time>.*?)\.vol(?P<num>[0-9]+)\.difftar($|\.)").unwrap(),
            inc_manifest_re : Regex::new(r"^duplicity-inc\.(?P<start_time>.*?)\.to\.(?P<end_time>.*?)\.manifest(?P<partial>(\.part))?(\.|$)").unwrap(),
            full_sig_re : Regex::new(r"^duplicity-full-signatures\.(?P<time>.*?)\.sigtar(?P<partial>(\.part))?(\.|$)").unwrap(),
            new_sig_re : Regex::new(r"^duplicity-new-signatures\.(?P<start_time>.*?)\.to\.(?P<end_time>.*?)\.sigtar(?P<partial>(\.part))?(\.|$)").unwrap(),
        }
    }

    pub fn parse(&self, filename : &str) -> Option<FileName> {
        use std::ascii::AsciiExt;

        let lower_fname = filename.to_ascii_lowercase();
        let mut opt_result = self.check_full(&lower_fname)
            .or(self.check_inc(&lower_fname))
            .or(self.check_sig(&lower_fname));

        // write encrypted and compressed properties
        // independently of which type of file is
        if let Some(ref mut result) = opt_result {
            result.compressed = self.is_compressed(lower_fname.as_ref());
            result.encrypted = self.is_encrypted(lower_fname.as_ref());
        }
        opt_result
    }

    fn check_full(&self, filename : &str) -> Option<FileName> {
        if let Some(captures) = self.full_vol_re.captures(filename) {
            let time = captures.name("time").unwrap();
            // TODO: str2time
            let vol_num = try_opt!(self.get_vol_num(captures.name("num").unwrap()));
            return Some(FileName::new().file_type(FileType::Full)
                        .volume_number(vol_num)
                        .time(time.to_owned()));
        }
        if let Some(captures) = self.full_manifest_re.captures(filename) {
            let time = captures.name("time").unwrap();
            // TODO: str2time
            return Some(FileName::new().file_type(FileType::Full)
                        .manifest(true)
                        .time(time.to_owned())
                        .partial(captures.name("partial").is_some()));
        }
        return None;
    }

    fn check_inc(&self, filename : &str) -> Option<FileName> {
        if let Some(captures) = self.inc_vol_re.captures(filename) {
            let start_time = captures.name("start_time").unwrap();
            let end_time = captures.name("end_time").unwrap();
            // TODO: str2time
            let vol_num = try_opt!(self.get_vol_num(captures.name("num").unwrap()));
            return Some(FileName::new().file_type(FileType::Inc)
                        .start_time(start_time.to_owned())
                        .end_time(end_time.to_owned())
                        .volume_number(vol_num));
        }
        if let Some(captures) = self.inc_manifest_re.captures(filename) {
            let start_time = captures.name("start_time").unwrap();
            let end_time = captures.name("end_time").unwrap();
            // TODO: str2time
            return Some(FileName::new().file_type(FileType::Inc)
                        .start_time(start_time.to_owned())
                        .end_time(end_time.to_owned())
                        .manifest(true)
                        .partial(captures.name("partial").is_some()));
        }
        return None;
    }

    fn check_sig(&self, filename : &str) -> Option<FileName> {
        if let Some(captures) = self.full_sig_re.captures(filename) {
            let time = captures.name("time").unwrap();
            // TODO: str2time
            return Some(FileName::new().file_type(FileType::FullSig)
                        .time(time.to_owned())
                        .partial(captures.name("partial").is_some()));
        }
        if let Some(captures) = self.new_sig_re.captures(filename) {
            let start_time = captures.name("start_time").unwrap();
            let end_time = captures.name("end_time").unwrap();
            // TODO: str2time
            return Some(FileName::new().file_type(FileType::NewSig)
                        .start_time(start_time.to_owned())
                        .end_time(end_time.to_owned())
                        .partial(captures.name("partial").is_some()));
        }
        return None;
    }

    fn get_vol_num(&self, s : &str) -> Option<i32> {
        s.parse::<i32>().ok()
    }

    fn is_encrypted(&self, s : &str) -> bool {
        s.ends_with(".gpg") || s.ends_with(".g")
    }

    fn is_compressed(&self, s : &str) -> bool {
        s.ends_with(".gz") || s.ends_with(".z")
    }
}

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

    #[test]
    fn parser_test() {
        let parser = FileNameParser::new();
        // invalid
        assert_eq!(parser.parse("invalid"), None);
        // full
        assert_eq!(parser.parse("duplicity-full.20150617T182545Z.vol1.difftar.gz"),
                   Some(FileName{file_type : FileType::Full,
                                 manifest : false,
                                 volume_number : 1,
                                 time : "20150617t182545z".to_owned(),
                                 start_time : String::new(),
                                 end_time : String::new(),
                                 compressed : true,
                                 encrypted: false,
                                 partial : false}));
        assert_eq!(parser.parse("duplicity-full.20150617T182545Z.manifest"),
                   Some(FileName{file_type : FileType::Full,
                                 manifest : true,
                                 volume_number : 0,
                                 time : "20150617t182545z".to_owned(),
                                 start_time : String::new(),
                                 end_time : String::new(),
                                 compressed : false,
                                 encrypted: false,
                                 partial : false}));
        // inc
        assert_eq!(parser.parse("duplicity-inc.20150617T182629Z.to.20150617T182650Z.vol1.difftar.gz"),
                   Some(FileName{file_type : FileType::Inc,
                                 manifest : false,
                                 volume_number : 1,
                                 time : String::new(),
                                 start_time : "20150617t182629z".to_owned(),
                                 end_time : "20150617t182650z".to_owned(),
                                 compressed : true,
                                 encrypted: false,
                                 partial : false}));
        assert_eq!(parser.parse("duplicity-inc.20150617T182545Z.to.20150617T182629Z.manifest"),
                   Some(FileName{file_type : FileType::Inc,
                                 manifest : true,
                                 volume_number : 0,
                                 time : String::new(),
                                 start_time : "20150617t182545z".to_owned(),
                                 end_time : "20150617t182629z".to_owned(),
                                 compressed : false,
                                 encrypted: false,
                                 partial : false}));
        // new sig
        assert_eq!(parser.parse("duplicity-new-signatures.20150617T182545Z.to.20150617T182629Z.sigtar.gz"),
                   Some(FileName{file_type : FileType::NewSig,
                                 manifest : false,
                                 volume_number : 0,
                                 time : String::new(),
                                 start_time : "20150617t182545z".to_owned(),
                                 end_time : "20150617t182629z".to_owned(),
                                 compressed : true,
                                 encrypted: false,
                                 partial : false}));
        // full sig
        assert_eq!(parser.parse("duplicity-full-signatures.20150617T182545Z.sigtar.gz"),
                   Some(FileName{file_type : FileType::FullSig,
                                 manifest : false,
                                 volume_number : 0,
                                 time : "20150617t182545z".to_owned(),
                                 start_time : String::new(),
                                 end_time : String::new(),
                                 compressed : true,
                                 encrypted: false,
                                 partial : false}));
    }

    #[test]
    fn time_test() {
        use ::time::{strptime, strftime, at_utc, Tm};

        // parse
        let tm = strptime("20150617t182545Z", "%Y%m%dt%H%M%S%Z").unwrap();
        // format
        assert_eq!(strftime("%a %d/%m/%Y %H:%M:%S", &tm).unwrap(), "Sun 17/06/2015 18:25:45");
        assert_eq!(format!("{}", tm.rfc3339()), "2015-06-17T18:25:45Z");
        // store in Timespec and restore in Tm
        let ts = tm.to_timespec();
        let tm1 = at_utc(ts);
        // somehow they have not the same identical structure :(
        // assert_eq!(tm, tm1);
        // test equally formatted
        let format_fn = |tm : &Tm| { format!("{}", tm.rfc3339()) };
        assert_eq!(format_fn(&tm), format_fn(&tm1));
    }
}
<|endoftext|>


<commit_before>use elapsed::measure_time;

use fall_tree::{Language, NodeType, File, ERROR, WHITESPACE, FileBuilder, NodeBuilder, TextRange};
use lex::{Token, LexRule, tokenize};

#[derive(Clone, Copy)]
pub struct TokenSequence<'a> {
    non_ws_indexes: &'a [usize],
    original_tokens: &'a [Token],
}

pub struct NodeFactory {}

pub enum Node {
    Leaf(NodeType, usize),
    Composite(Option<NodeType>, Vec<Node>)
}

impl<'a> TokenSequence<'a> {
    pub fn current(&self) -> Option<Token> {
        self.non_ws_indexes.first().map(|&idx| {
            self.original_tokens[idx]
        })
    }

    pub fn bump(&self) -> TokenSequence<'a> {
        if self.non_ws_indexes.is_empty() {
            panic!("Can't bump empty token sequence")
        }
        TokenSequence {
            non_ws_indexes: &self.non_ws_indexes[1..],
            original_tokens: self.original_tokens,
        }
    }
}

impl NodeFactory {
    pub fn create_composite_node(&mut self, ty: Option<NodeType>) -> Node {
        Node::Composite(ty, Vec::new())
    }

    pub fn create_error_node(&mut self) -> Node {
        self.create_composite_node(Some(ERROR))
    }

    pub fn create_leaf_node<'t>(&mut self, tokens: TokenSequence<'t>) -> (Node, TokenSequence<'t>) {
        let bumped = tokens.bump();
        let idx = tokens.non_ws_indexes[0];
        let node = Node::Leaf(tokens.current().unwrap().ty, idx);
        (node, bumped)
    }
}

impl Node {
    pub fn push_child(&mut self, child: Node) {
        self.children_mut().push(child)
    }

    fn children_mut(&mut self) -> &mut Vec<Node> {
        match *self {
            Node::Composite(_, ref mut children) => children,
            Node::Leaf(..) => {
                panic!("Can't add children to a leaf node")
            }
        }
    }

    fn children(&self) -> &[Node] {
        match *self {
            Node::Composite(_, ref children) => &*children,
            Node::Leaf(..) => {
                panic!("Can't add children to a leaf node")
            }
        }
    }
}

pub fn parse(
    lang: Language,
    text: String,
    tokenizer: &[LexRule],
    parser: &Fn(&TokenSequence, &mut NodeFactory) -> Node
) -> File {
    let (lex_time, owned_tokens) = measure_time(|| tokenize(&text, tokenizer).collect::<Vec<_>>());
    let non_ws_indexes: Vec<usize> = owned_tokens.iter().enumerate().filter_map(|(i, t)| {
        if t.ty == WHITESPACE {
            None
        } else {
            Some(i)
        }
    }).collect();
    let tokens = TokenSequence {
        non_ws_indexes: &non_ws_indexes,
        original_tokens: &owned_tokens,
    };
    let mut nf = NodeFactory {};
    let (parse_time, node) = measure_time(|| { parser(&tokens, &mut nf) });
    let pre_node = to_pre_node(node, &owned_tokens);

    let mut builder = FileBuilder::new(lang, text, lex_time, parse_time);
    go(&mut builder, None, pre_node);
    return builder.build();

    fn go(
        builder: &mut FileBuilder,
        parent: Option<NodeBuilder>,
        node: PreNode,
    ) {
        let id = builder.node(parent, node.ty, node.range);
        for child in node.children {
            go(builder, Some(id), child)
        }
    }
}

#[derive(Debug)]
struct PreNode {
    ty: NodeType,
    range: TextRange,
    children: Vec<PreNode>,
    first: Option<usize>,
    last: Option<usize>
}

impl PreNode {
    fn push_child(&mut self, child: PreNode, tokens: &[Token]) {
        match (self.last, child.first) {
            (Some(l), Some(r)) if l + 1 < r => {
                for idx in l + 1..r {
                    let t = tokens[idx];
                    assert!(t.ty == WHITESPACE);
                    self.push_child_raw(token_pre_node(idx, t))
                }
            }
            _ => {}
        }
        self.push_child_raw(child)
    }

    fn push_child_raw(&mut self, child: PreNode) {
        self.last = child.last.or(self.last);
        self.first = self.first.or(child.first);
        extend_range(&mut self.range, child.range);
        self.children.push(child);
    }
}

fn token_pre_node(idx: usize, t: Token) -> PreNode {
    PreNode {
        ty: t.ty,
        range: t.range,
        children: Vec::new(),
        first: Some(idx),
        last: Some(idx),
    }
}

fn to_pre_node(file_node: Node, tokens: &[Token]) -> PreNode {
    let ty = match file_node {
        Node::Composite(ty, _) => ty.unwrap(),
        _ => panic!()
    };
    let mut result = PreNode {
        ty: ty,
        range: TextRange::empty(),
        children: Vec::new(),
        first: None,
        last: None,
    };

    for (i, &t) in tokens.iter().enumerate() {
        if t.ty != WHITESPACE {
            break
        }
        result.push_child_raw(token_pre_node(i, t))
    }

    for child in file_node.children() {
        add_child(&mut result, child, tokens)
    }
    if let Some(idx) = result.last {
        for idx in idx + 1..tokens.len() {
            result.push_child_raw(token_pre_node(idx, tokens[idx]))
        }
    }
    result
}

fn add_child(parent: &mut PreNode, node: &Node, tokens: &[Token]) {
    match *node {
        Node::Leaf(_, idx) => {
            parent.push_child(token_pre_node(idx, tokens[idx]), tokens)
        }
        Node::Composite(ty, ref children) => {
            if ty.is_none() {
                for child in children {
                    add_child(parent, child, tokens)
                }
                return
            }
            let ty = ty.unwrap();
            let mut p = PreNode {
                ty: ty,
                range: TextRange::empty(),
                children: Vec::new(),
                first: None,
                last: None,
            };
            for child in children {
                add_child(&mut p, child, tokens);
            }
            parent.push_child(p, tokens)
        }
    }
}

fn extend_range(r: &mut TextRange, right: TextRange) {
    if right.end() == 0 {
        return
    }
    if r.end() == 0 {
        *r = right;
        return
    }
    assert!(r.end() == right.start());
    *r = TextRange::from_to(r.start(), right.end())
}
<commit_msg>Simplify<commit_after>use elapsed::measure_time;

use fall_tree::{Language, NodeType, File, ERROR, WHITESPACE, FileBuilder, NodeBuilder, TextRange};
use lex::{Token, LexRule, tokenize};

#[derive(Clone, Copy)]
pub struct TokenSequence<'a> {
    non_ws_indexes: &'a [usize],
    original_tokens: &'a [Token],
}

pub struct NodeFactory {}

pub enum Node {
    Leaf(NodeType, usize),
    Composite(Option<NodeType>, Vec<Node>)
}

impl<'a> TokenSequence<'a> {
    pub fn current(&self) -> Option<Token> {
        self.non_ws_indexes.first().map(|&idx| {
            self.original_tokens[idx]
        })
    }

    pub fn bump(&self) -> TokenSequence<'a> {
        if self.non_ws_indexes.is_empty() {
            panic!("Can't bump empty token sequence")
        }
        TokenSequence {
            non_ws_indexes: &self.non_ws_indexes[1..],
            original_tokens: self.original_tokens,
        }
    }
}

impl NodeFactory {
    pub fn create_composite_node(&mut self, ty: Option<NodeType>) -> Node {
        Node::Composite(ty, Vec::new())
    }

    pub fn create_error_node(&mut self) -> Node {
        self.create_composite_node(Some(ERROR))
    }

    pub fn create_leaf_node<'t>(&mut self, tokens: TokenSequence<'t>) -> (Node, TokenSequence<'t>) {
        let bumped = tokens.bump();
        let idx = tokens.non_ws_indexes[0];
        let node = Node::Leaf(tokens.current().unwrap().ty, idx);
        (node, bumped)
    }
}

impl Node {
    pub fn push_child(&mut self, child: Node) {
        match *self {
            Node::Composite(_, ref mut children) => children.push(child),
            Node::Leaf(..) => panic!("Can't add children to a leaf node"),
        }
    }
}

pub fn parse(
    lang: Language,
    text: String,
    tokenizer: &[LexRule],
    parser: &Fn(&TokenSequence, &mut NodeFactory) -> Node
) -> File {
    let (lex_time, owned_tokens) = measure_time(|| tokenize(&text, tokenizer).collect::<Vec<_>>());
    let non_ws_indexes: Vec<usize> = owned_tokens.iter().enumerate().filter_map(|(i, t)| {
        if t.ty == WHITESPACE {
            None
        } else {
            Some(i)
        }
    }).collect();
    let tokens = TokenSequence {
        non_ws_indexes: &non_ws_indexes,
        original_tokens: &owned_tokens,
    };
    let mut nf = NodeFactory {};
    let (parse_time, node) = measure_time(|| { parser(&tokens, &mut nf) });
    let pre_node = to_pre_node(node, &owned_tokens);

    let mut builder = FileBuilder::new(lang, text, lex_time, parse_time);
    go(&mut builder, None, pre_node);
    return builder.build();

    fn go(
        builder: &mut FileBuilder,
        parent: Option<NodeBuilder>,
        node: PreNode,
    ) {
        let id = builder.node(parent, node.ty, node.range);
        for child in node.children {
            go(builder, Some(id), child)
        }
    }
}

#[derive(Debug)]
struct PreNode {
    ty: NodeType,
    range: TextRange,
    children: Vec<PreNode>,
    first: Option<usize>,
    last: Option<usize>
}

impl PreNode {
    fn push_child(&mut self, child: PreNode, tokens: &[Token]) {
        match (self.last, child.first) {
            (Some(l), Some(r)) if l + 1 < r => {
                for idx in l + 1..r {
                    let t = tokens[idx];
                    assert!(t.ty == WHITESPACE);
                    self.push_child_raw(token_pre_node(idx, t))
                }
            }
            _ => {}
        }
        self.push_child_raw(child)
    }

    fn push_child_raw(&mut self, child: PreNode) {
        self.last = child.last.or(self.last);
        self.first = self.first.or(child.first);
        extend_range(&mut self.range, child.range);
        self.children.push(child);
    }
}

fn token_pre_node(idx: usize, t: Token) -> PreNode {
    PreNode {
        ty: t.ty,
        range: t.range,
        children: Vec::new(),
        first: Some(idx),
        last: Some(idx),
    }
}

fn to_pre_node(file_node: Node, tokens: &[Token]) -> PreNode {
    let (ty, children) = match file_node {
        Node::Composite(ty, children) => (ty.unwrap(), children),
        _ => panic!("Root node must be composite")
    };
    let mut result = PreNode {
        ty: ty,
        range: TextRange::empty(),
        children: Vec::new(),
        first: None,
        last: None,
    };

    for (i, &t) in tokens.iter().enumerate() {
        if t.ty != WHITESPACE {
            break
        }
        result.push_child_raw(token_pre_node(i, t))
    }

    for child in children {
        add_child(&mut result, &child, tokens)
    }
    if let Some(idx) = result.last {
        for idx in idx + 1..tokens.len() {
            result.push_child_raw(token_pre_node(idx, tokens[idx]))
        }
    }
    result
}

fn add_child(parent: &mut PreNode, node: &Node, tokens: &[Token]) {
    match *node {
        Node::Leaf(_, idx) => {
            parent.push_child(token_pre_node(idx, tokens[idx]), tokens)
        }
        Node::Composite(ty, ref children) => {
            if ty.is_none() {
                for child in children {
                    add_child(parent, child, tokens)
                }
                return
            }
            let ty = ty.unwrap();
            let mut p = PreNode {
                ty: ty,
                range: TextRange::empty(),
                children: Vec::new(),
                first: None,
                last: None,
            };
            for child in children {
                add_child(&mut p, child, tokens);
            }
            parent.push_child(p, tokens)
        }
    }
}

fn extend_range(r: &mut TextRange, right: TextRange) {
    if right.end() == 0 {
        return
    }
    if r.end() == 0 {
        *r = right;
        return
    }
    assert!(r.end() == right.start());
    *r = TextRange::from_to(r.start(), right.end())
}
<|endoftext|>