<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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 config::lists::*;
use syntax::ast::{self, BindingMode, FieldPat, Pat, PatKind, RangeEnd, RangeSyntax};
use syntax::codemap::{self, BytePos, Span};
use syntax::ptr;

use codemap::SpanUtils;
use comment::FindUncommented;
use expr::{
    can_be_overflowed_expr, rewrite_pair, rewrite_unary_prefix, wrap_struct_field, PairParts,
};
use lists::{
    itemize_list, shape_for_tactic, struct_lit_formatting, struct_lit_shape, struct_lit_tactic,
    write_list,
};
use macros::{rewrite_macro, MacroPosition};
use overflow;
use rewrite::{Rewrite, RewriteContext};
use shape::Shape;
use spanned::Spanned;
use types::{rewrite_path, PathContext};
use utils::{format_mutability, mk_sp, rewrite_ident};

/// Returns true if the given pattern is short. A short pattern is defined by the following grammer:
///
/// [small, ntp]:
///     - single token
///     - `&[single-line, ntp]`
///
/// [small]:
///     - `[small, ntp]`
///     - unary tuple constructor `([small, ntp])`
///     - `&[small]`
pub fn is_short_pattern(pat: &ast::Pat, pat_str: &str) -> bool {
    // We also require that the pattern is reasonably 'small' with its literal width.
    pat_str.len() <= 20 && !pat_str.contains('\n') && is_short_pattern_inner(pat)
}

fn is_short_pattern_inner(pat: &ast::Pat) -> bool {
    match pat.node {
        ast::PatKind::Wild | ast::PatKind::Lit(_) => true,
        ast::PatKind::Ident(_, _, ref pat) => pat.is_none(),
        ast::PatKind::Struct(..)
        | ast::PatKind::Mac(..)
        | ast::PatKind::Slice(..)
        | ast::PatKind::Path(..)
        | ast::PatKind::Range(..) => false,
        ast::PatKind::Tuple(ref subpats, _) => subpats.len() <= 1,
        ast::PatKind::TupleStruct(ref path, ref subpats, _) => {
            path.segments.len() <= 1 && subpats.len() <= 1
        }
        ast::PatKind::Box(ref p) | ast::PatKind::Ref(ref p, _) | ast::PatKind::Paren(ref p) => {
            is_short_pattern_inner(&*p)
        }
    }
}

impl Rewrite for Pat {
    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
        match self.node {
            PatKind::Box(ref pat) => rewrite_unary_prefix(context, "box ", &**pat, shape),
            PatKind::Ident(binding_mode, ident, ref sub_pat) => {
                let (prefix, mutability) = match binding_mode {
                    BindingMode::ByRef(mutability) => ("ref ", mutability),
                    BindingMode::ByValue(mutability) => ("", mutability),
                };
                let mut_infix = format_mutability(mutability);
                let id_str = rewrite_ident(context, ident);
                let sub_pat = match *sub_pat {
                    Some(ref p) => {
                        // 3 - ` @ `.
                        let width = shape
                            .width
                            .checked_sub(prefix.len() + mut_infix.len() + id_str.len() + 3)?;
                        format!(
                            " @ {}",
                            p.rewrite(context, Shape::legacy(width, shape.indent))?
                        )
                    }
                    None => "".to_owned(),
                };

                Some(format!("{}{}{}{}", prefix, mut_infix, id_str, sub_pat))
            }
            PatKind::Wild => {
                if 1 <= shape.width {
                    Some("_".to_owned())
                } else {
                    None
                }
            }
            PatKind::Range(ref lhs, ref rhs, ref end_kind) => {
                let infix = match *end_kind {
                    RangeEnd::Included(RangeSyntax::DotDotDot) => "...",
                    RangeEnd::Included(RangeSyntax::DotDotEq) => "..=",
                    RangeEnd::Excluded => "..",
                };
                let infix = if context.config.spaces_around_ranges() {
                    format!(" {} ", infix)
                } else {
                    infix.to_owned()
                };
                rewrite_pair(
                    &**lhs,
                    &**rhs,
                    PairParts::new("", &infix, ""),
                    context,
                    shape,
                    SeparatorPlace::Front,
                )
            }
            PatKind::Ref(ref pat, mutability) => {
                let prefix = format!("&{}", format_mutability(mutability));
                rewrite_unary_prefix(context, &prefix, &**pat, shape)
            }
            PatKind::Tuple(ref items, dotdot_pos) => {
                rewrite_tuple_pat(items, dotdot_pos, None, self.span, context, shape)
            }
            PatKind::Path(ref q_self, ref path) => {
                rewrite_path(context, PathContext::Expr, q_self.as_ref(), path, shape)
            }
            PatKind::TupleStruct(ref path, ref pat_vec, dotdot_pos) => {
                let path_str = rewrite_path(context, PathContext::Expr, None, path, shape)?;
                rewrite_tuple_pat(
                    pat_vec,
                    dotdot_pos,
                    Some(path_str),
                    self.span,
                    context,
                    shape,
                )
            }
            PatKind::Lit(ref expr) => expr.rewrite(context, shape),
            PatKind::Slice(ref prefix, ref slice_pat, ref suffix) => {
                // Rewrite all the sub-patterns.
                let prefix = prefix.iter().map(|p| p.rewrite(context, shape));
                let slice_pat = slice_pat
                    .as_ref()
                    .map(|p| Some(format!("{}..", p.rewrite(context, shape)?)));
                let suffix = suffix.iter().map(|p| p.rewrite(context, shape));

                // Munge them together.
                let pats: Option<Vec<String>> =
                    prefix.chain(slice_pat.into_iter()).chain(suffix).collect();

                // Check that all the rewrites succeeded, and if not return None.
                let pats = pats?;

                // Unwrap all the sub-strings and join them with commas.
                Some(format!("[{}]", pats.join(", ")))
            }
            PatKind::Struct(ref path, ref fields, ellipsis) => {
                rewrite_struct_pat(path, fields, ellipsis, self.span, context, shape)
            }
            PatKind::Mac(ref mac) => rewrite_macro(mac, None, context, shape, MacroPosition::Pat),
            PatKind::Paren(ref pat) => pat
                .rewrite(context, shape.offset_left(1)?.sub_width(1)?)
                .map(|inner_pat| format!("({})", inner_pat)),
        }
    }
}

fn rewrite_struct_pat(
    path: &ast::Path,
    fields: &[codemap::Spanned<ast::FieldPat>],
    ellipsis: bool,
    span: Span,
    context: &RewriteContext,
    shape: Shape,
) -> Option<String> {
    // 2 =  ` {`
    let path_shape = shape.sub_width(2)?;
    let path_str = rewrite_path(context, PathContext::Expr, None, path, path_shape)?;

    if fields.is_empty() && !ellipsis {
        return Some(format!("{} {{}}", path_str));
    }

    let (ellipsis_str, terminator) = if ellipsis { (", ..", "..") } else { ("", "}") };

    // 3 = ` { `, 2 = ` }`.
    let (h_shape, v_shape) =
        struct_lit_shape(shape, context, path_str.len() + 3, ellipsis_str.len() + 2)?;

    let items = itemize_list(
        context.snippet_provider,
        fields.iter(),
        terminator,
        ",",
        |f| f.span.lo(),
        |f| f.span.hi(),
        |f| f.node.rewrite(context, v_shape),
        context.snippet_provider.span_after(span, "{"),
        span.hi(),
        false,
    );
    let item_vec = items.collect::<Vec<_>>();

    let tactic = struct_lit_tactic(h_shape, context, &item_vec);
    let nested_shape = shape_for_tactic(tactic, h_shape, v_shape);
    let fmt = struct_lit_formatting(nested_shape, tactic, context, false);

    let mut fields_str = write_list(&item_vec, &fmt)?;
    let one_line_width = h_shape.map_or(0, |shape| shape.width);

    if ellipsis {
        if fields_str.contains('\n') || fields_str.len() > one_line_width {
            // Add a missing trailing comma.
            if fmt.trailing_separator == SeparatorTactic::Never {
                fields_str.push_str(",");
            }
            fields_str.push_str("\n");
            fields_str.push_str(&nested_shape.indent.to_string(context.config));
            fields_str.push_str("..");
        } else {
            if !fields_str.is_empty() {
                // there are preceding struct fields being matched on
                if fmt.tactic == DefinitiveListTactic::Vertical {
                    // if the tactic is Vertical, write_list already added a trailing ,
                    fields_str.push_str(" ");
                } else {
                    fields_str.push_str(", ");
                }
            }
            fields_str.push_str("..");
        }
    }

    let fields_str = wrap_struct_field(context, &fields_str, shape, v_shape, one_line_width);
    Some(format!("{} {{{}}}", path_str, fields_str))
}

impl Rewrite for FieldPat {
    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
        let pat = self.pat.rewrite(context, shape);
        if self.is_shorthand {
            pat
        } else {
            let pat_str = pat?;
            let id_str = rewrite_ident(context, self.ident);
            let one_line_width = id_str.len() + 2 + pat_str.len();
            if one_line_width <= shape.width {
                Some(format!("{}: {}", id_str, pat_str))
            } else {
                let nested_shape = shape.block_indent(context.config.tab_spaces());
                let pat_str = self.pat.rewrite(context, nested_shape)?;
                Some(format!(
                    "{}:\n{}{}",
                    id_str,
                    nested_shape.indent.to_string(context.config),
                    pat_str,
                ))
            }
        }
    }
}

pub enum TuplePatField<'a> {
    Pat(&'a ptr::P<ast::Pat>),
    Dotdot(Span),
}

impl<'a> Rewrite for TuplePatField<'a> {
    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
        match *self {
            TuplePatField::Pat(p) => p.rewrite(context, shape),
            TuplePatField::Dotdot(_) => Some("..".to_string()),
        }
    }
}

impl<'a> Spanned for TuplePatField<'a> {
    fn span(&self) -> Span {
        match *self {
            TuplePatField::Pat(p) => p.span(),
            TuplePatField::Dotdot(span) => span,
        }
    }
}

pub fn can_be_overflowed_pat(context: &RewriteContext, pat: &TuplePatField, len: usize) -> bool {
    match *pat {
        TuplePatField::Pat(pat) => match pat.node {
            ast::PatKind::Path(..)
            | ast::PatKind::Tuple(..)
            | ast::PatKind::Struct(..)
            | ast::PatKind::TupleStruct(..) => context.use_block_indent() && len == 1,
            ast::PatKind::Ref(ref p, _) | ast::PatKind::Box(ref p) => {
                can_be_overflowed_pat(context, &TuplePatField::Pat(p), len)
            }
            ast::PatKind::Lit(ref expr) => can_be_overflowed_expr(context, expr, len),
            _ => false,
        },
        TuplePatField::Dotdot(..) => false,
    }
}

fn rewrite_tuple_pat(
    pats: &[ptr::P<ast::Pat>],
    dotdot_pos: Option<usize>,
    path_str: Option<String>,
    span: Span,
    context: &RewriteContext,
    shape: Shape,
) -> Option<String> {
    let mut pat_vec: Vec<_> = pats.into_iter().map(|x| TuplePatField::Pat(x)).collect();

    if let Some(pos) = dotdot_pos {
        let prev = if pos == 0 {
            span.lo()
        } else {
            pats[pos - 1].span().hi()
        };
        let next = if pos + 1 >= pats.len() {
            span.hi()
        } else {
            pats[pos + 1].span().lo()
        };
        let dot_span = mk_sp(prev, next);
        let snippet = context.snippet(dot_span);
        let lo = dot_span.lo() + BytePos(snippet.find_uncommented("..").unwrap() as u32);
        let dotdot = TuplePatField::Dotdot(Span::new(
            lo,
            // 2 == "..".len()
            lo + BytePos(2),
            codemap::NO_EXPANSION,
        ));
        pat_vec.insert(pos, dotdot);
    }

    if pat_vec.is_empty() {
        return Some(format!("{}()", path_str.unwrap_or_default()));
    }

    let wildcard_suffix_len = count_wildcard_suffix_len(context, &pat_vec, span, shape);
    let (pat_vec, span) = if context.config.condense_wildcard_suffixes() && wildcard_suffix_len >= 2
    {
        let new_item_count = 1 + pat_vec.len() - wildcard_suffix_len;
        let sp = pat_vec[new_item_count - 1].span();
        let snippet = context.snippet(sp);
        let lo = sp.lo() + BytePos(snippet.find_uncommented("_").unwrap() as u32);
        pat_vec[new_item_count - 1] = TuplePatField::Dotdot(mk_sp(lo, lo + BytePos(1)));
        (
            &pat_vec[..new_item_count],
            mk_sp(span.lo(), lo + BytePos(1)),
        )
    } else {
        (&pat_vec[..], span)
    };

    // add comma if `(x,)`
    let add_comma = path_str.is_none() && pat_vec.len() == 1 && dotdot_pos.is_none();
    let path_str = path_str.unwrap_or_default();
    let pat_ref_vec = pat_vec.iter().collect::<Vec<_>>();

    overflow::rewrite_with_parens(
        &context,
        &path_str,
        &pat_ref_vec,
        shape,
        span,
        context.config.max_width(),
        if add_comma {
            Some(SeparatorTactic::Always)
        } else {
            None
        },
    )
}

fn count_wildcard_suffix_len(
    context: &RewriteContext,
    patterns: &[TuplePatField],
    span: Span,
    shape: Shape,
) -> usize {
    let mut suffix_len = 0;

    let items: Vec<_> = itemize_list(
        context.snippet_provider,
        patterns.iter(),
        ")",
        ",",
        |item| item.span().lo(),
        |item| item.span().hi(),
        |item| item.rewrite(context, shape),
        context.snippet_provider.span_after(span, "("),
        span.hi() - BytePos(1),
        false,
    ).collect();

    for item in items.iter().rev().take_while(|i| match i.item {
        Some(ref internal_string) if internal_string == "_" => true,
        _ => false,
    }) {
        suffix_len += 1;

        if item.has_comment() {
            break;
        }
    }

    suffix_len
}
<commit_msg>Fix compile error from breaking changes in libsyntax<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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 config::lists::*;
use syntax::ast::{self, BindingMode, FieldPat, Pat, PatKind, RangeEnd, RangeSyntax};
use syntax::codemap::{self, BytePos, Span};
use syntax::ptr;

use codemap::SpanUtils;
use comment::FindUncommented;
use expr::{
    can_be_overflowed_expr, rewrite_pair, rewrite_unary_prefix, wrap_struct_field, PairParts,
};
use lists::{
    itemize_list, shape_for_tactic, struct_lit_formatting, struct_lit_shape, struct_lit_tactic,
    write_list,
};
use macros::{rewrite_macro, MacroPosition};
use overflow;
use rewrite::{Rewrite, RewriteContext};
use shape::Shape;
use spanned::Spanned;
use types::{rewrite_path, PathContext};
use utils::{format_mutability, mk_sp, rewrite_ident};

/// Returns true if the given pattern is short. A short pattern is defined by the following grammer:
///
/// [small, ntp]:
///     - single token
///     - `&[single-line, ntp]`
///
/// [small]:
///     - `[small, ntp]`
///     - unary tuple constructor `([small, ntp])`
///     - `&[small]`
pub fn is_short_pattern(pat: &ast::Pat, pat_str: &str) -> bool {
    // We also require that the pattern is reasonably 'small' with its literal width.
    pat_str.len() <= 20 && !pat_str.contains('\n') && is_short_pattern_inner(pat)
}

fn is_short_pattern_inner(pat: &ast::Pat) -> bool {
    match pat.node {
        ast::PatKind::Wild | ast::PatKind::Lit(_) => true,
        ast::PatKind::Ident(_, _, ref pat) => pat.is_none(),
        ast::PatKind::Struct(..)
        | ast::PatKind::Mac(..)
        | ast::PatKind::Slice(..)
        | ast::PatKind::Path(..)
        | ast::PatKind::Range(..) => false,
        ast::PatKind::Tuple(ref subpats, _) => subpats.len() <= 1,
        ast::PatKind::TupleStruct(ref path, ref subpats, _) => {
            path.segments.len() <= 1 && subpats.len() <= 1
        }
        ast::PatKind::Box(ref p) | ast::PatKind::Ref(ref p, _) | ast::PatKind::Paren(ref p) => {
            is_short_pattern_inner(&*p)
        }
    }
}

impl Rewrite for Pat {
    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
        match self.node {
            PatKind::Box(ref pat) => rewrite_unary_prefix(context, "box ", &**pat, shape),
            PatKind::Ident(binding_mode, ident, ref sub_pat) => {
                let (prefix, mutability) = match binding_mode {
                    BindingMode::ByRef(mutability) => ("ref ", mutability),
                    BindingMode::ByValue(mutability) => ("", mutability),
                };
                let mut_infix = format_mutability(mutability);
                let id_str = rewrite_ident(context, ident);
                let sub_pat = match *sub_pat {
                    Some(ref p) => {
                        // 3 - ` @ `.
                        let width = shape
                            .width
                            .checked_sub(prefix.len() + mut_infix.len() + id_str.len() + 3)?;
                        format!(
                            " @ {}",
                            p.rewrite(context, Shape::legacy(width, shape.indent))?
                        )
                    }
                    None => "".to_owned(),
                };

                Some(format!("{}{}{}{}", prefix, mut_infix, id_str, sub_pat))
            }
            PatKind::Wild => {
                if 1 <= shape.width {
                    Some("_".to_owned())
                } else {
                    None
                }
            }
            PatKind::Range(ref lhs, ref rhs, ref end_kind) => {
                let infix = match end_kind.node {
                    RangeEnd::Included(RangeSyntax::DotDotDot) => "...",
                    RangeEnd::Included(RangeSyntax::DotDotEq) => "..=",
                    RangeEnd::Excluded => "..",
                };
                let infix = if context.config.spaces_around_ranges() {
                    format!(" {} ", infix)
                } else {
                    infix.to_owned()
                };
                rewrite_pair(
                    &**lhs,
                    &**rhs,
                    PairParts::new("", &infix, ""),
                    context,
                    shape,
                    SeparatorPlace::Front,
                )
            }
            PatKind::Ref(ref pat, mutability) => {
                let prefix = format!("&{}", format_mutability(mutability));
                rewrite_unary_prefix(context, &prefix, &**pat, shape)
            }
            PatKind::Tuple(ref items, dotdot_pos) => {
                rewrite_tuple_pat(items, dotdot_pos, None, self.span, context, shape)
            }
            PatKind::Path(ref q_self, ref path) => {
                rewrite_path(context, PathContext::Expr, q_self.as_ref(), path, shape)
            }
            PatKind::TupleStruct(ref path, ref pat_vec, dotdot_pos) => {
                let path_str = rewrite_path(context, PathContext::Expr, None, path, shape)?;
                rewrite_tuple_pat(
                    pat_vec,
                    dotdot_pos,
                    Some(path_str),
                    self.span,
                    context,
                    shape,
                )
            }
            PatKind::Lit(ref expr) => expr.rewrite(context, shape),
            PatKind::Slice(ref prefix, ref slice_pat, ref suffix) => {
                // Rewrite all the sub-patterns.
                let prefix = prefix.iter().map(|p| p.rewrite(context, shape));
                let slice_pat = slice_pat
                    .as_ref()
                    .map(|p| Some(format!("{}..", p.rewrite(context, shape)?)));
                let suffix = suffix.iter().map(|p| p.rewrite(context, shape));

                // Munge them together.
                let pats: Option<Vec<String>> =
                    prefix.chain(slice_pat.into_iter()).chain(suffix).collect();

                // Check that all the rewrites succeeded, and if not return None.
                let pats = pats?;

                // Unwrap all the sub-strings and join them with commas.
                Some(format!("[{}]", pats.join(", ")))
            }
            PatKind::Struct(ref path, ref fields, ellipsis) => {
                rewrite_struct_pat(path, fields, ellipsis, self.span, context, shape)
            }
            PatKind::Mac(ref mac) => rewrite_macro(mac, None, context, shape, MacroPosition::Pat),
            PatKind::Paren(ref pat) => pat
                .rewrite(context, shape.offset_left(1)?.sub_width(1)?)
                .map(|inner_pat| format!("({})", inner_pat)),
        }
    }
}

fn rewrite_struct_pat(
    path: &ast::Path,
    fields: &[codemap::Spanned<ast::FieldPat>],
    ellipsis: bool,
    span: Span,
    context: &RewriteContext,
    shape: Shape,
) -> Option<String> {
    // 2 =  ` {`
    let path_shape = shape.sub_width(2)?;
    let path_str = rewrite_path(context, PathContext::Expr, None, path, path_shape)?;

    if fields.is_empty() && !ellipsis {
        return Some(format!("{} {{}}", path_str));
    }

    let (ellipsis_str, terminator) = if ellipsis { (", ..", "..") } else { ("", "}") };

    // 3 = ` { `, 2 = ` }`.
    let (h_shape, v_shape) =
        struct_lit_shape(shape, context, path_str.len() + 3, ellipsis_str.len() + 2)?;

    let items = itemize_list(
        context.snippet_provider,
        fields.iter(),
        terminator,
        ",",
        |f| f.span.lo(),
        |f| f.span.hi(),
        |f| f.node.rewrite(context, v_shape),
        context.snippet_provider.span_after(span, "{"),
        span.hi(),
        false,
    );
    let item_vec = items.collect::<Vec<_>>();

    let tactic = struct_lit_tactic(h_shape, context, &item_vec);
    let nested_shape = shape_for_tactic(tactic, h_shape, v_shape);
    let fmt = struct_lit_formatting(nested_shape, tactic, context, false);

    let mut fields_str = write_list(&item_vec, &fmt)?;
    let one_line_width = h_shape.map_or(0, |shape| shape.width);

    if ellipsis {
        if fields_str.contains('\n') || fields_str.len() > one_line_width {
            // Add a missing trailing comma.
            if fmt.trailing_separator == SeparatorTactic::Never {
                fields_str.push_str(",");
            }
            fields_str.push_str("\n");
            fields_str.push_str(&nested_shape.indent.to_string(context.config));
            fields_str.push_str("..");
        } else {
            if !fields_str.is_empty() {
                // there are preceding struct fields being matched on
                if fmt.tactic == DefinitiveListTactic::Vertical {
                    // if the tactic is Vertical, write_list already added a trailing ,
                    fields_str.push_str(" ");
                } else {
                    fields_str.push_str(", ");
                }
            }
            fields_str.push_str("..");
        }
    }

    let fields_str = wrap_struct_field(context, &fields_str, shape, v_shape, one_line_width);
    Some(format!("{} {{{}}}", path_str, fields_str))
}

impl Rewrite for FieldPat {
    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
        let pat = self.pat.rewrite(context, shape);
        if self.is_shorthand {
            pat
        } else {
            let pat_str = pat?;
            let id_str = rewrite_ident(context, self.ident);
            let one_line_width = id_str.len() + 2 + pat_str.len();
            if one_line_width <= shape.width {
                Some(format!("{}: {}", id_str, pat_str))
            } else {
                let nested_shape = shape.block_indent(context.config.tab_spaces());
                let pat_str = self.pat.rewrite(context, nested_shape)?;
                Some(format!(
                    "{}:\n{}{}",
                    id_str,
                    nested_shape.indent.to_string(context.config),
                    pat_str,
                ))
            }
        }
    }
}

pub enum TuplePatField<'a> {
    Pat(&'a ptr::P<ast::Pat>),
    Dotdot(Span),
}

impl<'a> Rewrite for TuplePatField<'a> {
    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
        match *self {
            TuplePatField::Pat(p) => p.rewrite(context, shape),
            TuplePatField::Dotdot(_) => Some("..".to_string()),
        }
    }
}

impl<'a> Spanned for TuplePatField<'a> {
    fn span(&self) -> Span {
        match *self {
            TuplePatField::Pat(p) => p.span(),
            TuplePatField::Dotdot(span) => span,
        }
    }
}

pub fn can_be_overflowed_pat(context: &RewriteContext, pat: &TuplePatField, len: usize) -> bool {
    match *pat {
        TuplePatField::Pat(pat) => match pat.node {
            ast::PatKind::Path(..)
            | ast::PatKind::Tuple(..)
            | ast::PatKind::Struct(..)
            | ast::PatKind::TupleStruct(..) => context.use_block_indent() && len == 1,
            ast::PatKind::Ref(ref p, _) | ast::PatKind::Box(ref p) => {
                can_be_overflowed_pat(context, &TuplePatField::Pat(p), len)
            }
            ast::PatKind::Lit(ref expr) => can_be_overflowed_expr(context, expr, len),
            _ => false,
        },
        TuplePatField::Dotdot(..) => false,
    }
}

fn rewrite_tuple_pat(
    pats: &[ptr::P<ast::Pat>],
    dotdot_pos: Option<usize>,
    path_str: Option<String>,
    span: Span,
    context: &RewriteContext,
    shape: Shape,
) -> Option<String> {
    let mut pat_vec: Vec<_> = pats.into_iter().map(|x| TuplePatField::Pat(x)).collect();

    if let Some(pos) = dotdot_pos {
        let prev = if pos == 0 {
            span.lo()
        } else {
            pats[pos - 1].span().hi()
        };
        let next = if pos + 1 >= pats.len() {
            span.hi()
        } else {
            pats[pos + 1].span().lo()
        };
        let dot_span = mk_sp(prev, next);
        let snippet = context.snippet(dot_span);
        let lo = dot_span.lo() + BytePos(snippet.find_uncommented("..").unwrap() as u32);
        let dotdot = TuplePatField::Dotdot(Span::new(
            lo,
            // 2 == "..".len()
            lo + BytePos(2),
            codemap::NO_EXPANSION,
        ));
        pat_vec.insert(pos, dotdot);
    }

    if pat_vec.is_empty() {
        return Some(format!("{}()", path_str.unwrap_or_default()));
    }

    let wildcard_suffix_len = count_wildcard_suffix_len(context, &pat_vec, span, shape);
    let (pat_vec, span) = if context.config.condense_wildcard_suffixes() && wildcard_suffix_len >= 2
    {
        let new_item_count = 1 + pat_vec.len() - wildcard_suffix_len;
        let sp = pat_vec[new_item_count - 1].span();
        let snippet = context.snippet(sp);
        let lo = sp.lo() + BytePos(snippet.find_uncommented("_").unwrap() as u32);
        pat_vec[new_item_count - 1] = TuplePatField::Dotdot(mk_sp(lo, lo + BytePos(1)));
        (
            &pat_vec[..new_item_count],
            mk_sp(span.lo(), lo + BytePos(1)),
        )
    } else {
        (&pat_vec[..], span)
    };

    // add comma if `(x,)`
    let add_comma = path_str.is_none() && pat_vec.len() == 1 && dotdot_pos.is_none();
    let path_str = path_str.unwrap_or_default();
    let pat_ref_vec = pat_vec.iter().collect::<Vec<_>>();

    overflow::rewrite_with_parens(
        &context,
        &path_str,
        &pat_ref_vec,
        shape,
        span,
        context.config.max_width(),
        if add_comma {
            Some(SeparatorTactic::Always)
        } else {
            None
        },
    )
}

fn count_wildcard_suffix_len(
    context: &RewriteContext,
    patterns: &[TuplePatField],
    span: Span,
    shape: Shape,
) -> usize {
    let mut suffix_len = 0;

    let items: Vec<_> = itemize_list(
        context.snippet_provider,
        patterns.iter(),
        ")",
        ",",
        |item| item.span().lo(),
        |item| item.span().hi(),
        |item| item.rewrite(context, shape),
        context.snippet_provider.span_after(span, "("),
        span.hi() - BytePos(1),
        false,
    ).collect();

    for item in items.iter().rev().take_while(|i| match i.item {
        Some(ref internal_string) if internal_string == "_" => true,
        _ => false,
    }) {
        suffix_len += 1;

        if item.has_comment() {
            break;
        }
    }

    suffix_len
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use hyper::Url;
use hyper::client::{Client, IntoUrl, Response};
use hyper::header::ContentType;
use hyper::status::StatusCode;
use rustc_serialize::json::Json;

pub struct FleetAPI {
    root_url: &'static str,
}

impl FleetAPI {
    pub fn new(root_url: &'static str) -> FleetAPI {
        FleetAPI {
            root_url: root_url
        }
    }

    pub fn destroy_unit(&self, name: &str) -> Result<(), String> {
        let url = &self.url(&format!("/units/{}", name))[..];
        let response = self.delete(url);

        match response.status {
            StatusCode::Ok => Ok(()),
            StatusCode::NotFound => Err("Unit not found".to_string()),
            status_code => Err(format!("Unexpected response: {}", status_code)),
        }
    }

    pub fn get_unit(&self, name: &str) -> Result<Json, String> {
        let url = &self.url(&format!("/units/{}", name))[..];
        let mut response = self.get(url);

        match response.status {
            StatusCode::Ok => {
                let json = Json::from_reader(&mut response).unwrap();
                Ok(json.find("unit").unwrap().clone())
            },
            StatusCode::NotFound => Err("Unit not found".to_string()),
            status_code => Err(format!("Unexpected response: {}", status_code)),
        }
    }

    pub fn get_unit_states(&self, query_pairs: HashMap<&str, &str>) -> Result<Vec<Json>, String> {
        let base_url = &self.url("/state")[..];
        let mut url = Url::parse(base_url).unwrap();
        url.set_query_from_pairs(query_pairs.iter().map(|(k, v)| (*k, *v)));
        let mut response = self.get(url);

        match response.status {
            StatusCode::Ok => {
                let json = Json::from_reader(&mut response).unwrap();
                Ok(json.find("unit_states").unwrap().as_array().unwrap().clone())
            },
            status_code => Err(format!("Unexpected response: {}", status_code)),
        }
    }

    pub fn get_units(&self) -> Result<Vec<Json>, String> {
        let url = &self.url("/units")[..];
        let mut response = self.get(url);

        match response.status {
            StatusCode::Ok => {
                let json = Json::from_reader(&mut response).unwrap();
                Ok(json.find("units").unwrap().as_array().unwrap().clone())
            },
            status_code => Err(format!("Unexpected response: {}", status_code)),
        }
    }

    pub fn put_unit(&self, name: &'static str, body: &str) -> Result<(), String> {
        let url = &self.url(&format!("/units/{}", name))[..];
        let response = self.put(url, body);

        match response.status {
            StatusCode::Created => Ok(()),
            StatusCode::NoContent => Ok(()),
            StatusCode::Conflict => Err("UnitOptions are required".to_string()),
            StatusCode::BadRequest => Err("Invalid unit".to_string()),
            status_code => Err(format!("Unexpected response: {}", status_code))
        }
    }

    fn delete(&self, url: &str) -> Response {
        let mut client = Client::new();
        let content_type: ContentType = ContentType("application/json".parse().unwrap());

        client.delete(url).header(content_type).send().unwrap()
    }

    fn get<U: IntoUrl>(&self, url: U) -> Response {
        let mut client = Client::new();
        let content_type: ContentType = ContentType("application/json".parse().unwrap());

        client.get(url).header(content_type).send().unwrap()
    }

    fn put(&self, url: &str, body: &str) -> Response {
        let mut client = Client::new();
        let content_type: ContentType = ContentType("application/json".parse().unwrap());

        client.put(url).header(content_type).body(body).send().unwrap()
    }

    fn url(&self, path: &str) -> String {
        format!("{}{}", self.root_url, path)
    }
}
<commit_msg>Correct JSON parsing based on top level key names from the JSON schema in the fleet repo.<commit_after>use std::collections::HashMap;

use hyper::Url;
use hyper::client::{Client, IntoUrl, Response};
use hyper::header::ContentType;
use hyper::status::StatusCode;
use rustc_serialize::json::Json;

pub struct FleetAPI {
    root_url: &'static str,
}

impl FleetAPI {
    pub fn new(root_url: &'static str) -> FleetAPI {
        FleetAPI {
            root_url: root_url
        }
    }

    pub fn destroy_unit(&self, name: &str) -> Result<(), String> {
        let url = &self.url(&format!("/units/{}", name))[..];
        let response = self.delete(url);

        match response.status {
            StatusCode::Ok => Ok(()),
            StatusCode::NotFound => Err("Unit not found".to_string()),
            status_code => Err(format!("Unexpected response: {}", status_code)),
        }
    }

    pub fn get_unit(&self, name: &str) -> Result<Json, String> {
        let url = &self.url(&format!("/units/{}", name))[..];
        let mut response = self.get(url);

        match response.status {
            StatusCode::Ok => {
                Ok(Json::from_reader(&mut response).unwrap())
            },
            StatusCode::NotFound => Err("Unit not found".to_string()),
            status_code => Err(format!("Unexpected response: {}", status_code)),
        }
    }

    pub fn get_unit_states(&self, query_pairs: HashMap<&str, &str>) -> Result<Vec<Json>, String> {
        let base_url = &self.url("/state")[..];
        let mut url = Url::parse(base_url).unwrap();
        url.set_query_from_pairs(query_pairs.iter().map(|(k, v)| (*k, *v)));
        let mut response = self.get(url);

        match response.status {
            StatusCode::Ok => {
                let json = Json::from_reader(&mut response).unwrap();
                Ok(json.find("states").unwrap().as_array().unwrap().clone())
            },
            status_code => Err(format!("Unexpected response: {}", status_code)),
        }
    }

    pub fn get_units(&self) -> Result<Vec<Json>, String> {
        let url = &self.url("/units")[..];
        let mut response = self.get(url);

        match response.status {
            StatusCode::Ok => {
                let json = Json::from_reader(&mut response).unwrap();
                Ok(json.find("units").unwrap().as_array().unwrap().clone())
            },
            status_code => Err(format!("Unexpected response: {}", status_code)),
        }
    }

    pub fn put_unit(&self, name: &'static str, body: &str) -> Result<(), String> {
        let url = &self.url(&format!("/units/{}", name))[..];
        let response = self.put(url, body);

        match response.status {
            StatusCode::Created => Ok(()),
            StatusCode::NoContent => Ok(()),
            StatusCode::Conflict => Err("UnitOptions are required".to_string()),
            StatusCode::BadRequest => Err("Invalid unit".to_string()),
            status_code => Err(format!("Unexpected response: {}", status_code))
        }
    }

    fn delete(&self, url: &str) -> Response {
        let mut client = Client::new();
        let content_type: ContentType = ContentType("application/json".parse().unwrap());

        client.delete(url).header(content_type).send().unwrap()
    }

    fn get<U: IntoUrl>(&self, url: U) -> Response {
        let mut client = Client::new();
        let content_type: ContentType = ContentType("application/json".parse().unwrap());

        client.get(url).header(content_type).send().unwrap()
    }

    fn put(&self, url: &str, body: &str) -> Response {
        let mut client = Client::new();
        let content_type: ContentType = ContentType("application/json".parse().unwrap());

        client.put(url).header(content_type).body(body).send().unwrap()
    }

    fn url(&self, path: &str) -> String {
        format!("{}{}", self.root_url, path)
    }
}
<|endoftext|>


<commit_before>use std::ops::Deref;
use std::sync::{Arc, Mutex, RwLock};
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::collections::hash_state::DefaultState;

use std::mem;
use std::rc::Rc;
use linked_hash_map::LinkedHashMap;
use time::precise_time_s;
use fnv::FnvHasher;

use config::*;
use queue_backend::*;

#[derive(Debug)]
pub struct Channel {
    tail: u64,
    message_count: u64,
    in_flight: LinkedHashMap<u64, u32, DefaultState<FnvHasher>>
}

#[derive(Debug)]
pub struct Queue {
    config: Rc<QueueConfig>,
    // backend writes don't block readers
    // FIXME: queue_backend should handle it's concurrency access internally,
    // both for simplicity and performance
    backend_wlock: Mutex<()>,
    backend_rlock: RwLock<()>,
    backend: QueueBackend,
    channels: RwLock<HashMap<String, Mutex<Channel>, DefaultState<FnvHasher>>>,
    clock: u32
}

#[derive(Clone)]
pub struct ArcQueue(Arc<Queue>);

unsafe impl Sync for ArcQueue {}
unsafe impl Send for ArcQueue {}

impl Deref for ArcQueue {
    type Target = Queue;
    fn deref(&self) -> &Self::Target {
        let &ArcQueue(ref queue) = self;
        queue
    }
}

impl ArcQueue {
    pub fn new(queue: Queue) -> ArcQueue {
        ArcQueue(Arc::new(queue))
    }
}

impl Queue {

    pub fn new(config: QueueConfig, recover: bool) -> Queue {
        let rc_config = Rc::new(config);
        let mut queue = Queue {
            config: rc_config.clone(),
            backend_wlock: Mutex::new(()),
            backend_rlock: RwLock::new(()),
            backend: QueueBackend::new(rc_config.clone(), recover),
            channels: RwLock::new(Default::default()),
            clock: 0,
        };
        queue.tick();
        queue
    }

    pub fn create_channel<S>(&mut self, channel_name: S) -> bool
            where String: From<S> {
        let channel_name: String = channel_name.into();
        let mut locked_channel = self.channels.write().unwrap();
        if let Entry::Vacant(vacant_entry) = locked_channel.entry(channel_name) {
            vacant_entry.insert(
                Mutex::new(
                    Channel {
                        tail: 0,
                        message_count: 0,
                        in_flight: Default::default()
                    }
                )
            );
            true
        } else {
            false
        }
    }

    pub fn delete_channel(&mut self, channel_name: &str) -> bool {
        let mut locked_channel = self.channels.write().unwrap();
        locked_channel.remove(channel_name).is_some()
    }

    /// get access is suposed to be thread-safe, even while writing
    pub fn get(&mut self, channel_name: &str) -> Option<Message> {
        let _ = self.backend_rlock.read().unwrap();
        let locked_channels = self.channels.read().unwrap();
        if let Some(channel) = locked_channels.get(channel_name) {
            let mut locked_channel = channel.lock().unwrap();

            // check in flight queue for timeouts
            if let Some((&id, &expires)) = locked_channel.in_flight.front() {
                if self.clock >= expires {
                    // FIXME: double get bellow, not ideal
                    let new_expires = locked_channel.in_flight.get_refresh(&id).unwrap();
                    *new_expires = self.clock + self.config.time_to_live;
                    trace!("[{}] msg {} expired and will be sent again", self.config.name, id);
                    return Some(self.backend.get(id).unwrap().1)
                }
            }

            // fetch from the backend
            if let Some((new_tail, message)) = self.backend.get(locked_channel.tail) {
                locked_channel.tail = new_tail;
                locked_channel.in_flight.insert(message.id, self.clock + self.config.time_to_live);
                trace!("[{}] fetched msg {} from backend", self.config.name, message.id);
                return Some(message)
            }
        }
        None
    }

    /// all calls are serialized internally
    pub fn put(&mut self, message: &Message) -> Option<u64> {
        let _ = self.backend_wlock.lock().unwrap();
        trace!("[{}] putting message", self.config.name);
        self.backend.put(message)
    }

    /// delete access is suposed to be thread-safe, even while writing
    pub fn delete(&mut self, channel_name: &str, id: u64) -> Option<bool> {
        let _ = self.backend_rlock.read().unwrap();
        let locked_channels = self.channels.read().unwrap();
        if let Some(channel) = locked_channels.get(channel_name) {
            let removed_opt = channel.lock().unwrap().in_flight.remove(&id);
            trace!("[{}] message {} deleted from channel: {}",
                self.config.name, id, removed_opt.is_some());
            return Some(removed_opt.is_some())
        }
        None
    }

    pub fn purge(&mut self) {
        info!("[{}] purging", self.config.name);
        let _ = self.backend_rlock.write().unwrap();
        let _ = self.backend_wlock.lock().unwrap();
        self.backend.purge();
        self.channels.write().unwrap().clear();
    }

    pub fn maintenance(&mut self) {
        // add gc code here
    }

    pub fn tick(&mut self) {
        self.clock = precise_time_s() as u32;
        debug!("[{}] tick to {}", self.config.name, self.clock);
    }

    #[allow(mutable_transmutes)]
    pub fn as_mut(&self) -> &mut Self {
        unsafe { mem::transmute(self) }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use config::*;
    use queue_backend::Message;
    use std::thread;
    use test;

    fn get_queue_opt(name: &str, recover: bool) -> Queue {
        let server_config = ServerConfig::read();
        let mut queue_config = server_config.new_queue_config(name);
        queue_config.time_to_live = 1;
        let mut queue = Queue::new(queue_config, recover);
        queue
    }

    fn get_queue() -> Queue {
        let thread = thread::current();
        let name = thread.name().unwrap().split("::").last().unwrap();
        get_queue_opt(name, false)
    }

    fn gen_message(id: u64) -> Message<'static> {
        Message {
            id: id,
            body: b"333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333"
        }
    }

    fn init_logger() {
        use env_logger;
        env_logger::init();
    }

    #[test]
    fn test_fill() {
        let mut q = get_queue();
        let message = gen_message(0);
        for i in (0..100_000) {
            let r = q.put(&message);
            assert!(r.is_some());
        }
    }

    #[test]
    fn test_put_get() {
        let mut q = get_queue();
        let message = gen_message(0);
        assert!(q.create_channel("test"));
        for i in (0..100_000) {
            assert!(q.put(&message).is_some());
            let m = q.get("test");
            assert!(m.is_some());
        }
    }

    #[test]
    fn test_create_channel() {
        let mut q = get_queue();
        let message = gen_message(0);
        assert!(q.get("test").is_none());
        assert!(q.put(&message).is_some());
        assert!(q.create_channel("test") == true);
        assert!(q.create_channel("test") == false);
        assert!(q.get("test").is_some());
    }

    #[test]
    fn test_in_flight() {
        let mut q = get_queue();
        let message = gen_message(0);
        assert!(q.get("test").is_none());
        assert!(q.put(&message).is_some());
        assert!(q.create_channel("test") == true);
        assert!(q.create_channel("test") == false);
        assert!(q.get("test").is_some());
        assert!(q.get("test").is_none());
        // TODO: check in flight count
    }

    #[test]
    fn test_in_flight_timeout() {
        let mut q = get_queue();
        let message = gen_message(0);
        assert!(q.create_channel("test") == true);
        assert!(q.put(&message).is_some());
        assert!(q.get("test").is_some());
        assert!(q.get("test").is_none());
        thread::sleep_ms(1001);
        q.tick();
        assert!(q.get("test").is_some());
    }

    #[test]
    fn test_backend_recover() {
        init_logger();
        let mut q = get_queue_opt("test_reopen", false);
        let message = gen_message(0);
        let mut put_msg_count = 0;
        while q.backend.files_count() < 3 {
            assert!(q.put(&message).is_some());
            put_msg_count += 1;
        }
        drop(q);

        let mut q = get_queue_opt("test_reopen", true);
        assert!(q.create_channel("test") == true);
        assert_eq!(q.backend.files_count(), 3);
        let mut get_msg_count = 0;
        while let Some(_) = q.get("test") {
            get_msg_count += 1;
        }
        assert_eq!(get_msg_count, put_msg_count);
    }

    #[test]
    fn test_queue_recover() {
        // Add code here
    }

    #[bench]
    fn put_like_crazy(b: &mut test::Bencher) {
        let mut q = get_queue();
        let m = &gen_message(0);
        let n = 10000;
        b.bytes = (m.body.len() * n) as u64;
        b.iter(|| {
            for _ in (0..n) {
                let r = q.put(m);
                assert!(r.is_some());
            }
        });
    }

    #[bench]
    fn put_get_like_crazy(b: &mut test::Bencher) {
        let mut q = get_queue();
        let m = &gen_message(0);
        let n = 10000;
        q.create_channel("test");
        b.bytes = (m.body.len() * n) as u64;
        b.iter(|| {
            for _ in (0..n) {
                let p = q.put(m);
                let r = q.get("test");
                assert_eq!(p.unwrap(), r.unwrap().id);
            }
        });
    }
}
<commit_msg>store more information for in-flight messages<commit_after>use std::ops::Deref;
use std::sync::{Arc, Mutex, RwLock};
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::collections::hash_state::DefaultState;

use std::mem;
use std::rc::Rc;
use linked_hash_map::LinkedHashMap;
use time::precise_time_s;
use fnv::FnvHasher;

use config::*;
use queue_backend::*;

#[derive(Debug)]
struct InFlightState {
    expiration: u32,
    retry: u32,
}

#[derive(Debug)]
pub struct Channel {
    tail: u64,
    message_count: u64,
    in_flight: LinkedHashMap<u64, InFlightState, DefaultState<FnvHasher>>
}

#[derive(Debug)]
pub struct Queue {
    config: Rc<QueueConfig>,
    // backend writes don't block readers
    // FIXME: queue_backend should handle it's concurrency access internally,
    // both for simplicity and performance
    backend_wlock: Mutex<()>,
    backend_rlock: RwLock<()>,
    backend: QueueBackend,
    channels: RwLock<HashMap<String, Mutex<Channel>, DefaultState<FnvHasher>>>,
    clock: u32
}

#[derive(Clone)]
pub struct ArcQueue(Arc<Queue>);

unsafe impl Sync for ArcQueue {}
unsafe impl Send for ArcQueue {}

impl Deref for ArcQueue {
    type Target = Queue;
    fn deref(&self) -> &Self::Target {
        let &ArcQueue(ref queue) = self;
        queue
    }
}

impl ArcQueue {
    pub fn new(queue: Queue) -> ArcQueue {
        ArcQueue(Arc::new(queue))
    }
}

impl Queue {

    pub fn new(config: QueueConfig, recover: bool) -> Queue {
        let rc_config = Rc::new(config);
        let mut queue = Queue {
            config: rc_config.clone(),
            backend_wlock: Mutex::new(()),
            backend_rlock: RwLock::new(()),
            backend: QueueBackend::new(rc_config.clone(), recover),
            channels: RwLock::new(Default::default()),
            clock: 0,
        };
        queue.tick();
        queue
    }

    pub fn create_channel<S>(&mut self, channel_name: S) -> bool
            where String: From<S> {
        let channel_name: String = channel_name.into();
        let mut locked_channel = self.channels.write().unwrap();
        if let Entry::Vacant(vacant_entry) = locked_channel.entry(channel_name) {
            vacant_entry.insert(
                Mutex::new(
                    Channel {
                        tail: 0,
                        message_count: 0,
                        in_flight: Default::default()
                    }
                )
            );
            true
        } else {
            false
        }
    }

    pub fn delete_channel(&mut self, channel_name: &str) -> bool {
        let mut locked_channel = self.channels.write().unwrap();
        locked_channel.remove(channel_name).is_some()
    }

    /// get access is suposed to be thread-safe, even while writing
    pub fn get(&mut self, channel_name: &str) -> Option<Message> {
        let _ = self.backend_rlock.read().unwrap();
        let locked_channels = self.channels.read().unwrap();
        if let Some(channel) = locked_channels.get(channel_name) {
            let mut locked_channel = channel.lock().unwrap();

            // check in flight queue for timeouts
            if let Some((&id, &InFlightState { expiration, ..} )) = locked_channel.in_flight.front() {
                if self.clock >= expiration {
                    // FIXME: double get bellow, not ideal
                    let state = locked_channel.in_flight.get_refresh(&id).unwrap();
                    state.expiration = self.clock + self.config.time_to_live;
                    state.retry += 1;
                    trace!("[{}] msg {} expired and will be sent again", self.config.name, id);
                    return Some(self.backend.get(id).unwrap().1)
                }
            }

            // fetch from the backend
            if let Some((new_tail, message)) = self.backend.get(locked_channel.tail) {
                locked_channel.tail = new_tail;
                let state = InFlightState {
                    expiration: self.clock + self.config.time_to_live,
                    retry: 0
                };
                locked_channel.in_flight.insert(message.id, state);
                trace!("[{}] fetched msg {} from backend", self.config.name, message.id);
                return Some(message)
            }
        }
        None
    }

    /// all calls are serialized internally
    pub fn put(&mut self, message: &Message) -> Option<u64> {
        let _ = self.backend_wlock.lock().unwrap();
        trace!("[{}] putting message", self.config.name);
        self.backend.put(message)
    }

    /// delete access is suposed to be thread-safe, even while writing
    pub fn delete(&mut self, channel_name: &str, id: u64) -> Option<bool> {
        let _ = self.backend_rlock.read().unwrap();
        let locked_channels = self.channels.read().unwrap();
        if let Some(channel) = locked_channels.get(channel_name) {
            let removed_opt = channel.lock().unwrap().in_flight.remove(&id);
            trace!("[{}] message {} deleted from channel: {}",
                self.config.name, id, removed_opt.is_some());
            return Some(removed_opt.is_some())
        }
        None
    }

    pub fn purge(&mut self) {
        info!("[{}] purging", self.config.name);
        let _ = self.backend_rlock.write().unwrap();
        let _ = self.backend_wlock.lock().unwrap();
        self.backend.purge();
        self.channels.write().unwrap().clear();
    }

    pub fn maintenance(&mut self) {
        // add gc code here
    }

    pub fn tick(&mut self) {
        self.clock = precise_time_s() as u32;
        debug!("[{}] tick to {}", self.config.name, self.clock);
    }

    #[allow(mutable_transmutes)]
    pub fn as_mut(&self) -> &mut Self {
        unsafe { mem::transmute(self) }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use config::*;
    use queue_backend::Message;
    use std::thread;
    use test;

    fn get_queue_opt(name: &str, recover: bool) -> Queue {
        let server_config = ServerConfig::read();
        let mut queue_config = server_config.new_queue_config(name);
        queue_config.time_to_live = 1;
        let mut queue = Queue::new(queue_config, recover);
        queue
    }

    fn get_queue() -> Queue {
        let thread = thread::current();
        let name = thread.name().unwrap().split("::").last().unwrap();
        get_queue_opt(name, false)
    }

    fn gen_message(id: u64) -> Message<'static> {
        Message {
            id: id,
            body: b"333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333"
        }
    }

    fn init_logger() {
        use env_logger;
        env_logger::init();
    }

    #[test]
    fn test_fill() {
        let mut q = get_queue();
        let message = gen_message(0);
        for i in (0..100_000) {
            let r = q.put(&message);
            assert!(r.is_some());
        }
    }

    #[test]
    fn test_put_get() {
        let mut q = get_queue();
        let message = gen_message(0);
        assert!(q.create_channel("test"));
        for i in (0..100_000) {
            assert!(q.put(&message).is_some());
            let m = q.get("test");
            assert!(m.is_some());
        }
    }

    #[test]
    fn test_create_channel() {
        let mut q = get_queue();
        let message = gen_message(0);
        assert!(q.get("test").is_none());
        assert!(q.put(&message).is_some());
        assert!(q.create_channel("test") == true);
        assert!(q.create_channel("test") == false);
        assert!(q.get("test").is_some());
    }

    #[test]
    fn test_in_flight() {
        let mut q = get_queue();
        let message = gen_message(0);
        assert!(q.get("test").is_none());
        assert!(q.put(&message).is_some());
        assert!(q.create_channel("test") == true);
        assert!(q.create_channel("test") == false);
        assert!(q.get("test").is_some());
        assert!(q.get("test").is_none());
        // TODO: check in flight count
    }

    #[test]
    fn test_in_flight_timeout() {
        let mut q = get_queue();
        let message = gen_message(0);
        assert!(q.create_channel("test") == true);
        assert!(q.put(&message).is_some());
        assert!(q.get("test").is_some());
        assert!(q.get("test").is_none());
        thread::sleep_ms(1001);
        q.tick();
        assert!(q.get("test").is_some());
    }

    #[test]
    fn test_backend_recover() {
        init_logger();
        let mut q = get_queue_opt("test_reopen", false);
        let message = gen_message(0);
        let mut put_msg_count = 0;
        while q.backend.files_count() < 3 {
            assert!(q.put(&message).is_some());
            put_msg_count += 1;
        }
        drop(q);

        let mut q = get_queue_opt("test_reopen", true);
        assert!(q.create_channel("test") == true);
        assert_eq!(q.backend.files_count(), 3);
        let mut get_msg_count = 0;
        while let Some(_) = q.get("test") {
            get_msg_count += 1;
        }
        assert_eq!(get_msg_count, put_msg_count);
    }

    #[test]
    fn test_queue_recover() {
        // Add code here
    }

    #[bench]
    fn put_like_crazy(b: &mut test::Bencher) {
        let mut q = get_queue();
        let m = &gen_message(0);
        let n = 10000;
        b.bytes = (m.body.len() * n) as u64;
        b.iter(|| {
            for _ in (0..n) {
                let r = q.put(m);
                assert!(r.is_some());
            }
        });
    }

    #[bench]
    fn put_get_like_crazy(b: &mut test::Bencher) {
        let mut q = get_queue();
        let m = &gen_message(0);
        let n = 10000;
        q.create_channel("test");
        b.bytes = (m.body.len() * n) as u64;
        b.iter(|| {
            for _ in (0..n) {
                let p = q.put(m);
                let r = q.get("test");
                assert_eq!(p.unwrap(), r.unwrap().id);
            }
        });
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate image;
use clap::{Arg,App,SubCommand};
use std::fs::File;
use image::{FilterType, GenericImage, Pixel};
use image::DynamicImage;

fn main() {
     let matches = App::new("IPCLI")
                          .version("0.1")
                          .author("Mikolaj Wawrzyniak <mikolaj.wawrzyniak at fh-dortmund.de>")
                          .about("Basic CLI for image processing")
                          .arg(Arg::with_name("image")
                               .short("i")
                               .long("image")
                               .value_name("FILE")
                               .help("Opens specified image file and uses it for transformations.")
                               .takes_value(true))
                          .arg(Arg::with_name("save")
                               .short("s")
                               .long("save")
                               .value_name("FILE")
                               .help("Copies provided image to specified file.")
                               .takes_value(true))
                          .get_matches();

    // Gets a value for config if supplied by user, or defaults to "default.conf"
    let imagePath = matches.value_of("image").unwrap_or("empty");
    println!("Value for image path: {}", imagePath);

    let savePath = matches.value_of("save").unwrap_or("empty");
    println!("Value for save path: {}", savePath);

    openAndSave(imagePath, savePath);
    // Vary the output based on how many times the user used the "verbose" flag
    // (i.e. 'myprog -v -v -v' or 'myprog -vvv' vs 'myprog -v'
    match matches.occurrences_of("v") {
        0 => println!("No verbose info"),
        1 => println!("Some verbose info"),
        2 => println!("Tons of verbose info"),
        3 | _ => println!("Don't be crazy"),
    }
}

fn openAndSave(i: &str, s: &str){
    let img = image::open(i).expect("Opening image failed");
    let mut out = File::create(s).unwrap();
    img.save(&mut out, image::PNG).expect("Saving image failed");
}
<commit_msg>Added mutliple file output formats<commit_after>extern crate clap;
extern crate image;
use clap::{Arg,App,SubCommand};
use std::fs::File;
use image::{FilterType, GenericImage, Pixel};
use image::DynamicImage;

fn main() {
     let matches = App::new("IPCLI")
                          .version("0.1")
                          .author("Mikolaj Wawrzyniak <mikolaj.wawrzyniak at fh-dortmund.de>")
                          .about("Basic CLI for image processing")
                          .arg(Arg::with_name("image")
                               .short("i")
                               .long("image")
                               .value_name("FILE")
                               .help("Opens specified image file and uses it for transformations.")
                               .takes_value(true)
                               .required(true))
                          .arg(Arg::with_name("save")
                               .short("s")
                               .long("save")
                               .value_name("FILE")
                               .help("Outputs transformed image into specified file.")
                               .takes_value(true)
                               .required(true))
                          .get_matches();

    // Gets a value for config if supplied by user, or defaults to "default.conf"
    let imagePath = matches.value_of("image").unwrap_or("empty");
    println!("Transforming the image: {}", imagePath);

    let savePath = matches.value_of("save").unwrap_or("empty");
    println!("Into: {}", savePath);

    openAndSave(imagePath, savePath);
    // Vary the output based on how many times the user used the "verbose" flag
    // (i.e. 'myprog -v -v -v' or 'myprog -vvv' vs 'myprog -v'
    match matches.occurrences_of("v") {
        0 => println!("No verbose info"),
        1 => println!("Some verbose info"),
        2 => println!("Tons of verbose info"),
        3 | _ => println!("Don't be crazy"),
    }
}

fn openAndSave(i: &str, s: &str){
    let img = image::open(i).expect("Opening image failed");
    // get the type of the image
    let ext: String = i.chars().skip(i.len()-3).take(3).collect();
    let mut out = File::create(s).unwrap();
    match ext.as_ref() {
        "jpg" => {img.save(&mut out, image::JPEG).expect("Saving image failed");}
        "png" => {img.save(&mut out, image::PNG).expect("Saving image failed");}
        _ => {println!("something else")}
    }

}
<|endoftext|>


<commit_before>use tile::Tile;
use util::Grid;
use std::ops::{Index};
use na::Vec2;

pub struct Level {
    tiles: Grid<Option<Tile>>,
}

impl Level {
    pub fn new(width: usize, height: usize) -> Level {
        Level{
            tiles: Grid::new_filled_with(Some(Tile::Void) ,width, height),
        }
    }

    pub fn new_filled_with(tile: Option<Tile>, width: usize, height: usize) -> Level {
        Level{
            tiles: Grid::new_filled_with(tile, width, height),
        }
    }

    pub fn fill_with(&mut self, tile: Tile) {
        let width = self.tiles.get_width();
        let height = self.tiles.get_height();

        for x in 0..width {
            for y in 0..height {
                self.tiles[(x, y)] = Some(tile.clone());
            }
        }
    }

    pub fn get_width(&self) -> usize {
        self.tiles.get_width()
    }

    pub fn get_height(&self) -> usize {
        self.tiles.get_height()
    }

    pub fn get_mut_tile(&mut self, x: usize, y: usize) -> Option<&mut Tile> {
        if x < self.get_width() && y < self.get_height() {
            self.tiles[(x, y)].as_mut()
        } else {
            None
        }
    }

    pub fn get_mut_tile_with_vec(&mut self, pos: &Vec2<usize>) -> Option<&mut Tile> {
        self.get_mut_tile(pos.x, pos.y)
    }

    pub fn apply<F>(&mut self, gen: F) -> &mut Level where F: FnOnce(&mut Level) {
        gen(self);
        self
    }

}

static NONE: Option<Tile> = None;

impl Index<(usize, usize)> for Level {
    type Output= Option<Tile>;

    fn index(&self, (x, y): (usize, usize)) -> &Option<Tile>{
        if x < self.get_width() && y < self.get_height() {
            &self.tiles[(x, y)]
        } else {
            &NONE
        }
    }
}

impl Index<Vec2<usize>> for Level {
    type Output= Option<Tile>;

    fn index(&self, vec: Vec2<usize>) -> &Option<Tile>{
        if vec.x < self.get_width() && vec.y < self.get_height() {
            &self.tiles[(vec.x, vec.y)]
        } else {
            &NONE
        }
    }
}

pub fn fill_dead_ends(level: &mut Level) -> bool {
    let mut deadends = Vec::new();
    for y in 0..level.get_height() {
        for x in 0..level.get_width() {
            match level[(x,y)] {
                Tile::Floor => {
                    if is_deadend() {
                        deadends.push((x,y));
                    }
                },
                _ => {},
            }
        }
    }

    for (x,y) in deadends {
        level.get_mut_tile(x, y) = Some(Tile::Wall);
    }
    deadends.is_empty()
}

pub fn is_deadend(level: &mut Level) -> bool {
    use util::Direction;
    let mut paths = 0;
    for vector in Direction::get_orthogonal_dirs() {
        match level.get_mut_tile_with_vec(vector) {
            Some(tile) => {
                match tile {
                    Tile::Floor => paths+=1,
                    _ => {},
                }
            }
            None => {}
        }
	}
    paths < 2
}
<commit_msg>level debugginh<commit_after>use tile::Tile;
use util::Grid;
use std::ops::{Index};
use na::Vec2;

pub struct Level {
    tiles: Grid<Option<Tile>>,
}

impl Level {
    pub fn new(width: usize, height: usize) -> Level {
        Level{
            tiles: Grid::new_filled_with(Some(Tile::Void) ,width, height),
        }
    }

    pub fn new_filled_with(tile: Option<Tile>, width: usize, height: usize) -> Level {
        Level{
            tiles: Grid::new_filled_with(tile, width, height),
        }
    }

    pub fn fill_with(&mut self, tile: Tile) {
        let width = self.tiles.get_width();
        let height = self.tiles.get_height();

        for x in 0..width {
            for y in 0..height {
                self.tiles[(x, y)] = Some(tile.clone());
            }
        }
    }

    pub fn get_width(&self) -> usize {
        self.tiles.get_width()
    }

    pub fn get_height(&self) -> usize {
        self.tiles.get_height()
    }

    pub fn get_mut_tile(&mut self, x: usize, y: usize) -> Option<&mut Tile> {
        if x < self.get_width() && y < self.get_height() {
            self.tiles[(x, y)].as_mut()
        } else {
            None
        }
    }

    pub fn get_mut_tile_with_vec(&mut self, pos: &Vec2<usize>) -> Option<&mut Tile> {
        self.get_mut_tile(pos.x, pos.y)
    }

    pub fn apply<F>(&mut self, gen: F) -> &mut Level where F: FnOnce(&mut Level) {
        gen(self);
        self
    }

}

static NONE: Option<Tile> = None;

impl Index<(usize, usize)> for Level {
    type Output= Option<Tile>;

    fn index(&self, (x, y): (usize, usize)) -> &Option<Tile>{
        if x < self.get_width() && y < self.get_height() {
            &self.tiles[(x, y)]
        } else {
            &NONE
        }
    }
}

impl Index<Vec2<usize>> for Level {
    type Output= Option<Tile>;

    fn index(&self, vec: Vec2<usize>) -> &Option<Tile>{
        if vec.x < self.get_width() && vec.y < self.get_height() {
            &self.tiles[(vec.x, vec.y)]
        } else {
            &NONE
        }
    }
}

pub fn fill_dead_ends(level: &mut Level) -> bool {
    let mut deadends = Vec::new();
    for y in 0..level.get_height() {
        for x in 0..level.get_width() {
            match level[(x,y)] {
                Some(n) => {
                    match n {
                        Tile::Floor => {
                            if is_deadend(level, x, y) {
                                deadends.push((x,y));
                            }
                        },
                        _ => {},
                    }
                },
                None => {},
            }
        }
    }

    for (x,y) in deadends {
        match level.get_mut_tile(x, y) {
            Some(tile) => {
                *tile = Tile::Floor;
            }
        }
    }
    deadends.is_empty()
}

pub fn is_deadend(level: &mut Level, x: usize, y: usize) -> bool {
    use util::Direction;
    let mut paths = 0;
    for dir in Direction::get_orthogonal_dirs() {

        match level[&Direction::get_vec(dir)] {
            Some(tile) => {
                match tile {
                    Tile::Floor => paths+=1,
                    _ => {},
                }
            }
            None => {}
        }
	}
    paths < 2
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use combine::{between, choice, many, many1, optional, parser, satisfy, satisfy_map, sep_by, try};
use combine::{Parser, Stream, ParseError, ParseResult};
use combine::char::{alpha_num, digit, char, letter, spaces, string};

use token::{Literal, Token};

pub fn lex<'a>(line: &'a str) -> Result<(Vec<Token>, &'a str), ParseError<&'a str>> {
    spaces().with(parser(token_stream))
        .parse(line)
}

fn literal<I>(input: I) -> ParseResult<Literal, I>
    where I: Stream<Item=char>
{
    let digits = many1::<String, _>(digit());
    let integer = optional(char('-'))
        .and(digits.clone())
        .map(|(sign, s)| {
            let magnitude = s.parse::<i64>().unwrap();
            if sign.is_some() { -magnitude } else { magnitude }
        })
        .map(Literal::from);

    let float = optional(char('-'))
        .and((digits.clone(), char('.'), digits.clone())
            .map(|(prefix, _, suffix)| format!("{}.{}", prefix, suffix)))
        .map(|(sign, s)| {
            let magnitude = s.parse::<f64>().unwrap();
            if sign.is_some() { -magnitude } else { magnitude }
        })
        .map(Literal::from);

    let num = try(float).or(try(integer));

    let boolean = char('#')
        .with(satisfy_map(|c| {
            match c {
                't' => Some(true),
                'f' => Some(false),
                _ => None,
            }
        }))
        .map(Literal::from);

    let non_quote = satisfy(|c| c != '"');

    let string = between(char('"'), char('"'), many::<String, _>(non_quote))
        .map(Literal::from);

    boolean.or(string).or(num)
        .parse_stream(input)
}

fn symbol<I>(input: I) -> ParseResult<Token, I>
    where I: Stream<Item=char>
{
    let first = letter().or(char('_'));
    let rest = many::<String, _>(alpha_num().or(char('_')));
    first.and(rest)
        .map(|(f, mut r)| { r.insert(0, f); r })
        .map(Token::Symbol)
        .parse_stream(input)
}

fn punctuation<I>(input: I) -> ParseResult<Token, I>
    where I: Stream<Item=char>
{
    let single_char_tokens = satisfy_map(|c| {
        match c {
            '(' => Some(Token::LParen),
            ')' => Some(Token::RParen),
            '[' => Some(Token::LBracket),
            ']' => Some(Token::RBracket),
            '+' => Some(Token::Plus),
            '-' => Some(Token::Minus),
            '*' => Some(Token::Star),
            '/' => Some(Token::Slash),
            '=' => Some(Token::Equal),
            '<' => Some(Token::Less),
            '>' => Some(Token::Greater),
            _ => None
        }
    });

    let two_char_tokens = choice([
        string("<="),
        string(">="),
    ]).map(|s| match s {
        "<=" => Token::LessEqual,
        ">=" => Token::GreaterEqual,
        _ => unreachable!(),
    });

    // Maximal munch: attempt parsing two-char tokens before one-char tokens
    two_char_tokens.or(single_char_tokens).parse_stream(input)
}

fn token<I>(input: I) -> ParseResult<Token, I>
    where I: Stream<Item=char>
{
    parser(symbol)
        .or(parser(literal).map(Token::Literal))
        .or(parser(symbol))
        .or(parser(punctuation))
        .parse_stream(input)
}

fn token_stream<I>(input: I) -> ParseResult<Vec<Token>, I>
    where I: Stream<Item=char>
{
    sep_by(parser(token), spaces()).parse_stream(input)
}

#[cfg(test)]
mod test {
    use super::*;
    use float_cmp::ApproxEqUlps;
    use quickcheck::TestResult;

    #[test]
    fn parse_bool_literal() {
        assert_eq!(Ok((Literal::Bool(true), "")), parser(literal).parse("#t"));
        assert_eq!(Ok((Literal::Bool(false), "")), parser(literal).parse("#f"));
    }

    #[test]
    fn parse_zero_literal() {
        // Integer case
        assert_eq!(Ok((Literal::Int(0i64), "")), parser(literal).parse("0"));

        // Float case
        match parser(literal).parse("0.0") {
            Ok((Literal::Flt(flt), _)) => assert!(flt.approx_eq_ulps(&0.0f64, 4)),
            Ok(x) => assert!(false, format!("0.0 parsed as {}", x.0)),
            Err(e) => assert!(false, format!("0.0 parsed as {}", e)),
        };
    }

    #[test]
    #[should_panic]
    fn parse_empty() {
        let x = parser(token_stream).parse("");
        println!("{:#?}", x.unwrap().0);
    }

    quickcheck!{
        fn parse_int_literal(x: i64) -> bool {
            match parser(literal).parse(&*x.to_string()) {
                Ok((Literal::Int(y), _)) => x == y,
                _ => false,
            }
        }

        fn parse_float_literal(x: f64) -> bool {
            let mut string = x.to_string();
            if x.trunc() == x {
                string.push_str(".0");
            }

            if let Ok((Literal::Flt(y), _)) = parser(literal).parse(&*string) {
                x.approx_eq_ulps(&y, 4)
            } else {
                false
            }
        }

        fn parse_str_literal(x: String) -> TestResult {
            let string = format!("\"{}\"", x);
            if x.contains('\"') {
                return TestResult::discard()
            }
            match parser(literal).parse(&*string) {
                Ok((Literal::Str(result), _)) => TestResult::from_bool(result == x),
                _ => TestResult::failed(),
            }
        }

        fn parse_symbol(x: String) -> TestResult {
            if x.is_empty() {
                return TestResult::discard()
            }

            if !x.chars().next().unwrap().is_alphabetic() {
                return TestResult::discard()
            }

            // Test only valid symbols
            for c in x.chars() {
                if !(c.is_alphanumeric() || c == '_') {
                    return TestResult::discard()
                }
            }

            match parser(symbol).parse(&*x) {
                Ok((Token::Symbol(result), _)) => TestResult::from_bool(result == x),
                _ => TestResult::failed(),
            }
        }
    }
}
<commit_msg>Fix empty parsing test<commit_after>#![allow(dead_code)]

use combine::{between, choice, many, many1, optional, parser, satisfy, satisfy_map, sep_by, try};
use combine::{Parser, Stream, ParseError, ParseResult};
use combine::char::{alpha_num, digit, char, letter, spaces, string};

use token::{Literal, Token};

pub fn lex<'a>(line: &'a str) -> Result<(Vec<Token>, &'a str), ParseError<&'a str>> {
    spaces().with(parser(token_stream))
        .parse(line)
}

fn literal<I>(input: I) -> ParseResult<Literal, I>
    where I: Stream<Item=char>
{
    let digits = many1::<String, _>(digit());
    let integer = optional(char('-'))
        .and(digits.clone())
        .map(|(sign, s)| {
            let magnitude = s.parse::<i64>().unwrap();
            if sign.is_some() { -magnitude } else { magnitude }
        })
        .map(Literal::from);

    let float = optional(char('-'))
        .and((digits.clone(), char('.'), digits.clone())
            .map(|(prefix, _, suffix)| format!("{}.{}", prefix, suffix)))
        .map(|(sign, s)| {
            let magnitude = s.parse::<f64>().unwrap();
            if sign.is_some() { -magnitude } else { magnitude }
        })
        .map(Literal::from);

    let num = try(float).or(try(integer));

    let boolean = char('#')
        .with(satisfy_map(|c| {
            match c {
                't' => Some(true),
                'f' => Some(false),
                _ => None,
            }
        }))
        .map(Literal::from);

    let non_quote = satisfy(|c| c != '"');

    let string = between(char('"'), char('"'), many::<String, _>(non_quote))
        .map(Literal::from);

    boolean.or(string).or(num)
        .parse_stream(input)
}

fn symbol<I>(input: I) -> ParseResult<Token, I>
    where I: Stream<Item=char>
{
    let first = letter().or(char('_'));
    let rest = many::<String, _>(alpha_num().or(char('_')));
    first.and(rest)
        .map(|(f, mut r)| { r.insert(0, f); r })
        .map(Token::Symbol)
        .parse_stream(input)
}

fn punctuation<I>(input: I) -> ParseResult<Token, I>
    where I: Stream<Item=char>
{
    let single_char_tokens = satisfy_map(|c| {
        match c {
            '(' => Some(Token::LParen),
            ')' => Some(Token::RParen),
            '[' => Some(Token::LBracket),
            ']' => Some(Token::RBracket),
            '+' => Some(Token::Plus),
            '-' => Some(Token::Minus),
            '*' => Some(Token::Star),
            '/' => Some(Token::Slash),
            '=' => Some(Token::Equal),
            '<' => Some(Token::Less),
            '>' => Some(Token::Greater),
            _ => None
        }
    });

    let two_char_tokens = choice([
        string("<="),
        string(">="),
    ]).map(|s| match s {
        "<=" => Token::LessEqual,
        ">=" => Token::GreaterEqual,
        _ => unreachable!(),
    });

    // Maximal munch: attempt parsing two-char tokens before one-char tokens
    two_char_tokens.or(single_char_tokens).parse_stream(input)
}

fn token<I>(input: I) -> ParseResult<Token, I>
    where I: Stream<Item=char>
{
    parser(symbol)
        .or(parser(literal).map(Token::Literal))
        .or(parser(symbol))
        .or(parser(punctuation))
        .parse_stream(input)
}

fn token_stream<I>(input: I) -> ParseResult<Vec<Token>, I>
    where I: Stream<Item=char>
{
    sep_by(parser(token), spaces()).parse_stream(input)
}

#[cfg(test)]
mod test {
    use super::*;
    use float_cmp::ApproxEqUlps;
    use quickcheck::TestResult;

    #[test]
    fn parse_bool_literal() {
        assert_eq!(Ok((Literal::Bool(true), "")), parser(literal).parse("#t"));
        assert_eq!(Ok((Literal::Bool(false), "")), parser(literal).parse("#f"));
    }

    #[test]
    fn parse_zero_literal() {
        // Integer case
        assert_eq!(Ok((Literal::Int(0i64), "")), parser(literal).parse("0"));

        // Float case
        match parser(literal).parse("0.0") {
            Ok((Literal::Flt(flt), _)) => assert!(flt.approx_eq_ulps(&0.0f64, 4)),
            Ok(x) => assert!(false, format!("0.0 parsed as {}", x.0)),
            Err(e) => assert!(false, format!("0.0 parsed as {}", e)),
        };
    }

    #[test]
    fn parse_empty() {
        assert_eq!(Ok((Vec::new(), "")), parser(token_stream).parse(""));
    }

    quickcheck!{
        fn parse_int_literal(x: i64) -> bool {
            match parser(literal).parse(&*x.to_string()) {
                Ok((Literal::Int(y), _)) => x == y,
                _ => false,
            }
        }

        fn parse_float_literal(x: f64) -> bool {
            let mut string = x.to_string();
            if x.trunc() == x {
                string.push_str(".0");
            }

            if let Ok((Literal::Flt(y), _)) = parser(literal).parse(&*string) {
                x.approx_eq_ulps(&y, 4)
            } else {
                false
            }
        }

        fn parse_str_literal(x: String) -> TestResult {
            let string = format!("\"{}\"", x);
            if x.contains('\"') {
                return TestResult::discard()
            }
            match parser(literal).parse(&*string) {
                Ok((Literal::Str(result), _)) => TestResult::from_bool(result == x),
                _ => TestResult::failed(),
            }
        }

        fn parse_symbol(x: String) -> TestResult {
            if x.is_empty() {
                return TestResult::discard()
            }

            if !x.chars().next().unwrap().is_alphabetic() {
                return TestResult::discard()
            }

            // Test only valid symbols
            for c in x.chars() {
                if !(c.is_alphanumeric() || c == '_') {
                    return TestResult::discard()
                }
            }

            match parser(symbol).parse(&*x) {
                Ok((Token::Symbol(result), _)) => TestResult::from_bool(result == x),
                _ => TestResult::failed(),
            }
        }
    }
}
<|endoftext|>


<commit_before>
use core::str::StrExt;
use regex;

pub fn score(choice: &String, query: &String) -> f32 {
    if choice.len() == 0 {
        0.0
    } else if query.len() == 0 {
        1.0
    } else {
        if compute_match_length(choice, query) > 0 {
            1.0 / choice.len() as f32
        } else {
            0.0
        }
    }
}

// Find the length of the shortest substring matching the given characters.
fn compute_match_length(string: &String, query: &String) -> usize {
    let re_string = &make_query_regex(query);
    let re = match regex::Regex::new(re_string.as_slice()) {
        Ok(re)   => re,
        Err(err) => panic!("{}", err.msg)
    };
    match re.captures(string.as_slice()) {
        Some(caps) => caps.at(0).unwrap_or("").char_len(),
        None       => 0
    }
}

// Creates a regex for performing a case-insensitive non-greedy fuzzy match.
// Turns "abc" into "(?i)a.*?b.*?c.*?".
fn make_query_regex(query: &String) -> String {
    let mut parts = query
        .chars()
        .map(|ch| regex::quote(ch.to_string().as_slice()))
        .collect::<Vec<String>>();

    parts.insert(0, "(?i)".to_string());

    parts.connect(".*?")
}

#[cfg(test)]
mod test {

    use score::score;
    use core::str::StrExt;

    pub fn do_score(choice: &str, query: &str) -> f32 {
       let choice_string = choice.to_string();
       let query_string = query.to_string();
       score(&choice_string,  &query_string)
    }

    #[test]
    fn scores_zero_when_the_choice_is_empty() {
        assert_eq!(do_score("", ""), 0.0);
    }

    #[test]
    fn scores_one_when_the_query_is_empty() {
        assert_eq!(do_score("a", ""), 1.0);
    }

    #[test]
    fn scores_zero_when_the_query_is_longer_than_the_choice() {
        assert_eq!(do_score("short", "longer"), 0.0);
    }

    #[test]
    fn scores_zero_when_only_a_prefix_of_the_query_matches() {
        assert_eq!(do_score("ab", "ac"), 0.0);
    }

    #[test]
    fn scores_greater_than_zero_when_it_matches() {
        assert!(do_score("a", "a") > 0.0);
        assert!(do_score("ab", "a") > 0.0);
        assert!(do_score("ba", "a") > 0.0);
        assert!(do_score("bab", "a") > 0.0);
        assert!(do_score("babababab", "aaaa") > 0.0);
    }

    #[test]
    fn scores_one_normalized_to_length_when_the_query_equals_the_choice() {
        assert_eq!(do_score("a", "a"), 1.0);
        assert_eq!(do_score("ab", "ab"), 0.5f32);
        assert_eq!(do_score("a long string", "a long string"),
            1.0 / ("a long string".char_len() as f32));

        assert_eq!(do_score("spec/search_spec.rb", "sear"),
            1.0 / ("spec/search_spec.rb".char_len() as f32));
    }

    // Character matching

    #[test]
    fn it_matches_punctuation() {
        assert!(do_score("/! symbols $^", "/!$^") > 0.0);
    }

    #[test]
    fn it_is_case_insensitive() {
        assert_eq!(do_score("a", "A"), 1.0);
        assert_eq!(do_score("A", "a"), 1.0);
    }

    #[test]
    fn it_doesnt_match_when_the_same_letter_is_repeated_in_the_choice() {
        assert_eq!(do_score("a", "aa"), 0.0);
    }

    #[test]
    fn it_scores_higher_for_better_matches() {
        assert!(do_score("selecta.gemspec", "asp")
                > do_score("algorithm4_spec.rb", "asp"));
        assert!(do_score("README.md", "em")
                > do_score("benchmark.rb", "em"));
        assert!(do_score("search.rb", "sear")
                > do_score("spec/search_spec.rb", "sear"));
    }
}

<commit_msg>Added FIXME related to performance<commit_after>
use core::str::StrExt;
use regex;

pub fn score(choice: &String, query: &String) -> f32 {
    if choice.len() == 0 {
        0.0
    } else if query.len() == 0 {
        1.0
    } else {
        if compute_match_length(choice, query) > 0 {
            1.0 / choice.len() as f32
        } else {
            0.0
        }
    }
}

// Find the length of the shortest substring matching the given characters.
fn compute_match_length(string: &String, query: &String) -> usize {
    // FIXME (performance). Regexp is not reused.
    let re_string = &make_query_regex(query);
    let re = match regex::Regex::new(re_string.as_slice()) {
        Ok(re)   => re,
        Err(err) => panic!("{}", err.msg)
    };
    match re.captures(string.as_slice()) {
        Some(caps) => caps.at(0).unwrap_or("").char_len(),
        None       => 0
    }
}

// Creates a regex for performing a case-insensitive non-greedy fuzzy match.
// Turns "abc" into "(?i)a.*?b.*?c.*?".
fn make_query_regex(query: &String) -> String {
    let mut parts = query
        .chars()
        .map(|ch| regex::quote(ch.to_string().as_slice()))
        .collect::<Vec<String>>();

    parts.insert(0, "(?i)".to_string());

    parts.connect(".*?")
}

#[cfg(test)]
mod test {

    use score::score;
    use core::str::StrExt;

    pub fn do_score(choice: &str, query: &str) -> f32 {
       let choice_string = choice.to_string();
       let query_string = query.to_string();
       score(&choice_string,  &query_string)
    }

    #[test]
    fn scores_zero_when_the_choice_is_empty() {
        assert_eq!(do_score("", ""), 0.0);
    }

    #[test]
    fn scores_one_when_the_query_is_empty() {
        assert_eq!(do_score("a", ""), 1.0);
    }

    #[test]
    fn scores_zero_when_the_query_is_longer_than_the_choice() {
        assert_eq!(do_score("short", "longer"), 0.0);
    }

    #[test]
    fn scores_zero_when_only_a_prefix_of_the_query_matches() {
        assert_eq!(do_score("ab", "ac"), 0.0);
    }

    #[test]
    fn scores_greater_than_zero_when_it_matches() {
        assert!(do_score("a", "a") > 0.0);
        assert!(do_score("ab", "a") > 0.0);
        assert!(do_score("ba", "a") > 0.0);
        assert!(do_score("bab", "a") > 0.0);
        assert!(do_score("babababab", "aaaa") > 0.0);
    }

    #[test]
    fn scores_one_normalized_to_length_when_the_query_equals_the_choice() {
        assert_eq!(do_score("a", "a"), 1.0);
        assert_eq!(do_score("ab", "ab"), 0.5f32);
        assert_eq!(do_score("a long string", "a long string"),
            1.0 / ("a long string".char_len() as f32));

        assert_eq!(do_score("spec/search_spec.rb", "sear"),
            1.0 / ("spec/search_spec.rb".char_len() as f32));
    }

    // Character matching

    #[test]
    fn it_matches_punctuation() {
        assert!(do_score("/! symbols $^", "/!$^") > 0.0);
    }

    #[test]
    fn it_is_case_insensitive() {
        assert_eq!(do_score("a", "A"), 1.0);
        assert_eq!(do_score("A", "a"), 1.0);
    }

    #[test]
    fn it_doesnt_match_when_the_same_letter_is_repeated_in_the_choice() {
        assert_eq!(do_score("a", "aa"), 0.0);
    }

    #[test]
    fn it_scores_higher_for_better_matches() {
        assert!(do_score("selecta.gemspec", "asp")
                > do_score("algorithm4_spec.rb", "asp"));
        assert!(do_score("README.md", "em")
                > do_score("benchmark.rb", "em"));
        assert!(do_score("search.rb", "sear")
                > do_score("spec/search_spec.rb", "sear"));
    }
}

<|endoftext|>


<commit_before>use std::collections::{HashMap, BTreeMap, VecMap, HashSet, BTreeSet};

use super::traits::{SortedMap, SortedSet};

impl<T: Ord + Clone> SortedSet<T> for BTreeSet<T> {
    fn first(&mut self, remove: bool) -> Option<T> {
        if self.is_empty() { return None }

        let mut vec: Vec<T> = self.iter().cloned().collect();
        let ret = vec.remove(0);
        if remove {
            self.remove(&ret);
        }
        Some(ret)
    }

    fn last(&mut self, remove: bool) -> Option<T> {
        if self.is_empty() { return None }

        let mut vec: Vec<T> = self.iter().rev().cloned().collect();
        let ret = vec.remove(0);
        if remove {
            self.remove(&ret);
        }
        Some(ret)
    }

    fn head_set(&self, elem: &T, inclusive: bool) -> BTreeSet<T> {
        let mut vec: Vec<T>;
        if inclusive {
            vec = self.iter().cloned().filter(|x| x <= elem).collect();
        } else {
            vec = self.iter().cloned().filter(|x|  x < elem).collect();
        }
        vec.into_iter().collect::<BTreeSet<T>>()
    }

    fn sub_set(&self, from_elem: &T, from_inclusive: bool, to_elem: &T, to_inclusive:bool) -> BTreeSet<T> {
        assert!(from_elem <= to_elem);

        let mut vec: Vec<T>;
        if from_inclusive && to_inclusive {
            vec = self.iter().cloned().filter(|x| x >= from_elem && x <= to_elem).collect();
        } else if from_inclusive && !to_inclusive {
            vec = self.iter().cloned().filter(|x| x >= from_elem && x < to_elem).collect();
        } else if !from_inclusive && to_inclusive {
            vec = self.iter().cloned().filter(|x| x > from_elem && x <= to_elem).collect();
        } else {
            vec = self.iter().cloned().filter(|x| x > from_elem && x < to_elem).collect();
        }
        vec.into_iter().collect::<BTreeSet<T>>()
    }

    fn tail_set(&self, elem: &T, inclusive: bool) -> BTreeSet<T> {
        let mut vec: Vec<T>;
        if inclusive {
            vec = self.iter().cloned().filter(|x| x >= elem).collect();
        } else {
            vec = self.iter().cloned().filter(|x| x > elem).collect();
        }
        vec.into_iter().collect::<BTreeSet<T>>()
    }
}

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

    use super::super::traits::{SortedMap, SortedSet};

    #[test]
    fn test_sub_set() {
        use std::collections::BTreeSet;

        let set: BTreeSet<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
        let sub_set = set.sub_set(&2, true, &4, true);
        let v: Vec<u32> = sub_set.into_iter().collect();
        assert_eq!(v, vec![2u32, 3, 4]);
    }
}
<commit_msg>Clean up some impls and macro-ify.<commit_after>use std::collections::BTreeSet;

use super::traits::SortedSet;

macro_rules! sortedset_impl {
    ($typ:ty) => (
        impl<T: Ord + Clone> SortedSet<T> for $typ {
            fn first(&mut self, remove: bool) -> Option<T> {
                if self.is_empty() { return None }

                let ret = self.iter().min().unwrap().clone();
                if remove {
                    self.remove(&ret);
                }
                Some(ret)
            }

            fn last(&mut self, remove: bool) -> Option<T> {
                if self.is_empty() { return None }

                let ret = self.iter().max().unwrap().clone();
                if remove {
                    self.remove(&ret);
                }
                Some(ret)
            }

            fn head_set(&self, elem: &T, inclusive: bool) -> $typ {
                if inclusive {
                    return self.iter().cloned().filter(|x| x <= elem).collect();
                } else {
                    return self.iter().cloned().filter(|x|  x < elem).collect();
                }
            }

            fn sub_set(&self, from_elem: &T, from_inclusive: bool, to_elem: &T, to_inclusive:bool) -> $typ {
                assert!(from_elem <= to_elem);

                if from_inclusive && to_inclusive {
                    return self.iter().cloned().filter(|x| x >= from_elem && x <= to_elem).collect();
                } else if from_inclusive && !to_inclusive {
                    return self.iter().cloned().filter(|x| x >= from_elem && x < to_elem).collect();
                } else if !from_inclusive && to_inclusive {
                    return self.iter().cloned().filter(|x| x > from_elem && x <= to_elem).collect();
                } else {
                    return self.iter().cloned().filter(|x| x > from_elem && x < to_elem).collect();
                }
            }

            fn tail_set(&self, elem: &T, inclusive: bool) -> $typ {
                if inclusive {
                    return self.iter().cloned().filter(|x| x >= elem).collect();
                } else {
                    return self.iter().cloned().filter(|x| x > elem).collect();
                }
            }
        }
    );
}
sortedset_impl!(BTreeSet<T>);

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

    use super::super::traits::{SortedMap, SortedSet};

    #[test]
    fn test_sub_set() {
        use std::collections::BTreeSet;

        let set: BTreeSet<u32> = vec![1u32, 2, 3, 4, 5].into_iter().collect();
        let sub_set = set.sub_set(&2, true, &4, true);
        let v: Vec<u32> = sub_set.into_iter().collect();
        assert_eq!(v, vec![2u32, 3, 4]);
    }
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::ops::BitXor;

use chrono::NaiveDate;
use error::Result;

use habit::HabitTemplate;
use instance::HabitInstance;

pub const NAIVE_DATE_STRING_FORMAT : &'static str = "%Y-%m-%d";

pub fn date_to_string(ndt: &NaiveDate) -> String {
    ndt.format(NAIVE_DATE_STRING_FORMAT).to_string()
}

pub fn date_from_string(s: &str) -> Result<NaiveDate> {
    NaiveDate::parse_from_str(s, NAIVE_DATE_STRING_FORMAT).map_err(From::from)
}

/// Helper trait to check whether a object which can be a habit instance and a habit template is
/// actually a valid object, whereas "valid" is defined that it is _either_ an instance or a
/// template (think XOR).
pub trait IsValidHabitObj : HabitInstance + HabitTemplate {
    fn is_valid_havit_obj(&self) -> Result<bool> {
        self.is_habit_instance().and_then(|b| self.is_habit_template().map(|a| a.bitxor(b)))
    }
}

impl<H> IsValidHabitObj for H
    where H: HabitInstance + HabitTemplate
{
    // Empty
}

<commit_msg>Add extension to check whether an Entry or a StoreId points to a habit instance/template<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::ops::BitXor;

use chrono::NaiveDate;
use error::Result;

use habit::HabitTemplate;
use instance::HabitInstance;

use libimagstore::storeid::StoreId;
use libimagstore::store::Entry;

pub const NAIVE_DATE_STRING_FORMAT : &'static str = "%Y-%m-%d";

pub fn date_to_string(ndt: &NaiveDate) -> String {
    ndt.format(NAIVE_DATE_STRING_FORMAT).to_string()
}

pub fn date_from_string(s: &str) -> Result<NaiveDate> {
    NaiveDate::parse_from_str(s, NAIVE_DATE_STRING_FORMAT).map_err(From::from)
}

/// Helper trait to check whether a object which can be a habit instance and a habit template is
/// actually a valid object, whereas "valid" is defined that it is _either_ an instance or a
/// template (think XOR).
pub trait IsValidHabitObj : HabitInstance + HabitTemplate {
    fn is_valid_havit_obj(&self) -> Result<bool> {
        self.is_habit_instance().and_then(|b| self.is_habit_template().map(|a| a.bitxor(b)))
    }
}

impl<H> IsValidHabitObj for H
    where H: HabitInstance + HabitTemplate
{
    // Empty
}

pub trait IsHabitCheck {
    fn is_habit(&self) -> bool;
    fn is_habit_instance(&self) -> bool;
    fn is_habit_template(&self) -> bool;
}

impl IsHabitCheck for StoreId {
    fn is_habit(&self) -> bool {
        self.is_in_collection(&["habit"])
    }

    fn is_habit_instance(&self) -> bool {
        self.is_in_collection(&["habit", "instance"])
    }

    fn is_habit_template(&self) -> bool {
        self.is_in_collection(&["habit", "template"])
    }
}

impl IsHabitCheck for Entry {
    /// Helper function to check whether an entry is a habit (either instance or template)
    fn is_habit(&self) -> bool {
        self.get_location().is_habit()
    }

    /// Check whether an entry is a habit instance
    fn is_habit_instance(&self) -> bool {
        self.get_location().is_habit_instance()
    }

    /// Check whether an entry is a habit template
    fn is_habit_template(&self) -> bool {
        self.get_location().is_habit_template()
    }
}

<|endoftext|>