<commit_before>//! [β-reduction](https://en.wikipedia.org/wiki/Beta_normal_form) for lambda `Term`s

use term::*;
use term::Term::*;
use self::Closure::*;
use self::Expression::*;
use std::collections::VecDeque;

#[derive(Debug, PartialEq, Clone)]
enum Closure {
    Depth(usize),
    TermInEnv(Term, Environment)
}

#[derive(Debug, PartialEq)]
enum Expression {
    Evaluation(Closure),
    Application(Box<Expression>, Term, Environment)
}

type Environment = VecDeque<Closure>;

fn whnf(term: Term, mut env: Environment) -> Expression {
    match term {
        Var(i) => match env.remove(i - 1) {
            Some(Depth(i)) => Evaluation(Depth(i)),
            Some(TermInEnv(t, e)) => whnf(t, e),
            None => unreachable!()
        },
        Abs(t) => Evaluation(TermInEnv(Abs(t), env)),
        App(lhs, rhs) => match whnf(*lhs, env.clone()) { // TODO: try to remove this clone()
            Evaluation(TermInEnv(Abs(lhs2), mut env2)) => {
                env2.push_front(TermInEnv(*rhs, env));
                whnf(*lhs2, env2)
            },
            expr => Application(Box::new(expr), *rhs, env)
        }
    }
}

fn reduce(depth: usize, exp: Expression) -> Term {
    match exp {
        Application(lhs, rhs, env) => app(reduce(depth, *lhs), nf(depth, rhs, env)),
        Evaluation(TermInEnv(Abs(term), mut env)) => {
            env.push_front(Depth(depth));
            abs(nf(depth + 1, *term, env))
        },
        Evaluation(TermInEnv(term, _)) => term,
        Evaluation(Depth(i)) => Var(depth - i)
    }
}

fn nf(depth: usize, term: Term, env: Environment) -> Term {
    reduce(depth, whnf(term, env))
}

/// Returns a term reduced to its normal form. Consumes its argument.
///
/// # Example
///
/// ```
/// use lambda_calculus::booleans::{if_else, tru};
/// use lambda_calculus::arithmetic::{zero, one, succ};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(succ().app(zero())), one());
/// assert_eq!(normalize(if_else().app(tru()).app(one()).app(zero())), one());
/// ```
pub fn normalize(term: Term) -> Term {
    nf(0, term, VecDeque::new())
}

impl Term {
    /// Performs a single normal-order β-reduction on `self`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::succ;
    ///
    /// // SUCC := λ λ λ 2 (3 2 1)
    /// let mut succ_one = succ().apply(1.into()).unwrap();
    /// succ_one.beta_once();
    ///
    /// assert_eq!(&*format!("{}", succ_one), "λλ2((λ31)1)");
    /// ```
    pub fn beta_once(&mut self) {
        match *self {
            Var(_) => (),
            Abs(_) => self.unabs_ref_mut().unwrap().beta_once(), // safe
            App(_, _) => {
                let copy = self.clone();
                if let Ok(result) = copy.eval() {
                    // println!("{} reduces to {}", self, result);
                    *self = result
                } else if self.lhs_ref().unwrap().unvar_ref().is_err() {
                    self.lhs_ref_mut().unwrap().beta_once() // safe
                } else {
                    self.rhs_ref_mut().unwrap().beta_once() // safe
                }
            }
        }
    }

    // FIXME: doesn't reduce one last abstraction in PRED ONE
    /// Performs full normal-order β-reduction on `self`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::pred;
    ///
    /// // PRED := λλλ3(λλ1(24))(λ2)(λ1)
    /// let mut pred_one = pred().apply(1.into()).unwrap();
    /// pred_one.beta_full();
    ///
    /// assert_eq!(&*format!("{}", pred_one), "λλ1");
    /// ```
    pub fn beta_full(&mut self) {
        let mut tmp = self.clone();
        self.beta_once();

        while tmp != *self {
            tmp = self.clone();
            self.beta_once();
        }
    }
}

#[cfg(test)]
mod test {
    use arithmetic::{succ, pred, is_zero, one};
    use term::*;
    use term::Term::*;
    use parser::parse;

    #[test]
    fn weak_head_normal_form() {
        // TODO
    }
/*
    #[test]
    fn beta_reduce_tmp() {
        let term = parse(&*"").unwrap();

        term.beta_full();

        assert_eq!(format!("{}", ret), "(λλ1(35))(λ2)")
    }
*/
    #[test]
    fn succ_beta_reduction() {
        //println!("({})({})", succ(), Term::from(1));
        let mut succ_one = succ().apply(1.into()).unwrap();
        succ_one.beta_full();

        assert_eq!(&*format!("{}", succ_one), "λλ2(21)")
    }
/*
    #[test]
    fn pred_beta_reduction() {
        //println!("({})({})", pred(), Term::from(1));
        let mut pred_one = pred().apply(1.into()).unwrap();
        pred_one.beta_full();

        assert_eq!(&*format!("{}", pred_one), "λλ1")
    }
*/
}
<commit_msg>Adjust doc test cases for beta reduction<commit_after>//! [β-reduction](https://en.wikipedia.org/wiki/Beta_normal_form) for lambda `Term`s

use term::*;
use term::Term::*;
use self::Closure::*;
use self::Expression::*;
use std::collections::VecDeque;

#[derive(Debug, PartialEq, Clone)]
enum Closure {
    Depth(usize),
    TermInEnv(Term, Environment)
}

#[derive(Debug, PartialEq)]
enum Expression {
    Evaluation(Closure),
    Application(Box<Expression>, Term, Environment)
}

type Environment = VecDeque<Closure>;

fn whnf(term: Term, mut env: Environment) -> Expression {
    match term {
        Var(i) => match env.remove(i - 1) {
            Some(Depth(i)) => Evaluation(Depth(i)),
            Some(TermInEnv(t, e)) => whnf(t, e),
            None => unreachable!()
        },
        Abs(t) => Evaluation(TermInEnv(Abs(t), env)),
        App(lhs, rhs) => match whnf(*lhs, env.clone()) { // TODO: try to remove this clone()
            Evaluation(TermInEnv(Abs(lhs2), mut env2)) => {
                env2.push_front(TermInEnv(*rhs, env));
                whnf(*lhs2, env2)
            },
            expr => Application(Box::new(expr), *rhs, env)
        }
    }
}

fn reduce(depth: usize, exp: Expression) -> Term {
    match exp {
        Application(lhs, rhs, env) => app(reduce(depth, *lhs), nf(depth, rhs, env)),
        Evaluation(TermInEnv(Abs(term), mut env)) => {
            env.push_front(Depth(depth));
            abs(nf(depth + 1, *term, env))
        },
        Evaluation(TermInEnv(term, _)) => term,
        Evaluation(Depth(i)) => Var(depth - i)
    }
}

fn nf(depth: usize, term: Term, env: Environment) -> Term {
    reduce(depth, whnf(term, env))
}

/// Returns a term reduced to its normal form. Consumes its argument.
///
/// # Example
///
/// ```
/// use lambda_calculus::booleans::{if_else, tru};
/// use lambda_calculus::arithmetic::{zero, one, succ};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(succ().app(zero())), one());
/// assert_eq!(normalize(if_else().app(tru()).app(one()).app(zero())), one());
/// ```
pub fn normalize(term: Term) -> Term {
    nf(0, term, VecDeque::new())
}

impl Term {
    /// Performs a single normal-order β-reduction on `self`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::succ;
    ///
    /// // SUCC := λ λ λ 2 (3 2 1), ONE := λ λ 2 1
    /// let mut succ_one = succ().app(1.into());
    /// succ_one.beta_once();
    ///
    /// assert_eq!(&*format!("{}", succ_one), "λλ2((λλ21)21)");
    /// ```
    pub fn beta_once(&mut self) {
        match *self {
            Var(_) => (),
            Abs(_) => self.unabs_ref_mut().unwrap().beta_once(), // safe
            App(_, _) => {
                let copy = self.clone();
                if let Ok(result) = copy.eval() {
                    // println!("{} reduces to {}", self, result);
                    *self = result
                } else if self.lhs_ref().unwrap().unvar_ref().is_err() {
                    self.lhs_ref_mut().unwrap().beta_once() // safe
                } else {
                    self.rhs_ref_mut().unwrap().beta_once() // safe
                }
            }
        }
    }

    // FIXME: doesn't reduce one last abstraction in PRED ONE
    /// Performs full normal-order β-reduction on `self`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::pred;
    ///
    /// // PRED := λ λ λ 3 (λ λ 1 (2 4)) (λ 2) (λ 1), ONE := λ λ 2 1
    /// let mut pred_one = pred().app(1.into());
    /// pred_one.beta_full();
    ///
    /// assert_eq!(&*format!("{}", pred_one), "λλ1");
    /// ```
    pub fn beta_full(&mut self) {
        let mut tmp = self.clone();
        self.beta_once();

        while tmp != *self {
            tmp = self.clone();
            self.beta_once();
        }
    }
}

#[cfg(test)]
mod test {
    use arithmetic::{succ, pred, is_zero, one};
    use term::*;
    use term::Term::*;
    use parser::parse;

    #[test]
    fn weak_head_normal_form() {
        // TODO
    }
/*
    #[test]
    fn beta_reduce_tmp() {
        let term = parse(&*"").unwrap();

        term.beta_full();

        assert_eq!(format!("{}", ret), "(λλ1(35))(λ2)")
    }
*/
    #[test]
    fn succ_beta_reduction() {
        //println!("({})({})", succ(), Term::from(1));
        let mut succ_one = succ().apply(1.into()).unwrap();
        succ_one.beta_full();

        assert_eq!(&*format!("{}", succ_one), "λλ2(21)")
    }
/*
    #[test]
    fn pred_beta_reduction() {
        //println!("({})({})", pred(), Term::from(1));
        let mut pred_one = pred().apply(1.into()).unwrap();
        pred_one.beta_full();

        assert_eq!(&*format!("{}", pred_one), "λλ1")
    }
*/
}
<|endoftext|>


<commit_before>#![feature(unboxed_closures)]

//! Fern is a runtime-configurable rust logging library.

//! Current features are:
//!
//! - Multiple loggers. You can create as many loggers as you need, and configure them separately.
//! - Configurable output format via closures.
//! - Multiple outputs per logger - current options are to a file, or to stdout/stderr (or any combination of those)
//! - Each output can have a Level configured, so you can output all log messages to a log file, and only have warnings and above show up in the console!
//! - You can also define your own custom logging endpoints - have messages end up where you need them!
//! - Thread-local logger storage. This allows for convenient <level>!() and log!() macros via the fern_macros package.
//!
//! fern is still in development, and most features are experimental. The library is subject to change in non-backwards-compatible ways.
//!
//! This library can only be used while complying to the license terms in the `LICENSE` file.
//!
//! Examples
//! ========
//!
//! Usually, the first thing you want to do is create a logger. In fern, you can do this by first
//! creating a LoggerConfig struct, and then calling `.into_logger()` to turn it into a logger.
//!
//! Here's a logger that simply logs all messages to stdout, and an output.log file, formatting
//! each message with the current date, time, and logging level.
//!
//! ```
//! let logger_config = fern::LoggerConfig {
//!     format: box |msg: &str, level: &fern::Level| {
//!         return format!("[{}][{}] {}", chrono::Local::now().format("%Y-%m-%d][%H:%M:%S"), level, msg);
//!     },
//!     output: vec![fern::OutputConfig::Stdout, fern::OutputConfig::File(Path::new("output.log"))],
//!     level: fern::Level::Debug,
//! };
//! ```
//!
//! In the above example, here's what each part does.
//!
//! `format:` is a closure which all messages will be run through. In this example, use a
//! format!() macro to format the messages using the current time, date, and logging level.
//!
//! Side note: `chrono::Local::now().format("%Y-%m-%d][%H:%M:%S")` is a usage of the chrono time
//! library, and just returns the date in the format described. An output of this might look like
//! `2014-12-01][12:55:04`.
//!
//! With this formatting, the final output of the logger will look something like:
//!
//! ```
//! [2014-12-01][12:55:04][INFO] A message logged at the Level::Info logging level.
//! ```
//!
//! `output:` is a Vec<> of other configurations to send the messages to. In this example, we send
//! them to `OutputConfig::Stdout` and `OutputConfig::File(Path::new(config.log_file.as_slice())`.
//! This will send messages to the console, and to a file called "output.log".
//!
//! `level:` is a `fern::Level` which describes the minimum level that should be allowed to pass
//! through this logger. Setting this to `Level::Debug` allows all messages to be logged, as Debug
//! is the lowest logging level.
//!
//! After creating your logging config, you can turn it into a Logger using `into_logger()`:
//!
//! ```
//! let logger = match logger_config.into_logger() {
//!     Some(v) => v,
//!     Err(e) => panic!("Failed to create logger! Error: {}", e),
//! };
//! ```
//!
//! Eventually, this section will contain a few more examples as well. For now though, the above,
//! along with the LoggerConfig and OutputConfig docs, should be enough to get you started on
//! configuring your logger.
//!
//! #### Logging
//!
//! The next part of logging that you'll probably want to do is actually output some messages.
//!
//! The recommended/easiest way to do this is using the `local` module, along with the
//! `fern_macros` crate.
//!
//! To initialize your logger into thread-local storage for use, you can use
//! `fern::local::set_thread_logger()`
//!
//! ```
//! use std::sync;
//!
//! fern::local::set_thread_logger(sync::Arc::new(logger));
//! ```
//!
//! You can then log anywhere in this thread using the following macros from fern_macros:
//!
//! ```
//! #[feature(phase)]
//!
//! // ...
//!
//! #[phase(plugin)]
//! extern crate fern_macros;
//!
//! // ...
//!
//! info!("A message logged at info level");
//!
//! let var = true;
//! debug!("Debugging message containing a variable value: {}", var);
//!
//! warning!("Something bad happened!");
//!
//! severe!("Something really bad happened!");
//! ```
//!
//! If your application is multi-threaded, you can spread the logger across threads as follows (do
//! this instead of the initiating above):
//!
//! ```
//! use std::sync;
//!
//! let logger_arc = sync::Arc::new(logger); // Create a reference counted logger
//!
//! fern::local::set_thread_logger(logger_arc.clone()); // Initialize the logger for this thread.
//!
//! spawn(move || {
//!     fern::local::set_thread_logger(logger_arc.clone());
//! });
//! ```
//!
//! You can also pass the reference counted logger between functions - if you don't want to
//! type out `sync::Arc<Box<fern::Logger + Sync + Send>>` for all the function declarations, you
//! can use `fern::ArcLogger` instead.

pub use api::{Logger, BoxedLogger, ArcLogger, Level};
pub use config::{LoggerConfig, OutputConfig};
pub use loggers::NullLogger;

pub mod local;
mod api;
mod config;
mod loggers;
<commit_msg>One more little documentation update<commit_after>#![feature(unboxed_closures)]

//! Fern is a runtime-configurable rust logging library.

//! Current features are:
//!
//! - Multiple loggers. You can create as many loggers as you need, and configure them separately.
//! - Configurable output format via closures.
//! - Multiple outputs per logger - current options are to a file, or to stdout/stderr (or any combination of those)
//! - Each output can have a Level configured, so you can output all log messages to a log file, and only have warnings and above show up in the console!
//! - You can also define your own custom logging endpoints - have messages end up where you need them!
//! - Thread-local logger storage. This allows for convenient <level>!() and log!() macros via the fern_macros package.
//!
//! fern is still in development, and most features are experimental. The library is subject to change in non-backwards-compatible ways.
//!
//! This library can only be used while complying to the license terms in the `LICENSE` file.
//!
//! Examples
//! ========
//!
//! Usually, the first thing you want to do is create a logger. In fern, you can do this by first
//! creating a LoggerConfig struct, and then calling `.into_logger()` to turn it into a logger.
//!
//! Here's a logger that simply logs all messages to stdout, and an output.log file, formatting
//! each message with the current date, time, and logging level.
//!
//! ```
//! let logger_config = fern::LoggerConfig {
//!     format: box |msg: &str, level: &fern::Level| {
//!         return format!("[{}][{}] {}", chrono::Local::now().format("%Y-%m-%d][%H:%M:%S"), level, msg);
//!     },
//!     output: vec![fern::OutputConfig::Stdout, fern::OutputConfig::File(Path::new("output.log"))],
//!     level: fern::Level::Debug,
//! };
//! ```
//!
//! In the above example, here's what each part does.
//!
//! `format:` is a closure which all messages will be run through. In this example, use a
//! format!() macro to format the messages using the current time, date, and logging level.
//!
//! Side note: `chrono::Local::now().format("%Y-%m-%d][%H:%M:%S")` is a usage of the chrono time
//! library, and just returns the date in the format described. An output of this might look like
//! `2014-12-01][12:55:04`.
//!
//! With this formatting, the final output of the logger will look something like:
//!
//! ```
//! [2014-12-01][12:55:04][INFO] A message logged at the Level::Info logging level.
//! ```
//!
//! `output:` is a Vec<> of other configurations to send the messages to. In this example, we send
//! them to `OutputConfig::Stdout` and `OutputConfig::File(Path::new(config.log_file.as_slice())`.
//! This will send messages to the console, and to a file called "output.log".
//!
//! `level:` is a `fern::Level` which describes the minimum level that should be allowed to pass
//! through this logger. Setting this to `Level::Debug` allows all messages to be logged, as Debug
//! is the lowest logging level.
//!
//! After creating your logging config, you can turn it into a Logger using `into_logger()`:
//!
//! ```
//! let logger = match logger_config.into_logger() {
//!     Some(v) => v,
//!     Err(e) => panic!("Failed to create logger! Error: {}", e),
//! };
//! ```
//!
//! Eventually, this section will contain a few more examples as well. For now though, the above,
//! along with the LoggerConfig and OutputConfig docs, should be enough to get you started on
//! configuring your logger.
//!
//! #### Logging
//!
//! The next part of logging that you'll probably want to do is actually output some messages.
//!
//! The recommended/easiest way to do this is using the `local` module, along with the
//! `fern_macros` crate.
//!
//! To initialize your logger into thread-local storage for use, you can use
//! `fern::local::set_thread_logger()`
//!
//! ```
//! use std::sync;
//!
//! fern::local::set_thread_logger(sync::Arc::new(logger));
//! ```
//!
//! You can then log anywhere in this thread using the following macros from fern_macros:
//!
//! ```
//! #[feature(phase)]
//!
//! // ...
//!
//! #[phase(plugin)]
//! extern crate fern_macros;
//!
//! // ...
//!
//! info!("A message logged at info level");
//!
//! let var = true;
//! debug!("Debugging message containing a variable value: {}", var);
//!
//! warning!("Something bad happened!");
//!
//! severe!("Something really bad happened!");
//! ```
//!
//! If your application is multi-threaded, you can spread the logger across threads as follows:
//!
//! ```
//! use std::sync;
//!
//! let logger_arc = sync::Arc::new(logger); // Create a reference counted logger
//!
//! fern::local::set_thread_logger(logger_arc.clone()); // Initialize the logger for this thread.
//!
//! spawn(move || {
//!     fern::local::set_thread_logger(logger_arc.clone()); // Initialize the logger for this worker thread.
//!
//!     // Do other calculations, and log more here as well.
//! });
//! ```
//!
//! You can also pass the reference counted logger between functions - if you don't want to
//! type out `sync::Arc<Box<fern::Logger + Sync + Send>>` for all the function declarations, you
//! can use `fern::ArcLogger` instead.

pub use api::{Logger, BoxedLogger, ArcLogger, Level};
pub use config::{LoggerConfig, OutputConfig};
pub use loggers::NullLogger;

pub mod local;
mod api;
mod config;
mod loggers;
<|endoftext|>


<commit_before>//! [β-reduction](https://en.wikipedia.org/wiki/Beta_normal_form) for lambda `Term`s

use term::*;
use term::Term::*;
use self::Order::*;

/// Set to `true` to see all the steps of β-reductions. The default is `false`.
pub const SHOW_REDUCTIONS: bool = false;

/// The [evaluation order](https://en.wikipedia.org/wiki/Lambda_calculus#Reduction_strategies) of
/// β-reductions. `Applicative` order will fail to fully reduce expressions containing functions
/// without a normal form, e.g. the Y combinator (they will expand forever). `CallByName`,
/// `HeadSpine` and `CallByValue` orders don't always normalize fully. The default is `Normal`.
#[derive(Debug, PartialEq)]
pub enum Order {
    /// leftmost outermost
    Normal,
    /// leftmost outermost, but not inside abstractions
    CallByName,
    /// leftmost outermost, but abstractions reduced only in head position
    HeadSpine,
    /// `HeadSpine` + `Normal`
    HybridNormal,
    /// leftmost innermost
    Applicative,
    /// leftmost innermost, but not inside abstractions
    CallByValue,
    /// `CallByValue` + `Applicative`
    HybridApplicative
}

/// Applies two `Term`s with substitution and variable update, consuming the first one in the
/// process.
///
/// # Example
/// ```
/// use lambda_calculus::reduction::apply;
/// use lambda_calculus::parser::parse;
///
/// let lhs    = parse(&"λλ42(λ13)").unwrap();
/// let rhs    = parse(&"λ51").unwrap();
/// let result = parse(&"λ3(λ61)(λ1(λ71))").unwrap();
///
/// assert_eq!(apply(lhs, &rhs), Ok(result));
/// ```
pub fn apply(mut lhs: Term, rhs: &Term) -> Result<Term, Error> {
    _apply(&mut lhs, rhs, 0);

    lhs.unabs()
}

fn _apply(lhs: &mut Term, rhs: &Term, depth: usize) {
    match *lhs {
        Var(i) => if i == depth {
            *lhs = rhs.clone(); // substitute a top-level variable from lhs with rhs
            update_free_variables(lhs, depth - 1, 0); // update indices of free variables from rhs
        } else if i > depth {
            *lhs = Var(i - 1) // decrement a free variable's index
        },
        Abs(_) => {
            _apply(lhs.unabs_ref_mut().unwrap(), rhs, depth + 1)
        },
        App(_, _) => {
            _apply(lhs.lhs_ref_mut().unwrap(), rhs, depth);
            _apply(lhs.rhs_ref_mut().unwrap(), rhs, depth)
        }
    }
}

fn update_free_variables(term: &mut Term, added_depth: usize, own_depth: usize) {
    match *term {
        Var(i) => if i > own_depth {
            *term = Var(i + added_depth)
        },
        Abs(_) => {
            update_free_variables(term.unabs_ref_mut().unwrap(), added_depth, own_depth + 1)
        },
        App(_, _) => {
            update_free_variables(term.lhs_ref_mut().unwrap(), added_depth, own_depth);
            update_free_variables(term.rhs_ref_mut().unwrap(), added_depth, own_depth)
        }
    }
}

impl Term {
    /// Applies `self` to another `Term` and performs substitution, consuming `self` in the process.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::parser::parse;
    ///
    /// let lhs    = parse(&"λλ42(λ13)").unwrap();
    /// let rhs    = parse(&"λ51").unwrap();
    /// let result = parse(&"λ3(λ61)(λ1(λ71))").unwrap();
    ///
    /// assert_eq!(lhs.apply(&rhs), Ok(result));
    /// ```
    pub fn apply(self, rhs: &Term) -> Result<Term, Error> {
        apply(self, rhs)
    }

    /// Reduces an `App`lication by substitution and variable update.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::{app, abs};
    /// use lambda_calculus::term::Term::Var;
    /// use lambda_calculus::arithmetic::zero;
    /// use lambda_calculus::combinators::i;
    ///
    /// assert_eq!(app(i(), zero()).eval(), Ok(zero()));
    /// ```
    pub fn eval(self) -> Result<Term, Error> {
        let (lhs, rhs) = try!(self.unapp());

        apply(lhs, &rhs)
    }

    /// Performs a single β-reduction on `self` with the specified evaluation `Order`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::succ;
    /// use lambda_calculus::reduction::Order;
    ///
    /// let mut succ_one = succ().app(1.into());
    /// succ_one.beta_once(&Order::Normal);
    ///
    /// assert_eq!(succ_one, succ().apply(&1.into()).unwrap());
    /// ```
    pub fn beta_once(&mut self, order: &Order) {
        self.beta_once_indicative(order);
    }

    fn beta_once_indicative(&mut self, order: &Order) -> bool {
        match *order {
            Normal       => self._beta_once_normal(0),
            CallByName   => self._beta_once_call_by_name(),
            HeadSpine    => self._beta_once_head_spine(0, true),
            Applicative  => self._beta_once_applicative(0),
            CallByValue  => self._beta_once_call_by_value(),
            HybridNormal => {
                self._beta_once_head_spine(0, true);
                self._beta_once_normal(0)
            },
            HybridApplicative => {
                self._beta_once_call_by_value();
                self._beta_once_applicative(0)
            }
        }
    }

    fn eval_with_info(&mut self, depth: u32) {
        if SHOW_REDUCTIONS { print!("    {} reduces to ", show_precedence(self, 0, depth)) };
        let copy = self.clone();
        *self = copy.eval().unwrap();
        if SHOW_REDUCTIONS { println!("{}", show_precedence(self, 0, depth)) }
    }

    // the return value indicates if reduction was performed
    fn _beta_once_normal(&mut self, depth: u32) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => self.unabs_ref_mut().unwrap()._beta_once_normal(depth + 1),
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    self.eval_with_info(depth);
                    true
                } else {
                    self.lhs_ref_mut().unwrap()._beta_once_normal(depth) ||
                    self.rhs_ref_mut().unwrap()._beta_once_normal(depth)
                }
            }
        }
    }

    // the return value indicates if reduction was performed
    fn _beta_once_call_by_name(&mut self) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => false,
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    self.eval_with_info(0);
                    true
                } else {
                    self.lhs_ref_mut().unwrap()._beta_once_call_by_name()
                }
            }
        }
    }

    // the return value indicates if reduction was performed
    fn _beta_once_head_spine(&mut self, depth: u32, is_head: bool) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => if is_head {
                self.unabs_ref_mut().unwrap()._beta_once_head_spine(depth + 1, is_head)
            } else {
                false
            },
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    self.eval_with_info(0);
                    true
                } else {
                    self.lhs_ref_mut().unwrap()._beta_once_head_spine(depth, is_head) ||
                    self.rhs_ref_mut().unwrap()._beta_once_head_spine(depth, false)
                }
            }
        }
    }

    // the return value indicates if reduction was performed
    fn _beta_once_applicative(&mut self, depth: u32) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => self.unabs_ref_mut().unwrap()._beta_once_applicative(depth + 1),
            App(_, _) => {
                if  self.lhs_ref().unwrap().unabs_ref().is_ok() &&
                   !self.rhs_ref().unwrap().is_beta_reducible(&Applicative)
                {
                    self.eval_with_info(depth);
                    true
                } else {
                    self.lhs_ref_mut().unwrap()._beta_once_applicative(depth) ||
                    self.rhs_ref_mut().unwrap()._beta_once_applicative(depth)
                }
            }
        }
    }

    // the return value indicates if reduction was performed
    fn _beta_once_call_by_value(&mut self) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => false,
            App(_, _) => {
                if  self.lhs_ref().unwrap().unabs_ref().is_ok() &&
                   !self.rhs_ref().unwrap().is_beta_reducible(&CallByValue)
                {
                    self.eval_with_info(0);
                    true
                } else {
                    self.lhs_ref_mut().unwrap()._beta_once_call_by_value() ||
                    self.rhs_ref_mut().unwrap()._beta_once_call_by_value()
                }
            }
        }
    }

    /// Checks whether `self` is β-reducible under the specified evaluation `Order`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::{succ, zero};
    /// use lambda_calculus::reduction::Order;
    ///
    /// let reducible     = succ().app(1.into());
    /// let not_reducible = zero();
    ///
    /// assert!(reducible.is_beta_reducible(&Order::Normal));
    /// assert!(!not_reducible.is_beta_reducible(&Order::Normal));
    /// ```
    pub fn is_beta_reducible(&self, order: &Order) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => match *order {
                Normal | Applicative => self.unabs_ref().unwrap().is_beta_reducible(order),
                _ => false
            },
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    true
                } else {
                    self.lhs_ref().unwrap().is_beta_reducible(order) ||
                    self.rhs_ref().unwrap().is_beta_reducible(order)
                }
            }
        }
    }

    /// Performs full β-reduction on `self` using the specified evaluation `Order`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::pred;
    /// use lambda_calculus::reduction::Order;
    ///
    /// let mut pred_one = pred().app(1.into());
    /// pred_one.beta_full(&Order::Normal);
    ///
    /// assert_eq!(pred_one, 0.into());
    /// ```
    pub fn beta_full(&mut self, order: &Order) {
        loop {
            if SHOW_REDUCTIONS { println!("reducing {}", self) }
            if !self.beta_once_indicative(order) { break }
        }
        if SHOW_REDUCTIONS { println!("    doesn't reduce") }
    }
}

/// Performs full β-reduction on a `Term` using the specified evaluation `Order`, consuming its
/// argument in the process.
///
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::pred;
/// use lambda_calculus::reduction::{beta_full, Order};
///
/// let pred_one = pred().app(1.into());
///
/// assert_eq!(beta_full(pred_one, &Order::Normal), 0.into());
/// ```
pub fn beta_full(mut term: Term, order: &Order) -> Term {
    term.beta_full(order);
    term
}

/// Performs a single β-reduction on a `Term` using the specified evaluation `Order`, consuming its
/// argument in the process.
///
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::succ;
/// use lambda_calculus::reduction::{beta_once, Order};
///
/// let succ_one = succ().app(1.into());
///
/// assert_eq!(beta_once(succ_one, &Order::Normal), succ().apply(&1.into()).unwrap());
/// ```
pub fn beta_once(mut term: Term, order: &Order) -> Term {
    term.beta_once(order);
    term
}

#[cfg(test)]
mod test {
    use super::*;
    use parser::parse;
    use combinators::{i, y};

    #[test]
    fn normal_order() {
        let reduces_instantly = parse(&"(λλ1)((λλλ((32)1))(λλ2))").unwrap();
        assert_eq!(beta_full(reduces_instantly.clone(), &Normal),
                   beta_once(reduces_instantly, &Normal));

        let should_reduce = parse(&"(λ2)((λ111)(λ111))").unwrap();
        assert_eq!(beta_full(should_reduce, &Normal), Var(1))
    }

    #[test]
    fn call_by_name_order() {
        let mut expr = app(abs(app(i(), Var(1))), app(i(), i()));
        expr.beta_once(&CallByName);
        assert_eq!(expr, app(i(), app(i(), i())));
        expr.beta_once(&CallByName);
        assert_eq!(expr, app(i(), i()));
        expr.beta_once(&CallByName);
        assert_eq!(expr, i());
    }

    #[test]
    fn applicative_order() {
        let expr = parse(&"λ1(((λλλ1)1)((λλ21)1))").unwrap();
        assert_eq!(&format!("{}", beta_once(expr, &Applicative)), "λ1((λλ1)((λλ21)1))");

        let expands = parse(&"(λ2)((λ111)(λ111))").unwrap();
        assert_eq!(&format!("{}", beta_once(expands, &Applicative)), "(λ2)((λ111)(λ111)(λ111))")
    }

    #[test]
    fn call_by_value_order() {
        let mut expr = app(abs(app(i(), Var(1))), app(i(), i()));
        expr.beta_once(&CallByValue);
        assert_eq!(expr, app(abs(app(i(), Var(1))), i()));
        expr.beta_once(&CallByValue);
        assert_eq!(expr, app(i(), i()));
        expr.beta_once(&CallByValue);
        assert_eq!(expr, i());
    }

    #[test]
    fn reducibility() {
        assert!(y().is_beta_reducible(&Normal));
        assert!(y().is_beta_reducible(&Applicative));
        assert!(!y().is_beta_reducible(&CallByName));
        assert!(!y().is_beta_reducible(&CallByValue));
    }
}
<commit_msg>a separate function for HA<commit_after>//! [β-reduction](https://en.wikipedia.org/wiki/Beta_normal_form) for lambda `Term`s

use term::*;
use term::Term::*;
use self::Order::*;

/// Set to `true` to see all the steps of β-reductions. The default is `false`.
pub const SHOW_REDUCTIONS: bool = false;

/// The [evaluation order](https://en.wikipedia.org/wiki/Lambda_calculus#Reduction_strategies) of
/// β-reductions. `Applicative` order will fail to fully reduce expressions containing functions
/// without a normal form, e.g. the Y combinator (they will expand forever). `CallByName`,
/// `HeadSpine` and `CallByValue` orders don't always normalize fully. The default is `Normal`.
#[derive(Debug, PartialEq)]
pub enum Order {
    /// leftmost outermost
    Normal,
    /// leftmost outermost, but not inside abstractions
    CallByName,
    /// leftmost outermost, but abstractions reduced only in head position
    HeadSpine,
    /// `HeadSpine` + `Normal`
    HybridNormal,
    /// leftmost innermost
    Applicative,
    /// leftmost innermost, but not inside abstractions
    CallByValue,
    /// `CallByValue` + `Applicative`
    HybridApplicative
}

/// Applies two `Term`s with substitution and variable update, consuming the first one in the
/// process.
///
/// # Example
/// ```
/// use lambda_calculus::reduction::apply;
/// use lambda_calculus::parser::parse;
///
/// let lhs    = parse(&"λλ42(λ13)").unwrap();
/// let rhs    = parse(&"λ51").unwrap();
/// let result = parse(&"λ3(λ61)(λ1(λ71))").unwrap();
///
/// assert_eq!(apply(lhs, &rhs), Ok(result));
/// ```
pub fn apply(mut lhs: Term, rhs: &Term) -> Result<Term, Error> {
    _apply(&mut lhs, rhs, 0);

    lhs.unabs()
}

fn _apply(lhs: &mut Term, rhs: &Term, depth: usize) {
    match *lhs {
        Var(i) => if i == depth {
            *lhs = rhs.clone(); // substitute a top-level variable from lhs with rhs
            update_free_variables(lhs, depth - 1, 0); // update indices of free variables from rhs
        } else if i > depth {
            *lhs = Var(i - 1) // decrement a free variable's index
        },
        Abs(_) => {
            _apply(lhs.unabs_ref_mut().unwrap(), rhs, depth + 1)
        },
        App(_, _) => {
            _apply(lhs.lhs_ref_mut().unwrap(), rhs, depth);
            _apply(lhs.rhs_ref_mut().unwrap(), rhs, depth)
        }
    }
}

fn update_free_variables(term: &mut Term, added_depth: usize, own_depth: usize) {
    match *term {
        Var(i) => if i > own_depth {
            *term = Var(i + added_depth)
        },
        Abs(_) => {
            update_free_variables(term.unabs_ref_mut().unwrap(), added_depth, own_depth + 1)
        },
        App(_, _) => {
            update_free_variables(term.lhs_ref_mut().unwrap(), added_depth, own_depth);
            update_free_variables(term.rhs_ref_mut().unwrap(), added_depth, own_depth)
        }
    }
}

impl Term {
    /// Applies `self` to another `Term` and performs substitution, consuming `self` in the process.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::parser::parse;
    ///
    /// let lhs    = parse(&"λλ42(λ13)").unwrap();
    /// let rhs    = parse(&"λ51").unwrap();
    /// let result = parse(&"λ3(λ61)(λ1(λ71))").unwrap();
    ///
    /// assert_eq!(lhs.apply(&rhs), Ok(result));
    /// ```
    pub fn apply(self, rhs: &Term) -> Result<Term, Error> {
        apply(self, rhs)
    }

    /// Reduces an `App`lication by substitution and variable update.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::{app, abs};
    /// use lambda_calculus::term::Term::Var;
    /// use lambda_calculus::arithmetic::zero;
    /// use lambda_calculus::combinators::i;
    ///
    /// assert_eq!(app(i(), zero()).eval(), Ok(zero()));
    /// ```
    pub fn eval(self) -> Result<Term, Error> {
        let (lhs, rhs) = try!(self.unapp());

        apply(lhs, &rhs)
    }

    /// Performs a single β-reduction on `self` with the specified evaluation `Order`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::succ;
    /// use lambda_calculus::reduction::Order;
    ///
    /// let mut succ_one = succ().app(1.into());
    /// succ_one.beta_once(&Order::Normal);
    ///
    /// assert_eq!(succ_one, succ().apply(&1.into()).unwrap());
    /// ```
    pub fn beta_once(&mut self, order: &Order) {
        self.beta_once_indicative(order);
    }

    fn beta_once_indicative(&mut self, order: &Order) -> bool {
        match *order {
            Normal       => self._beta_once_normal(0),
            CallByName   => self._beta_once_call_by_name(),
            HeadSpine    => self._beta_once_head_spine(0, true),
            Applicative  => self._beta_once_applicative(0),
            CallByValue  => self._beta_once_call_by_value(),
            HybridNormal => {
                self._beta_once_head_spine(0, true);
                self._beta_once_normal(0)
            },
            HybridApplicative => self._beta_once_hybrid_applicative(0)
        }
    }

    fn eval_with_info(&mut self, depth: u32) {
        if SHOW_REDUCTIONS { print!("    {} reduces to ", show_precedence(self, 0, depth)) };
        let copy = self.clone();
        *self = copy.eval().unwrap();
        if SHOW_REDUCTIONS { println!("{}", show_precedence(self, 0, depth)) }
    }

    // the return value indicates if reduction was performed
    fn _beta_once_normal(&mut self, depth: u32) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => self.unabs_ref_mut().unwrap()._beta_once_normal(depth + 1),
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    self.eval_with_info(depth);
                    true
                } else {
                    self.lhs_ref_mut().unwrap()._beta_once_normal(depth) ||
                    self.rhs_ref_mut().unwrap()._beta_once_normal(depth)
                }
            }
        }
    }

    // the return value indicates if reduction was performed
    fn _beta_once_call_by_name(&mut self) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => false,
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    self.eval_with_info(0);
                    true
                } else {
                    self.lhs_ref_mut().unwrap()._beta_once_call_by_name()
                }
            }
        }
    }

    // the return value indicates if reduction was performed
    fn _beta_once_head_spine(&mut self, depth: u32, is_head: bool) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => if is_head {
                self.unabs_ref_mut().unwrap()._beta_once_head_spine(depth + 1, is_head)
            } else {
                false
            },
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    self.eval_with_info(0);
                    true
                } else {
                    self.lhs_ref_mut().unwrap()._beta_once_head_spine(depth, is_head) ||
                    self.rhs_ref_mut().unwrap()._beta_once_head_spine(depth, false)
                }
            }
        }
    }

    // the return value indicates if reduction was performed
    fn _beta_once_applicative(&mut self, depth: u32) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => self.unabs_ref_mut().unwrap()._beta_once_applicative(depth + 1),
            App(_, _) => {
                if  self.lhs_ref().unwrap().unabs_ref().is_ok() &&
                   !self.rhs_ref().unwrap().is_beta_reducible(&Applicative)
                {
                    self.eval_with_info(depth);
                    true
                } else {
                    self.lhs_ref_mut().unwrap()._beta_once_applicative(depth) ||
                    self.rhs_ref_mut().unwrap()._beta_once_applicative(depth)
                }
            }
        }
    }

    // the return value indicates if reduction was performed
    fn _beta_once_call_by_value(&mut self) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => false,
            App(_, _) => {
                if  self.lhs_ref().unwrap().unabs_ref().is_ok() &&
                   !self.rhs_ref().unwrap().is_beta_reducible(&CallByValue)
                {
                    self.eval_with_info(0);
                    true
                } else {
                    self.lhs_ref_mut().unwrap()._beta_once_call_by_value() ||
                    self.rhs_ref_mut().unwrap()._beta_once_call_by_value()
                }
            }
        }
    }

    // the return value indicates if reduction was performed
    fn _beta_once_hybrid_applicative(&mut self, depth: u32) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => self.unabs_ref_mut().unwrap()._beta_once_hybrid_applicative(depth + 1),
            App(_, _) => {
                if  self.lhs_ref().unwrap().unabs_ref().is_ok() &&
                   !self.rhs_ref().unwrap().is_beta_reducible(&HybridApplicative)
                {
                    self.eval_with_info(0);
                    true
                } else {
                    self.lhs_ref_mut().unwrap()._beta_once_call_by_value() || // TODO: pass depth
                    self.rhs_ref_mut().unwrap()._beta_once_hybrid_applicative(depth)
                }
            }
        }
    }

    /// Checks whether `self` is β-reducible under the specified evaluation `Order`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::{succ, zero};
    /// use lambda_calculus::reduction::Order;
    ///
    /// let reducible     = succ().app(1.into());
    /// let not_reducible = zero();
    ///
    /// assert!(reducible.is_beta_reducible(&Order::Normal));
    /// assert!(!not_reducible.is_beta_reducible(&Order::Normal));
    /// ```
    pub fn is_beta_reducible(&self, order: &Order) -> bool {
        match *self {
            Var(_) => false,
            Abs(_) => match *order {
                Normal | Applicative => self.unabs_ref().unwrap().is_beta_reducible(order),
                _ => false
            },
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    true
                } else {
                    self.lhs_ref().unwrap().is_beta_reducible(order) ||
                    self.rhs_ref().unwrap().is_beta_reducible(order)
                }
            }
        }
    }

    /// Performs full β-reduction on `self` using the specified evaluation `Order`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::pred;
    /// use lambda_calculus::reduction::Order;
    ///
    /// let mut pred_one = pred().app(1.into());
    /// pred_one.beta_full(&Order::Normal);
    ///
    /// assert_eq!(pred_one, 0.into());
    /// ```
    pub fn beta_full(&mut self, order: &Order) {
        loop {
            if SHOW_REDUCTIONS { println!("reducing {}", self) }
            if !self.beta_once_indicative(order) { break }
        }
        if SHOW_REDUCTIONS { println!("    doesn't reduce") }
    }
}

/// Performs full β-reduction on a `Term` using the specified evaluation `Order`, consuming its
/// argument in the process.
///
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::pred;
/// use lambda_calculus::reduction::{beta_full, Order};
///
/// let pred_one = pred().app(1.into());
///
/// assert_eq!(beta_full(pred_one, &Order::Normal), 0.into());
/// ```
pub fn beta_full(mut term: Term, order: &Order) -> Term {
    term.beta_full(order);
    term
}

/// Performs a single β-reduction on a `Term` using the specified evaluation `Order`, consuming its
/// argument in the process.
///
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::succ;
/// use lambda_calculus::reduction::{beta_once, Order};
///
/// let succ_one = succ().app(1.into());
///
/// assert_eq!(beta_once(succ_one, &Order::Normal), succ().apply(&1.into()).unwrap());
/// ```
pub fn beta_once(mut term: Term, order: &Order) -> Term {
    term.beta_once(order);
    term
}

#[cfg(test)]
mod test {
    use super::*;
    use parser::parse;
    use combinators::{i, y};

    #[test]
    fn normal_order() {
        let reduces_instantly = parse(&"(λλ1)((λλλ((32)1))(λλ2))").unwrap();
        assert_eq!(beta_full(reduces_instantly.clone(), &Normal),
                   beta_once(reduces_instantly, &Normal));

        let should_reduce = parse(&"(λ2)((λ111)(λ111))").unwrap();
        assert_eq!(beta_full(should_reduce, &Normal), Var(1))
    }

    #[test]
    fn call_by_name_order() {
        let mut expr = app(abs(app(i(), Var(1))), app(i(), i()));
        expr.beta_once(&CallByName);
        assert_eq!(expr, app(i(), app(i(), i())));
        expr.beta_once(&CallByName);
        assert_eq!(expr, app(i(), i()));
        expr.beta_once(&CallByName);
        assert_eq!(expr, i());
    }

    #[test]
    fn applicative_order() {
        let expr = parse(&"λ1(((λλλ1)1)((λλ21)1))").unwrap();
        assert_eq!(&format!("{}", beta_once(expr, &Applicative)), "λ1((λλ1)((λλ21)1))");

        let expands = parse(&"(λ2)((λ111)(λ111))").unwrap();
        assert_eq!(&format!("{}", beta_once(expands, &Applicative)), "(λ2)((λ111)(λ111)(λ111))")
    }

    #[test]
    fn call_by_value_order() {
        let mut expr = app(abs(app(i(), Var(1))), app(i(), i()));
        expr.beta_once(&CallByValue);
        assert_eq!(expr, app(abs(app(i(), Var(1))), i()));
        expr.beta_once(&CallByValue);
        assert_eq!(expr, app(i(), i()));
        expr.beta_once(&CallByValue);
        assert_eq!(expr, i());
    }

    #[test]
    fn reducibility() {
        assert!(y().is_beta_reducible(&Normal));
        assert!(y().is_beta_reducible(&Applicative));
        assert!(!y().is_beta_reducible(&CallByName));
        assert!(!y().is_beta_reducible(&CallByValue));
    }
}
<|endoftext|>


<commit_before>//! Repository references.

use object_id::ObjectId;
use repository::Repository;
use reference_collection::ReferenceCollection;
use std::io::fs::File;
use std::io::fs::readdir;
use std::io::IoError;

static LOCAL_BRANCH_PREFIX:           &'static str = "refs/heads/";
static REMOTE_TRACKING_BRANCH_PREFIX: &'static str = "refs/remotes/";
static TAG_PREFIX:                    &'static str = "refs/tags/";
static NOTE_PREFIX:                   &'static str = "refs/notes/";

#[deriving(PartialEq, Show, Clone)]
pub struct Reference {
    pub canonical_name: String,
    pub target_identifier: ObjectId,
    pub remote_name: Option<String>,
}

pub fn find(repository: &Repository) -> Result<ReferenceCollection, IoError> {
    let local_files = try!(readdir(&repository.path.join(LOCAL_BRANCH_PREFIX)));

    let local_references: Vec<Option<Reference>> = local_files.iter().map(|entry| {
        if entry.is_file() {
            Some(Reference {
                canonical_name: entry.filename_str().unwrap().into_string(),
                target_identifier: ObjectId::from_string(File::open(entry).read_to_string().unwrap().as_slice()), // TODO: TRIM!
                remote_name: None
            })
        } else {
            None
        }
    }).collect();

    Ok(ReferenceCollection {
        head: None,
        local_references: Vec::new(),
        remote_references: Vec::new(),
    })
}<commit_msg>Load HEAD reference<commit_after>//! Repository references.

use object_id::ObjectId;
use repository::Repository;
use reference_collection::ReferenceCollection;
use std::io::fs::File;
use std::io::fs::readdir;
use std::io::IoError;
use error::CorruptRepository;

static LOCAL_BRANCH_PREFIX:           &'static str = "refs/heads/";
static REMOTE_TRACKING_BRANCH_PREFIX: &'static str = "refs/remotes/";
static TAG_PREFIX:                    &'static str = "refs/tags/";
static NOTE_PREFIX:                   &'static str = "refs/notes/";

#[deriving(PartialEq, Show, Clone)]
pub struct Reference {
    pub canonical_name: String,
    pub target_identifier: ObjectId,
    pub remote_name: Option<String>,
}

pub fn find(repository: &Repository) -> Result<ReferenceCollection, IoError> {
    let local_files = try!(readdir(&repository.path.join(LOCAL_BRANCH_PREFIX)));

    let local_references: Vec<Reference> = local_files.iter().filter(|e| e.is_file()).map(|entry| {
        Reference {
            canonical_name: entry.filename_str().unwrap().into_string(),
            target_identifier: ObjectId::from_string(File::open(entry).read_to_string().unwrap().as_slice()), // TODO: TRIM!
            remote_name: None
        }
    }).collect();

    let head_contents = try!(File::open(&repository.path.join("HEAD")).read_to_string());
    let head_name = head_contents.replace("ref: refs/heads/", "").as_slice().trim_right().into_string();
    let head = local_references.move_iter().find(|r| r.canonical_name == head_name);

    Ok(ReferenceCollection {
        head: head,
        local_references: Vec::new(),
        remote_references: Vec::new(),
    })
}<|endoftext|>


<commit_before>#[deny(missing_docs)]

extern crate input;
extern crate piston_window;
extern crate rustc_serialize;
extern crate viewport;

mod builder;
mod rebind;

use input::{Input, Button, Motion};
use piston_window::Size;
use std::collections::HashMap;
use std::default::Default;
use std::hash::Hash;
use viewport::Viewport;

pub use rebind::InputRebind;
pub use builder::InputTranslatorBuilder;

/// Represents a logical action to be bound to a particular button press, e.g.
/// jump, attack, or move forward
pub trait Action: Copy + PartialEq + Eq + Hash { }

/// A translated action.
#[derive(Debug, Copy, Clone)]
pub enum Translated<A: Action> {
    /// A keypress event which was bound to an action
    Press(A),

    /// A key release event which was bound to an action
    Release(A),

    /// A translated mouse motion. The logical origin of a translated MouseCursor event
    /// is in the top left corner of the window, and the logical scroll is non-natural.
    /// Relative events are unchanged for now.
    Move(Motion)
}

/// An object which translates piston::input::Input events into input_map::Translated<A> events
#[derive(Clone)]
pub struct InputTranslator<A: Action> {
    keymap: KeyMap<A>,
    mouse_translator: MouseTranslator
}

impl<A: Action> InputTranslator<A> {

    /// Creates an empty InputTranslator.
    pub fn new(size: Size) -> Self {
        InputTranslator {
            keymap: KeyMap::new(),
            mouse_translator: MouseTranslator::new(size)
        }
    }

    /// Translate an Input into a Translated<A> event
    pub fn translate(&self, input: &Input) -> Option<Translated<A>> {
        macro_rules! translate_button(($but_state:ident, $but_var:ident) => (
            match self.keymap.translate($but_var) {
                Some(act) => Some(Translated::$but_state(act)),
                None => None
            });
        );

        match input {
            &Input::Press(button) => translate_button!(Press, button),
            &Input::Release(button) => translate_button!(Release, button),
            &Input::Move(motion) =>
                Some(Translated::Move(self.mouse_translator.translate(motion))),
            _ => None
        }
    }

    pub fn add_binding(&mut self, but: Button, act: A) {
        self.keymap.add_mapping(but, act);
    }

    /// Re-set the mouse bounds size used for calculating mouse events
    pub fn set_size(&mut self, size: Size) {
        self.mouse_translator.viewport_size = size
    }

    /// Re-set the mouse bounds size from a viewport
    pub fn set_size_from_viewport(&mut self, vp: Viewport) {
        self.set_size(Size::from(vp.draw_size));
    }
}

#[derive(Clone)]
struct MouseTranslator {
    pub x_axis_motion_inverted: bool,
    pub y_axis_motion_inverted: bool,
    pub x_axis_scroll_inverted: bool,
    pub y_axis_scroll_inverted: bool,
    pub viewport_size: Size
}

impl MouseTranslator {
    fn new(size: Size) -> Self {
        MouseTranslator {
            x_axis_motion_inverted: false,
            y_axis_motion_inverted: false,
            x_axis_scroll_inverted: false,
            y_axis_scroll_inverted: false,
            viewport_size: size
        }
    }

    fn translate(&self, motion: Motion) -> Motion {
        match motion {
            Motion::MouseCursor(x, y) => {
                let (sw, sh) = {
                    let Size {width, height} = self.viewport_size;
                    (width as f64, height as f64)
                };

                let cx = if self.x_axis_motion_inverted { sw - x } else { x };
                let cy = if self.y_axis_motion_inverted { sh - y } else { y };

                Motion::MouseCursor(cx, cy)
            },
            Motion::MouseScroll(x, y) => {
                let mx = if self.x_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                let my = if self.y_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                Motion::MouseScroll(x * mx, y * my)
            },
            relative => relative
        }
    }
}

#[derive(Clone, Debug)]
struct KeyMap<A: Action> {
    btn_map: HashMap<ButtonTuple, A>
}

impl<A: Action> KeyMap<A> {
    fn new() -> Self {
        KeyMap {
            btn_map: HashMap::new()
        }
    }

    fn add_mapping(&mut self, button: Button, action: A) {
        let mut bt = self.get_bindings_for_action(action).unwrap_or(ButtonTuple::new());
        let bt = if bt.insert_inplace(button) {bt} else {ButtonTuple::new()};
        self.btn_map.insert(bt, action);
    }

    fn get_bindings_for_action(&self, action: A) -> Option<ButtonTuple> {
        self.btn_map.iter().find(|&(_, &a)| a == action).map(|(&bt, _)| bt)
    }

    #[allow(dead_code)]
    fn get_ref_bindings_for_action(&self, action: A) -> Option<&ButtonTuple> {
        self.btn_map.iter().find(|&(_, &a)| a == action).map(|(bt, _)| bt)
    }

    #[cfg(unimplemented)] // This gives a compile error
    fn get_ref_bindings_for_action_mut(&mut self, action: A) -> Option<&mut ButtonTuple> {
        self.btn_map.iter_mut().find(|&(_, &mut a)| a == action).as_mut().map(|&mut (bt, _)| bt)
    }

    fn translate(&self, button: Button) -> Option<A> {
        self.btn_map.iter().find(|&(&bt, _)| bt.contains(button)).map(|(_, &a)| a)
    }
}

/// A three-element tuple of Option<Button>. Used as the key of an InputTranslator
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ButtonTuple(pub Option<Button>, pub Option<Button>, pub Option<Button>);

impl ButtonTuple {
    fn new() -> Self { Default::default() }

    fn contains(&self, btn: Button) -> bool {
        let sbtn = Some(btn);
        self.0 == sbtn || self.1 == sbtn || self.2 == sbtn
    }

    #[allow(dead_code)]
    fn remove_inplace(&mut self, btn: Button) {
        let sbtn = Some(btn);
        if self.0 == sbtn {self.0 = None}
        if self.1 == sbtn {self.1 = None}
        if self.2 == sbtn {self.2 = None}
    }

    #[allow(dead_code)]
    fn replace_inplace(&mut self, btn_idx: u32, btn: Button) -> bool {
        match btn_idx {
            0 => {self.0 = Some(btn); true},
            1 => {self.1 = Some(btn); true},
            2 => {self.2 = Some(btn); true},
            _ => false
        }
    }

    fn insert_inplace(&mut self, btn: Button) -> bool {
        match self {
            &mut ButtonTuple(a, b, c) if a.is_none() => {*self = ButtonTuple(Some(btn), b, c); true},
            &mut ButtonTuple(a, b, c) if b.is_none() => {*self = ButtonTuple(a, Some(btn), c); true},
            &mut ButtonTuple(a, b, c) if c.is_none() => {*self = ButtonTuple(a, b, Some(btn)); true}
            _ => false
        }
    }
}

impl Default for ButtonTuple {
    fn default() -> Self { ButtonTuple(None, None, None) }
}
<commit_msg>KeyMap => KeyTranslator<commit_after>#[deny(missing_docs)]

extern crate input;
extern crate piston_window;
extern crate rustc_serialize;
extern crate viewport;

mod builder;
mod rebind;

use input::{Input, Button, Motion};
use piston_window::Size;
use std::collections::HashMap;
use std::default::Default;
use std::hash::Hash;
use viewport::Viewport;

pub use rebind::InputRebind;
pub use builder::InputTranslatorBuilder;

/// Represents a logical action to be bound to a particular button press, e.g.
/// jump, attack, or move forward
pub trait Action: Copy + PartialEq + Eq + Hash { }

/// A translated action.
#[derive(Debug, Copy, Clone)]
pub enum Translated<A: Action> {
    /// A keypress event which was bound to an action
    Press(A),

    /// A key release event which was bound to an action
    Release(A),

    /// A translated mouse motion. The logical origin of a translated MouseCursor event
    /// is in the top left corner of the window, and the logical scroll is non-natural.
    /// Relative events are unchanged for now.
    Move(Motion)
}

/// An object which translates piston::input::Input events into input_map::Translated<A> events
#[derive(Clone)]
pub struct InputTranslator<A: Action> {
    keymap: KeyTranslator<A>,
    mouse_translator: MouseTranslator
}

impl<A: Action> InputTranslator<A> {

    /// Creates an empty InputTranslator.
    pub fn new(size: Size) -> Self {
        InputTranslator {
            keymap: KeyTranslator::new(),
            mouse_translator: MouseTranslator::new(size)
        }
    }

    /// Translate an Input into a Translated<A> event
    pub fn translate(&self, input: &Input) -> Option<Translated<A>> {
        macro_rules! translate_button(($but_state:ident, $but_var:ident) => (
            match self.keymap.translate($but_var) {
                Some(act) => Some(Translated::$but_state(act)),
                None => None
            });
        );

        match input {
            &Input::Press(button) => translate_button!(Press, button),
            &Input::Release(button) => translate_button!(Release, button),
            &Input::Move(motion) =>
                Some(Translated::Move(self.mouse_translator.translate(motion))),
            _ => None
        }
    }

    pub fn add_binding(&mut self, but: Button, act: A) {
        self.keymap.add_mapping(but, act);
    }

    /// Re-set the mouse bounds size used for calculating mouse events
    pub fn set_size(&mut self, size: Size) {
        self.mouse_translator.viewport_size = size
    }

    /// Re-set the mouse bounds size from a viewport
    pub fn set_size_from_viewport(&mut self, vp: Viewport) {
        self.set_size(Size::from(vp.draw_size));
    }
}

#[derive(Clone)]
struct MouseTranslator {
    pub x_axis_motion_inverted: bool,
    pub y_axis_motion_inverted: bool,
    pub x_axis_scroll_inverted: bool,
    pub y_axis_scroll_inverted: bool,
    pub viewport_size: Size
}

impl MouseTranslator {
    fn new(size: Size) -> Self {
        MouseTranslator {
            x_axis_motion_inverted: false,
            y_axis_motion_inverted: false,
            x_axis_scroll_inverted: false,
            y_axis_scroll_inverted: false,
            viewport_size: size
        }
    }

    fn translate(&self, motion: Motion) -> Motion {
        match motion {
            Motion::MouseCursor(x, y) => {
                let (sw, sh) = {
                    let Size {width, height} = self.viewport_size;
                    (width as f64, height as f64)
                };

                let cx = if self.x_axis_motion_inverted { sw - x } else { x };
                let cy = if self.y_axis_motion_inverted { sh - y } else { y };

                Motion::MouseCursor(cx, cy)
            },
            Motion::MouseScroll(x, y) => {
                let mx = if self.x_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                let my = if self.y_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                Motion::MouseScroll(x * mx, y * my)
            },
            relative => relative
        }
    }
}

#[derive(Clone, Debug)]
struct KeyTranslator<A: Action> {
    btn_map: HashMap<ButtonTuple, A>
}

impl<A: Action> KeyTranslator<A> {
    fn new() -> Self {
        KeyTranslator {
            btn_map: HashMap::new()
        }
    }

    fn add_mapping(&mut self, button: Button, action: A) {
        let mut bt = self.get_bindings_for_action(action).unwrap_or(ButtonTuple::new());
        let bt = if bt.insert_inplace(button) {bt} else {ButtonTuple::new()};
        self.btn_map.insert(bt, action);
    }

    fn get_bindings_for_action(&self, action: A) -> Option<ButtonTuple> {
        self.btn_map.iter().find(|&(_, &a)| a == action).map(|(&bt, _)| bt)
    }

    #[allow(dead_code)]
    fn get_ref_bindings_for_action(&self, action: A) -> Option<&ButtonTuple> {
        self.btn_map.iter().find(|&(_, &a)| a == action).map(|(bt, _)| bt)
    }

    #[cfg(unimplemented)] // This gives a compile error
    fn get_ref_bindings_for_action_mut(&mut self, action: A) -> Option<&mut ButtonTuple> {
        self.btn_map.iter_mut().find(|&(_, &mut a)| a == action).as_mut().map(|&mut (bt, _)| bt)
    }

    fn translate(&self, button: Button) -> Option<A> {
        self.btn_map.iter().find(|&(&bt, _)| bt.contains(button)).map(|(_, &a)| a)
    }
}

/// A three-element tuple of Option<Button>. Used as the key of an InputTranslator
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ButtonTuple(pub Option<Button>, pub Option<Button>, pub Option<Button>);

impl ButtonTuple {
    fn new() -> Self { Default::default() }

    fn contains(&self, btn: Button) -> bool {
        let sbtn = Some(btn);
        self.0 == sbtn || self.1 == sbtn || self.2 == sbtn
    }

    #[allow(dead_code)]
    fn remove_inplace(&mut self, btn: Button) {
        let sbtn = Some(btn);
        if self.0 == sbtn {self.0 = None}
        if self.1 == sbtn {self.1 = None}
        if self.2 == sbtn {self.2 = None}
    }

    #[allow(dead_code)]
    fn replace_inplace(&mut self, btn_idx: u32, btn: Button) -> bool {
        match btn_idx {
            0 => {self.0 = Some(btn); true},
            1 => {self.1 = Some(btn); true},
            2 => {self.2 = Some(btn); true},
            _ => false
        }
    }

    fn insert_inplace(&mut self, btn: Button) -> bool {
        match self {
            &mut ButtonTuple(a, b, c) if a.is_none() => {*self = ButtonTuple(Some(btn), b, c); true},
            &mut ButtonTuple(a, b, c) if b.is_none() => {*self = ButtonTuple(a, Some(btn), c); true},
            &mut ButtonTuple(a, b, c) if c.is_none() => {*self = ButtonTuple(a, b, Some(btn)); true}
            _ => false
        }
    }
}

impl Default for ButtonTuple {
    fn default() -> Self { ButtonTuple(None, None, None) }
}
<|endoftext|>


<commit_before>//! Compile-time assertions to ensure that invariants are met.
//!
//! # Usage
//!
//! This crate is available [on crates.io][crate] and can be used by adding the
//! following to your project's `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! static_assertions = "0.2.3"
//! ```
//!
//! and this to your crate root:
//!
//! ```
//! #[macro_use]
//! extern crate static_assertions;
//! # fn main() {}
//! ```
//!
//! # Assert Equal Size
//!
//! When performing operations such as pointer casts or dealing with [`usize`]
//! versus [`u64`] versus [`u32`], the size of your types matter. This is where
//! [`assert_eq_size`] comes into play. Types provided as arguments to
//! [`assert_eq_size`] are ensured to be the same size at compile-time. If the
//! types differ in size, the code will fail to compile.
//!
//! ```
//! # #[macro_use]
//! # extern crate static_assertions;
//! // Can be declared outside of a function if labeled
//! assert_eq_size!(bytes; (u8, u8), u16);
//!
//! // Fails to compile (same label):
//! // assert_eq_size!(bytes; u8, u8);
//!
//! fn main() {
//!     assert_eq_size!([u8; 4], (u16, u16), u32);
//!
//!     // Produces a compilation failure:
//!     // assert_eq_size!(u32, u8);
//! }
//! ```
//!
//! Similar to [`assert_eq_size`], there is [`assert_eq_size_val`]. Instead of
//! specifying types to compare, values' sizes can be directly compared against
//! each other.
//!
//! ```
//! # #[macro_use]
//! # extern crate static_assertions;
//! # fn main() {
//! let x = 42u8;
//! let y = true;
//!
//! assert_eq_size_val!(x, y);
//! # }
//! ```
//! [`assert_eq_size_val`] doesn't consume its arguments and thus works for
//! non-[`Clone`]able values.
//!
//! ```
//! # #[macro_use]
//! # extern crate static_assertions;
//! # fn main() {
//! struct Buffer([u8; 256]);
//!
//! let buf = Buffer([0; 256]);
//! let val = [0u64; 32];
//!
//! assert_eq_size_val!(buf, val);
//!
//! // `buf` and `val` can be used here
//! # }
//! ```
//!
//! Rather than dereference a pointer to achieve the same effect as
//! [`assert_eq_size_val`], there is also the option of [`assert_eq_size_ptr`].
//!
//! # Assert Constant Expression
//!
//! Constant expressions can be ensured to have certain properties via
//! [`const_assert`]. If the expression evaluates to `false`, the file will fail
//! to compile. This is synonymous to [`static_assert` in C++][static_assert].
//!
//! As a [limitation](#limitations), a unique label is required if the macro is
//! used outside of a function.
//!
//! ```
//! # #[macro_use]
//! # extern crate static_assertions;
//! # fn main() {
//! const NUM: usize = 32;
//!
//! const_assert!(NUM * NUM == 1024);
//! # }
//! ```
//!
//! As a shorthand for `const_assert!(a == b)`, there's [`const_assert_eq`]:
//!
//! ```
//! # #[macro_use]
//! # extern crate static_assertions;
//! const TWO: usize = 2;
//! const_assert_eq!(two; TWO * TWO, TWO + TWO, 4);
//!
//! // Fails to compile (same label):
//! // const_assert_eq!(two; TWO, TWO);
//!
//! fn main() {
//!     const NUM: usize = 32;
//!     const_assert_eq!(NUM + NUM, 64);
//! }
//! ```
//!
//! # Assert Object Safety
//!
//! Sometimes changes are made to traits that prevent them from being used in
//! the context of an object. Such a case would be adding a generic method and
//! forgetting to add `where Self: Sized` after it. If left unnoticed, that
//! mistake will end up affecting crate users and break compatibility.
//!
//! [`assert_obj_safe`] is here to save you from those troubles:
//!
//! ```
//! # #[macro_use]
//! # extern crate static_assertions;
//! assert_obj_safe!(basic; Send, Sync, AsRef<str>);
//!
//! trait MySafeTrait {}
//!
//! trait MyUnsafeTrait {
//!     fn generic<T>();
//! }
//!
//! fn main() {
//!     assert_obj_safe!(MySafeTrait);
//!
//!     // Produces a compilation failure:
//!     // assert_obj_safe!(MyUnsafeTrait);
//! }
//! ```
//!
//! # Assert Trait `impl`
//!
//! To ensure types implement [`Send`], [`Sync`], and other traits, there's
//! [`assert_impl`]:
//!
//! ```
//! # #[macro_use]
//! # extern crate static_assertions;
//! assert_impl!(str; String, Send, Sync, From<&'static str>);
//! assert_impl!(vec; &'static [u8], Into<Vec<u8>>);
//!
//! fn main() {
//!     // Produces a compilation failure:
//!     // `*const u8` cannot be sent between threads safely
//!     // assert_impl!(*const u8, Send);
//! }
//! ```
//!
//! # Limitations
//!
//! Due to implementation details, the following can only be used normally from
//! within the context of a function:
//!
//! - [`assert_eq_size`]
//! - [`assert_obj_safe`]
//! - [`assert_impl`]
//! - [`const_assert`]
//! - [`const_assert_eq`]
//!
//! To use these macros in other contexts, a unique label must be provided.
//!
//! If you want to read up about this and provide feedback, see
//! [the related issue on GitHub][issue1].
//!
//! [issue1]: https://github.com/nvzqz/static-assertions-rs/issues/1
//! [crate]: https://crates.io/crates/static_assertions
//! [static_assert]: http://en.cppreference.com/w/cpp/language/static_assert
//! [`Clone`]: https://doc.rust-lang.org/std/clone/trait.Clone.html
//! [`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
//! [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
//! [`usize`]: https://doc.rust-lang.org/std/primitive.usize.html
//! [`u64`]: https://doc.rust-lang.org/std/primitive.u64.html
//! [`u32`]: https://doc.rust-lang.org/std/primitive.u32.html
//! [`assert_eq_size_val`]: macro.assert_eq_size_val.html
//! [`assert_eq_size_ptr`]: macro.assert_eq_size_ptr.html
//! [`assert_eq_size`]: macro.assert_eq_size.html
//! [`assert_obj_safe`]: macro.assert_obj_safe.html
//! [`assert_impl`]: macro.assert_impl.html
//! [`const_assert`]: macro.const_assert.html
//! [`const_assert_eq`]: macro.const_assert_eq.html

#![no_std]

#![deny(unused_macros)]

#[doc(hidden)]
pub extern crate core as _core;

/// Asserts that the configuration is set.
///
/// # Examples
///
/// A project may not support a set of configurations and thus you may want to
/// report why:
///
/// ```
/// # #[macro_use]
/// # extern crate static_assertions;
/// // We should only be compiling for Unix or Linux
/// # #[cfg(any(unix, linux))]
/// assert_cfg!(any(unix, linux));
/// # fn main() {}
/// ```
///
/// If users need to specify a database back-end:
///
/// ```
/// # #[macro_use]
/// # extern crate static_assertions;
/// # #[cfg(target_pointer_width = "0")] // Impossible
/// assert_cfg!("Must exclusively use MySQL or MongoDB as database back-end",
///             all(not(all(feature = "mysql", feature = "mongodb")),
///                 any(    feature = "mysql", feature = "mongodb")));
/// # fn main() {}
/// ```
#[macro_export]
macro_rules! assert_cfg {
    () => {};
    ($msg:expr, $($cfg:tt)*) => {
        #[cfg(not($($cfg)*))]
        compile_error!($msg);
    };
    ($($cfg:tt)*) => {
        #[cfg(not($($cfg)*))]
        compile_error!(concat!("Cfg does not pass: ", stringify!($($cfg)*)));
    };
}

/// Asserts at compile-time that the types have equal sizes.
///
/// # Example
///
/// ```
/// # #[macro_use]
/// # extern crate static_assertions;
/// struct Byte(u8);
///
/// assert_eq_size!(pair; (u16, u16), [u16; 2], [u8; 4]);
///
/// // Fails to compile (same label):
/// // assert_eq_size!(pair; u8, u8);
///
/// fn main() {
///     assert_eq_size!(Byte, u8);
///
///     // Supports unlimited arguments:
///     assert_eq_size!([Byte; 4], [u16; 2], u32);
///
///     // Produces a compilation failure:
///     // assert_eq_size!(Byte, u16);
/// }
/// ```
#[macro_export]
macro_rules! assert_eq_size {
    ($x:ty, $($xs:ty),+ $(,)*) => {
        $(let _ = $crate::_core::mem::transmute::<$x, $xs>;)+
    };
    ($label:ident; $($xs:tt)+) => {
        #[allow(dead_code, non_snake_case)]
        fn $label() { assert_eq_size!($($xs)+); }
    };
}

/// Asserts at compile-time that the values pointed to have equal sizes.
///
/// This especially is useful for when coercing pointers between different types
/// and ensuring the underlying values are the same size.
///
/// # Example
///
/// ```
/// # #[macro_use]
/// # extern crate static_assertions;
/// fn operation(x: &(u32, u32), y: &[u16; 4]) {
///     assert_eq_size_ptr!(x, y);
/// }
/// # fn main() {}
/// ```
#[macro_export]
macro_rules! assert_eq_size_ptr {
    ($x:expr, $($xs:expr),+ $(,)*) => {
        #[allow(unknown_lints, forget_copy, unused_unsafe, useless_transmute)]
        unsafe {
            use $crate::_core::{mem, ptr};
            let mut copy = ptr::read($x);
            $(ptr::write(&mut copy, mem::transmute(ptr::read($xs)));)+
            mem::forget(copy);
        }
    }
}

/// Asserts at compile-time that the values have equal sizes.
///
/// # Example
///
/// ```
/// # #[macro_use]
/// # extern crate static_assertions;
/// # fn main() {
/// struct Byte(u8);
///
/// let x = 10u8;
/// let y = Byte(42); // Works for non-cloneable types
///
/// assert_eq_size_val!(x, y);
/// assert_eq_size_val!(x, y, 0u8);
///
/// // Fails to compile:
/// // assert_eq_size_val!(x, 0u32);
/// # }
/// ```
#[macro_export]
macro_rules! assert_eq_size_val {
    ($x:expr, $($xs:expr),+ $(,)*) => {
        assert_eq_size_ptr!(&$x, $(&$xs),+);
    }
}

/// Asserts at compile-time that the constant expression evaluates to `true`.
///
/// # Example
///
/// ```
/// # #[macro_use]
/// # extern crate static_assertions;
/// # fn main() {
/// const_assert!(2 + 2 == 4);
///
/// const FIVE: usize = 5;
/// const_assert!(FIVE - FIVE == 0);
///
/// // Produces a compilation failure:
/// // const_assert!(1 >= 2);
/// # }
/// ```
#[macro_export]
macro_rules! const_assert {
    ($($xs:expr),+ $(,)*) => {
        #[allow(unknown_lints, eq_op)]
        let _ = [(); 0 - !($($xs)&&+) as usize];
    };
    ($label:ident; $($xs:tt)+) => {
        #[allow(dead_code, non_snake_case)]
        fn $label() { const_assert!($($xs)+); }
    };
}

/// Asserts at compile-time that the constants are equal in value.
#[macro_export]
macro_rules! const_assert_eq {
    ($x:expr, $($xs:expr),+ $(,)*) => {
        const_assert!($($x == $xs),+);
    };
    ($label:ident; $x:expr, $($xs:expr),+ $(,)*) => {
        const_assert!($label; $($x == $xs),+);
    };
}

/// Asserts at compile-time that the traits are object-safe.
///
/// This is useful for when changes are made to a trait that accidentally
/// prevent it from being used as an object.
#[macro_export]
macro_rules! assert_obj_safe {
    ($($xs:ty),+ $(,)*) => {
        $(let _: Option<&$xs> = None;)+
    };
    ($label:ident; $($xs:tt)+) => {
        #[allow(dead_code, non_snake_case)]
        fn $label() { assert_obj_safe!($($xs)+); }
    };
}

/// Asserts at compile-time that the type has the given fields.
///
/// This is useful for when types have odd fields as a result of `#[cfg]`.
#[macro_export]
macro_rules! assert_fields {
    ($t:path, $($f:ident),+) => {
        $(let $t { $f: _, .. };)+
    };
    ($label:ident; $($xs:tt)+) => {
        #[allow(dead_code, non_snake_case)]
        fn $label() { assert_fields!($($xs)+); }
    };
}

/// Asserts at compile-time that the type implements the given traits.
#[macro_export]
macro_rules! assert_impl {
    ($x:ty, $($t:path),+ $(,)*) => {
        $({
            fn assert_impl<T: ?Sized + $t>() {}
            assert_impl::<$x>();
        })+
    };
    ($label:ident; $($xs:tt)+) => {
        #[allow(dead_code, non_snake_case)]
        fn $label() { assert_impl!($($xs)+); }
    };
}
<commit_msg>Improve docs for individual macros<commit_after>//! Compile-time assertions to ensure that invariants are met.
//!
//! # Usage
//!
//! This crate is available [on crates.io][crate] and can be used by adding the
//! following to your project's `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! static_assertions = "0.2.3"
//! ```
//!
//! and this to your crate root:
//!
//! ```
//! #[macro_use]
//! extern crate static_assertions;
//! # fn main() {}
//! ```
//!
//! # Limitations
//!
//! Due to implementation details, some macros can only be used normally from
//! within the context of a function. To use these macros in other contexts, a
//! unique label must be provided.
//!
//! This issue can be followed [here][issue1]. Feedback and potential solutions
//! are welcome!
//!
//! [issue1]: https://github.com/nvzqz/static-assertions-rs/issues/1
//! [crate]: https://crates.io/crates/static_assertions

#![no_std]

#![deny(unused_macros)]

#[doc(hidden)]
pub extern crate core as _core;

/// Asserts that the configuration is set.
///
/// # Examples
///
/// A project may not support a set of configurations and thus you may want to
/// report why:
///
/// ```
/// # #[macro_use]
/// # extern crate static_assertions;
/// // We should only be compiling for Unix or Linux
/// # #[cfg(any(unix, linux))]
/// assert_cfg!(any(unix, linux));
/// # fn main() {}
/// ```
///
/// If users need to specify a database back-end:
///
/// ```
/// # #[macro_use]
/// # extern crate static_assertions;
/// # #[cfg(target_pointer_width = "0")] // Impossible
/// assert_cfg!("Must exclusively use MySQL or MongoDB as database back-end",
///             all(not(all(feature = "mysql", feature = "mongodb")),
///                 any(    feature = "mysql", feature = "mongodb")));
/// # fn main() {}
/// ```
#[macro_export]
macro_rules! assert_cfg {
    () => {};
    ($msg:expr, $($cfg:tt)*) => {
        #[cfg(not($($cfg)*))]
        compile_error!($msg);
    };
    ($($cfg:tt)*) => {
        #[cfg(not($($cfg)*))]
        compile_error!(concat!("Cfg does not pass: ", stringify!($($cfg)*)));
    };
}

/// Asserts at compile-time that the types have equal sizes.
///
/// When performing operations such as pointer casts or dealing with [`usize`]
/// versus [`u64`] versus [`u32`], the size of your types matter. This is where
/// this macro comes into play.
///
/// # Alternatives
///
/// There are also [`assert_eq_size_val`](macro.assert_eq_size_val.html) and
/// [`assert_eq_size_ptr`](macro.assert_eq_size_ptr.html). Instead of specifying
/// types to compare, values' sizes can be directly compared against each other.
///
/// # Example
///
/// ```
/// # #[macro_use]
/// # extern crate static_assertions;
/// // Can be declared outside of a function if labeled
/// assert_eq_size!(bytes; (u8, u8), u16);
///
/// // Fails to compile (same label):
/// // assert_eq_size!(bytes; u8, u8);
///
/// fn main() {
///     // Supports unlimited arguments:
///     assert_eq_size!([u8; 4], (u16, u16), u32);
///
///     // Produces a compilation failure:
///     // assert_eq_size!(u32, u8);
/// }
/// ```
///
/// [`usize`]: https://doc.rust-lang.org/std/primitive.usize.html
/// [`u64`]: https://doc.rust-lang.org/std/primitive.u64.html
/// [`u32`]: https://doc.rust-lang.org/std/primitive.u32.html
#[macro_export]
macro_rules! assert_eq_size {
    ($x:ty, $($xs:ty),+ $(,)*) => {
        $(let _ = $crate::_core::mem::transmute::<$x, $xs>;)+
    };
    ($label:ident; $($xs:tt)+) => {
        #[allow(dead_code, non_snake_case)]
        fn $label() { assert_eq_size!($($xs)+); }
    };
}

/// Asserts at compile-time that the values pointed to have equal sizes.
///
/// This especially is useful for when coercing pointers between different types
/// and ensuring the underlying values are the same size.
///
/// # Example
///
/// ```
/// # #[macro_use]
/// # extern crate static_assertions;
/// fn operation(x: &(u32, u32), y: &[u16; 4]) {
///     assert_eq_size_ptr!(x, y);
/// }
/// # fn main() {}
/// ```
#[macro_export]
macro_rules! assert_eq_size_ptr {
    ($x:expr, $($xs:expr),+ $(,)*) => {
        #[allow(unknown_lints, forget_copy, unused_unsafe, useless_transmute)]
        unsafe {
            use $crate::_core::{mem, ptr};
            let mut copy = ptr::read($x);
            $(ptr::write(&mut copy, mem::transmute(ptr::read($xs)));)+
            mem::forget(copy);
        }
    }
}

/// Asserts at compile-time that the values have equal sizes.
///
/// This macro doesn't consume its arguments and thus works for
/// non-[`Clone`]able values.
///
/// # Example
///
/// ```
/// # #[macro_use]
/// # extern crate static_assertions;
/// # fn main() {
/// struct Byte(u8);
///
/// let x = 10u8;
/// let y = Byte(42); // Works for non-cloneable types
///
/// assert_eq_size_val!(x, y);
/// assert_eq_size_val!(x, y, 0u8);
///
/// // Fails to compile:
/// // assert_eq_size_val!(x, 0u32);
/// # }
/// ```
///
/// [`Clone`]: https://doc.rust-lang.org/std/clone/trait.Clone.html
#[macro_export]
macro_rules! assert_eq_size_val {
    ($x:expr, $($xs:expr),+ $(,)*) => {
        assert_eq_size_ptr!(&$x, $(&$xs),+);
    }
}

/// Asserts at compile-time that the constant expression evaluates to `true`.
///
/// There also exists [`const_assert_eq`](macro.const_assert_eq.html) for
/// validating whether a sequence of expressions are equal to one another.
///
/// # Example
///
/// Constant expressions can be ensured to have certain properties via this
/// macro If the expression evaluates to `false`, the file will fail to compile.
/// This is synonymous to [`static_assert` in C++][static_assert].
///
/// As a [limitation](index.html#limitations), a unique label is required if
/// the macro is used outside of a function.
///
/// ```
/// # #[macro_use]
/// # extern crate static_assertions;
/// const FIVE: usize = 5;
///
/// const_assert!(twenty_five; FIVE * FIVE == 25);
///
/// fn main() {
///     const_assert!(2 + 2 == 4);
///     const_assert!(FIVE - FIVE == 0);
///
///     // Produces a compilation failure:
///     // const_assert!(1 >= 2);
/// }
/// ```
///
/// [static_assert]: http://en.cppreference.com/w/cpp/language/static_assert
#[macro_export]
macro_rules! const_assert {
    ($($xs:expr),+ $(,)*) => {
        #[allow(unknown_lints, eq_op)]
        let _ = [(); 0 - !($($xs)&&+) as usize];
    };
    ($label:ident; $($xs:tt)+) => {
        #[allow(dead_code, non_snake_case)]
        fn $label() { const_assert!($($xs)+); }
    };
}

/// Asserts at compile-time that the constants are equal in value.
///
/// # Example
///
/// Works as a shorthand for `const_assert!(a == b)`:
///
/// ```
/// # #[macro_use]
/// # extern crate static_assertions;
/// const TWO: usize = 2;
/// const_assert_eq!(two; TWO * TWO, TWO + TWO, 4);
///
/// // Fails to compile (same label):
/// // const_assert_eq!(two; TWO, TWO);
///
/// fn main() {
///     const NUM: usize = 32;
///     const_assert_eq!(NUM + NUM, 64);
/// }
/// ```
#[macro_export]
macro_rules! const_assert_eq {
    ($x:expr, $($xs:expr),+ $(,)*) => {
        const_assert!($($x == $xs),+);
    };
    ($label:ident; $x:expr, $($xs:expr),+ $(,)*) => {
        const_assert!($label; $($x == $xs),+);
    };
}

/// Asserts at compile-time that the traits are object-safe.
///
/// This is useful for when changes are made to a trait that accidentally
/// prevent it from being used as an object. Such a case would be adding a
/// generic method and forgetting to add `where Self: Sized` after it. If left
/// unnoticed, that mistake will affect crate users and break both forward and
/// backward compatibility.
///
/// # Example
///
/// ```
/// # #[macro_use]
/// # extern crate static_assertions;
/// assert_obj_safe!(basic; Send, Sync, AsRef<str>);
///
/// trait MySafeTrait {
///     fn foo(&self) -> u32;
/// }
///
/// trait MyUnsafeTrait {
///     fn bar<T>(&self) -> T;
/// }
///
/// fn main() {
///     assert_obj_safe!(MySafeTrait);
///
///     // Produces a compilation failure:
///     // assert_obj_safe!(MyUnsafeTrait);
/// }
/// ```
#[macro_export]
macro_rules! assert_obj_safe {
    ($($xs:ty),+ $(,)*) => {
        $(let _: Option<&$xs> = None;)+
    };
    ($label:ident; $($xs:tt)+) => {
        #[allow(dead_code, non_snake_case)]
        fn $label() { assert_obj_safe!($($xs)+); }
    };
}

/// Asserts at compile-time that the type has the given fields.
///
/// This is useful for when types have odd fields as a result of `#[cfg]`.
#[macro_export]
macro_rules! assert_fields {
    ($t:path, $($f:ident),+) => {
        $(let $t { $f: _, .. };)+
    };
    ($label:ident; $($xs:tt)+) => {
        #[allow(dead_code, non_snake_case)]
        fn $label() { assert_fields!($($xs)+); }
    };
}

/// Asserts at compile-time that the type implements the given traits.
///
/// # Examples
///
/// Can be used to ensure types implement [`Send`], [`Sync`], and other traits:
///
/// ```
/// # #[macro_use]
/// # extern crate static_assertions;
/// assert_impl!(str; String, Send, Sync, From<&'static str>);
/// assert_impl!(vec; &'static [u8], Into<Vec<u8>>);
///
/// fn main() {
///     // Produces a compilation failure:
///     // `*const u8` cannot be sent between threads safely
///     // assert_impl!(*const u8, Send);
/// }
/// ```
///
/// [`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
/// [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
#[macro_export]
macro_rules! assert_impl {
    ($x:ty, $($t:path),+ $(,)*) => {
        $({
            fn assert_impl<T: ?Sized + $t>() {}
            assert_impl::<$x>();
        })+
    };
    ($label:ident; $($xs:tt)+) => {
        #[allow(dead_code, non_snake_case)]
        fn $label() { assert_impl!($($xs)+); }
    };
}
<|endoftext|>