<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;
extern crate itertools;

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

use strings::string_buffer::StringBuffer;

use std::io::{self, stdout, Write};
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;
use checkstyle::{output_header, output_footer};

pub use self::summary::Summary;

#[macro_use]
mod utils;
pub mod config;
pub mod filemap;
pub 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;
pub mod modules;
pub mod rustfmt_diff;
mod chains;
mod macros;
mod patterns;
mod summary;

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 {
    fn new() -> FormatReport {
        FormatReport { file_error_map: HashMap::new() }
    }

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

    pub fn has_warnings(&self) -> bool {
        self.warning_count() > 0
    }
}

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 format_ast<F>(krate: &ast::Crate,
                 parse_session: &ParseSess,
                 main_file: &Path,
                 config: &Config,
                 mut after_file: F)
                 -> Result<FileMap, io::Error>
    where F: FnMut(&str, &mut StringBuffer) -> Result<(), io::Error>
{
    let mut result = FileMap::new();

    // We always skip children for the "Plain" write mode, since there is
    // nothing to distinguish the nested module contents.
    let skip_children = config.skip_children || config.write_mode == config::WriteMode::Plain;
    for (path, module) in modules::list_files(krate, parse_session.codemap()) {
        if 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);

        try!(after_file(path, &mut visitor.buffer));

        result.push((path.to_owned(), visitor.buffer));
    }

    Ok(result)
}

// Formatting done on a char by char or line by line basis.
// FIXME(#209) warn on bad license
// FIXME(#20) other stuff for parity with make tidy
fn format_lines(text: &mut StringBuffer, name: &str, config: &Config, report: &mut FormatReport) {
    // Iterate over the chars in the file map.
    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: {} {}", text.len, newline_count);
        let line = text.len - newline_count + 1;
        text.truncate(line);
    }

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

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

fn parse_input(input: Input,
               parse_session: &ParseSess)
               -> Result<ast::Crate, Option<DiagnosticBuilder>> {
    let result = match input {
        Input::File(file) => parse::parse_crate_from_file(&file, Vec::new(), &parse_session),
        Input::Text(text) => {
            parse::parse_crate_from_source_str("stdin".to_owned(), text, Vec::new(), &parse_session)
        }
    };

    match result {
        Ok(c) => {
            if parse_session.span_diagnostic.has_errors() {
                // Bail out if the parser recovered from an error.
                Err(None)
            } else {
                Ok(c)
            }
        }
        Err(e) => Err(Some(e)),
    }
}

pub fn format_input<T: Write>(input: Input,
                              config: &Config,
                              mut out: Option<&mut T>)
                              -> Result<(Summary, FileMap, FormatReport), (io::Error, Summary)> {
    let mut summary = Summary::new();
    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 main_file = match input {
        Input::File(ref file) => file.clone(),
        Input::Text(..) => PathBuf::from("stdin"),
    };

    let krate = match parse_input(input, &parse_session) {
        Ok(krate) => krate,
        Err(diagnostic) => {
            if let Some(mut diagnostic) = diagnostic {
                diagnostic.emit();
            }
            summary.add_parsing_error();
            return Ok((summary, FileMap::new(), FormatReport::new()));
        }
    };

    if parse_session.span_diagnostic.has_errors() {
        summary.add_parsing_error();
    }

    // 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 report = FormatReport::new();

    match format_ast(&krate,
                     &parse_session,
                     &main_file,
                     config,
                     |file_name, file| {
        // For some reason, the codemap does not include terminating
        // newlines so we must add one on for each file. This is sad.
        filemap::append_newline(file);

        format_lines(file, file_name, config, &mut report);

        if let Some(ref mut out) = out {
            try!(filemap::write_file(file, file_name, out, config));
        }
        Ok(())
    }) {
        Ok(file_map) => {
            if report.has_warnings() {
                summary.add_formatting_error();
            }

            Ok((summary, file_map, report))
        }
        Err(e) => Err((e, summary)),
    }
}

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

pub fn run(input: Input, config: &Config) -> Summary {
    let mut out = &mut stdout();
    output_header(out, config.write_mode).ok();
    match format_input(input, config, Some(out)) {
        Ok((summary, _, report)) => {
            output_footer(out, config.write_mode).ok();

            if report.has_warnings() {
                msg!("{}", report);
            }

            summary
        }
        Err((msg, mut summary)) => {
            msg!("Error writing files: {}", msg);
            summary.add_operational_error();
            summary
        }
    }
}
<commit_msg>Derive Debug for the Input enum<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;
extern crate itertools;

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

use strings::string_buffer::StringBuffer;

use std::io::{self, stdout, Write};
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;
use checkstyle::{output_header, output_footer};

pub use self::summary::Summary;

#[macro_use]
mod utils;
pub mod config;
pub mod filemap;
pub 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;
pub mod modules;
pub mod rustfmt_diff;
mod chains;
mod macros;
mod patterns;
mod summary;

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 {
    fn new() -> FormatReport {
        FormatReport { file_error_map: HashMap::new() }
    }

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

    pub fn has_warnings(&self) -> bool {
        self.warning_count() > 0
    }
}

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 format_ast<F>(krate: &ast::Crate,
                 parse_session: &ParseSess,
                 main_file: &Path,
                 config: &Config,
                 mut after_file: F)
                 -> Result<FileMap, io::Error>
    where F: FnMut(&str, &mut StringBuffer) -> Result<(), io::Error>
{
    let mut result = FileMap::new();

    // We always skip children for the "Plain" write mode, since there is
    // nothing to distinguish the nested module contents.
    let skip_children = config.skip_children || config.write_mode == config::WriteMode::Plain;
    for (path, module) in modules::list_files(krate, parse_session.codemap()) {
        if 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);

        try!(after_file(path, &mut visitor.buffer));

        result.push((path.to_owned(), visitor.buffer));
    }

    Ok(result)
}

// Formatting done on a char by char or line by line basis.
// FIXME(#209) warn on bad license
// FIXME(#20) other stuff for parity with make tidy
fn format_lines(text: &mut StringBuffer, name: &str, config: &Config, report: &mut FormatReport) {
    // Iterate over the chars in the file map.
    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: {} {}", text.len, newline_count);
        let line = text.len - newline_count + 1;
        text.truncate(line);
    }

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

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

fn parse_input(input: Input,
               parse_session: &ParseSess)
               -> Result<ast::Crate, Option<DiagnosticBuilder>> {
    let result = match input {
        Input::File(file) => parse::parse_crate_from_file(&file, Vec::new(), &parse_session),
        Input::Text(text) => {
            parse::parse_crate_from_source_str("stdin".to_owned(), text, Vec::new(), &parse_session)
        }
    };

    match result {
        Ok(c) => {
            if parse_session.span_diagnostic.has_errors() {
                // Bail out if the parser recovered from an error.
                Err(None)
            } else {
                Ok(c)
            }
        }
        Err(e) => Err(Some(e)),
    }
}

pub fn format_input<T: Write>(input: Input,
                              config: &Config,
                              mut out: Option<&mut T>)
                              -> Result<(Summary, FileMap, FormatReport), (io::Error, Summary)> {
    let mut summary = Summary::new();
    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 main_file = match input {
        Input::File(ref file) => file.clone(),
        Input::Text(..) => PathBuf::from("stdin"),
    };

    let krate = match parse_input(input, &parse_session) {
        Ok(krate) => krate,
        Err(diagnostic) => {
            if let Some(mut diagnostic) = diagnostic {
                diagnostic.emit();
            }
            summary.add_parsing_error();
            return Ok((summary, FileMap::new(), FormatReport::new()));
        }
    };

    if parse_session.span_diagnostic.has_errors() {
        summary.add_parsing_error();
    }

    // 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 report = FormatReport::new();

    match format_ast(&krate,
                     &parse_session,
                     &main_file,
                     config,
                     |file_name, file| {
        // For some reason, the codemap does not include terminating
        // newlines so we must add one on for each file. This is sad.
        filemap::append_newline(file);

        format_lines(file, file_name, config, &mut report);

        if let Some(ref mut out) = out {
            try!(filemap::write_file(file, file_name, out, config));
        }
        Ok(())
    }) {
        Ok(file_map) => {
            if report.has_warnings() {
                summary.add_formatting_error();
            }

            Ok((summary, file_map, report))
        }
        Err(e) => Err((e, summary)),
    }
}

#[derive(Debug)]
pub enum Input {
    File(PathBuf),
    Text(String),
}

pub fn run(input: Input, config: &Config) -> Summary {
    let mut out = &mut stdout();
    output_header(out, config.write_mode).ok();
    match format_input(input, config, Some(out)) {
        Ok((summary, _, report)) => {
            output_footer(out, config.write_mode).ok();

            if report.has_warnings() {
                msg!("{}", report);
            }

            summary
        }
        Err((msg, mut summary)) => {
            msg!("Error writing files: {}", msg);
            summary.add_operational_error();
            summary
        }
    }
}
<|endoftext|>


<commit_before>/*
 *           _           _            _             _          _
 *          /\ \        /\ \         /\ \     _    /\ \       /\ \
 *         /  \ \      /  \ \       /  \ \   /\_\ /  \ \      \_\ \
 *        / /\ \ \    / /\ \ \     / /\ \ \_/ / // /\ \ \     /\__ \
 *       / / /\ \_\  / / /\ \_\   / / /\ \___/ // / /\ \_\   / /_ \ \
 *      / / /_/ / / / /_/_ \/_/  / / /  \/____// /_/_ \/_/  / / /\ \ \
 *     / / /__\/ / / /____/\    / / /    / / // /____/\    / / /  \/_/
 *    / / /_____/ / /\____\/   / / /    / / // /\____\/   / / /
 *   / / /\ \ \  / / /______  / / /    / / // / /______  / / /
 *  / / /  \ \ \/ / /_______\/ / /    / / // / /_______\/_/ /
 *  \/_/    \_\/\/__________/\/_/     \/_/ \/__________/\_\/
 *
 *
 * This file is released under terms described in the LICENSE file at
 * the top directory of this repository.
 *
 * Please contact Mark McDermott <mark.elias.mcdermott@gmail.com> or
 * the current maintainer of this software if you do not have a copy of
 * the license file.
 *
 * -------------------------------------------------------------------
 *  REnet is a rust language wrapper for the ENet networking library
 *
 *  TODO List
 * -------------------------------------------------------------------
 */

#![feature(libc)]
#![feature(raw)]
extern crate libc;

use libc::{c_uint,c_void,size_t,c_int};
use std::raw::Repr;

#[allow(non_snake_case)]
pub mod ffi;

pub fn initialize() -> Result<(), i32>  {
    unsafe {
        match ffi::enet_initialize() {
            0    => Ok(()),
            code => Err(code)
        }
    }
}

pub fn deinitialize() {
    unsafe {
        ffi::enet_deinitialize();
    }
}

pub fn linked_version() -> u32 {
    unsafe {
        ffi::enet_linked_version() as u32
    }
}

pub struct Host {
    ffi_handle : *mut c_void,
}

pub struct Peer {
    ffi_handle : *mut ffi::ENetPeer,
}

pub struct Packet {
    ffi_handle: *mut ffi::ENetPacket
}

/*
 * ------------------------------------------------------------------
 * Event: enum of event types*
 * ------------------------------------------------------------------
 */
pub enum Event {
    Connect(Peer),
    Receive(Peer,Packet),
    Disconnect(Peer),
    None,
}

/*
 * ------------------------------------------------------------------
 * Host object: a wrapper around ENetHost*
 * ------------------------------------------------------------------
 */

impl Host {
    pub fn new_server(port: u16,
                      peer_count: u32,
                      channel_count: u32,
                      incoming_bandwidth: u32,
                      outgoing_bandwidth: u32) -> Result<Host, &'static str> {
        let address = ffi::ENetAddress {
            host: ffi::ENET_HOST_ANY,
            port: port
        };

        let host_c = unsafe {
            ffi::enet_host_create(&address as *const ffi::ENetAddress,
                                  peer_count as size_t,
                                  channel_count as size_t,
                                  incoming_bandwidth as c_uint,
                                  outgoing_bandwidth as c_uint)
        };

        if host_c.is_null() {
            Err("Could not initialize host")
        } else {
            Ok(Host { ffi_handle: host_c })
        }
    }

    pub fn connect(timeout_ms: u32,
                   host_name: String,
                   port: u16,
                   channel_count: u32,
                   incoming_bandwidth: u32,
                   outgoing_bandwidth: u32) -> Result<(Host, Peer), &'static str> {
        let host_c = unsafe {
            ffi::enet_host_create(std::ptr::null(),
                                  1, // 1 outgoing connection
                                  channel_count as size_t,
                                  incoming_bandwidth as c_uint,
                                  outgoing_bandwidth as c_uint)
        };

        if host_c.is_null() {
            return Err("Could not initialize host");
        }

        let host = Host { ffi_handle: host_c };
        let mut address = ffi::ENetAddress {
            host: 0,
            port: port
        };
        let host_name_c = std::ffi::CString::new(host_name).unwrap();

        let peer_c = unsafe {
            let address_ptr = &mut address as *mut ffi::ENetAddress;
            ffi::enet_address_set_host(address_ptr, host_name_c.as_ptr());
            ffi::enet_host_connect(host_c, address_ptr, channel_count as libc::size_t, 0)
        };

        if peer_c.is_null() {
            return Err("Could not initialize peer");
        }

        match host.service(timeout_ms) {
            Ok(Event::Connect(_)) =>
                Ok((host, Peer { ffi_handle: peer_c })),
            _ =>
                Err("Could not connect")
        }
    }

    pub fn service(&self, timeout_ms: u32) -> Result<Event, &'static str> {
        let mut ffi_event = ffi::ENetEvent {
            etype: 0,
            peer: std::ptr::null_mut(),
            channelID: 0,
            data: 0,
            packet: std::ptr::null_mut()
        };

        let result: c_int = unsafe {
            let p_evt = &mut ffi_event as *mut _ as *mut c_void;
            ffi::enet_host_service(self.ffi_handle, p_evt, timeout_ms as c_uint)
        };

        if 0 > result {
            Err("Could not service the host")
        } else if 0 == result {
            Ok(Event::None)
        } else {
            let peer = Peer { ffi_handle: ffi_event.peer };

            match ffi_event.etype {
                ffi::ENET_EVENT_TYPE_CONNECT =>
                    Ok(Event::Connect(peer)),
                ffi::ENET_EVENT_TYPE_DISCONNECT =>
                    Ok(Event::Disconnect(peer)),
                ffi::ENET_EVENT_TYPE_RECEIVE =>
                    Ok(Event::Receive(peer, Packet { ffi_handle: ffi_event.packet })),
                _ =>
                    Err("Invalid event")
            }
        }
    }

    pub fn flush(&self) {
        unsafe {
            ffi::enet_host_flush(self.ffi_handle)
        }
    }
}

impl Peer {
    pub fn send(&self, data: &[u8], flags: libc::c_uint, channel_id: u16) {
        let repr = data.repr();

        unsafe {
            let data_ptr = repr.data as *mut libc::c_void;
            let data_len = repr.len as libc::size_t;
            let packet = ffi::enet_packet_create(data_ptr, data_len, flags);
            ffi::enet_peer_send(self.ffi_handle, channel_id, packet);
        }
    }
}

impl Drop for Host {
    fn drop(&mut self) {
        unsafe { ffi::enet_host_destroy(self.ffi_handle); }
    }
}

impl Drop for Packet {
    fn drop(&mut self) {
        unsafe { ffi::enet_packet_destroy(self.ffi_handle); }
    }
}
<commit_msg>Use String instead of &'static str for error messages. Give access to the user data stored in ENetPeer. Add Packet method to get data.<commit_after>/*
 *           _           _            _             _          _
 *          /\ \        /\ \         /\ \     _    /\ \       /\ \
 *         /  \ \      /  \ \       /  \ \   /\_\ /  \ \      \_\ \
 *        / /\ \ \    / /\ \ \     / /\ \ \_/ / // /\ \ \     /\__ \
 *       / / /\ \_\  / / /\ \_\   / / /\ \___/ // / /\ \_\   / /_ \ \
 *      / / /_/ / / / /_/_ \/_/  / / /  \/____// /_/_ \/_/  / / /\ \ \
 *     / / /__\/ / / /____/\    / / /    / / // /____/\    / / /  \/_/
 *    / / /_____/ / /\____\/   / / /    / / // /\____\/   / / /
 *   / / /\ \ \  / / /______  / / /    / / // / /______  / / /
 *  / / /  \ \ \/ / /_______\/ / /    / / // / /_______\/_/ /
 *  \/_/    \_\/\/__________/\/_/     \/_/ \/__________/\_\/
 *
 *
 * This file is released under terms described in the LICENSE file at
 * the top directory of this repository.
 *
 * Please contact Mark McDermott <mark.elias.mcdermott@gmail.com> or
 * the current maintainer of this software if you do not have a copy of
 * the license file.
 *
 * -------------------------------------------------------------------
 *  REnet is a rust language wrapper for the ENet networking library
 *
 *  TODO List
 * -------------------------------------------------------------------
 */

#![feature(libc)]
#![feature(raw)]
extern crate libc;

use libc::{c_uint,c_void,size_t,c_int};
use std::raw::Repr;

#[allow(non_snake_case)]
pub mod ffi;

pub fn initialize() -> Result<(), i32>  {
    unsafe {
        match ffi::enet_initialize() {
            0    => Ok(()),
            code => Err(code)
        }
    }
}

pub fn deinitialize() {
    unsafe {
        ffi::enet_deinitialize();
    }
}

pub fn linked_version() -> u32 {
    unsafe {
        ffi::enet_linked_version() as u32
    }
}

pub struct Host {
    ffi_handle : *mut c_void,
}

pub struct Peer {
    ffi_handle : *mut ffi::ENetPeer,
}

pub struct Packet {
    ffi_handle: *mut ffi::ENetPacket
}

/*
 * ------------------------------------------------------------------
 * Event: enum of event types*
 * ------------------------------------------------------------------
 */
pub enum Event {
    Connect(Peer),
    Receive(Peer,Packet),
    Disconnect(Peer),
    None,
}

/*
 * ------------------------------------------------------------------
 * Host object: a wrapper around ENetHost*
 * ------------------------------------------------------------------
 */

impl Host {
    pub fn new_server(port: u16,
                      peer_count: u32,
                      channel_count: u32,
                      incoming_bandwidth: u32,
                      outgoing_bandwidth: u32) -> Result<Host, String> {
        let address = ffi::ENetAddress {
            host: ffi::ENET_HOST_ANY,
            port: port
        };

        let host_c = unsafe {
            ffi::enet_host_create(&address as *const ffi::ENetAddress,
                                  peer_count as size_t,
                                  channel_count as size_t,
                                  incoming_bandwidth as c_uint,
                                  outgoing_bandwidth as c_uint)
        };

        if host_c.is_null() {
            Err("Could not initialize host".to_string())
        } else {
            Ok(Host { ffi_handle: host_c })
        }
    }

    pub fn connect(timeout_ms: u32,
                   host_name: String,
                   port: u16,
                   channel_count: u32,
                   incoming_bandwidth: u32,
                   outgoing_bandwidth: u32) -> Result<(Host, Peer), String> {
        let host_c = unsafe {
            ffi::enet_host_create(std::ptr::null(),
                                  1, // 1 outgoing connection
                                  channel_count as size_t,
                                  incoming_bandwidth as c_uint,
                                  outgoing_bandwidth as c_uint)
        };

        if host_c.is_null() {
            return Err("Could not initialize host".to_string());
        }

        let host = Host { ffi_handle: host_c };
        let mut address = ffi::ENetAddress {
            host: 0,
            port: port
        };
        let host_name_c = std::ffi::CString::new(host_name).unwrap();

        let peer_c = unsafe {
            let address_ptr = &mut address as *mut ffi::ENetAddress;
            ffi::enet_address_set_host(address_ptr, host_name_c.as_ptr());
            ffi::enet_host_connect(host_c, address_ptr, channel_count as libc::size_t, 0)
        };

        if peer_c.is_null() {
            return Err("Could not initialize peer".to_string());
        }

        match host.service(timeout_ms) {
            Ok(Event::Connect(_)) =>
                Ok((host, Peer { ffi_handle: peer_c })),
            _ =>
                Err("Could not connect".to_string())
        }
    }

    pub fn service(&self, timeout_ms: u32) -> Result<Event, String> {
        let mut ffi_event = ffi::ENetEvent {
            etype: 0,
            peer: std::ptr::null_mut(),
            channelID: 0,
            data: 0,
            packet: std::ptr::null_mut()
        };

        let result: c_int = unsafe {
            let p_evt = &mut ffi_event as *mut _ as *mut c_void;
            ffi::enet_host_service(self.ffi_handle, p_evt, timeout_ms as c_uint)
        };

        if 0 > result {
            Err("Could not service the host".to_string())
        } else if 0 == result {
            Ok(Event::None)
        } else {
            let peer = Peer { ffi_handle: ffi_event.peer };

            match ffi_event.etype {
                ffi::ENET_EVENT_TYPE_CONNECT =>
                    Ok(Event::Connect(peer)),
                ffi::ENET_EVENT_TYPE_DISCONNECT =>
                    Ok(Event::Disconnect(peer)),
                ffi::ENET_EVENT_TYPE_RECEIVE =>
                    Ok(Event::Receive(peer, Packet { ffi_handle: ffi_event.packet })),
                _ =>
                    Err("Invalid event".to_string())
            }
        }
    }

    pub fn flush(&self) {
        unsafe {
            ffi::enet_host_flush(self.ffi_handle)
        }
    }
}

impl Peer {
    pub fn send(&self, data: &[u8], flags: libc::c_uint, channel_id: u16) {
        let repr = data.repr();

        unsafe {
            let data_ptr = repr.data as *mut libc::c_void;
            let data_len = repr.len as libc::size_t;
            let packet = ffi::enet_packet_create(data_ptr, data_len, flags);
            ffi::enet_peer_send(self.ffi_handle, channel_id, packet);
        }
    }

    pub fn set_user_data(&self, data: *mut libc::c_void) {
        unsafe {
            (*self.ffi_handle).data = data;
        }
    }

    pub fn get_user_data(&self) -> *mut libc::c_void {
        unsafe {
            (*self.ffi_handle).data
        }
    }
}

impl Packet {
    pub fn data(&self) -> &[u8] {
        unsafe {
            std::slice::from_raw_parts((*self.ffi_handle).data as *const u8,
                (*self.ffi_handle).dataLength as usize)
        }
    }
}

impl Drop for Host {
    fn drop(&mut self) {
        unsafe { ffi::enet_host_destroy(self.ffi_handle); }
    }
}

impl Drop for Packet {
    fn drop(&mut self) {
        unsafe { ffi::enet_packet_destroy(self.ffi_handle); }
    }
}
<|endoftext|>


<commit_before>extern crate time;
extern crate num;
extern crate byteorder;
use num::BigUint;
use time::Timespec;
use byteorder::{LittleEndian, WriteBytesExt};

#[derive(Debug)]
enum FlakeError {
    ClockIsRunningBackwards
}

trait HasFlakes {
	fn update(&mut self) -> Result<(), FlakeError>;
	fn get_id(&mut self) -> BigUint;
}

struct Flaker {
    identifier: Vec<u8>,
    epoch: u64,
    last_generated_time_ms: u64,
    counter: u32,
}

impl Flaker {
	pub fn new_from_identifier(identifier: Vec<u8>) -> Flaker {
		let default_epoch_ts = Timespec::new(0, 0);
		let default_epoch_ms = default_epoch_ts.sec as u64 + default_epoch_ts.nsec as u64 / 1000 / 1000;

		Flaker::new(identifier, default_epoch_ms, false)
	}

	pub fn new(identifier: Vec<u8>, epoch: u64, little_endian: bool) -> Flaker {
		// TODO : check that identifier has a length of 6
		let mut l_identifier = identifier.clone();

		if !little_endian {
			l_identifier.reverse();
		}

		Flaker { identifier: l_identifier,
				 epoch: epoch,
				 last_generated_time_ms: Flaker::current_time_in_ms(),
				 counter: 0
			   }
	}

	fn current_time_in_ms() -> u64 {
		let now = time::now();
		let now_ts = now.to_timespec();

		now_ts.sec as u64 + now_ts.nsec as u64 / 1000 / 1000
	}
}

impl HasFlakes for Flaker {
	fn update(&mut self) -> Result<(), FlakeError> {
		let current_time_in_ms = Flaker::current_time_in_ms();

		if self.last_generated_time_ms > current_time_in_ms {
			return Result::Err(FlakeError::ClockIsRunningBackwards);
		}

		if self.last_generated_time_ms < current_time_in_ms {
			self.counter = 0;
		}
		else {
			self.counter += 1;
		}

		self.last_generated_time_ms = current_time_in_ms;

		Ok(())
	}

	fn get_id(&mut self) -> BigUint {
		self.update();

		let mut bytes = Vec::new();

		bytes.push(self.counter as u8);
		bytes.push((self.counter >> 8) as u8);

		// next 6 bytes are the worker id
		for i in &self.identifier {
			bytes.push(*i);
		}

		let mut wtr = vec![];

		wtr.write_u64::<LittleEndian>(self.last_generated_time_ms).unwrap();

		for w in wtr {
			bytes.push(w);
		}

		BigUint::from_bytes_le(&bytes)
	}
}

#[test]
fn ids_change_over_time() {
	let mut f1 = Flaker::new_from_identifier(vec![0, 1, 2, 3, 4, 5]);
	let id1 = f1.get_id();
	std::thread::sleep_ms(50);
	let id2 = f1.get_id();

	println!("{} < {}", id1, id2);

	assert!(id1 < id2);
}

#[test]
fn ids_change_quickly() {
	let mut f1 = Flaker::new_from_identifier(vec![0, 1, 2, 3, 4, 5]);

	let id3 = f1.get_id();
	let id4 = f1.get_id();

	assert!(id3 < id4);
}
<commit_msg>removing deprecated sleep_ms, adding TODOs, cleaning up whitespace<commit_after>extern crate time;
extern crate num;
extern crate byteorder;
use num::BigUint;
use time::Timespec;
use byteorder::{LittleEndian, WriteBytesExt};

#[derive(Debug)]
enum FlakeError {
    ClockIsRunningBackwards
}

trait HasFlakes {
	fn update(&mut self) -> Result<(), FlakeError>;
	fn get_id(&mut self) -> BigUint;
}

struct Flaker {
    identifier: Vec<u8>,
    epoch: u64,
    last_generated_time_ms: u64,
    counter: u32,
}

impl Flaker {
	pub fn new_from_identifier(identifier: Vec<u8>) -> Flaker {
		let default_epoch_ts = Timespec::new(0, 0);
		let default_epoch_ms = default_epoch_ts.sec as u64 + (default_epoch_ts.nsec as u64 / 1000 / 1000);

		Flaker::new(identifier, default_epoch_ms, false)
	}

	pub fn new(identifier: Vec<u8>, epoch: u64, little_endian: bool) -> Flaker {
		// TODO : check that identifier has a length of 6
		let mut l_identifier = identifier.clone();

		if !little_endian {
			l_identifier.reverse();
		}

		Flaker { identifier: l_identifier,
				 epoch: epoch,
				 last_generated_time_ms: Flaker::current_time_in_ms(),
				 counter: 0
			   }
	}

	fn current_time_in_ms() -> u64 {
		let now = time::now();
		let now_ts = now.to_timespec();

        // TODO should be `now_ts` minus `epoch`
        // changing this means we should rename this function, too
		now_ts.sec as u64 + (now_ts.nsec as u64 / 1000 / 1000)
	}
}

impl HasFlakes for Flaker {
	fn update(&mut self) -> Result<(), FlakeError> {
		let current_time_in_ms = Flaker::current_time_in_ms();

		if self.last_generated_time_ms > current_time_in_ms {
			return Result::Err(FlakeError::ClockIsRunningBackwards);
		}

		if self.last_generated_time_ms < current_time_in_ms {
			self.counter = 0;
		}
		else {
			self.counter += 1;
		}

		self.last_generated_time_ms = current_time_in_ms;

		Ok(())
	}

    // TODO signature needs to be changed to return a result
	fn get_id(&mut self) -> BigUint {
        // TODO check this for OK-ness
		self.update();

        // Create a new vec of bytes
		let mut bytes = Vec::new();

        // push the counter into bytes
        // TODO why did I use a u32 for counter if I only use 16 bits of it?
		bytes.push(self.counter as u8);
		bytes.push((self.counter >> 8) as u8);

		// next 6 bytes are the worker id
		for i in &self.identifier {
			bytes.push(*i);
		}

		let mut wtr = vec![];

		wtr.write_u64::<LittleEndian>(self.last_generated_time_ms).unwrap();

		for w in wtr {
			bytes.push(w);
		}

		BigUint::from_bytes_le(&bytes)
	}
}

#[test]
fn ids_change_over_time() {
	let mut f1 = Flaker::new_from_identifier(vec![0, 1, 2, 3, 4, 5]);
	let id1 = f1.get_id();
	std::thread::sleep(Duration::from_millis(50));
	let id2 = f1.get_id();

	println!("{} < {}", id1, id2);

	assert!(id1 < id2);
}

#[test]
fn ids_change_quickly() {
	let mut f1 = Flaker::new_from_identifier(vec![0, 1, 2, 3, 4, 5]);

	let id3 = f1.get_id();
	let id4 = f1.get_id();

	assert!(id3 < id4);
}
<|endoftext|>


<commit_before>//! A library for interacting with Twitter.
//!
//! Please see [the repository][] and its enclosed examples for tips on working with this library
//! while it's still in progress.
//!
//! [the repository]: https://github.com/icesoldier/twitter-rs

#![warn(missing_docs)]
#![warn(unused_extern_crates)]
#![warn(unused_qualifications)]

#[macro_use] extern crate hyper;
extern crate url;
extern crate time;
extern crate rand;
extern crate crypto;
extern crate rustc_serialize;
extern crate mime;

mod auth;
pub mod error;
pub mod user;
mod links;
mod common;

pub use auth::{Token, request_token, authorize_url, access_token};
pub use common::{Response, TwitterErrors, TwitterErrorCode, UserID};
<commit_msg>provide overview of auth process for docs<commit_after>//! A library for interacting with Twitter.
//!
//! Please see [the repository][] and its enclosed examples for tips on working with this library
//! while it's still in progress.
//!
//! [the repository]: https://github.com/icesoldier/twitter-rs
//!
//! ## Getting Started
//!
//! The very first thing you'll need to do to get access to the Twitter API is to head to
//! [Twitter's Application Manager][twitter-apps] and create an app. Once you've done that, there
//! are two sets of keys immediately available to you. First are the "consumer key" and "consumer
//! secret", that are used to represent you as the application author when signing requests. These
//! keys are given to every single API call regardless of permission level. Related are an "access
//! token" and "access token secret", that can be used to skip the authentication steps if you're
//! only interacting with your own account or with no account in particular. Generally, if you want
//! to read or write to a particular user's stream, you'll need to request authorization and get an
//! access token to work on their behalf.
//!
//! [twitter-apps]: https://apps.twitter.com/
//!
//! The process to get an access token for a specific user (with this library) has three basic
//! steps:
//!
//! 1. Log your request with Twitter by getting a [request token][].
//! 2. Direct the user to grant permission to your application by sending them to an
//!    [authenticate][] or [authorize][] URL, depending on the nature of your app.
//! 3. Convert the verifier given by the permission request into an [access token][].
//!
//! [request token]: fn.request_token.html
//! [authorize]: fn.authorize_url.html
//! [authenticate]: fn.authenticate_url.html
//! [access token]: fn.access_token.html
//!
//! The process changes some smaller details depending on whether your application is web- or
//! mobile-based, as opposed to desktop-based or in another situation where redirecting users to a
//! web browser and back automatically is difficult or impossible. In the former case where URLs
//! can be used to direct the user into and out of your app, give Twitter a "callback URL" when
//! setting up your request token, and redirect the user to an [authenticate][] URL to grant your
//! app permissions. When the user accepts the request, they will be redirected back to this URL to
//! get back to your app, with the original request token and a verifier given to your app to
//! signify their acceptance.
//!
//! On the other hand, if you can't use the callback URL in this fashion, you can instead use the
//! "PIN-based Auth" version of the flow. In this version, give a "callback URL" of "oob" when
//! setting up your request token, and use an [authorize][] URL. When the user grants the
//! permissions request in this fashion, they are given a numeric PIN that can be given back to
//! your app to use as a verifier.
//!
//! Either way, when you have a "verifier" from either of these methods, you can use your Tokens
//! from earlier in the process with that verifier to request an [access token][]. This access
//! token can then be saved and cached for future use.

#![warn(missing_docs)]
#![warn(unused_extern_crates)]
#![warn(unused_qualifications)]

#[macro_use] extern crate hyper;
extern crate url;
extern crate time;
extern crate rand;
extern crate crypto;
extern crate rustc_serialize;
extern crate mime;

mod auth;
pub mod error;
pub mod user;
mod links;
mod common;

pub use auth::{Token, request_token, authorize_url, access_token};
pub use common::{Response, TwitterErrors, TwitterErrorCode, UserID};
<|endoftext|>


<commit_before>//! A library for build scripts to compile custom C code
//!
//! This library is intended to be used as a `build-dependencies` entry in
//! `Cargo.toml`:
//!
//! ```toml
//! [build-dependencies]
//! gcc = "0.2"
//! ```
//!
//! The purpose of this crate is to provide the utility functions necessary to
//! compile C code into a static archive which is then linked into a Rust crate.
//! The top-level `compile_library` function serves as a convenience and more
//! advanced configuration is available through the `Config` builder.
//!
//! This crate will automatically detect situations such as cross compilation or
//! other environment variables set by Cargo and will build code appropriately.
//!
//! # Examples
//!
//! Use the default configuration:
//!
//! ```no_run
//! extern crate gcc;
//!
//! fn main() {
//!     gcc::compile_library("libfoo.a", &["src/foo.c"]);
//! }
//! ```
//!
//! Use more advanced configuration:
//!
//! ```no_run
//! extern crate gcc;
//!
//! fn main() {
//!     gcc::Config::new()
//!                 .file("src/foo.c")
//!                 .define("FOO", Some("bar"))
//!                 .include(Path::new("src"))
//!                 .compile("libfoo.a");
//! }
//! ```

#![feature(io, path, env, collections)]

use std::env;
use std::old_io::{self, Command};
use std::old_io::process::InheritFd;

/// Extra configuration to pass to gcc.
pub struct Config {
    include_directories: Vec<Path>,
    definitions: Vec<(String, Option<String>)>,
    objects: Vec<Path>,
    flags: Vec<String>,
    files: Vec<Path>,
}

fn getenv(v: &str) -> Option<String> {
    let r = env::var(v).ok();
    println!("{} = {:?}", v, r);
    r
}

fn getenv_unwrap(v: &str) -> String {
    match getenv(v) {
        Some(s) => s,
        None => fail(&format!("environment variable `{}` not defined", v)),
    }
}

/// Compile a library from the given set of input C files.
///
/// This will simply compile all files into object files and then assemble them
/// into the output. This will read the standard environment variables to detect
/// cross compilations and such.
///
/// This function will also print all metadata on standard output for Cargo.
///
/// # Example
///
/// ```no_run
/// gcc::compile_library("libfoo.a", &["foo.c", "bar.c"]);
/// ```
pub fn compile_library(output: &str, files: &[&str]) {
    let mut c = Config::new();
    for f in files.iter() {
        c.file(*f);
    }
    c.compile(output)
}

impl Config {
    /// Construct a new instance of a blank set of configuration.
    ///
    /// This builder is finished with the `compile` function.
    pub fn new() -> Config {
        Config {
            include_directories: Vec::new(),
            definitions: Vec::new(),
            objects: Vec::new(),
            flags: Vec::new(),
            files: Vec::new(),
        }
    }

    /// Add a directory to the `-I` or include path for headers
    pub fn include(&mut self, dir: Path) -> &mut Config {
        self.include_directories.push(dir);
        self
    }

    /// Specify a `-D` variable with an optional value.
    pub fn define(&mut self, var: &str, val: Option<&str>) -> &mut Config {
        self.definitions.push((var.to_string(), val.map(|s| s.to_string())));
        self
    }

    /// Add an arbitrary object file to link in
    pub fn object(&mut self, obj: Path) -> &mut Config {
        self.objects.push(obj);
        self
    }

    /// Add an arbitrary flag to the invocation of the compiler
    pub fn flag(&mut self, flag: &str) -> &mut Config {
        self.flags.push(flag.to_string());
        self
    }

    /// Add a file which will be compiled
    pub fn file(&mut self, p: &str) -> &mut Config {
        self.files.push(Path::new(p));
        self
    }

    /// Run the compiler, generating the file `output`
    ///
    /// The name `output` must begin with `lib` and end with `.a`
    pub fn compile(&self, output: &str) {
        assert!(output.starts_with("lib"));
        assert!(output.ends_with(".a"));

        let target = getenv_unwrap("TARGET");
        let opt_level = getenv_unwrap("OPT_LEVEL");
        let profile = getenv_unwrap("PROFILE");
        println!("{} {}", profile, opt_level);

        let mut cmd = Command::new(gcc(&target));
        cmd.arg(format!("-O{}", opt_level));
        cmd.arg("-c");
        cmd.arg("-ffunction-sections").arg("-fdata-sections");
        cmd.args(&cflags());

        if target.contains("-ios") {
            cmd.args(&ios_flags(&target));
        } else {
            if target.contains("windows") {
                cmd.arg("-mwin32");
            }

            if target.contains("i686") {
                cmd.arg("-m32");
            } else if target.contains("x86_64") {
                cmd.arg("-m64");
            }

            if !target.contains("i686") {
                cmd.arg("-fPIC");
            }
        }

        for directory in self.include_directories.iter() {
            cmd.arg("-I").arg(directory);
        }

        for flag in self.flags.iter() {
            cmd.arg(flag);
        }

        for &(ref key, ref value) in self.definitions.iter() {
            if let &Some(ref value) = value {
                cmd.arg(format!("-D{}={}", key, value));
            } else {
                cmd.arg(format!("-D{}", key));
            }
        }

        let src = Path::new(getenv_unwrap("CARGO_MANIFEST_DIR"));
        let dst = Path::new(getenv_unwrap("OUT_DIR"));
        let mut objects = Vec::new();
        for file in self.files.iter() {
            let obj = dst.join(file).with_extension("o");
            std::old_io::fs::mkdir_recursive(&obj.dir_path(),
                                             std::old_io::USER_RWX).unwrap();
            run(cmd.clone().arg(src.join(file)).arg("-o").arg(&obj),
                &gcc(&target));
            objects.push(obj);
        }

        run(Command::new(ar(&target)).arg("crus")
                                     .arg(dst.join(output))
                                     .args(&objects)
                                     .args(&self.objects),
            &ar(&target));
        println!("cargo:rustc-flags=-L native={} -l static={}",
                 dst.display(), output.slice(3, output.len() - 2));
    }
}

fn run(cmd: &mut Command, program: &str) {
    println!("running: {:?}", cmd);
    let status = match cmd.stdout(InheritFd(1)).stderr(InheritFd(2)).status() {
        Ok(status) => status,
        Err(ref e) if e.kind == old_io::FileNotFound => {
            fail(&format!("failed to execute command: {}\nis `{}` not installed?",
                          e, program));
        }
        Err(e) => fail(&format!("failed to execute command: {}", e)),
    };
    if !status.success() {
        fail(&format!("command did not execute successfully, got: {}", status));
    }
}

fn get_var(var_base: &str) -> Result<String, String> {
    let target = getenv_unwrap("TARGET");
    let host = getenv_unwrap("HOST");
    let kind = if host == target {"HOST"} else {"TARGET"};
    let target_u = target.replace("-", "_");
    let res = getenv(&format!("{}_{}", var_base, target))
        .or_else(|| getenv(&format!("{}_{}", var_base, target_u)))
        .or_else(|| getenv(&format!("{}_{}", kind, var_base)))
        .or_else(|| getenv(var_base));

    match res {
        Some(res) => Ok(res),
        None => Err("Could not get environment variable".to_string()),
    }
}

fn gcc(target: &str) -> String {
    let is_android = target.find_str("android").is_some();

    get_var("CC").unwrap_or(if cfg!(windows) {
        "gcc".to_string()
    } else if is_android {
        format!("{}-gcc", target)
    } else {
        "cc".to_string()
    })
}

fn ar(target: &str) -> String {
    let is_android = target.find_str("android").is_some();

    get_var("AR").unwrap_or(if is_android {
        format!("{}-ar", target)
    } else {
        "ar".to_string()
    })
}

fn cflags() -> Vec<String> {
    get_var("CFLAGS").unwrap_or(String::new())
       .words().map(|s| s.to_string())
       .collect()
}

fn ios_flags(target: &str) -> Vec<String> {
    enum ArchSpec {
        Device(&'static str),
        Simulator(&'static str),
    }

    let mut res = Vec::new();

    let arch = target.split('-').nth(0).expect("expected target in format `arch-vendor-os`");
    let arch = match arch {
        "arm" | "armv7" | "thumbv7" => ArchSpec::Device("armv7"),
        "armv7s" | "thumbv7s" => ArchSpec::Device("armv7s"),
        "arm64" | "aarch64" => ArchSpec::Device("aarch64"),
        "i386" | "i686" => ArchSpec::Simulator("-m32"),
        "x86_64" => ArchSpec::Simulator("-m64"),
        _ => unreachable!("Unknown arch for iOS target")
    };

    let sdk = match arch {
        ArchSpec::Device(arch) => {
            res.push("-arch".to_string());
            res.push(arch.to_string());
            "iphoneos"
        },
        ArchSpec::Simulator(arch) => {
            res.push(arch.to_string());
            "iphonesimulator"
        }
    };

    println!("Detecting iOS SDK path for {}", sdk);
    let sdk_path = Command::new("xcrun")
        .arg("--show-sdk-path")
        .arg("--sdk")
        .arg(sdk)
        .stderr(InheritFd(2))
        .output()
        .unwrap()
        .output;

    let sdk_path = String::from_utf8(sdk_path).unwrap();

    res.push("-isysroot".to_string());
    res.push(sdk_path.trim().to_string());

    res
}

fn fail(s: &str) -> ! {
    println!("{}", s);
    env::set_exit_status(1);
    old_io::stdio::set_stderr(Box::new(old_io::util::NullWriter));
    panic!()
}
<commit_msg>iOS: fixed aarch64 compilation<commit_after>//! A library for build scripts to compile custom C code
//!
//! This library is intended to be used as a `build-dependencies` entry in
//! `Cargo.toml`:
//!
//! ```toml
//! [build-dependencies]
//! gcc = "0.2"
//! ```
//!
//! The purpose of this crate is to provide the utility functions necessary to
//! compile C code into a static archive which is then linked into a Rust crate.
//! The top-level `compile_library` function serves as a convenience and more
//! advanced configuration is available through the `Config` builder.
//!
//! This crate will automatically detect situations such as cross compilation or
//! other environment variables set by Cargo and will build code appropriately.
//!
//! # Examples
//!
//! Use the default configuration:
//!
//! ```no_run
//! extern crate gcc;
//!
//! fn main() {
//!     gcc::compile_library("libfoo.a", &["src/foo.c"]);
//! }
//! ```
//!
//! Use more advanced configuration:
//!
//! ```no_run
//! extern crate gcc;
//!
//! fn main() {
//!     gcc::Config::new()
//!                 .file("src/foo.c")
//!                 .define("FOO", Some("bar"))
//!                 .include(Path::new("src"))
//!                 .compile("libfoo.a");
//! }
//! ```

#![feature(io, path, env, collections)]

use std::env;
use std::old_io::{self, Command};
use std::old_io::process::InheritFd;

/// Extra configuration to pass to gcc.
pub struct Config {
    include_directories: Vec<Path>,
    definitions: Vec<(String, Option<String>)>,
    objects: Vec<Path>,
    flags: Vec<String>,
    files: Vec<Path>,
}

fn getenv(v: &str) -> Option<String> {
    let r = env::var(v).ok();
    println!("{} = {:?}", v, r);
    r
}

fn getenv_unwrap(v: &str) -> String {
    match getenv(v) {
        Some(s) => s,
        None => fail(&format!("environment variable `{}` not defined", v)),
    }
}

/// Compile a library from the given set of input C files.
///
/// This will simply compile all files into object files and then assemble them
/// into the output. This will read the standard environment variables to detect
/// cross compilations and such.
///
/// This function will also print all metadata on standard output for Cargo.
///
/// # Example
///
/// ```no_run
/// gcc::compile_library("libfoo.a", &["foo.c", "bar.c"]);
/// ```
pub fn compile_library(output: &str, files: &[&str]) {
    let mut c = Config::new();
    for f in files.iter() {
        c.file(*f);
    }
    c.compile(output)
}

impl Config {
    /// Construct a new instance of a blank set of configuration.
    ///
    /// This builder is finished with the `compile` function.
    pub fn new() -> Config {
        Config {
            include_directories: Vec::new(),
            definitions: Vec::new(),
            objects: Vec::new(),
            flags: Vec::new(),
            files: Vec::new(),
        }
    }

    /// Add a directory to the `-I` or include path for headers
    pub fn include(&mut self, dir: Path) -> &mut Config {
        self.include_directories.push(dir);
        self
    }

    /// Specify a `-D` variable with an optional value.
    pub fn define(&mut self, var: &str, val: Option<&str>) -> &mut Config {
        self.definitions.push((var.to_string(), val.map(|s| s.to_string())));
        self
    }

    /// Add an arbitrary object file to link in
    pub fn object(&mut self, obj: Path) -> &mut Config {
        self.objects.push(obj);
        self
    }

    /// Add an arbitrary flag to the invocation of the compiler
    pub fn flag(&mut self, flag: &str) -> &mut Config {
        self.flags.push(flag.to_string());
        self
    }

    /// Add a file which will be compiled
    pub fn file(&mut self, p: &str) -> &mut Config {
        self.files.push(Path::new(p));
        self
    }

    /// Run the compiler, generating the file `output`
    ///
    /// The name `output` must begin with `lib` and end with `.a`
    pub fn compile(&self, output: &str) {
        assert!(output.starts_with("lib"));
        assert!(output.ends_with(".a"));

        let target = getenv_unwrap("TARGET");
        let opt_level = getenv_unwrap("OPT_LEVEL");
        let profile = getenv_unwrap("PROFILE");
        println!("{} {}", profile, opt_level);

        let mut cmd = Command::new(gcc(&target));
        cmd.arg(format!("-O{}", opt_level));
        cmd.arg("-c");
        cmd.arg("-ffunction-sections").arg("-fdata-sections");
        cmd.args(&cflags());

        if target.contains("-ios") {
            cmd.args(&ios_flags(&target));
        } else {
            if target.contains("windows") {
                cmd.arg("-mwin32");
            }

            if target.contains("i686") {
                cmd.arg("-m32");
            } else if target.contains("x86_64") {
                cmd.arg("-m64");
            }

            if !target.contains("i686") {
                cmd.arg("-fPIC");
            }
        }

        for directory in self.include_directories.iter() {
            cmd.arg("-I").arg(directory);
        }

        for flag in self.flags.iter() {
            cmd.arg(flag);
        }

        for &(ref key, ref value) in self.definitions.iter() {
            if let &Some(ref value) = value {
                cmd.arg(format!("-D{}={}", key, value));
            } else {
                cmd.arg(format!("-D{}", key));
            }
        }

        let src = Path::new(getenv_unwrap("CARGO_MANIFEST_DIR"));
        let dst = Path::new(getenv_unwrap("OUT_DIR"));
        let mut objects = Vec::new();
        for file in self.files.iter() {
            let obj = dst.join(file).with_extension("o");
            std::old_io::fs::mkdir_recursive(&obj.dir_path(),
                                             std::old_io::USER_RWX).unwrap();
            run(cmd.clone().arg(src.join(file)).arg("-o").arg(&obj),
                &gcc(&target));
            objects.push(obj);
        }

        run(Command::new(ar(&target)).arg("crus")
                                     .arg(dst.join(output))
                                     .args(&objects)
                                     .args(&self.objects),
            &ar(&target));
        println!("cargo:rustc-flags=-L native={} -l static={}",
                 dst.display(), output.slice(3, output.len() - 2));
    }
}

fn run(cmd: &mut Command, program: &str) {
    println!("running: {:?}", cmd);
    let status = match cmd.stdout(InheritFd(1)).stderr(InheritFd(2)).status() {
        Ok(status) => status,
        Err(ref e) if e.kind == old_io::FileNotFound => {
            fail(&format!("failed to execute command: {}\nis `{}` not installed?",
                          e, program));
        }
        Err(e) => fail(&format!("failed to execute command: {}", e)),
    };
    if !status.success() {
        fail(&format!("command did not execute successfully, got: {}", status));
    }
}

fn get_var(var_base: &str) -> Result<String, String> {
    let target = getenv_unwrap("TARGET");
    let host = getenv_unwrap("HOST");
    let kind = if host == target {"HOST"} else {"TARGET"};
    let target_u = target.replace("-", "_");
    let res = getenv(&format!("{}_{}", var_base, target))
        .or_else(|| getenv(&format!("{}_{}", var_base, target_u)))
        .or_else(|| getenv(&format!("{}_{}", kind, var_base)))
        .or_else(|| getenv(var_base));

    match res {
        Some(res) => Ok(res),
        None => Err("Could not get environment variable".to_string()),
    }
}

fn gcc(target: &str) -> String {
    let is_android = target.find_str("android").is_some();

    get_var("CC").unwrap_or(if cfg!(windows) {
        "gcc".to_string()
    } else if is_android {
        format!("{}-gcc", target)
    } else {
        "cc".to_string()
    })
}

fn ar(target: &str) -> String {
    let is_android = target.find_str("android").is_some();

    get_var("AR").unwrap_or(if is_android {
        format!("{}-ar", target)
    } else {
        "ar".to_string()
    })
}

fn cflags() -> Vec<String> {
    get_var("CFLAGS").unwrap_or(String::new())
       .words().map(|s| s.to_string())
       .collect()
}

fn ios_flags(target: &str) -> Vec<String> {
    enum ArchSpec {
        Device(&'static str),
        Simulator(&'static str),
    }

    let mut res = Vec::new();

    let arch = target.split('-').nth(0).expect("expected target in format `arch-vendor-os`");
    let arch = match arch {
        "arm" | "armv7" | "thumbv7" => ArchSpec::Device("armv7"),
        "armv7s" | "thumbv7s" => ArchSpec::Device("armv7s"),
        "arm64" | "aarch64" => ArchSpec::Device("arm64"),
        "i386" | "i686" => ArchSpec::Simulator("-m32"),
        "x86_64" => ArchSpec::Simulator("-m64"),
        _ => unreachable!("Unknown arch for iOS target")
    };

    let sdk = match arch {
        ArchSpec::Device(arch) => {
            res.push("-arch".to_string());
            res.push(arch.to_string());
            "iphoneos"
        },
        ArchSpec::Simulator(arch) => {
            res.push(arch.to_string());
            "iphonesimulator"
        }
    };

    println!("Detecting iOS SDK path for {}", sdk);
    let sdk_path = Command::new("xcrun")
        .arg("--show-sdk-path")
        .arg("--sdk")
        .arg(sdk)
        .stderr(InheritFd(2))
        .output()
        .unwrap()
        .output;

    let sdk_path = String::from_utf8(sdk_path).unwrap();

    res.push("-isysroot".to_string());
    res.push(sdk_path.trim().to_string());

    res
}

fn fail(s: &str) -> ! {
    println!("{}", s);
    env::set_exit_status(1);
    old_io::stdio::set_stderr(Box::new(old_io::util::NullWriter));
    panic!()
}
<|endoftext|>


<commit_before>//! This crate only provides the `MaybeOwned` enum
//!
//! Take a look at it's documentation for more information.
//!
#![warn(missing_docs)]
use std::convert::From;
use std::clone::Clone;
use std::ops::Deref;
use std::default::Default;

use self::MaybeOwned::*;

/// This type provides a way to store data to which you either have a
/// reference to or which you do own.
///
/// It provides `From<T>`, `From<&'a T>` implementations and, in difference
/// to `Cow` does _not_ require `ToOwned` to be implemented which makes it
/// compatible with non cloneable data, as a draw back of this it does not
/// know about `ToOwned`. As a consequence of it can't know that `&str` should
/// be the borrowed version of `String` and not `&String` this is especially
/// bad wrt. `Box` as the borrowed version of `Box<T>` would be `&Box<T>`.
///
/// While this crate has some drawbacks compared to `Cow` is has the benefit,
/// that it works with Types which neither implement `Clone` nor `ToOwned`.
/// Another benefit lies in the ability to write API functions which accept
/// a generic parameter `E: Into<MaybeOwned<'a, T>>` as the API consumer can
/// pass `T`, `&'a T` and `MaybeOwned<'a, T>` as argument, without requiring
/// a explicit `Cow::Onwed` or a split into two functions one accepting
/// owed and the other borrowed values.
///
/// # Alternatives
///
/// If you mainly have values implementing `ToOwned` like `&str`/`String`, `Path`/`PathBuf` or
/// `&[T]`/`Vec<T>` using `std::borrow::Cow` might be preferable.
///
/// If you want to be able to treat `&T`, `&mut T`, `Box<T>` and `Arc<T>` the same
/// consider using [`reffers::rbma::RBMA`](https://docs.rs/reffers)
/// (through not all types/platforms are supported because
/// as it relies on the fact that for many pointers the lowest two bits are 0, and stores
/// the discriminant in them, nevertheless this is can only be used with 32bit-aligned data,
/// e.g. using a &u8 _might_ fail). RBMA also allows you to recover a `&mut T` if it was created
/// from `Box<T>`, `&mut T` or a unique `Arc`.
///
///
/// # Examples
///
/// ```
/// # use maybe_owned::MaybeOwned;
/// struct PseudoBigData(u8);
/// fn pseudo_register_fn<'a, E>(_val: E) where E: Into<MaybeOwned<'a, PseudoBigData>> { }
///
/// let data = PseudoBigData(12);
/// let data2 = PseudoBigData(13);
///
/// pseudo_register_fn(&data);
/// pseudo_register_fn(&data);
/// pseudo_register_fn(data2);
/// pseudo_register_fn(MaybeOwned::Owned(PseudoBigData(111)));
/// ```
///
/// ```
/// # use maybe_owned::MaybeOwned;
/// #[repr(C)]
/// struct OpaqueFFI {
///     ref1:  * const u8
///     //we also might want to have PhantomData etc.
/// }
///
/// // does not work as it does not implement `ToOwned`
/// // let _ = Cow::Owned(OpaqueFFI { ref1: 0 as *const u8});
///
/// // ok, MaybeOwned can do this (but can't do &str<->String as tread of)
/// let _ = MaybeOwned::Owned(OpaqueFFI { ref1: 0 as *const u8 });
/// ```
#[derive(Debug)]
pub enum MaybeOwned<'a, T: 'a> {
    /// owns T
    Owned(T),
    /// has a reference to T
    Borrowed(&'a T)
}

impl<'a, T> MaybeOwned<'a, T> {

    /// returns true if the data is owned else false
    pub fn is_owned(&self) -> bool {
        match *self {
            Owned(_) => true,
            Borrowed(_) => false
        }
    }
}

impl<'a, T> Deref for MaybeOwned<'a, T> {
    type Target = T;

    fn deref(&self) -> &T {
        match *self {
            Owned(ref v) => v,
            Borrowed(v) => v
        }
    }
}

impl<'a, T> From<&'a T> for MaybeOwned<'a, T> {
    fn from(v: &'a T) -> MaybeOwned<'a, T> {
        Borrowed(v)
    }
}

impl<'a, T> From<T> for MaybeOwned<'a, T> {
    fn from(v: T) -> MaybeOwned<'a, T> {
        Owned(v)
    }
}

impl<'a, T> Default for MaybeOwned<'a, T> where T: Default {
    fn default() -> Self {
        Owned(T::default())
    }
}

impl<'a, T> Clone for MaybeOwned<'a, T> where T: Clone {
    fn clone(&self) -> MaybeOwned<'a, T> {
        match *self {
            Owned(ref v) => Owned(v.clone()),
            Borrowed(v) => Borrowed(v)
        }
    }
}

impl<'a, T> MaybeOwned<'a, T> where T: Clone {

    /// Aquires a mutable reference to owned data.
    ///
    /// Clones data if it is not already owned.
    ///
    /// ## Example
    ///
    /// ```
    /// use maybe_owned::MaybeOwned;
    ///
    /// #[derive(Clone, Debug, PartialEq, Eq)]
    /// struct PseudoBigData(u8);
    ///
    /// let data = PseudoBigData(12);
    ///
    /// let mut maybe: MaybeOwned<PseudoBigData> = (&data).into();
    /// assert_eq!(false, maybe.is_owned());
    ///
    /// {
    ///     let reference = maybe.to_mut();
    ///     assert_eq!(&mut PseudoBigData(12), reference);
    /// }
    /// assert!(maybe.is_owned());
    /// ```
    ///
    pub fn to_mut(&mut self) -> &mut T {
        match *self {
            Owned(ref mut v) => v,
            Borrowed(v) => {
                *self = Owned(v.clone());
                match *self {
                    Owned(ref mut v) => v,
                    Borrowed(..) => unreachable!()
                }
            }

        }
    }

    /// Extracts the owned data.
    ///
    /// If the data is borrowed it is cloned before being extracted.
    pub fn into_owned(self) -> T {
        match self {
            Owned(v) => v,
            Borrowed(v) => v.clone()
        }
    }
}

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

    type TestType = Vec<()>;

    fn with_into<'a, I: Into<MaybeOwned<'a, TestType>>>(v: I) -> MaybeOwned<'a, TestType> {
        v.into()
    }

    #[test]
    fn is_owned() {
        let data = TestType::default();
        assert!(MaybeOwned::Owned(data).is_owned());
    }

    #[test]
    fn into_with_owned() {
        //ty check if it accepts references
        let data = TestType::default();
        assert!(with_into(data).is_owned())

    }
    #[test]
    fn into_with_borrow() {
        //ty check if it accepts references
        let data = TestType::default();
        assert!(!with_into(&data).is_owned());
    }

    #[test]
    fn clone_owned() {
        let maybe = MaybeOwned::<TestType>::default();
        assert!(maybe.clone().is_owned());
    }

    #[test]
    fn clone_borrow() {
        let data = TestType::default();
        let maybe: MaybeOwned<TestType> = (&data).into();
        assert!(!maybe.clone().is_owned());
    }

    #[test]
    fn to_mut() {
        let data = TestType::default();
        let mut maybe: MaybeOwned<TestType> = (&data).into();
        assert!(!maybe.is_owned());
        {
            let _mut_ref = maybe.to_mut();
        }
        assert!(maybe.is_owned());
    }

    #[test]
    fn into_inner() {
        let data = vec![1u32,2];
        let maybe: MaybeOwned<Vec<u32>> = (&data).into();
        assert_eq!(data, maybe.into_owned());
    }

    #[test]
    fn has_default() {
        #[derive(Default)]
        struct TestType(u8);
        let _x: MaybeOwned<TestType> = Default::default();
    }

    #[test]
    fn has_clone() {
        #[derive(Clone)]
        struct TestType(u8);
        let _x  = TestType(12).clone();
    }
}<commit_msg>added extra trait implementations<commit_after>//! This crate only provides the `MaybeOwned` enum
//!
//! Take a look at it's documentation for more information.
//!
#![warn(missing_docs)]
use std::ops::Deref;
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
use std::fmt;

use self::MaybeOwned::*;

/// This type provides a way to store data to which you either have a
/// reference to or which you do own.
///
/// It provides `From<T>`, `From<&'a T>` implementations and, in difference
/// to `Cow` does _not_ require `ToOwned` to be implemented which makes it
/// compatible with non cloneable data, as a draw back of this it does not
/// know about `ToOwned`. As a consequence of it can't know that `&str` should
/// be the borrowed version of `String` and not `&String` this is especially
/// bad wrt. `Box` as the borrowed version of `Box<T>` would be `&Box<T>`.
///
/// While this crate has some drawbacks compared to `Cow` is has the benefit,
/// that it works with Types which neither implement `Clone` nor `ToOwned`.
/// Another benefit lies in the ability to write API functions which accept
/// a generic parameter `E: Into<MaybeOwned<'a, T>>` as the API consumer can
/// pass `T`, `&'a T` and `MaybeOwned<'a, T>` as argument, without requiring
/// a explicit `Cow::Onwed` or a split into two functions one accepting
/// owed and the other borrowed values.
///
/// # Alternatives
///
/// If you mainly have values implementing `ToOwned` like `&str`/`String`, `Path`/`PathBuf` or
/// `&[T]`/`Vec<T>` using `std::borrow::Cow` might be preferable.
///
/// If you want to be able to treat `&T`, `&mut T`, `Box<T>` and `Arc<T>` the same
/// consider using [`reffers::rbma::RBMA`](https://docs.rs/reffers)
/// (through not all types/platforms are supported because
/// as it relies on the fact that for many pointers the lowest two bits are 0, and stores
/// the discriminant in them, nevertheless this is can only be used with 32bit-aligned data,
/// e.g. using a &u8 _might_ fail). RBMA also allows you to recover a `&mut T` if it was created
/// from `Box<T>`, `&mut T` or a unique `Arc`.
///
///
/// # Examples
///
/// ```
/// # use maybe_owned::MaybeOwned;
/// struct PseudoBigData(u8);
/// fn pseudo_register_fn<'a, E>(_val: E) where E: Into<MaybeOwned<'a, PseudoBigData>> { }
///
/// let data = PseudoBigData(12);
/// let data2 = PseudoBigData(13);
///
/// pseudo_register_fn(&data);
/// pseudo_register_fn(&data);
/// pseudo_register_fn(data2);
/// pseudo_register_fn(MaybeOwned::Owned(PseudoBigData(111)));
/// ```
///
/// ```
/// # use maybe_owned::MaybeOwned;
/// #[repr(C)]
/// struct OpaqueFFI {
///     ref1:  * const u8
///     //we also might want to have PhantomData etc.
/// }
///
/// // does not work as it does not implement `ToOwned`
/// // let _ = Cow::Owned(OpaqueFFI { ref1: 0 as *const u8});
///
/// // ok, MaybeOwned can do this (but can't do &str<->String as tread of)
/// let _ = MaybeOwned::Owned(OpaqueFFI { ref1: 0 as *const u8 });
/// ```
#[derive(Debug)]
pub enum MaybeOwned<'a, T: 'a> {
    /// owns T
    Owned(T),
    /// has a reference to T
    Borrowed(&'a T)
}

impl<'a, T> MaybeOwned<'a, T> {

    /// returns true if the data is owned else false
    pub fn is_owned(&self) -> bool {
        match *self {
            Owned(_) => true,
            Borrowed(_) => false
        }
    }
}

impl<'a, T> Deref for MaybeOwned<'a, T> {
    type Target = T;

    fn deref(&self) -> &T {
        match *self {
            Owned(ref v) => v,
            Borrowed(v) => v
        }
    }
}

impl<'a, T> From<&'a T> for MaybeOwned<'a, T> {
    fn from(v: &'a T) -> MaybeOwned<'a, T> {
        Borrowed(v)
    }
}

impl<'a, T> From<T> for MaybeOwned<'a, T> {
    fn from(v: T) -> MaybeOwned<'a, T> {
        Owned(v)
    }
}

impl<'a, T> Default for MaybeOwned<'a, T> where T: Default {
    fn default() -> Self {
        Owned(T::default())
    }
}

impl<'a, T> Clone for MaybeOwned<'a, T> where T: Clone {
    fn clone(&self) -> MaybeOwned<'a, T> {
        match *self {
            Owned(ref v) => Owned(v.clone()),
            Borrowed(v) => Borrowed(v)
        }
    }
}

impl<'a, 'b, A, B> PartialEq<MaybeOwned<'b, B>> for MaybeOwned<'a, A>
    where A: PartialEq<B>
{
    #[inline]
    fn eq(&self, other: &MaybeOwned<'b, B>) -> bool {
        PartialEq::eq(self.deref(), other.deref())
    }
}

impl<'a, T> Eq for MaybeOwned<'a, T> where T: Eq {}

impl<'a, T> PartialOrd for MaybeOwned<'a, T>
    where T: PartialOrd
{
    #[inline]
    fn partial_cmp(&self, other: &MaybeOwned<'a, T>) -> Option<Ordering> {
        PartialOrd::partial_cmp(self.deref(), other.deref())
    }
}

impl<'a, T> Ord for MaybeOwned<'a, T>
    where T: Ord
{
    #[inline]
    fn cmp(&self, other: &MaybeOwned<'a, T>) -> Ordering {
        Ord::cmp(self.deref(), other.deref())
    }
}

impl<'a, T> Hash for MaybeOwned<'a, T>
    where T: Hash
{
    #[inline]
    fn hash<H: Hasher>(&self, state: &mut H) {
        Hash::hash(self.deref(), state)
    }
}

impl<'a, T> fmt::Display for MaybeOwned<'a, T>
    where T: fmt::Display
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Owned(ref o) => fmt::Display::fmt(o, f),
            Borrowed(b) => fmt::Display::fmt(b, f),
        }
    }
}

impl<'a, T> MaybeOwned<'a, T> where T: Clone {

    /// Aquires a mutable reference to owned data.
    ///
    /// Clones data if it is not already owned.
    ///
    /// ## Example
    ///
    /// ```
    /// use maybe_owned::MaybeOwned;
    ///
    /// #[derive(Clone, Debug, PartialEq, Eq)]
    /// struct PseudoBigData(u8);
    ///
    /// let data = PseudoBigData(12);
    ///
    /// let mut maybe: MaybeOwned<PseudoBigData> = (&data).into();
    /// assert_eq!(false, maybe.is_owned());
    ///
    /// {
    ///     let reference = maybe.to_mut();
    ///     assert_eq!(&mut PseudoBigData(12), reference);
    /// }
    /// assert!(maybe.is_owned());
    /// ```
    ///
    pub fn to_mut(&mut self) -> &mut T {
        match *self {
            Owned(ref mut v) => v,
            Borrowed(v) => {
                *self = Owned(v.clone());
                match *self {
                    Owned(ref mut v) => v,
                    Borrowed(..) => unreachable!()
                }
            }

        }
    }

    /// Extracts the owned data.
    ///
    /// If the data is borrowed it is cloned before being extracted.
    pub fn into_owned(self) -> T {
        match self {
            Owned(v) => v,
            Borrowed(v) => v.clone()
        }
    }
}

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

    type TestType = Vec<()>;

    fn with_into<'a, I: Into<MaybeOwned<'a, TestType>>>(v: I) -> MaybeOwned<'a, TestType> {
        v.into()
    }

    #[test]
    fn is_owned() {
        let data = TestType::default();
        assert!(MaybeOwned::Owned(data).is_owned());
    }

    #[test]
    fn into_with_owned() {
        //ty check if it accepts references
        let data = TestType::default();
        assert!(with_into(data).is_owned())

    }
    #[test]
    fn into_with_borrow() {
        //ty check if it accepts references
        let data = TestType::default();
        assert!(!with_into(&data).is_owned());
    }

    #[test]
    fn clone_owned() {
        let maybe = MaybeOwned::<TestType>::default();
        assert!(maybe.clone().is_owned());
    }

    #[test]
    fn clone_borrow() {
        let data = TestType::default();
        let maybe: MaybeOwned<TestType> = (&data).into();
        assert!(!maybe.clone().is_owned());
    }

    #[test]
    fn to_mut() {
        let data = TestType::default();
        let mut maybe: MaybeOwned<TestType> = (&data).into();
        assert!(!maybe.is_owned());
        {
            let _mut_ref = maybe.to_mut();
        }
        assert!(maybe.is_owned());
    }

    #[test]
    fn into_inner() {
        let data = vec![1u32,2];
        let maybe: MaybeOwned<Vec<u32>> = (&data).into();
        assert_eq!(data, maybe.into_owned());
    }

    #[test]
    fn has_default() {
        #[derive(Default)]
        struct TestType(u8);
        let _x: MaybeOwned<TestType> = Default::default();
    }

    #[test]
    fn has_clone() {
        #[derive(Clone)]
        struct TestType(u8);
        let _x  = TestType(12).clone();
    }

    #[test]
    fn has_partial_eq() {
        #[derive(PartialEq)]
        struct TestType(f32);

        let n = TestType(33.0);
        let a = MaybeOwned::Owned(TestType(42.0));
        let b = MaybeOwned::Borrowed(&n);
        let c = MaybeOwned::Owned(TestType(33.0));

        assert_eq!(a == b, false);
        assert_eq!(b == c, true);
        assert_eq!(c == a, false);
    }

    #[test]
    fn has_eq() {
        #[derive(PartialEq, Eq)]
        struct TestType(i32);

        let n = TestType(33);
        let a = MaybeOwned::Owned(TestType(42));
        let b = MaybeOwned::Borrowed(&n);
        let c = MaybeOwned::Owned(TestType(33));

        assert_eq!(a == b, false);
        assert_eq!(b == c, true);
        assert_eq!(c == a, false);
    }

    #[test]
    fn has_partial_ord() {
        #[derive(PartialEq, PartialOrd)]
        struct TestType(f32);

        let n = TestType(33.0);
        let a = MaybeOwned::Owned(TestType(42.0));
        let b = MaybeOwned::Borrowed(&n);
        let c = MaybeOwned::Owned(TestType(33.0));

        assert_eq!(a > b, true);
        assert_eq!(b > c, false);
        assert_eq!(a < c, false);
    }

    #[test]
    fn has_ord() {
        #[derive(PartialEq, Eq, PartialOrd, Ord)]
        struct TestType(i32);

        let n = TestType(33);
        let a = MaybeOwned::Owned(TestType(42));
        let b = MaybeOwned::Borrowed(&n);
        let c = MaybeOwned::Owned(TestType(33));

        assert_eq!(a > b, true);
        assert_eq!(b > c, false);
        assert_eq!(a < c, false);
    }

    #[test]
    fn has_hash() {
        use std::collections::HashMap;

        let mut map = HashMap::new();
        map.insert(MaybeOwned::Owned(42), 33);

        assert_eq!(map.get(&MaybeOwned::Borrowed(&42)), Some(&33));
    }

    #[test]
    fn has_display() {
        let n = 33;
        let a = MaybeOwned::Owned(42);
        let b = MaybeOwned::Borrowed(&n);

        let s = format!("{} {}", a, b);

        assert_eq!(s, "42 33");
    }
}
<|endoftext|>