<commit_before>//! A singly-linked list.
//!
//! Using this data structure only makes sense under very specific
//! circumstances:
//!
//! - If you have a list that rarely stores more than one element, then this
//!   data-structure can store the element without allocating and only uses as
//!   much space as a `Option<(T, usize)>`. If T can double as the `Option`
//!   discriminant, it will even only be as large as `T, usize`.
//!
//! If you expect to store more than 1 element in the common case, steer clear
//! and use a `Vec<T>`, `Box<[T]>`, or a `SmallVec<T>`.

#[cfg(test)]
mod tests;

#[derive(Clone, Hash, Debug, PartialEq)]
pub struct TinyList<T: PartialEq> {
    head: Option<Element<T>>
}

impl<T: PartialEq> TinyList<T> {

    #[inline]
    pub fn new() -> TinyList<T> {
        TinyList {
            head: None
        }
    }

    #[inline]
    pub fn new_single(data: T) -> TinyList<T> {
        TinyList {
            head: Some(Element {
                data,
                next: None,
            })
        }
    }

    #[inline]
    pub fn insert(&mut self, data: T) {
        self.head = Some(Element {
            data,
            next: self.head.take().map(Box::new)
        });
    }

    #[inline]
    pub fn remove(&mut self, data: &T) -> bool {
        self.head = match self.head {
            Some(ref mut head) if head.data == *data => {
                head.next.take().map(|x| *x)
            }
            Some(ref mut head) => return head.remove_next(data),
            None => return false,
        };
        true
    }

    #[inline]
    pub fn contains(&self, data: &T) -> bool {
        if let Some(ref head) = self.head {
            head.contains(data)
        } else {
            false
        }
    }

    #[inline]
    pub fn len(&self) -> usize {
        if let Some(ref head) = self.head {
            head.len()
        } else {
            0
        }
    }
}

#[derive(Clone, Hash, Debug, PartialEq)]
struct Element<T: PartialEq> {
    data: T,
    next: Option<Box<Element<T>>>,
}

impl<T: PartialEq> Element<T> {

    fn remove_next(&mut self, data: &T) -> bool {
        let new_next = if let Some(ref mut next) = self.next {
            if next.data != *data {
                return next.remove_next(data)
            } else {
                next.next.take()
            }
        } else {
            return false
        };

        self.next = new_next;

        true
    }

    fn len(&self) -> usize {
        if let Some(ref next) = self.next {
            1 + next.len()
        } else {
            1
        }
    }

    fn contains(&self, data: &T) -> bool {
        if self.data == *data {
            return true
        }

        if let Some(ref next) = self.next {
            next.contains(data)
        } else {
            false
        }
    }
}
<commit_msg>refactor `len` and `contains` to iterate instead of recurse<commit_after>//! A singly-linked list.
//!
//! Using this data structure only makes sense under very specific
//! circumstances:
//!
//! - If you have a list that rarely stores more than one element, then this
//!   data-structure can store the element without allocating and only uses as
//!   much space as a `Option<(T, usize)>`. If T can double as the `Option`
//!   discriminant, it will even only be as large as `T, usize`.
//!
//! If you expect to store more than 1 element in the common case, steer clear
//! and use a `Vec<T>`, `Box<[T]>`, or a `SmallVec<T>`.

#[cfg(test)]
mod tests;

#[derive(Clone, Hash, Debug, PartialEq)]
pub struct TinyList<T: PartialEq> {
    head: Option<Element<T>>
}

impl<T: PartialEq> TinyList<T> {
    #[inline]
    pub fn new() -> TinyList<T> {
        TinyList {
            head: None
        }
    }

    #[inline]
    pub fn new_single(data: T) -> TinyList<T> {
        TinyList {
            head: Some(Element {
                data,
                next: None,
            })
        }
    }

    #[inline]
    pub fn insert(&mut self, data: T) {
        self.head = Some(Element {
            data,
            next: self.head.take().map(Box::new)
        });
    }

    #[inline]
    pub fn remove(&mut self, data: &T) -> bool {
        self.head = match self.head {
            Some(ref mut head) if head.data == *data => {
                head.next.take().map(|x| *x)
            }
            Some(ref mut head) => return head.remove_next(data),
            None => return false,
        };
        true
    }

    #[inline]
    pub fn contains(&self, data: &T) -> bool {
        let mut elem = self.head.as_ref();
        while let Some(ref e) = elem {
            if &e.data == data {
                return true;
            }
            elem = e.next.as_ref().map(|e| &**e);
        }
        false
    }

    #[inline]
    pub fn len(&self) -> usize {
        let (mut elem, mut count) = (self.head.as_ref(), 0);
        while let Some(ref e) = elem {
            count += 1;
            elem = e.next.as_ref().map(|e| &**e);
        }
        count
    }
}

#[derive(Clone, Hash, Debug, PartialEq)]
struct Element<T: PartialEq> {
    data: T,
    next: Option<Box<Element<T>>>,
}

impl<T: PartialEq> Element<T> {
    fn remove_next(&mut self, data: &T) -> bool {
        let new_next = match self.next {
            Some(ref mut next) if next.data == *data => next.next.take(),
            Some(ref mut next) => return next.remove_next(data),
            None => return false,
        };
        self.next = new_next;
        true
    }
}
<|endoftext|>


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

#![allow(visible_private_types)]

use gtk::ffi;
use std::c_str::CString;
use std::c_vec::CVec;
use std::string::raw::from_buf;

pub struct TreePath {
    pointer:   *mut ffi::C_GtkTreePath,
    container: CVec<i32>
}

impl TreePath {
    pub fn new() -> Option<TreePath> {
        let tmp = unsafe { ffi::gtk_tree_path_new() };

        if tmp.is_null() {
            None
        } else {
            unsafe {
                Some(TreePath {
                    pointer: tmp,
                    container: CVec::new(::std::ptr::mut_null(), 0)
                })
            }
        }
    }

    pub fn new_from_string(path: &str) -> Option<TreePath> {
        let tmp = unsafe {
            path.with_c_str(|c_str| {
                ffi::gtk_tree_path_new_from_string(c_str)
            })
        };

        if tmp.is_null() {
            None
        } else {
            unsafe {
                Some(TreePath {
                    pointer: tmp,
                    container: CVec::new(::std::ptr::mut_null(), 0)
                })
            }
        }
    }

    pub fn new_from_indicesv(indices: &mut [i32]) -> Option<TreePath> {
        let tmp = unsafe { ffi::gtk_tree_path_new_from_indicesv(indices.as_mut_ptr(), indices.len() as u64) };

        if tmp.is_null() {
            None
        } else {
            unsafe {
                Some(TreePath {
                    pointer: tmp,
                    container: CVec::new(::std::ptr::mut_null(), 0)
                })
            }
        }
    }

    pub fn new_first() -> Option<TreePath> {
        let tmp = unsafe { ffi::gtk_tree_path_new_first() };

        if tmp.is_null() {
            None
        } else {
            unsafe {
                Some(TreePath {
                    pointer: tmp,
                    container: CVec::new(::std::ptr::mut_null(), 0)
                })
            }
        }
    }

    #[allow(unused_variable)]
    pub fn to_string(&self) -> String {
        let string = unsafe { ffi::gtk_tree_path_to_string(self.pointer) };

        if string.is_null() {
            String::new()
        } else {
            unsafe {
                // used to free the returned string
                let container = CString::new(string as *const i8, true);

                from_buf(string as *const u8)
            }
        }
    }

    pub fn append_index(&self, index_: i32) {
        unsafe { ffi::gtk_tree_path_append_index(self.pointer, index_) }
    }

    pub fn prepend_index(&self, index_: i32) {
        unsafe { ffi::gtk_tree_path_prepend_index(self.pointer, index_) }
    }

    pub fn get_depth(&self) -> i32 {
        unsafe { ffi::gtk_tree_path_get_depth(self.pointer) }
    }

    pub fn get_indices<'r>(&'r mut self) -> &'r [i32] {
        let tmp = unsafe { ffi::gtk_tree_path_get_indices(self.pointer) };
        let depth = self.get_depth();

        unsafe {
            self.container = CVec::new(tmp, depth as uint);
            self.container.as_slice()
        }
    }

    pub fn copy(&self) -> Option<TreePath> {
        let tmp = unsafe { ffi::gtk_tree_path_copy(self.pointer) };

        if tmp.is_null() {
            None
        } else {
            unsafe {
                Some(TreePath {
                    pointer: tmp,
                    container: CVec::new(::std::ptr::mut_null(), 0)
                })
            }
        }
    }

    pub fn compare(&self, other: &TreePath) -> i32 {
        unsafe { ffi::gtk_tree_path_compare(self.pointer as *const ffi::C_GtkTreePath, other.pointer as *const ffi::C_GtkTreePath) }
    }

    pub fn next(&self) {
        unsafe { ffi::gtk_tree_path_next(self.pointer) }
    }

    pub fn prev(&self) {
        unsafe { ffi::gtk_tree_path_prev(self.pointer) }
    }

    pub fn path_up(&self) -> bool {
        match unsafe { ffi::gtk_tree_path_up(self.pointer) } {
            0 => false,
            _ => true
        }
    }

    pub fn path_down(&self) {
        unsafe { ffi::gtk_tree_path_down(self.pointer) }
    }

    pub fn is_ancestor(&self, descendant: &TreePath) -> bool {
        match unsafe { ffi::gtk_tree_path_is_ancestor(self.pointer, descendant.pointer) } {
            0 => false,
            _ => true
        }
    }

    pub fn is_descendant(&self, ancestor: &TreePath) -> bool {
        match unsafe { ffi::gtk_tree_path_is_descendant(self.pointer, ancestor.pointer) } {
            0 => false,
            _ => true
        }
    }

    pub fn drop(&mut self) {
        unsafe { ffi::gtk_tree_path_free(self.pointer) }
        self.pointer = ::std::ptr::mut_null();
    }

    #[doc(hidden)]
    pub fn get_pointer(&self) -> *mut ffi::C_GtkTreePath {
        self.pointer
    }

    #[doc(hidden)]
    pub fn wrap_pointer(c_treepath: *mut ffi::C_GtkTreePath) -> TreePath {
        unsafe {
            TreePath {
                pointer: c_treepath,
                container: CVec::new(::std::ptr::mut_null(), 0)
            }
        }
    }
}
<commit_msg>Change CVec to Vec<commit_after>// This file is part of rgtk.
//
// rgtk is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// rgtk is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with rgtk.  If not, see <http://www.gnu.org/licenses/>.

#![allow(visible_private_types)]

use gtk::ffi;
use std::c_str::CString;
use std::string::raw::from_buf;

pub struct TreePath {
    pointer:   *mut ffi::C_GtkTreePath
}

impl TreePath {
    pub fn new() -> Option<TreePath> {
        let tmp = unsafe { ffi::gtk_tree_path_new() };

        if tmp.is_null() {
            None
        } else {
            Some(TreePath {
                pointer: tmp
            })
        }
    }

    pub fn new_from_string(path: &str) -> Option<TreePath> {
        let tmp = unsafe {
            path.with_c_str(|c_str| {
                ffi::gtk_tree_path_new_from_string(c_str)
            })
        };

        if tmp.is_null() {
            None
        } else {
            Some(TreePath {
                pointer: tmp
            })
        }
    }

    pub fn new_from_indicesv(indices: &mut [i32]) -> Option<TreePath> {
        let tmp = unsafe { ffi::gtk_tree_path_new_from_indicesv(indices.as_mut_ptr(), indices.len() as u64) };

        if tmp.is_null() {
            None
        } else {
            Some(TreePath {
                pointer: tmp
            })
        }
    }

    pub fn new_first() -> Option<TreePath> {
        let tmp = unsafe { ffi::gtk_tree_path_new_first() };

        if tmp.is_null() {
            None
        } else {
            Some(TreePath {
                pointer: tmp
            })
        }
    }

    #[allow(unused_variable)]
    pub fn to_string(&self) -> String {
        let string = unsafe { ffi::gtk_tree_path_to_string(self.pointer) };

        if string.is_null() {
            String::new()
        } else {
            unsafe {
                // used to free the returned string
                let container = CString::new(string as *const i8, true);

                from_buf(string as *const u8)
            }
        }
    }

    pub fn append_index(&self, index_: i32) {
        unsafe { ffi::gtk_tree_path_append_index(self.pointer, index_) }
    }

    pub fn prepend_index(&self, index_: i32) {
        unsafe { ffi::gtk_tree_path_prepend_index(self.pointer, index_) }
    }

    pub fn get_depth(&self) -> i32 {
        unsafe { ffi::gtk_tree_path_get_depth(self.pointer) }
    }

    pub fn get_indices(&self) -> Vec<i32> {
        let tmp = unsafe { ffi::gtk_tree_path_get_indices(self.pointer) };
        let depth = self.get_depth();

        unsafe {
            ::std::vec::raw::from_buf(tmp as *const i32, depth as uint)
        }
    }

    pub fn copy(&self) -> Option<TreePath> {
        let tmp = unsafe { ffi::gtk_tree_path_copy(self.pointer) };

        if tmp.is_null() {
            None
        } else {
            Some(TreePath {
                pointer: tmp
            })
        }
    }

    pub fn compare(&self, other: &TreePath) -> i32 {
        unsafe { ffi::gtk_tree_path_compare(self.pointer as *const ffi::C_GtkTreePath, other.pointer as *const ffi::C_GtkTreePath) }
    }

    pub fn next(&self) {
        unsafe { ffi::gtk_tree_path_next(self.pointer) }
    }

    pub fn prev(&self) {
        unsafe { ffi::gtk_tree_path_prev(self.pointer) }
    }

    pub fn path_up(&self) -> bool {
        match unsafe { ffi::gtk_tree_path_up(self.pointer) } {
            0 => false,
            _ => true
        }
    }

    pub fn path_down(&self) {
        unsafe { ffi::gtk_tree_path_down(self.pointer) }
    }

    pub fn is_ancestor(&self, descendant: &TreePath) -> bool {
        match unsafe { ffi::gtk_tree_path_is_ancestor(self.pointer, descendant.pointer) } {
            0 => false,
            _ => true
        }
    }

    pub fn is_descendant(&self, ancestor: &TreePath) -> bool {
        match unsafe { ffi::gtk_tree_path_is_descendant(self.pointer, ancestor.pointer) } {
            0 => false,
            _ => true
        }
    }

    pub fn drop(&mut self) {
        unsafe { ffi::gtk_tree_path_free(self.pointer) }
        self.pointer = ::std::ptr::mut_null();
    }

    #[doc(hidden)]
    pub fn get_pointer(&self) -> *mut ffi::C_GtkTreePath {
        self.pointer
    }

    #[doc(hidden)]
    pub fn wrap_pointer(c_treepath: *mut ffi::C_GtkTreePath) -> TreePath {
        TreePath {
            pointer: c_treepath
        }
    }
}
<|endoftext|>


<commit_before>/* diosix error codes
 *
 * (c) Chris Williams, 2019-2021.
 *
 * See LICENSE for usage and copying.
 */

/* how things can go wrong */
#[derive(Debug)]
pub enum Cause
{
    /* misc */
    NotImplemented,

    /* debug */
    DebugInitFailed,

    /* devices */
    DeviceTreeBad,
    CantCloneDevices,
    BootDeviceTreeBad,

    /* physical CPU cores */
    PhysicalCoreBadID,
    PhysicalCoreCountUnknown,

    /* capsule services */
    ServiceAlreadyRegistered,
    ServiceNotAllowed,
    ServiceNotFound,

    /* messages */
    MessageBadType,

    /* heap */
    HeapNotInUse,
    HeapBadBlock,
    HeapNoFreeMem,
    HeapBadSize,
    HeapBadMagic,

    /* host physical memory */
    PhysNoRAMFound,
    PhysNotEnoughFreeRAM,
    PhysRegionTooSmall,
    PhysRegionCollision,
    PhysRegionNoMatch,
    PhysRegionSplitOutOfBounds,
    PhysRegionRegionAlignmentFailure,
    PhysRegionSmallNotMultiple,
    PhysRegionLargeNotMultiple,

    /* capsule virtual memory */
    VirtMemPhysNotSet,

    /* capsules */
    CapsuleIDExhaustion,
    CapsuleBadID,
    CapsuleCannotRestart,

    /* scheduler and timer */
    SchedNoTimer,

    /* supervisor binary loading */
    LoaderUnrecognizedCPUArch,
    LoaderSupervisorTooLarge,
    LoaderSupervisorFileSizeTooLarge,
    LoaderSupervisorEntryOutOfRange,
    LoaderUnrecognizedSupervisor,
    LoaderSupervisorBadImageOffset,
    LoaderSupervisorBadPhysOffset,
    LoaderSupervisorBadDynamicArea,
    LoaderSupervisorBadRelaEntrySize,
    LoaderSupervisorRelaTableTooBig,
    LoaderSupervisorBadRelaTblEntry,
    LoaderSupervisorUnknownRelaType,
    LoaderBadEntry,

    /* manifest errors */
    ManifestBadFS,
    ManifestNoSuchAsset
}
<commit_msg>Add error codes for: Virtual core management Capsule death and restarts<commit_after>/* diosix error codes
 *
 * (c) Chris Williams, 2019-2021.
 *
 * See LICENSE for usage and copying.
 */

/* how things can go wrong */
#[derive(Debug)]
pub enum Cause
{
    /* misc */
    NotImplemented,

    /* debug */
    DebugInitFailed,

    /* devices */
    DeviceTreeBad,
    CantCloneDevices,
    BootDeviceTreeBad,

    /* physical CPU cores */
    PhysicalCoreBadID,
    PhysicalCoreCountUnknown,

    /* capsule services */
    ServiceAlreadyRegistered,
    ServiceNotAllowed,
    ServiceNotFound,

    /* messages */
    MessageBadType,

    /* heap */
    HeapNotInUse,
    HeapBadBlock,
    HeapNoFreeMem,
    HeapBadSize,
    HeapBadMagic,

    /* virtual core management */
    VirtualCoreBadID,
    VirtualCoreAWOL,

    /* host physical memory */
    PhysNoRAMFound,
    PhysNotEnoughFreeRAM,
    PhysRegionTooSmall,
    PhysRegionCollision,
    PhysRegionNoMatch,
    PhysRegionSplitOutOfBounds,
    PhysRegionRegionAlignmentFailure,
    PhysRegionSmallNotMultiple,
    PhysRegionLargeNotMultiple,

    /* capsule virtual memory */
    VirtMemPhysNotSet,

    /* capsules */
    CapsuleIDExhaustion,
    CapsuleBadID,
    CapsuleCannotRestart,
    CapsuleCantDie,
    CapsuleCantRestart,

    /* scheduler and timer */
    SchedNoTimer,

    /* supervisor binary loading */
    LoaderUnrecognizedCPUArch,
    LoaderSupervisorTooLarge,
    LoaderSupervisorFileSizeTooLarge,
    LoaderSupervisorEntryOutOfRange,
    LoaderUnrecognizedSupervisor,
    LoaderSupervisorBadImageOffset,
    LoaderSupervisorBadPhysOffset,
    LoaderSupervisorBadDynamicArea,
    LoaderSupervisorBadRelaEntrySize,
    LoaderSupervisorRelaTableTooBig,
    LoaderSupervisorBadRelaTblEntry,
    LoaderSupervisorUnknownRelaType,
    LoaderBadEntry,

    /* manifest errors */
    ManifestBadFS,
    ManifestNoSuchAsset
}
<|endoftext|>


<commit_before>// Helianto -- static website generator
// Copyright © 2015-2016 Mickaël RAYBAUD-ROIG
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use std::path::Path;
use std::fs::File;
use regex::Regex;
use std::io::Read;
use std::ascii::AsciiExt;
use std::mem::replace;
use pulldown_cmark::{Parser, Event, Tag};
use pulldown_cmark::{OPTION_ENABLE_TABLES, OPTION_ENABLE_FOOTNOTES};
use pulldown_cmark::html;
use super::{Metadata, Reader};
use super::super::{Error, Result, Settings};

#[derive(Debug, Clone)]
pub struct MarkdownReader;

static EXTENSIONS: &'static [&'static str] = &["markdown", "md", "mkd", "mdown"];

impl Reader for MarkdownReader {
    fn new(_settings: &Settings) -> MarkdownReader {
        MarkdownReader
    }

    fn extensions() -> &'static [&'static str] {
        EXTENSIONS
    }

    fn load(&self, path: &Path) -> Result<(String, Metadata)> {
        let mut input = String::new();
        try! {
            File::open(path)
                .and_then(|mut fd| fd.read_to_string(&mut input))
                .map_err(|err| Error::Reader {
                    path: path.into(),
                    cause: Box::new(err),
                }
            )
        };

        Ok(process_markdown(&input))
    }
}

#[derive(PartialEq, Eq, Debug)]
enum State {
    BeforeTitle,
    InsideTitle,
    BeforeMetadata,
    InsideMetadata,
    InsideBody,
}

struct MetadataExtractor<'a> {
    inner: Parser<'a>,
    regex: Regex,
    state: State,
    pub metadata: Metadata,
    buffer: Vec<Event<'a>>,
}

impl<'a> From<Parser<'a>> for MetadataExtractor<'a> {
    fn from(parser: Parser) -> MetadataExtractor {
        MetadataExtractor {
            inner: parser,
            regex: Regex::new(r"^[\w][\w\d_\x2D ]*\s*:").unwrap(),
            state: State::BeforeTitle,
            metadata: Metadata::new(),
            buffer: Vec::new(),
        }
    }
}

impl<'a> Iterator for MetadataExtractor<'a> {
    type Item = Event<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        use self::State::*;

        if self.state == State::InsideBody {
            if self.buffer.len() > 0 {
                return Some(self.buffer.remove(0));
            } else {
                return self.inner.next();
            }
        }

        let event = match self.inner.next() {
            Some(ev) => ev,
            None => return None,
        };

        println!("{:?} {:?}", self.state, event);
        match self.state {
            BeforeTitle => {
                match event {
                    Event::Start(Tag::Header(_)) => {
                        self.state = State::InsideTitle;
                        self.next()
                    },
                    Event::Start(Tag::Paragraph) => {
                        self.state = State::InsideMetadata;
                        self.buffer.push(event);
                        self.next()
                    },
                    _ => {
                        self.state = State::InsideBody;
                        Some(event)
                    }
                }
            },
            InsideTitle => {
                match event {
                    Event::Text(_) => {
                        self.metadata.insert("title".into(), get_event_text(&event));
                        self.next()
                    },
                    Event::End(Tag::Header(_)) => {
                        self.state = State::BeforeMetadata;
                        self.next()
                    },
                    _ => self.next(),
                }
            },
            BeforeMetadata => {
                match event {
                    Event::Start(Tag::Paragraph) => {
                        self.state = State::InsideMetadata;
                        self.buffer.push(event);
                        self.next()
                    },
                    _ => {
                        self.state = State::InsideBody;
                        Some(event)
                    }
                }
            },
            InsideMetadata => {
                match event {
                    Event::Text(_) => {
                        if ! self.regex.is_match(&get_event_text(&event)) {
                            self.state = State::InsideBody;
                            println!("metadata end: {}", get_event_text(&event));
                        }
                        self.buffer.push(event);
                        self.next()
                    },
                    Event::End(Tag::Paragraph) => {
                        self.metadata.extend(
                            replace(&mut self.buffer, Vec::new()).into_iter().filter_map(|event| {
                                if let Event::Text(text) = event {
                                    let (key, value) = split_pair(&text);
                                    Some((key.to_ascii_lowercase(), value))
                                } else {
                                    None
                                }
                            })
                        );
                        self.state = State::InsideBody;
                        self.next()
                    },
                    Event::SoftBreak | Event::HardBreak => {
                        self.buffer.push(event);
                        self.next()
                    },
                    _ => {
                        self.buffer.push(event);
                        self.state = State::InsideBody;
                        self.next()
                    }
                }
            },
            InsideBody => unreachable!(),
        }
    }
}

fn split_pair<S: AsRef<str>>(input: &S) -> (String, String) {
    let mut split = input.as_ref().splitn(2, ':');
    let key: &str = split.next().unwrap_or("");
    let value: &str = split.next().unwrap_or("");
    (key.trim().into(), value.trim().into())
}

fn get_event_text<'a>(event: &Event<'a>) -> String {
    if let Event::Text(ref text) = *event {
        text.clone().into_owned()
    } else {
        panic!()
    }
}

fn process_markdown<S: AsRef<str>>(input: &S) -> (String, Metadata) {
    let mut parser = MetadataExtractor::from(
        Parser::new_ext(input.as_ref(), OPTION_ENABLE_TABLES | OPTION_ENABLE_FOOTNOTES)
    );
    let mut output = String::with_capacity(input.as_ref().len() * (3/2));
    html::push_html(&mut output, &mut parser);
    (output, parser.metadata.clone())
}

#[test]
fn extract_title() {
    let (output, metadata) = process_markdown(&"# Foo\nbar\nbaz");
    assert_eq!(metadata.get("title"), Some(&"Foo".into()));
    assert_eq!(output, "
bar\nbaz
\n");
}

#[test]
fn extract_metadata() {
    let (output, metadata) = process_markdown(&"# Foo\n\nBar: baz:quux\nFoo bar: qux baz\n\nfoo: bar");
    assert_eq!(metadata.get("title"), Some(&"Foo".into()));
    assert_eq!(metadata.get("bar"), Some(&"baz:quux".into()));
    assert_eq!(metadata.get("foo bar"), Some(&"qux baz".into()));
    assert_eq!(output, "
foo: bar
\n");
}

#[test]
fn can_skip_to_metadata() {
    let (output, metadata) = process_markdown(&"\n\n\nBar: baz:quux\nFoo bar: qux baz\n\nfoo: bar");
    assert_eq!(metadata.get("title"), None);
    assert_eq!(metadata.get("bar"), Some(&"baz:quux".into()));
    assert_eq!(metadata.get("foo bar"), Some(&"qux baz".into()));
    assert_eq!(output, "
foo: bar
\n");
}

#[test]
fn can_skip_to_body() {
    let (output, metadata) = process_markdown(&"\n\n\nBar: baz:quux\nFoo bar: qux baz  \nlol\n\nfoo: bar");
    assert_eq!(metadata.get("title"), None);
    assert_eq!(metadata.get("bar"), None);
    assert_eq!(metadata.get("foo bar"), None);
    assert_eq!(output, "
Bar: baz:quux\nFoo bar: qux baz
\nlol
\n
foo: bar
\n");
}

#[test]
fn can_skip_metadata() {
    let (output, metadata) = process_markdown(&"# Title\n\n\nBar: baz:quux\nFoo bar: qux baz  \nlol\n\nfoo: bar");
    assert_eq!(metadata.get("title"), Some(&String::from("Title")));
    assert_eq!(metadata.get("bar"), None);
    assert_eq!(metadata.get("foo bar"), None);
    assert_eq!(output, "
Bar: baz:quux\nFoo bar: qux baz
\nlol
\n
foo: bar
\n");
}
<commit_msg>Remove forgotten calls to println!()<commit_after>// Helianto -- static website generator
// Copyright © 2015-2016 Mickaël RAYBAUD-ROIG
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use std::path::Path;
use std::fs::File;
use regex::Regex;
use std::io::Read;
use std::ascii::AsciiExt;
use std::mem::replace;
use pulldown_cmark::{Parser, Event, Tag};
use pulldown_cmark::{OPTION_ENABLE_TABLES, OPTION_ENABLE_FOOTNOTES};
use pulldown_cmark::html;
use super::{Metadata, Reader};
use super::super::{Error, Result, Settings};

#[derive(Debug, Clone)]
pub struct MarkdownReader;

static EXTENSIONS: &'static [&'static str] = &["markdown", "md", "mkd", "mdown"];

impl Reader for MarkdownReader {
    fn new(_settings: &Settings) -> MarkdownReader {
        MarkdownReader
    }

    fn extensions() -> &'static [&'static str] {
        EXTENSIONS
    }

    fn load(&self, path: &Path) -> Result<(String, Metadata)> {
        let mut input = String::new();
        try! {
            File::open(path)
                .and_then(|mut fd| fd.read_to_string(&mut input))
                .map_err(|err| Error::Reader {
                    path: path.into(),
                    cause: Box::new(err),
                }
            )
        };

        Ok(process_markdown(&input))
    }
}

#[derive(PartialEq, Eq, Debug)]
enum State {
    BeforeTitle,
    InsideTitle,
    BeforeMetadata,
    InsideMetadata,
    InsideBody,
}

struct MetadataExtractor<'a> {
    inner: Parser<'a>,
    regex: Regex,
    state: State,
    pub metadata: Metadata,
    buffer: Vec<Event<'a>>,
}

impl<'a> From<Parser<'a>> for MetadataExtractor<'a> {
    fn from(parser: Parser) -> MetadataExtractor {
        MetadataExtractor {
            inner: parser,
            regex: Regex::new(r"^[\w][\w\d_\x2D ]*\s*:").unwrap(),
            state: State::BeforeTitle,
            metadata: Metadata::new(),
            buffer: Vec::new(),
        }
    }
}

impl<'a> Iterator for MetadataExtractor<'a> {
    type Item = Event<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        use self::State::*;

        if self.state == State::InsideBody {
            if self.buffer.len() > 0 {
                return Some(self.buffer.remove(0));
            } else {
                return self.inner.next();
            }
        }

        let event = match self.inner.next() {
            Some(ev) => ev,
            None => return None,
        };

        match self.state {
            BeforeTitle => {
                match event {
                    Event::Start(Tag::Header(_)) => {
                        self.state = State::InsideTitle;
                        self.next()
                    },
                    Event::Start(Tag::Paragraph) => {
                        self.state = State::InsideMetadata;
                        self.buffer.push(event);
                        self.next()
                    },
                    _ => {
                        self.state = State::InsideBody;
                        Some(event)
                    }
                }
            },
            InsideTitle => {
                match event {
                    Event::Text(_) => {
                        self.metadata.insert("title".into(), get_event_text(&event));
                        self.next()
                    },
                    Event::End(Tag::Header(_)) => {
                        self.state = State::BeforeMetadata;
                        self.next()
                    },
                    _ => self.next(),
                }
            },
            BeforeMetadata => {
                match event {
                    Event::Start(Tag::Paragraph) => {
                        self.state = State::InsideMetadata;
                        self.buffer.push(event);
                        self.next()
                    },
                    _ => {
                        self.state = State::InsideBody;
                        Some(event)
                    }
                }
            },
            InsideMetadata => {
                match event {
                    Event::Text(_) => {
                        if ! self.regex.is_match(&get_event_text(&event)) {
                            self.state = State::InsideBody;
                        }
                        self.buffer.push(event);
                        self.next()
                    },
                    Event::End(Tag::Paragraph) => {
                        self.metadata.extend(
                            replace(&mut self.buffer, Vec::new()).into_iter().filter_map(|event| {
                                if let Event::Text(text) = event {
                                    let (key, value) = split_pair(&text);
                                    Some((key.to_ascii_lowercase(), value))
                                } else {
                                    None
                                }
                            })
                        );
                        self.state = State::InsideBody;
                        self.next()
                    },
                    Event::SoftBreak | Event::HardBreak => {
                        self.buffer.push(event);
                        self.next()
                    },
                    _ => {
                        self.buffer.push(event);
                        self.state = State::InsideBody;
                        self.next()
                    }
                }
            },
            InsideBody => unreachable!(),
        }
    }
}

fn split_pair<S: AsRef<str>>(input: &S) -> (String, String) {
    let mut split = input.as_ref().splitn(2, ':');
    let key: &str = split.next().unwrap_or("");
    let value: &str = split.next().unwrap_or("");
    (key.trim().into(), value.trim().into())
}

fn get_event_text<'a>(event: &Event<'a>) -> String {
    if let Event::Text(ref text) = *event {
        text.clone().into_owned()
    } else {
        panic!()
    }
}

fn process_markdown<S: AsRef<str>>(input: &S) -> (String, Metadata) {
    let mut parser = MetadataExtractor::from(
        Parser::new_ext(input.as_ref(), OPTION_ENABLE_TABLES | OPTION_ENABLE_FOOTNOTES)
    );
    let mut output = String::with_capacity(input.as_ref().len() * (3/2));
    html::push_html(&mut output, &mut parser);
    (output, parser.metadata.clone())
}

#[test]
fn extract_title() {
    let (output, metadata) = process_markdown(&"# Foo\nbar\nbaz");
    assert_eq!(metadata.get("title"), Some(&"Foo".into()));
    assert_eq!(output, "
bar\nbaz
\n");
}

#[test]
fn extract_metadata() {
    let (output, metadata) = process_markdown(&"# Foo\n\nBar: baz:quux\nFoo bar: qux baz\n\nfoo: bar");
    assert_eq!(metadata.get("title"), Some(&"Foo".into()));
    assert_eq!(metadata.get("bar"), Some(&"baz:quux".into()));
    assert_eq!(metadata.get("foo bar"), Some(&"qux baz".into()));
    assert_eq!(output, "
foo: bar
\n");
}

#[test]
fn can_skip_to_metadata() {
    let (output, metadata) = process_markdown(&"\n\n\nBar: baz:quux\nFoo bar: qux baz\n\nfoo: bar");
    assert_eq!(metadata.get("title"), None);
    assert_eq!(metadata.get("bar"), Some(&"baz:quux".into()));
    assert_eq!(metadata.get("foo bar"), Some(&"qux baz".into()));
    assert_eq!(output, "
foo: bar
\n");
}

#[test]
fn can_skip_to_body() {
    let (output, metadata) = process_markdown(&"\n\n\nBar: baz:quux\nFoo bar: qux baz  \nlol\n\nfoo: bar");
    assert_eq!(metadata.get("title"), None);
    assert_eq!(metadata.get("bar"), None);
    assert_eq!(metadata.get("foo bar"), None);
    assert_eq!(output, "
Bar: baz:quux\nFoo bar: qux baz
\nlol
\n
foo: bar
\n");
}

#[test]
fn can_skip_metadata() {
    let (output, metadata) = process_markdown(&"# Title\n\n\nBar: baz:quux\nFoo bar: qux baz  \nlol\n\nfoo: bar");
    assert_eq!(metadata.get("title"), Some(&String::from("Title")));
    assert_eq!(metadata.get("bar"), None);
    assert_eq!(metadata.get("foo bar"), None);
    assert_eq!(output, "
Bar: baz:quux\nFoo bar: qux baz
\nlol
\n
foo: bar
\n");
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
/// The XML structure for a cobatura report is roughly as follows:
/// ```xml
/// <coverage lines-valid="5" lines-covered="0" line-rate="0.0" branches-valid="0"
/// branches-covered="0" branch-rate="0.0" version="1.9" timestamp="...">
///   <sources>
///     <source>PATH</source>
///     ...
///   </sources>
///
///   <packages>
///     <package name=".."  line-rate="0.0" branch-rate="0.0" complexity="0.0">
///       <classes>
///         <class name="Main" filename="main.rs" line-rate="0.0" branch-rate="0.0" complexity="0.0">
///           <methods>
///             <method name="main" signature="()" line-rate="0.0" branch-rate="0.0">
///               <lines>
///                 <line number="1" hits="5" branch="false"/>
///                 <line number="3" hits="2" branch="true">
///                   <conditions>
///                     <condition number="0" type="jump" coverage="50%"/>
///                     ...
///                   </conditions>
///                 </line>
///               </lines>
///             </method>
///             ...
///           </methods>
///
///           <lines>
///             <line number="10" hits="4" branch="false"/>
///           </lines>
///         </class>
///         ...
///       </classes>
///     </package>
///     ...
///   </packages>
/// </coverage>
/// ```
use std::error;
use std::fmt;
use std::fs::File;
use std::io::{Cursor, Write};
use std::path::{Path, PathBuf};
use std::time::{SystemTime, UNIX_EPOCH};

use quick_xml::{
    events::{BytesDecl, BytesEnd, BytesStart, Event},
    Writer,
};

use chrono::offset::Utc;

use crate::config::Config;
use crate::traces::{CoverageStat, Trace, TraceMap};

pub fn report(traces: &TraceMap, config: &Config) -> Result<(), Error> {
    let result = Report::render(config, traces)?;
    result.export(config)
}

#[derive(Debug)]
pub enum Error {
    Unknown,
    ExportError(quick_xml::Error),
}

impl error::Error for Error {
    #[inline]
    fn description(&self) -> &str {
        match self {
            Error::ExportError(_) => "Error exporting xml file",
            Error::Unknown => "Unknown Error",
        }
    }

    #[inline]
    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

impl fmt::Display for Error {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Error::ExportError(ref e) => write!(f, "Export Error {}", e),
            Error::Unknown => write!(f, "Unknown Error"),
        }
    }
}

#[derive(Debug)]
pub struct Report {
    timestamp: i64,
    lines_covered: usize,
    lines_valid: usize,
    line_rate: f64,
    branches_covered: usize,
    branches_valid: usize,
    branch_rate: f64,
    sources: Vec<PathBuf>,
    packages: Vec<Package>,
}

impl Report {
    pub fn render(config: &Config, traces: &TraceMap) -> Result<Self, Error> {
        let timestamp = Utc::now().timestamp();
        let sources = render_sources(config);
        let packages = render_packages(config, traces);
        let mut line_rate = 0.0;
        let mut branch_rate = 0.0;

        if packages.len() > 0 {
            line_rate = packages.iter().map(|x| x.line_rate).sum::<f64>() / packages.len() as f64;
            branch_rate =
                packages.iter().map(|x| x.branch_rate).sum::<f64>() / packages.len() as f64;
        }

        Ok(Report {
            timestamp: timestamp,
            lines_covered: traces.total_covered(),
            lines_valid: traces.total_coverable(),
            line_rate: line_rate,
            branches_covered: 0,
            branches_valid: 0,
            branch_rate: branch_rate,
            sources: sources,
            packages: packages,
        })
    }

    pub fn export(&self, _config: &Config) -> Result<(), Error> {
        let mut file = File::create("cobertura.xml")
            .map_err(|e| Error::ExportError(quick_xml::Error::Io(e)))?;

        let mut writer = Writer::new(Cursor::new(vec![]));
        writer
            .write_event(Event::Decl(BytesDecl::new(b"1.0", None, None)))
            .map_err(|e| Error::ExportError(e))?;

        let cov_tag = b"coverage";
        let mut cov = BytesStart::borrowed(cov_tag, cov_tag.len());
        cov.push_attribute(("lines-covered", self.lines_covered.to_string().as_ref()));
        cov.push_attribute(("lines-valid", self.lines_valid.to_string().as_ref()));
        cov.push_attribute(("line-rate", self.line_rate.to_string().as_ref()));
        cov.push_attribute((
            "branches-covered",
            self.branches_covered.to_string().as_ref(),
        ));
        cov.push_attribute(("branches-valid", self.branches_valid.to_string().as_ref()));
        cov.push_attribute(("branch-rate", self.branch_rate.to_string().as_ref()));
        cov.push_attribute(("complexity", "0"));
        cov.push_attribute(("version", "1.9"));

        let secs = match SystemTime::now().duration_since(UNIX_EPOCH) {
            Ok(s) => s.as_secs().to_string(),
            Err(_) => String::from("0"),
        };
        cov.push_attribute(("timestamp", secs.as_ref()));

        writer
            .write_event(Event::Start(cov))
            .map_err(|e| Error::ExportError(e))?;

        self.export_header(&mut writer)
            .map_err(|e| Error::ExportError(e))?;

        self.export_packages(&mut writer)
            .map_err(|e| Error::ExportError(e))?;

        writer
            .write_event(Event::End(BytesEnd::borrowed(cov_tag)))
            .map_err(|e| Error::ExportError(e))?;

        let result = writer.into_inner().into_inner();
        file.write_all(&result)
            .map_err(|e| Error::ExportError(quick_xml::Error::Io(e)))
    }

    fn export_header<T: Write>(&self, writer: &mut Writer<T>) -> Result<(), quick_xml::Error> {
        let sources_tag = b"sources";
        let source_tag = b"source";
        writer.write_event(Event::Start(BytesStart::borrowed(
            sources_tag,
            sources_tag.len(),
        )))?;
        for source in self.sources.iter() {
            if let Some(ref path) = source.to_str() {
                writer.write_event(Event::Start(BytesStart::borrowed(
                    source_tag,
                    source_tag.len(),
                )))?;
                writer.write(path.as_bytes())?;
                writer.write_event(Event::End(BytesEnd::borrowed(source_tag)))?;
            }
        }
        writer
            .write_event(Event::End(BytesEnd::borrowed(sources_tag)))
            .map(|_| ())
    }

    fn export_packages<T: Write>(&self, writer: &mut Writer<T>) -> Result<(), quick_xml::Error> {
        let packages_tag = b"packages";
        let pack_tag = b"package";

        writer.write_event(Event::Start(BytesStart::borrowed(
            packages_tag,
            packages_tag.len(),
        )))?;
        // Export the package
        for package in &self.packages {
            let mut pack = BytesStart::borrowed(pack_tag, pack_tag.len());
            pack.push_attribute(("line-rate", package.line_rate.to_string().as_ref()));
            pack.push_attribute(("branch-rate", package.branch_rate.to_string().as_ref()));
            pack.push_attribute(("complexity", package.complexity.to_string().as_ref()));

            writer.write_event(Event::Start(pack))?;
            self.export_classes(&package.classes, writer)?;
            writer.write_event(Event::End(BytesEnd::borrowed(pack_tag)))?;
        }

        writer
            .write_event(Event::End(BytesEnd::borrowed(packages_tag)))
            .map(|_| ())
    }

    fn export_classes<T: Write>(
        &self,
        classes: &[Class],
        writer: &mut Writer<T>,
    ) -> Result<(), quick_xml::Error> {
        let classes_tag = b"classes";
        let class_tag = b"class";
        let methods_tag = b"methods";

        writer.write_event(Event::Start(BytesStart::borrowed(
            classes_tag,
            classes_tag.len(),
        )))?;
        for class in classes {
            let mut c = BytesStart::borrowed(class_tag, class_tag.len());
            c.push_attribute(("name", class.name.as_ref()));
            c.push_attribute(("filename", class.file_name.as_ref()));
            c.push_attribute(("line-rate", class.line_rate.to_string().as_ref()));
            c.push_attribute(("branch-rate", class.branch_rate.to_string().as_ref()));
            c.push_attribute(("complexity", class.complexity.to_string().as_ref()));

            writer.write_event(Event::Start(c))?;
            writer.write_event(Event::Empty(BytesStart::borrowed(
                methods_tag,
                methods_tag.len(),
            )))?;
            self.export_lines(&class.lines, writer)?;
            writer.write_event(Event::End(BytesEnd::borrowed(class_tag)))?;
        }
        writer
            .write_event(Event::End(BytesEnd::borrowed(classes_tag)))
            .map(|_| ())
    }

    fn export_lines<T: Write>(
        &self,
        lines: &[Line],
        writer: &mut Writer<T>,
    ) -> Result<(), quick_xml::Error> {
        let lines_tag = b"lines";
        let line_tag = b"line";

        writer.write_event(Event::Start(BytesStart::borrowed(
            lines_tag,
            lines_tag.len(),
        )))?;
        for line in lines {
            let mut l = BytesStart::borrowed(line_tag, line_tag.len());
            match line {
                Line::Plain {
                    ref number,
                    ref hits,
                } => {
                    l.push_attribute(("number", number.to_string().as_ref()));
                    l.push_attribute(("hits", hits.to_string().as_ref()));
                }
                Line::Branch { .. } => {}
            }
            writer.write_event(Event::Empty(l))?;
        }
        writer
            .write_event(Event::End(BytesEnd::borrowed(lines_tag)))
            .map(|_| ())
    }
}

fn render_sources(config: &Config) -> Vec<PathBuf> {
    let render_source = |&x| Path::to_path_buf(x);

    config.manifest.parent().iter().map(render_source).collect()
}

#[derive(Debug)]
struct Package {
    name: String,
    line_rate: f64,
    branch_rate: f64,
    complexity: f64,
    classes: Vec<Class>,
}

fn render_packages(config: &Config, traces: &TraceMap) -> Vec<Package> {
    let mut dirs: Vec<&Path> = traces
        .files()
        .into_iter()
        .filter_map(|x| x.parent())
        .collect();

    dirs.dedup();

    dirs.into_iter()
        .map(|x| render_package(config, traces, x))
        .collect()
}

fn render_package(config: &Config, traces: &TraceMap, pkg: &Path) -> Package {
    let root = config.manifest.parent().unwrap_or(&config.manifest);
    let name = pkg
        .strip_prefix(root)
        .map(|x| Path::to_str(x))
        .unwrap_or_default()
        .unwrap_or_default();

    let line_cover = traces.covered_in_path(pkg) as f64;
    let line_rate = line_cover / (traces.coverable_in_path(pkg) as f64);

    Package {
        name: name.to_string(),
        line_rate: line_rate,
        branch_rate: 0.0,
        complexity: 0.0,
        classes: render_classes(config, traces, pkg),
    }
}

#[derive(Debug)]
struct Class {
    name: String,
    file_name: String,
    line_rate: f64,
    branch_rate: f64,
    complexity: f64,
    lines: Vec<Line>,
    methods: Vec<Method>,
}

fn render_classes(config: &Config, traces: &TraceMap, pkg: &Path) -> Vec<Class> {
    traces
        .files()
        .iter()
        .filter(|x| x.parent() == Some(pkg))
        .map(|x| render_class(config, traces, x))
        .collect()
}

// TODO: Cobertura distinguishes between lines outside methods, and methods
// (which also contain lines). As there is currently no way to get traces from
// a particular function only, all traces are put into lines, and the vector
// of methods is empty.
//
// Until this is fixed, the render_method function will panic if called, as it
// cannot be properly implemented.
//
fn render_class(config: &Config, traces: &TraceMap, file: &Path) -> Class {
    let root = config.manifest.parent().unwrap_or(&config.manifest);
    let name = file
        .file_stem()
        .map(|x| x.to_str().unwrap())
        .unwrap_or_default()
        .to_string();

    let file_name = file
        .strip_prefix(root)
        .unwrap_or(file)
        .to_str()
        .unwrap()
        .to_string();

    let covered = traces.covered_in_path(file) as f64;
    let line_rate = covered / traces.coverable_in_path(file) as f64;
    let lines = traces
        .get_child_traces(file)
        .iter()
        .map(|x| render_line(x))
        .collect();

    Class {
        name: name,
        file_name: file_name,
        line_rate: line_rate,
        branch_rate: 0.0,
        complexity: 0.0,
        lines: lines,
        methods: vec![],
    }
}

#[derive(Debug)]
struct Method {
    name: String,
    signature: String,
    line_rate: f64,
    branch_rate: f64,
    lines: Vec<Line>,
}

fn render_methods() -> Vec<Method> {
    unimplemented!()
}

fn render_method() -> Method {
    unimplemented!()
}

#[derive(Debug)]
enum Line {
    Plain {
        number: usize,
        hits: usize,
    },

    Branch {
        number: usize,
        hits: usize,
        conditions: Vec<Condition>,
    },
}

fn render_line(trace: &Trace) -> Line {
    match &trace.stats {
        CoverageStat::Line(hits) => Line::Plain {
            number: trace.line as usize,
            hits: *hits as usize,
        },

        // TODO: Branches in cobertura are given a fresh number as a label,
        // which would require having some form of context when rendering.
        //
        _ => panic!("Not currently supported"),
    }
}

#[derive(Debug)]
struct Condition {
    number: usize,
    cond_type: ConditionType,
    coverage: f64,
}

// Condition types
#[derive(Debug)]
enum ConditionType {
    Jump,
}
<commit_msg>add missing name attribute for cobertura package tag<commit_after>#![allow(dead_code)]
/// The XML structure for a cobatura report is roughly as follows:
/// ```xml
/// <coverage lines-valid="5" lines-covered="0" line-rate="0.0" branches-valid="0"
/// branches-covered="0" branch-rate="0.0" version="1.9" timestamp="...">
///   <sources>
///     <source>PATH</source>
///     ...
///   </sources>
///
///   <packages>
///     <package name=".."  line-rate="0.0" branch-rate="0.0" complexity="0.0">
///       <classes>
///         <class name="Main" filename="main.rs" line-rate="0.0" branch-rate="0.0" complexity="0.0">
///           <methods>
///             <method name="main" signature="()" line-rate="0.0" branch-rate="0.0">
///               <lines>
///                 <line number="1" hits="5" branch="false"/>
///                 <line number="3" hits="2" branch="true">
///                   <conditions>
///                     <condition number="0" type="jump" coverage="50%"/>
///                     ...
///                   </conditions>
///                 </line>
///               </lines>
///             </method>
///             ...
///           </methods>
///
///           <lines>
///             <line number="10" hits="4" branch="false"/>
///           </lines>
///         </class>
///         ...
///       </classes>
///     </package>
///     ...
///   </packages>
/// </coverage>
/// ```
use std::error;
use std::fmt;
use std::fs::File;
use std::io::{Cursor, Write};
use std::path::{Path, PathBuf};
use std::time::{SystemTime, UNIX_EPOCH};

use quick_xml::{
    events::{BytesDecl, BytesEnd, BytesStart, Event},
    Writer,
};

use chrono::offset::Utc;

use crate::config::Config;
use crate::traces::{CoverageStat, Trace, TraceMap};

pub fn report(traces: &TraceMap, config: &Config) -> Result<(), Error> {
    let result = Report::render(config, traces)?;
    result.export(config)
}

#[derive(Debug)]
pub enum Error {
    Unknown,
    ExportError(quick_xml::Error),
}

impl error::Error for Error {
    #[inline]
    fn description(&self) -> &str {
        match self {
            Error::ExportError(_) => "Error exporting xml file",
            Error::Unknown => "Unknown Error",
        }
    }

    #[inline]
    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

impl fmt::Display for Error {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Error::ExportError(ref e) => write!(f, "Export Error {}", e),
            Error::Unknown => write!(f, "Unknown Error"),
        }
    }
}

#[derive(Debug)]
pub struct Report {
    timestamp: i64,
    lines_covered: usize,
    lines_valid: usize,
    line_rate: f64,
    branches_covered: usize,
    branches_valid: usize,
    branch_rate: f64,
    sources: Vec<PathBuf>,
    packages: Vec<Package>,
}

impl Report {
    pub fn render(config: &Config, traces: &TraceMap) -> Result<Self, Error> {
        let timestamp = Utc::now().timestamp();
        let sources = render_sources(config);
        let packages = render_packages(config, traces);
        let mut line_rate = 0.0;
        let mut branch_rate = 0.0;

        if packages.len() > 0 {
            line_rate = packages.iter().map(|x| x.line_rate).sum::<f64>() / packages.len() as f64;
            branch_rate =
                packages.iter().map(|x| x.branch_rate).sum::<f64>() / packages.len() as f64;
        }

        Ok(Report {
            timestamp: timestamp,
            lines_covered: traces.total_covered(),
            lines_valid: traces.total_coverable(),
            line_rate: line_rate,
            branches_covered: 0,
            branches_valid: 0,
            branch_rate: branch_rate,
            sources: sources,
            packages: packages,
        })
    }

    pub fn export(&self, _config: &Config) -> Result<(), Error> {
        let mut file = File::create("cobertura.xml")
            .map_err(|e| Error::ExportError(quick_xml::Error::Io(e)))?;

        let mut writer = Writer::new(Cursor::new(vec![]));
        writer
            .write_event(Event::Decl(BytesDecl::new(b"1.0", None, None)))
            .map_err(|e| Error::ExportError(e))?;

        let cov_tag = b"coverage";
        let mut cov = BytesStart::borrowed(cov_tag, cov_tag.len());
        cov.push_attribute(("lines-covered", self.lines_covered.to_string().as_ref()));
        cov.push_attribute(("lines-valid", self.lines_valid.to_string().as_ref()));
        cov.push_attribute(("line-rate", self.line_rate.to_string().as_ref()));
        cov.push_attribute((
            "branches-covered",
            self.branches_covered.to_string().as_ref(),
        ));
        cov.push_attribute(("branches-valid", self.branches_valid.to_string().as_ref()));
        cov.push_attribute(("branch-rate", self.branch_rate.to_string().as_ref()));
        cov.push_attribute(("complexity", "0"));
        cov.push_attribute(("version", "1.9"));

        let secs = match SystemTime::now().duration_since(UNIX_EPOCH) {
            Ok(s) => s.as_secs().to_string(),
            Err(_) => String::from("0"),
        };
        cov.push_attribute(("timestamp", secs.as_ref()));

        writer
            .write_event(Event::Start(cov))
            .map_err(|e| Error::ExportError(e))?;

        self.export_header(&mut writer)
            .map_err(|e| Error::ExportError(e))?;

        self.export_packages(&mut writer)
            .map_err(|e| Error::ExportError(e))?;

        writer
            .write_event(Event::End(BytesEnd::borrowed(cov_tag)))
            .map_err(|e| Error::ExportError(e))?;

        let result = writer.into_inner().into_inner();
        file.write_all(&result)
            .map_err(|e| Error::ExportError(quick_xml::Error::Io(e)))
    }

    fn export_header<T: Write>(&self, writer: &mut Writer<T>) -> Result<(), quick_xml::Error> {
        let sources_tag = b"sources";
        let source_tag = b"source";
        writer.write_event(Event::Start(BytesStart::borrowed(
            sources_tag,
            sources_tag.len(),
        )))?;
        for source in self.sources.iter() {
            if let Some(ref path) = source.to_str() {
                writer.write_event(Event::Start(BytesStart::borrowed(
                    source_tag,
                    source_tag.len(),
                )))?;
                writer.write(path.as_bytes())?;
                writer.write_event(Event::End(BytesEnd::borrowed(source_tag)))?;
            }
        }
        writer
            .write_event(Event::End(BytesEnd::borrowed(sources_tag)))
            .map(|_| ())
    }

    fn export_packages<T: Write>(&self, writer: &mut Writer<T>) -> Result<(), quick_xml::Error> {
        let packages_tag = b"packages";
        let pack_tag = b"package";

        writer.write_event(Event::Start(BytesStart::borrowed(
            packages_tag,
            packages_tag.len(),
        )))?;
        // Export the package
        for package in &self.packages {
            let mut pack = BytesStart::borrowed(pack_tag, pack_tag.len());
            pack.push_attribute(("name", package.name.as_str()));
            pack.push_attribute(("line-rate", package.line_rate.to_string().as_ref()));
            pack.push_attribute(("branch-rate", package.branch_rate.to_string().as_ref()));
            pack.push_attribute(("complexity", package.complexity.to_string().as_ref()));

            writer.write_event(Event::Start(pack))?;
            self.export_classes(&package.classes, writer)?;
            writer.write_event(Event::End(BytesEnd::borrowed(pack_tag)))?;
        }

        writer
            .write_event(Event::End(BytesEnd::borrowed(packages_tag)))
            .map(|_| ())
    }

    fn export_classes<T: Write>(
        &self,
        classes: &[Class],
        writer: &mut Writer<T>,
    ) -> Result<(), quick_xml::Error> {
        let classes_tag = b"classes";
        let class_tag = b"class";
        let methods_tag = b"methods";

        writer.write_event(Event::Start(BytesStart::borrowed(
            classes_tag,
            classes_tag.len(),
        )))?;
        for class in classes {
            let mut c = BytesStart::borrowed(class_tag, class_tag.len());
            c.push_attribute(("name", class.name.as_ref()));
            c.push_attribute(("filename", class.file_name.as_ref()));
            c.push_attribute(("line-rate", class.line_rate.to_string().as_ref()));
            c.push_attribute(("branch-rate", class.branch_rate.to_string().as_ref()));
            c.push_attribute(("complexity", class.complexity.to_string().as_ref()));

            writer.write_event(Event::Start(c))?;
            writer.write_event(Event::Empty(BytesStart::borrowed(
                methods_tag,
                methods_tag.len(),
            )))?;
            self.export_lines(&class.lines, writer)?;
            writer.write_event(Event::End(BytesEnd::borrowed(class_tag)))?;
        }
        writer
            .write_event(Event::End(BytesEnd::borrowed(classes_tag)))
            .map(|_| ())
    }

    fn export_lines<T: Write>(
        &self,
        lines: &[Line],
        writer: &mut Writer<T>,
    ) -> Result<(), quick_xml::Error> {
        let lines_tag = b"lines";
        let line_tag = b"line";

        writer.write_event(Event::Start(BytesStart::borrowed(
            lines_tag,
            lines_tag.len(),
        )))?;
        for line in lines {
            let mut l = BytesStart::borrowed(line_tag, line_tag.len());
            match line {
                Line::Plain {
                    ref number,
                    ref hits,
                } => {
                    l.push_attribute(("number", number.to_string().as_ref()));
                    l.push_attribute(("hits", hits.to_string().as_ref()));
                }
                Line::Branch { .. } => {}
            }
            writer.write_event(Event::Empty(l))?;
        }
        writer
            .write_event(Event::End(BytesEnd::borrowed(lines_tag)))
            .map(|_| ())
    }
}

fn render_sources(config: &Config) -> Vec<PathBuf> {
    let render_source = |&x| Path::to_path_buf(x);

    config.manifest.parent().iter().map(render_source).collect()
}

#[derive(Debug)]
struct Package {
    name: String,
    line_rate: f64,
    branch_rate: f64,
    complexity: f64,
    classes: Vec<Class>,
}

fn render_packages(config: &Config, traces: &TraceMap) -> Vec<Package> {
    let mut dirs: Vec<&Path> = traces
        .files()
        .into_iter()
        .filter_map(|x| x.parent())
        .collect();

    dirs.dedup();

    dirs.into_iter()
        .map(|x| render_package(config, traces, x))
        .collect()
}

fn render_package(config: &Config, traces: &TraceMap, pkg: &Path) -> Package {
    let root = config.manifest.parent().unwrap_or(&config.manifest);
    let name = pkg
        .strip_prefix(root)
        .map(|x| Path::to_str(x))
        .unwrap_or_default()
        .unwrap_or_default();

    let line_cover = traces.covered_in_path(pkg) as f64;
    let line_rate = line_cover / (traces.coverable_in_path(pkg) as f64);

    Package {
        name: name.to_string(),
        line_rate: line_rate,
        branch_rate: 0.0,
        complexity: 0.0,
        classes: render_classes(config, traces, pkg),
    }
}

#[derive(Debug)]
struct Class {
    name: String,
    file_name: String,
    line_rate: f64,
    branch_rate: f64,
    complexity: f64,
    lines: Vec<Line>,
    methods: Vec<Method>,
}

fn render_classes(config: &Config, traces: &TraceMap, pkg: &Path) -> Vec<Class> {
    traces
        .files()
        .iter()
        .filter(|x| x.parent() == Some(pkg))
        .map(|x| render_class(config, traces, x))
        .collect()
}

// TODO: Cobertura distinguishes between lines outside methods, and methods
// (which also contain lines). As there is currently no way to get traces from
// a particular function only, all traces are put into lines, and the vector
// of methods is empty.
//
// Until this is fixed, the render_method function will panic if called, as it
// cannot be properly implemented.
//
fn render_class(config: &Config, traces: &TraceMap, file: &Path) -> Class {
    let root = config.manifest.parent().unwrap_or(&config.manifest);
    let name = file
        .file_stem()
        .map(|x| x.to_str().unwrap())
        .unwrap_or_default()
        .to_string();

    let file_name = file
        .strip_prefix(root)
        .unwrap_or(file)
        .to_str()
        .unwrap()
        .to_string();

    let covered = traces.covered_in_path(file) as f64;
    let line_rate = covered / traces.coverable_in_path(file) as f64;
    let lines = traces
        .get_child_traces(file)
        .iter()
        .map(|x| render_line(x))
        .collect();

    Class {
        name: name,
        file_name: file_name,
        line_rate: line_rate,
        branch_rate: 0.0,
        complexity: 0.0,
        lines: lines,
        methods: vec![],
    }
}

#[derive(Debug)]
struct Method {
    name: String,
    signature: String,
    line_rate: f64,
    branch_rate: f64,
    lines: Vec<Line>,
}

fn render_methods() -> Vec<Method> {
    unimplemented!()
}

fn render_method() -> Method {
    unimplemented!()
}

#[derive(Debug)]
enum Line {
    Plain {
        number: usize,
        hits: usize,
    },

    Branch {
        number: usize,
        hits: usize,
        conditions: Vec<Condition>,
    },
}

fn render_line(trace: &Trace) -> Line {
    match &trace.stats {
        CoverageStat::Line(hits) => Line::Plain {
            number: trace.line as usize,
            hits: *hits as usize,
        },

        // TODO: Branches in cobertura are given a fresh number as a label,
        // which would require having some form of context when rendering.
        //
        _ => panic!("Not currently supported"),
    }
}

#[derive(Debug)]
struct Condition {
    number: usize,
    cond_type: ConditionType,
    coverage: f64,
}

// Condition types
#[derive(Debug)]
enum ConditionType {
    Jump,
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate xml;

use std;
use std::io::Read;

pub struct Client {
    http_client: hyper::Client,
    server_uri: String,
}

impl Client {
    pub fn new(server_uri: &str) -> Client {
        Client {
            http_client: hyper::Client::new(),
            server_uri: server_uri.to_owned(),
        }
    }

    pub fn request(&self, function_name: &str, parameters: &[&str]) -> ClientResult {
        let mut body = Vec::<u8>::new();
        {
            let mut writer = xml::EventWriter::new(&mut body);
            try!(writer.write(xml::writer::XmlEvent::start_element("methodCall")));
            try!(writer.write(xml::writer::XmlEvent::start_element("methodName")));
            try!(writer.write(xml::writer::XmlEvent::characters(function_name)));
            try!(writer.write(xml::writer::XmlEvent::end_element()));
            try!(writer.write(xml::writer::XmlEvent::start_element("params")));
            for param in parameters {
                try!(writer.write(xml::writer::XmlEvent::start_element("value")));
                try!(writer.write(xml::writer::XmlEvent::start_element("string")));
                try!(writer.write(xml::writer::XmlEvent::characters(param)));
                try!(writer.write(xml::writer::XmlEvent::end_element()));
                try!(writer.write(xml::writer::XmlEvent::end_element()));
            }
            try!(writer.write(xml::writer::XmlEvent::end_element()));
            try!(writer.write(xml::writer::XmlEvent::end_element()));
        }

        let body = try!(String::from_utf8(body));
        let res = try!(self.http_client
            .post(&self.server_uri)
            .body(&body)
            .send());

        let xml_tree = try!(read_xml_tree(&mut xml::EventReader::new(res)).ok_or(Error::Parse));
        parse_xml_tree(&xml_tree).ok_or(Error::Parse)
    }
}

fn read_xml_tree<T: Read>(mut parser: &mut xml::EventReader<T>) -> Option<XmlTreeNode> {
    match parser.next() {
        Ok(xml::reader::XmlEvent::StartElement { name, .. }) => {
            let mut children = Vec::<XmlTreeNode>::new();
            while let Some(tree) = read_xml_tree(&mut parser) {
                children.push(tree);
            }
            Some(XmlTreeNode::Node(name.local_name, children))
        }
        Ok(xml::reader::XmlEvent::Characters(value)) => Some(XmlTreeNode::Leaf(value)),
        Ok(xml::reader::XmlEvent::EndElement { .. }) => None,
        Err(..) => None,
        _ => read_xml_tree(&mut parser),
    }
}

fn parse_xml_tree(tree: &XmlTreeNode) -> Option<Member> {
    if let Some(tree) = peel_xml_layer(&tree, "methodResponse") {
        if let Some(tree) = peel_xml_layer(&tree, "params") {
            if let Some(tree) = peel_xml_layer(&tree, "param") {
                return parse_xml_tree_helper(&tree);
            }
        }
    }
    None
}

fn parse_xml_tree_helper(tree: &XmlTreeNode) -> Option<Member> {
    if let Some(tree) = peel_xml_layer(&tree, "value") {
        if let XmlTreeNode::Node(ref name, ref children) = *tree {
            if children.len() == 1 {
                let child = &children[0];
                return match name.as_str() {
                    "array" => parse_xml_array(child),
                    "string" => parse_xml_string(child),
                    "int" | "i4" => parse_xml_int(child),
                    _ => None,
                };
            }
        }
    }
    None
}

fn parse_xml_array(tree: &XmlTreeNode) -> Option<Member> {
    if let XmlTreeNode::Node(ref name, ref children) = *tree {
        if name.as_str() == "data" {
            return Some(Member::Array(children.iter().filter_map(parse_xml_tree_helper).collect()));
        }
    }
    None
}

fn parse_xml_int(tree: &XmlTreeNode) -> Option<Member> {
    if let Some(Member::String(text)) = parse_xml_string(&tree) {
        if let Ok(value) = text.parse::<i32>() {
            return Some(Member::Int(value));
        }
    }
    None
}

fn parse_xml_string(tree: &XmlTreeNode) -> Option<Member> {
    if let XmlTreeNode::Leaf(ref value) = *tree {
        return Some(Member::String(value.clone()));
    }
    None
}

fn peel_xml_layer<'a>(tree: &'a XmlTreeNode, node_name: &str) -> Option<&'a XmlTreeNode> {
    if let XmlTreeNode::Node(ref name, ref children) = *tree {
        if name.as_str() == node_name && children.len() == 1 {
            return Some(&children[0]);
        }
    }
    None
}

enum XmlTreeNode {
    Leaf(String),
    Node(String, Vec<XmlTreeNode>),
}

pub enum Member {
    Array(Vec<Member>),
    String(String),
    Int(i32),
}

pub type ClientResult = Result<Member, Error>;

#[derive(Debug)]
pub enum Error {
    Io(std::io::Error),
    Http(hyper::error::Error),
    Utf8(std::string::FromUtf8Error),
    XmlWrite(xml::writer::Error),
    XmlRead(xml::reader::Error),
    Parse,
}

impl From<std::io::Error> for Error {
    fn from(err: std::io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<hyper::error::Error> for Error {
    fn from(err: hyper::error::Error) -> Error {
        match err {
            hyper::error::Error::Io(err) => Error::Io(err),
            _ => Error::Http(err),
        }
    }
}

impl From<std::string::FromUtf8Error> for Error {
    fn from(err: std::string::FromUtf8Error) -> Error {
        Error::Utf8(err)
    }
}

impl From<xml::writer::Error> for Error {
    fn from(err: xml::writer::Error) -> Error {
        match err {
            xml::writer::Error::Io(err) => Error::Io(err),
            _ => Error::XmlWrite(err),
        }
    }
}

impl From<xml::reader::Error> for Error {
    fn from(err: xml::reader::Error) -> Error {
        Error::XmlRead(err)
    }
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match *self {
            Error::Io(ref err) => write!(f, "IO error: {}", err),
            Error::Http(ref err) => write!(f, "HTTP error: {}", err),
            Error::Utf8(ref err) => write!(f, "UTF8 error: {}", err),
            Error::XmlWrite(ref err) => write!(f, "XML writing error: {}", err),
            Error::XmlRead(ref err) => write!(f, "XML reading error: {}", err),
            Error::Parse => write!(f, "XMLRPC response parsing error"),
        }
    }
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Io(ref err) => err.description(),
            Error::Http(ref err) => err.description(),
            Error::Utf8(ref err) => err.description(),
            Error::XmlWrite(..) => "Descriptions not implemented for xml::writer::Error",
            Error::XmlRead(ref err) => err.description(),
            Error::Parse => "Could not parse XMLRPC response",
        }
    }

    fn cause(&self) -> Option<&std::error::Error> {
        match *self {
            Error::Io(ref err) => Some(err),
            Error::Http(ref err) => Some(err),
            Error::Utf8(ref err) => Some(err),
            Error::XmlWrite(..) => None,
            Error::XmlRead(ref err) => Some(err),
            Error::Parse => None,
        }
    }
}
<commit_msg>Remove chained referencing<commit_after>extern crate hyper;
extern crate xml;

use std;
use std::io::Read;

pub struct Client {
    http_client: hyper::Client,
    server_uri: String,
}

impl Client {
    pub fn new(server_uri: &str) -> Client {
        Client {
            http_client: hyper::Client::new(),
            server_uri: server_uri.to_owned(),
        }
    }

    pub fn request(&self, function_name: &str, parameters: &[&str]) -> ClientResult {
        let mut body = Vec::<u8>::new();
        {
            let mut writer = xml::EventWriter::new(&mut body);
            try!(writer.write(xml::writer::XmlEvent::start_element("methodCall")));
            try!(writer.write(xml::writer::XmlEvent::start_element("methodName")));
            try!(writer.write(xml::writer::XmlEvent::characters(function_name)));
            try!(writer.write(xml::writer::XmlEvent::end_element()));
            try!(writer.write(xml::writer::XmlEvent::start_element("params")));
            for param in parameters {
                try!(writer.write(xml::writer::XmlEvent::start_element("value")));
                try!(writer.write(xml::writer::XmlEvent::start_element("string")));
                try!(writer.write(xml::writer::XmlEvent::characters(param)));
                try!(writer.write(xml::writer::XmlEvent::end_element()));
                try!(writer.write(xml::writer::XmlEvent::end_element()));
            }
            try!(writer.write(xml::writer::XmlEvent::end_element()));
            try!(writer.write(xml::writer::XmlEvent::end_element()));
        }

        let body = try!(String::from_utf8(body));
        let res = try!(self.http_client
            .post(&self.server_uri)
            .body(&body)
            .send());

        let xml_tree = try!(read_xml_tree(&mut xml::EventReader::new(res)).ok_or(Error::Parse));
        parse_xml_tree(&xml_tree).ok_or(Error::Parse)
    }
}

fn read_xml_tree<T: Read>(parser: &mut xml::EventReader<T>) -> Option<XmlTreeNode> {
    match parser.next() {
        Ok(xml::reader::XmlEvent::StartElement { name, .. }) => {
            let mut children = Vec::<XmlTreeNode>::new();
            while let Some(tree) = read_xml_tree(parser) {
                children.push(tree);
            }
            Some(XmlTreeNode::Node(name.local_name, children))
        }
        Ok(xml::reader::XmlEvent::Characters(value)) => Some(XmlTreeNode::Leaf(value)),
        Ok(xml::reader::XmlEvent::EndElement { .. }) => None,
        Err(..) => None,
        _ => read_xml_tree(parser),
    }
}

fn parse_xml_tree(tree: &XmlTreeNode) -> Option<Member> {
    if let Some(tree) = peel_xml_layer(tree, "methodResponse") {
        if let Some(tree) = peel_xml_layer(tree, "params") {
            if let Some(tree) = peel_xml_layer(tree, "param") {
                return parse_xml_tree_helper(tree);
            }
        }
    }
    None
}

fn parse_xml_tree_helper(tree: &XmlTreeNode) -> Option<Member> {
    if let Some(tree) = peel_xml_layer(tree, "value") {
        if let XmlTreeNode::Node(ref name, ref children) = *tree {
            if children.len() == 1 {
                let child = &children[0];
                return match name.as_str() {
                    "array" => parse_xml_array(child),
                    "string" => parse_xml_string(child),
                    "int" | "i4" => parse_xml_int(child),
                    _ => None,
                };
            }
        }
    }
    None
}

fn parse_xml_array(tree: &XmlTreeNode) -> Option<Member> {
    if let XmlTreeNode::Node(ref name, ref children) = *tree {
        if name.as_str() == "data" {
            return Some(Member::Array(children.iter().filter_map(parse_xml_tree_helper).collect()));
        }
    }
    None
}

fn parse_xml_int(tree: &XmlTreeNode) -> Option<Member> {
    if let Some(Member::String(text)) = parse_xml_string(tree) {
        if let Ok(value) = text.parse::<i32>() {
            return Some(Member::Int(value));
        }
    }
    None
}

fn parse_xml_string(tree: &XmlTreeNode) -> Option<Member> {
    if let XmlTreeNode::Leaf(ref value) = *tree {
        return Some(Member::String(value.clone()));
    }
    None
}

fn peel_xml_layer<'a>(tree: &'a XmlTreeNode, node_name: &str) -> Option<&'a XmlTreeNode> {
    if let XmlTreeNode::Node(ref name, ref children) = *tree {
        if name.as_str() == node_name && children.len() == 1 {
            return Some(&children[0]);
        }
    }
    None
}

enum XmlTreeNode {
    Leaf(String),
    Node(String, Vec<XmlTreeNode>),
}

pub enum Member {
    Array(Vec<Member>),
    String(String),
    Int(i32),
}

pub type ClientResult = Result<Member, Error>;

#[derive(Debug)]
pub enum Error {
    Io(std::io::Error),
    Http(hyper::error::Error),
    Utf8(std::string::FromUtf8Error),
    XmlWrite(xml::writer::Error),
    XmlRead(xml::reader::Error),
    Parse,
}

impl From<std::io::Error> for Error {
    fn from(err: std::io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<hyper::error::Error> for Error {
    fn from(err: hyper::error::Error) -> Error {
        match err {
            hyper::error::Error::Io(err) => Error::Io(err),
            _ => Error::Http(err),
        }
    }
}

impl From<std::string::FromUtf8Error> for Error {
    fn from(err: std::string::FromUtf8Error) -> Error {
        Error::Utf8(err)
    }
}

impl From<xml::writer::Error> for Error {
    fn from(err: xml::writer::Error) -> Error {
        match err {
            xml::writer::Error::Io(err) => Error::Io(err),
            _ => Error::XmlWrite(err),
        }
    }
}

impl From<xml::reader::Error> for Error {
    fn from(err: xml::reader::Error) -> Error {
        Error::XmlRead(err)
    }
}

impl std::fmt::Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match *self {
            Error::Io(ref err) => write!(f, "IO error: {}", err),
            Error::Http(ref err) => write!(f, "HTTP error: {}", err),
            Error::Utf8(ref err) => write!(f, "UTF8 error: {}", err),
            Error::XmlWrite(ref err) => write!(f, "XML writing error: {}", err),
            Error::XmlRead(ref err) => write!(f, "XML reading error: {}", err),
            Error::Parse => write!(f, "XMLRPC response parsing error"),
        }
    }
}

impl std::error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Io(ref err) => err.description(),
            Error::Http(ref err) => err.description(),
            Error::Utf8(ref err) => err.description(),
            Error::XmlWrite(..) => "Descriptions not implemented for xml::writer::Error",
            Error::XmlRead(ref err) => err.description(),
            Error::Parse => "Could not parse XMLRPC response",
        }
    }

    fn cause(&self) -> Option<&std::error::Error> {
        match *self {
            Error::Io(ref err) => Some(err),
            Error::Http(ref err) => Some(err),
            Error::Utf8(ref err) => Some(err),
            Error::XmlWrite(..) => None,
            Error::XmlRead(ref err) => Some(err),
            Error::Parse => None,
        }
    }
}
<|endoftext|>


<commit_before>//! Wallet.

use exonum::messages::Field;
use exonum::crypto::{PublicKey, Hash};

storage_value! {
/// Wallet information stored in the database.
    struct Wallet {
        const SIZE = 88;

        field pub_key:            &PublicKey  [00 => 32]
        field name:               &str        [32 => 40]
        field balance:            u64         [40 => 48]
        field history_len:        u64         [48 => 56]
        field history_hash:       &Hash       [56 => 88]
    }
}

impl Wallet {
    /// Overwrites balance.
    pub fn set_balance(&mut self, balance: u64) {
        Field::write(&balance, &mut self.raw, 40, 48);
    }

    /// Sets history hash.
    pub fn grow_length_set_history_hash(&mut self, hash: &Hash) {
        Field::write(&hash, &mut self.raw, 56, 88);
        Field::write(&(self.history_len() + 1), &mut self.raw, 48, 56);
    }

    /// Transfers currency from this wallet to `other`. Returns `false` if `self.balance()` is
    /// less then `amount`.
    pub fn transfer_to(&mut self, other: &mut Wallet, amount: u64) -> bool {
        if self.balance() < amount {
            return false;
        }

        let self_amount = self.balance() - amount;
        let other_amount = other.balance() + amount;
        self.set_balance(self_amount);
        other.set_balance(other_amount);
        true
    }
}

#[cfg(test)]
pub fn assert_wallet(wallet: &Wallet,
                     pub_key: &PublicKey,
                     name: &str,
                     balance: u64,
                     history_len: u64,
                     history_hash: &Hash) {
    assert_eq!(wallet.pub_key(), pub_key);
    assert_eq!(wallet.name(), name);
    assert_eq!(wallet.balance(), balance);
    assert_eq!(wallet.history_hash(), history_hash);
    assert_eq!(wallet.history_len(), history_len);
}

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

    #[test]
    fn test_wallet() {
        let hash = Hash::new([2; 32]);
        let name = "foobar abacaba Юникод всяуи";
        let pub_key = PublicKey::from_slice([1u8; 32].as_ref()).unwrap();
        let wallet = Wallet::new(&pub_key, name, 100500, 0, &hash);

        let wallet = wallet.clone();
        assert_wallet(&wallet, &pub_key, name, 100500, 0, &hash);
    }

    #[test]
    fn test_wallet_serde() {
        use serde_json;
        use rand::{thread_rng, Rng};
        use exonum::crypto::{HASH_SIZE, gen_keypair};

        let mut rng = thread_rng();
        let generator = move |_| {
            let string_len = rng.gen_range(20u8, 255u8);
            let mut hash_bytes = [0; HASH_SIZE];

            let (pub_key, _) = gen_keypair();
            let name: String = rng.gen_ascii_chars().take(string_len as usize).collect();
            let balance = rng.next_u64();
            let history_len = rng.next_u64();
            rng.fill_bytes(&mut hash_bytes);
            let hash = Hash::new(hash_bytes);
            Wallet::new(&pub_key, &name, balance, history_len, &hash)
        };
        let wallet_non_ascii = Wallet::new(&gen_keypair().0,
                                           "foobar abacaba Юникод всяуи",
                                           100500,
                                           0,
                                           &Hash::new([2; HASH_SIZE]));
        let mut wallets = (0..50).map(generator).collect::<Vec<_>>();
        wallets.push(wallet_non_ascii);
        for wallet in wallets {
            let json_str = serde_json::to_string(&wallet).unwrap();
            let wallet1: Wallet = serde_json::from_str(&json_str).unwrap();
            assert_eq!(wallet, wallet1);
            println!("wallet test data: {}",
                     serde_json::to_string(&WalletTestData::new(wallet)).unwrap());
        }
    }

    #[test]
    fn test_amount_transfer() {
        let hash = Hash::new([5; 32]);
        let pub_key = PublicKey::from_slice([1u8; 32].as_ref()).unwrap();
        let mut a = Wallet::new(&pub_key, "a", 100, 12, &hash);
        let mut b = Wallet::new(&pub_key, "b", 0, 14, &hash);
        a.transfer_to(&mut b, 50);
        a.grow_length_set_history_hash(&hash);
        b.grow_length_set_history_hash(&hash);
        assert_eq!(a.balance(), 50);
        assert_eq!(a.history_len(), 13);
        assert_eq!(b.balance(), 50);
        assert_eq!(b.history_len(), 15);
    }

    #[derive(Serialize)]
    struct WalletTestData {
        wallet: Wallet,
        hash: Hash,
        raw: Vec<u8>,
    }

    impl WalletTestData {
        fn new(wallet: Wallet) -> WalletTestData {
            let wallet_hash = wallet.hash();
            let raw = StorageValue::serialize(wallet.clone());
            WalletTestData {
                wallet: wallet,
                hash: wallet_hash,
                raw: raw,
            }
        }
    }
}
<commit_msg>Add check to prevent transfer to the same wallet<commit_after>//! Wallet.

use exonum::messages::Field;
use exonum::crypto::{PublicKey, Hash};

storage_value! {
/// Wallet information stored in the database.
    struct Wallet {
        const SIZE = 88;

        field pub_key:            &PublicKey  [00 => 32]
        field name:               &str        [32 => 40]
        field balance:            u64         [40 => 48]
        field history_len:        u64         [48 => 56]
        field history_hash:       &Hash       [56 => 88]
    }
}

impl Wallet {
    /// Overwrites balance.
    pub fn set_balance(&mut self, balance: u64) {
        Field::write(&balance, &mut self.raw, 40, 48);
    }

    /// Sets history hash.
    pub fn grow_length_set_history_hash(&mut self, hash: &Hash) {
        Field::write(&hash, &mut self.raw, 56, 88);
        Field::write(&(self.history_len() + 1), &mut self.raw, 48, 56);
    }

    /// Transfers currency from this wallet to `other`. Returns `false` if `self.balance()` is
    /// less then `amount`.
    pub fn transfer_to(&mut self, other: &mut Wallet, amount: u64) -> bool {
        if self.pub_key() == other.pub_key() {
            return false;
        }

        if self.balance() < amount {
            return false;
        }

        let self_amount = self.balance() - amount;
        let other_amount = other.balance() + amount;
        self.set_balance(self_amount);
        other.set_balance(other_amount);
        true
    }
}

#[cfg(test)]
pub fn assert_wallet(wallet: &Wallet,
                     pub_key: &PublicKey,
                     name: &str,
                     balance: u64,
                     history_len: u64,
                     history_hash: &Hash) {
    assert_eq!(wallet.pub_key(), pub_key);
    assert_eq!(wallet.name(), name);
    assert_eq!(wallet.balance(), balance);
    assert_eq!(wallet.history_hash(), history_hash);
    assert_eq!(wallet.history_len(), history_len);
}

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

    #[test]
    fn test_wallet() {
        let hash = Hash::new([2; 32]);
        let name = "foobar abacaba Юникод всяуи";
        let pub_key = PublicKey::from_slice([1u8; 32].as_ref()).unwrap();
        let wallet = Wallet::new(&pub_key, name, 100500, 0, &hash);

        let wallet = wallet.clone();
        assert_wallet(&wallet, &pub_key, name, 100500, 0, &hash);
    }

    #[test]
    fn test_wallet_serde() {
        use serde_json;
        use rand::{thread_rng, Rng};
        use exonum::crypto::{HASH_SIZE, gen_keypair};

        let mut rng = thread_rng();
        let generator = move |_| {
            let string_len = rng.gen_range(20u8, 255u8);
            let mut hash_bytes = [0; HASH_SIZE];

            let (pub_key, _) = gen_keypair();
            let name: String = rng.gen_ascii_chars().take(string_len as usize).collect();
            let balance = rng.next_u64();
            let history_len = rng.next_u64();
            rng.fill_bytes(&mut hash_bytes);
            let hash = Hash::new(hash_bytes);
            Wallet::new(&pub_key, &name, balance, history_len, &hash)
        };
        let wallet_non_ascii = Wallet::new(&gen_keypair().0,
                                           "foobar abacaba Юникод всяуи",
                                           100500,
                                           0,
                                           &Hash::new([2; HASH_SIZE]));
        let mut wallets = (0..50).map(generator).collect::<Vec<_>>();
        wallets.push(wallet_non_ascii);
        for wallet in wallets {
            let json_str = serde_json::to_string(&wallet).unwrap();
            let wallet1: Wallet = serde_json::from_str(&json_str).unwrap();
            assert_eq!(wallet, wallet1);
            println!("wallet test data: {}",
                     serde_json::to_string(&WalletTestData::new(wallet)).unwrap());
        }
    }

    #[test]
    fn test_amount_transfer() {
        let hash = Hash::new([5; 32]);
        let pub_key_1 = PublicKey::from_slice([1u8; 32].as_ref()).unwrap();
        let pub_key_2 = PublicKey::from_slice([2u8; 32].as_ref()).unwrap();
        let mut a = Wallet::new(&pub_key_1, "a", 100, 12, &hash);
        let mut b = Wallet::new(&pub_key_2, "b", 0, 14, &hash);
        a.transfer_to(&mut b, 50);
        a.grow_length_set_history_hash(&hash);
        b.grow_length_set_history_hash(&hash);
        assert_eq!(a.balance(), 50);
        assert_eq!(a.history_len(), 13);
        assert_eq!(b.balance(), 50);
        assert_eq!(b.history_len(), 15);
    }

    #[derive(Serialize)]
    struct WalletTestData {
        wallet: Wallet,
        hash: Hash,
        raw: Vec<u8>,
    }

    impl WalletTestData {
        fn new(wallet: Wallet) -> WalletTestData {
            let wallet_hash = wallet.hash();
            let raw = StorageValue::serialize(wallet.clone());
            WalletTestData {
                wallet: wallet,
                hash: wallet_hash,
                raw: raw,
            }
        }
    }
}
<|endoftext|>


<commit_before>#![feature(globs)]

extern crate piston;

extern crate hgl;
extern crate gl;
extern crate sdl2_game_window;

use sdl2_game_window::GameWindowSDL2;
use piston::{
    Game,
    GameIteratorSettings,
    GameWindowSettings,
    RenderArgs
};

use std::mem::size_of;
use hgl::{Shader, Program, Triangles, Vbo, Vao};

#[allow(dead_code)]
pub struct App {
    program: Program,
    vao: Vao,
    vbo: Vbo
}

static VERTEX_SHADER: &'static str = r"
    attribute vec2 position;

    void main() {
        gl_Position = vec4(position, 0.0, 1.0);
    }
";

static FRAGMENT_SHADER: &'static str = r"
    void main() {
        gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
    }
";

impl App {
    /// Creates a new application.
    pub fn new() -> App {
        let vao = Vao::new();
        vao.bind();

        let program = Program::link([Shader::compile(VERTEX_SHADER, hgl::VertexShader).unwrap(),
        Shader::compile(FRAGMENT_SHADER, hgl::FragmentShader).unwrap()]).unwrap();
        program.bind();

        let vbo = Vbo::from_data([
            0.0f32, 0.5, 1.0, 0.0, 0.0,
            0.5,   -0.5, 0.0, 1.0, 0.0,
            -0.5,  -0.5, 0.0, 0.0, 1.0
        ], hgl::StaticDraw);

        vao.enable_attrib(&program, "position", gl::FLOAT, 2, 5*size_of::<f32>() as i32, 0);
        vao.enable_attrib(&program, "color", gl::FLOAT, 3, 5*size_of::<f32>() as i32, 2*size_of::<f32>());
        vbo.bind();

        App {
            program: program,
            vao: vao,
            vbo: vbo
        }
    }
}

impl Game for App {
    fn render(&mut self, args: &mut RenderArgs) {
        gl::Viewport(0, 0, args.width as i32, args.height as i32);
        gl::ClearColor(0.0, 0.0, 0.0, 0.1);
        gl::Clear(gl::COLOR_BUFFER_BIT);
        self.vao.draw_array(Triangles, 0, 3);
    }
}

fn main() {
    let mut window = GameWindowSDL2::new(
        GameWindowSettings {
            title: "Test".to_string(),
            size: [800, 600],
            fullscreen: false,
            exit_on_esc: true
        }
    );

    let game_iter_settings = GameIteratorSettings {
            updates_per_second: 120,
            max_frames_per_second: 60,
        };
    App::new().run(&mut window, &game_iter_settings);
}

<commit_msg>Upgraded example to latest hgl-rs<commit_after>#![feature(globs)]

extern crate piston;

extern crate hgl;
extern crate gl;
extern crate sdl2_game_window;

use sdl2_game_window::GameWindowSDL2;
use piston::{
    Game,
    GameIteratorSettings,
    GameWindowSettings,
    RenderArgs
};

use std::mem::size_of;
use hgl::{Shader, Program, Triangles, Vbo, Vao};

#[allow(dead_code)]
pub struct App {
    program: Program,
    vao: Vao,
    vbo: Vbo
}

static VERTEX_SHADER: &'static str = r"
    attribute vec2 position;

    void main() {
        gl_Position = vec4(position, 0.0, 1.0);
    }
";

static FRAGMENT_SHADER: &'static str = r"
    void main() {
        gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
    }
";

impl App {
    /// Creates a new application.
    pub fn new() -> App {
        let vao = Vao::new();
        vao.bind();

        let program = Program::link([Shader::compile(VERTEX_SHADER, hgl::VertexShader),
        Shader::compile(FRAGMENT_SHADER, hgl::FragmentShader)]).unwrap();
        program.bind();

        let vbo = Vbo::from_data([
            0.0f32, 0.5, 1.0, 0.0, 0.0,
            0.5,   -0.5, 0.0, 1.0, 0.0,
            -0.5,  -0.5, 0.0, 0.0, 1.0
        ], hgl::StaticDraw);

        vao.enable_attrib(&program, "position", gl::FLOAT, 2, 5*size_of::<f32>() as i32, 0);
        vao.enable_attrib(&program, "color", gl::FLOAT, 3, 5*size_of::<f32>() as i32, 2*size_of::<f32>());
        vbo.bind();

        App {
            program: program,
            vao: vao,
            vbo: vbo
        }
    }
}

impl Game for App {
    fn render(&mut self, args: &mut RenderArgs) {
        gl::Viewport(0, 0, args.width as i32, args.height as i32);
        gl::ClearColor(0.0, 0.0, 0.0, 0.1);
        gl::Clear(gl::COLOR_BUFFER_BIT);
        self.vao.draw_array(Triangles, 0, 3);
    }
}

fn main() {
    let mut window = GameWindowSDL2::new(
        GameWindowSettings {
            title: "Test".to_string(),
            size: [800, 600],
            fullscreen: false,
            exit_on_esc: true
        }
    );

    let game_iter_settings = GameIteratorSettings {
            updates_per_second: 120,
            max_frames_per_second: 60,
        };
    App::new().run(&mut window, &game_iter_settings);
}

<|endoftext|>


<commit_before>/*
 * Copyright 2017 Ben Ashford
 *
 * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 * http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
 * <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 * option. This file may not be copied, modified, or distributed
 * except according to those terms.
 */

#![feature(test)]

extern crate test;

extern crate futures;
extern crate tokio_core;
extern crate redis_async;

use std::sync::Arc;

use test::Bencher;

use futures::Future;

use tokio_core::reactor::Core;

use redis_async::client;

#[bench]
fn bench_simple_getsetdel(b: &mut Bencher) {
    let mut core = Core::new().unwrap();
    let addr = "127.0.0.1:6379".parse().unwrap();

    let connection = client::paired_connect(&addr, &core.handle());
    let connection = core.run(connection).unwrap();

    b.iter(|| {
               let set = connection.send(["SET", "test_key", "42"].as_ref());
               let get = connection.send(["GET", "test_key"].as_ref());
               let del = connection.send(["DEL", "test_key"].as_ref());
               let get_set = get.join(del);
               let (_, _) = core.run(get_set).unwrap();
           });
}

#[bench]
fn bench_big_pipeline(b: &mut Bencher) {
    let mut core = Core::new().unwrap();
    let addr = "127.0.0.1:6379".parse().unwrap();

    let connection = client::paired_connect(&addr, &core.handle());
    let connection = core.run(connection).unwrap();

    let data_size = 100;

    b.iter(|| {
        for x in 0..data_size {
            let test_key = format!("test_{}", x);
            connection.send(["SET", &test_key, &x.to_string()].as_ref());
        }
        let mut gets = Vec::with_capacity(data_size);
        for x in 0..data_size {
            let test_key = format!("test_{}", x);
            gets.push(connection.send(["GET", &test_key].as_ref()));
        }
        let last_get = gets.remove(data_size - 1);
        let _ = core.run(last_get);
    });
}

#[bench]
fn bench_complex_pipeline(b: &mut Bencher) {
    let mut core = Core::new().unwrap();
    let addr = "127.0.0.1:6379".parse().unwrap();

    let connection = client::paired_connect(&addr, &core.handle());
    let connection = Arc::new(core.run(connection).unwrap());

    let data_size = 100;

    b.iter(|| {
        let sets = (0..data_size).map(|x| {
            let connection_inner = connection.clone();
            connection
                .send(["INCR", "id_gen"].as_ref())
                .and_then(move |id| {
                              let id = format!("id_{}", id.into_string().unwrap());
                              connection_inner.send(["SET", &id, &x.to_string()].as_ref())
                          })
        });
        let all_sets = futures::future::join_all(sets);
        let _ = core.run(all_sets);
    });
}<commit_msg>Update benchmarks<commit_after>/*
 * Copyright 2017 Ben Ashford
 *
 * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 * http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
 * <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 * option. This file may not be copied, modified, or distributed
 * except according to those terms.
 */

#![feature(test)]

extern crate test;

extern crate futures;
extern crate tokio_core;
extern crate redis_async;

use std::sync::Arc;

use test::Bencher;

use futures::Future;

use tokio_core::reactor::Core;

use redis_async::client;

#[bench]
fn bench_simple_getsetdel(b: &mut Bencher) {
    let mut core = Core::new().unwrap();
    let addr = "127.0.0.1:6379".parse().unwrap();

    let connection = client::paired_connect(&addr, &core.handle());
    let connection = core.run(connection).unwrap();

    b.iter(|| {
               connection.send_and_forget(["SET", "test_key", "42"].as_ref());
               let get = connection.send(["GET", "test_key"].as_ref());
               let del = connection.send(["DEL", "test_key"].as_ref());
               let get_set = get.join(del);
               let (_, _): (String, String) = core.run(get_set).unwrap();
           });
}

#[bench]
fn bench_big_pipeline(b: &mut Bencher) {
    let mut core = Core::new().unwrap();
    let addr = "127.0.0.1:6379".parse().unwrap();

    let connection = client::paired_connect(&addr, &core.handle());
    let connection = core.run(connection).unwrap();

    let data_size = 100;

    b.iter(|| {
        for x in 0..data_size {
            let test_key = format!("test_{}", x);
            connection.send_and_forget(["SET", &test_key, &x.to_string()].as_ref());
        }
        let mut gets = Vec::with_capacity(data_size);
        for x in 0..data_size {
            let test_key = format!("test_{}", x);
            gets.push(connection.send(["GET", &test_key].as_ref()));
        }
        let last_get = gets.remove(data_size - 1);
        let _:String = core.run(last_get).unwrap();
    });
}

#[bench]
fn bench_complex_pipeline(b: &mut Bencher) {
    let mut core = Core::new().unwrap();
    let addr = "127.0.0.1:6379".parse().unwrap();

    let connection = client::paired_connect(&addr, &core.handle());
    let connection = Arc::new(core.run(connection).unwrap());

    let data_size = 100;

    b.iter(|| {
        let sets = (0..data_size).map(|x| {
            let connection_inner = connection.clone();
            connection
                .send(["INCR", "id_gen"].as_ref())
                .and_then(move |id: String| {
                              let id = format!("id_{}", id);
                              connection_inner.send(["SET", &id, &x.to_string()].as_ref())
                          })
        });
        let all_sets = futures::future::join_all(sets);
        let _:Vec<String> = core.run(all_sets).unwrap();
    });
}<|endoftext|>