<commit_before>#![feature(rustc_private)]

extern crate env_logger;
extern crate getopts;
#[macro_use]
extern crate log;
extern crate log_settings;
extern crate miri;
extern crate rustc;
extern crate rustc_codegen_utils;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_hir;
extern crate rustc_interface;
extern crate rustc_metadata;
extern crate rustc_span;

use std::convert::TryFrom;
use std::env;
use std::str::FromStr;

use hex::FromHexError;

use rustc_driver::Compilation;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_interface::{interface, Queries};

struct MiriCompilerCalls {
    miri_config: miri::MiriConfig,
}

impl rustc_driver::Callbacks for MiriCompilerCalls {
    fn after_analysis<'tcx>(
        &mut self,
        compiler: &interface::Compiler,
        queries: &'tcx Queries<'tcx>,
    ) -> Compilation {
        init_late_loggers();
        compiler.session().abort_if_errors();

        queries.global_ctxt().unwrap().peek_mut().enter(|tcx| {
            let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect("no main function found!");
            let mut config = self.miri_config.clone();

            // Add filename to `miri` arguments.
            config.args.insert(0, compiler.input().filestem().to_string());

            if let Some(return_code) = miri::eval_main(tcx, entry_def_id, config) {
                std::process::exit(
                    i32::try_from(return_code).expect("Return value was too large!"),
                );
            }
        });

        compiler.session().abort_if_errors();

        Compilation::Stop
    }
}

fn init_early_loggers() {
    // Note that our `extern crate log` is *not* the same as rustc's; as a result, we have to
    // initialize them both, and we always initialize `miri`'s first.
    let env = env_logger::Env::new().filter("MIRI_LOG").write_style("MIRI_LOG_STYLE");
    env_logger::init_from_env(env);
    // We only initialize `rustc` if the env var is set (so the user asked for it).
    // If it is not set, we avoid initializing now so that we can initialize
    // later with our custom settings, and *not* log anything for what happens before
    // `miri` gets started.
    if env::var("RUSTC_LOG").is_ok() {
        rustc_driver::init_rustc_env_logger();
    }
}

fn init_late_loggers() {
    // We initialize loggers right before we start evaluation. We overwrite the `RUSTC_LOG`
    // env var if it is not set, control it based on `MIRI_LOG`.
    if let Ok(var) = env::var("MIRI_LOG") {
        if env::var("RUSTC_LOG").is_err() {
            // We try to be a bit clever here: if `MIRI_LOG` is just a single level
            // used for everything, we only apply it to the parts of rustc that are
            // CTFE-related. Otherwise, we use it verbatim for `RUSTC_LOG`.
            // This way, if you set `MIRI_LOG=trace`, you get only the right parts of
            // rustc traced, but you can also do `MIRI_LOG=miri=trace,rustc_mir::interpret=debug`.
            if log::Level::from_str(&var).is_ok() {
                env::set_var(
                    "RUSTC_LOG",
                    &format!("rustc::mir::interpret={0},rustc_mir::interpret={0}", var),
                );
            } else {
                env::set_var("RUSTC_LOG", &var);
            }
            rustc_driver::init_rustc_env_logger();
        }
    }

    // If `MIRI_BACKTRACE` is set and `RUSTC_CTFE_BACKTRACE` is not, set `RUSTC_CTFE_BACKTRACE`.
    // Do this late, so we ideally only apply this to Miri's errors.
    if let Ok(var) = env::var("MIRI_BACKTRACE") {
        if env::var("RUSTC_CTFE_BACKTRACE") == Err(env::VarError::NotPresent) {
            env::set_var("RUSTC_CTFE_BACKTRACE", &var);
        }
    }
}

/// Returns the "default sysroot" that Miri will use if no `--sysroot` flag is set.
/// Should be a compile-time constant.
fn compile_time_sysroot() -> Option<String> {
    if option_env!("RUSTC_STAGE").is_some() {
        // This is being built as part of rustc, and gets shipped with rustup.
        // We can rely on the sysroot computation in librustc.
        return None;
    }
    // For builds outside rustc, we need to ensure that we got a sysroot
    // that gets used as a default.  The sysroot computation in librustc would
    // end up somewhere in the build dir.
    // Taken from PR <https://github.com/Manishearth/rust-clippy/pull/911>.
    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
    Some(match (home, toolchain) {
        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
        _ => option_env!("RUST_SYSROOT")
            .expect("To build Miri without rustup, set the `RUST_SYSROOT` env var at build time")
            .to_owned(),
    })
}

fn main() {
    init_early_loggers();

    // Parse our arguments and split them across `rustc` and `miri`.
    let mut validate = true;
    let mut stacked_borrows = true;
    let mut communicate = false;
    let mut ignore_leaks = false;
    let mut seed: Option<u64> = None;
    let mut tracked_pointer_tag: Option<miri::PtrId> = None;
    let mut tracked_alloc_id: Option<miri::AllocId> = None;
    let mut rustc_args = vec![];
    let mut miri_args = vec![];
    let mut after_dashdash = false;
    let mut excluded_env_vars = vec![];
    for arg in std::env::args() {
        if rustc_args.is_empty() {
            // Very first arg: for `rustc`.
            rustc_args.push(arg);
        } else if after_dashdash {
            // Everything that comes after are `miri` args.
            miri_args.push(arg);
        } else {
            match arg.as_str() {
                "-Zmiri-disable-validation" => {
                    validate = false;
                }
                "-Zmiri-disable-stacked-borrows" => {
                    stacked_borrows = false;
                }
                "-Zmiri-disable-isolation" => {
                    communicate = true;
                }
                "-Zmiri-ignore-leaks" => {
                    ignore_leaks = true;
                }
                "--" => {
                    after_dashdash = true;
                }
                arg if arg.starts_with("-Zmiri-seed=") => {
                    if seed.is_some() {
                        panic!("Cannot specify -Zmiri-seed multiple times!");
                    }
                    let seed_raw = hex::decode(arg.trim_start_matches("-Zmiri-seed="))
                        .unwrap_or_else(|err| match err {
                            FromHexError::InvalidHexCharacter { .. } => panic!(
                                "-Zmiri-seed should only contain valid hex digits [0-9a-fA-F]"
                            ),
                            FromHexError::OddLength =>
                                panic!("-Zmiri-seed should have an even number of digits"),
                            err => panic!("Unknown error decoding -Zmiri-seed as hex: {:?}", err),
                        });
                    if seed_raw.len() > 8 {
                        panic!(format!(
                            "-Zmiri-seed must be at most 8 bytes, was {}",
                            seed_raw.len()
                        ));
                    }

                    let mut bytes = [0; 8];
                    bytes[..seed_raw.len()].copy_from_slice(&seed_raw);
                    seed = Some(u64::from_be_bytes(bytes));
                }
                arg if arg.starts_with("-Zmiri-env-exclude=") => {
                    excluded_env_vars
                        .push(arg.trim_start_matches("-Zmiri-env-exclude=").to_owned());
                }
                arg if arg.starts_with("-Zmiri-track-pointer-tag=") => {
                    let id: u64 = match arg.trim_start_matches("-Zmiri-track-pointer-tag=").parse()
                    {
                        Ok(id) => id,
                        Err(err) => panic!(
                            "-Zmiri-track-pointer-tag requires a valid `u64` as the argument: {}",
                            err
                        ),
                    };
                    if let Some(id) = miri::PtrId::new(id) {
                        tracked_pointer_tag = Some(id);
                    } else {
                        panic!("-Zmiri-track-pointer-tag must be a nonzero id");
                    }
                }
                arg if arg.starts_with("-Zmiri-track-alloc-id=") => {
                    let id: u64 = match arg.trim_start_matches("-Zmiri-track-alloc-id=").parse()
                    {
                        Ok(id) => id,
                        Err(err) => panic!(
                            "-Zmiri-track-alloc-id requires a valid `u64` as the argument: {}",
                            err
                        ),
                    };
                    tracked_alloc_id = Some(miri::AllocId(id));
                }
                _ => {
                    rustc_args.push(arg);
                }
            }
        }
    }

    // Determine sysroot if needed.  Make sure we always call `compile_time_sysroot`
    // as that also does some sanity-checks of the environment we were built in.
    // FIXME: Ideally we'd turn a bad build env into a compile-time error, but
    // CTFE does not seem powerful enough for that yet.
    if let Some(sysroot) = compile_time_sysroot() {
        let sysroot_flag = "--sysroot";
        if !rustc_args.iter().any(|e| e == sysroot_flag) {
            // We need to overwrite the default that librustc would compute.
            rustc_args.push(sysroot_flag.to_owned());
            rustc_args.push(sysroot);
        }
    }

    // Finally, add the default flags all the way in the beginning, but after the binary name.
    rustc_args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string));

    debug!("rustc arguments: {:?}", rustc_args);
    debug!("miri arguments: {:?}", miri_args);
    let miri_config = miri::MiriConfig {
        validate,
        stacked_borrows,
        communicate,
        ignore_leaks,
        excluded_env_vars,
        seed,
        args: miri_args,
        tracked_pointer_tag,
        tracked_alloc_id,
    };
    rustc_driver::install_ice_hook();
    let result = rustc_driver::catch_fatal_errors(move || {
        rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None)
    })
    .and_then(|result| result);
    std::process::exit(result.is_err() as i32);
}
<commit_msg>use ctfe_backtracte variable for backtrace control<commit_after>#![feature(rustc_private)]

extern crate env_logger;
extern crate getopts;
#[macro_use]
extern crate log;
extern crate log_settings;
extern crate miri;
extern crate rustc;
extern crate rustc_driver;
extern crate rustc_hir;
extern crate rustc_interface;
extern crate rustc_session;

use std::convert::TryFrom;
use std::env;
use std::str::FromStr;

use hex::FromHexError;

use rustc_session::CtfeBacktrace;
use rustc_driver::Compilation;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_interface::{interface, Queries};
use rustc::ty::TyCtxt;

struct MiriCompilerCalls {
    miri_config: miri::MiriConfig,
}

impl rustc_driver::Callbacks for MiriCompilerCalls {
    fn after_analysis<'tcx>(
        &mut self,
        compiler: &interface::Compiler,
        queries: &'tcx Queries<'tcx>,
    ) -> Compilation {
        compiler.session().abort_if_errors();

        queries.global_ctxt().unwrap().peek_mut().enter(|tcx| {
            init_late_loggers(tcx);
            let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect("no main function found!");
            let mut config = self.miri_config.clone();

            // Add filename to `miri` arguments.
            config.args.insert(0, compiler.input().filestem().to_string());

            if let Some(return_code) = miri::eval_main(tcx, entry_def_id, config) {
                std::process::exit(
                    i32::try_from(return_code).expect("Return value was too large!"),
                );
            }
        });

        compiler.session().abort_if_errors();

        Compilation::Stop
    }
}

fn init_early_loggers() {
    // Note that our `extern crate log` is *not* the same as rustc's; as a result, we have to
    // initialize them both, and we always initialize `miri`'s first.
    let env = env_logger::Env::new().filter("MIRI_LOG").write_style("MIRI_LOG_STYLE");
    env_logger::init_from_env(env);
    // We only initialize `rustc` if the env var is set (so the user asked for it).
    // If it is not set, we avoid initializing now so that we can initialize
    // later with our custom settings, and *not* log anything for what happens before
    // `miri` gets started.
    if env::var("RUSTC_LOG").is_ok() {
        rustc_driver::init_rustc_env_logger();
    }
}

fn init_late_loggers(tcx: TyCtxt<'_>) {
    // We initialize loggers right before we start evaluation. We overwrite the `RUSTC_LOG`
    // env var if it is not set, control it based on `MIRI_LOG`.
    if let Ok(var) = env::var("MIRI_LOG") {
        if env::var("RUSTC_LOG").is_err() {
            // We try to be a bit clever here: if `MIRI_LOG` is just a single level
            // used for everything, we only apply it to the parts of rustc that are
            // CTFE-related. Otherwise, we use it verbatim for `RUSTC_LOG`.
            // This way, if you set `MIRI_LOG=trace`, you get only the right parts of
            // rustc traced, but you can also do `MIRI_LOG=miri=trace,rustc_mir::interpret=debug`.
            if log::Level::from_str(&var).is_ok() {
                env::set_var(
                    "RUSTC_LOG",
                    &format!("rustc::mir::interpret={0},rustc_mir::interpret={0}", var),
                );
            } else {
                env::set_var("RUSTC_LOG", &var);
            }
            rustc_driver::init_rustc_env_logger();
        }
    }

    // If `MIRI_BACKTRACE` is set and `RUSTC_CTFE_BACKTRACE` is not, set `RUSTC_CTFE_BACKTRACE`.
    // Do this late, so we ideally only apply this to Miri's errors.
    if let Ok(val) = env::var("MIRI_BACKTRACE") {
        let ctfe_backtrace = match &*val {
            "immediate" => CtfeBacktrace::Immediate,
            "0" => CtfeBacktrace::Disabled,
            _ => CtfeBacktrace::Capture,
        };
        *tcx.sess.ctfe_backtrace.borrow_mut() = ctfe_backtrace;
    }
}

/// Returns the "default sysroot" that Miri will use if no `--sysroot` flag is set.
/// Should be a compile-time constant.
fn compile_time_sysroot() -> Option<String> {
    if option_env!("RUSTC_STAGE").is_some() {
        // This is being built as part of rustc, and gets shipped with rustup.
        // We can rely on the sysroot computation in librustc.
        return None;
    }
    // For builds outside rustc, we need to ensure that we got a sysroot
    // that gets used as a default.  The sysroot computation in librustc would
    // end up somewhere in the build dir.
    // Taken from PR <https://github.com/Manishearth/rust-clippy/pull/911>.
    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
    Some(match (home, toolchain) {
        (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain),
        _ => option_env!("RUST_SYSROOT")
            .expect("To build Miri without rustup, set the `RUST_SYSROOT` env var at build time")
            .to_owned(),
    })
}

fn main() {
    init_early_loggers();

    // Parse our arguments and split them across `rustc` and `miri`.
    let mut validate = true;
    let mut stacked_borrows = true;
    let mut communicate = false;
    let mut ignore_leaks = false;
    let mut seed: Option<u64> = None;
    let mut tracked_pointer_tag: Option<miri::PtrId> = None;
    let mut tracked_alloc_id: Option<miri::AllocId> = None;
    let mut rustc_args = vec![];
    let mut miri_args = vec![];
    let mut after_dashdash = false;
    let mut excluded_env_vars = vec![];
    for arg in std::env::args() {
        if rustc_args.is_empty() {
            // Very first arg: for `rustc`.
            rustc_args.push(arg);
        } else if after_dashdash {
            // Everything that comes after are `miri` args.
            miri_args.push(arg);
        } else {
            match arg.as_str() {
                "-Zmiri-disable-validation" => {
                    validate = false;
                }
                "-Zmiri-disable-stacked-borrows" => {
                    stacked_borrows = false;
                }
                "-Zmiri-disable-isolation" => {
                    communicate = true;
                }
                "-Zmiri-ignore-leaks" => {
                    ignore_leaks = true;
                }
                "--" => {
                    after_dashdash = true;
                }
                arg if arg.starts_with("-Zmiri-seed=") => {
                    if seed.is_some() {
                        panic!("Cannot specify -Zmiri-seed multiple times!");
                    }
                    let seed_raw = hex::decode(arg.trim_start_matches("-Zmiri-seed="))
                        .unwrap_or_else(|err| match err {
                            FromHexError::InvalidHexCharacter { .. } => panic!(
                                "-Zmiri-seed should only contain valid hex digits [0-9a-fA-F]"
                            ),
                            FromHexError::OddLength =>
                                panic!("-Zmiri-seed should have an even number of digits"),
                            err => panic!("Unknown error decoding -Zmiri-seed as hex: {:?}", err),
                        });
                    if seed_raw.len() > 8 {
                        panic!(format!(
                            "-Zmiri-seed must be at most 8 bytes, was {}",
                            seed_raw.len()
                        ));
                    }

                    let mut bytes = [0; 8];
                    bytes[..seed_raw.len()].copy_from_slice(&seed_raw);
                    seed = Some(u64::from_be_bytes(bytes));
                }
                arg if arg.starts_with("-Zmiri-env-exclude=") => {
                    excluded_env_vars
                        .push(arg.trim_start_matches("-Zmiri-env-exclude=").to_owned());
                }
                arg if arg.starts_with("-Zmiri-track-pointer-tag=") => {
                    let id: u64 = match arg.trim_start_matches("-Zmiri-track-pointer-tag=").parse()
                    {
                        Ok(id) => id,
                        Err(err) => panic!(
                            "-Zmiri-track-pointer-tag requires a valid `u64` as the argument: {}",
                            err
                        ),
                    };
                    if let Some(id) = miri::PtrId::new(id) {
                        tracked_pointer_tag = Some(id);
                    } else {
                        panic!("-Zmiri-track-pointer-tag must be a nonzero id");
                    }
                }
                arg if arg.starts_with("-Zmiri-track-alloc-id=") => {
                    let id: u64 = match arg.trim_start_matches("-Zmiri-track-alloc-id=").parse()
                    {
                        Ok(id) => id,
                        Err(err) => panic!(
                            "-Zmiri-track-alloc-id requires a valid `u64` as the argument: {}",
                            err
                        ),
                    };
                    tracked_alloc_id = Some(miri::AllocId(id));
                }
                _ => {
                    rustc_args.push(arg);
                }
            }
        }
    }

    // Determine sysroot if needed.  Make sure we always call `compile_time_sysroot`
    // as that also does some sanity-checks of the environment we were built in.
    // FIXME: Ideally we'd turn a bad build env into a compile-time error, but
    // CTFE does not seem powerful enough for that yet.
    if let Some(sysroot) = compile_time_sysroot() {
        let sysroot_flag = "--sysroot";
        if !rustc_args.iter().any(|e| e == sysroot_flag) {
            // We need to overwrite the default that librustc would compute.
            rustc_args.push(sysroot_flag.to_owned());
            rustc_args.push(sysroot);
        }
    }

    // Finally, add the default flags all the way in the beginning, but after the binary name.
    rustc_args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string));

    debug!("rustc arguments: {:?}", rustc_args);
    debug!("miri arguments: {:?}", miri_args);
    let miri_config = miri::MiriConfig {
        validate,
        stacked_borrows,
        communicate,
        ignore_leaks,
        excluded_env_vars,
        seed,
        args: miri_args,
        tracked_pointer_tag,
        tracked_alloc_id,
    };
    rustc_driver::install_ice_hook();
    let result = rustc_driver::catch_fatal_errors(move || {
        rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None)
    })
    .and_then(|result| result);
    std::process::exit(result.is_err() as i32);
}
<|endoftext|>


<commit_before>fn main() {
    // TODO(gary): Rust doesn't expose sync. Revisit.
}
<commit_msg>Add sync command.<commit_after>extern crate libc;
extern crate getopts;

extern crate coreutils;

use std::os;

extern {
    fn sync() -> libc::c_void;
}

fn main() {

    let args = os::args();
    let program = args[0].clone();

    let opts = [
        getopts::optflag("h", "help", "display this help and exit"),
        getopts::optflag("V", "version", "output version information and exit"),
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m },
        Err(f) => {
            println!("{}", f.to_string());
            println!("-------------------------------");
            println!("Usage: {}", getopts::usage(program.as_slice(), opts));
            return;
        },
    };

    if matches.opt_present("help") {
        println!("Usage: {}", getopts::usage(program.as_slice(), opts));
        return;
    }

    if matches.opt_present("version") {
        println!("{}: {}", program, coreutils::version());
        return;
    }

    unsafe { sync(); }
}
<|endoftext|>


<commit_before>//! Checks for incompatible bit masks in comparisons, e.g. `x & 1 == 2`. This cannot work because the bit that makes up
//! the value two was zeroed out by the bit-and with 1. So the formula for detecting if an expression of the type
//! `_ <bit_op> m <cmp_op> c` (where `<bit_op>` is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` ,`!=`, `>=`,
//! `>`}) can be determined from the following table:
//!
//! |Comparison  |Bit-Op|Example     |is always|Formula               |
//! |------------|------|------------|---------|----------------------|
//! |`==` or `!=`| `&`  |`x & 2 == 3`|`false`  |`c & m != c`          |
//! |`<`  or `>=`| `&`  |`x & 2 < 3` |`true`   |`m < c`               |
//! |`>`  or `<=`| `&`  |`x & 1 > 1` |`false`  |`m <= c`              |
//! |`==` or `!=`| `|`  |`x | 1 == 0`|`false`  |`c | m != c`          |
//! |`<`  or `>=`| `|`  |`x | 1 < 1` |`false`  |`m >= c`			  |
//! |`<=` or `>` | `|`  |`x | 1 > 0` |`true`   |`m > c`               |
//!
//! *TODO*: There is the open question if things like `x | 1 > 1` should be caught by this lint, because it is basically
//! an obfuscated version of `x > 1`.
//!
//! This lint is **deny** by default

use rustc::plugin::Registry;
use rustc::lint::*;
use rustc::middle::const_eval::lookup_const_by_id;
use rustc::middle::def::*;
use syntax::ast::*;
use syntax::ast_util::{is_comparison_binop, binop_to_string};
use syntax::ptr::P;
use syntax::codemap::Span;

declare_lint! {
    pub BAD_BIT_MASK,
    Deny,
    "Deny the use of incompatible bit masks in comparisons, e.g. '(a & 1) == 2'"
}

#[derive(Copy,Clone)]
pub struct BitMask;

impl LintPass for BitMask {
    fn get_lints(&self) -> LintArray {
        lint_array!(BAD_BIT_MASK)
    }

    fn check_expr(&mut self, cx: &Context, e: &Expr) {
        if let ExprBinary(ref cmp, ref left, ref right) = e.node {
			if is_comparison_binop(cmp.node) {
				let cmp_opt = fetch_int_literal(cx, right);
				if cmp_opt.is_some() {
					check_compare(cx, left, cmp.node, cmp_opt.unwrap(), &e.span);
				} else {
					fetch_int_literal(cx, left).map(|cmp_val|
						check_compare(cx, right, invert_cmp(cmp.node), cmp_val, &e.span));
				}
			}
		}
    }
}

fn invert_cmp(cmp : BinOp_) -> BinOp_ {
	match cmp {
		BiEq => BiEq,
		BiNe => BiNe,
		BiLt => BiGt,
		BiGt => BiLt,
		BiLe => BiGe,
		BiGe => BiLe,
		_ => BiOr // Dummy
	}
}

fn check_compare(cx: &Context, bit_op: &Expr, cmp_op: BinOp_, cmp_value: u64, span: &Span) {
	match &bit_op.node {
		&ExprParen(ref subexp) => check_compare(cx, subexp, cmp_op, cmp_value, span),
		&ExprBinary(ref op, ref left, ref right) => {
			if op.node != BiBitAnd && op.node != BiBitOr { return; }
			if let Some(mask_value) = fetch_int_literal(cx, right) {
				check_bit_mask(cx, op.node, cmp_op, mask_value, cmp_value, span);
			} else if let Some(mask_value) = fetch_int_literal(cx, left) {
				check_bit_mask(cx, op.node, cmp_op, mask_value, cmp_value, span);
			}
		},
		_ => ()
	}
}

fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, mask_value: u64, cmp_value: u64, span: &Span) {
	match cmp_op {
		BiEq | BiNe => match bit_op {
			BiBitAnd => if mask_value & cmp_value != mask_value {
				cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ & {} can never be equal to {}", mask_value,
					cmp_value));
			} else {
				if mask_value == 0 {
					cx.span_lint(BAD_BIT_MASK, *span, &format!("&-masking with zero"));
				}
			},
			BiBitOr => if mask_value | cmp_value != cmp_value {
				cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ | {} can never be equal to {}", mask_value,
					cmp_value));
			},
			_ => ()
		},
		BiLt | BiGe => match bit_op {
			BiBitAnd => if mask_value < cmp_value {
				cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ & {} will always be lower than {}", mask_value,
					cmp_value));
			} else {
				if mask_value == 0 {
					cx.span_lint(BAD_BIT_MASK, *span, &format!("&-masking with zero"));
				}
			},
			BiBitOr => if mask_value >= cmp_value {
				cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ | {} will never be lower than {}", mask_value,
					cmp_value));
			},
			_ => ()
		},
		BiLe | BiGt => match bit_op {
			BiBitAnd => if mask_value <= cmp_value {
				cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ & {} will never be higher than {}", mask_value,
					cmp_value));
			} else {
				if mask_value == 0 {
					cx.span_lint(BAD_BIT_MASK, *span, &format!("&-masking with zero"));
				}
			},
			BiBitOr => if mask_value > cmp_value {
				cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ | {} will always be higher than {}", mask_value,
					cmp_value));
			},
			_ => ()
		},
		_ => ()
	}
}

fn fetch_int_literal(cx: &Context, lit : &Expr) -> Option<u64> {
	match &lit.node {
		&ExprLit(ref lit_ptr) => {
			if let &LitInt(value, _) = &lit_ptr.node {
				Option::Some(value) //TODO: Handle sign
			} else { Option::None }
		},
		&ExprPath(_, _) => {
			let def_map = cx.tcx.def_map.borrow();
			let path_res_op = def_map.get(&lit.id);
			path_res_op.as_ref().and_then(|x| {
				if let &DefConst(def_id) = &x.base_def {
					lookup_const_by_id(cx.tcx, def_id, Option::None).and_then(|l| fetch_int_literal(cx, l))
				} else { Option::None }
			})
		},
		_ => Option::None
	}
}
<commit_msg>Fix panic during constant lookup.<commit_after>//! Checks for incompatible bit masks in comparisons, e.g. `x & 1 == 2`. This cannot work because the bit that makes up
//! the value two was zeroed out by the bit-and with 1. So the formula for detecting if an expression of the type
//! `_ <bit_op> m <cmp_op> c` (where `<bit_op>` is one of {`&`, '|'} and `<cmp_op>` is one of {`!=`, `>=`, `>` ,`!=`, `>=`,
//! `>`}) can be determined from the following table:
//!
//! |Comparison  |Bit-Op|Example     |is always|Formula               |
//! |------------|------|------------|---------|----------------------|
//! |`==` or `!=`| `&`  |`x & 2 == 3`|`false`  |`c & m != c`          |
//! |`<`  or `>=`| `&`  |`x & 2 < 3` |`true`   |`m < c`               |
//! |`>`  or `<=`| `&`  |`x & 1 > 1` |`false`  |`m <= c`              |
//! |`==` or `!=`| `|`  |`x | 1 == 0`|`false`  |`c | m != c`          |
//! |`<`  or `>=`| `|`  |`x | 1 < 1` |`false`  |`m >= c`			  |
//! |`<=` or `>` | `|`  |`x | 1 > 0` |`true`   |`m > c`               |
//!
//! *TODO*: There is the open question if things like `x | 1 > 1` should be caught by this lint, because it is basically
//! an obfuscated version of `x > 1`.
//!
//! This lint is **deny** by default

use rustc::plugin::Registry;
use rustc::lint::*;
use rustc::middle::const_eval::lookup_const_by_id;
use rustc::middle::def::*;
use syntax::ast::*;
use syntax::ast_util::{is_comparison_binop, binop_to_string};
use syntax::ptr::P;
use syntax::codemap::Span;

declare_lint! {
    pub BAD_BIT_MASK,
    Deny,
    "Deny the use of incompatible bit masks in comparisons, e.g. '(a & 1) == 2'"
}

#[derive(Copy,Clone)]
pub struct BitMask;

impl LintPass for BitMask {
    fn get_lints(&self) -> LintArray {
        lint_array!(BAD_BIT_MASK)
    }

    fn check_expr(&mut self, cx: &Context, e: &Expr) {
        if let ExprBinary(ref cmp, ref left, ref right) = e.node {
			if is_comparison_binop(cmp.node) {
				let cmp_opt = fetch_int_literal(cx, right);
				if cmp_opt.is_some() {
					check_compare(cx, left, cmp.node, cmp_opt.unwrap(), &e.span);
				} else {
					fetch_int_literal(cx, left).map(|cmp_val|
						check_compare(cx, right, invert_cmp(cmp.node), cmp_val, &e.span));
				}
			}
		}
    }
}

fn invert_cmp(cmp : BinOp_) -> BinOp_ {
	match cmp {
		BiEq => BiEq,
		BiNe => BiNe,
		BiLt => BiGt,
		BiGt => BiLt,
		BiLe => BiGe,
		BiGe => BiLe,
		_ => BiOr // Dummy
	}
}

fn check_compare(cx: &Context, bit_op: &Expr, cmp_op: BinOp_, cmp_value: u64, span: &Span) {
	match &bit_op.node {
		&ExprParen(ref subexp) => check_compare(cx, subexp, cmp_op, cmp_value, span),
		&ExprBinary(ref op, ref left, ref right) => {
			if op.node != BiBitAnd && op.node != BiBitOr { return; }
			if let Some(mask_value) = fetch_int_literal(cx, right) {
				check_bit_mask(cx, op.node, cmp_op, mask_value, cmp_value, span);
			} else if let Some(mask_value) = fetch_int_literal(cx, left) {
				check_bit_mask(cx, op.node, cmp_op, mask_value, cmp_value, span);
			}
		},
		_ => ()
	}
}

fn check_bit_mask(cx: &Context, bit_op: BinOp_, cmp_op: BinOp_, mask_value: u64, cmp_value: u64, span: &Span) {
	match cmp_op {
		BiEq | BiNe => match bit_op {
			BiBitAnd => if mask_value & cmp_value != mask_value {
				cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ & {} can never be equal to {}", mask_value,
					cmp_value));
			} else {
				if mask_value == 0 {
					cx.span_lint(BAD_BIT_MASK, *span, &format!("&-masking with zero"));
				}
			},
			BiBitOr => if mask_value | cmp_value != cmp_value {
				cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ | {} can never be equal to {}", mask_value,
					cmp_value));
			},
			_ => ()
		},
		BiLt | BiGe => match bit_op {
			BiBitAnd => if mask_value < cmp_value {
				cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ & {} will always be lower than {}", mask_value,
					cmp_value));
			} else {
				if mask_value == 0 {
					cx.span_lint(BAD_BIT_MASK, *span, &format!("&-masking with zero"));
				}
			},
			BiBitOr => if mask_value >= cmp_value {
				cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ | {} will never be lower than {}", mask_value,
					cmp_value));
			},
			_ => ()
		},
		BiLe | BiGt => match bit_op {
			BiBitAnd => if mask_value <= cmp_value {
				cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ & {} will never be higher than {}", mask_value,
					cmp_value));
			} else {
				if mask_value == 0 {
					cx.span_lint(BAD_BIT_MASK, *span, &format!("&-masking with zero"));
				}
			},
			BiBitOr => if mask_value > cmp_value {
				cx.span_lint(BAD_BIT_MASK, *span, &format!("incompatible bit mask: _ | {} will always be higher than {}", mask_value,
					cmp_value));
			},
			_ => ()
		},
		_ => ()
	}
}

fn fetch_int_literal(cx: &Context, lit : &Expr) -> Option<u64> {
	match &lit.node {
		&ExprLit(ref lit_ptr) => {
			if let &LitInt(value, _) = &lit_ptr.node {
				Option::Some(value) //TODO: Handle sign
			} else { Option::None }
		},
		&ExprPath(_, _) => {
                // Important to let the borrow expire before the const lookup to avoid double
                // borrowing.
                let def_map = cx.tcx.def_map.borrow();
                match def_map.get(&lit.id) {
                    Some(&PathResolution { base_def: DefConst(def_id), ..}) => Some(def_id),
                    _ => None
                }
            }
            .and_then(|def_id| lookup_const_by_id(cx.tcx, def_id, Option::None))
            .and_then(|l| fetch_int_literal(cx, l)),
		_ => Option::None
	}
}
<|endoftext|>


<commit_before>//! The internal representation of a book and infrastructure for loading it from
//! disk and building it.
//!
//! For examples on using `MDBook`, consult the [top-level documentation][1].
//!
//! [1]: ../index.html

#![deny(missing_docs)]

mod summary;
mod book;
mod init;

pub use self::book::{load_book, Book, BookItem, BookItems, Chapter};
pub use self::summary::{parse_summary, Link, SectionNumber, Summary, SummaryItem};
pub use self::init::BookBuilder;

use std::path::{Path, PathBuf};
use std::io::Write;
use std::process::Command;
use tempdir::TempDir;

use utils;
use renderer::{HtmlHandlebars, Renderer};
use preprocess;
use errors::*;

use config::Config;

/// The object used to manage and build a book.
pub struct MDBook {
    /// The book's root directory.
    pub root: PathBuf,
    /// The configuration used to tweak now a book is built.
    pub config: Config,

    book: Book,
    renderer: Box<Renderer>,

    /// The URL used for live reloading when serving up the book.
    pub livereload: Option<String>,
}

impl MDBook {
    /// Load a book from its root directory on disk.
    pub fn load<P: Into<PathBuf>>(book_root: P) -> Result<MDBook> {
        let book_root = book_root.into();
        let config_location = book_root.join("book.toml");

        let config = if config_location.exists() {
            debug!("[*] Loading config from {}", config_location.display());
            Config::from_disk(&config_location)?
        } else {
            Config::default()
        };

        if log_enabled!(::log::LogLevel::Trace) {
            for line in format!("Config: {:#?}", config).lines() {
                trace!("{}", line);
            }
        }

        MDBook::load_with_config(book_root, config)
    }

    /// Load a book from its root directory using a custom config.
    pub fn load_with_config<P: Into<PathBuf>>(book_root: P, config: Config) -> Result<MDBook> {
        let book_root = book_root.into();

        let src_dir = book_root.join(&config.book.src);
        let book = book::load_book(&src_dir, &config.build)?;

        Ok(MDBook {
            root: book_root,
            config: config,
            book: book,
            renderer: Box::new(HtmlHandlebars::new()),
            livereload: None,
        })
    }

    /// Returns a flat depth-first iterator over the elements of the book,
    /// it returns an [BookItem enum](bookitem.html):
    /// `(section: String, bookitem: &BookItem)`
    ///
    /// ```no_run
    /// # extern crate mdbook;
    /// # use mdbook::MDBook;
    /// # use mdbook::book::BookItem;
    /// # #[allow(unused_variables)]
    /// # fn main() {
    /// # let book = MDBook::load("mybook").unwrap();
    /// for item in book.iter() {
    ///     match *item {
    ///         BookItem::Chapter(ref chapter) => {},
    ///         BookItem::Separator => {},
    ///     }
    /// }
    ///
    /// // would print something like this:
    /// // 1. Chapter 1
    /// // 1.1 Sub Chapter
    /// // 1.2 Sub Chapter
    /// // 2. Chapter 2
    /// //
    /// // etc.
    /// # }
    /// ```
    pub fn iter(&self) -> BookItems {
        self.book.iter()
    }

    /// `init()` gives you a `BookBuilder` which you can use to setup a new book
    /// and its accompanying directory structure.
    ///
    /// The `BookBuilder` creates some boilerplate files and directories to get
    /// you started with your book.
    ///
    /// ```text
    /// book-test/
    /// ├── book
    /// └── src
    ///     ├── chapter_1.md
    ///     └── SUMMARY.md
    /// ```
    ///
    /// It uses the path provided as the root directory for your book, then adds
    /// in a `src/` directory containing a `SUMMARY.md` and `chapter_1.md` file
    /// to get you started.
    pub fn init<P: Into<PathBuf>>(book_root: P) -> BookBuilder {
        BookBuilder::new(book_root)
    }

    /// Tells the renderer to build our book and put it in the build directory.
    pub fn build(&mut self) -> Result<()> {
        debug!("[fn]: build");

        let dest = self.get_destination();
        if dest.exists() {
            utils::fs::remove_dir_content(&dest).chain_err(|| "Unable to clear output directory")?;
        }

        self.renderer.render(self)
    }

    // FIXME: This doesn't belong as part of `MDBook`. It is only used by the HTML renderer
    #[doc(hidden)]
    pub fn write_file<P: AsRef<Path>>(&self, filename: P, content: &[u8]) -> Result<()> {
        let path = self.get_destination().join(filename);

        utils::fs::create_file(&path)?
            .write_all(content)
            .map_err(|e| e.into())
    }

    /// You can change the default renderer to another one by using this method.
    /// The only requirement is for your renderer to implement the [Renderer
    /// trait](../../renderer/renderer/trait.Renderer.html)
    pub fn set_renderer<R: Renderer + 'static>(mut self, renderer: R) -> Self {
        self.renderer = Box::new(renderer);
        self
    }

    /// Run `rustdoc` tests on the book, linking against the provided libraries.
    pub fn test(&mut self, library_paths: Vec<&str>) -> Result<()> {
        let library_args: Vec<&str> = (0..library_paths.len())
            .map(|_| "-L")
            .zip(library_paths.into_iter())
            .flat_map(|x| vec![x.0, x.1])
            .collect();

        let temp_dir = TempDir::new("mdbook")?;

        for item in self.iter() {
            if let BookItem::Chapter(ref ch) = *item {
                if !ch.path.as_os_str().is_empty() {
                    let path = self.source_dir().join(&ch.path);
                    let base = path.parent()
                        .ok_or_else(|| String::from("Invalid bookitem path!"))?;
                    let content = utils::fs::file_to_string(&path)?;
                    // Parse and expand links
                    let content = preprocess::links::replace_all(&content, base)?;
                    println!("[*]: Testing file: {:?}", path);

                    // write preprocessed file to tempdir
                    let path = temp_dir.path().join(&ch.path);
                    let mut tmpf = utils::fs::create_file(&path)?;
                    tmpf.write_all(content.as_bytes())?;

                    let output = Command::new("rustdoc")
                        .arg(&path)
                        .arg("--test")
                        .args(&library_args)
                        .output()?;

                    if !output.status.success() {
                        bail!(ErrorKind::Subprocess(
                            "Rustdoc returned an error".to_string(),
                            output
                        ));
                    }
                }
            }
        }
        Ok(())
    }

    // FIXME: This doesn't belong under `MDBook`, it should really be passed to the renderer directly.
    #[doc(hidden)]
    pub fn get_destination(&self) -> PathBuf {
        self.root.join(&self.config.build.build_dir)
    }

    /// Get the directory containing this book's source files.
    pub fn source_dir(&self) -> PathBuf {
        self.root.join(&self.config.book.src)
    }

    // FIXME: This belongs as part of the `HtmlConfig`.
    #[doc(hidden)]
    pub fn theme_dir(&self) -> PathBuf {
        match self.config.html_config().and_then(|h| h.theme) {
            Some(d) => self.root.join(d),
            None => self.root.join("theme"),
        }
    }
}
<commit_msg>Added a warning if people use the book.json config file<commit_after>//! The internal representation of a book and infrastructure for loading it from
//! disk and building it.
//!
//! For examples on using `MDBook`, consult the [top-level documentation][1].
//!
//! [1]: ../index.html

#![deny(missing_docs)]

mod summary;
mod book;
mod init;

pub use self::book::{load_book, Book, BookItem, BookItems, Chapter};
pub use self::summary::{parse_summary, Link, SectionNumber, Summary, SummaryItem};
pub use self::init::BookBuilder;

use std::path::{Path, PathBuf};
use std::io::Write;
use std::process::Command;
use tempdir::TempDir;

use utils;
use renderer::{HtmlHandlebars, Renderer};
use preprocess;
use errors::*;

use config::Config;

/// The object used to manage and build a book.
pub struct MDBook {
    /// The book's root directory.
    pub root: PathBuf,
    /// The configuration used to tweak now a book is built.
    pub config: Config,

    book: Book,
    renderer: Box<Renderer>,

    /// The URL used for live reloading when serving up the book.
    pub livereload: Option<String>,
}

impl MDBook {
    /// Load a book from its root directory on disk.
    pub fn load<P: Into<PathBuf>>(book_root: P) -> Result<MDBook> {
        let book_root = book_root.into();
        let config_location = book_root.join("book.toml");

        // the book.json file is no longer used, so we should emit a warning to
        // let people know to migrate to book.toml
        if book_root.join("book.json").exists() {
            warn!("It appears you are still using book.json for configuration.");
            warn!("This format is no longer used, so you should migrate to the");
            warn!("book.toml format.");
            warn!("Check the user guide for migration information:");
            warn!("\thttps://rust-lang-nursery.github.io/mdBook/format/config.html");
        }

        let config = if config_location.exists() {
            debug!("[*] Loading config from {}", config_location.display());
            Config::from_disk(&config_location)?
        } else {
            Config::default()
        };

        if log_enabled!(::log::LogLevel::Trace) {
            for line in format!("Config: {:#?}", config).lines() {
                trace!("{}", line);
            }
        }

        MDBook::load_with_config(book_root, config)
    }

    /// Load a book from its root directory using a custom config.
    pub fn load_with_config<P: Into<PathBuf>>(book_root: P, config: Config) -> Result<MDBook> {
        let book_root = book_root.into();

        let src_dir = book_root.join(&config.book.src);
        let book = book::load_book(&src_dir, &config.build)?;

        Ok(MDBook {
            root: book_root,
            config: config,
            book: book,
            renderer: Box::new(HtmlHandlebars::new()),
            livereload: None,
        })
    }

    /// Returns a flat depth-first iterator over the elements of the book,
    /// it returns an [BookItem enum](bookitem.html):
    /// `(section: String, bookitem: &BookItem)`
    ///
    /// ```no_run
    /// # extern crate mdbook;
    /// # use mdbook::MDBook;
    /// # use mdbook::book::BookItem;
    /// # #[allow(unused_variables)]
    /// # fn main() {
    /// # let book = MDBook::load("mybook").unwrap();
    /// for item in book.iter() {
    ///     match *item {
    ///         BookItem::Chapter(ref chapter) => {},
    ///         BookItem::Separator => {},
    ///     }
    /// }
    ///
    /// // would print something like this:
    /// // 1. Chapter 1
    /// // 1.1 Sub Chapter
    /// // 1.2 Sub Chapter
    /// // 2. Chapter 2
    /// //
    /// // etc.
    /// # }
    /// ```
    pub fn iter(&self) -> BookItems {
        self.book.iter()
    }

    /// `init()` gives you a `BookBuilder` which you can use to setup a new book
    /// and its accompanying directory structure.
    ///
    /// The `BookBuilder` creates some boilerplate files and directories to get
    /// you started with your book.
    ///
    /// ```text
    /// book-test/
    /// ├── book
    /// └── src
    ///     ├── chapter_1.md
    ///     └── SUMMARY.md
    /// ```
    ///
    /// It uses the path provided as the root directory for your book, then adds
    /// in a `src/` directory containing a `SUMMARY.md` and `chapter_1.md` file
    /// to get you started.
    pub fn init<P: Into<PathBuf>>(book_root: P) -> BookBuilder {
        BookBuilder::new(book_root)
    }

    /// Tells the renderer to build our book and put it in the build directory.
    pub fn build(&mut self) -> Result<()> {
        debug!("[fn]: build");

        let dest = self.get_destination();
        if dest.exists() {
            utils::fs::remove_dir_content(&dest).chain_err(|| "Unable to clear output directory")?;
        }

        self.renderer.render(self)
    }

    // FIXME: This doesn't belong as part of `MDBook`. It is only used by the HTML renderer
    #[doc(hidden)]
    pub fn write_file<P: AsRef<Path>>(&self, filename: P, content: &[u8]) -> Result<()> {
        let path = self.get_destination().join(filename);

        utils::fs::create_file(&path)?
            .write_all(content)
            .map_err(|e| e.into())
    }

    /// You can change the default renderer to another one by using this method.
    /// The only requirement is for your renderer to implement the [Renderer
    /// trait](../../renderer/renderer/trait.Renderer.html)
    pub fn set_renderer<R: Renderer + 'static>(mut self, renderer: R) -> Self {
        self.renderer = Box::new(renderer);
        self
    }

    /// Run `rustdoc` tests on the book, linking against the provided libraries.
    pub fn test(&mut self, library_paths: Vec<&str>) -> Result<()> {
        let library_args: Vec<&str> = (0..library_paths.len())
            .map(|_| "-L")
            .zip(library_paths.into_iter())
            .flat_map(|x| vec![x.0, x.1])
            .collect();

        let temp_dir = TempDir::new("mdbook")?;

        for item in self.iter() {
            if let BookItem::Chapter(ref ch) = *item {
                if !ch.path.as_os_str().is_empty() {
                    let path = self.source_dir().join(&ch.path);
                    let base = path.parent()
                        .ok_or_else(|| String::from("Invalid bookitem path!"))?;
                    let content = utils::fs::file_to_string(&path)?;
                    // Parse and expand links
                    let content = preprocess::links::replace_all(&content, base)?;
                    println!("[*]: Testing file: {:?}", path);

                    // write preprocessed file to tempdir
                    let path = temp_dir.path().join(&ch.path);
                    let mut tmpf = utils::fs::create_file(&path)?;
                    tmpf.write_all(content.as_bytes())?;

                    let output = Command::new("rustdoc")
                        .arg(&path)
                        .arg("--test")
                        .args(&library_args)
                        .output()?;

                    if !output.status.success() {
                        bail!(ErrorKind::Subprocess(
                            "Rustdoc returned an error".to_string(),
                            output
                        ));
                    }
                }
            }
        }
        Ok(())
    }

    // FIXME: This doesn't belong under `MDBook`, it should really be passed to the renderer directly.
    #[doc(hidden)]
    pub fn get_destination(&self) -> PathBuf {
        self.root.join(&self.config.build.build_dir)
    }

    /// Get the directory containing this book's source files.
    pub fn source_dir(&self) -> PathBuf {
        self.root.join(&self.config.book.src)
    }

    // FIXME: This belongs as part of the `HtmlConfig`.
    #[doc(hidden)]
    pub fn theme_dir(&self) -> PathBuf {
        match self.config.html_config().and_then(|h| h.theme) {
            Some(d) => self.root.join(d),
            None => self.root.join("theme"),
        }
    }
}
<|endoftext|>


<commit_before>//! [Church booleans](https://en.wikipedia.org/wiki/Church_encoding#Church_Booleans)

use term::*;

/// A Church-encoded boolean `true`.
///
/// TRUE := λab.a = λ λ 2
pub fn tru() -> Term { abs(abs(Var(2))) }

/// A Church-encoded boolean `false`.
///
/// FALSE := λab.b = λ λ 1
pub fn fls() -> Term { abs(abs(Var(1))) }

/// Applied to two Church-encoded booleans it returns their Church-encoded conjunction.
///
/// AND := λpq.p q p = λ λ 2 1 2
///
/// # Examples
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::booleans::{and, tru, fls};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(and(), tru(), tru()), NOR, 0, false), tru());
/// assert_eq!(beta(app!(and(), tru(), fls()), NOR, 0, false), fls());
/// assert_eq!(beta(app!(and(), fls(), tru()), NOR, 0, false), fls());
/// assert_eq!(beta(app!(and(), fls(), fls()), NOR, 0, false), fls());
/// # }
/// ```
pub fn and() -> Term {
    abs(abs(
        app!(Var(2), Var(1), Var(2))
    ))
}

/// Applied to two Church-encoded booleans it returns their Church-encoded disjunction.
///
/// OR := λpq.p p q = λ λ 2 2 1
///
/// # Examples
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::booleans::{or, tru, fls};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(or(), tru(), tru()), NOR, 0, false), tru());
/// assert_eq!(beta(app!(or(), tru(), fls()), NOR, 0, false), tru());
/// assert_eq!(beta(app!(or(), fls(), tru()), NOR, 0, false), tru());
/// assert_eq!(beta(app!(or(), fls(), fls()), NOR, 0, false), fls());
/// # }
/// ```
pub fn or() -> Term {
    abs(abs(
        app!(Var(2), Var(2), Var(1))
    ))
}

/// Applied to a Church-encoded boolean it returns its Church-encoded negation.
///
/// NOT := λp.p FALSE TRUE = λ 1 FALSE TRUE
///
/// # Examples
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::booleans::{not, tru, fls};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(not(), tru()), NOR, 0, false), fls());
/// assert_eq!(beta(app!(not(), fls()), NOR, 0, false), tru());
/// # }
/// ```
pub fn not() -> Term {
    abs(
        app!(Var(1), fls(), tru())
    )
}

/// Applied to a Church-encoded boolean it returns its Church-encoded exclusive disjunction.
///
/// XOR := λpq.p (NOT q) q = λ λ 2 (NOT 1) 1
///
/// # Examples
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::booleans::{xor, tru, fls};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(xor(), tru(), tru()), NOR, 0, false), fls());
/// assert_eq!(beta(app!(xor(), tru(), fls()), NOR, 0, false), tru());
/// assert_eq!(beta(app!(xor(), fls(), tru()), NOR, 0, false), tru());
/// assert_eq!(beta(app!(xor(), fls(), fls()), NOR, 0, false), fls());
/// # }
/// ```
pub fn xor() -> Term {
    abs(abs(
        app!(
            Var(2),
            app!(
                Var(1),
                abs(abs(Var(1))),
                abs(abs(Var(2)))
            ),
            Var(1)
        )
    ))
}

/// Applied to a Church-encoded boolean it returns its Church-encoded joint denial.
///
/// NOR := λpq.NOT (OR p q) = λ λ NOT (OR 2 1)
///
/// # Examples
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::booleans::{nor, tru, fls};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(nor(), tru(), tru()), NOR, 0, false), fls());
/// assert_eq!(beta(app!(nor(), tru(), fls()), NOR, 0, false), fls());
/// assert_eq!(beta(app!(nor(), fls(), tru()), NOR, 0, false), fls());
/// assert_eq!(beta(app!(nor(), fls(), fls()), NOR, 0, false), tru());
/// # }
/// ```
pub fn nor() -> Term {
    abs(abs(
        app!(
            Var(2),
            Var(2),
            Var(1),
            abs(abs(Var(1))),
            abs(abs(Var(2)))
        )
    ))
}

/// Applied to a Church encoded predicate and two terms it returns the first one if the predicate
/// is true or the second one if the predicate is false.
///
/// IF_ELSE := λpab.p a b = λ λ λ 3 2 1
///
/// # Examples
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::booleans::{if_else, tru, fls};
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(if_else(), tru(), one(), zero()), NOR, 0, false),  one());
/// assert_eq!(beta(app!(if_else(), fls(), one(), zero()), NOR, 0, false), zero());
/// # }
/// ```
pub fn if_else() -> Term {
    abs(abs(abs(
        app!(Var(3), Var(2), Var(1))
    )))
}

impl From<bool> for Term {
    fn from(b: bool) -> Self {
        if b { tru() } else { fls() }
    }
}
<commit_msg>add logical NAND<commit_after>//! [Church booleans](https://en.wikipedia.org/wiki/Church_encoding#Church_Booleans)

use term::*;

/// A Church-encoded boolean `true`.
///
/// TRUE := λab.a = λ λ 2
pub fn tru() -> Term { abs(abs(Var(2))) }

/// A Church-encoded boolean `false`.
///
/// FALSE := λab.b = λ λ 1
pub fn fls() -> Term { abs(abs(Var(1))) }

/// Applied to two Church-encoded booleans it returns their Church-encoded conjunction.
///
/// AND := λpq.p q p = λ λ 2 1 2
///
/// # Examples
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::booleans::{and, tru, fls};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(and(), tru(), tru()), NOR, 0, false), tru());
/// assert_eq!(beta(app!(and(), tru(), fls()), NOR, 0, false), fls());
/// assert_eq!(beta(app!(and(), fls(), tru()), NOR, 0, false), fls());
/// assert_eq!(beta(app!(and(), fls(), fls()), NOR, 0, false), fls());
/// # }
/// ```
pub fn and() -> Term {
    abs(abs(
        app!(Var(2), Var(1), Var(2))
    ))
}

/// Applied to two Church-encoded booleans it returns their Church-encoded disjunction.
///
/// OR := λpq.p p q = λ λ 2 2 1
///
/// # Examples
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::booleans::{or, tru, fls};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(or(), tru(), tru()), NOR, 0, false), tru());
/// assert_eq!(beta(app!(or(), tru(), fls()), NOR, 0, false), tru());
/// assert_eq!(beta(app!(or(), fls(), tru()), NOR, 0, false), tru());
/// assert_eq!(beta(app!(or(), fls(), fls()), NOR, 0, false), fls());
/// # }
/// ```
pub fn or() -> Term {
    abs(abs(
        app!(Var(2), Var(2), Var(1))
    ))
}

/// Applied to a Church-encoded boolean it returns its Church-encoded negation.
///
/// NOT := λp.p FALSE TRUE = λ 1 FALSE TRUE
///
/// # Examples
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::booleans::{not, tru, fls};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(not(), tru()), NOR, 0, false), fls());
/// assert_eq!(beta(app!(not(), fls()), NOR, 0, false), tru());
/// # }
/// ```
pub fn not() -> Term {
    abs(
        app!(Var(1), fls(), tru())
    )
}

/// Applied to a Church-encoded boolean it returns its Church-encoded exclusive disjunction.
///
/// XOR := λpq.p (NOT q) q = λ λ 2 (NOT 1) 1
///
/// # Examples
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::booleans::{xor, tru, fls};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(xor(), tru(), tru()), NOR, 0, false), fls());
/// assert_eq!(beta(app!(xor(), tru(), fls()), NOR, 0, false), tru());
/// assert_eq!(beta(app!(xor(), fls(), tru()), NOR, 0, false), tru());
/// assert_eq!(beta(app!(xor(), fls(), fls()), NOR, 0, false), fls());
/// # }
/// ```
pub fn xor() -> Term {
    abs(abs(
        app!(
            Var(2),
            app!(
                Var(1),
                abs(abs(Var(1))),
                abs(abs(Var(2)))
            ),
            Var(1)
        )
    ))
}

/// Applied to a Church-encoded boolean it returns its Church-encoded joint denial.
///
/// NOR := λpq.NOT (OR p q) = λ λ NOT (OR 2 1)
///
/// # Examples
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::booleans::{nor, tru, fls};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(nor(), tru(), tru()), NOR, 0, false), fls());
/// assert_eq!(beta(app!(nor(), tru(), fls()), NOR, 0, false), fls());
/// assert_eq!(beta(app!(nor(), fls(), tru()), NOR, 0, false), fls());
/// assert_eq!(beta(app!(nor(), fls(), fls()), NOR, 0, false), tru());
/// # }
/// ```
pub fn nor() -> Term {
    abs(abs(
        app!(
            Var(2),
            Var(2),
            Var(1),
            abs(abs(Var(1))),
            abs(abs(Var(2)))
        )
    ))
}

/// Applied to two Church-encoded booleans it returns their Church-encoded alternative denial.
///
/// NAND := λpq.NOT (AND p q) = λ λ NOT (AND 2 1)
///
/// # Examples
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::booleans::{nand, tru, fls};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(nand(), tru(), tru()), NOR, 0, false), fls());
/// assert_eq!(beta(app!(nand(), tru(), fls()), NOR, 0, false), tru());
/// assert_eq!(beta(app!(nand(), fls(), tru()), NOR, 0, false), tru());
/// assert_eq!(beta(app!(nand(), fls(), fls()), NOR, 0, false), tru());
/// # }
/// ```
pub fn nand() -> Term {
    abs(abs(
        app!(
            Var(2),
            Var(1),
            Var(2),
            abs(abs(Var(1))),
            abs(abs(Var(2)))
        )
    ))
}

/// Applied to a Church encoded predicate and two terms it returns the first one if the predicate
/// is true or the second one if the predicate is false.
///
/// IF_ELSE := λpab.p a b = λ λ λ 3 2 1
///
/// # Examples
/// ```
/// # #[macro_use] extern crate lambda_calculus;
/// # fn main() {
/// use lambda_calculus::booleans::{if_else, tru, fls};
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::beta;
/// use lambda_calculus::reduction::Order::*;
///
/// assert_eq!(beta(app!(if_else(), tru(), one(), zero()), NOR, 0, false),  one());
/// assert_eq!(beta(app!(if_else(), fls(), one(), zero()), NOR, 0, false), zero());
/// # }
/// ```
pub fn if_else() -> Term {
    abs(abs(abs(
        app!(Var(3), Var(2), Var(1))
    )))
}

impl From<bool> for Term {
    fn from(b: bool) -> Self {
        if b { tru() } else { fls() }
    }
}
<|endoftext|>


<commit_before>use stack::Stack;

/// Represents a builtin function
#[derive(Debug, Clone, PartialEq)]
pub enum Builtin {
    Dot,
    Plus,
    Minus,
    Star,
    Slash,
    Abs,
    And,
    Or,
    Xor,
    Equals,
    LessThan,
    GreaterThan,
    LessEqual,
    GreaterEqual,
    Emit,
    Dup,
    Swap,
    Over,
    Rot,
    Tuck,
    Drop,
}

impl Builtin {
    pub fn call(&self, stack: &mut Stack) {
        macro_rules! stackexpr {
            ( | $($aname:ident : $atype:ty),+ | $value:expr ) => {
                {
                    $(
                        let $aname: $atype = stack.pop();
                    )+
                    stack.push($value)
                }
            }
        }

        use self::Builtin::*;
        match *self {
            Dot => print!("{}", stack.pop::<i32>()),
            Plus => stackexpr!(|n2: i32, n1: i32| n1 + n2),
            Minus => stackexpr!(|n2: i32, n1: i32| n1 - n2),
            Star => stackexpr!(|n2: i32, n1: i32| n1 * n2),
            Slash => stackexpr!(|n2: i32, n1: i32| n1 / n2),
            Abs => stackexpr!(|n: i32| n.abs()),
            And => stackexpr!(|n2: i32, n1: i32| n1 & n2),
            Or => stackexpr!(|n2: i32, n1: i32| n1 | n2),
            Xor => stackexpr!(|n2: i32, n1: i32| n1 ^ n2),
            Equals => stackexpr!(|n2: i32, n1: i32| n1 == n2),
            LessThan => stackexpr!(|n2: i32, n1: i32| n1 < n2),
            GreaterThan => stackexpr!(|n2: i32, n1: i32| n1 > n2),
            LessEqual => stackexpr!(|n2: i32, n1: i32| n1 <= n2),
            GreaterEqual => stackexpr!(|n2: i32, n1: i32| n1 >= n2),
            Emit => print!("{}", stack.pop::<char>()),
            Dup => {
                let n: i32 = stack.peak();
                stack.push(n);
            }
            Swap => {
                let n2: i32 = stack.pop();
                let n1: i32 = stack.pop();
                stack.push(n2);
                stack.push(n1);
            }
            Over => {
                let n2: i32 = stack.pop();
                let n1: i32 = stack.pop();
                stack.push(n1);
                stack.push(n2);
                stack.push(n1);
            }
            Rot => {
                let n3: i32 = stack.pop();
                let n2: i32 = stack.pop();
                let n1: i32 = stack.pop();
                stack.push(n1);
                stack.push(n3);
                stack.push(n2);
            }
            Tuck => {
                let n2: i32 = stack.pop();
                let n1: i32 = stack.pop();
                stack.push(n2);
                stack.push(n1);
                stack.push(n2);
            }
            Drop => {
                stack.pop::<i32>();
            }
        }
    }
}
<commit_msg>Document stackexpr!<commit_after>use stack::Stack;

/// Represents a builtin function
#[derive(Debug, Clone, PartialEq)]
pub enum Builtin {
    Dot,
    Plus,
    Minus,
    Star,
    Slash,
    Abs,
    And,
    Or,
    Xor,
    Equals,
    LessThan,
    GreaterThan,
    LessEqual,
    GreaterEqual,
    Emit,
    Dup,
    Swap,
    Over,
    Rot,
    Tuck,
    Drop,
}

impl Builtin {
    pub fn call(&self, stack: &mut Stack) {
        /// Allows defining Builtin using closure-like syntax
        macro_rules! stackexpr {
            ( | $($aname:ident : $atype:ty),+ | $value:expr ) => {
                {
                    $(
                        let $aname: $atype = stack.pop();
                    )+
                    stack.push($value)
                }
            }
        }

        use self::Builtin::*;
        match *self {
            Dot => print!("{}", stack.pop::<i32>()),
            Plus => stackexpr!(|n2: i32, n1: i32| n1 + n2),
            Minus => stackexpr!(|n2: i32, n1: i32| n1 - n2),
            Star => stackexpr!(|n2: i32, n1: i32| n1 * n2),
            Slash => stackexpr!(|n2: i32, n1: i32| n1 / n2),
            Abs => stackexpr!(|n: i32| n.abs()),
            And => stackexpr!(|n2: i32, n1: i32| n1 & n2),
            Or => stackexpr!(|n2: i32, n1: i32| n1 | n2),
            Xor => stackexpr!(|n2: i32, n1: i32| n1 ^ n2),
            Equals => stackexpr!(|n2: i32, n1: i32| n1 == n2),
            LessThan => stackexpr!(|n2: i32, n1: i32| n1 < n2),
            GreaterThan => stackexpr!(|n2: i32, n1: i32| n1 > n2),
            LessEqual => stackexpr!(|n2: i32, n1: i32| n1 <= n2),
            GreaterEqual => stackexpr!(|n2: i32, n1: i32| n1 >= n2),
            Emit => print!("{}", stack.pop::<char>()),
            Dup => {
                let n: i32 = stack.peak();
                stack.push(n);
            }
            Swap => {
                let n2: i32 = stack.pop();
                let n1: i32 = stack.pop();
                stack.push(n2);
                stack.push(n1);
            }
            Over => {
                let n2: i32 = stack.pop();
                let n1: i32 = stack.pop();
                stack.push(n1);
                stack.push(n2);
                stack.push(n1);
            }
            Rot => {
                let n3: i32 = stack.pop();
                let n2: i32 = stack.pop();
                let n1: i32 = stack.pop();
                stack.push(n1);
                stack.push(n3);
                stack.push(n2);
            }
            Tuck => {
                let n2: i32 = stack.pop();
                let n1: i32 = stack.pop();
                stack.push(n2);
                stack.push(n1);
                stack.push(n2);
            }
            Drop => {
                stack.pop::<i32>();
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Jason White
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::str::FromStr;

/// Coloring of command output.
#[derive(Debug)]
pub enum Coloring {
    Auto,
    Never,
    Always
}

impl FromStr for Coloring {
    type Err = &'static str;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "auto"   => Ok(Coloring::Auto),
            "never"  => Ok(Coloring::Never),
            "always" => Ok(Coloring::Always),
            _        => Err("no match")
        }
    }
}

#[derive(Debug)]
pub enum Edges {
    Explicit,
    Implicit,
    Both
}

impl FromStr for Edges {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "explicit" => Ok(Edges::Explicit),
            "implicit" => Ok(Edges::Implicit),
            "both"     => Ok(Edges::Both),
            _          => Err(())
        }
    }
}
<commit_msg>Use same error type<commit_after>// Copyright (c) 2017 Jason White
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::str::FromStr;

/// Coloring of command output.
#[derive(Debug)]
pub enum Coloring {
    Auto,
    Never,
    Always
}

impl FromStr for Coloring {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "auto"   => Ok(Coloring::Auto),
            "never"  => Ok(Coloring::Never),
            "always" => Ok(Coloring::Always),
            _        => Err(())
        }
    }
}

#[derive(Debug)]
pub enum Edges {
    Explicit,
    Implicit,
    Both
}

impl FromStr for Edges {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "explicit" => Ok(Edges::Explicit),
            "implicit" => Ok(Edges::Implicit),
            "both"     => Ok(Edges::Both),
            _          => Err(())
        }
    }
}
<|endoftext|>


<commit_before>use std::fmt;

use serde::de::Visitor;
use serde::{self, Deserialize};
#[cfg(feature = "dates")]
 use once_cell::sync::OnceCell;

 use super::CellErrorType;

 #[cfg(feature = "dates")]
 static EXCEL_EPOCH: OnceCell<chrono::NaiveDateTime> = OnceCell::new();

/// An enum to represent all different data types that can appear as
/// a value in a worksheet cell
#[derive(Debug, Clone, PartialEq)]
pub enum DataType {
    /// Signed integer
    Int(i64),
    /// Float
    Float(f64),
    /// String
    String(String),
    /// Boolean
    Bool(bool),
    /// Date or Time
    DateTime(f64),
    /// Error
    Error(CellErrorType),
    /// Empty cell
    Empty,
}

impl Default for DataType {
    fn default() -> DataType {
        DataType::Empty
    }
}

impl DataType {
    /// Assess if datatype is empty
    pub fn is_empty(&self) -> bool {
        *self == DataType::Empty
    }
    /// Assess if datatype is a int
    pub fn is_int(&self) -> bool {
        if let DataType::Int(_) = *self {
            true
        } else {
            false
        }
    }
    /// Assess if datatype is a float
    pub fn is_float(&self) -> bool {
        if let DataType::Float(_) = *self {
            true
        } else {
            false
        }
    }
    /// Assess if datatype is a bool
    pub fn is_bool(&self) -> bool {
        if let DataType::Bool(_) = *self {
            true
        } else {
            false
        }
    }
    /// Assess if datatype is a string
    pub fn is_string(&self) -> bool {
        if let DataType::String(_) = *self {
            true
        } else {
            false
        }
    }

    /// Try getting int value
    pub fn get_int(&self) -> Option<i64> {
        if let DataType::Int(v) = self {
            Some(*v)
        } else {
            None
        }
    }
    /// Try getting float value
    pub fn get_float(&self) -> Option<f64> {
        if let DataType::Float(v) = self {
            Some(*v)
        } else {
            None
        }
    }
    /// Try getting bool value
    pub fn get_bool(&self) -> Option<bool> {
        if let DataType::Bool(v) = self {
            Some(*v)
        } else {
            None
        }
    }
    /// Try getting string value
    pub fn get_string(&self) -> Option<&str> {
        if let DataType::String(v) = self {
            Some(&**v)
        } else {
            None
        }
    }

    /// Try converting data type into a date
    #[cfg(feature = "dates")]
    pub fn as_date(&self) -> Option<chrono::NaiveDate> {
        self.as_datetime().map(|dt| dt.date())
    }

    /// Try converting data type into a time
    #[cfg(feature = "dates")]
    pub fn as_time(&self) -> Option<chrono::NaiveTime> {
        self.as_datetime().map(|dt| dt.time())
    }

    /// Try converting data type into a datetime
    #[cfg(feature = "dates")]
    pub fn as_datetime(&self) -> Option<chrono::NaiveDateTime> {
        const MS_MULTIPLIER:f64 = 24f64 * 60f64 * 60f64 * 1e+3f64;

        match self {
            DataType::Int(x) => {
                let days = x - 25569;
                let secs = days * 86400;
                chrono::NaiveDateTime::from_timestamp_opt(secs, 0)
            }
            DataType::Float(f) | DataType::DateTime(f) => {
                let excel_epoch = EXCEL_EPOCH
                     .get_or_init(|| chrono::NaiveDate::from_ymd(1899, 12, 30).and_hms(0, 0, 0));
                let ms = f * MS_MULTIPLIER;
                let excel_duration = chrono::Duration::milliseconds(ms as i64);
                Some(*excel_epoch + excel_duration)
            }
            _ => None,
        }
    }
}

impl PartialEq<str> for DataType {
    fn eq(&self, other: &str) -> bool {
        match *self {
            DataType::String(ref s) if s == other => true,
            _ => false,
        }
    }
}

impl PartialEq<f64> for DataType {
    fn eq(&self, other: &f64) -> bool {
        match *self {
            DataType::Float(ref s) if *s == *other => true,
            _ => false,
        }
    }
}

impl PartialEq<bool> for DataType {
    fn eq(&self, other: &bool) -> bool {
        match *self {
            DataType::Bool(ref s) if *s == *other => true,
            _ => false,
        }
    }
}

impl PartialEq<i64> for DataType {
    fn eq(&self, other: &i64) -> bool {
        match *self {
            DataType::Int(ref s) if *s == *other => true,
            _ => false,
        }
    }
}

impl fmt::Display for DataType {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
        match *self {
            DataType::Int(ref e) => write!(f, "{}", e),
            DataType::Float(ref e) => write!(f, "{}", e),
            DataType::String(ref e) => write!(f, "{}", e),
            DataType::Bool(ref e) => write!(f, "{}", e),
            DataType::DateTime(ref e) => write!(f, "{}", e),
            DataType::Error(ref e) => write!(f, "{}", e),
            DataType::Empty => Ok(()),
        }
    }
}

impl<'de> Deserialize<'de> for DataType {
    #[inline]
    fn deserialize<D>(deserializer: D) -> Result<DataType, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        struct DataTypeVisitor;

        impl<'de> Visitor<'de> for DataTypeVisitor {
            type Value = DataType;

            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
                formatter.write_str("any valid JSON value")
            }

            #[inline]
            fn visit_bool<E>(self, value: bool) -> Result<DataType, E> {
                Ok(DataType::Bool(value))
            }

            #[inline]
            fn visit_i64<E>(self, value: i64) -> Result<DataType, E> {
                Ok(DataType::Int(value))
            }

            #[inline]
            fn visit_u64<E>(self, value: u64) -> Result<DataType, E> {
                Ok(DataType::Int(value as i64))
            }

            #[inline]
            fn visit_f64<E>(self, value: f64) -> Result<DataType, E> {
                Ok(DataType::Float(value))
            }

            #[inline]
            fn visit_str<E>(self, value: &str) -> Result<DataType, E>
            where
                E: serde::de::Error,
            {
                self.visit_string(String::from(value))
            }

            #[inline]
            fn visit_string<E>(self, value: String) -> Result<DataType, E> {
                Ok(DataType::String(value))
            }

            #[inline]
            fn visit_none<E>(self) -> Result<DataType, E> {
                Ok(DataType::Empty)
            }

            #[inline]
            fn visit_some<D>(self, deserializer: D) -> Result<DataType, D::Error>
            where
                D: serde::Deserializer<'de>,
            {
                Deserialize::deserialize(deserializer)
            }

            #[inline]
            fn visit_unit<E>(self) -> Result<DataType, E> {
                Ok(DataType::Empty)
            }
        }

        deserializer.deserialize_any(DataTypeVisitor)
    }
}

macro_rules! define_from {
    ($variant:path, $ty:ty) => {
        impl From<$ty> for DataType {
            fn from(v: $ty) -> Self {
                $variant(v)
            }
        }
    };
}

define_from!(DataType::Int, i64);
define_from!(DataType::Float, f64);
define_from!(DataType::String, String);
define_from!(DataType::Bool, bool);
define_from!(DataType::Error, CellErrorType);

impl<'a> From<&'a str> for DataType {
    fn from(v: &'a str) -> Self {
        DataType::String(String::from(v))
    }
}

impl From<()> for DataType {
    fn from(_: ()) -> Self {
        DataType::Empty
    }
}

impl<T> From<Option<T>> for DataType
where
    DataType: From<T>,
{
    fn from(v: Option<T>) -> Self {
        match v {
            Some(v) => From::from(v),
            None => DataType::Empty,
        }
    }
}

#[cfg(all(test, feature = "dates"))]
mod tests {
    use super::*;

    #[test]
    fn test_dates() {
        use chrono::{Duration, NaiveDate, NaiveDateTime, NaiveTime};

        let unix_epoch = DataType::Float(25569.);
        assert_eq!(
            unix_epoch.as_datetime(),
            Some(NaiveDateTime::new(
                NaiveDate::from_ymd(1970, 1, 1),
                NaiveTime::from_hms(0, 0, 0)
            ))
        );

        // test for https://github.com/tafia/calamine/issues/251
        let unix_epoch_precision = DataType::Float(44484.7916666667);
        assert_eq!(
            unix_epoch_precision.as_datetime(),
            Some(NaiveDateTime::new(
                NaiveDate::from_ymd(2021, 10, 15),
                NaiveTime::from_hms(19, 0, 0)
            ))
        );

        let unix_epoch_15h30m = DataType::Float(25569.645833333333333);
        let chrono_dt = NaiveDateTime::new(
            NaiveDate::from_ymd(1970, 1, 1),
            NaiveTime::from_hms(15, 30, 0),
        );
        let micro = Duration::microseconds(1);
        assert!(unix_epoch_15h30m.as_datetime().unwrap() - chrono_dt < micro);
    }

    #[test]
    fn test_int_dates() {
        use chrono::{NaiveDate, NaiveDateTime, NaiveTime};

        let unix_epoch = DataType::Int(25569);
        assert_eq!(
            unix_epoch.as_datetime(),
            Some(NaiveDateTime::new(
                NaiveDate::from_ymd(1970, 1, 1),
                NaiveTime::from_hms(0, 0, 0)
            ))
        );

        let time = DataType::Int(44060);
        assert_eq!(
            time.as_datetime(),
            Some(NaiveDateTime::new(
                NaiveDate::from_ymd(2020, 8, 17),
                NaiveTime::from_hms(0, 0, 0),
            ))
        );
    }
}
<commit_msg>rustfmt<commit_after>use std::fmt;

#[cfg(feature = "dates")]
use once_cell::sync::OnceCell;
use serde::de::Visitor;
use serde::{self, Deserialize};

use super::CellErrorType;

#[cfg(feature = "dates")]
static EXCEL_EPOCH: OnceCell<chrono::NaiveDateTime> = OnceCell::new();

/// An enum to represent all different data types that can appear as
/// a value in a worksheet cell
#[derive(Debug, Clone, PartialEq)]
pub enum DataType {
    /// Signed integer
    Int(i64),
    /// Float
    Float(f64),
    /// String
    String(String),
    /// Boolean
    Bool(bool),
    /// Date or Time
    DateTime(f64),
    /// Error
    Error(CellErrorType),
    /// Empty cell
    Empty,
}

impl Default for DataType {
    fn default() -> DataType {
        DataType::Empty
    }
}

impl DataType {
    /// Assess if datatype is empty
    pub fn is_empty(&self) -> bool {
        *self == DataType::Empty
    }
    /// Assess if datatype is a int
    pub fn is_int(&self) -> bool {
        if let DataType::Int(_) = *self {
            true
        } else {
            false
        }
    }
    /// Assess if datatype is a float
    pub fn is_float(&self) -> bool {
        if let DataType::Float(_) = *self {
            true
        } else {
            false
        }
    }
    /// Assess if datatype is a bool
    pub fn is_bool(&self) -> bool {
        if let DataType::Bool(_) = *self {
            true
        } else {
            false
        }
    }
    /// Assess if datatype is a string
    pub fn is_string(&self) -> bool {
        if let DataType::String(_) = *self {
            true
        } else {
            false
        }
    }

    /// Try getting int value
    pub fn get_int(&self) -> Option<i64> {
        if let DataType::Int(v) = self {
            Some(*v)
        } else {
            None
        }
    }
    /// Try getting float value
    pub fn get_float(&self) -> Option<f64> {
        if let DataType::Float(v) = self {
            Some(*v)
        } else {
            None
        }
    }
    /// Try getting bool value
    pub fn get_bool(&self) -> Option<bool> {
        if let DataType::Bool(v) = self {
            Some(*v)
        } else {
            None
        }
    }
    /// Try getting string value
    pub fn get_string(&self) -> Option<&str> {
        if let DataType::String(v) = self {
            Some(&**v)
        } else {
            None
        }
    }

    /// Try converting data type into a date
    #[cfg(feature = "dates")]
    pub fn as_date(&self) -> Option<chrono::NaiveDate> {
        self.as_datetime().map(|dt| dt.date())
    }

    /// Try converting data type into a time
    #[cfg(feature = "dates")]
    pub fn as_time(&self) -> Option<chrono::NaiveTime> {
        self.as_datetime().map(|dt| dt.time())
    }

    /// Try converting data type into a datetime
    #[cfg(feature = "dates")]
    pub fn as_datetime(&self) -> Option<chrono::NaiveDateTime> {
        const MS_MULTIPLIER: f64 = 24f64 * 60f64 * 60f64 * 1e+3f64;

        match self {
            DataType::Int(x) => {
                let days = x - 25569;
                let secs = days * 86400;
                chrono::NaiveDateTime::from_timestamp_opt(secs, 0)
            }
            DataType::Float(f) | DataType::DateTime(f) => {
                let excel_epoch = EXCEL_EPOCH
                    .get_or_init(|| chrono::NaiveDate::from_ymd(1899, 12, 30).and_hms(0, 0, 0));
                let ms = f * MS_MULTIPLIER;
                let excel_duration = chrono::Duration::milliseconds(ms as i64);
                Some(*excel_epoch + excel_duration)
            }
            _ => None,
        }
    }
}

impl PartialEq<str> for DataType {
    fn eq(&self, other: &str) -> bool {
        match *self {
            DataType::String(ref s) if s == other => true,
            _ => false,
        }
    }
}

impl PartialEq<f64> for DataType {
    fn eq(&self, other: &f64) -> bool {
        match *self {
            DataType::Float(ref s) if *s == *other => true,
            _ => false,
        }
    }
}

impl PartialEq<bool> for DataType {
    fn eq(&self, other: &bool) -> bool {
        match *self {
            DataType::Bool(ref s) if *s == *other => true,
            _ => false,
        }
    }
}

impl PartialEq<i64> for DataType {
    fn eq(&self, other: &i64) -> bool {
        match *self {
            DataType::Int(ref s) if *s == *other => true,
            _ => false,
        }
    }
}

impl fmt::Display for DataType {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::result::Result<(), fmt::Error> {
        match *self {
            DataType::Int(ref e) => write!(f, "{}", e),
            DataType::Float(ref e) => write!(f, "{}", e),
            DataType::String(ref e) => write!(f, "{}", e),
            DataType::Bool(ref e) => write!(f, "{}", e),
            DataType::DateTime(ref e) => write!(f, "{}", e),
            DataType::Error(ref e) => write!(f, "{}", e),
            DataType::Empty => Ok(()),
        }
    }
}

impl<'de> Deserialize<'de> for DataType {
    #[inline]
    fn deserialize<D>(deserializer: D) -> Result<DataType, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        struct DataTypeVisitor;

        impl<'de> Visitor<'de> for DataTypeVisitor {
            type Value = DataType;

            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
                formatter.write_str("any valid JSON value")
            }

            #[inline]
            fn visit_bool<E>(self, value: bool) -> Result<DataType, E> {
                Ok(DataType::Bool(value))
            }

            #[inline]
            fn visit_i64<E>(self, value: i64) -> Result<DataType, E> {
                Ok(DataType::Int(value))
            }

            #[inline]
            fn visit_u64<E>(self, value: u64) -> Result<DataType, E> {
                Ok(DataType::Int(value as i64))
            }

            #[inline]
            fn visit_f64<E>(self, value: f64) -> Result<DataType, E> {
                Ok(DataType::Float(value))
            }

            #[inline]
            fn visit_str<E>(self, value: &str) -> Result<DataType, E>
            where
                E: serde::de::Error,
            {
                self.visit_string(String::from(value))
            }

            #[inline]
            fn visit_string<E>(self, value: String) -> Result<DataType, E> {
                Ok(DataType::String(value))
            }

            #[inline]
            fn visit_none<E>(self) -> Result<DataType, E> {
                Ok(DataType::Empty)
            }

            #[inline]
            fn visit_some<D>(self, deserializer: D) -> Result<DataType, D::Error>
            where
                D: serde::Deserializer<'de>,
            {
                Deserialize::deserialize(deserializer)
            }

            #[inline]
            fn visit_unit<E>(self) -> Result<DataType, E> {
                Ok(DataType::Empty)
            }
        }

        deserializer.deserialize_any(DataTypeVisitor)
    }
}

macro_rules! define_from {
    ($variant:path, $ty:ty) => {
        impl From<$ty> for DataType {
            fn from(v: $ty) -> Self {
                $variant(v)
            }
        }
    };
}

define_from!(DataType::Int, i64);
define_from!(DataType::Float, f64);
define_from!(DataType::String, String);
define_from!(DataType::Bool, bool);
define_from!(DataType::Error, CellErrorType);

impl<'a> From<&'a str> for DataType {
    fn from(v: &'a str) -> Self {
        DataType::String(String::from(v))
    }
}

impl From<()> for DataType {
    fn from(_: ()) -> Self {
        DataType::Empty
    }
}

impl<T> From<Option<T>> for DataType
where
    DataType: From<T>,
{
    fn from(v: Option<T>) -> Self {
        match v {
            Some(v) => From::from(v),
            None => DataType::Empty,
        }
    }
}

#[cfg(all(test, feature = "dates"))]
mod tests {
    use super::*;

    #[test]
    fn test_dates() {
        use chrono::{Duration, NaiveDate, NaiveDateTime, NaiveTime};

        let unix_epoch = DataType::Float(25569.);
        assert_eq!(
            unix_epoch.as_datetime(),
            Some(NaiveDateTime::new(
                NaiveDate::from_ymd(1970, 1, 1),
                NaiveTime::from_hms(0, 0, 0)
            ))
        );

        // test for https://github.com/tafia/calamine/issues/251
        let unix_epoch_precision = DataType::Float(44484.7916666667);
        assert_eq!(
            unix_epoch_precision.as_datetime(),
            Some(NaiveDateTime::new(
                NaiveDate::from_ymd(2021, 10, 15),
                NaiveTime::from_hms(19, 0, 0)
            ))
        );

        let unix_epoch_15h30m = DataType::Float(25569.645833333333333);
        let chrono_dt = NaiveDateTime::new(
            NaiveDate::from_ymd(1970, 1, 1),
            NaiveTime::from_hms(15, 30, 0),
        );
        let micro = Duration::microseconds(1);
        assert!(unix_epoch_15h30m.as_datetime().unwrap() - chrono_dt < micro);
    }

    #[test]
    fn test_int_dates() {
        use chrono::{NaiveDate, NaiveDateTime, NaiveTime};

        let unix_epoch = DataType::Int(25569);
        assert_eq!(
            unix_epoch.as_datetime(),
            Some(NaiveDateTime::new(
                NaiveDate::from_ymd(1970, 1, 1),
                NaiveTime::from_hms(0, 0, 0)
            ))
        );

        let time = DataType::Int(44060);
        assert_eq!(
            time.as_datetime(),
            Some(NaiveDateTime::new(
                NaiveDate::from_ymd(2020, 8, 17),
                NaiveTime::from_hms(0, 0, 0),
            ))
        );
    }
}
<|endoftext|>