<commit_before>//! ### rust-mysql-simple
//! Mysql client library implemented in rust nightly.
//!
//! #### Install
//! Just include another `[dependencies.*]` section into your Cargo.toml:
//!
//! ```toml
//! [dependencies.mysql]
//! git = "https://github.com/blackbeam/rust-mysql-simple"
//! ```
//!
//! rust-mysql-simple offer support of SSL via `ssl` cargo feature which is enabled by default. If you have no plans to use SSL, then you should disable that feature to not to depend on rust-openssl:
//!
//! ```toml
//! [dependencies.mysql]
//! git = "https://github.com/blackbeam/rust-mysql-simple"
//! default-features = false
//! ```
//!
//! #### Use
//! You should start by creating [`MyOpts`](conn/struct.MyOpts.html) struct.
//!
//! Then you can create [`MyPool`](conn/pool/struct.MyPool.html) which should be
//! enough to work with mysql server.
#![crate_name="mysql"]
#![crate_type="rlib"]
#![crate_type="dylib"]

#![feature(unsafe_destructor)]
#![feature(phase)]
#![feature(slicing_syntax)]

#![allow(dead_code)]
#![feature(macro_rules)]

#[cfg(test)]
extern crate test;
extern crate core;
extern crate time;
#[cfg(feature = "openssl")]
extern crate openssl;
extern crate regex;
#[phase(plugin)]
extern crate regex_macros;

#[phase(plugin)]
extern crate lazy_static;

mod scramble;
pub mod consts;
pub mod error;
mod packet;
mod io;
pub mod value;
pub mod conn;
<commit_msg>Remove trailing tabulation<commit_after>//! ### rust-mysql-simple
//! Mysql client library implemented in rust nightly.
//!
//! #### Install
//! Just include another `[dependencies.*]` section into your Cargo.toml:
//!
//! ```toml
//! [dependencies.mysql]
//! git = "https://github.com/blackbeam/rust-mysql-simple"
//! ```
//!
//! rust-mysql-simple offer support of SSL via `ssl` cargo feature which is enabled by default. If you have no plans to use SSL, then you should disable that feature to not to depend on rust-openssl:
//!
//! ```toml
//! [dependencies.mysql]
//! git = "https://github.com/blackbeam/rust-mysql-simple"
//! default-features = false
//! ```
//!
//! #### Use
//! You should start by creating [`MyOpts`](conn/struct.MyOpts.html) struct.
//!
//! Then you can create [`MyPool`](conn/pool/struct.MyPool.html) which should be
//! enough to work with mysql server.
#![crate_name="mysql"]
#![crate_type="rlib"]
#![crate_type="dylib"]

#![feature(unsafe_destructor)]
#![feature(phase)]
#![feature(slicing_syntax)]

#![allow(dead_code)]
#![feature(macro_rules)]

#[cfg(test)]
extern crate test;
extern crate core;
extern crate time;
#[cfg(feature = "openssl")]
extern crate openssl;
extern crate regex;
#[phase(plugin)]
extern crate regex_macros;

#[phase(plugin)]
extern crate lazy_static;

mod scramble;
pub mod consts;
pub mod error;
mod packet;
mod io;
pub mod value;
pub mod conn;
<|endoftext|>


<commit_before>use syntax::ast;
use syntax::codemap::{self, DUMMY_SP, Span, respan};
use syntax::ext::base::{DummyMacroLoader, ExtCtxt};
use syntax::ext::expand;
use syntax::ext::quote::rt::ToTokens;
use syntax::feature_gate::GatedCfgAttr;
use syntax::parse::ParseSess;
use syntax::ptr::P;

use expr::ExprBuilder;
use invoke::{Invoke, Identity};
use name::ToName;

/// A Builder for macro invocations.
///
/// Note that there are no commas added between args, as otherwise
/// that macro invocations that could be expressed would be limited.
/// You will need to add all required symbols with `with_arg` or
/// `with_argss`.
pub struct MacBuilder<F=Identity> {
    callback: F,
    span: Span,
    tokens: Vec<ast::TokenTree>,
    path: Option<ast::Path>,
}

impl MacBuilder {
    pub fn new() -> Self {
        MacBuilder::with_callback(Identity)
    }
}

impl<F> MacBuilder<F>
    where F: Invoke<ast::Mac>
{
    pub fn with_callback(callback: F) -> Self {
        MacBuilder {
            callback: callback,
            span: DUMMY_SP,
            tokens: vec![],
            path: None,
        }
    }

    pub fn span(mut self, span: Span) -> Self {
        self.span = span;
        self
    }

    pub fn path(mut self, path: ast::Path) -> Self {
        self.path = Some(path);
        self
    }

    pub fn build(self) -> F::Result {
        let mac = ast::Mac_ {
            path: self.path.expect("No path set for macro"),
            tts: self.tokens,
            ctxt: ast::EMPTY_CTXT,
        };
        self.callback.invoke(respan(self.span, mac))
    }

    pub fn with_args<I, T>(self, iter: I) -> Self
        where I: IntoIterator<Item=T>, T: ToTokens
    {
        iter.into_iter().fold(self, |self_, expr| self_.with_arg(expr))
    }

    pub fn with_arg<T>(mut self, expr: T) -> Self
        where T: ToTokens
    {
        let parse_sess = ParseSess::new();
        let mut feature_gated_cfgs = Vec::new();
        let mut macro_loader = DummyMacroLoader;
        let cx = make_ext_ctxt(&parse_sess, &mut feature_gated_cfgs, &mut macro_loader);
        let tokens = expr.to_tokens(&cx);
        assert!(tokens.len() == 1);
        self.tokens.push(tokens[0].clone());
        self
    }

    pub fn expr(self) -> ExprBuilder<Self> {
        ExprBuilder::with_callback(self)
    }

}

impl<F> Invoke<P<ast::Expr>> for MacBuilder<F>
    where F: Invoke<ast::Mac>,
{
    type Result = Self;

    fn invoke(self, expr: P<ast::Expr>) -> Self {
        self.with_arg(expr)
    }
}

fn make_ext_ctxt<'a>(sess: &'a ParseSess,
                     feature_gated_cfgs: &'a mut Vec<GatedCfgAttr>,
                     macro_loader: &'a mut DummyMacroLoader) -> ExtCtxt<'a> {
    let info = codemap::ExpnInfo {
        call_site: codemap::DUMMY_SP,
        callee: codemap::NameAndSpan {
            format: codemap::MacroAttribute("test".to_name()),
            allow_internal_unstable: false,
            span: None
        }
    };

    let cfg = vec![];
    let ecfg = expand::ExpansionConfig::default(String::new());
    let mut cx = ExtCtxt::new(sess, cfg, ecfg, feature_gated_cfgs, macro_loader);
    cx.bt_push(info);

    cx
}
<commit_msg>Remove feature_gated_cfgs<commit_after>use syntax::ast;
use syntax::codemap::{self, DUMMY_SP, Span, respan};
use syntax::ext::base::{DummyMacroLoader, ExtCtxt};
use syntax::ext::expand;
use syntax::ext::quote::rt::ToTokens;
use syntax::parse::ParseSess;
use syntax::ptr::P;

use expr::ExprBuilder;
use invoke::{Invoke, Identity};
use name::ToName;

/// A Builder for macro invocations.
///
/// Note that there are no commas added between args, as otherwise
/// that macro invocations that could be expressed would be limited.
/// You will need to add all required symbols with `with_arg` or
/// `with_argss`.
pub struct MacBuilder<F=Identity> {
    callback: F,
    span: Span,
    tokens: Vec<ast::TokenTree>,
    path: Option<ast::Path>,
}

impl MacBuilder {
    pub fn new() -> Self {
        MacBuilder::with_callback(Identity)
    }
}

impl<F> MacBuilder<F>
    where F: Invoke<ast::Mac>
{
    pub fn with_callback(callback: F) -> Self {
        MacBuilder {
            callback: callback,
            span: DUMMY_SP,
            tokens: vec![],
            path: None,
        }
    }

    pub fn span(mut self, span: Span) -> Self {
        self.span = span;
        self
    }

    pub fn path(mut self, path: ast::Path) -> Self {
        self.path = Some(path);
        self
    }

    pub fn build(self) -> F::Result {
        let mac = ast::Mac_ {
            path: self.path.expect("No path set for macro"),
            tts: self.tokens,
            ctxt: ast::EMPTY_CTXT,
        };
        self.callback.invoke(respan(self.span, mac))
    }

    pub fn with_args<I, T>(self, iter: I) -> Self
        where I: IntoIterator<Item=T>, T: ToTokens
    {
        iter.into_iter().fold(self, |self_, expr| self_.with_arg(expr))
    }

    pub fn with_arg<T>(mut self, expr: T) -> Self
        where T: ToTokens
    {
        let parse_sess = ParseSess::new();
        let mut macro_loader = DummyMacroLoader;
        let cx = make_ext_ctxt(&parse_sess, &mut macro_loader);
        let tokens = expr.to_tokens(&cx);
        assert!(tokens.len() == 1);
        self.tokens.push(tokens[0].clone());
        self
    }

    pub fn expr(self) -> ExprBuilder<Self> {
        ExprBuilder::with_callback(self)
    }

}

impl<F> Invoke<P<ast::Expr>> for MacBuilder<F>
    where F: Invoke<ast::Mac>,
{
    type Result = Self;

    fn invoke(self, expr: P<ast::Expr>) -> Self {
        self.with_arg(expr)
    }
}

fn make_ext_ctxt<'a>(sess: &'a ParseSess,
                     macro_loader: &'a mut DummyMacroLoader) -> ExtCtxt<'a> {
    let info = codemap::ExpnInfo {
        call_site: codemap::DUMMY_SP,
        callee: codemap::NameAndSpan {
            format: codemap::MacroAttribute("test".to_name()),
            allow_internal_unstable: false,
            span: None
        }
    };

    let cfg = vec![];
    let ecfg = expand::ExpansionConfig::default(String::new());
    let mut cx = ExtCtxt::new(sess, cfg, ecfg, macro_loader);
    cx.bt_push(info);

    cx
}
<|endoftext|>


<commit_before>use regex::Regex;
use super::formatter::FormatStr;

pub struct TagFormatter;

impl FormatStr for TagFormatter {
    fn format(&self, s: &str) -> String {
        let mut r = self.format_paragraphs(s);
        // currently no special formatting for links so just format like other tags (remove)
        r = self.format_code_tags(&r);
        self.format_tags(&r)
    }
}

impl TagFormatter {
    pub fn format_paragraphs(&self, s: &str) -> String {
        // todo split
        let mut r = self.replace_paragraphs_opening_tags(&s, "\n");
        r = self.replace_paragraphs_closing_tags(&r, "");
        r
    }

    pub fn format_links(&self, s: &str) -> String {
        let mut r = self.replace_link_opening_tags(s, "");
        r = self.replace_link_closing_tags(&r, "");
        r
    }

    pub fn format_tags(&self, s: &str) -> String {
        self.replace_tags(s, "")
    }

    pub fn format_code_tags(&self, s:&str) -> String {
        let mut r = self.replace_opening_code_tags(s, "\n\t");
        self.replace_closing_code_tags(&r, "")
    }

    fn replace_paragraphs_closing_tags(&self, s: &str, replacement: &str) -> String {
        let re = Regex::new(r"( *
 *)").unwrap();
        re.replace_all(s, replacement).into_owned()
    }

    fn replace_paragraphs_opening_tags(&self, s: &str, replacement: &str) -> String {
        let re = Regex::new(r"( *
 *)").unwrap();
        re.replace_all(s, replacement).into_owned()
    }

    fn replace_link_opening_tags(&self, s: &str, replacement: &str) -> String {
        let re = Regex::new(r"( *)").unwrap();
        re.replace_all(s, replacement).into_owned()
    }

    fn replace_link_closing_tags(&self, s: &str, replacement: &str) -> String {
        let re = Regex::new(r"( * *)").unwrap();
        re.replace_all(s, replacement).into_owned()
    }

    fn replace_tags(&self, s: &str, replacement: &str) -> String {
        // will just replace all tags and should be called after other methods have run before
        let re = Regex::new(r"(</?\w+((\s+\w+(\s*=\s*(?:\x22.*?\x22|'.*?'|[\^'\x22>\s]+))?)+\s*|\s*)/?>)").unwrap();
        re.replace_all(s, replacement).into_owned()
    }

    fn replace_closing_code_tags(&self, s: &str, replacement: &str) -> String {
        let re = Regex::new(r"( *)").unwrap();
        re.replace_all(s, replacement).into_owned()
    }

    fn replace_opening_code_tags(&self, s: &str, replacement: &str) -> String {
        let re = Regex::new(r"( * *)").unwrap();
        re.replace_all(s, replacement).into_owned()
    }
}
#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_replace_paragraphs() {
        let tag_formatter = TagFormatter;
        let mut s: String = format!("aaaaaa zzz zzaaa

");
        s = tag_formatter.format_paragraphs(&s);
        assert_eq!("aaaaaa zzz zzaaa\n", s);

        s = format!("
 para
 ");
        s = tag_formatter.format_paragraphs(&s);
        assert_eq!("\npara", s);
    }

    #[test]
    fn test_replace_codetags() {
        let tag_formatter = TagFormatter;
        let mut s = format!(" System.out.println(\"Hello world\"); ");
        s = tag_formatter.format_code_tags(&s);
        assert_eq!("\n\tSystem.out.println(\"Hello world\");", s);
    }
    #[test]
    fn test_replace_links() {
        let tag_formatter = TagFormatter;
        let mut s: String = format!("this is  \
                                     http://www.link.com ");
        s = tag_formatter.format_links(&s);
        assert_eq!("this is http://www.link.com", s);
    }

    #[test]
    fn test_replace_tags() {
        let tag_formatter = TagFormatter;
        let mut s: String = format!("this is http://www.link.com");
        s = tag_formatter.format_tags(&s);
        assert_eq!("this is http://www.link.com", s);
        s = format!("
para

div

heading
");
        s = tag_formatter.format_tags(&s);
        assert_eq!("para div heading ", s);
    }
    #[test]
    fn test_formatting_with_item() {
        use helpers::io_utils::read_file;
        use serde_json;
        use core::models::HnItem;

        let tag_formatter = TagFormatter;

        let unformatted_item:HnItem =  read_file("res/test/item-with-html.json")
            .and_then(|content| Some(serde_json::from_str(&content).unwrap()))
            .unwrap();
        let formatted_text = read_file("res/test/formatted-item-with-html.txt").unwrap();
        assert_eq!(formatted_text, tag_formatter.format(unformatted_item.text.as_ref().unwrap()));
        // ;
    }

}<commit_msg>Minor changes to code block formatting<commit_after>use regex::Regex;
use super::formatter::FormatStr;

pub struct TagFormatter;

impl FormatStr for TagFormatter {
    fn format(&self, s: &str) -> String {
        let mut r = self.format_paragraphs(s);
        // currently no special formatting for links so just format like other tags (remove)
        r = self.format_code_tags(&r);
        self.format_tags(&r)
    }
}

impl TagFormatter {
    pub fn format_paragraphs(&self, s: &str) -> String {
        // todo split
        let mut r = self.replace_paragraphs_opening_tags(&s, "\n");
        r = self.replace_paragraphs_closing_tags(&r, "");
        r
    }

    pub fn format_links(&self, s: &str) -> String {
        let mut r = self.replace_link_opening_tags(s, "");
        r = self.replace_link_closing_tags(&r, "");
        r
    }

    pub fn format_tags(&self, s: &str) -> String {
        self.replace_tags(s, "")
    }

    pub fn format_code_tags(&self, s:&str) -> String {
        let mut r = self.replace_opening_code_tags(s, "\n");
        self.replace_closing_code_tags(&r, "\n") // make code blocks stand out
    }

    fn replace_paragraphs_closing_tags(&self, s: &str, replacement: &str) -> String {
        let re = Regex::new(r"( *
 *)").unwrap();
        re.replace_all(s, replacement).into_owned()
    }

    fn replace_paragraphs_opening_tags(&self, s: &str, replacement: &str) -> String {
        let re = Regex::new(r"( *
 *)").unwrap();
        re.replace_all(s, replacement).into_owned()
    }

    fn replace_link_opening_tags(&self, s: &str, replacement: &str) -> String {
        let re = Regex::new(r"( *)").unwrap();
        re.replace_all(s, replacement).into_owned()
    }

    fn replace_link_closing_tags(&self, s: &str, replacement: &str) -> String {
        let re = Regex::new(r"( * *)").unwrap();
        re.replace_all(s, replacement).into_owned()
    }

    fn replace_tags(&self, s: &str, replacement: &str) -> String {
        // will just replace all tags and should be called after other methods have run before
        let re = Regex::new(r"(</?\w+((\s+\w+(\s*=\s*(?:\x22.*?\x22|'.*?'|[\^'\x22>\s]+))?)+\s*|\s*)/?>)").unwrap();
        re.replace_all(s, replacement).into_owned()
    }

    fn replace_closing_code_tags(&self, s: &str, replacement: &str) -> String {
        let re = Regex::new(r"( *)").unwrap();
        re.replace_all(s, replacement).into_owned()
    }

    fn replace_opening_code_tags(&self, s: &str, replacement: &str) -> String {
        let re = Regex::new(r"( *)").unwrap();
        re.replace_all(s, replacement).into_owned()
    }
}
#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_replace_paragraphs() {
        let tag_formatter = TagFormatter;
        let mut s: String = format!("aaaaaa zzz zzaaa

");
        s = tag_formatter.format_paragraphs(&s);
        assert_eq!("aaaaaa zzz zzaaa\n", s);

        s = format!("
 para
 ");
        s = tag_formatter.format_paragraphs(&s);
        assert_eq!("\npara", s);
    }

    #[test]
    fn test_replace_codetags() {
        let tag_formatter = TagFormatter;
        let mut s = format!(" System.out.println(\"Hello world\"); ");
        s = tag_formatter.format_code_tags(&s);
        assert_eq!("\n\tSystem.out.println(\"Hello world\");", s);
    }
    #[test]
    fn test_replace_links() {
        let tag_formatter = TagFormatter;
        let mut s: String = format!("this is  \
                                     http://www.link.com ");
        s = tag_formatter.format_links(&s);
        assert_eq!("this is http://www.link.com", s);
    }

    #[test]
    fn test_replace_tags() {
        let tag_formatter = TagFormatter;
        let mut s: String = format!("this is http://www.link.com");
        s = tag_formatter.format_tags(&s);
        assert_eq!("this is http://www.link.com", s);
        s = format!("
para

div

heading
");
        s = tag_formatter.format_tags(&s);
        assert_eq!("para div heading ", s);
    }
    #[test]
    fn test_formatting_with_item() {
        use helpers::io_utils::read_file;
        use serde_json;
        use core::models::HnItem;

        let tag_formatter = TagFormatter;

        let unformatted_item:HnItem =  read_file("res/test/item-with-html.json")
            .and_then(|content| Some(serde_json::from_str(&content).unwrap()))
            .unwrap();
        let formatted_text = read_file("res/test/formatted-item-with-html.txt").unwrap();
        assert_eq!(formatted_text, tag_formatter.format(unformatted_item.text.as_ref().unwrap()));
        // ;
    }

}<|endoftext|>


<commit_before>//! This module contains extension methods for `String` that expose
//! parallel iterators, such as `par_split_whitespace()`. You will
//! rarely need to interact with it directly, since if you add `use
//! rayon::prelude::*` to your file, that will include the helper
//! traits defined in this module.

use iter::*;
use iter::internal::*;
use std::cmp::min;

/// Test if a byte is the start of a UTF-8 character.
/// (extracted from `str::is_char_boundary`)
fn is_char_boundary(b: u8) -> bool {
    // This is bit magic equivalent to: b < 128 || b >= 192
    (b as i8) >= -0x40
}

/// Find the index of a character boundary near the midpoint.
fn find_char_midpoint(chars: &str) -> usize {
    let mid = chars.len() / 2;

    // We want to split near the midpoint, but we need to find an actual
    // character boundary.  So we look at the raw bytes, first scanning
    // forward from the midpoint for a boundary, then trying backward.
    let (left, right) = chars.as_bytes().split_at(mid);
    right.iter()
        .cloned()
        .position(is_char_boundary)
        .map(|i| mid + i)
        .or_else(|| left.iter().cloned().rposition(is_char_boundary))
        .unwrap_or(0)
}

/// Parallel extensions for strings.
///
/// Implementing this trait is not permitted outside of `rayon`.
pub trait ParallelString {
    private_decl!{}

    /// Returns a parallel iterator over the characters of a string.
    fn par_chars(&self) -> Chars;

    /// Returns a parallel iterator over substrings separated by a
    /// given character, similar to `str::split`.
    fn par_split<P: Pattern>(&self, P) -> Split<P>;

    /// Returns a parallel iterator over substrings terminated by a
    /// given character, similar to `str::split_terminator`.  It's
    /// equivalent to `par_split`, except it doesn't produce an empty
    /// substring after a trailing terminator.
    fn par_split_terminator<P: Pattern>(&self, P) -> SplitTerminator<P>;

    /// Returns a parallel iterator over the lines of a string, ending with an
    /// optional carriage return and with a newline (`\r\n` or just `\n`).
    /// The final line ending is optional, and line endings are not included in
    /// the output strings.
    fn par_lines(&self) -> Lines;

    /// Returns a parallel iterator over the sub-slices of a string that are
    /// separated by any amount of whitespace.
    ///
    /// As with `str::split_whitespace`, 'whitespace' is defined according to
    /// the terms of the Unicode Derived Core Property `White_Space`.
    fn par_split_whitespace(&self) -> SplitWhitespace;
}

impl ParallelString for str {
    private_impl!{}

    fn par_chars(&self) -> Chars {
        Chars { chars: self }
    }

    fn par_split<P: Pattern>(&self, separator: P) -> Split<P> {
        Split::new(self, separator)
    }

    fn par_split_terminator<P: Pattern>(&self, terminator: P) -> SplitTerminator<P> {
        SplitTerminator::new(self, terminator)
    }

    fn par_lines(&self) -> Lines {
        Lines(self)
    }

    fn par_split_whitespace(&self) -> SplitWhitespace {
        SplitWhitespace(self)
    }
}

// /////////////////////////////////////////////////////////////////////////

/// Pattern-matching trait for `ParallelString`, somewhat like a mix of
/// `std::str::pattern::{Pattern, Searcher}`.
///
/// Implementing this trait is not permitted outside of `rayon`.
pub trait Pattern: Sized + Sync {
    private_decl!{}
    fn find_in(&self, &str) -> Option<usize>;
    fn rfind_in(&self, &str) -> Option<usize>;
    fn is_suffix_of(&self, &str) -> bool;
    fn fold_with<'ch, F>(&self, &'ch str, folder: F, skip_last: bool) -> F where F: Folder<&'ch str>;
}

impl Pattern for char {
    private_impl!{}

    fn find_in(&self, chars: &str) -> Option<usize> {
        chars.find(*self)
    }

    fn rfind_in(&self, chars: &str) -> Option<usize> {
        chars.rfind(*self)
    }

    fn is_suffix_of(&self, chars: &str) -> bool {
        chars.ends_with(*self)
    }

    fn fold_with<'ch, F>(&self, chars: &'ch str, folder: F, skip_last: bool) -> F
        where F: Folder<&'ch str>
    {
        let mut split = chars.split(*self);
        if skip_last {
            split.next_back();
        }
        folder.consume_iter(split)
    }
}

impl<FN: Sync + Fn(char) -> bool> Pattern for FN {
    private_impl!{}

    fn find_in(&self, chars: &str) -> Option<usize> {
        chars.find(self)
    }

    fn rfind_in(&self, chars: &str) -> Option<usize> {
        chars.rfind(self)
    }

    fn is_suffix_of(&self, chars: &str) -> bool {
        chars.ends_with(self)
    }

    fn fold_with<'ch, F>(&self, chars: &'ch str, folder: F, skip_last: bool) -> F
        where F: Folder<&'ch str>
    {
        let mut split = chars.split(self);
        if skip_last {
            split.next_back();
        }
        folder.consume_iter(split)
    }
}

// /////////////////////////////////////////////////////////////////////////

pub struct Chars<'ch> {
    chars: &'ch str,
}

struct CharsProducer<'ch> {
    chars: &'ch str,
}

impl<'ch> ParallelIterator for Chars<'ch> {
    type Item = char;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        bridge_unindexed(CharsProducer { chars: self.chars }, consumer)
    }
}

impl<'ch> UnindexedProducer for CharsProducer<'ch> {
    type Item = char;

    fn split(mut self) -> (Self, Option<Self>) {
        let index = find_char_midpoint(self.chars);
        if index > 0 {
            let (left, right) = self.chars.split_at(index);
            self.chars = left;
            (self, Some(CharsProducer { chars: right }))
        } else {
            (self, None)
        }
    }

    fn fold_with<F>(self, folder: F) -> F
        where F: Folder<Self::Item>
    {
        folder.consume_iter(self.chars.chars())
    }
}

// /////////////////////////////////////////////////////////////////////////

pub struct Split<'ch, P: Pattern> {
    chars: &'ch str,
    separator: P,
}

struct SplitProducer<'ch, 'sep, P: Pattern + 'sep> {
    chars: &'ch str,
    separator: &'sep P,

    /// Marks the endpoint beyond which we've already found no separators.
    tail: usize,
}

impl<'ch, P: Pattern> Split<'ch, P> {
    fn new(chars: &'ch str, separator: P) -> Self {
        Split {
            chars: chars,
            separator: separator,
        }
    }
}

impl<'ch, 'sep, P: Pattern + 'sep> SplitProducer<'ch, 'sep, P> {
    fn new(split: &'sep Split<'ch, P>) -> Self {
        SplitProducer {
            chars: split.chars,
            separator: &split.separator,
            tail: split.chars.len(),
        }
    }

    /// Common `fold_with` implementation, integrating `SplitTerminator`'s
    /// need to sometimes skip its final empty item.
    fn fold_with<F>(self, folder: F, skip_last: bool) -> F
        where F: Folder<<Self as UnindexedProducer>::Item>
    {
        let SplitProducer { chars, separator, tail } = self;

        if tail == chars.len() {
            // No tail section, so just let `str::split` handle it.
            separator.fold_with(chars, folder, skip_last)

        } else if let Some(index) = separator.rfind_in(&chars[..tail]) {
            // We found the last separator to complete the tail, so
            // end with that slice after `str::split` finds the rest.
            let (left, right) = chars.split_at(index);
            let folder = separator.fold_with(left, folder, false);
            if skip_last || folder.full() {
                folder
            } else {
                let mut right_iter = right.chars();
                right_iter.next(); // skip the separator
                folder.consume(right_iter.as_str())
            }

        } else {
            // We know there are no separators at all.  Return our whole string.
            if skip_last {
                folder
            } else {
                folder.consume(chars)
            }
        }
    }
}

impl<'ch, P: Pattern> ParallelIterator for Split<'ch, P> {
    type Item = &'ch str;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        let producer = SplitProducer::new(&self);
        bridge_unindexed(producer, consumer)
    }
}

impl<'ch, 'sep, P: Pattern + 'sep> UnindexedProducer for SplitProducer<'ch, 'sep, P> {
    type Item = &'ch str;

    fn split(mut self) -> (Self, Option<Self>) {
        let SplitProducer { chars, separator, tail } = self;

        // First find a suitable UTF-8 boundary in the unsearched region.
        let char_index = find_char_midpoint(&chars[..tail]);

        // Look forward for the separator, and failing that look backward.
        let index = separator.find_in(&chars[char_index..tail])
            .map(|i| char_index + i)
            .or_else(|| separator.rfind_in(&chars[..char_index]));

        if let Some(index) = index {
            let (left, right) = chars.split_at(index);

            // Update `self` as the region before the separator.
            self.chars = left;
            self.tail = min(char_index, index);

            // Create the right split following the separator.
            let mut right_iter = right.chars();
            right_iter.next(); // skip the separator
            let right_chars = right_iter.as_str();
            let right_index = chars.len() - right_chars.len();

            let mut right = SplitProducer {
                chars: right_chars,
                separator: separator,
                tail: tail - right_index,
            };

            // If we scanned backwards to find the separator, everything in
            // the right side is exhausted, with no separators left to find.
            if index < char_index {
                right.tail = 0;
            }

            (self, Some(right))

        } else {
            self.tail = 0;
            (self, None)
        }
    }

    fn fold_with<F>(self, folder: F) -> F
        where F: Folder<Self::Item>
    {
        self.fold_with(folder, false)
    }
}

// /////////////////////////////////////////////////////////////////////////

pub struct SplitTerminator<'ch, P: Pattern> {
    splitter: Split<'ch, P>,
}

struct SplitTerminatorProducer<'ch, 'sep, P: Pattern + 'sep> {
    splitter: SplitProducer<'ch, 'sep, P>,
    endpoint: bool,
}

impl<'ch, P: Pattern> SplitTerminator<'ch, P> {
    fn new(chars: &'ch str, terminator: P) -> Self {
        SplitTerminator { splitter: Split::new(chars, terminator) }
    }
}

impl<'ch, 'sep, P: Pattern + 'sep> SplitTerminatorProducer<'ch, 'sep, P> {
    fn new(split: &'sep SplitTerminator<'ch, P>) -> Self {
        SplitTerminatorProducer {
            splitter: SplitProducer::new(&split.splitter),
            endpoint: true,
        }
    }
}

impl<'ch, P: Pattern> ParallelIterator for SplitTerminator<'ch, P> {
    type Item = &'ch str;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        let producer = SplitTerminatorProducer::new(&self);
        bridge_unindexed(producer, consumer)
    }
}

impl<'ch, 'sep, P: Pattern + 'sep> UnindexedProducer for SplitTerminatorProducer<'ch, 'sep, P> {
    type Item = &'ch str;

    fn split(mut self) -> (Self, Option<Self>) {
        let (left, right) = self.splitter.split();
        self.splitter = left;
        let right = right.map(|right| {
            let endpoint = self.endpoint;
            self.endpoint = false;
            SplitTerminatorProducer {
                splitter: right,
                endpoint: endpoint,
            }
        });
        (self, right)
    }

    fn fold_with<F>(self, folder: F) -> F
        where F: Folder<Self::Item>
    {
        // See if we need to eat the empty trailing substring
        let skip_last = if self.endpoint {
            let chars = self.splitter.chars;
            let terminator = self.splitter.separator;
            chars.is_empty() || terminator.is_suffix_of(chars)
        } else {
            false
        };

        self.splitter.fold_with(folder, skip_last)
    }
}

// /////////////////////////////////////////////////////////////////////////

pub struct Lines<'ch>(&'ch str);

impl<'ch> ParallelIterator for Lines<'ch> {
    type Item = &'ch str;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        self.0
            .par_split_terminator('\n')
            .map(|line| {
                if line.ends_with('\r') {
                    &line[..line.len() - 1]
                } else {
                    line
                }
            })
            .drive_unindexed(consumer)
    }
}

// /////////////////////////////////////////////////////////////////////////

pub struct SplitWhitespace<'ch>(&'ch str);

impl<'ch> ParallelIterator for SplitWhitespace<'ch> {
    type Item = &'ch str;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        self.0
            .par_split(char::is_whitespace)
            .filter(|string| !string.is_empty())
            .drive_unindexed(consumer)
    }
}
<commit_msg>Document string iterators<commit_after>//! This module contains extension methods for `String` that expose
//! parallel iterators, such as `par_split_whitespace()`. You will
//! rarely need to interact with it directly, since if you add `use
//! rayon::prelude::*` to your file, that will include the helper
//! traits defined in this module.

use iter::*;
use iter::internal::*;
use std::cmp::min;

/// Test if a byte is the start of a UTF-8 character.
/// (extracted from `str::is_char_boundary`)
fn is_char_boundary(b: u8) -> bool {
    // This is bit magic equivalent to: b < 128 || b >= 192
    (b as i8) >= -0x40
}

/// Find the index of a character boundary near the midpoint.
fn find_char_midpoint(chars: &str) -> usize {
    let mid = chars.len() / 2;

    // We want to split near the midpoint, but we need to find an actual
    // character boundary.  So we look at the raw bytes, first scanning
    // forward from the midpoint for a boundary, then trying backward.
    let (left, right) = chars.as_bytes().split_at(mid);
    right.iter()
        .cloned()
        .position(is_char_boundary)
        .map(|i| mid + i)
        .or_else(|| left.iter().cloned().rposition(is_char_boundary))
        .unwrap_or(0)
}

/// Parallel extensions for strings.
///
/// Implementing this trait is not permitted outside of `rayon`.
pub trait ParallelString {
    private_decl!{}

    /// Returns a parallel iterator over the characters of a string.
    fn par_chars(&self) -> Chars;

    /// Returns a parallel iterator over substrings separated by a
    /// given character, similar to `str::split`.
    fn par_split<P: Pattern>(&self, P) -> Split<P>;

    /// Returns a parallel iterator over substrings terminated by a
    /// given character, similar to `str::split_terminator`.  It's
    /// equivalent to `par_split`, except it doesn't produce an empty
    /// substring after a trailing terminator.
    fn par_split_terminator<P: Pattern>(&self, P) -> SplitTerminator<P>;

    /// Returns a parallel iterator over the lines of a string, ending with an
    /// optional carriage return and with a newline (`\r\n` or just `\n`).
    /// The final line ending is optional, and line endings are not included in
    /// the output strings.
    fn par_lines(&self) -> Lines;

    /// Returns a parallel iterator over the sub-slices of a string that are
    /// separated by any amount of whitespace.
    ///
    /// As with `str::split_whitespace`, 'whitespace' is defined according to
    /// the terms of the Unicode Derived Core Property `White_Space`.
    fn par_split_whitespace(&self) -> SplitWhitespace;
}

impl ParallelString for str {
    private_impl!{}

    fn par_chars(&self) -> Chars {
        Chars { chars: self }
    }

    fn par_split<P: Pattern>(&self, separator: P) -> Split<P> {
        Split::new(self, separator)
    }

    fn par_split_terminator<P: Pattern>(&self, terminator: P) -> SplitTerminator<P> {
        SplitTerminator::new(self, terminator)
    }

    fn par_lines(&self) -> Lines {
        Lines(self)
    }

    fn par_split_whitespace(&self) -> SplitWhitespace {
        SplitWhitespace(self)
    }
}

// /////////////////////////////////////////////////////////////////////////

/// Pattern-matching trait for `ParallelString`, somewhat like a mix of
/// `std::str::pattern::{Pattern, Searcher}`.
///
/// Implementing this trait is not permitted outside of `rayon`.
pub trait Pattern: Sized + Sync {
    private_decl!{}
    fn find_in(&self, &str) -> Option<usize>;
    fn rfind_in(&self, &str) -> Option<usize>;
    fn is_suffix_of(&self, &str) -> bool;
    fn fold_with<'ch, F>(&self, &'ch str, folder: F, skip_last: bool) -> F where F: Folder<&'ch str>;
}

impl Pattern for char {
    private_impl!{}

    fn find_in(&self, chars: &str) -> Option<usize> {
        chars.find(*self)
    }

    fn rfind_in(&self, chars: &str) -> Option<usize> {
        chars.rfind(*self)
    }

    fn is_suffix_of(&self, chars: &str) -> bool {
        chars.ends_with(*self)
    }

    fn fold_with<'ch, F>(&self, chars: &'ch str, folder: F, skip_last: bool) -> F
        where F: Folder<&'ch str>
    {
        let mut split = chars.split(*self);
        if skip_last {
            split.next_back();
        }
        folder.consume_iter(split)
    }
}

impl<FN: Sync + Fn(char) -> bool> Pattern for FN {
    private_impl!{}

    fn find_in(&self, chars: &str) -> Option<usize> {
        chars.find(self)
    }

    fn rfind_in(&self, chars: &str) -> Option<usize> {
        chars.rfind(self)
    }

    fn is_suffix_of(&self, chars: &str) -> bool {
        chars.ends_with(self)
    }

    fn fold_with<'ch, F>(&self, chars: &'ch str, folder: F, skip_last: bool) -> F
        where F: Folder<&'ch str>
    {
        let mut split = chars.split(self);
        if skip_last {
            split.next_back();
        }
        folder.consume_iter(split)
    }
}

// /////////////////////////////////////////////////////////////////////////

/// Parallel iterator over the characters of a string
pub struct Chars<'ch> {
    chars: &'ch str,
}

struct CharsProducer<'ch> {
    chars: &'ch str,
}

impl<'ch> ParallelIterator for Chars<'ch> {
    type Item = char;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        bridge_unindexed(CharsProducer { chars: self.chars }, consumer)
    }
}

impl<'ch> UnindexedProducer for CharsProducer<'ch> {
    type Item = char;

    fn split(mut self) -> (Self, Option<Self>) {
        let index = find_char_midpoint(self.chars);
        if index > 0 {
            let (left, right) = self.chars.split_at(index);
            self.chars = left;
            (self, Some(CharsProducer { chars: right }))
        } else {
            (self, None)
        }
    }

    fn fold_with<F>(self, folder: F) -> F
        where F: Folder<Self::Item>
    {
        folder.consume_iter(self.chars.chars())
    }
}

// /////////////////////////////////////////////////////////////////////////

/// Parallel iterator over substrings separated by a pattern
pub struct Split<'ch, P: Pattern> {
    chars: &'ch str,
    separator: P,
}

struct SplitProducer<'ch, 'sep, P: Pattern + 'sep> {
    chars: &'ch str,
    separator: &'sep P,

    /// Marks the endpoint beyond which we've already found no separators.
    tail: usize,
}

impl<'ch, P: Pattern> Split<'ch, P> {
    fn new(chars: &'ch str, separator: P) -> Self {
        Split {
            chars: chars,
            separator: separator,
        }
    }
}

impl<'ch, 'sep, P: Pattern + 'sep> SplitProducer<'ch, 'sep, P> {
    fn new(split: &'sep Split<'ch, P>) -> Self {
        SplitProducer {
            chars: split.chars,
            separator: &split.separator,
            tail: split.chars.len(),
        }
    }

    /// Common `fold_with` implementation, integrating `SplitTerminator`'s
    /// need to sometimes skip its final empty item.
    fn fold_with<F>(self, folder: F, skip_last: bool) -> F
        where F: Folder<<Self as UnindexedProducer>::Item>
    {
        let SplitProducer { chars, separator, tail } = self;

        if tail == chars.len() {
            // No tail section, so just let `str::split` handle it.
            separator.fold_with(chars, folder, skip_last)

        } else if let Some(index) = separator.rfind_in(&chars[..tail]) {
            // We found the last separator to complete the tail, so
            // end with that slice after `str::split` finds the rest.
            let (left, right) = chars.split_at(index);
            let folder = separator.fold_with(left, folder, false);
            if skip_last || folder.full() {
                folder
            } else {
                let mut right_iter = right.chars();
                right_iter.next(); // skip the separator
                folder.consume(right_iter.as_str())
            }

        } else {
            // We know there are no separators at all.  Return our whole string.
            if skip_last {
                folder
            } else {
                folder.consume(chars)
            }
        }
    }
}

impl<'ch, P: Pattern> ParallelIterator for Split<'ch, P> {
    type Item = &'ch str;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        let producer = SplitProducer::new(&self);
        bridge_unindexed(producer, consumer)
    }
}

impl<'ch, 'sep, P: Pattern + 'sep> UnindexedProducer for SplitProducer<'ch, 'sep, P> {
    type Item = &'ch str;

    fn split(mut self) -> (Self, Option<Self>) {
        let SplitProducer { chars, separator, tail } = self;

        // First find a suitable UTF-8 boundary in the unsearched region.
        let char_index = find_char_midpoint(&chars[..tail]);

        // Look forward for the separator, and failing that look backward.
        let index = separator.find_in(&chars[char_index..tail])
            .map(|i| char_index + i)
            .or_else(|| separator.rfind_in(&chars[..char_index]));

        if let Some(index) = index {
            let (left, right) = chars.split_at(index);

            // Update `self` as the region before the separator.
            self.chars = left;
            self.tail = min(char_index, index);

            // Create the right split following the separator.
            let mut right_iter = right.chars();
            right_iter.next(); // skip the separator
            let right_chars = right_iter.as_str();
            let right_index = chars.len() - right_chars.len();

            let mut right = SplitProducer {
                chars: right_chars,
                separator: separator,
                tail: tail - right_index,
            };

            // If we scanned backwards to find the separator, everything in
            // the right side is exhausted, with no separators left to find.
            if index < char_index {
                right.tail = 0;
            }

            (self, Some(right))

        } else {
            self.tail = 0;
            (self, None)
        }
    }

    fn fold_with<F>(self, folder: F) -> F
        where F: Folder<Self::Item>
    {
        self.fold_with(folder, false)
    }
}

// /////////////////////////////////////////////////////////////////////////

/// Parallel iterator over substrings separated by a terminator pattern
pub struct SplitTerminator<'ch, P: Pattern> {
    splitter: Split<'ch, P>,
}

struct SplitTerminatorProducer<'ch, 'sep, P: Pattern + 'sep> {
    splitter: SplitProducer<'ch, 'sep, P>,
    endpoint: bool,
}

impl<'ch, P: Pattern> SplitTerminator<'ch, P> {
    fn new(chars: &'ch str, terminator: P) -> Self {
        SplitTerminator { splitter: Split::new(chars, terminator) }
    }
}

impl<'ch, 'sep, P: Pattern + 'sep> SplitTerminatorProducer<'ch, 'sep, P> {
    fn new(split: &'sep SplitTerminator<'ch, P>) -> Self {
        SplitTerminatorProducer {
            splitter: SplitProducer::new(&split.splitter),
            endpoint: true,
        }
    }
}

impl<'ch, P: Pattern> ParallelIterator for SplitTerminator<'ch, P> {
    type Item = &'ch str;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        let producer = SplitTerminatorProducer::new(&self);
        bridge_unindexed(producer, consumer)
    }
}

impl<'ch, 'sep, P: Pattern + 'sep> UnindexedProducer for SplitTerminatorProducer<'ch, 'sep, P> {
    type Item = &'ch str;

    fn split(mut self) -> (Self, Option<Self>) {
        let (left, right) = self.splitter.split();
        self.splitter = left;
        let right = right.map(|right| {
            let endpoint = self.endpoint;
            self.endpoint = false;
            SplitTerminatorProducer {
                splitter: right,
                endpoint: endpoint,
            }
        });
        (self, right)
    }

    fn fold_with<F>(self, folder: F) -> F
        where F: Folder<Self::Item>
    {
        // See if we need to eat the empty trailing substring
        let skip_last = if self.endpoint {
            let chars = self.splitter.chars;
            let terminator = self.splitter.separator;
            chars.is_empty() || terminator.is_suffix_of(chars)
        } else {
            false
        };

        self.splitter.fold_with(folder, skip_last)
    }
}

// /////////////////////////////////////////////////////////////////////////

/// Parallel iterator over lines in a string
pub struct Lines<'ch>(&'ch str);

impl<'ch> ParallelIterator for Lines<'ch> {
    type Item = &'ch str;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        self.0
            .par_split_terminator('\n')
            .map(|line| {
                if line.ends_with('\r') {
                    &line[..line.len() - 1]
                } else {
                    line
                }
            })
            .drive_unindexed(consumer)
    }
}

// /////////////////////////////////////////////////////////////////////////

/// Parallel iterator over substrings separated by whitespace
pub struct SplitWhitespace<'ch>(&'ch str);

impl<'ch> ParallelIterator for SplitWhitespace<'ch> {
    type Item = &'ch str;

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        self.0
            .par_split(char::is_whitespace)
            .filter(|string| !string.is_empty())
            .drive_unindexed(consumer)
    }
}
<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::fmt::{Display, self};
use std::str::FromStr;
use url::Url;
use url::ParseError as UrlError;

use Error;

/// The Request-URI of a Request's StartLine.
///
/// From Section 5.3, Request Target:
/// > Once an inbound connection is obtained, the client sends an HTTP
/// > request message (Section 3) with a request-target derived from the
/// > target URI.  There are four distinct formats for the request-target,
/// > depending on both the method being requested and whether the request
/// > is to a proxy.
/// >
/// > ```notrust
/// > request-target = origin-form
/// >                / absolute-form
/// >                / authority-form
/// >                / asterisk-form
/// > ```
///
/// # Uri explanations
///
/// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
/// |-|   |-------------------------------||--------| |-------------------| |-----|
///  |                  |                       |               |              |
/// scheme          authority                 path            query         fragment
#[derive(Clone)]
pub struct Uri {
    source: Cow<'static, str>,
    scheme_end: Option<usize>,
    authority_end: Option<usize>,
    query: Option<usize>,
    fragment: Option<usize>,
}

impl Uri {
    /// Parse a string into a `Uri`.
    pub fn new(s: &str) -> Result<Uri, Error> {
        let bytes = s.as_bytes();
        if bytes.len() == 0 {
            Err(Error::Uri(UrlError::RelativeUrlWithoutBase))
        } else if bytes == b"*" {
            Ok(Uri {
                source: "*".into(),
                scheme_end: None,
                authority_end: None,
                query: None,
                fragment: None,
            })
        } else if bytes == b"/" {
            Ok(Uri::default())
        } else if bytes.starts_with(b"/") {
            Ok(Uri {
                source: s.to_owned().into(),
                scheme_end: None,
                authority_end: None,
                query: parse_query(s),
                fragment: parse_fragment(s),
            })
        } else if s.contains("://") {
            let scheme = parse_scheme(s);
            let auth = parse_authority(s);
            if let Some(end) = scheme {
                match &s[..end] {
                    "ftp" | "gopher" | "http" | "https" | "ws" | "wss" => {},
                    "blob" | "file" => return Err(Error::Method),
                    _ => return Err(Error::Method),
                }
                match auth {
                    Some(a) => {
                        if (end + 3) == a {
                            return Err(Error::Method);
                        }
                    },
                    None => return Err(Error::Method),
                }
            }
            Ok(Uri {
                source: s.to_owned().into(),
                scheme_end: scheme,
                authority_end: auth,
                query: parse_query(s),
                fragment: parse_fragment(s),
            })
        } else {
            Ok(Uri {
                source: s.to_owned().into(),
                scheme_end: None,
                authority_end: Some(s.len()),
                query: None,
                fragment: None,
            })
        }
    }

    /// Get the path of this `Uri`.
    pub fn path(&self) -> &str {
        let index = self.authority_end.unwrap_or(self.scheme_end.unwrap_or(0));
        let query_len = self.query.unwrap_or(0);
        let fragment_len = self.fragment.unwrap_or(0);
        let end = self.source.len() - if query_len > 0 { query_len + 1 } else { 0 } -
            if fragment_len > 0 { fragment_len + 1 } else { 0 };
        if index >= end {
            if self.scheme().is_some() {
                return "/" // absolute-form MUST have path
            }
            ""
        } else {
            &self.source[index..end]
        }
    }

    /// Get the scheme of this `Uri`.
    pub fn scheme(&self) -> Option<&str> {
        if let Some(end) = self.scheme_end {
            Some(&self.source[..end])
        } else {
            None
        }
    }

    /// Get the authority of this `Uri`.
    pub fn authority(&self) -> Option<&str> {
        if let Some(end) = self.authority_end {
            let index = self.scheme_end.map(|i| i + 3).unwrap_or(0);

            Some(&self.source[index..end])
        } else {
            None
        }
    }

    /// Get the host of this `Uri`.
    pub fn host(&self) -> Option<&str> {
        if let Some(auth) = self.authority() {
            auth.split(":").next()
        } else {
            None
        }
    }

    /// Get the port of this `Uri.
    pub fn port(&self) -> Option<u16> {
        match self.authority() {
            Some(auth) => auth.find(":").and_then(|i| u16::from_str(&auth[i+1..]).ok()),
            None => None,
       }
    }

    /// Get the query string of this `Uri`, starting after the `?`.
    pub fn query(&self) -> Option<&str> {
        let fragment_len = self.fragment.unwrap_or(0);
        let fragment_len = if fragment_len > 0 { fragment_len + 1 } else { 0 };
        if let Some(len) = self.query {
            Some(&self.source[self.source.len() - len - fragment_len..self.source.len() - fragment_len])
        } else {
            None
        }
    }

    #[cfg(test)]
    fn fragment(&self) -> Option<&str> {
        if let Some(len) = self.fragment {
            Some(&self.source[self.source.len() - len..])
        } else {
            None
        }
    }
}

fn parse_scheme(s: &str) -> Option<usize> {
    s.find(':')
}

fn parse_authority(s: &str) -> Option<usize> {
    let i = s.find("://").and_then(|p| Some(p + 3)).unwrap_or(0);

    Some(&s[i..].split("/")
         .next()
         .unwrap_or(s)
         .len() + i)
}

fn parse_query(s: &str) -> Option<usize> {
    match s.find('?') {
        Some(i) => {
            let frag_pos = s.find('#').unwrap_or(s.len());

            return Some(frag_pos - i - 1);
        },
        None => None,
    }
}

fn parse_fragment(s: &str) -> Option<usize> {
    match s.find('#') {
        Some(i) => Some(s.len() - i - 1),
        None => None,
    }
}

impl FromStr for Uri {
    type Err = Error;

    fn from_str(s: &str) -> Result<Uri, Error> {
        Uri::new(s)
    }
}

impl From<Url> for Uri {
    fn from(url: Url) -> Uri {
        Uri::new(url.as_str()).expect("Uri::From<Url> failed")
    }
}

impl PartialEq for Uri {
    fn eq(&self, other: &Uri) -> bool {
        self.source == other.source
    }
}

impl AsRef<str> for Uri {
    fn as_ref(&self) -> &str {
        &self.source
    }
}

impl Default for Uri {
    fn default() -> Uri {
        Uri {
            source: "/".into(),
            scheme_end: None,
            authority_end: None,
            query: None,
            fragment: None,
        }
    }
}

impl fmt::Debug for Uri {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.source.as_ref(), f)
    }
}

impl Display for Uri {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(&self.source)
    }
}

macro_rules! test_parse {
    (
        $test_name:ident,
        $str:expr,
        $($method:ident = $value:expr,)*
    ) => (
        #[test]
        fn $test_name() {
            let uri = Uri::new($str).unwrap();
            $(
            assert_eq!(uri.$method(), $value);
            )+
        }
    );
}

test_parse! {
    test_uri_parse_origin_form,
    "/some/path/here?and=then&hello#and-bye",

    scheme = None,
    authority = None,
    path = "/some/path/here",
    query = Some("and=then&hello"),
    fragment = Some("and-bye"),
}

test_parse! {
    test_uri_parse_absolute_form,
    "http://127.0.0.1:61761/chunks",

    scheme = Some("http"),
    authority = Some("127.0.0.1:61761"),
    path = "/chunks",
    query = None,
    fragment = None,
    port = Some(61761),
}

test_parse! {
    test_uri_parse_absolute_form_without_path,
    "https://127.0.0.1:61761",

    scheme = Some("https"),
    authority = Some("127.0.0.1:61761"),
    path = "/",
    query = None,
    fragment = None,
    port = Some(61761),
}

test_parse! {
    test_uri_parse_asterisk_form,
    "*",

    scheme = None,
    authority = None,
    path = "*",
    query = None,
    fragment = None,
}

test_parse! {
    test_uri_parse_authority_form,
    "localhost:3000",

    scheme = None,
    authority = Some("localhost:3000"),
    path = "",
    query = None,
    fragment = None,
    port = Some(3000),
}

test_parse! {
    test_uri_parse_absolute_with_default_port_http,
    "http://127.0.0.1:80",

    scheme = Some("http"),
    authority = Some("127.0.0.1:80"),
    path = "/",
    query = None,
    fragment = None,
    port = Some(80),
}

test_parse! {
    test_uri_parse_absolute_with_default_port_https,
    "https://127.0.0.1:443",

    scheme = Some("https"),
    authority = Some("127.0.0.1:443"),
    path = "/",
    query = None,
    fragment = None,
    port = Some(443),
}

#[test]
fn test_uri_parse_error() {
    fn err(s: &str) {
        Uri::new(s).unwrap_err();
    }

    err("http://");
    //TODO: these should error
    //err("htt:p//host");
    //err("hyper.rs/");
    //err("hyper.rs?key=val");
}

#[test]
fn test_uri_from_url() {
    let uri = Uri::from(Url::parse("http://test.com/nazghul?test=3").unwrap());
    assert_eq!(uri.path(), "/nazghul");
    assert_eq!(uri.authority(), Some("test.com"));
    assert_eq!(uri.scheme(), Some("http"));
    assert_eq!(uri.query(), Some("test=3"));
    assert_eq!(uri.as_ref(), "http://test.com/nazghul?test=3");
}
<commit_msg>test(uri): fix URI parse error tests<commit_after>use std::borrow::Cow;
use std::fmt::{Display, self};
use std::str::FromStr;
use url::Url;
use url::ParseError as UrlError;

use Error;

/// The Request-URI of a Request's StartLine.
///
/// From Section 5.3, Request Target:
/// > Once an inbound connection is obtained, the client sends an HTTP
/// > request message (Section 3) with a request-target derived from the
/// > target URI.  There are four distinct formats for the request-target,
/// > depending on both the method being requested and whether the request
/// > is to a proxy.
/// >
/// > ```notrust
/// > request-target = origin-form
/// >                / absolute-form
/// >                / authority-form
/// >                / asterisk-form
/// > ```
///
/// # Uri explanations
///
/// abc://username:password@example.com:123/path/data?key=value&key2=value2#fragid1
/// |-|   |-------------------------------||--------| |-------------------| |-----|
///  |                  |                       |               |              |
/// scheme          authority                 path            query         fragment
#[derive(Clone)]
pub struct Uri {
    source: Cow<'static, str>,
    scheme_end: Option<usize>,
    authority_end: Option<usize>,
    query: Option<usize>,
    fragment: Option<usize>,
}

impl Uri {
    /// Parse a string into a `Uri`.
    pub fn new(s: &str) -> Result<Uri, Error> {
        let bytes = s.as_bytes();
        if bytes.len() == 0 {
            Err(Error::Uri(UrlError::RelativeUrlWithoutBase))
        } else if bytes == b"*" {
            Ok(Uri {
                source: "*".into(),
                scheme_end: None,
                authority_end: None,
                query: None,
                fragment: None,
            })
        } else if bytes == b"/" {
            Ok(Uri::default())
        } else if bytes.starts_with(b"/") {
            Ok(Uri {
                source: s.to_owned().into(),
                scheme_end: None,
                authority_end: None,
                query: parse_query(s),
                fragment: parse_fragment(s),
            })
        } else if s.contains("://") {
            let scheme = parse_scheme(s);
            let auth = parse_authority(s);
            if let Some(end) = scheme {
                match &s[..end] {
                    "ftp" | "gopher" | "http" | "https" | "ws" | "wss" => {},
                    "blob" | "file" => return Err(Error::Method),
                    _ => return Err(Error::Method),
                }
                match auth {
                    Some(a) => {
                        if (end + 3) == a {
                            return Err(Error::Method);
                        }
                    },
                    None => return Err(Error::Method),
                }
            }
            Ok(Uri {
                source: s.to_owned().into(),
                scheme_end: scheme,
                authority_end: auth,
                query: parse_query(s),
                fragment: parse_fragment(s),
            })
        } else if (s.contains("/") || s.contains("?")) && !s.contains("://") {
            return Err(Error::Method)
        } else {
            Ok(Uri {
                source: s.to_owned().into(),
                scheme_end: None,
                authority_end: Some(s.len()),
                query: None,
                fragment: None,
            })
        }
    }

    /// Get the path of this `Uri`.
    pub fn path(&self) -> &str {
        let index = self.authority_end.unwrap_or(self.scheme_end.unwrap_or(0));
        let query_len = self.query.unwrap_or(0);
        let fragment_len = self.fragment.unwrap_or(0);
        let end = self.source.len() - if query_len > 0 { query_len + 1 } else { 0 } -
            if fragment_len > 0 { fragment_len + 1 } else { 0 };
        if index >= end {
            if self.scheme().is_some() {
                return "/" // absolute-form MUST have path
            }
            ""
        } else {
            &self.source[index..end]
        }
    }

    /// Get the scheme of this `Uri`.
    pub fn scheme(&self) -> Option<&str> {
        if let Some(end) = self.scheme_end {
            Some(&self.source[..end])
        } else {
            None
        }
    }

    /// Get the authority of this `Uri`.
    pub fn authority(&self) -> Option<&str> {
        if let Some(end) = self.authority_end {
            let index = self.scheme_end.map(|i| i + 3).unwrap_or(0);

            Some(&self.source[index..end])
        } else {
            None
        }
    }

    /// Get the host of this `Uri`.
    pub fn host(&self) -> Option<&str> {
        if let Some(auth) = self.authority() {
            auth.split(":").next()
        } else {
            None
        }
    }

    /// Get the port of this `Uri.
    pub fn port(&self) -> Option<u16> {
        match self.authority() {
            Some(auth) => auth.find(":").and_then(|i| u16::from_str(&auth[i+1..]).ok()),
            None => None,
       }
    }

    /// Get the query string of this `Uri`, starting after the `?`.
    pub fn query(&self) -> Option<&str> {
        let fragment_len = self.fragment.unwrap_or(0);
        let fragment_len = if fragment_len > 0 { fragment_len + 1 } else { 0 };
        if let Some(len) = self.query {
            Some(&self.source[self.source.len() - len - fragment_len..self.source.len() - fragment_len])
        } else {
            None
        }
    }

    #[cfg(test)]
    fn fragment(&self) -> Option<&str> {
        if let Some(len) = self.fragment {
            Some(&self.source[self.source.len() - len..])
        } else {
            None
        }
    }
}

fn parse_scheme(s: &str) -> Option<usize> {
    s.find(':')
}

fn parse_authority(s: &str) -> Option<usize> {
    let i = s.find("://").and_then(|p| Some(p + 3)).unwrap_or(0);

    Some(&s[i..].split("/")
         .next()
         .unwrap_or(s)
         .len() + i)
}

fn parse_query(s: &str) -> Option<usize> {
    match s.find('?') {
        Some(i) => {
            let frag_pos = s.find('#').unwrap_or(s.len());

            return Some(frag_pos - i - 1);
        },
        None => None,
    }
}

fn parse_fragment(s: &str) -> Option<usize> {
    match s.find('#') {
        Some(i) => Some(s.len() - i - 1),
        None => None,
    }
}

impl FromStr for Uri {
    type Err = Error;

    fn from_str(s: &str) -> Result<Uri, Error> {
        Uri::new(s)
    }
}

impl From<Url> for Uri {
    fn from(url: Url) -> Uri {
        Uri::new(url.as_str()).expect("Uri::From<Url> failed")
    }
}

impl PartialEq for Uri {
    fn eq(&self, other: &Uri) -> bool {
        self.source == other.source
    }
}

impl AsRef<str> for Uri {
    fn as_ref(&self) -> &str {
        &self.source
    }
}

impl Default for Uri {
    fn default() -> Uri {
        Uri {
            source: "/".into(),
            scheme_end: None,
            authority_end: None,
            query: None,
            fragment: None,
        }
    }
}

impl fmt::Debug for Uri {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.source.as_ref(), f)
    }
}

impl Display for Uri {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(&self.source)
    }
}

macro_rules! test_parse {
    (
        $test_name:ident,
        $str:expr,
        $($method:ident = $value:expr,)*
    ) => (
        #[test]
        fn $test_name() {
            let uri = Uri::new($str).unwrap();
            $(
            assert_eq!(uri.$method(), $value);
            )+
        }
    );
}

test_parse! {
    test_uri_parse_origin_form,
    "/some/path/here?and=then&hello#and-bye",

    scheme = None,
    authority = None,
    path = "/some/path/here",
    query = Some("and=then&hello"),
    fragment = Some("and-bye"),
}

test_parse! {
    test_uri_parse_absolute_form,
    "http://127.0.0.1:61761/chunks",

    scheme = Some("http"),
    authority = Some("127.0.0.1:61761"),
    path = "/chunks",
    query = None,
    fragment = None,
    port = Some(61761),
}

test_parse! {
    test_uri_parse_absolute_form_without_path,
    "https://127.0.0.1:61761",

    scheme = Some("https"),
    authority = Some("127.0.0.1:61761"),
    path = "/",
    query = None,
    fragment = None,
    port = Some(61761),
}

test_parse! {
    test_uri_parse_asterisk_form,
    "*",

    scheme = None,
    authority = None,
    path = "*",
    query = None,
    fragment = None,
}

test_parse! {
    test_uri_parse_authority_no_port,
    "localhost",

    scheme = None,
    authority = Some("localhost"),
    path = "",
    query = None,
    fragment = None,
    port = None,
}

test_parse! {
    test_uri_parse_authority_form,
    "localhost:3000",

    scheme = None,
    authority = Some("localhost:3000"),
    path = "",
    query = None,
    fragment = None,
    port = Some(3000),
}

test_parse! {
    test_uri_parse_absolute_with_default_port_http,
    "http://127.0.0.1:80",

    scheme = Some("http"),
    authority = Some("127.0.0.1:80"),
    path = "/",
    query = None,
    fragment = None,
    port = Some(80),
}

test_parse! {
    test_uri_parse_absolute_with_default_port_https,
    "https://127.0.0.1:443",

    scheme = Some("https"),
    authority = Some("127.0.0.1:443"),
    path = "/",
    query = None,
    fragment = None,
    port = Some(443),
}

#[test]
fn test_uri_parse_error() {
    fn err(s: &str) {
        Uri::new(s).unwrap_err();
    }

    err("http://");
    err("htt:p//host");
    err("hyper.rs/");
    err("hyper.rs?key=val");
    err("localhost/");
    err("localhost?key=val");
}

#[test]
fn test_uri_from_url() {
    let uri = Uri::from(Url::parse("http://test.com/nazghul?test=3").unwrap());
    assert_eq!(uri.path(), "/nazghul");
    assert_eq!(uri.authority(), Some("test.com"));
    assert_eq!(uri.scheme(), Some("http"));
    assert_eq!(uri.query(), Some("test=3"));
    assert_eq!(uri.as_ref(), "http://test.com/nazghul?test=3");
}
<|endoftext|>


<commit_before>#![ feature(libc, core, collections, unsafe_destructor) ]
#![ allow(non_snake_case) ]

extern crate libc;

use libusb::*;
use libc::c_int;
use std::intrinsics;
use std::slice;
use std::iter::repeat;
use std::result::Result;
use std::mem::transmute;
use std::mem::size_of;
use std::vec::Vec;
use std::cell::UnsafeCell;

pub mod libusb;

pub struct Context(*mut libusb_context);
unsafe impl Send for Context {}
unsafe impl Sync for Context {}

impl Context {
	pub fn new() -> Context {
		unsafe{
			let mut ctx: *mut libusb_context = intrinsics::init();
			let r = libusb_init(&mut ctx);
			assert!(r == 0);
			Context(ctx)
		}
	}

	pub fn ptr(&self) -> *mut libusb_context {
		self.0
	}

	pub fn set_debug(&self, level: u32) {
		unsafe{
			libusb_set_debug(self.ptr(), level as c_int);
		}
	}

	pub fn list_devices(&self) -> Vec<Device> {
		unsafe{
			let mut list: *mut *mut libusb_device = intrinsics::init();
			let num_devices = libusb_get_device_list(self.ptr(), &mut list);
			let l = slice::from_raw_parts_mut(list, num_devices as usize);
			let devices = l.iter().map(|i| Device { dev: *i, ctx: self }).collect();
			libusb_free_device_list(list, 0);
			devices
		}
	}

	pub fn find_by_vid_pid(&self, vid: u16, pid: u16) -> Option<Device> {
		self.list_devices().into_iter().find(|d| {
			let desc = d.descriptor();
			desc.idVendor == vid && desc.idProduct == pid
		})
	}
}

impl Drop for Context {
	fn drop(&mut self) {
		unsafe { libusb_exit(self.0); }
	}
}

pub struct Device<'c> {
	dev: *mut libusb_device,
	ctx: &'c Context,
}

impl<'c> Device<'c> {
	pub fn descriptor(&self) -> libusb_device_descriptor {
		unsafe{
			let mut d: libusb_device_descriptor = intrinsics::uninit();
			libusb_get_device_descriptor(self.dev, &mut d as *mut libusb_device_descriptor);
			d
		}
	}

	pub fn bus(&self) -> u8 {
		unsafe {
			libusb_get_bus_number(self.dev)
		}
	}

	pub fn address(&self) -> u8 {
		unsafe {
			libusb_get_device_address(self.dev)
		}
	}

	pub fn open(&self) -> Result<DeviceHandle, c_int> {
		unsafe {
			let mut handle: *mut libusb_device_handle = intrinsics::uninit();
			let r = libusb_open(self.dev, &mut handle);
			if r == 0 {
				Ok(DeviceHandle {
					dev: handle,
					ctx: self.ctx
				})
			}else{
				Err(r)
			}
		}
	}
}

#[unsafe_destructor]
impl<'c> Drop for Device<'c> {
	fn drop(&mut self) {
		unsafe {
			libusb_unref_device(self.dev);
		}
	}
}

impl<'c> Clone for Device<'c> {
	fn clone(&self) -> Device<'c> {
		unsafe {
			libusb_ref_device(self.dev);
		}
		Device{ dev: self.dev, ctx: self.ctx }
	}
}

pub struct DeviceHandle<'c> {
	dev: *mut libusb_device_handle,
	ctx: &'c Context
}
unsafe impl<'c> Sync for DeviceHandle<'c> {}

impl<'c> DeviceHandle<'c> {
	pub fn ptr(&self) -> *mut libusb_device_handle {
		self.dev
	}

	pub fn claim_interface(&self, iface_num: u16) {
		unsafe {
			libusb_claim_interface(self.ptr(), iface_num as c_int);
		}
	}

	pub unsafe fn submit_transfer_sync(&self,
		endpoint: u8,
		transfer_type: libusb_transfer_type,
		length: usize,
		buffer: *mut u8,
		timeout: u32) -> (libusb_transfer_status, usize) {

		let completed: UnsafeCell<c_int> = UnsafeCell::new(0);

		extern fn callback(transfer: *mut libusb_transfer) {
			unsafe {
				let completed: &UnsafeCell<c_int> = transmute((*transfer).user_data);
				*completed.get() = 1;
			}
		}

		let t = libusb_alloc_transfer(0);
		(*t).dev_handle = self.ptr();
		(*t).endpoint = endpoint;
		(*t).transfer_type = transfer_type as u8;
		(*t).timeout = timeout;
		(*t).length = length as c_int;
		(*t).callback = callback;
		(*t).user_data = transmute(&completed);
		(*t).buffer = buffer;

		libusb_submit_transfer(t);

		while *completed.get() == 0{
			libusb_handle_events_completed(self.ctx.ptr(), completed.get());
		}

		let r = ((*t).get_status(), (*t).actual_length as usize);
		libusb_free_transfer(t);
		return r;
	}

	pub fn read(&self,
			endpoint: u8,
			transfer_type: libusb_transfer_type,
			size: usize,
			timeout: u32
			) -> Result<Vec<u8>, libusb_transfer_status> {
		let mut buf: Vec<u8> = repeat(0u8).take(size).collect();
		unsafe {
			let ptr = buf.as_mut_ptr();
			let (status, actual_length) = self.submit_transfer_sync(
				endpoint, transfer_type, size, ptr, timeout);

			if status == LIBUSB_TRANSFER_COMPLETED {
				buf.truncate(actual_length);
				Ok(buf)
			} else {
				Err(status)
			}
		}
	}

	pub fn write(&self,
			endpoint: u8,
			transfer_type: libusb_transfer_type,
			buf: &[u8],
			timeout: u32
			) -> Result<(), libusb_transfer_status> {
		unsafe {
			let ptr = buf.as_ptr() as *mut u8;

			let (status, _) = self.submit_transfer_sync(
				endpoint, transfer_type, buf.len(), ptr, timeout);

			if status == LIBUSB_TRANSFER_COMPLETED {
				Ok(())
			} else {
				Err(status)
			}
		}
	}

	pub fn ctrl_read(&self, bmRequestType: u8, bRequest: u8,
		wValue:u16, wIndex: u16, length: usize, timeout: u32) -> Result<Vec<u8>, libusb_transfer_status> {

		let setup_length = size_of::<libusb_control_setup>();
		let total_length = setup_length + length;
		let mut buf: Vec<u8> = repeat(0u8).take(total_length).collect();
		let ptr = fill_setup_buf(&mut buf, bmRequestType, bRequest, wValue, wIndex, length);

		unsafe{
			let (status, actual_length) = self.submit_transfer_sync(
				0, LIBUSB_TRANSFER_TYPE_CONTROL, total_length, ptr, timeout);

			if status == LIBUSB_TRANSFER_COMPLETED {
				Ok(buf[setup_length..setup_length+actual_length].to_vec())
			} else {
				Err(status)
			}
		}
	}

	pub fn ctrl_write(&self, bmRequestType: u8, bRequest: u8,
		wValue:u16, wIndex: u16, buf: &[u8], timeout: u32) -> Result<(), libusb_transfer_status> {
		let mut setup_buf: Vec<_> = repeat(0u8).take(size_of::<libusb_control_setup>()).collect();
		fill_setup_buf(&mut setup_buf, bmRequestType, bRequest, wValue, wIndex, buf.len());
		setup_buf.push_all(buf);
		self.write(0, LIBUSB_TRANSFER_TYPE_CONTROL, &setup_buf, timeout)
	}
}

#[unsafe_destructor]
impl<'c> Drop for DeviceHandle<'c> {
	fn drop(&mut self) {
		unsafe {
			libusb_close(self.dev);
		}
	}
}

fn fill_setup_buf(buf: &mut [u8], bmRequestType: u8,
	bRequest: u8, wValue:u16, wIndex: u16, length: usize) -> *mut u8 {
	let ptr = buf.as_mut_ptr();
	let setup = ptr as *mut libusb_control_setup;

	assert!(buf.len() >= 8);
	assert!(length <= (std::u16::MAX as usize));

	unsafe {
		(*setup).bmRequestType = bmRequestType;
		(*setup).bRequest = bRequest;
		(*setup).wValue = wValue.to_le();
		(*setup).wIndex = wIndex.to_le();
		(*setup).wLength = (length as u16).to_le();
	}

	return ptr;
}
<commit_msg>rust: remove unsafe_destructor<commit_after>#![ feature(libc, core, collections) ]
#![ allow(non_snake_case) ]

extern crate libc;

use libusb::*;
use libc::c_int;
use std::intrinsics;
use std::slice;
use std::iter::repeat;
use std::result::Result;
use std::mem::transmute;
use std::mem::size_of;
use std::vec::Vec;
use std::cell::UnsafeCell;

pub mod libusb;

pub struct Context(*mut libusb_context);
unsafe impl Send for Context {}
unsafe impl Sync for Context {}

impl Context {
	pub fn new() -> Context {
		unsafe{
			let mut ctx: *mut libusb_context = intrinsics::init();
			let r = libusb_init(&mut ctx);
			assert!(r == 0);
			Context(ctx)
		}
	}

	pub fn ptr(&self) -> *mut libusb_context {
		self.0
	}

	pub fn set_debug(&self, level: u32) {
		unsafe{
			libusb_set_debug(self.ptr(), level as c_int);
		}
	}

	pub fn list_devices(&self) -> Vec<Device> {
		unsafe{
			let mut list: *mut *mut libusb_device = intrinsics::init();
			let num_devices = libusb_get_device_list(self.ptr(), &mut list);
			let l = slice::from_raw_parts_mut(list, num_devices as usize);
			let devices = l.iter().map(|i| Device { dev: *i, ctx: self }).collect();
			libusb_free_device_list(list, 0);
			devices
		}
	}

	pub fn find_by_vid_pid(&self, vid: u16, pid: u16) -> Option<Device> {
		self.list_devices().into_iter().find(|d| {
			let desc = d.descriptor();
			desc.idVendor == vid && desc.idProduct == pid
		})
	}
}

impl Drop for Context {
	fn drop(&mut self) {
		unsafe { libusb_exit(self.0); }
	}
}

pub struct Device<'c> {
	dev: *mut libusb_device,
	ctx: &'c Context,
}

impl<'c> Device<'c> {
	pub fn descriptor(&self) -> libusb_device_descriptor {
		unsafe{
			let mut d: libusb_device_descriptor = intrinsics::uninit();
			libusb_get_device_descriptor(self.dev, &mut d as *mut libusb_device_descriptor);
			d
		}
	}

	pub fn bus(&self) -> u8 {
		unsafe {
			libusb_get_bus_number(self.dev)
		}
	}

	pub fn address(&self) -> u8 {
		unsafe {
			libusb_get_device_address(self.dev)
		}
	}

	pub fn open(&self) -> Result<DeviceHandle, c_int> {
		unsafe {
			let mut handle: *mut libusb_device_handle = intrinsics::uninit();
			let r = libusb_open(self.dev, &mut handle);
			if r == 0 {
				Ok(DeviceHandle {
					dev: handle,
					ctx: self.ctx
				})
			}else{
				Err(r)
			}
		}
	}
}

impl<'c> Drop for Device<'c> {
	fn drop(&mut self) {
		unsafe {
			libusb_unref_device(self.dev);
		}
	}
}

impl<'c> Clone for Device<'c> {
	fn clone(&self) -> Device<'c> {
		unsafe {
			libusb_ref_device(self.dev);
		}
		Device{ dev: self.dev, ctx: self.ctx }
	}
}

pub struct DeviceHandle<'c> {
	dev: *mut libusb_device_handle,
	ctx: &'c Context
}
unsafe impl<'c> Sync for DeviceHandle<'c> {}

impl<'c> DeviceHandle<'c> {
	pub fn ptr(&self) -> *mut libusb_device_handle {
		self.dev
	}

	pub fn claim_interface(&self, iface_num: u16) {
		unsafe {
			libusb_claim_interface(self.ptr(), iface_num as c_int);
		}
	}

	pub unsafe fn submit_transfer_sync(&self,
		endpoint: u8,
		transfer_type: libusb_transfer_type,
		length: usize,
		buffer: *mut u8,
		timeout: u32) -> (libusb_transfer_status, usize) {

		let completed: UnsafeCell<c_int> = UnsafeCell::new(0);

		extern fn callback(transfer: *mut libusb_transfer) {
			unsafe {
				let completed: &UnsafeCell<c_int> = transmute((*transfer).user_data);
				*completed.get() = 1;
			}
		}

		let t = libusb_alloc_transfer(0);
		(*t).dev_handle = self.ptr();
		(*t).endpoint = endpoint;
		(*t).transfer_type = transfer_type as u8;
		(*t).timeout = timeout;
		(*t).length = length as c_int;
		(*t).callback = callback;
		(*t).user_data = transmute(&completed);
		(*t).buffer = buffer;

		libusb_submit_transfer(t);

		while *completed.get() == 0{
			libusb_handle_events_completed(self.ctx.ptr(), completed.get());
		}

		let r = ((*t).get_status(), (*t).actual_length as usize);
		libusb_free_transfer(t);
		return r;
	}

	pub fn read(&self,
			endpoint: u8,
			transfer_type: libusb_transfer_type,
			size: usize,
			timeout: u32
			) -> Result<Vec<u8>, libusb_transfer_status> {
		let mut buf: Vec<u8> = repeat(0u8).take(size).collect();
		unsafe {
			let ptr = buf.as_mut_ptr();
			let (status, actual_length) = self.submit_transfer_sync(
				endpoint, transfer_type, size, ptr, timeout);

			if status == LIBUSB_TRANSFER_COMPLETED {
				buf.truncate(actual_length);
				Ok(buf)
			} else {
				Err(status)
			}
		}
	}

	pub fn write(&self,
			endpoint: u8,
			transfer_type: libusb_transfer_type,
			buf: &[u8],
			timeout: u32
			) -> Result<(), libusb_transfer_status> {
		unsafe {
			let ptr = buf.as_ptr() as *mut u8;

			let (status, _) = self.submit_transfer_sync(
				endpoint, transfer_type, buf.len(), ptr, timeout);

			if status == LIBUSB_TRANSFER_COMPLETED {
				Ok(())
			} else {
				Err(status)
			}
		}
	}

	pub fn ctrl_read(&self, bmRequestType: u8, bRequest: u8,
		wValue:u16, wIndex: u16, length: usize, timeout: u32) -> Result<Vec<u8>, libusb_transfer_status> {

		let setup_length = size_of::<libusb_control_setup>();
		let total_length = setup_length + length;
		let mut buf: Vec<u8> = repeat(0u8).take(total_length).collect();
		let ptr = fill_setup_buf(&mut buf, bmRequestType, bRequest, wValue, wIndex, length);

		unsafe{
			let (status, actual_length) = self.submit_transfer_sync(
				0, LIBUSB_TRANSFER_TYPE_CONTROL, total_length, ptr, timeout);

			if status == LIBUSB_TRANSFER_COMPLETED {
				Ok(buf[setup_length..setup_length+actual_length].to_vec())
			} else {
				Err(status)
			}
		}
	}

	pub fn ctrl_write(&self, bmRequestType: u8, bRequest: u8,
		wValue:u16, wIndex: u16, buf: &[u8], timeout: u32) -> Result<(), libusb_transfer_status> {
		let mut setup_buf: Vec<_> = repeat(0u8).take(size_of::<libusb_control_setup>()).collect();
		fill_setup_buf(&mut setup_buf, bmRequestType, bRequest, wValue, wIndex, buf.len());
		setup_buf.push_all(buf);
		self.write(0, LIBUSB_TRANSFER_TYPE_CONTROL, &setup_buf, timeout)
	}
}

impl<'c> Drop for DeviceHandle<'c> {
	fn drop(&mut self) {
		unsafe {
			libusb_close(self.dev);
		}
	}
}

fn fill_setup_buf(buf: &mut [u8], bmRequestType: u8,
	bRequest: u8, wValue:u16, wIndex: u16, length: usize) -> *mut u8 {
	let ptr = buf.as_mut_ptr();
	let setup = ptr as *mut libusb_control_setup;

	assert!(buf.len() >= 8);
	assert!(length <= (std::u16::MAX as usize));

	unsafe {
		(*setup).bmRequestType = bmRequestType;
		(*setup).bRequest = bRequest;
		(*setup).wValue = wValue.to_le();
		(*setup).wIndex = wIndex.to_le();
		(*setup).wLength = (length as u16).to_le();
	}

	return ptr;
}
<|endoftext|>


<commit_before>use crate::utils::{match_def_path, span_lint_and_help};
use if_chain::if_chain;
use rustc_hir::def_id::DefId;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};

declare_clippy_lint! {
    /// **What it does:** Checks for usage of invalid atomic
    /// ordering in atomic loads/stores/exchanges/updates and
    /// memory fences.
    ///
    /// **Why is this bad?** Using an invalid atomic ordering
    /// will cause a panic at run-time.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust,no_run
    /// # use std::sync::atomic::{self, AtomicU8, Ordering};
    ///
    /// let x = AtomicU8::new(0);
    ///
    /// let _ = x.load(Ordering::Release);
    /// let _ = x.load(Ordering::AcqRel);
    ///
    /// x.store(1, Ordering::Acquire);
    /// x.store(2, Ordering::AcqRel);
    ///
    /// atomic::fence(Ordering::Relaxed);
    /// atomic::compiler_fence(Ordering::Relaxed);
    ///
    /// let _ = x.compare_exchange(1, 2, Ordering::Relaxed, Ordering::SeqCst);
    /// let _ = x.compare_exchange_weak(2, 3, Ordering::SeqCst, Ordering::Release);
    /// let _ = x.fetch_update(Ordering::AcqRel, Ordering::AcqRel, |val| Some(val + val));
    /// ```
    pub INVALID_ATOMIC_ORDERING,
    correctness,
    "usage of invalid atomic ordering in atomic operations and memory fences"
}

declare_lint_pass!(AtomicOrdering => [INVALID_ATOMIC_ORDERING]);

const ATOMIC_TYPES: [&str; 12] = [
    "AtomicBool",
    "AtomicI8",
    "AtomicI16",
    "AtomicI32",
    "AtomicI64",
    "AtomicIsize",
    "AtomicPtr",
    "AtomicU8",
    "AtomicU16",
    "AtomicU32",
    "AtomicU64",
    "AtomicUsize",
];

fn type_is_atomic(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
    if let ty::Adt(&ty::AdtDef { did, .. }, _) = cx.typeck_results().expr_ty(expr).kind() {
        ATOMIC_TYPES
            .iter()
            .any(|ty| match_def_path(cx, did, &["core", "sync", "atomic", ty]))
    } else {
        false
    }
}

fn match_ordering_def_path(cx: &LateContext<'_>, did: DefId, orderings: &[&str]) -> bool {
    orderings
        .iter()
        .any(|ordering| match_def_path(cx, did, &["core", "sync", "atomic", "Ordering", ordering]))
}

fn check_atomic_load_store(cx: &LateContext<'_>, expr: &Expr<'_>) {
    if_chain! {
        if let ExprKind::MethodCall(ref method_path, _, args, _) = &expr.kind;
        let method = method_path.ident.name.as_str();
        if type_is_atomic(cx, &args[0]);
        if method == "load" || method == "store";
        let ordering_arg = if method == "load" { &args[1] } else { &args[2] };
        if let ExprKind::Path(ref ordering_qpath) = ordering_arg.kind;
        if let Some(ordering_def_id) = cx.qpath_res(ordering_qpath, ordering_arg.hir_id).opt_def_id();
        then {
            if method == "load" &&
                match_ordering_def_path(cx, ordering_def_id, &["Release", "AcqRel"]) {
                span_lint_and_help(
                    cx,
                    INVALID_ATOMIC_ORDERING,
                    ordering_arg.span,
                    "atomic loads cannot have `Release` and `AcqRel` ordering",
                    None,
                    "consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`"
                );
            } else if method == "store" &&
                match_ordering_def_path(cx, ordering_def_id, &["Acquire", "AcqRel"]) {
                span_lint_and_help(
                    cx,
                    INVALID_ATOMIC_ORDERING,
                    ordering_arg.span,
                    "atomic stores cannot have `Acquire` and `AcqRel` ordering",
                    None,
                    "consider using ordering modes `Release`, `SeqCst` or `Relaxed`"
                );
            }
        }
    }
}

fn check_memory_fence(cx: &LateContext<'_>, expr: &Expr<'_>) {
    if_chain! {
        if let ExprKind::Call(ref func, ref args) = expr.kind;
        if let ExprKind::Path(ref func_qpath) = func.kind;
        if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id();
        if ["fence", "compiler_fence"]
            .iter()
            .any(|func| match_def_path(cx, def_id, &["core", "sync", "atomic", func]));
        if let ExprKind::Path(ref ordering_qpath) = &args[0].kind;
        if let Some(ordering_def_id) = cx.qpath_res(ordering_qpath, args[0].hir_id).opt_def_id();
        if match_ordering_def_path(cx, ordering_def_id, &["Relaxed"]);
        then {
            span_lint_and_help(
                cx,
                INVALID_ATOMIC_ORDERING,
                args[0].span,
                "memory fences cannot have `Relaxed` ordering",
                None,
                "consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst`"
            );
        }
    }
}

fn opt_ordering_defid(cx: &LateContext<'_>, ord_arg: &Expr<'_>) -> Option<DefId> {
    if let ExprKind::Path(ref ord_qpath) = ord_arg.kind {
        cx.qpath_res(ord_qpath, ord_arg.hir_id).opt_def_id()
    } else {
        None
    }
}
fn check_atomic_compare_exchange(cx: &LateContext<'_>, expr: &Expr<'_>) {
    if_chain! {
        if let ExprKind::MethodCall(ref method_path, _, args, _) = &expr.kind;
        let method = method_path.ident.name.as_str();
        if type_is_atomic(cx, &args[0]);
        if method == "compare_exchange" || method == "compare_exchange_weak" || method == "fetch_update";
        let (success_order_arg, failure_order_arg) = if method == "fetch_update" {
            (&args[1], &args[2])
        } else {
            (&args[3], &args[4])
        };
        if let Some(fail_ordering_def_id) = opt_ordering_defid(cx, failure_order_arg);
        then {
            // Helper type holding on to some checking and error reporting data. Has
            // - (success ordering name,
            // - list of failure orderings forbidden by the success order,
            // - suggestion message)
            type OrdLintInfo = (&'static str, &'static [&'static str], &'static str);
            let relaxed: OrdLintInfo = ("Relaxed", &["SeqCst", "Acquire"], "ordering mode `Relaxed`");
            let acquire: OrdLintInfo = ("Acquire", &["SeqCst"], "ordering modes `Acquire` or `Relaxed`");
            let seq_cst: OrdLintInfo = ("SeqCst", &[], "ordering modes `Acquire`, `SeqCst` or `Relaxed`");
            let release = ("Release", relaxed.1, relaxed.2);
            let acqrel = ("AcqRel", acquire.1, acquire.2);
            let search = [relaxed, acquire, seq_cst, release, acqrel];

            let success_lint_info = opt_ordering_defid(cx, success_order_arg)
                .and_then(|success_ord_def_id| -> Option<OrdLintInfo> {
                    search
                        .iter()
                        .find(|(ordering, ..)| {
                            match_def_path(cx, success_ord_def_id,
                                &["core", "sync", "atomic", "Ordering", ordering])
                        })
                        .copied()
                });

            if match_ordering_def_path(cx, fail_ordering_def_id, &["Release", "AcqRel"]) {
                // If we don't know the success order is, use what we'd suggest
                // if it were maximally permissive.
                let suggested = success_lint_info.unwrap_or(seq_cst).2;
                span_lint_and_help(
                    cx,
                    INVALID_ATOMIC_ORDERING,
                    failure_order_arg.span,
                    &format!(
                        "{}'s failure ordering may not be `Release` or `AcqRel`",
                        method,
                    ),
                    None,
                    &format!("consider using {} instead", suggested),
                );
            } else if let Some((success_ord_name, bad_ords_given_success, suggested)) = success_lint_info {
                if match_ordering_def_path(cx, fail_ordering_def_id, bad_ords_given_success) {
                    span_lint_and_help(
                        cx,
                        INVALID_ATOMIC_ORDERING,
                        failure_order_arg.span,
                        &format!(
                            "{}'s failure ordering may not stronger than the success ordering of `{}`",
                            method,
                            success_ord_name,
                        ),
                        None,
                        &format!("consider using {} instead", suggested),
                    );
                }
            }
        }
    }
}

impl<'tcx> LateLintPass<'tcx> for AtomicOrdering {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
        check_atomic_load_store(cx, expr);
        check_memory_fence(cx, expr);
        check_atomic_compare_exchange(cx, expr);
    }
}
<commit_msg>Address small review comments<commit_after>use crate::utils::{match_def_path, span_lint_and_help};
use if_chain::if_chain;
use rustc_hir::def_id::DefId;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};

declare_clippy_lint! {
    /// **What it does:** Checks for usage of invalid atomic
    /// ordering in atomic loads/stores/exchanges/updates and
    /// memory fences.
    ///
    /// **Why is this bad?** Using an invalid atomic ordering
    /// will cause a panic at run-time.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust,no_run
    /// # use std::sync::atomic::{self, AtomicU8, Ordering};
    ///
    /// let x = AtomicU8::new(0);
    ///
    /// let _ = x.load(Ordering::Release);
    /// let _ = x.load(Ordering::AcqRel);
    ///
    /// x.store(1, Ordering::Acquire);
    /// x.store(2, Ordering::AcqRel);
    ///
    /// atomic::fence(Ordering::Relaxed);
    /// atomic::compiler_fence(Ordering::Relaxed);
    ///
    /// let _ = x.compare_exchange(1, 2, Ordering::Relaxed, Ordering::SeqCst);
    /// let _ = x.compare_exchange_weak(2, 3, Ordering::SeqCst, Ordering::Release);
    /// let _ = x.fetch_update(Ordering::AcqRel, Ordering::AcqRel, |val| Some(val + val));
    /// ```
    pub INVALID_ATOMIC_ORDERING,
    correctness,
    "usage of invalid atomic ordering in atomic operations and memory fences"
}

declare_lint_pass!(AtomicOrdering => [INVALID_ATOMIC_ORDERING]);

const ATOMIC_TYPES: [&str; 12] = [
    "AtomicBool",
    "AtomicI8",
    "AtomicI16",
    "AtomicI32",
    "AtomicI64",
    "AtomicIsize",
    "AtomicPtr",
    "AtomicU8",
    "AtomicU16",
    "AtomicU32",
    "AtomicU64",
    "AtomicUsize",
];

fn type_is_atomic(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
    if let ty::Adt(&ty::AdtDef { did, .. }, _) = cx.typeck_results().expr_ty(expr).kind() {
        ATOMIC_TYPES
            .iter()
            .any(|ty| match_def_path(cx, did, &["core", "sync", "atomic", ty]))
    } else {
        false
    }
}

fn match_ordering_def_path(cx: &LateContext<'_>, did: DefId, orderings: &[&str]) -> bool {
    orderings
        .iter()
        .any(|ordering| match_def_path(cx, did, &["core", "sync", "atomic", "Ordering", ordering]))
}

fn check_atomic_load_store(cx: &LateContext<'_>, expr: &Expr<'_>) {
    if_chain! {
        if let ExprKind::MethodCall(ref method_path, _, args, _) = &expr.kind;
        let method = method_path.ident.name.as_str();
        if type_is_atomic(cx, &args[0]);
        if method == "load" || method == "store";
        let ordering_arg = if method == "load" { &args[1] } else { &args[2] };
        if let ExprKind::Path(ref ordering_qpath) = ordering_arg.kind;
        if let Some(ordering_def_id) = cx.qpath_res(ordering_qpath, ordering_arg.hir_id).opt_def_id();
        then {
            if method == "load" &&
                match_ordering_def_path(cx, ordering_def_id, &["Release", "AcqRel"]) {
                span_lint_and_help(
                    cx,
                    INVALID_ATOMIC_ORDERING,
                    ordering_arg.span,
                    "atomic loads cannot have `Release` and `AcqRel` ordering",
                    None,
                    "consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`"
                );
            } else if method == "store" &&
                match_ordering_def_path(cx, ordering_def_id, &["Acquire", "AcqRel"]) {
                span_lint_and_help(
                    cx,
                    INVALID_ATOMIC_ORDERING,
                    ordering_arg.span,
                    "atomic stores cannot have `Acquire` and `AcqRel` ordering",
                    None,
                    "consider using ordering modes `Release`, `SeqCst` or `Relaxed`"
                );
            }
        }
    }
}

fn check_memory_fence(cx: &LateContext<'_>, expr: &Expr<'_>) {
    if_chain! {
        if let ExprKind::Call(ref func, ref args) = expr.kind;
        if let ExprKind::Path(ref func_qpath) = func.kind;
        if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id();
        if ["fence", "compiler_fence"]
            .iter()
            .any(|func| match_def_path(cx, def_id, &["core", "sync", "atomic", func]));
        if let ExprKind::Path(ref ordering_qpath) = &args[0].kind;
        if let Some(ordering_def_id) = cx.qpath_res(ordering_qpath, args[0].hir_id).opt_def_id();
        if match_ordering_def_path(cx, ordering_def_id, &["Relaxed"]);
        then {
            span_lint_and_help(
                cx,
                INVALID_ATOMIC_ORDERING,
                args[0].span,
                "memory fences cannot have `Relaxed` ordering",
                None,
                "consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst`"
            );
        }
    }
}

fn opt_ordering_defid(cx: &LateContext<'_>, ord_arg: &Expr<'_>) -> Option<DefId> {
    if let ExprKind::Path(ref ord_qpath) = ord_arg.kind {
        cx.qpath_res(ord_qpath, ord_arg.hir_id).opt_def_id()
    } else {
        None
    }
}

fn check_atomic_compare_exchange(cx: &LateContext<'_>, expr: &Expr<'_>) {
    if_chain! {
        if let ExprKind::MethodCall(ref method_path, _, args, _) = &expr.kind;
        let method = method_path.ident.name.as_str();
        if type_is_atomic(cx, &args[0]);
        if method == "compare_exchange" || method == "compare_exchange_weak" || method == "fetch_update";
        let (success_order_arg, failure_order_arg) = if method == "fetch_update" {
            (&args[1], &args[2])
        } else {
            (&args[3], &args[4])
        };
        if let Some(fail_ordering_def_id) = opt_ordering_defid(cx, failure_order_arg);
        then {
            // Helper type holding on to some checking and error reporting data. Has
            // - (success ordering name,
            // - list of failure orderings forbidden by the success order,
            // - suggestion message)
            type OrdLintInfo = (&'static str, &'static [&'static str], &'static str);
            let relaxed: OrdLintInfo = ("Relaxed", &["SeqCst", "Acquire"], "ordering mode `Relaxed`");
            let acquire: OrdLintInfo = ("Acquire", &["SeqCst"], "ordering modes `Acquire` or `Relaxed`");
            let seq_cst: OrdLintInfo = ("SeqCst", &[], "ordering modes `Acquire`, `SeqCst` or `Relaxed`");
            let release = ("Release", relaxed.1, relaxed.2);
            let acqrel = ("AcqRel", acquire.1, acquire.2);
            let search = [relaxed, acquire, seq_cst, release, acqrel];

            let success_lint_info = opt_ordering_defid(cx, success_order_arg)
                .and_then(|success_ord_def_id| -> Option<OrdLintInfo> {
                    search
                        .iter()
                        .find(|(ordering, ..)| {
                            match_def_path(cx, success_ord_def_id,
                                &["core", "sync", "atomic", "Ordering", ordering])
                        })
                        .copied()
                });

            if match_ordering_def_path(cx, fail_ordering_def_id, &["Release", "AcqRel"]) {
                // If we don't know the success order is, use what we'd suggest
                // if it were maximally permissive.
                let suggested = success_lint_info.unwrap_or(seq_cst).2;
                span_lint_and_help(
                    cx,
                    INVALID_ATOMIC_ORDERING,
                    failure_order_arg.span,
                    &format!(
                        "{}'s failure ordering may not be `Release` or `AcqRel`",
                        method,
                    ),
                    None,
                    &format!("consider using {} instead", suggested),
                );
            } else if let Some((success_ord_name, bad_ords_given_success, suggested)) = success_lint_info {
                if match_ordering_def_path(cx, fail_ordering_def_id, bad_ords_given_success) {
                    span_lint_and_help(
                        cx,
                        INVALID_ATOMIC_ORDERING,
                        failure_order_arg.span,
                        &format!(
                            "{}'s failure ordering may not be stronger than the success ordering of `{}`",
                            method,
                            success_ord_name,
                        ),
                        None,
                        &format!("consider using {} instead", suggested),
                    );
                }
            }
        }
    }
}

impl<'tcx> LateLintPass<'tcx> for AtomicOrdering {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
        check_atomic_load_store(cx, expr);
        check_memory_fence(cx, expr);
        check_atomic_compare_exchange(cx, expr);
    }
}
<|endoftext|>