<commit_before>use if_chain::if_chain;
use rustc_ast::ast::Attribute;
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_expr, FnKind, NestedVisitorMap, Visitor};
use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, HirId, MatchSource, PatKind, StmtKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::hir::map::Map;
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
use rustc_span::sym;

use crate::utils::{fn_def_id, in_macro, match_qpath, snippet_opt, span_lint_and_sugg, span_lint_and_then};

declare_clippy_lint! {
    /// **What it does:** Checks for `let`-bindings, which are subsequently
    /// returned.
    ///
    /// **Why is this bad?** It is just extraneous code. Remove it to make your code
    /// more rusty.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// fn foo() -> String {
    ///     let x = String::new();
    ///     x
    /// }
    /// ```
    /// instead, use
    /// ```
    /// fn foo() -> String {
    ///     String::new()
    /// }
    /// ```
    pub LET_AND_RETURN,
    style,
    "creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block"
}

declare_clippy_lint! {
    /// **What it does:** Checks for return statements at the end of a block.
    ///
    /// **Why is this bad?** Removing the `return` and semicolon will make the code
    /// more rusty.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// fn foo(x: usize) -> usize {
    ///     return x;
    /// }
    /// ```
    /// simplify to
    /// ```rust
    /// fn foo(x: usize) -> usize {
    ///     x
    /// }
    /// ```
    pub NEEDLESS_RETURN,
    style,
    "using a return statement like `return expr;` where an expression would suffice"
}

#[derive(PartialEq, Eq, Copy, Clone)]
enum RetReplacement {
    Empty,
    Block,
}

declare_lint_pass!(Return => [LET_AND_RETURN, NEEDLESS_RETURN]);

impl<'tcx> LateLintPass<'tcx> for Return {
    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
        // we need both a let-binding stmt and an expr
        if_chain! {
            if let Some(retexpr) = block.expr;
            if let Some(stmt) = block.stmts.iter().last();
            if let StmtKind::Local(local) = &stmt.kind;
            if local.ty.is_none();
            if local.attrs.is_empty();
            if let Some(initexpr) = &local.init;
            if let PatKind::Binding(.., ident, _) = local.pat.kind;
            if let ExprKind::Path(qpath) = &retexpr.kind;
            if match_qpath(qpath, &[&*ident.name.as_str()]);
            if !last_statement_borrows(cx, initexpr);
            if !in_external_macro(cx.sess(), initexpr.span);
            if !in_external_macro(cx.sess(), retexpr.span);
            if !in_external_macro(cx.sess(), local.span);
            if !in_macro(local.span);
            then {
                span_lint_and_then(
                    cx,
                    LET_AND_RETURN,
                    retexpr.span,
                    "returning the result of a `let` binding from a block",
                    |err| {
                        err.span_label(local.span, "unnecessary `let` binding");

                        if let Some(mut snippet) = snippet_opt(cx, initexpr.span) {
                            if !cx.typeck_results().expr_adjustments(&retexpr).is_empty() {
                                snippet.push_str(" as _");
                            }
                            err.multipart_suggestion(
                                "return the expression directly",
                                vec![
                                    (local.span, String::new()),
                                    (retexpr.span, snippet),
                                ],
                                Applicability::MachineApplicable,
                            );
                        } else {
                            err.span_help(initexpr.span, "this expression can be directly returned");
                        }
                    },
                );
            }
        }
    }

    fn check_fn(
        &mut self,
        cx: &LateContext<'tcx>,
        kind: FnKind<'tcx>,
        _: &'tcx FnDecl<'tcx>,
        body: &'tcx Body<'tcx>,
        _: Span,
        _: HirId,
    ) {
        match kind {
            FnKind::Closure => {
                // when returning without value in closure, replace this `return`
                // with an empty block to prevent invalid suggestion (see #6501)
                let replacement = if let ExprKind::Ret(None) = &body.value.kind {
                    RetReplacement::Block
                } else {
                    RetReplacement::Empty
                };
                check_final_expr(cx, &body.value, Some(body.value.span), replacement)
            },
            FnKind::ItemFn(..) | FnKind::Method(..) => {
                if let ExprKind::Block(ref block, _) = body.value.kind {
                    check_block_return(cx, block);
                }
            },
        }
    }
}

fn attr_is_cfg(attr: &Attribute) -> bool {
    attr.meta_item_list().is_some() && attr.has_name(sym::cfg)
}

fn check_block_return<'tcx>(cx: &LateContext<'tcx>, block: &Block<'tcx>) {
    if let Some(expr) = block.expr {
        check_final_expr(cx, expr, Some(expr.span), RetReplacement::Empty);
    } else if let Some(stmt) = block.stmts.iter().last() {
        match stmt.kind {
            StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => {
                check_final_expr(cx, expr, Some(stmt.span), RetReplacement::Empty);
            },
            _ => (),
        }
    }
}

fn check_final_expr<'tcx>(
    cx: &LateContext<'tcx>,
    expr: &'tcx Expr<'tcx>,
    span: Option<Span>,
    replacement: RetReplacement,
) {
    match expr.kind {
        // simple return is always "bad"
        ExprKind::Ret(ref inner) => {
            // allow `#[cfg(a)] return a; #[cfg(b)] return b;`
            if !expr.attrs.iter().any(attr_is_cfg) {
                let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner));
                if !borrows {
                    emit_return_lint(
                        cx,
                        span.expect("`else return` is not possible"),
                        inner.as_ref().map(|i| i.span),
                        replacement,
                    );
                }
            }
        },
        // a whole block? check it!
        ExprKind::Block(ref block, _) => {
            check_block_return(cx, block);
        },
        ExprKind::If(_, then, else_clause_opt) => {
            if let ExprKind::Block(ref ifblock, _) = then.kind {
                check_block_return(cx, ifblock);
            }
            if let Some(else_clause) = else_clause_opt {
                check_final_expr(cx, else_clause, None, RetReplacement::Empty);
            }
        },
        // a match expr, check all arms
        // an if/if let expr, check both exprs
        // note, if without else is going to be a type checking error anyways
        // (except for unit type functions) so we don't match it
        ExprKind::Match(_, ref arms, source) => match source {
            MatchSource::Normal => {
                for arm in arms.iter() {
                    check_final_expr(cx, &arm.body, Some(arm.body.span), RetReplacement::Block);
                }
            },
            MatchSource::IfLetDesugar {
                contains_else_clause: true,
            } => {
                if let ExprKind::Block(ref ifblock, _) = arms[0].body.kind {
                    check_block_return(cx, ifblock);
                }
                check_final_expr(cx, arms[1].body, None, RetReplacement::Empty);
            },
            _ => (),
        },
        _ => (),
    }
}

fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, inner_span: Option<Span>, replacement: RetReplacement) {
    if ret_span.from_expansion() {
        return;
    }
    match inner_span {
        Some(inner_span) => {
            if in_external_macro(cx.tcx.sess, inner_span) || inner_span.from_expansion() {
                return;
            }

            span_lint_and_then(cx, NEEDLESS_RETURN, ret_span, "unneeded `return` statement", |diag| {
                if let Some(snippet) = snippet_opt(cx, inner_span) {
                    diag.span_suggestion(ret_span, "remove `return`", snippet, Applicability::MachineApplicable);
                }
            })
        },
        None => match replacement {
            RetReplacement::Empty => {
                span_lint_and_sugg(
                    cx,
                    NEEDLESS_RETURN,
                    ret_span,
                    "unneeded `return` statement",
                    "remove `return`",
                    String::new(),
                    Applicability::MachineApplicable,
                );
            },
            RetReplacement::Block => {
                span_lint_and_sugg(
                    cx,
                    NEEDLESS_RETURN,
                    ret_span,
                    "unneeded `return` statement",
                    "replace `return` with an empty block",
                    "{}".to_string(),
                    Applicability::MachineApplicable,
                );
            },
        },
    }
}

fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
    let mut visitor = BorrowVisitor { cx, borrows: false };
    walk_expr(&mut visitor, expr);
    visitor.borrows
}

struct BorrowVisitor<'a, 'tcx> {
    cx: &'a LateContext<'tcx>,
    borrows: bool,
}

impl<'tcx> Visitor<'tcx> for BorrowVisitor<'_, 'tcx> {
    type Map = Map<'tcx>;

    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
        if self.borrows {
            return;
        }

        if let Some(def_id) = fn_def_id(self.cx, expr) {
            self.borrows = self
                .cx
                .tcx
                .fn_sig(def_id)
                .output()
                .skip_binder()
                .walk()
                .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_)));
        }

        walk_expr(self, expr);
    }

    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
        NestedVisitorMap::None
    }
}
<commit_msg>Remove hir::Local::attrs.<commit_after>use if_chain::if_chain;
use rustc_ast::ast::Attribute;
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_expr, FnKind, NestedVisitorMap, Visitor};
use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, HirId, MatchSource, PatKind, StmtKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::hir::map::Map;
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;
use rustc_span::sym;

use crate::utils::{fn_def_id, in_macro, match_qpath, snippet_opt, span_lint_and_sugg, span_lint_and_then};

declare_clippy_lint! {
    /// **What it does:** Checks for `let`-bindings, which are subsequently
    /// returned.
    ///
    /// **Why is this bad?** It is just extraneous code. Remove it to make your code
    /// more rusty.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// fn foo() -> String {
    ///     let x = String::new();
    ///     x
    /// }
    /// ```
    /// instead, use
    /// ```
    /// fn foo() -> String {
    ///     String::new()
    /// }
    /// ```
    pub LET_AND_RETURN,
    style,
    "creating a let-binding and then immediately returning it like `let x = expr; x` at the end of a block"
}

declare_clippy_lint! {
    /// **What it does:** Checks for return statements at the end of a block.
    ///
    /// **Why is this bad?** Removing the `return` and semicolon will make the code
    /// more rusty.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// fn foo(x: usize) -> usize {
    ///     return x;
    /// }
    /// ```
    /// simplify to
    /// ```rust
    /// fn foo(x: usize) -> usize {
    ///     x
    /// }
    /// ```
    pub NEEDLESS_RETURN,
    style,
    "using a return statement like `return expr;` where an expression would suffice"
}

#[derive(PartialEq, Eq, Copy, Clone)]
enum RetReplacement {
    Empty,
    Block,
}

declare_lint_pass!(Return => [LET_AND_RETURN, NEEDLESS_RETURN]);

impl<'tcx> LateLintPass<'tcx> for Return {
    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
        // we need both a let-binding stmt and an expr
        if_chain! {
            if let Some(retexpr) = block.expr;
            if let Some(stmt) = block.stmts.iter().last();
            if let StmtKind::Local(local) = &stmt.kind;
            if local.ty.is_none();
            if cx.tcx.hir().attrs(local.hir_id).is_empty();
            if let Some(initexpr) = &local.init;
            if let PatKind::Binding(.., ident, _) = local.pat.kind;
            if let ExprKind::Path(qpath) = &retexpr.kind;
            if match_qpath(qpath, &[&*ident.name.as_str()]);
            if !last_statement_borrows(cx, initexpr);
            if !in_external_macro(cx.sess(), initexpr.span);
            if !in_external_macro(cx.sess(), retexpr.span);
            if !in_external_macro(cx.sess(), local.span);
            if !in_macro(local.span);
            then {
                span_lint_and_then(
                    cx,
                    LET_AND_RETURN,
                    retexpr.span,
                    "returning the result of a `let` binding from a block",
                    |err| {
                        err.span_label(local.span, "unnecessary `let` binding");

                        if let Some(mut snippet) = snippet_opt(cx, initexpr.span) {
                            if !cx.typeck_results().expr_adjustments(&retexpr).is_empty() {
                                snippet.push_str(" as _");
                            }
                            err.multipart_suggestion(
                                "return the expression directly",
                                vec![
                                    (local.span, String::new()),
                                    (retexpr.span, snippet),
                                ],
                                Applicability::MachineApplicable,
                            );
                        } else {
                            err.span_help(initexpr.span, "this expression can be directly returned");
                        }
                    },
                );
            }
        }
    }

    fn check_fn(
        &mut self,
        cx: &LateContext<'tcx>,
        kind: FnKind<'tcx>,
        _: &'tcx FnDecl<'tcx>,
        body: &'tcx Body<'tcx>,
        _: Span,
        _: HirId,
    ) {
        match kind {
            FnKind::Closure => {
                // when returning without value in closure, replace this `return`
                // with an empty block to prevent invalid suggestion (see #6501)
                let replacement = if let ExprKind::Ret(None) = &body.value.kind {
                    RetReplacement::Block
                } else {
                    RetReplacement::Empty
                };
                check_final_expr(cx, &body.value, Some(body.value.span), replacement)
            },
            FnKind::ItemFn(..) | FnKind::Method(..) => {
                if let ExprKind::Block(ref block, _) = body.value.kind {
                    check_block_return(cx, block);
                }
            },
        }
    }
}

fn attr_is_cfg(attr: &Attribute) -> bool {
    attr.meta_item_list().is_some() && attr.has_name(sym::cfg)
}

fn check_block_return<'tcx>(cx: &LateContext<'tcx>, block: &Block<'tcx>) {
    if let Some(expr) = block.expr {
        check_final_expr(cx, expr, Some(expr.span), RetReplacement::Empty);
    } else if let Some(stmt) = block.stmts.iter().last() {
        match stmt.kind {
            StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => {
                check_final_expr(cx, expr, Some(stmt.span), RetReplacement::Empty);
            },
            _ => (),
        }
    }
}

fn check_final_expr<'tcx>(
    cx: &LateContext<'tcx>,
    expr: &'tcx Expr<'tcx>,
    span: Option<Span>,
    replacement: RetReplacement,
) {
    match expr.kind {
        // simple return is always "bad"
        ExprKind::Ret(ref inner) => {
            // allow `#[cfg(a)] return a; #[cfg(b)] return b;`
            if !expr.attrs.iter().any(attr_is_cfg) {
                let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner));
                if !borrows {
                    emit_return_lint(
                        cx,
                        span.expect("`else return` is not possible"),
                        inner.as_ref().map(|i| i.span),
                        replacement,
                    );
                }
            }
        },
        // a whole block? check it!
        ExprKind::Block(ref block, _) => {
            check_block_return(cx, block);
        },
        ExprKind::If(_, then, else_clause_opt) => {
            if let ExprKind::Block(ref ifblock, _) = then.kind {
                check_block_return(cx, ifblock);
            }
            if let Some(else_clause) = else_clause_opt {
                check_final_expr(cx, else_clause, None, RetReplacement::Empty);
            }
        },
        // a match expr, check all arms
        // an if/if let expr, check both exprs
        // note, if without else is going to be a type checking error anyways
        // (except for unit type functions) so we don't match it
        ExprKind::Match(_, ref arms, source) => match source {
            MatchSource::Normal => {
                for arm in arms.iter() {
                    check_final_expr(cx, &arm.body, Some(arm.body.span), RetReplacement::Block);
                }
            },
            MatchSource::IfLetDesugar {
                contains_else_clause: true,
            } => {
                if let ExprKind::Block(ref ifblock, _) = arms[0].body.kind {
                    check_block_return(cx, ifblock);
                }
                check_final_expr(cx, arms[1].body, None, RetReplacement::Empty);
            },
            _ => (),
        },
        _ => (),
    }
}

fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, inner_span: Option<Span>, replacement: RetReplacement) {
    if ret_span.from_expansion() {
        return;
    }
    match inner_span {
        Some(inner_span) => {
            if in_external_macro(cx.tcx.sess, inner_span) || inner_span.from_expansion() {
                return;
            }

            span_lint_and_then(cx, NEEDLESS_RETURN, ret_span, "unneeded `return` statement", |diag| {
                if let Some(snippet) = snippet_opt(cx, inner_span) {
                    diag.span_suggestion(ret_span, "remove `return`", snippet, Applicability::MachineApplicable);
                }
            })
        },
        None => match replacement {
            RetReplacement::Empty => {
                span_lint_and_sugg(
                    cx,
                    NEEDLESS_RETURN,
                    ret_span,
                    "unneeded `return` statement",
                    "remove `return`",
                    String::new(),
                    Applicability::MachineApplicable,
                );
            },
            RetReplacement::Block => {
                span_lint_and_sugg(
                    cx,
                    NEEDLESS_RETURN,
                    ret_span,
                    "unneeded `return` statement",
                    "replace `return` with an empty block",
                    "{}".to_string(),
                    Applicability::MachineApplicable,
                );
            },
        },
    }
}

fn last_statement_borrows<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
    let mut visitor = BorrowVisitor { cx, borrows: false };
    walk_expr(&mut visitor, expr);
    visitor.borrows
}

struct BorrowVisitor<'a, 'tcx> {
    cx: &'a LateContext<'tcx>,
    borrows: bool,
}

impl<'tcx> Visitor<'tcx> for BorrowVisitor<'_, 'tcx> {
    type Map = Map<'tcx>;

    fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
        if self.borrows {
            return;
        }

        if let Some(def_id) = fn_def_id(self.cx, expr) {
            self.borrows = self
                .cx
                .tcx
                .fn_sig(def_id)
                .output()
                .skip_binder()
                .walk()
                .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_)));
        }

        walk_expr(self, expr);
    }

    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
        NestedVisitorMap::None
    }
}
<|endoftext|>


<commit_before>extern crate env_logger;
#[macro_use]
extern crate log;
extern crate edge;

use edge::{Edge, Cookie, Request, Response, Status};
use edge::header::AccessControlAllowOrigin;
use std::sync::atomic::{AtomicUsize, Ordering};

use std::collections::BTreeMap;
use edge::value;

struct MyApp {
    tmpl_path: String,
    counter: AtomicUsize
}

impl MyApp {

    fn new() -> MyApp {
        MyApp {
            tmpl_path: "toto".to_owned(),
            counter: AtomicUsize::new(0)
        }
    }

    fn home(&self, _req: &mut Request, mut res: Response) {
        let cnt = self.counter.fetch_add(1, Ordering::SeqCst);

        println!("in home, count = {}, path = {}", cnt, self.tmpl_path);

        // set length manually because we're streaming
        res.status(Status::Ok).len(80).content_type("text/html").header(AccessControlAllowOrigin::Any);
        res.send("<title>home</title>
Hello, world!
")
    }

    fn hello(&self,  req: &mut Request, mut res: Response) {
        let first_name = req.param("first_name").unwrap_or("John");
        let last_name = req.param("last_name").unwrap_or("Doe");

        let mut data = BTreeMap::new();
        data.insert("first_name", value::to_value(first_name));
        data.insert("last_name", value::to_value(last_name));

        res.content_type("text/plain");
        res.render("views/hello.hbs", data)
    }

    fn settings(&self, req: &mut Request, mut res: Response) {
        let mut cookies = req.cookies();
        println!("name cookie: {}", cookies.find(|cookie| cookie.name == "name")
            .map_or("nope", |cookie| &cookie.value));

        //res.render(self.tmpl_path + "/sample.tpl", data)

        res.content_type("text/html");
        res.send("<title>Settings</title>
Settings
")
    }

    fn login(&self, req: &mut Request, mut res: Response) {
        let form = req.form().unwrap();
        match form.iter().find(|pair| pair.0 == "username").map(|pair| &pair.1) {
            None => (),
            Some(ref username) => {
                let mut cookie = Cookie::new("name".to_owned(), username.to_string());
                cookie.domain = Some("localhost".to_string());
                cookie.httponly = true;
                res.cookie(cookie);
            }
        }

        res.end(Status::NoContent)
    }

    fn files(&self, req: &mut Request, res: Response) {
        let path = req.path()[1..].join("/");
        res.send_file("web/".to_string() + &path)
    }

    fn redirect(&self, _req: &mut Request, res: Response) {
        use std::thread;
        use std::time::Duration;

        thread::spawn(|| {
            println!("waiting 3 seconds");
            thread::sleep(Duration::from_secs(3));
            res.redirect("http://google.com", None)
        });
    }

    fn streaming(&self, _req: &mut Request, res: Response) {
        use std::thread;
        use std::time::Duration;

        thread::spawn(move || {
            thread::sleep(Duration::from_secs(1));
            let mut res = res.stream();
            res.append("toto".as_bytes());
            thread::sleep(Duration::from_secs(1));
            res.append("tata".as_bytes());
            thread::sleep(Duration::from_secs(1));
            res.append("titi".as_bytes());
        });
    }

}

fn main() {
    env_logger::init().unwrap();

    let app = MyApp::new();
    let mut cter = Edge::new("0.0.0.0:3000", app);
    cter.get("/", MyApp::home);
    cter.get("/hello/:first_name/:last_name", MyApp::hello);
    cter.get("/settings", MyApp::settings);
    cter.get("/static", MyApp::files);

    cter.get("/redirect", MyApp::redirect);
    cter.get("/streaming", MyApp::streaming);

    cter.post("/login", MyApp::login);
    cter.start().unwrap();
}
<commit_msg>added charset in basic, simplified home handler<commit_after>extern crate env_logger;
#[macro_use]
extern crate log;
extern crate edge;

use edge::{Edge, Cookie, Request, Response, Status};
use edge::header::AccessControlAllowOrigin;
use std::sync::atomic::{AtomicUsize, Ordering};

use std::collections::BTreeMap;
use edge::value;

struct MyApp {
    tmpl_path: String,
    counter: AtomicUsize
}

impl MyApp {

    fn new() -> MyApp {
        MyApp {
            tmpl_path: "toto".to_owned(),
            counter: AtomicUsize::new(0)
        }
    }

    fn home(&self, _req: &mut Request, mut res: Response) {
        let cnt = self.counter.fetch_add(1, Ordering::SeqCst);

        println!("in home, count = {}, path = {}", cnt, self.tmpl_path);

        res.content_type("text/html; charset=UTF-8").header(AccessControlAllowOrigin::Any);
        res.send("<title>home</title>
Hello, world!
")
    }

    fn hello(&self,  req: &mut Request, mut res: Response) {
        let first_name = req.param("first_name").unwrap_or("John");
        let last_name = req.param("last_name").unwrap_or("Doe");

        let mut data = BTreeMap::new();
        data.insert("first_name", value::to_value(first_name));
        data.insert("last_name", value::to_value(last_name));

        res.content_type("text/plain; charset=UTF-8");
        res.render("views/hello.hbs", data)
    }

    fn settings(&self, req: &mut Request, mut res: Response) {
        let mut cookies = req.cookies();
        println!("name cookie: {}", cookies.find(|cookie| cookie.name == "name")
            .map_or("nope", |cookie| &cookie.value));

        //res.render(self.tmpl_path + "/sample.tpl", data)

        res.content_type("text/html; charset=UTF-8");
        res.send("<title>Settings</title>
Settings
")
    }

    fn login(&self, req: &mut Request, mut res: Response) {
        let form = req.form().unwrap();
        match form.iter().find(|pair| pair.0 == "username").map(|pair| &pair.1) {
            None => (),
            Some(ref username) => {
                let mut cookie = Cookie::new("name".to_owned(), username.to_string());
                cookie.domain = Some("localhost".to_string());
                cookie.httponly = true;
                res.cookie(cookie);
            }
        }

        res.end(Status::NoContent)
    }

    fn files(&self, req: &mut Request, res: Response) {
        let path = req.path()[1..].join("/");
        res.send_file("web/".to_string() + &path)
    }

    fn redirect(&self, _req: &mut Request, res: Response) {
        use std::thread;
        use std::time::Duration;

        thread::spawn(|| {
            println!("waiting 3 seconds");
            thread::sleep(Duration::from_secs(3));
            res.redirect("http://google.com", None)
        });
    }

    fn streaming(&self, _req: &mut Request, res: Response) {
        use std::thread;
        use std::time::Duration;

        thread::spawn(move || {
            let mut res = res.stream();
            res.append("toto".as_bytes());
            thread::sleep(Duration::from_secs(1));

            res.append("tata".as_bytes());
            thread::sleep(Duration::from_secs(1));

            res.append("titi".as_bytes());
        });
    }

}

fn main() {
    env_logger::init().unwrap();

    let app = MyApp::new();
    let mut cter = Edge::new("0.0.0.0:3000", app);
    cter.get("/", MyApp::home);
    cter.get("/hello/:first_name/:last_name", MyApp::hello);
    cter.get("/settings", MyApp::settings);
    cter.get("/static", MyApp::files);

    cter.get("/redirect", MyApp::redirect);
    cter.get("/streaming", MyApp::streaming);

    cter.post("/login", MyApp::login);
    cter.start().unwrap();
}
<|endoftext|>


<commit_before>/*
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see
 * <http://www.gnu.org/licenses/>.
 *
 * Sahid Orentino Ferdjaoui <sahid.ferdjaoui@redhat.com>
 */

//! This file contains trivial example code to connect to the running
//! hypervisor and gather a few bits of information about domains.
//! Similar API's exist for storage pools, networks, and interfaces.
//!
//! Largely inspired by hellolibvirt.c

extern crate virt;

use std::env;

use virt::connect::Connect;
use virt::error::Error;

fn show_hypervisor_info(conn: Connect) -> Result<(), Error> {
    if let Ok(hv_type) = conn.get_type() {
        if let Ok(mut hv_ver) = conn.get_hyp_version() {
            let major = hv_ver / 1000000;
            hv_ver %= 1000000;
            let minor = hv_ver / 1000;
            let release = hv_ver % 1000;
            println!("Hypervisor: '{}' version: {}.{}.{}",
                     hv_type,
                     major,
                     minor,
                     release);
            return Ok(());
        }
    }
    Err(Error::new())
}

fn main() {
    let uri = match env::args().nth(1) {
        Some(u) => u,
        None => String::from(""),
    };
    println!("Attempting to connect to hypervisor: '{}'", uri);

    let conn = match Connect::open(&uri) {
        Ok(c) => c,
        Err(e) => {
            panic!("No connection to hypervisor: code {}, message: {}",
                   e.code,
                   e.message)
        }
    };

    match conn.get_uri() {
        Ok(u) => println!("Connected to hypervisor at '{}'", u),
        Err(e) => {
            disconnect(conn);
            panic!("Failed to get URI for hypervisor connection: code {}, message: {}",
                   e.code,
                   e.message);
        }
    };

    if let Err(e) = show_hypervisor_info(conn.clone()) {
        disconnect(conn);
        panic!("Failed to show hypervisor info: code {}, message: {}",
               e.code,
               e.message);
    }

    fn disconnect(mut conn: Connect) {
        if let Err(e) = conn.close() {
            panic!("Failed to disconnect from hypervisor: code {}, message: {}",
                   e.code,
                   e.message);
        }
        println!("Disconnected from hypervisor");
    }
}
<commit_msg>example improve helloworld<commit_after>/*
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see
 * <http://www.gnu.org/licenses/>.
 *
 * Sahid Orentino Ferdjaoui <sahid.ferdjaoui@redhat.com>
 */

//! This file contains trivial example code to connect to the running
//! hypervisor and gather a few bits of information about domains.
//! Similar API's exist for storage pools, networks, and interfaces.
//!
//! Largely inspired by hellolibvirt.c

extern crate virt;

use std::env;

use virt::connect::Connect;
use virt::error::Error;

fn show_hypervisor_info(conn: Connect) -> Result<(), Error> {
    if let Ok(hv_type) = conn.get_type() {
        if let Ok(mut hv_ver) = conn.get_hyp_version() {
            let major = hv_ver / 1000000;
            hv_ver %= 1000000;
            let minor = hv_ver / 1000;
            let release = hv_ver % 1000;
            println!("Hypervisor: '{}' version: {}.{}.{}",
                     hv_type,
                     major,
                     minor,
                     release);
            return Ok(());
        }
    }
    Err(Error::new())
}

fn show_domains(conn: Connect) -> Result<(), Error> {
    let flags = virt::connect::VIR_CONNECT_LIST_DOMAINS_ACTIVE |
                virt::connect::VIR_CONNECT_LIST_DOMAINS_INACTIVE;

    if let Ok(num_active_domains) = conn.num_of_domains() {
        if let Ok(num_inactive_domains) = conn.num_of_defined_domains() {
            println!("There are {} active and {} inactive domains",
                     num_active_domains,
                     num_inactive_domains);
            /* Return a list of all active and inactive domains. Using this API
             * instead of virConnectListDomains() and virConnectListDefinedDomains()
             * is preferred since it "solves" an inherit race between separated API
             * calls if domains are started or stopped between calls */
            if let Ok(doms) = conn.list_all_domains(flags) {
                for dom in doms {
                    let name = dom.get_name().unwrap_or(String::from("no-name"));
                    let active = dom.is_active().unwrap_or(false);
                    println!("domain: {}, active: {}", name, active);
                }
            }
            return Ok(());
        }
    }
    Err(Error::new())
}

fn main() {
    let uri = match env::args().nth(1) {
        Some(u) => u,
        None => String::from(""),
    };
    println!("Attempting to connect to hypervisor: '{}'", uri);

    let conn = match Connect::open(&uri) {
        Ok(c) => c,
        Err(e) => {
            panic!("No connection to hypervisor: code {}, message: {}",
                   e.code,
                   e.message)
        }
    };

    match conn.get_uri() {
        Ok(u) => println!("Connected to hypervisor at '{}'", u),
        Err(e) => {
            disconnect(conn);
            panic!("Failed to get URI for hypervisor connection: code {}, message: {}",
                   e.code,
                   e.message);
        }
    };

    if let Err(e) = show_hypervisor_info(conn.clone()) {
        disconnect(conn);
        panic!("Failed to show hypervisor info: code {}, message: {}",
               e.code,
               e.message);
    }

    if let Err(e) = show_domains(conn.clone()) {
        disconnect(conn);
        panic!("Failed to show domains info: code {}, message: {}",
               e.code,
               e.message);
    }

    fn disconnect(mut conn: Connect) {
        if let Err(e) = conn.close() {
            panic!("Failed to disconnect from hypervisor: code {}, message: {}",
                   e.code,
                   e.message);
        }
        println!("Disconnected from hypervisor");
    }
}
<|endoftext|>


<commit_before>export QuartzNativeFont, with_test_native_font;

import glyph::GlyphIndex;

class QuartzNativeFont/& {
    let bogus: int;

    new() { self.bogus = 0; }

    fn glyph_index(_codepoint: char) -> option<GlyphIndex> {
        fail;
    }

    // FIXME: What unit is this returning? Let's have a custom type
    fn glyph_h_advance(_glyph: GlyphIndex) -> option<int> {
        fail;
    }
}

fn with_test_native_font(_f: fn@(nf: &NativeFont)) {
    fail
}
<commit_msg>Begin implementing QuartzNativeFont<commit_after>use cocoa;

export QuartzNativeFont, with_test_native_font;

import libc::size_t;
import ptr::null;
import unsafe::reinterpret_cast;
import result::{result, ok};
import glyph::GlyphIndex;
import cocoa::cg::{
    CGDataProviderRef,
    CGFontRef
};
import cocoa::cg::cg::{
    CGDataProviderCreateWithData,
    CGDataProviderRelease,
    CGFontCreateWithDataProvider,
    CGFontRelease
};

class QuartzNativeFont/& {
    let fontprov: CGDataProviderRef;
    let cgfont: CGFontRef;

    new (fontprov: CGDataProviderRef, cgfont: CGFontRef) {
        assert fontprov.is_not_null();
        assert cgfont.is_not_null();

        self.fontprov = fontprov;
        self.cgfont = cgfont;
    }

    drop {
        assert self.cgfont.is_not_null();
        assert self.fontprov.is_not_null();

        CGFontRelease(self.cgfont);
        CGDataProviderRelease(self.fontprov);
    }

    fn glyph_index(_codepoint: char) -> option<GlyphIndex> {
        fail;
    }

    // FIXME: What unit is this returning? Let's have a custom type
    fn glyph_h_advance(_glyph: GlyphIndex) -> option<int> {
        fail;
    }
}

fn create(buf: &[u8]) -> result<QuartzNativeFont, ()> {
    let fontprov = vec::as_buf(*buf) { |cbuf|
        CGDataProviderCreateWithData(
            null(),
            unsafe { reinterpret_cast(cbuf) },
            (*buf).len() as size_t,
            null())
    };
    // FIXME: Error handling
    assert fontprov.is_not_null();
    let cgfont = CGFontCreateWithDataProvider(fontprov);
    // FIXME: Error handling
    assert cgfont.is_not_null();

    ret ok(QuartzNativeFont(fontprov, cgfont));
}

fn with_test_native_font(f: fn@(nf: &NativeFont)) {
    import font::test_font_bin;
    import unwrap_result = result::unwrap;

    let buf = test_font_bin();
    let font = unwrap_result(create(&buf));
    f(&font);
}
<|endoftext|>


<commit_before>// This makes use of a clever hack that brson came up with to
// workaround our lack of traits and lack of macros.  See core.{rc,rs} for
// how this file is used.

import inst::{IMPL_T, EACH, SIZE_HINT};
export extensions;

impl extensions<A> of iter::base_iter<A> for IMPL_T<A> {
    fn each(blk: fn(A) -> bool) { EACH(self, blk) }
    fn size_hint() -> option<uint> { SIZE_HINT(self) }
    fn eachi(blk: fn(uint, A) -> bool) { iter::eachi(self, blk) }
    fn all(blk: fn(A) -> bool) -> bool { iter::all(self, blk) }
    fn any(blk: fn(A) -> bool) -> bool { iter::any(self, blk) }
    fn foldl<B>(+b0: B, blk: fn(B, A) -> B) -> B {
        iter::foldl(self, b0, blk)
    }
    fn contains(x: A) -> bool { iter::contains(self, x) }
    fn count(x: A) -> uint { iter::count(self, x) }
}

impl extensions<A:copy> for IMPL_T<A> {
    fn filter_to_vec(pred: fn(A) -> bool) -> [A] {
        iter::filter_to_vec(self, pred)
    }
    fn map_to_vec<B>(op: fn(A) -> B) -> [B] { iter::map_to_vec(self, op) }
    fn to_vec() -> [A] { iter::to_vec(self) }

    // FIXME--bug in resolve prevents this from working
    // fn flat_map_to_vec<B:copy,IB:base_iter<B>>(op: fn(A) -> IB) -> [B] {
    //     iter::flat_map_to_vec(self, op)
    // }

    fn min() -> A { iter::min(self) }
    fn max() -> A { iter::max(self) }
}
<commit_msg>annotate FIXME in iter-trait<commit_after>// This makes use of a clever hack that brson came up with to
// workaround our lack of traits and lack of macros.  See core.{rc,rs} for
// how this file is used.

import inst::{IMPL_T, EACH, SIZE_HINT};
export extensions;

impl extensions<A> of iter::base_iter<A> for IMPL_T<A> {
    fn each(blk: fn(A) -> bool) { EACH(self, blk) }
    fn size_hint() -> option<uint> { SIZE_HINT(self) }
    fn eachi(blk: fn(uint, A) -> bool) { iter::eachi(self, blk) }
    fn all(blk: fn(A) -> bool) -> bool { iter::all(self, blk) }
    fn any(blk: fn(A) -> bool) -> bool { iter::any(self, blk) }
    fn foldl<B>(+b0: B, blk: fn(B, A) -> B) -> B {
        iter::foldl(self, b0, blk)
    }
    fn contains(x: A) -> bool { iter::contains(self, x) }
    fn count(x: A) -> uint { iter::count(self, x) }
}

impl extensions<A:copy> for IMPL_T<A> {
    fn filter_to_vec(pred: fn(A) -> bool) -> [A] {
        iter::filter_to_vec(self, pred)
    }
    fn map_to_vec<B>(op: fn(A) -> B) -> [B] { iter::map_to_vec(self, op) }
    fn to_vec() -> [A] { iter::to_vec(self) }

    // FIXME--bug in resolve prevents this from working (#2611)
    // fn flat_map_to_vec<B:copy,IB:base_iter<B>>(op: fn(A) -> IB) -> [B] {
    //     iter::flat_map_to_vec(self, op)
    // }

    fn min() -> A { iter::min(self) }
    fn max() -> A { iter::max(self) }
}
<|endoftext|>


<commit_before>//! Conversion lsp_types types to rust-analyzer specific ones.
use anyhow::format_err;
use ide::{Annotation, AnnotationKind, AssistKind, LineCol, LineColUtf16};
use ide_db::base_db::{FileId, FilePosition, FileRange};
use syntax::{TextRange, TextSize};
use vfs::AbsPathBuf;

use crate::{
    from_json,
    global_state::GlobalStateSnapshot,
    line_index::{LineIndex, PositionEncoding},
    lsp_ext,
    lsp_utils::invalid_params_error,
    Result,
};

pub(crate) fn abs_path(url: &lsp_types::Url) -> Result<AbsPathBuf> {
    let path = url.to_file_path().map_err(|()| "url is not a file")?;
    Ok(AbsPathBuf::try_from(path).unwrap())
}

pub(crate) fn vfs_path(url: &lsp_types::Url) -> Result<vfs::VfsPath> {
    abs_path(url).map(vfs::VfsPath::from)
}

pub(crate) fn offset(line_index: &LineIndex, position: lsp_types::Position) -> Result<TextSize> {
    let line_col = match line_index.encoding {
        PositionEncoding::Utf8 => {
            LineCol { line: position.line as u32, col: position.character as u32 }
        }
        PositionEncoding::Utf16 => {
            let line_col =
                LineColUtf16 { line: position.line as u32, col: position.character as u32 };
            line_index.index.to_utf8(line_col)
        }
    };
    let text_size =
        line_index.index.offset(line_col).ok_or_else(|| format_err!("Invalid offset"))?;
    Ok(text_size)
}

pub(crate) fn text_range(line_index: &LineIndex, range: lsp_types::Range) -> Result<TextRange> {
    let start = offset(line_index, range.start)?;
    let end = offset(line_index, range.end)?;
    let text_range = TextRange::new(start, end);
    Ok(text_range)
}

pub(crate) fn file_id(snap: &GlobalStateSnapshot, url: &lsp_types::Url) -> Result<FileId> {
    snap.url_to_file_id(url)
}

pub(crate) fn file_position(
    snap: &GlobalStateSnapshot,
    tdpp: lsp_types::TextDocumentPositionParams,
) -> Result<FilePosition> {
    let file_id = file_id(snap, &tdpp.text_document.uri)?;
    let line_index = snap.file_line_index(file_id)?;
    let offset = offset(&line_index, tdpp.position)?;
    Ok(FilePosition { file_id, offset })
}

pub(crate) fn file_range(
    snap: &GlobalStateSnapshot,
    text_document_identifier: lsp_types::TextDocumentIdentifier,
    range: lsp_types::Range,
) -> Result<FileRange> {
    let file_id = file_id(snap, &text_document_identifier.uri)?;
    let line_index = snap.file_line_index(file_id)?;
    let range = text_range(&line_index, range)?;
    Ok(FileRange { file_id, range })
}

pub(crate) fn assist_kind(kind: lsp_types::CodeActionKind) -> Option<AssistKind> {
    let assist_kind = match &kind {
        k if k == &lsp_types::CodeActionKind::EMPTY => AssistKind::None,
        k if k == &lsp_types::CodeActionKind::QUICKFIX => AssistKind::QuickFix,
        k if k == &lsp_types::CodeActionKind::REFACTOR => AssistKind::Refactor,
        k if k == &lsp_types::CodeActionKind::REFACTOR_EXTRACT => AssistKind::RefactorExtract,
        k if k == &lsp_types::CodeActionKind::REFACTOR_INLINE => AssistKind::RefactorInline,
        k if k == &lsp_types::CodeActionKind::REFACTOR_REWRITE => AssistKind::RefactorRewrite,
        _ => return None,
    };

    Some(assist_kind)
}

pub(crate) fn annotation(
    snap: &GlobalStateSnapshot,
    code_lens: lsp_types::CodeLens,
) -> Result<Annotation> {
    let data =
        code_lens.data.ok_or_else(|| invalid_params_error("code lens without data".to_string()))?;
    let resolve = from_json::<lsp_ext::CodeLensResolveData>("CodeLensResolveData", &data)?;

    match resolve {
        lsp_ext::CodeLensResolveData::Impls(params) => {
            let pos @ FilePosition { file_id, .. } =
                file_position(snap, params.text_document_position_params)?;
            let line_index = snap.file_line_index(file_id)?;

            Ok(Annotation {
                range: text_range(&line_index, code_lens.range)?,
                kind: AnnotationKind::HasImpls { pos, data: None },
            })
        }
        lsp_ext::CodeLensResolveData::References(params) => {
            let pos @ FilePosition { file_id, .. } = file_position(snap, params)?;
            let line_index = snap.file_line_index(file_id)?;

            Ok(Annotation {
                range: text_range(&line_index, code_lens.range)?,
                kind: AnnotationKind::HasReferences { pos, data: None },
            })
        }
    }
}
<commit_msg>Auto merge of #13573 - Veykril:invalid-file-range, r=Veykril<commit_after>//! Conversion lsp_types types to rust-analyzer specific ones.
use anyhow::format_err;
use ide::{Annotation, AnnotationKind, AssistKind, LineCol, LineColUtf16};
use ide_db::base_db::{FileId, FilePosition, FileRange};
use syntax::{TextRange, TextSize};
use vfs::AbsPathBuf;

use crate::{
    from_json,
    global_state::GlobalStateSnapshot,
    line_index::{LineIndex, PositionEncoding},
    lsp_ext,
    lsp_utils::invalid_params_error,
    Result,
};

pub(crate) fn abs_path(url: &lsp_types::Url) -> Result<AbsPathBuf> {
    let path = url.to_file_path().map_err(|()| "url is not a file")?;
    Ok(AbsPathBuf::try_from(path).unwrap())
}

pub(crate) fn vfs_path(url: &lsp_types::Url) -> Result<vfs::VfsPath> {
    abs_path(url).map(vfs::VfsPath::from)
}

pub(crate) fn offset(line_index: &LineIndex, position: lsp_types::Position) -> Result<TextSize> {
    let line_col = match line_index.encoding {
        PositionEncoding::Utf8 => {
            LineCol { line: position.line as u32, col: position.character as u32 }
        }
        PositionEncoding::Utf16 => {
            let line_col =
                LineColUtf16 { line: position.line as u32, col: position.character as u32 };
            line_index.index.to_utf8(line_col)
        }
    };
    let text_size =
        line_index.index.offset(line_col).ok_or_else(|| format_err!("Invalid offset"))?;
    Ok(text_size)
}

pub(crate) fn text_range(line_index: &LineIndex, range: lsp_types::Range) -> Result<TextRange> {
    let start = offset(line_index, range.start)?;
    let end = offset(line_index, range.end)?;
    match end < start {
        true => Err(format_err!("Invalid Range").into()),
        false => Ok(TextRange::new(start, end)),
    }
}

pub(crate) fn file_id(snap: &GlobalStateSnapshot, url: &lsp_types::Url) -> Result<FileId> {
    snap.url_to_file_id(url)
}

pub(crate) fn file_position(
    snap: &GlobalStateSnapshot,
    tdpp: lsp_types::TextDocumentPositionParams,
) -> Result<FilePosition> {
    let file_id = file_id(snap, &tdpp.text_document.uri)?;
    let line_index = snap.file_line_index(file_id)?;
    let offset = offset(&line_index, tdpp.position)?;
    Ok(FilePosition { file_id, offset })
}

pub(crate) fn file_range(
    snap: &GlobalStateSnapshot,
    text_document_identifier: lsp_types::TextDocumentIdentifier,
    range: lsp_types::Range,
) -> Result<FileRange> {
    let file_id = file_id(snap, &text_document_identifier.uri)?;
    let line_index = snap.file_line_index(file_id)?;
    let range = text_range(&line_index, range)?;
    Ok(FileRange { file_id, range })
}

pub(crate) fn assist_kind(kind: lsp_types::CodeActionKind) -> Option<AssistKind> {
    let assist_kind = match &kind {
        k if k == &lsp_types::CodeActionKind::EMPTY => AssistKind::None,
        k if k == &lsp_types::CodeActionKind::QUICKFIX => AssistKind::QuickFix,
        k if k == &lsp_types::CodeActionKind::REFACTOR => AssistKind::Refactor,
        k if k == &lsp_types::CodeActionKind::REFACTOR_EXTRACT => AssistKind::RefactorExtract,
        k if k == &lsp_types::CodeActionKind::REFACTOR_INLINE => AssistKind::RefactorInline,
        k if k == &lsp_types::CodeActionKind::REFACTOR_REWRITE => AssistKind::RefactorRewrite,
        _ => return None,
    };

    Some(assist_kind)
}

pub(crate) fn annotation(
    snap: &GlobalStateSnapshot,
    code_lens: lsp_types::CodeLens,
) -> Result<Annotation> {
    let data =
        code_lens.data.ok_or_else(|| invalid_params_error("code lens without data".to_string()))?;
    let resolve = from_json::<lsp_ext::CodeLensResolveData>("CodeLensResolveData", &data)?;

    match resolve {
        lsp_ext::CodeLensResolveData::Impls(params) => {
            let pos @ FilePosition { file_id, .. } =
                file_position(snap, params.text_document_position_params)?;
            let line_index = snap.file_line_index(file_id)?;

            Ok(Annotation {
                range: text_range(&line_index, code_lens.range)?,
                kind: AnnotationKind::HasImpls { pos, data: None },
            })
        }
        lsp_ext::CodeLensResolveData::References(params) => {
            let pos @ FilePosition { file_id, .. } = file_position(snap, params)?;
            let line_index = snap.file_line_index(file_id)?;

            Ok(Annotation {
                range: text_range(&line_index, code_lens.range)?,
                kind: AnnotationKind::HasReferences { pos, data: None },
            })
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Compare strings using &str<commit_after><|endoftext|>


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

#[macro_use] extern crate bitflags;
extern crate libc;
#[cfg(windows)]
extern crate serial_win;
#[cfg(unix)]
extern crate serial;

use std::io::{ self, Error, ErrorKind };

#[cfg(windows)]
pub struct Connection {
	conn: serial_win::Connection
}
#[cfg(windows)]
impl Connection {
	pub fn open(port: &str, baud_rate: u32) -> io::Result<Connection> {
		serial_win::Connection::new(port, baud_rate).map(|conn| Connection { conn: conn })
	}
}

#[cfg(unix)]
pub struct Connection {
	conn: serial::SerialPort
}
#[cfg(unix)]
impl Connection {
	/// Open a connection through a serial port.
	///
	/// Supported baud rates are:
	/// 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800,
	/// 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400
	pub fn open(port: &str, baud_rate: u32) -> io::Result<Connection> {
		use serial::BaudRate::*;
		use std::path::Path;

		let baud_rate = match baud_rate {
			0 => B0,
			50 => B50,
			75 => B75,
			110 => B110,
			134 => B134,
			150 => B150,
			200 => B200,
			300 => B300,
			600 => B600,
			1200 => B1200,
			1800 => B1800,
			2400 => B2400,
			4800 => B4800,
			9600 => B9600,
			19200 => B19200,
			38400 => B38400,
			57600 => B57600,
			115200 => B115200,
			230400 => B230400,
			_ => return Err(Error::new(ErrorKind::InvalidInput, "Unsupported baud rate. View docs for more info"))
		};

		match serial::SerialPort::open(&Path::new(port)) {
			Ok(mut conn) => match conn.set_baud_rate(serial::Direction::Both, baud_rate) {
				Ok(_) => Ok(Connection{ conn: conn }),
				Err(e) => Err(e),
			},
			Err(e) => Err(e),
		}
	}
}

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

	#[cfg(unix)]
	const PORTS: [&'static str; 10] = [
		"/dev/ttyS0", "/dev/ttyS1", "/dev/ttyS2", "/dev/ttyS3", "/dev/ttyS4",
		"/dev/ttyUSB0", "/dev/ttyUSB1", "/dev/ttyUSB2",
		"/dev/ttyACM0", "/dev/ttyACM1"
	];
	#[cfg(windows)]
	const PORTS: [&'static str; 10] = [
		"COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9"
	];

	#[test]
	fn test() {
		let (conn, port) = PORTS.iter().filter_map(|&port| {
				match Connection::open(&port, 9600).map(|c| (c, port)) {
					Ok(o) => Some(o),
					Err(e) => {
						println!("Error opening connection on port {}: {}", port, e);
						None
					}
				}
			})
			.next()
			.unwrap();
		println!("Serial connection open on port {}", port);
	}
}<commit_msg>Add baud_rate methods<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2015 Johan Johansson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#[macro_use] extern crate bitflags;
extern crate libc;
#[cfg(windows)]
extern crate serial_win;
#[cfg(unix)]
extern crate serial;

use std::io;
#[cfg(unix)]
use std::io::{ Error, ErrorKind };

// Windows only
#[cfg(windows)]
pub struct Connection {
	conn: serial_win::Connection
}
#[cfg(windows)]
impl Connection {
	pub fn open(port: &str, baud_rate: u32) -> io::Result<Connection> {
		serial_win::Connection::new(port, baud_rate).map(|conn| Connection { conn: conn })
	}

	pub fn baud_rate(&self) -> io::Result<u32> {
		self.conn.baud_rate()
	}

	pub fn set_baud_rate(&mut self, baud_rate: u32) -> io::Result<()> {
		self.conn.set_baud_rate(baud_rate)
	}
}

// Unix-like only
#[cfg(unix)]
pub struct Connection {
	conn: serial::SerialPort
}
#[cfg(unix)]
impl Connection {
	/// Open a connection through a serial port.
	///
	/// Supported baud rates are:
	/// 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800,
	/// 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400
	pub fn open(port: &str, baud_rate: u32) -> io::Result<Connection> {
		serial::SerialPort::open(&std::path::Path::new(port))
			.map(|serial_port| Connection{ conn: serial_port })
			.and_then(|mut conn| conn.set_baud_rate(baud_rate).map(|_| conn))
	}

	pub fn baud_rate(&self) -> io::Result<u32> {
		use serial::BaudRate::*;
		self.conn.baud_rate().map(|(_, ebaud)| match ebaud {
			B0 => 0,
			B50 => 50,
			B75 => 75,
			B110 => 110,
			B134 => 134,
			B150 => 150,
			B200 => 200,
			B300 => 300,
			B600 => 600,
			B1200 => 1200,
			B1800 => 1800,
			B2400 => 2400,
			B4800 => 4800,
			B9600 => 9600,
			B19200 => 19200,
			B38400 => 38400,
			B57600 => 57600,
			B115200 => 115200,
			B230400 => 230400,
		})
	}

	pub fn set_baud_rate(&mut self, baud_rate: u32) -> io::Result<()> {
		use serial::BaudRate::*;

		let ebaud_rate = match baud_rate {
			0 => B0,
			50 => B50,
			75 => B75,
			110 => B110,
			134 => B134,
			150 => B150,
			200 => B200,
			300 => B300,
			600 => B600,
			1200 => B1200,
			1800 => B1800,
			2400 => B2400,
			4800 => B4800,
			9600 => B9600,
			19200 => B19200,
			38400 => B38400,
			57600 => B57600,
			115200 => B115200,
			230400 => B230400,
			_ => return Err(Error::new(
				ErrorKind::InvalidInput, "Unsupported baud rate"
			))
		};

		self.conn.set_baud_rate(serial::Direction::Both, ebaud_rate)
	}
}

// Common implementations
impl Connection {

}

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

	#[cfg(unix)]
	const PORTS: [&'static str; 10] = [
		"/dev/ttyS0", "/dev/ttyS1", "/dev/ttyS2", "/dev/ttyS3", "/dev/ttyS4",
		"/dev/ttyUSB0", "/dev/ttyUSB1", "/dev/ttyUSB2",
		"/dev/ttyACM0", "/dev/ttyACM1"
	];
	#[cfg(windows)]
	const PORTS: [&'static str; 10] = [
		"COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9"
	];

	#[test]
	fn test() {
		let (mut conn, port) = PORTS.iter().filter_map(|&port| {
				match Connection::open(&port, 9600).map(|c| (c, port)) {
					Ok(o) => Some(o),
					Err(e) => {
						println!("Error opening connection on port {}: {}", port, e);
						None
					}
				}
			})
			.next()
			.unwrap();

		println!("Serial connection open on port {}", port);

		println!("baud: {}", conn.baud_rate().unwrap());
		conn.set_baud_rate(115_200).unwrap();
		println!("new baud: {}", conn.baud_rate().unwrap());
	}
}<|endoftext|>


<commit_before>//! Serenity is an ergonomic and high-level Rust library for the Discord API.
//!
//! View the [examples] on how to make and structure a bot.
//!
//! Serenity supports both bot and user login via the use of [`Client::login_bot`]
//! and [`Client::login_user`].
//!
//! You may also check your tokens prior to login via the use of
//! [`validate_token`].
//!
//! Once logged in, you may add handlers to your client to dispatch [`Event`]s,
//! such as [`Client::on_message`]. This will cause your handler to be called
//! when a [`Event::MessageCreate`] is received. Each handler is given a
//! [`Context`], giving information about the event. See the
//! [client's module-level documentation].
//!
//! The [`Shard`] is transparently handled by the library, removing
//! unnecessary complexity. Sharded connections are automatically handled for
//! you. See the [gateway's documentation][gateway docs] for more information.
//!
//! A [`Cache`] is also provided for you. This will be updated automatically for
//! you as data is received from the Discord API via events. When calling a
//! method on a [`Context`], the cache will first be searched for relevant data
//! to avoid unnecessary HTTP requests to the Discord API. For more information,
//! see the [cache's module-level documentation][cache docs].
//!
//! Note that, although this documentation will try to be as up-to-date and
//! accurate as possible, Discord hosts [official documentation][docs]. If you
//! need to be sure that some information piece is sanctioned by Discord, refer
//! to their own documentation.
//!
//! # Example Bot
//!
//! A basic ping-pong bot looks like:
//!
//! ```rust,no-run
//! extern crate serenity;
//!
//! use serenity::client::{Client, Context};
//! use serenity::model::Message;
//! use std::env;
//!
//! fn main() {
//!     // Login with a bot token from the environment
//!     let mut client = Client::login_bot(&env::var("DISCORD_TOKEN").expect("token"));
//!     client.with_framework(|f| f
//!         .configure(|c| c.prefix("~")) // set the bot's prefix to "~"
//!         .on("ping", ping));
//!
//!     // start listening for events by starting a single shard
//!     let _ = client.start();
//! }
//!
//! fn ping(_context: &Context, message: &Message, _args: Vec<String>) {
//!     let _ = message.reply("Pong!");
//! }
//! ```
//!
//! ### Full Examples
//!
//! Full examples, detailing and explaining usage of the basic functionality of the
//! library, can be found in the [`examples`] directory.
//!
//! # Features
//!
//! Features can be enabled or disabled by configuring the library through
//! Cargo.toml:
//!
//! ```toml
//! [dependencies.serenity]
//! git = "https://github.com/zeyla/serenity.rs.git"
//! default-features = false
//! features = ["pick", "your", "feature", "names", "here"]
//! ```
//!
//! The following is a full list of features:
//!
//! - **cache**: The cache will store information about guilds, channels, users,
//! and other data, to avoid performing REST requests. If you are low on RAM, do
//! not enable this;
//! - **framework**: Enables the framework, which is a utility to allow simple
//! command parsing, before/after command execution, prefix setting, and more;
//! - **methods**: Enables compilation of extra methods on struct
//! implementations, such as `Message::delete()`, `Message::reply()`,
//! `Guild::edit()`, and more. Without this enabled, requests will need to go
//! through the [`Context`] or [`rest`] module, which are slightly less
//! efficient from a development standpoint, and do not automatically perform
//! permission checking;
//! - **voice**: Enables compilation of voice support, so that voice channels
//! can be connected to and audio can be sent/received.
//!
//! # Dependencies
//!
//! Serenity requires the following dependencies:
//!
//! - openssl
//!
//! ### Voice
//!
//! The following dependencies all require the **voice** feature to be enabled
//! in your Cargo.toml:
//!
//! - libsodium (Arch: `community/libsodium`)
//! - opus (Arch: `extra/opus`)
//!
//! Voice+ffmpeg:
//!
//! - ffmpeg (Arch: `extra/ffmpeg`)
//!
//! Voice+youtube-dl:
//!
//! - youtube-dl (Arch: `community/youtube-dl`)
//!
//! [`Cache`]: ext/cache/struct.Cache.html
//! [`Client::login_bot`]: client/struct.Client.html#method.login_bot
//! [`Client::login_user`]: client/struct.Client.html#method.login_user
//! [`Client::on_message`]: client/struct.Client.html#method.on_message
//! [`Context`]: client/struct.Context.html
//! [`Event`]: model/event/enum.Event.html
//! [`Event::MessageCreate`]: model/event/enum.Event.html#variant.MessageCreate
//! [`Shard`]: client/struct.Shard.html
//! [`examples`]: https://github.com/zeyla/serenity.rs.git/blob/master/examples
//! [`rest`]: client/rest/index.html
//! [`validate_token`]: client/fn.validate_token.html
//! [cache docs]: ext/cache/index.html
//! [client's module-level documentation]: client/index.html
//! [docs]: https://discordapp.com/developers/docs/intro
//! [examples]: https://github.com/zeyla/serenity.rs/tree/master/examples
//! [gateway docs]: client/gateway/index.html
#![allow(doc_markdown, inline_always, unknown_lints)]
#![doc(html_logo_url = "https://docs.austinhellyer.me/serenity.rs/docs_header.png")]
#![warn(enum_glob_use, if_not_else)]

#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;

extern crate base64;
extern crate byteorder;
extern crate flate2;
extern crate hyper;
extern crate multipart;
extern crate serde_json;
extern crate time;
extern crate websocket;

#[cfg(feature="voice")]
extern crate opus;
#[cfg(feature="voice")]
extern crate sodiumoxide;

#[macro_use]
pub mod utils;

pub mod client;
pub mod ext;
pub mod model;
pub mod prelude;

mod constants;
mod error;
mod internal;

pub use client::Client;
pub use error::{Error, Result};
<commit_msg>Example should be no-run<commit_after>//! Serenity is an ergonomic and high-level Rust library for the Discord API.
//!
//! View the [examples] on how to make and structure a bot.
//!
//! Serenity supports both bot and user login via the use of [`Client::login_bot`]
//! and [`Client::login_user`].
//!
//! You may also check your tokens prior to login via the use of
//! [`validate_token`].
//!
//! Once logged in, you may add handlers to your client to dispatch [`Event`]s,
//! such as [`Client::on_message`]. This will cause your handler to be called
//! when a [`Event::MessageCreate`] is received. Each handler is given a
//! [`Context`], giving information about the event. See the
//! [client's module-level documentation].
//!
//! The [`Shard`] is transparently handled by the library, removing
//! unnecessary complexity. Sharded connections are automatically handled for
//! you. See the [gateway's documentation][gateway docs] for more information.
//!
//! A [`Cache`] is also provided for you. This will be updated automatically for
//! you as data is received from the Discord API via events. When calling a
//! method on a [`Context`], the cache will first be searched for relevant data
//! to avoid unnecessary HTTP requests to the Discord API. For more information,
//! see the [cache's module-level documentation][cache docs].
//!
//! Note that, although this documentation will try to be as up-to-date and
//! accurate as possible, Discord hosts [official documentation][docs]. If you
//! need to be sure that some information piece is sanctioned by Discord, refer
//! to their own documentation.
//!
//! # Example Bot
//!
//! A basic ping-pong bot looks like:
//!
//! ```rust,ignore
//! extern crate serenity;
//!
//! use serenity::client::{Client, Context};
//! use serenity::model::Message;
//! use std::env;
//!
//! fn main() {
//!     // Login with a bot token from the environment
//!     let mut client = Client::login_bot(&env::var("DISCORD_TOKEN").expect("token"));
//!     client.with_framework(|f| f
//!         .configure(|c| c.prefix("~")) // set the bot's prefix to "~"
//!         .on("ping", ping));
//!
//!     // start listening for events by starting a single shard
//!     let _ = client.start();
//! }
//!
//! fn ping(_context: &Context, message: &Message, _args: Vec<String>) {
//!     let _ = message.reply("Pong!");
//! }
//! ```
//!
//! ### Full Examples
//!
//! Full examples, detailing and explaining usage of the basic functionality of the
//! library, can be found in the [`examples`] directory.
//!
//! # Features
//!
//! Features can be enabled or disabled by configuring the library through
//! Cargo.toml:
//!
//! ```toml
//! [dependencies.serenity]
//! git = "https://github.com/zeyla/serenity.rs.git"
//! default-features = false
//! features = ["pick", "your", "feature", "names", "here"]
//! ```
//!
//! The following is a full list of features:
//!
//! - **cache**: The cache will store information about guilds, channels, users,
//! and other data, to avoid performing REST requests. If you are low on RAM, do
//! not enable this;
//! - **framework**: Enables the framework, which is a utility to allow simple
//! command parsing, before/after command execution, prefix setting, and more;
//! - **methods**: Enables compilation of extra methods on struct
//! implementations, such as `Message::delete()`, `Message::reply()`,
//! `Guild::edit()`, and more. Without this enabled, requests will need to go
//! through the [`Context`] or [`rest`] module, which are slightly less
//! efficient from a development standpoint, and do not automatically perform
//! permission checking;
//! - **voice**: Enables compilation of voice support, so that voice channels
//! can be connected to and audio can be sent/received.
//!
//! # Dependencies
//!
//! Serenity requires the following dependencies:
//!
//! - openssl
//!
//! ### Voice
//!
//! The following dependencies all require the **voice** feature to be enabled
//! in your Cargo.toml:
//!
//! - libsodium (Arch: `community/libsodium`)
//! - opus (Arch: `extra/opus`)
//!
//! Voice+ffmpeg:
//!
//! - ffmpeg (Arch: `extra/ffmpeg`)
//!
//! Voice+youtube-dl:
//!
//! - youtube-dl (Arch: `community/youtube-dl`)
//!
//! [`Cache`]: ext/cache/struct.Cache.html
//! [`Client::login_bot`]: client/struct.Client.html#method.login_bot
//! [`Client::login_user`]: client/struct.Client.html#method.login_user
//! [`Client::on_message`]: client/struct.Client.html#method.on_message
//! [`Context`]: client/struct.Context.html
//! [`Event`]: model/event/enum.Event.html
//! [`Event::MessageCreate`]: model/event/enum.Event.html#variant.MessageCreate
//! [`Shard`]: client/struct.Shard.html
//! [`examples`]: https://github.com/zeyla/serenity.rs.git/blob/master/examples
//! [`rest`]: client/rest/index.html
//! [`validate_token`]: client/fn.validate_token.html
//! [cache docs]: ext/cache/index.html
//! [client's module-level documentation]: client/index.html
//! [docs]: https://discordapp.com/developers/docs/intro
//! [examples]: https://github.com/zeyla/serenity.rs/tree/master/examples
//! [gateway docs]: client/gateway/index.html
#![allow(doc_markdown, inline_always, unknown_lints)]
#![doc(html_logo_url = "https://docs.austinhellyer.me/serenity.rs/docs_header.png")]
#![warn(enum_glob_use, if_not_else)]

#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;

extern crate base64;
extern crate byteorder;
extern crate flate2;
extern crate hyper;
extern crate multipart;
extern crate serde_json;
extern crate time;
extern crate websocket;

#[cfg(feature="voice")]
extern crate opus;
#[cfg(feature="voice")]
extern crate sodiumoxide;

#[macro_use]
pub mod utils;

pub mod client;
pub mod ext;
pub mod model;
pub mod prelude;

mod constants;
mod error;
mod internal;

pub use client::Client;
pub use error::{Error, Result};
<|endoftext|>


<commit_before>/*!
Rust bindings to the [sodium library](https://github.com/jedisct1/libsodium).

Sodium is a portable implementation of Dan Bernsteins [NaCl: Networking and
Cryptography library](http://nacl.cr.yp.to)

For most users, if you want public-key (asymmetric) cryptography you should use
the functions in `crypto::asymmetricbox` for encryption/decryption.

If you want secret-key (symmetric) cryptography you should be using the
functions in `crypto::secretbox` for encryption/decryption.

For public-key signatures you should use the functions in `crypto::sign` for
signature creation and verification.

Unless you know what you're doing you most certainly don't want to use the
functions in `crypto::scalarmult`, `crypto::stream`, `crypto::auth` and
`crypto::onetimeauth`.

## Thread Safety
All functions in this library are thread-safe provided that the `init()`
function has been called during program execution.

If `init()` hasn't been called then all functions except the random-number
generation functions and the key-generation functions are thread-safe.

# Public-key cryptography
 `crypto::asymmetricbox`

 `crypto::sign`

# Secret-key cryptography
 `crypto::secretbox`

 `crypto::stream`

 `crypto::auth`

 `crypto::onetimeauth`

# Low-level functions
 `crypto::hash`

 `crypto::verify`

 `crypto::shorthash`
 */
#![crate_name = "sodiumoxide"]
#![comment = "Fast cryptographic library"]
#![license = "MIT"]
#![crate_type = "lib"]
#![warn(missing_doc)]
#![warn(non_uppercase_statics)]
#![warn(non_camel_case_types)]
#![warn(unnecessary_qualification)]
#![feature(globs)]
#![feature(macro_rules)]
extern crate libc;
use libc::c_int;

#[link(name = "sodium")]
extern {
    fn sodium_init() -> c_int;
}

/**
 * `init()` initializes the sodium library and chooses faster versions of
 * the primitives if possible. `init()` also makes the random number generation
 * functions (`gen_key`, `gen_keypair`, `gen_nonce`, `randombytes`, `randombytes_into`)
 * thread-safe
 */
pub fn init() -> bool {
    unsafe {
        sodium_init() == 0
    }
}

mod utils;

/**
 * Random number generation
 */
pub mod randombytes;

/**
 * Cryptographic functions
 */
pub mod crypto {
    pub mod asymmetricbox;
    pub mod sign;
    pub mod scalarmult;
    pub mod auth;
    pub mod hash;
    pub mod secretbox;
    pub mod onetimeauth;
    pub mod stream;
    pub mod shorthash;
    pub mod verify;
}

<commit_msg>Fixed small documentation bug<commit_after>/*!
Rust bindings to the [sodium library](https://github.com/jedisct1/libsodium).

Sodium is a portable implementation of Dan Bernsteins [NaCl: Networking and
Cryptography library](http://nacl.cr.yp.to)

For most users, if you want public-key (asymmetric) cryptography you should use
the functions in `crypto::asymmetricbox` for encryption/decryption.

If you want secret-key (symmetric) cryptography you should be using the
functions in `crypto::secretbox` for encryption/decryption.

For public-key signatures you should use the functions in `crypto::sign` for
signature creation and verification.

Unless you know what you're doing you most certainly don't want to use the
functions in `crypto::scalarmult`, `crypto::stream`, `crypto::auth` and
`crypto::onetimeauth`.

## Thread Safety
All functions in this library are thread-safe provided that the `init()`
function has been called during program execution.

If `init()` hasn't been called then all functions except the random-number
generation functions and the key-generation functions are thread-safe.

# Public-key cryptography
 `crypto::asymmetricbox`

 `crypto::sign`

# Secret-key cryptography
 `crypto::secretbox`

 `crypto::stream`

 `crypto::auth`

 `crypto::onetimeauth`

# Low-level functions
 `crypto::hash`

 `crypto::verify`

 `crypto::shorthash`
 */
#![crate_name = "sodiumoxide"]
#![comment = "Fast cryptographic library"]
#![license = "MIT"]
#![crate_type = "lib"]
#![warn(missing_doc)]
#![warn(non_uppercase_statics)]
#![warn(non_camel_case_types)]
#![warn(unnecessary_qualification)]
#![feature(globs)]
#![feature(macro_rules)]
extern crate libc;
use libc::c_int;

#[link(name = "sodium")]
extern {
    fn sodium_init() -> c_int;
}

/**
 * `init()` initializes the sodium library and chooses faster versions of
 * the primitives if possible. `init()` also makes the random number generation
 * functions (`gen_key`, `gen_keypair`, `gen_nonce`, `randombytes`, `randombytes_into`)
 * thread-safe
 */
pub fn init() -> bool {
    unsafe {
        sodium_init() == 0
    }
}

mod utils;

pub mod randombytes;

/**
 * Cryptographic functions
 */
pub mod crypto {
    pub mod asymmetricbox;
    pub mod sign;
    pub mod scalarmult;
    pub mod auth;
    pub mod hash;
    pub mod secretbox;
    pub mod onetimeauth;
    pub mod stream;
    pub mod shorthash;
    pub mod verify;
}

<|endoftext|>


<commit_before>//! # Mime
//!
//! Mime is now Media Type, technically, but `Mime` is more immediately
//! understandable, so the main type here is `Mime`.
//!
//! ## What is Mime?
//!
//! Example mime string: `text/plain;charset=utf-8`
//!
//! ```rust
//! # #![allow(unstable)]
//! # use mime::Mime;
//! # use mime::TopLevel::Text;
//! # use mime::SubLevel::Plain;
//! # use mime::Attr::Charset;
//! # use mime::Value::Utf8;
//! let mime: Mime = "text/plain;charset=utf-8".parse().unwrap();
//! assert_eq!(mime, Mime(Text, Plain, vec![(Charset, Utf8)]));
//! ```

#![doc(html_root_url = "http://hyperium.github.io/mime.rs")]
#![cfg_attr(test, deny(warnings))]
#![cfg_attr(test, feature(test))]
#![feature(std_misc)]

#[macro_use]
extern crate log;

#[cfg(test)]
extern crate test;

use std::ascii::AsciiExt;
use std::fmt;
use std::str::FromStr;
use std::iter::Enumerate;
use std::str::Chars;

macro_rules! inspect(
    ($s:expr, $t:expr) => ({
        let t = $t;
        trace!("inspect {}: {:?}", $s, t);
        t
    })
);

/// Mime, or Media Type. Encapsulates common registers types.
///
/// Consider that a traditional mime type contains a "top level type",
/// a "sub level type", and 0-N "parameters". And they're all strings.
/// Strings everywhere. Strings mean typos. Rust has type safety. We should
/// use types!
///
/// So, Mime bundles together this data into types so the compiler can catch
/// your typos.
///
/// This improves things so you use match without Strings:
///
/// ```rust
/// # #![allow(unstable)]
/// use mime::{Mime, TopLevel, SubLevel};
///
/// let mime: mime::Mime = "application/json".parse().unwrap();
///
/// match mime {
///     Mime(TopLevel::Application, SubLevel::Json, _) => println!("matched json!"),
///     _ => ()
/// }
/// ```
#[derive(Clone, PartialEq, Debug)]
pub struct Mime(pub TopLevel, pub SubLevel, pub Vec<Param>);

macro_rules! enoom {
    (pub enum $en:ident; $ext:ident; $($ty:ident, $text:expr;)*) => (

        #[derive(Clone, Debug)]
        pub enum $en {
            $($ty),*,
            $ext(String)
        }

        impl PartialEq for $en {
            fn eq(&self, other: &$en) -> bool {
                match (self, other) {
                    $( (&$en::$ty, &$en::$ty) => true ),*,
                    (&$en::$ext(ref a), &$en::$ext(ref b)) => a == b,
                    _ => self.to_string() == other.to_string()
                }
            }
        }

        impl fmt::Display for $en {
            fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
                fmt.write_str(match *self {
                    $($en::$ty => $text),*,
                    $en::$ext(ref s) => &**s
                })
            }
        }

        impl FromStr for $en {
            type Err = ();
            fn from_str(s: &str) -> Result<$en, ()> {
                Ok(match s {
                    $(_s if _s == $text => $en::$ty),*,
                    s => $en::$ext(inspect!(stringify!($ext), s).to_string())
                })
            }
        }
    )
}

enoom! {
    pub enum TopLevel;
    Ext;
    Star, "*";
    Text, "text";
    Image, "image";
    Audio, "audio";
    Video, "video";
    Application, "application";
    Multipart, "multipart";
    Message, "message";
    Model, "model";
}

enoom! {
    pub enum SubLevel;
    Ext;
    Star, "*";

    // common text/*
    Plain, "plain";
    Html, "html";
    Xml, "xml";
    Javascript, "javascript";
    Css, "css";

    // common application/*
    Json, "json";
    WwwFormUrlEncoded, "x-www-form-urlencoded";

    // multipart/*
    FormData, "form-data";

    // common image/*
    Png, "png";
    Gif, "gif";
    Bmp, "bmp";
    Jpeg, "jpeg";
}

enoom! {
    pub enum Attr;
    Ext;
    Charset, "charset";
    Q, "q";
}

enoom! {
    pub enum Value;
    Ext;
    Utf8, "utf-8";
}

pub type Param = (Attr, Value);

impl fmt::Display for Mime {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let Mime(ref top, ref sub, ref params) = *self;
        try!(write!(fmt, "{}/{}", top, sub));
        fmt_params(&**params, fmt)
    }
}

impl FromStr for Mime {
    type Err = ();
    fn from_str(raw: &str) -> Result<Mime, ()> {
        let ascii = raw.to_ascii_lowercase(); // lifetimes :(
        let raw = &*ascii;
        let len = raw.len();
        let mut iter = raw.chars().enumerate();
        let mut params = vec![];
        // toplevel
        let mut start;
        let mut top;
        loop {
            match inspect!("top iter", iter.next()) {
                Some((0, c)) if is_restricted_name_first_char(c) => (),
                Some((i, c)) if i > 0 && is_restricted_name_char(c) => (),
                Some((i, '/')) if i > 0 => match FromStr::from_str(&raw[..i]) {
                    Ok(t) => {
                        top = t;
                        start = i + 1;
                        break;
                    }
                    Err(_) => return Err(())
                },
                _ => return Err(()) // EOF and no toplevel is no Mime
            };

        }

        // sublevel
        let mut sub;
        loop {
            match inspect!("sub iter", iter.next()) {
                Some((i, c)) if i == start && is_restricted_name_first_char(c) => (),
                Some((i, c)) if i > start && is_restricted_name_char(c) => (),
                Some((i, ';')) if i > start => match FromStr::from_str(&raw[start..i]) {
                    Ok(s) => {
                        sub = s;
                        start = i + 1;
                        break;
                    }
                    Err(_) => return Err(())
                },
                None => match FromStr::from_str(&raw[start..]) {
                    Ok(s) => return Ok(Mime(top, s, params)),
                    Err(_) => return Err(())
                },
                _ => return Err(())
            };
        }

        // params
        debug!("starting params, len={}", len);
        loop {
            match inspect!("param", param_from_str(raw, &mut iter, start)) {
                Some((p, end)) => {
                    params.push(p);
                    start = end;
                    if start >= len {
                        break;
                    }
                }
                None => break
            }
        }

        Ok(Mime(top, sub, params))
    }
}

fn param_from_str(raw: &str, iter: &mut Enumerate<Chars>, mut start: usize) -> Option<(Param, usize)> {
    let mut attr;
    debug!("param_from_str, start={}", start);
    loop {
        match inspect!("attr iter", iter.next()) {
            Some((i, ' ')) if i == start => start = i + 1,
            Some((i, c)) if i == start && is_restricted_name_first_char(c) => (),
            Some((i, c)) if i > start && is_restricted_name_char(c) => (),
            Some((i, '=')) if i > start => match FromStr::from_str(&raw[start..i]) {
                Ok(a) => {
                    attr = inspect!("attr", a);
                    start = i + 1;
                    break;
                },
                Err(_) => return None
            },
            _ => return None
        }
    }
    let mut value;
    // values must be restrict-name-char or "anything goes"
    let mut is_quoted = false;
    loop {
        match inspect!("value iter", iter.next()) {
            Some((i, '"')) if i == start => {
                debug!("quoted");
                is_quoted = true;
                start = i + 1;
            },
            Some((i, c)) if i == start && is_restricted_name_first_char(c) => (),
            Some((i, '"')) if i > start && is_quoted => match FromStr::from_str(&raw[start..i]) {
                Ok(v) => {
                    value = v;
                    start = i + 1;
                    break;
                },
                Err(_) => return None
            },
            Some((i, c)) if i > start && is_quoted || is_restricted_name_char(c) => (),
            Some((i, ';')) if i > start => match FromStr::from_str(&raw[start..i]) {
                Ok(v) => {
                    value = v;
                    start = i + 1;
                    break;
                },
                Err(_) => return None
            },
            None => match FromStr::from_str(&raw[start..]) {
                Ok(v) => {
                    value = v;
                    start = raw.len();
                    break;
                },
                Err(_) => return None
            },

            _ => return None
        }
    }

    Some(((attr, value), start))
}

// From [RFC6838](http://tools.ietf.org/html/rfc6838#section-4.2):
//
// > All registered media types MUST be assigned top-level type and
// > subtype names.  The combination of these names serves to uniquely
// > identify the media type, and the subtype name facet (or the absence
// > of one) identifies the registration tree.  Both top-level type and
// > subtype names are case-insensitive.
// >
// > Type and subtype names MUST conform to the following ABNF:
// >
// >     type-name = restricted-name
// >     subtype-name = restricted-name
// >
// >     restricted-name = restricted-name-first *126restricted-name-chars
// >     restricted-name-first  = ALPHA / DIGIT
// >     restricted-name-chars  = ALPHA / DIGIT / "!" / "#" /
// >                              "$" / "&" / "-" / "^" / "_"
// >     restricted-name-chars =/ "." ; Characters before first dot always
// >                                  ; specify a facet name
// >     restricted-name-chars =/ "+" ; Characters after last plus always
// >                                  ; specify a structured syntax suffix
//
fn is_restricted_name_first_char(c: char) -> bool {
    match c {
        'a'...'z' |
        '0'...'9' => true,
        _ => false
    }
}

fn is_restricted_name_char(c: char) -> bool {
    if is_restricted_name_first_char(c) {
        true
    } else {
        match c {
            '!' |
            '#' |
            '$' |
            '&' |
            '-' |
            '^' |
            '.' |
            '+' |
            '_' => true,
            _ => false
        }
    }
}

#[inline]
fn fmt_params(params: &[Param], fmt: &mut fmt::Formatter) -> fmt::Result {
    for param in params.iter() {
        try!(fmt_param(param, fmt));
    }
    Ok(())
}

#[inline]
fn fmt_param(param: &Param, fmt: &mut fmt::Formatter) -> fmt::Result {
    let (ref attr, ref value) = *param;
    write!(fmt, "; {}={}", attr, value)
}

#[cfg(test)]
mod tests {
    use std::str::FromStr;
    use test::Bencher;
    use super::{TopLevel, SubLevel, Attr, Value, Mime};

    #[test]
    fn test_mime_show() {
        let mime = Mime(TopLevel::Text, SubLevel::Plain, vec![]);
        assert_eq!(mime.to_string(), "text/plain".to_string());
        let mime = Mime(TopLevel::Text, SubLevel::Plain, vec![(Attr::Charset, Value::Utf8)]);
        assert_eq!(mime.to_string(), "text/plain; charset=utf-8".to_string());
    }

    #[test]
    fn test_mime_from_str() {
        assert_eq!(FromStr::from_str("text/plain"), Ok(Mime(TopLevel::Text, SubLevel::Plain, vec![])));
        assert_eq!(FromStr::from_str("TEXT/PLAIN"), Ok(Mime(TopLevel::Text, SubLevel::Plain, vec![])));
        assert_eq!(FromStr::from_str("text/plain; charset=utf-8"), Ok(Mime(TopLevel::Text, SubLevel::Plain, vec![(Attr::Charset, Value::Utf8)])));
        assert_eq!(FromStr::from_str("text/plain;charset=\"utf-8\""), Ok(Mime(TopLevel::Text, SubLevel::Plain, vec![(Attr::Charset, Value::Utf8)])));
        assert_eq!(FromStr::from_str("text/plain; charset=utf-8; foo=bar"),
            Ok(Mime(TopLevel::Text, SubLevel::Plain, vec![(Attr::Charset, Value::Utf8),
                                        (Attr::Ext("foo".to_string()), Value::Ext("bar".to_string())) ])));
    }

    #[bench]
    fn bench_show(b: &mut Bencher) {
        let mime = Mime(TopLevel::Text, SubLevel::Plain, vec![(Attr::Charset, Value::Utf8), (Attr::Ext("foo".to_string()), Value::Ext("bar".to_string()))]);
        b.bytes = mime.to_string().as_bytes().len() as u64;
        b.iter(|| mime.to_string())
    }

    #[bench]
    fn bench_from_str(b: &mut Bencher) {
        let s = "text/plain; charset=utf-8; foo=bar";
        b.bytes = s.as_bytes().len() as u64;
        b.iter(|| s.parse::<Mime>())
    }
}
<commit_msg>Clean up dereferencing logic<commit_after>//! # Mime
//!
//! Mime is now Media Type, technically, but `Mime` is more immediately
//! understandable, so the main type here is `Mime`.
//!
//! ## What is Mime?
//!
//! Example mime string: `text/plain;charset=utf-8`
//!
//! ```rust
//! # #![allow(unstable)]
//! # use mime::Mime;
//! # use mime::TopLevel::Text;
//! # use mime::SubLevel::Plain;
//! # use mime::Attr::Charset;
//! # use mime::Value::Utf8;
//! let mime: Mime = "text/plain;charset=utf-8".parse().unwrap();
//! assert_eq!(mime, Mime(Text, Plain, vec![(Charset, Utf8)]));
//! ```

#![doc(html_root_url = "http://hyperium.github.io/mime.rs")]
#![cfg_attr(test, deny(warnings))]
#![cfg_attr(test, feature(test))]
#![feature(std_misc)]

#[macro_use]
extern crate log;

#[cfg(test)]
extern crate test;

use std::ascii::AsciiExt;
use std::fmt;
use std::str::FromStr;
use std::iter::Enumerate;
use std::str::Chars;

macro_rules! inspect(
    ($s:expr, $t:expr) => ({
        let t = $t;
        trace!("inspect {}: {:?}", $s, t);
        t
    })
);

/// Mime, or Media Type. Encapsulates common registers types.
///
/// Consider that a traditional mime type contains a "top level type",
/// a "sub level type", and 0-N "parameters". And they're all strings.
/// Strings everywhere. Strings mean typos. Rust has type safety. We should
/// use types!
///
/// So, Mime bundles together this data into types so the compiler can catch
/// your typos.
///
/// This improves things so you use match without Strings:
///
/// ```rust
/// # #![allow(unstable)]
/// use mime::{Mime, TopLevel, SubLevel};
///
/// let mime: mime::Mime = "application/json".parse().unwrap();
///
/// match mime {
///     Mime(TopLevel::Application, SubLevel::Json, _) => println!("matched json!"),
///     _ => ()
/// }
/// ```
#[derive(Clone, PartialEq, Debug)]
pub struct Mime(pub TopLevel, pub SubLevel, pub Vec<Param>);

macro_rules! enoom {
    (pub enum $en:ident; $ext:ident; $($ty:ident, $text:expr;)*) => (

        #[derive(Clone, Debug)]
        pub enum $en {
            $($ty),*,
            $ext(String)
        }

        impl PartialEq for $en {
            fn eq(&self, other: &$en) -> bool {
                match (self, other) {
                    $( (&$en::$ty, &$en::$ty) => true ),*,
                    (&$en::$ext(ref a), &$en::$ext(ref b)) => a == b,
                    _ => self.to_string() == other.to_string()
                }
            }
        }

        impl fmt::Display for $en {
            fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
                fmt.write_str(match *self {
                    $($en::$ty => $text),*,
                    $en::$ext(ref s) => s
                })
            }
        }

        impl FromStr for $en {
            type Err = ();
            fn from_str(s: &str) -> Result<$en, ()> {
                Ok(match s {
                    $(_s if _s == $text => $en::$ty),*,
                    s => $en::$ext(inspect!(stringify!($ext), s).to_string())
                })
            }
        }
    )
}

enoom! {
    pub enum TopLevel;
    Ext;
    Star, "*";
    Text, "text";
    Image, "image";
    Audio, "audio";
    Video, "video";
    Application, "application";
    Multipart, "multipart";
    Message, "message";
    Model, "model";
}

enoom! {
    pub enum SubLevel;
    Ext;
    Star, "*";

    // common text/*
    Plain, "plain";
    Html, "html";
    Xml, "xml";
    Javascript, "javascript";
    Css, "css";

    // common application/*
    Json, "json";
    WwwFormUrlEncoded, "x-www-form-urlencoded";

    // multipart/*
    FormData, "form-data";

    // common image/*
    Png, "png";
    Gif, "gif";
    Bmp, "bmp";
    Jpeg, "jpeg";
}

enoom! {
    pub enum Attr;
    Ext;
    Charset, "charset";
    Q, "q";
}

enoom! {
    pub enum Value;
    Ext;
    Utf8, "utf-8";
}

pub type Param = (Attr, Value);

impl fmt::Display for Mime {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let Mime(ref top, ref sub, ref params) = *self;
        try!(write!(fmt, "{}/{}", top, sub));
        fmt_params(params, fmt)
    }
}

impl FromStr for Mime {
    type Err = ();
    fn from_str(raw: &str) -> Result<Mime, ()> {
        let ascii = raw.to_ascii_lowercase(); // lifetimes :(
        let len = ascii.len();
        let mut iter = ascii.chars().enumerate();
        let mut params = vec![];
        // toplevel
        let mut start;
        let mut top;
        loop {
            match inspect!("top iter", iter.next()) {
                Some((0, c)) if is_restricted_name_first_char(c) => (),
                Some((i, c)) if i > 0 && is_restricted_name_char(c) => (),
                Some((i, '/')) if i > 0 => match FromStr::from_str(&ascii[..i]) {
                    Ok(t) => {
                        top = t;
                        start = i + 1;
                        break;
                    }
                    Err(_) => return Err(())
                },
                _ => return Err(()) // EOF and no toplevel is no Mime
            };

        }

        // sublevel
        let mut sub;
        loop {
            match inspect!("sub iter", iter.next()) {
                Some((i, c)) if i == start && is_restricted_name_first_char(c) => (),
                Some((i, c)) if i > start && is_restricted_name_char(c) => (),
                Some((i, ';')) if i > start => match FromStr::from_str(&ascii[start..i]) {
                    Ok(s) => {
                        sub = s;
                        start = i + 1;
                        break;
                    }
                    Err(_) => return Err(())
                },
                None => match FromStr::from_str(&ascii[start..]) {
                    Ok(s) => return Ok(Mime(top, s, params)),
                    Err(_) => return Err(())
                },
                _ => return Err(())
            };
        }

        // params
        debug!("starting params, len={}", len);
        loop {
            match inspect!("param", param_from_str(&ascii, &mut iter, start)) {
                Some((p, end)) => {
                    params.push(p);
                    start = end;
                    if start >= len {
                        break;
                    }
                }
                None => break
            }
        }

        Ok(Mime(top, sub, params))
    }
}

fn param_from_str(raw: &str, iter: &mut Enumerate<Chars>, mut start: usize) -> Option<(Param, usize)> {
    let mut attr;
    debug!("param_from_str, start={}", start);
    loop {
        match inspect!("attr iter", iter.next()) {
            Some((i, ' ')) if i == start => start = i + 1,
            Some((i, c)) if i == start && is_restricted_name_first_char(c) => (),
            Some((i, c)) if i > start && is_restricted_name_char(c) => (),
            Some((i, '=')) if i > start => match FromStr::from_str(&raw[start..i]) {
                Ok(a) => {
                    attr = inspect!("attr", a);
                    start = i + 1;
                    break;
                },
                Err(_) => return None
            },
            _ => return None
        }
    }
    let mut value;
    // values must be restrict-name-char or "anything goes"
    let mut is_quoted = false;
    loop {
        match inspect!("value iter", iter.next()) {
            Some((i, '"')) if i == start => {
                debug!("quoted");
                is_quoted = true;
                start = i + 1;
            },
            Some((i, c)) if i == start && is_restricted_name_first_char(c) => (),
            Some((i, '"')) if i > start && is_quoted => match FromStr::from_str(&raw[start..i]) {
                Ok(v) => {
                    value = v;
                    start = i + 1;
                    break;
                },
                Err(_) => return None
            },
            Some((i, c)) if i > start && is_quoted || is_restricted_name_char(c) => (),
            Some((i, ';')) if i > start => match FromStr::from_str(&raw[start..i]) {
                Ok(v) => {
                    value = v;
                    start = i + 1;
                    break;
                },
                Err(_) => return None
            },
            None => match FromStr::from_str(&raw[start..]) {
                Ok(v) => {
                    value = v;
                    start = raw.len();
                    break;
                },
                Err(_) => return None
            },

            _ => return None
        }
    }

    Some(((attr, value), start))
}

// From [RFC6838](http://tools.ietf.org/html/rfc6838#section-4.2):
//
// > All registered media types MUST be assigned top-level type and
// > subtype names.  The combination of these names serves to uniquely
// > identify the media type, and the subtype name facet (or the absence
// > of one) identifies the registration tree.  Both top-level type and
// > subtype names are case-insensitive.
// >
// > Type and subtype names MUST conform to the following ABNF:
// >
// >     type-name = restricted-name
// >     subtype-name = restricted-name
// >
// >     restricted-name = restricted-name-first *126restricted-name-chars
// >     restricted-name-first  = ALPHA / DIGIT
// >     restricted-name-chars  = ALPHA / DIGIT / "!" / "#" /
// >                              "$" / "&" / "-" / "^" / "_"
// >     restricted-name-chars =/ "." ; Characters before first dot always
// >                                  ; specify a facet name
// >     restricted-name-chars =/ "+" ; Characters after last plus always
// >                                  ; specify a structured syntax suffix
//
fn is_restricted_name_first_char(c: char) -> bool {
    match c {
        'a'...'z' |
        '0'...'9' => true,
        _ => false
    }
}

fn is_restricted_name_char(c: char) -> bool {
    if is_restricted_name_first_char(c) {
        true
    } else {
        match c {
            '!' |
            '#' |
            '$' |
            '&' |
            '-' |
            '^' |
            '.' |
            '+' |
            '_' => true,
            _ => false
        }
    }
}

#[inline]
fn fmt_params(params: &[Param], fmt: &mut fmt::Formatter) -> fmt::Result {
    for param in params.iter() {
        try!(fmt_param(param, fmt));
    }
    Ok(())
}

#[inline]
fn fmt_param(param: &Param, fmt: &mut fmt::Formatter) -> fmt::Result {
    let (ref attr, ref value) = *param;
    write!(fmt, "; {}={}", attr, value)
}

#[cfg(test)]
mod tests {
    use std::str::FromStr;
    use test::Bencher;
    use super::{TopLevel, SubLevel, Attr, Value, Mime};

    #[test]
    fn test_mime_show() {
        let mime = Mime(TopLevel::Text, SubLevel::Plain, vec![]);
        assert_eq!(mime.to_string(), "text/plain".to_string());
        let mime = Mime(TopLevel::Text, SubLevel::Plain, vec![(Attr::Charset, Value::Utf8)]);
        assert_eq!(mime.to_string(), "text/plain; charset=utf-8".to_string());
    }

    #[test]
    fn test_mime_from_str() {
        assert_eq!(FromStr::from_str("text/plain"), Ok(Mime(TopLevel::Text, SubLevel::Plain, vec![])));
        assert_eq!(FromStr::from_str("TEXT/PLAIN"), Ok(Mime(TopLevel::Text, SubLevel::Plain, vec![])));
        assert_eq!(FromStr::from_str("text/plain; charset=utf-8"), Ok(Mime(TopLevel::Text, SubLevel::Plain, vec![(Attr::Charset, Value::Utf8)])));
        assert_eq!(FromStr::from_str("text/plain;charset=\"utf-8\""), Ok(Mime(TopLevel::Text, SubLevel::Plain, vec![(Attr::Charset, Value::Utf8)])));
        assert_eq!(FromStr::from_str("text/plain; charset=utf-8; foo=bar"),
            Ok(Mime(TopLevel::Text, SubLevel::Plain, vec![(Attr::Charset, Value::Utf8),
                                        (Attr::Ext("foo".to_string()), Value::Ext("bar".to_string())) ])));
    }

    #[bench]
    fn bench_show(b: &mut Bencher) {
        let mime = Mime(TopLevel::Text, SubLevel::Plain, vec![(Attr::Charset, Value::Utf8), (Attr::Ext("foo".to_string()), Value::Ext("bar".to_string()))]);
        b.bytes = mime.to_string().as_bytes().len() as u64;
        b.iter(|| mime.to_string())
    }

    #[bench]
    fn bench_from_str(b: &mut Bencher) {
        let s = "text/plain; charset=utf-8; foo=bar";
        b.bytes = s.as_bytes().len() as u64;
        b.iter(|| s.parse::<Mime>())
    }
}
<|endoftext|>