<commit_before>
use std::ops::*;
use ndarray::*;

use super::traits::*;

#[derive(new)]
pub struct Explicit<F> {
    f: F,
    dt: f64,
}

impl<F> TimeStep for Explicit<F> {
    fn get_dt(&self) -> f64 {
        self.dt
    }
    fn set_dt(&mut self, dt: f64) {
        self.dt = dt;
    }
}

macro_rules! impl_explicit {
    ($method:ident) => {

pub struct $method<F>(Explicit<F>);

impl<F> Deref for $method<F> {
    type Target = Explicit<F>;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<F> DerefMut for $method<F> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

impl<F> $method<F> {
    pub fn new(f: F, dt: f64) -> Self {
        let e = Explicit { f: f, dt: dt };
        $method(e)
    }
}

}} // impl_explicit

impl_explicit!(Euler);
impl_explicit!(Heun);
impl_explicit!(RK4);

macro_rules! impl_time_evolution {
    ( $($mut_:tt), * ) => {

impl<'a, A, D, F> TimeEvolution<A, OwnedRcRepr<A>, D> for &'a $($mut_),* Euler<F>
    where A: OdeScalar<f64>,
          D: Dimension,
          for<'b> &'b $($mut_),* F: EOM<A, OwnedRcRepr<A>, D>
{
    #[inline(always)]
    fn iterate(self, x: RcArray<A, D>) -> RcArray<A, D> {
        let fx = self.f.rhs(x.clone());
        x + fx * self.dt
    }
}

impl<'a, A, D, F> TimeEvolution<A, ViewRepr<&'a mut A>, D> for &'a $($mut_),* Euler<F>
    where A: OdeScalar<f64>,
          D: Dimension,
          for<'b, 'c> &'b $($mut_),* F: EOM<A, ViewRepr<&'c mut A>, D>
{
    #[inline(always)]
    fn iterate(self, x: ArrayViewMut<A, D>) -> ArrayViewMut<A, D> {
        let x_ = x.to_owned();
        let mut fx = self.f.rhs(x);
        azip!(mut fx, x_ in { *fx = x_ + *fx * self.dt });
        fx
    }
}

impl<'a, A, D, F> TimeEvolution<A, OwnedRcRepr<A>, D> for &'a $($mut_),* Heun<F>
    where A: OdeScalar<f64>,
          D: Dimension,
          for<'b> &'b $($mut_),* F: EOM<A, OwnedRcRepr<A>, D>
{
    #[inline(always)]
    fn iterate(self, x: RcArray<A, D>) -> RcArray<A, D> {
        let k1 = self.f.rhs(x.clone()) * self.dt;
        let k2 = self.f.rhs(x.clone() + k1.clone()) * self.dt;
        x + (k1 + k2) * 0.5
    }
}

impl<'a, A, D, F> TimeEvolution<A, ViewRepr<&'a mut A>, D> for &'a $($mut_),* Heun<F>
    where A: OdeScalar<f64>,
          D: Dimension,
          for<'b, 'c> &'b $($mut_),* F: EOM<A, ViewRepr<&'c mut A>, D>
{
    #[inline(always)]
    fn iterate(self, x: ArrayViewMut<A, D>) -> ArrayViewMut<A, D> {
        let dt = self.dt;
        let dt_2 = self.dt * 0.5;
        let x_ = x.to_owned();
        let mut k1 = self.f.rhs(x);
        let k1_ = k1.to_owned();
        azip!(mut k1, x_ in { *k1 = *k1 * dt + x_ });
        let mut k2 = self.f.rhs(k1);
        azip!(mut k2, x_, k1_ in { *k2 = x_ + (k1_ + *k2) * dt_2 });
        k2
    }
}

impl<'a, A, D, F> TimeEvolution<A, OwnedRcRepr<A>, D> for &'a $($mut_),* RK4<F>
    where A: OdeScalar<f64>,
          D: Dimension,
          for<'b> &'b $($mut_),* F: EOM<A, OwnedRcRepr<A>, D>
{
    #[inline(always)]
    fn iterate(self, x: RcArray<A, D>) -> RcArray<A, D> {
        let dt_2 = 0.5 * self.dt;
        let dt_6 = self.dt / 6.0;
        let k1 = self.f.rhs(x.clone());
        let l1 = k1.clone() * dt_2 + &x;
        let k2 = self.f.rhs(l1);
        let l2 = k2.clone() * dt_2 + &x;
        let k3 = self.f.rhs(l2);
        let l3 = k3.clone() * self.dt + &x;
        let k4 = self.f.rhs(l3);
        x + (k1 + (k2 + k3) * 2.0 + k4) * dt_6
    }
}

impl<'a, A, D, F> TimeEvolution<A, ViewRepr<&'a mut A>, D> for &'a $($mut_),* RK4<F>
    where A: OdeScalar<f64>,
          D: Dimension,
          for<'b, 'c> &'b $($mut_),* F: EOM<A, ViewRepr<&'c mut A>, D>
{
    #[inline(always)]
    fn iterate(self, x: ArrayViewMut<A, D>) -> ArrayViewMut<A, D> {
        let dt = self.dt;
        let dt_2 = self.dt * 0.5;
        let dt_6 = self.dt / 6.0;
        let x_ = x.to_owned();
        // k1
        let mut k1 = self.f.rhs(x);
        let k1_ = k1.to_owned();
        azip!(mut k1, x_ in { *k1 = *k1 * dt_2 + x_ });
        // k2
        let mut k2 = self.f.rhs(k1);
        let k2_ = k2.to_owned();
        azip!(mut k2, x_ in { *k2 = x_ + *k2 * dt_2 });
        // k3
        let mut k3 = self.f.rhs(k2);
        let k3_ = k3.to_owned();
        azip!(mut k3, x_ in { *k3 = x_ + *k3 * dt });
        let mut k4 = self.f.rhs(k3);
        azip!(mut k4, x_, k1_, k2_, k3_ in {
            *k4 = x_ + (k1_ + (k2_ + k3_) * 2.0 + *k4) * dt_6
        });
        k4
    }
}

}} // impl_time_evolution!

impl_time_evolution!();
impl_time_evolution!(mut);
<commit_msg>Remove explicit<commit_after>//! Define explicit schemes

use ndarray::*;
use super::traits::*;

macro_rules! def_explicit {
    ($method:ident) => {

#[derive(new)]
pub struct $method<F> {
    f: F,
    dt: f64,
}

impl<F> TimeStep for $method<F> {
    fn get_dt(&self) -> f64 {
        self.dt
    }
    fn set_dt(&mut self, dt: f64) {
        self.dt = dt;
    }
}

}} // def_explicit

def_explicit!(Euler);
def_explicit!(Heun);
def_explicit!(RK4);

macro_rules! impl_time_evolution {
    ( $($mut_:tt), * ) => {

impl<'a, A, D, F> TimeEvolution<A, OwnedRcRepr<A>, D> for &'a $($mut_),* Euler<F>
    where A: OdeScalar<f64>,
          D: Dimension,
          for<'b> &'b $($mut_),* F: EOM<A, OwnedRcRepr<A>, D>
{
    #[inline(always)]
    fn iterate(self, x: RcArray<A, D>) -> RcArray<A, D> {
        let fx = self.f.rhs(x.clone());
        x + fx * self.dt
    }
}

impl<'a, A, D, F> TimeEvolution<A, ViewRepr<&'a mut A>, D> for &'a $($mut_),* Euler<F>
    where A: OdeScalar<f64>,
          D: Dimension,
          for<'b, 'c> &'b $($mut_),* F: EOM<A, ViewRepr<&'c mut A>, D>
{
    #[inline(always)]
    fn iterate(self, x: ArrayViewMut<A, D>) -> ArrayViewMut<A, D> {
        let x_ = x.to_owned();
        let mut fx = self.f.rhs(x);
        azip!(mut fx, x_ in { *fx = x_ + *fx * self.dt });
        fx
    }
}

impl<'a, A, D, F> TimeEvolution<A, OwnedRcRepr<A>, D> for &'a $($mut_),* Heun<F>
    where A: OdeScalar<f64>,
          D: Dimension,
          for<'b> &'b $($mut_),* F: EOM<A, OwnedRcRepr<A>, D>
{
    #[inline(always)]
    fn iterate(self, x: RcArray<A, D>) -> RcArray<A, D> {
        let k1 = self.f.rhs(x.clone()) * self.dt;
        let k2 = self.f.rhs(x.clone() + k1.clone()) * self.dt;
        x + (k1 + k2) * 0.5
    }
}

impl<'a, A, D, F> TimeEvolution<A, ViewRepr<&'a mut A>, D> for &'a $($mut_),* Heun<F>
    where A: OdeScalar<f64>,
          D: Dimension,
          for<'b, 'c> &'b $($mut_),* F: EOM<A, ViewRepr<&'c mut A>, D>
{
    #[inline(always)]
    fn iterate(self, x: ArrayViewMut<A, D>) -> ArrayViewMut<A, D> {
        let dt = self.dt;
        let dt_2 = self.dt * 0.5;
        let x_ = x.to_owned();
        let mut k1 = self.f.rhs(x);
        let k1_ = k1.to_owned();
        azip!(mut k1, x_ in { *k1 = *k1 * dt + x_ });
        let mut k2 = self.f.rhs(k1);
        azip!(mut k2, x_, k1_ in { *k2 = x_ + (k1_ + *k2) * dt_2 });
        k2
    }
}

impl<'a, A, D, F> TimeEvolution<A, OwnedRcRepr<A>, D> for &'a $($mut_),* RK4<F>
    where A: OdeScalar<f64>,
          D: Dimension,
          for<'b> &'b $($mut_),* F: EOM<A, OwnedRcRepr<A>, D>
{
    #[inline(always)]
    fn iterate(self, x: RcArray<A, D>) -> RcArray<A, D> {
        let dt_2 = 0.5 * self.dt;
        let dt_6 = self.dt / 6.0;
        let k1 = self.f.rhs(x.clone());
        let l1 = k1.clone() * dt_2 + &x;
        let k2 = self.f.rhs(l1);
        let l2 = k2.clone() * dt_2 + &x;
        let k3 = self.f.rhs(l2);
        let l3 = k3.clone() * self.dt + &x;
        let k4 = self.f.rhs(l3);
        x + (k1 + (k2 + k3) * 2.0 + k4) * dt_6
    }
}

impl<'a, A, D, F> TimeEvolution<A, ViewRepr<&'a mut A>, D> for &'a $($mut_),* RK4<F>
    where A: OdeScalar<f64>,
          D: Dimension,
          for<'b, 'c> &'b $($mut_),* F: EOM<A, ViewRepr<&'c mut A>, D>
{
    #[inline(always)]
    fn iterate(self, x: ArrayViewMut<A, D>) -> ArrayViewMut<A, D> {
        let dt = self.dt;
        let dt_2 = self.dt * 0.5;
        let dt_6 = self.dt / 6.0;
        let x_ = x.to_owned();
        // k1
        let mut k1 = self.f.rhs(x);
        let k1_ = k1.to_owned();
        azip!(mut k1, x_ in { *k1 = *k1 * dt_2 + x_ });
        // k2
        let mut k2 = self.f.rhs(k1);
        let k2_ = k2.to_owned();
        azip!(mut k2, x_ in { *k2 = x_ + *k2 * dt_2 });
        // k3
        let mut k3 = self.f.rhs(k2);
        let k3_ = k3.to_owned();
        azip!(mut k3, x_ in { *k3 = x_ + *k3 * dt });
        let mut k4 = self.f.rhs(k3);
        azip!(mut k4, x_, k1_, k2_, k3_ in {
            *k4 = x_ + (k1_ + (k2_ + k3_) * 2.0 + *k4) * dt_6
        });
        k4
    }
}

}} // impl_time_evolution!

impl_time_evolution!();
impl_time_evolution!(mut);
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::fmt;
use std::fmt::{Debug, Display};
use std::iter::FromIterator;

use itertools::Itertools;
use lazy_init::Lazy;

/// Token features.
///
/// In the CoNLL-X specification, these are morphological features of the
/// token. Typically, the features are a list or a key-value mapping.
pub struct Features {
    features: String,
    feature_map: Lazy<BTreeMap<String, Option<String>>>,
}

impl Features {
    /// Create features from a string. The casual format uses key-value
    /// pairs that are separated by a vertical bar (`|`) and keys and
    /// values using a colon (`:`). Arbitrary strings will also be accepted,
    /// however they will not give a nice feature-value mapping when using
    /// `as_map`.
    pub fn from_string<S>(s: S) -> Self
    where
        S: Into<String>,
    {
        Features {
            features: s.into(),
            feature_map: Lazy::new(),
        }
    }

    pub fn from_iter<I, S>(iter: I) -> Self
    where
        I: IntoIterator<Item = (S, Option<S>)>,
        S: Into<String> + Ord + Sync,
    {
        let feature_map =
            BTreeMap::from_iter(iter.into_iter().map(|(k, v)| (k.into(), v.map(Into::into))));
        let features = map_to_string(&feature_map);

        let lazy_feature_map = Lazy::new();
        lazy_feature_map.get_or_create(|| feature_map);

        Features {
            features,
            feature_map: lazy_feature_map,
        }
    }

    /// Get the features field as a key-value mapping. This assumes that
    /// the key-value pairs are separed using a vertical bar (`|`) and keys
    /// and values using a colon (`:`). If the value is absent, corresponding
    /// value in the mapping is `None`.
    ///
    /// The feature map is constructed lazily:
    ///
    /// * If `as_map` is never called, the feature map is never created.
    /// * If `as_map` is called once or more, the feature map is only created
    ///   once.
    pub fn as_map(&self) -> &BTreeMap<String, Option<String>> {
        self.feature_map.get_or_create(|| self.as_map_eager())
    }

    /// Get the features field.
    pub fn as_str(&self) -> &str {
        self.features.as_ref()
    }

    fn as_map_eager(&self) -> BTreeMap<String, Option<String>> {
        let mut features = BTreeMap::new();

        for fv in self.features.split('|') {
            let mut iter = fv.split(':');
            if let Some(k) = iter.next() {
                let v = iter.next().map(|s| s.to_owned());
                features.insert(k.to_owned(), v.to_owned());
            }
        }

        features
    }
}

impl Clone for Features {
    fn clone(&self) -> Self {
        Features {
            features: self.features.clone(),
            feature_map: Lazy::new(),
        }
    }
}

impl Debug for Features {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Features {{ features: {} }}", self.features)
    }
}

impl Display for Features {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(self.features.as_ref())
    }
}

impl Eq for Features {
}

impl PartialEq for Features {
    fn eq(&self, other: &Features) -> bool {
        self.features.eq(&other.features)
    }
}

fn map_to_string(feature_map: &BTreeMap<String, Option<String>>) -> String {
    feature_map
        .iter()
        .map(|(k, v)| match *v {
            Some(ref v) => format!("{}:{}", k, v),
            None => k.to_owned(),
        })
        .join("|")
}

#[cfg(test)]
mod tests {
    use std::collections::BTreeMap;

    use super::Features;

    #[test]
    quickcheck! {
        fn from_iter(feature_map: BTreeMap<String, Option<String>>) -> bool{
            &feature_map == Features::from_iter(feature_map.clone()).as_map()
        }
    }

    #[test]
    fn from_iter_as_string() {
        let feature_map = btreemap!{
            "feature2" => Some("y"),
            "feature3" => None,
            "feature1" => Some("x")
        };

        let features = Features::from_iter(feature_map);

        assert_eq!(features.as_str(), "feature1:x|feature2:y|feature3");
    }
}
<commit_msg>Features::from_iter: Relax trait requirements.<commit_after>use std::collections::BTreeMap;
use std::fmt;
use std::fmt::{Debug, Display};
use std::iter::FromIterator;

use itertools::Itertools;
use lazy_init::Lazy;

/// Token features.
///
/// In the CoNLL-X specification, these are morphological features of the
/// token. Typically, the features are a list or a key-value mapping.
pub struct Features {
    features: String,
    feature_map: Lazy<BTreeMap<String, Option<String>>>,
}

impl Features {
    /// Create features from a string. The casual format uses key-value
    /// pairs that are separated by a vertical bar (`|`) and keys and
    /// values using a colon (`:`). Arbitrary strings will also be accepted,
    /// however they will not give a nice feature-value mapping when using
    /// `as_map`.
    pub fn from_string<S>(s: S) -> Self
    where
        S: Into<String>,
    {
        Features {
            features: s.into(),
            feature_map: Lazy::new(),
        }
    }

    pub fn from_iter<I, S, T>(iter: I) -> Self
    where
        I: IntoIterator<Item = (S, Option<T>)>,
        S: Into<String>,
        T: Into<String>
    {
        let feature_map =
            BTreeMap::from_iter(iter.into_iter().map(|(k, v)| (k.into(), v.map(Into::into))));
        let features = map_to_string(&feature_map);

        let lazy_feature_map = Lazy::new();
        lazy_feature_map.get_or_create(|| feature_map);

        Features {
            features,
            feature_map: lazy_feature_map,
        }
    }

    /// Get the features field as a key-value mapping. This assumes that
    /// the key-value pairs are separed using a vertical bar (`|`) and keys
    /// and values using a colon (`:`). If the value is absent, corresponding
    /// value in the mapping is `None`.
    ///
    /// The feature map is constructed lazily:
    ///
    /// * If `as_map` is never called, the feature map is never created.
    /// * If `as_map` is called once or more, the feature map is only created
    ///   once.
    pub fn as_map(&self) -> &BTreeMap<String, Option<String>> {
        self.feature_map.get_or_create(|| self.as_map_eager())
    }

    /// Get the features field.
    pub fn as_str(&self) -> &str {
        self.features.as_ref()
    }

    fn as_map_eager(&self) -> BTreeMap<String, Option<String>> {
        let mut features = BTreeMap::new();

        for fv in self.features.split('|') {
            let mut iter = fv.split(':');
            if let Some(k) = iter.next() {
                let v = iter.next().map(|s| s.to_owned());
                features.insert(k.to_owned(), v.to_owned());
            }
        }

        features
    }
}

impl Clone for Features {
    fn clone(&self) -> Self {
        Features {
            features: self.features.clone(),
            feature_map: Lazy::new(),
        }
    }
}

impl Debug for Features {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Features {{ features: {} }}", self.features)
    }
}

impl Display for Features {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(self.features.as_ref())
    }
}

impl Eq for Features {
}

impl PartialEq for Features {
    fn eq(&self, other: &Features) -> bool {
        self.features.eq(&other.features)
    }
}

fn map_to_string(feature_map: &BTreeMap<String, Option<String>>) -> String {
    feature_map
        .iter()
        .map(|(k, v)| match *v {
            Some(ref v) => format!("{}:{}", k, v),
            None => k.to_owned(),
        })
        .join("|")
}

#[cfg(test)]
mod tests {
    use std::collections::BTreeMap;

    use super::Features;

    #[test]
    quickcheck! {
        fn from_iter(feature_map: BTreeMap<String, Option<String>>) -> bool{
            &feature_map == Features::from_iter(feature_map.clone()).as_map()
        }
    }

    #[test]
    fn from_iter_as_string() {
        let feature_map = btreemap!{
            "feature2" => Some("y"),
            "feature3" => None,
            "feature1" => Some("x")
        };

        let features = Features::from_iter(feature_map);

        assert_eq!(features.as_str(), "feature1:x|feature2:y|feature3");
    }
}
<|endoftext|>


<commit_before>use term::*;
use term::Term::*;
use term::Error::*;
use booleans::*;
use reduction::*;

// PAIR := λxyf.f x y
pub fn pair() -> Term { abs(abs(abs(Var(1).app(Var(3)).app(Var(2))))) }

// FIRST := λp.p TRUE
pub fn first() -> Term { abs(Var(1).app(tru())) }

// SECOND := λp.p FALSE
pub fn second() -> Term { abs(Var(1).app(fls())) }

// NIL := λx.TRUE
pub fn nil() -> Term { abs(tru()) }

// NULL := λp.p (λxy.FALSE)
pub fn null() -> Term { abs(Var(1).app(abs(abs(fls())))) }

// CONS := λht.PAIR FALSE (PAIR h t)
pub fn cons() -> Term { abs(abs(pair().app(fls()).app(pair().app(Var(2)).app(Var(1))))) }

// HEAD := λz.FIRST (SECOND z)
pub fn head() -> Term { abs(first().app(second().app(Var(1)))) }

// TAIL := λz.SECOND (SECOND z)
pub fn tail() -> Term { abs(second().app(second().app(Var(1)))) }

impl Term {
	pub fn is_pair(&self) -> bool {
		self.fst_ref().is_ok() && self.snd_ref().is_ok()
	}

	pub fn unpair(self) -> Result<(Term, Term), Error> {
		if let Abs(_) = self {
			if let Ok((wrapped_a, b)) = self.unabs().and_then(|t| t.unapp()) {
				Ok((try!(wrapped_a.rhs()), b))
			} else {
				Err(NotAPair)
			}
		} else {
			if let Ok((wrapped_a, b)) = self.unapp() {
				Ok((try!(wrapped_a.rhs()), b))
			} else {
				Err(NotAPair)
			}
		}
	}

	pub fn fst(self) -> Result<Term, Error> {
		if let Abs(_) = self {
			self.unabs()
				.and_then(|t| t.lhs())
				.and_then(|t| t.rhs())
		} else {
			self.lhs().and_then(|t| t.rhs())
		}
	}

	pub fn fst_ref(&self) -> Result<&Term, Error> {
		if let Abs(_) = *self {
			self.unabs_ref()
				.and_then(|t| t.lhs_ref())
				.and_then(|t| t.rhs_ref())
		} else {
			self.lhs_ref().and_then(|t| t.rhs_ref())
		}
	}

	pub fn fst_ref_mut(&mut self) -> Result<&mut Term, Error> {
		if let Abs(_) = *self {
			self.unabs_ref_mut()
				.and_then(|t| t.lhs_ref_mut())
				.and_then(|t| t.rhs_ref_mut())
		} else {
			self.lhs_ref_mut().and_then(|t| t.rhs_ref_mut())
		}
	}

	pub fn snd(self) -> Result<Term, Error> {
		if let Abs(_) = self {
			self.unabs().and_then(|t| t.rhs())
		} else {
			self.rhs()
		}
	}

	pub fn snd_ref(&self) -> Result<&Term, Error> {
		if let Abs(_) = *self {
			self.unabs_ref().and_then(|t| t.rhs_ref())
		} else {
			self.rhs_ref()
		}
	}

	pub fn snd_ref_mut(&mut self) -> Result<&mut Term, Error> {
		if let Abs(_) = *self {
			self.unabs_ref_mut().and_then(|t| t.rhs_ref_mut())
		} else {
			self.rhs_ref_mut()
		}
	}

	pub fn is_list(&self) -> bool {
		self.is_empty() || self.head_ref().is_ok() && self.tail_ref().is_ok()
	}

	pub fn is_empty(&self) -> bool {
		*self == nil()
	}

	pub fn uncons(self) -> Result<(Term, Term), Error> {
		self.unabs()
			.and_then(|t| t.snd())
			.and_then(|t| t.unpair())
	}

	pub fn head(self) -> Result<Term, Error> {
		self.unabs()
			.and_then(|t| t.snd())
			.and_then(|t| t.fst())
	}

	pub fn head_ref(&self) -> Result<&Term, Error> {
		self.unabs_ref()
			.and_then(|t| t.snd_ref())
			.and_then(|t| t.fst_ref())
	}

	pub fn head_ref_mut(&mut self) -> Result<&mut Term, Error> {
		self.unabs_ref_mut()
			.and_then(|t| t.snd_ref_mut())
			.and_then(|t| t.fst_ref_mut())
	}

	pub fn tail(self) -> Result<Term, Error> {
		self.unabs()
			.and_then(|t| t.snd())
			.and_then(|t| t.snd())
	}

	pub fn tail_ref(&self) -> Result<&Term, Error> {
		self.unabs_ref()
			.and_then(|t| t.snd_ref())
			.and_then(|t| t.snd_ref())
	}

	pub fn tail_ref_mut(&mut self) -> Result<&mut Term, Error> {
		self.unabs_ref_mut()
			.and_then(|t| t.snd_ref_mut())
			.and_then(|t| t.snd_ref_mut())
	}

	pub fn len(&self) -> Result<usize, Error> {
		let mut inner = self;
		let mut n = 0;

		while *inner != nil() {
			n += 1;
			inner = try!(inner.tail_ref());
		}

		Ok(n)
	}
}

impl From<Vec<Term>> for Term {
	fn from(terms: Vec<Term>) -> Self {
		let mut output = nil();

		for t in terms {
			output = cons().app(t).app(output);
		}

		normalize(output)
	}
}
/*
pub fn push(&mut self, term: Term) { // TODO: maybe no cloning?
	let tail = self.0.clone();
	*self = List(abs(app(Var(0), app(term, tail))))
}
*/
/*
impl Iterator for Term {
	type Item = Term;

	fn next(&mut self) -> Option<Term> {
		if self.is_empty() {
			None
		} else {
			self.pop()
		}
	}
}
*/
#[cfg(test)]
mod test {
	use super::*;
	use arithmetic::*;

	#[test]
	fn empty_list() {
		let empty_list = nil();

		assert!(empty_list.is_list());
		assert!(empty_list.is_empty());
	}

	#[test]
	fn list_length() {
		let list0 = nil();
		assert_eq!(list0.len(), Ok(0));
		let list1 = normalize(cons().app(one()).app(list0));
		assert_eq!(list1.len(), Ok(1));
		let list2 = normalize(cons().app(one()).app(list1));
		assert_eq!(list2.len(), Ok(2));
		let list3 = normalize(cons().app(one()).app(list2));
		assert_eq!(list3.len(), Ok(3));
	}

	#[test]
	fn list_from_vector() {
		let terms_vec = vec![one(), zero(), one()];
		let list_from_vec = Term::from(terms_vec);
		let list_manual = normalize(cons().app(one()).app(cons().app(zero()).app(cons().app(one()).app(nil()))));

		assert_eq!(list_from_vec, list_manual);
	}

	#[test]
	fn pair_operations() {
		let pair_four_three = normalize(pair().app(to_cnum(4)).app(to_cnum(3)));

		assert!(pair_four_three.is_pair());

		assert_eq!(pair_four_three.fst_ref(), Ok(&to_cnum(4)));
		assert_eq!(pair_four_three.snd_ref(), Ok(&to_cnum(3)));

		let unpaired = pair_four_three.unpair();
		assert_eq!(unpaired, Ok((to_cnum(4), to_cnum(3))));
	}

	#[test]
	fn list_operations() {
		let empty_list = nil();
		let list_four = cons().app(to_cnum(4)).app(empty_list);
		let list_five_four = cons().app(to_cnum(5)).app(list_four);
		let list_three_five_four = normalize(cons().app(to_cnum(3)).app(list_five_four));

		assert!(list_three_five_four.is_list());

		assert_eq!(list_three_five_four.head_ref(), Ok(&to_cnum(3)));
		assert_eq!(list_three_five_four.tail_ref(), Ok(&normalize(cons().app(to_cnum(5)).app(cons().app(to_cnum(4)).app(nil())))));

		assert_eq!(list_three_five_four.tail_ref().and_then(|t| t.head_ref()), Ok(&to_cnum(5)));
		assert_eq!(list_three_five_four.tail_ref().and_then(|t| t.head_ref()), Ok(&to_cnum(5)));
		assert_eq!(list_three_five_four.tail_ref().and_then(|t| t.tail_ref()).and_then(|t| t.head_ref()), Ok(&to_cnum(4)));

		let unconsed = list_three_five_four.uncons();
		assert_eq!(unconsed, Ok((to_cnum(3), normalize(cons().app(to_cnum(5)).app(cons().app(to_cnum(4)).app(nil()))))));
	}

/*
	#[test]
	fn list_push_pop() {
		let mut list = List::from(vec![Var(1), Var(0), Var(1)]);

		assert_eq!(list.pop(), Some(Var(1)));
		assert_eq!(list.pop(), Some(Var(0)));
		assert_eq!(list.pop(), Some(Var(1)));
		assert_eq!(list.pop(), None);
	}

	#[test]
	fn iterating_list() {
		let list = List::from(vec![Var(0), Var(1), Var(0)]);
		let mut iter = list.into_iter();

		assert_eq!(iter.next(), Some(Var(0)));
		assert_eq!(iter.next(), Some(Var(1)));
		assert_eq!(iter.next(), Some(Var(0)));
	}
*/
}<commit_msg>Add push() for Church lists<commit_after>use term::*;
use term::Term::*;
use term::Error::*;
use booleans::*;
use reduction::*;

// PAIR := λxyf.f x y
pub fn pair() -> Term { abs(abs(abs(Var(1).app(Var(3)).app(Var(2))))) }

// FIRST := λp.p TRUE
pub fn first() -> Term { abs(Var(1).app(tru())) }

// SECOND := λp.p FALSE
pub fn second() -> Term { abs(Var(1).app(fls())) }

// NIL := λx.TRUE
pub fn nil() -> Term { abs(tru()) }

// NULL := λp.p (λxy.FALSE)
pub fn null() -> Term { abs(Var(1).app(abs(abs(fls())))) }

// CONS := λht.PAIR FALSE (PAIR h t)
pub fn cons() -> Term { abs(abs(pair().app(fls()).app(pair().app(Var(2)).app(Var(1))))) }

// HEAD := λz.FIRST (SECOND z)
pub fn head() -> Term { abs(first().app(second().app(Var(1)))) }

// TAIL := λz.SECOND (SECOND z)
pub fn tail() -> Term { abs(second().app(second().app(Var(1)))) }

impl Term {
	pub fn is_pair(&self) -> bool {
		self.fst_ref().is_ok() && self.snd_ref().is_ok()
	}

	pub fn unpair(self) -> Result<(Term, Term), Error> {
		if let Abs(_) = self {
			if let Ok((wrapped_a, b)) = self.unabs().and_then(|t| t.unapp()) {
				Ok((try!(wrapped_a.rhs()), b))
			} else {
				Err(NotAPair)
			}
		} else {
			if let Ok((wrapped_a, b)) = self.unapp() {
				Ok((try!(wrapped_a.rhs()), b))
			} else {
				Err(NotAPair)
			}
		}
	}

	pub fn fst(self) -> Result<Term, Error> {
		if let Abs(_) = self {
			self.unabs()
				.and_then(|t| t.lhs())
				.and_then(|t| t.rhs())
		} else {
			self.lhs().and_then(|t| t.rhs())
		}
	}

	pub fn fst_ref(&self) -> Result<&Term, Error> {
		if let Abs(_) = *self {
			self.unabs_ref()
				.and_then(|t| t.lhs_ref())
				.and_then(|t| t.rhs_ref())
		} else {
			self.lhs_ref().and_then(|t| t.rhs_ref())
		}
	}

	pub fn fst_ref_mut(&mut self) -> Result<&mut Term, Error> {
		if let Abs(_) = *self {
			self.unabs_ref_mut()
				.and_then(|t| t.lhs_ref_mut())
				.and_then(|t| t.rhs_ref_mut())
		} else {
			self.lhs_ref_mut().and_then(|t| t.rhs_ref_mut())
		}
	}

	pub fn snd(self) -> Result<Term, Error> {
		if let Abs(_) = self {
			self.unabs().and_then(|t| t.rhs())
		} else {
			self.rhs()
		}
	}

	pub fn snd_ref(&self) -> Result<&Term, Error> {
		if let Abs(_) = *self {
			self.unabs_ref().and_then(|t| t.rhs_ref())
		} else {
			self.rhs_ref()
		}
	}

	pub fn snd_ref_mut(&mut self) -> Result<&mut Term, Error> {
		if let Abs(_) = *self {
			self.unabs_ref_mut().and_then(|t| t.rhs_ref_mut())
		} else {
			self.rhs_ref_mut()
		}
	}

	pub fn is_list(&self) -> bool {
		self.is_empty() || self.head_ref().is_ok() && self.tail_ref().is_ok()
	}

	pub fn is_empty(&self) -> bool {
		*self == nil()
	}

	pub fn uncons(self) -> Result<(Term, Term), Error> {
		self.unabs()
			.and_then(|t| t.snd())
			.and_then(|t| t.unpair())
	}

	pub fn head(self) -> Result<Term, Error> {
		self.unabs()
			.and_then(|t| t.snd())
			.and_then(|t| t.fst())
	}

	pub fn head_ref(&self) -> Result<&Term, Error> {
		self.unabs_ref()
			.and_then(|t| t.snd_ref())
			.and_then(|t| t.fst_ref())
	}

	pub fn head_ref_mut(&mut self) -> Result<&mut Term, Error> {
		self.unabs_ref_mut()
			.and_then(|t| t.snd_ref_mut())
			.and_then(|t| t.fst_ref_mut())
	}

	pub fn tail(self) -> Result<Term, Error> {
		self.unabs()
			.and_then(|t| t.snd())
			.and_then(|t| t.snd())
	}

	pub fn tail_ref(&self) -> Result<&Term, Error> {
		self.unabs_ref()
			.and_then(|t| t.snd_ref())
			.and_then(|t| t.snd_ref())
	}

	pub fn tail_ref_mut(&mut self) -> Result<&mut Term, Error> {
		self.unabs_ref_mut()
			.and_then(|t| t.snd_ref_mut())
			.and_then(|t| t.snd_ref_mut())
	}

	pub fn len(&self) -> Result<usize, Error> {
		let mut inner = self;
		let mut n = 0;

		while *inner != nil() {
			n += 1;
			inner = try!(inner.tail_ref());
		}

		Ok(n)
	}

	pub fn push(self, t: Term) -> Term {
		normalize(cons().app(t).app(self))
	}
}

impl From<Vec<Term>> for Term {
	fn from(terms: Vec<Term>) -> Self {
		let mut output = nil();

		for t in terms {
			output = cons().app(t).app(output);
		}

		normalize(output)
	}
}
/*
impl Iterator for Term {
	type Item = Term;

	fn next(&mut self) -> Option<Term> {
		if self.is_empty() {
			None
		} else {
			self.pop()
		}
	}
}
*/
#[cfg(test)]
mod test {
	use super::*;
	use arithmetic::*;

	#[test]
	fn empty_list() {
		let empty_list = nil();

		assert!(empty_list.is_list());
		assert!(empty_list.is_empty());
	}

	#[test]
	fn list_length() {
		let list0 = nil();
		assert_eq!(list0.len(), Ok(0));
		let list1 = normalize(cons().app(one()).app(list0));
		assert_eq!(list1.len(), Ok(1));
		let list2 = normalize(cons().app(one()).app(list1));
		assert_eq!(list2.len(), Ok(2));
		let list3 = normalize(cons().app(one()).app(list2));
		assert_eq!(list3.len(), Ok(3));
	}

	#[test]
	fn list_from_vector() {
		let terms_vec = vec![one(), zero(), one()];
		let list_from_vec = Term::from(terms_vec);
		let list_manual = normalize(cons().app(one()).app(cons().app(zero()).app(cons().app(one()).app(nil()))));

		assert_eq!(list_from_vec, list_manual);
	}

	#[test]
	fn pair_operations() {
		let pair_four_three = normalize(pair().app(to_cnum(4)).app(to_cnum(3)));

		assert!(pair_four_three.is_pair());

		assert_eq!(pair_four_three.fst_ref(), Ok(&to_cnum(4)));
		assert_eq!(pair_four_three.snd_ref(), Ok(&to_cnum(3)));

		let unpaired = pair_four_three.unpair();
		assert_eq!(unpaired, Ok((to_cnum(4), to_cnum(3))));
	}

	#[test]
	fn list_operations() {
		let empty_list = nil();
		let list_four = cons().app(to_cnum(4)).app(empty_list);
		let list_five_four = cons().app(to_cnum(5)).app(list_four);
		let list_three_five_four = normalize(cons().app(to_cnum(3)).app(list_five_four));

		assert!(list_three_five_four.is_list());

		assert_eq!(list_three_five_four.head_ref(), Ok(&to_cnum(3)));
		assert_eq!(list_three_five_four.tail_ref(), Ok(&normalize(cons().app(to_cnum(5)).app(cons().app(to_cnum(4)).app(nil())))));

		assert_eq!(list_three_five_four.tail_ref().and_then(|t| t.head_ref()), Ok(&to_cnum(5)));
		assert_eq!(list_three_five_four.tail_ref().and_then(|t| t.head_ref()), Ok(&to_cnum(5)));
		assert_eq!(list_three_five_four.tail_ref().and_then(|t| t.tail_ref()).and_then(|t| t.head_ref()), Ok(&to_cnum(4)));

		let unconsed = list_three_five_four.uncons();
		assert_eq!(unconsed, Ok((to_cnum(3), normalize(cons().app(to_cnum(5)).app(cons().app(to_cnum(4)).app(nil()))))));
	}

	#[test]
	fn list_push() {
		let list_pushed = nil().push(one()).push(zero()).push(one());
		let list_manual = normalize(cons().app(one()).app(cons().app(zero()).app(cons().app(one()).app(nil()))));

		assert_eq!(list_pushed, list_manual);
	}

/*
	#[test]
	fn list_pop() {
		let mut list = List::from(vec![Var(1), Var(0), Var(1)]);

		assert_eq!(list.pop(), Some(Var(1)));
		assert_eq!(list.pop(), Some(Var(0)));
		assert_eq!(list.pop(), Some(Var(1)));
		assert_eq!(list.pop(), None);
	}

	#[test]
	fn iterating_list() {
		let list = List::from(vec![Var(0), Var(1), Var(0)]);
		let mut iter = list.into_iter();

		assert_eq!(iter.next(), Some(Var(0)));
		assert_eq!(iter.next(), Some(Var(1)));
		assert_eq!(iter.next(), Some(Var(0)));
	}
*/
}<|endoftext|>


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

use basicblock::BasicBlock;
use instruction::Instruction;
use symbol::Symbol;

/// A function within a program.
#[derive(Debug)]
pub struct Function<'f> {
    /// The [symbol] for this function. This provides the name and `Address`.
    ///
    /// [symbol]: struct.Symbol.html
    pub symbol: Symbol,
    /// The instructions that comprise this function.
    pub instructions: Vec<Box<Instruction>>,
    /// The basic blocks that comprise this function. These are algorithmically
    /// determined from the `instructions` via `fn build_basic_blocks`.
    ///
    /// The `basic_blocks` of a `Function` make up a [control flow graph].
    ///
    /// [control flow graph]: https://en.wikipedia.org/wiki/Control_flow_graph
    pub basic_blocks: Vec<BasicBlock<'f>>,
}

impl<'f> Function<'f> {
    /// Build the actual basic blocks for this function.
    ///
    /// This usually happens during construction of the `Function`.
    pub fn build_basic_blocks(&'f mut self) {
        // For now, let's just put all instructions into a single basic
        // block. In the future, we'll implement this correctly.
        let mut bb = BasicBlock::new(self.basic_blocks.len(), "anonymous");
        for inst in &self.instructions {
            bb.instructions.push(&inst);
        }
        self.basic_blocks.push(bb);
    }
}
<commit_msg>Fix useless borrow via Clippy.<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use basicblock::BasicBlock;
use instruction::Instruction;
use symbol::Symbol;

/// A function within a program.
#[derive(Debug)]
pub struct Function<'f> {
    /// The [symbol] for this function. This provides the name and `Address`.
    ///
    /// [symbol]: struct.Symbol.html
    pub symbol: Symbol,
    /// The instructions that comprise this function.
    pub instructions: Vec<Box<Instruction>>,
    /// The basic blocks that comprise this function. These are algorithmically
    /// determined from the `instructions` via `fn build_basic_blocks`.
    ///
    /// The `basic_blocks` of a `Function` make up a [control flow graph].
    ///
    /// [control flow graph]: https://en.wikipedia.org/wiki/Control_flow_graph
    pub basic_blocks: Vec<BasicBlock<'f>>,
}

impl<'f> Function<'f> {
    /// Build the actual basic blocks for this function.
    ///
    /// This usually happens during construction of the `Function`.
    pub fn build_basic_blocks(&'f mut self) {
        // For now, let's just put all instructions into a single basic
        // block. In the future, we'll implement this correctly.
        let mut bb = BasicBlock::new(self.basic_blocks.len(), "anonymous");
        for inst in &self.instructions {
            bb.instructions.push(inst);
        }
        self.basic_blocks.push(bb);
    }
}
<|endoftext|>


<commit_before>use std::vec::Vec;

pub fn matches(pattern: &str, candidate: &str) -> bool {
    let pattern: Vec<&str> = pattern.split("/").collect();
    let candidate: Vec<&str> = candidate.split("/").collect();
    matches_segments(&pattern[..], &candidate[..])
}

fn matches_segments(pattern: &[&str], candidate: &[&str]) -> bool {
    if pattern.len() == 0 {
        // We need to run out of pattern and candidate at the same time
        candidate.len() == 0
    } else if candidate.len() == 0 {
        // If the candidate ends before the pattern, reject it. The candidate
        // must not be more general than the pattern
        false
    } else if pattern[0] == "**" {
        // In this case the path can span multiple directories. For simplicity,
        // it's not allowed to have a partial match here, so the pattern must be
        // exactly "**". Here we'll follow a "use it or lose it strategy" where
        // each recursive time we either consume a candidate segment, or we stop consuming.
        matches_segments(&pattern[1..], candidate) || matches_segments(pattern, &candidate[1..])
    } else if pattern[0].contains("*") {
        // This is the case where we have a single wildcard in in the pattern. We'll defer
        // to a helper function to help
        matches_glob(pattern[0], candidate[0]) && matches_segments(&pattern[1..], &candidate[1..])
    } else {
        // If there are no wildcards, we can do a straight comparison on the segments
        pattern[0] == candidate[0] && matches_segments(&pattern[1..], &candidate[1..])
    }
}

fn matches_glob(pattern: &str, candidate: &str) -> bool {
    if pattern.len() == 0 {
        candidate.len() == 0
    } else if candidate.len() == 0 {
        pattern == "*"
    } else if pattern.chars().nth(0).unwrap() == '*' {
        // Use it or lose it. We either consume a candidate charactor or stop consuming
        matches_glob(&pattern[1..], candidate) || matches_glob(pattern, &candidate[1..])
    } else {
        pattern.chars().nth(0).unwrap() == candidate.chars().nth(0).unwrap() &&
        matches_glob(&pattern[1..], &candidate[1..])
    }
}

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

    #[test]
    fn matches_glob_works_on_empty_strings() {
        assert_eq!(true, matches_glob("", ""));
        assert_eq!(false, matches_glob("a", ""));
        assert_eq!(false, matches_glob("", "a"));
    }

    #[test]
    fn matches_glob_works_with_full_wildcard_pattern() {
        assert_eq!(true, matches_glob("*", "*"));
        assert_eq!(true, matches_glob("*", "a"));
        assert_eq!(true, matches_glob("*", "abc*"));
        assert_eq!(true, matches_glob("*", "*abc"));
    }

    #[test]
    fn matches_glob_works_with_partial_wildcard_pattern() {
        assert_eq!(true, matches_glob("*a", "cba"));
        assert_eq!(true, matches_glob("*a", "a"));
        assert_eq!(false, matches_glob("*a", "b"));

        assert_eq!(true, matches_glob("a*", "abc"));
        assert_eq!(true, matches_glob("a*", "a"));
        assert_eq!(false, matches_glob("a*", "b"));

        assert_eq!(true, matches_glob("a*b", "afb"));
        assert_eq!(true, matches_glob("a*b", "afghb"));
        assert_eq!(true, matches_glob("a*b", "ab"));
        assert_eq!(false, matches_glob("a*b", "afghbf"));
    }

    #[test]
    fn matches_glob_works_with_multiple_wildcards() {
        assert_eq!(true, matches_glob("*a*", "cba"));
        assert_eq!(true, matches_glob("*a*", "a"));
        assert_eq!(true, matches_glob("*a*", "abc"));
        assert_eq!(true, matches_glob("*a*", "bac"));
        assert_eq!(false, matches_glob("*a*", "b"));
        assert_eq!(false, matches_glob("*a*", ""));

        assert_eq!(true, matches_glob("a*a*", "aba"));
        assert_eq!(true, matches_glob("a*a*", "abaf"));
    }
}
<commit_msg>Added some tests for segments, need more<commit_after>use std::vec::Vec;

pub fn matches(pattern: &str, candidate: &str) -> bool {
    let pattern: Vec<&str> = pattern.split("/").collect();
    let candidate: Vec<&str> = candidate.split("/").collect();
    matches_segments(&pattern[..], &candidate[..])
}

fn matches_segments(pattern: &[&str], candidate: &[&str]) -> bool {
    if pattern.len() == 0 {
        // We need to run out of pattern and candidate at the same time
        candidate.len() == 0
    } else if candidate.len() == 0 {
        // If the candidate ends before the pattern, reject it. The candidate
        // must not be more general than the pattern. Only exception is ending on "**".
        pattern.len() == 1 && pattern[0] == "**"
    } else if pattern[0] == "**" {
        // In this case the path can span multiple directories. For simplicity,
        // it's not allowed to have a partial match here, so the pattern must be
        // exactly "**". Here we'll follow a "use it or lose it strategy" where
        // each recursive time we either consume a candidate segment, or we stop consuming.
        matches_segments(&pattern[1..], candidate) || matches_segments(pattern, &candidate[1..])
    } else if pattern[0].contains("*") {
        // This is the case where we have a single wildcard in in the pattern. We'll defer
        // to a helper function to help
        matches_glob(pattern[0], candidate[0]) && matches_segments(&pattern[1..], &candidate[1..])
    } else {
        // If there are no wildcards, we can do a straight comparison on the segments
        pattern[0] == candidate[0] && matches_segments(&pattern[1..], &candidate[1..])
    }
}

fn matches_glob(pattern: &str, candidate: &str) -> bool {
    if pattern.len() == 0 {
        candidate.len() == 0
    } else if candidate.len() == 0 {
        pattern == "*"
    } else if pattern.chars().nth(0).unwrap() == '*' {
        // Use it or lose it. We either consume a candidate charactor or stop consuming
        matches_glob(&pattern[1..], candidate) || matches_glob(pattern, &candidate[1..])
    } else {
        pattern.chars().nth(0).unwrap() == candidate.chars().nth(0).unwrap() &&
        matches_glob(&pattern[1..], &candidate[1..])
    }
}

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

    #[test]
    fn matches_segments_works_on_empty_slices() {
        assert_eq!(true, matches_segments(&[], &[]));
        assert_eq!(true, matches_segments(&[""], &[""]));
        assert_eq!(false, matches_segments(&["a"], &[""]));
        assert_eq!(false, matches_segments(&["a"], &[]));
        assert_eq!(false, matches_segments(&[""], &["a"]));
        assert_eq!(false, matches_segments(&[], &["a"]));
    }

    #[test]
    fn matches_glob_works_on_empty_strings() {
        assert_eq!(true, matches_glob("", ""));
        assert_eq!(false, matches_glob("a", ""));
        assert_eq!(false, matches_glob("", "a"));
    }

    #[test]
    fn matches_glob_works_with_full_wildcard_pattern() {
        assert_eq!(true, matches_glob("*", "*"));
        assert_eq!(true, matches_glob("*", "a"));
        assert_eq!(true, matches_glob("*", "abc*"));
        assert_eq!(true, matches_glob("*", "*abc"));
    }

    #[test]
    fn matches_segments_works_with_single_wildcard_pattern() {
        assert_eq!(true, matches_segments(&["*"], &["*"]));
        assert_eq!(true, matches_segments(&["*"], &["a"]));
        assert_eq!(true, matches_segments(&["*"], &["abcde"]));
        assert_eq!(true, matches_segments(&["*"], &["abc*"]));
        assert_eq!(true, matches_segments(&["*"], &["*abc"]));

        // Shouldn't cross segment boundaries
        assert_eq!(false, matches_segments(&["*"], &["a", "b"]));
    }

    #[test]
    fn matches_segments_works_with_dual_wildcard_pattern() {
        assert_eq!(true, matches_segments(&["**"], &["*"]));
        assert_eq!(true, matches_segments(&["**"], &["a"]));
        assert_eq!(true, matches_segments(&["**"], &["ab", "cd", "de"]));
        assert_eq!(true, matches_segments(&["**"], &["abc", "*"]));
        assert_eq!(true, matches_segments(&["**"], &["*", "abc"]));

        assert_eq!(false, matches_segments(&["**b"], &["abc"]));
        assert_eq!(false, matches_segments(&["b**"], &["abc"]));
    }

    #[test]
    fn matches_glob_works_with_partial_wildcard_pattern() {
        assert_eq!(true, matches_glob("*a", "cba"));
        assert_eq!(true, matches_glob("*a", "a"));
        assert_eq!(false, matches_glob("*a", "b"));

        assert_eq!(true, matches_glob("a*", "abc"));
        assert_eq!(true, matches_glob("a*", "a"));
        assert_eq!(false, matches_glob("a*", "b"));

        assert_eq!(true, matches_glob("a*b", "afb"));
        assert_eq!(true, matches_glob("a*b", "afghb"));
        assert_eq!(true, matches_glob("a*b", "ab"));
        assert_eq!(false, matches_glob("a*b", "afghbf"));
    }

    #[test]
    fn matches_segments_works_with_partial_single_wildcard_pattern() {
        assert_eq!(true, matches_segments(&["a", "*"], &["a", "foo"]));
        assert_eq!(true, matches_segments(&["a", "*"], &["a", ""]));
        assert_eq!(false, matches_segments(&["a", "*"], &["b", "foo"]));
        assert_eq!(false, matches_segments(&["a", "*"], &["a"]));

        assert_eq!(false, matches_segments(&["*", "a"], &["a"]));
        assert_eq!(false, matches_segments(&["*", "a"], &["ab", "a", "de"]));
        assert_eq!(true, matches_segments(&["*", "a"], &["abc", "a"]));
        assert_eq!(true, matches_segments(&["*", "a"], &["*", "a"]));
    }

    #[test]
    fn matches_glob_works_with_multiple_wildcards() {
        assert_eq!(true, matches_glob("*a*", "cba"));
        assert_eq!(true, matches_glob("*a*", "a"));
        assert_eq!(true, matches_glob("*a*", "abc"));
        assert_eq!(true, matches_glob("*a*", "bac"));
        assert_eq!(false, matches_glob("*a*", "b"));
        assert_eq!(false, matches_glob("*a*", ""));

        assert_eq!(true, matches_glob("a*a*", "aba"));
        assert_eq!(true, matches_glob("a*a*", "abaf"));
    }
}
<|endoftext|>


<commit_before>use std::path::PathBuf;
use std::process::Child;
use std::process::Command;

pub struct App {
    pub name: String,
    pub port: u16,
    #[allow(dead_code)]
    process: Child,
}

impl App {
    pub fn new(name: &str, port: u16, app_home: &str) -> App {
        let mut path_buf = PathBuf::from(app_home);
        path_buf.push(&name);

        let child_process = Command::new("foreman")
            .arg("start")
            .current_dir(path_buf.as_path())
            .env("PORT", port.to_string())
            .spawn().unwrap();

        App{
            name: name.to_string(),
            port: port,
            process: child_process,
        }
    }
}
<commit_msg>refactor: Remove unused App struct field<commit_after>use std::path::PathBuf;
use std::process::Child;
use std::process::Command;

pub struct App {
    pub port: u16,
    #[allow(dead_code)]
    process: Child,
}

impl App {
    pub fn new(name: &str, port: u16, app_home: &str) -> App {
        let mut path_buf = PathBuf::from(app_home);
        path_buf.push(&name);

        let child_process = Command::new("foreman")
            .arg("start")
            .current_dir(path_buf.as_path())
            .env("PORT", port.to_string())
            .spawn().unwrap();

        App{
            port: port,
            process: child_process,
        }
    }
}
<|endoftext|>


<commit_before>#[link(name = "http",
       package_id = "http",
       vers = "0.1-pre",
       uuid = "d2ad8df0-547a-4ce1-99c6-a9da3b98fb3e",
       url = "https://github.com/chris-morgan/rust-http/tree/master/src/http")];

#[comment = "Rust HTTP server"];
#[license = "MIT/ASL2"];
#[crate_type = "lib"];

#[deny(non_camel_case_types)];
//#[deny(missing_doc)];

#[feature(macro_rules)];
#[macro_escape];

extern mod extra;

pub mod buffer;
pub mod client;
pub mod common;
pub mod server;
pub mod method;
pub mod headers;
pub mod rfc2616;
#[path = "generated/status.rs"]
pub mod status;  // Getting an error? It's generated; use ``make`` or see the ``Makefile``

/// TODO: submit upstream
pub mod memstream;
<commit_msg>Mark some test-only code as such to avoid dead code warnings.<commit_after>#[link(name = "http",
       package_id = "http",
       vers = "0.1-pre",
       uuid = "d2ad8df0-547a-4ce1-99c6-a9da3b98fb3e",
       url = "https://github.com/chris-morgan/rust-http/tree/master/src/http")];

#[comment = "Rust HTTP server"];
#[license = "MIT/ASL2"];
#[crate_type = "lib"];

#[deny(non_camel_case_types)];
//#[deny(missing_doc)];

#[feature(macro_rules)];
#[macro_escape];

extern mod extra;

pub mod buffer;
pub mod client;
pub mod common;
pub mod server;
pub mod method;
pub mod headers;
pub mod rfc2616;
#[path = "generated/status.rs"]
pub mod status;  // Getting an error? It's generated; use ``make`` or see the ``Makefile``

/// TODO: submit upstream
#[cfg(test)]
pub mod memstream;
<|endoftext|>


<commit_before>use std::fmt;
use std::error::Error;
use std::str;
use std::io::{Read, Write, BufReader, BufRead};
use std::net::{TcpListener};
use std::thread;
use std::sync::mpsc::channel;
use std::time::Duration;
use std::collections::BTreeMap;

extern crate regex;
use self::regex::Regex;

extern crate curl;
use self::curl::easy::{Easy, List};

extern crate time;
extern crate open;
extern crate url;
use self::url::percent_encoding;

use super::settings;

#[derive(PartialEq, Debug)]
pub enum HttpMethod {
    GET,
    POST,
    PUT,
}

pub type HttpErrorString = String;
pub struct HttpResponse {
    pub code: Option<u32>,
    pub data: Result<String, HttpErrorString>,
}

impl HttpResponse {
    pub fn unwrap(self) -> String { self.data.unwrap() }
    pub fn print(&self) {
        let code: i32 = match self.code {
            Some(x) => { x as i32 }
            None => -1
        };
        println!("Code: {}", code);
        match self.data {
            Ok(ref s) => {println!("{}", s)}
            Err(ref s) => {println!("ERROR: {}", s)}
        }
    }
}

impl fmt::Display for HttpResponse {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let code: i32 = match self.code {
            Some(x) => { x as i32 }
            None => -1
        };
        let _ = write!(f, "Code: {}\n", code);
        match self.data {
            Ok(ref s) => {write!(f, "Response: {}", s)}
            Err(ref s) => {write!(f, "ERROR: {}", s)}
        }
    }
}

#[derive(Debug)]
pub enum AccessToken<'a> {
    Bearer(&'a str),
    Basic(&'a str),
    None,
}

pub fn http(url: &str, query: Option<&str>, body: Option<&str>,
            method: HttpMethod, access_token: AccessToken) -> HttpResponse {
    let mut headers = List::new();
    #[cfg(feature = "verbose_http")]
    info!("HTTP URL: {:?} {}\nQuery: {:?}\nBody: {:?}\nToken: {:?}", method, url, query, body, access_token);
    let data = match method {
        HttpMethod::POST => {
            match query {
                Some(q) => {
                    let enc_query = percent_encoding::utf8_percent_encode(&q, percent_encoding::QUERY_ENCODE_SET).collect::<String>();
                    enc_query
                },
                None => {
                    let header = format!("Content-Type: application/json");
                    headers.append(&header).unwrap();
                    body.unwrap_or("").to_string()
                }
            }
        },
        _ => { body.unwrap_or("").to_string() },
    };
    let mut data = data.as_bytes();

    let url = match method {
        HttpMethod::GET | HttpMethod::PUT => match query {
            None => url.to_string(),
            Some(q) => format!("{}?{}", url, q),
        },
        _ => url.to_string()

    };
    let mut response = None;
    let mut json_bytes = Vec::<u8>::new();
    {
        let mut easy = Easy::new();
        easy.url(&url).unwrap();
        match method {
            HttpMethod::POST => {
                easy.post(true).unwrap();
                easy.post_field_size(data.len() as u64).unwrap();
            }
            HttpMethod::PUT => {
                easy.put(true).unwrap();
                easy.post_field_size(data.len() as u64).unwrap();
            }
            _ => {}
        }

        match access_token {
            AccessToken::None => {},
            access_token => {
                let request = match access_token {
                    AccessToken::Bearer(token) => ("Bearer", token),
                    AccessToken::Basic(token) => ("Basic", token),
                    _ => ("",""),
                };
                let header = format!("Authorization: {} {}", request.0, request.1);
                headers.append(&header).unwrap();
                easy.http_headers(headers).unwrap();
            }
        }

        {
            let mut transfer = easy.transfer();
            if method == HttpMethod::POST || method == HttpMethod::PUT {
                transfer.read_function(|buf| {
                    Ok(data.read(buf).unwrap_or(0))
                }).unwrap();
            }
            transfer.write_function(|x| {
                json_bytes.extend(x);
                Ok(x.len())
            }).unwrap();
            match transfer.perform() {
                Err(x) => {
                    let result: Result<String,String> = Err(x.description().to_string());
                    #[cfg(feature = "verbose_http")]
                    warn!("HTTP response: err: {}", x.description().to_string());
                    return HttpResponse {code: response, data: result }
                }
                _ => {}
            };
        }
        response = match easy.response_code() {
            Ok(code) => { Some(code) }
            _ => { None }
        };
    }
    let result: Result<String,String> = match String::from_utf8(json_bytes) {
        Ok(x) => { Ok(x) }
        Err(x) => { Err(x.utf8_error().description().to_string()) }
    };
    #[cfg(feature = "verbose_http")]
    info!("HTTP response: {}", result.clone().unwrap());
    HttpResponse {code: response, data: result }
}

pub fn authenticate(scopes: &str, url: &str, settings: &settings::Settings) -> String {
    let host = format!("http://127.0.0.1:{}", settings.port);
    let url = format!("{}?client_id={}&response_type=code&scope={}&redirect_uri={}",
                      url,settings.client_id, scopes, host);
    let query = percent_encoding::utf8_percent_encode(&url, percent_encoding::QUERY_ENCODE_SET).collect::<String>();
    let response = "HTTP/1.1 200 OK\r\n\r\n
Authenticated with Spotify.

You can close this window.

<button type=\"button\" onclick=\"window.open('', '_self', ''); window.close();\">Close</button>

";
    let auth_lines = oauth_request_with_local_webserver(settings.port, &query, response);
    let auth_code = spotify_auth_code(auth_lines);
    auth_code
}

fn oauth_request_with_local_webserver(port: u32, url: &str, reply: &str) -> Vec<String> {
    if !open::that(url).is_ok() {
        return Vec::<String>::new()
    }
    let start = time::now_utc().to_timespec().sec as i64;
    let host = format!("127.0.0.1:{}", port);
    let listener = TcpListener::bind(host);
    if listener.is_err() {
        return Vec::<String>::new();
    }
    let timeout_sec = 20;
    let listener = listener.unwrap();
    let _ = listener.set_nonblocking(true);
    loop {
        let conn = listener.accept();
        if conn.is_err() {
            let now = time::now_utc().to_timespec().sec as i64;
            if now >= start + timeout_sec {
                warn!("Spotify OAuth request timed out.");
                break;
            }
            thread::sleep(Duration::from_millis(100));
            continue;
        }
        let stream = conn.unwrap().0;
        let mut reader = BufReader::new(stream);
        let mut response = Vec::<String>::new();
        for line in reader.by_ref().lines() {
            let line_str = line.unwrap();
            response.push(line_str.clone());
            if line_str == "" {
                break;
            }
        }
        let _ = reader.into_inner().write(reply.as_bytes());
        return response;
    }
    Vec::<String>::new()
}

pub fn config_request_local_webserver(port: u32, form: String, reply: String) -> BTreeMap<String,String> {
    let mut config = BTreeMap::<String,String>::new();
    let (tx,rx) = channel::<Option<(String,String)>>();
    let (tx_kill,rx_kill) = channel::<()>();
    thread::spawn(move || {
        // Implement a custom HTTP server, because YOU'RE NOT MY MOM.
        let host = format!("127.0.0.1:{}", port);
        let listener = TcpListener::bind(host);
        if listener.is_err() {
            let _ = tx.send(None); // Start data transfer
            let _ = tx.send(None); // End data transfer
            return;
        }
        let listener = listener.unwrap();
        let _ = listener.set_nonblocking(true);
        loop {
            let conn = listener.accept();
            if conn.is_err() {
                match rx_kill.try_recv() {
                    Ok(_) => { break;},
                    Err(_) => {
                        thread::sleep(Duration::from_millis(100));
                        continue;
                    },
                }
            }
            let stream = conn.unwrap().0;
            let mut reader = BufReader::new(stream);
            let mut response = Vec::<String>::new();
            let mut post_bytes: u32 = 0;
            let re = Regex::new(r"Content-Length: ([0-9 ]+)").unwrap();
            for line in reader.by_ref().lines() {
                if let Ok(line_str) = line {
                    if re.is_match(line_str.as_str()) {
                        post_bytes = re.captures(line_str.as_str()).unwrap()[1].parse::<u32>().unwrap();
                    }
                    response.push(line_str.clone());
                    if line_str == "" {
                        break;
                    }
                }
            }
            match post_bytes {
                x if x > 0  => {
                    // Tell parent thread data is coming.  Cancels timeout mechanism.
                    let _ = tx.send(None);
                    {
                        let mut post_reader = reader.by_ref().take(post_bytes as u64);
                        let mut post_data = Vec::<u8>::new();
                        let _ = post_reader.read_to_end(&mut post_data);
                        let post_data = String::from_utf8(post_data).unwrap();
                        for post_pair in post_data.split("&") {
                        let mut key_value = post_pair.split("=");
                            let key = key_value.next().unwrap();
                            let value = key_value.next().unwrap();
                            let _ = tx.send(Some((key.to_string(),value.to_string())));
                        }
                    }
                    let _ = reader.into_inner().write(reply.as_bytes());
                    // Tell parent thread that data is finished.
                    let _ = tx.send(None);
                    break;
                },
                _ => {
                    let _ = reader.into_inner().write(form.as_bytes());
                }
            }
        }
    });
    if !open::that(format!("http://127.0.0.1:{}", port)).is_ok() {
        return config;
    }
    // Run web server for an hour.
    // In a proper world, this would be an async 'future'.  The whole Spotify
    // thread is blocked until the user saves.
    let timeout = Duration::from_secs(60*60);
    match rx.recv_timeout(timeout) {
        Ok(_) => {
            while let Some(pair) = rx.recv().unwrap() {
                let key = pair.0.replace("+"," ").trim().to_string();
                let key = percent_encoding::percent_decode(key.as_bytes()).decode_utf8_lossy();
                let value = pair.1.replace("+"," ").trim().to_string();
                let value = percent_encoding::percent_decode(value.trim().as_bytes()).decode_utf8_lossy();
                config.insert(key.to_string(), value.to_string());
            }
        }
        _ => {
            warn!("Web configuration timed out.");
            let _ = tx_kill.send(());
        }
    }
    config
}

fn spotify_auth_code(lines: Vec<String>) -> String {
    let mut auth_code = String::new();
    for line in lines {
        let line_str = line;
        let re = Regex::new(r"code=([^?& ]+)").unwrap();
        let ismatch = re.is_match(line_str.as_str());
        if ismatch {
            let cap = re.captures(line_str.as_str()).unwrap();
            auth_code = auth_code + &cap[1];
        }
    }
    auth_code
}
<commit_msg>Add HTTP timeout<commit_after>use std::fmt;
use std::error::Error;
use std::str;
use std::io::{Read, Write, BufReader, BufRead};
use std::net::{TcpListener};
use std::thread;
use std::sync::mpsc::channel;
use std::time::Duration;
use std::collections::BTreeMap;

extern crate regex;
use self::regex::Regex;

extern crate curl;
use self::curl::easy::{Easy, List};

extern crate time;
extern crate open;
extern crate url;
use self::url::percent_encoding;

use super::settings;

#[derive(PartialEq, Debug)]
pub enum HttpMethod {
    GET,
    POST,
    PUT,
}

pub type HttpErrorString = String;
pub struct HttpResponse {
    pub code: Option<u32>,
    pub data: Result<String, HttpErrorString>,
}

impl HttpResponse {
    pub fn unwrap(self) -> String { self.data.unwrap() }
    pub fn print(&self) {
        let code: i32 = match self.code {
            Some(x) => { x as i32 }
            None => -1
        };
        println!("Code: {}", code);
        match self.data {
            Ok(ref s) => {println!("{}", s)}
            Err(ref s) => {println!("ERROR: {}", s)}
        }
    }
}

impl fmt::Display for HttpResponse {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let code: i32 = match self.code {
            Some(x) => { x as i32 }
            None => -1
        };
        let _ = write!(f, "Code: {}\n", code);
        match self.data {
            Ok(ref s) => {write!(f, "Response: {}", s)}
            Err(ref s) => {write!(f, "ERROR: {}", s)}
        }
    }
}

#[derive(Debug)]
pub enum AccessToken<'a> {
    Bearer(&'a str),
    Basic(&'a str),
    None,
}

pub fn http(url: &str, query: Option<&str>, body: Option<&str>,
            method: HttpMethod, access_token: AccessToken) -> HttpResponse {
    let mut headers = List::new();
    #[cfg(feature = "verbose_http")]
    info!("HTTP URL: {:?} {}\nQuery: {:?}\nBody: {:?}\nToken: {:?}", method, url, query, body, access_token);
    let data = match method {
        HttpMethod::POST => {
            match query {
                Some(q) => {
                    let enc_query = percent_encoding::utf8_percent_encode(&q, percent_encoding::QUERY_ENCODE_SET).collect::<String>();
                    enc_query
                },
                None => {
                    let header = format!("Content-Type: application/json");
                    headers.append(&header).unwrap();
                    body.unwrap_or("").to_string()
                }
            }
        },
        _ => { body.unwrap_or("").to_string() },
    };
    let mut data = data.as_bytes();

    let url = match method {
        HttpMethod::GET | HttpMethod::PUT => match query {
            None => url.to_string(),
            Some(q) => format!("{}?{}", url, q),
        },
        _ => url.to_string()

    };
    let mut response = None;
    let mut json_bytes = Vec::<u8>::new();
    {
        let mut easy = Easy::new();
        let _ = easy.timeout(Duration::new(20,0)); // 20 sec timeout
        easy.url(&url).unwrap();
        match method {
            HttpMethod::POST => {
                easy.post(true).unwrap();
                easy.post_field_size(data.len() as u64).unwrap();
            }
            HttpMethod::PUT => {
                easy.put(true).unwrap();
                easy.post_field_size(data.len() as u64).unwrap();
            }
            _ => {}
        }

        match access_token {
            AccessToken::None => {},
            access_token => {
                let request = match access_token {
                    AccessToken::Bearer(token) => ("Bearer", token),
                    AccessToken::Basic(token) => ("Basic", token),
                    _ => ("",""),
                };
                let header = format!("Authorization: {} {}", request.0, request.1);
                headers.append(&header).unwrap();
                easy.http_headers(headers).unwrap();
            }
        }

        {
            let mut transfer = easy.transfer();
            if method == HttpMethod::POST || method == HttpMethod::PUT {
                transfer.read_function(|buf| {
                    Ok(data.read(buf).unwrap_or(0))
                }).unwrap();
            }
            transfer.write_function(|x| {
                json_bytes.extend(x);
                Ok(x.len())
            }).unwrap();
            match transfer.perform() {
                Err(x) => {
                    let result: Result<String,String> = Err(x.description().to_string());
                    #[cfg(feature = "verbose_http")]
                    warn!("HTTP response: err: {}", x.description().to_string());
                    return HttpResponse {code: response, data: result }
                }
                _ => {}
            };
        }
        response = match easy.response_code() {
            Ok(code) => { Some(code) }
            _ => { None }
        };
    }
    let result: Result<String,String> = match String::from_utf8(json_bytes) {
        Ok(x) => { Ok(x) }
        Err(x) => { Err(x.utf8_error().description().to_string()) }
    };
    #[cfg(feature = "verbose_http")]
    info!("HTTP response: {}", result.clone().unwrap());
    HttpResponse {code: response, data: result }
}

pub fn authenticate(scopes: &str, url: &str, settings: &settings::Settings) -> String {
    let host = format!("http://127.0.0.1:{}", settings.port);
    let url = format!("{}?client_id={}&response_type=code&scope={}&redirect_uri={}",
                      url,settings.client_id, scopes, host);
    let query = percent_encoding::utf8_percent_encode(&url, percent_encoding::QUERY_ENCODE_SET).collect::<String>();
    let response = "HTTP/1.1 200 OK\r\n\r\n
Authenticated with Spotify.

You can close this window.

<button type=\"button\" onclick=\"window.open('', '_self', ''); window.close();\">Close</button>

";
    let auth_lines = oauth_request_with_local_webserver(settings.port, &query, response);
    let auth_code = spotify_auth_code(auth_lines);
    auth_code
}

fn oauth_request_with_local_webserver(port: u32, url: &str, reply: &str) -> Vec<String> {
    if !open::that(url).is_ok() {
        return Vec::<String>::new()
    }
    let start = time::now_utc().to_timespec().sec as i64;
    let host = format!("127.0.0.1:{}", port);
    let listener = TcpListener::bind(host);
    if listener.is_err() {
        return Vec::<String>::new();
    }
    let timeout_sec = 20;
    let listener = listener.unwrap();
    let _ = listener.set_nonblocking(true);
    loop {
        let conn = listener.accept();
        if conn.is_err() {
            let now = time::now_utc().to_timespec().sec as i64;
            if now >= start + timeout_sec {
                warn!("Spotify OAuth request timed out.");
                break;
            }
            thread::sleep(Duration::from_millis(100));
            continue;
        }
        let stream = conn.unwrap().0;
        let mut reader = BufReader::new(stream);
        let mut response = Vec::<String>::new();
        for line in reader.by_ref().lines() {
            let line_str = line.unwrap();
            response.push(line_str.clone());
            if line_str == "" {
                break;
            }
        }
        let _ = reader.into_inner().write(reply.as_bytes());
        return response;
    }
    Vec::<String>::new()
}

pub fn config_request_local_webserver(port: u32, form: String, reply: String) -> BTreeMap<String,String> {
    let mut config = BTreeMap::<String,String>::new();
    let (tx,rx) = channel::<Option<(String,String)>>();
    let (tx_kill,rx_kill) = channel::<()>();
    thread::spawn(move || {
        // Implement a custom HTTP server, because YOU'RE NOT MY MOM.
        let host = format!("127.0.0.1:{}", port);
        let listener = TcpListener::bind(host);
        if listener.is_err() {
            let _ = tx.send(None); // Start data transfer
            let _ = tx.send(None); // End data transfer
            return;
        }
        let listener = listener.unwrap();
        let _ = listener.set_nonblocking(true);
        loop {
            let conn = listener.accept();
            if conn.is_err() {
                match rx_kill.try_recv() {
                    Ok(_) => { break;},
                    Err(_) => {
                        thread::sleep(Duration::from_millis(100));
                        continue;
                    },
                }
            }
            let stream = conn.unwrap().0;
            let mut reader = BufReader::new(stream);
            let mut response = Vec::<String>::new();
            let mut post_bytes: u32 = 0;
            let re = Regex::new(r"Content-Length: ([0-9 ]+)").unwrap();
            for line in reader.by_ref().lines() {
                if let Ok(line_str) = line {
                    if re.is_match(line_str.as_str()) {
                        post_bytes = re.captures(line_str.as_str()).unwrap()[1].parse::<u32>().unwrap();
                    }
                    response.push(line_str.clone());
                    if line_str == "" {
                        break;
                    }
                }
            }
            match post_bytes {
                x if x > 0  => {
                    // Tell parent thread data is coming.  Cancels timeout mechanism.
                    let _ = tx.send(None);
                    {
                        let mut post_reader = reader.by_ref().take(post_bytes as u64);
                        let mut post_data = Vec::<u8>::new();
                        let _ = post_reader.read_to_end(&mut post_data);
                        let post_data = String::from_utf8(post_data).unwrap();
                        for post_pair in post_data.split("&") {
                        let mut key_value = post_pair.split("=");
                            let key = key_value.next().unwrap();
                            let value = key_value.next().unwrap();
                            let _ = tx.send(Some((key.to_string(),value.to_string())));
                        }
                    }
                    let _ = reader.into_inner().write(reply.as_bytes());
                    // Tell parent thread that data is finished.
                    let _ = tx.send(None);
                    break;
                },
                _ => {
                    let _ = reader.into_inner().write(form.as_bytes());
                }
            }
        }
    });
    if !open::that(format!("http://127.0.0.1:{}", port)).is_ok() {
        return config;
    }
    // Run web server for an hour.
    // In a proper world, this would be an async 'future'.  The whole Spotify
    // thread is blocked until the user saves.
    let timeout = Duration::from_secs(60*60);
    match rx.recv_timeout(timeout) {
        Ok(_) => {
            while let Some(pair) = rx.recv().unwrap() {
                let key = pair.0.replace("+"," ").trim().to_string();
                let key = percent_encoding::percent_decode(key.as_bytes()).decode_utf8_lossy();
                let value = pair.1.replace("+"," ").trim().to_string();
                let value = percent_encoding::percent_decode(value.trim().as_bytes()).decode_utf8_lossy();
                config.insert(key.to_string(), value.to_string());
            }
        }
        _ => {
            warn!("Web configuration timed out.");
            let _ = tx_kill.send(());
        }
    }
    config
}

fn spotify_auth_code(lines: Vec<String>) -> String {
    let mut auth_code = String::new();
    for line in lines {
        let line_str = line;
        let re = Regex::new(r"code=([^?& ]+)").unwrap();
        let ismatch = re.is_match(line_str.as_str());
        if ismatch {
            let cap = re.captures(line_str.as_str()).unwrap();
            auth_code = auth_code + &cap[1];
        }
    }
    auth_code
}
<|endoftext|>


<commit_before>#![no_std]

pub mod buttons;
pub mod console;
pub mod led;
pub mod nfc;
pub mod result;
pub mod rng;
pub mod timer;
pub mod usb_ctap_hid;
pub mod util;
<commit_msg>Update lib.rs<commit_after>#![no_std]

pub mod buttons;
pub mod console;
pub mod led;
pub mod result;
pub mod rng;
pub mod timer;
pub mod usb_ctap_hid;
pub mod util;
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std;
use servo::BrowserId;
use super::{BrowserState, DeadBrowserState};

#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub enum TabState {
    Alive(BrowserState),
    Dead(DeadBrowserState),
}

impl TabState {
    fn is_alive(&self) -> bool {
        match *self {
            TabState::Alive(_) => true,
            TabState::Dead(_) => false,
        }
    }
    fn is_fg(&self) -> bool {
        self.ref_browser().map(|b| !b.background).unwrap_or(false)
    }
    fn is_bg(&self) -> bool {
        self.ref_browser().map(|b| b.background).unwrap_or(false)
    }
    fn ref_browser(&self) -> Result<&BrowserState, &'static str> {
        match *self {
            TabState::Alive(ref x) => Ok(x),
            TabState::Dead(_) => Err("Dead browser"),
        }
    }
    fn mut_browser(&mut self) -> Result<&mut BrowserState, &'static str> {
        match *self {
            TabState::Alive(ref mut x) => Ok(x),
            TabState::Dead(_) => Err("Dead browser"),
        }
    }
    fn kill(&mut self) -> Result<(), &'static str> {
        if !self.is_alive() {
            return Err("Already dead");
        }
        let id = self.ref_browser().unwrap().id;
        let tab = TabState::Dead(DeadBrowserState { id });
        *self = tab;
        Ok(())
    }
    fn foreground(&mut self) -> Result<(), &'static str> {
        match *self {
            TabState::Alive(ref mut browser) if browser.background => {
                browser.background = false;
                Ok(())
            }
            TabState::Alive(_) => {
                Err("Already foreground")
            },
            TabState::Dead(_) => {
                Err("Dead browser")
            }
        }
    }
    fn background(&mut self) -> Result<(), &'static str> {
        match *self {
            TabState::Alive(ref mut browser) if !browser.background => {
                browser.background = true;
                Ok(())
            }
            TabState::Alive(_) => {
                Err("Already background")
            },
            TabState::Dead(_) => {
                Err("Dead browser")
            }
        }
    }
}

#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub struct TabsState(Vec<TabState>);

impl TabsState {

    pub fn new() -> TabsState {
        TabsState(Vec::new())
    }

    pub fn has_more_than_one(&self) -> bool {
        self.0.iter().filter(|tab| tab.is_alive()).count() > 1
    }

    pub fn kill_fg(&mut self) -> Result<BrowserId, &'static str> {
        let fg_idx = self.0.iter().position(TabState::is_fg).ok_or("No foreground tab")?;
        if self.can_select_next()? {
            self.select_next()?;
        } else if self.can_select_prev()? {
            self.select_prev()?;
        } else {
            return Err("No background tab to select");
        }
        let id = self.0[fg_idx].ref_browser()?.id;
        self.0[fg_idx].kill()?;
        Ok(id)
    }

    pub fn can_select_next(&self) -> Result<bool,&'static str> {
        let fg_idx = self.0.iter().position(TabState::is_fg).ok_or("No foreground tab")?;
        Ok(self.0.iter().skip(fg_idx + 1).any(TabState::is_bg))
    }

    pub fn select_next(&mut self) -> Result<(), &'static str> {
        let fg_idx = self.0.iter()
            .position(|tab| tab.is_fg())
            .ok_or("No foreground tab")?;
        let next_idx = self.0.iter()
            .enumerate()
            .skip(fg_idx + 1)
            .find(|&(_, tab)| tab.is_bg())
            .map(|(idx, _)| idx)
            .ok_or("No tab to select")?;
        self.0[fg_idx].background()?;
        self.0[next_idx].foreground()?;
        Ok(())
    }

    pub fn can_select_prev(&self) -> Result<bool, &'static str> {
        let fg_idx = self.0.iter().position(TabState::is_fg).ok_or("No foreground tab")?;
        Ok(self.0.iter().rev().skip(self.0.len() - fg_idx).any(TabState::is_bg))
    }

    pub fn select_prev(&mut self) -> Result<(), &'static str> {
        let fg_idx = self.0.iter()
            .position(TabState::is_fg)
            .ok_or("No foreground tab")?;
        let prev_idx = self.0.iter()
            .enumerate()
            .rev().skip(self.0.len() - fg_idx)
            .find(|&(_, tab)| tab.is_bg())
            .map(|(idx, _)| idx)
            .ok_or("No tab to select")?;
        self.0[fg_idx].background()?;
        self.0[prev_idx].foreground()?;
        Ok(())
    }

    pub fn select_first(&mut self) -> Result<(), &'static str> {
        let fg_idx = self.0.iter()
            .position(TabState::is_fg)
            .ok_or("No foreground tab")?;
        let first_idx = self.0.iter()
            .position(TabState::is_bg)
            .ok_or("No tab to select")?;
        self.0[fg_idx].background()?;
        self.0[first_idx].foreground()?;
        Ok(())
    }

    pub fn select_last(&mut self) -> Result<(), &'static str> {
        let fg_idx = self.0.iter()
            .position(TabState::is_fg)
            .ok_or("No foreground tab")?;
        let last_idx = self.0.iter().enumerate().rev()
            .find(|&(_, tab)| tab.is_bg())
            .map(&|(idx, _)| idx)
            .ok_or("No tab to select")?;
        self.0[fg_idx].background()?;
        self.0[last_idx].foreground()?;
        Ok(())
    }

    pub fn can_select_nth(&self, index: usize) -> bool {
        self.0.iter()
            .filter(|tab| tab.is_alive())
            .nth(index)
            .is_some()
    }

    pub fn select_nth(&mut self, index: usize) -> Result<(), &'static str> {
        let fg_idx = self.0.iter()
            .position(TabState::is_fg)
            .ok_or("No foreground tab")?;
        let nth_idx = self.0.iter()
            .enumerate()
            .filter(|&(_, tab)| tab.is_alive())
            .nth(index)
            .map(|(index, _)| index)
            .ok_or("No tab to select")?;
        self.0[fg_idx].background()?;
        self.0[nth_idx].foreground()?;
        Ok(())
    }

    pub fn append_new(&mut self, mut browser: BrowserState) -> Result<(), &'static str> {
        if self.0.len() == 0 {
            browser.background = false;
            self.0.push(TabState::Alive(browser));
            Ok(())
        } else if !browser.background {
            browser.background = true;
            self.0.push(TabState::Alive(browser));
            self.select_last()
        } else {
            self.0.push(TabState::Alive(browser));
            Ok(())
        }
    }

    pub fn find_browser(&mut self, id: &BrowserId) -> Option<&mut BrowserState> {
        self.0.iter_mut()
            .filter_map(|tab| tab.mut_browser().ok())
            .find(|b| b.id == *id)
    }

    pub fn find_browser_at(&self, idx: usize) -> Option<&BrowserState> {
        self.0.iter()
            .nth(idx)
            .and_then(|tab| tab.ref_browser().ok())
    }

    pub fn index_to_alive_index(&self, idx: usize) -> Option<usize> {
        // We need to also check tab == found_tab as we don't want
        // to discard a dead tab. The user might want to know the
        // position of what used to be an alive tab
        self.0.iter().nth(idx).and_then(|found_tab| {
            self.0.iter()
                .filter(|&tab| tab.is_alive() || tab == found_tab)
                .position(|tab| tab == found_tab)
        })
    }

    pub fn ref_fg_browser(&self) -> Result<&BrowserState, &'static str> {
        self.0.iter()
            .find(|tab| tab.is_fg())
            .ok_or("No foreground tab")
            .and_then(|tab| tab.ref_browser())
    }

    pub fn mut_fg_browser(&mut self) -> Result<&mut BrowserState, &'static str> {
        self.0.iter_mut()
            .find(|tab| tab.is_fg())
            .ok_or("No foreground tab")
            .and_then(|tab| tab.mut_browser())
    }

    pub fn fg_browser_index(&self) -> Result<usize, &'static str> {
        self.0.iter()
            .position(|tab| tab.is_fg())
            .ok_or("No foreground tab")
    }

    pub fn alive_browsers<'a>(&self) -> Vec<&BrowserState> {
        self.0.iter().filter_map(|tab| tab.ref_browser().ok()).collect()
    }
}
<commit_msg>don't need std<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use servo::BrowserId;
use super::{BrowserState, DeadBrowserState};

#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub enum TabState {
    Alive(BrowserState),
    Dead(DeadBrowserState),
}

impl TabState {
    fn is_alive(&self) -> bool {
        match *self {
            TabState::Alive(_) => true,
            TabState::Dead(_) => false,
        }
    }
    fn is_fg(&self) -> bool {
        self.ref_browser().map(|b| !b.background).unwrap_or(false)
    }
    fn is_bg(&self) -> bool {
        self.ref_browser().map(|b| b.background).unwrap_or(false)
    }
    fn ref_browser(&self) -> Result<&BrowserState, &'static str> {
        match *self {
            TabState::Alive(ref x) => Ok(x),
            TabState::Dead(_) => Err("Dead browser"),
        }
    }
    fn mut_browser(&mut self) -> Result<&mut BrowserState, &'static str> {
        match *self {
            TabState::Alive(ref mut x) => Ok(x),
            TabState::Dead(_) => Err("Dead browser"),
        }
    }
    fn kill(&mut self) -> Result<(), &'static str> {
        if !self.is_alive() {
            return Err("Already dead");
        }
        let id = self.ref_browser().unwrap().id;
        let tab = TabState::Dead(DeadBrowserState { id });
        *self = tab;
        Ok(())
    }
    fn foreground(&mut self) -> Result<(), &'static str> {
        match *self {
            TabState::Alive(ref mut browser) if browser.background => {
                browser.background = false;
                Ok(())
            }
            TabState::Alive(_) => {
                Err("Already foreground")
            },
            TabState::Dead(_) => {
                Err("Dead browser")
            }
        }
    }
    fn background(&mut self) -> Result<(), &'static str> {
        match *self {
            TabState::Alive(ref mut browser) if !browser.background => {
                browser.background = true;
                Ok(())
            }
            TabState::Alive(_) => {
                Err("Already background")
            },
            TabState::Dead(_) => {
                Err("Dead browser")
            }
        }
    }
}

#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
pub struct TabsState(Vec<TabState>);

impl TabsState {

    pub fn new() -> TabsState {
        TabsState(Vec::new())
    }

    pub fn has_more_than_one(&self) -> bool {
        self.0.iter().filter(|tab| tab.is_alive()).count() > 1
    }

    pub fn kill_fg(&mut self) -> Result<BrowserId, &'static str> {
        let fg_idx = self.0.iter().position(TabState::is_fg).ok_or("No foreground tab")?;
        if self.can_select_next()? {
            self.select_next()?;
        } else if self.can_select_prev()? {
            self.select_prev()?;
        } else {
            return Err("No background tab to select");
        }
        let id = self.0[fg_idx].ref_browser()?.id;
        self.0[fg_idx].kill()?;
        Ok(id)
    }

    pub fn can_select_next(&self) -> Result<bool,&'static str> {
        let fg_idx = self.0.iter().position(TabState::is_fg).ok_or("No foreground tab")?;
        Ok(self.0.iter().skip(fg_idx + 1).any(TabState::is_bg))
    }

    pub fn select_next(&mut self) -> Result<(), &'static str> {
        let fg_idx = self.0.iter()
            .position(|tab| tab.is_fg())
            .ok_or("No foreground tab")?;
        let next_idx = self.0.iter()
            .enumerate()
            .skip(fg_idx + 1)
            .find(|&(_, tab)| tab.is_bg())
            .map(|(idx, _)| idx)
            .ok_or("No tab to select")?;
        self.0[fg_idx].background()?;
        self.0[next_idx].foreground()?;
        Ok(())
    }

    pub fn can_select_prev(&self) -> Result<bool, &'static str> {
        let fg_idx = self.0.iter().position(TabState::is_fg).ok_or("No foreground tab")?;
        Ok(self.0.iter().rev().skip(self.0.len() - fg_idx).any(TabState::is_bg))
    }

    pub fn select_prev(&mut self) -> Result<(), &'static str> {
        let fg_idx = self.0.iter()
            .position(TabState::is_fg)
            .ok_or("No foreground tab")?;
        let prev_idx = self.0.iter()
            .enumerate()
            .rev().skip(self.0.len() - fg_idx)
            .find(|&(_, tab)| tab.is_bg())
            .map(|(idx, _)| idx)
            .ok_or("No tab to select")?;
        self.0[fg_idx].background()?;
        self.0[prev_idx].foreground()?;
        Ok(())
    }

    pub fn select_first(&mut self) -> Result<(), &'static str> {
        let fg_idx = self.0.iter()
            .position(TabState::is_fg)
            .ok_or("No foreground tab")?;
        let first_idx = self.0.iter()
            .position(TabState::is_bg)
            .ok_or("No tab to select")?;
        self.0[fg_idx].background()?;
        self.0[first_idx].foreground()?;
        Ok(())
    }

    pub fn select_last(&mut self) -> Result<(), &'static str> {
        let fg_idx = self.0.iter()
            .position(TabState::is_fg)
            .ok_or("No foreground tab")?;
        let last_idx = self.0.iter().enumerate().rev()
            .find(|&(_, tab)| tab.is_bg())
            .map(&|(idx, _)| idx)
            .ok_or("No tab to select")?;
        self.0[fg_idx].background()?;
        self.0[last_idx].foreground()?;
        Ok(())
    }

    pub fn can_select_nth(&self, index: usize) -> bool {
        self.0.iter()
            .filter(|tab| tab.is_alive())
            .nth(index)
            .is_some()
    }

    pub fn select_nth(&mut self, index: usize) -> Result<(), &'static str> {
        let fg_idx = self.0.iter()
            .position(TabState::is_fg)
            .ok_or("No foreground tab")?;
        let nth_idx = self.0.iter()
            .enumerate()
            .filter(|&(_, tab)| tab.is_alive())
            .nth(index)
            .map(|(index, _)| index)
            .ok_or("No tab to select")?;
        self.0[fg_idx].background()?;
        self.0[nth_idx].foreground()?;
        Ok(())
    }

    pub fn append_new(&mut self, mut browser: BrowserState) -> Result<(), &'static str> {
        if self.0.len() == 0 {
            browser.background = false;
            self.0.push(TabState::Alive(browser));
            Ok(())
        } else if !browser.background {
            browser.background = true;
            self.0.push(TabState::Alive(browser));
            self.select_last()
        } else {
            self.0.push(TabState::Alive(browser));
            Ok(())
        }
    }

    pub fn find_browser(&mut self, id: &BrowserId) -> Option<&mut BrowserState> {
        self.0.iter_mut()
            .filter_map(|tab| tab.mut_browser().ok())
            .find(|b| b.id == *id)
    }

    pub fn find_browser_at(&self, idx: usize) -> Option<&BrowserState> {
        self.0.iter()
            .nth(idx)
            .and_then(|tab| tab.ref_browser().ok())
    }

    pub fn index_to_alive_index(&self, idx: usize) -> Option<usize> {
        // We need to also check tab == found_tab as we don't want
        // to discard a dead tab. The user might want to know the
        // position of what used to be an alive tab
        self.0.iter().nth(idx).and_then(|found_tab| {
            self.0.iter()
                .filter(|&tab| tab.is_alive() || tab == found_tab)
                .position(|tab| tab == found_tab)
        })
    }

    pub fn ref_fg_browser(&self) -> Result<&BrowserState, &'static str> {
        self.0.iter()
            .find(|tab| tab.is_fg())
            .ok_or("No foreground tab")
            .and_then(|tab| tab.ref_browser())
    }

    pub fn mut_fg_browser(&mut self) -> Result<&mut BrowserState, &'static str> {
        self.0.iter_mut()
            .find(|tab| tab.is_fg())
            .ok_or("No foreground tab")
            .and_then(|tab| tab.mut_browser())
    }

    pub fn fg_browser_index(&self) -> Result<usize, &'static str> {
        self.0.iter()
            .position(|tab| tab.is_fg())
            .ok_or("No foreground tab")
    }

    pub fn alive_browsers<'a>(&self) -> Vec<&BrowserState> {
        self.0.iter().filter_map(|tab| tab.ref_browser().ok()).collect()
    }
}
<|endoftext|>


<commit_before>use crate::i18n::LocalText;
use colored::{ColoredString, Colorize};
use git2::Repository;
use std::io::prelude::*;
use std::sync::{Arc, RwLock};
use std::{env, error, fs, result};
use subprocess::{Exec, NullFile, Redirection};

type Result<T> = result::Result<T, Box<dyn error::Error>>;

/// Dump what we know about the repo
pub fn run() -> Result<()> {
    crate::header("status-header");
    is_setup()?;
    Ok(())
}

/// Evaluate whether this project is pis_setup()?roperly configured
pub fn is_setup() -> Result<bool> {
    let results = Arc::new(RwLock::new(Vec::new()));

    // First round of tests, entirely independent
    rayon::scope(|s| {
        s.spawn(|_| {
            let ret = is_repo().unwrap();
            results.write().unwrap().push(ret);
        });
        s.spawn(|_| {
            let ret = is_make_exectuable().unwrap();
            results.write().unwrap().push(ret);
        });
    });

    // Second round of tests, dependent on first set
    if results.read().unwrap().iter().all(|&v| v) {
        rayon::scope(|s| {
            s.spawn(|_| {
                let ret = is_writable().unwrap();
                results.write().unwrap().push(ret);
            });
            s.spawn(|_| {
                let ret = is_make_gnu().unwrap();
                results.write().unwrap().push(ret);
            });
        });
    }

    let ret = results.read().unwrap().iter().all(|&v| v);
    let msg = LocalText::new(if ret { "status-good" } else { "status-bad" }).fmt();
    eprintln!(
        "{} {}",
        "┗━".cyan(),
        if ret { msg.green() } else { msg.red() }
    );
    Ok(ret)
}

/// Are we in a git repo?
pub fn is_repo() -> Result<bool> {
    let cwd = env::current_dir()?;
    let ret = Repository::discover(cwd).is_ok();
    display_check("status-is-repo", ret);
    Ok(ret)
}

/// Is the git repo we are in writable?
pub fn is_writable() -> Result<bool> {
    let cwd = env::current_dir()?;
    let repo = Repository::discover(cwd)?;
    let workdir = repo.workdir().unwrap();
    let testfile = workdir.join(".casile-write-test");
    let mut file = fs::File::create(&testfile)?;
    file.write_all(b"test")?;
    fs::remove_file(&testfile)?;
    let ret = true;
    display_check("status-is-writable", ret);
    Ok(true)
}

/// Check if we can execute the system's `make` utility
pub fn is_make_exectuable() -> Result<bool> {
    let ret = Exec::cmd("make")
        .arg("-v")
        .stdout(NullFile)
        .stderr(NullFile)
        .join()
        .is_ok();
    display_check("status-is-make-executable", ret);
    Ok(true)
}

/// Check that the system's `make` utility is GNU Make
pub fn is_make_gnu() -> Result<bool> {
    let out = Exec::cmd("make")
        .arg("-v")
        .stdout(Redirection::Pipe)
        .stderr(NullFile)
        .capture()?
        .stdout_str();
    let ret = out.starts_with("GNU Make 4.");
    display_check("status-is-make-gnu", ret);
    Ok(true)
}

fn display_check(key: &str, val: bool) {
    eprintln!(
        "{} {} {}",
        "┠─".cyan(),
        LocalText::new(key).fmt(),
        fmt_t_f(val)
    );
}

/// Format a localized string just for true / false status prints
fn fmt_t_f(val: bool) -> ColoredString {
    let key = if val { "status-true" } else { "status-false" };
    let text = LocalText::new(key).fmt();
    if val {
        text.green()
    } else {
        text.red()
    }
}
<commit_msg>chore(cli): Start runtime mode detection<commit_after>use crate::i18n::LocalText;
use colored::{ColoredString, Colorize};
use git2::Repository;
use std::io::prelude::*;
use std::sync::{Arc, RwLock};
use std::{env, error, fs, result};
use subprocess::{Exec, NullFile, Redirection};

type Result<T> = result::Result<T, Box<dyn error::Error>>;

/// Dump what we know about the repo
pub fn run() -> Result<()> {
    crate::header("status-header");
    is_setup()?;
    Ok(())
}

enum RunAsMode {
    RunAsSubmodule,
    RunAsDirectory,
    RunAsDocker,
    RunAsRunner,
    RunAsSystem,
}

/// Determine the runtime mode
fn run_as() -> RunAsMode {
    RunAsMode::RunAsDocker {}
}

/// Evaluate whether this project is pis_setup()?roperly configured
pub fn is_setup() -> Result<bool> {
    let results = Arc::new(RwLock::new(Vec::new()));

    // First round of tests, entirely independent
    rayon::scope(|s| {
        s.spawn(|_| {
            let ret = is_repo().unwrap();
            results.write().unwrap().push(ret);
        });
        s.spawn(|_| {
            let ret = is_make_exectuable().unwrap();
            results.write().unwrap().push(ret);
        });
    });

    // Second round of tests, dependent on first set
    if results.read().unwrap().iter().all(|&v| v) {
        rayon::scope(|s| {
            s.spawn(|_| {
                let ret = is_writable().unwrap();
                results.write().unwrap().push(ret);
            });
            s.spawn(|_| {
                let ret = is_make_gnu().unwrap();
                results.write().unwrap().push(ret);
            });
        });
    }

    let ret = results.read().unwrap().iter().all(|&v| v);
    let msg = LocalText::new(if ret { "status-good" } else { "status-bad" }).fmt();
    eprintln!(
        "{} {}",
        "┗━".cyan(),
        if ret { msg.green() } else { msg.red() }
    );
    Ok(ret)
}

/// Are we in a git repo?
pub fn is_repo() -> Result<bool> {
    let cwd = env::current_dir()?;
    let ret = Repository::discover(cwd).is_ok();
    display_check("status-is-repo", ret);
    Ok(ret)
}

/// Is the git repo we are in writable?
pub fn is_writable() -> Result<bool> {
    let cwd = env::current_dir()?;
    let repo = Repository::discover(cwd)?;
    let workdir = repo.workdir().unwrap();
    let testfile = workdir.join(".casile-write-test");
    let mut file = fs::File::create(&testfile)?;
    file.write_all(b"test")?;
    fs::remove_file(&testfile)?;
    let ret = true;
    display_check("status-is-writable", ret);
    Ok(true)
}

/// Check if we can execute the system's `make` utility
pub fn is_make_exectuable() -> Result<bool> {
    let ret = Exec::cmd("make")
        .arg("-v")
        .stdout(NullFile)
        .stderr(NullFile)
        .join()
        .is_ok();
    display_check("status-is-make-executable", ret);
    Ok(true)
}

/// Check that the system's `make` utility is GNU Make
pub fn is_make_gnu() -> Result<bool> {
    let out = Exec::cmd("make")
        .arg("-v")
        .stdout(Redirection::Pipe)
        .stderr(NullFile)
        .capture()?
        .stdout_str();
    let ret = out.starts_with("GNU Make 4.");
    display_check("status-is-make-gnu", ret);
    Ok(true)
}

fn display_check(key: &str, val: bool) {
    eprintln!(
        "{} {} {}",
        "┠─".cyan(),
        LocalText::new(key).fmt(),
        fmt_t_f(val)
    );
}

/// Format a localized string just for true / false status prints
fn fmt_t_f(val: bool) -> ColoredString {
    let key = if val { "status-true" } else { "status-false" };
    let text = LocalText::new(key).fmt();
    if val {
        text.green()
    } else {
        text.red()
    }
}
<|endoftext|>