<commit_before>//use std::collections::HashMap;
use std::ffi::{CString};
use libc::{c_int};

use super::ffi;

use {SqliteResult, SqliteError, SqliteConnection, SqliteStatement, SqliteRows};
use types::{ToSql};

impl SqliteConnection {
}

impl<'conn> SqliteStatement<'conn> {
    /*pub fn parameter_names(&self) -> HashMap<String, i32> {
        let n = unsafe { ffi::sqlite3_bind_parameter_count(self.stmt) };
        let mut index_by_name = HashMap::with_capacity(n as usize);
        for i in 1..n+1 {
            let c_name = unsafe { ffi::sqlite3_bind_parameter_name(self.stmt, i) };
            if !c_name.is_null() {
                let c_slice = unsafe { CStr::from_ptr(c_name).to_bytes() };
                index_by_name.insert(str::from_utf8(c_slice).unwrap().to_string(), n);
            }
        }
        index_by_name
    }*/

    /// Return the index of an SQL parameter given its name.
    /// Return None if `name` is invalid (NulError) or if no matching parameter is found.
    pub fn parameter_index(&self, name: &str) -> Option<i32> {
        unsafe {
            CString::new(name).ok().and_then(|c_name|
                match ffi::sqlite3_bind_parameter_index(self.stmt, c_name.as_ptr()) {
                    0 => None, // A zero is returned if no matching parameter is found.
                    n => Some(n)
                }
            )

        }
    }

    /// Execute the prepared statement with named parameter(s).
    ///
    /// On success, returns the number of rows that were changed or inserted or deleted (via
    /// `sqlite3_changes`).
    pub fn named_execute(&mut self, params: &[(&str, &ToSql)]) -> SqliteResult<c_int> {
        unsafe {
            try!(self.bind_named_parameters(params));
            self.execute_()
        }
    }

    /// Execute the prepared statement with named parameter(s), returning an iterator over the resulting rows.
    pub fn named_query<'a>(&'a mut self, params: &[(&str, &ToSql)]) -> SqliteResult<SqliteRows<'a>> {
        self.reset_if_needed();

        unsafe {
            try!(self.bind_named_parameters(params));
        }

        self.needs_reset = true;
        Ok(SqliteRows::new(self))
    }

    unsafe fn bind_named_parameters(&mut self, params: &[(&str, &ToSql)]) -> SqliteResult<()> {
        for &(name, value) in params {
            let i = try!(self.parameter_index(name).ok_or(SqliteError{
                code: ffi::SQLITE_MISUSE,
                message: format!("Invalid parameter name: {}", name)
            }));
            try!(self.conn.decode_result(value.bind_parameter(self.stmt, i)));
        }
        Ok(())
    }
}

#[cfg(test)]
mod test {
    use SqliteConnection;

   #[test]
    fn test_named_execute() {
        let db = SqliteConnection::open_in_memory().unwrap();
        let sql = "CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag INTEGER)";
        db.execute_batch(sql).unwrap();

        let mut stmt = db.prepare("INSERT INTO test (id, name, flag) VALUES (:id, :name, :flag)").unwrap();
        stmt.named_execute(&[(":name", &"one")]).unwrap();
    }

   #[test]
    fn test_named_query() {
        let db = SqliteConnection::open_in_memory().unwrap();
        let sql = "CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag INTEGER)";
        db.execute_batch(sql).unwrap();

        let mut stmt = db.prepare("SELECT * FROM test where name = :name").unwrap();
        stmt.named_query(&[(":name", &"one")]).unwrap();
    }
}<commit_msg>Add SqliteConnection.execute_named,query_named_row.<commit_after>//use std::collections::HashMap;
use std::ffi::{CString};
use libc::{c_int};

use super::ffi;

use {SqliteResult, SqliteError, SqliteConnection, SqliteStatement, SqliteRows, SqliteRow};
use types::{ToSql};

impl SqliteConnection {
    /// Convenience method to prepare and execute a single SQL statement with named parameter(s).
    pub fn execute_named(&self, sql: &str, params: &[(&str, &ToSql)]) -> SqliteResult<c_int> {
        self.prepare(sql).and_then(|mut stmt| stmt.execute_named(params))
    }

    /// Convenience method to execute a query with named parameter(s) that is expected to return a single row.
    ///
    /// If the query returns more than one row, all rows except the first are ignored.
    pub fn query_named_row<T, F>(&self, sql: &str, params: &[(&str, &ToSql)], f: F) -> SqliteResult<T>
                           where F: FnOnce(SqliteRow) -> T {
        let mut stmt = try!(self.prepare(sql));
        let mut rows = try!(stmt.query_named(params));

        match rows.next() {
            Some(row) => row.map(f),
            None      => Err(SqliteError{
                code: ffi::SQLITE_NOTICE,
                message: "Query did not return a row".to_string(),
            })
        }
    }
}

impl<'conn> SqliteStatement<'conn> {
    /*pub fn parameter_names(&self) -> HashMap<String, i32> {
        let n = unsafe { ffi::sqlite3_bind_parameter_count(self.stmt) };
        let mut index_by_name = HashMap::with_capacity(n as usize);
        for i in 1..n+1 {
            let c_name = unsafe { ffi::sqlite3_bind_parameter_name(self.stmt, i) };
            if !c_name.is_null() {
                let c_slice = unsafe { CStr::from_ptr(c_name).to_bytes() };
                index_by_name.insert(str::from_utf8(c_slice).unwrap().to_string(), n);
            }
        }
        index_by_name
    }*/

    /// Return the index of an SQL parameter given its name.
    /// Return None if `name` is invalid (NulError) or if no matching parameter is found.
    pub fn parameter_index(&self, name: &str) -> Option<i32> {
        unsafe {
            CString::new(name).ok().and_then(|c_name|
                match ffi::sqlite3_bind_parameter_index(self.stmt, c_name.as_ptr()) {
                    0 => None, // A zero is returned if no matching parameter is found.
                    n => Some(n)
                }
            )

        }
    }

    /// Execute the prepared statement with named parameter(s).
    ///
    /// On success, returns the number of rows that were changed or inserted or deleted (via
    /// `sqlite3_changes`).
    pub fn execute_named(&mut self, params: &[(&str, &ToSql)]) -> SqliteResult<c_int> {
        unsafe {
            try!(self.bind_named_parameters(params));
            self.execute_()
        }
    }

    /// Execute the prepared statement with named parameter(s), returning an iterator over the resulting rows.
    pub fn query_named<'a>(&'a mut self, params: &[(&str, &ToSql)]) -> SqliteResult<SqliteRows<'a>> {
        self.reset_if_needed();

        unsafe {
            try!(self.bind_named_parameters(params));
        }

        self.needs_reset = true;
        Ok(SqliteRows::new(self))
    }

    unsafe fn bind_named_parameters(&mut self, params: &[(&str, &ToSql)]) -> SqliteResult<()> {
        for &(name, value) in params {
            let i = try!(self.parameter_index(name).ok_or(SqliteError{
                code: ffi::SQLITE_MISUSE,
                message: format!("Invalid parameter name: {}", name)
            }));
            try!(self.conn.decode_result(value.bind_parameter(self.stmt, i)));
        }
        Ok(())
    }
}

#[cfg(test)]
mod test {
    use SqliteConnection;

    #[test]
    fn test_execute_named() {
        let db = SqliteConnection::open_in_memory().unwrap();
        db.execute_batch("CREATE TABLE foo(x INTEGER)").unwrap();

        assert_eq!(db.execute_named("INSERT INTO foo(x) VALUES (:x)", &[(":x", &1i32)]).unwrap(), 1);
        assert_eq!(db.execute_named("INSERT INTO foo(x) VALUES (:x)", &[(":x", &2i32)]).unwrap(), 1);

        assert_eq!(3i32, db.query_named_row("SELECT SUM(x) FROM foo WHERE x > :x", &[(":x", &0i32)], |r| r.get(0)).unwrap());
    }

   #[test]
    fn test_stmt_execute_named() {
        let db = SqliteConnection::open_in_memory().unwrap();
        let sql = "CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag INTEGER)";
        db.execute_batch(sql).unwrap();

        let mut stmt = db.prepare("INSERT INTO test (id, name, flag) VALUES (:id, :name, :flag)").unwrap();
        stmt.execute_named(&[(":name", &"one")]).unwrap();
    }

   #[test]
    fn test_query_named() {
        let db = SqliteConnection::open_in_memory().unwrap();
        let sql = "CREATE TABLE test (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, flag INTEGER)";
        db.execute_batch(sql).unwrap();

        let mut stmt = db.prepare("SELECT * FROM test where name = :name").unwrap();
        stmt.query_named(&[(":name", &"one")]).unwrap();
    }
}<|endoftext|>


<commit_before>use std::cmp;

use crate::utils::{is_copy, is_self_ty, snippet, span_lint_and_sugg};
use if_chain::if_chain;
use rustc_ast::attr;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{Body, FnDecl, HirId, ItemKind, MutTy, Mutability, Node};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::config::Config as SessionConfig;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::Span;
use rustc_target::abi::LayoutOf;
use rustc_target::spec::abi::Abi;

declare_clippy_lint! {
    /// **What it does:** Checks for functions taking arguments by reference, where
    /// the argument type is `Copy` and small enough to be more efficient to always
    /// pass by value.
    ///
    /// **Why is this bad?** In many calling conventions instances of structs will
    /// be passed through registers if they fit into two or less general purpose
    /// registers.
    ///
    /// **Known problems:** This lint is target register size dependent, it is
    /// limited to 32-bit to try and reduce portability problems between 32 and
    /// 64-bit, but if you are compiling for 8 or 16-bit targets then the limit
    /// will be different.
    ///
    /// The configuration option `trivial_copy_size_limit` can be set to override
    /// this limit for a project.
    ///
    /// This lint attempts to allow passing arguments by reference if a reference
    /// to that argument is returned. This is implemented by comparing the lifetime
    /// of the argument and return value for equality. However, this can cause
    /// false positives in cases involving multiple lifetimes that are bounded by
    /// each other.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// // Bad
    /// fn foo(v: &u32) {}
    /// ```
    ///
    /// ```rust
    /// // Better
    /// fn foo(v: u32) {}
    /// ```
    pub TRIVIALLY_COPY_PASS_BY_REF,
    pedantic,
    "functions taking small copyable arguments by reference"
}

#[derive(Copy, Clone)]
pub struct TriviallyCopyPassByRef {
    limit: u64,
}

impl<'tcx> TriviallyCopyPassByRef {
    pub fn new(limit: Option<u64>, target: &SessionConfig) -> Self {
        let limit = limit.unwrap_or_else(|| {
            let bit_width = u64::from(target.ptr_width);
            // Cap the calculated bit width at 32-bits to reduce
            // portability problems between 32 and 64-bit targets
            let bit_width = cmp::min(bit_width, 32);
            #[allow(clippy::integer_division)]
            let byte_width = bit_width / 8;
            // Use a limit of 2 times the register byte width
            byte_width * 2
        });
        Self { limit }
    }

    fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, hir_id: HirId, decl: &FnDecl<'_>, span: Option<Span>) {
        let fn_def_id = cx.tcx.hir().local_def_id(hir_id);

        let fn_sig = cx.tcx.fn_sig(fn_def_id);
        let fn_sig = cx.tcx.erase_late_bound_regions(&fn_sig);

        // Use lifetimes to determine if we're returning a reference to the
        // argument. In that case we can't switch to pass-by-value as the
        // argument will not live long enough.
        let output_lts = match *fn_sig.output().kind() {
            ty::Ref(output_lt, _, _) => vec![output_lt],
            ty::Adt(_, substs) => substs.regions().collect(),
            _ => vec![],
        };

        for (input, &ty) in decl.inputs.iter().zip(fn_sig.inputs()) {
            // All spans generated from a proc-macro invocation are the same...
            match span {
                Some(s) if s == input.span => return,
                _ => (),
            }

            if_chain! {
                if let ty::Ref(input_lt, ty, Mutability::Not) = ty.kind();
                if !output_lts.contains(&input_lt);
                if is_copy(cx, ty);
                if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes());
                if size <= self.limit;
                if let hir::TyKind::Rptr(_, MutTy { ty: ref decl_ty, .. }) = input.kind;
                then {
                    let value_type = if is_self_ty(decl_ty) {
                        "self".into()
                    } else {
                        snippet(cx, decl_ty.span, "_").into()
                    };
                    span_lint_and_sugg(
                        cx,
                        TRIVIALLY_COPY_PASS_BY_REF,
                        input.span,
                        &format!("this argument ({} byte) is passed by reference, but would be more efficient if passed by value (limit: {} byte)", size, self.limit),
                        "consider passing by value instead",
                        value_type,
                        Applicability::Unspecified,
                    );
                }
            }
        }
    }
}

impl_lint_pass!(TriviallyCopyPassByRef => [TRIVIALLY_COPY_PASS_BY_REF]);

impl<'tcx> LateLintPass<'tcx> for TriviallyCopyPassByRef {
    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
        if item.span.from_expansion() {
            return;
        }

        if let hir::TraitItemKind::Fn(method_sig, _) = &item.kind {
            self.check_poly_fn(cx, item.hir_id, &*method_sig.decl, None);
        }
    }

    fn check_fn(
        &mut self,
        cx: &LateContext<'tcx>,
        kind: FnKind<'tcx>,
        decl: &'tcx FnDecl<'_>,
        _body: &'tcx Body<'_>,
        span: Span,
        hir_id: HirId,
    ) {
        if span.from_expansion() {
            return;
        }

        match kind {
            FnKind::ItemFn(.., header, _, attrs) => {
                if header.abi != Abi::Rust {
                    return;
                }
                for a in attrs {
                    if let Some(meta_items) = a.meta_item_list() {
                        if a.has_name(sym!(proc_macro_derive))
                            || (a.has_name(sym!(inline)) && attr::list_contains_name(&meta_items, sym!(always)))
                        {
                            return;
                        }
                    }
                }
            },
            FnKind::Method(..) => (),
            FnKind::Closure(..) => return,
        }

        // Exclude non-inherent impls
        if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
            if matches!(item.kind, ItemKind::Impl{ of_trait: Some(_), .. } |
                ItemKind::Trait(..))
            {
                return;
            }
        }

        self.check_poly_fn(cx, hir_id, decl, Some(span));
    }
}
<commit_msg>Remove rustc_session::config::Config<commit_after>use std::cmp;

use crate::utils::{is_copy, is_self_ty, snippet, span_lint_and_sugg};
use if_chain::if_chain;
use rustc_ast::attr;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{Body, FnDecl, HirId, ItemKind, MutTy, Mutability, Node};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::Span;
use rustc_target::abi::LayoutOf;
use rustc_target::spec::Target;
use rustc_target::spec::abi::Abi;

declare_clippy_lint! {
    /// **What it does:** Checks for functions taking arguments by reference, where
    /// the argument type is `Copy` and small enough to be more efficient to always
    /// pass by value.
    ///
    /// **Why is this bad?** In many calling conventions instances of structs will
    /// be passed through registers if they fit into two or less general purpose
    /// registers.
    ///
    /// **Known problems:** This lint is target register size dependent, it is
    /// limited to 32-bit to try and reduce portability problems between 32 and
    /// 64-bit, but if you are compiling for 8 or 16-bit targets then the limit
    /// will be different.
    ///
    /// The configuration option `trivial_copy_size_limit` can be set to override
    /// this limit for a project.
    ///
    /// This lint attempts to allow passing arguments by reference if a reference
    /// to that argument is returned. This is implemented by comparing the lifetime
    /// of the argument and return value for equality. However, this can cause
    /// false positives in cases involving multiple lifetimes that are bounded by
    /// each other.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// // Bad
    /// fn foo(v: &u32) {}
    /// ```
    ///
    /// ```rust
    /// // Better
    /// fn foo(v: u32) {}
    /// ```
    pub TRIVIALLY_COPY_PASS_BY_REF,
    pedantic,
    "functions taking small copyable arguments by reference"
}

#[derive(Copy, Clone)]
pub struct TriviallyCopyPassByRef {
    limit: u64,
}

impl<'tcx> TriviallyCopyPassByRef {
    pub fn new(limit: Option<u64>, target: &Target) -> Self {
        let limit = limit.unwrap_or_else(|| {
            let bit_width = u64::from(target.pointer_width);
            // Cap the calculated bit width at 32-bits to reduce
            // portability problems between 32 and 64-bit targets
            let bit_width = cmp::min(bit_width, 32);
            #[allow(clippy::integer_division)]
            let byte_width = bit_width / 8;
            // Use a limit of 2 times the register byte width
            byte_width * 2
        });
        Self { limit }
    }

    fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, hir_id: HirId, decl: &FnDecl<'_>, span: Option<Span>) {
        let fn_def_id = cx.tcx.hir().local_def_id(hir_id);

        let fn_sig = cx.tcx.fn_sig(fn_def_id);
        let fn_sig = cx.tcx.erase_late_bound_regions(&fn_sig);

        // Use lifetimes to determine if we're returning a reference to the
        // argument. In that case we can't switch to pass-by-value as the
        // argument will not live long enough.
        let output_lts = match *fn_sig.output().kind() {
            ty::Ref(output_lt, _, _) => vec![output_lt],
            ty::Adt(_, substs) => substs.regions().collect(),
            _ => vec![],
        };

        for (input, &ty) in decl.inputs.iter().zip(fn_sig.inputs()) {
            // All spans generated from a proc-macro invocation are the same...
            match span {
                Some(s) if s == input.span => return,
                _ => (),
            }

            if_chain! {
                if let ty::Ref(input_lt, ty, Mutability::Not) = ty.kind();
                if !output_lts.contains(&input_lt);
                if is_copy(cx, ty);
                if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes());
                if size <= self.limit;
                if let hir::TyKind::Rptr(_, MutTy { ty: ref decl_ty, .. }) = input.kind;
                then {
                    let value_type = if is_self_ty(decl_ty) {
                        "self".into()
                    } else {
                        snippet(cx, decl_ty.span, "_").into()
                    };
                    span_lint_and_sugg(
                        cx,
                        TRIVIALLY_COPY_PASS_BY_REF,
                        input.span,
                        &format!("this argument ({} byte) is passed by reference, but would be more efficient if passed by value (limit: {} byte)", size, self.limit),
                        "consider passing by value instead",
                        value_type,
                        Applicability::Unspecified,
                    );
                }
            }
        }
    }
}

impl_lint_pass!(TriviallyCopyPassByRef => [TRIVIALLY_COPY_PASS_BY_REF]);

impl<'tcx> LateLintPass<'tcx> for TriviallyCopyPassByRef {
    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
        if item.span.from_expansion() {
            return;
        }

        if let hir::TraitItemKind::Fn(method_sig, _) = &item.kind {
            self.check_poly_fn(cx, item.hir_id, &*method_sig.decl, None);
        }
    }

    fn check_fn(
        &mut self,
        cx: &LateContext<'tcx>,
        kind: FnKind<'tcx>,
        decl: &'tcx FnDecl<'_>,
        _body: &'tcx Body<'_>,
        span: Span,
        hir_id: HirId,
    ) {
        if span.from_expansion() {
            return;
        }

        match kind {
            FnKind::ItemFn(.., header, _, attrs) => {
                if header.abi != Abi::Rust {
                    return;
                }
                for a in attrs {
                    if let Some(meta_items) = a.meta_item_list() {
                        if a.has_name(sym!(proc_macro_derive))
                            || (a.has_name(sym!(inline)) && attr::list_contains_name(&meta_items, sym!(always)))
                        {
                            return;
                        }
                    }
                }
            },
            FnKind::Method(..) => (),
            FnKind::Closure(..) => return,
        }

        // Exclude non-inherent impls
        if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
            if matches!(item.kind, ItemKind::Impl{ of_trait: Some(_), .. } |
                ItemKind::Trait(..))
            {
                return;
            }
        }

        self.check_poly_fn(cx, hir_id, decl, Some(span));
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014 Maciej Piechotka
 *
 * 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.
 */

#[comment = "Wrapper for libxml2's DOM parser."];
#[crate_id = "github.com/uzytkownik/xml-rs#xml:0.1"];
#[crate_type = "lib"];
#[license = "MIT"];

extern mod extra;

mod ffi;

/**
 * An XML document.
 */
pub struct Document {
    priv doc: *ffi::xmlDoc
}

/**
 * An XML element
 */
pub struct Element<'r> {
    priv node: &'r ffi::xmlNode
}

/**
 * Text inside an XML.
 */
pub struct Text<'r> {
    priv node: &'r ffi::xmlNode
}

/**
 * Possible children of an element.
 */
pub enum ElementChildren<'r> {
    ElementElementChild(Element<'r>),
    TextElementChild(Text<'r>)
}

#[unsafe_destructor]
impl Drop for Document {
    fn drop(&mut self) {
        unsafe {
            ffi::xmlFreeDoc(self.doc);
        }
    }
}

impl Document {
    /**
     * Find the root element, if it exists.
     */
    pub fn get_root_element<'r>(&'r self) -> Option<Element<'r>> {
        use std::ptr::is_not_null;
        unsafe {
            let elem = ffi::xmlDocGetRootElement(self.doc);
            if (is_not_null(elem)) {
                Some(Element {node: &*elem})
            } else {
                None
            }
        }
    }
}

impl<'r> Element<'r> {
    /**
     * Gets the name of the element.
     */
    pub fn name(&self) -> ~str {
        unsafe {std::str::raw::from_c_str(self.node.name as *i8)}
    }
    /**
     * Finds all children of the element.
     */
    pub fn children(&self) -> ~[ElementChildren<'r>] {
        std::vec::build(None, |push| {
            unsafe {
                let mut cur = self.node.children;
                while (std::ptr::is_not_null(cur)) {
                    match (*cur)._type {
                        ffi::ElementNode => push(ElementElementChild(Element {node: &*cur})),
                        ffi::TextNode => push(TextElementChild(Text {node: &*cur})),
                        t => error!("Unsupported type {}", t.to_str())
                    }
                    cur = (*cur).next;
                }
            }
        })
    }
}

impl<'r> Text<'r> {
    pub fn content(&self) -> ~str {
        unsafe {
            std::str::raw::from_c_str(self.node.content as *i8)
        }
    }
}

/**
 * Reads the buffer treating it as if it came from url.
 *
 * It returns the document if buffer contained valid XML.
 */
pub fn read_memory_with_url(buffer: &[u8], url: Option<&str>) -> Option<Document> {
    unsafe {
        use std::libc::c_int;
        use std::ptr::{null,is_not_null};
        ffi::xmlCheckVersion(ffi::xmlVersion);
        let doc = ffi::xmlReadMemory(buffer.as_ptr(), buffer.len() as c_int,
                                     url.map(|x| x.as_ptr()).unwrap_or(null()) as *i8,
                                     null(), 64 | 32 /* No errors or warnings for now */);
        if (is_not_null(doc)) {
            Some(Document {doc: doc})
        } else {
            None
        }
    }
}

/**
 * Reads the buffer and return the document if it contains valid XML.
 */
pub fn read_memory(buffer: &[u8]) -> Option<Document> {
    read_memory_with_url(buffer, None)
}
<commit_msg>Refactor null check and move implementation of traits after structs<commit_after>/*
 * Copyright (C) 2014 Maciej Piechotka
 *
 * 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.
 */

#[comment = "Wrapper for libxml2's DOM parser."];
#[crate_id = "github.com/uzytkownik/xml-rs#xml:0.1"];
#[crate_type = "lib"];
#[license = "MIT"];

extern mod extra;

mod ffi;

/**
 * An XML document.
 */
pub struct Document {
    priv doc: *ffi::xmlDoc
}

/**
 * An XML element
 */
pub struct Element<'r> {
    priv node: &'r ffi::xmlNode
}

/**
 * Text inside an XML.
 */
pub struct Text<'r> {
    priv node: &'r ffi::xmlNode
}

/**
 * Possible children of an element.
 */
pub enum ElementChildren<'r> {
    ElementElementChild(Element<'r>),
    TextElementChild(Text<'r>)
}

impl Document {
    /**
     * Find the root element, if it exists.
     */
    pub fn get_root_element<'r>(&'r self) -> Option<Element<'r>> {
        unsafe {
            ptr_to_option(ffi::xmlDocGetRootElement(self.doc)).map(|elem| Element{node: &*elem})
        }
    }
}

#[unsafe_destructor]
impl Drop for Document {
    fn drop(&mut self) {
        unsafe {
            ffi::xmlFreeDoc(self.doc);
        }
    }
}

impl<'r> Element<'r> {
    /**
     * Gets the name of the element.
     */
    pub fn name(&self) -> ~str {
        unsafe {std::str::raw::from_c_str(self.node.name as *i8)}
    }
    /**
     * Finds all children of the element.
     */
    pub fn children(&self) -> ~[ElementChildren<'r>] {
        std::vec::build(None, |push| {
            unsafe {
                let mut cur = self.node.children;
                while (std::ptr::is_not_null(cur)) {
                    match (*cur)._type {
                        ffi::ElementNode => push(ElementElementChild(Element {node: &*cur})),
                        ffi::TextNode => push(TextElementChild(Text {node: &*cur})),
                        t => error!("Unsupported type {}", t.to_str())
                    }
                    cur = (*cur).next;
                }
            }
        })
    }
}

impl<'r> Text<'r> {
    pub fn content(&self) -> ~str {
        unsafe {
            std::str::raw::from_c_str(self.node.content as *i8)
        }
    }
}

/**
 * Reads the buffer treating it as if it came from url.
 *
 * It returns the document if buffer contained valid XML.
 */
pub fn read_memory_with_url(buffer: &[u8], url: Option<&str>) -> Option<Document> {
    unsafe {
        use std::libc::c_int;
        use std::ptr::null;
        ffi::xmlCheckVersion(ffi::xmlVersion);
        let doc = ffi::xmlReadMemory(buffer.as_ptr(), buffer.len() as c_int,
                                     url.map(|x| x.as_ptr()).unwrap_or(null()) as *i8,
                                     null(), 64 | 32 /* No errors or warnings for now */);
        ptr_to_option(doc).map(|doc| Document {doc: doc})
    }
}

/**
 * Reads the buffer and return the document if it contains valid XML.
 */
pub fn read_memory(buffer: &[u8]) -> Option<Document> {
    read_memory_with_url(buffer, None)
}

fn ptr_to_option<T>(ptr: *T) -> Option<*T> {
    if (std::ptr::is_not_null(ptr)) {
        Some(ptr)
    } else {
        None
    }
}
<|endoftext|>


<commit_before>//! Utilities for generalized iterators over trees of arbitrary types.

use super::iter::*;
pub use self::action::Action;

/// Descriptions of actions that may be taken on a given node when traversing
/// a pattern tree.
pub mod action {
    use super::WalkType;

    enum Flag {
        /// Terminate iteration after performing other specified actions.
        TERMINATE = 1,
    }

    pub use self::Flag::*;

    pub struct Action<Type> where Type: WalkType {
        pub yield_value: Option<<Type as WalkType>::Yield>,
        pub recurse: bool,
        pub flags: u8
    }

    impl<Type> Action<Type> where Type: WalkType {
        pub fn new(y: Option<<Type as WalkType>::Yield>, r: bool, f: u8) -> Action<Type> {
            Action{yield_value: y, recurse: r, flags: f}
        }
    }

}

/// Defines a particular kind of walk.
pub trait WalkType {
    /// Type yielded by iterators for this trait.
    type Yield;

    /// Value produced by base iterators for the container being walked.
    type Item;
}

/// Interface for patterns whose elements may be visited in
/// a runtime-specified manner.
///
/// @tparam Type Marker type used to discriminate the "type" of walk being
///     implemented.  A particular type may be walked for different purposes,
///     such as to visit *all* elements, or only certain ones.
///
/// @tparam
pub trait Walkable<'a,Type>: Iterable<'a,Box<Iterator<Item=<Type as WalkType>::Item>>> /*Iterable<'a,IterBox<'a,&'a <Type as WalkType>::Item>>*/
where Type: WalkType {
    /// Determine the action to take for a given node in the implementor's
    /// element tree.
    ///
    /// @param element Pattern element to process.
    ///
    /// @return Tuple containing the optionally-yielded element, and a set of
    ///     flags indicating how to proceed.  Action::RECURSE is only valid
    ///     when `Item` implements Walkable<Tag>.
    fn action(&'a self, element: <Type as WalkType>::Item)
                  -> Action<Type>;
}

/// Iterator used to perform a particular walk on a particular type.
///
/// @tparam Tag Walk-type tag.
///
/// @tparam Yield `Item` type for the iterator implementation of
///     the structure.
///
/// @tparam T Top-level Walkable type for which this structure is an iterator.
pub struct Walker<'a,Type>
    where Type: WalkType,
          <Type as WalkType>::Item: 'a {

    walkable: &'a Walkable<'a,Type>,
    base_iterator: Option<Box<Iterator<Item=<Type as WalkType>::Item> + 'a>>,
    //base_iterator: Option<IterBox<'a,&'a <Type as WalkType>::Item>>,
    sub_iterator: Option<Box<Iterator<Item=<Type as WalkType>::Yield> + 'a>>
    //sub_iterator: Option<IterBox<'a,<Type as WalkType>::Yield>>
}

impl<'a,Type> Walker<'a,Type>
    where Type: WalkType,
          <Type as WalkType>::Item: 'a {
    /// Create a new walker iterator from the given base iterator.
    pub fn new(base: &'a Walkable<'a,Type>) -> Walker<'a,Type> {
        Walker{walkable: base,
               base_iterator: Some(base.iter()),
               sub_iterator: None}
    }
}

impl<'a,Type> Iterator for Walker<'a,Type>
where Type: 'a + WalkType,
      <Type as WalkType>::Yield: 'a,
      <Type as WalkType>::Item: 'a + Iterable<'a,Box<Iterator<Item=<Type as WalkType>::Yield>+'a>> + Walkable<'a,Type>,/*Iterable<'a,IterBox<'a,<Type as WalkType>::Yield>> + Walkable<'a,Type>*/
{
    type Item = <Type as WalkType>::Yield;

    fn next(&mut self) -> Option<<Self as Iterator>::Item> {
        let mut terminate: bool = false;
        loop {
            if terminate { self.base_iterator = None;
                           break; }

            // If the sub-iterator exists and isn't exhausted, return its
            // yielded value...
            if let Some(ref mut iter) = self.sub_iterator {
                let yielded_opt = (*iter).next();
                if yielded_opt.is_some() {
                    return yielded_opt }
            }
            // ...otherwise clear it and check if the base iterator exists
            self.sub_iterator = None;
            if let Some(ref mut iter) = self.base_iterator {
                if let Some(ref element) = (*iter).next() {
                    let action = self.walkable.action(*element);

                    // FIXME: need to provide a way to specify order in which
                    // to recurse vs. yield.  The solution should allow for
                    // selection of different traversal methods -- need to come
                    // up with an API for that.
                    if action.recurse {
                        self.sub_iterator = Some(Box::new(Walker::new(element as &Walkable<'a,Type>)));

                        // Recurse immediately if we have no value to yield.
                        if ! action.yield_value.is_some() {
                            continue;
                        }
                    }

                    // For now we'll just do depth-first, since it's simplest.
                    if action.yield_value.is_some() {
                        return action.yield_value;
                    }

                    // Clear the base iterator if we were asked to terminate
                    // the walk.  Note that any recursive walks on
                    // `self.sub_iterator` will continue until that iterator
                    // is exhausted.
                    if (action.flags & action::TERMINATE as u8) != 0 {
                        terminate = true; }
                } else {
                    // Base iterator is exhausted; clear it.
                    terminate = true;
                }
            }
        }
        if terminate { self.base_iterator = None; }
        return None;
    }

    /// We implement `size_hint` as the sum of the hints for the current base-
    /// and sub-iterators, if they're not `None`.  We return an upper bound
    /// only if both iterators are `None`.
    fn size_hint(&self) -> (usize, Option<usize>) {
        let mut min = 0;
        if let Some(ref iter) = self.sub_iterator { min += iter.size_hint().0 }
        if let Some(ref iter) = self.base_iterator { min += iter.size_hint().0 }

        (min, if self.sub_iterator.is_none() && self.base_iterator.is_none() { Some(0) } else { None })
    }
}
<commit_msg>pattern/walk: remove some unnecessary explicit dereferences<commit_after>//! Utilities for generalized iterators over trees of arbitrary types.

use super::iter::*;
pub use self::action::Action;

/// Descriptions of actions that may be taken on a given node when traversing
/// a pattern tree.
pub mod action {
    use super::WalkType;

    enum Flag {
        /// Terminate iteration after performing other specified actions.
        TERMINATE = 1,
    }

    pub use self::Flag::*;

    pub struct Action<Type> where Type: WalkType {
        pub yield_value: Option<<Type as WalkType>::Yield>,
        pub recurse: bool,
        pub flags: u8
    }

    impl<Type> Action<Type> where Type: WalkType {
        pub fn new(y: Option<<Type as WalkType>::Yield>, r: bool, f: u8) -> Action<Type> {
            Action{yield_value: y, recurse: r, flags: f}
        }
    }

}

/// Defines a particular kind of walk.
pub trait WalkType {
    /// Type yielded by iterators for this trait.
    type Yield;

    /// Value produced by base iterators for the container being walked.
    type Item;
}

/// Interface for patterns whose elements may be visited in
/// a runtime-specified manner.
///
/// @tparam Type Marker type used to discriminate the "type" of walk being
///     implemented.  A particular type may be walked for different purposes,
///     such as to visit *all* elements, or only certain ones.
///
/// @tparam
pub trait Walkable<'a,Type>: Iterable<'a,Box<Iterator<Item=<Type as WalkType>::Item>>> /*Iterable<'a,IterBox<'a,&'a <Type as WalkType>::Item>>*/
where Type: WalkType {
    /// Determine the action to take for a given node in the implementor's
    /// element tree.
    ///
    /// @param element Pattern element to process.
    ///
    /// @return Tuple containing the optionally-yielded element, and a set of
    ///     flags indicating how to proceed.  Action::RECURSE is only valid
    ///     when `Item` implements Walkable<Tag>.
    fn action(&'a self, element: <Type as WalkType>::Item)
                  -> Action<Type>;
}

/// Iterator used to perform a particular walk on a particular type.
///
/// @tparam Tag Walk-type tag.
///
/// @tparam Yield `Item` type for the iterator implementation of
///     the structure.
///
/// @tparam T Top-level Walkable type for which this structure is an iterator.
pub struct Walker<'a,Type>
    where Type: WalkType,
          <Type as WalkType>::Item: 'a {

    walkable: &'a Walkable<'a,Type>,
    base_iterator: Option<Box<Iterator<Item=<Type as WalkType>::Item> + 'a>>,
    //base_iterator: Option<IterBox<'a,&'a <Type as WalkType>::Item>>,
    sub_iterator: Option<Box<Iterator<Item=<Type as WalkType>::Yield> + 'a>>
    //sub_iterator: Option<IterBox<'a,<Type as WalkType>::Yield>>
}

impl<'a,Type> Walker<'a,Type>
    where Type: WalkType,
          <Type as WalkType>::Item: 'a {
    /// Create a new walker iterator from the given base iterator.
    pub fn new(base: &'a Walkable<'a,Type>) -> Walker<'a,Type> {
        Walker{walkable: base,
               base_iterator: Some(base.iter()),
               sub_iterator: None}
    }
}

impl<'a,Type> Iterator for Walker<'a,Type>
where Type: 'a + WalkType,
      <Type as WalkType>::Yield: 'a,
      <Type as WalkType>::Item: 'a + Iterable<'a,Box<Iterator<Item=<Type as WalkType>::Yield>+'a>> + Walkable<'a,Type>,/*Iterable<'a,IterBox<'a,<Type as WalkType>::Yield>> + Walkable<'a,Type>*/
{
    type Item = <Type as WalkType>::Yield;

    fn next(&mut self) -> Option<<Self as Iterator>::Item> {
        let mut terminate: bool = false;
        loop {
            if terminate { self.base_iterator = None;
                           break; }

            // If the sub-iterator exists and isn't exhausted, return its
            // yielded value...
            if let Some(ref mut iter) = self.sub_iterator {
                let yielded_opt = iter.next();
                if yielded_opt.is_some() {
                    return yielded_opt }
            }
            // ...otherwise clear it and check if the base iterator exists
            self.sub_iterator = None;
            if let Some(ref mut iter) = self.base_iterator {
                if let Some(ref element) = iter.next() {
                    let action = self.walkable.action(*element);

                    // FIXME: need to provide a way to specify order in which
                    // to recurse vs. yield.  The solution should allow for
                    // selection of different traversal methods -- need to come
                    // up with an API for that.
                    if action.recurse {
                        self.sub_iterator = Some(Box::new(Walker::new(element as &Walkable<'a,Type>)));

                        // Recurse immediately if we have no value to yield.
                        if ! action.yield_value.is_some() {
                            continue;
                        }
                    }

                    // For now we'll just do depth-first, since it's simplest.
                    if action.yield_value.is_some() {
                        return action.yield_value;
                    }

                    // Clear the base iterator if we were asked to terminate
                    // the walk.  Note that any recursive walks on
                    // `self.sub_iterator` will continue until that iterator
                    // is exhausted.
                    if (action.flags & action::TERMINATE as u8) != 0 {
                        terminate = true; }
                } else {
                    // Base iterator is exhausted; clear it.
                    terminate = true;
                }
            }
        }
        if terminate { self.base_iterator = None; }
        return None;
    }

    /// We implement `size_hint` as the sum of the hints for the current base-
    /// and sub-iterators, if they're not `None`.  We return an upper bound
    /// only if both iterators are `None`.
    fn size_hint(&self) -> (usize, Option<usize>) {
        let mut min = 0;
        if let Some(ref iter) = self.sub_iterator { min += iter.size_hint().0 }
        if let Some(ref iter) = self.base_iterator { min += iter.size_hint().0 }

        (min, if self.sub_iterator.is_none() && self.base_iterator.is_none() { Some(0) } else { None })
    }
}
<|endoftext|>


<commit_before>//! Utilities for generalized iterators over trees of arbitrary types.

use std;

#[repr(u8)]

/// Descriptions of actions that may be taken on a given node when traversing
/// a pattern tree.
pub mod action {
    enum Flag {
        /// Terminate iteration after performing other specified actions.
        TERMINATE = 1,
    }

    pub use self::Flag::*;

    struct Action<U,V> {
        yield_value: Option<U>,
        recurse_on: Option<V>,
        flags: u8
    }
}

pub use self::action::Action;

/// Interface for patterns whose elements may be visited in
/// a runtime-specified manner.
///
/// @tparam Tag Marker type used to discriminate the "type" of walk being
///     implemented.  A particular type may be walked for different purposes,
///     such as to visit *all* elements, or only certain ones.
///
/// @tparam Yielded Type of item the walkable should implement an iterator for.
trait Walkable<Tag,Yielded>: std::marker::PhantomFn<Tag> {
    /// Iterator type that for the implementer's underlying container.
    type BaseIterator;
    type Item = <Self::BaseIterator as Iterator>::Item;
    type Action = Action<Yielded,Self::Item>;

    /// Fetch the initial iterator to use for a walk.
    fn iter(&self) -> Self::BaseIterator;

    /// Determine the action to take for a given node in the implementor's
    /// element tree.
    ///
    /// @param element Pattern element to process.
    ///
    /// @return Tuple containing the optionally-yielded element, and a set of
    ///     flags indicating how to proceed.  Action::RECURSE is only valid
    ///     when `Item` implements Walkable<Yielded>.
    fn action<'a>(element: &'a Self::Item) -> Action
        where Self::Item: Walkable<Tag,Yielded>;
}

// FIXME: should the order of `T` and `Yielded` be reversed?
/// Iterator used to perform a particular walk on a particular type.
///
/// @tparam Tag Walk-type tag.
///
/// @tparam Yielded `Item` type for the iterator implementation of
///     the structure.
///
/// @tparam T Top-level Walkable type for which this structure is an iterator.
struct Walker<Tag,Yielded,T> where T: Walkable<Tag,Yielded> {
    base_iterator: Option<<T as Walkable<Tag,Yielded>>::BaseIterator>,
    sub_iterator: Option<Walker<Tag,Yielded,Yielded>>,
}

impl<Tag,Yielded,T> Walker<Tag,Yielded,T>
where T: Walkable<Tag,Yielded> {
    /// Create a new walker iterator from the given base iterator.
    pub fn new(base: <T as Walkable<Tag,Yielded>>::BaseIterator) -> Walker<Tag,Yielded,T> {
        Walker{base_iterator: base, sub_iterator: None}
    }
}

impl<'a,Tag,Yielded,T> Iterator for Walker<Tag,Yielded,T>
where T: Walkable<Tag,Yielded>, Yielded: Walkable<Tag,Yielded> {
    type Item = &'a Yielded;

    fn next(&mut self) -> Option<<Self as Iterator>::Item> {
        // "can't use type parameter from outer function" Why not?  And it's not a function.
        //type Walk = Walkable<Tag,Yielded>;
        // "huh?  why's there a less-than sign in here?"  Because I put it there.
        //use self::Walkable<Tag,Yielded> as Walk;

        if let Some(ref iter) = self.sub_iterator {
            if let Some(yielded) = (*iter).next() {
                return yielded; }
            else {
                // Sub-iterator is empty; clear it and fall through to the
                // base iterator.
                self.sub_iterator = None;
            } }
        if let Some(ref iter) = self.base_iterator {
            if let Some(ref element) = (*iter).next() {
                let action = <T as Walk>::action(element);

                // FIXME: need to provide a way to specify order in which
                // to recurse vs. yield.  The solution should allow for
                // selection of different traversal methods -- need to come
                // up with an API for that.
                if let Some(recurse_item) = action.recurse_on {
                    self.sub_iterator = Some(Walker::new(<Yielded as Walk>::iter(recurse_item)));

                    // Recurse immediately if we have no value to yield.
                    if ! action.yield_value.is_some() {
                        self.next()
                    }
                }

                // For now we'll just do depth-first, since it's simplest.
                if let Some(yielded) = action.yield_value {
                    return yielded;
                }

                // Clear the base iterator if we were asked to terminate
                // the walk.  Note that any recursive walks on
                // `self.sub_iterator` will continue until that iterator
                // is exhausted.
                if action.flags & action::TERMINATE {
                    self.base_iterator = None; }
            } else {
                // Base iterator is exhausted; clear it.
                self.base_iterator = None;
            }
        }
        return None;
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (1, None)
    }
}
<commit_msg>pattern/walk: just use the verbose trait name, for now<commit_after>//! Utilities for generalized iterators over trees of arbitrary types.

use std;

#[repr(u8)]

/// Descriptions of actions that may be taken on a given node when traversing
/// a pattern tree.
pub mod action {
    enum Flag {
        /// Terminate iteration after performing other specified actions.
        TERMINATE = 1,
    }

    pub use self::Flag::*;

    struct Action<U,V> {
        yield_value: Option<U>,
        recurse_on: Option<V>,
        flags: u8
    }
}

pub use self::action::Action;

/// Interface for patterns whose elements may be visited in
/// a runtime-specified manner.
///
/// @tparam Tag Marker type used to discriminate the "type" of walk being
///     implemented.  A particular type may be walked for different purposes,
///     such as to visit *all* elements, or only certain ones.
///
/// @tparam Yielded Type of item the walkable should implement an iterator for.
trait Walkable<Tag,Yielded>: std::marker::PhantomFn<Tag> {
    /// Iterator type that for the implementer's underlying container.
    type BaseIterator;
    type Item = <Self::BaseIterator as Iterator>::Item;
    type Action = Action<Yielded,Self::Item>;

    /// Fetch the initial iterator to use for a walk.
    fn iter(&self) -> Self::BaseIterator;

    /// Determine the action to take for a given node in the implementor's
    /// element tree.
    ///
    /// @param element Pattern element to process.
    ///
    /// @return Tuple containing the optionally-yielded element, and a set of
    ///     flags indicating how to proceed.  Action::RECURSE is only valid
    ///     when `Item` implements Walkable<Yielded>.
    fn action<'a>(element: &'a Self::Item) -> Action
        where Self::Item: Walkable<Tag,Yielded>;
}

// FIXME: should the order of `T` and `Yielded` be reversed?
/// Iterator used to perform a particular walk on a particular type.
///
/// @tparam Tag Walk-type tag.
///
/// @tparam Yielded `Item` type for the iterator implementation of
///     the structure.
///
/// @tparam T Top-level Walkable type for which this structure is an iterator.
struct Walker<Tag,Yielded,T> where T: Walkable<Tag,Yielded> {
    base_iterator: Option<<T as Walkable<Tag,Yielded>>::BaseIterator>,
    sub_iterator: Option<Walker<Tag,Yielded,Yielded>>,
}

impl<Tag,Yielded,T> Walker<Tag,Yielded,T>
where T: Walkable<Tag,Yielded> {
    /// Create a new walker iterator from the given base iterator.
    pub fn new(base: <T as Walkable<Tag,Yielded>>::BaseIterator) -> Walker<Tag,Yielded,T> {
        Walker{base_iterator: base, sub_iterator: None}
    }
}

impl<'a,Tag,Yielded,T> Iterator for Walker<Tag,Yielded,T>
where T: Walkable<Tag,Yielded>, Yielded: Walkable<Tag,Yielded> {
    type Item = &'a Yielded;

    fn next(&mut self) -> Option<<Self as Iterator>::Item> {
        // "can't use type parameter from outer function" Why not?  And it's not a function.
        //type Walk = Walkable<Tag,Yielded>;
        // "huh?  why's there a less-than sign in here?"  Because I put it there.
        //use self::Walkable<Tag,Yielded> as Walk;

        if let Some(ref iter) = self.sub_iterator {
            if let Some(yielded) = (*iter).next() {
                return yielded; }
            else {
                // Sub-iterator is empty; clear it and fall through to the
                // base iterator.
                self.sub_iterator = None;
            } }
        if let Some(ref iter) = self.base_iterator {
            if let Some(ref element) = (*iter).next() {
                let action = <T as Walkable<Tag,Yielded>>::action(element);

                // FIXME: need to provide a way to specify order in which
                // to recurse vs. yield.  The solution should allow for
                // selection of different traversal methods -- need to come
                // up with an API for that.
                if let Some(recurse_item) = action.recurse_on {
                    self.sub_iterator = Some(Walker::new(<Yielded as Walkable<Tag,Yielded>>::iter(recurse_item)));

                    // Recurse immediately if we have no value to yield.
                    if ! action.yield_value.is_some() {
                        self.next()
                    }
                }

                // For now we'll just do depth-first, since it's simplest.
                if let Some(yielded) = action.yield_value {
                    return yielded;
                }

                // Clear the base iterator if we were asked to terminate
                // the walk.  Note that any recursive walks on
                // `self.sub_iterator` will continue until that iterator
                // is exhausted.
                if action.flags & action::TERMINATE {
                    self.base_iterator = None; }
            } else {
                // Base iterator is exhausted; clear it.
                self.base_iterator = None;
            }
        }
        return None;
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (1, None)
    }
}
<|endoftext|>


<commit_before>//! Labels interface
use serde::{Deserialize, Serialize};

use crate::{Future, Github, Stream};

pub struct Labels {
    github: Github,
    owner: String,
    repo: String,
}

impl Labels {
    #[doc(hidden)]
    pub fn new<O, R>(github: Github, owner: O, repo: R) -> Self
    where
        O: Into<String>,
        R: Into<String>,
    {
        Labels {
            github,
            owner: owner.into(),
            repo: repo.into(),
        }
    }

    fn path(&self, more: &str) -> String {
        format!("/repos/{}/{}/labels{}", self.owner, self.repo, more)
    }

    pub fn create(&self, lab: &LabelOptions) -> Future<Label> {
        self.github.post(&self.path(""), json!(lab))
    }

    pub fn update(&self, prevname: &str, lab: &LabelOptions) -> Future<Label> {
        self.github
            .patch(&self.path(&format!("/{}", prevname)), json!(lab))
    }

    pub fn delete(&self, name: &str) -> Future<()> {
        self.github.delete(&self.path(&format!("/{}", name)))
    }

    pub fn list(&self) -> Future<Vec<Label>> {
        self.github.get(&self.path(""))
    }

    /// provides a stream over all pages of this repo's labels
    pub fn iter(&self) -> Stream<Label> {
        self.github.get_stream(&self.path(""))
    }
}

// representations

#[derive(Debug, Serialize)]
pub struct LabelOptions {
    pub name: String,
    pub color: String,
}

impl LabelOptions {
    pub fn new<N, C>(name: N, color: C) -> LabelOptions
    where
        N: Into<String>,
        C: Into<String>,
    {
        LabelOptions {
            name: name.into(),
            color: color.into(),
        }
    }
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Label {
    pub url: String,
    pub name: String,
    pub color: String,
}
<commit_msg>add a description to labels<commit_after>//! Labels interface
use serde::{Deserialize, Serialize};

use crate::{Future, Github, Stream};

pub struct Labels {
    github: Github,
    owner: String,
    repo: String,
}

impl Labels {
    #[doc(hidden)]
    pub fn new<O, R>(github: Github, owner: O, repo: R) -> Self
    where
        O: Into<String>,
        R: Into<String>,
    {
        Labels {
            github,
            owner: owner.into(),
            repo: repo.into(),
        }
    }

    fn path(&self, more: &str) -> String {
        format!("/repos/{}/{}/labels{}", self.owner, self.repo, more)
    }

    pub fn create(&self, lab: &LabelOptions) -> Future<Label> {
        self.github.post(&self.path(""), json!(lab))
    }

    pub fn update(&self, prevname: &str, lab: &LabelOptions) -> Future<Label> {
        self.github
            .patch(&self.path(&format!("/{}", prevname)), json!(lab))
    }

    pub fn delete(&self, name: &str) -> Future<()> {
        self.github.delete(&self.path(&format!("/{}", name)))
    }

    pub fn list(&self) -> Future<Vec<Label>> {
        self.github.get(&self.path(""))
    }

    /// provides a stream over all pages of this repo's labels
    pub fn iter(&self) -> Stream<Label> {
        self.github.get_stream(&self.path(""))
    }
}

// representations

#[derive(Debug, Serialize)]
pub struct LabelOptions {
    pub name: String,
    pub color: String,
    pub description: String,
}

impl LabelOptions {
    pub fn new<N, C, D>(name: N, color: C, description: D) -> LabelOptions
    where
        N: Into<String>,
        C: Into<String>,
        D: Into<String>,
    {
        LabelOptions {
            name: name.into(),
            color: color.into(),
            description: description.into(),
        }
    }
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Label {
    pub url: String,
    pub name: String,
    pub color: String,
}
<|endoftext|>


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

use std::collections::VecDeque;
use std::net::SocketAddr;
use std::sync::{Arc, RwLock};

use futures::Future;
use rand::Rng;
use rand::os::OsRng;
use tokio_core::net::TcpStream;

use core::core::target::Difficulty;
use core::ser;
use msg::*;
use types::*;
use protocol::ProtocolV1;
use util::LOGGER;

const NONCES_CAP: usize = 100;

/// Handles the handshake negotiation when two peers connect and decides on
/// protocol.
pub struct Handshake {
	/// Ring buffer of nonces sent to detect self connections without requiring
	/// a node id.
	nonces: Arc<RwLock<VecDeque<u64>>>,
}

unsafe impl Sync for Handshake {}
unsafe impl Send for Handshake {}

impl Handshake {
	/// Creates a new handshake handler
	pub fn new() -> Handshake {
		Handshake {
			nonces: Arc::new(RwLock::new(VecDeque::with_capacity(NONCES_CAP))),
		}
	}

	/// Handles connecting to a new remote peer, starting the version handshake.
	pub fn connect(
		&self,
		capab: Capabilities,
		total_difficulty: Difficulty,
		self_addr: SocketAddr,
		conn: TcpStream,
	) -> Box<Future<Item = (TcpStream, ProtocolV1, PeerInfo), Error = Error>> {
		// prepare the first part of the handshake
		let nonce = self.next_nonce();
		debug!(
			LOGGER,
			"handshake connect with nonce - {}, sender - {:?}, receiver - {:?}",
			nonce,
			self_addr,
			conn.peer_addr().unwrap(),
		);

		let hand = Hand {
			version: PROTOCOL_VERSION,
			capabilities: capab,
			nonce: nonce,
			total_difficulty: total_difficulty,
			sender_addr: SockAddr(self_addr),
			receiver_addr: SockAddr(conn.peer_addr().unwrap()),
			user_agent: USER_AGENT.to_string(),
		};

		// write and read the handshake response
		Box::new(
			write_msg(conn, hand, Type::Hand)
				.and_then(|conn| read_msg::<Shake>(conn))
				.and_then(|(conn, shake)| {
					if shake.version != 1 {
						Err(Error::Serialization(ser::Error::UnexpectedData {
							expected: vec![PROTOCOL_VERSION as u8],
							received: vec![shake.version as u8],
						}))
					} else {
						let peer_info = PeerInfo {
							capabilities: shake.capabilities,
							user_agent: shake.user_agent,
							addr: conn.peer_addr().unwrap(),
							version: shake.version,
							total_difficulty: shake.total_difficulty,
						};

						info!(LOGGER, "Connected to peer {:?}", peer_info);
						// when more than one protocol version is supported, choosing should go here
						Ok((conn, ProtocolV1::new(), peer_info))
					}
				}),
		)
	}

	/// Handles receiving a connection from a new remote peer that started the
	/// version handshake.
	pub fn handshake(
		&self,
		capab: Capabilities,
		total_difficulty: Difficulty,
		conn: TcpStream,
	) -> Box<Future<Item = (TcpStream, ProtocolV1, PeerInfo), Error = Error>> {
		let nonces = self.nonces.clone();
		Box::new(
			read_msg::<Hand>(conn)
				.and_then(move |(conn, hand)| {
					if hand.version != 1 {
						return Err(Error::Serialization(ser::Error::UnexpectedData {
							expected: vec![PROTOCOL_VERSION as u8],
							received: vec![hand.version as u8],
						}));
					}
					{
						// check the nonce to see if we could be trying to connect to ourselves
						let nonces = nonces.read().unwrap();
						debug!(
							LOGGER,
							"checking the nonce - {}, {:?}",
							&hand.nonce,
							nonces,
						);
						if nonces.contains(&hand.nonce) {
							debug!(LOGGER, "***** nonce matches! Avoiding connecting to ourselves");
							return Err(Error::Serialization(ser::Error::UnexpectedData {
								expected: vec![],
								received: vec![],
							}));
						}
					}

					// all good, keep peer info
					let peer_info = PeerInfo {
						capabilities: hand.capabilities,
						user_agent: hand.user_agent,
						addr: extract_ip(&hand.sender_addr.0, &conn),
						version: hand.version,
						total_difficulty: hand.total_difficulty,
					};
					// send our reply with our info
					let shake = Shake {
						version: PROTOCOL_VERSION,
						capabilities: capab,
						total_difficulty: total_difficulty,
						user_agent: USER_AGENT.to_string(),
					};
					Ok((conn, shake, peer_info))
				})
				.and_then(|(conn, shake, peer_info)| {
					debug!(LOGGER, "Success handshake with {}.", peer_info.addr);
					write_msg(conn, shake, Type::Shake)
				  // when more than one protocol version is supported, choosing should go here
					.map(|conn| (conn, ProtocolV1::new(), peer_info))
				}),
		)
	}

	/// Generate a new random nonce and store it in our ring buffer
	fn next_nonce(&self) -> u64 {
		let mut rng = OsRng::new().unwrap();
		let nonce = rng.next_u64();

		let mut nonces = self.nonces.write().unwrap();
		nonces.push_back(nonce);
		if nonces.len() >= NONCES_CAP {
			nonces.pop_front();
		}
		nonce
	}
}

// Attempts to make a best guess at the correct remote IP by checking if the
// advertised address is the loopback and our TCP connection. Note that the
// port reported by the connection is always incorrect for receiving
// connections as it's dynamically allocated by the server.
fn extract_ip(advertised: &SocketAddr, conn: &TcpStream) -> SocketAddr {
  match advertised {
    &SocketAddr::V4(v4sock) => {
      let ip = v4sock.ip();
	  debug!(LOGGER, "extract_ip - {:?}, {:?}", ip, conn.peer_addr());

      if ip.is_loopback() || ip.is_unspecified() {
        if let Ok(addr) =  conn.peer_addr() {
          return SocketAddr::new(addr.ip(), advertised.port());
        }
      }
    }
    &SocketAddr::V6(v6sock) => {
      let ip = v6sock.ip();
      if ip.is_loopback() || ip.is_unspecified() {
        if let Ok(addr) =  conn.peer_addr() {
          return SocketAddr::new(addr.ip(), advertised.port());
        }
      }
    }
  }
  advertised.clone()
}
<commit_msg>Return error when peer_addr() fails on connection<commit_after>// Copyright 2016 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::collections::VecDeque;
use std::net::SocketAddr;
use std::sync::{Arc, RwLock};

use futures::{self, Future};
use rand::Rng;
use rand::os::OsRng;
use tokio_core::net::TcpStream;

use core::core::target::Difficulty;
use core::ser;
use msg::*;
use types::*;
use protocol::ProtocolV1;
use util::LOGGER;

const NONCES_CAP: usize = 100;

/// Handles the handshake negotiation when two peers connect and decides on
/// protocol.
pub struct Handshake {
	/// Ring buffer of nonces sent to detect self connections without requiring
	/// a node id.
	nonces: Arc<RwLock<VecDeque<u64>>>,
}

unsafe impl Sync for Handshake {}
unsafe impl Send for Handshake {}

impl Handshake {
	/// Creates a new handshake handler
	pub fn new() -> Handshake {
		Handshake {
			nonces: Arc::new(RwLock::new(VecDeque::with_capacity(NONCES_CAP))),
		}
	}

	/// Handles connecting to a new remote peer, starting the version handshake.
	pub fn connect(
		&self,
		capab: Capabilities,
		total_difficulty: Difficulty,
		self_addr: SocketAddr,
		conn: TcpStream,
	) -> Box<Future<Item = (TcpStream, ProtocolV1, PeerInfo), Error = Error>> {

		// prepare the first part of the handshake
		let nonce = self.next_nonce();
		let peer_addr = match conn.peer_addr() {
			Ok(pa) => pa,
			Err(e) => return Box::new(futures::future::err(Error::Connection(e))),
		};
		debug!(
			LOGGER,
			"handshake connect with nonce - {}, sender - {:?}, receiver - {:?}",
			nonce,
			self_addr,
			peer_addr,
		);

		let hand = Hand {
			version: PROTOCOL_VERSION,
			capabilities: capab,
			nonce: nonce,
			total_difficulty: total_difficulty,
			sender_addr: SockAddr(self_addr),
			receiver_addr: SockAddr(peer_addr),
			user_agent: USER_AGENT.to_string(),
		};

		// write and read the handshake response
		Box::new(
			write_msg(conn, hand, Type::Hand)
				.and_then(|conn| read_msg::<Shake>(conn))
				.and_then(move |(conn, shake)| {
					if shake.version != 1 {
						Err(Error::Serialization(ser::Error::UnexpectedData {
							expected: vec![PROTOCOL_VERSION as u8],
							received: vec![shake.version as u8],
						}))
					} else {
						let peer_info = PeerInfo {
							capabilities: shake.capabilities,
							user_agent: shake.user_agent,
							addr: peer_addr,
							version: shake.version,
							total_difficulty: shake.total_difficulty,
						};

						info!(LOGGER, "Connected to peer {:?}", peer_info);
						// when more than one protocol version is supported, choosing should go here
						Ok((conn, ProtocolV1::new(), peer_info))
					}
				}),
		)
	}

	/// Handles receiving a connection from a new remote peer that started the
	/// version handshake.
	pub fn handshake(
		&self,
		capab: Capabilities,
		total_difficulty: Difficulty,
		conn: TcpStream,
	) -> Box<Future<Item = (TcpStream, ProtocolV1, PeerInfo), Error = Error>> {
		let nonces = self.nonces.clone();
		Box::new(
			read_msg::<Hand>(conn)
				.and_then(move |(conn, hand)| {
					if hand.version != 1 {
						return Err(Error::Serialization(ser::Error::UnexpectedData {
							expected: vec![PROTOCOL_VERSION as u8],
							received: vec![hand.version as u8],
						}));
					}
					{
						// check the nonce to see if we could be trying to connect to ourselves
						let nonces = nonces.read().unwrap();
						debug!(
							LOGGER,
							"checking the nonce - {}, {:?}",
							&hand.nonce,
							nonces,
						);
						if nonces.contains(&hand.nonce) {
							debug!(LOGGER, "***** nonce matches! Avoiding connecting to ourselves");
							return Err(Error::Serialization(ser::Error::UnexpectedData {
								expected: vec![],
								received: vec![],
							}));
						}
					}

					// all good, keep peer info
					let peer_info = PeerInfo {
						capabilities: hand.capabilities,
						user_agent: hand.user_agent,
						addr: extract_ip(&hand.sender_addr.0, &conn),
						version: hand.version,
						total_difficulty: hand.total_difficulty,
					};
					// send our reply with our info
					let shake = Shake {
						version: PROTOCOL_VERSION,
						capabilities: capab,
						total_difficulty: total_difficulty,
						user_agent: USER_AGENT.to_string(),
					};
					Ok((conn, shake, peer_info))
				})
				.and_then(|(conn, shake, peer_info)| {
					debug!(LOGGER, "Success handshake with {}.", peer_info.addr);
					write_msg(conn, shake, Type::Shake)
				  // when more than one protocol version is supported, choosing should go here
					.map(|conn| (conn, ProtocolV1::new(), peer_info))
				}),
		)
	}

	/// Generate a new random nonce and store it in our ring buffer
	fn next_nonce(&self) -> u64 {
		let mut rng = OsRng::new().unwrap();
		let nonce = rng.next_u64();

		let mut nonces = self.nonces.write().unwrap();
		nonces.push_back(nonce);
		if nonces.len() >= NONCES_CAP {
			nonces.pop_front();
		}
		nonce
	}
}

// Attempts to make a best guess at the correct remote IP by checking if the
// advertised address is the loopback and our TCP connection. Note that the
// port reported by the connection is always incorrect for receiving
// connections as it's dynamically allocated by the server.
fn extract_ip(advertised: &SocketAddr, conn: &TcpStream) -> SocketAddr {
  match advertised {
    &SocketAddr::V4(v4sock) => {
      let ip = v4sock.ip();
	  debug!(LOGGER, "extract_ip - {:?}, {:?}", ip, conn.peer_addr());

      if ip.is_loopback() || ip.is_unspecified() {
        if let Ok(addr) =  conn.peer_addr() {
          return SocketAddr::new(addr.ip(), advertised.port());
        }
      }
    }
    &SocketAddr::V6(v6sock) => {
      let ip = v6sock.ip();
      if ip.is_loopback() || ip.is_unspecified() {
        if let Ok(addr) =  conn.peer_addr() {
          return SocketAddr::new(addr.ip(), advertised.port());
        }
      }
    }
  }
  advertised.clone()
}
<|endoftext|>


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

// ----------------

// This program exercises the Rust GIF decoder at
// https://github.com/image-rs/image-gif
// which is the top result for https://crates.io/search?q=gif&sort=downloads
//
// Wuffs' C code doesn't depend on Rust per se, but this program gives some
// performance data for specific Rust GIF implementations. The equivalent Wuffs
// benchmarks (on the same test images) are run via:
//
// wuffs bench std/gif
//
// To run this program, do "cargo run --release" from the parent directory (the
// directory containing the Cargo.toml file).

// TODO: unify this program, bench-rust-gif-dot-rs, with bench-rust-gif, the
// other Rust GIF benchmark program. They are two separate programs because
// both libraries want to be named "gif", and the cargo package manager cannot
// handle duplicate names (https://github.com/rust-lang/cargo/issues/1311).

extern crate gif;
extern crate rustc_version_runtime;

use gif::SetParameter;
use std::time::Instant;

const ITERSCALE: u64 = 10;
const REPS: u64 = 5;

fn main() {
    let version = rustc_version_runtime::version();
    print!(
        "# Rust {}.{}.{}\n",
        version.major,
        version.minor,
        version.patch
    );
    print!("#\n");
    print!("# The output format, including the \"Benchmark\" prefixes, is compatible with the\n");
    print!("# https://godoc.org/golang.org/x/perf/cmd/benchstat tool. To install it, first\n");
    print!("# install Go, then run \"go get golang.org/x/perf/cmd/benchstat\".\n");

    let mut dst = vec![0u8; 64 * 1024 * 1024];

    // The various magic constants below are copied from test/c/std/gif.c
    for i in 0..(1 + REPS) {
        bench(
            "1k_bw",
            &mut dst[..],
            include_bytes!("../../../test/data/pjw-thumbnail.gif"),
            i == 0, // warm_up
            2000, // iters_unscaled
        );

        bench(
            "1k_color",
            &mut dst[..],
            include_bytes!("../../../test/data/hippopotamus.regular.gif"),
            i == 0, // warm_up
            1000, // iters_unscaled
        );

        bench(
            "10k_bgra",
            &mut dst[..],
            include_bytes!("../../../test/data/hat.gif"),
            i == 0, // warm_up
            100, // iters_unscaled
        );

        bench(
            "10k_indexed",
            &mut dst[..],
            include_bytes!("../../../test/data/hat.gif"),
            i == 0, // warm_up
            100, // iters_unscaled
        );

        bench(
            "20k",
            &mut dst[..],
            include_bytes!("../../../test/data/bricks-gray.gif"),
            i == 0, // warm_up
            50, // iters_unscaled
        );

        bench(
            "100k_artificial",
            &mut dst[..],
            include_bytes!("../../../test/data/hibiscus.primitive.gif"),
            i == 0, // warm_up
            15, // iters_unscaled
        );

        bench(
            "100k_realistic",
            &mut dst[..],
            include_bytes!("../../../test/data/hibiscus.regular.gif"),
            i == 0, // warm_up
            10, // iters_unscaled
        );

        bench(
            "1000k",
            &mut dst[..],
            include_bytes!("../../../test/data/harvesters.gif"),
            i == 0, // warm_up
            1, // iters_unscaled
        );

        bench(
            "anim_screencap",
            &mut dst[..],
            include_bytes!("../../../test/data/gifplayer-muybridge.gif"),
            i == 0, // warm_up
            1, // iters_unscaled
        );
    }
}

fn bench(
    name: &str, // Benchmark name.
    dst: &mut [u8], // Destination buffer.
    src: &[u8], // Source data.
    warm_up: bool, // Whether this is a warm up rep.
    iters_unscaled: u64, // Base number of iterations.
) {
    let iters = iters_unscaled * ITERSCALE;
    let output_32_bit_color = name.ends_with("_bgra");
    let mut num_bytes = 0u64;

    let start = Instant::now();
    for _ in 0..iters {
        num_bytes += decode(&mut dst[..], src, output_32_bit_color);
    }
    let elapsed = start.elapsed();

    let elapsed_nanos = (elapsed.as_secs() * 1_000_000_000) + (elapsed.subsec_nanos() as u64);
    let kb_per_s: u64 = num_bytes * 1_000_000 / elapsed_nanos;

    if warm_up {
        return;
    }

    print!(
        "Benchmarkrust_gif_decode_{:16}   {:8}   {:12} ns/op   {:3}.{:03} MB/s\n",
        name,
        iters,
        elapsed_nanos / iters,
        kb_per_s / 1_000,
        kb_per_s % 1_000
    );
}

// decode returns the number of bytes processed.
fn decode(dst: &mut [u8], src: &[u8], output_32_bit_color: bool) -> u64 {
    let mut decoder = gif::Decoder::new(src);
    if output_32_bit_color {
        decoder.set(gif::ColorOutput::RGBA);
    }

    let mut num_bytes = 0u64;
    let mut reader = decoder.read_info().unwrap();
    while let Some(_) = reader.next_frame_info().unwrap() {
        num_bytes += reader.buffer_size() as u64;
        reader.read_into_buffer(dst).unwrap();
    }
    num_bytes
}
<commit_msg>Add num_want_bytes to script/bench-rust-gif<commit_after>// Copyright 2018 The Wuffs Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// ----------------

// This program exercises the Rust GIF decoder at
// https://github.com/image-rs/image-gif
// which is the top result for https://crates.io/search?q=gif&sort=downloads
//
// Wuffs' C code doesn't depend on Rust per se, but this program gives some
// performance data for specific Rust GIF implementations. The equivalent Wuffs
// benchmarks (on the same test images) are run via:
//
// wuffs bench std/gif
//
// To run this program, do "cargo run --release" from the parent directory (the
// directory containing the Cargo.toml file).

// TODO: unify this program, bench-rust-gif-dot-rs, with bench-rust-gif, the
// other Rust GIF benchmark program. They are two separate programs because
// both libraries want to be named "gif", and the cargo package manager cannot
// handle duplicate names (https://github.com/rust-lang/cargo/issues/1311).

extern crate gif;
extern crate rustc_version_runtime;

use gif::SetParameter;
use std::time::Instant;

const ITERSCALE: u64 = 10;
const REPS: u64 = 5;

fn main() {
    let version = rustc_version_runtime::version();
    print!(
        "# Rust {}.{}.{}\n",
        version.major,
        version.minor,
        version.patch
    );
    print!("#\n");
    print!("# The output format, including the \"Benchmark\" prefixes, is compatible with the\n");
    print!("# https://godoc.org/golang.org/x/perf/cmd/benchstat tool. To install it, first\n");
    print!("# install Go, then run \"go get golang.org/x/perf/cmd/benchstat\".\n");

    let mut dst = vec![0u8; 64 * 1024 * 1024];

    // The various magic constants below are copied from test/c/std/gif.c
    for i in 0..(1 + REPS) {
        bench(
            "1k_bw",
            &mut dst[..],
            include_bytes!("../../../test/data/pjw-thumbnail.gif"),
            i == 0, // warm_up
            32 * 32 * 1, // want_num_bytes
            2000, // iters_unscaled
        );

        bench(
            "1k_color",
            &mut dst[..],
            include_bytes!("../../../test/data/hippopotamus.regular.gif"),
            i == 0, // warm_up
            36 * 28 * 1, // want_num_bytes
            1000, // iters_unscaled
        );

        bench(
            "10k_bgra",
            &mut dst[..],
            include_bytes!("../../../test/data/hat.gif"),
            i == 0, // warm_up
            90 * 112 * 4, // want_num_bytes
            100, // iters_unscaled
        );

        bench(
            "10k_indexed",
            &mut dst[..],
            include_bytes!("../../../test/data/hat.gif"),
            i == 0, // warm_up
            90 * 112 * 1, // want_num_bytes
            100, // iters_unscaled
        );

        bench(
            "20k",
            &mut dst[..],
            include_bytes!("../../../test/data/bricks-gray.gif"),
            i == 0, // warm_up
            160 * 120 * 1, // want_num_bytes
            50, // iters_unscaled
        );

        bench(
            "100k_artificial",
            &mut dst[..],
            include_bytes!("../../../test/data/hibiscus.primitive.gif"),
            i == 0, // warm_up
            312 * 442 * 1, // want_num_bytes
            15, // iters_unscaled
        );

        bench(
            "100k_realistic",
            &mut dst[..],
            include_bytes!("../../../test/data/hibiscus.regular.gif"),
            i == 0, // warm_up
            312 * 442 * 1, // want_num_bytes
            10, // iters_unscaled
        );

        bench(
            "1000k",
            &mut dst[..],
            include_bytes!("../../../test/data/harvesters.gif"),
            i == 0, // warm_up
            1165 * 859, // want_num_bytes
            1, // iters_unscaled
        );

        bench(
            "anim_screencap",
            &mut dst[..],
            include_bytes!("../../../test/data/gifplayer-muybridge.gif"),
            i == 0, // warm_up
            4652198, // want_num_bytes
            1, // iters_unscaled
        );
    }
}

fn bench(
    name: &str, // Benchmark name.
    dst: &mut [u8], // Destination buffer.
    src: &[u8], // Source data.
    warm_up: bool, // Whether this is a warm up rep.
    want_num_bytes: u64, // Expected num_bytes per iteration.
    iters_unscaled: u64, // Base number of iterations.
) {
    let iters = iters_unscaled * ITERSCALE;
    let output_32_bit_color = name.ends_with("_bgra");
    let mut total_num_bytes = 0u64;

    let start = Instant::now();
    for _ in 0..iters {
        let n = decode(&mut dst[..], src, output_32_bit_color);
        if n != want_num_bytes {
            panic!("num_bytes: got {}, want {}", n, want_num_bytes);
        }
        total_num_bytes += n;
    }
    let elapsed = start.elapsed();

    let elapsed_nanos = (elapsed.as_secs() * 1_000_000_000) + (elapsed.subsec_nanos() as u64);
    let kb_per_s: u64 = total_num_bytes * 1_000_000 / elapsed_nanos;

    if warm_up {
        return;
    }

    print!(
        "Benchmarkrust_gif_decode_{:16}   {:8}   {:12} ns/op   {:3}.{:03} MB/s\n",
        name,
        iters,
        elapsed_nanos / iters,
        kb_per_s / 1_000,
        kb_per_s % 1_000
    );
}

// decode returns the number of bytes processed.
fn decode(dst: &mut [u8], src: &[u8], output_32_bit_color: bool) -> u64 {
    let mut num_bytes = 0u64;
    let mut decoder = gif::Decoder::new(src);
    if output_32_bit_color {
        decoder.set(gif::ColorOutput::RGBA);
    }

    let mut reader = decoder.read_info().unwrap();
    while let Some(_) = reader.next_frame_info().unwrap() {
        num_bytes += reader.buffer_size() as u64;
        reader.read_into_buffer(dst).unwrap();
    }
    num_bytes
}
<|endoftext|>


<commit_before>extern crate walkdir;

use self::walkdir::{DirEntry as WalkDirEntry, WalkDir, WalkDirIterator};

use constant::{WORKING_DIR_NAME, KEEPED_FILE_NAME};
use std::collections::BTreeSet;
use std::ffi::OsString;
use std::fs;
use std::io::Error as IoError;
use std::path::{MAIN_SEPARATOR, Path};
use std::result::Result;

macro_rules! path_buf {
    ($($x: expr),*) => {
        PathBuf::new()
            $(.join($x))*
    };
}

pub fn append_current_dir_prefix_if_need(path: &String) -> String {
    let prefix       = format!(".{}", MAIN_SEPARATOR);
    let prefix: &str = prefix.as_ref();
    format!("{}{}", if path.starts_with(prefix) { "" } else { prefix }, path)
}

pub fn ls<P: AsRef<Path>>(path: &P) -> Result<BTreeSet<String>, IoError> {
    let dirs = try!(fs::read_dir(path));
    let dirs = dirs
        .filter_map(Result::ok)
        .map(|d| d.file_name())
        .map(OsString::into_string)
        .filter_map(Result::ok)
        .collect::<BTreeSet<String>>();
    Ok(dirs)
}

pub fn is_empty_dir<P: AsRef<Path>>(path: P) -> bool {
    match fs::read_dir(path) {
        Ok(rd) => rd.count() == 0,
        Err(_) => false,
    }
}

fn is_hidden(entry: &WalkDirEntry) -> bool {
    entry
        .file_name()
        .to_str()
        .map_or(false, |s| s.starts_with(".") && s.len() > 1 && s != "..")
}

fn is_pinned(entry: &WalkDirEntry) -> bool {
    entry
        .file_name()
        .to_str()
        .map_or(false, |s| s == WORKING_DIR_NAME || s == KEEPED_FILE_NAME)
}

fn is_target(entry: &WalkDirEntry) -> bool {
    !is_hidden(entry) && !is_pinned(entry)
}

fn to_string(entry: WalkDirEntry) -> Result<String, OsString> {
    entry
        .path()
        .as_os_str()
        .to_os_string()
        .into_string()
}

pub fn walk_dir<P: AsRef<Path>>(root: P) -> BTreeSet<String> {
    let walker = WalkDir::new(root)
        .into_iter()
        .filter_entry(is_target)
        .filter_map(Result::ok)
        .filter(|e| !e.file_type().is_dir())
        .collect::<Vec<WalkDirEntry>>();

    walker
        .into_iter()
        .map(to_string)
        .filter_map(Result::ok)
        .collect::<BTreeSet<String>>()
}

pub fn dirs_ordered_by_descending_depth<P: AsRef<Path>>(root: P) -> Vec<String> {
    let mut walker = WalkDir::new(root)
        .into_iter()
        .filter_entry(is_target)
        .filter_entry(|e| e.file_type().is_dir())
        .filter_map(Result::ok)
        .collect::<Vec<WalkDirEntry>>();

    walker.sort_by(|l, r| {
        let l_depth = &l.depth();
        let r_depth = &r.depth();
        r_depth.cmp(l_depth)
    });

    walker
        .into_iter()
        .map(to_string)
        .filter_map(Result::ok)
        .collect::<Vec<String>>()
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::path::{MAIN_SEPARATOR, PathBuf};

    fn to_string_forcedly(path: PathBuf) -> String {
        path
            .to_str()
            .unwrap()
            .to_string()
    }

    #[test]
    fn create_path_buf() {
        use std::path::PathBuf;
        let collect = PathBuf::new()
            .join("path")
            .join("to")
            .join("file");
        assert_eq!(collect, path_buf!["path", "to", "file"]);
    }

    #[test]
    fn append_current_dir_prefix() {
        let path = to_string_forcedly(path_buf!["path", "to", "file"]);
        assert_eq!(format!(".{}{}", MAIN_SEPARATOR, path), append_current_dir_prefix_if_need(&path));
    }
    #[test]
    fn not_append_current_dir_prefix() {
        let path = to_string_forcedly(path_buf![".", "path", "to", "file"]);
        assert_eq!(path, append_current_dir_prefix_if_need(&path))
    }
}
<commit_msg>[Test] Enforce tests for lib::fs<commit_after>extern crate walkdir;

use self::walkdir::{DirEntry as WalkDirEntry, WalkDir, WalkDirIterator};

use constant::{WORKING_DIR_NAME, KEEPED_FILE_NAME};
use std::collections::BTreeSet;
use std::ffi::OsString;
use std::fs;
use std::io::Error as IoError;
use std::path::{MAIN_SEPARATOR, Path};
use std::result::Result;

macro_rules! path_buf {
    ($($x: expr),*) => {
        PathBuf::new()
            $(.join($x))*
    };
}

pub fn append_current_dir_prefix_if_need(path: &String) -> String {
    let prefix       = format!(".{}", MAIN_SEPARATOR);
    let prefix: &str = prefix.as_ref();
    format!("{}{}", if path.starts_with(prefix) { "" } else { prefix }, path)
}

pub fn ls<P: AsRef<Path>>(path: &P) -> Result<BTreeSet<String>, IoError> {
    let dirs = try!(fs::read_dir(path));
    let dirs = dirs
        .filter_map(Result::ok)
        .map(|d| d.file_name())
        .map(OsString::into_string)
        .filter_map(Result::ok)
        .collect::<BTreeSet<String>>();
    Ok(dirs)
}

pub fn is_empty_dir<P: AsRef<Path>>(path: P) -> bool {
    match fs::read_dir(path) {
        Ok(rd) => rd.count() == 0,
        Err(_) => false,
    }
}

fn is_hidden_name(file_name: &str) -> bool {
    file_name.starts_with(".") && file_name.len() > 1 && file_name != ".."
}
#[test]
fn hidden_name() {
    let file_names = [
        ".a",
        ".ab",
        ".abc",
        "..a",
        "...",
    ];
    for file_name in &file_names {
        assert!(is_hidden_name(file_name));
    }
}
#[test]
fn non_hidden_name() {
    let file_names = [
        "",

        ".",
        "..",
        "a",
        "ab",
        "abc",
    ];
    for file_name in &file_names {
        assert!(!is_hidden_name(file_name));
    }
}

fn is_hidden(entry: &WalkDirEntry) -> bool {
    entry
        .file_name()
        .to_str()
        .map_or(false, is_hidden_name)
}

fn is_pinned(entry: &WalkDirEntry) -> bool {
    entry
        .file_name()
        .to_str()
        .map_or(false, |s| s == WORKING_DIR_NAME || s == KEEPED_FILE_NAME)
}

fn is_target(entry: &WalkDirEntry) -> bool {
    !is_hidden(entry) && !is_pinned(entry)
}

fn to_string(entry: WalkDirEntry) -> Result<String, OsString> {
    entry
        .path()
        .as_os_str()
        .to_os_string()
        .into_string()
}

pub fn walk_dir<P: AsRef<Path>>(root: P) -> BTreeSet<String> {
    let walker = WalkDir::new(root)
        .into_iter()
        .filter_entry(is_target)
        .filter_map(Result::ok)
        .filter(|e| !e.file_type().is_dir())
        .collect::<Vec<WalkDirEntry>>();

    walker
        .into_iter()
        .map(to_string)
        .filter_map(Result::ok)
        .collect::<BTreeSet<String>>()
}

pub fn dirs_ordered_by_descending_depth<P: AsRef<Path>>(root: P) -> Vec<String> {
    let mut walker = WalkDir::new(root)
        .into_iter()
        .filter_entry(is_target)
        .filter_entry(|e| e.file_type().is_dir())
        .filter_map(Result::ok)
        .collect::<Vec<WalkDirEntry>>();

    walker.sort_by(|l, r| {
        let l_depth = &l.depth();
        let r_depth = &r.depth();
        r_depth.cmp(l_depth)
    });

    walker
        .into_iter()
        .map(to_string)
        .filter_map(Result::ok)
        .collect::<Vec<String>>()
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::path::{MAIN_SEPARATOR, Path, PathBuf};

    fn to_string_unsafely(path: &PathBuf) -> String {
        path
            .to_str()
            .unwrap()
            .to_string()
    }

    #[test]
    fn create_path_buf() {
        use std::path::PathBuf;
        let paths = [
            (PathBuf::new()                           , path_buf![                    ]),
            (Path::new("path").to_path_buf()          , path_buf!["path"              ]),
            (Path::new("path").join("to")             , path_buf!["path", "to"        ]),
            (Path::new("path").join("to").join("file"), path_buf!["path", "to", "file"]),
        ];
        for &(ref correct, ref calculated) in &paths {
            assert_eq!(correct, calculated);
        }
    }

    #[test]
    fn append_current_dir_prefix() {
        let paths = [
            path_buf!["."                 ],
            path_buf![".."                ],
            path_buf!["..", "path"        ],
            path_buf!["path"              ],
            path_buf!["path", "to"        ],
            path_buf!["path", "to", "file"],
        ];
        for path in &paths {
            let path    = to_string_unsafely(path);
            let correct = format!(".{}{}", MAIN_SEPARATOR, path);
            assert_eq!(correct, append_current_dir_prefix_if_need(&path));
        }
    }
    #[test]
    fn not_append_current_dir_prefix() {
        let paths = [
            path_buf![".", "."                 ],
            path_buf![".", ".."                ],
            path_buf![".", "..", "path"        ],
            path_buf![".", "path"              ],
            path_buf![".", "path", "to"        ],
            path_buf![".", "path", "to", "file"],
        ];
        for path in &paths {
            let path    = to_string_unsafely(path);
            let correct = path.clone();
            assert_eq!(correct, append_current_dir_prefix_if_need(&path));
        }
    }
}
<|endoftext|>


<commit_before>use std::cmp::Ordering;

use cmp;
use denormalize;
use normalize;

pub fn add(num_l: &str, num_r: &str) -> String {
    let sum = merge(denormalize(num_l), denormalize(num_r));
    normalize(&sum)
}

fn merge(num_l: String, num_r: String) -> String {
    let mut digits_l = num_l.chars();
    let mut digits_r = num_r.chars();

    let mut sum = String::new();

    let mut next_l = digits_l.next();
    let mut next_r = digits_r.next();
    loop {
        match (next_l, next_r) {
            (Some(l), Some(r)) => {
                if cmp(l, r) == Ordering::Greater {
                    sum.push(l);
                    next_l = digits_l.next();
                } else {
                    sum.push(r);
                    next_r = digits_r.next();
                }
            },
            (Some(l), None) => {
                sum.push(l);
                next_l = digits_l.next();
            },
            (None, Some(r)) => {
                sum.push(r);
                next_r = digits_r.next();
            },
            (None, None) => { break }
        }
    }

    sum
}

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

    #[test]
    fn add_i_i() {
        assert_eq!("II", add("I", "I"));
    }

    #[test]
    fn add_i_ii() {
        assert_eq!("III", add("I", "II"));
    }

    #[test]
    fn add_ii_iii_requires_normalization_to_v() {
        assert_eq!("V", add("II", "III"));

    }

    #[test]
    fn add_v_i() {
        assert_eq!("VI", add("V", "I"));
    }

    #[test]
    fn add_i_v_understands_the_relative_order_of_v_and_i() {
        assert_eq!("VI", add("I", "V"));
    }

    #[test]
    fn add_i_iv_denormalizes_before_adding() {
        assert_eq!("V", add("I", "IV"));
    }

    #[test]
    fn add_l_i_supports_l() {
        assert_eq!("LI", add("L", "I"));
    }

    #[test]
    fn add_l_xi_understands_l_x_sort_order() {
        assert_eq!("LXI", add("L", "XI"));
    }
}
<commit_msg>First acceptance test for too-big result<commit_after>use std::cmp::Ordering;

use cmp;
use denormalize;
use normalize;

pub fn add(num_l: &str, num_r: &str) -> String {
    let sum = merge(denormalize(num_l), denormalize(num_r));
    normalize(&sum)
}

fn merge(num_l: String, num_r: String) -> String {
    let mut digits_l = num_l.chars();
    let mut digits_r = num_r.chars();

    let mut sum = String::new();

    let mut next_l = digits_l.next();
    let mut next_r = digits_r.next();
    loop {
        match (next_l, next_r) {
            (Some(l), Some(r)) => {
                if cmp(l, r) == Ordering::Greater {
                    sum.push(l);
                    next_l = digits_l.next();
                } else {
                    sum.push(r);
                    next_r = digits_r.next();
                }
            },
            (Some(l), None) => {
                sum.push(l);
                next_l = digits_l.next();
            },
            (None, Some(r)) => {
                sum.push(r);
                next_r = digits_r.next();
            },
            (None, None) => { break }
        }
    }

    sum
}

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

    #[test]
    fn add_i_i() {
        assert_eq!("II", add("I", "I"));
    }

    #[test]
    fn add_i_ii() {
        assert_eq!("III", add("I", "II"));
    }

    #[test]
    fn add_ii_iii_requires_normalization_to_v() {
        assert_eq!("V", add("II", "III"));

    }

    #[test]
    fn add_v_i() {
        assert_eq!("VI", add("V", "I"));
    }

    #[test]
    fn add_i_v_understands_the_relative_order_of_v_and_i() {
        assert_eq!("VI", add("I", "V"));
    }

    #[test]
    fn add_i_iv_denormalizes_before_adding() {
        assert_eq!("V", add("I", "IV"));
    }

    #[test]
    fn add_l_i_supports_l() {
        assert_eq!("LI", add("L", "I"));
    }

    #[test]
    fn add_l_xi_understands_l_x_sort_order() {
        assert_eq!("LXI", add("L", "XI"));
    }

    #[test]
    fn add_fails_when_result_is_too_big_to_be_represented() {
        assert!(add("MCMXCIX", "MMCMXCIX").is_err());
    }
}
<|endoftext|>


<commit_before>macro_rules! fail {
    ($err:expr) => (
        return Err(From::from($err));
    )
}

macro_rules! ensure {
    ($expr:expr, $err:expr) => (
        if !($expr) {
            fail!($err);
        }
    )
}

macro_rules! assert_err {
    ($expr:expr, $err:expr) => {
        match &($expr) {
            &Ok(_) => {
                panic!("assertion failed: not an error in `{}`", stringify!($expr));
            }
            &Err(ref value) => {
                use regex::Regex;
                use std::error::Error as BaseError;
                let re = Regex::new($err).unwrap();
                let desc = value.description().to_string();
                if !re.is_match(desc.as_ref()) {
                    panic!("assertion failed: error message \"{}\" doesn't match \"{}\" in `{}`",
                           desc, re, stringify!($expr));
                }
            }
        }
    }
}

macro_rules! h5lock_s {
    ($expr:expr) => ({
        use ::sync::sync;
        sync(|| { $expr })
    })
}

macro_rules! h5lock {
    ($expr:expr) => (h5lock_s!(unsafe { $expr }))
}

macro_rules! h5call_s {
    ($expr:expr) => ({
        use error::h5check;
        h5lock_s!(h5check($expr))
    })
}

macro_rules! h5call {
    ($expr:expr) => (h5call_s!(unsafe { $expr }))
}

macro_rules! h5try_s {
    ($expr:expr) => (match h5call_s!($expr) {
        Ok(value) => value,
        Err(err)  => {
            return Err(From::from(err))
        },
    })
}

macro_rules! h5try {
    ($expr:expr) => (h5try_s!(unsafe { $expr }))
}

macro_rules! register_hid {
    ($rust_name:ident, $c_name:ident) => {
        #[link(name = "hdf5")]
        extern {
            static $c_name: hid_t;
        }
        lazy_static! {
            pub static ref $rust_name: hid_t = {
                use ffi::h5;
                h5lock!(h5::H5open());
                $c_name
            };
        }
    }
}
<commit_msg>Allow fail!() to format arguments<commit_after>macro_rules! fail {
    ($err:expr) => (
        return Err(From::from($err));
    );
    ($fmt:expr, $($arg:tt)*) => (
        return Err(From::from(format!($fmt, $($arg)*)));
    );
}

macro_rules! ensure {
    ($expr:expr, $err:expr) => (
        if !($expr) {
            fail!($err);
        }
    )
}

macro_rules! assert_err {
    ($expr:expr, $err:expr) => {
        match &($expr) {
            &Ok(_) => {
                panic!("assertion failed: not an error in `{}`", stringify!($expr));
            }
            &Err(ref value) => {
                use regex::Regex;
                use std::error::Error as BaseError;
                let re = Regex::new($err).unwrap();
                let desc = value.description().to_string();
                if !re.is_match(desc.as_ref()) {
                    panic!("assertion failed: error message \"{}\" doesn't match \"{}\" in `{}`",
                           desc, re, stringify!($expr));
                }
            }
        }
    }
}

macro_rules! h5lock_s {
    ($expr:expr) => ({
        use ::sync::sync;
        sync(|| { $expr })
    })
}

macro_rules! h5lock {
    ($expr:expr) => (h5lock_s!(unsafe { $expr }))
}

macro_rules! h5call_s {
    ($expr:expr) => ({
        use error::h5check;
        h5lock_s!(h5check($expr))
    })
}

macro_rules! h5call {
    ($expr:expr) => (h5call_s!(unsafe { $expr }))
}

macro_rules! h5try_s {
    ($expr:expr) => (match h5call_s!($expr) {
        Ok(value) => value,
        Err(err)  => {
            return Err(From::from(err))
        },
    })
}

macro_rules! h5try {
    ($expr:expr) => (h5try_s!(unsafe { $expr }))
}

macro_rules! register_hid {
    ($rust_name:ident, $c_name:ident) => {
        #[link(name = "hdf5")]
        extern {
            static $c_name: hid_t;
        }
        lazy_static! {
            pub static ref $rust_name: hid_t = {
                use ffi::h5;
                h5lock!(h5::H5open());
                $c_name
            };
        }
    }
}
<|endoftext|>


<commit_before>fn main() {
    println!("Loop forever!");
}
<commit_msg>loop forever<commit_after>fn main() {
    loop {
        println!("Loop forever!");
    }
}
<|endoftext|>