<commit_before>#[cfg(not(feature="num"))]
macro_rules! num_impl_num {($($_tts:tt)*) => {}}

#[cfg(feature="num")]
macro_rules! num_impl_num {
    (($kind:tt) pub struct $name:ident($fty:ty);) => {
        impl num::traits::Bounded for $name {
            #[inline]
            fn min_value() -> $name {
                $name(num::traits::Bounded::min_value())
            }

            #[inline]
            fn max_value() -> $name {
                $name(num::traits::Bounded::max_value())
            }
        }

        // `Float`: requires `Num`.
        nan_branch! {
            $kind;
            option {}
            panic {
                impl num::traits::Float for $name {
                    #[inline]
                    fn nan() -> $name {
                        panic!(concat!(stringify!($name), " does not have a NaN representation"))
                    }

                    #[inline]
                    fn infinity() -> $name {
                        $name::from_float(<$fty>::infinity()).expect(::NAN_MSG)
                    }

                    #[inline]
                    fn neg_infinity() -> $name {
                        $name::from_float(<$fty>::neg_infinity()).expect(::NAN_MSG)
                    }

                    #[inline]
                    fn neg_zero() -> $name {
                        $name::from_float(<$fty>::neg_zero()).expect(::NAN_MSG)
                    }

                    #[inline]
                    fn min_value() -> $name {
                        $name::from_float(<$fty>::min_value()).expect(::NAN_MSG)
                    }

                    #[inline]
                    fn min_positive_value() -> $name {
                        $name::from_float(<$fty>::min_positive_value()).expect(::NAN_MSG)
                    }

                    #[inline]
                    fn max_value() -> $name {
                        $name::from_float(<$fty>::max_value()).expect(::NAN_MSG)
                    }

                    #[inline]
                    fn is_nan(self) -> bool {
                        false
                    }

                    #[inline]
                    fn is_infinite(self) -> bool {
                        (self.0).is_infinite()
                    }

                    #[inline]
                    fn is_finite(self) -> bool {
                        (self.0).is_finite()
                    }

                    #[inline]
                    fn is_normal(self) -> bool {
                        (self.0).is_normal()
                    }

                    #[inline]
                    fn classify(self) -> ::std::num::FpCategory {
                        (self.0).classify()
                    }

                    #[inline]
                    fn floor(self) -> $name {
                        $name::floor(self)
                    }

                    #[inline]
                    fn ceil(self) -> $name {
                        $name::ceil(self)
                    }

                    #[inline]
                    fn round(self) -> $name {
                        $name::round(self)
                    }

                    #[inline]
                    fn trunc(self) -> $name {
                        $name::trunc(self)
                    }

                    #[inline]
                    fn fract(self) -> $name {
                        $name::fract(self)
                    }

                    #[inline]
                    fn abs(self) -> $name {
                        $name::abs(self)
                    }

                    #[inline]
                    fn signum(self) -> $name {
                        $name::signum(self)
                    }

                    #[inline]
                    fn is_sign_positive(self) -> bool {
                        $name::is_sign_positive(self)
                    }

                    #[inline]
                    fn is_sign_negative(self) -> bool {
                        $name::is_sign_negative(self)
                    }

                    #[inline]
                    fn mul_add(self, a: $name, b: $name) -> $name {
                        $name::mul_add(self, a, b)
                    }

                    #[inline]
                    fn recip(self) -> $name {
                        $name::recip(self)
                    }

                    #[inline]
                    fn powi(self, n: i32) -> $name {
                        $name::powi(self, n)
                    }

                    #[inline]
                    fn powf(self, n: $name) -> $name {
                        $name::powf(self, n)
                    }

                    #[inline]
                    fn sqrt(self) -> $name {
                        $name::sqrt(self)
                    }

                    #[inline]
                    fn exp(self) -> $name {
                        $name::exp(self)
                    }

                    #[inline]
                    fn exp2(self) -> $name {
                        $name::exp2(self)
                    }

                    #[inline]
                    fn ln(self) -> $name {
                        $name::ln(self)
                    }

                    #[inline]
                    fn log(self, base: $name) -> $name {
                        $name::log(self, base)
                    }

                    #[inline]
                    fn log2(self) -> $name {
                        $name::log2(self)
                    }

                    #[inline]
                    fn log10(self) -> $name {
                        $name::log10(self)
                    }

                    #[inline]
                    fn max(self, other: $name) -> $name {
                        $name::max(self, other)
                    }

                    #[inline]
                    fn min(self, other: $name) -> $name {
                        $name::min(self, other)
                    }

                    #[inline]
                    fn abs_sub(self, other: $name) -> $name {
                        $name::abs_sub(self, other)
                    }

                    #[inline]
                    fn cbrt(self) -> $name {
                        $name::cbrt(self)
                    }

                    #[inline]
                    fn hypot(self, other: $name) -> $name {
                        $name::hypot(self, other)
                    }

                    #[inline]
                    fn sin(self) -> $name {
                        $name::sin(self)
                    }

                    #[inline]
                    fn cos(self) -> $name {
                        $name::cos(self)
                    }

                    #[inline]
                    fn tan(self) -> $name {
                        $name::tan(self)
                    }

                    #[inline]
                    fn asin(self) -> $name {
                        $name::asin(self)
                    }

                    #[inline]
                    fn acos(self) -> $name {
                        $name::acos(self)
                    }

                    #[inline]
                    fn atan(self) -> $name {
                        $name::atan(self)
                    }

                    #[inline]
                    fn atan2(self, other: $name) -> $name {
                        $name::atan2(self, other)
                    }

                    #[inline]
                    fn sin_cos(self) -> ($name, $name) {
                        $name::sin_cos(self)
                    }

                    #[inline]
                    fn exp_m1(self) -> $name {
                        $name::exp_m1(self)
                    }

                    #[inline]
                    fn ln_1p(self) -> $name {
                        $name::ln_1p(self)
                    }

                    #[inline]
                    fn sinh(self) -> $name {
                        $name::sinh(self)
                    }

                    #[inline]
                    fn cosh(self) -> $name {
                        $name::cosh(self)
                    }

                    #[inline]
                    fn tanh(self) -> $name {
                        $name::tanh(self)
                    }

                    #[inline]
                    fn asinh(self) -> $name {
                        $name::asinh(self)
                    }

                    #[inline]
                    fn acosh(self) -> $name {
                        $name::acosh(self)
                    }

                    #[inline]
                    fn atanh(self) -> $name {
                        $name::atanh(self)
                    }

                    #[inline]
                    fn integer_decode(self) -> (u64, i16, i8) {
                        num::traits::Float::integer_decode(self.0)
                    }
                }
            }
        }

        impl num::traits::FromPrimitive for $name {
            #[inline]
            fn from_i64(n: i64) -> Option<$name> {
                num::traits::FromPrimitive::from_i64(n).and_then($name::from_float)
            }

            #[inline]
            fn from_u64(n: u64) -> Option<$name> {
                num::traits::FromPrimitive::from_u64(n).and_then($name::from_float)
            }

            #[inline]
            fn from_isize(n: isize) -> Option<$name> {
                num::traits::FromPrimitive::from_isize(n).and_then($name::from_float)
            }

            #[inline]
            fn from_i8(n: i8) -> Option<$name> {
                num::traits::FromPrimitive::from_i8(n).and_then($name::from_float)
            }

            #[inline]
            fn from_i16(n: i16) -> Option<$name> {
                num::traits::FromPrimitive::from_i16(n).and_then($name::from_float)
            }

            #[inline]
            fn from_i32(n: i32) -> Option<$name> {
                num::traits::FromPrimitive::from_i32(n).and_then($name::from_float)
            }

            #[inline]
            fn from_usize(n: usize) -> Option<$name> {
                num::traits::FromPrimitive::from_usize(n).and_then($name::from_float)
            }

            #[inline]
            fn from_u8(n: u8) -> Option<$name> {
                num::traits::FromPrimitive::from_u8(n).and_then($name::from_float)
            }

            #[inline]
            fn from_u16(n: u16) -> Option<$name> {
                num::traits::FromPrimitive::from_u16(n).and_then($name::from_float)
            }

            #[inline]
            fn from_u32(n: u32) -> Option<$name> {
                num::traits::FromPrimitive::from_u32(n).and_then($name::from_float)
            }

            #[inline]
            fn from_f32(n: f32) -> Option<$name> {
                num::traits::FromPrimitive::from_f32(n).and_then($name::from_float)
            }

            #[inline]
            fn from_f64(n: f64) -> Option<$name> {
                num::traits::FromPrimitive::from_f64(n).and_then($name::from_float)
            }
        }

        // `Num`: requires `One`, plus `+`, `-`, `*`, `/`, and `%` to result in `$name`.
        nan_branch! {
            $kind;
            option {}
            panic {
                impl num::traits::Num for $name {
                    type FromStrRadixErr = num::traits::ParseFloatError;

                    #[inline]
                    fn from_str_radix(s: &str, radix: u32) -> Result<$name, Self::FromStrRadixErr> {
                        let v = try!(<$fty as num::traits::Num>::from_str_radix(s, radix));
                        if v.is_nan() {
                            return Err(num::traits::ParseFloatError {
                                kind: num::traits::FloatErrorKind::Invalid
                            });
                        } else {
                            unsafe { Ok($name::from_float_unchecked(v)) }
                        }
                    }
                }
            }
        }

        impl num::traits::NumCast for $name {
            #[inline]
            fn from<T: num::traits::ToPrimitive>(n: T) -> Option<$name> {
                num::traits::NumCast::from(n).and_then($name::from_float)
            }
        }

        // `One`: requires `$name * $name -> $name`.
        nan_branch! {
            $kind;
            option {}
            panic {
                impl num::traits::One for $name {
                    #[inline]
                    fn one() -> $name {
                        $name(1.0)
                    }
                }
            }
        }

        // `Signed`: requires `Num`.
        nan_branch! {
            $kind;
            option {}
            panic {
                // TODO
            }
        }

        impl num::traits::ToPrimitive for $name {
            #[inline]
            fn to_i64(&self) -> Option<i64> {
                self.0.to_i64()
            }

            #[inline]
            fn to_u64(&self) -> Option<u64> {
                self.0.to_u64()
            }

            #[inline]
            fn to_isize(&self) -> Option<isize> {
                self.0.to_isize()
            }

            #[inline]
            fn to_i8(&self) -> Option<i8> {
                self.0.to_i8()
            }

            #[inline]
            fn to_i16(&self) -> Option<i16> {
                self.0.to_i16()
            }

            #[inline]
            fn to_i32(&self) -> Option<i32> {
                self.0.to_i32()
            }

            #[inline]
            fn to_usize(&self) -> Option<usize> {
                self.0.to_usize()
            }

            #[inline]
            fn to_u8(&self) -> Option<u8> {
                self.0.to_u8()
            }

            #[inline]
            fn to_u16(&self) -> Option<u16> {
                self.0.to_u16()
            }

            #[inline]
            fn to_u32(&self) -> Option<u32> {
                self.0.to_u32()
            }

            #[inline]
            fn to_f32(&self) -> Option<f32> {
                self.0.to_f32()
            }

            #[inline]
            fn to_f64(&self) -> Option<f64> {
                self.0.to_f64()
            }
        }

        // `Zero`: requires `$name + $name -> $name`.
        nan_branch! {
            $kind;
            option {}
            panic {
                impl num::traits::Zero for $name {
                    #[inline]
                    fn zero() -> $name {
                        $name(0.0)
                    }

                    #[inline]
                    fn is_zero(&self) -> bool {
                        (self.0).is_zero()
                    }
                }
            }
        }
    };
}
<commit_msg>Added `num::Signed` impl.<commit_after>#[cfg(not(feature="num"))]
macro_rules! num_impl_num {($($_tts:tt)*) => {}}

#[cfg(feature="num")]
macro_rules! num_impl_num {
    (($kind:tt) pub struct $name:ident($fty:ty);) => {
        impl num::traits::Bounded for $name {
            #[inline]
            fn min_value() -> $name {
                $name(num::traits::Bounded::min_value())
            }

            #[inline]
            fn max_value() -> $name {
                $name(num::traits::Bounded::max_value())
            }
        }

        // `Float`: requires `Num`.
        nan_branch! {
            $kind;
            option {}
            panic {
                impl num::traits::Float for $name {
                    #[inline]
                    fn nan() -> $name {
                        panic!(concat!(stringify!($name), " does not have a NaN representation"))
                    }

                    #[inline]
                    fn infinity() -> $name {
                        $name::from_float(<$fty>::infinity()).expect(::NAN_MSG)
                    }

                    #[inline]
                    fn neg_infinity() -> $name {
                        $name::from_float(<$fty>::neg_infinity()).expect(::NAN_MSG)
                    }

                    #[inline]
                    fn neg_zero() -> $name {
                        $name::from_float(<$fty>::neg_zero()).expect(::NAN_MSG)
                    }

                    #[inline]
                    fn min_value() -> $name {
                        $name::from_float(<$fty>::min_value()).expect(::NAN_MSG)
                    }

                    #[inline]
                    fn min_positive_value() -> $name {
                        $name::from_float(<$fty>::min_positive_value()).expect(::NAN_MSG)
                    }

                    #[inline]
                    fn max_value() -> $name {
                        $name::from_float(<$fty>::max_value()).expect(::NAN_MSG)
                    }

                    #[inline]
                    fn is_nan(self) -> bool {
                        false
                    }

                    #[inline]
                    fn is_infinite(self) -> bool {
                        (self.0).is_infinite()
                    }

                    #[inline]
                    fn is_finite(self) -> bool {
                        (self.0).is_finite()
                    }

                    #[inline]
                    fn is_normal(self) -> bool {
                        (self.0).is_normal()
                    }

                    #[inline]
                    fn classify(self) -> ::std::num::FpCategory {
                        (self.0).classify()
                    }

                    #[inline]
                    fn floor(self) -> $name {
                        $name::floor(self)
                    }

                    #[inline]
                    fn ceil(self) -> $name {
                        $name::ceil(self)
                    }

                    #[inline]
                    fn round(self) -> $name {
                        $name::round(self)
                    }

                    #[inline]
                    fn trunc(self) -> $name {
                        $name::trunc(self)
                    }

                    #[inline]
                    fn fract(self) -> $name {
                        $name::fract(self)
                    }

                    #[inline]
                    fn abs(self) -> $name {
                        $name::abs(self)
                    }

                    #[inline]
                    fn signum(self) -> $name {
                        $name::signum(self)
                    }

                    #[inline]
                    fn is_sign_positive(self) -> bool {
                        $name::is_sign_positive(self)
                    }

                    #[inline]
                    fn is_sign_negative(self) -> bool {
                        $name::is_sign_negative(self)
                    }

                    #[inline]
                    fn mul_add(self, a: $name, b: $name) -> $name {
                        $name::mul_add(self, a, b)
                    }

                    #[inline]
                    fn recip(self) -> $name {
                        $name::recip(self)
                    }

                    #[inline]
                    fn powi(self, n: i32) -> $name {
                        $name::powi(self, n)
                    }

                    #[inline]
                    fn powf(self, n: $name) -> $name {
                        $name::powf(self, n)
                    }

                    #[inline]
                    fn sqrt(self) -> $name {
                        $name::sqrt(self)
                    }

                    #[inline]
                    fn exp(self) -> $name {
                        $name::exp(self)
                    }

                    #[inline]
                    fn exp2(self) -> $name {
                        $name::exp2(self)
                    }

                    #[inline]
                    fn ln(self) -> $name {
                        $name::ln(self)
                    }

                    #[inline]
                    fn log(self, base: $name) -> $name {
                        $name::log(self, base)
                    }

                    #[inline]
                    fn log2(self) -> $name {
                        $name::log2(self)
                    }

                    #[inline]
                    fn log10(self) -> $name {
                        $name::log10(self)
                    }

                    #[inline]
                    fn max(self, other: $name) -> $name {
                        $name::max(self, other)
                    }

                    #[inline]
                    fn min(self, other: $name) -> $name {
                        $name::min(self, other)
                    }

                    #[inline]
                    fn abs_sub(self, other: $name) -> $name {
                        $name::abs_sub(self, other)
                    }

                    #[inline]
                    fn cbrt(self) -> $name {
                        $name::cbrt(self)
                    }

                    #[inline]
                    fn hypot(self, other: $name) -> $name {
                        $name::hypot(self, other)
                    }

                    #[inline]
                    fn sin(self) -> $name {
                        $name::sin(self)
                    }

                    #[inline]
                    fn cos(self) -> $name {
                        $name::cos(self)
                    }

                    #[inline]
                    fn tan(self) -> $name {
                        $name::tan(self)
                    }

                    #[inline]
                    fn asin(self) -> $name {
                        $name::asin(self)
                    }

                    #[inline]
                    fn acos(self) -> $name {
                        $name::acos(self)
                    }

                    #[inline]
                    fn atan(self) -> $name {
                        $name::atan(self)
                    }

                    #[inline]
                    fn atan2(self, other: $name) -> $name {
                        $name::atan2(self, other)
                    }

                    #[inline]
                    fn sin_cos(self) -> ($name, $name) {
                        $name::sin_cos(self)
                    }

                    #[inline]
                    fn exp_m1(self) -> $name {
                        $name::exp_m1(self)
                    }

                    #[inline]
                    fn ln_1p(self) -> $name {
                        $name::ln_1p(self)
                    }

                    #[inline]
                    fn sinh(self) -> $name {
                        $name::sinh(self)
                    }

                    #[inline]
                    fn cosh(self) -> $name {
                        $name::cosh(self)
                    }

                    #[inline]
                    fn tanh(self) -> $name {
                        $name::tanh(self)
                    }

                    #[inline]
                    fn asinh(self) -> $name {
                        $name::asinh(self)
                    }

                    #[inline]
                    fn acosh(self) -> $name {
                        $name::acosh(self)
                    }

                    #[inline]
                    fn atanh(self) -> $name {
                        $name::atanh(self)
                    }

                    #[inline]
                    fn integer_decode(self) -> (u64, i16, i8) {
                        num::traits::Float::integer_decode(self.0)
                    }
                }
            }
        }

        impl num::traits::FromPrimitive for $name {
            #[inline]
            fn from_i64(n: i64) -> Option<$name> {
                num::traits::FromPrimitive::from_i64(n).and_then($name::from_float)
            }

            #[inline]
            fn from_u64(n: u64) -> Option<$name> {
                num::traits::FromPrimitive::from_u64(n).and_then($name::from_float)
            }

            #[inline]
            fn from_isize(n: isize) -> Option<$name> {
                num::traits::FromPrimitive::from_isize(n).and_then($name::from_float)
            }

            #[inline]
            fn from_i8(n: i8) -> Option<$name> {
                num::traits::FromPrimitive::from_i8(n).and_then($name::from_float)
            }

            #[inline]
            fn from_i16(n: i16) -> Option<$name> {
                num::traits::FromPrimitive::from_i16(n).and_then($name::from_float)
            }

            #[inline]
            fn from_i32(n: i32) -> Option<$name> {
                num::traits::FromPrimitive::from_i32(n).and_then($name::from_float)
            }

            #[inline]
            fn from_usize(n: usize) -> Option<$name> {
                num::traits::FromPrimitive::from_usize(n).and_then($name::from_float)
            }

            #[inline]
            fn from_u8(n: u8) -> Option<$name> {
                num::traits::FromPrimitive::from_u8(n).and_then($name::from_float)
            }

            #[inline]
            fn from_u16(n: u16) -> Option<$name> {
                num::traits::FromPrimitive::from_u16(n).and_then($name::from_float)
            }

            #[inline]
            fn from_u32(n: u32) -> Option<$name> {
                num::traits::FromPrimitive::from_u32(n).and_then($name::from_float)
            }

            #[inline]
            fn from_f32(n: f32) -> Option<$name> {
                num::traits::FromPrimitive::from_f32(n).and_then($name::from_float)
            }

            #[inline]
            fn from_f64(n: f64) -> Option<$name> {
                num::traits::FromPrimitive::from_f64(n).and_then($name::from_float)
            }
        }

        // `Num`: requires `One`, plus `+`, `-`, `*`, `/`, and `%` to result in `$name`.
        nan_branch! {
            $kind;
            option {}
            panic {
                impl num::traits::Num for $name {
                    type FromStrRadixErr = num::traits::ParseFloatError;

                    #[inline]
                    fn from_str_radix(s: &str, radix: u32) -> Result<$name, Self::FromStrRadixErr> {
                        let v = try!(<$fty as num::traits::Num>::from_str_radix(s, radix));
                        if v.is_nan() {
                            return Err(num::traits::ParseFloatError {
                                kind: num::traits::FloatErrorKind::Invalid
                            });
                        } else {
                            unsafe { Ok($name::from_float_unchecked(v)) }
                        }
                    }
                }
            }
        }

        impl num::traits::NumCast for $name {
            #[inline]
            fn from<T: num::traits::ToPrimitive>(n: T) -> Option<$name> {
                num::traits::NumCast::from(n).and_then($name::from_float)
            }
        }

        // `One`: requires `$name * $name -> $name`.
        nan_branch! {
            $kind;
            option {}
            panic {
                impl num::traits::One for $name {
                    #[inline]
                    fn one() -> $name {
                        $name(1.0)
                    }
                }
            }
        }

        // `Signed`: requires `Num`.
        nan_branch! {
            $kind;
            option {}
            panic {
                impl num::traits::Signed for $name {
                    fn abs(&self) -> $name {
                        $name::abs(*self)
                    }
                    fn abs_sub(&self, other: &$name) -> $name {
                        $name::abs_sub(*self, *other)
                    }
                    fn signum(&self) -> $name {
                        $name::signum(*self)
                    }
                    fn is_positive(&self) -> bool {
                        $name::is_sign_positive(*self)
                    }
                    fn is_negative(&self) -> bool {
                        $name::is_sign_negative(*self)
                    }
                }
            }
        }

        impl num::traits::ToPrimitive for $name {
            #[inline]
            fn to_i64(&self) -> Option<i64> {
                self.0.to_i64()
            }

            #[inline]
            fn to_u64(&self) -> Option<u64> {
                self.0.to_u64()
            }

            #[inline]
            fn to_isize(&self) -> Option<isize> {
                self.0.to_isize()
            }

            #[inline]
            fn to_i8(&self) -> Option<i8> {
                self.0.to_i8()
            }

            #[inline]
            fn to_i16(&self) -> Option<i16> {
                self.0.to_i16()
            }

            #[inline]
            fn to_i32(&self) -> Option<i32> {
                self.0.to_i32()
            }

            #[inline]
            fn to_usize(&self) -> Option<usize> {
                self.0.to_usize()
            }

            #[inline]
            fn to_u8(&self) -> Option<u8> {
                self.0.to_u8()
            }

            #[inline]
            fn to_u16(&self) -> Option<u16> {
                self.0.to_u16()
            }

            #[inline]
            fn to_u32(&self) -> Option<u32> {
                self.0.to_u32()
            }

            #[inline]
            fn to_f32(&self) -> Option<f32> {
                self.0.to_f32()
            }

            #[inline]
            fn to_f64(&self) -> Option<f64> {
                self.0.to_f64()
            }
        }

        // `Zero`: requires `$name + $name -> $name`.
        nan_branch! {
            $kind;
            option {}
            panic {
                impl num::traits::Zero for $name {
                    #[inline]
                    fn zero() -> $name {
                        $name(0.0)
                    }

                    #[inline]
                    fn is_zero(&self) -> bool {
                        (self.0).is_zero()
                    }
                }
            }
        }
    };
}
<|endoftext|>


<commit_before>//! Draw Line

use { types, triangulation, DrawState, Graphics };
use types::{ Color, Radius, Width };
use math::{ Matrix2d, Scalar };

/// The shape of the line
#[derive(Copy, Clone)]
pub enum Shape {
    /// Square edges
    Square,
    /// Round edges
    Round,
    /// Bevel edges
    Bevel,
}

/// A colored line with a default border radius
#[derive(Copy, Clone)]
pub struct Line {
    /// The line color
    pub color: Color,
    /// The line radius
    pub radius: Radius,
    /// The line shape
    pub shape: Shape,
}

impl Line {
    /// Creates a new line
    pub fn new(color: Color, radius: Radius) -> Line {
        Line {
            color: color,
            radius: radius,
            shape: Shape::Square,
        }
    }

    /// Creates a new line
    pub fn new_round(color: Color, radius: Radius) -> Line {
        Line {
            color: color,
            radius: radius,
            shape: Shape::Round,
        }
    }

    /// Sets color.
    pub fn color(mut self, value: Color) -> Self {
        self.color = value;
        self
    }

    /// Sets radius.
    pub fn radius(mut self, value: Radius) -> Self {
        self.radius = value;
        self
    }

    /// Sets width.
    pub fn width(mut self, value: types::Width) -> Self {
        self.radius = 0.5 * value;
        self
    }

    /// Sets shape.
    pub fn shape(mut self, value: Shape) -> Self {
        self.shape = value;
        self
    }

    /// Draw the line.
    pub fn draw<G>(
        &self,
        line: types::Line,
        draw_state: &DrawState,
        transform: Matrix2d,
        g: &mut G
    )
        where G: Graphics
    {
        match self.shape {
            Shape::Square => {
                g.tri_list(
                    draw_state,
                    &self.color,
                    |f|
                triangulation::with_round_border_line_tri_list(
                    2,
                    transform,
                    line,
                    self.radius,
                    |vertices| f(vertices)
                ));
            }
            Shape::Round => {
                g.tri_list(
                    draw_state,
                    &self.color,
                    |f|
                triangulation::with_round_border_line_tri_list(
                    64,
                    transform,
                    line,
                    self.radius,
                    |vertices| f(vertices)
                ));
            }
            Shape::Bevel => {
                g.tri_list(
                    draw_state,
                    &self.color,
                    |f|
                triangulation::with_round_border_line_tri_list(
                    3,
                    transform,
                    line,
                    self.radius,
                    |vertices| f(vertices)
                ));
            }
        }
    }

    /// Draws an arrow
    ///
    /// Head size is the sides of the triangle
    /// between the arrow hooks and the line
    pub fn draw_arrow<G>(
        &self,
        line: types::Line,
        head_size: Scalar,
        draw_state: &DrawState,
        transform: Matrix2d,
        g: &mut G
    )
        where G: Graphics
    {
        use Transformed;

        self.draw(line, draw_state, transform, g);
        let diff = [line[2] - line[0], line[3] - line[1]];
        let arrow_head = transform
            .trans(line[2], line[3])
            .orient(diff[0], diff[1]);
        self.draw([-head_size, head_size, 0.0, 0.0], draw_state, arrow_head, g);
        self.draw([-head_size, -head_size, 0.0, 0.0], draw_state, arrow_head, g);
    }
}

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

    #[test]
    fn test_line() {
        use Colored;

        let _line = Line::new([0.0; 4], 3.0)
            .color([1.0; 4])
            .radius(3.0)
            .shape(Shape::Round)
            .hue_deg(1.0);
    }
}
<commit_msg>Use `Into<types::Line>`<commit_after>//! Draw Line

use { types, triangulation, DrawState, Graphics };
use types::{ Color, Radius, Width };
use math::{ Matrix2d, Scalar };

/// The shape of the line
#[derive(Copy, Clone)]
pub enum Shape {
    /// Square edges
    Square,
    /// Round edges
    Round,
    /// Bevel edges
    Bevel,
}

/// A colored line with a default border radius
#[derive(Copy, Clone)]
pub struct Line {
    /// The line color
    pub color: Color,
    /// The line radius
    pub radius: Radius,
    /// The line shape
    pub shape: Shape,
}

impl Line {
    /// Creates a new line
    pub fn new(color: Color, radius: Radius) -> Line {
        Line {
            color: color,
            radius: radius,
            shape: Shape::Square,
        }
    }

    /// Creates a new line
    pub fn new_round(color: Color, radius: Radius) -> Line {
        Line {
            color: color,
            radius: radius,
            shape: Shape::Round,
        }
    }

    /// Sets color.
    pub fn color(mut self, value: Color) -> Self {
        self.color = value;
        self
    }

    /// Sets radius.
    pub fn radius(mut self, value: Radius) -> Self {
        self.radius = value;
        self
    }

    /// Sets width.
    pub fn width(mut self, value: types::Width) -> Self {
        self.radius = 0.5 * value;
        self
    }

    /// Sets shape.
    pub fn shape(mut self, value: Shape) -> Self {
        self.shape = value;
        self
    }

    /// Draw the line.
    pub fn draw<L: Into<types::Line>, G>(
        &self,
        line: L,
        draw_state: &DrawState,
        transform: Matrix2d,
        g: &mut G
    )
        where G: Graphics
    {
        let line = line.into();
        match self.shape {
            Shape::Square => {
                g.tri_list(
                    draw_state,
                    &self.color,
                    |f|
                triangulation::with_round_border_line_tri_list(
                    2,
                    transform,
                    line,
                    self.radius,
                    |vertices| f(vertices)
                ));
            }
            Shape::Round => {
                g.tri_list(
                    draw_state,
                    &self.color,
                    |f|
                triangulation::with_round_border_line_tri_list(
                    64,
                    transform,
                    line,
                    self.radius,
                    |vertices| f(vertices)
                ));
            }
            Shape::Bevel => {
                g.tri_list(
                    draw_state,
                    &self.color,
                    |f|
                triangulation::with_round_border_line_tri_list(
                    3,
                    transform,
                    line,
                    self.radius,
                    |vertices| f(vertices)
                ));
            }
        }
    }

    /// Draws an arrow
    ///
    /// Head size is the sides of the triangle
    /// between the arrow hooks and the line
    pub fn draw_arrow<L: Into<types::Line>, G>(
        &self,
        line: L,
        head_size: Scalar,
        draw_state: &DrawState,
        transform: Matrix2d,
        g: &mut G
    )
        where G: Graphics
    {
        use Transformed;

        let line = line.into();
        self.draw(line, draw_state, transform, g);
        let diff = [line[2] - line[0], line[3] - line[1]];
        let arrow_head = transform
            .trans(line[2], line[3])
            .orient(diff[0], diff[1]);
        self.draw([-head_size, head_size, 0.0, 0.0], draw_state, arrow_head, g);
        self.draw([-head_size, -head_size, 0.0, 0.0], draw_state, arrow_head, g);
    }
}

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

    #[test]
    fn test_line() {
        use Colored;

        let _line = Line::new([0.0; 4], 3.0)
            .color([1.0; 4])
            .radius(3.0)
            .shape(Shape::Round)
            .hue_deg(1.0);
    }
}
<|endoftext|>


<commit_before>use std::ops::{Add, Sub, Mul, Div, Rem};

//TODO: Refactor Unit into its own newtype
//TODO: Define a `.next()` method that returns the next unit from a given unit (use this in EvalContext) instead of manually incrementing the unit in create_unit
pub type Unit = usize;

#[derive(Debug, Clone, Copy)]
pub struct RichNumber {
    //TODO: These should not be public as modifying them may not always force strict adherence to mathematical laws
    pub value: f64,
    pub unit: Option<Unit>,
}

impl RichNumber {
    pub fn new(value: f64, unit: Option<Unit>) -> RichNumber {
        RichNumber {
            value: value,
            unit: unit,
        }
    }

    //TODO: Rename from_unit to with_unit per Rust styleguide
    pub fn from_unit(value: f64, unit: Unit) -> RichNumber {
        RichNumber::new(value, Some(unit))
    }

    pub fn is_dimensionless(&self) -> bool {
        self.unit.is_none()
    }

    pub fn has_units(&self) -> bool {
        !self.is_dimensionless()
    }

    pub fn without_units(&self) -> RichNumber {
        RichNumber::new(self.value, None)
    }

    pub fn pow(&self, other: RichNumber) -> RichNumber {
        assert!(self.is_dimensionless() && other.is_dimensionless(),
            "Applying exponents to quantities with units is not supported yet, only raise dimensionless/scalar quantities to dimensionless/scalar exponents");

        RichNumber::from(self.value.powf(other.value))
    }

    /// Applies an operator to two values given the values and what the resulting unit should be
    fn apply_operator<F>(self, other: RichNumber, operator: F, unit: Option<Unit>) -> RichNumber
        where F: FnOnce(f64, f64) -> f64 {

        let value = operator(self.value, other.value);
        RichNumber::new(value, unit)
    }
}

impl From<i64> for RichNumber {
    fn from(number: i64) -> RichNumber {
        RichNumber::from(number as f64)
    }
}

impl From<f64> for RichNumber {
    fn from(number: f64) -> RichNumber {
        RichNumber::new(number, None)
    }
}

impl PartialEq for RichNumber {
    fn eq(&self, other: &RichNumber) -> bool {
        assert!(self.unit == other.unit,
            "Cannot compare values with different units");

        (self.value - other.value).abs() < 1e-10
    }
}

impl Add for RichNumber {
    type Output = RichNumber;

    fn add(self, other: RichNumber) -> Self::Output {
        assert!(self.unit == other.unit,
            "Cannot add values with different units");
        self.apply_operator(other, |a, b| a + b, self.unit)
    }
}

impl Sub for RichNumber {
    type Output = RichNumber;

    fn sub(self, other: RichNumber) -> Self::Output {
        assert!(self.unit == other.unit,
            "Cannot subtract values with different units");
        self.apply_operator(other, |a, b| a - b, self.unit)
    }
}

impl Mul for RichNumber {
    type Output = RichNumber;

    fn mul(self, other: RichNumber) -> Self::Output {
        let unit;
        if self.is_dimensionless() {
            unit = other.unit;
        }
        else if other.is_dimensionless() {
            unit = self.unit;
        }
        else {
            panic!("Multiplying units is not supported yet. Try a dimensionaless/scalar value");
        }

        self.apply_operator(other, |a, b| a * b, unit)
    }
}

impl Div for RichNumber {
    type Output = RichNumber;

    fn div(self, other: RichNumber) -> Self::Output {
        let unit;
        if other.is_dimensionless() {
            unit = self.unit;
        }
        else if self.unit == other.unit {
            unit = None;
        }
        else {
            panic!("Dividing units is not supported yet. Use two values with the same unit or multiply by a dimensionless/scalar value");
        }

        self.apply_operator(other, |a, b| a / b, unit)
    }
}

impl Rem for RichNumber {
    type Output = RichNumber;

    fn rem(self, other: RichNumber) -> Self::Output {
        let unit;
        if other.is_dimensionless() {
            unit = self.unit;
        }
        else if self.unit == other.unit {
            unit = None;
        }
        else {
            panic!("Taking the remainder of quantities with units is not supported. Use two values with the same unit or multiply by a dimensionless/scalar value");
        }

        self.apply_operator(other, |a, b| a % b, unit)
    }
}

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

    #[test]
    fn equality() {
        let a = RichNumber::from(2);
        let b = RichNumber::from(2);
        let c = RichNumber::from(3.6);

        assert_eq!(a, b);
        assert!(a != c);
    }

    #[test]
    fn basic_operations() {
        let a = RichNumber::from(2);
        let b = RichNumber::from(3.6);

        assert_eq!(a + b, RichNumber::from(5.6f64));
        assert_eq!(b + a, RichNumber::from(5.6f64));

        assert_eq!(a - b, RichNumber::from(-1.6f64));
        assert_eq!(b - a, RichNumber::from(1.6f64));

        assert_eq!(a * b, RichNumber::from(7.2f64));
        assert_eq!(b * a, RichNumber::from(7.2f64));

        assert_eq!(a / b, RichNumber::from(0.55555555555f64));
        assert_eq!(b / a, RichNumber::from(1.8f64));

        assert_eq!(a % b, RichNumber::from(2f64));
        assert_eq!(b % a, RichNumber::from(1.6f64));
    }
}

<commit_msg>Implementing ordering for rich numbers<commit_after>use std::cmp::Ordering;
use std::ops::{Add, Sub, Mul, Div, Rem};

//TODO: Refactor Unit into its own newtype
//TODO: Define a `.next()` method that returns the next unit from a given unit (use this in EvalContext) instead of manually incrementing the unit in create_unit
pub type Unit = usize;

#[derive(Debug, Clone, Copy, PartialOrd)]
pub struct RichNumber {
    //TODO: These should not be public as modifying them may not always force strict adherence to mathematical laws
    pub value: f64,
    pub unit: Option<Unit>,
}

impl RichNumber {
    pub fn new(value: f64, unit: Option<Unit>) -> RichNumber {
        RichNumber {
            value: value,
            unit: unit,
        }
    }

    //TODO: Rename from_unit to with_unit per Rust styleguide
    pub fn from_unit(value: f64, unit: Unit) -> RichNumber {
        RichNumber::new(value, Some(unit))
    }

    pub fn is_dimensionless(&self) -> bool {
        self.unit.is_none()
    }

    pub fn has_units(&self) -> bool {
        !self.is_dimensionless()
    }

    pub fn without_units(&self) -> RichNumber {
        RichNumber::new(self.value, None)
    }

    pub fn pow(&self, other: RichNumber) -> RichNumber {
        assert!(self.is_dimensionless() && other.is_dimensionless(),
            "Applying exponents to quantities with units is not supported yet, only raise dimensionless/scalar quantities to dimensionless/scalar exponents");

        RichNumber::from(self.value.powf(other.value))
    }

    /// Applies an operator to two values given the values and what the resulting unit should be
    fn apply_operator<F>(self, other: RichNumber, operator: F, unit: Option<Unit>) -> RichNumber
        where F: FnOnce(f64, f64) -> f64 {

        let value = operator(self.value, other.value);
        RichNumber::new(value, unit)
    }
}

impl From<i64> for RichNumber {
    fn from(number: i64) -> RichNumber {
        RichNumber::from(number as f64)
    }
}

impl From<f64> for RichNumber {
    fn from(number: f64) -> RichNumber {
        RichNumber::new(number, None)
    }
}

impl PartialEq for RichNumber {
    fn eq(&self, other: &RichNumber) -> bool {
        assert!(self.unit == other.unit,
            "Cannot compare values with different units");

        (self.value - other.value).abs() < 1e-10
    }
}

impl Eq for RichNumber {}

impl Ord for RichNumber {
    fn cmp(&self, other: &Self) -> Ordering {
        assert!(self.unit == other.unit,
            "Cannot compare values with different units");

        self.value.partial_cmp(&other.value).unwrap()
    }
}

impl Add for RichNumber {
    type Output = RichNumber;

    fn add(self, other: RichNumber) -> Self::Output {
        assert!(self.unit == other.unit,
            "Cannot add values with different units");
        self.apply_operator(other, |a, b| a + b, self.unit)
    }
}

impl Sub for RichNumber {
    type Output = RichNumber;

    fn sub(self, other: RichNumber) -> Self::Output {
        assert!(self.unit == other.unit,
            "Cannot subtract values with different units");
        self.apply_operator(other, |a, b| a - b, self.unit)
    }
}

impl Mul for RichNumber {
    type Output = RichNumber;

    fn mul(self, other: RichNumber) -> Self::Output {
        let unit;
        if self.is_dimensionless() {
            unit = other.unit;
        }
        else if other.is_dimensionless() {
            unit = self.unit;
        }
        else {
            panic!("Multiplying units is not supported yet. Try a dimensionaless/scalar value");
        }

        self.apply_operator(other, |a, b| a * b, unit)
    }
}

impl Div for RichNumber {
    type Output = RichNumber;

    fn div(self, other: RichNumber) -> Self::Output {
        let unit;
        if other.is_dimensionless() {
            unit = self.unit;
        }
        else if self.unit == other.unit {
            unit = None;
        }
        else {
            panic!("Dividing units is not supported yet. Use two values with the same unit or multiply by a dimensionless/scalar value");
        }

        self.apply_operator(other, |a, b| a / b, unit)
    }
}

impl Rem for RichNumber {
    type Output = RichNumber;

    fn rem(self, other: RichNumber) -> Self::Output {
        let unit;
        if other.is_dimensionless() {
            unit = self.unit;
        }
        else if self.unit == other.unit {
            unit = None;
        }
        else {
            panic!("Taking the remainder of quantities with units is not supported. Use two values with the same unit or multiply by a dimensionless/scalar value");
        }

        self.apply_operator(other, |a, b| a % b, unit)
    }
}

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

    #[test]
    fn equality() {
        let a = RichNumber::from(2);
        let b = RichNumber::from(2);
        let c = RichNumber::from(3.6);

        assert_eq!(a, b);
        assert!(a != c);
    }

    #[test]
    fn basic_operations() {
        let a = RichNumber::from(2);
        let b = RichNumber::from(3.6);

        assert_eq!(a + b, RichNumber::from(5.6f64));
        assert_eq!(b + a, RichNumber::from(5.6f64));

        assert_eq!(a - b, RichNumber::from(-1.6f64));
        assert_eq!(b - a, RichNumber::from(1.6f64));

        assert_eq!(a * b, RichNumber::from(7.2f64));
        assert_eq!(b * a, RichNumber::from(7.2f64));

        assert_eq!(a / b, RichNumber::from(0.55555555555f64));
        assert_eq!(b / a, RichNumber::from(1.8f64));

        assert_eq!(a % b, RichNumber::from(2f64));
        assert_eq!(b % a, RichNumber::from(1.6f64));
    }

    #[test]
    fn ordering() {
        let a = RichNumber::from(2);
        let b = RichNumber::from(3.6666666666666);
        let c = RichNumber::from(3.6666666666667);
        let d = RichNumber::from(3.6666666666667);

        assert!(a < b);
        assert!(b < c);
        assert!(c <= d);
        assert!(d > b);
        assert!(b >= a);
    }
}

<|endoftext|>


<commit_before>/* kernel::fs.rs */

use core::*;
use core::str::*;
use core::option::{Some, Option, None}; // Match statement
use core::iter::Iterator;
use core::vec::Vec;
use super::super::platform::*;

pub fn open(node: *tree_node, file: cstr) -> (*tree_node, bool, bool)
{
    if dir.isLeaf() || file == ""
    {
	return (node, dir.isLeaf(), file == "");
    }
    let mut children: uint = (*node).child_count;
    let mut i: uint = 0;
    let mut split = file.before('/');
    while i < children
    {
	if (*node).children[i].name == k
	{
	    return open((*node).children[i], file.remainder('/'));
	} else
	{
	    i += 1;
	}
    }
    return cstr::new();
}

pub fn append(node: *tree_node, file: cstr, content: cstr) -> bool
{
    let (mut f, _, _) = open(node, file);
    if f == cstr::new()
    {
	return false;
    }
    let mut x = 0;
    let mut f_contents = (*f).contents;
    while x < content.len()
    {
	let b = f_contents.push_char(content.char_at(x));
	if !b
	{
	    return false;
	}
    }
    let (*f).contents = f_contents;
    return true;
}

pub fn new(node: *tree_node, dir: cstr, name: cstr) -> bool
{
    let (mut n, _, _) = open(node, file);
    if !n.isLeaf()
    {
	n.insert(name);
    }
    return false;

}
<commit_msg>Update.<commit_after><|endoftext|>


<commit_before>use crossbeam_channel::bounded;
use crossbeam_channel::Receiver;
use crossbeam_channel::Sender;
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::process::ExitCode;
use std::thread;
use std::vec::Vec;

#[derive(Debug)]
struct TranscodeJob {
    src: PathBuf,
    dest: PathBuf,
}

fn main() -> Result<(), ExitCode> {
    let (srcdir, destdir) = parse_args()?;

    println!(
        "videos src: {} dest: {}",
        srcdir.display(),
        destdir.display()
    );

    if srcdir == destdir {
        println!("src and dest dirs must differ");
        return Err(ExitCode::FAILURE);
    }

    thread::scope(|s| {
        const NTHREADS: i32 = 6;

        let (job_sender, job_recv) = bounded::<TranscodeJob>(0);

        for i in 0..NTHREADS {
            let job_recv = job_recv.clone();
            s.spawn(move || transcoder(i, job_recv));
        }

        jobscheduler(srcdir.as_path(), destdir.as_path(), job_sender);
    });

    println!("done");

    Ok(())
}

fn jobscheduler(srcdir: &Path, destdir: &Path, job_sender: Sender<TranscodeJob>) {
    println!("starting job scheduler");

    let entries = fs::read_dir(srcdir).unwrap();
    let mut srcs = Vec::new();

    for entry in entries {
        match entry {
            Ok(entry) => {
                let srcdir = entry.path();
                if let Some(extension) = srcdir.extension() {
                    let extension = extension
                        .to_str()
                        .expect("file extensions should be valid utf-8");

                    match extension {
                        "avi" => {
                            srcs.push(srcdir);
                        }
                        _ => {
                            println!("ignoring file with extension: {}", extension)
                        }
                    }
                }
            }
            Err(err) => {
                print!("error reading dir {}: {}", srcdir.display(), err);
            }
        }
    }

    for src in srcs {
        // We already validated srcs, so they always have a filename
        let dest_file = src.with_extension("mkv");
        let mut dest = destdir.to_path_buf();
        dest.push(dest_file.file_name().unwrap());

        let job = TranscodeJob {
            src: src,
            dest: dest,
        };
        job_sender.send(job).expect("failed to send job to workers");
    }

    drop(job_sender);
}

fn transcoder(id: i32, job_recv: Receiver<TranscodeJob>) {
    println!("starting transcoder {}", id);

    while let Ok(job) = job_recv.recv() {
        println!(
            "transcoder {} transcoding from {} to {}",
            id,
            job.src.display(),
            job.dest.display()
        );

        // I usually go with Gstreamer, but it does not have a proper
        // way to increase the framerate. So I used ffmpeg.
        //let pipeline = format!(
        //r#"
        //gst-launch-1.0 filesrc location="{}" ! decodebin name=decoder ! \
        //queue ! videoconvert ! videoscale ! videorate ! x264enc ! queue ! \
        //matroskamux name=muxer ! queue ! filesink location="{}" decoder. ! \
        //queue ! audioconvert ! audioresample ! vorbisenc ! queue ! muxer.
        //"#,
        //job.src.display(),
        //job.dest.display(),
        //);

        let mut cmd = Command::new("ffmpeg");
        cmd.arg("-i");
        cmd.arg(job.src);
        cmd.arg("-crf");
        cmd.arg("10");
        cmd.arg("-filter:v");
        cmd.arg("tblend");
        cmd.arg("-r");
        cmd.arg("60");
        cmd.arg(job.dest);

        match cmd.spawn() {
            Ok(mut child) => match child.wait() {
                Ok(res) => {
                    println!("transcoder result: {}", res);
                }
                Err(err) => {
                    println!("error running transcoder: {}", err);
                }
            },
            Err(err) => {
                println!("error starting transcoder: {}", err);
            }
        }
    }

    println!("finishing transcoder {}", id);
}

fn parse_args() -> Result<(PathBuf, PathBuf), ExitCode> {
    let args: Vec<String> = env::args().collect();

    return match args.len() {
        1 => {
            let src = env::current_dir().unwrap();
            let mut dest = src.clone();
            dest.push("transcoded");
            Ok((src, dest))
        }
        3 => Ok((PathBuf::from(&args[1]), PathBuf::from(&args[2]))),
        _ => {
            println!("usage using current dir: {}", args[0]);
            println!("usage explicit dirs: {} <src dir> <dest dir>", args[0]);
            Err(ExitCode::FAILURE)
        }
    };
}
<commit_msg>chore: create less threads<commit_after>use crossbeam_channel::bounded;
use crossbeam_channel::Receiver;
use crossbeam_channel::Sender;
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::process::ExitCode;
use std::thread;
use std::vec::Vec;

#[derive(Debug)]
struct TranscodeJob {
    src: PathBuf,
    dest: PathBuf,
}

fn main() -> Result<(), ExitCode> {
    let (srcdir, destdir) = parse_args()?;

    println!(
        "videos src: {} dest: {}",
        srcdir.display(),
        destdir.display()
    );

    if srcdir == destdir {
        println!("src and dest dirs must differ");
        return Err(ExitCode::FAILURE);
    }

    thread::scope(|s| {
        const NTHREADS: i32 = 4;

        let (job_sender, job_recv) = bounded::<TranscodeJob>(0);

        for i in 0..NTHREADS {
            let job_recv = job_recv.clone();
            s.spawn(move || transcoder(i, job_recv));
        }

        jobscheduler(srcdir.as_path(), destdir.as_path(), job_sender);
    });

    println!("done");

    Ok(())
}

fn jobscheduler(srcdir: &Path, destdir: &Path, job_sender: Sender<TranscodeJob>) {
    println!("starting job scheduler");

    let entries = fs::read_dir(srcdir).unwrap();
    let mut srcs = Vec::new();

    for entry in entries {
        match entry {
            Ok(entry) => {
                let srcdir = entry.path();
                if let Some(extension) = srcdir.extension() {
                    let extension = extension
                        .to_str()
                        .expect("file extensions should be valid utf-8");

                    match extension {
                        "avi" => {
                            srcs.push(srcdir);
                        }
                        _ => {
                            println!("ignoring file with extension: {}", extension)
                        }
                    }
                }
            }
            Err(err) => {
                print!("error reading dir {}: {}", srcdir.display(), err);
            }
        }
    }

    for src in srcs {
        // We already validated srcs, so they always have a filename
        let dest_file = src.with_extension("mkv");
        let mut dest = destdir.to_path_buf();
        dest.push(dest_file.file_name().unwrap());

        let job = TranscodeJob {
            src: src,
            dest: dest,
        };
        job_sender.send(job).expect("failed to send job to workers");
    }

    drop(job_sender);
}

fn transcoder(id: i32, job_recv: Receiver<TranscodeJob>) {
    println!("starting transcoder {}", id);

    while let Ok(job) = job_recv.recv() {
        println!(
            "transcoder {} transcoding from {} to {}",
            id,
            job.src.display(),
            job.dest.display()
        );

        // I usually go with Gstreamer, but it does not have a proper
        // way to increase the framerate. So I used ffmpeg.
        //let pipeline = format!(
        //r#"
        //gst-launch-1.0 filesrc location="{}" ! decodebin name=decoder ! \
        //queue ! videoconvert ! videoscale ! videorate ! x264enc ! queue ! \
        //matroskamux name=muxer ! queue ! filesink location="{}" decoder. ! \
        //queue ! audioconvert ! audioresample ! vorbisenc ! queue ! muxer.
        //"#,
        //job.src.display(),
        //job.dest.display(),
        //);

        let mut cmd = Command::new("ffmpeg");
        cmd.arg("-i");
        cmd.arg(job.src);
        cmd.arg("-crf");
        cmd.arg("10");
        cmd.arg("-filter:v");
        cmd.arg("tblend");
        cmd.arg("-r");
        cmd.arg("60");
        cmd.arg(job.dest);

        match cmd.spawn() {
            Ok(mut child) => match child.wait() {
                Ok(res) => {
                    println!("transcoder result: {}", res);
                }
                Err(err) => {
                    println!("error running transcoder: {}", err);
                }
            },
            Err(err) => {
                println!("error starting transcoder: {}", err);
            }
        }
    }

    println!("finishing transcoder {}", id);
}

fn parse_args() -> Result<(PathBuf, PathBuf), ExitCode> {
    let args: Vec<String> = env::args().collect();

    return match args.len() {
        1 => {
            let src = env::current_dir().unwrap();
            let mut dest = src.clone();
            dest.push("transcoded");
            Ok((src, dest))
        }
        3 => Ok((PathBuf::from(&args[1]), PathBuf::from(&args[2]))),
        _ => {
            println!("usage using current dir: {}", args[0]);
            println!("usage explicit dirs: {} <src dir> <dest dir>", args[0]);
            Err(ExitCode::FAILURE)
        }
    };
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate serde_derive;
extern crate serde_json;
#[macro_use]
extern crate quick_error;
#[macro_use]
extern crate clap;
extern crate colored;

extern crate rustfix;

use std::fs::File;
use std::io::{Read, Write};
use std::error::Error;
use std::process::Command;

use colored::Colorize;
use clap::{Arg, App};

use rustfix::Suggestion;
use rustfix::diagnostics::Diagnostic;

const USER_OPTIONS: &'static str = "What do you want to do? \
    [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving)";

fn main() {
    let program = try_main();
    match program {
        Ok(_) => std::process::exit(0),
        Err(ProgramError::UserAbort) => {
            writeln!(std::io::stdout(), "{}", ProgramError::UserAbort).unwrap();
            std::process::exit(0);
        }
        Err(error) => {
            writeln!(std::io::stderr(), "An error occured: {}", error).unwrap();
            writeln!(std::io::stderr(), "{:?}", error).unwrap();
            if let Some(cause) = error.cause() {
                writeln!(std::io::stderr(), "Cause: {:?}", cause).unwrap();
            }
            std::process::exit(1);
        }
    }
}

macro_rules! flush {
    () => (try!(std::io::stdout().flush());)
}

fn try_main() -> Result<(), ProgramError> {
    let matches = App::new("rustfix")
        .about("Automatically apply suggestions made by rustc")
        .version(crate_version!())
        .arg(Arg::with_name("clippy")
            .long("clippy")
            .help("Use `cargo clippy` for suggestions"))
        .get_matches();

    // Get JSON output from rustc...
        let subcommand = if matches.is_present("clippy") {
            "clippy"
        } else {
            "rustc"
        };
        try!(json_from_subcommand(subcommand))

    let suggestions: Vec<Suggestion> = json.lines()
        .filter(not_empty)
        // Convert JSON string (and eat parsing errors)
        .flat_map(|line| serde_json::from_str::<CargoMessage>(line))
        // One diagnostic line might have multiple suggestions
        .flat_map(|cargo_msg| rustfix::collect_suggestions(&cargo_msg.message, None))
        .collect();

    try!(handle_suggestions(&suggestions));

    Ok(())
}

#[derive(Deserialize)]
struct CargoMessage {
    message: Diagnostic,
}

fn json_from_subcommand(subcommand: &str) -> Result<String, ProgramError> {
    let output = try!(Command::new("cargo")
        .args(&[subcommand, "--message-format", "json"])
        .output());

    let content = try!(String::from_utf8(output.stderr));

    Ok(content)
}

fn handle_suggestions(suggestions: &[Suggestion]) -> Result<(), ProgramError> {
    let mut accepted_suggestions: Vec<&Suggestion> = vec![];

    if suggestions.is_empty() {
        println!("I don't have any suggestions for you right now. Check back later!");
        return Ok(());
    }

    'suggestions: for suggestion in suggestions {
        println!("\n\n{info}: {message}\n\
            {arrow} {file}:{range}\n\
            {suggestion}\n\n\
            {lead}{text}{tail}\n\n\
            {with}\n\n\
            {replacement}\n",
            info = "Info".green().bold(),
            message = split_at_lint_name(&suggestion.message),
            arrow = "  -->".blue().bold(),
            suggestion = "Suggestion - Replace:".yellow().bold(),
            file = suggestion.file_name,
            range = suggestion.line_range,
            lead = indent(4, &suggestion.text.0),
            text = suggestion.text.1.red(),
            tail = suggestion.text.2,
            with = "with:".yellow().bold(),
            replacement = indent(4, &suggestion.replacement));

        'userinput: loop {
            print!("{arrow} {user_options}\n\
                {prompt} ",
                arrow = "==>".green().bold(),
                prompt = "  >".green().bold(),
                user_options = USER_OPTIONS.green());

            flush!();
            let mut input = String::new();
            try!(std::io::stdin().read_line(&mut input));

            match input.trim() {
                "s" => {
                    println!("Skipped.");
                    continue 'suggestions;
                }
                "r" => {
                    accepted_suggestions.push(suggestion);
                    println!("Suggestion accepted. I'll remember that and apply it later.");
                    continue 'suggestions;
                }
                "q" => {
                    println!("Thanks for playing!");
                    break 'suggestions;
                }
                "a" => {
                    return Err(ProgramError::UserAbort);
                }
                _ => {
                    println!("{error}: I didn't quite get that. {user_options}",
                                error = "Error".red().bold(),
                                user_options = USER_OPTIONS);
                    continue 'userinput;
                }
            }
        }
    }

    if !accepted_suggestions.is_empty() {
        println!("Good work. Let me just apply these {} changes!",
                 accepted_suggestions.len());

        for suggestion in accepted_suggestions.iter().rev() {
            try!(apply_suggestion(suggestion));

            print!(".");
            flush!();
        }

        println!("\nDone.");
    }

    Ok(())
}

quick_error! {
    /// All possible errors in programm lifecycle
    #[derive(Debug)]
    pub enum ProgramError {
        UserAbort {
            display("Let's get outta here!")
        }
        /// Missing File
        NoFile {
            display("No input file given")
        }
        SubcommandError(subcommand: String, output: String) {
            display("Error executing subcommand `{}`", subcommand)
            description(output)
        }
        /// Error while dealing with file or stdin/stdout
        Io(err: std::io::Error) {
            from()
            cause(err)
            display("I/O error")
            description(err.description())
        }
        Utf8Error(err: std::string::FromUtf8Error) {
            from()
            display("Error reading input as UTF-8")
        }
        /// Error with deserialization
        Serde(err: serde_json::Error) {
            from()
            cause(err)
            display("Serde JSON error")
            description(err.description())
        }
    }
}

// Helpers
// -------

fn read_file_to_string(file_name: &str) -> Result<String, std::io::Error> {
    let mut file = try!(File::open(file_name));
    let mut buffer = String::new();
    try!(file.read_to_string(&mut buffer));
    Ok(buffer)
}

fn not_empty(s: &&str) -> bool {
    !s.trim().is_empty()
}

fn split_at_lint_name(s: &str) -> String {
    s.split(", #[")
        .collect::<Vec<_>>()
        .join("\n      #[") // Length of whitespace == length of "Info: "
}

fn indent(size: u32, s: &str) -> String {
    let whitespace: String = std::iter::repeat(' ').take(size as usize).collect();

    s.lines()
        .map(|l| format!("{}{}", whitespace, l))
        .collect::<Vec<_>>()
        .join("\n")
}

/// Apply suggestion to a file
///
/// Please beware of ugly hacks below! Originally, I wanted to replace byte ranges, but sadly the
/// ranges rustc's JSON output gives me do not correspond to the parts of the file they are meant
/// to correspond to. So, for now, let's just replace lines!
///
/// This function is as stupid as possible. Make sure you call for the replacemnts in one file in
/// reverse order to not mess up the lines for replacements further down the road.
fn apply_suggestion(suggestion: &Suggestion) -> Result<(), ProgramError> {
    use std::cmp::max;

    let file_content = try!(read_file_to_string(&suggestion.file_name));
    let mut new_content = String::new();

    // Add the lines before the section we want to replace
    new_content.push_str(&file_content.lines()
        .take(max(suggestion.line_range.start.line - 1, 0) as usize)
        .collect::<Vec<_>>()
        .join("\n"));
    new_content.push_str("\n");

    // Parts of line before replacement
    new_content.push_str(&file_content.lines()
        .nth(suggestion.line_range.start.line - 1)
        .unwrap_or("")
        .chars()
        .take(suggestion.line_range.start.column - 1)
        .collect::<String>());

    // Insert new content! Finally!
    new_content.push_str(&suggestion.replacement);

    // Parts of line after replacement
    new_content.push_str(&file_content.lines()
        .nth(suggestion.line_range.end.line - 1)
        .unwrap_or("")
        .chars()
        .skip(suggestion.line_range.end.column - 1)
        .collect::<String>());

    // Add the lines after the section we want to replace
    new_content.push_str("\n");
    new_content.push_str(&file_content.lines()
        .skip(suggestion.line_range.end.line as usize)
        .collect::<Vec<_>>()
        .join("\n"));
    new_content.push_str("\n");

    let mut file = try!(File::create(&suggestion.file_name));
    let new_content = new_content.as_bytes();

    try!(file.set_len(new_content.len() as u64));
    try!(file.write_all(&new_content));

    Ok(())
}
<commit_msg>Always use `cargo clippy`, but don't enable the lints by default<commit_after>#[macro_use]
extern crate serde_derive;
extern crate serde_json;
#[macro_use]
extern crate quick_error;
#[macro_use]
extern crate clap;
extern crate colored;

extern crate rustfix;

use std::fs::File;
use std::io::{Read, Write};
use std::error::Error;
use std::process::Command;

use colored::Colorize;
use clap::{Arg, App};

use rustfix::Suggestion;
use rustfix::diagnostics::Diagnostic;

const USER_OPTIONS: &'static str = "What do you want to do? \
    [r]eplace | [s]kip | save and [q]uit | [a]bort (without saving)";

fn main() {
    let program = try_main();
    match program {
        Ok(_) => std::process::exit(0),
        Err(ProgramError::UserAbort) => {
            writeln!(std::io::stdout(), "{}", ProgramError::UserAbort).unwrap();
            std::process::exit(0);
        }
        Err(error) => {
            writeln!(std::io::stderr(), "An error occured: {}", error).unwrap();
            writeln!(std::io::stderr(), "{:?}", error).unwrap();
            if let Some(cause) = error.cause() {
                writeln!(std::io::stderr(), "Cause: {:?}", cause).unwrap();
            }
            std::process::exit(1);
        }
    }
}

macro_rules! flush {
    () => (try!(std::io::stdout().flush());)
}

fn try_main() -> Result<(), ProgramError> {
    let matches = App::new("rustfix")
        .about("Automatically apply suggestions made by rustc")
        .version(crate_version!())
        .arg(Arg::with_name("clippy")
            .long("clippy")
            .help("Use `cargo clippy` for suggestions"))
        .get_matches();

    let mut extra_args = Vec::new();

    if !matches.is_present("clippy") {
        extra_args.push("-Aclippy");
    }

    // Get JSON output from rustc...
    let json = get_json(&extra_args)?;

    let suggestions: Vec<Suggestion> = json.lines()
        .filter(not_empty)
        // Convert JSON string (and eat parsing errors)
        .flat_map(|line| serde_json::from_str::<CargoMessage>(line))
        // One diagnostic line might have multiple suggestions
        .flat_map(|cargo_msg| rustfix::collect_suggestions(&cargo_msg.message, None))
        .collect();

    try!(handle_suggestions(&suggestions));

    Ok(())
}

#[derive(Deserialize)]
struct CargoMessage {
    message: Diagnostic,
}

fn get_json(extra_args: &[&str]) -> Result<String, ProgramError> {
    let output = try!(Command::new("cargo")
        .args(&["clippy", "--message-format", "json"])
        .arg("--")
        .args(extra_args)
        .output());

    Ok(String::from_utf8(output.stdout)?)
}

fn handle_suggestions(suggestions: &[Suggestion]) -> Result<(), ProgramError> {
    let mut accepted_suggestions: Vec<&Suggestion> = vec![];

    if suggestions.is_empty() {
        println!("I don't have any suggestions for you right now. Check back later!");
        return Ok(());
    }

    'suggestions: for suggestion in suggestions {
        println!("\n\n{info}: {message}\n\
            {arrow} {file}:{range}\n\
            {suggestion}\n\n\
            {lead}{text}{tail}\n\n\
            {with}\n\n\
            {replacement}\n",
            info = "Info".green().bold(),
            message = split_at_lint_name(&suggestion.message),
            arrow = "  -->".blue().bold(),
            suggestion = "Suggestion - Replace:".yellow().bold(),
            file = suggestion.file_name,
            range = suggestion.line_range,
            lead = indent(4, &suggestion.text.0),
            text = suggestion.text.1.red(),
            tail = suggestion.text.2,
            with = "with:".yellow().bold(),
            replacement = indent(4, &suggestion.replacement));

        'userinput: loop {
            print!("{arrow} {user_options}\n\
                {prompt} ",
                arrow = "==>".green().bold(),
                prompt = "  >".green().bold(),
                user_options = USER_OPTIONS.green());

            flush!();
            let mut input = String::new();
            try!(std::io::stdin().read_line(&mut input));

            match input.trim() {
                "s" => {
                    println!("Skipped.");
                    continue 'suggestions;
                }
                "r" => {
                    accepted_suggestions.push(suggestion);
                    println!("Suggestion accepted. I'll remember that and apply it later.");
                    continue 'suggestions;
                }
                "q" => {
                    println!("Thanks for playing!");
                    break 'suggestions;
                }
                "a" => {
                    return Err(ProgramError::UserAbort);
                }
                _ => {
                    println!("{error}: I didn't quite get that. {user_options}",
                                error = "Error".red().bold(),
                                user_options = USER_OPTIONS);
                    continue 'userinput;
                }
            }
        }
    }

    if !accepted_suggestions.is_empty() {
        println!("Good work. Let me just apply these {} changes!",
                 accepted_suggestions.len());

        for suggestion in accepted_suggestions.iter().rev() {
            try!(apply_suggestion(suggestion));

            print!(".");
            flush!();
        }

        println!("\nDone.");
    }

    Ok(())
}

quick_error! {
    /// All possible errors in programm lifecycle
    #[derive(Debug)]
    pub enum ProgramError {
        UserAbort {
            display("Let's get outta here!")
        }
        /// Missing File
        NoFile {
            display("No input file given")
        }
        SubcommandError(subcommand: String, output: String) {
            display("Error executing subcommand `{}`", subcommand)
            description(output)
        }
        /// Error while dealing with file or stdin/stdout
        Io(err: std::io::Error) {
            from()
            cause(err)
            display("I/O error")
            description(err.description())
        }
        Utf8Error(err: std::string::FromUtf8Error) {
            from()
            display("Error reading input as UTF-8")
        }
        /// Error with deserialization
        Serde(err: serde_json::Error) {
            from()
            cause(err)
            display("Serde JSON error")
            description(err.description())
        }
    }
}

// Helpers
// -------

fn read_file_to_string(file_name: &str) -> Result<String, std::io::Error> {
    let mut file = try!(File::open(file_name));
    let mut buffer = String::new();
    try!(file.read_to_string(&mut buffer));
    Ok(buffer)
}

fn not_empty(s: &&str) -> bool {
    !s.trim().is_empty()
}

fn split_at_lint_name(s: &str) -> String {
    s.split(", #[")
        .collect::<Vec<_>>()
        .join("\n      #[") // Length of whitespace == length of "Info: "
}

fn indent(size: u32, s: &str) -> String {
    let whitespace: String = std::iter::repeat(' ').take(size as usize).collect();

    s.lines()
        .map(|l| format!("{}{}", whitespace, l))
        .collect::<Vec<_>>()
        .join("\n")
}

/// Apply suggestion to a file
///
/// Please beware of ugly hacks below! Originally, I wanted to replace byte ranges, but sadly the
/// ranges rustc's JSON output gives me do not correspond to the parts of the file they are meant
/// to correspond to. So, for now, let's just replace lines!
///
/// This function is as stupid as possible. Make sure you call for the replacemnts in one file in
/// reverse order to not mess up the lines for replacements further down the road.
fn apply_suggestion(suggestion: &Suggestion) -> Result<(), ProgramError> {
    use std::cmp::max;

    let file_content = try!(read_file_to_string(&suggestion.file_name));
    let mut new_content = String::new();

    // Add the lines before the section we want to replace
    new_content.push_str(&file_content.lines()
        .take(max(suggestion.line_range.start.line - 1, 0) as usize)
        .collect::<Vec<_>>()
        .join("\n"));
    new_content.push_str("\n");

    // Parts of line before replacement
    new_content.push_str(&file_content.lines()
        .nth(suggestion.line_range.start.line - 1)
        .unwrap_or("")
        .chars()
        .take(suggestion.line_range.start.column - 1)
        .collect::<String>());

    // Insert new content! Finally!
    new_content.push_str(&suggestion.replacement);

    // Parts of line after replacement
    new_content.push_str(&file_content.lines()
        .nth(suggestion.line_range.end.line - 1)
        .unwrap_or("")
        .chars()
        .skip(suggestion.line_range.end.column - 1)
        .collect::<String>());

    // Add the lines after the section we want to replace
    new_content.push_str("\n");
    new_content.push_str(&file_content.lines()
        .skip(suggestion.line_range.end.line as usize)
        .collect::<Vec<_>>()
        .join("\n"));
    new_content.push_str("\n");

    let mut file = try!(File::create(&suggestion.file_name));
    let new_content = new_content.as_bytes();

    try!(file.set_len(new_content.len() as u64));
    try!(file.write_all(&new_content));

    Ok(())
}
<|endoftext|>


<commit_before>//! Preprocess and rearrange lines of input.
//!
//! Used for literate programming.

#[macro_use] extern crate error_chain;
extern crate regex;
extern crate docopt;
extern crate rustc_serialize;

mod parsing;
mod input;

mod errors {
  error_chain! {
    links {
      Parse(::parsing::errors::Error, ::parsing::errors::ErrorKind);
      Input(::input::errors::Error, ::input::errors::ErrorKind);
    }
  }
}

use errors::*;

use std::process;
use std::io::{stdout, stderr};
use std::io::Write;
use std::io;

use std::collections::BTreeMap;
use std::cell::RefCell;
use std::rc::Rc;
use std::iter::IntoIterator;

use docopt::Docopt;

static VERSION: &'static str = "0.1.0";
macro_rules! VERSION_INFO {
  () => { "\
kaiseki {}
copyright (c) 2017 William Yao <williamyaoh@gmail.com>
license BSD 3-Clause
no warranty, whether implied or not
" }
}
static USAGE: &'static str = "
kaiseki -- literate programming preprocessing

Usage:
    kaiseki [options] [(<files> | [-])...]
    kaiseki (--help | --version)

Options:
    -h, --help              Display this help message
    --version               Display version information
    --comment, -c COMMENT   Add comments to output showing where lines of code
                            came from. Prefix them with the comment syntax COMMENT.

Tangles together all lines of code into a single file, which then
gets output to `stdout'. See kaiseki(1) for a description of the
literate programming syntax.
";

#[derive(RustcDecodable)]
struct CLIArgs {
  arg_files: Vec<String>,
  flag_comment: Option<String>
}

fn main() {
  let cli_parser = Docopt::new(USAGE).unwrap()
    .version(Some(VERSION.to_string()))
    .help(true);

  let cli_args: CLIArgs = cli_parser.decode().map_err(|err| match err {
    ::docopt::Error::Version(version) => {
      print!(VERSION_INFO!(), version);
      process::exit(0);
    },
    other => other.exit()
  }).unwrap();

  if let Err(ref e) = go(cli_args) {
    writeln!(stderr(), "kaiseki: {}", e)
      .unwrap();

    for e in e.iter().skip(1) {
      writeln!(stderr(), "  caused by: {}", e)
        .unwrap();
    }

    process::exit(1);
  }
}

/// Each Block is a part of an input file, delineated by anchor tags.
struct Block {
  contents: Vec<String>,
  from: Rc<String>,
  line: usize
}

impl Block {
  fn new(from: Rc<String>, line: usize) -> Self {
    Block {
      contents: Vec::new(),
      from: from,
      line: line
    }
  }
}

enum Section {
  Normal(Block),
  Anchored {
    /// Stored in reverse order of appearance in output file
    before: Vec<Block>,
    /// Stored in normal order of appearance in output file
    after: Vec<Block>
  }
}

fn go(args: CLIArgs) -> Result<()> {
  let files = input::open_files(args.arg_files)?;

  // Errors that we accumulate during processing. We output them at the end.
  let mut errors = Vec::new();

  let mut sections = Vec::new();

  {
    let mut lookup: BTreeMap<String, Rc<RefCell<Section>>> = BTreeMap::new();

    enum State {
      Insert,
      Before(String),
      After(String)
    }

    for file in files {
      use std::io::{BufReader, BufRead};

      let filename = Rc::new(file.name);
      let lines = BufReader::new(file.contents).lines();
      let mut lines = lines
        .enumerate()
        .map(|(lineno, line)| (lineno+1, line))
        .peekable();

      let mut state = State::Insert;
      let mut last_block = Block::new(filename.clone(), 1);

      loop {
        let next_anchor = process_block_lines(&mut lines, &mut last_block, &mut errors);

        if last_block.contents.len() > 0 {
          match state {
            State::Insert => {
              let section = Section::Normal(last_block);
              let section = Rc::new(RefCell::new(section));

              sections.push(section);
            },
            State::After(label) => {
              match lookup.get_mut(&label) {
                None => {
                  errors.push(format!("error: {}: anchor {} doesn't exist", filename, label));
                  let section = Section::Normal(last_block);
                  let section = Rc::new(RefCell::new(section));

                  sections.push(section);
                },
                Some(section) => {
                  let mut section_ref = section.borrow_mut();
                  let section: &mut Section = &mut section_ref;

                  if let &mut Section::Anchored { ref mut after, .. } = section {
                    after.push(last_block);
                  }

                  // No reason to worry if the section is a Normal. We don't
                  // ever put that kind of section in `lookup'.
                }
              };
            },
            State::Before(label) => {
              match lookup.get_mut(&label) {
                None => {
                  errors.push(format!("error: {}: anchor {} doesn't exist", filename, label));
                  let section = Section::Normal(last_block);
                  let section = Rc::new(RefCell::new(section));

                  sections.push(section);
                }
                Some(section) => {
                  let mut section_ref = section.borrow_mut();
                  let section: &mut Section = &mut section_ref;

                  if let &mut Section::Anchored { ref mut before, .. } = section {
                    before.push(last_block);
                  }

                  // No reason to worry if the section is a Normal. We don't
                  // every put that kind of section in `lookup'.
                }
              };
            }
          };
        }

        match next_anchor {
          None => break,
          Some(anchor) => {
            use parsing::Anchor;

            match anchor {
              Anchor::Insert => state = State::Insert,
              Anchor::Before(label) => state = State::Before(label),
              Anchor::After(label) => state = State::After(label),
              Anchor::Label(label) => {
                let section = Section::Anchored {
                  before: Vec::new(),
                  after: Vec::new()
                };
                let section = Rc::new(RefCell::new(section));

                sections.push(section.clone());
                lookup.insert(label, section.clone());

                state = State::Insert;
              }
            };

            let lineno = match lines.peek() {
              None => 9999999,
              Some(&(lineno, ref _line)) => lineno
            };

            last_block = Block::new(filename.clone(), lineno);
          }
        };
      }
    }
  }

  let sections = unpack_sections(sections);
  let out: Box<Write> = Box::new(stdout());
  print_processed_output(sections, args.flag_comment, out)?;

  for error in errors {
    writeln!(stderr(), "{}", error)
      .unwrap();
  }

  Ok(())
}

/// Each block will end in either an anchor tag, or the end of the file.
/// Since our caller needs to handle the anchor tag, we pass it back.
fn process_block_lines<I>(lines: &mut I, block: &mut Block, errors: &mut Vec<String>) -> Option<parsing::Anchor> where
  I: Iterator<Item=(usize, std::result::Result<String, io::Error>)>
{
  for (lineno, line) in lines {
    match line {
      Err(err) => errors.push(format!("error: {}, line {}: {}", block.from, lineno, err)),
      Ok(line) => {
        let is_normal_line;

        match parsing::might_be_anchor(&line) {
          None => is_normal_line = true,
          Some(anchor) => {
            let text = anchor.as_str();
            let anchor = parsing::parse(text);

            match anchor {
              Ok(anchor) => {
                return Some(anchor);
              },
              Err(_) => {
                errors.push(format!("warn: {}, line {}: ignoring something that looks like an anchor: {}", block.from, lineno, text));
                is_normal_line = true;
              }
            };
          }
        };

        if is_normal_line {
          block.contents.push(line);
        }
      }
    }
  }

  None
}

/// Get rid of all that indirection around our sections.
fn unpack_sections(sections: Vec<Rc<RefCell<Section>>>) -> Vec<Section> {
  let mut result = Vec::new();

  for section in sections {
    // this unwrap should never fail
    let section = Rc::try_unwrap(section)
      .map_err(|_| "invariant failed: section had more than one strong reference")
      .unwrap();
    let section = section.into_inner();

    result.push(section);
  }

  result
}

/// Print all the lines in the order that they should be.
fn print_processed_output(sections: Vec<Section>, comment: Option<String>, mut out: Box<Write>) -> Result<()> {
  macro_rules! try_output {
    ($format:expr, $($arg:expr),*) => {
      writeln!(out, $format, $($arg),*).chain_err(|| "failed to write output")?
    }
  }
  macro_rules! block_header {
    ($block:expr) => {
      if let &Some(ref leader) = &comment {
        writeln!(out, "{} '{}', line {}", leader, $block.from, $block.line)
          .chain_err(|| "failed to write output")?
      }
    }
  }

  // Typically, we only have confusion over where *inserted* blocks are
  // coming from. So we don't bother outputting headers for normal sections.

  for section in sections {
    match section {
      Section::Normal(block) => {
        for line in block.contents {
          try_output!("{}", line);
        }
      },
      Section::Anchored { before, after } => {
        for block in before.into_iter().rev() {
          block_header!(block);
          for line in block.contents {
            try_output!("{}", line);
          }
        }
        for block in after.into_iter() {
          block_header!(block);
          for line in block.contents {
            try_output!("{}", line);
          }
        }
      }
    };
  }

  Ok(())
}
<commit_msg>add some comments<commit_after>//! Preprocess and rearrange lines of input.
//!
//! Used for literate programming.

#[macro_use] extern crate error_chain;
extern crate regex;
extern crate docopt;
extern crate rustc_serialize;

mod parsing;
mod input;

mod errors {
  error_chain! {
    links {
      Parse(::parsing::errors::Error, ::parsing::errors::ErrorKind);
      Input(::input::errors::Error, ::input::errors::ErrorKind);
    }
  }
}

use errors::*;

use std::process;
use std::io::{stdout, stderr};
use std::io::Write;
use std::io;

use std::collections::BTreeMap;
use std::cell::RefCell;
use std::rc::Rc;
use std::iter::IntoIterator;

use docopt::Docopt;

static VERSION: &'static str = "0.1.0";
macro_rules! VERSION_INFO {
  () => { "\
kaiseki {}
copyright (c) 2017 William Yao <williamyaoh@gmail.com>
license BSD 3-Clause
no warranty, whether implied or not
" }
}
static USAGE: &'static str = "
kaiseki -- literate programming preprocessing

Usage:
    kaiseki [options] [(<files> | [-])...]
    kaiseki (--help | --version)

Options:
    -h, --help              Display this help message
    --version               Display version information
    --comment, -c COMMENT   Add comments to output showing where lines of code
                            came from. Prefix them with the comment syntax COMMENT.

Tangles together all lines of code into a single file, which then
gets output to `stdout'. See kaiseki(1) for a description of the
literate programming syntax.
";

#[derive(RustcDecodable)]
struct CLIArgs {
  arg_files: Vec<String>,
  flag_comment: Option<String>
}

fn main() {
  let cli_parser = Docopt::new(USAGE).unwrap()
    .version(Some(VERSION.to_string()))
    .help(true);

  let cli_args: CLIArgs = cli_parser.decode().map_err(|err| match err {
    ::docopt::Error::Version(version) => {
      print!(VERSION_INFO!(), version);
      process::exit(0);
    },
    other => other.exit()
  }).unwrap();

  if let Err(ref e) = go(cli_args) {
    writeln!(stderr(), "kaiseki: {}", e)
      .unwrap();

    for e in e.iter().skip(1) {
      writeln!(stderr(), "  caused by: {}", e)
        .unwrap();
    }

    process::exit(1);
  }
}

/// Each Block is a part of an input file, delineated by anchor tags.
struct Block {
  contents: Vec<String>,
  from: Rc<String>,
  line: usize
}

impl Block {
  fn new(from: Rc<String>, line: usize) -> Self {
    Block {
      contents: Vec::new(),
      from: from,
      line: line
    }
  }
}

enum Section {
  Normal(Block),
  Anchored {
    /// Stored in reverse order of appearance in output file
    before: Vec<Block>,
    /// Stored in normal order of appearance in output file
    after: Vec<Block>
  }
}

fn go(args: CLIArgs) -> Result<()> {
  let files = input::open_files(args.arg_files)?;

  // Errors that we accumulate during processing. We output them at the end.
  let mut errors = Vec::new();

  let mut sections = Vec::new();

  {
    let mut lookup: BTreeMap<String, Rc<RefCell<Section>>> = BTreeMap::new();

    enum State {
      Insert,
      Before(String),
      After(String)
    }

    for file in files {
      use std::io::{BufReader, BufRead};

      let filename = Rc::new(file.name);
      let lines = BufReader::new(file.contents).lines();
      let mut lines = lines
        .enumerate()
        .map(|(lineno, line)| (lineno+1, line))
        .peekable();

      let mut state = State::Insert;
      let mut last_block = Block::new(filename.clone(), 1);

      loop {
        let next_anchor = process_block_lines(&mut lines, &mut last_block, &mut errors);

        // Stick the last block where it needs to go.
        if last_block.contents.len() > 0 {
          match state {
            State::Insert => {
              let section = Section::Normal(last_block);
              let section = Rc::new(RefCell::new(section));

              sections.push(section);
            },
            State::After(label) => {
              match lookup.get_mut(&label) {
                None => {
                  errors.push(format!("error: {}: anchor {} doesn't exist", filename, label));
                  let section = Section::Normal(last_block);
                  let section = Rc::new(RefCell::new(section));

                  sections.push(section);
                },
                Some(section) => {
                  let mut section_ref = section.borrow_mut();
                  let section: &mut Section = &mut section_ref;

                  if let &mut Section::Anchored { ref mut after, .. } = section {
                    after.push(last_block);
                  }

                  // No reason to worry if the section is a Normal. We don't
                  // ever put that kind of section in `lookup'.
                }
              };
            },
            State::Before(label) => {
              match lookup.get_mut(&label) {
                None => {
                  errors.push(format!("error: {}: anchor {} doesn't exist", filename, label));
                  let section = Section::Normal(last_block);
                  let section = Rc::new(RefCell::new(section));

                  sections.push(section);
                }
                Some(section) => {
                  let mut section_ref = section.borrow_mut();
                  let section: &mut Section = &mut section_ref;

                  if let &mut Section::Anchored { ref mut before, .. } = section {
                    before.push(last_block);
                  }

                  // No reason to worry if the section is a Normal. We don't
                  // every put that kind of section in `lookup'.
                }
              };
            }
          };
        }

        // Process the next anchor we've found and create sections accordingly.
        match next_anchor {
          None => break,
          Some(anchor) => {
            use parsing::Anchor;

            match anchor {
              Anchor::Insert => state = State::Insert,
              Anchor::Before(label) => state = State::Before(label),
              Anchor::After(label) => state = State::After(label),
              Anchor::Label(label) => {
                let section = Section::Anchored {
                  before: Vec::new(),
                  after: Vec::new()
                };
                let section = Rc::new(RefCell::new(section));

                sections.push(section.clone());
                lookup.insert(label, section.clone());

                state = State::Insert;
              }
            };

            let lineno = match lines.peek() {
              None => 9999999,
              Some(&(lineno, ref _line)) => lineno
            };

            last_block = Block::new(filename.clone(), lineno);
          }
        };
      }
    }
  }

  let sections = unpack_sections(sections);
  let out: Box<Write> = Box::new(stdout());
  print_processed_output(sections, args.flag_comment, out)?;

  for error in errors {
    writeln!(stderr(), "{}", error)
      .unwrap();
  }

  Ok(())
}

/// Each block will end in either an anchor tag, or the end of the file.
/// Since our caller needs to handle the anchor tag, we pass it back.
fn process_block_lines<I>(lines: &mut I, block: &mut Block, errors: &mut Vec<String>) -> Option<parsing::Anchor> where
  I: Iterator<Item=(usize, std::result::Result<String, io::Error>)>
{
  for (lineno, line) in lines {
    match line {
      Err(err) => errors.push(format!("error: {}, line {}: {}", block.from, lineno, err)),
      Ok(line) => {
        let is_normal_line;

        match parsing::might_be_anchor(&line) {
          None => is_normal_line = true,
          Some(anchor) => {
            let text = anchor.as_str();
            let anchor = parsing::parse(text);

            match anchor {
              Ok(anchor) => {
                return Some(anchor);
              },
              Err(_) => {
                errors.push(format!("warn: {}, line {}: ignoring something that looks like an anchor: {}", block.from, lineno, text));
                is_normal_line = true;
              }
            };
          }
        };

        if is_normal_line {
          block.contents.push(line);
        }
      }
    }
  }

  None
}

/// Get rid of all that indirection around our sections.
fn unpack_sections(sections: Vec<Rc<RefCell<Section>>>) -> Vec<Section> {
  let mut result = Vec::new();

  for section in sections {
    // this unwrap should never fail
    let section = Rc::try_unwrap(section)
      .map_err(|_| "invariant failed: section had more than one strong reference")
      .unwrap();
    let section = section.into_inner();

    result.push(section);
  }

  result
}

/// Print all the lines in the order that they should be.
fn print_processed_output(sections: Vec<Section>, comment: Option<String>, mut out: Box<Write>) -> Result<()> {
  macro_rules! try_output {
    ($format:expr, $($arg:expr),*) => {
      writeln!(out, $format, $($arg),*).chain_err(|| "failed to write output")?
    }
  }
  macro_rules! block_header {
    ($block:expr) => {
      if let &Some(ref leader) = &comment {
        writeln!(out, "{} '{}', line {}", leader, $block.from, $block.line)
          .chain_err(|| "failed to write output")?
      }
    }
  }

  // Typically, we only have confusion over where *inserted* blocks are
  // coming from. So we don't bother outputting headers for normal sections.

  for section in sections {
    match section {
      Section::Normal(block) => {
        for line in block.contents {
          try_output!("{}", line);
        }
      },
      Section::Anchored { before, after } => {
        for block in before.into_iter().rev() {
          block_header!(block);
          for line in block.contents {
            try_output!("{}", line);
          }
        }
        for block in after.into_iter() {
          block_header!(block);
          for line in block.contents {
            try_output!("{}", line);
          }
        }
      }
    };
  }

  Ok(())
}
<|endoftext|>