<commit_before>use std::fs::{File, create_dir_all, set_permissions, Permissions, remove_file};
use std::fs::{symlink_metadata};
use std::io::Write;
use std::os::unix::fs::PermissionsExt;
use std::path::Path;

use regex::Regex;
use scan_dir::{ScanDir};

use config::builders::Builder;
use config::builders::Builder as B;
use config::builders::Source as S;
use config::read_config;
use container::util::{clean_dir, copy_dir};
use super::super::path_util::ToRelative;
use super::commands::ubuntu;
use super::commands::alpine;
use super::commands::generic;
use super::commands::pip;
use super::commands::npm;
use super::commands::vcs;
use super::commands::download;
use super::tarcmd;
use version::short_version;
use builder::distrib::{DistroBox};
use builder::guard::Guard;
use builder::error::StepError;
use path_util::PathExt;
use file_util::{create_dir, shallow_copy};

pub trait BuildCommand {
    fn build(&self, ctx: &mut Guard, build: bool) -> Result<(), StepError>;
}

impl BuildCommand for Builder {
    fn build(&self, guard: &mut Guard, build: bool)
        -> Result<(), StepError>
    {
        use builder::error::StepError as E;
        match self {
            &B::Install(ref pkgs) => {
                guard.ctx.packages.extend(pkgs.clone().into_iter());
                for i in pkgs.iter() {
                    guard.ctx.build_deps.remove(i);
                }
                if build {
                    try!(guard.distro.install(&mut guard.ctx, pkgs));
                }
            }
            &B::BuildDeps(ref pkgs) => {
                for i in pkgs.iter() {
                    if !guard.ctx.packages.contains(i) {
                        guard.ctx.build_deps.insert(i.clone());
                    }
                }
                if build {
                    try!(guard.distro.install(&mut guard.ctx, pkgs));
                }
            }
            &B::Container(ref name) => {
                let cont = guard.ctx.config.containers.get(name)
                    .expect("Subcontainer not found");  // TODO
                for b in cont.setup.iter() {
                    try!(b.build(guard, false)
                        .map_err(|e| E::SubStep(b.clone(), Box::new(e))));
                }
                if build {
                    let version = try!(short_version(&cont, &guard.ctx.config)
                        .map_err(|(s, e)| format!("step {}: {}", s, e)));
                    let path = Path::new("/vagga/base/.roots")
                        .join(format!("{}.{}", name, version)).join("root");
                    try_msg!(copy_dir(&path, &Path::new("/vagga/root")),
                        "Error copying dir {p:?}: {err}", p=path);
                }
            }
            &B::SubConfig(ref sconfig) => {
                let path = match sconfig.source {
                    S::Container(ref container) => {
                        let cont = guard.ctx.config.containers.get(container)
                            .expect("Subcontainer not found");  // TODO
                        let version = try!(short_version(&cont, &guard.ctx.config)
                            .map_err(|(s, e)| format!("step {}: {}", s, e)));
                        Path::new("/vagga/base/.roots")
                            .join(format!("{}.{}", container, version))
                            .join("root").join(&sconfig.path)
                    }
                    S::Git(ref _git) => {
                        unimplemented!();
                    }
                    S::Directory => {
                        Path::new("/work").join(&sconfig.path)
                    }
                };
                let subcfg = try!(read_config(&path));
                let cont = subcfg.containers.get(&sconfig.container)
                    .expect("Subcontainer not found");  // TODO
                for b in cont.setup.iter() {
                    try!(b.build(guard, build)
                        .map_err(|e| E::SubStep(b.clone(), Box::new(e))));
                }
            }
            &B::Text(ref files) => {
                if build {
                    for (path, text) in files.iter() {
                        let realpath = Path::new("/vagga/root")
                            .join(path.rel());
                        try!(File::create(&realpath)
                            .and_then(|mut f| f.write_all(text.as_bytes()))
                            .map_err(|e| format!("Can't create file: {}", e)));
                        try!(set_permissions(&realpath,
                            Permissions::from_mode(0o755))
                            .map_err(|e| format!("Can't chmod file: {}", e)));
                    }
                }
            }
            &B::Copy(ref cinfo) => {
                if build {
                    let ref src = cinfo.source;
                    let dest = Path::new("/vagga/root").join(cinfo.path.rel());
                    let typ = try!(symlink_metadata(src)
                        .map_err(|e| E::Write(src.into(), e)));
                    if typ.is_dir() {
                        try!(create_dir(&dest, false)
                            .map_err(|e| E::Write(dest.clone(), e)));
                        let re = try!(Regex::new(&cinfo.ignore_regex));
                        try!(ScanDir::all().walk(src, |iter| {
                            for (entry, _) in iter {
                                let fpath = entry.path();
                                // We know that directory is inside
                                // the source
                                let path = fpath.rel_to(src).unwrap();
                                // We know that it's decodable
                                let strpath = path.to_str().unwrap();
                                if re.is_match(strpath) {
                                    continue;
                                }
                                let fdest = dest.join(path);
                                try!(shallow_copy(&fpath, &fdest)
                                    .map_err(|e| E::Write(fdest, e)));
                            }
                            Ok(())
                        }).map_err(E::ScanDir).and_then(|x| x));
                    } else {
                        try!(shallow_copy(&cinfo.source, &dest)
                             .map_err(|e| E::Write(dest.clone(), e)));
                    }
                }
            }
            &B::Ubuntu(ref codename) => {
                try!(ubuntu::configure_simple(guard, codename));
                if build {
                    try!(guard.distro.bootstrap(&mut guard.ctx));
                }
            }
            &B::UbuntuRelease(ref release_info) => {
                try!(ubuntu::configure(guard, release_info));
                if build {
                    try!(guard.distro.bootstrap(&mut guard.ctx));
                }
            }
            &B::UbuntuRepo(ref repo) => {
                if build {
                    let ref mut ctx = guard.ctx;
                    try!(guard.distro.specific(|u: &mut ubuntu::Ubuntu| {
                        try!(u.add_debian_repo(ctx, repo));
                        Ok(())
                    }));
                }
            }
            &B::UbuntuPPA(ref name) => {
                if build {
                    let ref mut ctx = guard.ctx;
                    try!(guard.distro.specific(|u: &mut ubuntu::Ubuntu| {
                        u.add_ubuntu_ppa(ctx, name)
                    }));
                }
            }
            &B::AptTrust(ref key) => {
                if build {
                    let ref mut ctx = guard.ctx;
                    try!(guard.distro.specific(|u: &mut ubuntu::Ubuntu| {
                        u.add_apt_key(ctx, key)
                    }));
                }
            }
            &B::UbuntuUniverse => {
                let ref mut ctx = guard.ctx;
                try!(guard.distro.specific(|u: &mut ubuntu::Ubuntu| {
                    try!(u.enable_universe());
                    if build {
                        try!(u.add_universe(ctx));
                    }
                    Ok(())
                }));
            }
            &B::Sh(ref text) => {
                if build {
                    try!(generic::run_command(&mut guard.ctx,
                        &["/bin/sh".to_string(),
                          "-exc".to_string(),
                          text.to_string()]));
                }
            }
            &B::Cmd(ref cmd) => {
                if build {
                    try!(generic::run_command(&mut guard.ctx, &cmd));
                }
            }
            &B::Env(ref pairs) => {
                for (k, v) in pairs.iter() {
                    guard.ctx.environ.insert(k.clone(), v.clone());
                }
            }
            &B::Remove(ref path) => {
                let fpath = Path::new("/vagga/root").join(path.rel());
                if fpath.is_dir() {
                    try!(clean_dir(&fpath, true));
                } else if fpath.exists() {
                    try!(remove_file(&fpath)
                        .map_err(|e| format!("Error removing file {:?}: {}",
                                             &fpath, e)));
                }
                guard.ctx.add_remove_dir(&path);
            }
            &B::EmptyDir(ref path) => {
                try!(clean_dir(path, false));
                guard.ctx.add_empty_dir(&path);
            }
            &B::EnsureDir(ref path) => {
                let fpath = Path::new("/vagga/root").join(path.rel());
                try!(create_dir_all(&fpath)
                    .map_err(|e| format!("Error creating dir: {}", e)));
                try!(set_permissions(&fpath, Permissions::from_mode(0o755))
                    .map_err(|e| format!("Error setting permissions: {}", e)));
                for mount_point in guard.ctx.container_config.volumes.keys() {
                    if path != mount_point && path.starts_with(mount_point) {
                        warn!("{0:?} directory is in the volume: {1:?}.\n\t\
                               {0:?} will be unaccessible inside the container.",
                            path,
                            mount_point);
                    }
                }
                guard.ctx.add_ensure_dir(path);
            }
            &B::CacheDirs(ref pairs) => {
                for (k, v) in pairs.iter() {
                    try!(guard.ctx.add_cache_dir(k, v.clone()));
                }
            }
            &B::Depends(_) => {
            }
            &B::Git(ref git) => {
                if build {
                    try!(vcs::git_command(&mut guard.ctx, git));
                }
            }
            &B::GitInstall(ref git) => {
                if build {
                    try!(vcs::git_install(&mut guard.ctx, git));
                }
            }
            &B::Tar(ref tar) => {
                if build {
                    try!(tarcmd::tar_command(&mut guard.ctx, tar));
                }
            }
            &B::TarInstall(ref tar_inst) => {
                if build {
                    try!(tarcmd::tar_install(&mut guard.ctx, tar_inst));
                }
            }
            &B::Download(ref dlinfo) => {
                if build {
                    try!(download::download(&mut guard.ctx, dlinfo));
                }
            }
            &B::Alpine(ref version) => {
                try!(alpine::configure(&mut guard.distro, &mut guard.ctx,
                    version));
                if build {
                    try!(guard.distro.bootstrap(&mut guard.ctx));
                }
            }
            &B::PipConfig(ref pip_settings) => {
                guard.ctx.pip_settings = pip_settings.clone();
            }
            &B::Py2Install(ref pkgs) => {
                try!(pip::configure(&mut guard.ctx));
                if build {
                    try!(pip::pip_install(&mut guard.distro, &mut guard.ctx,
                        2, pkgs));
                }
            }
            &B::Py3Install(ref pkgs) => {
                try!(pip::configure(&mut guard.ctx));
                if build {
                    try!(pip::pip_install(&mut guard.distro, &mut guard.ctx,
                        3, pkgs));
                }
            }
            &B::Py2Requirements(ref fname) => {
                try!(pip::configure(&mut guard.ctx));
                if build {
                    try!(pip::pip_requirements(&mut guard.distro,
                        &mut guard.ctx, 2, fname));
                }
            }
            &B::Py3Requirements(ref fname) => {
                try!(pip::configure(&mut guard.ctx));
                if build {
                    try!(pip::pip_requirements(&mut guard.distro,
                        &mut guard.ctx, 3, fname));
                }
            }
            &B::PyFreeze(_) => unimplemented!(),
            &B::NpmInstall(ref pkgs) => {
                try!(guard.distro.npm_configure(&mut guard.ctx));
                if build {
                    try!(npm::npm_install(&mut guard.distro, &mut guard.ctx,
                        pkgs));
                }
            }
            &B::NpmDependencies(ref info) => {
                try!(guard.distro.npm_configure(&mut guard.ctx));
                if build {
                    try!(npm::npm_deps(&mut guard.distro, &mut guard.ctx,
                        info));
                }
            }
        }
        if build {
            try!(guard.ctx.timelog.mark(format_args!("Step: {:?}", self))
                .map_err(|e| format!("Can't write timelog: {}", e)));
        }
        Ok(())
    }
}
<commit_msg>Fix permissions of Text files created<commit_after>use std::fs::{File, create_dir_all, set_permissions, Permissions, remove_file};
use std::fs::{symlink_metadata};
use std::io::Write;
use std::os::unix::fs::PermissionsExt;
use std::path::Path;

use regex::Regex;
use scan_dir::{ScanDir};

use config::builders::Builder;
use config::builders::Builder as B;
use config::builders::Source as S;
use config::read_config;
use container::util::{clean_dir, copy_dir};
use super::super::path_util::ToRelative;
use super::commands::ubuntu;
use super::commands::alpine;
use super::commands::generic;
use super::commands::pip;
use super::commands::npm;
use super::commands::vcs;
use super::commands::download;
use super::tarcmd;
use version::short_version;
use builder::distrib::{DistroBox};
use builder::guard::Guard;
use builder::error::StepError;
use path_util::PathExt;
use file_util::{create_dir, shallow_copy};

pub trait BuildCommand {
    fn build(&self, ctx: &mut Guard, build: bool) -> Result<(), StepError>;
}

impl BuildCommand for Builder {
    fn build(&self, guard: &mut Guard, build: bool)
        -> Result<(), StepError>
    {
        use builder::error::StepError as E;
        match self {
            &B::Install(ref pkgs) => {
                guard.ctx.packages.extend(pkgs.clone().into_iter());
                for i in pkgs.iter() {
                    guard.ctx.build_deps.remove(i);
                }
                if build {
                    try!(guard.distro.install(&mut guard.ctx, pkgs));
                }
            }
            &B::BuildDeps(ref pkgs) => {
                for i in pkgs.iter() {
                    if !guard.ctx.packages.contains(i) {
                        guard.ctx.build_deps.insert(i.clone());
                    }
                }
                if build {
                    try!(guard.distro.install(&mut guard.ctx, pkgs));
                }
            }
            &B::Container(ref name) => {
                let cont = guard.ctx.config.containers.get(name)
                    .expect("Subcontainer not found");  // TODO
                for b in cont.setup.iter() {
                    try!(b.build(guard, false)
                        .map_err(|e| E::SubStep(b.clone(), Box::new(e))));
                }
                if build {
                    let version = try!(short_version(&cont, &guard.ctx.config)
                        .map_err(|(s, e)| format!("step {}: {}", s, e)));
                    let path = Path::new("/vagga/base/.roots")
                        .join(format!("{}.{}", name, version)).join("root");
                    try_msg!(copy_dir(&path, &Path::new("/vagga/root")),
                        "Error copying dir {p:?}: {err}", p=path);
                }
            }
            &B::SubConfig(ref sconfig) => {
                let path = match sconfig.source {
                    S::Container(ref container) => {
                        let cont = guard.ctx.config.containers.get(container)
                            .expect("Subcontainer not found");  // TODO
                        let version = try!(short_version(&cont, &guard.ctx.config)
                            .map_err(|(s, e)| format!("step {}: {}", s, e)));
                        Path::new("/vagga/base/.roots")
                            .join(format!("{}.{}", container, version))
                            .join("root").join(&sconfig.path)
                    }
                    S::Git(ref _git) => {
                        unimplemented!();
                    }
                    S::Directory => {
                        Path::new("/work").join(&sconfig.path)
                    }
                };
                let subcfg = try!(read_config(&path));
                let cont = subcfg.containers.get(&sconfig.container)
                    .expect("Subcontainer not found");  // TODO
                for b in cont.setup.iter() {
                    try!(b.build(guard, build)
                        .map_err(|e| E::SubStep(b.clone(), Box::new(e))));
                }
            }
            &B::Text(ref files) => {
                if build {
                    for (path, text) in files.iter() {
                        let realpath = Path::new("/vagga/root")
                            .join(path.rel());
                        try!(File::create(&realpath)
                            .and_then(|mut f| f.write_all(text.as_bytes()))
                            .map_err(|e| format!("Can't create file: {}", e)));
                        try!(set_permissions(&realpath,
                            Permissions::from_mode(0o644))
                            .map_err(|e| format!("Can't chmod file: {}", e)));
                    }
                }
            }
            &B::Copy(ref cinfo) => {
                if build {
                    let ref src = cinfo.source;
                    let dest = Path::new("/vagga/root").join(cinfo.path.rel());
                    let typ = try!(symlink_metadata(src)
                        .map_err(|e| E::Write(src.into(), e)));
                    if typ.is_dir() {
                        try!(create_dir(&dest, false)
                            .map_err(|e| E::Write(dest.clone(), e)));
                        let re = try!(Regex::new(&cinfo.ignore_regex));
                        try!(ScanDir::all().walk(src, |iter| {
                            for (entry, _) in iter {
                                let fpath = entry.path();
                                // We know that directory is inside
                                // the source
                                let path = fpath.rel_to(src).unwrap();
                                // We know that it's decodable
                                let strpath = path.to_str().unwrap();
                                if re.is_match(strpath) {
                                    continue;
                                }
                                let fdest = dest.join(path);
                                try!(shallow_copy(&fpath, &fdest)
                                    .map_err(|e| E::Write(fdest, e)));
                            }
                            Ok(())
                        }).map_err(E::ScanDir).and_then(|x| x));
                    } else {
                        try!(shallow_copy(&cinfo.source, &dest)
                             .map_err(|e| E::Write(dest.clone(), e)));
                    }
                }
            }
            &B::Ubuntu(ref codename) => {
                try!(ubuntu::configure_simple(guard, codename));
                if build {
                    try!(guard.distro.bootstrap(&mut guard.ctx));
                }
            }
            &B::UbuntuRelease(ref release_info) => {
                try!(ubuntu::configure(guard, release_info));
                if build {
                    try!(guard.distro.bootstrap(&mut guard.ctx));
                }
            }
            &B::UbuntuRepo(ref repo) => {
                if build {
                    let ref mut ctx = guard.ctx;
                    try!(guard.distro.specific(|u: &mut ubuntu::Ubuntu| {
                        try!(u.add_debian_repo(ctx, repo));
                        Ok(())
                    }));
                }
            }
            &B::UbuntuPPA(ref name) => {
                if build {
                    let ref mut ctx = guard.ctx;
                    try!(guard.distro.specific(|u: &mut ubuntu::Ubuntu| {
                        u.add_ubuntu_ppa(ctx, name)
                    }));
                }
            }
            &B::AptTrust(ref key) => {
                if build {
                    let ref mut ctx = guard.ctx;
                    try!(guard.distro.specific(|u: &mut ubuntu::Ubuntu| {
                        u.add_apt_key(ctx, key)
                    }));
                }
            }
            &B::UbuntuUniverse => {
                let ref mut ctx = guard.ctx;
                try!(guard.distro.specific(|u: &mut ubuntu::Ubuntu| {
                    try!(u.enable_universe());
                    if build {
                        try!(u.add_universe(ctx));
                    }
                    Ok(())
                }));
            }
            &B::Sh(ref text) => {
                if build {
                    try!(generic::run_command(&mut guard.ctx,
                        &["/bin/sh".to_string(),
                          "-exc".to_string(),
                          text.to_string()]));
                }
            }
            &B::Cmd(ref cmd) => {
                if build {
                    try!(generic::run_command(&mut guard.ctx, &cmd));
                }
            }
            &B::Env(ref pairs) => {
                for (k, v) in pairs.iter() {
                    guard.ctx.environ.insert(k.clone(), v.clone());
                }
            }
            &B::Remove(ref path) => {
                let fpath = Path::new("/vagga/root").join(path.rel());
                if fpath.is_dir() {
                    try!(clean_dir(&fpath, true));
                } else if fpath.exists() {
                    try!(remove_file(&fpath)
                        .map_err(|e| format!("Error removing file {:?}: {}",
                                             &fpath, e)));
                }
                guard.ctx.add_remove_dir(&path);
            }
            &B::EmptyDir(ref path) => {
                try!(clean_dir(path, false));
                guard.ctx.add_empty_dir(&path);
            }
            &B::EnsureDir(ref path) => {
                let fpath = Path::new("/vagga/root").join(path.rel());
                try!(create_dir_all(&fpath)
                    .map_err(|e| format!("Error creating dir: {}", e)));
                try!(set_permissions(&fpath, Permissions::from_mode(0o755))
                    .map_err(|e| format!("Error setting permissions: {}", e)));
                for mount_point in guard.ctx.container_config.volumes.keys() {
                    if path != mount_point && path.starts_with(mount_point) {
                        warn!("{0:?} directory is in the volume: {1:?}.\n\t\
                               {0:?} will be unaccessible inside the container.",
                            path,
                            mount_point);
                    }
                }
                guard.ctx.add_ensure_dir(path);
            }
            &B::CacheDirs(ref pairs) => {
                for (k, v) in pairs.iter() {
                    try!(guard.ctx.add_cache_dir(k, v.clone()));
                }
            }
            &B::Depends(_) => {
            }
            &B::Git(ref git) => {
                if build {
                    try!(vcs::git_command(&mut guard.ctx, git));
                }
            }
            &B::GitInstall(ref git) => {
                if build {
                    try!(vcs::git_install(&mut guard.ctx, git));
                }
            }
            &B::Tar(ref tar) => {
                if build {
                    try!(tarcmd::tar_command(&mut guard.ctx, tar));
                }
            }
            &B::TarInstall(ref tar_inst) => {
                if build {
                    try!(tarcmd::tar_install(&mut guard.ctx, tar_inst));
                }
            }
            &B::Download(ref dlinfo) => {
                if build {
                    try!(download::download(&mut guard.ctx, dlinfo));
                }
            }
            &B::Alpine(ref version) => {
                try!(alpine::configure(&mut guard.distro, &mut guard.ctx,
                    version));
                if build {
                    try!(guard.distro.bootstrap(&mut guard.ctx));
                }
            }
            &B::PipConfig(ref pip_settings) => {
                guard.ctx.pip_settings = pip_settings.clone();
            }
            &B::Py2Install(ref pkgs) => {
                try!(pip::configure(&mut guard.ctx));
                if build {
                    try!(pip::pip_install(&mut guard.distro, &mut guard.ctx,
                        2, pkgs));
                }
            }
            &B::Py3Install(ref pkgs) => {
                try!(pip::configure(&mut guard.ctx));
                if build {
                    try!(pip::pip_install(&mut guard.distro, &mut guard.ctx,
                        3, pkgs));
                }
            }
            &B::Py2Requirements(ref fname) => {
                try!(pip::configure(&mut guard.ctx));
                if build {
                    try!(pip::pip_requirements(&mut guard.distro,
                        &mut guard.ctx, 2, fname));
                }
            }
            &B::Py3Requirements(ref fname) => {
                try!(pip::configure(&mut guard.ctx));
                if build {
                    try!(pip::pip_requirements(&mut guard.distro,
                        &mut guard.ctx, 3, fname));
                }
            }
            &B::PyFreeze(_) => unimplemented!(),
            &B::NpmInstall(ref pkgs) => {
                try!(guard.distro.npm_configure(&mut guard.ctx));
                if build {
                    try!(npm::npm_install(&mut guard.distro, &mut guard.ctx,
                        pkgs));
                }
            }
            &B::NpmDependencies(ref info) => {
                try!(guard.distro.npm_configure(&mut guard.ctx));
                if build {
                    try!(npm::npm_deps(&mut guard.distro, &mut guard.ctx,
                        info));
                }
            }
        }
        if build {
            try!(guard.ctx.timelog.mark(format_args!("Step: {:?}", self))
                .map_err(|e| format!("Can't write timelog: {}", e)));
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>use crate::attr;
use proc_macro2::TokenStream;
use quote::{format_ident, quote, quote_spanned};
use syn::spanned::Spanned;
use syn::{
    Data, DataEnum, DataStruct, DeriveInput, Error, Field, Fields, Ident, Index, Member, Result,
    Type,
};

pub fn derive(input: &DeriveInput) -> Result<TokenStream> {
    match &input.data {
        Data::Struct(data) => impl_struct(input, data),
        Data::Enum(data) => impl_enum(input, data),
        Data::Union(_) => Err(Error::new_spanned(
            input,
            "union as errors are not supported",
        )),
    }
}

fn impl_struct(input: &DeriveInput, data: &DataStruct) -> Result<TokenStream> {
    let ident = &input.ident;
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

    let source = match &data.fields {
        Fields::Named(fields) => source_member(&fields.named)?,
        Fields::Unnamed(fields) => source_member(&fields.unnamed)?,
        Fields::Unit => None,
    };

    let backtrace = match &data.fields {
        Fields::Named(fields) => backtrace_member(&fields.named)?,
        Fields::Unnamed(fields) => backtrace_member(&fields.unnamed)?,
        Fields::Unit => None,
    };

    let source_method = source.map(|source| {
        let member = quote_spanned!(source.span()=> self.#source);
        quote! {
            fn source(&self) -> std::option::Option<&(dyn std::error::Error + 'static)> {
                use thiserror::private::AsDynError;
                std::option::Option::Some(#member.as_dyn_error())
            }
        }
    });

    let backtrace_method = backtrace.map(|backtrace| {
        quote! {
            fn backtrace(&self) -> std::option::Option<&std::backtrace::Backtrace> {
                std::option::Option::Some(&self.#backtrace)
            }
        }
    });

    let display = attr::display(&input.attrs)?.map(|display| {
        let pat = match &data.fields {
            Fields::Named(fields) => {
                let var = fields.named.iter().map(|field| &field.ident);
                quote!(Self { #(#var),* })
            }
            Fields::Unnamed(fields) => {
                let var = (0..fields.unnamed.len()).map(|i| format_ident!("_{}", i));
                quote!(Self(#(#var),*))
            }
            Fields::Unit => quote!(_),
        };
        quote! {
            impl #impl_generics std::fmt::Display for #ident #ty_generics #where_clause {
                fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                    #[allow(unused_variables)]
                    let #pat = self;
                    #display
                }
            }
        }
    });

    Ok(quote! {
        impl #impl_generics std::error::Error for #ident #ty_generics #where_clause {
            #source_method
            #backtrace_method
        }
        #display
    })
}

fn impl_enum(input: &DeriveInput, data: &DataEnum) -> Result<TokenStream> {
    let ident = &input.ident;
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

    let sources = data
        .variants
        .iter()
        .map(|variant| match &variant.fields {
            Fields::Named(fields) => source_member(&fields.named),
            Fields::Unnamed(fields) => source_member(&fields.unnamed),
            Fields::Unit => Ok(None),
        })
        .collect::<Result<Vec<_>>>()?;

    let backtraces = data
        .variants
        .iter()
        .map(|variant| match &variant.fields {
            Fields::Named(fields) => backtrace_member(&fields.named),
            Fields::Unnamed(fields) => backtrace_member(&fields.unnamed),
            Fields::Unit => Ok(None),
        })
        .collect::<Result<Vec<_>>>()?;

    let source_method = if sources.iter().any(Option::is_some) {
        let arms = data.variants.iter().zip(sources).map(|(variant, source)| {
            let ident = &variant.ident;
            match source {
                Some(source) => quote! {
                    Self::#ident {#source: source, ..} => std::option::Option::Some(source.as_dyn_error()),
                },
                None => quote! {
                    Self::#ident {..} => std::option::Option::None,
                },
            }
        });
        Some(quote! {
            fn source(&self) -> std::option::Option<&(dyn std::error::Error + 'static)> {
                use thiserror::private::AsDynError;
                match self {
                    #(#arms)*
                }
            }
        })
    } else {
        None
    };

    let backtrace_method = if backtraces.iter().any(Option::is_some) {
        let arms = data.variants.iter().zip(backtraces).map(|(variant, backtrace)| {
            let ident = &variant.ident;
            match backtrace {
                Some(backtrace) => quote! {
                    Self::#ident {#backtrace: backtrace, ..} => std::option::Option::Some(backtrace),
                },
                None => quote! {
                    Self::#ident {..} => std::option::Option::None,
                },
            }
        });
        Some(quote! {
            fn backtrace(&self) -> std::option::Option<&std::backtrace::Backtrace> {
                match self {
                    #(#arms)*
                }
            }
        })
    } else {
        None
    };

    let displays = data
        .variants
        .iter()
        .map(|variant| attr::display(&variant.attrs))
        .collect::<Result<Vec<_>>>()?;
    let display = if displays.iter().any(Option::is_some) {
        let arms = data
            .variants
            .iter()
            .zip(displays)
            .map(|(variant, display)| {
                let display = display.ok_or_else(|| {
                    Error::new_spanned(variant, "missing #[error(\"...\")] display attribute")
                })?;
                let ident = &variant.ident;
                Ok(match &variant.fields {
                    Fields::Named(fields) => {
                        let var = fields.named.iter().map(|field| &field.ident);
                        quote!(Self::#ident { #(#var),* } => #display)
                    }
                    Fields::Unnamed(fields) => {
                        let var = (0..fields.unnamed.len()).map(|i| format_ident!("_{}", i));
                        quote!(Self::#ident(#(#var),*) => #display)
                    }
                    Fields::Unit => quote!(Self::#ident => #display),
                })
            })
            .collect::<Result<Vec<_>>>()?;
        Some(quote! {
            impl #impl_generics std::fmt::Display for #ident #ty_generics #where_clause {
                fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                    #[allow(unused_variables)]
                    match self {
                        #(#arms,)*
                    }
                }
            }
        })
    } else {
        None
    };

    Ok(quote! {
        impl #impl_generics std::error::Error for #ident #ty_generics #where_clause {
            #source_method
            #backtrace_method
        }
        #display
    })
}

fn source_member<'a>(fields: impl IntoIterator<Item = &'a Field>) -> Result<Option<Member>> {
    for (i, field) in fields.into_iter().enumerate() {
        if attr::is_source(field)? {
            return Ok(Some(member(i, &field.ident)));
        }
    }
    Ok(None)
}

fn backtrace_member<'a>(fields: impl IntoIterator<Item = &'a Field>) -> Result<Option<Member>> {
    for (i, field) in fields.into_iter().enumerate() {
        if type_is_backtrace(&field.ty) {
            return Ok(Some(member(i, &field.ident)));
        }
    }
    Ok(None)
}

fn type_is_backtrace(ty: &Type) -> bool {
    let path = match ty {
        Type::Path(ty) => &ty.path,
        _ => return false,
    };

    let last = path.segments.last().unwrap();
    last.ident == "Backtrace" && last.arguments.is_empty()
}

fn member(i: usize, ident: &Option<Ident>) -> Member {
    match ident {
        Some(ident) => Member::Named(ident.clone()),
        None => Member::Unnamed(Index::from(i)),
    }
}
<commit_msg>Avoid enum variants through Self<commit_after>use crate::attr;
use proc_macro2::TokenStream;
use quote::{format_ident, quote, quote_spanned};
use syn::spanned::Spanned;
use syn::{
    Data, DataEnum, DataStruct, DeriveInput, Error, Field, Fields, Ident, Index, Member, Result,
    Type,
};

pub fn derive(input: &DeriveInput) -> Result<TokenStream> {
    match &input.data {
        Data::Struct(data) => impl_struct(input, data),
        Data::Enum(data) => impl_enum(input, data),
        Data::Union(_) => Err(Error::new_spanned(
            input,
            "union as errors are not supported",
        )),
    }
}

fn impl_struct(input: &DeriveInput, data: &DataStruct) -> Result<TokenStream> {
    let ty = &input.ident;
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

    let source = match &data.fields {
        Fields::Named(fields) => source_member(&fields.named)?,
        Fields::Unnamed(fields) => source_member(&fields.unnamed)?,
        Fields::Unit => None,
    };

    let backtrace = match &data.fields {
        Fields::Named(fields) => backtrace_member(&fields.named)?,
        Fields::Unnamed(fields) => backtrace_member(&fields.unnamed)?,
        Fields::Unit => None,
    };

    let source_method = source.map(|source| {
        let member = quote_spanned!(source.span()=> self.#source);
        quote! {
            fn source(&self) -> std::option::Option<&(dyn std::error::Error + 'static)> {
                use thiserror::private::AsDynError;
                std::option::Option::Some(#member.as_dyn_error())
            }
        }
    });

    let backtrace_method = backtrace.map(|backtrace| {
        quote! {
            fn backtrace(&self) -> std::option::Option<&std::backtrace::Backtrace> {
                std::option::Option::Some(&self.#backtrace)
            }
        }
    });

    let display = attr::display(&input.attrs)?.map(|display| {
        let pat = match &data.fields {
            Fields::Named(fields) => {
                let var = fields.named.iter().map(|field| &field.ident);
                quote!(Self { #(#var),* })
            }
            Fields::Unnamed(fields) => {
                let var = (0..fields.unnamed.len()).map(|i| format_ident!("_{}", i));
                quote!(Self(#(#var),*))
            }
            Fields::Unit => quote!(_),
        };
        quote! {
            impl #impl_generics std::fmt::Display for #ty #ty_generics #where_clause {
                fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                    #[allow(unused_variables)]
                    let #pat = self;
                    #display
                }
            }
        }
    });

    Ok(quote! {
        impl #impl_generics std::error::Error for #ty #ty_generics #where_clause {
            #source_method
            #backtrace_method
        }
        #display
    })
}

fn impl_enum(input: &DeriveInput, data: &DataEnum) -> Result<TokenStream> {
    let ty = &input.ident;
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

    let sources = data
        .variants
        .iter()
        .map(|variant| match &variant.fields {
            Fields::Named(fields) => source_member(&fields.named),
            Fields::Unnamed(fields) => source_member(&fields.unnamed),
            Fields::Unit => Ok(None),
        })
        .collect::<Result<Vec<_>>>()?;

    let backtraces = data
        .variants
        .iter()
        .map(|variant| match &variant.fields {
            Fields::Named(fields) => backtrace_member(&fields.named),
            Fields::Unnamed(fields) => backtrace_member(&fields.unnamed),
            Fields::Unit => Ok(None),
        })
        .collect::<Result<Vec<_>>>()?;

    let source_method = if sources.iter().any(Option::is_some) {
        let arms = data.variants.iter().zip(sources).map(|(variant, source)| {
            let ident = &variant.ident;
            match source {
                Some(source) => quote! {
                    #ty::#ident {#source: source, ..} => std::option::Option::Some(source.as_dyn_error()),
                },
                None => quote! {
                    #ty::#ident {..} => std::option::Option::None,
                },
            }
        });
        Some(quote! {
            fn source(&self) -> std::option::Option<&(dyn std::error::Error + 'static)> {
                use thiserror::private::AsDynError;
                match self {
                    #(#arms)*
                }
            }
        })
    } else {
        None
    };

    let backtrace_method = if backtraces.iter().any(Option::is_some) {
        let arms = data.variants.iter().zip(backtraces).map(|(variant, backtrace)| {
            let ident = &variant.ident;
            match backtrace {
                Some(backtrace) => quote! {
                    #ty::#ident {#backtrace: backtrace, ..} => std::option::Option::Some(backtrace),
                },
                None => quote! {
                    #ty::#ident {..} => std::option::Option::None,
                },
            }
        });
        Some(quote! {
            fn backtrace(&self) -> std::option::Option<&std::backtrace::Backtrace> {
                match self {
                    #(#arms)*
                }
            }
        })
    } else {
        None
    };

    let displays = data
        .variants
        .iter()
        .map(|variant| attr::display(&variant.attrs))
        .collect::<Result<Vec<_>>>()?;
    let display = if displays.iter().any(Option::is_some) {
        let arms = data
            .variants
            .iter()
            .zip(displays)
            .map(|(variant, display)| {
                let display = display.ok_or_else(|| {
                    Error::new_spanned(variant, "missing #[error(\"...\")] display attribute")
                })?;
                let ident = &variant.ident;
                Ok(match &variant.fields {
                    Fields::Named(fields) => {
                        let var = fields.named.iter().map(|field| &field.ident);
                        quote!(#ty::#ident { #(#var),* } => #display)
                    }
                    Fields::Unnamed(fields) => {
                        let var = (0..fields.unnamed.len()).map(|i| format_ident!("_{}", i));
                        quote!(#ty::#ident(#(#var),*) => #display)
                    }
                    Fields::Unit => quote!(#ty::#ident => #display),
                })
            })
            .collect::<Result<Vec<_>>>()?;
        Some(quote! {
            impl #impl_generics std::fmt::Display for #ty #ty_generics #where_clause {
                fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
                    #[allow(unused_variables)]
                    match self {
                        #(#arms,)*
                    }
                }
            }
        })
    } else {
        None
    };

    Ok(quote! {
        impl #impl_generics std::error::Error for #ty #ty_generics #where_clause {
            #source_method
            #backtrace_method
        }
        #display
    })
}

fn source_member<'a>(fields: impl IntoIterator<Item = &'a Field>) -> Result<Option<Member>> {
    for (i, field) in fields.into_iter().enumerate() {
        if attr::is_source(field)? {
            return Ok(Some(member(i, &field.ident)));
        }
    }
    Ok(None)
}

fn backtrace_member<'a>(fields: impl IntoIterator<Item = &'a Field>) -> Result<Option<Member>> {
    for (i, field) in fields.into_iter().enumerate() {
        if type_is_backtrace(&field.ty) {
            return Ok(Some(member(i, &field.ident)));
        }
    }
    Ok(None)
}

fn type_is_backtrace(ty: &Type) -> bool {
    let path = match ty {
        Type::Path(ty) => &ty.path,
        _ => return false,
    };

    let last = path.segments.last().unwrap();
    last.ident == "Backtrace" && last.arguments.is_empty()
}

fn member(i: usize, ident: &Option<Ident>) -> Member {
    match ident {
        Some(ident) => Member::Named(ident.clone()),
        None => Member::Unnamed(Index::from(i)),
    }
}
<|endoftext|>


<commit_before>use toml::Value;

use libimagerror::into::IntoError;

use vcs::git::error::GitHookErrorKind as GHEK;
use vcs::git::error::MapErrInto;
use vcs::git::result::Result;

use vcs::git::action::StoreAction;

pub fn commit_interactive(config: &Value) -> bool {
    unimplemented!()
}

pub fn commit_message(config: &Value, action: StoreAction) -> Option<String> {
    if commit_interactive(config) {
        unimplemented!()
    } else {
        unimplemented!()
    }
}

pub fn abort_on_repo_init_err(cfg: Option<&Value>) -> bool {
    cfg.map(|cfg| {
        match cfg.lookup("abort_on_repo_init_failure") {
            Some(&Value::Boolean(b)) => b,
            Some(_) => {
                warn!("Configuration error, 'abort_on_repo_init_failure' must be a Boolean (true|false).");
                warn!("Assuming 'true' now.");
                true
            },
            None => {
                debug!("No key `abort_on_repo_init_failure' - Assuming 'true'");
                true
            },
        }
    })
    .unwrap_or(false)
}

pub fn ensure_branch(cfg: Option<&Value>) -> Result<Option<String>> {
    match cfg {
        Some(cfg) => {
            match cfg.lookup("ensure_branch") {
                Some(&Value::String(ref s)) => Ok(Some(s.clone())),
                Some(_) => {
                    warn!("Configuration error, 'ensure_branch' must be a String.");
                    Err(GHEK::ConfigTypeError.into_error())
                        .map_err_into(GHEK::ConfigTypeError)
                },
                None => {
                    debug!("No key `ensure_branch'");
                    Ok(None)
                },
            }
        },
        None => Ok(None),
    }
}

pub fn do_checkout_ensure_branch(cfg: Option<&Value>) -> bool {
    cfg.map(|cfg| {
        match cfg.lookup("try_checkout_ensure_branch") {
            Some(&Value::Boolean(b)) => b,
            Some(_) => {
                warn!("Configuration error, 'try_checkout_ensure_branch' must be a Boolean (true|false).");
                warn!("Assuming 'true' now.");
                true
            },
            None => {
                debug!("No key `try_checkout_ensure_branch' - Assuming 'true'");
                true
            },
        }
    })
    .unwrap_or(false)
}

<commit_msg>Refactor: Use helper function internally<commit_after>use toml::Value;

use libimagerror::into::IntoError;

use vcs::git::error::GitHookErrorKind as GHEK;
use vcs::git::error::MapErrInto;
use vcs::git::result::Result;

use vcs::git::action::StoreAction;

pub fn commit_interactive(config: &Value) -> bool {
    unimplemented!()
}

pub fn commit_message(config: &Value, action: StoreAction) -> Option<String> {
    if commit_interactive(config) {
        unimplemented!()
    } else {
        unimplemented!()
    }
}

pub fn abort_on_repo_init_err(cfg: Option<&Value>) -> bool {
    get_bool_cfg(cfg, "abort_on_repo_init_failure", true, true)
}

pub fn ensure_branch(cfg: Option<&Value>) -> Result<Option<String>> {
    match cfg {
        Some(cfg) => {
            match cfg.lookup("ensure_branch") {
                Some(&Value::String(ref s)) => Ok(Some(s.clone())),
                Some(_) => {
                    warn!("Configuration error, 'ensure_branch' must be a String.");
                    Err(GHEK::ConfigTypeError.into_error())
                        .map_err_into(GHEK::ConfigTypeError)
                },
                None => {
                    debug!("No key `ensure_branch'");
                    Ok(None)
                },
            }
        },
        None => Ok(None),
    }
}

pub fn do_checkout_ensure_branch(cfg: Option<&Value>) -> bool {
    get_bool_cfg(cfg, "try_checkout_ensure_branch", true, true)
}

fn get_bool_cfg(cfg: Option<&Value>, name: &str, on_fail: bool, on_unavail: bool) -> bool {
    cfg.map(|cfg| {
        match cfg.lookup(name) {
            Some(&Value::Boolean(b)) => b,
            Some(_) => {
                warn!("Configuration error, '{}' must be a Boolean (true|false).", name);
                warn!("Assuming 'true' now.");
                on_fail
            },
            None => {
                debug!("No key '{}' - Assuming 'true'", name);
                on_fail
            },
        }
    })
    .unwrap_or(on_unavail)
}

<|endoftext|>


<commit_before>#[macro_export]
macro_rules! sequence {
    ($pm:expr, $pt:expr, {let $x:pat = $parser:expr; $($rest:tt)*}, $creator:expr) => {{
        let (pt, $x) = try_parse!($parser($pm, $pt));
        sequence!($pm, pt, {$($rest)*}, $creator)
    }};
    ($pm:expr, $pt:expr, {$x:pat = $parser:expr; $($rest:tt)*}, $creator:expr) => {{
        let (pt, $x) = try_parse!($parser($pm, $pt));
        sequence!($pm, pt, {$($rest)*}, $creator)
    }};
    ($pm:expr, $pt:expr, {$parser:expr; $($rest:tt)*}, $creator:expr) => {{
        let (pt, _) = try_parse!($parser($pm, $pt));
        sequence!($pm, pt, {$($rest)*}, $creator)
    }};
    ($pm:expr, $pt:expr, {}, $creator:expr) => {
        Progress::success($pt, $creator($pm, $pt))
    };
}

use super::{ParseMaster, Progress, Status, Point, Recoverable};

pub trait IntoAppend<T> {
    fn into(self) -> Vec<T>;
}

impl<T> IntoAppend<T> for Vec<T> {
    fn into(self) -> Vec<T> { self }
}

impl<T> IntoAppend<T> for Option<T> {
    fn into(self) -> Vec<T> {
        self.map(|v| vec![v]).unwrap_or_else(Vec::new)
    }
}

pub fn optional<P, E, S, F, T>
    (parser: F)
     -> impl FnOnce(&mut ParseMaster<P, E, S>, P) -> Progress<P, Option<T>, E>
    where F: FnOnce(&mut ParseMaster<P, E, S>, P) -> Progress<P, T, E>,
          P: Point,
          E: Recoverable,
{
    move |pm, pt| pm.optional(pt, parser)
}

pub fn optional_append<P, E, S, A, F, T>
    (append_to: A, parser: F)
     -> impl FnOnce(&mut ParseMaster<P, E, S>, P) -> Progress<P, Vec<T>, E>
    where F: FnOnce(&mut ParseMaster<P, E, S>, P) -> Progress<P, T, E>,
          A: IntoAppend<T>,
          P: Point,
          //E: Recoverable, // TODO: use this
{
    move |pm, pt| {
        let mut append_to = append_to.into();
        match parser(pm, pt) {
            Progress { point, status: Status::Success(v) } => {
                append_to.push(v);
                Progress::success(point, append_to)
            }
            Progress { point, status: Status::Failure(..) } => {
                Progress::success(point, append_to)
            }
        }
    }
}

pub fn zero_or_more<P, E, S, F, T>
    (parser: F)
     -> impl Fn(&mut ParseMaster<P, E, S>, P) -> Progress<P, Vec<T>, E>
    where F: Fn(&mut ParseMaster<P, E, S>, P) -> Progress<P, T, E>,
          P: Point,
          E: Recoverable,
{
    move |pm, pt| pm.zero_or_more(pt, &parser) // what why ref?
}

pub fn zero_or_more_append<P, E, S, A, F, T>
    (append_to: A, parser: F)
     -> impl FnOnce(&mut ParseMaster<P, E, S>, P) -> Progress<P, Vec<T>, E>
    where F: Fn(&mut ParseMaster<P, E, S>, P) -> Progress<P, T, E>,
          A: IntoAppend<T>,
          P: Point,
          E: Recoverable,
{
    move |pm, mut pt| {
        let mut append_to = append_to.into();
        loop {
            match parser(pm, pt) {
                Progress { point, status: Status::Success(v) } => {
                    append_to.push(v);
                    pt = point;
                },
                Progress { .. } => return Progress::success(pt, append_to),
            }
        }
    }
}

pub fn one_or_more<P, E, S, F, T>
    (parser: F)
     -> impl FnOnce(&mut ParseMaster<P, E, S>, P) -> Progress<P, Vec<T>, E>
    where F: Fn(&mut ParseMaster<P, E, S>, P) -> Progress<P, T, E>,
          P: Point,
          E: Recoverable,
{
    move |pm, pt| {
        let (pt, head) = try_parse!(parser(pm, pt));
        let append_to = vec![head];
        let (pt, tail) = try_parse!(zero_or_more_append(append_to, parser)(pm, pt));

        Progress::success(pt, tail)
    }
}

pub fn one_or_more_append<P, E, S, A, F, T>
    (append_to: A, parser: F)
     -> impl FnOnce(&mut ParseMaster<P, E, S>, P) -> Progress<P, Vec<T>, E>
    where F: Fn(&mut ParseMaster<P, E, S>, P) -> Progress<P, T, E>,
          A: IntoAppend<T>,
          P: Point,
          E: Recoverable,
{
    move |pm, pt| {
        let mut append_to = append_to.into();
        let (pt, head) = try_parse!(parser(pm, pt));
        append_to.push(head);
        let (pt, tail) = try_parse!(zero_or_more_append(append_to, parser)(pm, pt));

        Progress::success(pt, tail)
    }
}

pub fn map<P, E, S, F, C, T, U>
    (parser: F, convert: C)
     -> impl FnOnce(&mut ParseMaster<P, E, S>, P) -> Progress<P, U, E>
    where F: FnOnce(&mut ParseMaster<P, E, S>, P) -> Progress<P, T, E>,
          C: FnOnce(T) -> U,
          P: Point,
          E: Recoverable,
{
    move |pm, pt| {
        parser(pm, pt).map(convert)
    }
}

pub fn point<P, E, S>
    (_: &mut ParseMaster<P, E, S>, pt: P)
     -> Progress<P, P, E>
    where P: Clone,
{
    Progress::success(pt.clone(), pt)
}

pub fn inspect<P, E, S, F>
    (f: F)
     -> impl Fn(&mut ParseMaster<P, E, S>, P) -> Progress<P, (), E>
    where F: Fn(&P),
{
    move |_, pt| {
        f(&pt);
        Progress::success(pt, ())
    }
}

pub fn state<P, E, S, F>
    (f: F)
     -> impl Fn(&mut ParseMaster<P, E, S>, P) -> Progress<P, (), E>
    where F: Fn(&mut S),
{
    move |pm, pt| {
        f(&mut pm.state);
        Progress::success(pt, ())
    }
}
<commit_msg>Format the combinators module<commit_after>use super::{ParseMaster, Point, Progress, Recoverable, Status};

#[macro_export]
macro_rules! sequence {
    ($pm:expr, $pt:expr, {let $x:pat = $parser:expr; $($rest:tt)*}, $creator:expr) => {{
        let (pt, $x) = try_parse!($parser($pm, $pt));
        sequence!($pm, pt, {$($rest)*}, $creator)
    }};
    ($pm:expr, $pt:expr, {$x:pat = $parser:expr; $($rest:tt)*}, $creator:expr) => {{
        let (pt, $x) = try_parse!($parser($pm, $pt));
        sequence!($pm, pt, {$($rest)*}, $creator)
    }};
    ($pm:expr, $pt:expr, {$parser:expr; $($rest:tt)*}, $creator:expr) => {{
        let (pt, _) = try_parse!($parser($pm, $pt));
        sequence!($pm, pt, {$($rest)*}, $creator)
    }};
    ($pm:expr, $pt:expr, {}, $creator:expr) => {
        Progress::success($pt, $creator($pm, $pt))
    };
}

pub trait IntoAppend<T> {
    fn into(self) -> Vec<T>;
}

impl<T> IntoAppend<T> for Vec<T> {
    fn into(self) -> Vec<T> {
        self
    }
}

impl<T> IntoAppend<T> for Option<T> {
    fn into(self) -> Vec<T> {
        self.map(|v| vec![v]).unwrap_or_else(Vec::new)
    }
}

pub fn optional<P, E, S, F, T>(
    parser: F,
) -> impl FnOnce(&mut ParseMaster<P, E, S>, P) -> Progress<P, Option<T>, E>
where
    F: FnOnce(&mut ParseMaster<P, E, S>, P) -> Progress<P, T, E>,
    P: Point,
    E: Recoverable,
{
    move |pm, pt| pm.optional(pt, parser)
}

pub fn optional_append<P, E, S, A, F, T>(
    append_to: A,
    parser: F,
) -> impl FnOnce(&mut ParseMaster<P, E, S>, P) -> Progress<P, Vec<T>, E>
where
    F: FnOnce(&mut ParseMaster<P, E, S>, P) -> Progress<P, T, E>,
    A: IntoAppend<T>,
    P: Point,
    //E: Recoverable, // TODO: use this
{
    move |pm, pt| {
        let mut append_to = append_to.into();
        match parser(pm, pt) {
            Progress {
                point,
                status: Status::Success(v),
            } => {
                append_to.push(v);
                Progress::success(point, append_to)
            }
            Progress {
                point,
                status: Status::Failure(..),
            } => Progress::success(point, append_to),
        }
    }
}

pub fn zero_or_more<P, E, S, F, T>(
    parser: F,
) -> impl Fn(&mut ParseMaster<P, E, S>, P) -> Progress<P, Vec<T>, E>
where
    F: Fn(&mut ParseMaster<P, E, S>, P) -> Progress<P, T, E>,
    P: Point,
    E: Recoverable,
{
    move |pm, pt| pm.zero_or_more(pt, &parser) // what why ref?
}

pub fn zero_or_more_append<P, E, S, A, F, T>(
    append_to: A,
    parser: F,
) -> impl FnOnce(&mut ParseMaster<P, E, S>, P) -> Progress<P, Vec<T>, E>
where
    F: Fn(&mut ParseMaster<P, E, S>, P) -> Progress<P, T, E>,
    A: IntoAppend<T>,
    P: Point,
    E: Recoverable,
{
    move |pm, mut pt| {
        let mut append_to = append_to.into();
        loop {
            match parser(pm, pt) {
                Progress {
                    point,
                    status: Status::Success(v),
                } => {
                    append_to.push(v);
                    pt = point;
                }
                Progress { .. } => return Progress::success(pt, append_to),
            }
        }
    }
}

pub fn one_or_more<P, E, S, F, T>(
    parser: F,
) -> impl FnOnce(&mut ParseMaster<P, E, S>, P) -> Progress<P, Vec<T>, E>
where
    F: Fn(&mut ParseMaster<P, E, S>, P) -> Progress<P, T, E>,
    P: Point,
    E: Recoverable,
{
    move |pm, pt| {
        let (pt, head) = try_parse!(parser(pm, pt));
        let append_to = vec![head];
        let (pt, tail) = try_parse!(zero_or_more_append(append_to, parser)(pm, pt));

        Progress::success(pt, tail)
    }
}

pub fn one_or_more_append<P, E, S, A, F, T>(
    append_to: A,
    parser: F,
) -> impl FnOnce(&mut ParseMaster<P, E, S>, P) -> Progress<P, Vec<T>, E>
where
    F: Fn(&mut ParseMaster<P, E, S>, P) -> Progress<P, T, E>,
    A: IntoAppend<T>,
    P: Point,
    E: Recoverable,
{
    move |pm, pt| {
        let mut append_to = append_to.into();
        let (pt, head) = try_parse!(parser(pm, pt));
        append_to.push(head);
        let (pt, tail) = try_parse!(zero_or_more_append(append_to, parser)(pm, pt));

        Progress::success(pt, tail)
    }
}

pub fn map<P, E, S, F, C, T, U>(
    parser: F,
    convert: C,
) -> impl FnOnce(&mut ParseMaster<P, E, S>, P) -> Progress<P, U, E>
where
    F: FnOnce(&mut ParseMaster<P, E, S>, P) -> Progress<P, T, E>,
    C: FnOnce(T) -> U,
    P: Point,
    E: Recoverable,
{
    move |pm, pt| parser(pm, pt).map(convert)
}

pub fn point<P, E, S>(_: &mut ParseMaster<P, E, S>, pt: P) -> Progress<P, P, E>
where
    P: Clone,
{
    Progress::success(pt.clone(), pt)
}

pub fn inspect<P, E, S, F>(f: F) -> impl Fn(&mut ParseMaster<P, E, S>, P) -> Progress<P, (), E>
where
    F: Fn(&P),
{
    move |_, pt| {
        f(&pt);
        Progress::success(pt, ())
    }
}

pub fn state<P, E, S, F>(f: F) -> impl Fn(&mut ParseMaster<P, E, S>, P) -> Progress<P, (), E>
where
    F: Fn(&mut S),
{
    move |pm, pt| {
        f(&mut pm.state);
        Progress::success(pt, ())
    }
}
<|endoftext|>


<commit_before>extern crate x11;

use std::collections::HashMap;
use std::io::prelude::*;
use std::io::BufReader;
use std::io::Lines;
use std::fs::File;
use std::path::PathBuf;
use std::process::Command;
use std::ffi;
use std::env;
use x11::xlib;
use std::boxed::Box;

use super::layout;
use super::handler::{
    KeyBind,
    Handler,
    ExecHandler,
    LayoutHandler,
    WorkspaceHandler,
    WindowToWorkspaceHandler,
    WindowFocusHandler,
    WindowCloseHandler,
    FullscreenHandler,
    SplitHandler};

pub struct Config {
    mod_key: u32,
    pub bindsyms: HashMap<KeyBind, Box<Handler>>,
    pub titlebar_height: u32,
}

impl Config {
    pub fn load() -> Config {
        let mut config = Config::default();

        let home = match env::var_os("HOME") {
            Some(v) => v,
            None => {
                // can't find HOME, return default config
                return config;
            }
        };

        let mut pathbuf = PathBuf::from(home);
        pathbuf.push(".rustile");
        match File::open(pathbuf.as_path()) {
            Ok(f) => {
                let buf = BufReader::new(f);
                for line in buf.lines() {
                    match line {
                        Ok(s) => {
                            config.parse_line(s);
                        }
                        Err(err) => {
                            // do nothing
                        }
                    }
                }
            }
            Err(err) => {
                // use default config
                println!("no config file");
            }
        }
        config
    }

    pub fn default() -> Config {
        let mut config = Config {
            mod_key: xlib::Mod4Mask,
            bindsyms: HashMap::new(),
            titlebar_height: 20,
        };
        // let dmenu = vec!["$mod+c", "exec", "dmenu_run"];
        // let split = vec!["$mod+b", "layout", "split"];
        // config.bind_sym(&dmenu);
        // config.bind_sym(&split);
        config
    }

    fn parse_line(&mut self, line: String) {
        // # is comment
        if !line.starts_with("#") {
            let tokens: Vec<&str> = line.split(' ').collect();
            let (cmd, args) = tokens.split_at(1);
            match cmd[0] {
                "set" => {
                    if args.len() > 1 {
                        self.set_var(args[0], args[1]);
                    }
                }
                "exec" => {
                    let mut handler = ExecHandler::new(args);
                    handler.cmd.spawn();
                }
                "bind" => {
                    self.bind_sym(args);
                }
                _ => {
                    // not supported cmd, ignore
                }
            }
        }
    }

    fn bind_sym(&mut self, args: &[&str]) {
        let (keyseq, cmd) = args.split_at(1);
        let keys: Vec<&str> = keyseq[0].split("+").collect();

        let bind = KeyBind::build(self.mod_key, &keys);

        let (name, args) = cmd.split_at(1);
        match name[0] {
            "exec" => {
                println!("exec");
                let handler = ExecHandler::new(args);
                self.bindsyms.insert(bind, Box::new(handler));
            }
            "layout" => {
                println!("layout");
                let layout = args[0];
                match layout {
                    "split" => {
                        let handler = LayoutHandler::new(layout::Type::Tiling);
                        self.bindsyms.insert(bind, Box::new(handler));
                    }
                    "tab" => {
                        let handler = LayoutHandler::new(layout::Type::Tab);
                        self.bindsyms.insert(bind, Box::new(handler));
                    }
                    _ => {}
                }
            }
            "fullscreen" => {
                let handler = FullscreenHandler;
                self.bindsyms.insert(bind, Box::new(handler));
            }
            "split" => {
                let handler = SplitHandler;
                self.bindsyms.insert(bind, Box::new(handler));
            }
            "workspace" => {
                println!("workspace");
                let c = args[0].chars().nth(0);
                match c {
                    Some(v) => {
                        let handler = WorkspaceHandler {
                            key: v,
                        };
                        self.bindsyms.insert(bind, Box::new(handler));
                    }
                    None => {}
                }
            }
            "window" => {
                let c = args[0].chars().nth(0);
                match c {
                    Some(v) => {
                        println!("window");
                        let handler = WindowToWorkspaceHandler {
                            key: v,
                        };
                        self.bindsyms.insert(bind, Box::new(handler));
                    }
                    None => {}
                }
            }
            "focus" => {
                let direction = match args[0] {
                    "left" => layout::Direction::Left,
                    "right" => layout::Direction::Right,
                    "up" => layout::Direction::Up,
                    "down" => layout::Direction::Down,
                    _ => layout::Direction::Right
                };
                let handler = WindowFocusHandler {
                    direction: direction
                };
                self.bindsyms.insert(bind, Box::new(handler));
            }
            "kill" => {
                let handler = WindowCloseHandler;
                self.bindsyms.insert(bind, Box::new(handler));
            }
            _ => {}
        };
    }

    fn set_var(&mut self, key: &str, val: &str) {
        match key {
            "$mod" => {
                self.mod_key = match val {
                    "Shift" => xlib::ShiftMask,
                    "Ctrl"  => xlib::ControlMask,
                    "Mod1"  => xlib::Mod1Mask,
                    "Mod2" => xlib::Mod2Mask,
                    "Mod3" => xlib::Mod3Mask,
                    "Mod4" => xlib::Mod4Mask,
                    "Mod5" => xlib::Mod5Mask,
                    _ => xlib::Mod4Mask
                };
            }
            _ => {}
        }
    }
}

#[test]
fn test_map() {
    let mut bindsyms: HashMap<KeyBind, i32> = HashMap::new();
    let b = KeyBind {
        key: 0,
        mask: 0
    };
    bindsyms.insert(b, 1);

    let c = KeyBind {
        key: 0,
        mask: 0
    };
    assert!(bindsyms.contains_key(&c), true);
}
<commit_msg>config<commit_after>extern crate x11;

use std::collections::HashMap;
use std::io::prelude::*;
use std::io::BufReader;
use std::io::Lines;
use std::fs::File;
use std::path::PathBuf;
use std::process::Command;
use std::ffi;
use std::env;
use x11::xlib;
use std::boxed::Box;

use super::layout;
use super::handler::{
    KeyBind,
    Handler,
    ExecHandler,
    LayoutHandler,
    WorkspaceHandler,
    WindowToWorkspaceHandler,
    WindowFocusHandler,
    WindowCloseHandler,
    FullscreenHandler,
    SplitHandler};

pub struct Config {
    mod_key: u32,
    pub bindsyms: HashMap<KeyBind, Box<Handler>>,
    pub titlebar_height: u32,
}

impl Config {
    pub fn load() -> Config {
        let mut config = Config::default();

        let mut pathbuf = match env::var_os("HOME") {
            Some(v) => {
                PathBuf::from(v)
            }
            None => {
                // can't find HOME, return default config
                return config;
            }
        };

        pathbuf.push(".rustile");
        match File::open(pathbuf.as_path()) {
            Ok(f) => {
                let buf = BufReader::new(f);
                for line in buf.lines() {
                    match line {
                        Ok(s) => {
                            config.parse_line(s);
                        }
                        Err(err) => {
                            // do nothing
                        }
                    }
                }
            }
            Err(err) => {
                // use default config
                println!("no config file");
            }
        }
        config
    }

    pub fn default() -> Config {
        let mut config = Config {
            mod_key: xlib::Mod4Mask,
            bindsyms: HashMap::new(),
            titlebar_height: 20,
        };
        // let dmenu = vec!["$mod+c", "exec", "dmenu_run"];
        // let split = vec!["$mod+b", "layout", "split"];
        // config.bind_sym(&dmenu);
        // config.bind_sym(&split);
        config
    }

    fn parse_line(&mut self, line: String) {
        // # is comment
        if !line.starts_with("#") {
            let tokens: Vec<&str> = line.split(' ').collect();
            let (cmd, args) = tokens.split_at(1);
            match cmd[0] {
                "set" => {
                    if args.len() > 1 {
                        self.set_var(args[0], args[1]);
                    }
                }
                "exec" => {
                    let mut handler = ExecHandler::new(args);
                    handler.cmd.spawn();
                }
                "bind" => {
                    self.bind_sym(args);
                }
                _ => {
                    // not supported cmd, ignore
                }
            }
        }
    }

    fn bind_sym(&mut self, args: &[&str]) {
        let (keyseq, cmd) = args.split_at(1);
        let keys: Vec<&str> = keyseq[0].split("+").collect();

        let bind = KeyBind::build(self.mod_key, &keys);

        let (name, args) = cmd.split_at(1);
        match name[0] {
            "exec" => {
                println!("exec");
                let handler = ExecHandler::new(args);
                self.bindsyms.insert(bind, Box::new(handler));
            }
            "layout" => {
                println!("layout");
                let layout = args[0];
                match layout {
                    "split" => {
                        let handler = LayoutHandler::new(layout::Type::Tiling);
                        self.bindsyms.insert(bind, Box::new(handler));
                    }
                    "tab" => {
                        let handler = LayoutHandler::new(layout::Type::Tab);
                        self.bindsyms.insert(bind, Box::new(handler));
                    }
                    _ => {}
                }
            }
            "fullscreen" => {
                let handler = FullscreenHandler;
                self.bindsyms.insert(bind, Box::new(handler));
            }
            "split" => {
                let handler = SplitHandler;
                self.bindsyms.insert(bind, Box::new(handler));
            }
            "workspace" => {
                println!("workspace");
                let c = args[0].chars().nth(0);
                match c {
                    Some(v) => {
                        let handler = WorkspaceHandler {
                            key: v,
                        };
                        self.bindsyms.insert(bind, Box::new(handler));
                    }
                    None => {}
                }
            }
            "window" => {
                let c = args[0].chars().nth(0);
                match c {
                    Some(v) => {
                        println!("window");
                        let handler = WindowToWorkspaceHandler {
                            key: v,
                        };
                        self.bindsyms.insert(bind, Box::new(handler));
                    }
                    None => {}
                }
            }
            "focus" => {
                let direction = match args[0] {
                    "left" => layout::Direction::Left,
                    "right" => layout::Direction::Right,
                    "up" => layout::Direction::Up,
                    "down" => layout::Direction::Down,
                    _ => layout::Direction::Right
                };
                let handler = WindowFocusHandler {
                    direction: direction
                };
                self.bindsyms.insert(bind, Box::new(handler));
            }
            "kill" => {
                let handler = WindowCloseHandler;
                self.bindsyms.insert(bind, Box::new(handler));
            }
            _ => {}
        };
    }

    fn set_var(&mut self, key: &str, val: &str) {
        match key {
            "$mod" => {
                self.mod_key = match val {
                    "Shift" => xlib::ShiftMask,
                    "Ctrl"  => xlib::ControlMask,
                    "Mod1"  => xlib::Mod1Mask,
                    "Mod2" => xlib::Mod2Mask,
                    "Mod3" => xlib::Mod3Mask,
                    "Mod4" => xlib::Mod4Mask,
                    "Mod5" => xlib::Mod5Mask,
                    _ => xlib::Mod4Mask
                };
            }
            _ => {}
        }
    }
}

#[test]
fn test_map() {
    let mut bindsyms: HashMap<KeyBind, i32> = HashMap::new();
    let b = KeyBind {
        key: 0,
        mask: 0
    };
    bindsyms.insert(b, 1);

    let c = KeyBind {
        key: 0,
        mask: 0
    };
    assert!(bindsyms.contains_key(&c), true);
}
<|endoftext|>


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

use std::fmt;
use std::slice::Iter;

pub const DBUS_TIMEOUT: i32 = 20000; // millieconds

pub const STRATIS_VERSION: &'static str = "1";
pub const MANAGER_NAME: &'static str = "/Manager";
pub const STRATIS_BASE_PATH: &'static str = "/org/storage/stratis1";
pub const STRATIS_BASE_SERVICE: &'static str = "org.storage.stratis1";
pub const STRATIS_BASE_MANAGER: &'static str = "/org/storage/stratis1/Manager";
pub const STRATIS_MANAGER_INTERFACE: &'static str = "org.storage.stratis1.Manager";
pub const STRATIS_POOL_BASE_INTERFACE: &'static str = "org.storage.stratis1.pool";
pub const STRATIS_VOLUME_BASE_INTERFACE: &'static str = "org.storage.stratis1.volume";
pub const STRATIS_DEV_BASE_INTERFACE: &'static str = "org.storage.stratis1.dev";
pub const STRATIS_CACHE_BASE_INTERFACE: &'static str = "org.storage.stratis1.cache";
pub const STRATIS_POOL_BASE_PATH: &'static str = "/org/storage/stratis/pool";

pub const LIST_POOLS: &'static str = "ListPools";
pub const CREATE_POOL: &'static str = "CreatePool";
pub const DESTROY_POOL: &'static str = "DestroyPool";
pub const GET_POOL_OBJECT_PATH: &'static str = "GetPoolObjectPath";
pub const GET_VOLUME_OBJECT_PATH: &'static str = "GetVolumeObjectPath";
pub const GET_DEV_OBJECT_PATH: &'static str = "GetDevObjectPath";
pub const GET_CACHE_OBJECT_PATH: &'static str = "GetCacheObjectPath";
pub const GET_ERROR_CODES: &'static str = "GetErrorCodes";
pub const GET_RAID_LEVELS: &'static str = "GetRaidLevels";
pub const GET_DEV_TYPES: &'static str = "GetDevTypes";

#[derive(Copy, Clone)]
#[allow(non_camel_case_types)]
pub enum StratisErrorEnum {
    STRATIS_OK,
    STRATIS_ERROR,
    STRATIS_NULL,
    STRATIS_NOTFOUND,
    STRATIS_POOL_NOTFOUND,
    STRATIS_VOLUME_NOTFOUND,
    STRATIS_DEV_NOTFOUND,
    STRATIS_CACHE_NOTFOUND,
    STRATIS_BAD_PARAM,
    STRATIS_ALREADY_EXISTS,
    STRATIS_NULL_NAME,
    STRATIS_NO_POOLS,
    STRATIS_LIST_FAILURE,
}

impl StratisErrorEnum {
    pub fn iterator() -> Iter<'static, StratisErrorEnum> {
        static CODES: [StratisErrorEnum; 13] = [StratisErrorEnum::STRATIS_OK,
                                                StratisErrorEnum::STRATIS_ERROR,
                                                StratisErrorEnum::STRATIS_NULL,
                                                StratisErrorEnum::STRATIS_NOTFOUND,
                                                StratisErrorEnum::STRATIS_POOL_NOTFOUND,
                                                StratisErrorEnum::STRATIS_VOLUME_NOTFOUND,
                                                StratisErrorEnum::STRATIS_DEV_NOTFOUND,
                                                StratisErrorEnum::STRATIS_CACHE_NOTFOUND,
                                                StratisErrorEnum::STRATIS_BAD_PARAM,
                                                StratisErrorEnum::STRATIS_ALREADY_EXISTS,
                                                StratisErrorEnum::STRATIS_NULL_NAME,
                                                StratisErrorEnum::STRATIS_NO_POOLS,
                                                StratisErrorEnum::STRATIS_LIST_FAILURE];
        CODES.into_iter()
    }

    pub fn get_error_int(error: &StratisErrorEnum) -> u16 {
        *error as u16
    }

    pub fn get_error_string(error: &StratisErrorEnum) -> &str {
        match *error {
            // TODO deal with internationalization/do this better
            StratisErrorEnum::STRATIS_OK => "Ok",
            StratisErrorEnum::STRATIS_ERROR => "A general error happened",
            StratisErrorEnum::STRATIS_NULL => "Null parameter was supplied",
            StratisErrorEnum::STRATIS_NOTFOUND => "Not found",
            StratisErrorEnum::STRATIS_POOL_NOTFOUND => "Pool not found",
            StratisErrorEnum::STRATIS_VOLUME_NOTFOUND => "Volume not found",
            StratisErrorEnum::STRATIS_CACHE_NOTFOUND => "Cache not found",
            StratisErrorEnum::STRATIS_BAD_PARAM => "Bad parameter",
            StratisErrorEnum::STRATIS_DEV_NOTFOUND => "Dev not found",
            StratisErrorEnum::STRATIS_ALREADY_EXISTS => "Already exists",
            StratisErrorEnum::STRATIS_NULL_NAME => "Null name supplied",
            StratisErrorEnum::STRATIS_NO_POOLS => "No pools",
            StratisErrorEnum::STRATIS_LIST_FAILURE => "List operation failure.",
        }
    }
}
impl fmt::Display for StratisErrorEnum {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            StratisErrorEnum::STRATIS_OK => write!(f, "STRATIS_OK"),
            StratisErrorEnum::STRATIS_ERROR => write!(f, "STRATIS_ERROR"),
            StratisErrorEnum::STRATIS_NULL => write!(f, "STRATIS_NULL"),
            StratisErrorEnum::STRATIS_NOTFOUND => write!(f, "STRATIS_NOTFOUND"),
            StratisErrorEnum::STRATIS_POOL_NOTFOUND => write!(f, "STRATIS_POOL_NOTFOUND"),
            StratisErrorEnum::STRATIS_VOLUME_NOTFOUND => write!(f, "STRATIS_VOLUME_NOTFOUND"),
            StratisErrorEnum::STRATIS_CACHE_NOTFOUND => write!(f, "STRATIS_CACHE_NOTFOUND"),
            StratisErrorEnum::STRATIS_BAD_PARAM => write!(f, "STRATIS_BAD_PARAM"),
            StratisErrorEnum::STRATIS_DEV_NOTFOUND => write!(f, "STRATIS_DEV_NOTFOUND"),
            StratisErrorEnum::STRATIS_ALREADY_EXISTS => write!(f, "STRATIS_ALREADY_EXISTS"),
            StratisErrorEnum::STRATIS_NULL_NAME => write!(f, "STRATIS_NULL_NAME"),
            StratisErrorEnum::STRATIS_NO_POOLS => write!(f, "STRATIS_NO_POOLS"),
            StratisErrorEnum::STRATIS_LIST_FAILURE => write!(f, "STRATIS_LIST_FAILURE"),
        }
    }
}
#[derive(Copy, Clone)]
#[allow(non_camel_case_types)]
pub enum StratisRaidType {
    STRATIS_RAID_TYPE_UNKNOWN,
    /** Single */
    STRATIS_RAID_TYPE_SINGLE,
    /** Mirror between two disks. For 4 disks or more, they are RAID10.*/
    STRATIS_RAID_TYPE_RAID1,
    /** Block-level striping with distributed parity */
    STRATIS_RAID_TYPE_RAID5,
    /** Block-level striping with two distributed parities, aka, RAID-DP */
    STRATIS_RAID_TYPE_RAID6,
}

impl StratisRaidType {
    pub fn iterator() -> Iter<'static, StratisRaidType> {
        static TYPES: [StratisRaidType; 5] = [StratisRaidType::STRATIS_RAID_TYPE_UNKNOWN,
                                              StratisRaidType::STRATIS_RAID_TYPE_SINGLE,
                                              StratisRaidType::STRATIS_RAID_TYPE_RAID1,
                                              StratisRaidType::STRATIS_RAID_TYPE_RAID5,
                                              StratisRaidType::STRATIS_RAID_TYPE_RAID6];
        TYPES.into_iter()
    }

    pub fn get_error_int(error: &StratisRaidType) -> u16 {
        *error as u16
    }

    pub fn get_error_string(error: &StratisRaidType) -> &str {
        match *error {
            // TODO deal with internationalization/do this better
            StratisRaidType::STRATIS_RAID_TYPE_UNKNOWN => "Ok",
            StratisRaidType::STRATIS_RAID_TYPE_SINGLE => "Single",
            StratisRaidType::STRATIS_RAID_TYPE_RAID1 => {
                "Mirror between two disks. For 4 disks or more, they are RAID10"
            }
            StratisRaidType::STRATIS_RAID_TYPE_RAID5 => {
                "Block-level striping with distributed parity"
            }
            StratisRaidType::STRATIS_RAID_TYPE_RAID6 => {
                "Block-level striping with two distributed parities, aka, RAID-DP"
            }
        }
    }
}
impl fmt::Display for StratisRaidType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            StratisRaidType::STRATIS_RAID_TYPE_UNKNOWN => write!(f, "STRATIS_RAID_TYPE_UNKNOWN"),
            StratisRaidType::STRATIS_RAID_TYPE_SINGLE => write!(f, "STRATIS_RAID_TYPE_SINGLE"),
            StratisRaidType::STRATIS_RAID_TYPE_RAID1 => write!(f, "STRATIS_RAID_TYPE_RAID1"),
            StratisRaidType::STRATIS_RAID_TYPE_RAID5 => write!(f, "STRATIS_RAID_TYPE_RAID5"),
            StratisRaidType::STRATIS_RAID_TYPE_RAID6 => write!(f, "STRATIS_RAID_TYPE_RAID6"),
        }
    }
}
<commit_msg>Add some whitespace between definitions.<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::fmt;
use std::slice::Iter;

pub const DBUS_TIMEOUT: i32 = 20000; // millieconds

pub const STRATIS_VERSION: &'static str = "1";
pub const MANAGER_NAME: &'static str = "/Manager";
pub const STRATIS_BASE_PATH: &'static str = "/org/storage/stratis1";
pub const STRATIS_BASE_SERVICE: &'static str = "org.storage.stratis1";
pub const STRATIS_BASE_MANAGER: &'static str = "/org/storage/stratis1/Manager";
pub const STRATIS_MANAGER_INTERFACE: &'static str = "org.storage.stratis1.Manager";
pub const STRATIS_POOL_BASE_INTERFACE: &'static str = "org.storage.stratis1.pool";
pub const STRATIS_VOLUME_BASE_INTERFACE: &'static str = "org.storage.stratis1.volume";
pub const STRATIS_DEV_BASE_INTERFACE: &'static str = "org.storage.stratis1.dev";
pub const STRATIS_CACHE_BASE_INTERFACE: &'static str = "org.storage.stratis1.cache";
pub const STRATIS_POOL_BASE_PATH: &'static str = "/org/storage/stratis/pool";

pub const LIST_POOLS: &'static str = "ListPools";
pub const CREATE_POOL: &'static str = "CreatePool";
pub const DESTROY_POOL: &'static str = "DestroyPool";
pub const GET_POOL_OBJECT_PATH: &'static str = "GetPoolObjectPath";
pub const GET_VOLUME_OBJECT_PATH: &'static str = "GetVolumeObjectPath";
pub const GET_DEV_OBJECT_PATH: &'static str = "GetDevObjectPath";
pub const GET_CACHE_OBJECT_PATH: &'static str = "GetCacheObjectPath";
pub const GET_ERROR_CODES: &'static str = "GetErrorCodes";
pub const GET_RAID_LEVELS: &'static str = "GetRaidLevels";
pub const GET_DEV_TYPES: &'static str = "GetDevTypes";

#[derive(Copy, Clone)]
#[allow(non_camel_case_types)]
pub enum StratisErrorEnum {
    STRATIS_OK,
    STRATIS_ERROR,
    STRATIS_NULL,
    STRATIS_NOTFOUND,
    STRATIS_POOL_NOTFOUND,
    STRATIS_VOLUME_NOTFOUND,
    STRATIS_DEV_NOTFOUND,
    STRATIS_CACHE_NOTFOUND,
    STRATIS_BAD_PARAM,
    STRATIS_ALREADY_EXISTS,
    STRATIS_NULL_NAME,
    STRATIS_NO_POOLS,
    STRATIS_LIST_FAILURE,
}

impl StratisErrorEnum {
    pub fn iterator() -> Iter<'static, StratisErrorEnum> {
        static CODES: [StratisErrorEnum; 13] = [StratisErrorEnum::STRATIS_OK,
                                                StratisErrorEnum::STRATIS_ERROR,
                                                StratisErrorEnum::STRATIS_NULL,
                                                StratisErrorEnum::STRATIS_NOTFOUND,
                                                StratisErrorEnum::STRATIS_POOL_NOTFOUND,
                                                StratisErrorEnum::STRATIS_VOLUME_NOTFOUND,
                                                StratisErrorEnum::STRATIS_DEV_NOTFOUND,
                                                StratisErrorEnum::STRATIS_CACHE_NOTFOUND,
                                                StratisErrorEnum::STRATIS_BAD_PARAM,
                                                StratisErrorEnum::STRATIS_ALREADY_EXISTS,
                                                StratisErrorEnum::STRATIS_NULL_NAME,
                                                StratisErrorEnum::STRATIS_NO_POOLS,
                                                StratisErrorEnum::STRATIS_LIST_FAILURE];
        CODES.into_iter()
    }

    pub fn get_error_int(error: &StratisErrorEnum) -> u16 {
        *error as u16
    }

    pub fn get_error_string(error: &StratisErrorEnum) -> &str {
        match *error {
            // TODO deal with internationalization/do this better
            StratisErrorEnum::STRATIS_OK => "Ok",
            StratisErrorEnum::STRATIS_ERROR => "A general error happened",
            StratisErrorEnum::STRATIS_NULL => "Null parameter was supplied",
            StratisErrorEnum::STRATIS_NOTFOUND => "Not found",
            StratisErrorEnum::STRATIS_POOL_NOTFOUND => "Pool not found",
            StratisErrorEnum::STRATIS_VOLUME_NOTFOUND => "Volume not found",
            StratisErrorEnum::STRATIS_CACHE_NOTFOUND => "Cache not found",
            StratisErrorEnum::STRATIS_BAD_PARAM => "Bad parameter",
            StratisErrorEnum::STRATIS_DEV_NOTFOUND => "Dev not found",
            StratisErrorEnum::STRATIS_ALREADY_EXISTS => "Already exists",
            StratisErrorEnum::STRATIS_NULL_NAME => "Null name supplied",
            StratisErrorEnum::STRATIS_NO_POOLS => "No pools",
            StratisErrorEnum::STRATIS_LIST_FAILURE => "List operation failure.",
        }
    }
}

impl fmt::Display for StratisErrorEnum {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            StratisErrorEnum::STRATIS_OK => write!(f, "STRATIS_OK"),
            StratisErrorEnum::STRATIS_ERROR => write!(f, "STRATIS_ERROR"),
            StratisErrorEnum::STRATIS_NULL => write!(f, "STRATIS_NULL"),
            StratisErrorEnum::STRATIS_NOTFOUND => write!(f, "STRATIS_NOTFOUND"),
            StratisErrorEnum::STRATIS_POOL_NOTFOUND => write!(f, "STRATIS_POOL_NOTFOUND"),
            StratisErrorEnum::STRATIS_VOLUME_NOTFOUND => write!(f, "STRATIS_VOLUME_NOTFOUND"),
            StratisErrorEnum::STRATIS_CACHE_NOTFOUND => write!(f, "STRATIS_CACHE_NOTFOUND"),
            StratisErrorEnum::STRATIS_BAD_PARAM => write!(f, "STRATIS_BAD_PARAM"),
            StratisErrorEnum::STRATIS_DEV_NOTFOUND => write!(f, "STRATIS_DEV_NOTFOUND"),
            StratisErrorEnum::STRATIS_ALREADY_EXISTS => write!(f, "STRATIS_ALREADY_EXISTS"),
            StratisErrorEnum::STRATIS_NULL_NAME => write!(f, "STRATIS_NULL_NAME"),
            StratisErrorEnum::STRATIS_NO_POOLS => write!(f, "STRATIS_NO_POOLS"),
            StratisErrorEnum::STRATIS_LIST_FAILURE => write!(f, "STRATIS_LIST_FAILURE"),
        }
    }
}

#[derive(Copy, Clone)]
#[allow(non_camel_case_types)]
pub enum StratisRaidType {
    STRATIS_RAID_TYPE_UNKNOWN,
    /** Single */
    STRATIS_RAID_TYPE_SINGLE,
    /** Mirror between two disks. For 4 disks or more, they are RAID10.*/
    STRATIS_RAID_TYPE_RAID1,
    /** Block-level striping with distributed parity */
    STRATIS_RAID_TYPE_RAID5,
    /** Block-level striping with two distributed parities, aka, RAID-DP */
    STRATIS_RAID_TYPE_RAID6,
}

impl StratisRaidType {
    pub fn iterator() -> Iter<'static, StratisRaidType> {
        static TYPES: [StratisRaidType; 5] = [StratisRaidType::STRATIS_RAID_TYPE_UNKNOWN,
                                              StratisRaidType::STRATIS_RAID_TYPE_SINGLE,
                                              StratisRaidType::STRATIS_RAID_TYPE_RAID1,
                                              StratisRaidType::STRATIS_RAID_TYPE_RAID5,
                                              StratisRaidType::STRATIS_RAID_TYPE_RAID6];
        TYPES.into_iter()
    }

    pub fn get_error_int(error: &StratisRaidType) -> u16 {
        *error as u16
    }

    pub fn get_error_string(error: &StratisRaidType) -> &str {
        match *error {
            // TODO deal with internationalization/do this better
            StratisRaidType::STRATIS_RAID_TYPE_UNKNOWN => "Ok",
            StratisRaidType::STRATIS_RAID_TYPE_SINGLE => "Single",
            StratisRaidType::STRATIS_RAID_TYPE_RAID1 => {
                "Mirror between two disks. For 4 disks or more, they are RAID10"
            }
            StratisRaidType::STRATIS_RAID_TYPE_RAID5 => {
                "Block-level striping with distributed parity"
            }
            StratisRaidType::STRATIS_RAID_TYPE_RAID6 => {
                "Block-level striping with two distributed parities, aka, RAID-DP"
            }
        }
    }
}

impl fmt::Display for StratisRaidType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            StratisRaidType::STRATIS_RAID_TYPE_UNKNOWN => write!(f, "STRATIS_RAID_TYPE_UNKNOWN"),
            StratisRaidType::STRATIS_RAID_TYPE_SINGLE => write!(f, "STRATIS_RAID_TYPE_SINGLE"),
            StratisRaidType::STRATIS_RAID_TYPE_RAID1 => write!(f, "STRATIS_RAID_TYPE_RAID1"),
            StratisRaidType::STRATIS_RAID_TYPE_RAID5 => write!(f, "STRATIS_RAID_TYPE_RAID5"),
            StratisRaidType::STRATIS_RAID_TYPE_RAID6 => write!(f, "STRATIS_RAID_TYPE_RAID6"),
        }
    }
}
<|endoftext|>