<commit_before>// Copyright 2017 Jeremy Wall <jeremy@marzhillstudios.com>
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.

//! Bottom up parser for precedence parsing of expressions separated by binary
//! operators.
use abortable_parser::combinators::eoi;
use abortable_parser::{Error, Result, SliceIter};

use super::{non_op_expression, NomResult};
use crate::ast::*;

/// Defines the intermediate stages of our bottom up parser for precedence parsing.
#[derive(Debug, PartialEq, Clone)]
pub enum Element {
    Expr(Expression),
    MathOp(BinaryExprType),
    CompareOp(CompareType),
}

make_fn!(
    math_op_type<SliceIter<Token>, Element>,
    either!(
        do_each!(
            _ => punct!("+"),
            (Element::MathOp(BinaryExprType::Add))),
        do_each!(
            _ => punct!("-"),
            (Element::MathOp(BinaryExprType::Sub))),
        do_each!(
            _ => punct!("*"),
            (Element::MathOp(BinaryExprType::Mul))),
        do_each!(
            _ => punct!("/"),
            (Element::MathOp(BinaryExprType::Div)))
    )
);

fn parse_expression(i: SliceIter<Element>) -> Result<SliceIter<Element>, Expression> {
    let mut i_ = i.clone();
    if eoi(i_.clone()).is_complete() {
        return Result::Abort(Error::new(
            "Expected Expression found End Of Input",
            Box::new(i_),
        ));
    }
    let el = i_.next();
    if let Some(&Element::Expr(ref expr)) = el {
        return Result::Complete(i_.clone(), expr.clone());
    }
    return Result::Fail(Error::new(
        format!(
            "Error while parsing Binary Expression Expected Expression got {:?}",
            el
        ),
        Box::new(i_),
    ));
}

fn parse_sum_operator(i: SliceIter<Element>) -> Result<SliceIter<Element>, BinaryExprType> {
    let mut i_ = i.clone();
    if eoi(i_.clone()).is_complete() {
        return Result::Fail(Error::new(
            format!("Expected Expression found End Of Input"),
            Box::new(i_),
        ));
    }
    let el = i_.next();
    if let Some(&Element::MathOp(ref op)) = el {
        match op {
            &BinaryExprType::Add => {
                return Result::Complete(i_.clone(), op.clone());
            }
            &BinaryExprType::Sub => {
                return Result::Complete(i_.clone(), op.clone());
            }
            _other => {
                // noop
            }
        };
    }
    return Result::Fail(Error::new(
        format!(
            "Error while parsing Binary Expression Unexpected Operator {:?}",
            el
        ),
        Box::new(i_),
    ));
}

fn tuple_to_binary_expression(
    kind: BinaryExprType,
    left: Expression,
    right: Expression,
) -> Expression {
    let pos = left.pos().clone();
    Expression::Binary(BinaryOpDef {
        kind: kind,
        left: Box::new(left),
        right: Box::new(right),
        pos: pos,
    })
}

fn parse_product_operator(i: SliceIter<Element>) -> Result<SliceIter<Element>, BinaryExprType> {
    let mut i_ = i.clone();
    if eoi(i_.clone()).is_complete() {
        return Result::Fail(Error::new(
            format!("Expected Expression found End Of Input"),
            Box::new(i_),
        ));
    }
    let el = i_.next();
    if let Some(&Element::MathOp(ref op)) = el {
        match op {
            &BinaryExprType::Mul => {
                return Result::Complete(i_.clone(), op.clone());
            }
            &BinaryExprType::Div => {
                return Result::Complete(i_.clone(), op.clone());
            }
            _other => {
                // noop
            }
        };
    }
    return Result::Fail(Error::new(
        format!(
            "Error while parsing Binary Expression Unexpected Operator {:?}",
            el
        ),
        Box::new(i_),
    ));
}

/// do_binary_expr implements precedence based parsing where the more tightly bound
/// parsers are passed in as lowerrule parsers. We default to any non_op_expression
/// as the most tightly bound expressions.
macro_rules! do_binary_expr {
    ($i:expr, $oprule:ident, $lowerrule:ident) => {
        do_binary_expr!($i, run!($oprule), $lowerrule)
    };

    ($i:expr, $oprule:ident, $lowerrule:ident!( $($lowerargs:tt)* )) => {
        do_binary_expr!($i, run!($oprule), $lowerrule!($($lowerargs)*))
    };

    ($i:expr, $oprule:ident) => {
        do_binary_expr!($i, run!($oprule))
    };

    ($i:expr, $oprule:ident!( $($args:tt)* )) => {
        do_binary_expr!($i, $oprule!($($args)*), parse_expression)
    };

    ($i:expr, $oprule:ident!( $($args:tt)* ), $lowerrule:ident) => {
        do_binary_expr!($i, $oprule!($($args)*), run!($lowerrule))
    };

    ($i:expr, $oprule:ident!( $($args:tt)* ), $lowerrule:ident!( $($lowerargs:tt)* )) => {
        do_each!($i,
            left => $lowerrule!($($lowerargs)*),
                typ => $oprule!($($args)*),
                right => $lowerrule!($($lowerargs)*),
                (tuple_to_binary_expression(typ, left, right))
        )
    };
}

make_fn!(
    sum_expression<SliceIter<Element>, Expression>,
    do_binary_expr!(
        parse_sum_operator,
        either!(trace_parse!(product_expression), trace_parse!(parse_expression))
    )
);

make_fn!(
    product_expression<SliceIter<Element>, Expression>,
    do_binary_expr!(parse_product_operator, trace_parse!(parse_expression))
);

make_fn!(
    math_expression<SliceIter<Element>, Expression>,
    either!(trace_parse!(sum_expression), trace_parse!(product_expression))
);

// TODO(jwall): Change comparison operators to use the do_binary_expr! with precedence?
fn tuple_to_compare_expression(
    kind: CompareType,
    left: Expression,
    right: Expression,
) -> Expression {
    let pos = left.pos().clone();
    Expression::Compare(ComparisonDef {
        kind: kind,
        left: Box::new(left),
        right: Box::new(right),
        pos: pos,
    })
}

make_fn!(
    compare_op_type<SliceIter<Token>, Element>,
    either!(
        do_each!(_ => punct!("=="), (Element::CompareOp(CompareType::Equal))),
        do_each!(_ => punct!("!="), (Element::CompareOp(CompareType::NotEqual))),
        do_each!(_ => punct!("<="), (Element::CompareOp(CompareType::LTEqual))),
        do_each!(_ => punct!(">="), (Element::CompareOp(CompareType::GTEqual))),
        do_each!(_ => punct!("<"),  (Element::CompareOp(CompareType::LT))),
        do_each!(_ => punct!(">"),  (Element::CompareOp(CompareType::GT)))
    )
);

fn parse_compare_operator(i: SliceIter<Element>) -> Result<SliceIter<Element>, CompareType> {
    let mut i_ = i.clone();
    if eoi(i_.clone()).is_complete() {
        return Result::Fail(Error::new(
            format!("Expected Expression found End Of Input"),
            Box::new(i_),
        ));
    }
    let el = i_.next();
    if let Some(&Element::CompareOp(ref op)) = el {
        return Result::Complete(i_.clone(), op.clone());
    }
    return Result::Fail(Error::new(
        format!(
            "Error while parsing Binary Expression Unexpected Operator {:?}",
            el
        ),
        Box::new(i),
    ));
}

make_fn!(
    compare_expression<SliceIter<Element>, Expression>,
    do_each!(
        left => either!(trace_parse!(math_expression), trace_parse!(parse_expression)),
        typ => parse_compare_operator,
        right => either!(trace_parse!(math_expression), trace_parse!(parse_expression)),
        (tuple_to_compare_expression(typ, left, right))
    )
);

/// Parse a list of expressions separated by operators into a Vec<Element>.
fn parse_operand_list<'a>(i: SliceIter<'a, Token>) -> NomResult<'a, Vec<Element>> {
    // 1. First try to parse a non_op_expression,
    let mut _i = i.clone();
    let mut list = Vec::new();
    // 1. loop
    let mut firstrun = true;
    loop {
        // 2. Parse a non_op_expression.
        match non_op_expression(_i.clone()) {
            Result::Fail(e) => {
                // A failure to parse an expression
                // is always an error.
                return Result::Fail(e);
            }
            Result::Abort(e) => {
                // A failure to parse an expression
                // is always an error.
                return Result::Abort(e);
            }
            Result::Incomplete(i) => {
                return Result::Incomplete(i);
            }
            Result::Complete(rest, expr) => {
                list.push(Element::Expr(expr));
                _i = rest.clone();
            }
        }
        // 3. Parse an operator.
        match either!(_i.clone(), math_op_type, compare_op_type) {
            Result::Fail(e) => {
                if firstrun {
                    // If we don't find an operator in our first
                    // run then this is not an operand list.
                    return Result::Fail(e);
                }
                // if we don't find one on subsequent runs then
                // that's the end of the operand list.
                break;
            }
            Result::Abort(e) => {
                // A failure to parse an expression
                // is always an error.
                return Result::Abort(e);
            }
            Result::Incomplete(i) => {
                return Result::Incomplete(i);
            }
            Result::Complete(rest, el) => {
                list.push(el);
                _i = rest.clone();
            }
        }
        firstrun = false;
    }
    return Result::Complete(_i, list);
}

/// Parse a binary operator expression.
pub fn op_expression<'a>(i: SliceIter<'a, Token>) -> Result<SliceIter<Token>, Expression> {
    let preparse = parse_operand_list(i.clone());
    match preparse {
        Result::Fail(e) => {
            let err = Error::caused_by(
                "Failed while parsing operator expression",
                Box::new(e),
                Box::new(i),
            );
            Result::Fail(err)
        }
        Result::Abort(e) => {
            let err = Error::caused_by(
                "Failed while parsing operator expression",
                Box::new(e),
                Box::new(i),
            );
            Result::Fail(err)
        }
        Result::Incomplete(i) => Result::Incomplete(i),
        Result::Complete(rest, oplist) => {
            let i_ = SliceIter::new(&oplist);
            let parse_result = either!(
                i_.clone(),
                trace_parse!(compare_expression),
                trace_parse!(math_expression)
            );

            match parse_result {
                Result::Fail(_e) => {
                    // TODO(jwall): It would be good to be able to use caused_by here.
                    let err = Error::new(
                        "Failed while parsing operator expression",
                        Box::new(rest.clone()),
                    );
                    Result::Fail(err)
                }
                Result::Abort(_e) => {
                    let err = Error::new(
                        "Failed while parsing operator expression",
                        Box::new(rest.clone()),
                    );
                    Result::Abort(err)
                }
                Result::Incomplete(_) => Result::Incomplete(i.clone()),
                Result::Complete(_, expr) => Result::Complete(rest.clone(), expr),
            }
        }
    }
}
<commit_msg>MAINT: formatting using cargo fmt.<commit_after>// Copyright 2017 Jeremy Wall <jeremy@marzhillstudios.com>
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.

//! Bottom up parser for precedence parsing of expressions separated by binary
//! operators.
use abortable_parser::combinators::eoi;
use abortable_parser::{Error, Result, SliceIter};

use super::{non_op_expression, NomResult};
use crate::ast::*;

/// Defines the intermediate stages of our bottom up parser for precedence parsing.
#[derive(Debug, PartialEq, Clone)]
pub enum Element {
    Expr(Expression),
    MathOp(BinaryExprType),
    CompareOp(CompareType),
}

make_fn!(
    math_op_type<SliceIter<Token>, Element>,
    either!(
        do_each!(
            _ => punct!("+"),
            (Element::MathOp(BinaryExprType::Add))),
        do_each!(
            _ => punct!("-"),
            (Element::MathOp(BinaryExprType::Sub))),
        do_each!(
            _ => punct!("*"),
            (Element::MathOp(BinaryExprType::Mul))),
        do_each!(
            _ => punct!("/"),
            (Element::MathOp(BinaryExprType::Div)))
    )
);

fn parse_expression(i: SliceIter<Element>) -> Result<SliceIter<Element>, Expression> {
    let mut i_ = i.clone();
    if eoi(i_.clone()).is_complete() {
        return Result::Abort(Error::new(
            "Expected Expression found End Of Input",
            Box::new(i_),
        ));
    }
    let el = i_.next();
    if let Some(&Element::Expr(ref expr)) = el {
        return Result::Complete(i_.clone(), expr.clone());
    }
    return Result::Fail(Error::new(
        format!(
            "Error while parsing Binary Expression Expected Expression got {:?}",
            el
        ),
        Box::new(i_),
    ));
}

fn parse_sum_operator(i: SliceIter<Element>) -> Result<SliceIter<Element>, BinaryExprType> {
    let mut i_ = i.clone();
    if eoi(i_.clone()).is_complete() {
        return Result::Fail(Error::new(
            format!("Expected Expression found End Of Input"),
            Box::new(i_),
        ));
    }
    let el = i_.next();
    if let Some(&Element::MathOp(ref op)) = el {
        match op {
            &BinaryExprType::Add => {
                return Result::Complete(i_.clone(), op.clone());
            }
            &BinaryExprType::Sub => {
                return Result::Complete(i_.clone(), op.clone());
            }
            _other => {
                // noop
            }
        };
    }
    return Result::Fail(Error::new(
        format!(
            "Error while parsing Binary Expression Unexpected Operator {:?}",
            el
        ),
        Box::new(i_),
    ));
}

fn tuple_to_binary_expression(
    kind: BinaryExprType,
    left: Expression,
    right: Expression,
) -> Expression {
    let pos = left.pos().clone();
    Expression::Binary(BinaryOpDef {
        kind: kind,
        left: Box::new(left),
        right: Box::new(right),
        pos: pos,
    })
}

fn parse_product_operator(i: SliceIter<Element>) -> Result<SliceIter<Element>, BinaryExprType> {
    let mut i_ = i.clone();
    if eoi(i_.clone()).is_complete() {
        return Result::Fail(Error::new(
            format!("Expected Expression found End Of Input"),
            Box::new(i_),
        ));
    }
    let el = i_.next();
    if let Some(&Element::MathOp(ref op)) = el {
        match op {
            &BinaryExprType::Mul => {
                return Result::Complete(i_.clone(), op.clone());
            }
            &BinaryExprType::Div => {
                return Result::Complete(i_.clone(), op.clone());
            }
            _other => {
                // noop
            }
        };
    }
    return Result::Fail(Error::new(
        format!(
            "Error while parsing Binary Expression Unexpected Operator {:?}",
            el
        ),
        Box::new(i_),
    ));
}

/// do_binary_expr implements precedence based parsing where the more tightly bound
/// parsers are passed in as lowerrule parsers. We default to any non_op_expression
/// as the most tightly bound expressions.
macro_rules! do_binary_expr {
    ($i:expr, $oprule:ident, $lowerrule:ident) => {
        do_binary_expr!($i, run!($oprule), $lowerrule)
    };

    ($i:expr, $oprule:ident, $lowerrule:ident!( $($lowerargs:tt)* )) => {
        do_binary_expr!($i, run!($oprule), $lowerrule!($($lowerargs)*))
    };

    ($i:expr, $oprule:ident) => {
        do_binary_expr!($i, run!($oprule))
    };

    ($i:expr, $oprule:ident!( $($args:tt)* )) => {
        do_binary_expr!($i, $oprule!($($args)*), parse_expression)
    };

    ($i:expr, $oprule:ident!( $($args:tt)* ), $lowerrule:ident) => {
        do_binary_expr!($i, $oprule!($($args)*), run!($lowerrule))
    };

    ($i:expr, $oprule:ident!( $($args:tt)* ), $lowerrule:ident!( $($lowerargs:tt)* )) => {
        do_each!($i,
            left => $lowerrule!($($lowerargs)*),
                typ => $oprule!($($args)*),
                right => $lowerrule!($($lowerargs)*),
                (tuple_to_binary_expression(typ, left, right))
        )
    };
}

make_fn!(
    sum_expression<SliceIter<Element>, Expression>,
    do_binary_expr!(
        parse_sum_operator,
        either!(
            trace_parse!(product_expression),
            trace_parse!(parse_expression)
        )
    )
);

make_fn!(
    product_expression<SliceIter<Element>, Expression>,
    do_binary_expr!(parse_product_operator, trace_parse!(parse_expression))
);

make_fn!(
    math_expression<SliceIter<Element>, Expression>,
    either!(
        trace_parse!(sum_expression),
        trace_parse!(product_expression)
    )
);

// TODO(jwall): Change comparison operators to use the do_binary_expr! with precedence?
fn tuple_to_compare_expression(
    kind: CompareType,
    left: Expression,
    right: Expression,
) -> Expression {
    let pos = left.pos().clone();
    Expression::Compare(ComparisonDef {
        kind: kind,
        left: Box::new(left),
        right: Box::new(right),
        pos: pos,
    })
}

make_fn!(
    compare_op_type<SliceIter<Token>, Element>,
    either!(
        do_each!(_ => punct!("=="), (Element::CompareOp(CompareType::Equal))),
        do_each!(_ => punct!("!="), (Element::CompareOp(CompareType::NotEqual))),
        do_each!(_ => punct!("<="), (Element::CompareOp(CompareType::LTEqual))),
        do_each!(_ => punct!(">="), (Element::CompareOp(CompareType::GTEqual))),
        do_each!(_ => punct!("<"),  (Element::CompareOp(CompareType::LT))),
        do_each!(_ => punct!(">"),  (Element::CompareOp(CompareType::GT)))
    )
);

fn parse_compare_operator(i: SliceIter<Element>) -> Result<SliceIter<Element>, CompareType> {
    let mut i_ = i.clone();
    if eoi(i_.clone()).is_complete() {
        return Result::Fail(Error::new(
            format!("Expected Expression found End Of Input"),
            Box::new(i_),
        ));
    }
    let el = i_.next();
    if let Some(&Element::CompareOp(ref op)) = el {
        return Result::Complete(i_.clone(), op.clone());
    }
    return Result::Fail(Error::new(
        format!(
            "Error while parsing Binary Expression Unexpected Operator {:?}",
            el
        ),
        Box::new(i),
    ));
}

make_fn!(
    compare_expression<SliceIter<Element>, Expression>,
    do_each!(
        left => either!(trace_parse!(math_expression), trace_parse!(parse_expression)),
        typ => parse_compare_operator,
        right => either!(trace_parse!(math_expression), trace_parse!(parse_expression)),
        (tuple_to_compare_expression(typ, left, right))
    )
);

/// Parse a list of expressions separated by operators into a Vec<Element>.
fn parse_operand_list<'a>(i: SliceIter<'a, Token>) -> NomResult<'a, Vec<Element>> {
    // 1. First try to parse a non_op_expression,
    let mut _i = i.clone();
    let mut list = Vec::new();
    // 1. loop
    let mut firstrun = true;
    loop {
        // 2. Parse a non_op_expression.
        match non_op_expression(_i.clone()) {
            Result::Fail(e) => {
                // A failure to parse an expression
                // is always an error.
                return Result::Fail(e);
            }
            Result::Abort(e) => {
                // A failure to parse an expression
                // is always an error.
                return Result::Abort(e);
            }
            Result::Incomplete(i) => {
                return Result::Incomplete(i);
            }
            Result::Complete(rest, expr) => {
                list.push(Element::Expr(expr));
                _i = rest.clone();
            }
        }
        // 3. Parse an operator.
        match either!(_i.clone(), math_op_type, compare_op_type) {
            Result::Fail(e) => {
                if firstrun {
                    // If we don't find an operator in our first
                    // run then this is not an operand list.
                    return Result::Fail(e);
                }
                // if we don't find one on subsequent runs then
                // that's the end of the operand list.
                break;
            }
            Result::Abort(e) => {
                // A failure to parse an expression
                // is always an error.
                return Result::Abort(e);
            }
            Result::Incomplete(i) => {
                return Result::Incomplete(i);
            }
            Result::Complete(rest, el) => {
                list.push(el);
                _i = rest.clone();
            }
        }
        firstrun = false;
    }
    return Result::Complete(_i, list);
}

/// Parse a binary operator expression.
pub fn op_expression<'a>(i: SliceIter<'a, Token>) -> Result<SliceIter<Token>, Expression> {
    let preparse = parse_operand_list(i.clone());
    match preparse {
        Result::Fail(e) => {
            let err = Error::caused_by(
                "Failed while parsing operator expression",
                Box::new(e),
                Box::new(i),
            );
            Result::Fail(err)
        }
        Result::Abort(e) => {
            let err = Error::caused_by(
                "Failed while parsing operator expression",
                Box::new(e),
                Box::new(i),
            );
            Result::Fail(err)
        }
        Result::Incomplete(i) => Result::Incomplete(i),
        Result::Complete(rest, oplist) => {
            let i_ = SliceIter::new(&oplist);
            let parse_result = either!(
                i_.clone(),
                trace_parse!(compare_expression),
                trace_parse!(math_expression)
            );

            match parse_result {
                Result::Fail(_e) => {
                    // TODO(jwall): It would be good to be able to use caused_by here.
                    let err = Error::new(
                        "Failed while parsing operator expression",
                        Box::new(rest.clone()),
                    );
                    Result::Fail(err)
                }
                Result::Abort(_e) => {
                    let err = Error::new(
                        "Failed while parsing operator expression",
                        Box::new(rest.clone()),
                    );
                    Result::Abort(err)
                }
                Result::Incomplete(_) => Result::Incomplete(i.clone()),
                Result::Complete(_, expr) => Result::Complete(rest.clone(), expr),
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Pattern-sequence data structures and implementations.

use std::ops::Index;
use std::iter::FromIterator;

use util::set::{self, Contains};
use super::{Atom, Class, Element, Repetition, Union};
use super::{Reduce, flatten_and_reduce};

// To hide the implementation details, we wrap the type alias in
// a private submodule.
mod seq_impl {
    use ::pattern::Element;
    pub type Inner<T> = Vec<Element<T>>;
}

/// Sequence of patterns.
#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord)]
pub struct Sequence<T: Atom>(seq_impl::Inner<T>);

impl<T: Atom> Sequence<T> {
    /// Create a new sequence from the given vector.
    ///
    /// This method will **panic** if the given vector is not at least two
    /// elements long.
    pub fn new(v: Vec<Element<T>>) -> Self {
        if v.len() < 2 {
            panic!("Sequences must have at least two elements");
        }
        Sequence(v)
    }

    /// Get the number of elements in the sequence.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Fetch an iterator over the elements in the sequence
    pub fn iter<'a>(&'a self) -> impl Iterator<Item=&'a Element<T>> {
        self.0.iter()
    }

    fn into_inner(self) -> seq_impl::Inner<T> {
        self.0
    }

    /// Transforms each contained atom using the supplied function or closure
    /// to produce a new sequence.
    pub fn map_atoms<U, F>(self, f: F) -> Sequence<U>
        where F: Fn(T) -> U,
              U: Atom
    {
        self.0.into_iter().map(|elt| elt.map_atoms(&f)).collect()
    }
}

impl<T: Atom> Reduce for Sequence<T> {
    type Output = Option<Element<T>>;

    /// Flatten the sequence and apply implementation-defined optimizations.
    fn reduce(mut self) -> Self::Output {
        // Flatten and reduce the vector *first* so we can reduce `self` based
        // on the size of the *reduced* vector.
       flatten_and_reduce(&mut self.0, Element::Wildcard,
                           |elt| match elt { &Element::Sequence(ref s) => Some(s.len()), _ => None },
                           |elt| match elt { Element::Sequence(s) => s.into_inner(), _ => unreachable!() });
        match self.0.len() {
            0 => None,
            1 => Some(self.0.swap_remove(0)),
            _ => Some(Element::Sequence(self))
        }
    }
}

impl<T: Atom> Index<usize> for Sequence<T> {
    type Output = Element<T>;
    fn index(&self, index: usize) -> &Self::Output {
        &self.0[index]
    }

}

impl<T: Atom> FromIterator<Element<T>> for Sequence<T> {
    fn from_iter<I>(iter: I) -> Self
        where I: IntoIterator<Item=Element<T>>
    {
        Sequence(iter.into_iter().collect())
    }
}

impl<T: Atom> set::Contains<T> for Sequence<T> {
    /// A sequence always contains at least two elements, and thus will never
    /// match a single atom.
    #[inline(always)]
    fn contains(&self, _: T) -> bool {
        false
    }
}

impl<T: Atom> set::IsSubsetOf<T> for Sequence<T> {
    /// A sequence is a subset of a particular atom whenever the sequence has
    /// length one, and the first element is a subset of that atom.
    #[inline(always)]
    fn is_subset_of(&self, atom: &T) -> bool {
        self.len() == 1 && self[0].is_subset_of(atom)
    }
}

// A sequence `A` can be a subset of another sequence `B` *if* both have the
// same length and each element in `A` is a subset of the corresponding element
// in `B`:
//
// A ⊂ B ⇔ |A|=|B|=n ∧ Aᵢ ⊂ Bᵢ ∀ i∈[0,n]
impl<T: Atom> set::IsSubsetOf<Sequence<T>> for Sequence<T> {
    fn is_subset_of(&self, other: &Sequence<T>) -> bool {
        other.len() == self.len() &&
            self.iter().zip(other.iter()).all(|(u, v)| u.is_subset_of(v))
    }
}

impl<T: Atom> set::IsSubsetOf<Class<T>> for Sequence<T> {
    /// A sequence is never a subset of an atom class because sequences are
    /// guaranteed to contain at least two elements.
    #[inline(always)]
    fn is_subset_of(&self, _: &Class<T>) -> bool {
        false
    }
}

impl<T: Atom> set::IsSubsetOf<Union<T>> for Sequence<T> {
    /// A sequence is a subset of a union whenever it is a subset of one of the
    /// union's members.
    fn is_subset_of(&self, union: &Union<T>) -> bool {
        union.iter().any(|m| self.is_subset_of(m))
    }
}

impl<T: Atom> set::IsSubsetOf<Repetition<T>> for Sequence<T> {
    /// A sequence is a subset of a repetition if the sequence's length is
    /// contained by the repetition's count and all members of the sequence are
    /// subsets of the repeated element.
    fn is_subset_of(&self, rep: &Repetition<T>) -> bool {
        rep.count().contains(self.len()) && self.iter().all(|elt| elt.is_subset_of(rep.element()))
    }
}

impl<T: Atom> set::IsSubsetOf<Element<T>> for Sequence<T> {
    fn is_subset_of(&self, elt: &Element<T>) -> bool {
        match elt {
            &Element::Tagged{ref element, ..} => self.is_subset_of(&**element),
            &Element::Sequence(ref s) => self.is_subset_of(s),
            &Element::Union(ref u) => self.is_subset_of(u),
            &Element::Repeat(ref r) => self.is_subset_of(r),

            &Element::Anchor(_) => false,
            &Element::Atom(_) => false,
            &Element::Class(_) => false,
            &Element::Wildcard => false,
        }
    }
}
<commit_msg>pattern/sequence: make comment for `IsSubsetOf<Sequence>` a doc comment<commit_after>//! Pattern-sequence data structures and implementations.

use std::ops::Index;
use std::iter::FromIterator;

use util::set::{self, Contains};
use super::{Atom, Class, Element, Repetition, Union};
use super::{Reduce, flatten_and_reduce};

// To hide the implementation details, we wrap the type alias in
// a private submodule.
mod seq_impl {
    use ::pattern::Element;
    pub type Inner<T> = Vec<Element<T>>;
}

/// Sequence of patterns.
#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord)]
pub struct Sequence<T: Atom>(seq_impl::Inner<T>);

impl<T: Atom> Sequence<T> {
    /// Create a new sequence from the given vector.
    ///
    /// This method will **panic** if the given vector is not at least two
    /// elements long.
    pub fn new(v: Vec<Element<T>>) -> Self {
        if v.len() < 2 {
            panic!("Sequences must have at least two elements");
        }
        Sequence(v)
    }

    /// Get the number of elements in the sequence.
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Fetch an iterator over the elements in the sequence
    pub fn iter<'a>(&'a self) -> impl Iterator<Item=&'a Element<T>> {
        self.0.iter()
    }

    fn into_inner(self) -> seq_impl::Inner<T> {
        self.0
    }

    /// Transforms each contained atom using the supplied function or closure
    /// to produce a new sequence.
    pub fn map_atoms<U, F>(self, f: F) -> Sequence<U>
        where F: Fn(T) -> U,
              U: Atom
    {
        self.0.into_iter().map(|elt| elt.map_atoms(&f)).collect()
    }
}

impl<T: Atom> Reduce for Sequence<T> {
    type Output = Option<Element<T>>;

    /// Flatten the sequence and apply implementation-defined optimizations.
    fn reduce(mut self) -> Self::Output {
        // Flatten and reduce the vector *first* so we can reduce `self` based
        // on the size of the *reduced* vector.
       flatten_and_reduce(&mut self.0, Element::Wildcard,
                           |elt| match elt { &Element::Sequence(ref s) => Some(s.len()), _ => None },
                           |elt| match elt { Element::Sequence(s) => s.into_inner(), _ => unreachable!() });
        match self.0.len() {
            0 => None,
            1 => Some(self.0.swap_remove(0)),
            _ => Some(Element::Sequence(self))
        }
    }
}

impl<T: Atom> Index<usize> for Sequence<T> {
    type Output = Element<T>;
    fn index(&self, index: usize) -> &Self::Output {
        &self.0[index]
    }

}

impl<T: Atom> FromIterator<Element<T>> for Sequence<T> {
    fn from_iter<I>(iter: I) -> Self
        where I: IntoIterator<Item=Element<T>>
    {
        Sequence(iter.into_iter().collect())
    }
}

impl<T: Atom> set::Contains<T> for Sequence<T> {
    /// A sequence always contains at least two elements, and thus will never
    /// match a single atom.
    #[inline(always)]
    fn contains(&self, _: T) -> bool {
        false
    }
}

impl<T: Atom> set::IsSubsetOf<T> for Sequence<T> {
    /// A sequence is a subset of a particular atom whenever the sequence has
    /// length one, and the first element is a subset of that atom.
    #[inline(always)]
    fn is_subset_of(&self, atom: &T) -> bool {
        self.len() == 1 && self[0].is_subset_of(atom)
    }
}

impl<T: Atom> set::IsSubsetOf<Sequence<T>> for Sequence<T> {
    /// A sequence `A` can be a subset of another sequence `B` *if* both have the
    /// same length and each element in `A` is a subset of the corresponding element
    /// in `B`:
    ///
    /// A ⊂ B ⇔ |A|=|B|=n ∧ Aᵢ ⊂ Bᵢ ∀ i∈[0,n]
    fn is_subset_of(&self, other: &Sequence<T>) -> bool {
        other.len() == self.len() &&
            self.iter().zip(other.iter()).all(|(u, v)| u.is_subset_of(v))
    }
}

impl<T: Atom> set::IsSubsetOf<Class<T>> for Sequence<T> {
    /// A sequence is never a subset of an atom class because sequences are
    /// guaranteed to contain at least two elements.
    #[inline(always)]
    fn is_subset_of(&self, _: &Class<T>) -> bool {
        false
    }
}

impl<T: Atom> set::IsSubsetOf<Union<T>> for Sequence<T> {
    /// A sequence is a subset of a union whenever it is a subset of one of the
    /// union's members.
    fn is_subset_of(&self, union: &Union<T>) -> bool {
        union.iter().any(|m| self.is_subset_of(m))
    }
}

impl<T: Atom> set::IsSubsetOf<Repetition<T>> for Sequence<T> {
    /// A sequence is a subset of a repetition if the sequence's length is
    /// contained by the repetition's count and all members of the sequence are
    /// subsets of the repeated element.
    fn is_subset_of(&self, rep: &Repetition<T>) -> bool {
        rep.count().contains(self.len()) && self.iter().all(|elt| elt.is_subset_of(rep.element()))
    }
}

impl<T: Atom> set::IsSubsetOf<Element<T>> for Sequence<T> {
    fn is_subset_of(&self, elt: &Element<T>) -> bool {
        match elt {
            &Element::Tagged{ref element, ..} => self.is_subset_of(&**element),
            &Element::Sequence(ref s) => self.is_subset_of(s),
            &Element::Union(ref u) => self.is_subset_of(u),
            &Element::Repeat(ref r) => self.is_subset_of(r),

            &Element::Anchor(_) => false,
            &Element::Atom(_) => false,
            &Element::Class(_) => false,
            &Element::Wildcard => false,
        }
    }
}
<|endoftext|>


<commit_before>use std::sync::Mutex;

use prelude::*;
use jack_utils::*;

#[derive(Debug, Default)]
pub struct Counter {
    pub process_return_val: JackControl,
    pub induce_xruns: bool,
    pub thread_init_count: Mutex<usize>,
    pub frames_processed: Mutex<usize>,
    pub buffer_size_change_history: Mutex<Vec<JackFrames>>,
    pub registered_client_history: Mutex<Vec<String>>,
    pub unregistered_client_history: Mutex<Vec<String>>,
    pub port_register_history: Mutex<Vec<JackPortId>>,
    pub port_unregister_history: Mutex<Vec<JackPortId>>,
    pub xruns_count: Mutex<usize>,
}

impl JackHandler for Counter {
    fn thread_init(&self) {
        *self.thread_init_count.lock().unwrap() += 1;
    }

    fn process(&self, ps: &ProcessScope) -> JackControl {
        *self.frames_processed.lock().unwrap() += ps.n_frames() as usize;
        if self.induce_xruns {
            default_sleep();
        }
        JackControl::Continue
    }

    fn buffer_size(&self, size: JackFrames) -> JackControl {
        self.buffer_size_change_history.lock().unwrap().push(size);
        JackControl::Continue
    }

    fn client_registration(&self, name: &str, is_registered: bool) {
        match is_registered {
            true => self.registered_client_history.lock().unwrap().push(name.to_string()),
            false => self.unregistered_client_history.lock().unwrap().push(name.to_string()),
        }
    }

    fn port_registration(&self, pid: JackPortId, is_registered: bool) {
        match is_registered {
            true => self.port_register_history.lock().unwrap().push(pid),
            false => self.port_unregister_history.lock().unwrap().push(pid),
        }
    }

    fn xrun(&self) -> JackControl {
        *self.xruns_count.lock().unwrap() += 1;
        JackControl::Continue
    }
}

fn open_test_client(name: &str) -> Client {
    default_sleep();
    Client::open(name, client_options::NO_START_SERVER).unwrap().0
}

fn active_test_client(name: &str) -> (ActiveClient<Counter>) {
    let c = open_test_client(name);
    let ac = c.activate(Counter::default()).unwrap();
    default_longer_sleep();
    ac
}

#[test]
fn client_cback_calls_thread_init() {
    let ac = active_test_client("client_cback_calls_thread_init");
    let counter = ac.deactivate().unwrap().1;
    // IDK why this isn't 1.
    assert!(*counter.thread_init_count.lock().unwrap() > 0);
}

#[test]
fn client_cback_calls_process() {
    let ac = active_test_client("client_cback_calls_process");
    let counter = ac.deactivate().unwrap().1;
    assert!(*counter.frames_processed.lock().unwrap() > 0);
}

#[test]
fn client_cback_calls_buffer_size() {
    let ac = active_test_client("client_cback_calls_process");
    let initial = ac.buffer_size();
    let second = initial / 2;
    let third = second / 2;
    ac.set_buffer_size(second).unwrap();
    ac.set_buffer_size(third).unwrap();
    ac.set_buffer_size(initial).unwrap();
    let counter = ac.deactivate().unwrap().1;
    assert_eq!(*counter.buffer_size_change_history.lock().unwrap(),
               vec![initial, second, third, initial]);
}

#[test]
fn client_cback_calls_after_client_registered() {
    let ac = active_test_client("client_cback_cacr");
    default_longer_sleep();
    let _other_client = open_test_client("client_cback_cacr_other");
    let counter = ac.deactivate().unwrap().1;
    assert_eq!(*counter.registered_client_history.lock().unwrap(),
               vec!["client_cback_cacr_other"]);
    assert!(counter.unregistered_client_history.lock().unwrap().is_empty());
}

#[test]
fn client_cback_calls_after_client_unregistered() {
    let ac = active_test_client("client_cback_cacu");
    default_longer_sleep();
    let other_client = open_test_client("client_cback_cacu_other");
    drop(other_client);
    let counter = ac.deactivate().unwrap().1;
    assert_eq!(*counter.registered_client_history.lock().unwrap(),
               vec!["client_cback_cacu_other"],
               "wrong clients detected as registered");
    assert_eq!(*counter.unregistered_client_history.lock().unwrap(),
               vec!["client_cback_cacu_other"],
               "wrong clients detected as unregistered");
}

#[test]
fn client_cback_doesnt_call_port_registered_when_no_ports() {
    let ac = active_test_client("client_cback_dcprwnp");
    let counter = ac.deactivate().unwrap().1;
    assert!(counter.port_register_history.lock().unwrap().is_empty());
    assert!(counter.port_unregister_history.lock().unwrap().is_empty());
}

#[test]
fn client_cback_reports_xruns() {
    let c = open_test_client("client_cback_reports_xruns");
    let mut counter = Counter::default();
    counter.induce_xruns = true;
    let ac = c.activate(counter).unwrap();
    default_longer_sleep();
    let counter = ac.deactivate().unwrap().1;
    assert!(*counter.xruns_count.lock().unwrap() > 0,
            "No xruns encountered.");
}

#[test]
fn client_cback_calls_port_registered() {
    let mut ac = active_test_client("client_cback_cpr");
    let _pa = ac.register_port("pa", AudioInSpec::default()).unwrap();
    let _pb = ac.register_port("pb", AudioInSpec::default()).unwrap();
    default_sleep();
    let counter = ac.deactivate().unwrap().1;
    assert_eq!(counter.port_register_history.lock().unwrap().len(),
               2,
               "Did not detect port registrations.");
    assert!(counter.port_unregister_history.lock().unwrap().is_empty(),
            "Detected false port deregistrations.");
}

#[test]
fn client_cback_calls_port_unregistered() {
    let mut ac = active_test_client("client_cback_cpr");
    let _pa = ac.register_port("pa", AudioInSpec::default()).unwrap();
    let _pb = ac.register_port("pb", AudioInSpec::default()).unwrap();
    default_sleep();
    _pa.unregister().unwrap();
    _pb.unregister().unwrap();
    default_sleep();
    let counter = ac.deactivate().unwrap().1;
    assert_eq!(counter.port_register_history.lock().unwrap().len(),
               2,
               "Did not detect port registrations.");
    assert_eq!(counter.port_unregister_history.lock().unwrap().len(),
               2,
               "Did not detect port deregistrations.");
}
<commit_msg>delay to make test less flaky<commit_after>use std::sync::Mutex;

use prelude::*;
use jack_utils::*;

#[derive(Debug, Default)]
pub struct Counter {
    pub process_return_val: JackControl,
    pub induce_xruns: bool,
    pub thread_init_count: Mutex<usize>,
    pub frames_processed: Mutex<usize>,
    pub buffer_size_change_history: Mutex<Vec<JackFrames>>,
    pub registered_client_history: Mutex<Vec<String>>,
    pub unregistered_client_history: Mutex<Vec<String>>,
    pub port_register_history: Mutex<Vec<JackPortId>>,
    pub port_unregister_history: Mutex<Vec<JackPortId>>,
    pub xruns_count: Mutex<usize>,
}

impl JackHandler for Counter {
    fn thread_init(&self) {
        *self.thread_init_count.lock().unwrap() += 1;
    }

    fn process(&self, ps: &ProcessScope) -> JackControl {
        *self.frames_processed.lock().unwrap() += ps.n_frames() as usize;
        if self.induce_xruns {
            default_sleep();
        }
        JackControl::Continue
    }

    fn buffer_size(&self, size: JackFrames) -> JackControl {
        self.buffer_size_change_history.lock().unwrap().push(size);
        JackControl::Continue
    }

    fn client_registration(&self, name: &str, is_registered: bool) {
        match is_registered {
            true => self.registered_client_history.lock().unwrap().push(name.to_string()),
            false => self.unregistered_client_history.lock().unwrap().push(name.to_string()),
        }
    }

    fn port_registration(&self, pid: JackPortId, is_registered: bool) {
        match is_registered {
            true => self.port_register_history.lock().unwrap().push(pid),
            false => self.port_unregister_history.lock().unwrap().push(pid),
        }
    }

    fn xrun(&self) -> JackControl {
        *self.xruns_count.lock().unwrap() += 1;
        JackControl::Continue
    }
}

fn open_test_client(name: &str) -> Client {
    default_sleep();
    Client::open(name, client_options::NO_START_SERVER).unwrap().0
}

fn active_test_client(name: &str) -> (ActiveClient<Counter>) {
    let c = open_test_client(name);
    let ac = c.activate(Counter::default()).unwrap();
    default_longer_sleep();
    ac
}

#[test]
fn client_cback_calls_thread_init() {
    let ac = active_test_client("client_cback_calls_thread_init");
    let counter = ac.deactivate().unwrap().1;
    // IDK why this isn't 1.
    assert!(*counter.thread_init_count.lock().unwrap() > 0);
}

#[test]
fn client_cback_calls_process() {
    let ac = active_test_client("client_cback_calls_process");
    let counter = ac.deactivate().unwrap().1;
    assert!(*counter.frames_processed.lock().unwrap() > 0);
}

#[test]
fn client_cback_calls_buffer_size() {
    let ac = active_test_client("client_cback_calls_process");
    let initial = ac.buffer_size();
    let second = initial / 2;
    let third = second / 2;
    ac.set_buffer_size(second).unwrap();
    ac.set_buffer_size(third).unwrap();
    ac.set_buffer_size(initial).unwrap();
    let counter = ac.deactivate().unwrap().1;
    assert_eq!(*counter.buffer_size_change_history.lock().unwrap(),
               vec![initial, second, third, initial]);
}

#[test]
fn client_cback_calls_after_client_registered() {
    let ac = active_test_client("client_cback_cacr");
    default_longer_sleep();
    let _other_client = open_test_client("client_cback_cacr_other");
    let counter = ac.deactivate().unwrap().1;
    assert_eq!(*counter.registered_client_history.lock().unwrap(),
               vec!["client_cback_cacr_other"]);
    assert!(counter.unregistered_client_history.lock().unwrap().is_empty());
}

#[test]
fn client_cback_calls_after_client_unregistered() {
    let ac = active_test_client("client_cback_cacu");
    default_longer_sleep();
    let other_client = open_test_client("client_cback_cacu_other");
    drop(other_client);
    default_longer_sleep();
    let counter = ac.deactivate().unwrap().1;
    assert_eq!(*counter.registered_client_history.lock().unwrap(),
               vec!["client_cback_cacu_other"],
               "wrong clients detected as registered");
    assert_eq!(*counter.unregistered_client_history.lock().unwrap(),
               vec!["client_cback_cacu_other"],
               "wrong clients detected as unregistered");
}

#[test]
fn client_cback_doesnt_call_port_registered_when_no_ports() {
    let ac = active_test_client("client_cback_dcprwnp");
    let counter = ac.deactivate().unwrap().1;
    assert!(counter.port_register_history.lock().unwrap().is_empty());
    assert!(counter.port_unregister_history.lock().unwrap().is_empty());
}

#[test]
fn client_cback_reports_xruns() {
    let c = open_test_client("client_cback_reports_xruns");
    let mut counter = Counter::default();
    counter.induce_xruns = true;
    let ac = c.activate(counter).unwrap();
    default_longer_sleep();
    let counter = ac.deactivate().unwrap().1;
    assert!(*counter.xruns_count.lock().unwrap() > 0,
            "No xruns encountered.");
}

#[test]
fn client_cback_calls_port_registered() {
    let mut ac = active_test_client("client_cback_cpr");
    let _pa = ac.register_port("pa", AudioInSpec::default()).unwrap();
    let _pb = ac.register_port("pb", AudioInSpec::default()).unwrap();
    default_sleep();
    let counter = ac.deactivate().unwrap().1;
    assert_eq!(counter.port_register_history.lock().unwrap().len(),
               2,
               "Did not detect port registrations.");
    assert!(counter.port_unregister_history.lock().unwrap().is_empty(),
            "Detected false port deregistrations.");
}

#[test]
fn client_cback_calls_port_unregistered() {
    let mut ac = active_test_client("client_cback_cpr");
    let _pa = ac.register_port("pa", AudioInSpec::default()).unwrap();
    let _pb = ac.register_port("pb", AudioInSpec::default()).unwrap();
    default_sleep();
    _pa.unregister().unwrap();
    _pb.unregister().unwrap();
    default_sleep();
    let counter = ac.deactivate().unwrap().1;
    assert_eq!(counter.port_register_history.lock().unwrap().len(),
               2,
               "Did not detect port registrations.");
    assert_eq!(counter.port_unregister_history.lock().unwrap().len(),
               2,
               "Did not detect port deregistrations.");
}
<|endoftext|>


<commit_before>// run-pass
// Ignore this test on Android, because it segfaults there.

// ignore-android
// ignore-windows
// ignore-cloudabi no execve
// ignore-emscripten no execve
// ignore-sgx no execve
// no-prefer-dynamic

#![feature(rustc_private)]

extern crate libc;

use libc::c_char;
use libc::execve;
use std::env;
use std::ffi::CString;
use std::os::unix::prelude::*;
use std::ptr;

fn main() {
    if env::args_os().count() == 2 {
        for (key, value) in env::vars_os() {
            panic!("found env value {:?} {:?}", key, value);
        }
        return;
    }

    let current_exe = CString::new(env::current_exe()
                                       .unwrap()
                                       .as_os_str()
                                       .as_bytes()).unwrap();
    let new_env_var = CString::new("FOOBAR").unwrap();
    let filename: *const c_char = current_exe.as_ptr();
    let argv: &[*const c_char] = &[filename, filename, ptr::null()];
    let envp: &[*const c_char] = &[new_env_var.as_ptr(), ptr::null()];
    unsafe {
        execve(filename, &argv[0], &envp[0]);
    }
    panic!("execve failed");
}
<commit_msg>Rollup merge of #68575 - Wind-River:master_2020, r=alexcrichton<commit_after>// run-pass
// Ignore this test on Android, because it segfaults there.

// ignore-android
// ignore-windows
// ignore-cloudabi no execve
// ignore-emscripten no execve
// ignore-sgx no execve
// ignore-vxworks no execve
// no-prefer-dynamic

#![feature(rustc_private)]

extern crate libc;

use libc::c_char;
use libc::execve;
use std::env;
use std::ffi::CString;
use std::os::unix::prelude::*;
use std::ptr;

fn main() {
    if env::args_os().count() == 2 {
        for (key, value) in env::vars_os() {
            panic!("found env value {:?} {:?}", key, value);
        }
        return;
    }

    let current_exe = CString::new(env::current_exe()
                                       .unwrap()
                                       .as_os_str()
                                       .as_bytes()).unwrap();
    let new_env_var = CString::new("FOOBAR").unwrap();
    let filename: *const c_char = current_exe.as_ptr();
    let argv: &[*const c_char] = &[filename, filename, ptr::null()];
    let envp: &[*const c_char] = &[new_env_var.as_ptr(), ptr::null()];
    unsafe {
        execve(filename, &argv[0], &envp[0]);
    }
    panic!("execve failed");
}
<|endoftext|>


<commit_before>use std::path::Path;
use std::path::PathBuf;
use std::env;
use std::process::Command;

fn main() {
    let out_dir = env::var("OUT_DIR").unwrap();
    let target = env::var("TARGET").unwrap();

    // http://doc.crates.io/build-script.html#inputs-to-the-build-script
    // "the build script’s current directory is the source directory of the build script’s package."
    let current_dir = env::current_dir().unwrap();
    let src_dir = current_dir.join("src");

    let home_dir = env::home_dir().map(|p| PathBuf::from(p)).unwrap();

    let qt_dir = env::var("QT_DIR").map(|p| PathBuf::from(p)).unwrap_or({
        println!("Environnement variable 'QT_DIR' not set!");
        println!("Defaulting to ${{HOME}}/Qt/${{QT_VER}}/${{QT_COMP}} where:");
        let default_qt_ver = "5.7".to_string();
        let default_qt_comp = if target.contains("linux") {
            "gcc_64".to_string()
        } else if target.contains("darwin") {
            "clang_64".to_string()
        } else {
            panic!("Unsuported platform in gallery's build.rs!")
        };
        println!("    QT_VER:  {}", default_qt_ver);
        println!("    QT_COMP: {}", default_qt_comp);
        let qt_dir_default = home_dir.join("Qt")
                                  .join(env::var("QT_VER").unwrap_or(default_qt_ver))
                                  .join(env::var("QT_COMP").unwrap_or(default_qt_comp));
        qt_dir_default
    });
    println!("Using Qt directory: {:?}", qt_dir);
    println!("Use QT_DIR environment variable to ovewrite.");

    let qmake = qt_dir.join("bin").join("qmake");

    // Run qmake to create a library with the reousrce file
    let output = Command::new(qmake).args(&[src_dir])
                                  .current_dir(&Path::new(&out_dir))
                                  .output()
                                  .expect("failed to execute 'qmake' process");

    println!("output.status: {}", output.status);
    println!("output.stdout: {}", String::from_utf8_lossy(&output.stdout));
    println!("output.stderr: {}", String::from_utf8_lossy(&output.stderr));

    assert!(output.status.success(), "failed to execute qmake process");

    // Call 'make'
    let output = Command::new("make").current_dir(&Path::new(&out_dir))
                                  .output()
                                  .expect("failed to execute 'make' process");

    println!("output.status: {}", output.status);
    println!("output.stdout: {}", String::from_utf8_lossy(&output.stdout));
    println!("output.stderr: {}", String::from_utf8_lossy(&output.stderr));

    assert!(output.status.success(), "failed to execute make process");

    println!("cargo:rustc-link-search={}", out_dir);
    println!("cargo:rustc-link-lib=galleryresources");
}
<commit_msg>Example 'gallery': Move 'home_dir' inside closure as it's not required outside<commit_after>use std::path::Path;
use std::path::PathBuf;
use std::env;
use std::process::Command;

fn main() {
    let out_dir = env::var("OUT_DIR").unwrap();
    let target = env::var("TARGET").unwrap();

    // http://doc.crates.io/build-script.html#inputs-to-the-build-script
    // "the build script’s current directory is the source directory of the build script’s package."
    let current_dir = env::current_dir().unwrap();
    let src_dir = current_dir.join("src");

    let qt_dir = env::var("QT_DIR").map(|p| PathBuf::from(p)).unwrap_or({
        println!("Environnement variable 'QT_DIR' not set!");
        println!("Defaulting to ${{HOME}}/Qt/${{QT_VER}}/${{QT_COMP}} where:");
        let home_dir = env::home_dir().map(|p| PathBuf::from(p)).unwrap();
        let default_qt_ver = "5.7".to_string();
        let default_qt_comp = if target.contains("linux") {
            "gcc_64".to_string()
        } else if target.contains("darwin") {
            "clang_64".to_string()
        } else {
            panic!("Unsuported platform in gallery's build.rs!")
        };
        println!("    QT_VER:  {}", default_qt_ver);
        println!("    QT_COMP: {}", default_qt_comp);
        let qt_dir_default = home_dir.join("Qt")
                                  .join(env::var("QT_VER").unwrap_or(default_qt_ver))
                                  .join(env::var("QT_COMP").unwrap_or(default_qt_comp));
        qt_dir_default
    });
    println!("Using Qt directory: {:?}", qt_dir);
    println!("Use QT_DIR environment variable to ovewrite.");

    let qmake = qt_dir.join("bin").join("qmake");

    // Run qmake to create a library with the reousrce file
    let output = Command::new(qmake).args(&[src_dir])
                                  .current_dir(&Path::new(&out_dir))
                                  .output()
                                  .expect("failed to execute 'qmake' process");

    println!("output.status: {}", output.status);
    println!("output.stdout: {}", String::from_utf8_lossy(&output.stdout));
    println!("output.stderr: {}", String::from_utf8_lossy(&output.stderr));

    assert!(output.status.success(), "failed to execute qmake process");

    // Call 'make'
    let output = Command::new("make").current_dir(&Path::new(&out_dir))
                                  .output()
                                  .expect("failed to execute 'make' process");

    println!("output.status: {}", output.status);
    println!("output.stdout: {}", String::from_utf8_lossy(&output.stdout));
    println!("output.stderr: {}", String::from_utf8_lossy(&output.stderr));

    assert!(output.status.success(), "failed to execute make process");

    println!("cargo:rustc-link-search={}", out_dir);
    println!("cargo:rustc-link-lib=galleryresources");
}
<|endoftext|>


<commit_before>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # Regular language
//!
//! This provides a data structure representing a regular language. This is a more generalised form of a regular
//! expression (it supports symbol types other than simple strings). A regular language using the `u8` symbol forms
//! a simple regular expression.
//!

use super::phrase::*;
<commit_msg>First pass at defining a type representing a pattern in a regular language<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # Regular language
//!
//! This provides a data structure representing a regular language. This is a more generalised form of a regular
//! expression (it supports symbol types other than simple strings). A regular language using the `u8` symbol forms
//! a simple regular expression.
//!

use super::phrase::*;
use std::ops::Range;

///
/// An Pattern represents a matching pattern in a regular language
///
#[derive(Clone)]
pub enum Pattern<Symbol, PhraseType: Phrase<Symbol>> {
    ///
    /// Matches nothing
    ///
    Nothing,

    ///
    /// Matches a single symbol
    ///
    Symbol(Symbol),

    ///
    /// Matches a specific literal phrase
    ///
    Phrase(PhraseType),

    ///
    /// Matches at least a particular number of repetitions of a pattern
    ///
    /// `RepeatInfinite(0, X)` is the equivalent of the regular expression `X*`, `RepeatInfinite(1, X)` is the equivalent of the regular expression `X+`
    ///
    RepeatInfinite(u32, Box<Pattern<Symbol, PhraseType>>),

    ///
    /// Matches a range of repetitions of a pattern
    ///
    Repeat(Range<u32>, Box<Pattern<Symbol, PhraseType>>),

    ///
    /// Matches 0 or 1 instances of a pattern
    ///
    Optional(Box<Pattern<Symbol, PhraseType>>),

    ///
    /// Matches a set of sub-patterns in order
    ///
    And(Vec<Pattern<Symbol, PhraseType>>),

    ///
    /// Matches any one of a set of patterns
    ///
    Or(Vec<Pattern<Symbol, PhraseType>>)
}
<|endoftext|>


<commit_before>use collections::hashmap::HashMap;
use http::headers::content_type::MediaType;
use std::io::File;
use request;
use http::status;
use sync::Arc;
use route::Router;
use request::Request;
use http::server::ResponseWriter;

//TODO: ensure routes are valid URLs

pub type View = fn (&Request, &mut ResponseWriter, &~[(~str,~str)]);

pub struct TrieRouter<'a> {
    trie: Arc<OxidizeTrie>,
    reverse_routes: Arc<HashMap<~str, ~str>>
}

impl<'a> Router for TrieRouter<'a> {
	fn route(&self, request: &mut request::Request, response: &mut ResponseWriter) {
        let (handler,vars) = self.get_handler(request.uri);
        match handler {
        	Some(fptr) => (fptr)(request, response, &vars),
        	None => debug!("Implement 404 for TrieRouter")
        }
    }

    fn reverse<'a>(&'a self, name: &str, vars: Option<~[(~str,~str)]>) -> Option<&'a ~str> {
        // TODO: use the vars to replace
        self.reverse_routes.get().find_equiv(&name).and_then(
            |path: &'a ~str| { Some(path) }
        )
    }

    fn copy(&self) -> ~Router {
        ~TrieRouter {
            trie: self.trie.clone(),
            reverse_routes: self.reverse_routes.clone(),
        } as ~Router
    }
}

impl<'a> TrieRouter<'a> {
	pub fn new(routes: ~[TrieRoute]) -> TrieRouter {
		let mut reverse_routes = HashMap::<~str,~str>::new();
        for route in routes.iter() {
        	match *route {
        		Simple(r) => {reverse_routes.insert(r.name.to_owned(),r.path.to_owned());},
        		Variable(r) => {reverse_routes.insert(r.name.to_owned(),r.path.to_owned());}
        	}
        }
        let trie = OxidizeTrie::new(&routes);
        TrieRouter {
            trie: Arc::new(trie),
            reverse_routes: Arc::new(reverse_routes)
        }
	}

	pub fn get_handler(&'a self, uri: &str) -> (Option<View>,~[(~str,~str)]) {
		let mut path = uri.to_owned();
		let trie = &self.trie;

		if(path.len() != 1 && path[path.len() - 1] == '/' as u8) {
			path.pop_char();
		}

		let mut current_node = &trie.get().root;
		let mut current_var = ~"";
		let mut current_key = ~"";
		let mut building_var = false;
		let mut not_found = false;
		let mut vars = ~[];

		for ch in path.chars() {
			if (building_var && ch == '/') {
				vars.push((current_key,current_var));
				building_var = false;
				if(current_node.children.contains_key(&ch)) {
					current_node = current_node.children.get(&ch);
				}
				else {
					not_found = true;
					break;
				}
			}
			else if (building_var) {
				current_var.push_char(ch);
			}
			else if(current_node.children.contains_key(&'*')) {
				current_node = current_node.children.get(&'*');
				current_key = match current_node.varname{
					Some(k) => k,
					None => ~""
				};
				current_var.truncate(0);
				current_var.push_char(ch);
				building_var = true;
			}
			else if(current_node.children.contains_key(&ch)) {
				current_node = current_node.children.get(&ch);
			}
			else {
				not_found = true;
				break;
			}
		}
		(current_node.fptr, vars)
	}
}

pub enum TrieRoute {
    Simple(Route),
    Variable(Route)
}

pub struct OxidizeTrie {
	root: OxidizeTrieNode,
}

impl OxidizeTrie {
	pub fn new(routes : &~[TrieRoute]) -> OxidizeTrie {
		let mut head = OxidizeTrieNode::new();

		for route in routes.iter() {
			match *route {
				Simple(r) => head.add(r),
				Variable(r) => head.add_variable(r)
			}
		}

		OxidizeTrie {
			root: head,
		}
	}
}

pub struct OxidizeTrieNode {
	fptr: Option<View>,
	varname: Option<~str>,
	children: HashMap<char,OxidizeTrieNode>
}

impl OxidizeTrieNode {
	pub fn new() -> OxidizeTrieNode {
		OxidizeTrieNode {
			fptr: None,
			varname: None,
			children: HashMap::<char,OxidizeTrieNode>::new()
		}
	}

	pub fn add<'a>(&'a mut self, route: Route) {
		let mut current_node = self;
		let mut current_char: char;
		let mut current_var: ~str;
		let mut building_var = false;
		let path = route.path;

		if(path[0] != '/' as u8) {
			// error: route path must begin with '/'
		}
		if(path.len() != 1 && path[path.len()-1] == '/' as u8) {
			// error: route path must not end with '/'
		}

		for ch in path.chars() {
			current_node = current_node.children.find_or_insert(ch,OxidizeTrieNode::new());
		}
		current_node.fptr = Some(route.fptr);
	}

	pub fn add_variable<'a>(&'a mut self, route: Route) {
		let mut current_node = self;
		let mut current_char: char;
		let mut current_var = ~"";
		let mut building_var = false;
		let path = route.path;

		if(path[0] != '/' as u8) {
			// error: route path must begin with '/'
		}
		if(path.len() != 1 && path[path.len()-1] == '/' as u8) {
			// error: route path must not end with '/'
		}

		for ch in path.chars() {
			if (building_var && ch == '/') {
				if(current_var.len() == 0) {
					// error: can't allow empty string as varname
				}
				current_node.varname = Some(current_var.clone());
				current_node = current_node.children.find_or_insert('*',OxidizeTrieNode::new());
				current_node = current_node.children.find_or_insert(ch,OxidizeTrieNode::new());
				building_var = false;
			}
			else if (building_var) {
				current_var.push_char(ch);
			}
			else if(ch == ':') {
				building_var = true;
				current_var.truncate(0);
			}
			else {
				current_node = current_node.children.find_or_insert(ch,OxidizeTrieNode::new());
			}
		}
		current_node.fptr = Some(route.fptr);
		if(building_var) {
			current_node.varname = Some(current_var);
		}
	}
}

//TODO: seems like this shouldn't be in declared in multiple files
pub struct Route {
    method: &'static str,
    path : &'static str,
    name : &'static str,
    fptr : View,
}<commit_msg>This compiles at least. Its not in use yet though<commit_after>use collections::hashmap::HashMap;
use request;
use sync::Arc;
use route::Router;
use request::Request;
use http::server::ResponseWriter;

//TODO: ensure routes are valid URLs

pub type View = fn (&Request, &mut ResponseWriter, &~[(~str,~str)]);

pub struct TrieRouter<'a> {
    priv trie: Arc<TrieNode>,
    priv reverse_routes: Arc<HashMap<~str, ~str>>
}

impl<'a> Router for TrieRouter<'a> {
    fn route(&self, request: &mut request::Request, response: &mut ResponseWriter) {
        let (handler,vars) = self.get_handler(request.uri);
        match handler {
            Some(fptr) => (fptr)(request, response, &vars),
            None => debug!("Implement 404 for TrieRouter")
        }
    }
    #[allow(unused_variable)]
    fn reverse<'a>(&'a self, name: &str, vars: Option<~[(~str,~str)]>) -> Option<&'a ~str> {
        // TODO: use the vars to replace
        self.reverse_routes.get().find_equiv(&name).and_then(
            |path: &'a ~str| { Some(path) }
        )
    }

    fn copy(&self) -> ~Router {
        ~TrieRouter {
            trie: self.trie.clone(),
            reverse_routes: self.reverse_routes.clone(),
        } as ~Router
    }
}

impl<'a> TrieRouter<'a> {
    pub fn new(routes: ~[TrieRoute]) -> TrieRouter {
        let mut reverse_routes = HashMap::<~str,~str>::new();
        for route in routes.iter() {
            match *route {
                Simple(r) => {reverse_routes.insert(r.name.to_owned(),r.path.to_owned());},
                Variable(r) => {reverse_routes.insert(r.name.to_owned(),r.path.to_owned());}
            }
        }
        let trie = TrieNode::new(&routes);
        TrieRouter {
            trie: Arc::new(trie),
            reverse_routes: Arc::new(reverse_routes)
        }
    }

    pub fn get_handler<'a>(&'a self, uri: &str) -> (Option<View>,~[(~str,~str)]) {
        let mut path = uri.to_owned();

        if path.len() != 1 && path[path.len() - 1] == '/' as u8 {
            path.pop_char();
        }

        let mut current_node = self.trie.get();
        let mut current_var = ~"";
        let mut current_key = ~"";
        let mut building_var = false;
        // let mut not_found = false;
        let mut vars = ~[];

        for ch in path.chars() {
            if building_var && ch == '/' {
                vars.push((current_key.clone(),current_var.clone()));
                building_var = false;
                if current_node.children.contains_key(&ch) {
                    current_node = current_node.children.get(&ch);
                }
                else {
                    // not_found = true;
                    break;
                }
            }
            else if building_var {
                current_var.push_char(ch);
            }
            else if current_node.children.contains_key(&'*') {
                current_node = current_node.children.get(&'*');
                // cloning here because it tried to move varname but the current_node
                // is only a non mutable pointer here so it can't move.
                current_key = current_node.varname.clone().unwrap_or(~"");
                current_var.truncate(0);
                current_var.push_char(ch);
                building_var = true;
            }
            else if current_node.children.contains_key(&ch) {
                current_node = current_node.children.get(&ch);
            }
            else {
                // not_found = true;
                break;
            }
        }
        (current_node.fptr, vars)
    }
}

pub enum TrieRoute {
    Simple(Route),
    Variable(Route)
}

pub struct Route {
    method: &'static str,
    path : &'static str,
    name : &'static str,
    fptr : View,
}

struct TrieNode {
    children: HashMap<char, TrieNode>,
    fptr: Option<View>,
    varname: Option<~str>,
}

impl TrieNode {
    pub fn new(routes : &~[TrieRoute]) -> TrieNode {
        let mut root = TrieNode::setup();

        for route in routes.iter() {
            match *route {
                Simple(r) => {root.add(r);},
                Variable(r) => {root.add_variable(r);},
            }
        }
        root
    }

    fn setup() -> TrieNode {
        TrieNode {
            children : HashMap::new(),
            fptr: None,
            varname: None,
        }
    }

    fn add(&mut self, route: Route) {
        // let mut current_node = self;
        // let mut current_char: char;
        // let mut current_var: ~str;
        // let mut building_var = false;
        let path = route.path;

        if path[0] != '/' as u8 {
            // warn!("route path must begin with '/'");
        }
        if path.len() != 1 && path[path.len()-1] == '/' as u8 {
            // warn!("route path must not end with '/'");
        }

        {
            let mut ptr = self;
            for ch in path.chars() {
                let tmp = ptr;
                ptr = tmp.children.find_or_insert(ch, TrieNode::setup());
            }
            ptr.fptr = Some(route.fptr);
        }
    }

    fn add_variable(&mut self, route: Route) {
        // let mut current_node = self;
        // let mut current_char: char;
        let mut current_var = ~"";
        let mut building_var = false;
        let path = route.path;

        if path[0] != '/' as u8 {
            // error: route path must begin with '/'
        }
        if path.len() != 1 && path[path.len()-1] == '/' as u8 {
            // error: route path must not end with '/'
        }

        {
            let mut ptr = self;
            for ch in path.chars() {
                if building_var && ch == '/' {
                    if current_var.len() == 0 {
                        // error: can't allow empty string as varname
                    }
                    ptr.varname = Some(current_var.clone());
                    let tmp = ptr;
                    tmp.children.find_or_insert('*', TrieNode::setup());
                    ptr = tmp.children.find_or_insert(ch, TrieNode::setup());
                    building_var = false;
                }
                else if building_var {
                    current_var.push_char(ch);
                }
                else if ch == ':' {
                    building_var = true;
                    current_var.truncate(0);
                }
                else {
                    let tmp = ptr;
                    ptr = tmp.children.find_or_insert(ch, TrieNode::setup());
                }
            }
            ptr.fptr = Some(route.fptr);

            if building_var {
                ptr.varname = Some(current_var);
            }
        }
    }
}<|endoftext|>


<commit_before>//! This provides wrappers around the `StdoutTerminal` and `StderrTerminal` types
//! that does not fail if `StdoutTerminal` etc can't be constructed, which happens
//! if TERM isn't defined.

use std::io;
use term;
use rustup_utils::tty;
use markdown::{Block, Span, ListItem};
use markdown::tokenize;

pub use term::color;
pub use term::Attr;

pub trait Instantiable {
    fn instance() -> Self;
}

impl Instantiable for io::Stdout {
    fn instance() -> Self { io::stdout() }
}

impl Instantiable for io::Stderr {
    fn instance() -> Self { io::stderr() }
}

pub trait Isatty {
    fn isatty() -> bool;
}

impl Isatty for io::Stdout {
    fn isatty() -> bool {
        tty::stdout_isatty()
    }
}

impl Isatty for io::Stderr {
    fn isatty() -> bool {
        tty::stderr_isatty()
    }
}

pub struct Terminal<T>(Option<Box<term::Terminal<Output = T> + Send>>)
    where T: Instantiable + Isatty + io::Write;
pub type StdoutTerminal = Terminal<io::Stdout>;
pub type StderrTerminal = Terminal<io::Stderr>;

pub fn stdout() -> StdoutTerminal {
    Terminal(term::stdout())
}

pub fn stderr() -> StderrTerminal {
    Terminal(term::stderr())
}

// Handles the wrapping of text written to the console
struct LineWrapper<'a, T: io::Write + 'a> {
    indent: u32,
    margin: u32,
    pos: u32,
    pub w: &'a mut T
}

impl<'a, T: io::Write + 'a> LineWrapper<'a, T> {
    // Just write a newline
    fn write_line(&mut self) {
        let _ = writeln!(self.w, "");
        // Reset column position to start of line
        self.pos = 0;
    }
    // Called before writing text to ensure indent is applied
    fn write_indent(&mut self) {
        if self.pos == 0 {
            // Write a space for each level of indent
            for _ in 0..self.indent {
                let _ = write!(self.w, " ");
            }
            self.pos = self.indent;
        }
    }
    // Write a non-breaking word
    fn write_word(&mut self, word: &str) {
        // Ensure correct indentation
        self.write_indent();
        let word_len = word.len() as u32;

        // If this word goes past the margin
        if self.pos + word_len > self.margin {
            // And adding a newline would give us more space
            if self.pos > self.indent {
                // Then add a newline!
                self.write_line();
                self.write_indent();
            }
        }

        // Write the word
        let _ = write!(self.w, "{}", word);
        self.pos += word_len;
    }
    fn write_space(&mut self) {
        if self.pos > self.indent {
            if self.pos < self.margin {
                self.write_word(" ");
            } else {
                self.write_line();
            }
        }
    }
    // Writes a span of text which wraps at the margin
    fn write_span(&mut self, text: &str) {
        // Allow words to wrap on whitespace
        let mut is_first = true;
        for word in text.split(char::is_whitespace) {
            if is_first {
                is_first = false;
            } else {
                self.write_space();
            }
            self.write_word(word);
        }
    }
    // Constructor
    fn new(w: &'a mut T, indent: u32, margin: u32) -> Self {
        LineWrapper {
            indent: indent,
            margin: margin,
            pos: indent,
            w: w
        }
    }
}

// Handles the formatting of text
struct LineFormatter<'a, T: Instantiable + Isatty + io::Write + 'a> {
    wrapper: LineWrapper<'a, Terminal<T>>,
    attrs: Vec<Attr>
}

impl<'a, T: Instantiable + Isatty + io::Write + 'a> LineFormatter<'a, T> {
    fn new(w: &'a mut Terminal<T>, indent: u32, margin: u32) -> Self {
        LineFormatter {
            wrapper: LineWrapper::new(w, indent, margin),
            attrs: Vec::new()
        }
    }
    fn push_attr(&mut self, attr: Attr) {
        self.attrs.push(attr);
        let _ = self.wrapper.w.attr(attr);
    }
    fn pop_attr(&mut self) {
        self.attrs.pop();
        let _ = self.wrapper.w.reset();
        for attr in &self.attrs {
            let _ = self.wrapper.w.attr(*attr);
        }
    }
    fn do_spans(&mut self, spans: Vec<Span>) {
        for span in spans {
            match span {
                Span::Break => {},
                Span::Text(text) => {
                    self.wrapper.write_span(&text);
                },
                Span::Code(code) => {
                    self.push_attr(Attr::Bold);
                    self.wrapper.write_word(&code);
                    self.pop_attr();
                },
                Span::Emphasis(spans) => {
                    self.push_attr(Attr::ForegroundColor(color::BRIGHT_RED));
                    self.do_spans(spans);
                    self.pop_attr();
                }
                _ => {}
            }
        }
    }
    fn do_block(&mut self, b: Block) {
        match b {
            Block::Header(spans, _) => {
                self.push_attr(Attr::ForegroundColor(color::BRIGHT_WHITE));
                self.wrapper.write_line();
                self.do_spans(spans);
                self.wrapper.write_line();
                self.pop_attr();
            },
            Block::CodeBlock(code) => {
                self.wrapper.write_line();
                self.wrapper.indent += 2;
                for line in code.lines() {
                    // Don't word-wrap code lines
                    self.wrapper.write_word(line);
                    self.wrapper.write_line();
                }
                self.wrapper.indent -= 2;
            },
            Block::Paragraph(spans) => {
                self.wrapper.write_line();
                self.do_spans(spans);
                self.wrapper.write_line();
            },
            Block::UnorderedList(items) => {
                self.wrapper.write_line();
                for item in items {
                    self.wrapper.indent += 2;
                    match item {
                        ListItem::Simple(spans) => {
                            self.do_spans(spans);
                        },
                        ListItem::Paragraph(blocks) => {
                            for block in blocks {
                                self.do_block(block);
                            }
                        }
                    }
                    self.wrapper.write_line();
                    self.wrapper.indent -= 2;
                }
            }
            _ => {}
        }
    }
}

impl<T: Instantiable + Isatty + io::Write> io::Write for Terminal<T> {
    fn write(&mut self, buf: &[u8]) -> Result<usize, io::Error> {
        if let Some(ref mut t) = self.0 {
            t.write(buf)
        } else {
            let mut t = T::instance();
            t.write(buf)
        }
    }

    fn flush(&mut self) -> Result<(), io::Error> {
        if let Some(ref mut t) = self.0 {
            t.flush()
        } else {
            let mut t = T::instance();
            t.flush()
        }
    }
}

impl<T: Instantiable + Isatty + io::Write> Terminal<T> {
    pub fn fg(&mut self, color: color::Color) -> Result<(), term::Error> {
        if !T::isatty() { return Ok(()) }

        if let Some(ref mut t) = self.0 {
            t.fg(color)
        } else {
            Ok(())
        }
    }

    pub fn attr(&mut self, attr: Attr) -> Result<(), term::Error> {
        if !T::isatty() { return Ok(()) }

        if let Some(ref mut t) = self.0 {
            if let Err(e) = t.attr(attr) {
                // If `attr` is not supported, try to emulate it
                match attr {
                    Attr::Bold => t.fg(color::BRIGHT_WHITE),
                    _ => Err(e)
                }
            } else {
                Ok(())
            }
        } else {
            Ok(())
        }
    }

    pub fn reset(&mut self) -> Result<(), term::Error> {
        if !T::isatty() { return Ok(()) }

        if let Some(ref mut t) = self.0 {
            t.reset()
        } else {
            Ok(())
        }
    }

    pub fn md<S: AsRef<str>>(&mut self, content: S) {
        let mut f = LineFormatter::new(self, 0, 79);
        let blocks = tokenize(content.as_ref());
        for b in blocks {
            f.do_block(b);
        }
    }
}
<commit_msg>Fix white welcome text on white background<commit_after>//! This provides wrappers around the `StdoutTerminal` and `StderrTerminal` types
//! that does not fail if `StdoutTerminal` etc can't be constructed, which happens
//! if TERM isn't defined.

use std::io;
use term;
use rustup_utils::tty;
use markdown::{Block, Span, ListItem};
use markdown::tokenize;

pub use term::color;
pub use term::Attr;

pub trait Instantiable {
    fn instance() -> Self;
}

impl Instantiable for io::Stdout {
    fn instance() -> Self { io::stdout() }
}

impl Instantiable for io::Stderr {
    fn instance() -> Self { io::stderr() }
}

pub trait Isatty {
    fn isatty() -> bool;
}

impl Isatty for io::Stdout {
    fn isatty() -> bool {
        tty::stdout_isatty()
    }
}

impl Isatty for io::Stderr {
    fn isatty() -> bool {
        tty::stderr_isatty()
    }
}

pub struct Terminal<T>(Option<Box<term::Terminal<Output = T> + Send>>)
    where T: Instantiable + Isatty + io::Write;
pub type StdoutTerminal = Terminal<io::Stdout>;
pub type StderrTerminal = Terminal<io::Stderr>;

pub fn stdout() -> StdoutTerminal {
    Terminal(term::stdout())
}

pub fn stderr() -> StderrTerminal {
    Terminal(term::stderr())
}

// Handles the wrapping of text written to the console
struct LineWrapper<'a, T: io::Write + 'a> {
    indent: u32,
    margin: u32,
    pos: u32,
    pub w: &'a mut T
}

impl<'a, T: io::Write + 'a> LineWrapper<'a, T> {
    // Just write a newline
    fn write_line(&mut self) {
        let _ = writeln!(self.w, "");
        // Reset column position to start of line
        self.pos = 0;
    }
    // Called before writing text to ensure indent is applied
    fn write_indent(&mut self) {
        if self.pos == 0 {
            // Write a space for each level of indent
            for _ in 0..self.indent {
                let _ = write!(self.w, " ");
            }
            self.pos = self.indent;
        }
    }
    // Write a non-breaking word
    fn write_word(&mut self, word: &str) {
        // Ensure correct indentation
        self.write_indent();
        let word_len = word.len() as u32;

        // If this word goes past the margin
        if self.pos + word_len > self.margin {
            // And adding a newline would give us more space
            if self.pos > self.indent {
                // Then add a newline!
                self.write_line();
                self.write_indent();
            }
        }

        // Write the word
        let _ = write!(self.w, "{}", word);
        self.pos += word_len;
    }
    fn write_space(&mut self) {
        if self.pos > self.indent {
            if self.pos < self.margin {
                self.write_word(" ");
            } else {
                self.write_line();
            }
        }
    }
    // Writes a span of text which wraps at the margin
    fn write_span(&mut self, text: &str) {
        // Allow words to wrap on whitespace
        let mut is_first = true;
        for word in text.split(char::is_whitespace) {
            if is_first {
                is_first = false;
            } else {
                self.write_space();
            }
            self.write_word(word);
        }
    }
    // Constructor
    fn new(w: &'a mut T, indent: u32, margin: u32) -> Self {
        LineWrapper {
            indent: indent,
            margin: margin,
            pos: indent,
            w: w
        }
    }
}

// Handles the formatting of text
struct LineFormatter<'a, T: Instantiable + Isatty + io::Write + 'a> {
    wrapper: LineWrapper<'a, Terminal<T>>,
    attrs: Vec<Attr>
}

impl<'a, T: Instantiable + Isatty + io::Write + 'a> LineFormatter<'a, T> {
    fn new(w: &'a mut Terminal<T>, indent: u32, margin: u32) -> Self {
        LineFormatter {
            wrapper: LineWrapper::new(w, indent, margin),
            attrs: Vec::new()
        }
    }
    fn push_attr(&mut self, attr: Attr) {
        self.attrs.push(attr);
        let _ = self.wrapper.w.attr(attr);
    }
    fn pop_attr(&mut self) {
        self.attrs.pop();
        let _ = self.wrapper.w.reset();
        for attr in &self.attrs {
            let _ = self.wrapper.w.attr(*attr);
        }
    }
    fn do_spans(&mut self, spans: Vec<Span>) {
        for span in spans {
            match span {
                Span::Break => {},
                Span::Text(text) => {
                    self.wrapper.write_span(&text);
                },
                Span::Code(code) => {
                    self.push_attr(Attr::Bold);
                    self.wrapper.write_word(&code);
                    self.pop_attr();
                },
                Span::Emphasis(spans) => {
                    self.push_attr(Attr::ForegroundColor(color::BRIGHT_RED));
                    self.do_spans(spans);
                    self.pop_attr();
                }
                _ => {}
            }
        }
    }
    fn do_block(&mut self, b: Block) {
        match b {
            Block::Header(spans, _) => {
                self.push_attr(Attr::Bold);
                self.wrapper.write_line();
                self.do_spans(spans);
                self.wrapper.write_line();
                self.pop_attr();
            },
            Block::CodeBlock(code) => {
                self.wrapper.write_line();
                self.wrapper.indent += 2;
                for line in code.lines() {
                    // Don't word-wrap code lines
                    self.wrapper.write_word(line);
                    self.wrapper.write_line();
                }
                self.wrapper.indent -= 2;
            },
            Block::Paragraph(spans) => {
                self.wrapper.write_line();
                self.do_spans(spans);
                self.wrapper.write_line();
            },
            Block::UnorderedList(items) => {
                self.wrapper.write_line();
                for item in items {
                    self.wrapper.indent += 2;
                    match item {
                        ListItem::Simple(spans) => {
                            self.do_spans(spans);
                        },
                        ListItem::Paragraph(blocks) => {
                            for block in blocks {
                                self.do_block(block);
                            }
                        }
                    }
                    self.wrapper.write_line();
                    self.wrapper.indent -= 2;
                }
            }
            _ => {}
        }
    }
}

impl<T: Instantiable + Isatty + io::Write> io::Write for Terminal<T> {
    fn write(&mut self, buf: &[u8]) -> Result<usize, io::Error> {
        if let Some(ref mut t) = self.0 {
            t.write(buf)
        } else {
            let mut t = T::instance();
            t.write(buf)
        }
    }

    fn flush(&mut self) -> Result<(), io::Error> {
        if let Some(ref mut t) = self.0 {
            t.flush()
        } else {
            let mut t = T::instance();
            t.flush()
        }
    }
}

impl<T: Instantiable + Isatty + io::Write> Terminal<T> {
    pub fn fg(&mut self, color: color::Color) -> Result<(), term::Error> {
        if !T::isatty() { return Ok(()) }

        if let Some(ref mut t) = self.0 {
            t.fg(color)
        } else {
            Ok(())
        }
    }

    pub fn attr(&mut self, attr: Attr) -> Result<(), term::Error> {
        if !T::isatty() { return Ok(()) }

        if let Some(ref mut t) = self.0 {
            if let Err(e) = t.attr(attr) {
                // If `attr` is not supported, try to emulate it
                match attr {
                    Attr::Bold => t.fg(color::BRIGHT_WHITE),
                    _ => Err(e)
                }
            } else {
                Ok(())
            }
        } else {
            Ok(())
        }
    }

    pub fn reset(&mut self) -> Result<(), term::Error> {
        if !T::isatty() { return Ok(()) }

        if let Some(ref mut t) = self.0 {
            t.reset()
        } else {
            Ok(())
        }
    }

    pub fn md<S: AsRef<str>>(&mut self, content: S) {
        let mut f = LineFormatter::new(self, 0, 79);
        let blocks = tokenize(content.as_ref());
        for b in blocks {
            f.do_block(b);
        }
    }
}
<|endoftext|>