<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.

// TODO we're going to allocate a whole bunch of temp Strings, is it worth
// keeping some scratch mem for this and running our own StrPool?
// TODO for lint violations of names, emit a refactor script

#[macro_use]
extern crate log;

extern crate syntex_syntax as syntax;
extern crate rustc_serialize;

extern crate strings;

extern crate unicode_segmentation;
extern crate regex;
extern crate diff;
extern crate term;

use syntax::ast;
use syntax::codemap::{mk_sp, CodeMap, Span};
use syntax::errors::Handler;
use syntax::errors::emitter::{ColorConfig, EmitterWriter};
use syntax::parse::{self, ParseSess};

use std::io::stdout;
use std::ops::{Add, Sub};
use std::path::{Path, PathBuf};
use std::rc::Rc;
use std::collections::HashMap;
use std::fmt;

use issues::{BadIssueSeeker, Issue};
use filemap::FileMap;
use visitor::FmtVisitor;
use config::{Config, WriteMode};

#[macro_use]
mod utils;
pub mod config;
pub mod filemap;
mod visitor;
mod checkstyle;
mod items;
mod missed_spans;
mod lists;
mod types;
mod expr;
mod imports;
mod issues;
mod rewrite;
mod string;
mod comment;
mod modules;
pub mod rustfmt_diff;
mod chains;
mod macros;
mod patterns;

const MIN_STRING: usize = 10;
// When we get scoped annotations, we should have rustfmt::skip.
const SKIP_ANNOTATION: &'static str = "rustfmt_skip";

pub trait Spanned {
    fn span(&self) -> Span;
}

impl Spanned for ast::Expr {
    fn span(&self) -> Span {
        self.span
    }
}

impl Spanned for ast::Pat {
    fn span(&self) -> Span {
        self.span
    }
}

impl Spanned for ast::Ty {
    fn span(&self) -> Span {
        self.span
    }
}

impl Spanned for ast::Arg {
    fn span(&self) -> Span {
        if items::is_named_arg(self) {
            mk_sp(self.pat.span.lo, self.ty.span.hi)
        } else {
            self.ty.span
        }
    }
}

#[derive(Copy, Clone, Debug)]
pub struct Indent {
    // Width of the block indent, in characters. Must be a multiple of
    // Config::tab_spaces.
    pub block_indent: usize,
    // Alignment in characters.
    pub alignment: usize,
}

impl Indent {
    pub fn new(block_indent: usize, alignment: usize) -> Indent {
        Indent {
            block_indent: block_indent,
            alignment: alignment,
        }
    }

    pub fn empty() -> Indent {
        Indent::new(0, 0)
    }

    pub fn block_indent(mut self, config: &Config) -> Indent {
        self.block_indent += config.tab_spaces;
        self
    }

    pub fn block_unindent(mut self, config: &Config) -> Indent {
        self.block_indent -= config.tab_spaces;
        self
    }

    pub fn width(&self) -> usize {
        self.block_indent + self.alignment
    }

    pub fn to_string(&self, config: &Config) -> String {
        let (num_tabs, num_spaces) = if config.hard_tabs {
            (self.block_indent / config.tab_spaces, self.alignment)
        } else {
            (0, self.block_indent + self.alignment)
        };
        let num_chars = num_tabs + num_spaces;
        let mut indent = String::with_capacity(num_chars);
        for _ in 0..num_tabs {
            indent.push('\t')
        }
        for _ in 0..num_spaces {
            indent.push(' ')
        }
        indent
    }
}

impl Add for Indent {
    type Output = Indent;

    fn add(self, rhs: Indent) -> Indent {
        Indent {
            block_indent: self.block_indent + rhs.block_indent,
            alignment: self.alignment + rhs.alignment,
        }
    }
}

impl Sub for Indent {
    type Output = Indent;

    fn sub(self, rhs: Indent) -> Indent {
        Indent::new(self.block_indent - rhs.block_indent,
                    self.alignment - rhs.alignment)
    }
}

impl Add<usize> for Indent {
    type Output = Indent;

    fn add(self, rhs: usize) -> Indent {
        Indent::new(self.block_indent, self.alignment + rhs)
    }
}

impl Sub<usize> for Indent {
    type Output = Indent;

    fn sub(self, rhs: usize) -> Indent {
        Indent::new(self.block_indent, self.alignment - rhs)
    }
}

pub enum ErrorKind {
    // Line has exceeded character limit
    LineOverflow,
    // Line ends in whitespace
    TrailingWhitespace,
    // TO-DO or FIX-ME item without an issue number
    BadIssue(Issue),
}

impl fmt::Display for ErrorKind {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            ErrorKind::LineOverflow => write!(fmt, "line exceeded maximum length"),
            ErrorKind::TrailingWhitespace => write!(fmt, "left behind trailing whitespace"),
            ErrorKind::BadIssue(issue) => write!(fmt, "found {}", issue),
        }
    }
}

// Formatting errors that are identified *after* rustfmt has run.
pub struct FormattingError {
    line: u32,
    kind: ErrorKind,
}

impl FormattingError {
    fn msg_prefix(&self) -> &str {
        match self.kind {
            ErrorKind::LineOverflow |
            ErrorKind::TrailingWhitespace => "Rustfmt failed at",
            ErrorKind::BadIssue(_) => "WARNING:",
        }
    }

    fn msg_suffix(&self) -> &str {
        match self.kind {
            ErrorKind::LineOverflow |
            ErrorKind::TrailingWhitespace => "(sorry)",
            ErrorKind::BadIssue(_) => "",
        }
    }
}

pub struct FormatReport {
    // Maps stringified file paths to their associated formatting errors.
    file_error_map: HashMap<String, Vec<FormattingError>>,
}

impl FormatReport {
    pub fn warning_count(&self) -> usize {
        self.file_error_map.iter().map(|(_, ref errors)| errors.len()).fold(0, |acc, x| acc + x)
    }
}

impl fmt::Display for FormatReport {
    // Prints all the formatting errors.
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        for (file, errors) in &self.file_error_map {
            for error in errors {
                try!(write!(fmt,
                            "{} {}:{}: {} {}\n",
                            error.msg_prefix(),
                            file,
                            error.line,
                            error.kind,
                            error.msg_suffix()));
            }
        }
        Ok(())
    }
}

// Formatting which depends on the AST.
fn fmt_ast(krate: &ast::Crate,
           parse_session: &ParseSess,
           main_file: &Path,
           config: &Config)
           -> FileMap {
    let mut file_map = FileMap::new();
    for (path, module) in modules::list_files(krate, parse_session.codemap()) {
        if config.skip_children && path.as_path() != main_file {
            continue;
        }
        let path = path.to_str().unwrap();
        if config.verbose {
            println!("Formatting {}", path);
        }
        let mut visitor = FmtVisitor::from_codemap(parse_session, config);
        visitor.format_separate_mod(module);
        file_map.insert(path.to_owned(), visitor.buffer);
    }
    file_map
}

// Formatting done on a char by char or line by line basis.
// TODO(#209) warn on bad license
// TODO(#20) other stuff for parity with make tidy
pub fn fmt_lines(file_map: &mut FileMap, config: &Config) -> FormatReport {
    let mut truncate_todo = Vec::new();
    let mut report = FormatReport { file_error_map: HashMap::new() };

    // Iterate over the chars in the file map.
    for (f, text) in file_map.iter() {
        let mut trims = vec![];
        let mut last_wspace: Option<usize> = None;
        let mut line_len = 0;
        let mut cur_line = 1;
        let mut newline_count = 0;
        let mut errors = vec![];
        let mut issue_seeker = BadIssueSeeker::new(config.report_todo, config.report_fixme);

        for (c, b) in text.chars() {
            if c == '\r' {
                line_len += c.len_utf8();
                continue;
            }

            // Add warnings for bad todos/ fixmes
            if let Some(issue) = issue_seeker.inspect(c) {
                errors.push(FormattingError {
                    line: cur_line,
                    kind: ErrorKind::BadIssue(issue),
                });
            }

            if c == '\n' {
                // Check for (and record) trailing whitespace.
                if let Some(lw) = last_wspace {
                    trims.push((cur_line, lw, b));
                    line_len -= b - lw;
                }
                // Check for any line width errors we couldn't correct.
                if line_len > config.max_width {
                    errors.push(FormattingError {
                        line: cur_line,
                        kind: ErrorKind::LineOverflow,
                    });
                }
                line_len = 0;
                cur_line += 1;
                newline_count += 1;
                last_wspace = None;
            } else {
                newline_count = 0;
                line_len += c.len_utf8();
                if c.is_whitespace() {
                    if last_wspace.is_none() {
                        last_wspace = Some(b);
                    }
                } else {
                    last_wspace = None;
                }
            }
        }

        if newline_count > 1 {
            debug!("track truncate: {} {} {}", f, text.len, newline_count);
            truncate_todo.push((f.to_owned(), text.len - newline_count + 1))
        }

        for &(l, _, _) in &trims {
            errors.push(FormattingError {
                line: l,
                kind: ErrorKind::TrailingWhitespace,
            });
        }

        report.file_error_map.insert(f.to_owned(), errors);
    }

    for (f, l) in truncate_todo {
        file_map.get_mut(&f).unwrap().truncate(l);
    }

    report
}

pub fn format_string(input: String, config: &Config) -> FileMap {
    let path = "stdin";
    let codemap = Rc::new(CodeMap::new());

    let tty_handler = Handler::with_tty_emitter(ColorConfig::Auto,
                                                None,
                                                true,
                                                false,
                                                codemap.clone());
    let mut parse_session = ParseSess::with_span_handler(tty_handler, codemap.clone());

    let krate = parse::parse_crate_from_source_str(path.to_owned(),
                                                   input,
                                                   Vec::new(),
                                                   &parse_session)
                    .unwrap();

    // Suppress error output after parsing.
    let silent_emitter = Box::new(EmitterWriter::new(Box::new(Vec::new()), None, codemap.clone()));
    parse_session.span_diagnostic = Handler::with_emitter(true, false, silent_emitter);

    // FIXME: we still use a FileMap even though we only have
    // one file, because fmt_lines requires a FileMap
    let mut file_map = FileMap::new();

    // do the actual formatting
    let mut visitor = FmtVisitor::from_codemap(&parse_session, config);
    visitor.format_separate_mod(&krate.module);

    // append final newline
    visitor.buffer.push_str("\n");
    file_map.insert(path.to_owned(), visitor.buffer);

    file_map
}

fn format(file: &Path, config: &Config) -> FileMap {
    let codemap = Rc::new(CodeMap::new());

    let tty_handler = Handler::with_tty_emitter(ColorConfig::Auto,
                                                None,
                                                true,
                                                false,
                                                codemap.clone());
    let mut parse_session = ParseSess::with_span_handler(tty_handler, codemap.clone());

    let krate = parse::parse_crate_from_file(file, Vec::new(), &parse_session).unwrap();

    // Suppress error output after parsing.
    let silent_emitter = Box::new(EmitterWriter::new(Box::new(Vec::new()), None, codemap.clone()));
    parse_session.span_diagnostic = Handler::with_emitter(true, false, silent_emitter);

    let mut file_map = fmt_ast(&krate, &parse_session, file, config);

    // For some reason, the codemap does not include terminating
    // newlines so we must add one on for each file. This is sad.
    filemap::append_newlines(&mut file_map);

    file_map
}

pub fn format_input(input: Input, config: &Config) -> (FileMap, FormatReport) {
    let mut file_map = match input {
        Input::File(ref file) => format(file, config),
        Input::Text(text) => format_string(text, config),
    };

    let report = fmt_lines(&mut file_map, config);
    (file_map, report)
}

pub enum Input {
    File(PathBuf),
    Text(String),
}

pub fn run(input: Input, config: &Config) {
    let (file_map, report) = format_input(input, config);

    let ignore_errors = config.write_mode == WriteMode::Plain;
    if !ignore_errors {
        print!("{}", report);
    }

    let mut out = stdout();
    let write_result = filemap::write_all_files(&file_map, &mut out, config);

    if let Err(msg) = write_result {
        if !ignore_errors {
            println!("Error writing files: {}", msg);
        }
    }
}
<commit_msg>make format_string and fmt_lines private<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.

// TODO we're going to allocate a whole bunch of temp Strings, is it worth
// keeping some scratch mem for this and running our own StrPool?
// TODO for lint violations of names, emit a refactor script

#[macro_use]
extern crate log;

extern crate syntex_syntax as syntax;
extern crate rustc_serialize;

extern crate strings;

extern crate unicode_segmentation;
extern crate regex;
extern crate diff;
extern crate term;

use syntax::ast;
use syntax::codemap::{mk_sp, CodeMap, Span};
use syntax::errors::Handler;
use syntax::errors::emitter::{ColorConfig, EmitterWriter};
use syntax::parse::{self, ParseSess};

use std::io::stdout;
use std::ops::{Add, Sub};
use std::path::{Path, PathBuf};
use std::rc::Rc;
use std::collections::HashMap;
use std::fmt;

use issues::{BadIssueSeeker, Issue};
use filemap::FileMap;
use visitor::FmtVisitor;
use config::{Config, WriteMode};

#[macro_use]
mod utils;
pub mod config;
pub mod filemap;
mod visitor;
mod checkstyle;
mod items;
mod missed_spans;
mod lists;
mod types;
mod expr;
mod imports;
mod issues;
mod rewrite;
mod string;
mod comment;
mod modules;
pub mod rustfmt_diff;
mod chains;
mod macros;
mod patterns;

const MIN_STRING: usize = 10;
// When we get scoped annotations, we should have rustfmt::skip.
const SKIP_ANNOTATION: &'static str = "rustfmt_skip";

pub trait Spanned {
    fn span(&self) -> Span;
}

impl Spanned for ast::Expr {
    fn span(&self) -> Span {
        self.span
    }
}

impl Spanned for ast::Pat {
    fn span(&self) -> Span {
        self.span
    }
}

impl Spanned for ast::Ty {
    fn span(&self) -> Span {
        self.span
    }
}

impl Spanned for ast::Arg {
    fn span(&self) -> Span {
        if items::is_named_arg(self) {
            mk_sp(self.pat.span.lo, self.ty.span.hi)
        } else {
            self.ty.span
        }
    }
}

#[derive(Copy, Clone, Debug)]
pub struct Indent {
    // Width of the block indent, in characters. Must be a multiple of
    // Config::tab_spaces.
    pub block_indent: usize,
    // Alignment in characters.
    pub alignment: usize,
}

impl Indent {
    pub fn new(block_indent: usize, alignment: usize) -> Indent {
        Indent {
            block_indent: block_indent,
            alignment: alignment,
        }
    }

    pub fn empty() -> Indent {
        Indent::new(0, 0)
    }

    pub fn block_indent(mut self, config: &Config) -> Indent {
        self.block_indent += config.tab_spaces;
        self
    }

    pub fn block_unindent(mut self, config: &Config) -> Indent {
        self.block_indent -= config.tab_spaces;
        self
    }

    pub fn width(&self) -> usize {
        self.block_indent + self.alignment
    }

    pub fn to_string(&self, config: &Config) -> String {
        let (num_tabs, num_spaces) = if config.hard_tabs {
            (self.block_indent / config.tab_spaces, self.alignment)
        } else {
            (0, self.block_indent + self.alignment)
        };
        let num_chars = num_tabs + num_spaces;
        let mut indent = String::with_capacity(num_chars);
        for _ in 0..num_tabs {
            indent.push('\t')
        }
        for _ in 0..num_spaces {
            indent.push(' ')
        }
        indent
    }
}

impl Add for Indent {
    type Output = Indent;

    fn add(self, rhs: Indent) -> Indent {
        Indent {
            block_indent: self.block_indent + rhs.block_indent,
            alignment: self.alignment + rhs.alignment,
        }
    }
}

impl Sub for Indent {
    type Output = Indent;

    fn sub(self, rhs: Indent) -> Indent {
        Indent::new(self.block_indent - rhs.block_indent,
                    self.alignment - rhs.alignment)
    }
}

impl Add<usize> for Indent {
    type Output = Indent;

    fn add(self, rhs: usize) -> Indent {
        Indent::new(self.block_indent, self.alignment + rhs)
    }
}

impl Sub<usize> for Indent {
    type Output = Indent;

    fn sub(self, rhs: usize) -> Indent {
        Indent::new(self.block_indent, self.alignment - rhs)
    }
}

pub enum ErrorKind {
    // Line has exceeded character limit
    LineOverflow,
    // Line ends in whitespace
    TrailingWhitespace,
    // TO-DO or FIX-ME item without an issue number
    BadIssue(Issue),
}

impl fmt::Display for ErrorKind {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            ErrorKind::LineOverflow => write!(fmt, "line exceeded maximum length"),
            ErrorKind::TrailingWhitespace => write!(fmt, "left behind trailing whitespace"),
            ErrorKind::BadIssue(issue) => write!(fmt, "found {}", issue),
        }
    }
}

// Formatting errors that are identified *after* rustfmt has run.
pub struct FormattingError {
    line: u32,
    kind: ErrorKind,
}

impl FormattingError {
    fn msg_prefix(&self) -> &str {
        match self.kind {
            ErrorKind::LineOverflow |
            ErrorKind::TrailingWhitespace => "Rustfmt failed at",
            ErrorKind::BadIssue(_) => "WARNING:",
        }
    }

    fn msg_suffix(&self) -> &str {
        match self.kind {
            ErrorKind::LineOverflow |
            ErrorKind::TrailingWhitespace => "(sorry)",
            ErrorKind::BadIssue(_) => "",
        }
    }
}

pub struct FormatReport {
    // Maps stringified file paths to their associated formatting errors.
    file_error_map: HashMap<String, Vec<FormattingError>>,
}

impl FormatReport {
    pub fn warning_count(&self) -> usize {
        self.file_error_map.iter().map(|(_, ref errors)| errors.len()).fold(0, |acc, x| acc + x)
    }
}

impl fmt::Display for FormatReport {
    // Prints all the formatting errors.
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        for (file, errors) in &self.file_error_map {
            for error in errors {
                try!(write!(fmt,
                            "{} {}:{}: {} {}\n",
                            error.msg_prefix(),
                            file,
                            error.line,
                            error.kind,
                            error.msg_suffix()));
            }
        }
        Ok(())
    }
}

// Formatting which depends on the AST.
fn fmt_ast(krate: &ast::Crate,
           parse_session: &ParseSess,
           main_file: &Path,
           config: &Config)
           -> FileMap {
    let mut file_map = FileMap::new();
    for (path, module) in modules::list_files(krate, parse_session.codemap()) {
        if config.skip_children && path.as_path() != main_file {
            continue;
        }
        let path = path.to_str().unwrap();
        if config.verbose {
            println!("Formatting {}", path);
        }
        let mut visitor = FmtVisitor::from_codemap(parse_session, config);
        visitor.format_separate_mod(module);
        file_map.insert(path.to_owned(), visitor.buffer);
    }
    file_map
}

// Formatting done on a char by char or line by line basis.
// TODO(#209) warn on bad license
// TODO(#20) other stuff for parity with make tidy
fn fmt_lines(file_map: &mut FileMap, config: &Config) -> FormatReport {
    let mut truncate_todo = Vec::new();
    let mut report = FormatReport { file_error_map: HashMap::new() };

    // Iterate over the chars in the file map.
    for (f, text) in file_map.iter() {
        let mut trims = vec![];
        let mut last_wspace: Option<usize> = None;
        let mut line_len = 0;
        let mut cur_line = 1;
        let mut newline_count = 0;
        let mut errors = vec![];
        let mut issue_seeker = BadIssueSeeker::new(config.report_todo, config.report_fixme);

        for (c, b) in text.chars() {
            if c == '\r' {
                line_len += c.len_utf8();
                continue;
            }

            // Add warnings for bad todos/ fixmes
            if let Some(issue) = issue_seeker.inspect(c) {
                errors.push(FormattingError {
                    line: cur_line,
                    kind: ErrorKind::BadIssue(issue),
                });
            }

            if c == '\n' {
                // Check for (and record) trailing whitespace.
                if let Some(lw) = last_wspace {
                    trims.push((cur_line, lw, b));
                    line_len -= b - lw;
                }
                // Check for any line width errors we couldn't correct.
                if line_len > config.max_width {
                    errors.push(FormattingError {
                        line: cur_line,
                        kind: ErrorKind::LineOverflow,
                    });
                }
                line_len = 0;
                cur_line += 1;
                newline_count += 1;
                last_wspace = None;
            } else {
                newline_count = 0;
                line_len += c.len_utf8();
                if c.is_whitespace() {
                    if last_wspace.is_none() {
                        last_wspace = Some(b);
                    }
                } else {
                    last_wspace = None;
                }
            }
        }

        if newline_count > 1 {
            debug!("track truncate: {} {} {}", f, text.len, newline_count);
            truncate_todo.push((f.to_owned(), text.len - newline_count + 1))
        }

        for &(l, _, _) in &trims {
            errors.push(FormattingError {
                line: l,
                kind: ErrorKind::TrailingWhitespace,
            });
        }

        report.file_error_map.insert(f.to_owned(), errors);
    }

    for (f, l) in truncate_todo {
        file_map.get_mut(&f).unwrap().truncate(l);
    }

    report
}

fn format_string(input: String, config: &Config) -> FileMap {
    let path = "stdin";
    let codemap = Rc::new(CodeMap::new());

    let tty_handler = Handler::with_tty_emitter(ColorConfig::Auto,
                                                None,
                                                true,
                                                false,
                                                codemap.clone());
    let mut parse_session = ParseSess::with_span_handler(tty_handler, codemap.clone());

    let krate = parse::parse_crate_from_source_str(path.to_owned(),
                                                   input,
                                                   Vec::new(),
                                                   &parse_session)
                    .unwrap();

    // Suppress error output after parsing.
    let silent_emitter = Box::new(EmitterWriter::new(Box::new(Vec::new()), None, codemap.clone()));
    parse_session.span_diagnostic = Handler::with_emitter(true, false, silent_emitter);

    // FIXME: we still use a FileMap even though we only have
    // one file, because fmt_lines requires a FileMap
    let mut file_map = FileMap::new();

    // do the actual formatting
    let mut visitor = FmtVisitor::from_codemap(&parse_session, config);
    visitor.format_separate_mod(&krate.module);

    // append final newline
    visitor.buffer.push_str("\n");
    file_map.insert(path.to_owned(), visitor.buffer);

    file_map
}

fn format(file: &Path, config: &Config) -> FileMap {
    let codemap = Rc::new(CodeMap::new());

    let tty_handler = Handler::with_tty_emitter(ColorConfig::Auto,
                                                None,
                                                true,
                                                false,
                                                codemap.clone());
    let mut parse_session = ParseSess::with_span_handler(tty_handler, codemap.clone());

    let krate = parse::parse_crate_from_file(file, Vec::new(), &parse_session).unwrap();

    // Suppress error output after parsing.
    let silent_emitter = Box::new(EmitterWriter::new(Box::new(Vec::new()), None, codemap.clone()));
    parse_session.span_diagnostic = Handler::with_emitter(true, false, silent_emitter);

    let mut file_map = fmt_ast(&krate, &parse_session, file, config);

    // For some reason, the codemap does not include terminating
    // newlines so we must add one on for each file. This is sad.
    filemap::append_newlines(&mut file_map);

    file_map
}

pub fn format_input(input: Input, config: &Config) -> (FileMap, FormatReport) {
    let mut file_map = match input {
        Input::File(ref file) => format(file, config),
        Input::Text(text) => format_string(text, config),
    };

    let report = fmt_lines(&mut file_map, config);
    (file_map, report)
}

pub enum Input {
    File(PathBuf),
    Text(String),
}

pub fn run(input: Input, config: &Config) {
    let (file_map, report) = format_input(input, config);

    let ignore_errors = config.write_mode == WriteMode::Plain;
    if !ignore_errors {
        print!("{}", report);
    }

    let mut out = stdout();
    let write_result = filemap::write_all_files(&file_map, &mut out, config);

    if let Err(msg) = write_result {
        if !ignore_errors {
            println!("Error writing files: {}", msg);
        }
    }
}
<|endoftext|>


<commit_before>extern crate num;

use num::{Complex, Zero};
use std::iter::{repeat, range_step_inclusive, range_step};
use std::f32;
use stride::{Stride, StrideMut};

mod stride;

pub struct FFT {
    scratch: Vec<Complex<f32>>,
    factors: Vec<usize>,
}

impl FFT {
    pub fn new(len: usize) -> Self {
        FFT {
            scratch: repeat(Zero::zero()).take(len).collect(),
            factors: factor(len),
        }
    }

    pub fn process(&mut self, signal: &[Complex<f32>], spectrum: &mut [Complex<f32>]) {
        cooley_tukey(Stride::from_slice(signal),
                     StrideMut::from_slice(spectrum),
                     StrideMut::from_slice(self.scratch.as_mut_slice()),
                     self.factors.as_slice());
    }
}

fn cooley_tukey<'a>(signal: Stride<'a, Complex<f32>>,
                    spectrum: StrideMut<'a, Complex<f32>>,
                    scratch: StrideMut<'a, Complex<f32>>,
                    factors: &[usize]) {
    match factors {
        [_] | [] => dft(signal, spectrum),
        [n1, other_factors..] => {
            let n2 = signal.len() / n1;
            for i in range(0, n1)
            {
                cooley_tukey(signal.skip_some(i).stride(n1),
                             scratch.skip_some(i).stride(n1),
                             spectrum.skip_some(i).stride(n1),
                             other_factors);
            }

            multiply_by_twiddles(scratch.clone(), n1, n2);

            for (i, offset) in range_step(0us, scratch.len(), n1).enumerate() {
                let row = scratch.skip_some(offset).take_some(n1);
                dft_mut(row, spectrum.skip_some(i).stride(n2));
            }
        }
    }
}

fn multiply_by_twiddles<'a, I>(xs: I, n1: usize, n2: usize) where I: Iterator<Item=&'a mut Complex<f32>>
{
    for (i, elt) in xs.enumerate() {
        let k2 = i / n1;
        let k1 = i % n1;
        let angle: f32 = (-1is as f32) * ((k2 * k1) as f32) * f32::consts::PI_2 / ((n1 * n2) as f32);
        let twiddle: Complex<f32> = Complex::from_polar(&1f32, &angle);
        *elt = *elt * twiddle;
    }
}

//TODO this suffers from accumulation of error in calcualtion of `angle`
pub fn dft<'a, 'b, I, O>(signal: I, spectrum: O)
where I: Iterator<Item=&'a Complex<f32>> + ExactSizeIterator + Clone,
      O: Iterator<Item=&'b mut Complex<f32>>
{
    for (k, spec_bin) in spectrum.enumerate()
    {
        let mut signal_iter = signal.clone();
        let mut sum: Complex<f32> = Zero::zero();
        let mut angle = 0f32;
        let rad_per_sample = (k as f32) * f32::consts::PI_2 / (signal.len() as f32);
        for &x in signal_iter
        {
            let twiddle: Complex<f32> = Complex::from_polar(&1f32, &angle);
            sum = sum + twiddle * x;
            angle = angle - rad_per_sample;
        }
        *spec_bin = sum;
    }
}

//TODO this suffers from accumulation of error in calcualtion of `angle`
//TODO how can we avoid this duplication?
pub fn dft_mut<'a, 'b, I, O>(signal: I, spectrum: O)
where I: Iterator<Item=&'a mut Complex<f32>> + ExactSizeIterator + Clone,
      O: Iterator<Item=&'b mut Complex<f32>>
{
    for (k, spec_bin) in spectrum.enumerate()
    {
        let mut signal_iter = signal.clone();
        let mut sum: Complex<f32> = Zero::zero();
        let mut angle = 0f32;
        let rad_per_sample = (k as f32) * f32::consts::PI_2 / (signal.len() as f32);
        for &mut x in signal_iter
        {
            let twiddle: Complex<f32> = Complex::from_polar(&1f32, &angle);
            sum = sum + twiddle * x;
            angle = angle - rad_per_sample;
        }
        *spec_bin = sum;
    }
}

fn factor(n: usize) -> Vec<usize>
{
    let mut factors: Vec<usize> = Vec::new();
    let mut next = n;
    while next > 1
    {
        for div in Some(2us).into_iter().chain(range_step_inclusive(3us, next, 2))
        {
            if next % div == 0
            {
                next = next / div;
                factors.push(div);
                break;
            }
        }
    }
    return factors;
}
<commit_msg>Fixed error accumulation in DFT. Fixes #4<commit_after>extern crate num;

use num::{Complex, Zero};
use std::iter::{repeat, range_step_inclusive, range_step};
use std::f32;
use stride::{Stride, StrideMut};

mod stride;

pub struct FFT {
    scratch: Vec<Complex<f32>>,
    factors: Vec<usize>,
}

impl FFT {
    pub fn new(len: usize) -> Self {
        FFT {
            scratch: repeat(Zero::zero()).take(len).collect(),
            factors: factor(len),
        }
    }

    pub fn process(&mut self, signal: &[Complex<f32>], spectrum: &mut [Complex<f32>]) {
        cooley_tukey(Stride::from_slice(signal),
                     StrideMut::from_slice(spectrum),
                     StrideMut::from_slice(self.scratch.as_mut_slice()),
                     self.factors.as_slice());
    }
}

fn cooley_tukey<'a>(signal: Stride<'a, Complex<f32>>,
                    spectrum: StrideMut<'a, Complex<f32>>,
                    scratch: StrideMut<'a, Complex<f32>>,
                    factors: &[usize]) {
    match factors {
        [_] | [] => dft(signal, spectrum),
        [n1, other_factors..] => {
            let n2 = signal.len() / n1;
            for i in range(0, n1)
            {
                cooley_tukey(signal.skip_some(i).stride(n1),
                             scratch.skip_some(i).stride(n1),
                             spectrum.skip_some(i).stride(n1),
                             other_factors);
            }

            multiply_by_twiddles(scratch.clone(), n1, n2);

            for (i, offset) in range_step(0us, scratch.len(), n1).enumerate() {
                let row = scratch.skip_some(offset).take_some(n1);
                dft_mut(row, spectrum.skip_some(i).stride(n2));
            }
        }
    }
}

fn multiply_by_twiddles<'a, I>(xs: I, n1: usize, n2: usize) where I: Iterator<Item=&'a mut Complex<f32>>
{
    for (i, elt) in xs.enumerate() {
        let k2 = i / n1;
        let k1 = i % n1;
        let angle: f32 = (-1is as f32) * ((k2 * k1) as f32) * f32::consts::PI_2 / ((n1 * n2) as f32);
        let twiddle: Complex<f32> = Complex::from_polar(&1f32, &angle);
        *elt = *elt * twiddle;
    }
}

//TODO this suffers from accumulation of error in calcualtion of `angle`
pub fn dft<'a, 'b, I, O>(signal: I, spectrum: O)
where I: Iterator<Item=&'a Complex<f32>> + ExactSizeIterator + Clone,
      O: Iterator<Item=&'b mut Complex<f32>>
{
    for (k, spec_bin) in spectrum.enumerate()
    {
        let mut signal_iter = signal.clone();
        let mut sum: Complex<f32> = Zero::zero();
        for (i, &x) in signal_iter.enumerate() {
            let angle = -1. * ((i * k) as f32) * f32::consts::PI_2 / (signal.len() as f32);
            let twiddle: Complex<f32> = Complex::from_polar(&1f32, &angle);
            sum = sum + twiddle * x;
        }
        *spec_bin = sum;
    }
}

//TODO this suffers from accumulation of error in calcualtion of `angle`
//TODO how can we avoid this duplication?
pub fn dft_mut<'a, 'b, I, O>(signal: I, spectrum: O)
where I: Iterator<Item=&'a mut Complex<f32>> + ExactSizeIterator + Clone,
      O: Iterator<Item=&'b mut Complex<f32>>
{
    for (k, spec_bin) in spectrum.enumerate()
    {
        let mut signal_iter = signal.clone();
        let mut sum: Complex<f32> = Zero::zero();
        for (i, &mut x) in signal_iter.enumerate() {
            let angle = -1. * ((i * k) as f32) * f32::consts::PI_2 / (signal.len() as f32);
            let twiddle: Complex<f32> = Complex::from_polar(&1f32, &angle);
            sum = sum + twiddle * x;
        }
        *spec_bin = sum;
    }
}

fn factor(n: usize) -> Vec<usize>
{
    let mut factors: Vec<usize> = Vec::new();
    let mut next = n;
    while next > 1
    {
        for div in Some(2us).into_iter().chain(range_step_inclusive(3us, next, 2))
        {
            if next % div == 0
            {
                next = next / div;
                factors.push(div);
                break;
            }
        }
    }
    return factors;
}
<|endoftext|>


<commit_before>#![deny(warnings)]
#![feature(globs, phase, tuple_indexing)]

extern crate libc;
#[cfg(test)]
extern crate quickcheck;
#[cfg(test)]
#[phase(plugin)]
extern crate quickcheck_macros;

use std::io::{File, FileAccess, FileMode, IoError, IoResult};
use std::os::unix::AsRawFd;

use termios::{FAILURE, Termios, SUCCESS};

mod termios;
#[cfg(test)]
mod socat;
#[cfg(test)]
mod test;

#[deriving(Copy, PartialEq)]
pub struct BlockingMode {
    /// The device will block until `bytes` are received
    pub bytes: u8,
    /// The device will block for at least `deciseconds` after each `read()` call
    pub deciseconds: u8,
}

pub struct SerialPort {
    fd: libc::c_int,
    file: File,
    termios: Termios,
}

impl SerialPort {
    /// Opens a serial `device` in "raw" mode
    pub fn open(device: &Path, access: FileAccess) -> IoResult<SerialPort> {
        let file = try!(File::open_mode(device, FileMode::Open, access));
        let fd = file.as_raw_fd();

        let mut termios = Termios::new();

        match unsafe { termios::tcgetattr(fd, &mut termios) } {
            FAILURE => return Err(IoError::last_error()),
            SUCCESS => {},
            _ => unreachable!(),
        }

        unsafe { termios::cfmakeraw(&mut termios) };

        let sp = SerialPort { fd: fd, file: file, termios: termios };

        try!(sp.update());

        Ok(sp)
    }

    /// Returns the input and output baud rates
    #[cfg(target_os = "linux")]
    pub fn baud_rate(&self) -> IoResult<(BaudRate, BaudRate)> {
        let termios = try!(self.fetch());

        let input = termios.c_ispeed;
        let input = match FromPrimitive::from_u32(input) {
            None => panic!("unrecognized BaudRate value: {}", input),
            Some(input) => input,
        };

        let output = termios.c_ospeed;
        let output = match FromPrimitive::from_u32(output) {
            None => panic!("unrecognized BaudRate value: {}", output),
            Some(output) => output,
        };

        Ok((input, output))
    }

    /// Returns the input and output baud rates
    #[cfg(target_os = "macos")]
    pub fn baud_rate(&self) -> IoResult<(BaudRate, BaudRate)> {
        let termios = try!(self.fetch());

        let input = termios.c_ispeed;
        let input = match FromPrimitive::from_u64(input) {
            None => panic!("unrecognized BaudRate value: {}", input),
            Some(input) => input,
        };

        let output = termios.c_ospeed;
        let output = match FromPrimitive::from_u64(output) {
            None => panic!("unrecognized BaudRate value: {}", output),
            Some(output) => output,
        };

        Ok((input, output))
    }

    /// Returns the blocking mode used by the device
    pub fn blocking_mode(&self) -> IoResult<BlockingMode> {
        use termios::{VMIN, VTIME};

        Ok(BlockingMode {
            bytes: self.termios.c_cc[VMIN as uint],
            deciseconds: self.termios.c_cc[VTIME as uint],
        })
    }

    /// Returns the number of data bits used per character
    #[cfg(target_os = "linux")]
    pub fn data_bits(&self) -> IoResult<DataBits> {
        use termios::CSIZE;

        let bits = try!(self.fetch()).c_cflag & CSIZE;

        match FromPrimitive::from_u32(bits) {
            None => panic!("unrecognized DataBits value: {}", bits),
            Some(bits) => Ok(bits),
        }
    }

    /// Returns the number of data bits used per character
    #[cfg(target_os = "macos")]
    pub fn data_bits(&self) -> IoResult<DataBits> {
        use termios::CSIZE;

        let bits = try!(self.fetch()).c_cflag & CSIZE;

        match FromPrimitive::from_u64(bits) {
            None => panic!("unrecognized DataBits value: {}", bits),
            Some(bits) => Ok(bits),
        }
    }

    /// Returns the flow control used by the device
    pub fn flow_control(&self) -> IoResult<FlowControl> {
        use FlowControl::*;
        use termios::{CRTSCTS, IXANY, IXOFF, IXON};

        let termios = try!(self.fetch());

        if termios.c_cflag & CRTSCTS != 0 {
            Ok(Hardware)
        } else if termios.c_iflag & (IXANY | IXOFF | IXON) == 0 {
            Ok(None)
        } else {
            Ok(Software)
        }
    }

    /// Returns the bit parity used by the device
    pub fn parity(&self) -> IoResult<Parity> {
        use Parity::*;
        use termios::{PARENB, PARODD};

        let termios = try!(self.fetch());

        match (termios.c_cflag & PARENB != 0, termios.c_cflag & PARODD != 0) {
            (true, true) => Ok(Odd),
            (true, false) => Ok(Even),
            (false, _) => Ok(None),
        }
    }

    /// Changes the baud rate of the input/output or both directions
    pub fn set_baud_rate(&mut self, direction: Direction, rate: BaudRate) -> IoResult<()> {
        use Direction::*;
        use termios::speed_t;

        match unsafe { match direction {
            Both => termios::cfsetspeed(&mut self.termios, rate as speed_t),
            Input => termios::cfsetispeed(&mut self.termios, rate as speed_t),
            Output => termios::cfsetospeed(&mut self.termios, rate as speed_t),
        } } {
            FAILURE => Err(IoError::last_error()),
            SUCCESS => self.update(),
            _ => unreachable!(),
        }
    }

    /// Changes the blocking mode used by the device
    pub fn set_blocking_mode(&mut self, mode: BlockingMode) -> IoResult<()> {
        use termios::{VMIN, VTIME};

        self.termios.c_cc[VMIN as uint] = mode.bytes;
        self.termios.c_cc[VTIME as uint] = mode.deciseconds;

        self.update()
    }

    /// Changes the number of data bits per character
    #[cfg(target_os = "linux")]
    pub fn set_data_bits(&mut self, bits: DataBits) -> IoResult<()> {
        use termios::CSIZE;

        self.termios.c_cflag &= !CSIZE;
        self.termios.c_cflag |= bits as u32;

        self.update()
    }

    /// Changes the number of data bits per character
    #[cfg(target_os = "macos")]
    pub fn set_data_bits(&mut self, bits: DataBits) -> IoResult<()> {
        use termios::CSIZE;

        self.termios.c_cflag &= !CSIZE;
        self.termios.c_cflag |= bits as u64;

        self.update()
    }

    /// Changes the flow control used by the device
    pub fn set_flow_control(&mut self, flow: FlowControl) -> IoResult<()> {
        use FlowControl::*;
        use termios::{CRTSCTS, IXANY, IXOFF, IXON};

        match flow {
            Hardware=> {
                self.termios.c_cflag |= CRTSCTS;
                self.termios.c_iflag &= !(IXANY | IXOFF | IXON);
            },
            None => {
                self.termios.c_cflag &= !CRTSCTS;
                self.termios.c_iflag &= !(IXANY | IXOFF | IXON);
            },
            Software => {
                self.termios.c_cflag &= !CRTSCTS;
                self.termios.c_iflag |= IXANY | IXOFF | IXON;
            },
        }

        self.update()
    }

    /// Changes the bit parity used by the device
    pub fn set_parity(&mut self, parity: Parity) -> IoResult<()> {
        use Parity::*;
        use termios::{PARENB, PARODD};

        match parity {
            Even=> {
                self.termios.c_cflag |= PARENB;
                self.termios.c_cflag &= !PARODD;
            },
            None => self.termios.c_cflag &= !PARENB,
            Odd=> self.termios.c_cflag |= PARENB | PARODD,
        }

        self.update()
    }

    /// Changes the number of stop bits per character
    pub fn set_stop_bits(&mut self, bits: StopBits) -> IoResult<()> {
        use StopBits::*;
        use termios::CSTOPB;

        match bits {
            One => self.termios.c_cflag &= !CSTOPB,
            Two => self.termios.c_cflag |= CSTOPB,
        }

        self.update()
    }

    /// Returns the number of stop bits per character
    pub fn stop_bits(&self) -> IoResult<StopBits> {
        use StopBits::*;
        use termios::CSTOPB;

        if try!(self.fetch()).c_cflag & CSTOPB == 0 {
            Ok(One)
        } else {
            Ok(Two)
        }
    }

    /// Fetches the current state of the termios structure
    fn fetch(&self) -> IoResult<Termios> {
        let mut termios = Termios::new();

        match unsafe { termios::tcgetattr(self.fd, &mut termios) } {
            FAILURE => Err(IoError::last_error()),
            SUCCESS => Ok(termios),
            _ => unreachable!(),
        }
    }

    /// Updates the underlying termios structure
    fn update(&self) -> IoResult<()> {
        use termios::TCSANOW;

        match unsafe { termios::tcsetattr(self.fd, TCSANOW, &self.termios) } {
            FAILURE => Err(IoError::last_error()),
            SUCCESS => Ok(()),
            _ => unreachable!(),
        }
    }
}

impl Reader for SerialPort {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        self.file.read(buf)
    }
}

impl Writer for SerialPort {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        self.file.write(buf)
    }
}

#[cfg(target_os = "linux")]
#[deriving(Copy, FromPrimitive, PartialEq, Show)]
#[repr(u32)]
pub enum BaudRate {
    B0 = termios::B0,
    B50 = termios::B50,
    B75 = termios::B75,
    B110 = termios::B110,
    B134 = termios::B134,
    B150 = termios::B150,
    B200 = termios::B200,
    B300 = termios::B300,
    B600 = termios::B600,
    B1K2 = termios::B1200,
    B1K8 = termios::B1800,
    B2K4 = termios::B2400,
    B4K8 = termios::B4800,
    B9K6 = termios::B9600,
    B19K2 = termios::B19200,
    B38K4 = termios::B38400,
    B57K6 = termios::B57600,
    B115K2 = termios::B115200,
    B230K4 = termios::B230400,
    B460K8 = termios::B460800,
    B500K = termios::B500000,
    B576K = termios::B576000,
    B921K6 = termios::B921600,
    B1M = termios::B1000000,
    B1M152 = termios::B1152000,
    B1M5 = termios::B1500000,
    B2M = termios::B2000000,
    B2M5 = termios::B2500000,
    B3M = termios::B3000000,
    B3M5 = termios::B3500000,
    B4M = termios::B4000000,
}

#[cfg(target_os = "macos")]
#[deriving(Copy, FromPrimitive, PartialEq, Show)]
#[repr(u64)]
pub enum BaudRate {
    B0 = termios::B0,
    B50 = termios::B50,
    B75 = termios::B75,
    B110 = termios::B110,
    B134 = termios::B134,
    B150 = termios::B150,
    B200 = termios::B200,
    B300 = termios::B300,
    B600 = termios::B600,
    B1K2 = termios::B1200,
    B1K8 = termios::B1800,
    B2K4 = termios::B2400,
    B4K8 = termios::B4800,
    B7K2 = termios::B7200,
    B9K6 = termios::B9600,
    B14K4 = termios::B14400,
    B19K2 = termios::B19200,
    B28K8 = termios::B28800,
    B38K4 = termios::B38400,
    B57K6 = termios::B57600,
    B76K8 = termios::B76800,
    B115K2 = termios::B115200,
    B230K4 = termios::B230400,
}

#[cfg(target_os = "linux")]
#[deriving(Copy, FromPrimitive, PartialEq, Show)]
#[repr(u32)]
pub enum DataBits {
    Five = termios::CS5,
    Six = termios::CS6,
    Seven = termios::CS7,
    Eight = termios::CS8,
}

#[cfg(target_os = "macos")]
#[deriving(Copy, FromPrimitive, PartialEq, Show)]
#[repr(u64)]
pub enum DataBits {
    Five = termios::CS5,
    Six = termios::CS6,
    Seven = termios::CS7,
    Eight = termios::CS8,
}

#[deriving(Copy)]
pub enum Direction {
    Both,
    Input,
    Output,
}

#[deriving(Copy, FromPrimitive, PartialEq, Show)]
pub enum FlowControl {
    Hardware,
    None,
    Software,
}

#[deriving(Copy, FromPrimitive, PartialEq, Show)]
pub enum Parity {
    Even,
    None,
    Odd,
}

#[deriving(Copy, FromPrimitive, PartialEq, Show)]
#[repr(u32)]
pub enum StopBits {
    One,
    Two,
}
<commit_msg>fix(warnings): remove unnecessary feature gate<commit_after>#![deny(warnings)]
#![feature(globs, phase)]

extern crate libc;
#[cfg(test)]
extern crate quickcheck;
#[cfg(test)]
#[phase(plugin)]
extern crate quickcheck_macros;

use std::io::{File, FileAccess, FileMode, IoError, IoResult};
use std::os::unix::AsRawFd;

use termios::{FAILURE, Termios, SUCCESS};

mod termios;
#[cfg(test)]
mod socat;
#[cfg(test)]
mod test;

#[deriving(Copy, PartialEq)]
pub struct BlockingMode {
    /// The device will block until `bytes` are received
    pub bytes: u8,
    /// The device will block for at least `deciseconds` after each `read()` call
    pub deciseconds: u8,
}

pub struct SerialPort {
    fd: libc::c_int,
    file: File,
    termios: Termios,
}

impl SerialPort {
    /// Opens a serial `device` in "raw" mode
    pub fn open(device: &Path, access: FileAccess) -> IoResult<SerialPort> {
        let file = try!(File::open_mode(device, FileMode::Open, access));
        let fd = file.as_raw_fd();

        let mut termios = Termios::new();

        match unsafe { termios::tcgetattr(fd, &mut termios) } {
            FAILURE => return Err(IoError::last_error()),
            SUCCESS => {},
            _ => unreachable!(),
        }

        unsafe { termios::cfmakeraw(&mut termios) };

        let sp = SerialPort { fd: fd, file: file, termios: termios };

        try!(sp.update());

        Ok(sp)
    }

    /// Returns the input and output baud rates
    #[cfg(target_os = "linux")]
    pub fn baud_rate(&self) -> IoResult<(BaudRate, BaudRate)> {
        let termios = try!(self.fetch());

        let input = termios.c_ispeed;
        let input = match FromPrimitive::from_u32(input) {
            None => panic!("unrecognized BaudRate value: {}", input),
            Some(input) => input,
        };

        let output = termios.c_ospeed;
        let output = match FromPrimitive::from_u32(output) {
            None => panic!("unrecognized BaudRate value: {}", output),
            Some(output) => output,
        };

        Ok((input, output))
    }

    /// Returns the input and output baud rates
    #[cfg(target_os = "macos")]
    pub fn baud_rate(&self) -> IoResult<(BaudRate, BaudRate)> {
        let termios = try!(self.fetch());

        let input = termios.c_ispeed;
        let input = match FromPrimitive::from_u64(input) {
            None => panic!("unrecognized BaudRate value: {}", input),
            Some(input) => input,
        };

        let output = termios.c_ospeed;
        let output = match FromPrimitive::from_u64(output) {
            None => panic!("unrecognized BaudRate value: {}", output),
            Some(output) => output,
        };

        Ok((input, output))
    }

    /// Returns the blocking mode used by the device
    pub fn blocking_mode(&self) -> IoResult<BlockingMode> {
        use termios::{VMIN, VTIME};

        Ok(BlockingMode {
            bytes: self.termios.c_cc[VMIN as uint],
            deciseconds: self.termios.c_cc[VTIME as uint],
        })
    }

    /// Returns the number of data bits used per character
    #[cfg(target_os = "linux")]
    pub fn data_bits(&self) -> IoResult<DataBits> {
        use termios::CSIZE;

        let bits = try!(self.fetch()).c_cflag & CSIZE;

        match FromPrimitive::from_u32(bits) {
            None => panic!("unrecognized DataBits value: {}", bits),
            Some(bits) => Ok(bits),
        }
    }

    /// Returns the number of data bits used per character
    #[cfg(target_os = "macos")]
    pub fn data_bits(&self) -> IoResult<DataBits> {
        use termios::CSIZE;

        let bits = try!(self.fetch()).c_cflag & CSIZE;

        match FromPrimitive::from_u64(bits) {
            None => panic!("unrecognized DataBits value: {}", bits),
            Some(bits) => Ok(bits),
        }
    }

    /// Returns the flow control used by the device
    pub fn flow_control(&self) -> IoResult<FlowControl> {
        use FlowControl::*;
        use termios::{CRTSCTS, IXANY, IXOFF, IXON};

        let termios = try!(self.fetch());

        if termios.c_cflag & CRTSCTS != 0 {
            Ok(Hardware)
        } else if termios.c_iflag & (IXANY | IXOFF | IXON) == 0 {
            Ok(None)
        } else {
            Ok(Software)
        }
    }

    /// Returns the bit parity used by the device
    pub fn parity(&self) -> IoResult<Parity> {
        use Parity::*;
        use termios::{PARENB, PARODD};

        let termios = try!(self.fetch());

        match (termios.c_cflag & PARENB != 0, termios.c_cflag & PARODD != 0) {
            (true, true) => Ok(Odd),
            (true, false) => Ok(Even),
            (false, _) => Ok(None),
        }
    }

    /// Changes the baud rate of the input/output or both directions
    pub fn set_baud_rate(&mut self, direction: Direction, rate: BaudRate) -> IoResult<()> {
        use Direction::*;
        use termios::speed_t;

        match unsafe { match direction {
            Both => termios::cfsetspeed(&mut self.termios, rate as speed_t),
            Input => termios::cfsetispeed(&mut self.termios, rate as speed_t),
            Output => termios::cfsetospeed(&mut self.termios, rate as speed_t),
        } } {
            FAILURE => Err(IoError::last_error()),
            SUCCESS => self.update(),
            _ => unreachable!(),
        }
    }

    /// Changes the blocking mode used by the device
    pub fn set_blocking_mode(&mut self, mode: BlockingMode) -> IoResult<()> {
        use termios::{VMIN, VTIME};

        self.termios.c_cc[VMIN as uint] = mode.bytes;
        self.termios.c_cc[VTIME as uint] = mode.deciseconds;

        self.update()
    }

    /// Changes the number of data bits per character
    #[cfg(target_os = "linux")]
    pub fn set_data_bits(&mut self, bits: DataBits) -> IoResult<()> {
        use termios::CSIZE;

        self.termios.c_cflag &= !CSIZE;
        self.termios.c_cflag |= bits as u32;

        self.update()
    }

    /// Changes the number of data bits per character
    #[cfg(target_os = "macos")]
    pub fn set_data_bits(&mut self, bits: DataBits) -> IoResult<()> {
        use termios::CSIZE;

        self.termios.c_cflag &= !CSIZE;
        self.termios.c_cflag |= bits as u64;

        self.update()
    }

    /// Changes the flow control used by the device
    pub fn set_flow_control(&mut self, flow: FlowControl) -> IoResult<()> {
        use FlowControl::*;
        use termios::{CRTSCTS, IXANY, IXOFF, IXON};

        match flow {
            Hardware=> {
                self.termios.c_cflag |= CRTSCTS;
                self.termios.c_iflag &= !(IXANY | IXOFF | IXON);
            },
            None => {
                self.termios.c_cflag &= !CRTSCTS;
                self.termios.c_iflag &= !(IXANY | IXOFF | IXON);
            },
            Software => {
                self.termios.c_cflag &= !CRTSCTS;
                self.termios.c_iflag |= IXANY | IXOFF | IXON;
            },
        }

        self.update()
    }

    /// Changes the bit parity used by the device
    pub fn set_parity(&mut self, parity: Parity) -> IoResult<()> {
        use Parity::*;
        use termios::{PARENB, PARODD};

        match parity {
            Even=> {
                self.termios.c_cflag |= PARENB;
                self.termios.c_cflag &= !PARODD;
            },
            None => self.termios.c_cflag &= !PARENB,
            Odd=> self.termios.c_cflag |= PARENB | PARODD,
        }

        self.update()
    }

    /// Changes the number of stop bits per character
    pub fn set_stop_bits(&mut self, bits: StopBits) -> IoResult<()> {
        use StopBits::*;
        use termios::CSTOPB;

        match bits {
            One => self.termios.c_cflag &= !CSTOPB,
            Two => self.termios.c_cflag |= CSTOPB,
        }

        self.update()
    }

    /// Returns the number of stop bits per character
    pub fn stop_bits(&self) -> IoResult<StopBits> {
        use StopBits::*;
        use termios::CSTOPB;

        if try!(self.fetch()).c_cflag & CSTOPB == 0 {
            Ok(One)
        } else {
            Ok(Two)
        }
    }

    /// Fetches the current state of the termios structure
    fn fetch(&self) -> IoResult<Termios> {
        let mut termios = Termios::new();

        match unsafe { termios::tcgetattr(self.fd, &mut termios) } {
            FAILURE => Err(IoError::last_error()),
            SUCCESS => Ok(termios),
            _ => unreachable!(),
        }
    }

    /// Updates the underlying termios structure
    fn update(&self) -> IoResult<()> {
        use termios::TCSANOW;

        match unsafe { termios::tcsetattr(self.fd, TCSANOW, &self.termios) } {
            FAILURE => Err(IoError::last_error()),
            SUCCESS => Ok(()),
            _ => unreachable!(),
        }
    }
}

impl Reader for SerialPort {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        self.file.read(buf)
    }
}

impl Writer for SerialPort {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        self.file.write(buf)
    }
}

#[cfg(target_os = "linux")]
#[deriving(Copy, FromPrimitive, PartialEq, Show)]
#[repr(u32)]
pub enum BaudRate {
    B0 = termios::B0,
    B50 = termios::B50,
    B75 = termios::B75,
    B110 = termios::B110,
    B134 = termios::B134,
    B150 = termios::B150,
    B200 = termios::B200,
    B300 = termios::B300,
    B600 = termios::B600,
    B1K2 = termios::B1200,
    B1K8 = termios::B1800,
    B2K4 = termios::B2400,
    B4K8 = termios::B4800,
    B9K6 = termios::B9600,
    B19K2 = termios::B19200,
    B38K4 = termios::B38400,
    B57K6 = termios::B57600,
    B115K2 = termios::B115200,
    B230K4 = termios::B230400,
    B460K8 = termios::B460800,
    B500K = termios::B500000,
    B576K = termios::B576000,
    B921K6 = termios::B921600,
    B1M = termios::B1000000,
    B1M152 = termios::B1152000,
    B1M5 = termios::B1500000,
    B2M = termios::B2000000,
    B2M5 = termios::B2500000,
    B3M = termios::B3000000,
    B3M5 = termios::B3500000,
    B4M = termios::B4000000,
}

#[cfg(target_os = "macos")]
#[deriving(Copy, FromPrimitive, PartialEq, Show)]
#[repr(u64)]
pub enum BaudRate {
    B0 = termios::B0,
    B50 = termios::B50,
    B75 = termios::B75,
    B110 = termios::B110,
    B134 = termios::B134,
    B150 = termios::B150,
    B200 = termios::B200,
    B300 = termios::B300,
    B600 = termios::B600,
    B1K2 = termios::B1200,
    B1K8 = termios::B1800,
    B2K4 = termios::B2400,
    B4K8 = termios::B4800,
    B7K2 = termios::B7200,
    B9K6 = termios::B9600,
    B14K4 = termios::B14400,
    B19K2 = termios::B19200,
    B28K8 = termios::B28800,
    B38K4 = termios::B38400,
    B57K6 = termios::B57600,
    B76K8 = termios::B76800,
    B115K2 = termios::B115200,
    B230K4 = termios::B230400,
}

#[cfg(target_os = "linux")]
#[deriving(Copy, FromPrimitive, PartialEq, Show)]
#[repr(u32)]
pub enum DataBits {
    Five = termios::CS5,
    Six = termios::CS6,
    Seven = termios::CS7,
    Eight = termios::CS8,
}

#[cfg(target_os = "macos")]
#[deriving(Copy, FromPrimitive, PartialEq, Show)]
#[repr(u64)]
pub enum DataBits {
    Five = termios::CS5,
    Six = termios::CS6,
    Seven = termios::CS7,
    Eight = termios::CS8,
}

#[deriving(Copy)]
pub enum Direction {
    Both,
    Input,
    Output,
}

#[deriving(Copy, FromPrimitive, PartialEq, Show)]
pub enum FlowControl {
    Hardware,
    None,
    Software,
}

#[deriving(Copy, FromPrimitive, PartialEq, Show)]
pub enum Parity {
    Even,
    None,
    Odd,
}

#[deriving(Copy, FromPrimitive, PartialEq, Show)]
#[repr(u32)]
pub enum StopBits {
    One,
    Two,
}
<|endoftext|>


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

use std::ascii::AsciiExt;
use std::collections::HashMap;
use std::ffi::OsStr;
use std::fs;
use std::io::{BufRead, BufReader};
use std::path::PathBuf;

extern crate git2;
extern crate glob;
extern crate rustc_serialize;

static INDEX_GIT_URL: &'static str = "https://github.com/rust-lang/crates.io-index";

/// A single version of a crate published to the index
#[derive(RustcDecodable, Clone)]
pub struct Version {
    name: String,
    vers: String,
    deps: Vec<Dependency>,
    cksum: String,
    features: HashMap<String, Vec<String>>,
    yanked: bool,
}

impl Version {
    /// Name of the crate
    pub fn name(&self) -> &str {
        &self.name
    }

    /// Name of this version
    pub fn version(&self) -> &str {
        &self.vers
    }

    /// Dependencies for this version
    pub fn dependencies(&self) -> &[Dependency] {
        &self.deps
    }

    /// Checksum of the package for this version
    pub fn checksum(&self) -> &str {
        &self.cksum
    }

    pub fn features(&self) -> &HashMap<String, Vec<String>> {
        &self.features
    }

    /// Whether this version was [yanked](http://doc.crates.io/crates-io.html#cargo-yank) from the
    /// index
    pub fn is_yanked(&self) -> bool {
        self.yanked
    }
}

/// A single dependency of a specific crate version
#[derive(RustcDecodable, Clone)]
pub struct Dependency {
    name: String,
    req: String,
    features: Vec<String>,
    optional: bool,
    default_features: bool,
    target: Option<String>,
    kind: Option<String>
}

impl Dependency {
    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn requirement(&self) -> &str {
        &self.req
    }

    pub fn features(&self) -> &[String] {
        &self.features
    }

    pub fn is_optional(&self) -> bool {
        self.optional
    }

    pub fn has_default_features(&self) -> bool {
        self.default_features
    }

    pub fn target(&self) -> Option<&str> {
        match self.target {
            Some(ref s) => Some(s),
            None => None,
        }
    }

    pub fn kind(&self) -> Option<&str> {
        match self.kind {
            Some(ref s) => Some(s),
            None => None,
        }
    }
}

/// Constructed from `Index::crates`
pub struct Crates(CrateIndexPaths);

impl Iterator for Crates {
    type Item = Crate;
    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|p| Crate::new(&p))
    }
}

/// Constructed from `Index::crate_index_paths`
pub struct CrateIndexPaths(std::iter::Chain<glob::Paths, glob::Paths>);

impl CrateIndexPaths {
    fn new(path: PathBuf) -> CrateIndexPaths {
        let mut match_options = glob::MatchOptions::new();
        match_options.require_literal_leading_dot = true;

        let glob_pattern = format!("{}/*/*/*", path.to_str().unwrap());
        let index_paths1 = glob::glob_with(&glob_pattern, &match_options).unwrap();

        let glob_pattern = format!("{}/[12]/*", path.to_str().unwrap());
        let index_paths2 = glob::glob_with(&glob_pattern, &match_options).unwrap();

        CrateIndexPaths(index_paths1.chain(index_paths2))
    }
}

impl Iterator for CrateIndexPaths {
    type Item = PathBuf;
    fn next(&mut self)  -> Option<Self::Item> {
        self.0.next().map(|glob_result| glob_result.unwrap())
    }
}

/// Wrapper around managing the crates.io-index git repository
pub struct Index {
    path: PathBuf,
}

impl Index {
    /// Construct a new Index supplying a path where the index lives or should live
    pub fn new(path: PathBuf) -> Index {
        Index{path: path}
    }

    /// Determines if *anything* exists at the path specified from the constructor
    pub fn exists(&self) -> bool {
        fs::metadata(&self.path).is_ok()
    }

    /// Clones the index to the path specified from the constructor
    pub fn clone(&self) -> Result<(), git2::Error> {
        let _ = try!(git2::Repository::clone(INDEX_GIT_URL, &self.path));
        Ok(())
    }

    /// Retrieve a single crate by name (case insensitive) from the index
    pub fn crate_(&self, crate_name: &str) -> Option<Crate> {
        self.crate_index_paths()
            .find(|path| path.file_name()
                             .and_then(OsStr::to_str)
                             .map(|file_name| file_name.eq_ignore_ascii_case(crate_name))
                             .unwrap_or(false))
            .map(|p| Crate::new(&p))
    }

    /// Retrieve an iterator over all the crates in the index
    pub fn crates(&self) -> Crates {
        Crates(self.crate_index_paths())
    }

    /// Returns all the crate index file paths in the index
    pub fn crate_index_paths(&self) -> CrateIndexPaths {
        CrateIndexPaths::new(self.path.clone())  // TODO: remove this clone
    }
}

/// A single crate that contains many published versions
pub struct Crate {
    versions: Vec<Version>,
}

impl Crate {
    pub fn new(index_path: &PathBuf) -> Crate {
        let mut versions = vec![];
        let file = fs::File::open(&index_path).unwrap();
        for line in BufReader::new(file).lines() {
            let version: Version = rustc_serialize::json::decode(&line.unwrap()).unwrap();
            versions.push(version);
        }
        Crate {versions: versions}
    }

    /// Published versions of this crate sorted chronologically by date published
    pub fn versions(&self) -> &[Version] {
        &self.versions
    }

    pub fn earliest_version(&self) -> &Version {
        &self.versions[0]
    }

    pub fn latest_version(&self) -> &Version {
        &self.versions[self.versions.len() - 1]
    }
}

#[test]
fn test_dependencies() {
    let index = Index::new("_test".into());
    if !index.exists() {
        index.clone().unwrap();
    }
    let crate_ = index.crates().nth(0).unwrap();
    let version = crate_.latest_version();
    let _ = version.deps;
}
<commit_msg>No need to take borrowed owned PathBuf.<commit_after>// Copyright 2015 Corey Farwell
// Copyright 2015 Contributors of github.com/huonw/crates.io-graph
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//	http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::ascii::AsciiExt;
use std::collections::HashMap;
use std::ffi::OsStr;
use std::fs;
use std::io::{BufRead, BufReader};
use std::path::{Path, PathBuf};

extern crate git2;
extern crate glob;
extern crate rustc_serialize;

static INDEX_GIT_URL: &'static str = "https://github.com/rust-lang/crates.io-index";

/// A single version of a crate published to the index
#[derive(RustcDecodable, Clone)]
pub struct Version {
    name: String,
    vers: String,
    deps: Vec<Dependency>,
    cksum: String,
    features: HashMap<String, Vec<String>>,
    yanked: bool,
}

impl Version {
    /// Name of the crate
    pub fn name(&self) -> &str {
        &self.name
    }

    /// Name of this version
    pub fn version(&self) -> &str {
        &self.vers
    }

    /// Dependencies for this version
    pub fn dependencies(&self) -> &[Dependency] {
        &self.deps
    }

    /// Checksum of the package for this version
    pub fn checksum(&self) -> &str {
        &self.cksum
    }

    pub fn features(&self) -> &HashMap<String, Vec<String>> {
        &self.features
    }

    /// Whether this version was [yanked](http://doc.crates.io/crates-io.html#cargo-yank) from the
    /// index
    pub fn is_yanked(&self) -> bool {
        self.yanked
    }
}

/// A single dependency of a specific crate version
#[derive(RustcDecodable, Clone)]
pub struct Dependency {
    name: String,
    req: String,
    features: Vec<String>,
    optional: bool,
    default_features: bool,
    target: Option<String>,
    kind: Option<String>
}

impl Dependency {
    pub fn name(&self) -> &str {
        &self.name
    }

    pub fn requirement(&self) -> &str {
        &self.req
    }

    pub fn features(&self) -> &[String] {
        &self.features
    }

    pub fn is_optional(&self) -> bool {
        self.optional
    }

    pub fn has_default_features(&self) -> bool {
        self.default_features
    }

    pub fn target(&self) -> Option<&str> {
        match self.target {
            Some(ref s) => Some(s),
            None => None,
        }
    }

    pub fn kind(&self) -> Option<&str> {
        match self.kind {
            Some(ref s) => Some(s),
            None => None,
        }
    }
}

/// Constructed from `Index::crates`
pub struct Crates(CrateIndexPaths);

impl Iterator for Crates {
    type Item = Crate;
    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(|p| Crate::new(&p))
    }
}

/// Constructed from `Index::crate_index_paths`
pub struct CrateIndexPaths(std::iter::Chain<glob::Paths, glob::Paths>);

impl CrateIndexPaths {
    fn new(path: PathBuf) -> CrateIndexPaths {
        let mut match_options = glob::MatchOptions::new();
        match_options.require_literal_leading_dot = true;

        let glob_pattern = format!("{}/*/*/*", path.to_str().unwrap());
        let index_paths1 = glob::glob_with(&glob_pattern, &match_options).unwrap();

        let glob_pattern = format!("{}/[12]/*", path.to_str().unwrap());
        let index_paths2 = glob::glob_with(&glob_pattern, &match_options).unwrap();

        CrateIndexPaths(index_paths1.chain(index_paths2))
    }
}

impl Iterator for CrateIndexPaths {
    type Item = PathBuf;
    fn next(&mut self)  -> Option<Self::Item> {
        self.0.next().map(|glob_result| glob_result.unwrap())
    }
}

/// Wrapper around managing the crates.io-index git repository
pub struct Index {
    path: PathBuf,
}

impl Index {
    /// Construct a new Index supplying a path where the index lives or should live
    pub fn new(path: PathBuf) -> Index {
        Index{path: path}
    }

    /// Determines if *anything* exists at the path specified from the constructor
    pub fn exists(&self) -> bool {
        fs::metadata(&self.path).is_ok()
    }

    /// Clones the index to the path specified from the constructor
    pub fn clone(&self) -> Result<(), git2::Error> {
        let _ = try!(git2::Repository::clone(INDEX_GIT_URL, &self.path));
        Ok(())
    }

    /// Retrieve a single crate by name (case insensitive) from the index
    pub fn crate_(&self, crate_name: &str) -> Option<Crate> {
        self.crate_index_paths()
            .find(|path| path.file_name()
                             .and_then(OsStr::to_str)
                             .map(|file_name| file_name.eq_ignore_ascii_case(crate_name))
                             .unwrap_or(false))
            .map(|p| Crate::new(&p))
    }

    /// Retrieve an iterator over all the crates in the index
    pub fn crates(&self) -> Crates {
        Crates(self.crate_index_paths())
    }

    /// Returns all the crate index file paths in the index
    pub fn crate_index_paths(&self) -> CrateIndexPaths {
        CrateIndexPaths::new(self.path.clone())  // TODO: remove this clone
    }
}

/// A single crate that contains many published versions
pub struct Crate {
    versions: Vec<Version>,
}

impl Crate {
    pub fn new(index_path: &Path) -> Crate {
        let mut versions = vec![];
        let file = fs::File::open(&index_path).unwrap();
        for line in BufReader::new(file).lines() {
            let version: Version = rustc_serialize::json::decode(&line.unwrap()).unwrap();
            versions.push(version);
        }
        Crate {versions: versions}
    }

    /// Published versions of this crate sorted chronologically by date published
    pub fn versions(&self) -> &[Version] {
        &self.versions
    }

    pub fn earliest_version(&self) -> &Version {
        &self.versions[0]
    }

    pub fn latest_version(&self) -> &Version {
        &self.versions[self.versions.len() - 1]
    }
}

#[test]
fn test_dependencies() {
    let index = Index::new("_test".into());
    if !index.exists() {
        index.clone().unwrap();
    }
    let crate_ = index.crates().nth(0).unwrap();
    let version = crate_.latest_version();
    let _ = version.deps;
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! # Cap'n Proto Runtime Library
//!
//! [Cap'n Proto](https://capnproto.org) is an extremely efficient protocol for
//! sharing data and capabilities.
//!
//! The Rust implementation is split into three separate crates.
//!
//! Code generation is handled by [capnpc-rust](https://github.com/dwrensha/capnpc-rust).
//!
//! The present crate is the runtime library required by that generated code. It is hosted on Github
//! [here](https://github.com/dwrensha/capnproto-rust).
//!
//! [capnp-rpc-rust](https://github.com/dwrensha/capnp-rpc-rust) is an implementation of a
//! distributed object-capability layer.

#![allow(raw_pointer_derive)]

extern crate byteorder;

#[cfg(any(feature="quickcheck", test))]
extern crate quickcheck;

#[cfg(feature = "rpc")]
extern crate gj;

pub mod any_pointer;
pub mod capability;
pub mod data;
pub mod data_list;
pub mod enum_list;
pub mod list_list;
pub mod message;
pub mod primitive_list;
pub mod private;
pub mod serialize;
pub mod serialize_packed;
pub mod struct_list;
pub mod text;
pub mod text_list;
pub mod traits;

mod util;

/// Eight bytes of memory with opaque interior.
///
/// This type is used to ensure that the data of a message is properly aligned.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(C)]
pub struct Word(u64);

impl Word {
    /// Does this, but faster:
    /// `::std::iter::repeat(Word(0)).take(length).collect()`
    pub fn allocate_zeroed_vec(length: usize) -> Vec<Word> {
        let mut result : Vec<Word> = Vec::with_capacity(length);
        unsafe {
            result.set_len(length);
            let p : *mut u8 = result.as_mut_ptr() as *mut u8;
            ::std::ptr::write_bytes(p, 0u8, length * ::std::mem::size_of::<Word>());
        }
        result
    }

    pub fn bytes_to_words<'a>(bytes: &'a [u8]) -> &'a [Word] {
        unsafe {
            ::std::slice::from_raw_parts(bytes.as_ptr() as *const Word, bytes.len() / 8)
        }
    }

    pub fn bytes_to_words_mut<'a>(bytes: &'a mut [u8]) -> &'a mut [Word] {
        unsafe {
            ::std::slice::from_raw_parts_mut(bytes.as_ptr() as *mut Word, bytes.len() / 8)
        }
    }

    pub fn words_to_bytes<'a>(words: &'a [Word]) -> &'a [u8] {
        unsafe {
            ::std::slice::from_raw_parts(words.as_ptr() as *const u8, words.len() * 8)
        }
    }

    pub fn words_to_bytes_mut<'a>(words: &'a mut [Word]) -> &'a mut [u8] {
        unsafe {
            ::std::slice::from_raw_parts_mut(words.as_mut_ptr() as *mut u8, words.len() * 8)
        }
    }

    #[cfg(test)]
    pub fn from(n: u64) -> Word {
        Word(n)
    }
}

#[cfg(any(feature="quickcheck", test))]
impl quickcheck::Arbitrary for Word {
    fn arbitrary<G: quickcheck::Gen>(g: &mut G) -> Word {
        Word(quickcheck::Arbitrary::arbitrary(g))
    }
}

/// Size of a message. Every generated struct has a method `.total_size()` that returns this.
#[derive(Clone, Copy, PartialEq)]
pub struct MessageSize {
    pub word_count: u64,

    /// Size of the capability table.
    pub cap_count: u32
}

impl MessageSize {
    pub fn plus_eq(&mut self, other : MessageSize) {
        self.word_count += other.word_count;
        self.cap_count += other.cap_count;
    }
}

/// An enum value or union discriminant that was not found among those defined in a schema.
#[derive(PartialEq, Clone, Copy, Debug)]
pub struct NotInSchema(pub u16);

impl ::std::fmt::Display for NotInSchema {
    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> {
        write!(fmt, "Enum value or union discriminant {} was not present in the schema.", self.0)
    }
}

impl ::std::error::Error for NotInSchema {
    fn description<'a>(&'a self) -> &'a str {
        "Enum value or union disriminant was not present in schema."
    }
}

/// Because messages are lazily validated, the return type of any method that reads a pointer field
/// must be wrapped in a Result.
pub type Result<T> = ::std::result::Result<T, Error>;

/// Describes an arbitrary error that prevented an operation from completing.
#[derive(Debug, Clone)]
pub struct Error {
    /// The type of the error. The purpose of this enum is not to describe the error itself, but
    /// rather to describe how the client might want to respond to the error.
    pub kind: ErrorKind,

    /// Human-readable failure description.
    pub description: String,
}

#[derive(Debug, Clone, Copy)]
pub enum ErrorKind {
    // Something went wrong. This is the usual error kind. It includes decoding errors and I/O
    // errors.
    Failed,

    // The call failed because of a temporary lack of resources. This could be space resources
    // (out of memory, out of disk space) or time resources (request queue overflow, operation
    // timed out).
    //
    // The operation might work if tried again, but it should NOT be repeated immediately as this
    // may simply exacerbate the problem.
    Overloaded,

    // The call required communication over a connection that has been lost. The callee will need
    // to re-establish connections and try again.
    Disconnected,

    // The requested method is not implemented. The caller may wish to revert to a fallback
    // approach based on other methods.
    Unimplemented,
}

impl Error {
    pub fn failed(description: String) -> Error {
        Error { description: description, kind: ErrorKind::Failed }
    }
    pub fn unimplemented(description: String) -> Error {
        Error { description: description, kind: ErrorKind::Unimplemented }
    }
}

impl ::std::convert::From<::std::io::Error> for Error {
    fn from(err: ::std::io::Error) -> Error {
        Error { description: format!("{}", err), kind: ErrorKind::Failed }
    }
}

impl ::std::convert::From<NotInSchema> for Error {
    fn from(e: NotInSchema) -> Error {
        Error::failed(format!("Enum value or union discriminant {} was not present in schema.", e.0))
    }
}

impl ::std::fmt::Display for Error {
    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> {
        write!(fmt, "{:?}: {}", self.kind, self.description)
    }
}

impl ::std::error::Error for Error {
    fn description(&self) -> &str {
        &self.description
    }
    fn cause(&self) -> Option<&::std::error::Error> {
        None
    }
}

#[cfg(feature = "rpc")]
impl ::gj::FulfillerDropped for Error {
    fn fulfiller_dropped() -> Error {
        Error {
            reason: "Promise fulfiller was dropped.".to_string(),
            kind: ErrorKind::Failed
        }
    }
}

/// Helper struct that allows `MessageBuilder::get_segments_for_output()` to avoid heap allocations
/// in the single-segment case.
pub enum OutputSegments<'a> {
    #[doc(hidden)]
    SingleSegment([&'a [Word]; 1]),

    #[doc(hidden)]
    MultiSegment(Vec<&'a [Word]>),
}

impl <'a> ::std::ops::Deref for OutputSegments<'a> {
    type Target = [&'a [Word]];
    fn deref<'b>(&'b self) -> &'b [&'a [Word]] {
        match self {
            &OutputSegments::SingleSegment(ref s) => {
                s
            }
            &OutputSegments::MultiSegment(ref v) => {
                &*v
            }
        }
    }
}
<commit_msg>missed one<commit_after>// Copyright (c) 2013-2015 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

//! # Cap'n Proto Runtime Library
//!
//! [Cap'n Proto](https://capnproto.org) is an extremely efficient protocol for
//! sharing data and capabilities.
//!
//! The Rust implementation is split into three separate crates.
//!
//! Code generation is handled by [capnpc-rust](https://github.com/dwrensha/capnpc-rust).
//!
//! The present crate is the runtime library required by that generated code. It is hosted on Github
//! [here](https://github.com/dwrensha/capnproto-rust).
//!
//! [capnp-rpc-rust](https://github.com/dwrensha/capnp-rpc-rust) is an implementation of a
//! distributed object-capability layer.

#![allow(raw_pointer_derive)]

extern crate byteorder;

#[cfg(any(feature="quickcheck", test))]
extern crate quickcheck;

#[cfg(feature = "rpc")]
extern crate gj;

pub mod any_pointer;
pub mod capability;
pub mod data;
pub mod data_list;
pub mod enum_list;
pub mod list_list;
pub mod message;
pub mod primitive_list;
pub mod private;
pub mod serialize;
pub mod serialize_packed;
pub mod struct_list;
pub mod text;
pub mod text_list;
pub mod traits;

mod util;

/// Eight bytes of memory with opaque interior.
///
/// This type is used to ensure that the data of a message is properly aligned.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(C)]
pub struct Word(u64);

impl Word {
    /// Does this, but faster:
    /// `::std::iter::repeat(Word(0)).take(length).collect()`
    pub fn allocate_zeroed_vec(length: usize) -> Vec<Word> {
        let mut result : Vec<Word> = Vec::with_capacity(length);
        unsafe {
            result.set_len(length);
            let p : *mut u8 = result.as_mut_ptr() as *mut u8;
            ::std::ptr::write_bytes(p, 0u8, length * ::std::mem::size_of::<Word>());
        }
        result
    }

    pub fn bytes_to_words<'a>(bytes: &'a [u8]) -> &'a [Word] {
        unsafe {
            ::std::slice::from_raw_parts(bytes.as_ptr() as *const Word, bytes.len() / 8)
        }
    }

    pub fn bytes_to_words_mut<'a>(bytes: &'a mut [u8]) -> &'a mut [Word] {
        unsafe {
            ::std::slice::from_raw_parts_mut(bytes.as_ptr() as *mut Word, bytes.len() / 8)
        }
    }

    pub fn words_to_bytes<'a>(words: &'a [Word]) -> &'a [u8] {
        unsafe {
            ::std::slice::from_raw_parts(words.as_ptr() as *const u8, words.len() * 8)
        }
    }

    pub fn words_to_bytes_mut<'a>(words: &'a mut [Word]) -> &'a mut [u8] {
        unsafe {
            ::std::slice::from_raw_parts_mut(words.as_mut_ptr() as *mut u8, words.len() * 8)
        }
    }

    #[cfg(test)]
    pub fn from(n: u64) -> Word {
        Word(n)
    }
}

#[cfg(any(feature="quickcheck", test))]
impl quickcheck::Arbitrary for Word {
    fn arbitrary<G: quickcheck::Gen>(g: &mut G) -> Word {
        Word(quickcheck::Arbitrary::arbitrary(g))
    }
}

/// Size of a message. Every generated struct has a method `.total_size()` that returns this.
#[derive(Clone, Copy, PartialEq)]
pub struct MessageSize {
    pub word_count: u64,

    /// Size of the capability table.
    pub cap_count: u32
}

impl MessageSize {
    pub fn plus_eq(&mut self, other : MessageSize) {
        self.word_count += other.word_count;
        self.cap_count += other.cap_count;
    }
}

/// An enum value or union discriminant that was not found among those defined in a schema.
#[derive(PartialEq, Clone, Copy, Debug)]
pub struct NotInSchema(pub u16);

impl ::std::fmt::Display for NotInSchema {
    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> {
        write!(fmt, "Enum value or union discriminant {} was not present in the schema.", self.0)
    }
}

impl ::std::error::Error for NotInSchema {
    fn description<'a>(&'a self) -> &'a str {
        "Enum value or union disriminant was not present in schema."
    }
}

/// Because messages are lazily validated, the return type of any method that reads a pointer field
/// must be wrapped in a Result.
pub type Result<T> = ::std::result::Result<T, Error>;

/// Describes an arbitrary error that prevented an operation from completing.
#[derive(Debug, Clone)]
pub struct Error {
    /// The type of the error. The purpose of this enum is not to describe the error itself, but
    /// rather to describe how the client might want to respond to the error.
    pub kind: ErrorKind,

    /// Human-readable failure description.
    pub description: String,
}

#[derive(Debug, Clone, Copy)]
pub enum ErrorKind {
    // Something went wrong. This is the usual error kind. It includes decoding errors and I/O
    // errors.
    Failed,

    // The call failed because of a temporary lack of resources. This could be space resources
    // (out of memory, out of disk space) or time resources (request queue overflow, operation
    // timed out).
    //
    // The operation might work if tried again, but it should NOT be repeated immediately as this
    // may simply exacerbate the problem.
    Overloaded,

    // The call required communication over a connection that has been lost. The callee will need
    // to re-establish connections and try again.
    Disconnected,

    // The requested method is not implemented. The caller may wish to revert to a fallback
    // approach based on other methods.
    Unimplemented,
}

impl Error {
    pub fn failed(description: String) -> Error {
        Error { description: description, kind: ErrorKind::Failed }
    }
    pub fn unimplemented(description: String) -> Error {
        Error { description: description, kind: ErrorKind::Unimplemented }
    }
}

impl ::std::convert::From<::std::io::Error> for Error {
    fn from(err: ::std::io::Error) -> Error {
        Error { description: format!("{}", err), kind: ErrorKind::Failed }
    }
}

impl ::std::convert::From<NotInSchema> for Error {
    fn from(e: NotInSchema) -> Error {
        Error::failed(format!("Enum value or union discriminant {} was not present in schema.", e.0))
    }
}

impl ::std::fmt::Display for Error {
    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> {
        write!(fmt, "{:?}: {}", self.kind, self.description)
    }
}

impl ::std::error::Error for Error {
    fn description(&self) -> &str {
        &self.description
    }
    fn cause(&self) -> Option<&::std::error::Error> {
        None
    }
}

#[cfg(feature = "rpc")]
impl ::gj::FulfillerDropped for Error {
    fn fulfiller_dropped() -> Error {
        Error::failed("Promise fulfiller was dropped.".to_string())
    }
}

/// Helper struct that allows `MessageBuilder::get_segments_for_output()` to avoid heap allocations
/// in the single-segment case.
pub enum OutputSegments<'a> {
    #[doc(hidden)]
    SingleSegment([&'a [Word]; 1]),

    #[doc(hidden)]
    MultiSegment(Vec<&'a [Word]>),
}

impl <'a> ::std::ops::Deref for OutputSegments<'a> {
    type Target = [&'a [Word]];
    fn deref<'b>(&'b self) -> &'b [&'a [Word]] {
        match self {
            &OutputSegments::SingleSegment(ref s) => {
                s
            }
            &OutputSegments::MultiSegment(ref v) => {
                &*v
            }
        }
    }
}
<|endoftext|>