<commit_before>use std::time;
use std::fmt;
use std::ops;
use std::convert;

use chrono;

use super::error;
use super::error::DurationError;

pub const SECS_PER_DAY: f64 = 60.0*60.0*24.0;
pub const SECS_PER_HOUR: f64 = 60.0*60.0;
pub const SECS_PER_MINUTE: f64 = 60.0;

pub trait TimePoint<Rhs=Self> {
    fn duration_between(&self, rhs: &Rhs) -> FloatDuration;
}

#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub struct FloatDuration {
    secs: f64,
}

#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct DecomposedTime {
    pub days: u32,
    pub hours: u32,
    pub minutes: u32,
    pub seconds: u32,
    pub fractional_seconds: f64,
    pub sign: i8,
}

impl FloatDuration {
    pub fn new(secs: f64) -> FloatDuration {
        FloatDuration {secs}
    }

    pub fn days(days: f64) -> FloatDuration {
        FloatDuration {secs: days * (3600.0 * 24.0)}
    }
    pub fn hours(hours: f64) -> FloatDuration {
        FloatDuration {secs: hours * 3600.0}
    }
    pub fn minutes(mins: f64) -> FloatDuration {
        FloatDuration {secs: mins * 60.0}
    }
    pub fn seconds(secs: f64) -> FloatDuration {
        FloatDuration {secs}
    }
    pub fn milliseconds(millis: f64) -> FloatDuration {
        FloatDuration {secs: millis / 1000.0}
    }
    pub fn microseconds(micros: f64) -> FloatDuration {
        FloatDuration {secs: micros / 1.0e6}
    }
    pub fn nanoseconds(nanos: f64) -> FloatDuration {
        FloatDuration {secs: nanos / 1.0e9}
    }

    pub fn decompose(&self) -> DecomposedTime {
        let mut secs_left = self.secs;

        let days = (secs_left / SECS_PER_DAY).trunc();
        secs_left -= days*SECS_PER_DAY;
        let hours = (secs_left / SECS_PER_HOUR).trunc();
        secs_left -= hours*SECS_PER_HOUR;
        let minutes = (secs_left / SECS_PER_MINUTE).trunc();
        secs_left -= minutes*SECS_PER_MINUTE;
        let seconds = secs_left.trunc();
        let fract = secs_left.fract();

        DecomposedTime {
            days: days as u32,
            hours: hours as u32,
            minutes: minutes as u32,
            seconds: seconds as u32,
            fractional_seconds: fract,
            sign: self.secs.signum() as i8,
        }
    }

    pub fn as_days(&self) -> f64 {
        self.secs / SECS_PER_DAY
    }
    pub fn as_hours(&self) -> f64 {
        self.secs / SECS_PER_HOUR
    }
    pub fn as_minutes(&self) -> f64 {
        self.secs / SECS_PER_MINUTE
    }
    pub fn as_seconds(&self) -> f64 {
        self.secs
    }
    pub fn as_milliseconds(&self) -> f64 {
        self.secs * 1.0e3
    }
    pub fn as_microseconds(&self) -> f64 {
        self.secs * 1.0e6
    }
    pub fn as_nanoseconds(&self) -> f64 {
        self.secs * 1.0e9
    }

    pub fn zero() -> FloatDuration {
        FloatDuration {secs: 0.0}
    }
    pub fn is_zero(&self) -> bool {
        self.secs == 0.0
    }
    pub fn is_positive(&self) -> bool {
        self.secs.is_sign_positive()
    }
    pub fn is_negative(&self) -> bool {
        self.secs.is_sign_negative()
    }

    pub fn as_std(&self) -> error::Result<time::Duration> {
        if self.secs.is_sign_negative() {
            Err(DurationError::StdOutOfRange)
        } else {
            let seconds = self.secs.trunc();
            let nanos = self.secs.fract() * 1e9;

            Ok(time::Duration::new(seconds as u64, nanos as u32))
        }
    }

    pub fn from_std(duration: time::Duration) -> error::Result<FloatDuration> {
        Ok(FloatDuration::seconds(
            (duration.as_secs() as f64) + (duration.subsec_nanos() as f64)*1.0e-9))
    }

    pub fn from_decomposed(decomposed: &DecomposedTime) -> FloatDuration {
        let seconds = (decomposed.days as f64)*SECS_PER_DAY
            + (decomposed.hours as f64)*SECS_PER_HOUR
            + (decomposed.minutes as f64)*SECS_PER_MINUTE
            + (decomposed.seconds as f64)
            + decomposed.fractional_seconds;

        FloatDuration {
            secs: seconds
        }
    }
}

impl FloatDuration {
    pub fn as_chrono_duration(&self) -> error::Result<chrono::Duration> {
        let std_duration = self.as_std()?;
        chrono::Duration::from_std(std_duration).map_err(|e| convert::From::from(e))
    }

    pub fn from_chrono_duration(duration: &chrono::Duration)
            -> error::Result<FloatDuration>
    {
        let std_duration = duration.to_std()?;
        FloatDuration::from_std(std_duration)
    }
}

impl DecomposedTime {
    pub fn new() -> DecomposedTime {
        DecomposedTime { days: 0, hours: 0, minutes: 0, seconds: 0,
            fractional_seconds: 0.0, sign: 1 }
    }

    pub fn from_components(days: u32, hours: u32, minutes: u32,
               seconds: u32, fractional_seconds: f64) -> DecomposedTime
    {
        DecomposedTime {
            days, hours, minutes, seconds, fractional_seconds, sign: 1}
    }

    pub fn negate(mut self) -> DecomposedTime {
        self.sign *= -1;
        self
    }
}

impl fmt::Display for DecomposedTime {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        if self.days > 0 {
            write!(fmt, "{}d ", self.days as u64)?;
        }

        if self.sign.is_negative() {
            write!(fmt, "-")?;
        }
        write!(fmt, "{:02}:{:02}:{:02}.{}",
            self.hours,
            self.minutes,
            self.seconds,
            self.fractional_seconds)
    }
}

impl fmt::Display for FloatDuration {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        if self.secs > SECS_PER_DAY {
            write!(fmt, "{} days", self.as_days())
        } else if self.secs > SECS_PER_HOUR {
            write!(fmt, "{} hours", self.as_hours())
        } else if self.secs > SECS_PER_MINUTE {
            write!(fmt, "{} minutes", self.as_minutes())
        } else if self.secs > 1.0 {
            write!(fmt, "{} seconds", self.as_seconds())
        } else if self.secs > 1.0e-3 {
            write!(fmt, "{} milliseconds", self.as_milliseconds())
        } else if self.secs > 1.0e-6 {
            write!(fmt, "{} microseconds", self.as_microseconds())
        } else {
            write!(fmt, "{} nanoseconds", self.as_nanoseconds())
        }
    }
}

impl ops::Neg for FloatDuration {
    type Output = FloatDuration;

    fn neg(self) -> FloatDuration {
        FloatDuration {secs: -self.secs}
    }
}

impl ops::Add<FloatDuration> for FloatDuration {
    type Output = FloatDuration;

    fn add(self, rhs: FloatDuration) -> FloatDuration {
        FloatDuration {secs: self.secs + rhs.secs}
    }
}
impl ops::Sub<FloatDuration> for FloatDuration {
    type Output = FloatDuration;

    fn sub(self, rhs: FloatDuration) -> FloatDuration {
        FloatDuration {secs: self.secs - rhs.secs}
    }
}

impl ops::Mul<f64> for FloatDuration {
    type Output = FloatDuration;

    fn mul(self, rhs: f64) -> FloatDuration {
        FloatDuration {secs: self.secs * rhs}
    }
}
impl ops::Div<f64> for FloatDuration {
    type Output = FloatDuration;

    fn div(self, rhs: f64) -> FloatDuration {
        FloatDuration {secs: self.secs / rhs}
    }
}

impl ops::AddAssign<FloatDuration> for FloatDuration {
    fn add_assign(&mut self, rhs: FloatDuration) {
        self.secs += rhs.secs;
    }
}
impl ops::SubAssign<FloatDuration> for FloatDuration {
    fn sub_assign(&mut self, rhs: FloatDuration) {
        self.secs -= rhs.secs;
    }
}

impl ops::MulAssign<f64> for FloatDuration {
    fn mul_assign(&mut self, rhs: f64) {
        self.secs *= rhs;
    }
}
impl ops::DivAssign<f64> for FloatDuration {
    fn div_assign(&mut self, rhs: f64) {
        self.secs /= rhs;
    }
}

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

    #[test]
    fn test_construct() {
        let duration1 = FloatDuration::hours(3.0);
        assert_eq!(duration1.as_hours(), 3.0);
        assert_eq!(duration1.as_minutes(), 180.0);
        assert_eq!(duration1.as_seconds(), 180.0*60.0);
        assert_eq!(duration1.as_days(), 3.0/24.0);
        assert_eq!(duration1.as_milliseconds(), 180.0*60.0*1000.0);

        let duration2 = FloatDuration::milliseconds(55.0);
        assert_eq!(duration2.as_seconds(), 0.055);
        assert_eq!(duration2.as_milliseconds(), 55.0);
        assert_eq!(duration2.as_microseconds(), 55000.0);
        assert_eq!(duration2.as_nanoseconds(), 55000000.0);
        assert!(!duration2.is_zero());

        let duration3 = FloatDuration::zero();
        assert!(duration3.is_zero());

        assert_eq!(FloatDuration::days(1.5), FloatDuration::hours(36.0));
        assert_eq!(FloatDuration::minutes(30.0), FloatDuration::hours(0.5));
        assert_eq!(FloatDuration::seconds(180.0), FloatDuration::minutes(3.0));
        assert_eq!(FloatDuration::seconds(3.5), FloatDuration::milliseconds(3500.0));
        assert_eq!(FloatDuration::microseconds(300.0), FloatDuration::milliseconds(0.30));
        assert_eq!(FloatDuration::nanoseconds(1000.0), FloatDuration::microseconds(1.0));
    }

    #[test]
    fn test_arithmetic() {
        let duration1 = FloatDuration::minutes(5.0) + FloatDuration::seconds(30.0);
        assert_eq!(duration1, FloatDuration::seconds(330.0));

        let duration2 = FloatDuration::hours(3.0) * 2.5;
        assert_eq!(duration2, FloatDuration::hours(7.5));

        let duration3 = FloatDuration::days(3.0) / 3.0 - FloatDuration::hours(2.0);
        assert_eq!(duration3, FloatDuration::hours(22.0));

        let duration4 = FloatDuration::zero() + FloatDuration::milliseconds(500.0)
            + FloatDuration::microseconds(500.0);
        assert_eq!(duration4, FloatDuration::microseconds(500500.0));

    }

    #[test]
    fn test_std_conversion() {
        let duration1 = FloatDuration::minutes(5.0);
        let std_duration1 = duration1.as_std().unwrap();
        assert!(duration1.is_positive());
        assert_eq!(std_duration1, time::Duration::new(300, 0));
        assert_eq!(FloatDuration::from_std(std_duration1).unwrap(), duration1);

        let duration2 = FloatDuration::hours(-2.0);
        assert!(duration2.is_negative());
        assert!(!duration2.as_std().is_ok());
        let std_duration2 = (-duration2).as_std().unwrap();
        assert_eq!(std_duration2, time::Duration::new(3600*2, 0));
        assert_eq!(FloatDuration::from_std(std_duration2).unwrap(), -duration2);
    }

    #[test]
    fn test_display() {
        use std::fmt::Write;

        let mut buffer1 = "".to_string();
        let mut buffer1_2 = "".to_string();
        let duration1 = FloatDuration::minutes(3.5);

        write!(buffer1, "{}", duration1);
        write!(buffer1_2, "{}", duration1.decompose());
        assert_eq!(buffer1, "3.5 minutes");
        assert_eq!(buffer1_2, "00:03:30.0");

        let mut buffer2 = "".to_string();
        let mut buffer2_2 = "".to_string();
        let duration2 = FloatDuration::days(3.0) + FloatDuration::hours(12.0);

        write!(buffer2, "{}", duration2);
        write!(buffer2_2, "{}", duration2.decompose());
        assert_eq!(buffer2, "3.5 days");
        assert_eq!(buffer2_2, "3d 12:00:00.0");
    }
}

<commit_msg>Added `min_value` and `max_value` functions. Fixed some warnings.<commit_after>use std::time;
use std::fmt;
use std::ops;
use std::convert;
use std::f64;

use chrono;

use super::error;
use super::error::DurationError;

pub const SECS_PER_DAY: f64 = 60.0*60.0*24.0;
pub const SECS_PER_HOUR: f64 = 60.0*60.0;
pub const SECS_PER_MINUTE: f64 = 60.0;

pub trait TimePoint<Rhs=Self> {
    fn duration_between(&self, rhs: &Rhs) -> FloatDuration;
}

#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
pub struct FloatDuration {
    secs: f64,
}

#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct DecomposedTime {
    pub days: u32,
    pub hours: u32,
    pub minutes: u32,
    pub seconds: u32,
    pub fractional_seconds: f64,
    pub sign: i8,
}

impl FloatDuration {
    pub fn new(secs: f64) -> FloatDuration {
        FloatDuration {secs}
    }

    pub fn days(days: f64) -> FloatDuration {
        FloatDuration {secs: days * (3600.0 * 24.0)}
    }
    pub fn hours(hours: f64) -> FloatDuration {
        FloatDuration {secs: hours * 3600.0}
    }
    pub fn minutes(mins: f64) -> FloatDuration {
        FloatDuration {secs: mins * 60.0}
    }
    pub fn seconds(secs: f64) -> FloatDuration {
        FloatDuration {secs}
    }
    pub fn milliseconds(millis: f64) -> FloatDuration {
        FloatDuration {secs: millis / 1000.0}
    }
    pub fn microseconds(micros: f64) -> FloatDuration {
        FloatDuration {secs: micros / 1.0e6}
    }
    pub fn nanoseconds(nanos: f64) -> FloatDuration {
        FloatDuration {secs: nanos / 1.0e9}
    }

    pub fn decompose(&self) -> DecomposedTime {
        let mut secs_left = self.secs;

        let days = (secs_left / SECS_PER_DAY).trunc();
        secs_left -= days*SECS_PER_DAY;
        let hours = (secs_left / SECS_PER_HOUR).trunc();
        secs_left -= hours*SECS_PER_HOUR;
        let minutes = (secs_left / SECS_PER_MINUTE).trunc();
        secs_left -= minutes*SECS_PER_MINUTE;
        let seconds = secs_left.trunc();
        let fract = secs_left.fract();

        DecomposedTime {
            days: days as u32,
            hours: hours as u32,
            minutes: minutes as u32,
            seconds: seconds as u32,
            fractional_seconds: fract,
            sign: self.secs.signum() as i8,
        }
    }

    pub fn as_days(&self) -> f64 {
        self.secs / SECS_PER_DAY
    }
    pub fn as_hours(&self) -> f64 {
        self.secs / SECS_PER_HOUR
    }
    pub fn as_minutes(&self) -> f64 {
        self.secs / SECS_PER_MINUTE
    }
    pub fn as_seconds(&self) -> f64 {
        self.secs
    }
    pub fn as_milliseconds(&self) -> f64 {
        self.secs * 1.0e3
    }
    pub fn as_microseconds(&self) -> f64 {
        self.secs * 1.0e6
    }
    pub fn as_nanoseconds(&self) -> f64 {
        self.secs * 1.0e9
    }

    pub fn zero() -> FloatDuration {
        FloatDuration {secs: 0.0}
    }
    pub fn is_zero(&self) -> bool {
        self.secs == 0.0
    }
    pub fn is_positive(&self) -> bool {
        self.secs.is_sign_positive()
    }
    pub fn is_negative(&self) -> bool {
        self.secs.is_sign_negative()
    }

    pub fn min_value() -> FloatDuration {
        FloatDuration { secs: f64::MIN }
    }
    pub fn max_value() -> FloatDuration {
        FloatDuration { secs: f64::MAX }
    }

    pub fn as_std(&self) -> error::Result<time::Duration> {
        if self.secs.is_sign_negative() {
            Err(DurationError::StdOutOfRange)
        } else {
            let seconds = self.secs.trunc();
            let nanos = self.secs.fract() * 1e9;

            Ok(time::Duration::new(seconds as u64, nanos as u32))
        }
    }

    pub fn from_std(duration: time::Duration) -> error::Result<FloatDuration> {
        Ok(FloatDuration::seconds(
            (duration.as_secs() as f64) + (duration.subsec_nanos() as f64)*1.0e-9))
    }

    pub fn from_decomposed(decomposed: &DecomposedTime) -> FloatDuration {
        let seconds = (decomposed.days as f64)*SECS_PER_DAY
            + (decomposed.hours as f64)*SECS_PER_HOUR
            + (decomposed.minutes as f64)*SECS_PER_MINUTE
            + (decomposed.seconds as f64)
            + decomposed.fractional_seconds;

        FloatDuration {
            secs: seconds
        }
    }
}

impl FloatDuration {
    pub fn as_chrono_duration(&self) -> error::Result<chrono::Duration> {
        let std_duration = self.as_std()?;
        chrono::Duration::from_std(std_duration).map_err(|e| convert::From::from(e))
    }

    pub fn from_chrono_duration(duration: &chrono::Duration)
            -> error::Result<FloatDuration>
    {
        let std_duration = duration.to_std()?;
        FloatDuration::from_std(std_duration)
    }
}

impl DecomposedTime {
    pub fn new() -> DecomposedTime {
        DecomposedTime { days: 0, hours: 0, minutes: 0, seconds: 0,
            fractional_seconds: 0.0, sign: 1 }
    }

    pub fn from_components(days: u32, hours: u32, minutes: u32,
               seconds: u32, fractional_seconds: f64) -> DecomposedTime
    {
        DecomposedTime {
            days, hours, minutes, seconds, fractional_seconds, sign: 1}
    }

    pub fn negate(mut self) -> DecomposedTime {
        self.sign *= -1;
        self
    }
}

impl fmt::Display for DecomposedTime {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        if self.days > 0 {
            write!(fmt, "{}d ", self.days as u64)?;
        }

        if self.sign.is_negative() {
            write!(fmt, "-")?;
        }
        write!(fmt, "{:02}:{:02}:{:02}.{}",
            self.hours,
            self.minutes,
            self.seconds,
            self.fractional_seconds)
    }
}

impl fmt::Display for FloatDuration {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        if self.secs > SECS_PER_DAY {
            write!(fmt, "{} days", self.as_days())
        } else if self.secs > SECS_PER_HOUR {
            write!(fmt, "{} hours", self.as_hours())
        } else if self.secs > SECS_PER_MINUTE {
            write!(fmt, "{} minutes", self.as_minutes())
        } else if self.secs > 1.0 {
            write!(fmt, "{} seconds", self.as_seconds())
        } else if self.secs > 1.0e-3 {
            write!(fmt, "{} milliseconds", self.as_milliseconds())
        } else if self.secs > 1.0e-6 {
            write!(fmt, "{} microseconds", self.as_microseconds())
        } else {
            write!(fmt, "{} nanoseconds", self.as_nanoseconds())
        }
    }
}

impl ops::Neg for FloatDuration {
    type Output = FloatDuration;

    fn neg(self) -> FloatDuration {
        FloatDuration {secs: -self.secs}
    }
}

impl ops::Add<FloatDuration> for FloatDuration {
    type Output = FloatDuration;

    fn add(self, rhs: FloatDuration) -> FloatDuration {
        FloatDuration {secs: self.secs + rhs.secs}
    }
}
impl ops::Sub<FloatDuration> for FloatDuration {
    type Output = FloatDuration;

    fn sub(self, rhs: FloatDuration) -> FloatDuration {
        FloatDuration {secs: self.secs - rhs.secs}
    }
}

impl ops::Mul<f64> for FloatDuration {
    type Output = FloatDuration;

    fn mul(self, rhs: f64) -> FloatDuration {
        FloatDuration {secs: self.secs * rhs}
    }
}
impl ops::Div<f64> for FloatDuration {
    type Output = FloatDuration;

    fn div(self, rhs: f64) -> FloatDuration {
        FloatDuration {secs: self.secs / rhs}
    }
}

impl ops::AddAssign<FloatDuration> for FloatDuration {
    fn add_assign(&mut self, rhs: FloatDuration) {
        self.secs += rhs.secs;
    }
}
impl ops::SubAssign<FloatDuration> for FloatDuration {
    fn sub_assign(&mut self, rhs: FloatDuration) {
        self.secs -= rhs.secs;
    }
}

impl ops::MulAssign<f64> for FloatDuration {
    fn mul_assign(&mut self, rhs: f64) {
        self.secs *= rhs;
    }
}
impl ops::DivAssign<f64> for FloatDuration {
    fn div_assign(&mut self, rhs: f64) {
        self.secs /= rhs;
    }
}

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

    #[test]
    fn test_construct() {
        let duration1 = FloatDuration::hours(3.0);
        assert_eq!(duration1.as_hours(), 3.0);
        assert_eq!(duration1.as_minutes(), 180.0);
        assert_eq!(duration1.as_seconds(), 180.0*60.0);
        assert_eq!(duration1.as_days(), 3.0/24.0);
        assert_eq!(duration1.as_milliseconds(), 180.0*60.0*1000.0);

        let duration2 = FloatDuration::milliseconds(55.0);
        assert_eq!(duration2.as_seconds(), 0.055);
        assert_eq!(duration2.as_milliseconds(), 55.0);
        assert_eq!(duration2.as_microseconds(), 55000.0);
        assert_eq!(duration2.as_nanoseconds(), 55000000.0);
        assert!(!duration2.is_zero());

        let duration3 = FloatDuration::zero();
        assert!(duration3.is_zero());

        assert_eq!(FloatDuration::days(1.5), FloatDuration::hours(36.0));
        assert_eq!(FloatDuration::minutes(30.0), FloatDuration::hours(0.5));
        assert_eq!(FloatDuration::seconds(180.0), FloatDuration::minutes(3.0));
        assert_eq!(FloatDuration::seconds(3.5), FloatDuration::milliseconds(3500.0));
        assert_eq!(FloatDuration::microseconds(300.0), FloatDuration::milliseconds(0.30));
        assert_eq!(FloatDuration::nanoseconds(1000.0), FloatDuration::microseconds(1.0));
    }

    #[test]
    fn test_arithmetic() {
        let duration1 = FloatDuration::minutes(5.0) + FloatDuration::seconds(30.0);
        assert_eq!(duration1, FloatDuration::seconds(330.0));

        let duration2 = FloatDuration::hours(3.0) * 2.5;
        assert_eq!(duration2, FloatDuration::hours(7.5));

        let duration3 = FloatDuration::days(3.0) / 3.0 - FloatDuration::hours(2.0);
        assert_eq!(duration3, FloatDuration::hours(22.0));

        let duration4 = FloatDuration::zero() + FloatDuration::milliseconds(500.0)
            + FloatDuration::microseconds(500.0);
        assert_eq!(duration4, FloatDuration::microseconds(500500.0));

    }

    #[test]
    fn test_std_conversion() {
        let duration1 = FloatDuration::minutes(5.0);
        let std_duration1 = duration1.as_std().unwrap();
        assert!(duration1.is_positive());
        assert_eq!(std_duration1, time::Duration::new(300, 0));
        assert_eq!(FloatDuration::from_std(std_duration1).unwrap(), duration1);

        let duration2 = FloatDuration::hours(-2.0);
        assert!(duration2.is_negative());
        assert!(!duration2.as_std().is_ok());
        let std_duration2 = (-duration2).as_std().unwrap();
        assert_eq!(std_duration2, time::Duration::new(3600*2, 0));
        assert_eq!(FloatDuration::from_std(std_duration2).unwrap(), -duration2);
    }

    #[test]
    fn test_display() {
        use std::fmt::Write;

        let mut buffer1 = "".to_string();
        let mut buffer1_2 = "".to_string();
        let duration1 = FloatDuration::minutes(3.5);

        write!(buffer1, "{}", duration1).unwrap();
        write!(buffer1_2, "{}", duration1.decompose()).unwrap();
        assert_eq!(buffer1, "3.5 minutes");
        assert_eq!(buffer1_2, "00:03:30.0");

        let mut buffer2 = "".to_string();
        let mut buffer2_2 = "".to_string();
        let duration2 = FloatDuration::days(3.0) + FloatDuration::hours(12.0);

        write!(buffer2, "{}", duration2).unwrap();
        write!(buffer2_2, "{}", duration2.decompose()).unwrap();
        assert_eq!(buffer2, "3.5 days");
        assert_eq!(buffer2_2, "3d 12:00:00.0");
    }
}
<|endoftext|>


<commit_before>//! General purpose state transition operator.
use std::hash::Hash;
use std::collections::HashMap;

use ::{Data, ExchangeData};
use dataflow::{Stream, Scope};
use dataflow::operators::generic::unary::Unary;
use dataflow::channels::pact::Exchange;

/// Generic state-transition machinery: each key has a state, and receives a sequence of events.
/// Events are applied in time-order, but no other promises are made. Each state transition can
/// produce output, which is sent.
///
/// `state_machine` will buffer inputs if earlier inputs may still arrive. it will directly apply
/// updates for the current time reflected in the notificator, though. In the case of partially
/// ordered times, the only guarantee is that updates are not applied out of order, not that there
/// is some total order on times respecting the total order (updates may be interleaved).

/// Provides the `state_machine` method.
pub trait StateMachine<S: Scope, K: ExchangeData+Hash+Eq, V: ExchangeData> {
    /// Tracks a state for each presented key, using user-supplied state transition logic.
    ///
    /// The transition logic `fold` may mutate the state, and produce both output records and
    /// a `bool` indicating that it is appropriate to deregister the state, cleaning up once
    /// the state is no longer helpful.
    ///
    /// #Examples
    /// ```
    /// use timely::dataflow::operators::{ToStream, Map, Inspect};
    /// use timely::dataflow::operators::aggregation::StateMachine;
    ///
    /// timely::example(|scope| {
    ///
    ///     // these results happen to be right, but aren't guaranteed.
    ///     // the system is at liberty to re-order within a timestamp.
    ///     let result = vec![(0,0), (0,2), (0,6), (0,12), (0,20),
    ///                       (1,1), (1,4), (1,9), (1,16), (1,25)];
    ///
    ///         (0..10).to_stream(scope)
    ///                .map(|x| (x % 2, x))
    ///                .state_machine(
    ///                    |_key, val, agg| { *agg += val; (false, Some((*_key, *agg))) },
    ///                    |key| *key as u64
    ///                )
    ///                .inspect(move |x| assert!(result.contains(x)));
    /// });
    /// ```
    fn state_machine<
        R: Data,                                    // output type
        D: Default+'static,                         // per-key state (data)
        I: IntoIterator<Item=R>,                    // type of output iterator
        F: Fn(&K, V, &mut D)->(bool, I)+'static,    // state update logic
        H: Fn(&K)->u64+'static,                     // "hash" function for keys
    >(&self, fold: F, hash: H) -> Stream<S, R> where S::Timestamp : Hash+Eq ;
}

impl<S: Scope, K: ExchangeData+Hash+Eq, V: ExchangeData> StateMachine<S, K, V> for Stream<S, (K, V)> {
    fn state_machine<
            R: Data,                                    // output type
            D: Default+'static,                         // per-key state (data)
            I: IntoIterator<Item=R>,                    // type of output iterator
            F: Fn(&K, V, &mut D)->(bool, I)+'static,    // state update logic
            H: Fn(&K)->u64+'static,                     // "hash" function for keys
        >(&self, fold: F, hash: H) -> Stream<S, R> where S::Timestamp : Hash+Eq {

        let mut pending = HashMap::new();   // times -> (keys -> state)
        let mut states = HashMap::new();    // keys -> state

        self.unary_notify(Exchange::new(move |&(ref k, _)| hash(k)), "StateMachine", vec![], move |input, output, notificator| {

            // stash each input and request a notification when ready
            input.for_each(|time, data| {
                // Unconditionally stash data as `state_machine` requires data to be folded in-order.
                // Processing here can violate this invariant.
                pending.entry(time.time().clone()).or_insert_with(Vec::new).extend(data.drain(..));
                notificator.notify_at(time.retain());
            });

            // go through each time with data, process each (key, val) pair.
            notificator.for_each(|time,_,_| {
                if let Some(pend) = pending.remove(time.time()) {
                    let mut session = output.session(&time);
                    for (key, val) in pend {
                        let (remove, output) = {
                            let state = states.entry(key.clone()).or_insert_with(Default::default);
                            fold(&key, val, state)
                        };
                        if remove { states.remove(&key); }
                        session.give_iterator(output.into_iter());
                    }
                }
            });
        })
    }
}
<commit_msg>state_machine: process available times before consuming new inputs<commit_after>//! General purpose state transition operator.
use std::hash::Hash;
use std::collections::HashMap;

use ::{Data, ExchangeData};
use dataflow::{Stream, Scope};
use dataflow::operators::generic::unary::Unary;
use dataflow::channels::pact::Exchange;

/// Generic state-transition machinery: each key has a state, and receives a sequence of events.
/// Events are applied in time-order, but no other promises are made. Each state transition can
/// produce output, which is sent.
///
/// `state_machine` will buffer inputs if earlier inputs may still arrive. it will directly apply
/// updates for the current time reflected in the notificator, though. In the case of partially
/// ordered times, the only guarantee is that updates are not applied out of order, not that there
/// is some total order on times respecting the total order (updates may be interleaved).

/// Provides the `state_machine` method.
pub trait StateMachine<S: Scope, K: ExchangeData+Hash+Eq, V: ExchangeData> {
    /// Tracks a state for each presented key, using user-supplied state transition logic.
    ///
    /// The transition logic `fold` may mutate the state, and produce both output records and
    /// a `bool` indicating that it is appropriate to deregister the state, cleaning up once
    /// the state is no longer helpful.
    ///
    /// #Examples
    /// ```
    /// use timely::dataflow::operators::{ToStream, Map, Inspect};
    /// use timely::dataflow::operators::aggregation::StateMachine;
    ///
    /// timely::example(|scope| {
    ///
    ///     // these results happen to be right, but aren't guaranteed.
    ///     // the system is at liberty to re-order within a timestamp.
    ///     let result = vec![(0,0), (0,2), (0,6), (0,12), (0,20),
    ///                       (1,1), (1,4), (1,9), (1,16), (1,25)];
    ///
    ///         (0..10).to_stream(scope)
    ///                .map(|x| (x % 2, x))
    ///                .state_machine(
    ///                    |_key, val, agg| { *agg += val; (false, Some((*_key, *agg))) },
    ///                    |key| *key as u64
    ///                )
    ///                .inspect(move |x| assert!(result.contains(x)));
    /// });
    /// ```
    fn state_machine<
        R: Data,                                    // output type
        D: Default+'static,                         // per-key state (data)
        I: IntoIterator<Item=R>,                    // type of output iterator
        F: Fn(&K, V, &mut D)->(bool, I)+'static,    // state update logic
        H: Fn(&K)->u64+'static,                     // "hash" function for keys
    >(&self, fold: F, hash: H) -> Stream<S, R> where S::Timestamp : Hash+Eq ;
}

impl<S: Scope, K: ExchangeData+Hash+Eq, V: ExchangeData> StateMachine<S, K, V> for Stream<S, (K, V)> {
    fn state_machine<
            R: Data,                                    // output type
            D: Default+'static,                         // per-key state (data)
            I: IntoIterator<Item=R>,                    // type of output iterator
            F: Fn(&K, V, &mut D)->(bool, I)+'static,    // state update logic
            H: Fn(&K)->u64+'static,                     // "hash" function for keys
        >(&self, fold: F, hash: H) -> Stream<S, R> where S::Timestamp : Hash+Eq {

        let mut pending: HashMap<_, Vec<(K, V)>> = HashMap::new();   // times -> (keys -> state)
        let mut states = HashMap::new();    // keys -> state

        self.unary_notify(Exchange::new(move |&(ref k, _)| hash(k)), "StateMachine", vec![], move |input, output, notificator| {

            // go through each time with data, process each (key, val) pair.
            notificator.for_each(|time,_,_| {
                if let Some(pend) = pending.remove(time.time()) {
                    let mut session = output.session(&time);
                    for (key, val) in pend {
                        let (remove, output) = {
                            let state = states.entry(key.clone()).or_insert_with(Default::default);
                            fold(&key, val, state)
                        };
                        if remove { states.remove(&key); }
                        session.give_iterator(output.into_iter());
                    }
                }
            });

            // stash each input and request a notification when ready
            input.for_each(|time, data| {
                // stash if not time yet
                if notificator.frontier(0).less_than(time.time()) {
                    pending.entry(time.time().clone()).or_insert_with(Vec::new).extend(data.drain(..));
                    notificator.notify_at(time.retain());
                }
                else {
                    // else we can process immediately
                    let mut session = output.session(&time);
                    for (key, val) in data.drain(..) {
                        let (remove, output) = {
                            let state = states.entry(key.clone()).or_insert_with(Default::default);
                            fold(&key, val, state)
                        };
                        if remove { states.remove(&key); }
                        session.give_iterator(output.into_iter());
                    }
                }
            });
        })
    }
}
<|endoftext|>


<commit_before>//! High layer providing somewhat automatic marshalling of Rust closures
//! as C function pointers.
//!
//! The main facility here is given by the structs `Closure`*`N`* and
//! `ClosureMut`*`N`*, for natural numbers *`N`* from 0 to 12 (as of now).
//! These represent C closures, which can be used to turn Rust lambdas
//! (or in generally, anything that implements `Fn` or `FnMut`) into
//! ordinary C function pointers. For example, a Rust value of type
//! `Fn(u32, u32) -> u64` can be turned into a closure of type
//! `Closure2<u32, u32, u64>`. Then a C function pointer of type
//! `extern "C" fn(u32, u32) -> u64` can be borrowed from the closure
//! and passed to C.
//!
//! Here’s an example using [`ClosureMut1`](struct.ClosureMut1.html):
//!
//! ```
//! use libffi::high::ClosureMut1;
//!
//! let mut x = 0u64;
//! let mut f = |y: u32| { x += y as u64; x };
//!
//! let closure = ClosureMut1::new(&mut f);
//! let counter = closure.code_ptr();
//!
//! assert_eq!(5, counter(5));
//! assert_eq!(6, counter(1));
//! assert_eq!(8, counter(2));
//! ```
//!
//! Note that in the above example, `closure` is an ordinary C function
//! pointer of type `extern "C" fn(u64) -> u64`.
use std::marker::PhantomData;
use std::mem;

use middle;

/// Representations of C types for the high layer.
pub mod types;
use self::types::*;

macro_rules! define_closure_types {
    (
        $cif:ident $callback:ident $callback_mut:ident
                   $closure:ident  $closure_mut:ident ;
                   $( $T:ident )*
    )
        =>
    {
        /// Typed CIF (“Call InterFace”), which statically tracks
        /// argument and result types.
        pub struct $cif<$( $T, )* R> {
            untyped: middle::Cif,
            _marker: PhantomData<fn($( $T, )*) -> R>,
        }

        impl<$( $T, )* R> $cif<$( $T, )* R> {
            /// Creates a new statically-typed CIF from the given argument
            /// and result types.
            #[allow(non_snake_case)]
            pub fn new($( $T: Type<$T>, )* result: Type<R>) -> Self {
                let cif = middle::Cif::new(vec![$( $T.into_untyped() ),*],
                                           result.into_untyped());
                $cif { untyped: cif, _marker: PhantomData }
            }
        }

        impl<$( $T: FfiType, )* R: FfiType> $cif<$( $T, )* R> {
            /// Creates a new statically-typed CIF by reifying the
            /// argument types as `Type<T>`s.
            pub fn reify() -> Self {
                Self::new($( $T::get_type(), )* R::get_type())
            }
        }

        /// The type of function that gets called from an immutable
        /// typed closure.
        pub type $callback<U, $( $T, )* R>
            = extern "C" fn(cif:      &::low::ffi_cif,
                            result:   &mut R,
                            args:     &($( &$T, )*),
                            userdata: &U);

        /// The type of function that gets called from a mutable
        /// typed closure.
        pub type $callback_mut<U, $( $T, )* R>
            = extern "C" fn(cif:      &::low::ffi_cif,
                            result:   &mut R,
                            args:     &($( &$T, )*),
                            userdata: &mut U);

        /// A mutable typed closure with the given argument and result
        /// types.
        pub struct $closure<'a, $( $T, )* R> {
            untyped: middle::Closure<'a>,
            _marker: PhantomData<fn($( $T, )*) -> R>,
        }

        impl<'a, $($T: Copy + FfiType,)* R: FfiType>
            $closure<'a, $($T,)* R>
        {
            /// Constructs a typed closure callable from C from a
            /// Rust closure.
            pub fn new<Callback>(callback: &'a Callback) -> Self
                where Callback: Fn($( $T, )*) -> R + 'a
            {
                Self::new_with_cif($cif::reify(), callback)
            }
        }

        impl<'a, $( $T, )* R> $closure<'a, $( $T, )* R> {
            /// Gets the C code pointer that is used to invoke the
            /// closure.
            pub fn code_ptr(&self) -> &extern "C" fn($( $T, )*) -> R {
                unsafe {
                    mem::transmute(self.untyped.code_ptr())
                }
            }

            /// Constructs a typed closure callable from C from a CIF
            /// describing the calling convention for the resulting
            /// function, a callback for the function to call, and
            /// userdata to pass to the callback.
            pub fn from_parts<U>(cif: $cif<$( $T, )* R>,
                                 callback: $callback<U, $( $T, )* R>,
                                 userdata: &'a U) -> Self
            {
                let callback: middle::Callback<U, R>
                    = unsafe { mem::transmute(callback) };
                let closure
                    = middle::Closure::new(cif.untyped,
                                           callback,
                                           userdata);
                $closure {
                    untyped: closure,
                    _marker: PhantomData,
                }
            }
        }

        impl<'a, $( $T: Copy, )* R> $closure<'a, $( $T, )* R> {
            /// Constructs a typed closure callable from C from a CIF
            /// describing the calling convention for the resulting
            /// function and the Rust closure to call.
            pub fn new_with_cif<Callback>(cif: $cif<$( $T, )* R>,
                                          callback: &'a Callback) -> Self
                where Callback: Fn($( $T, )*) -> R + 'a
            {
                Self::from_parts(cif,
                                 Self::static_callback,
                                 callback)
            }

            #[allow(non_snake_case)]
            extern "C" fn static_callback<Callback>
                (_cif:     &::low::ffi_cif,
                 result:   &mut R,
                 &($( &$T, )*):
                           &($( &$T, )*),
                 userdata: &Callback)
              where Callback: Fn($( $T, )*) -> R + 'a
            {
                *result = userdata($( $T, )*);
            }
        }

        /// An immutable typed closure with the given argument and
        /// result types.
        pub struct $closure_mut<'a, $( $T, )* R> {
            untyped: middle::Closure<'a>,
            _marker: PhantomData<fn($( $T, )*) -> R>,
        }

        impl<'a, $($T: Copy + FfiType,)* R: FfiType>
            $closure_mut<'a, $($T,)* R>
        {
            /// Constructs a typed closure callable from C from a
            /// Rust closure.
            pub fn new<Callback>(callback: &'a mut Callback) -> Self
                where Callback: FnMut($( $T, )*) -> R + 'a
            {
                Self::new_with_cif($cif::reify(), callback)
            }
        }

        impl<'a, $( $T, )* R> $closure_mut<'a, $( $T, )* R> {
            /// Gets the C code pointer that is used to invoke the
            /// closure.
            pub fn code_ptr(&self) -> &extern "C" fn($( $T, )*) -> R {
                unsafe {
                    mem::transmute(self.untyped.code_ptr())
                }
            }

            /// Constructs a typed closure callable from C from a CIF
            /// describing the calling convention for the resulting
            /// function, a callback for the function to call, and
            /// userdata to pass to the callback.
            pub fn from_parts<U>(cif:      $cif<$( $T, )* R>,
                                 callback: $callback_mut<U, $( $T, )* R>,
                                 userdata: &'a mut U) -> Self
            {
                let callback: middle::CallbackMut<U, R>
                    = unsafe { mem::transmute(callback) };
                let closure
                    = middle::Closure::new_mut(cif.untyped,
                                               callback,
                                               userdata);
                $closure_mut {
                    untyped: closure,
                    _marker: PhantomData,
                }
            }
        }

        impl<'a, $( $T: Copy, )* R> $closure_mut<'a, $( $T, )* R> {
            /// Constructs a typed closure callable from C from a CIF
            /// describing the calling convention for the resulting
            /// function and the Rust closure to call.
            pub fn new_with_cif<Callback>(cif: $cif<$( $T, )* R>,
                                          callback: &'a mut Callback) -> Self
                where Callback: FnMut($( $T, )*) -> R + 'a
            {
                Self::from_parts(cif,
                                 Self::static_callback,
                                 callback)
            }

            #[allow(non_snake_case)]
            extern "C" fn static_callback<Callback>
                (_cif:     &::low::ffi_cif,
                 result:   &mut R,
                 &($( &$T, )*):
                           &($( &$T, )*),
                 userdata: &mut Callback)
              where Callback: FnMut($( $T, )*) -> R + 'a
            {
                *result = userdata($( $T, )*);
            }
        }
    }
}

define_closure_types!(Cif0 Callback0 CallbackMut0 Closure0 ClosureMut0;
                      );
define_closure_types!(Cif1 Callback1 CallbackMut1 Closure1 ClosureMut1;
                      A);
define_closure_types!(Cif2 Callback2 CallbackMut2 Closure2 ClosureMut2;
                      A B);
define_closure_types!(Cif3 Callback3 CallbackMut3 Closure3 ClosureMut3;
                      A B C);
define_closure_types!(Cif4 Callback4 CallbackMut4 Closure4 ClosureMut4;
                      A B C D);
define_closure_types!(Cif5 Callback5 CallbackMut5 Closure5 ClosureMut5;
                      A B C D E);
define_closure_types!(Cif6 Callback6 CallbackMut6 Closure6 ClosureMut6;
                      A B C D E F);
define_closure_types!(Cif7 Callback7 CallbackMut7 Closure7 ClosureMut7;
                      A B C D E F G);
define_closure_types!(Cif8 Callback8 CallbackMut8 Closure8 ClosureMut8;
                      A B C D E F G H);
define_closure_types!(Cif9 Callback9 CallbackMut9 Closure9 ClosureMut9;
                      A B C D E F G H I);
define_closure_types!(Cif10 Callback10 CallbackMut10 Closure10 ClosureMut10;
                      A B C D E F G H I J);
define_closure_types!(Cif11 Callback11 CallbackMut11 Closure11 ClosureMut11;
                      A B C D E F G H I J K);
define_closure_types!(Cif12 Callback12 CallbackMut12 Closure12 ClosureMut12;
                      A B C D E F G H I J K L);

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

    #[test]
    fn new_with_cif() {
        let x: u64 = 1;
        let f = |y: u64, z: u64| x + y + z;

        let type_   = u64::get_type();
        let cif     = Cif2::new(type_.clone(), type_.clone(), type_.clone());
        let closure = Closure2::new_with_cif(cif, &f);

        assert_eq!(12, closure.code_ptr()(5, 6));
    }

    #[test]
    fn new_with_cif_mut() {
        let mut x: u64 = 0;
        let mut f = |y: u64| { x += y; x };

        let type_   = u64::get_type();
        let cif     = Cif1::new(type_.clone(), type_.clone());
        let closure = ClosureMut1::new_with_cif(cif, &mut f);

        let counter = closure.code_ptr();

        assert_eq!(5, counter(5));
        assert_eq!(6, counter(1));
        assert_eq!(8, counter(2));
    }

    #[test]
    fn new() {
        let x: u64 = 1;
        let f = |y: u64, z: u64| x + y + z;

        let closure = Closure2::new(&f);

        assert_eq!(12, closure.code_ptr()(5, 6));
    }

    #[test]
    fn new_mut() {
        let mut x: u64 = 0;
        let mut f = |y: u32| { x += y as u64; x };

        let closure = ClosureMut1::new(&mut f);
        let counter = closure.code_ptr();

        assert_eq!(5, counter(5));
        assert_eq!(6, counter(1));
        assert_eq!(8, counter(2));
    }
}
<commit_msg>Using ptr::write instead of pointer assignment to store the callback result.<commit_after>//! High layer providing somewhat automatic marshalling of Rust closures
//! as C function pointers.
//!
//! The main facility here is given by the structs `Closure`*`N`* and
//! `ClosureMut`*`N`*, for natural numbers *`N`* from 0 to 12 (as of now).
//! These represent C closures, which can be used to turn Rust lambdas
//! (or in generally, anything that implements `Fn` or `FnMut`) into
//! ordinary C function pointers. For example, a Rust value of type
//! `Fn(u32, u32) -> u64` can be turned into a closure of type
//! `Closure2<u32, u32, u64>`. Then a C function pointer of type
//! `extern "C" fn(u32, u32) -> u64` can be borrowed from the closure
//! and passed to C.
//!
//! Here’s an example using [`ClosureMut1`](struct.ClosureMut1.html):
//!
//! ```
//! use libffi::high::ClosureMut1;
//!
//! let mut x = 0u64;
//! let mut f = |y: u32| { x += y as u64; x };
//!
//! let closure = ClosureMut1::new(&mut f);
//! let counter = closure.code_ptr();
//!
//! assert_eq!(5, counter(5));
//! assert_eq!(6, counter(1));
//! assert_eq!(8, counter(2));
//! ```
//!
//! Note that in the above example, `closure` is an ordinary C function
//! pointer of type `extern "C" fn(u64) -> u64`.
use std::marker::PhantomData;
use std::{mem, ptr};

use middle;

/// Representations of C types for the high layer.
pub mod types;
use self::types::*;

macro_rules! define_closure_types {
    (
        $cif:ident $callback:ident $callback_mut:ident
                   $closure:ident  $closure_mut:ident ;
                   $( $T:ident )*
    )
        =>
    {
        /// Typed CIF (“Call InterFace”), which statically tracks
        /// argument and result types.
        pub struct $cif<$( $T, )* R> {
            untyped: middle::Cif,
            _marker: PhantomData<fn($( $T, )*) -> R>,
        }

        impl<$( $T, )* R> $cif<$( $T, )* R> {
            /// Creates a new statically-typed CIF from the given argument
            /// and result types.
            #[allow(non_snake_case)]
            pub fn new($( $T: Type<$T>, )* result: Type<R>) -> Self {
                let cif = middle::Cif::new(vec![$( $T.into_untyped() ),*],
                                           result.into_untyped());
                $cif { untyped: cif, _marker: PhantomData }
            }
        }

        impl<$( $T: FfiType, )* R: FfiType> $cif<$( $T, )* R> {
            /// Creates a new statically-typed CIF by reifying the
            /// argument types as `Type<T>`s.
            pub fn reify() -> Self {
                Self::new($( $T::get_type(), )* R::get_type())
            }
        }

        /// The type of function that gets called from an immutable
        /// typed closure.
        pub type $callback<U, $( $T, )* R>
            = extern "C" fn(cif:      &::low::ffi_cif,
                            result:   &mut R,
                            args:     &($( &$T, )*),
                            userdata: &U);

        /// The type of function that gets called from a mutable
        /// typed closure.
        pub type $callback_mut<U, $( $T, )* R>
            = extern "C" fn(cif:      &::low::ffi_cif,
                            result:   &mut R,
                            args:     &($( &$T, )*),
                            userdata: &mut U);

        /// A mutable typed closure with the given argument and result
        /// types.
        pub struct $closure<'a, $( $T, )* R> {
            untyped: middle::Closure<'a>,
            _marker: PhantomData<fn($( $T, )*) -> R>,
        }

        impl<'a, $($T: Copy + FfiType,)* R: FfiType>
            $closure<'a, $($T,)* R>
        {
            /// Constructs a typed closure callable from C from a
            /// Rust closure.
            pub fn new<Callback>(callback: &'a Callback) -> Self
                where Callback: Fn($( $T, )*) -> R + 'a
            {
                Self::new_with_cif($cif::reify(), callback)
            }
        }

        impl<'a, $( $T, )* R> $closure<'a, $( $T, )* R> {
            /// Gets the C code pointer that is used to invoke the
            /// closure.
            pub fn code_ptr(&self) -> &extern "C" fn($( $T, )*) -> R {
                unsafe {
                    mem::transmute(self.untyped.code_ptr())
                }
            }

            /// Constructs a typed closure callable from C from a CIF
            /// describing the calling convention for the resulting
            /// function, a callback for the function to call, and
            /// userdata to pass to the callback.
            pub fn from_parts<U>(cif: $cif<$( $T, )* R>,
                                 callback: $callback<U, $( $T, )* R>,
                                 userdata: &'a U) -> Self
            {
                let callback: middle::Callback<U, R>
                    = unsafe { mem::transmute(callback) };
                let closure
                    = middle::Closure::new(cif.untyped,
                                           callback,
                                           userdata);
                $closure {
                    untyped: closure,
                    _marker: PhantomData,
                }
            }
        }

        impl<'a, $( $T: Copy, )* R> $closure<'a, $( $T, )* R> {
            /// Constructs a typed closure callable from C from a CIF
            /// describing the calling convention for the resulting
            /// function and the Rust closure to call.
            pub fn new_with_cif<Callback>(cif: $cif<$( $T, )* R>,
                                          callback: &'a Callback) -> Self
                where Callback: Fn($( $T, )*) -> R + 'a
            {
                Self::from_parts(cif,
                                 Self::static_callback,
                                 callback)
            }

            #[allow(non_snake_case)]
            extern "C" fn static_callback<Callback>
                (_cif:     &::low::ffi_cif,
                 result:   &mut R,
                 &($( &$T, )*):
                           &($( &$T, )*),
                 userdata: &Callback)
              where Callback: Fn($( $T, )*) -> R + 'a
            {
                unsafe {
                    ptr::write(result, userdata($( $T, )*));
                }
            }
        }

        /// An immutable typed closure with the given argument and
        /// result types.
        pub struct $closure_mut<'a, $( $T, )* R> {
            untyped: middle::Closure<'a>,
            _marker: PhantomData<fn($( $T, )*) -> R>,
        }

        impl<'a, $($T: Copy + FfiType,)* R: FfiType>
            $closure_mut<'a, $($T,)* R>
        {
            /// Constructs a typed closure callable from C from a
            /// Rust closure.
            pub fn new<Callback>(callback: &'a mut Callback) -> Self
                where Callback: FnMut($( $T, )*) -> R + 'a
            {
                Self::new_with_cif($cif::reify(), callback)
            }
        }

        impl<'a, $( $T, )* R> $closure_mut<'a, $( $T, )* R> {
            /// Gets the C code pointer that is used to invoke the
            /// closure.
            pub fn code_ptr(&self) -> &extern "C" fn($( $T, )*) -> R {
                unsafe {
                    mem::transmute(self.untyped.code_ptr())
                }
            }

            /// Constructs a typed closure callable from C from a CIF
            /// describing the calling convention for the resulting
            /// function, a callback for the function to call, and
            /// userdata to pass to the callback.
            pub fn from_parts<U>(cif:      $cif<$( $T, )* R>,
                                 callback: $callback_mut<U, $( $T, )* R>,
                                 userdata: &'a mut U) -> Self
            {
                let callback: middle::CallbackMut<U, R>
                    = unsafe { mem::transmute(callback) };
                let closure
                    = middle::Closure::new_mut(cif.untyped,
                                               callback,
                                               userdata);
                $closure_mut {
                    untyped: closure,
                    _marker: PhantomData,
                }
            }
        }

        impl<'a, $( $T: Copy, )* R> $closure_mut<'a, $( $T, )* R> {
            /// Constructs a typed closure callable from C from a CIF
            /// describing the calling convention for the resulting
            /// function and the Rust closure to call.
            pub fn new_with_cif<Callback>(cif: $cif<$( $T, )* R>,
                                          callback: &'a mut Callback) -> Self
                where Callback: FnMut($( $T, )*) -> R + 'a
            {
                Self::from_parts(cif,
                                 Self::static_callback,
                                 callback)
            }

            #[allow(non_snake_case)]
            extern "C" fn static_callback<Callback>
                (_cif:     &::low::ffi_cif,
                 result:   &mut R,
                 &($( &$T, )*):
                           &($( &$T, )*),
                 userdata: &mut Callback)
              where Callback: FnMut($( $T, )*) -> R + 'a
            {
                unsafe {
                    ptr::write(result, userdata($( $T, )*));
                }
            }
        }
    }
}

define_closure_types!(Cif0 Callback0 CallbackMut0 Closure0 ClosureMut0;
                      );
define_closure_types!(Cif1 Callback1 CallbackMut1 Closure1 ClosureMut1;
                      A);
define_closure_types!(Cif2 Callback2 CallbackMut2 Closure2 ClosureMut2;
                      A B);
define_closure_types!(Cif3 Callback3 CallbackMut3 Closure3 ClosureMut3;
                      A B C);
define_closure_types!(Cif4 Callback4 CallbackMut4 Closure4 ClosureMut4;
                      A B C D);
define_closure_types!(Cif5 Callback5 CallbackMut5 Closure5 ClosureMut5;
                      A B C D E);
define_closure_types!(Cif6 Callback6 CallbackMut6 Closure6 ClosureMut6;
                      A B C D E F);
define_closure_types!(Cif7 Callback7 CallbackMut7 Closure7 ClosureMut7;
                      A B C D E F G);
define_closure_types!(Cif8 Callback8 CallbackMut8 Closure8 ClosureMut8;
                      A B C D E F G H);
define_closure_types!(Cif9 Callback9 CallbackMut9 Closure9 ClosureMut9;
                      A B C D E F G H I);
define_closure_types!(Cif10 Callback10 CallbackMut10 Closure10 ClosureMut10;
                      A B C D E F G H I J);
define_closure_types!(Cif11 Callback11 CallbackMut11 Closure11 ClosureMut11;
                      A B C D E F G H I J K);
define_closure_types!(Cif12 Callback12 CallbackMut12 Closure12 ClosureMut12;
                      A B C D E F G H I J K L);

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

    #[test]
    fn new_with_cif() {
        let x: u64 = 1;
        let f = |y: u64, z: u64| x + y + z;

        let type_   = u64::get_type();
        let cif     = Cif2::new(type_.clone(), type_.clone(), type_.clone());
        let closure = Closure2::new_with_cif(cif, &f);

        assert_eq!(12, closure.code_ptr()(5, 6));
    }

    #[test]
    fn new_with_cif_mut() {
        let mut x: u64 = 0;
        let mut f = |y: u64| { x += y; x };

        let type_   = u64::get_type();
        let cif     = Cif1::new(type_.clone(), type_.clone());
        let closure = ClosureMut1::new_with_cif(cif, &mut f);

        let counter = closure.code_ptr();

        assert_eq!(5, counter(5));
        assert_eq!(6, counter(1));
        assert_eq!(8, counter(2));
    }

    #[test]
    fn new() {
        let x: u64 = 1;
        let f = |y: u64, z: u64| x + y + z;

        let closure = Closure2::new(&f);

        assert_eq!(12, closure.code_ptr()(5, 6));
    }

    #[test]
    fn new_mut() {
        let mut x: u64 = 0;
        let mut f = |y: u32| { x += y as u64; x };

        let closure = ClosureMut1::new(&mut f);
        let counter = closure.code_ptr();

        assert_eq!(5, counter(5));
        assert_eq!(6, counter(1));
        assert_eq!(8, counter(2));
    }
}
<|endoftext|>


<commit_before>#![feature(collections, core, old_io, old_path, env)]

extern crate "git2-curl" as git2_curl;
extern crate "rustc-serialize" as rustc_serialize;
extern crate cargo;
extern crate env_logger;
#[macro_use] extern crate log;

use std::collections::BTreeSet;
use std::env;
use std::old_io::fs::{self, PathExtensions};
use std::old_io::process::{Command,InheritFd,ExitStatus,ExitSignal};
use std::old_io;

use cargo::{execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::{CliError, CliResult, lev_distance, Config};

#[derive(RustcDecodable)]
struct Flags {
    flag_list: bool,
    flag_verbose: bool,
    arg_command: String,
    arg_args: Vec<String>,
}

const USAGE: &'static str = "
Rust's package manager

Usage:
    cargo <command> [<args>...]
    cargo [options]

Options:
    -h, --help       Display this message
    -V, --version    Print version info and exit
    --list           List installed commands
    -v, --verbose    Use verbose output

Some common cargo commands are:
    build       Compile the current project
    clean       Remove the target directory
    doc         Build this project's and its dependencies' documentation
    new         Create a new cargo project
    run         Build and execute src/main.rs
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock

See 'cargo help <command>' for more information on a specific command.
";

fn main() {
    env_logger::init().unwrap();
    execute_main_without_stdin(execute, true, USAGE)
}

macro_rules! each_subcommand{ ($mac:ident) => ({
    $mac!(bench);
    $mac!(build);
    $mac!(clean);
    $mac!(doc);
    $mac!(fetch);
    $mac!(generate_lockfile);
    $mac!(git_checkout);
    $mac!(help);
    $mac!(locate_project);
    $mac!(login);
    $mac!(new);
    $mac!(owner);
    $mac!(package);
    $mac!(pkgid);
    $mac!(publish);
    $mac!(read_manifest);
    $mac!(run);
    $mac!(search);
    $mac!(test);
    $mac!(update);
    $mac!(verify_project);
    $mac!(version);
    $mac!(yank);
}) }

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute(flags: Flags, config: &Config) -> CliResult<Option<()>> {
    config.shell().set_verbose(flags.flag_verbose);

    init_git_transports(config);

    if flags.flag_list {
        println!("Installed Commands:");
        for command in list_commands().into_iter() {
            println!("    {}", command);
        };
        return Ok(None)
    }

    let (mut args, command) = match &flags.arg_command[..] {
        "" | "help" if flags.arg_args.len() == 0 => {
            config.shell().set_verbose(true);
            let args = &["foo".to_string(), "-h".to_string()];
            let r = cargo::call_main_without_stdin(execute, config, USAGE, args,
                                                   false);
            cargo::process_executed(r, &mut **config.shell());
            return Ok(None)
        }
        "help" if flags.arg_args[0] == "-h" ||
                  flags.arg_args[0] == "--help" =>
            (flags.arg_args, "help"),
        "help" => (vec!["-h".to_string()], &flags.arg_args[0][..]),
        s => (flags.arg_args.clone(), s),
    };
    args.insert(0, command.to_string());
    args.insert(0, "foo".to_string());

    macro_rules! cmd{ ($name:ident) => (
        if command == stringify!($name).replace("_", "-") {
            mod $name;
            config.shell().set_verbose(true);
            let r = cargo::call_main_without_stdin($name::execute, config,
                                                   $name::USAGE,
                                                   &args,
                                                   false);
            cargo::process_executed(r, &mut **config.shell());
            return Ok(None)
        }
    ) }
    each_subcommand!(cmd);

    execute_subcommand(&command, &args, &mut config.shell());
    Ok(None)
}

fn find_closest(cmd: &str) -> Option<String> {
    match list_commands().iter()
                            // doing it this way (instead of just .min_by(|c|
                            // c.lev_distance(cmd))) allows us to only make
                            // suggestions that have an edit distance of
                            // 3 or less
                            .map(|c| (lev_distance(&c, cmd), c))
                            .filter(|&(d, _): &(usize, &String)| d < 4)
                            .min_by(|&(d, _)| d) {
        Some((_, c)) => {
            Some(c.to_string())
        },
        None => None
    }
}

fn execute_subcommand(cmd: &str, args: &[String], shell: &mut MultiShell) {
    let command = match find_command(cmd) {
        Some(command) => command,
        None => {
            let msg = match find_closest(cmd) {
                Some(closest) => format!("No such subcommand\n\n\t\
                                          Did you mean `{}`?\n", closest),
                None => "No such subcommand".to_string()
            };
            return handle_error(CliError::new(&msg, 127), shell)
        }
    };
    let status = Command::new(command)
                         .args(args)
                         .stdin(InheritFd(0))
                         .stdout(InheritFd(1))
                         .stderr(InheritFd(2))
                         .status();

    match status {
        Ok(ExitStatus(0)) => (),
        Ok(ExitStatus(i)) => {
            handle_error(CliError::new("", i as i32), shell)
        }
        Ok(ExitSignal(i)) => {
            let msg = format!("subcommand failed with signal: {}", i);
            handle_error(CliError::new(&msg, i as i32), shell)
        }
        Err(old_io::IoError{kind, ..}) if kind == old_io::FileNotFound =>
            handle_error(CliError::new("No such subcommand", 127), shell),
        Err(err) => handle_error(
            CliError::new(
                &format!("Subcommand failed to run: {}", err), 127),
            shell)
    }
}

/// List all runnable commands. find_command should always succeed
/// if given one of returned command.
fn list_commands() -> BTreeSet<String> {
    let command_prefix = "cargo-";
    let mut commands = BTreeSet::new();
    for dir in list_command_directory().iter() {
        let entries = match fs::readdir(dir) {
            Ok(entries) => entries,
            _ => continue
        };
        for entry in entries.iter() {
            let filename = match entry.filename_str() {
                Some(filename) => filename,
                _ => continue
            };
            if filename.starts_with(command_prefix) &&
                    filename.ends_with(env::consts::EXE_SUFFIX) &&
                    is_executable(entry) {
                let command = &filename[
                    command_prefix.len()..
                    filename.len() - env::consts::EXE_SUFFIX.len()];
                commands.insert(String::from_str(command));
            }
        }
    }

    macro_rules! add_cmd{ ($cmd:ident) => ({
        commands.insert(stringify!($cmd).replace("_", "-"));
    }) }
    each_subcommand!(add_cmd);
    commands
}

fn is_executable(path: &Path) -> bool {
    match fs::stat(path) {
        Ok(old_io::FileStat{ kind: old_io::FileType::RegularFile, perm, ..}) =>
            perm.contains(old_io::OTHER_EXECUTE),
        _ => false
    }
}

/// Get `Command` to run given command.
fn find_command(cmd: &str) -> Option<Path> {
    let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX);
    let dirs = list_command_directory();
    let mut command_paths = dirs.iter().map(|dir| dir.join(&command_exe));
    command_paths.find(|path| path.exists())
}

/// List candidate locations where subcommands might be installed.
fn list_command_directory() -> Vec<Path> {
    let mut dirs = vec![];
    if let Ok(mut path) = env::current_exe() {
        path.pop();
        dirs.push(path.join("../lib/cargo"));
        dirs.push(path);
    }
    if let Some(val) = env::var_os("PATH") {
        dirs.extend(env::split_paths(&val));
    }
    dirs
}

fn init_git_transports(config: &Config) {
    // Only use a custom transport if a proxy is configured, right now libgit2
    // doesn't support proxies and we have to use a custom transport in this
    // case. The custom transport, however, is not as well battle-tested.
    match cargo::ops::http_proxy_exists(config) {
        Ok(true) => {}
        _ => return
    }

    let handle = match cargo::ops::http_handle(config) {
        Ok(handle) => handle,
        Err(..) => return,
    };

    // The unsafety of the registration function derives from two aspects:
    //
    // 1. This call must be synchronized with all other registration calls as
    //    well as construction of new transports.
    // 2. The argument is leaked.
    //
    // We're clear on point (1) because this is only called at the start of this
    // binary (we know what the state of the world looks like) and we're mostly
    // clear on point (2) because we'd only free it after everything is done
    // anyway
    unsafe {
        git2_curl::register(handle);
    }
}
<commit_msg>Auto merge of #1345 - badboy:pass-cargo-name, r=alexcrichton<commit_after>#![feature(collections, core, old_io, old_path, env)]

extern crate "git2-curl" as git2_curl;
extern crate "rustc-serialize" as rustc_serialize;
extern crate cargo;
extern crate env_logger;
#[macro_use] extern crate log;

use std::collections::BTreeSet;
use std::env;
use std::old_io::fs::{self, PathExtensions};
use std::old_io::process::{Command,InheritFd,ExitStatus,ExitSignal};
use std::old_io;

use cargo::{execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::{CliError, CliResult, lev_distance, Config};

#[derive(RustcDecodable)]
struct Flags {
    flag_list: bool,
    flag_verbose: bool,
    arg_command: String,
    arg_args: Vec<String>,
}

const USAGE: &'static str = "
Rust's package manager

Usage:
    cargo <command> [<args>...]
    cargo [options]

Options:
    -h, --help       Display this message
    -V, --version    Print version info and exit
    --list           List installed commands
    -v, --verbose    Use verbose output

Some common cargo commands are:
    build       Compile the current project
    clean       Remove the target directory
    doc         Build this project's and its dependencies' documentation
    new         Create a new cargo project
    run         Build and execute src/main.rs
    test        Run the tests
    bench       Run the benchmarks
    update      Update dependencies listed in Cargo.lock

See 'cargo help <command>' for more information on a specific command.
";

fn main() {
    env_logger::init().unwrap();
    execute_main_without_stdin(execute, true, USAGE)
}

macro_rules! each_subcommand{ ($mac:ident) => ({
    $mac!(bench);
    $mac!(build);
    $mac!(clean);
    $mac!(doc);
    $mac!(fetch);
    $mac!(generate_lockfile);
    $mac!(git_checkout);
    $mac!(help);
    $mac!(locate_project);
    $mac!(login);
    $mac!(new);
    $mac!(owner);
    $mac!(package);
    $mac!(pkgid);
    $mac!(publish);
    $mac!(read_manifest);
    $mac!(run);
    $mac!(search);
    $mac!(test);
    $mac!(update);
    $mac!(verify_project);
    $mac!(version);
    $mac!(yank);
}) }

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute(flags: Flags, config: &Config) -> CliResult<Option<()>> {
    config.shell().set_verbose(flags.flag_verbose);

    init_git_transports(config);

    if flags.flag_list {
        println!("Installed Commands:");
        for command in list_commands().into_iter() {
            println!("    {}", command);
        };
        return Ok(None)
    }

    let (mut args, command) = match &flags.arg_command[..] {
        "" | "help" if flags.arg_args.len() == 0 => {
            config.shell().set_verbose(true);
            let args = &["foo".to_string(), "-h".to_string()];
            let r = cargo::call_main_without_stdin(execute, config, USAGE, args,
                                                   false);
            cargo::process_executed(r, &mut **config.shell());
            return Ok(None)
        }
        "help" if flags.arg_args[0] == "-h" ||
                  flags.arg_args[0] == "--help" =>
            (flags.arg_args, "help"),
        "help" => (vec!["-h".to_string()], &flags.arg_args[0][..]),
        s => (flags.arg_args.clone(), s),
    };
    args.insert(0, command.to_string());
    args.insert(0, "foo".to_string());

    macro_rules! cmd{ ($name:ident) => (
        if command == stringify!($name).replace("_", "-") {
            mod $name;
            config.shell().set_verbose(true);
            let r = cargo::call_main_without_stdin($name::execute, config,
                                                   $name::USAGE,
                                                   &args,
                                                   false);
            cargo::process_executed(r, &mut **config.shell());
            return Ok(None)
        }
    ) }
    each_subcommand!(cmd);

    execute_subcommand(&command, &args, &mut config.shell());
    Ok(None)
}

fn find_closest(cmd: &str) -> Option<String> {
    match list_commands().iter()
                            // doing it this way (instead of just .min_by(|c|
                            // c.lev_distance(cmd))) allows us to only make
                            // suggestions that have an edit distance of
                            // 3 or less
                            .map(|c| (lev_distance(&c, cmd), c))
                            .filter(|&(d, _): &(usize, &String)| d < 4)
                            .min_by(|&(d, _)| d) {
        Some((_, c)) => {
            Some(c.to_string())
        },
        None => None
    }
}

fn execute_subcommand(cmd: &str, args: &[String], shell: &mut MultiShell) {
    let command = match find_command(cmd) {
        Some(command) => command,
        None => {
            let msg = match find_closest(cmd) {
                Some(closest) => format!("No such subcommand\n\n\t\
                                          Did you mean `{}`?\n", closest),
                None => "No such subcommand".to_string()
            };
            return handle_error(CliError::new(&msg, 127), shell)
        }
    };
    let status = Command::new(command)
                         .args(&args[1..])
                         .stdin(InheritFd(0))
                         .stdout(InheritFd(1))
                         .stderr(InheritFd(2))
                         .status();

    match status {
        Ok(ExitStatus(0)) => (),
        Ok(ExitStatus(i)) => {
            handle_error(CliError::new("", i as i32), shell)
        }
        Ok(ExitSignal(i)) => {
            let msg = format!("subcommand failed with signal: {}", i);
            handle_error(CliError::new(&msg, i as i32), shell)
        }
        Err(old_io::IoError{kind, ..}) if kind == old_io::FileNotFound =>
            handle_error(CliError::new("No such subcommand", 127), shell),
        Err(err) => handle_error(
            CliError::new(
                &format!("Subcommand failed to run: {}", err), 127),
            shell)
    }
}

/// List all runnable commands. find_command should always succeed
/// if given one of returned command.
fn list_commands() -> BTreeSet<String> {
    let command_prefix = "cargo-";
    let mut commands = BTreeSet::new();
    for dir in list_command_directory().iter() {
        let entries = match fs::readdir(dir) {
            Ok(entries) => entries,
            _ => continue
        };
        for entry in entries.iter() {
            let filename = match entry.filename_str() {
                Some(filename) => filename,
                _ => continue
            };
            if filename.starts_with(command_prefix) &&
                    filename.ends_with(env::consts::EXE_SUFFIX) &&
                    is_executable(entry) {
                let command = &filename[
                    command_prefix.len()..
                    filename.len() - env::consts::EXE_SUFFIX.len()];
                commands.insert(String::from_str(command));
            }
        }
    }

    macro_rules! add_cmd{ ($cmd:ident) => ({
        commands.insert(stringify!($cmd).replace("_", "-"));
    }) }
    each_subcommand!(add_cmd);
    commands
}

fn is_executable(path: &Path) -> bool {
    match fs::stat(path) {
        Ok(old_io::FileStat{ kind: old_io::FileType::RegularFile, perm, ..}) =>
            perm.contains(old_io::OTHER_EXECUTE),
        _ => false
    }
}

/// Get `Command` to run given command.
fn find_command(cmd: &str) -> Option<Path> {
    let command_exe = format!("cargo-{}{}", cmd, env::consts::EXE_SUFFIX);
    let dirs = list_command_directory();
    let mut command_paths = dirs.iter().map(|dir| dir.join(&command_exe));
    command_paths.find(|path| path.exists())
}

/// List candidate locations where subcommands might be installed.
fn list_command_directory() -> Vec<Path> {
    let mut dirs = vec![];
    if let Ok(mut path) = env::current_exe() {
        path.pop();
        dirs.push(path.join("../lib/cargo"));
        dirs.push(path);
    }
    if let Some(val) = env::var_os("PATH") {
        dirs.extend(env::split_paths(&val));
    }
    dirs
}

fn init_git_transports(config: &Config) {
    // Only use a custom transport if a proxy is configured, right now libgit2
    // doesn't support proxies and we have to use a custom transport in this
    // case. The custom transport, however, is not as well battle-tested.
    match cargo::ops::http_proxy_exists(config) {
        Ok(true) => {}
        _ => return
    }

    let handle = match cargo::ops::http_handle(config) {
        Ok(handle) => handle,
        Err(..) => return,
    };

    // The unsafety of the registration function derives from two aspects:
    //
    // 1. This call must be synchronized with all other registration calls as
    //    well as construction of new transports.
    // 2. The argument is leaked.
    //
    // We're clear on point (1) because this is only called at the start of this
    // binary (we know what the state of the world looks like) and we're mostly
    // clear on point (2) because we'd only free it after everything is done
    // anyway
    unsafe {
        git2_curl::register(handle);
    }
}
<|endoftext|>


<commit_before>#![crate_type = "bin"]
extern crate script;
extern crate collections;
use script::lexer::Lexer;
use script::parser::Parser;
use script::exec::{Executor, Interpreter};
use script::ast::{Token, TComment};
use script::js::value::{Value, ResultValue, to_value, from_value};
use collections::treemap::TreeMap;
use std::path::posix::Path;
use std::io::fs::{File, walk_dir};
use std::io::BufferedReader;
fn find_attrs(tokens: Vec<Token>) -> TreeMap<~str, ~str> {
	let mut map = TreeMap::new();
	for tk in tokens.iter() {
		match tk.data {
			TComment(ref comm) => {
				let current = comm.as_slice();
				if current.starts_with(" @") {
					let space_ind = current.slice_from(1).find(' ').unwrap() + 1;
					let key = comm.slice_chars(2, space_ind);
					let value = comm.slice_from(space_ind);
					map.insert(key.into_owned(), value.into_owned());
				}
			},
			_ => ()
		}
	}
	map
}
fn assert(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	if args.len() < 2 {
		return Err(to_value("'assert' function expects assertion and description arguments"));
	}
	let val : bool = from_value(*args.get(0)).unwrap();
	let desc : Value = *args.get(1);
	if val {
		Ok(desc)
	} else {
		Err(desc)
	}
}
fn main() {
	let mut path = Path::new("tests");
	if !path.is_dir() {
		path = Path::new("../tests");
	}
	if !path.is_dir() {
		fail!("Could not find tests directory");
	}
	for file in walk_dir(&path).unwrap() {
		if file.is_file() && file.extension_str() == Some("js") {
			let file_str = file.as_str().unwrap();
			let mut lexer = Lexer::new(BufferedReader::new(File::open(&file).unwrap()));
			lexer.lex().unwrap();
			let attributes = find_attrs(lexer.tokens.clone());
			let description = match attributes.find(&"description".into_owned()) {
				Some(desc) => desc,
				None => fail!("{} does not have @description metadata", file_str)
			};
			let mut parser = Parser::new(lexer.tokens);
			let expr = match parser.parse_all() {
				Ok(v) => v,
				Err(v) => fail!("{}: {}", file_str, v)
			};
			let mut engine : Interpreter = Executor::new();
			engine.set_global("assert".into_maybe_owned(), to_value(assert));
			let result : Result<Value, Value> = engine.run(&expr);
			match result {
				Ok(_) => println!("All tests passed: {} - {}", file_str, description),
				Err(v) => fail!("Test failed: {} - {}: {}", file_str, description, v.borrow())
			}
		}
	}
}<commit_msg>Re-word success and fail output for tests<commit_after>#![crate_type = "bin"]
extern crate script;
extern crate collections;
use script::lexer::Lexer;
use script::parser::Parser;
use script::exec::{Executor, Interpreter};
use script::ast::{Token, TComment};
use script::js::value::{Value, ResultValue, to_value, from_value};
use collections::treemap::TreeMap;
use std::path::posix::Path;
use std::io::fs::{File, walk_dir};
use std::io::BufferedReader;
fn find_attrs(tokens: Vec<Token>) -> TreeMap<~str, ~str> {
	let mut map = TreeMap::new();
	for tk in tokens.iter() {
		match tk.data {
			TComment(ref comm) => {
				let current = comm.as_slice();
				if current.starts_with(" @") {
					let space_ind = current.slice_from(1).find(' ').unwrap() + 1;
					let key = comm.slice_chars(2, space_ind);
					let value = comm.slice_from(space_ind);
					map.insert(key.into_owned(), value.into_owned());
				}
			},
			_ => ()
		}
	}
	map
}
fn assert(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	if args.len() < 2 {
		return Err(to_value("'assert' function expects assertion and description arguments"));
	}
	let val : bool = from_value(*args.get(0)).unwrap();
	let desc : Value = *args.get(1);
	if val {
		Ok(desc)
	} else {
		Err(desc)
	}
}
fn main() {
	let mut path = Path::new("tests");
	if !path.is_dir() {
		path = Path::new("../tests");
	}
	if !path.is_dir() {
		fail!("Could not find tests directory");
	}
	for file in walk_dir(&path).unwrap() {
		if file.is_file() && file.extension_str() == Some("js") {
			let file_str = file.as_str().unwrap();
			let mut lexer = Lexer::new(BufferedReader::new(File::open(&file).unwrap()));
			lexer.lex().unwrap();
			let attributes = find_attrs(lexer.tokens.clone());
			let description = match attributes.find(&"description".into_owned()) {
				Some(desc) => desc,
				None => fail!("{} does not have @description metadata", file_str)
			};
			let mut parser = Parser::new(lexer.tokens);
			let expr = match parser.parse_all() {
				Ok(v) => v,
				Err(v) => fail!("{}: {}", file_str, v)
			};
			let mut engine : Interpreter = Executor::new();
			engine.set_global("assert".into_maybe_owned(), to_value(assert));
			let result : Result<Value, Value> = engine.run(&expr);
			match result {
				Ok(_) => println!("{}: All tests passed for {}", file_str, description),
				Err(v) => fail!("{}: Test failed for {} in {}", file_str, v.borrow(), description)
			}
		}
	}
}<|endoftext|>