<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 std::borrow::Cow;
use std::iter::repeat;

use syntax::codemap::{BytePos, Pos, Span};

use comment::{rewrite_comment, CodeCharKind, CommentCodeSlices};
use config::WriteMode;
use shape::{Indent, Shape};
use utils::{count_newlines, mk_sp};
use visitor::FmtVisitor;

impl<'a> FmtVisitor<'a> {
    fn output_at_start(&self) -> bool {
        self.buffer.len == 0
    }

    // TODO these format_missing methods are ugly. Refactor and add unit tests
    // for the central whitespace stripping loop.
    pub fn format_missing(&mut self, end: BytePos) {
        self.format_missing_inner(end, |this, last_snippet, _| {
            this.buffer.push_str(last_snippet)
        })
    }

    pub fn format_missing_with_indent(&mut self, end: BytePos) {
        let config = self.config;
        self.format_missing_inner(end, |this, last_snippet, snippet| {
            this.buffer.push_str(last_snippet.trim_right());
            if last_snippet == snippet && !this.output_at_start() {
                // No new lines in the snippet.
                this.buffer.push_str("\n");
            }
            let indent = this.block_indent.to_string(config);
            this.buffer.push_str(&indent);
        })
    }

    pub fn format_missing_no_indent(&mut self, end: BytePos) {
        self.format_missing_inner(end, |this, last_snippet, _| {
            this.buffer.push_str(last_snippet.trim_right());
        })
    }

    fn format_missing_inner<F: Fn(&mut FmtVisitor, &str, &str)>(
        &mut self,
        end: BytePos,
        process_last_snippet: F,
    ) {
        let start = self.last_pos;

        if start == end {
            // Do nothing if this is the beginning of the file.
            if !self.output_at_start() {
                process_last_snippet(self, "", "");
            }
            return;
        }

        assert!(
            start < end,
            "Request to format inverted span: {:?} to {:?}",
            self.codemap.lookup_char_pos(start),
            self.codemap.lookup_char_pos(end)
        );

        self.last_pos = end;
        let span = mk_sp(start, end);
        let snippet = self.snippet(span);
        if snippet.trim().is_empty() {
            // Keep vertical spaces within range.
            self.push_vertical_spaces(count_newlines(&snippet));
            process_last_snippet(self, "", &snippet);
        } else {
            self.write_snippet(span, &process_last_snippet);
        }
    }

    fn push_vertical_spaces(&mut self, mut newline_count: usize) {
        let newline_upper_bound = self.config.blank_lines_upper_bound() + 1;
        let newline_lower_bound = self.config.blank_lines_lower_bound() + 1;
        if newline_count > newline_upper_bound {
            newline_count = newline_upper_bound;
        } else if newline_count < newline_lower_bound {
            newline_count = newline_lower_bound;
        }
        let blank_lines: String = repeat('\n').take(newline_count).collect();
        self.buffer.push_str(&blank_lines);
    }

    fn write_snippet<F>(&mut self, span: Span, process_last_snippet: F)
    where
        F: Fn(&mut FmtVisitor, &str, &str),
    {
        // Get a snippet from the file start to the span's hi without allocating.
        // We need it to determine what precedes the current comment. If the comment
        // follows code on the same line, we won't touch it.
        let big_span_lo = self.codemap.lookup_char_pos(span.lo()).file.start_pos;
        let local_begin = self.codemap.lookup_byte_offset(big_span_lo);
        let local_end = self.codemap.lookup_byte_offset(span.hi());
        let start_index = local_begin.pos.to_usize();
        let end_index = local_end.pos.to_usize();
        let big_snippet = &local_begin.fm.src.as_ref().unwrap()[start_index..end_index];

        let big_diff = (span.lo() - big_span_lo).to_usize();
        let snippet = self.snippet(span);

        debug!("write_snippet `{}`", snippet);

        self.write_snippet_inner(big_snippet, big_diff, &snippet, span, process_last_snippet);
    }

    fn process_comment(
        &mut self,
        status: &mut SnippetStatus,
        snippet: &str,
        big_snippet: &str,
        offset: usize,
        big_diff: usize,
        subslice: &str,
        file_name: &str,
    ) -> bool {
        let last_char = big_snippet[..(offset + big_diff)]
            .chars()
            .rev()
            .skip_while(|rev_c| [' ', '\t'].contains(rev_c))
            .next();

        let fix_indent = last_char.map_or(true, |rev_c| ['{', '\n'].contains(&rev_c));

        let subslice_num_lines = count_newlines(subslice);
        let skip_this_range = !self.config.file_lines().intersects_range(
            file_name,
            status.cur_line,
            status.cur_line + subslice_num_lines,
        );

        if status.rewrite_next_comment && skip_this_range {
            status.rewrite_next_comment = false;
        }

        if status.rewrite_next_comment {
            if fix_indent {
                if let Some('{') = last_char {
                    self.buffer.push_str("\n");
                }
                self.buffer
                    .push_str(&self.block_indent.to_string(self.config));
            } else {
                self.buffer.push_str(" ");
            }

            let comment_width = ::std::cmp::min(
                self.config.comment_width(),
                self.config.max_width() - self.block_indent.width(),
            );
            let comment_indent = Indent::from_width(self.config, self.buffer.cur_offset());
            let comment_shape = Shape::legacy(comment_width, comment_indent);
            let comment_str = rewrite_comment(subslice, false, comment_shape, self.config)
                .unwrap_or_else(|| String::from(subslice));
            self.buffer.push_str(&comment_str);

            status.last_wspace = None;
            status.line_start = offset + subslice.len();

            if let Some('/') = subslice.chars().nth(1) {
                // check that there are no contained block comments
                if !subslice
                    .split('\n')
                    .map(|s| s.trim_left())
                    .any(|s| s.len() >= 2 && &s[0..2] == "/*")
                {
                    // Add a newline after line comments
                    self.buffer.push_str("\n");
                }
            } else if status.line_start <= snippet.len() {
                // For other comments add a newline if there isn't one at the end already
                match snippet[status.line_start..].chars().next() {
                    Some('\n') | Some('\r') => (),
                    _ => self.buffer.push_str("\n"),
                }
            }

            status.cur_line += subslice_num_lines;
            true
        } else {
            status.rewrite_next_comment = false;
            false
        }
    }

    fn write_snippet_inner<F>(
        &mut self,
        big_snippet: &str,
        big_diff: usize,
        old_snippet: &str,
        span: Span,
        process_last_snippet: F,
    ) where
        F: Fn(&mut FmtVisitor, &str, &str),
    {
        // Trim whitespace from the right hand side of each line.
        // Annoyingly, the library functions for splitting by lines etc. are not
        // quite right, so we must do it ourselves.
        let char_pos = self.codemap.lookup_char_pos(span.lo());
        let file_name = &char_pos.file.name;
        let mut status = SnippetStatus::new(char_pos.line);

        fn replace_chars<'a>(string: &'a str) -> Cow<'a, str> {
            if string.contains(char::is_whitespace) {
                Cow::from(
                    string
                        .chars()
                        .map(|ch| if ch.is_whitespace() { ch } else { 'X' })
                        .collect::<String>(),
                )
            } else {
                Cow::from(string)
            }
        }

        let snippet = &*match self.config.write_mode() {
            WriteMode::Coverage => replace_chars(old_snippet),
            _ => Cow::from(old_snippet),
        };

        for (kind, offset, subslice) in CommentCodeSlices::new(snippet) {
            debug!("{:?}: {:?}", kind, subslice);

            if let CodeCharKind::Comment = kind {
                if self.process_comment(
                    &mut status,
                    snippet,
                    big_snippet,
                    offset,
                    big_diff,
                    subslice,
                    file_name,
                ) {
                    continue;
                }
            }

            let newline_count = count_newlines(&subslice);
            if subslice.trim().is_empty() && newline_count > 0
                && self.config.file_lines().intersects_range(
                    file_name,
                    status.cur_line,
                    status.cur_line + newline_count,
                ) {
                self.push_vertical_spaces(newline_count);
                status.cur_line += newline_count;
                status.rewrite_next_comment = true;
                status.line_start = offset + newline_count;
            } else {
                for (mut i, c) in subslice.char_indices() {
                    i += offset;

                    if c == '\n' {
                        if !self.config
                            .file_lines()
                            .contains_line(file_name, status.cur_line)
                        {
                            status.last_wspace = None;
                        }

                        if let Some(lw) = status.last_wspace {
                            self.buffer.push_str(&snippet[status.line_start..lw]);
                            self.buffer.push_str("\n");
                        } else {
                            self.buffer.push_str(&snippet[status.line_start..i + 1]);
                        }

                        status.cur_line += 1;
                        status.line_start = i + 1;
                        status.last_wspace = None;
                        status.rewrite_next_comment = true;
                    } else if c.is_whitespace() {
                        if status.last_wspace.is_none() {
                            status.last_wspace = Some(i);
                        }
                    } else if c == ';' {
                        if status.last_wspace.is_some() {
                            status.line_start = i;
                        }

                        status.rewrite_next_comment = true;
                        status.last_wspace = None;
                    } else {
                        status.rewrite_next_comment = true;
                        status.last_wspace = None;
                    }
                }

                let remaining = snippet[status.line_start..subslice.len() + offset].trim();
                if !remaining.is_empty() {
                    self.buffer.push_str(remaining);
                    status.line_start = subslice.len() + offset;
                    status.rewrite_next_comment = true;
                }
            }
        }

        process_last_snippet(self, &snippet[status.line_start..], snippet);
    }
}

struct SnippetStatus {
    line_start: usize,
    last_wspace: Option<usize>,
    rewrite_next_comment: bool,
    cur_line: usize,
}

impl SnippetStatus {
    fn new(cur_line: usize) -> Self {
        SnippetStatus {
            line_start: 0,
            last_wspace: None,
            rewrite_next_comment: true,
            cur_line,
        }
    }
}
<commit_msg>Process blank lines if only they're within file lines range<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 std::borrow::Cow;
use std::iter::repeat;

use syntax::codemap::{BytePos, Pos, Span};

use codemap::LineRangeUtils;
use comment::{rewrite_comment, CodeCharKind, CommentCodeSlices};
use config::WriteMode;
use shape::{Indent, Shape};
use utils::{count_newlines, mk_sp};
use visitor::FmtVisitor;

impl<'a> FmtVisitor<'a> {
    fn output_at_start(&self) -> bool {
        self.buffer.len == 0
    }

    // TODO these format_missing methods are ugly. Refactor and add unit tests
    // for the central whitespace stripping loop.
    pub fn format_missing(&mut self, end: BytePos) {
        self.format_missing_inner(end, |this, last_snippet, _| {
            this.buffer.push_str(last_snippet)
        })
    }

    pub fn format_missing_with_indent(&mut self, end: BytePos) {
        let config = self.config;
        self.format_missing_inner(end, |this, last_snippet, snippet| {
            this.buffer.push_str(last_snippet.trim_right());
            if last_snippet == snippet && !this.output_at_start() {
                // No new lines in the snippet.
                this.buffer.push_str("\n");
            }
            let indent = this.block_indent.to_string(config);
            this.buffer.push_str(&indent);
        })
    }

    pub fn format_missing_no_indent(&mut self, end: BytePos) {
        self.format_missing_inner(end, |this, last_snippet, _| {
            this.buffer.push_str(last_snippet.trim_right());
        })
    }

    fn format_missing_inner<F: Fn(&mut FmtVisitor, &str, &str)>(
        &mut self,
        end: BytePos,
        process_last_snippet: F,
    ) {
        let start = self.last_pos;

        if start == end {
            // Do nothing if this is the beginning of the file.
            if !self.output_at_start() {
                process_last_snippet(self, "", "");
            }
            return;
        }

        assert!(
            start < end,
            "Request to format inverted span: {:?} to {:?}",
            self.codemap.lookup_char_pos(start),
            self.codemap.lookup_char_pos(end)
        );

        self.last_pos = end;
        let span = mk_sp(start, end);
        let snippet = self.snippet(span);
        if snippet.trim().is_empty() && !out_of_file_lines_range!(self, span) {
            // Keep vertical spaces within range.
            self.push_vertical_spaces(count_newlines(&snippet));
            process_last_snippet(self, "", &snippet);
        } else {
            self.write_snippet(span, &process_last_snippet);
        }
    }

    fn push_vertical_spaces(&mut self, mut newline_count: usize) {
        let newline_upper_bound = self.config.blank_lines_upper_bound() + 1;
        let newline_lower_bound = self.config.blank_lines_lower_bound() + 1;
        if newline_count > newline_upper_bound {
            newline_count = newline_upper_bound;
        } else if newline_count < newline_lower_bound {
            newline_count = newline_lower_bound;
        }
        let blank_lines: String = repeat('\n').take(newline_count).collect();
        self.buffer.push_str(&blank_lines);
    }

    fn write_snippet<F>(&mut self, span: Span, process_last_snippet: F)
    where
        F: Fn(&mut FmtVisitor, &str, &str),
    {
        // Get a snippet from the file start to the span's hi without allocating.
        // We need it to determine what precedes the current comment. If the comment
        // follows code on the same line, we won't touch it.
        let big_span_lo = self.codemap.lookup_char_pos(span.lo()).file.start_pos;
        let local_begin = self.codemap.lookup_byte_offset(big_span_lo);
        let local_end = self.codemap.lookup_byte_offset(span.hi());
        let start_index = local_begin.pos.to_usize();
        let end_index = local_end.pos.to_usize();
        let big_snippet = &local_begin.fm.src.as_ref().unwrap()[start_index..end_index];

        let big_diff = (span.lo() - big_span_lo).to_usize();
        let snippet = self.snippet(span);

        debug!("write_snippet `{}`", snippet);

        self.write_snippet_inner(big_snippet, big_diff, &snippet, span, process_last_snippet);
    }

    fn process_comment(
        &mut self,
        status: &mut SnippetStatus,
        snippet: &str,
        big_snippet: &str,
        offset: usize,
        big_diff: usize,
        subslice: &str,
        file_name: &str,
    ) -> bool {
        let last_char = big_snippet[..(offset + big_diff)]
            .chars()
            .rev()
            .skip_while(|rev_c| [' ', '\t'].contains(rev_c))
            .next();

        let fix_indent = last_char.map_or(true, |rev_c| ['{', '\n'].contains(&rev_c));

        let subslice_num_lines = count_newlines(subslice);
        let skip_this_range = !self.config.file_lines().intersects_range(
            file_name,
            status.cur_line,
            status.cur_line + subslice_num_lines,
        );

        if status.rewrite_next_comment && skip_this_range {
            status.rewrite_next_comment = false;
        }

        if status.rewrite_next_comment {
            if fix_indent {
                if let Some('{') = last_char {
                    self.buffer.push_str("\n");
                }
                self.buffer
                    .push_str(&self.block_indent.to_string(self.config));
            } else {
                self.buffer.push_str(" ");
            }

            let comment_width = ::std::cmp::min(
                self.config.comment_width(),
                self.config.max_width() - self.block_indent.width(),
            );
            let comment_indent = Indent::from_width(self.config, self.buffer.cur_offset());
            let comment_shape = Shape::legacy(comment_width, comment_indent);
            let comment_str = rewrite_comment(subslice, false, comment_shape, self.config)
                .unwrap_or_else(|| String::from(subslice));
            self.buffer.push_str(&comment_str);

            status.last_wspace = None;
            status.line_start = offset + subslice.len();

            if let Some('/') = subslice.chars().nth(1) {
                // check that there are no contained block comments
                if !subslice
                    .split('\n')
                    .map(|s| s.trim_left())
                    .any(|s| s.len() >= 2 && &s[0..2] == "/*")
                {
                    // Add a newline after line comments
                    self.buffer.push_str("\n");
                }
            } else if status.line_start <= snippet.len() {
                // For other comments add a newline if there isn't one at the end already
                match snippet[status.line_start..].chars().next() {
                    Some('\n') | Some('\r') => (),
                    _ => self.buffer.push_str("\n"),
                }
            }

            status.cur_line += subslice_num_lines;
            true
        } else {
            status.rewrite_next_comment = false;
            false
        }
    }

    fn write_snippet_inner<F>(
        &mut self,
        big_snippet: &str,
        big_diff: usize,
        old_snippet: &str,
        span: Span,
        process_last_snippet: F,
    ) where
        F: Fn(&mut FmtVisitor, &str, &str),
    {
        // Trim whitespace from the right hand side of each line.
        // Annoyingly, the library functions for splitting by lines etc. are not
        // quite right, so we must do it ourselves.
        let char_pos = self.codemap.lookup_char_pos(span.lo());
        let file_name = &char_pos.file.name;
        let mut status = SnippetStatus::new(char_pos.line);

        fn replace_chars<'a>(string: &'a str) -> Cow<'a, str> {
            if string.contains(char::is_whitespace) {
                Cow::from(
                    string
                        .chars()
                        .map(|ch| if ch.is_whitespace() { ch } else { 'X' })
                        .collect::<String>(),
                )
            } else {
                Cow::from(string)
            }
        }

        let snippet = &*match self.config.write_mode() {
            WriteMode::Coverage => replace_chars(old_snippet),
            _ => Cow::from(old_snippet),
        };

        for (kind, offset, subslice) in CommentCodeSlices::new(snippet) {
            debug!("{:?}: {:?}", kind, subslice);

            if let CodeCharKind::Comment = kind {
                if self.process_comment(
                    &mut status,
                    snippet,
                    big_snippet,
                    offset,
                    big_diff,
                    subslice,
                    file_name,
                ) {
                    continue;
                }
            }

            let newline_count = count_newlines(&subslice);
            if subslice.trim().is_empty() && newline_count > 0
                && self.config.file_lines().intersects_range(
                    file_name,
                    status.cur_line,
                    status.cur_line + newline_count,
                ) {
                self.push_vertical_spaces(newline_count);
                status.cur_line += newline_count;
                status.rewrite_next_comment = true;
                status.line_start = offset + newline_count;
            } else {
                for (mut i, c) in subslice.char_indices() {
                    i += offset;

                    if c == '\n' {
                        if !self.config
                            .file_lines()
                            .contains_line(file_name, status.cur_line)
                        {
                            status.last_wspace = None;
                        }

                        if let Some(lw) = status.last_wspace {
                            self.buffer.push_str(&snippet[status.line_start..lw]);
                            self.buffer.push_str("\n");
                        } else {
                            self.buffer.push_str(&snippet[status.line_start..i + 1]);
                        }

                        status.cur_line += 1;
                        status.line_start = i + 1;
                        status.last_wspace = None;
                        status.rewrite_next_comment = true;
                    } else if c.is_whitespace() {
                        if status.last_wspace.is_none() {
                            status.last_wspace = Some(i);
                        }
                    } else if c == ';' {
                        if status.last_wspace.is_some() {
                            status.line_start = i;
                        }

                        status.rewrite_next_comment = true;
                        status.last_wspace = None;
                    } else {
                        status.rewrite_next_comment = true;
                        status.last_wspace = None;
                    }
                }

                let remaining = snippet[status.line_start..subslice.len() + offset].trim();
                if !remaining.is_empty() {
                    self.buffer.push_str(remaining);
                    status.line_start = subslice.len() + offset;
                    status.rewrite_next_comment = true;
                }
            }
        }

        process_last_snippet(self, &snippet[status.line_start..], snippet);
    }
}

struct SnippetStatus {
    line_start: usize,
    last_wspace: Option<usize>,
    rewrite_next_comment: bool,
    cur_line: usize,
}

impl SnippetStatus {
    fn new(cur_line: usize) -> Self {
        SnippetStatus {
            line_start: 0,
            last_wspace: None,
            rewrite_next_comment: true,
            cur_line,
        }
    }
}
<|endoftext|>


<commit_before>use parsers::*;

#[deriving(Show, Eq, PartialEq, Clone)]
enum Input {
  A,
  B,
  C,
  D,
}

//need more tests :/

#[test]
fn test_seq() {
  let input = [Input::A, Input::B, Input::C, Input::D];
  let parser = seq!(literal(Input::A), literal(Input::B), literal(Input::C));
  assert_eq!( parser.parse(input.as_slice()) , Ok(((Input::A, (Input::B, Input::C)), input.slice_from(3))));
}

#[test]
fn test_seq_map() {
  let input = [Input::A, Input::B];
  let parser = seq!(literal(Input::A), literal(Input::B) to |&: (a, b)| 5u);
  let expected = Ok( (5u, [].as_slice()) );
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_rep() {
  let input = [Input::A, Input::B, Input::A, Input::B, Input::A, Input::C];
  let parser = rep!(seq!(literal(Input::A), literal(Input::B)));
  let expected = Ok((
    vec![(Input::A, Input::B), (Input::A, Input::B)],
    input.slice_from(4)
  ));
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_or() {
  let input = [Input::A, Input::B, Input::A, Input::C];
  let parser = rep!(or!(literal(Input::A), literal(Input::B)));
  let expected = Ok((
    vec![Input::A, Input::B, Input::A],
    input.slice_from(3)
  ));
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_multi_or() {
  let input = [Input::A];
  let parser = or!(literal(Input::A), literal(Input::B), literal(Input::C));
  let expected = Ok( (Input::A, [].as_slice()) );
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_or_map() {
  let input = [Input::B];
  let parser = or!(literal(Input::A), literal(Input::B) to |&: x| 5u);
  let expected = Ok( (5u, [].as_slice()) );
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_map() {
  let input = [Input::A];
  let parser = map!(literal(Input::A), |&: a| 5u);
  let expected = Ok( (5u, [].as_slice()) );
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_recursive_or() {
  let input = [Input::A, Input::A, Input::C];
  fn a_seq<'a>() -> Box<Parser<'a, &'a [Input], uint> + 'a> {
    box or!(
      map!(literal(Input::C), |&: _| 2u),
      map!(seq!(literal(Input::A), lazy!(a_seq())), |&: (a, seq)| 1u + seq)
    )
  }
  let parser = a_seq();
  let expected = Ok( (4u, [].as_slice()) );
  assert_eq!( parser.parse(input.as_slice()), expected );

}

#[test]
fn test_repsep() {
  let input = [Input::A, Input::B, Input::C, Input::B, Input::A, Input::A];
  let parser = repsep!(or!(literal(Input::A), literal(Input::C)) , literal(Input::B));
  let expected = Ok((vec![Input::A, Input::C, Input::A], input.slice_from(5)));
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_opt() {
  let input = [Input::A, Input::A, Input::B];
  let parser = rep!(seq!(literal(Input::A), opt!(literal(Input::B))));
  let expected = Ok((vec![(Input::A, None), (Input::A, Some(Input::B))], input.slice_from(3)));
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_matcher() {
  let input = [Input::A, Input::B, Input::C];
  let parser = rep!(matcher!(Input : Input::A => 4u, Input::B => 5u));
  let expected = Ok( (vec![4u, 5u], input.slice_from(2)) );
  assert_eq!( parser.parse(input.as_slice()), expected );

}

<commit_msg>Use Box::new rather than box to appease new Rust<commit_after>use parsers::*;

#[deriving(Show, Eq, PartialEq, Clone)]
enum Input {
  A,
  B,
  C,
  D,
}

//need more tests :/

#[test]
fn test_seq() {
  let input = [Input::A, Input::B, Input::C, Input::D];
  let parser = seq!(literal(Input::A), literal(Input::B), literal(Input::C));
  assert_eq!( parser.parse(input.as_slice()) , Ok(((Input::A, (Input::B, Input::C)), input.slice_from(3))));
}

#[test]
fn test_seq_map() {
  let input = [Input::A, Input::B];
  let parser = seq!(literal(Input::A), literal(Input::B) to |&: (a, b)| 5u);
  let expected = Ok( (5u, [].as_slice()) );
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_rep() {
  let input = [Input::A, Input::B, Input::A, Input::B, Input::A, Input::C];
  let parser = rep!(seq!(literal(Input::A), literal(Input::B)));
  let expected = Ok((
    vec![(Input::A, Input::B), (Input::A, Input::B)],
    input.slice_from(4)
  ));
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_or() {
  let input = [Input::A, Input::B, Input::A, Input::C];
  let parser = rep!(or!(literal(Input::A), literal(Input::B)));
  let expected = Ok((
    vec![Input::A, Input::B, Input::A],
    input.slice_from(3)
  ));
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_multi_or() {
  let input = [Input::A];
  let parser = or!(literal(Input::A), literal(Input::B), literal(Input::C));
  let expected = Ok( (Input::A, [].as_slice()) );
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_or_map() {
  let input = [Input::B];
  let parser = or!(literal(Input::A), literal(Input::B) to |&: x| 5u);
  let expected = Ok( (5u, [].as_slice()) );
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_map() {
  let input = [Input::A];
  let parser = map!(literal(Input::A), |&: a| 5u);
  let expected = Ok( (5u, [].as_slice()) );
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_recursive_or() {
  let input = [Input::A, Input::A, Input::C];
  fn a_seq<'a>() -> Box<Parser<'a, &'a [Input], uint> + 'a> {
    Box::new(or!(
      map!(literal(Input::C), |&: _| 2u),
      map!(seq!(literal(Input::A), lazy!(a_seq())), |&: (a, seq)| 1u + seq)
    ))
  }
  let parser = a_seq();
  let expected = Ok( (4u, [].as_slice()) );
  assert_eq!( parser.parse(input.as_slice()), expected );

}

#[test]
fn test_repsep() {
  let input = [Input::A, Input::B, Input::C, Input::B, Input::A, Input::A];
  let parser = repsep!(or!(literal(Input::A), literal(Input::C)) , literal(Input::B));
  let expected = Ok((vec![Input::A, Input::C, Input::A], input.slice_from(5)));
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_opt() {
  let input = [Input::A, Input::A, Input::B];
  let parser = rep!(seq!(literal(Input::A), opt!(literal(Input::B))));
  let expected = Ok((vec![(Input::A, None), (Input::A, Some(Input::B))], input.slice_from(3)));
  assert_eq!( parser.parse(input.as_slice()), expected );
}

#[test]
fn test_matcher() {
  let input = [Input::A, Input::B, Input::C];
  let parser = rep!(matcher!(Input : Input::A => 4u, Input::B => 5u));
  let expected = Ok( (vec![4u, 5u], input.slice_from(2)) );
  assert_eq!( parser.parse(input.as_slice()), expected );

}

<|endoftext|>


<commit_before>use Result;
use point::Error;
use std::fmt;

const TIME_FORMATS: &'static [u8] = &[1, 3, 4, 5, 6, 7, 8, 9, 10];
const COLOR_FORMATS: &'static [u8] = &[2, 3, 5, 7, 8, 10];
const WAVEFORM_FORMATS: &'static [u8] = &[4, 5, 9, 10];
const NIR_FORMATS: &'static [u8] = &[8, 10];

/// A point format describes the attributes associated with the point.
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Format {
    /// Does this point format include gps time?
    pub has_gps_time: bool,
    /// Does this point format include red, green, and blue colors?
    pub has_color: bool,
    /// Does this point format use two bytes for its flags and scaled scan angles?
    pub is_extended: bool,
    /// Does this point format have waveforms?
    pub has_waveform: bool,
    /// Does this point format have near infrared data?
    pub has_nir: bool,
    /// The number of extra bytes on each point.
    pub extra_bytes: u16,
}

impl Format {
    /// Creates a new point format from a u8.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::point::Format;
    /// let format = Format::new(0).unwrap();
    /// assert!(!format.has_gps_time);
    /// assert!(!format.has_color);
    ///
    /// let format = Format::new(3).unwrap();
    /// assert!(format.has_gps_time);
    /// assert!(format.has_color);
    ///
    /// assert!(Format::new(11).is_err());
    /// ```
    pub fn new(n: u8) -> Result<Format> {
        if n > 10 {
            Err(Error::FormatNumber(n).into())
        } else {
            Ok(Format {
                has_gps_time: TIME_FORMATS.contains(&n),
                has_color: COLOR_FORMATS.contains(&n),
                has_waveform: WAVEFORM_FORMATS.contains(&n),
                has_nir: NIR_FORMATS.contains(&n),
                is_extended: n >= 6,
                ..Default::default()
            })
        }
    }

    /// Returns this point format's length.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::point::Format;
    /// let mut format = Format::new(0).unwrap();
    /// assert_eq!(20, format.len());
    /// format.has_gps_time = true;
    /// assert_eq!(28, format.len());
    /// ```
    pub fn len(&self) -> u16 {
        let mut len = if self.is_extended { 22 } else { 20 } + self.extra_bytes;
        if self.has_gps_time {
            len += 8;
        }
        if self.has_color {
            len += 6;
        }
        if self.has_nir {
            len += 2;
        }
        if self.has_waveform {
            len += 29;
        }
        len
    }

    /// Converts this point format to a u8.
    ///
    /// Can return an error if there is an invalid combination of attributes.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::point::Format;
    /// let mut format = Format::default();
    /// assert_eq!(0, format.to_u8().unwrap());
    /// format.is_extended = true;
    /// assert!(format.to_u8().is_err());
    /// format.has_gps_time = true;
    /// assert_eq!(6, format.to_u8().unwrap());
    /// ```
    pub fn to_u8(&self) -> Result<u8> {
        if self.is_extended {
            if self.has_gps_time {
                if self.has_color {
                    if self.has_nir {
                        if self.has_waveform { Ok(10) } else { Ok(8) }
                    } else {
                        if self.has_waveform {
                            Err(Error::Format(*self).into())
                        } else {
                            Ok(7)
                        }
                    }
                } else {
                    if self.has_nir {
                        Err(Error::Format(*self).into())
                    } else {
                        if self.has_waveform { Ok(9) } else { Ok(6) }
                    }
                }
            } else {
                Err(Error::Format(*self).into())
            }
        } else if self.has_nir {
            Err(Error::Format(*self).into())
        } else {
            if self.has_waveform {
                if self.has_gps_time {
                    if self.has_color { Ok(5) } else { Ok(4) }
                } else {
                    Err(Error::Format(*self).into())
                }
            } else {
                let mut n = if self.has_gps_time { 1 } else { 0 };
                if self.has_color {
                    n += 2;
                }
                Ok(n)
            }
        }
    }
}

impl fmt::Display for Format {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Ok(n) = self.to_u8() {
            write!(f, "point format {}", n)
        } else {
            write!(f, "point format that does not map onto a code: {:?}", self)
        }
    }
}

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

    macro_rules! format {
        ($name:ident, $n:expr, $expected:expr, $len:expr) => {
            mod $name {
                use point::Format;

                #[test]
                fn new() {
                    assert_eq!($expected, Format::new($n).unwrap());
                }

                #[test]
                fn len() {
                    assert_eq!($len, Format::new($n).unwrap().len());
                }

                #[test]
                fn to_u8() {
                    assert_eq!($n, Format::new($n).unwrap().to_u8().unwrap());
                }
            }
        }
    }

    format!(format_0, 0, Format::default(), 20);
    format!(
        format_1,
        1,
        Format {
            has_gps_time: true,
            ..Default::default()
        },
        28
    );
    format!(
        format_2,
        2,
        Format {
            has_color: true,
            ..Default::default()
        },
        26
    );
    format!(
        format_3,
        3,
        Format {
            has_gps_time: true,
            has_color: true,
            ..Default::default()
        },
        34
    );
    format!(
        format_4,
        4,
        Format {
            has_gps_time: true,
            has_waveform: true,
            ..Default::default()
        },
        57
    );
    format!(
        format_5,
        5,
        Format {
            has_gps_time: true,
            has_color: true,
            has_waveform: true,
            ..Default::default()
        },
        63
    );
    format!(
        format_6,
        6,
        Format {
            has_gps_time: true,
            is_extended: true,
            ..Default::default()
        },
        30
    );
    format!(
        format_7,
        7,
        Format {
            has_gps_time: true,
            has_color: true,
            is_extended: true,
            ..Default::default()
        },
        36
    );
    format!(
        format_8,
        8,
        Format {
            has_gps_time: true,
            has_color: true,
            has_nir: true,
            is_extended: true,
            ..Default::default()
        },
        38
    );
    format!(
        format_9,
        9,
        Format {
            has_gps_time: true,
            has_waveform: true,
            is_extended: true,
            ..Default::default()
        },
        59
    );
    format!(
        format_10,
        10,
        Format {
            has_gps_time: true,
            has_color: true,
            has_nir: true,
            has_waveform: true,
            is_extended: true,
            ..Default::default()
        },
        67
    );

    #[test]
    fn waveform_without_gps_time() {
        let format = Format {
            has_waveform: true,
            ..Default::default()
        };
        assert!(format.to_u8().is_err());
    }

    #[test]
    fn extended_without_gps_time() {
        let format = Format {
            is_extended: true,
            ..Default::default()
        };
        assert!(format.to_u8().is_err());
    }

    #[test]
    fn nir_without_extended() {
        let format = Format {
            has_nir: true,
            ..Default::default()
        };
        assert!(format.to_u8().is_err());
    }

    #[test]
    fn nir_without_color() {
        let format = Format {
            is_extended: true,
            has_nir: true,
            ..Default::default()
        };
        assert!(format.to_u8().is_err());
    }

    #[test]
    fn extra_bytes() {
        let format = Format {
            extra_bytes: 1,
            ..Default::default()
        };
        assert_eq!(21, format.len());
    }
}
<commit_msg>Add Format::extend<commit_after>use Result;
use point::Error;
use std::fmt;

const TIME_FORMATS: &'static [u8] = &[1, 3, 4, 5, 6, 7, 8, 9, 10];
const COLOR_FORMATS: &'static [u8] = &[2, 3, 5, 7, 8, 10];
const WAVEFORM_FORMATS: &'static [u8] = &[4, 5, 9, 10];
const NIR_FORMATS: &'static [u8] = &[8, 10];

/// A point format describes the attributes associated with the point.
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Format {
    /// Does this point format include gps time?
    pub has_gps_time: bool,
    /// Does this point format include red, green, and blue colors?
    pub has_color: bool,
    /// Does this point format use two bytes for its flags and scaled scan angles?
    pub is_extended: bool,
    /// Does this point format have waveforms?
    pub has_waveform: bool,
    /// Does this point format have near infrared data?
    pub has_nir: bool,
    /// The number of extra bytes on each point.
    pub extra_bytes: u16,
}

impl Format {
    /// Creates a new point format from a u8.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::point::Format;
    /// let format = Format::new(0).unwrap();
    /// assert!(!format.has_gps_time);
    /// assert!(!format.has_color);
    ///
    /// let format = Format::new(3).unwrap();
    /// assert!(format.has_gps_time);
    /// assert!(format.has_color);
    ///
    /// assert!(Format::new(11).is_err());
    /// ```
    pub fn new(n: u8) -> Result<Format> {
        if n > 10 {
            Err(Error::FormatNumber(n).into())
        } else {
            Ok(Format {
                has_gps_time: TIME_FORMATS.contains(&n),
                has_color: COLOR_FORMATS.contains(&n),
                has_waveform: WAVEFORM_FORMATS.contains(&n),
                has_nir: NIR_FORMATS.contains(&n),
                is_extended: n >= 6,
                ..Default::default()
            })
        }
    }

    /// Converts this point format into an extended format.
    ///
    /// "Extended" formats can contain more information per point, and must have gps time.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::point::Format;
    /// let mut format = Format::default();
    /// assert!(!format.has_gps_time);
    /// assert!(!format.is_extended);
    /// format.extend();
    /// assert!(format.has_gps_time);
    /// assert!(format.is_extended);
    pub fn extend(&mut self) {
        self.has_gps_time = true;
        self.is_extended = true;
    }

    /// Returns this point format's length.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::point::Format;
    /// let mut format = Format::new(0).unwrap();
    /// assert_eq!(20, format.len());
    /// format.has_gps_time = true;
    /// assert_eq!(28, format.len());
    /// ```
    pub fn len(&self) -> u16 {
        let mut len = if self.is_extended { 22 } else { 20 } + self.extra_bytes;
        if self.has_gps_time {
            len += 8;
        }
        if self.has_color {
            len += 6;
        }
        if self.has_nir {
            len += 2;
        }
        if self.has_waveform {
            len += 29;
        }
        len
    }

    /// Converts this point format to a u8.
    ///
    /// Can return an error if there is an invalid combination of attributes.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::point::Format;
    /// let mut format = Format::default();
    /// assert_eq!(0, format.to_u8().unwrap());
    /// format.is_extended = true;
    /// assert!(format.to_u8().is_err());
    /// format.has_gps_time = true;
    /// assert_eq!(6, format.to_u8().unwrap());
    /// ```
    pub fn to_u8(&self) -> Result<u8> {
        if self.is_extended {
            if self.has_gps_time {
                if self.has_color {
                    if self.has_nir {
                        if self.has_waveform { Ok(10) } else { Ok(8) }
                    } else {
                        if self.has_waveform {
                            Err(Error::Format(*self).into())
                        } else {
                            Ok(7)
                        }
                    }
                } else {
                    if self.has_nir {
                        Err(Error::Format(*self).into())
                    } else {
                        if self.has_waveform { Ok(9) } else { Ok(6) }
                    }
                }
            } else {
                Err(Error::Format(*self).into())
            }
        } else if self.has_nir {
            Err(Error::Format(*self).into())
        } else {
            if self.has_waveform {
                if self.has_gps_time {
                    if self.has_color { Ok(5) } else { Ok(4) }
                } else {
                    Err(Error::Format(*self).into())
                }
            } else {
                let mut n = if self.has_gps_time { 1 } else { 0 };
                if self.has_color {
                    n += 2;
                }
                Ok(n)
            }
        }
    }
}

impl fmt::Display for Format {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Ok(n) = self.to_u8() {
            write!(f, "point format {}", n)
        } else {
            write!(f, "point format that does not map onto a code: {:?}", self)
        }
    }
}

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

    macro_rules! format {
        ($name:ident, $n:expr, $expected:expr, $len:expr) => {
            mod $name {
                use point::Format;

                #[test]
                fn new() {
                    assert_eq!($expected, Format::new($n).unwrap());
                }

                #[test]
                fn len() {
                    assert_eq!($len, Format::new($n).unwrap().len());
                }

                #[test]
                fn to_u8() {
                    assert_eq!($n, Format::new($n).unwrap().to_u8().unwrap());
                }
            }
        }
    }

    format!(format_0, 0, Format::default(), 20);
    format!(
        format_1,
        1,
        Format {
            has_gps_time: true,
            ..Default::default()
        },
        28
    );
    format!(
        format_2,
        2,
        Format {
            has_color: true,
            ..Default::default()
        },
        26
    );
    format!(
        format_3,
        3,
        Format {
            has_gps_time: true,
            has_color: true,
            ..Default::default()
        },
        34
    );
    format!(
        format_4,
        4,
        Format {
            has_gps_time: true,
            has_waveform: true,
            ..Default::default()
        },
        57
    );
    format!(
        format_5,
        5,
        Format {
            has_gps_time: true,
            has_color: true,
            has_waveform: true,
            ..Default::default()
        },
        63
    );
    format!(
        format_6,
        6,
        Format {
            has_gps_time: true,
            is_extended: true,
            ..Default::default()
        },
        30
    );
    format!(
        format_7,
        7,
        Format {
            has_gps_time: true,
            has_color: true,
            is_extended: true,
            ..Default::default()
        },
        36
    );
    format!(
        format_8,
        8,
        Format {
            has_gps_time: true,
            has_color: true,
            has_nir: true,
            is_extended: true,
            ..Default::default()
        },
        38
    );
    format!(
        format_9,
        9,
        Format {
            has_gps_time: true,
            has_waveform: true,
            is_extended: true,
            ..Default::default()
        },
        59
    );
    format!(
        format_10,
        10,
        Format {
            has_gps_time: true,
            has_color: true,
            has_nir: true,
            has_waveform: true,
            is_extended: true,
            ..Default::default()
        },
        67
    );

    #[test]
    fn waveform_without_gps_time() {
        let format = Format {
            has_waveform: true,
            ..Default::default()
        };
        assert!(format.to_u8().is_err());
    }

    #[test]
    fn extended_without_gps_time() {
        let format = Format {
            is_extended: true,
            ..Default::default()
        };
        assert!(format.to_u8().is_err());
    }

    #[test]
    fn nir_without_extended() {
        let format = Format {
            has_nir: true,
            ..Default::default()
        };
        assert!(format.to_u8().is_err());
    }

    #[test]
    fn nir_without_color() {
        let format = Format {
            is_extended: true,
            has_nir: true,
            ..Default::default()
        };
        assert!(format.to_u8().is_err());
    }

    #[test]
    fn extra_bytes() {
        let format = Format {
            extra_bytes: 1,
            ..Default::default()
        };
        assert_eq!(21, format.len());
    }
}
<|endoftext|>


<commit_before>//! List projects
//!
//! https://docs.gitlab.com/ce/api/projects.html
//!
//! # List projects
//!
//! Get a list of projects for which the authenticated user is a member.
//!
//! ```text
//! GET /projects
//! ```
//!
//! Parameters:
//!
//! | Attribute | Type | Required | Description |
//! | --------- | ---- | -------- | ----------- |
//! | `archived` | boolean | no | Limit by archived status |
//! | `visibility` | string | no | Limit by visibility `public`, `internal`, or `private` |
//! | `order_by` | string | no | Return projects ordered by `id`, `name`, `path`, `created_at`, `updated_at`, or `last_activity_at` fields. Default is `created_at` |
//! | `sort` | string | no | Return projects sorted in `asc` or `desc` order. Default is `desc` |
//! | `search` | string | no | Return list of authorized projects matching the search criteria |
//! | `simple` | boolean | no | Return only the ID, URL, name, and path of each project |
//!

use serde_urlencoded;

use BuildQuery;
use Project;
use Projects;

pub mod all;
pub mod id_branches;
pub mod id_branch;
pub mod id_events;
pub mod id_hooks_id;
pub mod id_hooks;
pub mod id;
pub mod owned;
pub mod search;
pub mod starred;
pub mod visible;

use ::errors::*;

#[cfg(feature = "serde_derive")]
include!("serde_types.in.rs");

#[cfg(feature = "serde_codegen")]
include!(concat!(env!("OUT_DIR"), "/projects/serde_types.rs"));

#[derive(Debug, Clone)]
pub struct ProjectsLister<'a> {
    gl: &'a ::GitLab,
    internal: ProjectListerInternal,
}

impl<'a> ProjectsLister<'a> {
    pub fn new(gl: &'a ::GitLab) -> ProjectsLister {
        ProjectsLister {
            gl: gl,
            internal: ProjectListerInternal {
                archived: None,
                visibility: None,
                order_by: None,
                sort: None,
                search: None,
                simple: None,
            },
        }
    }

    pub fn all(self) -> all::ProjectsLister<'a> {
        // assert_eq!(self, ProjectsLister::new(self.gl));
        all::ProjectsLister::new(self.gl)
    }

    pub fn owned(self) -> owned::ProjectsLister<'a> {
        // assert_eq!(self, ProjectsLister::new(self.gl));
        owned::ProjectsLister::new(self.gl)
    }

    pub fn search(self, query: String) -> search::ProjectsLister<'a> {
        // assert_eq!(self, ProjectsLister::new(self.gl));
        search::ProjectsLister::new(self.gl, query)
    }

    pub fn id(self, id: ListingId) -> id::ProjectsLister<'a> {
        // assert_eq!(self, ProjectsLister::new(self.gl));
        id::ProjectsLister::new(self.gl, id)
    }

    pub fn archived(&'a mut self, archived: bool) -> &'a mut ProjectsLister {
        self.internal.archived = Some(archived);
        self
    }

    pub fn visibility(&'a mut self, visibility: ::ListingVisibility) -> &'a mut ProjectsLister {
        self.internal.visibility = Some(visibility);
        self
    }

    pub fn order_by(&'a mut self, order_by: ListingOrderBy) -> &'a mut ProjectsLister {
        self.internal.order_by = Some(order_by);
        self
    }

    pub fn sort(&'a mut self, sort: ::ListingSort) -> &'a mut ProjectsLister {
        self.internal.sort = Some(sort);
        self
    }

    pub fn search_pattern(&'a mut self, search: String) -> &'a mut ProjectsLister {
        self.internal.search = Some(search);
        self
    }

    pub fn simple(&'a mut self, simple: bool) -> &'a mut ProjectsLister {
        self.internal.simple = Some(simple);
        self
    }

    /// Commit the lister: Query GitLab and return a list of projects.
    pub fn list(&self) -> Result<Projects> {
        let query = self.build_query();
        debug!("query: {:?}", query);

        self.gl.get(&query).chain_err(|| format!("cannot get query {}", query))
    }
}

impl<'a> BuildQuery for ProjectsLister<'a> {
    fn build_query(&self) -> String {

        let encoded = serde_urlencoded::to_string(&self.internal).unwrap();
        let mut query = String::from("projects");
        if !encoded.is_empty() {
            query.push_str("?");
            query.push_str(&encoded);
        }

        query
    }
}

impl<'a> Project {
    /// Return a lister for the project's issues
    pub fn issues(&'a self, gl: &'a ::GitLab) -> ::issues::project::IssuesLister {
        ::issues::project::IssuesLister::new(gl, self.id)
    }

    /// Return a lister for the project's merge requests
    pub fn merge_requests(&'a self, gl: &'a ::GitLab) -> ::merge_requests::MergeRequestsLister {
        ::merge_requests::MergeRequestsLister::new(gl)
    }
}

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

    #[test]
    fn build_query_default() {
        let expected_string = "projects";

        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let projects_lister = gl.projects();
        let query = projects_lister.build_query();
        assert_eq!(query, expected_string);

        let query = gl.projects().build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_archived() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = "projects?archived=true";

        let mut projects_lister = gl.projects();
        let query = projects_lister.archived(true).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().archived(true).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?archived=false";

        let mut projects_lister = gl.projects();
        let query = projects_lister.archived(false).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().archived(false).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_visibility() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = "projects?visibility=public";
        let mut projects_lister = gl.projects();
        let query = projects_lister.visibility(::ListingVisibility::Public).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().visibility(::ListingVisibility::Public).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?visibility=internal";
        let mut projects_lister = gl.projects();
        let query = projects_lister.visibility(::ListingVisibility::Internal).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().visibility(::ListingVisibility::Internal).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?visibility=private";
        let mut projects_lister = gl.projects();
        let query = projects_lister.visibility(::ListingVisibility::Private).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().visibility(::ListingVisibility::Private).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_order_by() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = "projects?order_by=id";
        let mut projects_lister = gl.projects();
        let query = projects_lister.order_by(::projects::ListingOrderBy::Id).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().order_by(::projects::ListingOrderBy::Id).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?order_by=name";
        let mut projects_lister = gl.projects();
        let query = projects_lister.order_by(::projects::ListingOrderBy::Name).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().order_by(::projects::ListingOrderBy::Name).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?order_by=path";
        let mut projects_lister = gl.projects();
        let query = projects_lister.order_by(::projects::ListingOrderBy::Path).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().order_by(::projects::ListingOrderBy::Path).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?order_by=created_at";
        let mut projects_lister = gl.projects();
        let query = projects_lister.order_by(::projects::ListingOrderBy::CreatedAt).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().order_by(::projects::ListingOrderBy::CreatedAt).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?order_by=updated_at";
        let mut projects_lister = gl.projects();
        let query = projects_lister.order_by(::projects::ListingOrderBy::UpdatedAt).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().order_by(::projects::ListingOrderBy::UpdatedAt).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?order_by=last_activity_at";
        let mut projects_lister = gl.projects();
        let query = projects_lister.order_by(::projects::ListingOrderBy::LastActivityAt)
            .build_query();
        assert_eq!(query, expected_string);
        let query =
            gl.projects().order_by(::projects::ListingOrderBy::LastActivityAt).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_sort() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = "projects?sort=asc";
        let mut projects_lister = gl.projects();
        let query = projects_lister.sort(::ListingSort::Asc).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().sort(::ListingSort::Asc).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?sort=desc";
        let mut projects_lister = gl.projects();
        let query = projects_lister.sort(::ListingSort::Desc).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().sort(::ListingSort::Desc).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_search() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = "projects?search=SearchPattern";
        let mut projects_lister = gl.projects();
        let query = projects_lister.search_pattern(String::from("SearchPattern")).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().search_pattern(String::from("SearchPattern")).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_simple() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = "projects?simple=true";
        let mut projects_lister = gl.projects();
        let query = projects_lister.simple(true).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().simple(true).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?simple=false";
        let mut projects_lister = gl.projects();
        let query = projects_lister.simple(false).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().simple(false).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn groups_build_query_multiple() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = "projects?archived=true&simple=true";
        let mut projects_lister = gl.projects();
        let query = projects_lister.archived(true).simple(true).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().archived(true).simple(true).build_query();
        assert_eq!(query, expected_string);
    }
}
<commit_msg>Bug fix: Let `Project::merge_requests()` pass the project id to the lister constructor<commit_after>//! List projects
//!
//! https://docs.gitlab.com/ce/api/projects.html
//!
//! # List projects
//!
//! Get a list of projects for which the authenticated user is a member.
//!
//! ```text
//! GET /projects
//! ```
//!
//! Parameters:
//!
//! | Attribute | Type | Required | Description |
//! | --------- | ---- | -------- | ----------- |
//! | `archived` | boolean | no | Limit by archived status |
//! | `visibility` | string | no | Limit by visibility `public`, `internal`, or `private` |
//! | `order_by` | string | no | Return projects ordered by `id`, `name`, `path`, `created_at`, `updated_at`, or `last_activity_at` fields. Default is `created_at` |
//! | `sort` | string | no | Return projects sorted in `asc` or `desc` order. Default is `desc` |
//! | `search` | string | no | Return list of authorized projects matching the search criteria |
//! | `simple` | boolean | no | Return only the ID, URL, name, and path of each project |
//!

use serde_urlencoded;

use BuildQuery;
use Project;
use Projects;

pub mod all;
pub mod id_branches;
pub mod id_branch;
pub mod id_events;
pub mod id_hooks_id;
pub mod id_hooks;
pub mod id;
pub mod owned;
pub mod search;
pub mod starred;
pub mod visible;

use ::errors::*;

#[cfg(feature = "serde_derive")]
include!("serde_types.in.rs");

#[cfg(feature = "serde_codegen")]
include!(concat!(env!("OUT_DIR"), "/projects/serde_types.rs"));

#[derive(Debug, Clone)]
pub struct ProjectsLister<'a> {
    gl: &'a ::GitLab,
    internal: ProjectListerInternal,
}

impl<'a> ProjectsLister<'a> {
    pub fn new(gl: &'a ::GitLab) -> ProjectsLister {
        ProjectsLister {
            gl: gl,
            internal: ProjectListerInternal {
                archived: None,
                visibility: None,
                order_by: None,
                sort: None,
                search: None,
                simple: None,
            },
        }
    }

    pub fn all(self) -> all::ProjectsLister<'a> {
        // assert_eq!(self, ProjectsLister::new(self.gl));
        all::ProjectsLister::new(self.gl)
    }

    pub fn owned(self) -> owned::ProjectsLister<'a> {
        // assert_eq!(self, ProjectsLister::new(self.gl));
        owned::ProjectsLister::new(self.gl)
    }

    pub fn search(self, query: String) -> search::ProjectsLister<'a> {
        // assert_eq!(self, ProjectsLister::new(self.gl));
        search::ProjectsLister::new(self.gl, query)
    }

    pub fn id(self, id: ListingId) -> id::ProjectsLister<'a> {
        // assert_eq!(self, ProjectsLister::new(self.gl));
        id::ProjectsLister::new(self.gl, id)
    }

    pub fn archived(&'a mut self, archived: bool) -> &'a mut ProjectsLister {
        self.internal.archived = Some(archived);
        self
    }

    pub fn visibility(&'a mut self, visibility: ::ListingVisibility) -> &'a mut ProjectsLister {
        self.internal.visibility = Some(visibility);
        self
    }

    pub fn order_by(&'a mut self, order_by: ListingOrderBy) -> &'a mut ProjectsLister {
        self.internal.order_by = Some(order_by);
        self
    }

    pub fn sort(&'a mut self, sort: ::ListingSort) -> &'a mut ProjectsLister {
        self.internal.sort = Some(sort);
        self
    }

    pub fn search_pattern(&'a mut self, search: String) -> &'a mut ProjectsLister {
        self.internal.search = Some(search);
        self
    }

    pub fn simple(&'a mut self, simple: bool) -> &'a mut ProjectsLister {
        self.internal.simple = Some(simple);
        self
    }

    /// Commit the lister: Query GitLab and return a list of projects.
    pub fn list(&self) -> Result<Projects> {
        let query = self.build_query();
        debug!("query: {:?}", query);

        self.gl.get(&query).chain_err(|| format!("cannot get query {}", query))
    }
}

impl<'a> BuildQuery for ProjectsLister<'a> {
    fn build_query(&self) -> String {

        let encoded = serde_urlencoded::to_string(&self.internal).unwrap();
        let mut query = String::from("projects");
        if !encoded.is_empty() {
            query.push_str("?");
            query.push_str(&encoded);
        }

        query
    }
}

impl<'a> Project {
    /// Return a lister for the project's issues
    pub fn issues(&'a self, gl: &'a ::GitLab) -> ::issues::project::IssuesLister {
        ::issues::project::IssuesLister::new(gl, self.id)
    }

    /// Return a lister for the project's merge requests
    pub fn merge_requests(&'a self, gl: &'a ::GitLab) -> ::merge_requests::MergeRequestsLister {
        ::merge_requests::MergeRequestsLister::new(gl, self.id)
    }
}

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

    #[test]
    fn build_query_default() {
        let expected_string = "projects";

        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let projects_lister = gl.projects();
        let query = projects_lister.build_query();
        assert_eq!(query, expected_string);

        let query = gl.projects().build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_archived() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = "projects?archived=true";

        let mut projects_lister = gl.projects();
        let query = projects_lister.archived(true).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().archived(true).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?archived=false";

        let mut projects_lister = gl.projects();
        let query = projects_lister.archived(false).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().archived(false).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_visibility() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = "projects?visibility=public";
        let mut projects_lister = gl.projects();
        let query = projects_lister.visibility(::ListingVisibility::Public).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().visibility(::ListingVisibility::Public).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?visibility=internal";
        let mut projects_lister = gl.projects();
        let query = projects_lister.visibility(::ListingVisibility::Internal).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().visibility(::ListingVisibility::Internal).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?visibility=private";
        let mut projects_lister = gl.projects();
        let query = projects_lister.visibility(::ListingVisibility::Private).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().visibility(::ListingVisibility::Private).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_order_by() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = "projects?order_by=id";
        let mut projects_lister = gl.projects();
        let query = projects_lister.order_by(::projects::ListingOrderBy::Id).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().order_by(::projects::ListingOrderBy::Id).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?order_by=name";
        let mut projects_lister = gl.projects();
        let query = projects_lister.order_by(::projects::ListingOrderBy::Name).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().order_by(::projects::ListingOrderBy::Name).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?order_by=path";
        let mut projects_lister = gl.projects();
        let query = projects_lister.order_by(::projects::ListingOrderBy::Path).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().order_by(::projects::ListingOrderBy::Path).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?order_by=created_at";
        let mut projects_lister = gl.projects();
        let query = projects_lister.order_by(::projects::ListingOrderBy::CreatedAt).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().order_by(::projects::ListingOrderBy::CreatedAt).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?order_by=updated_at";
        let mut projects_lister = gl.projects();
        let query = projects_lister.order_by(::projects::ListingOrderBy::UpdatedAt).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().order_by(::projects::ListingOrderBy::UpdatedAt).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?order_by=last_activity_at";
        let mut projects_lister = gl.projects();
        let query = projects_lister.order_by(::projects::ListingOrderBy::LastActivityAt)
            .build_query();
        assert_eq!(query, expected_string);
        let query =
            gl.projects().order_by(::projects::ListingOrderBy::LastActivityAt).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_sort() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = "projects?sort=asc";
        let mut projects_lister = gl.projects();
        let query = projects_lister.sort(::ListingSort::Asc).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().sort(::ListingSort::Asc).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?sort=desc";
        let mut projects_lister = gl.projects();
        let query = projects_lister.sort(::ListingSort::Desc).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().sort(::ListingSort::Desc).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_search() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = "projects?search=SearchPattern";
        let mut projects_lister = gl.projects();
        let query = projects_lister.search_pattern(String::from("SearchPattern")).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().search_pattern(String::from("SearchPattern")).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_simple() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = "projects?simple=true";
        let mut projects_lister = gl.projects();
        let query = projects_lister.simple(true).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().simple(true).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects?simple=false";
        let mut projects_lister = gl.projects();
        let query = projects_lister.simple(false).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().simple(false).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn groups_build_query_multiple() {
        let gl = ::GitLab::new(&"localhost", "XXXXXXXXXXXXXXXXXXXX").unwrap();
        // let gl: ::GitLab = Default::default();

        let expected_string = "projects?archived=true&simple=true";
        let mut projects_lister = gl.projects();
        let query = projects_lister.archived(true).simple(true).build_query();
        assert_eq!(query, expected_string);
        let query = gl.projects().archived(true).simple(true).build_query();
        assert_eq!(query, expected_string);
    }
}
<|endoftext|>


<commit_before>//! Iron's HTTP Response representation and associated methods.

use std::io::{mod, IoResult};
use std::fmt::{mod, Show};

use typemap::TypeMap;
use plugin::Extensible;
use modifier::{Set, Modifier};

use hyper::header::Headers;

use status::{mod, Status};
use {headers};

pub use hyper::server::response::Response as HttpResponse;
use hyper::net::Fresh;

pub mod modifiers;

/// The response representation given to `Middleware`
pub struct Response {
    /// The response status-code.
    pub status: Option<Status>,

    /// The headers of the response.
    pub headers: Headers,

    /// A TypeMap to be used as an extensible storage for data
    /// associated with this Response.
    pub extensions: TypeMap,

    /// The body of the response.
    ///
    /// This is a Reader for generality, most data should
    /// be sent using either `serve` or `serve_file`.
    ///
    /// Arbitrary Readers can be sent by assigning to body.
    pub body: Option<Box<Reader + Send>>
}

impl Response {
    /// Construct a blank Response
    pub fn new() -> Response {
        Response {
            status: None, // Start with no response code.
            body: None, // Start with no body.
            headers: Headers::new(),
            extensions: TypeMap::new()
        }
    }

    /// Construct a Response with the specified modifier pre-applied.
    pub fn with<M: Modifier<Response>>(m: M) -> Response {
        Response::new().set(m)
    }

    // `write_back` is used to put all the data added to `self`
    // back onto an `HttpResponse` so that it is sent back to the
    // client.
    //
    // `write_back` consumes the `Response`.
    #[doc(hidden)]
    pub fn write_back(self, mut http_res: HttpResponse<Fresh>) {
        *http_res.headers_mut() = self.headers;

        // Default to a 404 if no response code was set
        *http_res.status_mut() = self.status.clone().unwrap_or(status::NotFound);

        let out = match self.body {
            Some(body) => write_with_body(http_res, body),
            None => {
                http_res.headers_mut().set(headers::ContentLength(0));
                http_res.start().and_then(|res| res.end())
            }
        };

        match out {
            Err(e) => {
                error!("Error writing response: {}", e);
            },
            _ => {}
        }
    }
}

fn write_with_body(mut res: HttpResponse<Fresh>, mut body: Box<Reader + Send>) -> IoResult<()> {
    let content_type = res.headers().get::<headers::ContentType>()
                           .map(|cx| cx.clone())
                           .unwrap_or_else(|| headers::ContentType("text/plain".parse().unwrap()));
    res.headers_mut().set(content_type);

    let mut res = try!(res.start());

    // FIXME: Manually inlined io::util::copy
    // because Box<Reader + Send> does not impl Reader.
    //
    // Tracking issue: rust-lang/rust#18542
    let mut buf = &mut [0, ..1024 * 64];
    loop {
        let len = match body.read(buf) {
            Ok(len) => len,
            Err(ref e) if e.kind == io::EndOfFile => break,
            Err(e) => { return Err(e) },
        };

        try!(res.write(buf[..len]))
    }

    res.end()
}

impl Show for Response {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "HTTP/1.1 {} {}\n{}",
            self.status.unwrap_or(status::NotFound),
            self.status.unwrap_or(status::NotFound).canonical_reason().unwrap(),
            self.headers
        )
    }
}

// Allow plugins to attach to responses.
impl Extensible for Response {
    fn extensions(&self) -> &TypeMap {
        &self.extensions
    }

    fn extensions_mut(&mut self) -> &mut TypeMap {
        &mut self.extensions
    }
}

impl Set for Response {}

<commit_msg>(fix) Update to use new array syntax.<commit_after>//! Iron's HTTP Response representation and associated methods.

use std::io::{mod, IoResult};
use std::fmt::{mod, Show};

use typemap::TypeMap;
use plugin::Extensible;
use modifier::{Set, Modifier};

use hyper::header::Headers;

use status::{mod, Status};
use {headers};

pub use hyper::server::response::Response as HttpResponse;
use hyper::net::Fresh;

pub mod modifiers;

/// The response representation given to `Middleware`
pub struct Response {
    /// The response status-code.
    pub status: Option<Status>,

    /// The headers of the response.
    pub headers: Headers,

    /// A TypeMap to be used as an extensible storage for data
    /// associated with this Response.
    pub extensions: TypeMap,

    /// The body of the response.
    ///
    /// This is a Reader for generality, most data should
    /// be sent using either `serve` or `serve_file`.
    ///
    /// Arbitrary Readers can be sent by assigning to body.
    pub body: Option<Box<Reader + Send>>
}

impl Response {
    /// Construct a blank Response
    pub fn new() -> Response {
        Response {
            status: None, // Start with no response code.
            body: None, // Start with no body.
            headers: Headers::new(),
            extensions: TypeMap::new()
        }
    }

    /// Construct a Response with the specified modifier pre-applied.
    pub fn with<M: Modifier<Response>>(m: M) -> Response {
        Response::new().set(m)
    }

    // `write_back` is used to put all the data added to `self`
    // back onto an `HttpResponse` so that it is sent back to the
    // client.
    //
    // `write_back` consumes the `Response`.
    #[doc(hidden)]
    pub fn write_back(self, mut http_res: HttpResponse<Fresh>) {
        *http_res.headers_mut() = self.headers;

        // Default to a 404 if no response code was set
        *http_res.status_mut() = self.status.clone().unwrap_or(status::NotFound);

        let out = match self.body {
            Some(body) => write_with_body(http_res, body),
            None => {
                http_res.headers_mut().set(headers::ContentLength(0));
                http_res.start().and_then(|res| res.end())
            }
        };

        match out {
            Err(e) => {
                error!("Error writing response: {}", e);
            },
            _ => {}
        }
    }
}

fn write_with_body(mut res: HttpResponse<Fresh>, mut body: Box<Reader + Send>) -> IoResult<()> {
    let content_type = res.headers().get::<headers::ContentType>()
                           .map(|cx| cx.clone())
                           .unwrap_or_else(|| headers::ContentType("text/plain".parse().unwrap()));
    res.headers_mut().set(content_type);

    let mut res = try!(res.start());

    // FIXME: Manually inlined io::util::copy
    // because Box<Reader + Send> does not impl Reader.
    //
    // Tracking issue: rust-lang/rust#18542
    let mut buf = &mut [0; 1024 * 64];
    loop {
        let len = match body.read(buf) {
            Ok(len) => len,
            Err(ref e) if e.kind == io::EndOfFile => break,
            Err(e) => { return Err(e) },
        };

        try!(res.write(buf[..len]))
    }

    res.end()
}

impl Show for Response {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "HTTP/1.1 {} {}\n{}",
            self.status.unwrap_or(status::NotFound),
            self.status.unwrap_or(status::NotFound).canonical_reason().unwrap(),
            self.headers
        )
    }
}

// Allow plugins to attach to responses.
impl Extensible for Response {
    fn extensions(&self) -> &TypeMap {
        &self.extensions
    }

    fn extensions_mut(&mut self) -> &mut TypeMap {
        &mut self.extensions
    }
}

impl Set for Response {}
<|endoftext|>