<commit_before>//! [Lambda terms](https://en.wikipedia.org/wiki/Lambda_calculus#Lambda_terms)

use self::Term::*;
use self::Error::*;
use std::fmt;
use std::borrow::Cow;

/// A lambda term that is either a variable with a De Bruijn index, an abstraction over a term or
/// an applicaction of one term to another.
#[derive(Debug, PartialEq, Clone)]
pub enum Term {
    Var(usize),
    Abs(Box<Term>),
    App(Box<Term>, Box<Term>)
}

/// An error that can be returned when an inapplicable function is applied to a term.
#[derive(Debug, PartialEq, Clone)]
pub enum Error {
    NotAVar,
    NotAnAbs,
    NotAnApp,
    NotANum,
    NotAPair,
    NotAList
}

impl Term {
    /// Applies `self` to another term without substitution or reduction.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::Term::*;
    /// use lambda_calculus::arithmetic::{zero, succ};
    ///
    /// assert_eq!(succ().app(zero()), App(Box::new(succ()), Box::new(zero())));
    /// ```
    pub fn app(self, argument: Term) -> Term { App(Box::new(self), Box::new(argument)) }

    /// Consumes a lambda variable and returns its De Bruijn index.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::Term::*;
    ///
    /// assert_eq!(Var(1).unvar(), Ok(1));
    /// ```
    pub fn unvar(self) -> Result<usize, Error> {
        match self {
            Var(n) => Ok(n),
            _ => Err(NotAVar)
        }
    }

    /// Consumes an abstraction and returns its underlying term.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::Term::*;
    /// use lambda_calculus::term::abs;
    ///
    /// assert_eq!(abs(Var(1)).unabs(), Ok(Var(1)));
    /// ```
    pub fn unabs(self) -> Result<Term, Error> {
        match self {
            Abs(x) => Ok(*x),
            _ => Err(NotAnAbs)
        }
    }

    /// Returns a reference to an abstraction's underlying term.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::Term::*;
    /// use lambda_calculus::term::abs;
    ///
    /// assert_eq!(abs(Var(1)).unabs_ref(), Ok(&Var(1)));
    /// ```
    pub fn unabs_ref(&self) -> Result<&Term, Error> {
        match *self {
            Abs(ref x) => Ok(&*x),
            _ => Err(NotAnAbs)
        }
    }

    /// Returns a mutable reference to an abstraction's underlying term.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::Term::*;
    /// use lambda_calculus::term::abs;
    ///
    /// assert_eq!(abs(Var(1)).unabs_ref_mut(), Ok(&mut Var(1)));
    /// ```
    pub fn unabs_ref_mut(&mut self) -> Result<&mut Term, Error> {
        match *self {
            Abs(ref mut x) => Ok(&mut *x),
            _ => Err(NotAnAbs)
        }
    }

    /// Consumes an application and returns a pair containing its underlying terms.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::Term::*;
    ///
    /// assert_eq!(Var(0).app(Var(1)).unapp(), Ok((Var(0), Var(1))));
    /// ```
    pub fn unapp(self) -> Result<(Term, Term), Error> {
        match self {
            App(lhs, rhs) => Ok((*lhs, *rhs)),
            _ => Err(NotAnApp)
        }
    }

    /// Returns a pair containing references to an application's underlying terms.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::Term::*;
    ///
    /// assert_eq!(Var(0).app(Var(1)).unapp_ref(), Ok((&Var(0), &Var(1))));
    /// ```
    pub fn unapp_ref(&self) -> Result<(&Term, &Term), Error> {
        match *self {
            App(ref lhs, ref rhs) => Ok((&*lhs, &*rhs)),
            _ => Err(NotAnApp)
        }
    }

    /// Returns a pair containing mutable references to an application's underlying terms.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::Term::*;
    ///
    /// assert_eq!(Var(0).app(Var(1)).unapp_ref_mut(), Ok((&mut Var(0), &mut Var(1))));
    /// ```
    pub fn unapp_ref_mut(&mut self) -> Result<(&mut Term, &mut Term), Error> {
        match *self {
            App(ref mut lhs, ref mut rhs) => Ok((&mut *lhs, &mut *rhs)),
            _ => Err(NotAnApp)
        }
    }

    /// Returns the left-hand side term of an application. Consumes `self`.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::Term::*;
    ///
    /// assert_eq!(Var(0).app(Var(1)).lhs(), Ok(Var(0)));
    /// ```
    pub fn lhs(self) -> Result<Term, Error> {
        if let Ok((lhs, _)) = self.unapp() { Ok(lhs) } else { Err(NotAnApp) }
    }

    /// Returns a reference to the left-hand side term of an application.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::Term::*;
    ///
    /// assert_eq!(Var(0).app(Var(1)).lhs_ref(), Ok(&Var(0)));
    /// ```
    pub fn lhs_ref(&self) -> Result<&Term, Error> {
        if let Ok((lhs, _)) = self.unapp_ref() { Ok(lhs) } else { Err(NotAnApp) }
    }

    /// Returns a mutable reference to the left-hand side term of an application.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::Term::*;
    ///
    /// assert_eq!(Var(0).app(Var(1)).lhs_ref_mut(), Ok(&mut Var(0)));
    /// ```
    pub fn lhs_ref_mut(&mut self) -> Result<&mut Term, Error> {
        if let Ok((lhs, _)) = self.unapp_ref_mut() { Ok(lhs) } else { Err(NotAnApp) }
    }

    /// Returns the right-hand side term of an application. Consumes `self`.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::Term::*;
    ///
    /// assert_eq!(Var(0).app(Var(1)).rhs(), Ok(Var(1)));
    /// ```
    pub fn rhs(self) -> Result<Term, Error> {
        if let Ok((_, rhs)) = self.unapp() { Ok(rhs) } else { Err(NotAnApp) }
    }

    /// Returns a reference to the right-hand side term of an application.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::Term::*;
    ///
    /// assert_eq!(Var(0).app(Var(1)).rhs_ref(), Ok(&Var(1)));
    /// ```
    pub fn rhs_ref(&self) -> Result<&Term, Error> {
        if let Ok((_, rhs)) = self.unapp_ref() { Ok(rhs) } else { Err(NotAnApp) }
    }

    /// Returns a mutable reference to the right-hand side term of an application.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::Term::*;
    ///
    /// assert_eq!(Var(0).app(Var(1)).rhs_ref_mut(), Ok(&mut Var(1)));
    /// ```
    pub fn rhs_ref_mut(&mut self) -> Result<&mut Term, Error> {
        if let Ok((_, rhs)) = self.unapp_ref_mut() { Ok(rhs) } else { Err(NotAnApp) }
    }
}

/// Wraps a term in an abstraction. Consumes its argument.
///
/// # Example
/// ```
/// use lambda_calculus::term::Term::*;
/// use lambda_calculus::term::abs;
///
/// assert_eq!(abs(Var(1)), Abs(Box::new(Var(1))));
/// ```
pub fn abs(term: Term) -> Term { Abs(Box::new(term)) }

/// Produces an application of its arguments without substitution or reduction, consuming them in
/// the process.
///
/// # Example
/// ```
/// use lambda_calculus::term::Term::*;
/// use lambda_calculus::term::app;
///
/// assert_eq!(app(Var(0), Var(1)), App(Box::new(Var(0)), Box::new(Var(1))));
/// ```
pub fn app(lhs: Term, rhs: Term) -> Term { App(Box::new(lhs), Box::new(rhs)) }

/// Applies two terms with substitution and variable update (but without reduction), consuming them
/// in the process.
///
/// # Example
/// ```
/// use lambda_calculus::term::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);

    Ok(try!(lhs.unabs()))
}

fn _apply(lhs: &mut Term, rhs: Term, depth: usize) {
    match *lhs {
        Var(i) => if i == depth {
            *lhs = rhs; // substitute a top-level variable from lhs with rhs
            update_free_variables(lhs, depth - 1) // update free variables' indices 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.clone(), depth);
            _apply(lhs.rhs_ref_mut().unwrap(), rhs, depth);
        }
    }
}

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

/// Set to `true` for λ or `false` for \ when displaying lambda terms. The default is `true`.
pub const DISPLAY_PRETTY: bool = true;

impl fmt::Display for Term {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", show_precedence(0, self))
    }
}

fn show_precedence(context_precedence: usize, term: &Term) -> String {
    match *term {
        Var(i) => format!("{:X}", i), // max. index = 15
        Abs(ref t) => {
            let ret = format!("{}{}", if DISPLAY_PRETTY { 'λ' } else { '\\' }, t);
            parenthesize_if(context_precedence > 1, &ret).into()
        },
        App(ref t1, ref t2) => {
            let ret = format!("{}{}", show_precedence(2, t1), show_precedence(3, t2));
            parenthesize_if(context_precedence == 3, &ret).into()
        }
    }
}

fn parenthesize_if(condition: bool, input: &str) -> Cow<str> {
    if condition {
        format!("({})", input).into()
    } else {
        input.into()
    }
}

// WIP
/*
fn beta_reduce(mut term: Term) -> Result<Term, Error> {
    match term {
        App(lhs, rhs) => term = try!(apply(*lhs, *rhs)),
        Abs(t) => try!(beta_reduce(*t)),
        _ => ()
    }

    Ok(term)
}
*/
fn _beta_reduce(term: &mut Term) {
    match *term {
        App(_, _) => {
            let (lhs, rhs) = term.clone().unapp().unwrap();
            println!("attempting to reduce {}...", *term);
            if let Ok(reduced) = apply(lhs, rhs) {
                println!("\tattempt successful: {}", reduced);
                *term = reduced;
            } else {
                println!("\tfailed; trying to reduce the inner terms");
                let (mut lhs, mut rhs) = term.clone().unapp().unwrap();
                _beta_reduce(&mut lhs);
                _beta_reduce(&mut rhs);
            }
        },
        Abs(ref mut t) => _beta_reduce(t),
        _ => ()
    }
}

#[cfg(test)]
mod test {
    use arithmetic::*;
    use term::{apply, _beta_reduce};

    #[test]
    fn applying() {
        let mut unreduced = apply(succ(), zero()).unwrap();
        println!("before: {}", unreduced);
        let _ = _beta_reduce(&mut unreduced);
        println!("after: {}", unreduced);
    }

    #[test]
    fn displaying_terms() {
        assert_eq!(&format!("{}", zero()), "λλ1");
        assert_eq!(&format!("{}", succ()), "λλλ2(321)");
        assert_eq!(&format!("{}", pred()), "λλλ3(λλ1(24))(λ2)(λ1)");
    }
}
<commit_msg>Add evaluate(), extra test for apply()<commit_after>//! [Lambda terms](https://en.wikipedia.org/wiki/Lambda_calculus#Lambda_terms)

use self::Term::*;
use self::Error::*;
use std::fmt;
use std::borrow::Cow;

/// A lambda term that is either a variable with a De Bruijn index, an abstraction over a term or
/// an applicaction of one term to another.
#[derive(Debug, PartialEq, Clone)]
pub enum Term {
    Var(usize),
    Abs(Box<Term>),
    App(Box<Term>, Box<Term>)
}

/// An error that can be returned when an inapplicable function is applied to a term.
#[derive(Debug, PartialEq, Clone)]
pub enum Error {
    NotAVar,
    NotAnAbs,
    NotAnApp,
    NotANum,
    NotAPair,
    NotAList
}

impl Term {
    /// Applies `self` to another term without substitution or reduction.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::Term::*;
    /// use lambda_calculus::arithmetic::{zero, succ};
    ///
    /// assert_eq!(succ().app(zero()), App(Box::new(succ()), Box::new(zero())));
    /// ```
    pub fn app(self, argument: Term) -> Term { App(Box::new(self), Box::new(argument)) }

    /// Consumes a lambda variable and returns its De Bruijn index.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::Term::*;
    ///
    /// assert_eq!(Var(1).unvar(), Ok(1));
    /// ```
    pub fn unvar(self) -> Result<usize, Error> {
        match self {
            Var(n) => Ok(n),
            _ => Err(NotAVar)
        }
    }

    /// Consumes an abstraction and returns its underlying term.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::Term::*;
    /// use lambda_calculus::term::abs;
    ///
    /// assert_eq!(abs(Var(1)).unabs(), Ok(Var(1)));
    /// ```
    pub fn unabs(self) -> Result<Term, Error> {
        match self {
            Abs(x) => Ok(*x),
            _ => Err(NotAnAbs)
        }
    }

    /// Returns a reference to an abstraction's underlying term.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::Term::*;
    /// use lambda_calculus::term::abs;
    ///
    /// assert_eq!(abs(Var(1)).unabs_ref(), Ok(&Var(1)));
    /// ```
    pub fn unabs_ref(&self) -> Result<&Term, Error> {
        match *self {
            Abs(ref x) => Ok(&*x),
            _ => Err(NotAnAbs)
        }
    }

    /// Returns a mutable reference to an abstraction's underlying term.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::Term::*;
    /// use lambda_calculus::term::abs;
    ///
    /// assert_eq!(abs(Var(1)).unabs_ref_mut(), Ok(&mut Var(1)));
    /// ```
    pub fn unabs_ref_mut(&mut self) -> Result<&mut Term, Error> {
        match *self {
            Abs(ref mut x) => Ok(&mut *x),
            _ => Err(NotAnAbs)
        }
    }

    /// Consumes an application and returns a pair containing its underlying terms.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::Term::*;
    ///
    /// assert_eq!(Var(0).app(Var(1)).unapp(), Ok((Var(0), Var(1))));
    /// ```
    pub fn unapp(self) -> Result<(Term, Term), Error> {
        match self {
            App(lhs, rhs) => Ok((*lhs, *rhs)),
            _ => Err(NotAnApp)
        }
    }

    /// Returns a pair containing references to an application's underlying terms.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::Term::*;
    ///
    /// assert_eq!(Var(0).app(Var(1)).unapp_ref(), Ok((&Var(0), &Var(1))));
    /// ```
    pub fn unapp_ref(&self) -> Result<(&Term, &Term), Error> {
        match *self {
            App(ref lhs, ref rhs) => Ok((&*lhs, &*rhs)),
            _ => Err(NotAnApp)
        }
    }

    /// Returns a pair containing mutable references to an application's underlying terms.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::Term::*;
    ///
    /// assert_eq!(Var(0).app(Var(1)).unapp_ref_mut(), Ok((&mut Var(0), &mut Var(1))));
    /// ```
    pub fn unapp_ref_mut(&mut self) -> Result<(&mut Term, &mut Term), Error> {
        match *self {
            App(ref mut lhs, ref mut rhs) => Ok((&mut *lhs, &mut *rhs)),
            _ => Err(NotAnApp)
        }
    }

    /// Returns the left-hand side term of an application. Consumes `self`.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::Term::*;
    ///
    /// assert_eq!(Var(0).app(Var(1)).lhs(), Ok(Var(0)));
    /// ```
    pub fn lhs(self) -> Result<Term, Error> {
        if let Ok((lhs, _)) = self.unapp() { Ok(lhs) } else { Err(NotAnApp) }
    }

    /// Returns a reference to the left-hand side term of an application.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::Term::*;
    ///
    /// assert_eq!(Var(0).app(Var(1)).lhs_ref(), Ok(&Var(0)));
    /// ```
    pub fn lhs_ref(&self) -> Result<&Term, Error> {
        if let Ok((lhs, _)) = self.unapp_ref() { Ok(lhs) } else { Err(NotAnApp) }
    }

    /// Returns a mutable reference to the left-hand side term of an application.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::Term::*;
    ///
    /// assert_eq!(Var(0).app(Var(1)).lhs_ref_mut(), Ok(&mut Var(0)));
    /// ```
    pub fn lhs_ref_mut(&mut self) -> Result<&mut Term, Error> {
        if let Ok((lhs, _)) = self.unapp_ref_mut() { Ok(lhs) } else { Err(NotAnApp) }
    }

    /// Returns the right-hand side term of an application. Consumes `self`.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::Term::*;
    ///
    /// assert_eq!(Var(0).app(Var(1)).rhs(), Ok(Var(1)));
    /// ```
    pub fn rhs(self) -> Result<Term, Error> {
        if let Ok((_, rhs)) = self.unapp() { Ok(rhs) } else { Err(NotAnApp) }
    }

    /// Returns a reference to the right-hand side term of an application.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::Term::*;
    ///
    /// assert_eq!(Var(0).app(Var(1)).rhs_ref(), Ok(&Var(1)));
    /// ```
    pub fn rhs_ref(&self) -> Result<&Term, Error> {
        if let Ok((_, rhs)) = self.unapp_ref() { Ok(rhs) } else { Err(NotAnApp) }
    }

    /// Returns a mutable reference to the right-hand side term of an application.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::Term::*;
    ///
    /// assert_eq!(Var(0).app(Var(1)).rhs_ref_mut(), Ok(&mut Var(1)));
    /// ```
    pub fn rhs_ref_mut(&mut self) -> Result<&mut Term, Error> {
        if let Ok((_, rhs)) = self.unapp_ref_mut() { Ok(rhs) } else { Err(NotAnApp) }
    }

    /// Performs 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()).evaluate(), Ok(abs(abs(Var(1)))));
    /// ```
    pub fn evaluate(self) -> Result<Term, Error> {
        let (mut lhs, rhs) = try!(self.unapp());

        _apply(&mut lhs, rhs, 0);

        Ok(try!(lhs.unabs()))
    }
}

/// Wraps a term in an abstraction. Consumes its argument.
///
/// # Example
/// ```
/// use lambda_calculus::term::Term::*;
/// use lambda_calculus::term::abs;
///
/// assert_eq!(abs(Var(1)), Abs(Box::new(Var(1))));
/// ```
pub fn abs(term: Term) -> Term { Abs(Box::new(term)) }

/// Produces an application of its arguments without substitution or reduction, consuming them in
/// the process.
///
/// # Example
/// ```
/// use lambda_calculus::term::Term::*;
/// use lambda_calculus::term::app;
///
/// assert_eq!(app(Var(0), Var(1)), App(Box::new(Var(0)), Box::new(Var(1))));
/// ```
pub fn app(lhs: Term, rhs: Term) -> Term { App(Box::new(lhs), Box::new(rhs)) }

/// Applies two terms with substitution and variable update (but without reduction), consuming them
/// in the process.
///
/// # Example
/// ```
/// use lambda_calculus::term::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);

    Ok(try!(lhs.unabs()))
}

fn _apply(lhs: &mut Term, rhs: Term, depth: usize) {
    match *lhs {
        Var(i) => if i == depth {
            *lhs = rhs; // substitute a top-level variable from lhs with rhs
            update_free_variables(lhs, depth - 1) // update free variables' indices 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.clone(), depth);
            _apply(lhs.rhs_ref_mut().unwrap(), rhs, depth);
        }
    }
}

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

/// Set to `true` for λ or `false` for \ when displaying lambda terms. The default is `true`.
pub const DISPLAY_PRETTY: bool = true;

impl fmt::Display for Term {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", show_precedence(0, self))
    }
}

fn show_precedence(context_precedence: usize, term: &Term) -> String {
    match *term {
        Var(i) => format!("{:X}", i), // max. index = 15
        Abs(ref t) => {
            let ret = format!("{}{}", if DISPLAY_PRETTY { 'λ' } else { '\\' }, t);
            parenthesize_if(context_precedence > 1, &ret).into()
        },
        App(ref t1, ref t2) => {
            let ret = format!("{}{}", show_precedence(2, t1), show_precedence(3, t2));
            parenthesize_if(context_precedence == 3, &ret).into()
        }
    }
}

fn parenthesize_if(condition: bool, input: &str) -> Cow<str> {
    if condition {
        format!("({})", input).into()
    } else {
        input.into()
    }
}

// WIP
/*
fn beta_reduce(mut term: Term) -> Result<Term, Error> {
    match term {
        App(lhs, rhs) => term = try!(apply(*lhs, *rhs)),
        Abs(t) => try!(beta_reduce(*t)),
        _ => ()
    }

    Ok(term)
}
*/
fn _beta_reduce(term: &mut Term) {
    match *term {
        App(_, _) => {
            let (lhs, rhs) = term.clone().unapp().unwrap();
            println!("attempting to reduce {}...", *term);
            if let Ok(reduced) = apply(lhs, rhs) {
                println!("\tattempt successful: {}", reduced);
                *term = reduced;
            } else {
                println!("\tfailed; trying to reduce the inner terms");
                let (mut lhs, mut rhs) = term.clone().unapp().unwrap();
                _beta_reduce(&mut lhs);
                _beta_reduce(&mut rhs);
            }
        },
        Abs(ref mut t) => _beta_reduce(t),
        _ => ()
    }
}

#[cfg(test)]
mod test {
    use arithmetic::*;
    use term::{apply, _beta_reduce};

    #[test]
    fn applying() {
        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));

        assert_eq!(apply(i(), zero()).unwrap(), abs(abs(Var(1))));
    }
        let mut unreduced = apply(succ(), zero()).unwrap();
        println!("before: {}", unreduced);
        let _ = _beta_reduce(&mut unreduced);
        println!("after: {}", unreduced);
    }

    #[test]
    fn displaying_terms() {
        assert_eq!(&format!("{}", zero()), "λλ1");
        assert_eq!(&format!("{}", succ()), "λλλ2(321)");
        assert_eq!(&format!("{}", pred()), "λλλ3(λλ1(24))(λ2)(λ1)");
    }
}
<|endoftext|>


<commit_before>use super::mpfr::Mpfr;

#[test]
fn test_init() {
	let mpfr1 : Mpfr = From::<i64>::from(1000);
	let mpfr2 : Mpfr = From::<i64>::from(5000);
	assert!(mpfr1 != mpfr2);
}<commit_msg>More tests<commit_after>use super::mpfr::Mpfr;

#[test]
fn test_set() {
	let mut a : Mpfr = From::<i64>::from(1000);
	let b : Mpfr = From::<i64>::from(5000);
	assert!(a != b);
	a.set(&b);
	assert!(a == b);
}

#[test]
fn test_eq() {
    let x: Mpfr = From::<f64>::from(1.234567);
    let y: Mpfr = From::<f64>::from(1.234567);
    let z: Mpfr = From::<f64>::from(1.234568);

    assert!(x == y);
    assert!(x != z);
    assert!(y != z);
}

#[test]
fn test_ord() {
    let x: Mpfr = From::<i64>::from(-1048576);
    let y: Mpfr = From::<i64>::from(2);
    let z: Mpfr = From::<i64>::from(1048576);

    assert!(x < y && x < z && y < z);
    assert!(x <= x && x <= y && x <= z && y <= z);
    assert!(z > y && z > x && y > x);
    assert!(z >= z && z >= y && z >= x && y >= x);
}

#[test]
#[should_panic]
fn test_div_zero() {
    let x: Mpfr = From::<i64>::from(1);
    let y = Mpfr::zero(1);
    x / y;
}

#[test]
fn test_clone() {
    let a: Mpfr = From::<i64>::from(100);
    let b = a.clone();
    assert!(b == a);
}

#[test]
fn test_add() {
	let a: Mpfr = From::<i64>::from(15);
	let b: Mpfr = From::<i64>::from(20);
	let result: Mpfr = From::<i64>::from(35);

	assert!(a + b == result);
}

#[test]
fn test_sub() {
	let a: Mpfr = From::<i64>::from(15);
	let b: Mpfr = From::<i64>::from(20);
	let result: Mpfr = From::<i64>::from(-5);

	assert!(a - b == result);
}

#[test]
fn test_mul() {
	let a: Mpfr = From::<i64>::from(15);
	let b: Mpfr = From::<i64>::from(20);
	let result: Mpfr = From::<i64>::from(300);

	assert!(a * b == result);
}

#[test]
fn test_div() {
	let a: Mpfr = From::<i64>::from(15);
	let b: Mpfr = From::<i64>::from(20);
	let result: Mpfr = From::<f64>::from(0.75);

	assert!(a / b == result);
}<|endoftext|>


<commit_before>#![allow(dead_code, unused_variables)]

use {Action, InputTranslator, RebindBuilder, InputRebind};
use window::Size;

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
enum TestAction {
    Action1, Action2, Action3, Action4, Action5,
    Action6, Action7, Action8, Action9, Action10
}

impl Action for TestAction { }

type TestBuilder = RebindBuilder<TestAction>;
type TestTranslator = InputTranslator<TestAction>;
type TestRebind = InputRebind<TestAction>;

const TEST_SIZE: Size = Size {
    width:  800,
    height: 600
};

fn create_prepopulated_builder() -> TestBuilder {
    use input::keyboard::Key;
    use input::Button::Keyboard;

    RebindBuilder::new(TEST_SIZE)
        .with_action_mapping(Keyboard(Key::Up),    TestAction::Action1)
        .with_action_mapping(Keyboard(Key::W),     TestAction::Action1)
        .with_action_mapping(Keyboard(Key::Down),  TestAction::Action2)
        .with_action_mapping(Keyboard(Key::S),     TestAction::Action2)
        .with_action_mapping(Keyboard(Key::Left),  TestAction::Action3)
        .with_action_mapping(Keyboard(Key::A),     TestAction::Action3)
        .with_action_mapping(Keyboard(Key::Right), TestAction::Action4)
        .with_action_mapping(Keyboard(Key::D),     TestAction::Action4)
}

#[test]
fn test_empty() {
    let builder = TestBuilder::new(TEST_SIZE).build();
}

#[test]
fn test_conversion_from_rebind_to_translator() {
    let translator: TestTranslator = create_prepopulated_builder().build();
    let translator_clone = translator.clone();
    let converted_translator: TestTranslator = {
        let rebind = translator.into();
        rebind.into()
    };

    assert_eq!(converted_translator, translator_clone);
}
<commit_msg>Update tests to use latest rebind api, and do some refactoring<commit_after>#![allow(dead_code, unused_variables)]

use {Action, InputTranslator, RebindBuilder, InputRebind};
use window::Size;

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
enum TestAction {
    Action1, Action2, Action3, Action4, Action5,
    Action6, Action7, Action8, Action9, Action10
}

impl Action for TestAction { }

type TestBuilder = RebindBuilder<TestAction>;
type TestTranslator = InputTranslator<TestAction>;
type TestRebind = InputRebind<TestAction>;

const TEST_SIZE: Size = Size {
    width:  800,
    height: 600
};

fn create_prepopulated_builder() -> TestBuilder {
    use input::keyboard::Key;
    use input::Button::Keyboard;

    RebindBuilder::new(TEST_SIZE)
        .with_action_mapping(Keyboard(Key::Up),    TestAction::Action1)
        .with_action_mapping(Keyboard(Key::W),     TestAction::Action1)
        .with_action_mapping(Keyboard(Key::Down),  TestAction::Action2)
        .with_action_mapping(Keyboard(Key::S),     TestAction::Action2)
        .with_action_mapping(Keyboard(Key::Left),  TestAction::Action3)
        .with_action_mapping(Keyboard(Key::A),     TestAction::Action3)
        .with_action_mapping(Keyboard(Key::Right), TestAction::Action4)
        .with_action_mapping(Keyboard(Key::D),     TestAction::Action4)
}

#[test]
fn test_empty() {
    let builder = TestBuilder::new(TEST_SIZE).build_translator();
}

#[test]
fn test_conversion_from_rebind_to_translator() {
    let translator = create_prepopulated_builder().build_translator();

    let translator_clone = translator.clone();
    let converted_translator = Into::<TestRebind>::into(translator).into();

    assert_eq!(converted_translator, translator_clone);
}
<|endoftext|>


<commit_before>
use std::time::{Instant, Duration};
use std::ops::{Add, Sub, AddAssign, SubAssign};

/// Utility to track time in a program
#[derive(Clone)]
pub struct Timer {
    start: Instant,
    last: Instant,
}

impl Timer {
    pub fn new() -> Timer {
        let now = Instant::now();

        Timer {
            start: now,
            last: now,
        }
    }

    /// Returns `(time_since_start, time_since_last_tick)`
    pub fn tick(&mut self) -> (Time, Time) {
        let now = Instant::now();

        let age = (now - self.start).into();
        let delta = (now - self.last).into();

        self.last = now;

        (age, delta)
    }
}

/// Time, stored as nanoseconds
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Time(pub u64);

impl Time {
    pub const ZERO: Time = Time(0);
    pub const NANOSECONDS_PER_SECOND: u64 = 1_000_000_000;
    pub const NANOSECONDS_PER_MILISECOND: u64 = 1_000_000;

    pub fn from_ms(ms: u64) -> Time {
        Time(ms * Time::NANOSECONDS_PER_MILISECOND)
    }

    pub fn from_secs(s: u64) -> Time {
        Time(s * Time::NANOSECONDS_PER_SECOND)
    }

    pub fn from_secs_f32(s: f32) -> Time {
        Time((s * Time::NANOSECONDS_PER_SECOND as f32) as u64)
    }

    /// Converts this timing to milliseconds, truncating any overflow. 1.999 ms will be converted to 1 ms.
    pub fn to_ms(self) -> u64 {
        self.0 / Time::NANOSECONDS_PER_MILISECOND
    }

    pub fn to_ms_f32(self) -> f32 {
        self.0 as f32 / Time::NANOSECONDS_PER_MILISECOND as f32
    }

    /// Converts this timing to seconds, truncating any overflow. 1.999 seconds will be converted to 1.
    pub fn to_secs(self) -> u64 {
        self.0 / Time::NANOSECONDS_PER_SECOND
    }

    pub fn to_secs_f32(self) -> f32 {
        self.0 as f32 / Time::NANOSECONDS_PER_SECOND as f32
    }

    pub fn max(self, other: Time) -> Time {
        ::std::cmp::max(self, other)
    }

    pub fn min(self, other: Time) -> Time {
        ::std::cmp::min(self, other)
    }

    /// Interpolates between the two given times. `t = 0` is `self`, and `t = 1` is `other`. Note
    /// that unlike other lerp functions I commonly use, this one clamps `t` to avoid overflows
    /// with unsigned integers.
    pub fn lerp(self, other: Time, t: f32) -> Time {
        if t <= 0.0 {
            return self;
        } else if t >= 1.0 {
            return other;
        }

        if self.0 > other.0 {
            let d = self.0 - other.0;
            Time(other.0 + (d as f32 * (1.0 - t)) as u64)
        } else {
            let d = other.0 - self.0;
            Time(self.0 + (d as f32 * t) as u64)
        }
    }
}

impl Add for Time {
    type Output = Time;
    fn add(self, rhs: Time) -> Time {
        Time(self.0 + rhs.0)
    }
}

impl Sub for Time {
    type Output = Time;
    fn sub(self, rhs: Time) -> Time {
        Time(self.0 - rhs.0)
    }
}

impl AddAssign for Time {
    fn add_assign(&mut self, rhs: Time) {
        self.0 += rhs.0;
    }
}

impl SubAssign for Time {
    fn sub_assign(&mut self, rhs: Time) {
        self.0 -= rhs.0;
    }
}

impl From<Duration> for Time {
    fn from(d: Duration) -> Time {
        Time(d.as_secs()*Time::NANOSECONDS_PER_SECOND + (d.subsec_nanos() as u64))
    }
}

impl From<Time> for Duration {
    fn from(t: Time) -> Duration {
        let nanos = t.0 % Time::NANOSECONDS_PER_SECOND;
        let secs = t.0 / Time::NANOSECONDS_PER_SECOND;
        Duration::new(secs, nanos as u32)
    }
}
<commit_msg>Added `fn time` to `Timer`<commit_after>
use std::time::{Instant, Duration};
use std::ops::{Add, Sub, AddAssign, SubAssign};

/// Utility to track time in a program
#[derive(Clone)]
pub struct Timer {
    start: Instant,
    last: Instant,
}

impl Timer {
    pub fn new() -> Timer {
        let now = Instant::now();

        Timer {
            start: now,
            last: now,
        }
    }

    /// Returns `(time_since_start, time_since_last_tick)`
    pub fn tick(&mut self) -> (Time, Time) {
        let now = Instant::now();

        let age = (now - self.start).into();
        let delta = (now - self.last).into();

        self.last = now;

        (age, delta)
    }

    /// Finds `time_since_start` but does not affect `time_since_last_tick` which is computed by
    /// `Timer::tick`.
    pub fn time(&self) -> Time {
        (Instant::now() - self.start).into()
    }
}

/// Time, stored as nanoseconds
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Time(pub u64);

impl Time {
    pub const ZERO: Time = Time(0);
    pub const NANOSECONDS_PER_SECOND: u64 = 1_000_000_000;
    pub const NANOSECONDS_PER_MILISECOND: u64 = 1_000_000;

    pub fn from_ms(ms: u64) -> Time {
        Time(ms * Time::NANOSECONDS_PER_MILISECOND)
    }

    pub fn from_secs(s: u64) -> Time {
        Time(s * Time::NANOSECONDS_PER_SECOND)
    }

    pub fn from_secs_f32(s: f32) -> Time {
        Time((s * Time::NANOSECONDS_PER_SECOND as f32) as u64)
    }

    /// Converts this timing to milliseconds, truncating any overflow. 1.999 ms will be converted to 1 ms.
    pub fn to_ms(self) -> u64 {
        self.0 / Time::NANOSECONDS_PER_MILISECOND
    }

    pub fn to_ms_f32(self) -> f32 {
        self.0 as f32 / Time::NANOSECONDS_PER_MILISECOND as f32
    }

    /// Converts this timing to seconds, truncating any overflow. 1.999 seconds will be converted to 1.
    pub fn to_secs(self) -> u64 {
        self.0 / Time::NANOSECONDS_PER_SECOND
    }

    pub fn to_secs_f32(self) -> f32 {
        self.0 as f32 / Time::NANOSECONDS_PER_SECOND as f32
    }

    pub fn max(self, other: Time) -> Time {
        ::std::cmp::max(self, other)
    }

    pub fn min(self, other: Time) -> Time {
        ::std::cmp::min(self, other)
    }

    /// Interpolates between the two given times. `t = 0` is `self`, and `t = 1` is `other`. Note
    /// that unlike other lerp functions I commonly use, this one clamps `t` to avoid overflows
    /// with unsigned integers.
    pub fn lerp(self, other: Time, t: f32) -> Time {
        if t <= 0.0 {
            return self;
        } else if t >= 1.0 {
            return other;
        }

        if self.0 > other.0 {
            let d = self.0 - other.0;
            Time(other.0 + (d as f32 * (1.0 - t)) as u64)
        } else {
            let d = other.0 - self.0;
            Time(self.0 + (d as f32 * t) as u64)
        }
    }
}

impl Add for Time {
    type Output = Time;
    fn add(self, rhs: Time) -> Time {
        Time(self.0 + rhs.0)
    }
}

impl Sub for Time {
    type Output = Time;
    fn sub(self, rhs: Time) -> Time {
        Time(self.0 - rhs.0)
    }
}

impl AddAssign for Time {
    fn add_assign(&mut self, rhs: Time) {
        self.0 += rhs.0;
    }
}

impl SubAssign for Time {
    fn sub_assign(&mut self, rhs: Time) {
        self.0 -= rhs.0;
    }
}

impl From<Duration> for Time {
    fn from(d: Duration) -> Time {
        Time(d.as_secs()*Time::NANOSECONDS_PER_SECOND + (d.subsec_nanos() as u64))
    }
}

impl From<Time> for Duration {
    fn from(t: Time) -> Duration {
        let nanos = t.0 % Time::NANOSECONDS_PER_SECOND;
        let secs = t.0 / Time::NANOSECONDS_PER_SECOND;
        Duration::new(secs, nanos as u32)
    }
}
<|endoftext|>


<commit_before>//! Tools for working with time.

use err::{err_str, Result};

/// The minimum spacing between two points in time to count as
/// unambiguously different.  This is related to the typical precision used
/// in *.srt subtitle files.
pub const MIN_SPACING: f32 = 0.001;

/// A period of time, in seconds.  The beginning is guaranteed to be less
/// than the end, and all times are positive.  This is lightweight
/// structure which implements `Copy`, so it can be passed by value.
///
/// ```
/// use substudy::time::Period;
///
/// let period = Period::new(1.0, 5.0).unwrap();
/// assert_eq!(1.0, period.begin());
/// assert_eq!(5.0, period.end());
/// assert_eq!(4.0, period.duration());
/// assert_eq!(3.0, period.midpoint());
/// ```
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Period {
    begin: f32,
    end: f32,
}

impl Period {
    /// Create a new time period.
    pub fn new(begin: f32, end: f32) -> Result<Period> {
        if begin < end && begin >= 0.0 && end >= 0.0 {
            Ok(Period { begin: begin, end: end })
        } else {
            Err(err_str(format!("Beginning of range is before end: {}-{}",
                                begin, end)))
        }
    }

    /// Construct a time period from two optional time periods, taking the
    /// union if both are present.  This is normally used when working with
    /// aligned subtitle pairs, either of which might be missing.
    ///
    /// ```
    /// use substudy::time::Period;
    ///
    /// assert_eq!(None, Period::from_union_opt(None, None));
    ///
    /// let p1 = Period::new(1.0, 2.0).unwrap();
    /// let p2 = Period::new(2.5, 3.0).unwrap();
    /// assert_eq!(Some(p1),
    ///            Period::from_union_opt(Some(p1), None));
    /// assert_eq!(Some(Period::new(1.0, 3.0).unwrap()),
    ///            Period::from_union_opt(Some(p1), Some(p2)));
    /// ```
    pub fn from_union_opt(p1: Option<Period>, p2: Option<Period>) ->
        Option<Period>
    {
        match (p1, p2) {
            (None, None) => None,
            (Some(p), None) => Some(p),
            (None, Some(p)) => Some(p),
            (Some(p1), Some(p2)) => Some(p1.union(p2)),
        }
    }

    /// The beginning of this time period.
    pub fn begin(&self) -> f32 {
        self.begin
    }

    /// The end of this time period.
    pub fn end(&self) -> f32 {
        self.end
    }

    /// How long this time period lasts.
    pub fn duration(&self) -> f32 {
        self.end - self.begin
    }

    /// The midpoint of this time period.
    pub fn midpoint(&self) -> f32 {
        self.begin + self.duration()/2.0
    }

    /// Grow this time period by the specified amount, making any necessary
    /// adjustments to keep it valid.
    ///
    /// ```
    /// use substudy::time::Period;
    ///
    /// let period = Period::new(1.0, 5.0).unwrap();
    /// assert_eq!(Period::new(0.0, 7.0).unwrap(),
    ///            period.grow(1.5, 2.0));
    /// ```
    pub fn grow(&self, before: f32, after: f32) -> Period {
        let mid = self.midpoint();
        Period {
            begin: (self.begin - before).min(mid).max(0.0),
            end: (self.end + after).max(mid + MIN_SPACING),
        }
    }

    /// Calculate the smallest time period containing this time period and
    /// another.
    ///
    /// ```
    /// use substudy::time::Period;
    ///
    /// let p1 = Period::new(1.0, 2.0).unwrap();
    /// let p2 = Period::new(2.5, 3.0).unwrap();
    /// assert_eq!(Period::new(1.0, 3.0).unwrap(),
    ///            p1.union(p2));
    /// ```
    pub fn union(&self, other: Period) -> Period {
        Period {
            begin: self.begin.min(other.begin),
            end: self.end.max(other.end),
        }
    }

    /// Make sure this subtitle begins after `limit`.
    pub fn begin_after(&mut self, limit: f32) -> Result<()> {
        if limit > self.end - 2.0*MIN_SPACING {
            try!(Err(err_str(format!("Cannot begin time period {:?} after {}",
                                     self, limit))));
        }

        self.begin = self.begin.max(limit + MIN_SPACING);
        Ok(())
    }

    /// Truncate this subtitle before `limit`, which must be at least
    /// `2*MIN_SPACING` greater than the begin time.
    pub fn end_before(&mut self, limit: f32) -> Result<()> {
        if limit < self.begin + 2.0*MIN_SPACING {
            try!(Err(err_str(format!("Cannot truncate time period {:?} at {}",
                                     self, limit))));
        }

        self.end = self.end.min(limit - MIN_SPACING);
        Ok(())
    }

    /// Return the absolute value of the distance between two durations, or
    /// `None` if the durations overlap.
    ///
    /// ```
    /// use substudy::time::Period;
    ///
    /// let p1 = Period::new(1.0, 2.0).unwrap();
    /// let p2 = Period::new(2.0, 3.0).unwrap();
    /// let p3 = Period::new(2.5, 3.0).unwrap();
    /// assert_eq!(Some(0.5), p1.distance(p3));
    /// assert_eq!(Some(0.5), p3.distance(p1));
    /// assert_eq!(Some(0.0), p1.distance(p2));
    /// assert_eq!(None, p2.distance(p3));
    /// ```
    pub fn distance(&self, other: Period) -> Option<f32> {
        if self.end <= other.begin {
            Some((other.begin - self.end).abs())
        } else if other.end <= self.begin {
            Some((self.begin - other.end).abs())
        } else {
            None
        }
    }

    /// Return the total amount of time which appears in both durations.
    ///
    /// ```
    /// use substudy::time::Period;
    ///
    /// let p1 = Period::new(1.0, 2.0).unwrap();
    /// let p2 = Period::new(2.0, 3.0).unwrap();
    /// let p3 = Period::new(2.5, 3.0).unwrap();
    /// assert_eq!(0.0, p1.overlap(p3));
    /// assert_eq!(0.0, p3.overlap(p1));
    /// assert_eq!(0.0, p1.overlap(p2));
    /// assert_eq!(0.5, p2.overlap(p3));
    /// ```
    pub fn overlap(&self, other: Period) -> f32 {
        (self.end.min(other.end) - self.begin.max(other.begin)).max(0.0)
    }
}

/// Convert a time to a timestamp string.  This is mostly used for giving
/// files semi-unique names so that we can dump files from multiple,
/// related export runs into a single directory without too much chance of
/// them overwriting each other unless they're basically the same file.
pub trait ToTimestamp {
    /// Convert to a string describing this time.
    fn to_timestamp(&self) -> String;

    /// Convert to a string describing this time, replacing periods with
    /// "_".
    fn to_file_timestamp(&self) -> String {
        self.to_timestamp().replace(".", "_")
    }
}

impl ToTimestamp for f32 {
    fn to_timestamp(&self) -> String {
        format!("{:09.4}", *self)
    }
}

impl ToTimestamp for Period {
    fn to_timestamp(&self) -> String {
        format!("{:09.4}-{:09.4}", self.begin(), self.end())
    }
}

#[test]
fn test_timestamp() {
    assert_eq!("00010.500", (10.5).to_timestamp());
    let period = Period::new(10.0, 20.0).unwrap();
    assert_eq!("00010.000-00020.000", period.to_timestamp());
    assert_eq!("00010_000-00020_000", period.to_file_timestamp());
}
<commit_msg>Fix: Fix timestamp format specifier<commit_after>//! Tools for working with time.

use err::{err_str, Result};

/// The minimum spacing between two points in time to count as
/// unambiguously different.  This is related to the typical precision used
/// in *.srt subtitle files.
pub const MIN_SPACING: f32 = 0.001;

/// A period of time, in seconds.  The beginning is guaranteed to be less
/// than the end, and all times are positive.  This is lightweight
/// structure which implements `Copy`, so it can be passed by value.
///
/// ```
/// use substudy::time::Period;
///
/// let period = Period::new(1.0, 5.0).unwrap();
/// assert_eq!(1.0, period.begin());
/// assert_eq!(5.0, period.end());
/// assert_eq!(4.0, period.duration());
/// assert_eq!(3.0, period.midpoint());
/// ```
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Period {
    begin: f32,
    end: f32,
}

impl Period {
    /// Create a new time period.
    pub fn new(begin: f32, end: f32) -> Result<Period> {
        if begin < end && begin >= 0.0 && end >= 0.0 {
            Ok(Period { begin: begin, end: end })
        } else {
            Err(err_str(format!("Beginning of range is before end: {}-{}",
                                begin, end)))
        }
    }

    /// Construct a time period from two optional time periods, taking the
    /// union if both are present.  This is normally used when working with
    /// aligned subtitle pairs, either of which might be missing.
    ///
    /// ```
    /// use substudy::time::Period;
    ///
    /// assert_eq!(None, Period::from_union_opt(None, None));
    ///
    /// let p1 = Period::new(1.0, 2.0).unwrap();
    /// let p2 = Period::new(2.5, 3.0).unwrap();
    /// assert_eq!(Some(p1),
    ///            Period::from_union_opt(Some(p1), None));
    /// assert_eq!(Some(Period::new(1.0, 3.0).unwrap()),
    ///            Period::from_union_opt(Some(p1), Some(p2)));
    /// ```
    pub fn from_union_opt(p1: Option<Period>, p2: Option<Period>) ->
        Option<Period>
    {
        match (p1, p2) {
            (None, None) => None,
            (Some(p), None) => Some(p),
            (None, Some(p)) => Some(p),
            (Some(p1), Some(p2)) => Some(p1.union(p2)),
        }
    }

    /// The beginning of this time period.
    pub fn begin(&self) -> f32 {
        self.begin
    }

    /// The end of this time period.
    pub fn end(&self) -> f32 {
        self.end
    }

    /// How long this time period lasts.
    pub fn duration(&self) -> f32 {
        self.end - self.begin
    }

    /// The midpoint of this time period.
    pub fn midpoint(&self) -> f32 {
        self.begin + self.duration()/2.0
    }

    /// Grow this time period by the specified amount, making any necessary
    /// adjustments to keep it valid.
    ///
    /// ```
    /// use substudy::time::Period;
    ///
    /// let period = Period::new(1.0, 5.0).unwrap();
    /// assert_eq!(Period::new(0.0, 7.0).unwrap(),
    ///            period.grow(1.5, 2.0));
    /// ```
    pub fn grow(&self, before: f32, after: f32) -> Period {
        let mid = self.midpoint();
        Period {
            begin: (self.begin - before).min(mid).max(0.0),
            end: (self.end + after).max(mid + MIN_SPACING),
        }
    }

    /// Calculate the smallest time period containing this time period and
    /// another.
    ///
    /// ```
    /// use substudy::time::Period;
    ///
    /// let p1 = Period::new(1.0, 2.0).unwrap();
    /// let p2 = Period::new(2.5, 3.0).unwrap();
    /// assert_eq!(Period::new(1.0, 3.0).unwrap(),
    ///            p1.union(p2));
    /// ```
    pub fn union(&self, other: Period) -> Period {
        Period {
            begin: self.begin.min(other.begin),
            end: self.end.max(other.end),
        }
    }

    /// Make sure this subtitle begins after `limit`.
    pub fn begin_after(&mut self, limit: f32) -> Result<()> {
        if limit > self.end - 2.0*MIN_SPACING {
            try!(Err(err_str(format!("Cannot begin time period {:?} after {}",
                                     self, limit))));
        }

        self.begin = self.begin.max(limit + MIN_SPACING);
        Ok(())
    }

    /// Truncate this subtitle before `limit`, which must be at least
    /// `2*MIN_SPACING` greater than the begin time.
    pub fn end_before(&mut self, limit: f32) -> Result<()> {
        if limit < self.begin + 2.0*MIN_SPACING {
            try!(Err(err_str(format!("Cannot truncate time period {:?} at {}",
                                     self, limit))));
        }

        self.end = self.end.min(limit - MIN_SPACING);
        Ok(())
    }

    /// Return the absolute value of the distance between two durations, or
    /// `None` if the durations overlap.
    ///
    /// ```
    /// use substudy::time::Period;
    ///
    /// let p1 = Period::new(1.0, 2.0).unwrap();
    /// let p2 = Period::new(2.0, 3.0).unwrap();
    /// let p3 = Period::new(2.5, 3.0).unwrap();
    /// assert_eq!(Some(0.5), p1.distance(p3));
    /// assert_eq!(Some(0.5), p3.distance(p1));
    /// assert_eq!(Some(0.0), p1.distance(p2));
    /// assert_eq!(None, p2.distance(p3));
    /// ```
    pub fn distance(&self, other: Period) -> Option<f32> {
        if self.end <= other.begin {
            Some((other.begin - self.end).abs())
        } else if other.end <= self.begin {
            Some((self.begin - other.end).abs())
        } else {
            None
        }
    }

    /// Return the total amount of time which appears in both durations.
    ///
    /// ```
    /// use substudy::time::Period;
    ///
    /// let p1 = Period::new(1.0, 2.0).unwrap();
    /// let p2 = Period::new(2.0, 3.0).unwrap();
    /// let p3 = Period::new(2.5, 3.0).unwrap();
    /// assert_eq!(0.0, p1.overlap(p3));
    /// assert_eq!(0.0, p3.overlap(p1));
    /// assert_eq!(0.0, p1.overlap(p2));
    /// assert_eq!(0.5, p2.overlap(p3));
    /// ```
    pub fn overlap(&self, other: Period) -> f32 {
        (self.end.min(other.end) - self.begin.max(other.begin)).max(0.0)
    }
}

/// Convert a time to a timestamp string.  This is mostly used for giving
/// files semi-unique names so that we can dump files from multiple,
/// related export runs into a single directory without too much chance of
/// them overwriting each other unless they're basically the same file.
pub trait ToTimestamp {
    /// Convert to a string describing this time.
    fn to_timestamp(&self) -> String;

    /// Convert to a string describing this time, replacing periods with
    /// "_".
    fn to_file_timestamp(&self) -> String {
        self.to_timestamp().replace(".", "_")
    }
}

impl ToTimestamp for f32 {
    fn to_timestamp(&self) -> String {
        format!("{:09.3}", *self)
    }
}

impl ToTimestamp for Period {
    fn to_timestamp(&self) -> String {
        format!("{:09.3}-{:09.3}", self.begin(), self.end())
    }
}

#[test]
fn test_timestamp() {
    assert_eq!("00010.500", (10.5).to_timestamp());
    let period = Period::new(10.0, 20.0).unwrap();
    assert_eq!("00010.000-00020.000", period.to_timestamp());
    assert_eq!("00010_000-00020_000", period.to_file_timestamp());
}
<|endoftext|>


<commit_before>use request::ToParams;
use errors::*;

use std::str::FromStr;

#[derive(Debug)]
pub struct UserId(String);
#[derive(Debug)]
pub struct OAuthToken(String);

// These trait impls provide a way to reference our types as &str
impl AsRef<str> for UserId {
    fn as_ref(&self) -> &str {
        self.0.as_str()
    }
}

impl AsRef<str> for OAuthToken {
    fn as_ref(&self) -> &str {
        self.0.as_str()
    }
}

// These trait impls provide a way to &str#parse()
impl FromStr for UserId {
    type Err = Error;

    fn from_str(s: &str) -> Result<UserId> {
        Ok(UserId(s.to_owned()))
    }
}

impl FromStr for OAuthToken {
    type Err = Error;

    fn from_str(s: &str) -> Result<OAuthToken> {
        Ok(OAuthToken(s.to_owned()))
    }
}

// These trait impls are similar to FromStr (but are infallible)
impl<'a> From<&'a str> for UserId where Self: FromStr {
    fn from(s: &'a str) -> UserId {
        s.parse().unwrap()
    }
}

impl<'a> From<&'a str> for OAuthToken where Self: FromStr {
    fn from(s: &'a str) -> OAuthToken {
        s.parse().unwrap()
    }
}

// These trait impls take ownership of a given String
impl From<String> for UserId {
    fn from(s: String) -> UserId {
        UserId(s)
    }
}

impl From<String> for OAuthToken {
    fn from(s: String) -> OAuthToken {
        OAuthToken(s)
    }
}

#[derive(Debug)]
pub enum User {
    UserId(UserId),
    OAuthToken(OAuthToken)
}

impl Into<User> for UserId {
    fn into(self) -> User {
        User::UserId(self)
    }
}

impl Into<User> for OAuthToken {
    fn into(self) -> User {
        User::OAuthToken(self)
    }
}

impl User {
    pub fn from_user_id<T: Into<UserId>>(user_id: T) -> Self {
        User::UserId(user_id.into())
    }

    pub fn from_oauth_token<T: Into<OAuthToken>>(token: T) -> Self {
        User::OAuthToken(token.into())
    }
}

impl ToParams for User {
    fn to_params(&self) -> Vec<(&str, &str)> {
        let (field, value) = match *self {
            User::UserId(ref user_id) => ("user_id", user_id.as_ref()),
            User::OAuthToken(ref token) => ("access_token", token.as_ref())
        };
        vec![(field, value)]
    }
}

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

    #[test]
    fn transforms_user_id_into_params() {
        let user_id = "my_user_id";
        let user = User::from_user_id(user_id.to_owned());

        let result = user.to_params();

        let expected = vec![("user_id", user_id)];
        assert_eq!(expected, result);
    }

    #[test]
    fn transforms_oauth_token_into_params() {
        let oauth_token = "my_oauth_token";
        let user = User::from_oauth_token(oauth_token.to_owned());

        let result = user.to_params();

        let expected = vec![("access_token", oauth_token)];
        assert_eq!(expected, result);
    }
}
<commit_msg>user: add doc tests<commit_after>use request::ToParams;
use errors::*;

use std::str::FromStr;

#[derive(Debug)]
pub struct UserId(String);
#[derive(Debug)]
pub struct OAuthToken(String);

// These trait impls provide a way to reference our types as &str
impl AsRef<str> for UserId {
    fn as_ref(&self) -> &str {
        self.0.as_str()
    }
}

impl AsRef<str> for OAuthToken {
    fn as_ref(&self) -> &str {
        self.0.as_str()
    }
}

// These trait impls provide a way to &str#parse()
impl FromStr for UserId {
    type Err = Error;

    fn from_str(s: &str) -> Result<UserId> {
        Ok(UserId(s.to_owned()))
    }
}

impl FromStr for OAuthToken {
    type Err = Error;

    fn from_str(s: &str) -> Result<OAuthToken> {
        Ok(OAuthToken(s.to_owned()))
    }
}

// These trait impls are similar to FromStr (but are infallible)
impl<'a> From<&'a str> for UserId where Self: FromStr {
    fn from(s: &'a str) -> UserId {
        s.parse().unwrap()
    }
}

impl<'a> From<&'a str> for OAuthToken where Self: FromStr {
    fn from(s: &'a str) -> OAuthToken {
        s.parse().unwrap()
    }
}

// These trait impls take ownership of a given String
impl From<String> for UserId {
    fn from(s: String) -> UserId {
        UserId(s)
    }
}

impl From<String> for OAuthToken {
    fn from(s: String) -> OAuthToken {
        OAuthToken(s)
    }
}

#[derive(Debug)]
pub enum User {
    UserId(UserId),
    OAuthToken(OAuthToken)
}

impl Into<User> for UserId {
    fn into(self) -> User {
        User::UserId(self)
    }
}

impl Into<User> for OAuthToken {
    fn into(self) -> User {
        User::OAuthToken(self)
    }
}

impl User {
    /// Creates a `User` from a `UserId`.
    ///
    /// # Examples
    ///
    /// ```
    /// use threescalers::user::*;
    ///
    /// let user = User::from_user_id("my_id");
    /// ```
    pub fn from_user_id<T: Into<UserId>>(user_id: T) -> Self {
        User::UserId(user_id.into())
    }

    /// Creates a `User` from an `OAuthToken`.
    ///
    /// # Examples
    ///
    /// ```
    /// use threescalers::user::*;
    ///
    /// let user = User::from_oauth_token("my_token");
    /// ```
    pub fn from_oauth_token<T: Into<OAuthToken>>(token: T) -> Self {
        User::OAuthToken(token.into())
    }
}

impl ToParams for User {
    fn to_params(&self) -> Vec<(&str, &str)> {
        let (field, value) = match *self {
            User::UserId(ref user_id) => ("user_id", user_id.as_ref()),
            User::OAuthToken(ref token) => ("access_token", token.as_ref())
        };
        vec![(field, value)]
    }
}

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

    #[test]
    fn transforms_user_id_into_params() {
        let user_id = "my_user_id";
        let user = User::from_user_id(user_id.to_owned());

        let result = user.to_params();

        let expected = vec![("user_id", user_id)];
        assert_eq!(expected, result);
    }

    #[test]
    fn transforms_oauth_token_into_params() {
        let oauth_token = "my_oauth_token";
        let user = User::from_oauth_token(oauth_token.to_owned());

        let result = user.to_params();

        let expected = vec![("access_token", oauth_token)];
        assert_eq!(expected, result);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 Robert Clipsham <robert@octarineparrot.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Miscellaneous utilities for low level networking

use bindings::libc;

use std::fmt;
use std::from_str;
use std::mem;
use std::num::from_str_radix;
use std::io::net::ip::IpAddr;

#[cfg(not(windows))] use internal;

/// A MAC address
#[deriving(PartialEq, Eq, Clone)]
pub struct MacAddr(pub u8, pub u8, pub u8, pub u8, pub u8, pub u8);

impl fmt::Show for MacAddr {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            MacAddr(a, b, c, d, e, f) =>
                write!(fmt, "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}",
                       a, b, c, d, e, f)
        }
    }
}

impl from_str::FromStr for MacAddr {
    fn from_str(s: &str) -> Option<MacAddr> {
        let mut parts = [0u8, ..6];
        let mut splits = s.split(':');
        let mut i = 0;
        for split in splits {
            if i == 6 {
                return None;
            }
            match from_str_radix(split, 16) {
                Some(b) if split.len() != 0 => parts[i] = b,
                _ => return None,
            }
            i += 1;
        }

        if i == 6 {
            Some(MacAddr(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5]))
        } else {
            None
        }
    }
}

#[test]
fn mac_addr_from_str() {
    assert_eq!(from_str::<MacAddr>("00:00:00:00:00:00"), Some(MacAddr(0, 0, 0, 0, 0, 0)));
    assert_eq!(from_str::<MacAddr>("ff:ff:ff:ff:ff:ff"), Some(MacAddr(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF)));
    assert_eq!(from_str::<MacAddr>("12:34:56:78:90:ab"), Some(MacAddr(0x12, 0x34, 0x56, 0x78, 0x90, 0xAB)));
    assert_eq!(from_str::<MacAddr>("::::::"), None);
    assert_eq!(from_str::<MacAddr>("0::::::"), None);
    assert_eq!(from_str::<MacAddr>("::::0::"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78:"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78:90"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78:90:"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78:90:00:00"), None);
    assert_eq!(from_str::<MacAddr>("xx:xx:xx:xx:xx:xx"), None);
}

/// Represents a network interface and its associated addresses
#[deriving(Clone, PartialEq, Eq, Show)]
pub struct NetworkInterface {
    /// The name of the interface
    pub name: String,
    /// The interface index (operating system specific)
    pub index: u32,
    /// A MAC address for the interface
    pub mac: Option<MacAddr>,
    /// An IP addresses for the interface
    pub ips: Option<Vec<IpAddr>>,
    /// Operating system specific flags for the interface
    pub flags: u32,
}

impl NetworkInterface {
    /// Retreive the MAC address associated with the interface
    pub fn mac_address(&self) -> MacAddr {
        self.mac.unwrap()
    }

    /// Is the interface a loopback interface?
    pub fn is_loopback(&self) -> bool {
        self.flags & (libc::IFF_LOOPBACK as u32) != 0
    }
}

#[cfg(target_os = "linux")]
fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> (Option<MacAddr>, Option<IpAddr>) {
    unsafe {
        if sa.is_null() {
            (None, None)
        } else if (*sa).sa_family as libc::c_int == libc::AF_PACKET {
            let sll: *const libc::sockaddr_ll = mem::transmute(sa);
            let mac = MacAddr((*sll).sll_addr[0], (*sll).sll_addr[1],
                              (*sll).sll_addr[2], (*sll).sll_addr[3],
                              (*sll).sll_addr[4], (*sll).sll_addr[5]);
            return (Some(mac), None);
        } else {
            let addr = internal::sockaddr_to_addr(mem::transmute(sa),
                                        mem::size_of::<libc::sockaddr_storage>());
            return match addr {
                Ok(sa) => (None, Some(sa.ip)),
                Err(_) => (None, None)
            };
        }
    }
}

#[cfg(any(target_os = "freebsd", target_os = "macos"))]
fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> (Option<MacAddr>, Option<IpAddr>) {
    use bindings::bpf;
    unsafe {
        if sa.is_null() {
            (None, None)
        } else if (*sa).sa_family as libc::c_int == bpf::AF_LINK {
            let sdl: *const bpf::sockaddr_dl = mem::transmute(sa);
            let nlen = (*sdl).sdl_nlen as uint;
            let mac = MacAddr((*sdl).sdl_data[nlen + 0] as u8,
                              (*sdl).sdl_data[nlen + 1] as u8,
                              (*sdl).sdl_data[nlen + 2] as u8,
                              (*sdl).sdl_data[nlen + 3] as u8,
                              (*sdl).sdl_data[nlen + 4] as u8,
                              (*sdl).sdl_data[nlen + 5] as u8
                      );
            (Some(mac), None)
        } else {
            let addr = internal::sockaddr_to_addr(mem::transmute(sa),
                                        mem::size_of::<libc::sockaddr_storage>());
            match addr {
                Ok(sa) => (None, Some(sa.ip)),
                Err(_) => (None, None)
            }
        }
    }
}

/// Get a list of available network interfaces for the current machine.
#[inline]
pub fn get_network_interfaces() -> Vec<NetworkInterface> {
    get_network_interfaces_impl()
}

#[cfg(not(windows))]
fn get_network_interfaces_impl() -> Vec<NetworkInterface> {
    use std::string::raw as strraw;

    let mut ifaces: Vec<NetworkInterface> = Vec::new();
    unsafe {
        let mut addrs: *mut libc::ifaddrs = mem::uninitialized();
        if libc::getifaddrs(&mut addrs) != 0 {
            return ifaces;
        }
        let mut addr = addrs;
        while addr.is_not_null() {
            let name = strraw::from_buf((*addr).ifa_name as *const u8);
            let (mac, ip) = sockaddr_to_network_addr((*addr).ifa_addr as *const libc::sockaddr);
            let ni = NetworkInterface {
                name: name.clone(),
                index: 0,
                mac: mac,
                ips: ip.map(|ip| [ip].to_vec()),
                flags: (*addr).ifa_flags
            };
            let mut found: bool = false;
            for iface in ifaces.iter_mut() {
                if name == iface.name {
                    merge(iface, &ni);
                    found = true;
                }
            }
            if !found {
                ifaces.push(ni);
            }

            addr = (*addr).ifa_next;
        }
        libc::freeifaddrs(addrs);

        for iface in ifaces.iter_mut() {
            iface.index = iface.name.with_c_str(
                |name| libc::if_nametoindex(name)
            );
        }
        return ifaces;
    }

    fn merge(old: &mut NetworkInterface, new: &NetworkInterface) {
        old.mac = match new.mac {
            None => old.mac,
            _ => new.mac
        };
        match (&mut old.ips, &new.ips) {
            (&Some(ref mut old_ips), &Some(ref new_ips)) => old_ips.push_all(new_ips.as_slice()),
            _ => {}
        };
        old.flags = old.flags | new.flags;
    }

}

#[cfg(windows)]
fn get_network_interfaces_impl() -> Vec<NetworkInterface> {
    use std::str::from_utf8;
    use std::string::raw;

    use bindings::winpcap;

    let mut adapters_size = 0u32;

    unsafe {
        let mut tmp: winpcap::IP_ADAPTER_INFO = mem::zeroed();
        // FIXME [windows] This only gets IPv4 addresses - should use GetAdaptersAddresses
        winpcap::GetAdaptersInfo(
            &mut tmp,
            &mut adapters_size
        );
    }

    let vec_size = adapters_size / mem::size_of::<winpcap::IP_ADAPTER_INFO>() as u32;

    let mut adapters = Vec::with_capacity(vec_size as uint);

    // FIXME [windows] Check return code
    unsafe {
        winpcap::GetAdaptersInfo(adapters.as_mut_ptr(), &mut adapters_size);
    }

    // Create a complete list of NetworkInterfaces for the machine
    let mut cursor = adapters.as_mut_ptr();
    let mut all_ifaces = Vec::with_capacity(vec_size as uint);
    while cursor.is_not_null() {
        let mac = unsafe {
                    MacAddr((*cursor).Address[0],
                            (*cursor).Address[1],
                            (*cursor).Address[2],
                            (*cursor).Address[3],
                            (*cursor).Address[4],
                            (*cursor).Address[5])
                  };
        let mut ip_cursor = unsafe { &mut (*cursor).IpAddressList as winpcap::PIP_ADDR_STRING};
        let mut ips: Vec<IpAddr> = Vec::new();
        while ip_cursor.is_not_null() {
            let ip_str = unsafe {
                            raw::from_buf((*ip_cursor).IpAddress.String.as_ptr() as *const u8)
                         };
            ips.push(from_str(ip_str.as_slice()).unwrap());
            ip_cursor = unsafe { (*ip_cursor).Next };
        }
        unsafe {
            all_ifaces.push(NetworkInterface {
                        name: raw::from_buf((*cursor).AdapterName.as_ptr() as *const u8),
                        index: (*cursor).Index,
                        mac: Some(mac),
                        ips: Some(ips),
                        //flags: (*cursor).Type, // FIXME [windows]
                        flags: 0,
                     });

            cursor = (*cursor).Next;
        }
    }

    let mut buf = [0u8, ..4096];
    let mut buflen = buf.len() as u32;

    // Gets list of supported adapters in form:
    // adapter1\0adapter2\0\0desc1\0desc2\0\0
    if unsafe { winpcap::PacketGetAdapterNames(buf.as_mut_ptr() as *mut i8, &mut buflen) } == 0 {
        // FIXME [windows] Should allocate a buffer big enough and try again
        //        - size should be buf.len() + buflen (buflen is overwritten)
        panic!("FIXME [windows] unable to get interface list");
    }

    let buf_str = from_utf8(buf).unwrap();
    let iface_names = buf_str.split_str("\0\0").next();
    let mut vec = Vec::new();

    // Return only supported adapters
    match iface_names {
        Some(iface_names) => {
            for iface in iface_names.split('\0') {
                let name = iface.to_string();
                let next = all_ifaces.iter()
                                     .filter(|x| name.as_slice().ends_with(x.name.as_slice()))
                                     .next();
                if next.is_some() {
                    let mut iface = next.unwrap().clone();
                    iface.name = name;
                    vec.push(iface);
                }
            }
        },
        None => ()
    };

    vec
}

<commit_msg>Fixes FromStr moving locations<commit_after>// Copyright (c) 2014 Robert Clipsham <robert@octarineparrot.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Miscellaneous utilities for low level networking

use bindings::libc;

use std::fmt;
use std::str::FromStr;
use std::mem;
use std::num::from_str_radix;
use std::io::net::ip::IpAddr;

#[cfg(not(windows))] use internal;

/// A MAC address
#[deriving(PartialEq, Eq, Clone)]
pub struct MacAddr(pub u8, pub u8, pub u8, pub u8, pub u8, pub u8);

impl fmt::Show for MacAddr {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            MacAddr(a, b, c, d, e, f) =>
                write!(fmt, "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}",
                       a, b, c, d, e, f)
        }
    }
}

impl FromStr for MacAddr {
    fn from_str(s: &str) -> Option<MacAddr> {
        let mut parts = [0u8, ..6];
        let mut splits = s.split(':');
        let mut i = 0;
        for split in splits {
            if i == 6 {
                return None;
            }
            match from_str_radix(split, 16) {
                Some(b) if split.len() != 0 => parts[i] = b,
                _ => return None,
            }
            i += 1;
        }

        if i == 6 {
            Some(MacAddr(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5]))
        } else {
            None
        }
    }
}

#[test]
fn mac_addr_from_str() {
    assert_eq!(from_str::<MacAddr>("00:00:00:00:00:00"), Some(MacAddr(0, 0, 0, 0, 0, 0)));
    assert_eq!(from_str::<MacAddr>("ff:ff:ff:ff:ff:ff"), Some(MacAddr(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF)));
    assert_eq!(from_str::<MacAddr>("12:34:56:78:90:ab"), Some(MacAddr(0x12, 0x34, 0x56, 0x78, 0x90, 0xAB)));
    assert_eq!(from_str::<MacAddr>("::::::"), None);
    assert_eq!(from_str::<MacAddr>("0::::::"), None);
    assert_eq!(from_str::<MacAddr>("::::0::"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78:"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78:90"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78:90:"), None);
    assert_eq!(from_str::<MacAddr>("12:34:56:78:90:00:00"), None);
    assert_eq!(from_str::<MacAddr>("xx:xx:xx:xx:xx:xx"), None);
}

/// Represents a network interface and its associated addresses
#[deriving(Clone, PartialEq, Eq, Show)]
pub struct NetworkInterface {
    /// The name of the interface
    pub name: String,
    /// The interface index (operating system specific)
    pub index: u32,
    /// A MAC address for the interface
    pub mac: Option<MacAddr>,
    /// An IP addresses for the interface
    pub ips: Option<Vec<IpAddr>>,
    /// Operating system specific flags for the interface
    pub flags: u32,
}

impl NetworkInterface {
    /// Retreive the MAC address associated with the interface
    pub fn mac_address(&self) -> MacAddr {
        self.mac.unwrap()
    }

    /// Is the interface a loopback interface?
    pub fn is_loopback(&self) -> bool {
        self.flags & (libc::IFF_LOOPBACK as u32) != 0
    }
}

#[cfg(target_os = "linux")]
fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> (Option<MacAddr>, Option<IpAddr>) {
    unsafe {
        if sa.is_null() {
            (None, None)
        } else if (*sa).sa_family as libc::c_int == libc::AF_PACKET {
            let sll: *const libc::sockaddr_ll = mem::transmute(sa);
            let mac = MacAddr((*sll).sll_addr[0], (*sll).sll_addr[1],
                              (*sll).sll_addr[2], (*sll).sll_addr[3],
                              (*sll).sll_addr[4], (*sll).sll_addr[5]);
            return (Some(mac), None);
        } else {
            let addr = internal::sockaddr_to_addr(mem::transmute(sa),
                                        mem::size_of::<libc::sockaddr_storage>());
            return match addr {
                Ok(sa) => (None, Some(sa.ip)),
                Err(_) => (None, None)
            };
        }
    }
}

#[cfg(any(target_os = "freebsd", target_os = "macos"))]
fn sockaddr_to_network_addr(sa: *const libc::sockaddr) -> (Option<MacAddr>, Option<IpAddr>) {
    use bindings::bpf;
    unsafe {
        if sa.is_null() {
            (None, None)
        } else if (*sa).sa_family as libc::c_int == bpf::AF_LINK {
            let sdl: *const bpf::sockaddr_dl = mem::transmute(sa);
            let nlen = (*sdl).sdl_nlen as uint;
            let mac = MacAddr((*sdl).sdl_data[nlen + 0] as u8,
                              (*sdl).sdl_data[nlen + 1] as u8,
                              (*sdl).sdl_data[nlen + 2] as u8,
                              (*sdl).sdl_data[nlen + 3] as u8,
                              (*sdl).sdl_data[nlen + 4] as u8,
                              (*sdl).sdl_data[nlen + 5] as u8
                      );
            (Some(mac), None)
        } else {
            let addr = internal::sockaddr_to_addr(mem::transmute(sa),
                                        mem::size_of::<libc::sockaddr_storage>());
            match addr {
                Ok(sa) => (None, Some(sa.ip)),
                Err(_) => (None, None)
            }
        }
    }
}

/// Get a list of available network interfaces for the current machine.
#[inline]
pub fn get_network_interfaces() -> Vec<NetworkInterface> {
    get_network_interfaces_impl()
}

#[cfg(not(windows))]
fn get_network_interfaces_impl() -> Vec<NetworkInterface> {
    use std::string::raw as strraw;

    let mut ifaces: Vec<NetworkInterface> = Vec::new();
    unsafe {
        let mut addrs: *mut libc::ifaddrs = mem::uninitialized();
        if libc::getifaddrs(&mut addrs) != 0 {
            return ifaces;
        }
        let mut addr = addrs;
        while addr.is_not_null() {
            let name = strraw::from_buf((*addr).ifa_name as *const u8);
            let (mac, ip) = sockaddr_to_network_addr((*addr).ifa_addr as *const libc::sockaddr);
            let ni = NetworkInterface {
                name: name.clone(),
                index: 0,
                mac: mac,
                ips: ip.map(|ip| [ip].to_vec()),
                flags: (*addr).ifa_flags
            };
            let mut found: bool = false;
            for iface in ifaces.iter_mut() {
                if name == iface.name {
                    merge(iface, &ni);
                    found = true;
                }
            }
            if !found {
                ifaces.push(ni);
            }

            addr = (*addr).ifa_next;
        }
        libc::freeifaddrs(addrs);

        for iface in ifaces.iter_mut() {
            iface.index = iface.name.with_c_str(
                |name| libc::if_nametoindex(name)
            );
        }
        return ifaces;
    }

    fn merge(old: &mut NetworkInterface, new: &NetworkInterface) {
        old.mac = match new.mac {
            None => old.mac,
            _ => new.mac
        };
        match (&mut old.ips, &new.ips) {
            (&Some(ref mut old_ips), &Some(ref new_ips)) => old_ips.push_all(new_ips.as_slice()),
            _ => {}
        };
        old.flags = old.flags | new.flags;
    }

}

#[cfg(windows)]
fn get_network_interfaces_impl() -> Vec<NetworkInterface> {
    use std::str::from_utf8;
    use std::string::raw;

    use bindings::winpcap;

    let mut adapters_size = 0u32;

    unsafe {
        let mut tmp: winpcap::IP_ADAPTER_INFO = mem::zeroed();
        // FIXME [windows] This only gets IPv4 addresses - should use GetAdaptersAddresses
        winpcap::GetAdaptersInfo(
            &mut tmp,
            &mut adapters_size
        );
    }

    let vec_size = adapters_size / mem::size_of::<winpcap::IP_ADAPTER_INFO>() as u32;

    let mut adapters = Vec::with_capacity(vec_size as uint);

    // FIXME [windows] Check return code
    unsafe {
        winpcap::GetAdaptersInfo(adapters.as_mut_ptr(), &mut adapters_size);
    }

    // Create a complete list of NetworkInterfaces for the machine
    let mut cursor = adapters.as_mut_ptr();
    let mut all_ifaces = Vec::with_capacity(vec_size as uint);
    while cursor.is_not_null() {
        let mac = unsafe {
                    MacAddr((*cursor).Address[0],
                            (*cursor).Address[1],
                            (*cursor).Address[2],
                            (*cursor).Address[3],
                            (*cursor).Address[4],
                            (*cursor).Address[5])
                  };
        let mut ip_cursor = unsafe { &mut (*cursor).IpAddressList as winpcap::PIP_ADDR_STRING};
        let mut ips: Vec<IpAddr> = Vec::new();
        while ip_cursor.is_not_null() {
            let ip_str = unsafe {
                            raw::from_buf((*ip_cursor).IpAddress.String.as_ptr() as *const u8)
                         };
            ips.push(from_str(ip_str.as_slice()).unwrap());
            ip_cursor = unsafe { (*ip_cursor).Next };
        }
        unsafe {
            all_ifaces.push(NetworkInterface {
                        name: raw::from_buf((*cursor).AdapterName.as_ptr() as *const u8),
                        index: (*cursor).Index,
                        mac: Some(mac),
                        ips: Some(ips),
                        //flags: (*cursor).Type, // FIXME [windows]
                        flags: 0,
                     });

            cursor = (*cursor).Next;
        }
    }

    let mut buf = [0u8, ..4096];
    let mut buflen = buf.len() as u32;

    // Gets list of supported adapters in form:
    // adapter1\0adapter2\0\0desc1\0desc2\0\0
    if unsafe { winpcap::PacketGetAdapterNames(buf.as_mut_ptr() as *mut i8, &mut buflen) } == 0 {
        // FIXME [windows] Should allocate a buffer big enough and try again
        //        - size should be buf.len() + buflen (buflen is overwritten)
        panic!("FIXME [windows] unable to get interface list");
    }

    let buf_str = from_utf8(buf).unwrap();
    let iface_names = buf_str.split_str("\0\0").next();
    let mut vec = Vec::new();

    // Return only supported adapters
    match iface_names {
        Some(iface_names) => {
            for iface in iface_names.split('\0') {
                let name = iface.to_string();
                let next = all_ifaces.iter()
                                     .filter(|x| name.as_slice().ends_with(x.name.as_slice()))
                                     .next();
                if next.is_some() {
                    let mut iface = next.unwrap().clone();
                    iface.name = name;
                    vec.push(iface);
                }
            }
        },
        None => ()
    };

    vec
}

<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub fn supports_aesni() -> bool {
    let mut flags: u32;
    unsafe {
        asm!(
        "
        mov $$1, %eax;
        cpuid;
        mov %ecx, $0;
        "
        : "=r" (flags) // output
        : // input
        : "eax", "ebx", "ecx", "edx" // clobbers
        );
        // No idea why, but on 32-bit targets, the compiler complains
        // about not having enough registers. Adding in this dummy
        // section, however, seems to fix it.
        asm!("");
    }

    (flags & 0x02000000) != 0
}

#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
#[allow(unused_assignments)]
#[allow(unused_variables)]
unsafe fn fixed_time_eq_asm(mut lhsp: *const u8, mut rhsp: *const u8, mut count: uint) -> bool {
    let mut result: u8 = 0;

    asm!(
        "
            1:

            mov ($1), %cl
            xor ($2), %cl
            or %cl, $0

            inc $1
            inc $2
            dec $3
            jnz 1b
        "
        : "+r" (result), "+r" (lhsp), "+r" (rhsp), "+r" (count) // all input and output
        : // input
        : "cl", "cc" // clobbers
        : "volatile" // flags
    );

    result == 0
}

#[cfg(target_arch = "arm")]
#[allow(unused_assignments)]
unsafe fn fixed_time_eq_asm(mut lhsp: *const u8, mut rhsp: *const u8, mut count: uint) -> bool {
    let mut result: u8 = 0;

    asm!(
        "
            1:

            ldrb r4, [$1]
            ldrb r5, [$2]
            eor r4, r4, r5
            orr $0, $0, r4

            add $1, $1, #1
            add $2, $2, #1
            subs $3, $3, #1
            bne 1b
        "
        : "+r" (result), "+r" (lhsp), "+r" (rhsp), "+r" (count) // all input and output
        : // input
        : "r4", "r5", "cc" // clobbers
        : "volatile" // flags
    );

    result == 0
}

/// Compare two vectors using a fixed number of operations. If the two vectors are not of equal
/// length, the function returns false immediately.
pub fn fixed_time_eq(lhs: &[u8], rhs: &[u8]) -> bool {
    if lhs.len() != rhs.len() {
        false
    } else if lhs.len() == 0 {
        true
    } else {
        let count = lhs.len();

        unsafe {
            let lhsp = lhs.get_unchecked(0);
            let rhsp = rhs.get_unchecked(0);
            fixed_time_eq_asm(lhsp, rhsp, count)
        }
    }
}

#[cfg(test)]
mod test {
    use util::fixed_time_eq;

    #[test]
    pub fn test_fixed_time_eq() {
        let a = [0, 1, 2];
        let b = [0, 1, 2];
        let c = [0, 1, 9];
        let d = [9, 1, 2];
        let e = [2, 1, 0];
        let f = [2, 2, 2];
        let g = [0, 0, 0];

        assert!(fixed_time_eq(&a, &a));
        assert!(fixed_time_eq(&a, &b));

        assert!(!fixed_time_eq(&a, &c));
        assert!(!fixed_time_eq(&a, &d));
        assert!(!fixed_time_eq(&a, &e));
        assert!(!fixed_time_eq(&a, &f));
        assert!(!fixed_time_eq(&a, &g));
    }
}
<commit_msg>Pick more appropriate int types for util<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub fn supports_aesni() -> bool {
    let mut flags: u32;
    unsafe {
        asm!(
        "
        mov $$1, %eax;
        cpuid;
        mov %ecx, $0;
        "
        : "=r" (flags) // output
        : // input
        : "eax", "ebx", "ecx", "edx" // clobbers
        );
        // No idea why, but on 32-bit targets, the compiler complains
        // about not having enough registers. Adding in this dummy
        // section, however, seems to fix it.
        asm!("");
    }

    (flags & 0x02000000) != 0
}

#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
#[allow(unused_assignments)]
#[allow(unused_variables)]
unsafe fn fixed_time_eq_asm(mut lhsp: *const u8, mut rhsp: *const u8, mut count: usize) -> bool {
    let mut result: u8 = 0;

    asm!(
        "
            1:

            mov ($1), %cl
            xor ($2), %cl
            or %cl, $0

            inc $1
            inc $2
            dec $3
            jnz 1b
        "
        : "+r" (result), "+r" (lhsp), "+r" (rhsp), "+r" (count) // all input and output
        : // input
        : "cl", "cc" // clobbers
        : "volatile" // flags
    );

    result == 0
}

#[cfg(target_arch = "arm")]
#[allow(unused_assignments)]
unsafe fn fixed_time_eq_asm(mut lhsp: *const u8, mut rhsp: *const u8, mut count: usize) -> bool {
    let mut result: u8 = 0;

    asm!(
        "
            1:

            ldrb r4, [$1]
            ldrb r5, [$2]
            eor r4, r4, r5
            orr $0, $0, r4

            add $1, $1, #1
            add $2, $2, #1
            subs $3, $3, #1
            bne 1b
        "
        : "+r" (result), "+r" (lhsp), "+r" (rhsp), "+r" (count) // all input and output
        : // input
        : "r4", "r5", "cc" // clobbers
        : "volatile" // flags
    );

    result == 0
}

/// Compare two vectors using a fixed number of operations. If the two vectors are not of equal
/// length, the function returns false immediately.
pub fn fixed_time_eq(lhs: &[u8], rhs: &[u8]) -> bool {
    if lhs.len() != rhs.len() {
        false
    } else if lhs.len() == 0 {
        true
    } else {
        let count = lhs.len();

        unsafe {
            let lhsp = lhs.get_unchecked(0);
            let rhsp = rhs.get_unchecked(0);
            fixed_time_eq_asm(lhsp, rhsp, count)
        }
    }
}

#[cfg(test)]
mod test {
    use util::fixed_time_eq;

    #[test]
    pub fn test_fixed_time_eq() {
        let a = [0, 1, 2];
        let b = [0, 1, 2];
        let c = [0, 1, 9];
        let d = [9, 1, 2];
        let e = [2, 1, 0];
        let f = [2, 2, 2];
        let g = [0, 0, 0];

        assert!(fixed_time_eq(&a, &a));
        assert!(fixed_time_eq(&a, &b));

        assert!(!fixed_time_eq(&a, &c));
        assert!(!fixed_time_eq(&a, &d));
        assert!(!fixed_time_eq(&a, &e));
        assert!(!fixed_time_eq(&a, &f));
        assert!(!fixed_time_eq(&a, &g));
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use std::ffi::CString;
use std::fs;
use std::io;
use std::os::unix::prelude::*;
use std::path::Path;

use self::libc::{c_int, c_char, timeval, time_t, suseconds_t, c_long};
use self::libc::{timespec};

use FileTime;

cfg_if! {
    if #[cfg(target_os = "linux")] {
        mod linux;
        pub use self::linux::*;
    } else if #[cfg(any(target_os = "android",
                        target_os = "solaris",
                        target_os = "netbsd",
                        target_os = "openbsd"))] {
        mod utimensat;
        pub use self::utimensat::*;
    } else {
        mod utimes;
        pub use self::utimes::*;
    }
}

#[allow(dead_code)]
fn utimes(p: &Path,
          atime: FileTime,
          mtime: FileTime,
          utimes: unsafe extern fn(*const c_char, *const timeval) -> c_int)
    -> io::Result<()>
{
    let times = [to_timeval(&atime), to_timeval(&mtime)];
    let p = try!(CString::new(p.as_os_str().as_bytes()));
    return if unsafe { utimes(p.as_ptr() as *const _, times.as_ptr()) == 0 } {
        Ok(())
    } else {
        Err(io::Error::last_os_error())
    };

    fn to_timeval(ft: &FileTime) -> timeval {
        timeval {
            tv_sec: ft.seconds() as time_t,
            tv_usec: (ft.nanoseconds() / 1000) as suseconds_t,
        }
    }
}

#[allow(dead_code)]
fn utimensat(p: &Path,
             atime: FileTime,
             mtime: FileTime,
             f: unsafe extern fn(c_int, *const c_char, *const timespec, c_int) -> c_int,
             flags: c_int)
    -> io::Result<()>
{
    let times = [to_timespec(&atime), to_timespec(&mtime)];
    let p = try!(CString::new(p.as_os_str().as_bytes()));
    let rc = unsafe {
        f(libc::AT_FDCWD, p.as_ptr() as *const _, times.as_ptr(), flags)
    };
    return if rc == 0 {
        Ok(())
    } else {
        Err(io::Error::last_os_error())
    };

    fn to_timespec(ft: &FileTime) -> timespec {
        timespec {
            tv_sec: ft.seconds() as time_t,
            tv_nsec: ft.nanoseconds() as c_long,
        }
    }
}

pub fn from_last_modification_time(meta: &fs::Metadata) -> FileTime {
    FileTime {
        seconds: meta.mtime() as u64,
        nanos: meta.mtime_nsec() as u32,
    }
}

pub fn from_last_access_time(meta: &fs::Metadata) -> FileTime {
    FileTime {
        seconds: meta.atime() as u64,
        nanos: meta.atime_nsec() as u32,
    }
}

pub fn from_creation_time(meta: &fs::Metadata) -> Option<FileTime> {
    macro_rules! birthtim {
        ($(($e:expr, $i:ident)),*) => {
            #[cfg(any($(target_os = $e),*))]
            fn imp(meta: &fs::Metadata) -> Option<FileTime> {
                $(
                    #[cfg(target_os = $e)]
                    use std::os::$i::fs::MetadataExt;
                )*
                Some(FileTime {
                    seconds: meta.st_birthtime() as u64,
                    nanos: meta.st_birthtime_nsec() as u32,
                })
            }

            #[cfg(all($(not(target_os = $e)),*))]
            fn imp(_meta: &fs::Metadata) -> Option<FileTime> {
                None
            }
        }
    }

    birthtim! {
        ("bitrig", bitrig),
        ("freebsd", freebsd),
        ("ios", ios),
        ("macos", macos),
        ("openbsd", openbsd)
    }

    imp(meta)
}
<commit_msg>Fix compilation for x86_64-unknown-linux-gnux32 target<commit_after>extern crate libc;

use std::ffi::CString;
use std::fs;
use std::io;
use std::os::unix::prelude::*;
use std::path::Path;

use self::libc::{c_int, c_char, timeval, time_t, suseconds_t};
use self::libc::{timespec};

use FileTime;

cfg_if! {
    if #[cfg(target_os = "linux")] {
        mod linux;
        pub use self::linux::*;
    } else if #[cfg(any(target_os = "android",
                        target_os = "solaris",
                        target_os = "netbsd",
                        target_os = "openbsd"))] {
        mod utimensat;
        pub use self::utimensat::*;
    } else {
        mod utimes;
        pub use self::utimes::*;
    }
}

#[allow(dead_code)]
fn utimes(p: &Path,
          atime: FileTime,
          mtime: FileTime,
          utimes: unsafe extern fn(*const c_char, *const timeval) -> c_int)
    -> io::Result<()>
{
    let times = [to_timeval(&atime), to_timeval(&mtime)];
    let p = try!(CString::new(p.as_os_str().as_bytes()));
    return if unsafe { utimes(p.as_ptr() as *const _, times.as_ptr()) == 0 } {
        Ok(())
    } else {
        Err(io::Error::last_os_error())
    };

    fn to_timeval(ft: &FileTime) -> timeval {
        timeval {
            tv_sec: ft.seconds() as time_t,
            tv_usec: (ft.nanoseconds() / 1000) as suseconds_t,
        }
    }
}

#[allow(dead_code)]
fn utimensat(p: &Path,
             atime: FileTime,
             mtime: FileTime,
             f: unsafe extern fn(c_int, *const c_char, *const timespec, c_int) -> c_int,
             flags: c_int)
    -> io::Result<()>
{
    let times = [to_timespec(&atime), to_timespec(&mtime)];
    let p = try!(CString::new(p.as_os_str().as_bytes()));
    let rc = unsafe {
        f(libc::AT_FDCWD, p.as_ptr() as *const _, times.as_ptr(), flags)
    };
    return if rc == 0 {
        Ok(())
    } else {
        Err(io::Error::last_os_error())
    };

    fn to_timespec(ft: &FileTime) -> timespec {
        timespec {
            tv_sec: ft.seconds() as time_t,
            tv_nsec: ft.nanoseconds() as _,
        }
    }
}

pub fn from_last_modification_time(meta: &fs::Metadata) -> FileTime {
    FileTime {
        seconds: meta.mtime() as u64,
        nanos: meta.mtime_nsec() as u32,
    }
}

pub fn from_last_access_time(meta: &fs::Metadata) -> FileTime {
    FileTime {
        seconds: meta.atime() as u64,
        nanos: meta.atime_nsec() as u32,
    }
}

pub fn from_creation_time(meta: &fs::Metadata) -> Option<FileTime> {
    macro_rules! birthtim {
        ($(($e:expr, $i:ident)),*) => {
            #[cfg(any($(target_os = $e),*))]
            fn imp(meta: &fs::Metadata) -> Option<FileTime> {
                $(
                    #[cfg(target_os = $e)]
                    use std::os::$i::fs::MetadataExt;
                )*
                Some(FileTime {
                    seconds: meta.st_birthtime() as u64,
                    nanos: meta.st_birthtime_nsec() as u32,
                })
            }

            #[cfg(all($(not(target_os = $e)),*))]
            fn imp(_meta: &fs::Metadata) -> Option<FileTime> {
                None
            }
        }
    }

    birthtim! {
        ("bitrig", bitrig),
        ("freebsd", freebsd),
        ("ios", ios),
        ("macos", macos),
        ("openbsd", openbsd)
    }

    imp(meta)
}
<|endoftext|>


<commit_before>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Implementations that just need to read from a file
use crate::{
    util::LazyUsize,
    util_libc::{open_readonly, sys_fill_exact},
    Error,
};
use core::{
    cell::UnsafeCell,
    sync::atomic::{AtomicUsize, Ordering::Relaxed},
};

#[cfg(any(
    target_os = "dragonfly",
    target_os = "emscripten",
    target_os = "haiku",
    target_os = "macos",
    target_os = "solaris",
    target_os = "illumos"
))]
const FILE_PATH: &str = "/dev/random\0";
#[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))]
const FILE_PATH: &str = "/dev/urandom\0";

pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
    let fd = get_rng_fd()?;
    let read = |buf: &mut [u8]| unsafe { libc::read(fd, buf.as_mut_ptr() as *mut _, buf.len()) };

    if cfg!(target_os = "emscripten") {
        // `Crypto.getRandomValues` documents `dest` should be at most 65536 bytes.
        for chunk in dest.chunks_mut(65536) {
            sys_fill_exact(chunk, read)?;
        }
    } else {
        sys_fill_exact(dest, read)?;
    }
    Ok(())
}

// Returns the file descriptor for the device file used to retrieve random
// bytes. The file will be opened exactly once. All successful calls will
// return the same file descriptor. This file descriptor is never closed.
fn get_rng_fd() -> Result<libc::c_int, Error> {
    static FD: AtomicUsize = AtomicUsize::new(LazyUsize::UNINIT);
    fn get_fd() -> Option<libc::c_int> {
        match FD.load(Relaxed) {
            LazyUsize::UNINIT => None,
            val => Some(val as libc::c_int),
        }
    }

    // Use double-checked locking to avoid acquiring the lock if possible.
    if let Some(fd) = get_fd() {
        return Ok(fd);
    }

    // SAFETY: We use the mutex only in this method, and we always unlock it
    // before returning, making sure we don't violate the pthread_mutex_t API.
    static MUTEX: Mutex = Mutex::new();
    unsafe { MUTEX.lock() };
    let _guard = DropGuard(|| unsafe { MUTEX.unlock() });

    if let Some(fd) = get_fd() {
        return Ok(fd);
    }

    // On Linux, /dev/urandom might return insecure values.
    #[cfg(any(target_os = "android", target_os = "linux"))]
    wait_until_rng_ready()?;

    let fd = unsafe { open_readonly(FILE_PATH)? };
    // The fd always fits in a usize without conflicting with UNINIT.
    debug_assert!(fd >= 0 && (fd as usize) < LazyUsize::UNINIT);
    FD.store(fd as usize, Relaxed);

    Ok(fd)
}

// Succeeds once /dev/urandom is safe to read from
#[cfg(any(target_os = "android", target_os = "linux"))]
fn wait_until_rng_ready() -> Result<(), Error> {
    // Poll /dev/random to make sure it is ok to read from /dev/urandom.
    let fd = unsafe { open_readonly("/dev/random\0")? };
    let mut pfd = libc::pollfd {
        fd,
        events: libc::POLLIN,
        revents: 0,
    };
    let _guard = DropGuard(|| unsafe {
        libc::close(fd);
    });

    loop {
        // A negative timeout means an infinite timeout.
        let res = unsafe { libc::poll(&mut pfd, 1, -1) };
        if res >= 0 {
            debug_assert_eq!(res, 1); // We only used one fd, and cannot timeout.
            return Ok(());
        }
        let err = crate::util_libc::last_os_error();
        match err.raw_os_error() {
            Some(libc::EINTR) | Some(libc::EAGAIN) => continue,
            _ => return Err(err),
        }
    }
}

struct Mutex(UnsafeCell<libc::pthread_mutex_t>);

impl Mutex {
    const fn new() -> Self {
        Self(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER))
    }
    unsafe fn lock(&self) {
        let r = libc::pthread_mutex_lock(self.0.get());
        debug_assert_eq!(r, 0);
    }
    unsafe fn unlock(&self) {
        let r = libc::pthread_mutex_unlock(self.0.get());
        debug_assert_eq!(r, 0);
    }
}

unsafe impl Sync for Mutex {}

struct DropGuard<F: FnMut()>(F);

impl<F: FnMut()> Drop for DropGuard<F> {
    fn drop(&mut self) {
        self.0()
    }
}
<commit_msg>Fix get_rng_fd comment typo (#240)<commit_after>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Implementations that just need to read from a file
use crate::{
    util::LazyUsize,
    util_libc::{open_readonly, sys_fill_exact},
    Error,
};
use core::{
    cell::UnsafeCell,
    sync::atomic::{AtomicUsize, Ordering::Relaxed},
};

#[cfg(any(
    target_os = "dragonfly",
    target_os = "emscripten",
    target_os = "haiku",
    target_os = "macos",
    target_os = "solaris",
    target_os = "illumos"
))]
const FILE_PATH: &str = "/dev/random\0";
#[cfg(any(target_os = "android", target_os = "linux", target_os = "redox"))]
const FILE_PATH: &str = "/dev/urandom\0";

pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
    let fd = get_rng_fd()?;
    let read = |buf: &mut [u8]| unsafe { libc::read(fd, buf.as_mut_ptr() as *mut _, buf.len()) };

    if cfg!(target_os = "emscripten") {
        // `Crypto.getRandomValues` documents `dest` should be at most 65536 bytes.
        for chunk in dest.chunks_mut(65536) {
            sys_fill_exact(chunk, read)?;
        }
    } else {
        sys_fill_exact(dest, read)?;
    }
    Ok(())
}

// Returns the file descriptor for the device file used to retrieve random
// bytes. The file will be opened exactly once. All subsequent calls will
// return the same file descriptor. This file descriptor is never closed.
fn get_rng_fd() -> Result<libc::c_int, Error> {
    static FD: AtomicUsize = AtomicUsize::new(LazyUsize::UNINIT);
    fn get_fd() -> Option<libc::c_int> {
        match FD.load(Relaxed) {
            LazyUsize::UNINIT => None,
            val => Some(val as libc::c_int),
        }
    }

    // Use double-checked locking to avoid acquiring the lock if possible.
    if let Some(fd) = get_fd() {
        return Ok(fd);
    }

    // SAFETY: We use the mutex only in this method, and we always unlock it
    // before returning, making sure we don't violate the pthread_mutex_t API.
    static MUTEX: Mutex = Mutex::new();
    unsafe { MUTEX.lock() };
    let _guard = DropGuard(|| unsafe { MUTEX.unlock() });

    if let Some(fd) = get_fd() {
        return Ok(fd);
    }

    // On Linux, /dev/urandom might return insecure values.
    #[cfg(any(target_os = "android", target_os = "linux"))]
    wait_until_rng_ready()?;

    let fd = unsafe { open_readonly(FILE_PATH)? };
    // The fd always fits in a usize without conflicting with UNINIT.
    debug_assert!(fd >= 0 && (fd as usize) < LazyUsize::UNINIT);
    FD.store(fd as usize, Relaxed);

    Ok(fd)
}

// Succeeds once /dev/urandom is safe to read from
#[cfg(any(target_os = "android", target_os = "linux"))]
fn wait_until_rng_ready() -> Result<(), Error> {
    // Poll /dev/random to make sure it is ok to read from /dev/urandom.
    let fd = unsafe { open_readonly("/dev/random\0")? };
    let mut pfd = libc::pollfd {
        fd,
        events: libc::POLLIN,
        revents: 0,
    };
    let _guard = DropGuard(|| unsafe {
        libc::close(fd);
    });

    loop {
        // A negative timeout means an infinite timeout.
        let res = unsafe { libc::poll(&mut pfd, 1, -1) };
        if res >= 0 {
            debug_assert_eq!(res, 1); // We only used one fd, and cannot timeout.
            return Ok(());
        }
        let err = crate::util_libc::last_os_error();
        match err.raw_os_error() {
            Some(libc::EINTR) | Some(libc::EAGAIN) => continue,
            _ => return Err(err),
        }
    }
}

struct Mutex(UnsafeCell<libc::pthread_mutex_t>);

impl Mutex {
    const fn new() -> Self {
        Self(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER))
    }
    unsafe fn lock(&self) {
        let r = libc::pthread_mutex_lock(self.0.get());
        debug_assert_eq!(r, 0);
    }
    unsafe fn unlock(&self) {
        let r = libc::pthread_mutex_unlock(self.0.get());
        debug_assert_eq!(r, 0);
    }
}

unsafe impl Sync for Mutex {}

struct DropGuard<F: FnMut()>(F);

impl<F: FnMut()> Drop for DropGuard<F> {
    fn drop(&mut self) {
        self.0()
    }
}
<|endoftext|>