<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::activation::Activatable;
use dom::attr::Attr;
use dom::bindings::codegen::Bindings::HTMLButtonElementBinding;
use dom::bindings::codegen::Bindings::HTMLButtonElementBinding::HTMLButtonElementMethods;
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLButtonElementCast, HTMLElementCast};
use dom::bindings::codegen::InheritTypes::{HTMLFieldSetElementDerived, NodeCast};
use dom::bindings::js::Root;
use dom::document::Document;
use dom::element::{AttributeMutation, Element, IN_ENABLED_STATE};
use dom::event::Event;
use dom::eventtarget::EventTarget;
use dom::htmlelement::HTMLElement;
use dom::htmlformelement::{FormControl, FormSubmitter};
use dom::htmlformelement::{SubmittedFrom, HTMLFormElement};
use dom::node::{Node, document_from_node, window_from_node};
use dom::validitystate::ValidityState;
use dom::virtualmethods::VirtualMethods;
use std::ascii::AsciiExt;
use std::borrow::ToOwned;
use std::cell::Cell;
use util::str::DOMString;

#[derive(JSTraceable, PartialEq, Copy, Clone)]
#[allow(dead_code)]
#[derive(HeapSizeOf)]
enum ButtonType {
    ButtonSubmit,
    ButtonReset,
    ButtonButton,
    ButtonMenu
}

#[dom_struct]
pub struct HTMLButtonElement {
    htmlelement: HTMLElement,
    button_type: Cell<ButtonType>
}

impl HTMLButtonElement {
    fn new_inherited(localName: DOMString,
                     prefix: Option<DOMString>,
                     document: &Document) -> HTMLButtonElement {
        HTMLButtonElement {
            htmlelement:
                HTMLElement::new_inherited_with_state(IN_ENABLED_STATE,
                                                      localName, prefix, document),
            //TODO: implement button_type in attribute_mutated
            button_type: Cell::new(ButtonType::ButtonSubmit)
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(localName: DOMString,
               prefix: Option<DOMString>,
               document: &Document) -> Root<HTMLButtonElement> {
        let element = HTMLButtonElement::new_inherited(localName, prefix, document);
        Node::reflect_node(box element, document, HTMLButtonElementBinding::Wrap)
    }
}

impl HTMLButtonElementMethods for HTMLButtonElement {
    // https://html.spec.whatwg.org/multipage/#dom-cva-validity
    fn Validity(&self) -> Root<ValidityState> {
        let window = window_from_node(self);
        ValidityState::new(window.r())
    }

    // https://html.spec.whatwg.org/multipage/#dom-fe-disabled
    make_bool_getter!(Disabled);

    // https://html.spec.whatwg.org/multipage/#dom-fe-disabled
    make_bool_setter!(SetDisabled, "disabled");

    // https://html.spec.whatwg.org/multipage/#dom-fae-form
    fn GetForm(&self) -> Option<Root<HTMLFormElement>> {
        self.form_owner()
    }

    // https://html.spec.whatwg.org/multipage/#dom-button-type
    fn Type(&self) -> DOMString {
        let elem = ElementCast::from_ref(self);
        let mut ty = elem.get_string_attribute(&atom!("type"));
        ty.make_ascii_lowercase();
        // https://html.spec.whatwg.org/multipage/#attr-button-type
        match &*ty {
            "reset" | "button" | "menu" => ty,
            _ => "submit".to_owned()
        }
    }

    // https://html.spec.whatwg.org/multipage/#dom-button-type
    make_setter!(SetType, "type");

    // https://html.spec.whatwg.org/multipage/#dom-fs-formaction
    make_url_or_base_getter!(FormAction);

    // https://html.spec.whatwg.org/multipage/#dom-fs-formaction
    make_setter!(SetFormAction, "formaction");

    // https://html.spec.whatwg.org/multipage/#dom-fs-formenctype
    make_enumerated_getter!(
        FormEnctype, "application/x-www-form-urlencoded", ("text/plain") | ("multipart/form-data"));

    // https://html.spec.whatwg.org/multipage/#dom-fs-formenctype
    make_setter!(SetFormEnctype, "formenctype");

    // https://html.spec.whatwg.org/multipage/#dom-fs-formmethod
    make_enumerated_getter!(FormMethod, "get", ("post") | ("dialog"));

    // https://html.spec.whatwg.org/multipage/#dom-fs-formmethod
    make_setter!(SetFormMethod, "formmethod");

    // https://html.spec.whatwg.org/multipage/#dom-fs-formtarget
    make_getter!(FormTarget);

    // https://html.spec.whatwg.org/multipage/#dom-fs-formtarget
    make_setter!(SetFormTarget, "formtarget");

    // https://html.spec.whatwg.org/multipage/#dom-fe-name
    make_getter!(Name);

    // https://html.spec.whatwg.org/multipage/#dom-fe-name
    make_setter!(SetName, "name");

    // https://html.spec.whatwg.org/multipage/#dom-button-value
    make_getter!(Value);

    // https://html.spec.whatwg.org/multipage/#dom-button-value
    make_setter!(SetValue, "value");
}

impl VirtualMethods for HTMLButtonElement {
    fn super_type(&self) -> Option<&VirtualMethods> {
        let htmlelement: &HTMLElement = HTMLElementCast::from_ref(self);
        Some(htmlelement as &VirtualMethods)
    }

    fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
        self.super_type().unwrap().attribute_mutated(attr, mutation);
        match attr.local_name() {
            &atom!(disabled) => {
                let el = ElementCast::from_ref(self);
                match mutation {
                    AttributeMutation::Set(Some(_)) => {}
                    AttributeMutation::Set(None) => {
                        el.set_disabled_state(true);
                        el.set_enabled_state(false);
                    },
                    AttributeMutation::Removed => {
                        el.set_disabled_state(false);
                        el.set_enabled_state(true);
                        el.check_ancestors_disabled_state_for_form_control();
                    }
                }
            },
            _ => {},
        }
    }

    fn bind_to_tree(&self, tree_in_doc: bool) {
        if let Some(ref s) = self.super_type() {
            s.bind_to_tree(tree_in_doc);
        }

        let el = ElementCast::from_ref(self);
        el.check_ancestors_disabled_state_for_form_control();
    }

    fn unbind_from_tree(&self, tree_in_doc: bool) {
        if let Some(ref s) = self.super_type() {
            s.unbind_from_tree(tree_in_doc);
        }

        let node = NodeCast::from_ref(self);
        let el = ElementCast::from_ref(self);
        if node.ancestors().any(|ancestor| ancestor.r().is_htmlfieldsetelement()) {
            el.check_ancestors_disabled_state_for_form_control();
        } else {
            el.check_disabled_attribute();
        }
    }
}

impl FormControl for HTMLButtonElement {}

impl<'a> Activatable for &'a HTMLButtonElement {
    fn as_element(&self) -> &Element {
        ElementCast::from_ref(*self)
    }

    fn is_instance_activatable(&self) -> bool {
        //https://html.spec.whatwg.org/multipage/#the-button-element
        let el = ElementCast::from_ref(*self);
        !(el.get_disabled_state())
    }

    // https://html.spec.whatwg.org/multipage/#run-pre-click-activation-steps
    // https://html.spec.whatwg.org/multipage/#the-button-element:activation-behavior
    fn pre_click_activation(&self) {
    }

    // https://html.spec.whatwg.org/multipage/#run-canceled-activation-steps
    fn canceled_activation(&self) {
    }

    // https://html.spec.whatwg.org/multipage/#run-post-click-activation-steps
    fn activation_behavior(&self, _event: &Event, _target: &EventTarget) {
        let ty = self.button_type.get();
        match ty {
            //https://html.spec.whatwg.org/multipage/#attr-button-type-submit-state
            ButtonType::ButtonSubmit => {
                self.form_owner().map(|o| {
                    o.r().submit(SubmittedFrom::NotFromFormSubmitMethod,
                                 FormSubmitter::ButtonElement(self.clone()))
                });
            },
            _ => ()
        }
    }

    // https://html.spec.whatwg.org/multipage/#implicit-submission
    #[allow(unsafe_code)]
    fn implicit_submission(&self, ctrlKey: bool, shiftKey: bool, altKey: bool, metaKey: bool) {
        let doc = document_from_node(*self);
        let node = NodeCast::from_ref(doc.r());
        let owner = self.form_owner();
        let elem = ElementCast::from_ref(*self);
        if owner.is_none() || elem.click_in_progress() {
            return;
        }
        node.query_selector_iter("button[type=submit]".to_owned()).unwrap()
            .filter_map(HTMLButtonElementCast::to_root)
            .find(|r| r.r().form_owner() == owner)
            .map(|s| s.r().synthetic_click_activation(ctrlKey, shiftKey, altKey, metaKey));
    }
}
<commit_msg>Remove Button prefix from names of variants of ButtonType enum<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::activation::Activatable;
use dom::attr::Attr;
use dom::bindings::codegen::Bindings::HTMLButtonElementBinding;
use dom::bindings::codegen::Bindings::HTMLButtonElementBinding::HTMLButtonElementMethods;
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLButtonElementCast, HTMLElementCast};
use dom::bindings::codegen::InheritTypes::{HTMLFieldSetElementDerived, NodeCast};
use dom::bindings::js::Root;
use dom::document::Document;
use dom::element::{AttributeMutation, Element, IN_ENABLED_STATE};
use dom::event::Event;
use dom::eventtarget::EventTarget;
use dom::htmlelement::HTMLElement;
use dom::htmlformelement::{FormControl, FormSubmitter};
use dom::htmlformelement::{SubmittedFrom, HTMLFormElement};
use dom::node::{Node, document_from_node, window_from_node};
use dom::validitystate::ValidityState;
use dom::virtualmethods::VirtualMethods;
use std::ascii::AsciiExt;
use std::borrow::ToOwned;
use std::cell::Cell;
use util::str::DOMString;

#[derive(JSTraceable, PartialEq, Copy, Clone)]
#[allow(dead_code)]
#[derive(HeapSizeOf)]
enum ButtonType {
    Submit,
    Reset,
    Button,
    Menu
}

#[dom_struct]
pub struct HTMLButtonElement {
    htmlelement: HTMLElement,
    button_type: Cell<ButtonType>
}

impl HTMLButtonElement {
    fn new_inherited(localName: DOMString,
                     prefix: Option<DOMString>,
                     document: &Document) -> HTMLButtonElement {
        HTMLButtonElement {
            htmlelement:
                HTMLElement::new_inherited_with_state(IN_ENABLED_STATE,
                                                      localName, prefix, document),
            //TODO: implement button_type in attribute_mutated
            button_type: Cell::new(ButtonType::Submit)
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(localName: DOMString,
               prefix: Option<DOMString>,
               document: &Document) -> Root<HTMLButtonElement> {
        let element = HTMLButtonElement::new_inherited(localName, prefix, document);
        Node::reflect_node(box element, document, HTMLButtonElementBinding::Wrap)
    }
}

impl HTMLButtonElementMethods for HTMLButtonElement {
    // https://html.spec.whatwg.org/multipage/#dom-cva-validity
    fn Validity(&self) -> Root<ValidityState> {
        let window = window_from_node(self);
        ValidityState::new(window.r())
    }

    // https://html.spec.whatwg.org/multipage/#dom-fe-disabled
    make_bool_getter!(Disabled);

    // https://html.spec.whatwg.org/multipage/#dom-fe-disabled
    make_bool_setter!(SetDisabled, "disabled");

    // https://html.spec.whatwg.org/multipage/#dom-fae-form
    fn GetForm(&self) -> Option<Root<HTMLFormElement>> {
        self.form_owner()
    }

    // https://html.spec.whatwg.org/multipage/#dom-button-type
    fn Type(&self) -> DOMString {
        let elem = ElementCast::from_ref(self);
        let mut ty = elem.get_string_attribute(&atom!("type"));
        ty.make_ascii_lowercase();
        // https://html.spec.whatwg.org/multipage/#attr-button-type
        match &*ty {
            "reset" | "button" | "menu" => ty,
            _ => "submit".to_owned()
        }
    }

    // https://html.spec.whatwg.org/multipage/#dom-button-type
    make_setter!(SetType, "type");

    // https://html.spec.whatwg.org/multipage/#dom-fs-formaction
    make_url_or_base_getter!(FormAction);

    // https://html.spec.whatwg.org/multipage/#dom-fs-formaction
    make_setter!(SetFormAction, "formaction");

    // https://html.spec.whatwg.org/multipage/#dom-fs-formenctype
    make_enumerated_getter!(
        FormEnctype, "application/x-www-form-urlencoded", ("text/plain") | ("multipart/form-data"));

    // https://html.spec.whatwg.org/multipage/#dom-fs-formenctype
    make_setter!(SetFormEnctype, "formenctype");

    // https://html.spec.whatwg.org/multipage/#dom-fs-formmethod
    make_enumerated_getter!(FormMethod, "get", ("post") | ("dialog"));

    // https://html.spec.whatwg.org/multipage/#dom-fs-formmethod
    make_setter!(SetFormMethod, "formmethod");

    // https://html.spec.whatwg.org/multipage/#dom-fs-formtarget
    make_getter!(FormTarget);

    // https://html.spec.whatwg.org/multipage/#dom-fs-formtarget
    make_setter!(SetFormTarget, "formtarget");

    // https://html.spec.whatwg.org/multipage/#dom-fe-name
    make_getter!(Name);

    // https://html.spec.whatwg.org/multipage/#dom-fe-name
    make_setter!(SetName, "name");

    // https://html.spec.whatwg.org/multipage/#dom-button-value
    make_getter!(Value);

    // https://html.spec.whatwg.org/multipage/#dom-button-value
    make_setter!(SetValue, "value");
}

impl VirtualMethods for HTMLButtonElement {
    fn super_type(&self) -> Option<&VirtualMethods> {
        let htmlelement: &HTMLElement = HTMLElementCast::from_ref(self);
        Some(htmlelement as &VirtualMethods)
    }

    fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
        self.super_type().unwrap().attribute_mutated(attr, mutation);
        match attr.local_name() {
            &atom!(disabled) => {
                let el = ElementCast::from_ref(self);
                match mutation {
                    AttributeMutation::Set(Some(_)) => {}
                    AttributeMutation::Set(None) => {
                        el.set_disabled_state(true);
                        el.set_enabled_state(false);
                    },
                    AttributeMutation::Removed => {
                        el.set_disabled_state(false);
                        el.set_enabled_state(true);
                        el.check_ancestors_disabled_state_for_form_control();
                    }
                }
            },
            _ => {},
        }
    }

    fn bind_to_tree(&self, tree_in_doc: bool) {
        if let Some(ref s) = self.super_type() {
            s.bind_to_tree(tree_in_doc);
        }

        let el = ElementCast::from_ref(self);
        el.check_ancestors_disabled_state_for_form_control();
    }

    fn unbind_from_tree(&self, tree_in_doc: bool) {
        if let Some(ref s) = self.super_type() {
            s.unbind_from_tree(tree_in_doc);
        }

        let node = NodeCast::from_ref(self);
        let el = ElementCast::from_ref(self);
        if node.ancestors().any(|ancestor| ancestor.r().is_htmlfieldsetelement()) {
            el.check_ancestors_disabled_state_for_form_control();
        } else {
            el.check_disabled_attribute();
        }
    }
}

impl FormControl for HTMLButtonElement {}

impl<'a> Activatable for &'a HTMLButtonElement {
    fn as_element(&self) -> &Element {
        ElementCast::from_ref(*self)
    }

    fn is_instance_activatable(&self) -> bool {
        //https://html.spec.whatwg.org/multipage/#the-button-element
        let el = ElementCast::from_ref(*self);
        !(el.get_disabled_state())
    }

    // https://html.spec.whatwg.org/multipage/#run-pre-click-activation-steps
    // https://html.spec.whatwg.org/multipage/#the-button-element:activation-behavior
    fn pre_click_activation(&self) {
    }

    // https://html.spec.whatwg.org/multipage/#run-canceled-activation-steps
    fn canceled_activation(&self) {
    }

    // https://html.spec.whatwg.org/multipage/#run-post-click-activation-steps
    fn activation_behavior(&self, _event: &Event, _target: &EventTarget) {
        let ty = self.button_type.get();
        match ty {
            //https://html.spec.whatwg.org/multipage/#attr-button-type-submit-state
            ButtonType::Submit => {
                self.form_owner().map(|o| {
                    o.r().submit(SubmittedFrom::NotFromFormSubmitMethod,
                                 FormSubmitter::ButtonElement(self.clone()))
                });
            },
            _ => ()
        }
    }

    // https://html.spec.whatwg.org/multipage/#implicit-submission
    #[allow(unsafe_code)]
    fn implicit_submission(&self, ctrlKey: bool, shiftKey: bool, altKey: bool, metaKey: bool) {
        let doc = document_from_node(*self);
        let node = NodeCast::from_ref(doc.r());
        let owner = self.form_owner();
        let elem = ElementCast::from_ref(*self);
        if owner.is_none() || elem.click_in_progress() {
            return;
        }
        node.query_selector_iter("button[type=submit]".to_owned()).unwrap()
            .filter_map(HTMLButtonElementCast::to_root)
            .find(|r| r.r().form_owner() == owner)
            .map(|s| s.r().synthetic_click_activation(ctrlKey, shiftKey, altKey, metaKey));
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![allow(unsafe_code)]

use gecko_bindings::bindings::Gecko_AddRefAtom;
use gecko_bindings::bindings::Gecko_Atomize;
use gecko_bindings::bindings::Gecko_ReleaseAtom;
use gecko_bindings::structs::nsIAtom;
use heapsize::HeapSizeOf;
use selectors::bloom::BloomHash;
use selectors::parser::FromCowStr;
use std::ascii::AsciiExt;
use std::borrow::{Cow, Borrow};
use std::char::{self, DecodeUtf16};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::iter::Cloned;
use std::mem;
use std::ops::Deref;
use std::slice;

#[macro_use]
#[allow(improper_ctypes)]
pub mod atom_macro;
#[macro_use]
pub mod namespace;

pub use string_cache::namespace::{Namespace, WeakNamespace};

/// A strong reference to a Gecko atom.
#[derive(PartialEq, Eq)]
pub struct Atom(*mut WeakAtom);

/// An atom *without* a strong reference.
///
/// Only usable as `&'a WeakAtom`,
/// where `'a` is the lifetime of something that holds a strong reference to that atom.
pub struct WeakAtom(nsIAtom);

pub type BorrowedAtom<'a> = &'a WeakAtom;

impl Deref for Atom {
    type Target = WeakAtom;

    #[inline]
    fn deref(&self) -> &WeakAtom {
        unsafe {
            &*self.0
        }
    }
}

impl Borrow<WeakAtom> for Atom {
    #[inline]
    fn borrow(&self) -> &WeakAtom {
        self
    }
}

impl Eq for WeakAtom {}
impl PartialEq for WeakAtom {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        let weak: *const WeakAtom = self;
        let other: *const WeakAtom = other;
        weak == other
    }
}

unsafe impl Send for Atom {}
unsafe impl Sync for Atom {}
unsafe impl Sync for WeakAtom {}

impl WeakAtom {
    #[inline]
    pub unsafe fn new<'a>(atom: *mut nsIAtom) -> &'a mut Self {
        &mut *(atom as *mut WeakAtom)
    }

    #[inline]
    pub fn clone(&self) -> Atom {
        Atom::from(self.as_ptr())
    }

    #[inline]
    pub fn get_hash(&self) -> u32 {
        self.0.mHash
    }

    pub fn as_slice(&self) -> &[u16] {
        unsafe {
            slice::from_raw_parts((*self.as_ptr()).mString, self.len() as usize)
        }
    }

    // NOTE: don't expose this, since it's slow, and easy to be misused.
    fn chars(&self) -> DecodeUtf16<Cloned<slice::Iter<u16>>> {
        char::decode_utf16(self.as_slice().iter().cloned())
    }

    pub fn with_str<F, Output>(&self, cb: F) -> Output
        where F: FnOnce(&str) -> Output
    {
        // FIXME(bholley): We should measure whether it makes more sense to
        // cache the UTF-8 version in the Gecko atom table somehow.
        let owned = String::from_utf16(self.as_slice()).unwrap();
        cb(&owned)
    }

    #[inline]
    pub fn eq_str_ignore_ascii_case(&self, s: &str) -> bool {
        self.chars().map(|r| match r {
            Ok(c) => c.to_ascii_lowercase() as u32,
            Err(e) => e.unpaired_surrogate() as u32,
        }).eq(s.chars().map(|c| c.to_ascii_lowercase() as u32))
    }

    #[inline]
    pub fn to_string(&self) -> String {
        String::from_utf16(self.as_slice()).unwrap()
    }

    #[inline]
    pub fn is_static(&self) -> bool {
        unsafe {
            (*self.as_ptr()).mIsStatic() != 0
        }
    }

    #[inline]
    pub fn len(&self) -> u32 {
        unsafe {
            (*self.as_ptr()).mLength()
        }
    }

    #[inline]
    pub fn as_ptr(&self) -> *mut nsIAtom {
        let const_ptr: *const nsIAtom = &self.0;
        const_ptr as *mut nsIAtom
    }
}

impl fmt::Debug for WeakAtom {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        write!(w, "Gecko WeakAtom({:p}, {})", self, self)
    }
}

impl fmt::Display for WeakAtom {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        for c in self.chars() {
            try!(write!(w, "{}", c.unwrap_or(char::REPLACEMENT_CHARACTER)))
        }
        Ok(())
    }
}

impl Atom {
    pub unsafe fn with<F>(ptr: *mut nsIAtom, callback: &mut F) where F: FnMut(&Atom) {
        let atom = Atom(WeakAtom::new(ptr));
        callback(&atom);
        mem::forget(atom);
    }

    /// Creates an atom from an static atom pointer without checking in release
    /// builds.
    ///
    /// Right now it's only used by the atom macro, and ideally it should keep
    /// that way, now we have sugar for is_static, creating atoms using
    /// Atom::from should involve almost no overhead.
    #[inline]
    unsafe fn from_static(ptr: *mut nsIAtom) -> Self {
        let atom = Atom(ptr as *mut WeakAtom);
        debug_assert!(atom.is_static(),
                      "Called from_static for a non-static atom!");
        atom
    }
}

impl BloomHash for Atom {
    #[inline]
    fn bloom_hash(&self) -> u32 {
        self.get_hash()
    }
}

impl BloomHash for WeakAtom {
    #[inline]
    fn bloom_hash(&self) -> u32 {
        self.get_hash()
    }
}

impl Hash for Atom {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        state.write_u32(self.get_hash());
    }
}

impl Hash for WeakAtom {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        state.write_u32(self.get_hash());
    }
}

impl Clone for Atom {
    #[inline(always)]
    fn clone(&self) -> Atom {
        Atom::from(self.as_ptr())
    }
}

impl Drop for Atom {
    #[inline]
    fn drop(&mut self) {
        if !self.is_static() {
            unsafe {
                Gecko_ReleaseAtom(self.as_ptr());
            }
        }
    }
}

impl Default for Atom {
    #[inline]
    fn default() -> Self {
        atom!("")
    }
}

impl HeapSizeOf for Atom {
    fn heap_size_of_children(&self) -> usize {
        0
    }
}

impl fmt::Debug for Atom {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        write!(w, "Gecko Atom({:p}, {})", self.0, self)
    }
}

impl fmt::Display for Atom {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        unsafe {
            (&*self.0).fmt(w)
        }
    }
}

impl<'a> From<&'a str> for Atom {
    #[inline]
    fn from(string: &str) -> Atom {
        debug_assert!(string.len() <= u32::max_value() as usize);
        unsafe {
            Atom(WeakAtom::new(
                Gecko_Atomize(string.as_ptr() as *const _, string.len() as u32)
            ))
        }
    }
}

impl<'a> From<Cow<'a, str>> for Atom {
    #[inline]
    fn from(string: Cow<'a, str>) -> Atom {
        Atom::from(&*string)
    }
}

impl FromCowStr for Atom {
    #[inline]
    fn from_cow_str(string: Cow<str>) -> Atom {
        Atom::from(&*string)
    }
}

impl From<String> for Atom {
    #[inline]
    fn from(string: String) -> Atom {
        Atom::from(&*string)
    }
}

impl From<*mut nsIAtom> for Atom {
    #[inline]
    fn from(ptr: *mut nsIAtom) -> Atom {
        debug_assert!(!ptr.is_null());
        unsafe {
            if (*ptr).mIsStatic() == 0 {
                Gecko_AddRefAtom(ptr);
            }
            Atom(WeakAtom::new(ptr))
        }
    }
}
<commit_msg>Auto merge of #13433 - servo:jdm-patch-3, r=Ms2ger<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![allow(unsafe_code)]

use gecko_bindings::bindings::Gecko_AddRefAtom;
use gecko_bindings::bindings::Gecko_Atomize;
use gecko_bindings::bindings::Gecko_ReleaseAtom;
use gecko_bindings::structs::nsIAtom;
use heapsize::HeapSizeOf;
use selectors::bloom::BloomHash;
use selectors::parser::FromCowStr;
use std::ascii::AsciiExt;
use std::borrow::{Cow, Borrow};
use std::char::{self, DecodeUtf16};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::iter::Cloned;
use std::mem;
use std::ops::Deref;
use std::slice;

#[macro_use]
#[allow(improper_ctypes, safe_extern_statics)]
pub mod atom_macro;
#[macro_use]
pub mod namespace;

pub use string_cache::namespace::{Namespace, WeakNamespace};

/// A strong reference to a Gecko atom.
#[derive(PartialEq, Eq)]
pub struct Atom(*mut WeakAtom);

/// An atom *without* a strong reference.
///
/// Only usable as `&'a WeakAtom`,
/// where `'a` is the lifetime of something that holds a strong reference to that atom.
pub struct WeakAtom(nsIAtom);

pub type BorrowedAtom<'a> = &'a WeakAtom;

impl Deref for Atom {
    type Target = WeakAtom;

    #[inline]
    fn deref(&self) -> &WeakAtom {
        unsafe {
            &*self.0
        }
    }
}

impl Borrow<WeakAtom> for Atom {
    #[inline]
    fn borrow(&self) -> &WeakAtom {
        self
    }
}

impl Eq for WeakAtom {}
impl PartialEq for WeakAtom {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        let weak: *const WeakAtom = self;
        let other: *const WeakAtom = other;
        weak == other
    }
}

unsafe impl Send for Atom {}
unsafe impl Sync for Atom {}
unsafe impl Sync for WeakAtom {}

impl WeakAtom {
    #[inline]
    pub unsafe fn new<'a>(atom: *mut nsIAtom) -> &'a mut Self {
        &mut *(atom as *mut WeakAtom)
    }

    #[inline]
    pub fn clone(&self) -> Atom {
        Atom::from(self.as_ptr())
    }

    #[inline]
    pub fn get_hash(&self) -> u32 {
        self.0.mHash
    }

    pub fn as_slice(&self) -> &[u16] {
        unsafe {
            slice::from_raw_parts((*self.as_ptr()).mString, self.len() as usize)
        }
    }

    // NOTE: don't expose this, since it's slow, and easy to be misused.
    fn chars(&self) -> DecodeUtf16<Cloned<slice::Iter<u16>>> {
        char::decode_utf16(self.as_slice().iter().cloned())
    }

    pub fn with_str<F, Output>(&self, cb: F) -> Output
        where F: FnOnce(&str) -> Output
    {
        // FIXME(bholley): We should measure whether it makes more sense to
        // cache the UTF-8 version in the Gecko atom table somehow.
        let owned = String::from_utf16(self.as_slice()).unwrap();
        cb(&owned)
    }

    #[inline]
    pub fn eq_str_ignore_ascii_case(&self, s: &str) -> bool {
        self.chars().map(|r| match r {
            Ok(c) => c.to_ascii_lowercase() as u32,
            Err(e) => e.unpaired_surrogate() as u32,
        }).eq(s.chars().map(|c| c.to_ascii_lowercase() as u32))
    }

    #[inline]
    pub fn to_string(&self) -> String {
        String::from_utf16(self.as_slice()).unwrap()
    }

    #[inline]
    pub fn is_static(&self) -> bool {
        unsafe {
            (*self.as_ptr()).mIsStatic() != 0
        }
    }

    #[inline]
    pub fn len(&self) -> u32 {
        unsafe {
            (*self.as_ptr()).mLength()
        }
    }

    #[inline]
    pub fn as_ptr(&self) -> *mut nsIAtom {
        let const_ptr: *const nsIAtom = &self.0;
        const_ptr as *mut nsIAtom
    }
}

impl fmt::Debug for WeakAtom {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        write!(w, "Gecko WeakAtom({:p}, {})", self, self)
    }
}

impl fmt::Display for WeakAtom {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        for c in self.chars() {
            try!(write!(w, "{}", c.unwrap_or(char::REPLACEMENT_CHARACTER)))
        }
        Ok(())
    }
}

impl Atom {
    pub unsafe fn with<F>(ptr: *mut nsIAtom, callback: &mut F) where F: FnMut(&Atom) {
        let atom = Atom(WeakAtom::new(ptr));
        callback(&atom);
        mem::forget(atom);
    }

    /// Creates an atom from an static atom pointer without checking in release
    /// builds.
    ///
    /// Right now it's only used by the atom macro, and ideally it should keep
    /// that way, now we have sugar for is_static, creating atoms using
    /// Atom::from should involve almost no overhead.
    #[inline]
    unsafe fn from_static(ptr: *mut nsIAtom) -> Self {
        let atom = Atom(ptr as *mut WeakAtom);
        debug_assert!(atom.is_static(),
                      "Called from_static for a non-static atom!");
        atom
    }
}

impl BloomHash for Atom {
    #[inline]
    fn bloom_hash(&self) -> u32 {
        self.get_hash()
    }
}

impl BloomHash for WeakAtom {
    #[inline]
    fn bloom_hash(&self) -> u32 {
        self.get_hash()
    }
}

impl Hash for Atom {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        state.write_u32(self.get_hash());
    }
}

impl Hash for WeakAtom {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        state.write_u32(self.get_hash());
    }
}

impl Clone for Atom {
    #[inline(always)]
    fn clone(&self) -> Atom {
        Atom::from(self.as_ptr())
    }
}

impl Drop for Atom {
    #[inline]
    fn drop(&mut self) {
        if !self.is_static() {
            unsafe {
                Gecko_ReleaseAtom(self.as_ptr());
            }
        }
    }
}

impl Default for Atom {
    #[inline]
    fn default() -> Self {
        atom!("")
    }
}

impl HeapSizeOf for Atom {
    fn heap_size_of_children(&self) -> usize {
        0
    }
}

impl fmt::Debug for Atom {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        write!(w, "Gecko Atom({:p}, {})", self.0, self)
    }
}

impl fmt::Display for Atom {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        unsafe {
            (&*self.0).fmt(w)
        }
    }
}

impl<'a> From<&'a str> for Atom {
    #[inline]
    fn from(string: &str) -> Atom {
        debug_assert!(string.len() <= u32::max_value() as usize);
        unsafe {
            Atom(WeakAtom::new(
                Gecko_Atomize(string.as_ptr() as *const _, string.len() as u32)
            ))
        }
    }
}

impl<'a> From<Cow<'a, str>> for Atom {
    #[inline]
    fn from(string: Cow<'a, str>) -> Atom {
        Atom::from(&*string)
    }
}

impl FromCowStr for Atom {
    #[inline]
    fn from_cow_str(string: Cow<str>) -> Atom {
        Atom::from(&*string)
    }
}

impl From<String> for Atom {
    #[inline]
    fn from(string: String) -> Atom {
        Atom::from(&*string)
    }
}

impl From<*mut nsIAtom> for Atom {
    #[inline]
    fn from(ptr: *mut nsIAtom) -> Atom {
        debug_assert!(!ptr.is_null());
        unsafe {
            if (*ptr).mIsStatic() == 0 {
                Gecko_AddRefAtom(ptr);
            }
            Atom(WeakAtom::new(ptr))
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate::account_address::AccountAddress;
use crate::{
    account_config::CORE_CODE_ADDRESS,
    event::{EventHandle, EventKey},
};
use anyhow::Result;
use move_deps::move_core_types::{
    ident_str,
    identifier::IdentStr,
    move_resource::{MoveResource, MoveStructType},
};
use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize};

/// Struct that represents a NewBlockEvent.
/// Should be kept in-sync with NewBlockEvent move struct in block.move.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct NewBlockEvent {
    epoch: u64,
    round: u64,
    height: u64,
    previous_block_votes: Vec<bool>,
    proposer: AccountAddress,
    failed_proposer_indices: Vec<u64>,
    timestamp: u64,
}

impl NewBlockEvent {
    pub fn epoch(&self) -> u64 {
        self.epoch
    }

    pub fn round(&self) -> u64 {
        self.round
    }

    pub fn height(&self) -> u64 {
        self.height
    }

    pub fn previous_block_votes(&self) -> &Vec<bool> {
        &self.previous_block_votes
    }

    pub fn proposer(&self) -> AccountAddress {
        self.proposer
    }

    /// The list of indices in the validators list,
    /// of consecutive proposers from the immediately preceeding
    /// rounds that didn't produce a successful block
    pub fn failed_proposer_indices(&self) -> &Vec<u64> {
        &self.failed_proposer_indices
    }

    pub fn proposed_time(&self) -> u64 {
        self.timestamp
    }

    pub fn try_from_bytes(bytes: &[u8]) -> Result<Self> {
        bcs::from_bytes(bytes).map_err(Into::into)
    }

    #[cfg(any(test, feature = "fuzzing"))]
    pub fn new(
        epoch: u64,
        round: u64,
        height: u64,
        previous_block_votes: Vec<bool>,
        proposer: AccountAddress,
        failed_proposer_indices: Vec<u64>,
        timestamp: u64,
    ) -> Self {
        Self {
            epoch,
            round,
            height,
            previous_block_votes,
            proposer,
            failed_proposer_indices,
            timestamp,
        }
    }
}

impl MoveStructType for NewBlockEvent {
    const MODULE_NAME: &'static IdentStr = ident_str!("block");
    const STRUCT_NAME: &'static IdentStr = ident_str!("NewBlockEvent");
}

pub fn new_block_event_key() -> EventKey {
    EventKey::new(2, CORE_CODE_ADDRESS)
}

/// The path to the new block event handle under a Block::BlockResource resource.
pub static NEW_BLOCK_EVENT_PATH: Lazy<Vec<u8>> = Lazy::new(|| {
    let mut path = BlockResource::resource_path();
    // it can be anything as long as it's referenced in AccountState::get_event_handle_by_query_path
    path.extend_from_slice(b"/new_block_event/");
    path
});

/// Should be kept in-sync with BlockResource move struct in block.move.
#[derive(Deserialize, Serialize)]
pub struct BlockResource {
    height: u64,
    epoch_interval: u64,
    new_block_events: EventHandle,
}

impl BlockResource {
    pub fn new_block_events(&self) -> &EventHandle {
        &self.new_block_events
    }

    pub fn height(&self) -> u64 {
        self.height
    }
}

impl MoveStructType for BlockResource {
    const MODULE_NAME: &'static IdentStr = ident_str!("block");
    const STRUCT_NAME: &'static IdentStr = ident_str!("BlockResource");
}

impl MoveResource for BlockResource {}
<commit_msg>Make NewBlockEvent::new accessible without a feature (#2720)<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate::account_address::AccountAddress;
use crate::{
    account_config::CORE_CODE_ADDRESS,
    event::{EventHandle, EventKey},
};
use anyhow::Result;
use move_deps::move_core_types::{
    ident_str,
    identifier::IdentStr,
    move_resource::{MoveResource, MoveStructType},
};
use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize};

/// Struct that represents a NewBlockEvent.
/// Should be kept in-sync with NewBlockEvent move struct in block.move.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct NewBlockEvent {
    epoch: u64,
    round: u64,
    height: u64,
    previous_block_votes: Vec<bool>,
    proposer: AccountAddress,
    failed_proposer_indices: Vec<u64>,
    timestamp: u64,
}

impl NewBlockEvent {
    pub fn epoch(&self) -> u64 {
        self.epoch
    }

    pub fn round(&self) -> u64 {
        self.round
    }

    pub fn height(&self) -> u64 {
        self.height
    }

    pub fn previous_block_votes(&self) -> &Vec<bool> {
        &self.previous_block_votes
    }

    pub fn proposer(&self) -> AccountAddress {
        self.proposer
    }

    /// The list of indices in the validators list,
    /// of consecutive proposers from the immediately preceeding
    /// rounds that didn't produce a successful block
    pub fn failed_proposer_indices(&self) -> &Vec<u64> {
        &self.failed_proposer_indices
    }

    pub fn proposed_time(&self) -> u64 {
        self.timestamp
    }

    pub fn try_from_bytes(bytes: &[u8]) -> Result<Self> {
        bcs::from_bytes(bytes).map_err(Into::into)
    }

    pub fn new(
        epoch: u64,
        round: u64,
        height: u64,
        previous_block_votes: Vec<bool>,
        proposer: AccountAddress,
        failed_proposer_indices: Vec<u64>,
        timestamp: u64,
    ) -> Self {
        Self {
            epoch,
            round,
            height,
            previous_block_votes,
            proposer,
            failed_proposer_indices,
            timestamp,
        }
    }
}

impl MoveStructType for NewBlockEvent {
    const MODULE_NAME: &'static IdentStr = ident_str!("block");
    const STRUCT_NAME: &'static IdentStr = ident_str!("NewBlockEvent");
}

pub fn new_block_event_key() -> EventKey {
    EventKey::new(2, CORE_CODE_ADDRESS)
}

/// The path to the new block event handle under a Block::BlockResource resource.
pub static NEW_BLOCK_EVENT_PATH: Lazy<Vec<u8>> = Lazy::new(|| {
    let mut path = BlockResource::resource_path();
    // it can be anything as long as it's referenced in AccountState::get_event_handle_by_query_path
    path.extend_from_slice(b"/new_block_event/");
    path
});

/// Should be kept in-sync with BlockResource move struct in block.move.
#[derive(Deserialize, Serialize)]
pub struct BlockResource {
    height: u64,
    epoch_interval: u64,
    new_block_events: EventHandle,
}

impl BlockResource {
    pub fn new_block_events(&self) -> &EventHandle {
        &self.new_block_events
    }

    pub fn height(&self) -> u64 {
        self.height
    }
}

impl MoveStructType for BlockResource {
    const MODULE_NAME: &'static IdentStr = ident_str!("block");
    const STRUCT_NAME: &'static IdentStr = ident_str!("BlockResource");
}

impl MoveResource for BlockResource {}
<|endoftext|>


<commit_before>use core::hint;

/// Tock programs' entry point. Called by the kernel at program start. Sets up
/// the stack then calls rust_start() for the remainder of setup.
#[doc(hidden)]
#[naked]
#[no_mangle]
#[link_section = ".start"]
// The args for this function are:
//    app_start: usize,
//    mem_start: usize,
//    memory_len: usize,
//    app_heap_break: usize,
// Due to Rust issue: https://github.com/rust-lang/rust/issues/42779 we can't have
// args to the function
pub unsafe extern "C" fn _start() -> ! {
    asm!(
    // Compute the stack top.
    //
    // struct hdr* myhdr = (struct hdr*) app_start;
    // uint32_t stacktop = (((uint32_t) mem_start + myhdr->stack_size + 7) & 0xfffffff8);
    "lw   t0, 36(a0)         // t0 = myhdr->stack_size
    addi t0, t0, 7          // t0 = myhdr->stack_size + 7
    add  t0, t0, a1         // t0 = mem_start + myhdr->stack_size + 7
    li   t1, 7              // t1 = 7
    not  t1, t1             // t1 = ~0x7
    and  t0, t0, t1         // t0 = (mem_start + myhdr->stack_size + 7) & ~0x7
    //
    // Compute the app data size and where initial app brk should go.
    // This includes the GOT, data, and BSS sections. However, we can't be sure
    // the linker puts them back-to-back, but we do assume that BSS is last
    // (i.e. myhdr->got_start < myhdr->bss_start && myhdr->data_start <
    // myhdr->bss_start). With all of that true, then the size is equivalent
    // to the end of the BSS section.
    //
    // uint32_t appdata_size = myhdr->bss_start + myhdr->bss_size;
    lw   t1, 24(a0)         // t1 = myhdr->bss_start
    lw   t2, 28(a0)         // t2 = myhdr->bss_size
    lw   t3,  4(a0)         // t3 = myhdr->got_start
    add  t1, t1, t2         // t1 = bss_start + bss_size
    //
    // Move arguments we need to keep over to callee-saved locations.
    mv   s0, a0             // s0 = void* app_start
    mv   s1, t0             // s1 = stack_top
    mv   s2, a3             // s2 = app_heap_break
    //
    // Now we may want to move the stack pointer. If the kernel set the
    // `app_heap_break` larger than we need (and we are going to call `brk()`
    // to reduce it) then our stack pointer will fit and we can move it now.
    // Otherwise after the first syscall (the memop to set the brk), the return
    // will use a stack that is outside of the process accessible memory.
    //
    bgt t1, a3, skip_set_sp // Compare `app_heap_break` with new brk.
                                // If our current `app_heap_break` is larger
                                // then we need to move the stack pointer
                                // before we call the `brk` syscall.
    mv  sp, t0              // Update the stack pointer

    skip_set_sp:            // Back to regularly scheduled programming.

    // Call `brk` to set to requested memory

    // memop(0, stacktop + appdata_size);
    li  a0, 4               // a0 = 4   // memop syscall
    li  a1, 0               // a1 = 0
    mv  a2, t1              // a2 = appdata_size
    ecall                   // memop
    //
    // Debug support, tell the kernel the stack location
    //
    // memop(10, stacktop);
    li  a0, 4               // a0 = 4   // memop syscall
    li  a1, 10              // a1 = 10
    mv  a2, s1              // a2 = stacktop
    ecall                   // memop
    //
    // Debug support, tell the kernel the heap location
    //
    // memop(11, stacktop + appdata_size);
    li  a0, 4               // a0 = 4   // memop syscall
    li  a1, 11              // a1 = 10
    mv  a2, t1              // a2 = appdata_size
    ecall                   // memop
    //
    // Setup initial stack pointer for normal execution
    // Call into the rest of startup. This should never return.
    mv   sp, s1             // sp = stacktop
    mv   a0, s0             // first arg is app_start
    mv   s0, sp             // Set the frame pointer to sp.
    mv   a1, s1             // second arg is stacktop
    mv   a2, s2             // third arg is app_heap_break
    jal  rust_start"
    :                                                              // No output operands
    :
    : "memory", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17",
      "x5", "x6", "x7", "x28", "x29", "x30", "x31", "x1"           // Clobbers
    : "volatile"                                                   // Options
    );
    hint::unreachable_unchecked();
}

/// Ensure an abort symbol exists.
#[cfg(target_arch = "riscv32")]
#[link_section = ".start"]
#[export_name = "abort"]
pub extern "C" fn abort() {
    unsafe {
        asm! ("
            // Simply go back to the start as if we had just booted.
            j    _start
        "
        :
        :
        :
        : "volatile");
    }
}
<commit_msg>start_item_riscv32: Fix typo in assembly comment<commit_after>use core::hint;

/// Tock programs' entry point. Called by the kernel at program start. Sets up
/// the stack then calls rust_start() for the remainder of setup.
#[doc(hidden)]
#[naked]
#[no_mangle]
#[link_section = ".start"]
// The args for this function are:
//    app_start: usize,
//    mem_start: usize,
//    memory_len: usize,
//    app_heap_break: usize,
// Due to Rust issue: https://github.com/rust-lang/rust/issues/42779 we can't have
// args to the function
pub unsafe extern "C" fn _start() -> ! {
    asm!(
    // Compute the stack top.
    //
    // struct hdr* myhdr = (struct hdr*) app_start;
    // uint32_t stacktop = (((uint32_t) mem_start + myhdr->stack_size + 7) & 0xfffffff8);
    "lw   t0, 36(a0)         // t0 = myhdr->stack_size
    addi t0, t0, 7          // t0 = myhdr->stack_size + 7
    add  t0, t0, a1         // t0 = mem_start + myhdr->stack_size + 7
    li   t1, 7              // t1 = 7
    not  t1, t1             // t1 = ~0x7
    and  t0, t0, t1         // t0 = (mem_start + myhdr->stack_size + 7) & ~0x7
    //
    // Compute the app data size and where initial app brk should go.
    // This includes the GOT, data, and BSS sections. However, we can't be sure
    // the linker puts them back-to-back, but we do assume that BSS is last
    // (i.e. myhdr->got_start < myhdr->bss_start && myhdr->data_start <
    // myhdr->bss_start). With all of that true, then the size is equivalent
    // to the end of the BSS section.
    //
    // uint32_t appdata_size = myhdr->bss_start + myhdr->bss_size;
    lw   t1, 24(a0)         // t1 = myhdr->bss_start
    lw   t2, 28(a0)         // t2 = myhdr->bss_size
    lw   t3,  4(a0)         // t3 = myhdr->got_start
    add  t1, t1, t2         // t1 = bss_start + bss_size
    //
    // Move arguments we need to keep over to callee-saved locations.
    mv   s0, a0             // s0 = void* app_start
    mv   s1, t0             // s1 = stack_top
    mv   s2, a3             // s2 = app_heap_break
    //
    // Now we may want to move the stack pointer. If the kernel set the
    // `app_heap_break` larger than we need (and we are going to call `brk()`
    // to reduce it) then our stack pointer will fit and we can move it now.
    // Otherwise after the first syscall (the memop to set the brk), the return
    // will use a stack that is outside of the process accessible memory.
    //
    bgt t1, a3, skip_set_sp // Compare `app_heap_break` with new brk.
                                // If our current `app_heap_break` is larger
                                // then we need to move the stack pointer
                                // before we call the `brk` syscall.
    mv  sp, t0              // Update the stack pointer

    skip_set_sp:            // Back to regularly scheduled programming.

    // Call `brk` to set to requested memory

    // memop(0, stacktop + appdata_size);
    li  a0, 4               // a0 = 4   // memop syscall
    li  a1, 0               // a1 = 0
    mv  a2, t1              // a2 = appdata_size
    ecall                   // memop
    //
    // Debug support, tell the kernel the stack location
    //
    // memop(10, stacktop);
    li  a0, 4               // a0 = 4   // memop syscall
    li  a1, 10              // a1 = 10
    mv  a2, s1              // a2 = stacktop
    ecall                   // memop
    //
    // Debug support, tell the kernel the heap location
    //
    // memop(11, stacktop + appdata_size);
    li  a0, 4               // a0 = 4   // memop syscall
    li  a1, 11              // a1 = 11
    mv  a2, t1              // a2 = appdata_size
    ecall                   // memop
    //
    // Setup initial stack pointer for normal execution
    // Call into the rest of startup. This should never return.
    mv   sp, s1             // sp = stacktop
    mv   a0, s0             // first arg is app_start
    mv   s0, sp             // Set the frame pointer to sp.
    mv   a1, s1             // second arg is stacktop
    mv   a2, s2             // third arg is app_heap_break
    jal  rust_start"
    :                                                              // No output operands
    :
    : "memory", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17",
      "x5", "x6", "x7", "x28", "x29", "x30", "x31", "x1"           // Clobbers
    : "volatile"                                                   // Options
    );
    hint::unreachable_unchecked();
}

/// Ensure an abort symbol exists.
#[cfg(target_arch = "riscv32")]
#[link_section = ".start"]
#[export_name = "abort"]
pub extern "C" fn abort() {
    unsafe {
        asm! ("
            // Simply go back to the start as if we had just booted.
            j    _start
        "
        :
        :
        :
        : "volatile");
    }
}
<|endoftext|>


<commit_before>use error::{Error,Result};
use token::Token;
use html::HtmlRenderer;
use book::{Book,Number};
use zipper::Zipper;
use templates::epub::*;

use mustache;
use chrono;
use uuid;

use std::io::{Read,Write};
use std::path::Path;
use std::fs::File;

/// Renderer for Epub
///
/// Uses part of the HTML renderer
pub struct EpubRenderer<'a> {
    book: &'a Book,
    current_numbering: bool,
    current_chapter: i32,
    toc: Vec<String>,
    html: HtmlRenderer<'a>,
}

impl<'a> EpubRenderer<'a> {
    /// Creates a new Epub renderer
    pub fn new(book: &'a Book) -> EpubRenderer<'a> {
         EpubRenderer {
            book: book,
            html: HtmlRenderer::new(book),
            current_numbering: book.numbering,
            current_chapter: 1,
            toc: vec!(),
        }
    }

    /// Render a book
    pub fn render_book(&mut self) -> Result<String> {
        let mut zipper = try!(Zipper::new(&self.book.temp_dir, &vec!("META-INF")));

        // Write mimetype
        try!(zipper.write("mimetype", b"application/epub+zip"));

        // Write chapters
        let mut i = 0;
        for &(ref n, ref v) in &self.book.chapters {
            match n {
                &Number::Unnumbered => self.current_numbering = false,
                &Number::Default => self.current_numbering = self.book.numbering,
                &Number::Specified(n) => {
                    self.current_numbering = self.book.numbering;
                    self.current_chapter = n;
                }
            }
            let chapter = try!(self.render_chapter(v));

            try!(zipper.write(&filenamer(i), &chapter.as_bytes()));
            i += 1;
        }

        // Write CSS file
        try!(zipper.write("stylesheet.css",
                          &try!(self.book.get_template("epub_css")).as_bytes()));

        // Write titlepage
        try!(zipper.write("title_page.xhtml", &try!(self.render_titlepage()).as_bytes()));

        // Write file for ibook (why?)
        try!(zipper.write("META-INF/com.apple.ibooks.display-options.xml", IBOOK.as_bytes()));

        // Write container.xml
        try!(zipper.write("META-INF/container.xml", CONTAINER.as_bytes()));

        // Write nav.xhtml
        try!(zipper.write("nav.xhtml", &try!(self.render_nav()).as_bytes()));

        // Write content.opf
        try!(zipper.write("content.opf", &try!(self.render_opf()).as_bytes()));

        // Write toc.ncx
        try!(zipper.write("toc.ncx", &try!(self.render_toc()).as_bytes()));

        // Write the cover (if needs be)
        if let Some(ref cover) = self.book.cover {
            let s: &str = &*cover;
            let mut f = try!(File::open(s).map_err(|_| Error::FileNotFound(String::from(s))));
            let mut content = vec!();
            try!(f.read_to_end(&mut content).map_err(|_| Error::Render("Error while reading cover file")));
            try!(zipper.write(s, &content));

            // also write cover.xhtml
            try!(zipper.write("over.xhtml", &try!(self.render_cover()).as_bytes()));
        }

        if let Some(ref epub_file) = self.book.output_epub {
            let res = try!(zipper.generate_epub(epub_file));
            Ok(res)
        } else {
            Err(Error::Render("no output epub file specified in book config"))
        }
    }

    /// Render the titlepgae
    fn render_titlepage(&self) -> Result<String> {
        let template = mustache::compile_str(TITLE);
        let data = self.book.get_mapbuilder()
            .build();
        let mut res:Vec<u8> = vec!();
        template.render_data(&mut res, &data);
        match String::from_utf8(res) {
            Err(_) => Err(Error::Render("generated HTML in titlepage was not utf-8 valid")),
            Ok(res) => Ok(res)
        }
    }

    /// Render toc.ncx
    fn render_toc(&self) -> Result<String> {
        let mut nav_points = String::new();

        for (n, ref title) in self.toc.iter().enumerate() {
            let filename = filenamer(n);
            let id = format!("navPoint-{}", n + 1);
            nav_points.push_str(&format!(
"   <navPoint id=\"{}\">
      <navLabel>
        <text>{}</text>
      </navLabel>
      <content src = \"{}\" />
    </navPoint>\n", id, title, filename));
        }
        let template = mustache::compile_str(TOC);
        let data = self.book.get_mapbuilder()
            .insert_str("nav_points", nav_points)
            .build();
        let mut res:Vec<u8> = vec!();
        template.render_data(&mut res, &data);
        match String::from_utf8(res) {
            Err(_) => Err(Error::Render("generated HTML in toc.ncx was not valid utf-8")),
            Ok(res) => Ok(res)
        }
    }

    /// Render content.opf
    fn render_opf(&self) -> Result<String> {
        // Optional metadata
        let mut cover_xhtml = String::new();
        let mut optional = String::new();
        if let Some(ref s) = self.book.description {
            optional.push_str(&format!("<dc:description>{}</dc:description>\n", s));
        }
        if let Some(ref s) = self.book.subject {
            optional.push_str(&format!("<dc:subject>{}</dc:subject>\n", s));
        }
        if let Some(ref s) = self.book.cover {
            optional.push_str(&format!("<meta name = \"cover\" content = \"{}\" />\n", s));
            cover_xhtml.push_str(&format!("<reference type=\"cover\" title=\"Cover\" href=\"cover.xhtml\" />"));
        }

        // date
        let date = chrono::UTC::now().format("%Y-%m-%d").to_string();

        // uuid
        let uuid = uuid::Uuid::new_v4().to_urn_string();

        let mut items = String::new();
        let mut itemrefs = String::new();
        let mut coverref = String::new();
        if let Some(_) = self.book.cover {
            items.push_str("<item id = \"cover.xhtml\" href = \"cover.xhtml\" media-type = \"application/xhtml+xml\" />\n");
            coverref.push_str("<itemref idref = \"cover.xhtml\" />");
        }
        for n in 0..self.toc.len() {
            let filename = filenamer(n);
            items.push_str(&format!("<item id = \"{}\" href = \"{}\" media-type=\"application/xhtml+xml\" />\n",
                                    filename,
                                    filename));
            itemrefs.push_str(&format!("<itemref idref=\"{}\" />\n", filename));
        }
        // oh we must put cover in the manifest too
        if let Some(ref s) = self.book.cover {
            let format = if let Some(ext) = Path::new(s).extension() {
                if let Some(extension) = ext.to_str() {
                    match extension {
                        "png" => "png",
                        "jpg" | "jpeg" => "jpeg",
                        "gif" => "gif",
                        _ => {
                            println!("Warning: could not guess cover format based on extension. Assuming png.");
                            "png"
                        },
                    }
                } else {
                    println!("Warning: could not guess cover format based on extension. Assuming png.");
                    "png"
                }
            } else {
                println!("Warning: could not guess cover format based on extension. Assuming png.");
                "png"
            };
            items.push_str(&format!("<item media-type = \"image/{}\" id =\"{}\" href = \"{}\" />\n", format, s, s));
        }

        let template = mustache::compile_str(OPF);
        let data = self.book.get_mapbuilder()
            .insert_str("optional", optional)
            .insert_str("items", items)
            .insert_str("itemrefs", itemrefs)
            .insert_str("date", date)
            .insert_str("uuid", uuid)
            .insert_str("cover_xhtml", cover_xhtml)
            .insert_str("coverref", coverref)
            .build();
        let mut res:Vec<u8> = vec!();
        template.render_data(&mut res, &data);
        match String::from_utf8(res) {
            Err(_) => Err(Error::Render("generated HTML in content.opf was not valid utf-8")),
            Ok(res) => Ok(res)
        }
    }

    /// Render cover.xhtml
    fn render_cover(&self) -> Result<String> {
        if let Some(ref cover) = self.book.cover {
            let template = mustache::compile_str(COVER);
            let data = self.book.get_mapbuilder()
                .insert_str("cover", cover.clone())
                .build();
            let mut res:Vec<u8> = vec!();
            template.render_data(&mut res, &data);
            match String::from_utf8(res) {
                Err(_) => Err(Error::Render("generated HTML for cover.xhtml was not utf-8 valid")),
                Ok(res) => Ok(res)
            }
        } else {
            panic!("Why is this method called if cover is None???");
        }
    }

    /// Render nav.xhtml
    fn render_nav(&self) -> Result<String> {
        let mut content = String::new();
        for (x, ref title) in self.toc.iter().enumerate() {
            let link = filenamer(x);
            content.push_str(&format!("
{}
\n",
                                 link,
                                 title));
        }

        let template = mustache::compile_str(NAV);
        let data = self.book.get_mapbuilder()
            .insert_str("content", content)
            .build();
        let mut res:Vec<u8> = vec!();
        template.render_data(&mut res, &data);
        match String::from_utf8(res) {
            Err(_) => Err(Error::Render("generated HTML in nav.xhtml was not utf-8 valid")),
            Ok(res) => Ok(res)
        }
    }

    /// Render a chapter
    pub fn render_chapter(&mut self, v: &[Token]) -> Result<String> {
        let mut content = String::new();
        let mut title = String::new();

        for token in v {
            content.push_str(&self.parse_token(&token, &mut title));
        }
        if title.is_empty() {
            if self.current_numbering {
                self.current_chapter += 1;
                title = format!("Chapitre {}", self.current_chapter);
            } else {
                return Err(Error::Render("chapter without h1 tag is not OK if numbering is off"));
            }
        }
        self.toc.push(title.clone());

        let template = mustache::compile_str(try!(self.book.get_template("epub_template")).as_ref());
        let data = self.book.get_mapbuilder()
            .insert_str("content", content)
            .insert_str("chapter_title", title)
            .build();
        let mut res:Vec<u8> = vec!();
        template.render_data(&mut res, &data);
        match String::from_utf8(res) {
            Err(_) => Err(Error::Render("generated HTML was not utf-8 valid")),
            Ok(res) => Ok(res)
        }
    }

    fn parse_token(&mut self, token: &Token, title: &mut String) -> String {
        match *token {
            Token::Header(n, ref vec) => {
                let s = if n == 1 && self.current_numbering {
                    let chapter = self.current_chapter;
                    self.current_chapter += 1;
                    self.book.get_header(chapter, &self.html.render_vec(vec)).unwrap()
                } else {
                    self.html.render_vec(vec)
                };
                if title.is_empty() {
                    *title = s.clone();
                } else {
                    println!("Warning: detected two chapters inside the same markdown file.");
                }
                format!("<h{}>{}</h{}>\n", n, s, n)
            },
            _ => self.html.parse_token(token)
        }
    }
}

fn filenamer(i: usize) -> String {
    format!("chapter_{:03}.xhtml", i)
}
<commit_msg>fixed a bug when multiple chapters in same files were detected for any level of heading<commit_after>use error::{Error,Result};
use token::Token;
use html::HtmlRenderer;
use book::{Book,Number};
use zipper::Zipper;
use templates::epub::*;

use mustache;
use chrono;
use uuid;

use std::io::{Read,Write};
use std::path::Path;
use std::fs::File;

/// Renderer for Epub
///
/// Uses part of the HTML renderer
pub struct EpubRenderer<'a> {
    book: &'a Book,
    current_numbering: bool,
    current_chapter: i32,
    toc: Vec<String>,
    html: HtmlRenderer<'a>,
}

impl<'a> EpubRenderer<'a> {
    /// Creates a new Epub renderer
    pub fn new(book: &'a Book) -> EpubRenderer<'a> {
         EpubRenderer {
            book: book,
            html: HtmlRenderer::new(book),
            current_numbering: book.numbering,
            current_chapter: 1,
            toc: vec!(),
        }
    }

    /// Render a book
    pub fn render_book(&mut self) -> Result<String> {
        let mut zipper = try!(Zipper::new(&self.book.temp_dir, &vec!("META-INF")));

        // Write mimetype
        try!(zipper.write("mimetype", b"application/epub+zip"));

        // Write chapters
        let mut i = 0;
        for &(ref n, ref v) in &self.book.chapters {
            match n {
                &Number::Unnumbered => self.current_numbering = false,
                &Number::Default => self.current_numbering = self.book.numbering,
                &Number::Specified(n) => {
                    self.current_numbering = self.book.numbering;
                    self.current_chapter = n;
                }
            }
            let chapter = try!(self.render_chapter(v));

            try!(zipper.write(&filenamer(i), &chapter.as_bytes()));
            i += 1;
        }

        // Write CSS file
        try!(zipper.write("stylesheet.css",
                          &try!(self.book.get_template("epub_css")).as_bytes()));

        // Write titlepage
        try!(zipper.write("title_page.xhtml", &try!(self.render_titlepage()).as_bytes()));

        // Write file for ibook (why?)
        try!(zipper.write("META-INF/com.apple.ibooks.display-options.xml", IBOOK.as_bytes()));

        // Write container.xml
        try!(zipper.write("META-INF/container.xml", CONTAINER.as_bytes()));

        // Write nav.xhtml
        try!(zipper.write("nav.xhtml", &try!(self.render_nav()).as_bytes()));

        // Write content.opf
        try!(zipper.write("content.opf", &try!(self.render_opf()).as_bytes()));

        // Write toc.ncx
        try!(zipper.write("toc.ncx", &try!(self.render_toc()).as_bytes()));

        // Write the cover (if needs be)
        if let Some(ref cover) = self.book.cover {
            let s: &str = &*cover;
            let mut f = try!(File::open(s).map_err(|_| Error::FileNotFound(String::from(s))));
            let mut content = vec!();
            try!(f.read_to_end(&mut content).map_err(|_| Error::Render("Error while reading cover file")));
            try!(zipper.write(s, &content));

            // also write cover.xhtml
            try!(zipper.write("over.xhtml", &try!(self.render_cover()).as_bytes()));
        }

        if let Some(ref epub_file) = self.book.output_epub {
            let res = try!(zipper.generate_epub(epub_file));
            Ok(res)
        } else {
            Err(Error::Render("no output epub file specified in book config"))
        }
    }

    /// Render the titlepgae
    fn render_titlepage(&self) -> Result<String> {
        let template = mustache::compile_str(TITLE);
        let data = self.book.get_mapbuilder()
            .build();
        let mut res:Vec<u8> = vec!();
        template.render_data(&mut res, &data);
        match String::from_utf8(res) {
            Err(_) => Err(Error::Render("generated HTML in titlepage was not utf-8 valid")),
            Ok(res) => Ok(res)
        }
    }

    /// Render toc.ncx
    fn render_toc(&self) -> Result<String> {
        let mut nav_points = String::new();

        for (n, ref title) in self.toc.iter().enumerate() {
            let filename = filenamer(n);
            let id = format!("navPoint-{}", n + 1);
            nav_points.push_str(&format!(
"   <navPoint id=\"{}\">
      <navLabel>
        <text>{}</text>
      </navLabel>
      <content src = \"{}\" />
    </navPoint>\n", id, title, filename));
        }
        let template = mustache::compile_str(TOC);
        let data = self.book.get_mapbuilder()
            .insert_str("nav_points", nav_points)
            .build();
        let mut res:Vec<u8> = vec!();
        template.render_data(&mut res, &data);
        match String::from_utf8(res) {
            Err(_) => Err(Error::Render("generated HTML in toc.ncx was not valid utf-8")),
            Ok(res) => Ok(res)
        }
    }

    /// Render content.opf
    fn render_opf(&self) -> Result<String> {
        // Optional metadata
        let mut cover_xhtml = String::new();
        let mut optional = String::new();
        if let Some(ref s) = self.book.description {
            optional.push_str(&format!("<dc:description>{}</dc:description>\n", s));
        }
        if let Some(ref s) = self.book.subject {
            optional.push_str(&format!("<dc:subject>{}</dc:subject>\n", s));
        }
        if let Some(ref s) = self.book.cover {
            optional.push_str(&format!("<meta name = \"cover\" content = \"{}\" />\n", s));
            cover_xhtml.push_str(&format!("<reference type=\"cover\" title=\"Cover\" href=\"cover.xhtml\" />"));
        }

        // date
        let date = chrono::UTC::now().format("%Y-%m-%d").to_string();

        // uuid
        let uuid = uuid::Uuid::new_v4().to_urn_string();

        let mut items = String::new();
        let mut itemrefs = String::new();
        let mut coverref = String::new();
        if let Some(_) = self.book.cover {
            items.push_str("<item id = \"cover.xhtml\" href = \"cover.xhtml\" media-type = \"application/xhtml+xml\" />\n");
            coverref.push_str("<itemref idref = \"cover.xhtml\" />");
        }
        for n in 0..self.toc.len() {
            let filename = filenamer(n);
            items.push_str(&format!("<item id = \"{}\" href = \"{}\" media-type=\"application/xhtml+xml\" />\n",
                                    filename,
                                    filename));
            itemrefs.push_str(&format!("<itemref idref=\"{}\" />\n", filename));
        }
        // oh we must put cover in the manifest too
        if let Some(ref s) = self.book.cover {
            let format = if let Some(ext) = Path::new(s).extension() {
                if let Some(extension) = ext.to_str() {
                    match extension {
                        "png" => "png",
                        "jpg" | "jpeg" => "jpeg",
                        "gif" => "gif",
                        _ => {
                            println!("Warning: could not guess cover format based on extension. Assuming png.");
                            "png"
                        },
                    }
                } else {
                    println!("Warning: could not guess cover format based on extension. Assuming png.");
                    "png"
                }
            } else {
                println!("Warning: could not guess cover format based on extension. Assuming png.");
                "png"
            };
            items.push_str(&format!("<item media-type = \"image/{}\" id =\"{}\" href = \"{}\" />\n", format, s, s));
        }

        let template = mustache::compile_str(OPF);
        let data = self.book.get_mapbuilder()
            .insert_str("optional", optional)
            .insert_str("items", items)
            .insert_str("itemrefs", itemrefs)
            .insert_str("date", date)
            .insert_str("uuid", uuid)
            .insert_str("cover_xhtml", cover_xhtml)
            .insert_str("coverref", coverref)
            .build();
        let mut res:Vec<u8> = vec!();
        template.render_data(&mut res, &data);
        match String::from_utf8(res) {
            Err(_) => Err(Error::Render("generated HTML in content.opf was not valid utf-8")),
            Ok(res) => Ok(res)
        }
    }

    /// Render cover.xhtml
    fn render_cover(&self) -> Result<String> {
        if let Some(ref cover) = self.book.cover {
            let template = mustache::compile_str(COVER);
            let data = self.book.get_mapbuilder()
                .insert_str("cover", cover.clone())
                .build();
            let mut res:Vec<u8> = vec!();
            template.render_data(&mut res, &data);
            match String::from_utf8(res) {
                Err(_) => Err(Error::Render("generated HTML for cover.xhtml was not utf-8 valid")),
                Ok(res) => Ok(res)
            }
        } else {
            panic!("Why is this method called if cover is None???");
        }
    }

    /// Render nav.xhtml
    fn render_nav(&self) -> Result<String> {
        let mut content = String::new();
        for (x, ref title) in self.toc.iter().enumerate() {
            let link = filenamer(x);
            content.push_str(&format!("
{}
\n",
                                 link,
                                 title));
        }

        let template = mustache::compile_str(NAV);
        let data = self.book.get_mapbuilder()
            .insert_str("content", content)
            .build();
        let mut res:Vec<u8> = vec!();
        template.render_data(&mut res, &data);
        match String::from_utf8(res) {
            Err(_) => Err(Error::Render("generated HTML in nav.xhtml was not utf-8 valid")),
            Ok(res) => Ok(res)
        }
    }

    /// Render a chapter
    pub fn render_chapter(&mut self, v: &[Token]) -> Result<String> {
        let mut content = String::new();
        let mut title = String::new();

        for token in v {
            content.push_str(&self.parse_token(&token, &mut title));
        }
        if title.is_empty() {
            if self.current_numbering {
                self.current_chapter += 1;
                title = format!("Chapitre {}", self.current_chapter);
            } else {
                return Err(Error::Render("chapter without h1 tag is not OK if numbering is off"));
            }
        }
        self.toc.push(title.clone());

        let template = mustache::compile_str(try!(self.book.get_template("epub_template")).as_ref());
        let data = self.book.get_mapbuilder()
            .insert_str("content", content)
            .insert_str("chapter_title", title)
            .build();
        let mut res:Vec<u8> = vec!();
        template.render_data(&mut res, &data);
        match String::from_utf8(res) {
            Err(_) => Err(Error::Render("generated HTML was not utf-8 valid")),
            Ok(res) => Ok(res)
        }
    }

    fn parse_token(&mut self, token: &Token, title: &mut String) -> String {
        match *token {
            Token::Header(n, ref vec) => {
                let s = if n == 1 && self.current_numbering {
                    let chapter = self.current_chapter;
                    self.current_chapter += 1;
                    self.book.get_header(chapter, &self.html.render_vec(vec)).unwrap()
                } else {
                    self.html.render_vec(vec)
                };
                if n == 1 {
                    if title.is_empty() {
                        *title = s.clone();
                    } else {
                        println!("Warning: detected two chapters inside the same markdown file.");
                        println!("prev_chapter: {}, old_chapter: {}", title, s);
                    }
                }
                format!("<h{}>{}</h{}>\n", n, s, n)
            },
            _ => self.html.parse_token(token)
        }
    }
}

fn filenamer(i: usize) -> String {
    format!("chapter_{:03}.xhtml", i)
}
<|endoftext|>


<commit_before>use std::mem;
use std::sync;

pub struct Lazy<T> {
    pub lock: sync::Once,
    pub ptr: *const T,
}

impl<T> Lazy<T> {
    pub fn get<F>(&'static self, init: F) -> &'static T
        where F : Fn() -> T
    {
        unsafe {
            self.lock.call_once(|| {
                mem::transmute::<&Lazy<T>, &mut Lazy<T>>(self).ptr = mem::transmute(Box::new(init()))
            });
            mem::transmute(self.ptr)
        }
    }
}

pub const ONCE_INIT: sync::Once = sync::ONCE_INIT;
<commit_msg>replace transmute with safer Box functions<commit_after>use std::mem;
use std::sync;
use std::boxed;

pub struct Lazy<T> {
    pub lock: sync::Once,
    pub ptr: *const T,
}

impl<T> Lazy<T> {
    pub fn get<F>(&'static self, init: F) -> &'static T
        where F : Fn() -> T
    {
        unsafe {
            self.lock.call_once(|| {
                mem::transmute::<&Lazy<T>, &mut Lazy<T>>(self).ptr = boxed::into_raw(Box::new(init()));
            });
            mem::transmute(self.ptr)
        }
    }
}

pub const ONCE_INIT: sync::Once = sync::ONCE_INIT;
<|endoftext|>


<commit_before>/*
Module: rand

Random number generation
*/
#[abi = "cdecl"]
native mod rustrt {
    type rctx;
    fn rand_new() -> rctx;
    fn rand_next(c: rctx) -> u32;
    fn rand_free(c: rctx);
}

/* Section: Types */

/*
Obj: rng

A random number generator
*/
type rng = obj {
    /*
    Method: next

    Return the next random integer
    */
    fn next() -> u32;

    /*
    Method: next_float

    Return the next random float
    */
    fn next_float() -> float;
};

resource rand_res(c: rustrt::rctx) { rustrt::rand_free(c); }

/* Section: Operations */

/*
Function: mk_rng

Create a random number generator
*/
fn mk_rng() -> rng {
    obj rt_rng(c: @rand_res) {
        fn next() -> u32 { ret rustrt::rand_next(**c); }
        fn next_float() -> float {
          let u1 = rustrt::rand_next(**c) as float;
          let u2 = rustrt::rand_next(**c) as float;
          let u3 = rustrt::rand_next(**c) as float;
          let scale = u32::max_value as float;
          ret ((u1 / scale + u2) / scale + u3) / scale;
        }
    }
    ret rt_rng(@rand_res(rustrt::rand_new()));
}
// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>std: add fs::mkdir(), rng.gen_str(), tempfile::mkdtemp()<commit_after>/*
Module: rand

Random number generation
*/
#[abi = "cdecl"]
native mod rustrt {
    type rctx;
    fn rand_new() -> rctx;
    fn rand_next(c: rctx) -> u32;
    fn rand_free(c: rctx);
}

/* Section: Types */

/*
Obj: rng

A random number generator
*/
type rng = obj {
    /*
    Method: next

    Return the next random integer
    */
    fn next() -> u32;

    /*
    Method: next_float

    Return the next random float
    */
    fn next_float() -> float;

    /*
    Method: gen_str

    Return a random string composed of A-Z, a-z, 0-9.
    */
    fn gen_str(len: uint) -> str;
};

resource rand_res(c: rustrt::rctx) { rustrt::rand_free(c); }

/* Section: Operations */

/*
Function: mk_rng

Create a random number generator
*/
fn mk_rng() -> rng {
    obj rt_rng(c: @rand_res) {
        fn next() -> u32 { ret rustrt::rand_next(**c); }
        fn next_float() -> float {
          let u1 = rustrt::rand_next(**c) as float;
          let u2 = rustrt::rand_next(**c) as float;
          let u3 = rustrt::rand_next(**c) as float;
          let scale = u32::max_value as float;
          ret ((u1 / scale + u2) / scale + u3) / scale;
        }
        fn gen_str(len: uint) -> str {
            let charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
                          "abcdefghijklmnopqrstuvwxyz" +
                          "0123456789";
            let s = "";
            let i = 0u;
            while (i < len) {
                let n = rustrt::rand_next(**c) as uint % str::char_len(charset);
                s = s + str::from_char(str::char_at(charset, n));
                i += 1u;
            }
            s
        }
    }
    ret rt_rng(@rand_res(rustrt::rand_new()));
}
// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::{
    fs::OpenOptions,
    os::unix::io::AsRawFd,
    panic,
    path::{Path, PathBuf},
};

use loopdev::{LoopControl, LoopDevice};
use nix;
use tempfile;

use devicemapper::{Bytes, Sectors, IEC};

use crate::engine::strat_engine::tests::{logger::init_logger, util::clean_up};

/// Ways of specifying range of numbers of devices to use for tests.
/// Unlike real tests, there is no AtLeast constructor, as, at least in theory
/// there is no upper bound to the number of loop devices that can be made.
/// The default value for size, if not specified, is 1 GiB.
pub enum DeviceLimits {
    /// Require exactly the number of devices specified.
    /// Specify their size in Sectors.
    Exactly(usize, Option<Sectors>),
    /// Required exactly the number of devices specified in the first and
    /// second argument to the constructors. Specify their size in Sectors.
    Range(usize, usize, Option<Sectors>),
}

pub struct LoopTestDev {
    ld: LoopDevice,
}

impl LoopTestDev {
    /// Create a new loopbacked device.
    /// Create its backing store of specified size. The file is sparse but
    /// will appear to be zeroed.
    pub fn new(lc: &LoopControl, path: &Path, size: Option<Sectors>) -> LoopTestDev {
        let size = size.unwrap_or_else(|| Bytes(IEC::Gi).sectors());

        let f = OpenOptions::new()
            .read(true)
            .write(true)
            .create(true)
            .open(&path)
            .unwrap();

        nix::unistd::ftruncate(f.as_raw_fd(), *size.bytes() as nix::libc::off_t).unwrap();
        f.sync_all().unwrap();

        let ld = lc.next_free().unwrap();
        ld.attach_file(path).unwrap();

        LoopTestDev { ld }
    }
}

impl Drop for LoopTestDev {
    fn drop(&mut self) {
        self.ld.detach().unwrap()
    }
}

/// Get a list of counts of devices to use for tests.
fn get_device_counts(limits: &DeviceLimits) -> Vec<(usize, Option<Sectors>)> {
    match limits {
        DeviceLimits::Exactly(num, size) => vec![(*num, *size)],
        DeviceLimits::Range(lower, upper, size) => {
            assert!(lower < upper);
            vec![(*lower, *size), (*upper, *size)]
        }
    }
}

/// Setup count loop backed devices in dir of specified size.
fn get_devices(count: usize, size: Option<Sectors>, dir: &tempfile::TempDir) -> Vec<LoopTestDev> {
    let lc = LoopControl::open().unwrap();
    let mut loop_devices = Vec::new();

    for index in 0..count {
        let path = dir.path().join(format!("store{}", &index));
        loop_devices.push(LoopTestDev::new(&lc, &path, size));
    }
    loop_devices
}

/// Run the designated tests according to the specification.
pub fn test_with_spec<F>(limits: &DeviceLimits, test: F)
where
    F: Fn(&[&Path]) -> () + panic::RefUnwindSafe,
{
    let counts = get_device_counts(limits);

    init_logger();

    for (count, size) in counts {
        let tmpdir = tempfile::Builder::new()
            .prefix("stratis")
            .tempdir()
            .unwrap();
        let loop_devices: Vec<LoopTestDev> = get_devices(count, size, &tmpdir);
        let device_paths: Vec<PathBuf> =
            loop_devices.iter().map(|x| x.ld.path().unwrap()).collect();
        let device_paths: Vec<&Path> = device_paths.iter().map(|x| x.as_path()).collect();

        clean_up().unwrap();

        let result = panic::catch_unwind(|| {
            test(&device_paths);
        });
        let tear_down = clean_up();

        result.unwrap();
        tear_down.unwrap();
    }
}
<commit_msg>Fix documentation for ranges of test devices<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

use std::{
    fs::OpenOptions,
    os::unix::io::AsRawFd,
    panic,
    path::{Path, PathBuf},
};

use loopdev::{LoopControl, LoopDevice};
use nix;
use tempfile;

use devicemapper::{Bytes, Sectors, IEC};

use crate::engine::strat_engine::tests::{logger::init_logger, util::clean_up};

/// Ways of specifying range of numbers of devices to use for tests.
/// Unlike real tests, there is no AtLeast constructor, as, at least in theory
/// there is no upper bound to the number of loop devices that can be made.
/// The default value for size, if not specified, is 1 GiB.
pub enum DeviceLimits {
    /// Require exactly the number of devices specified.
    /// Specify their size in Sectors.
    Exactly(usize, Option<Sectors>),
    /// Specify a minimum and maximum number of devices in the first and
    /// second argument to the constructors. Specify their size in Sectors.
    Range(usize, usize, Option<Sectors>),
}

pub struct LoopTestDev {
    ld: LoopDevice,
}

impl LoopTestDev {
    /// Create a new loopbacked device.
    /// Create its backing store of specified size. The file is sparse but
    /// will appear to be zeroed.
    pub fn new(lc: &LoopControl, path: &Path, size: Option<Sectors>) -> LoopTestDev {
        let size = size.unwrap_or_else(|| Bytes(IEC::Gi).sectors());

        let f = OpenOptions::new()
            .read(true)
            .write(true)
            .create(true)
            .open(&path)
            .unwrap();

        nix::unistd::ftruncate(f.as_raw_fd(), *size.bytes() as nix::libc::off_t).unwrap();
        f.sync_all().unwrap();

        let ld = lc.next_free().unwrap();
        ld.attach_file(path).unwrap();

        LoopTestDev { ld }
    }
}

impl Drop for LoopTestDev {
    fn drop(&mut self) {
        self.ld.detach().unwrap()
    }
}

/// Get a list of counts of devices to use for tests.
fn get_device_counts(limits: &DeviceLimits) -> Vec<(usize, Option<Sectors>)> {
    match limits {
        DeviceLimits::Exactly(num, size) => vec![(*num, *size)],
        DeviceLimits::Range(lower, upper, size) => {
            assert!(lower < upper);
            vec![(*lower, *size), (*upper, *size)]
        }
    }
}

/// Setup count loop backed devices in dir of specified size.
fn get_devices(count: usize, size: Option<Sectors>, dir: &tempfile::TempDir) -> Vec<LoopTestDev> {
    let lc = LoopControl::open().unwrap();
    let mut loop_devices = Vec::new();

    for index in 0..count {
        let path = dir.path().join(format!("store{}", &index));
        loop_devices.push(LoopTestDev::new(&lc, &path, size));
    }
    loop_devices
}

/// Run the designated tests according to the specification.
pub fn test_with_spec<F>(limits: &DeviceLimits, test: F)
where
    F: Fn(&[&Path]) -> () + panic::RefUnwindSafe,
{
    let counts = get_device_counts(limits);

    init_logger();

    for (count, size) in counts {
        let tmpdir = tempfile::Builder::new()
            .prefix("stratis")
            .tempdir()
            .unwrap();
        let loop_devices: Vec<LoopTestDev> = get_devices(count, size, &tmpdir);
        let device_paths: Vec<PathBuf> =
            loop_devices.iter().map(|x| x.ld.path().unwrap()).collect();
        let device_paths: Vec<&Path> = device_paths.iter().map(|x| x.as_path()).collect();

        clean_up().unwrap();

        let result = panic::catch_unwind(|| {
            test(&device_paths);
        });
        let tear_down = clean_up();

        result.unwrap();
        tear_down.unwrap();
    }
}
<|endoftext|>


<commit_before>#![crate_id = "js#0.1-pre"]
#![comment = "Javascript execution"]
#![license = "MIT"]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(
	html_favicon_url = "http://tombebbington.github.io/favicon.png",
	html_root_url = "http://tombebbington.github.io/js.rs/"
)]
#![experimental]
#![feature(phase, globs)]
#![deny(non_uppercase_statics, missing_doc, unnecessary_parens, unrecognized_lint, unreachable_code, unnecessary_allocation, unnecessary_typecast, unnecessary_allocation, uppercase_variables, non_camel_case_types, unused_must_use)]

//! This crate provides a Javascript execution library with an
//! JITCompiler and a Javascript standard library.
extern crate collections;
extern crate syntax = "js_syntax";
extern crate rand;
extern crate serialize;
extern crate time;
extern crate url;
extern crate jit;
#[phase(syntax)]
extern crate jit_macro;
#[phase(syntax, link)]
extern crate log;
/// The execution engines
pub mod run {
	/// Defines the base executor trait which the execution engines derive from
	pub mod exec;
	/// Just-In-Time Compilation using libJIT
	pub mod jit;
}
/// The standard Javascript library
pub mod stdlib {
	/// Javascript values, utility methods and conversion between Javascript values and Rust values
	pub mod value;
	/// The global `Function` object and function value representations
	pub mod function;
	/// The global `Object` object
	pub mod object;
	/// The global `Array` object
	pub mod array;
	/// The global `console` object
	pub mod console;
	/// The global `Math` object
	pub mod math;
	/// The global `JSON` object
	pub mod json;
	/// The global `Number` object with related functions and constants
	pub mod number;
	/// The global `Error` object
	pub mod error;
	/// Contains global methods concerning URIs
	pub mod uri;
	/// The global `String` object
	pub mod string;
}<commit_msg>Update with `plugin` instead of `macro`<commit_after>#![crate_id = "js#0.1-pre"]
#![comment = "Javascript execution"]
#![license = "MIT"]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(
	html_favicon_url = "http://tombebbington.github.io/favicon.png",
	html_root_url = "http://tombebbington.github.io/js.rs/"
)]
#![experimental]
#![feature(phase, globs)]
#![deny(non_uppercase_statics, missing_doc, unnecessary_parens, unrecognized_lint, unreachable_code, unnecessary_allocation, unnecessary_typecast, unnecessary_allocation, uppercase_variables, non_camel_case_types, unused_must_use)]

//! This crate provides a Javascript execution library with an
//! JITCompiler and a Javascript standard library.
extern crate collections;
extern crate syntax = "js_syntax";
extern crate rand;
extern crate serialize;
extern crate time;
extern crate url;
extern crate jit;
#[phase(plugin)]
extern crate jit_macro;
#[phase(plugin, link)]
extern crate log;
/// The execution engines
pub mod run {
	/// Defines the base executor trait which the execution engines derive from
	pub mod exec;
	/// Just-In-Time Compilation using libJIT
	pub mod jit;
}
/// The standard Javascript library
pub mod stdlib {
	/// Javascript values, utility methods and conversion between Javascript values and Rust values
	pub mod value;
	/// The global `Function` object and function value representations
	pub mod function;
	/// The global `Object` object
	pub mod object;
	/// The global `Array` object
	pub mod array;
	/// The global `console` object
	pub mod console;
	/// The global `Math` object
	pub mod math;
	/// The global `JSON` object
	pub mod json;
	/// The global `Number` object with related functions and constants
	pub mod number;
	/// The global `Error` object
	pub mod error;
	/// Contains global methods concerning URIs
	pub mod uri;
	/// The global `String` object
	pub mod string;
}<|endoftext|>


<commit_before>use syntax::{
    ast::{self, AttrsOwner},
    AstNode, AstToken,
};

use crate::{utils::test_related_attribute, AssistContext, AssistId, AssistKind, Assists};

// Assist: ignore_test
//
// Adds `#[ignore]` attribute to the test.
//
// ```
// <|>#[test]
// fn arithmetics {
//     assert_eq!(2 + 2, 5);
// }
// ```
// ->
// ```
// #[test]
// #[ignore]
// fn arithmetics {
//     assert_eq!(2 + 2, 5);
// }
// ```
pub(crate) fn ignore_test(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let attr: ast::Attr = ctx.find_node_at_offset()?;
    let func = attr.syntax().parent().and_then(ast::Fn::cast)?;
    let attr = test_related_attribute(&func)?;

    match has_ignore_attribute(&func) {
        None => acc.add(
            AssistId("ignore_test", AssistKind::None),
            "Ignore this test",
            attr.syntax().text_range(),
            |builder| builder.insert(attr.syntax().text_range().end(), &format!("\n#[ignore]")),
        ),
        Some(ignore_attr) => acc.add(
            AssistId("unignore_test", AssistKind::None),
            "Re-enable this test",
            ignore_attr.syntax().text_range(),
            |builder| {
                builder.delete(ignore_attr.syntax().text_range());
                let whitespace = ignore_attr
                    .syntax()
                    .next_sibling_or_token()
                    .and_then(|x| x.into_token())
                    .and_then(ast::Whitespace::cast);
                if let Some(whitespace) = whitespace {
                    builder.delete(whitespace.syntax().text_range());
                }
            },
        ),
    }
}

fn has_ignore_attribute(fn_def: &ast::Fn) -> Option<ast::Attr> {
    fn_def.attrs().find_map(|attr| {
        if attr.path()?.syntax().text().to_string() == "ignore" {
            Some(attr)
        } else {
            None
        }
    })
}

#[cfg(test)]
mod tests {
    use super::ignore_test;
    use crate::tests::check_assist;

    #[test]
    fn test_base_case() {
        check_assist(
            ignore_test,
            r#"
            #[test<|>]
            fn test() {}
            "#,
            r#"
            #[test]
            #[ignore]
            fn test() {}
            "#,
        )
    }

    #[test]
    fn test_unignore() {
        check_assist(
            ignore_test,
            r#"
            #[test<|>]
            #[ignore]
            fn test() {}
            "#,
            r#"
            #[test]
            fn test() {}
            "#,
        )
    }
}
<commit_msg>Avoid string allocations in ignore_test<commit_after>use syntax::{
    ast::{self, AttrsOwner},
    AstNode, AstToken,
};

use crate::{utils::test_related_attribute, AssistContext, AssistId, AssistKind, Assists};

// Assist: ignore_test
//
// Adds `#[ignore]` attribute to the test.
//
// ```
// <|>#[test]
// fn arithmetics {
//     assert_eq!(2 + 2, 5);
// }
// ```
// ->
// ```
// #[test]
// #[ignore]
// fn arithmetics {
//     assert_eq!(2 + 2, 5);
// }
// ```
pub(crate) fn ignore_test(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let attr: ast::Attr = ctx.find_node_at_offset()?;
    let func = attr.syntax().parent().and_then(ast::Fn::cast)?;
    let attr = test_related_attribute(&func)?;

    match has_ignore_attribute(&func) {
        None => acc.add(
            AssistId("ignore_test", AssistKind::None),
            "Ignore this test",
            attr.syntax().text_range(),
            |builder| builder.insert(attr.syntax().text_range().end(), &format!("\n#[ignore]")),
        ),
        Some(ignore_attr) => acc.add(
            AssistId("unignore_test", AssistKind::None),
            "Re-enable this test",
            ignore_attr.syntax().text_range(),
            |builder| {
                builder.delete(ignore_attr.syntax().text_range());
                let whitespace = ignore_attr
                    .syntax()
                    .next_sibling_or_token()
                    .and_then(|x| x.into_token())
                    .and_then(ast::Whitespace::cast);
                if let Some(whitespace) = whitespace {
                    builder.delete(whitespace.syntax().text_range());
                }
            },
        ),
    }
}

fn has_ignore_attribute(fn_def: &ast::Fn) -> Option<ast::Attr> {
    fn_def.attrs().find_map(|attr| {
        if attr.path()?.syntax().text() == "ignore" {
            Some(attr)
        } else {
            None
        }
    })
}

#[cfg(test)]
mod tests {
    use super::ignore_test;
    use crate::tests::check_assist;

    #[test]
    fn test_base_case() {
        check_assist(
            ignore_test,
            r#"
            #[test<|>]
            fn test() {}
            "#,
            r#"
            #[test]
            #[ignore]
            fn test() {}
            "#,
        )
    }

    #[test]
    fn test_unignore() {
        check_assist(
            ignore_test,
            r#"
            #[test<|>]
            #[ignore]
            fn test() {}
            "#,
            r#"
            #[test]
            fn test() {}
            "#,
        )
    }
}
<|endoftext|>


<commit_before>use error::Error;
use json;
use std::default::Default;

#[derive(Debug, Default)]
pub struct Manifest {
    pub edition: Edition,
    pub targets: Vec<Target>,
}

impl Manifest {
    fn from_str(src: &str) -> Result<Self, Error> {
        let mut j = json::parse(src).map_err(Error::InvalidManifestJson)?;

        let edition: Edition = match j["edition"].as_str() {
            Some("2015") => Edition::E2015,
            Some("2018") => Edition::E2018,
            Some(unknown) => panic!("Unrecognized value for edition \"{}\"", unknown),
            None => Edition::default(),
        };

        let targets: Vec<Target> = j["targets"].members_mut().map(Target::from_json).collect();

        Result::Ok(Manifest { edition, targets })
    }
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Edition {
    E2015,
    E2018,
}

impl Default for Edition {
    fn default() -> Self {
        Edition::E2015
    }
}

#[derive(Debug, PartialEq)]
pub enum Target {
    Lib {
        kind: Vec<String>,
        crate_types: Vec<String>,
        name: String,
        src_path: String,
        edition: Option<String>,
    },
}

impl Target {
    fn from_json(j: &mut json::JsonValue) -> Target {
        Target::Lib {
            kind: {
                assert!(j["kind"].is_array());
                j["kind"]
                    .members_mut()
                    .map(|k| k.take_string().unwrap())
                    .collect()
            },
            crate_types: {
                assert!(j["crate_types"].is_array());
                j["crate_types"]
                    .members_mut()
                    .map(|k| k.take_string().unwrap())
                    .collect()
            },
            name: j["name"].take_string().expect("name is missing"),
            src_path: j["src_path"].take_string().expect("src_path is missing"),
            edition: j["edition"].take_string(),
        }
    }
}

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

    #[test]
    fn manifest_with_edition2018_can_be_parsed() {
        let manifest_filename = "test-resources/example-edition-2018.json";
        let manifest_str: String =
            fs::read_to_string(manifest_filename).expect("manifest file cannot be read");
        let manifest = Manifest::from_str(&manifest_str).expect("manifest cannot be read");
        assert_eq!(Edition::E2018, manifest.edition);
    }

    #[test]
    fn manifest_with_edition2015_can_be_parsed() {
        let manifest_filename = "test-resources/example-edition-2015.json";
        let manifest_str: String =
            fs::read_to_string(manifest_filename).expect("manifest file cannot be read");
        let manifest = Manifest::from_str(&manifest_str).expect("manifest cannot be read");
        assert_eq!(Edition::E2015, manifest.edition);
    }

    #[test]
    fn manifest_without_edition_can_be_parsed() {
        let manifest_filename = "test-resources/example-no-edition.json";
        let manifest_str: String =
            fs::read_to_string(manifest_filename).expect("manifest file cannot be read");
        let manifest = Manifest::from_str(&manifest_str).expect("manifest cannot be read");
        assert_eq!(Edition::E2015, manifest.edition);
    }

    #[test]
    fn manifest_for_simple_lib() {
        let manifest_filename = "test-resources/example-lib.json";
        let manifest_str: String =
            fs::read_to_string(manifest_filename).expect("manifest file cannot be read");
        let manifest = Manifest::from_str(&manifest_str).expect("manifest cannot be read");
        assert_eq!(
            Target::Lib {
                kind: vec!(String::from("lib")),
                crate_types: vec!(String::from("lib")),
                name: String::from("example-lib"),
                src_path: String::from("/home/muhuk/Documents/code/example-lib/src/lib.rs"),
                edition: Some(String::from("2018"))
            },
            manifest.targets[0]
        );
    }
}
<commit_msg>Refactor repetition<commit_after>use error::Error;
use json;
use std::default::Default;

#[derive(Debug, Default)]
pub struct Manifest {
    pub edition: Edition,
    pub targets: Vec<Target>,
}

impl Manifest {
    fn from_str(src: &str) -> Result<Self, Error> {
        let mut j = json::parse(src).map_err(Error::InvalidManifestJson)?;

        let edition: Edition = match j["edition"].as_str() {
            Some("2015") => Edition::E2015,
            Some("2018") => Edition::E2018,
            Some(unknown) => panic!("Unrecognized value for edition \"{}\"", unknown),
            None => Edition::default(),
        };

        let targets: Vec<Target> = j["targets"].members_mut().map(Target::from_json).collect();

        Result::Ok(Manifest { edition, targets })
    }
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Edition {
    E2015,
    E2018,
}

impl Default for Edition {
    fn default() -> Self {
        Edition::E2015
    }
}

#[derive(Debug, PartialEq)]
pub enum Target {
    Lib {
        kind: Vec<String>,
        crate_types: Vec<String>,
        name: String,
        src_path: String,
        edition: Option<String>,
    },
}

impl Target {
    fn from_json(j: &mut json::JsonValue) -> Target {
        Target::Lib {
            kind: {
                assert!(j["kind"].is_array());
                j["kind"]
                    .members_mut()
                    .map(|k| k.take_string().unwrap())
                    .collect()
            },
            crate_types: {
                assert!(j["crate_types"].is_array());
                j["crate_types"]
                    .members_mut()
                    .map(|k| k.take_string().unwrap())
                    .collect()
            },
            name: j["name"].take_string().expect("name is missing"),
            src_path: j["src_path"].take_string().expect("src_path is missing"),
            edition: j["edition"].take_string(),
        }
    }
}

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

    fn read_manifest(filename: &str) -> Manifest {
        let manifest_str: String =
            fs::read_to_string(filename).expect("manifest file cannot be read");
        Manifest::from_str(&manifest_str).expect("manifest cannot be read")
    }

    #[test]
    fn manifest_with_edition2018_can_be_parsed() {
        let manifest = read_manifest("test-resources/example-edition-2018.json");
        assert_eq!(Edition::E2018, manifest.edition);
    }

    #[test]
    fn manifest_with_edition2015_can_be_parsed() {
        let manifest = read_manifest("test-resources/example-edition-2015.json");
        assert_eq!(Edition::E2015, manifest.edition);
    }

    #[test]
    fn manifest_without_edition_can_be_parsed() {
        let manifest = read_manifest("test-resources/example-no-edition.json");
        assert_eq!(Edition::E2015, manifest.edition);
    }

    #[test]
    fn manifest_for_simple_lib() {
        let manifest = read_manifest("test-resources/example-lib.json");
        assert_eq!(
            Target::Lib {
                kind: vec!(String::from("lib")),
                crate_types: vec!(String::from("lib")),
                name: String::from("example-lib"),
                src_path: String::from("/home/muhuk/Documents/code/example-lib/src/lib.rs"),
                edition: Some(String::from("2018"))
            },
            manifest.targets[0]
        );
    }
}
<|endoftext|>