<commit_before>use std::fmt;
use world::{HEX_INNER_RADIUS, HEX_OUTER_RADIUS};
use super::{AxialType, DefaultFloat, Vector2f};
use math::cgmath::{VectorSpace, Zero};
use std::ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Rem,
               RemAssign, Sub, SubAssign};
use math::cgmath::prelude::{Array, MetricSpace};
use std::cmp;

/// A 2-dimensional vector in axial coordinates. See [here][hex-blog] for more
/// information.
///
/// [hex-blog]: http://www.redblobgames.com/grids/hexagons/#coordinates
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[repr(C, packed)]
pub struct AxialVector {
    pub q: AxialType,
    pub r: AxialType,
}

// TODO: implement cgmath::Zero
// TODO: implement cgmath::Array
// TODO: implement cgmath::MatricSpace
// TODO: implement cgmath::VectorSpace
// TODO: implement cgmath::InnerSpace
// TODO: implement ops::{ ... }
// TODO: Add `unit_q()` and `unit_r()` (see `Vector2::unit_x()` for reference)
// For all of the above, see
// http://bjz.github.io/cgmath/cgmath/struct.Vector2.html
//

/// AxialVector defines a vector specificly for Axial cordinate system.
impl AxialVector {
    pub fn new(q: AxialType, r: AxialType) -> Self {
        AxialVector { q: q, r: r }
    }

    /// Returns the position of the hexagons center in the standard coordinate
    /// system using `world::{HEX_INNER_RADIUS, HEX_OUTER_RADIUS}`.
    pub fn to_real(&self) -> Vector2f {
        Vector2f {
            x: ((2 * self.q + self.r) as DefaultFloat) * HEX_INNER_RADIUS,
            y: (self.r as DefaultFloat) * (3.0 / 2.0) * HEX_OUTER_RADIUS,
        }
    }

    /// Returns the `s` component of corresponding cube coordinates. In cube
    /// coordinates 'q + r + s = 0', so saving `s` is redundant and can be
    /// calculated on the fly when needed.
    pub fn s(&self) -> AxialType {
        -self.q - self.r
    }

    /// unit_q creates an default AxialVector with q:1 r:0.
    pub fn unit_q() -> AxialVector {
        AxialVector { q: 1, r: 0 }
    }

    /// unit_r creates an default AxialVector with q:0 r:1.
    pub fn unit_r() -> AxialVector {
        AxialVector { q: 0, r: 1 }
    }
}

impl fmt::Debug for AxialVector {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_tuple("")
            .field(&self.q)
            .field(&self.r)
            .finish()
    }
}

// ********************* Basic Arithmetic (OPS) *********************

impl Neg for AxialVector {
    type Output = AxialVector;

    fn neg(self) -> Self::Output {
        AxialVector {
            q: -self.q,
            r: -self.r,
        }
    }
}

impl Add<AxialVector> for AxialVector {
    type Output = AxialVector;

    fn add(self, arg2: AxialVector) -> AxialVector {
        AxialVector {
            r: self.r + arg2.r,
            q: self.q + arg2.q,
        }
    }
}

impl AddAssign<AxialVector> for AxialVector {

    fn add_assign(&mut self, arg2: AxialVector) {
        self.r += arg2.r;
        self.q += arg2.q;

    }
}

impl Sub<AxialVector> for AxialVector {
    type Output = AxialVector;

    fn sub(self, arg2: AxialVector) -> AxialVector {
        AxialVector {
            r: self.r - arg2.r,
            q: self.q - arg2.q,
        }
    }
}

impl SubAssign<AxialVector> for AxialVector {

    fn sub_assign(&mut self, arg2: AxialVector) {
        self.r -= arg2.r;
        self.q -= arg2.q;

    }
}

impl Mul<AxialType> for AxialVector {
    type Output = AxialVector;

    fn mul(self, arg2: AxialType) -> AxialVector {
        AxialVector {
            r: self.r * arg2,
            q: self.q * arg2,
        }
    }
}

impl MulAssign<AxialType> for AxialVector {

    fn mul_assign(&mut self, arg2: AxialType) {
        self.r *= arg2;
        self.q *= arg2;

    }
}

impl Div<AxialType> for AxialVector {
    type Output = AxialVector;

    fn div(self, arg2: AxialType) -> AxialVector {
        AxialVector {
            r: self.r / arg2,
            q: self.q / arg2,
        }
    }
}

impl DivAssign<AxialType> for AxialVector {

    fn div_assign(&mut self, arg2: AxialType) {
        self.r /= arg2;
        self.q /= arg2;

    }
}

impl Rem<AxialType> for AxialVector {
    type Output = AxialVector;

    fn rem(self, arg2: AxialType) -> AxialVector {
        AxialVector {
            r: self.r % arg2,
            q: self.q % arg2,
        }
    }
}

impl RemAssign<AxialType> for AxialVector {

    fn rem_assign(&mut self, arg2: AxialType) {
        self.r %= arg2;
        self.q %= arg2;

    }
}

// ************ Metric Space ************

impl MetricSpace for AxialVector {
    type Metric = DefaultFloat;

    fn distance(self, other: AxialVector) -> DefaultFloat {
        (self.distance2(other)).sqrt()
    }

    fn distance2(self, other: AxialVector) -> DefaultFloat {
        ((self.q - other.q).pow(2) + (self.r - other.r).pow(2)) as DefaultFloat
    }
}

// ************ Vector Space ************

impl VectorSpace for AxialVector {
    type Scalar = AxialType;
}

// ************** Zero ****************

impl Zero for AxialVector {

    fn zero() -> AxialVector {
        AxialVector { q: 0, r: 0 }
    }

    fn is_zero(&self) -> bool {
        self.q == 0 && self.r == 0
    }
}

// *************** Array & Index *******************

impl Array for AxialVector {
    type Element = AxialType;

    fn from_value(value: Self::Element) -> Self {
        AxialVector::new(value, value)
    }

    fn sum(self) -> Self::Element {
        self.q + self.r
    }

    fn product(self) -> Self::Element {
        self.q * self.r
    }

    fn min(self) -> Self::Element {
        cmp::min(self.q, self.r)
    }

    fn max(self) -> Self::Element {
        cmp::max(self.q, self.r)
    }
}

impl Index<usize> for AxialVector {
    type Output = AxialType;

    fn index(&self, index: usize) -> &Self::Output {
        match index {
            0 => &self.q,
            1 => &self.r,
            _ => panic!("Illegal Index Argument: was {:?}", index),
        }
    }
}

impl IndexMut<usize> for AxialVector {

    fn index_mut(&mut self, index: usize) -> &mut AxialType {
        match index {
            0 => &mut self.q,
            1 => &mut self.r,
            _ => panic!("Illegal Index Argument: was {:?}", index),
        }
    }
}
<commit_msg>remove newlines started adding tests<commit_after>use std::fmt;
use world::{HEX_INNER_RADIUS, HEX_OUTER_RADIUS};
use super::{AxialType, DefaultFloat, Vector2f};
use math::cgmath::{VectorSpace, Zero};
use std::ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Rem,
               RemAssign, Sub, SubAssign};
use math::cgmath::prelude::{Array, MetricSpace};
use std::cmp;

/// A 2-dimensional vector in axial coordinates. See [here][hex-blog] for more
/// information.
///
/// [hex-blog]: http://www.redblobgames.com/grids/hexagons/#coordinates
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[repr(C, packed)]
pub struct AxialVector {
    pub q: AxialType,
    pub r: AxialType,
}
// TODO: implement cgmath::Zero
// TODO: implement cgmath::Array
// TODO: implement cgmath::MatricSpace
// TODO: implement cgmath::VectorSpace
// TODO: implement cgmath::InnerSpace
// TODO: implement ops::{ ... }
// TODO: Add `unit_q()` and `unit_r()` (see `Vector2::unit_x()` for reference)
// For all of the above, see
// http://bjz.github.io/cgmath/cgmath/struct.Vector2.html
//
/// AxialVector defines a vector specificly for Axial cordinate system.
impl AxialVector {
    pub fn new(q: AxialType, r: AxialType) -> Self {
        AxialVector { q: q, r: r }
    }
    /// Returns the position of the hexagons center in the standard coordinate
    /// system using `world::{HEX_INNER_RADIUS, HEX_OUTER_RADIUS}`.
    pub fn to_real(&self) -> Vector2f {
        Vector2f {
            x: ((2 * self.q + self.r) as DefaultFloat) * HEX_INNER_RADIUS,
            y: (self.r as DefaultFloat) * (3.0 / 2.0) * HEX_OUTER_RADIUS,
        }
    }
    /// Returns the `s` component of corresponding cube coordinates. In cube
    /// coordinates 'q + r + s = 0', so saving `s` is redundant and can be
    /// calculated on the fly when needed.
    pub fn s(&self) -> AxialType {
        -self.q - self.r
    }
    /// unit_q creates an default AxialVector with q:1 r:0.
    pub fn unit_q() -> AxialVector {
        AxialVector { q: 1, r: 0 }
    }
    /// unit_r creates an default AxialVector with q:0 r:1.
    pub fn unit_r() -> AxialVector {
        AxialVector { q: 0, r: 1 }
    }
}
impl fmt::Debug for AxialVector {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_tuple("")
            .field(&self.q)
            .field(&self.r)
            .finish()
    }
}
// ********************* Basic Arithmetic (OPS) *********************
impl Neg for AxialVector {
    type Output = AxialVector;
    fn neg(self) -> Self::Output {
        AxialVector {
            q: -self.q,
            r: -self.r,
        }
    }
}
impl Add<AxialVector> for AxialVector {
    type Output = AxialVector;
    fn add(self, arg2: AxialVector) -> AxialVector {
        AxialVector {
            r: self.r + arg2.r,
            q: self.q + arg2.q,
        }
    }
}
impl AddAssign<AxialVector> for AxialVector {
    fn add_assign(&mut self, arg2: AxialVector) {
        self.r += arg2.r;
        self.q += arg2.q;

    }
}
impl Sub<AxialVector> for AxialVector {
    type Output = AxialVector;
    fn sub(self, arg2: AxialVector) -> AxialVector {
        AxialVector {
            r: self.r - arg2.r,
            q: self.q - arg2.q,
        }
    }
}
impl SubAssign<AxialVector> for AxialVector {
    fn sub_assign(&mut self, arg2: AxialVector) {
        self.r -= arg2.r;
        self.q -= arg2.q;
    }
}
impl Mul<AxialType> for AxialVector {
    type Output = AxialVector;
    fn mul(self, arg2: AxialType) -> AxialVector {
        AxialVector {
            r: self.r * arg2,
            q: self.q * arg2,
        }
    }
}
impl MulAssign<AxialType> for AxialVector {
    fn mul_assign(&mut self, arg2: AxialType) {
        self.r *= arg2;
        self.q *= arg2;

    }
}
impl Div<AxialType> for AxialVector {
    type Output = AxialVector;
    fn div(self, arg2: AxialType) -> AxialVector {
        AxialVector {
            r: self.r / arg2,
            q: self.q / arg2,
        }
    }
}
impl DivAssign<AxialType> for AxialVector {
    fn div_assign(&mut self, arg2: AxialType) {
        self.r /= arg2;
        self.q /= arg2;
    }
}
impl Rem<AxialType> for AxialVector {
    type Output = AxialVector;
    fn rem(self, arg2: AxialType) -> AxialVector {
        AxialVector {
            r: self.r % arg2,
            q: self.q % arg2,
        }
    }
}
impl RemAssign<AxialType> for AxialVector {
    fn rem_assign(&mut self, arg2: AxialType) {
        self.r %= arg2;
        self.q %= arg2;
    }
}
// ************ Metric Space ************
impl MetricSpace for AxialVector {
    type Metric = DefaultFloat;
    fn distance(self, other: AxialVector) -> DefaultFloat {
        self.distance2(other).sqrt()
    }
    fn distance2(self, other: AxialVector) -> DefaultFloat {
        ((self.q - other.q).pow(2) + (self.r - other.r).pow(2)) as DefaultFloat
    }
}
// ************ Vector Space ************
impl VectorSpace for AxialVector {
    type Scalar = AxialType;
}
// ************** Zero ****************
impl Zero for AxialVector {
    fn zero() -> AxialVector {
        AxialVector { q: 0, r: 0 }
    }
    fn is_zero(&self) -> bool {
        self.q == 0 && self.r == 0
    }
}
// *************** Array & Index *******************
impl Array for AxialVector {
    type Element = AxialType;
    fn from_value(value: Self::Element) -> Self {
        AxialVector::new(value, value)
    }
    fn sum(self) -> Self::Element {
        self.q + self.r
    }
    fn product(self) -> Self::Element {
        self.q * self.r
    }
    fn min(self) -> Self::Element {
        cmp::min(self.q, self.r)
    }
    fn max(self) -> Self::Element {
        cmp::max(self.q, self.r)
    }
}
impl Index<usize> for AxialVector {
    type Output = AxialType;
    fn index(&self, index: usize) -> &Self::Output {
        match index {
            0 => &self.q,
            1 => &self.r,
            _ => panic!("Illegal Index Argument: was {:?}", index),
        }
    }
}
impl IndexMut<usize> for AxialVector {
    fn index_mut(&mut self, index: usize) -> &mut AxialType {
        match index {
            0 => &mut self.q,
            1 => &mut self.r,
            _ => panic!("Illegal Index Argument: was {:?}", index),
        }
    }
}
#[test]
fn test_my_foo_feature() {
    // ***** Unit Vectors *****
    let uvq = AxialVector::unit_q();
    assert!(uvq.q == 1 && uvq.r == 0);
    let uvr = AxialVector::unit_r();
    assert!(uvq.r == 0 && uvr.r == 1);
    let test1 = AxialVector { q: -5, r: 2 };
    let test2 = AxialVector { q: 13, r: -4 };
    assert_eq!(-uvq, AxialVector { q: -1, r: 0 });
    assert_eq!(-test1, AxialVector { q: 5, r: -2 });
    assert_eq!(test1 + uvq, AxialVector { q: -4, r: 2 });
    assert_eq!(test2 + test1, AxialVector { q: 8, r: -2 });
    let mut test3 = AxialVector { q: -9, r: 19 };
    test3 += test1;
    assert_eq!(test3, AxialVector { q: -14, r: 21 });
    assert_eq!(test2 - test1, AxialVector { q: 18, r: -6 });
    assert_eq!(test1 - uvr, AxialVector { q: -5, r: 1 });
    test3 -= test2;
    assert!(test3.q == -27 && test3.r == 25);
    test3 = test1 * 2;
    assert!(test3.q == -10, test3.r == 4);
    test3 = test1 * -4;
    assert!(test3.q == 20 && test3.r == -8);
    test3 *= -3;
    assert!(test3.q == -60 && test3.r == 24);
    test3 = test3 / 3;
    assert!(test3.q == -20 && test3.r == 8);
    test3 /= 5;
    assert!(test3.q == -4 && test3.r == 1);
    test3 = test2 % 2;
    assert!(test3.q == 1 && test3.r == 0);
    test3.q = 11;
    test3.r = 6;
    test3 %= 3;
    assert!(test3.q == 2 && test3.r == 0);
    // let mut f: f32 = 2.0;
    // f = f.sqrt();
    // assert_eq!(uvq.distance(uvq), f);
}
<|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 dom::attr::AttrHelpers;
use dom::bindings::codegen::Bindings::HTMLIFrameElementBinding;
use dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElementMethods;
use dom::bindings::codegen::InheritTypes::{NodeCast, ElementCast};
use dom::bindings::codegen::InheritTypes::{HTMLElementCast, HTMLIFrameElementDerived};
use dom::bindings::js::{JSRef, Temporary, OptionalRootable};
use dom::bindings::trace::Traceable;
use dom::bindings::utils::{Reflectable, Reflector};
use dom::document::Document;
use dom::element::{HTMLIFrameElementTypeId, Element};
use dom::element::AttributeHandlers;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, NodeHelpers, ElementNodeTypeId, window_from_node};
use dom::virtualmethods::VirtualMethods;
use dom::window::Window;
use page::IterablePage;

use servo_msg::constellation_msg::{PipelineId, SubpageId};
use servo_msg::constellation_msg::{IFrameSandboxed, IFrameUnsandboxed};
use servo_msg::constellation_msg::{ConstellationChan, LoadIframeUrlMsg};
use servo_util::atom::Atom;
use servo_util::namespace::Null;
use servo_util::str::DOMString;

use std::ascii::StrAsciiExt;
use std::cell::Cell;
use url::{Url, UrlParser};

enum SandboxAllowance {
    AllowNothing = 0x00,
    AllowSameOrigin = 0x01,
    AllowTopNavigation = 0x02,
    AllowForms = 0x04,
    AllowScripts = 0x08,
    AllowPointerLock = 0x10,
    AllowPopups = 0x20
}

#[jstraceable]
#[must_root]
pub struct HTMLIFrameElement {
    pub htmlelement: HTMLElement,
    pub size: Traceable<Cell<Option<IFrameSize>>>,
    pub sandbox: Traceable<Cell<Option<u8>>>,
}

impl HTMLIFrameElementDerived for EventTarget {
    fn is_htmliframeelement(&self) -> bool {
       self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLIFrameElementTypeId))
    }
}

#[jstraceable]
pub struct IFrameSize {
    pub pipeline_id: PipelineId,
    pub subpage_id: SubpageId,
}

pub trait HTMLIFrameElementHelpers {
    fn is_sandboxed(self) -> bool;
    fn get_url(self) -> Option<Url>;
    /// http://www.whatwg.org/html/#process-the-iframe-attributes
    fn process_the_iframe_attributes(self);
}

impl<'a> HTMLIFrameElementHelpers for JSRef<'a, HTMLIFrameElement> {
    fn is_sandboxed(self) -> bool {
        self.sandbox.deref().get().is_some()
    }

    fn get_url(self) -> Option<Url> {
        let element: JSRef<Element> = ElementCast::from_ref(self);
        element.get_attribute(Null, "src").root().and_then(|src| {
            let url = src.deref().value();
            if url.as_slice().is_empty() {
                None
            } else {
                let window = window_from_node(self).root();
                UrlParser::new().base_url(&window.deref().page().get_url())
                    .parse(url.as_slice()).ok()
            }
        })
    }

    fn process_the_iframe_attributes(self) {
        let url = match self.get_url() {
            Some(url) => url.clone(),
            None => Url::parse("about:blank").unwrap(),
        };

        let sandboxed = if self.is_sandboxed() {
            IFrameSandboxed
        } else {
            IFrameUnsandboxed
        };

        // Subpage Id
        let window = window_from_node(self).root();
        let page = window.deref().page();
        let subpage_id = page.get_next_subpage_id();

        self.deref().size.deref().set(Some(IFrameSize {
            pipeline_id: page.id,
            subpage_id: subpage_id,
        }));

        let ConstellationChan(ref chan) = *page.constellation_chan.deref();
        chan.send(LoadIframeUrlMsg(url, page.id, subpage_id, sandboxed));
    }
}

impl HTMLIFrameElement {
    fn new_inherited(localName: DOMString, document: JSRef<Document>) -> HTMLIFrameElement {
        HTMLIFrameElement {
            htmlelement: HTMLElement::new_inherited(HTMLIFrameElementTypeId, localName, document),
            size: Traceable::new(Cell::new(None)),
            sandbox: Traceable::new(Cell::new(None)),
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(localName: DOMString, document: JSRef<Document>) -> Temporary<HTMLIFrameElement> {
        let element = HTMLIFrameElement::new_inherited(localName, document);
        Node::reflect_node(box element, document, HTMLIFrameElementBinding::Wrap)
    }
}

impl<'a> HTMLIFrameElementMethods for JSRef<'a, HTMLIFrameElement> {
    fn Src(self) -> DOMString {
        let element: JSRef<Element> = ElementCast::from_ref(self);
        element.get_string_attribute("src")
    }

    fn SetSrc(self, src: DOMString) {
        let element: JSRef<Element> = ElementCast::from_ref(self);
        element.set_url_attribute("src", src)
    }

    fn Sandbox(self) -> DOMString {
        let element: JSRef<Element> = ElementCast::from_ref(self);
        element.get_string_attribute("sandbox")
    }

    fn SetSandbox(self, sandbox: DOMString) {
        let element: JSRef<Element> = ElementCast::from_ref(self);
        element.set_string_attribute("sandbox", sandbox);
    }

    fn GetContentWindow(self) -> Option<Temporary<Window>> {
        self.size.deref().get().and_then(|size| {
            let window = window_from_node(self).root();
            let children = window.deref().page.children.deref().borrow();
            let child = children.iter().find(|child| {
                child.subpage_id.unwrap() == size.subpage_id
            });
            child.and_then(|page| {
                page.frame.deref().borrow().as_ref().map(|frame| {
                    Temporary::new(frame.window.clone())
                })
            })
        })
    }
}

impl<'a> VirtualMethods for JSRef<'a, HTMLIFrameElement> {
    fn super_type<'a>(&'a self) -> Option<&'a VirtualMethods> {
        let htmlelement: &JSRef<HTMLElement> = HTMLElementCast::from_borrowed_ref(self);
        Some(htmlelement as &VirtualMethods)
    }

    fn after_set_attr(&self, name: &Atom, value: DOMString) {
        match self.super_type() {
            Some(ref s) => s.after_set_attr(name, value.clone()),
            _ => (),
        }

        if "sandbox" == name.as_slice() {
            let mut modes = AllowNothing as u8;
            for word in value.as_slice().split(' ') {
                modes |= match word.to_ascii_lower().as_slice() {
                    "allow-same-origin" => AllowSameOrigin,
                    "allow-forms" => AllowForms,
                    "allow-pointer-lock" => AllowPointerLock,
                    "allow-popups" => AllowPopups,
                    "allow-scripts" => AllowScripts,
                    "allow-top-navigation" => AllowTopNavigation,
                    _ => AllowNothing
                } as u8;
            }
            self.deref().sandbox.deref().set(Some(modes));
        }

        if "src" == name.as_slice() {
            let node: JSRef<Node> = NodeCast::from_ref(*self);
            if node.is_in_doc() {
                self.process_the_iframe_attributes()
            }
        }
    }

    fn before_remove_attr(&self, name: &Atom, value: DOMString) {
        match self.super_type() {
            Some(ref s) => s.before_remove_attr(name, value),
            _ => (),
        }

        if "sandbox" == name.as_slice() {
            self.deref().sandbox.deref().set(None);
        }
    }

    fn bind_to_tree(&self, tree_in_doc: bool) {
        match self.super_type() {
            Some(ref s) => s.bind_to_tree(tree_in_doc),
            _ => (),
        }

        if tree_in_doc {
            self.process_the_iframe_attributes();
        }
    }
}

impl Reflectable for HTMLIFrameElement {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.htmlelement.reflector()
    }
}
<commit_msg>Fix indentation in is_htmliframeelement.<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::attr::AttrHelpers;
use dom::bindings::codegen::Bindings::HTMLIFrameElementBinding;
use dom::bindings::codegen::Bindings::HTMLIFrameElementBinding::HTMLIFrameElementMethods;
use dom::bindings::codegen::InheritTypes::{NodeCast, ElementCast};
use dom::bindings::codegen::InheritTypes::{HTMLElementCast, HTMLIFrameElementDerived};
use dom::bindings::js::{JSRef, Temporary, OptionalRootable};
use dom::bindings::trace::Traceable;
use dom::bindings::utils::{Reflectable, Reflector};
use dom::document::Document;
use dom::element::{HTMLIFrameElementTypeId, Element};
use dom::element::AttributeHandlers;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, NodeHelpers, ElementNodeTypeId, window_from_node};
use dom::virtualmethods::VirtualMethods;
use dom::window::Window;
use page::IterablePage;

use servo_msg::constellation_msg::{PipelineId, SubpageId};
use servo_msg::constellation_msg::{IFrameSandboxed, IFrameUnsandboxed};
use servo_msg::constellation_msg::{ConstellationChan, LoadIframeUrlMsg};
use servo_util::atom::Atom;
use servo_util::namespace::Null;
use servo_util::str::DOMString;

use std::ascii::StrAsciiExt;
use std::cell::Cell;
use url::{Url, UrlParser};

enum SandboxAllowance {
    AllowNothing = 0x00,
    AllowSameOrigin = 0x01,
    AllowTopNavigation = 0x02,
    AllowForms = 0x04,
    AllowScripts = 0x08,
    AllowPointerLock = 0x10,
    AllowPopups = 0x20
}

#[jstraceable]
#[must_root]
pub struct HTMLIFrameElement {
    pub htmlelement: HTMLElement,
    pub size: Traceable<Cell<Option<IFrameSize>>>,
    pub sandbox: Traceable<Cell<Option<u8>>>,
}

impl HTMLIFrameElementDerived for EventTarget {
    fn is_htmliframeelement(&self) -> bool {
        self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLIFrameElementTypeId))
    }
}

#[jstraceable]
pub struct IFrameSize {
    pub pipeline_id: PipelineId,
    pub subpage_id: SubpageId,
}

pub trait HTMLIFrameElementHelpers {
    fn is_sandboxed(self) -> bool;
    fn get_url(self) -> Option<Url>;
    /// http://www.whatwg.org/html/#process-the-iframe-attributes
    fn process_the_iframe_attributes(self);
}

impl<'a> HTMLIFrameElementHelpers for JSRef<'a, HTMLIFrameElement> {
    fn is_sandboxed(self) -> bool {
        self.sandbox.deref().get().is_some()
    }

    fn get_url(self) -> Option<Url> {
        let element: JSRef<Element> = ElementCast::from_ref(self);
        element.get_attribute(Null, "src").root().and_then(|src| {
            let url = src.deref().value();
            if url.as_slice().is_empty() {
                None
            } else {
                let window = window_from_node(self).root();
                UrlParser::new().base_url(&window.deref().page().get_url())
                    .parse(url.as_slice()).ok()
            }
        })
    }

    fn process_the_iframe_attributes(self) {
        let url = match self.get_url() {
            Some(url) => url.clone(),
            None => Url::parse("about:blank").unwrap(),
        };

        let sandboxed = if self.is_sandboxed() {
            IFrameSandboxed
        } else {
            IFrameUnsandboxed
        };

        // Subpage Id
        let window = window_from_node(self).root();
        let page = window.deref().page();
        let subpage_id = page.get_next_subpage_id();

        self.deref().size.deref().set(Some(IFrameSize {
            pipeline_id: page.id,
            subpage_id: subpage_id,
        }));

        let ConstellationChan(ref chan) = *page.constellation_chan.deref();
        chan.send(LoadIframeUrlMsg(url, page.id, subpage_id, sandboxed));
    }
}

impl HTMLIFrameElement {
    fn new_inherited(localName: DOMString, document: JSRef<Document>) -> HTMLIFrameElement {
        HTMLIFrameElement {
            htmlelement: HTMLElement::new_inherited(HTMLIFrameElementTypeId, localName, document),
            size: Traceable::new(Cell::new(None)),
            sandbox: Traceable::new(Cell::new(None)),
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(localName: DOMString, document: JSRef<Document>) -> Temporary<HTMLIFrameElement> {
        let element = HTMLIFrameElement::new_inherited(localName, document);
        Node::reflect_node(box element, document, HTMLIFrameElementBinding::Wrap)
    }
}

impl<'a> HTMLIFrameElementMethods for JSRef<'a, HTMLIFrameElement> {
    fn Src(self) -> DOMString {
        let element: JSRef<Element> = ElementCast::from_ref(self);
        element.get_string_attribute("src")
    }

    fn SetSrc(self, src: DOMString) {
        let element: JSRef<Element> = ElementCast::from_ref(self);
        element.set_url_attribute("src", src)
    }

    fn Sandbox(self) -> DOMString {
        let element: JSRef<Element> = ElementCast::from_ref(self);
        element.get_string_attribute("sandbox")
    }

    fn SetSandbox(self, sandbox: DOMString) {
        let element: JSRef<Element> = ElementCast::from_ref(self);
        element.set_string_attribute("sandbox", sandbox);
    }

    fn GetContentWindow(self) -> Option<Temporary<Window>> {
        self.size.deref().get().and_then(|size| {
            let window = window_from_node(self).root();
            let children = window.deref().page.children.deref().borrow();
            let child = children.iter().find(|child| {
                child.subpage_id.unwrap() == size.subpage_id
            });
            child.and_then(|page| {
                page.frame.deref().borrow().as_ref().map(|frame| {
                    Temporary::new(frame.window.clone())
                })
            })
        })
    }
}

impl<'a> VirtualMethods for JSRef<'a, HTMLIFrameElement> {
    fn super_type<'a>(&'a self) -> Option<&'a VirtualMethods> {
        let htmlelement: &JSRef<HTMLElement> = HTMLElementCast::from_borrowed_ref(self);
        Some(htmlelement as &VirtualMethods)
    }

    fn after_set_attr(&self, name: &Atom, value: DOMString) {
        match self.super_type() {
            Some(ref s) => s.after_set_attr(name, value.clone()),
            _ => (),
        }

        if "sandbox" == name.as_slice() {
            let mut modes = AllowNothing as u8;
            for word in value.as_slice().split(' ') {
                modes |= match word.to_ascii_lower().as_slice() {
                    "allow-same-origin" => AllowSameOrigin,
                    "allow-forms" => AllowForms,
                    "allow-pointer-lock" => AllowPointerLock,
                    "allow-popups" => AllowPopups,
                    "allow-scripts" => AllowScripts,
                    "allow-top-navigation" => AllowTopNavigation,
                    _ => AllowNothing
                } as u8;
            }
            self.deref().sandbox.deref().set(Some(modes));
        }

        if "src" == name.as_slice() {
            let node: JSRef<Node> = NodeCast::from_ref(*self);
            if node.is_in_doc() {
                self.process_the_iframe_attributes()
            }
        }
    }

    fn before_remove_attr(&self, name: &Atom, value: DOMString) {
        match self.super_type() {
            Some(ref s) => s.before_remove_attr(name, value),
            _ => (),
        }

        if "sandbox" == name.as_slice() {
            self.deref().sandbox.deref().set(None);
        }
    }

    fn bind_to_tree(&self, tree_in_doc: bool) {
        match self.super_type() {
            Some(ref s) => s.bind_to_tree(tree_in_doc),
            _ => (),
        }

        if tree_in_doc {
            self.process_the_iframe_attributes();
        }
    }
}

impl Reflectable for HTMLIFrameElement {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.htmlelement.reflector()
    }
}
<|endoftext|>


<commit_before><commit_msg>gpu_renderer: Make eglDebugMessageControlKHR usage optional.<commit_after><|endoftext|>


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

//! Interfaces for asking the user for information: forms, opening files, etc.

use binaryninjacore_sys::*;

use std::ffi::CString;
use std::os::raw::c_void;
use std::path::PathBuf;

use crate::string::BnString;

pub fn get_text_line_input(prompt: &str, title: &str) -> Option<String> {
    let prompt = CString::new(prompt).unwrap();
    let title = CString::new(title).unwrap();
    let mut value: *mut libc::c_char = std::ptr::null_mut();

    let result = unsafe { BNGetTextLineInput(&mut value, prompt.into_raw(), title.into_raw()) };
    if !result {
        return None;
    }

    Some(unsafe { BnString::from_raw(value).to_string() })
}

pub fn get_integer_input(prompt: &str, title: &str) -> Option<i64> {
    let prompt = CString::new(prompt).unwrap();
    let title = CString::new(title).unwrap();
    let mut value: i64 = 0;

    let result = unsafe { BNGetIntegerInput(&mut value, prompt.into_raw(), title.into_raw()) };

    if !result {
        return None;
    }

    Some(value)
}

pub fn get_address_input(prompt: &str, title: &str) -> Option<u64> {
    let prompt = CString::new(prompt).unwrap();
    let title = CString::new(title).unwrap();
    let mut value: u64 = 0;

    let result = unsafe {
        BNGetAddressInput(
            &mut value,
            prompt.into_raw(),
            title.into_raw(),
            std::ptr::null_mut(),
            0,
        )
    };

    if !result {
        return None;
    }

    Some(value)
}

pub fn get_open_filename_input(prompt: &str, extension: &str) -> Option<PathBuf> {
    let prompt = CString::new(prompt).unwrap();
    let extension = CString::new(extension).unwrap();
    let mut value: *mut libc::c_char = std::ptr::null_mut();

    let result =
        unsafe { BNGetOpenFileNameInput(&mut value, prompt.into_raw(), extension.into_raw()) };
    if !result {
        return None;
    }

    let string = unsafe { BnString::from_raw(value) };
    Some(PathBuf::from(string.as_str()))
}

pub fn get_save_filename_input(prompt: &str, title: &str, default_name: &str) -> Option<PathBuf> {
    let prompt = CString::new(prompt).unwrap();
    let title = CString::new(title).unwrap();
    let default_name = CString::new(default_name).unwrap();
    let mut value: *mut libc::c_char = std::ptr::null_mut();

    let result = unsafe {
        BNGetSaveFileNameInput(
            &mut value,
            prompt.into_raw(),
            title.into_raw(),
            default_name.into_raw(),
        )
    };
    if !result {
        return None;
    }

    let string = unsafe { BnString::from_raw(value) };
    Some(PathBuf::from(string.as_str()))
}

pub fn get_directory_name_input(prompt: &str, default_name: &str) -> Option<PathBuf> {
    let prompt = CString::new(prompt).unwrap();
    let default_name = CString::new(default_name).unwrap();
    let mut value: *mut libc::c_char = std::ptr::null_mut();

    let result =
        unsafe { BNGetDirectoryNameInput(&mut value, prompt.into_raw(), default_name.into_raw()) };
    if !result {
        return None;
    }

    let string = unsafe { BnString::from_raw(value) };
    Some(PathBuf::from(string.as_str()))
}

struct TaskContext<F: Fn(Box<dyn Fn(usize, usize) -> Result<(), ()>>)>(F);

pub fn run_progress_dialog<F: Fn(Box<dyn Fn(usize, usize) -> Result<(), ()>>)>(
    title: &str,
    can_cancel: bool,
    task: F,
) -> Result<(), ()> {
    let title = CString::new(title).unwrap();

    let mut ctxt = TaskContext::<F>(task);

    unsafe extern "C" fn cb_task<F: Fn(Box<dyn Fn(usize, usize) -> Result<(), ()>>)>(
        ctxt: *mut c_void,
        progress: Option<unsafe extern "C" fn(*mut c_void, usize, usize) -> bool>,
        progress_ctxt: *mut c_void,
    ) {
        ffi_wrap!("run_progress_dialog", unsafe {
            let context = ctxt as *mut TaskContext<F>;
            let progress_fn = Box::new(move |cur: usize, max: usize| -> Result<(), ()> {
                match progress {
                    Some(func) => {
                        if (func)(progress_ctxt, cur, max) {
                            Ok(())
                        } else {
                            Err(())
                        }
                    }
                    None => Ok(()),
                }
            });
            ((*context).0)(progress_fn);
        })
    }

    if unsafe {
        BNRunProgressDialog(
            title.as_ptr(),
            can_cancel,
            Some(cb_task::<F>),
            &mut ctxt as *mut _ as *mut c_void,
        )
    } {
        Ok(())
    } else {
        Err(())
    }
}
<commit_msg>[Rust API] interaction::show_message_box<commit_after>// Copyright 2022 Vector 35 Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Interfaces for asking the user for information: forms, opening files, etc.

use binaryninjacore_sys::*;

use std::ffi::CString;
use std::os::raw::c_void;
use std::path::PathBuf;

use crate::string::BnString;

pub fn get_text_line_input(prompt: &str, title: &str) -> Option<String> {
    let prompt = CString::new(prompt).unwrap();
    let title = CString::new(title).unwrap();
    let mut value: *mut libc::c_char = std::ptr::null_mut();

    let result = unsafe { BNGetTextLineInput(&mut value, prompt.into_raw(), title.into_raw()) };
    if !result {
        return None;
    }

    Some(unsafe { BnString::from_raw(value).to_string() })
}

pub fn get_integer_input(prompt: &str, title: &str) -> Option<i64> {
    let prompt = CString::new(prompt).unwrap();
    let title = CString::new(title).unwrap();
    let mut value: i64 = 0;

    let result = unsafe { BNGetIntegerInput(&mut value, prompt.into_raw(), title.into_raw()) };

    if !result {
        return None;
    }

    Some(value)
}

pub fn get_address_input(prompt: &str, title: &str) -> Option<u64> {
    let prompt = CString::new(prompt).unwrap();
    let title = CString::new(title).unwrap();
    let mut value: u64 = 0;

    let result = unsafe {
        BNGetAddressInput(
            &mut value,
            prompt.into_raw(),
            title.into_raw(),
            std::ptr::null_mut(),
            0,
        )
    };

    if !result {
        return None;
    }

    Some(value)
}

pub fn get_open_filename_input(prompt: &str, extension: &str) -> Option<PathBuf> {
    let prompt = CString::new(prompt).unwrap();
    let extension = CString::new(extension).unwrap();
    let mut value: *mut libc::c_char = std::ptr::null_mut();

    let result =
        unsafe { BNGetOpenFileNameInput(&mut value, prompt.into_raw(), extension.into_raw()) };
    if !result {
        return None;
    }

    let string = unsafe { BnString::from_raw(value) };
    Some(PathBuf::from(string.as_str()))
}

pub fn get_save_filename_input(prompt: &str, title: &str, default_name: &str) -> Option<PathBuf> {
    let prompt = CString::new(prompt).unwrap();
    let title = CString::new(title).unwrap();
    let default_name = CString::new(default_name).unwrap();
    let mut value: *mut libc::c_char = std::ptr::null_mut();

    let result = unsafe {
        BNGetSaveFileNameInput(
            &mut value,
            prompt.into_raw(),
            title.into_raw(),
            default_name.into_raw(),
        )
    };
    if !result {
        return None;
    }

    let string = unsafe { BnString::from_raw(value) };
    Some(PathBuf::from(string.as_str()))
}

pub fn get_directory_name_input(prompt: &str, default_name: &str) -> Option<PathBuf> {
    let prompt = CString::new(prompt).unwrap();
    let default_name = CString::new(default_name).unwrap();
    let mut value: *mut libc::c_char = std::ptr::null_mut();

    let result =
        unsafe { BNGetDirectoryNameInput(&mut value, prompt.into_raw(), default_name.into_raw()) };
    if !result {
        return None;
    }

    let string = unsafe { BnString::from_raw(value) };
    Some(PathBuf::from(string.as_str()))
}

pub type MessageBoxButtonSet = BNMessageBoxButtonSet;
pub type MessageBoxIcon = BNMessageBoxIcon;
pub type MessageBoxButtonResult = BNMessageBoxButtonResult;
pub fn show_message_box(
    title: &str,
    text: &str,
    buttons: MessageBoxButtonSet,
    icon: MessageBoxIcon,
) -> MessageBoxButtonResult {
    let title = CString::new(title).unwrap();
    let text = CString::new(text).unwrap();

    unsafe { BNShowMessageBox(title.as_ptr(), text.as_ptr(), buttons, icon) }
}

struct TaskContext<F: Fn(Box<dyn Fn(usize, usize) -> Result<(), ()>>)>(F);

pub fn run_progress_dialog<F: Fn(Box<dyn Fn(usize, usize) -> Result<(), ()>>)>(
    title: &str,
    can_cancel: bool,
    task: F,
) -> Result<(), ()> {
    let title = CString::new(title).unwrap();

    let mut ctxt = TaskContext::<F>(task);

    unsafe extern "C" fn cb_task<F: Fn(Box<dyn Fn(usize, usize) -> Result<(), ()>>)>(
        ctxt: *mut c_void,
        progress: Option<unsafe extern "C" fn(*mut c_void, usize, usize) -> bool>,
        progress_ctxt: *mut c_void,
    ) {
        ffi_wrap!("run_progress_dialog", unsafe {
            let context = ctxt as *mut TaskContext<F>;
            let progress_fn = Box::new(move |cur: usize, max: usize| -> Result<(), ()> {
                match progress {
                    Some(func) => {
                        if (func)(progress_ctxt, cur, max) {
                            Ok(())
                        } else {
                            Err(())
                        }
                    }
                    None => Ok(()),
                }
            });
            ((*context).0)(progress_fn);
        })
    }

    if unsafe {
        BNRunProgressDialog(
            title.as_ptr(),
            can_cancel,
            Some(cb_task::<F>),
            &mut ctxt as *mut _ as *mut c_void,
        )
    } {
        Ok(())
    } else {
        Err(())
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::collections::HashMap;
use std::collections::hash_map::Entry;

pub trait Labeled {
    fn add_label(&mut self, label: &str);
}

pub trait Offset {
    fn get_offset(&self) -> usize;
}

#[derive(Debug)]
pub struct BootInfo {
    pub reserve_info: Vec<ReserveInfo>,
    pub boot_cpuid: u32,
    pub root: Node,
}

#[derive(Debug)]
pub struct ReserveInfo {
    pub address: u64,
    pub size: u64,
    pub labels: Vec<String>,
}

impl Labeled for ReserveInfo {
    fn add_label(&mut self, label: &str) {
        let label = label.to_owned();
        if !self.labels.contains(&label) {
            self.labels.push(label);
        }
    }
}

#[derive(PartialEq, Eq, Debug)]
pub enum Node {
    Deleted { name: NodeName, offset: usize },
    Existing {
        name: NodeName,

        proplist: HashMap<String, Property>,
        children: HashMap<String, Node>,
        // fullpath: Option<PathBuf>,
        // length to the # part of node_name@#
        // basenamelen: usize,
        //
        // phandle: u32,
        // addr_cells: i32,
        // size_cells: i32,
        labels: Vec<String>,

        offset: usize,
    },
}

impl Node {
    /// Convenience function to get the NodeName no matter what form the
    /// `Node`is in.
    pub fn name(&self) -> &NodeName {
        match *self {
            Node::Deleted { ref name, .. } |
            Node::Existing { ref name, .. } => name,
        }
    }
}

impl Labeled for Node {
    fn add_label(&mut self, label: &str) {
        match *self {
            Node::Deleted { .. } => panic!("Why are you adding a label to a deleted node?!"),
            Node::Existing { ref mut labels, .. } => {
                let label = label.to_owned();
                if labels.contains(&label) {
                    labels.push(label);
                }
            }
        }
    }
}

impl Offset for Node {
    fn get_offset(&self) -> usize {
        match *self {
            Node::Deleted { offset, .. } |
            Node::Existing { offset, .. } => offset,
        }
    }
}

impl fmt::Display for Node {
    // TODO: labels - issue 3
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Node::Deleted { ref name, .. } => write!(f, "// Node {} deleted", name)?,
            Node::Existing { ref name, ref proplist, ref children, .. } => {
                writeln!(f, "{} {{", name)?;
                for prop in proplist.values() {
                    writeln!(f, "    {}", prop)?;
                }
                for node in children.values() {
                    match *node {
                        Node::Deleted { ref name, .. } => {
                            writeln!(f, "    // Node {} deleted", name)?
                        }
                        Node::Existing { ref name, .. } => writeln!(f, "    {} {{ ... }}", name)?,
                    }
                }
                write!(f, "}}")?;
            }
        }

        Ok(())
    }
}

#[derive(PartialEq, Eq, Debug)]
pub enum NodeName {
    Ref(String),
    Full(String),
}

impl fmt::Display for NodeName {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            NodeName::Ref(ref name) |
            NodeName::Full(ref name) => write!(f, "{}", name),
        }
    }
}

impl NodeName {
    pub fn as_str(&self) -> &str {
        match *self {
            NodeName::Ref(ref name) |
            NodeName::Full(ref name) => name,
        }
    }
}

#[derive(PartialEq, Eq, Debug)]
pub enum Property {
    Deleted { name: String, offset: usize },
    Existing {
        name: String,
        val: Option<Vec<Data>>,
        labels: Vec<String>,
        offset: usize,
    },
}

impl Property {
    /// Convenience function to get the name no matter what form the
    /// `Property`is in.
    pub fn name(&self) -> &str {
        match *self {
           Property::Deleted{ref name, ..} |
           Property::Existing{ref name, ..} => name
        }
    }
}

impl Labeled for Property {
    fn add_label(&mut self, label: &str) {
        match *self {
            Property::Deleted { .. } => {
                panic!("Why are you adding a label to a deleted property?!")
            }
            Property::Existing { ref mut labels, .. } => {
                let label = label.to_owned();
                if labels.contains(&label) {
                    labels.push(label);
                }
            }
        }
    }
}

impl Offset for Property {
    fn get_offset(&self) -> usize {
        match *self {
            Property::Deleted { offset, .. } |
            Property::Existing { offset, .. } => offset,
        }
    }
}

impl fmt::Display for Property {
    // TODO: labels - issue 3
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Property::Deleted { ref name, .. } => write!(f, "// Property {} deleted", name)?,
            Property::Existing { ref name, ref val, .. } => {
                write!(f, "{}", name)?;
                if let Some(ref data) = *val {
                    if !data.is_empty() {
                        let mut iter = data.iter();
                        write!(f, " = {}", iter.next().unwrap())?;
                        for d in iter {
                            write!(f, ", {}", d)?;
                        }
                    }
                }
                write!(f, ";")?;
            }
        }

        Ok(())
    }
}

#[derive(PartialEq, Eq, Debug)]
pub enum Data {
    Reference(String, Option<u64>),
    String(String),
    Cells(usize, Vec<Cell>),
    ByteArray(Vec<u8>),
}

impl fmt::Display for Data {
    // TODO: labels - issue 3 - issue 6
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Data::Reference(ref r, _) => write!(f, "&{}", r)?,
            Data::String(ref s) => write!(f, "{}", s)?,
            Data::Cells(bits, ref cells) => {
                if bits != 32 {
                    write!(f, "/bits/ {}", bits)?;
                }
                write!(f, "<")?;
                if !cells.is_empty() {
                    let mut iter = cells.iter();
                    write!(f, "{}", iter.next().unwrap())?;
                    for c in iter {
                        write!(f, "{}", c)?;
                    }
                }
                write!(f, ">")?;
            }
            Data::ByteArray(ref arr) => {
                write!(f, "[ ")?;
                if !arr.is_empty() {
                    let mut iter = arr.iter();
                    write!(f, "{:02X}", iter.next().unwrap())?;
                    for d in iter {
                        write!(f, " {:02X}", d)?;
                    }
                }
                write!(f, " ]")?;
            }
        }

        Ok(())
    }
}

#[derive(PartialEq, Eq, Debug, Clone)]
pub enum Cell {
    Num(u64),
    Ref(String, Option<u64>),
}

impl fmt::Display for Cell {
    // TODO: labels - issue 3 - issue 6
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Cell::Num(i) => write!(f, "{}", i)?,
            Cell::Ref(ref s, _) => write!(f, "&{}", s)?,
        }

        Ok(())
    }
}
<commit_msg>Properly handle errors in tree.rs<commit_after>use std::fmt;
use std::collections::HashMap;
use std::collections::hash_map::Entry;

pub trait Labeled {
    fn add_label(&mut self, label: &str) -> Result<(), ()>;
}

pub trait Offset {
    fn get_offset(&self) -> usize;
}

#[derive(Debug)]
pub struct BootInfo {
    pub reserve_info: Vec<ReserveInfo>,
    pub boot_cpuid: u32,
    pub root: Node,
}

#[derive(Debug)]
pub struct ReserveInfo {
    pub address: u64,
    pub size: u64,
    pub labels: Vec<String>,
}

impl Labeled for ReserveInfo {
    fn add_label(&mut self, label: &str) -> Result<(), ()> {
        let label = label.to_owned();
        if !self.labels.contains(&label) {
            self.labels.push(label);
        }

        Ok(())
    }
}

#[derive(PartialEq, Eq, Debug)]
pub enum Node {
    Deleted { name: NodeName, offset: usize },
    Existing {
        name: NodeName,

        proplist: HashMap<String, Property>,
        children: HashMap<String, Node>,
        // fullpath: Option<PathBuf>,
        // length to the # part of node_name@#
        // basenamelen: usize,
        //
        // phandle: u32,
        // addr_cells: i32,
        // size_cells: i32,
        labels: Vec<String>,

        offset: usize,
    },
}

impl Node {
    /// Convenience function to get the NodeName no matter what form the
    /// `Node`is in.
    pub fn name(&self) -> &NodeName {
        match *self {
            Node::Deleted { ref name, .. } |
            Node::Existing { ref name, .. } => name,
        }
    }
}

impl Labeled for Node {
    fn add_label(&mut self, label: &str) -> Result<(), ()> {
        match *self {
            Node::Deleted { .. } => Err(()),
            Node::Existing { ref mut labels, .. } => {
                let label = label.to_owned();
                if labels.contains(&label) {
                    labels.push(label);
                }

                Ok(())
            }
        }
    }
}

impl Offset for Node {
    fn get_offset(&self) -> usize {
        match *self {
            Node::Deleted { offset, .. } |
            Node::Existing { offset, .. } => offset,
        }
    }
}

impl fmt::Display for Node {
    // TODO: labels - issue 3
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Node::Deleted { ref name, .. } => write!(f, "// Node {} deleted", name)?,
            Node::Existing { ref name, ref proplist, ref children, .. } => {
                writeln!(f, "{} {{", name)?;
                for prop in proplist.values() {
                    writeln!(f, "    {}", prop)?;
                }
                for node in children.values() {
                    match *node {
                        Node::Deleted { ref name, .. } => {
                            writeln!(f, "    // Node {} deleted", name)?
                        }
                        Node::Existing { ref name, .. } => writeln!(f, "    {} {{ ... }}", name)?,
                    }
                }
                write!(f, "}}")?;
            }
        }

        Ok(())
    }
}

#[derive(PartialEq, Eq, Debug)]
pub enum NodeName {
    Ref(String),
    Full(String),
}

impl fmt::Display for NodeName {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            NodeName::Ref(ref name) |
            NodeName::Full(ref name) => write!(f, "{}", name),
        }
    }
}

impl NodeName {
    pub fn as_str(&self) -> &str {
        match *self {
            NodeName::Ref(ref name) |
            NodeName::Full(ref name) => name,
        }
    }
}

#[derive(PartialEq, Eq, Debug)]
pub enum Property {
    Deleted { name: String, offset: usize },
    Existing {
        name: String,
        val: Option<Vec<Data>>,
        labels: Vec<String>,
        offset: usize,
    },
}

impl Property {
    /// Convenience function to get the name no matter what form the
    /// `Property`is in.
    pub fn name(&self) -> &str {
        match *self {
           Property::Deleted{ref name, ..} |
           Property::Existing{ref name, ..} => name
        }
    }
}

impl Labeled for Property {
    fn add_label(&mut self, label: &str) -> Result<(), ()> {
        match *self {
            Property::Deleted { .. } => Err(()),
            Property::Existing { ref mut labels, .. } => {
                let label = label.to_owned();
                if labels.contains(&label) {
                    labels.push(label);
                }
                Ok(())
            }
        }
    }
}

impl Offset for Property {
    fn get_offset(&self) -> usize {
        match *self {
            Property::Deleted { offset, .. } |
            Property::Existing { offset, .. } => offset,
        }
    }
}

impl fmt::Display for Property {
    // TODO: labels - issue 3
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Property::Deleted { ref name, .. } => write!(f, "// Property {} deleted", name)?,
            Property::Existing { ref name, ref val, .. } => {
                write!(f, "{}", name)?;
                if let Some(ref data) = *val {
                    if !data.is_empty() {
                        let mut iter = data.iter();
                        write!(f, " = {}", iter.next().unwrap())?;
                        for d in iter {
                            write!(f, ", {}", d)?;
                        }
                    }
                }
                write!(f, ";")?;
            }
        }

        Ok(())
    }
}

#[derive(PartialEq, Eq, Debug)]
pub enum Data {
    Reference(String, Option<u64>),
    String(String),
    Cells(usize, Vec<Cell>),
    ByteArray(Vec<u8>),
}

impl fmt::Display for Data {
    // TODO: labels - issue 3 - issue 6
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Data::Reference(ref r, _) => write!(f, "&{}", r)?,
            Data::String(ref s) => write!(f, "{}", s)?,
            Data::Cells(bits, ref cells) => {
                if bits != 32 {
                    write!(f, "/bits/ {}", bits)?;
                }
                write!(f, "<")?;
                if !cells.is_empty() {
                    let mut iter = cells.iter();
                    write!(f, "{}", iter.next().unwrap())?;
                    for c in iter {
                        write!(f, "{}", c)?;
                    }
                }
                write!(f, ">")?;
            }
            Data::ByteArray(ref arr) => {
                write!(f, "[ ")?;
                if !arr.is_empty() {
                    let mut iter = arr.iter();
                    write!(f, "{:02X}", iter.next().unwrap())?;
                    for d in iter {
                        write!(f, " {:02X}", d)?;
                    }
                }
                write!(f, " ]")?;
            }
        }

        Ok(())
    }
}

#[derive(PartialEq, Eq, Debug, Clone)]
pub enum Cell {
    Num(u64),
    Ref(String, Option<u64>),
}

impl fmt::Display for Cell {
    // TODO: labels - issue 3 - issue 6
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Cell::Num(i) => write!(f, "{}", i)?,
            Cell::Ref(ref s, _) => write!(f, "&{}", s)?,
        }

        Ok(())
    }
}
<|endoftext|>


<commit_before>// Ensure that there are no drop terminators in `unwrap<T>` (except the one along the cleanup
// path).

fn unwrap<T>(opt: Option<T>) -> T {
    match opt {
        Some(x) => x,
        None => panic!(),
    }
}

fn main() {
    let _ = unwrap(Some(1i32));
}

// END RUST SOURCE
// START rustc.unwrap.SimplifyCfg-elaborate-drops.after.mir
// fn unwrap(_1: std::option::Option<T>) -> T {
//     ...
//     bb0: {
//         ...
//         switchInt(move _2) -> [0isize: bb2, 1isize: bb4, otherwise: bb3];
//     }
//     bb1 (cleanup): {
//         resume;
//     }
//     bb2: {
//         ...
//         const std::rt::begin_panic::<&'static str>(const "explicit panic") -> bb5;
//     }
//     bb3: {
//         unreachable;
//     }
//     bb4: {
//         ...
//         return;
//     }
//     bb5 (cleanup): {
//         drop(_1) -> bb1;
//     }
// }
// END rustc.unwrap.SimplifyCfg-elaborate-drops.after.mir
<commit_msg>Ignore `mir-opt` test when panic=abort<commit_after>// ignore-wasm32-bare compiled with panic=abort by default

// Ensure that there are no drop terminators in `unwrap<T>` (except the one along the cleanup
// path).

fn unwrap<T>(opt: Option<T>) -> T {
    match opt {
        Some(x) => x,
        None => panic!(),
    }
}

fn main() {
    let _ = unwrap(Some(1i32));
}

// END RUST SOURCE
// START rustc.unwrap.SimplifyCfg-elaborate-drops.after.mir
// fn unwrap(_1: std::option::Option<T>) -> T {
//     ...
//     bb0: {
//         ...
//         switchInt(move _2) -> [0isize: bb2, 1isize: bb4, otherwise: bb3];
//     }
//     bb1 (cleanup): {
//         resume;
//     }
//     bb2: {
//         ...
//         const std::rt::begin_panic::<&'static str>(const "explicit panic") -> bb5;
//     }
//     bb3: {
//         unreachable;
//     }
//     bb4: {
//         ...
//         return;
//     }
//     bb5 (cleanup): {
//         drop(_1) -> bb1;
//     }
// }
// END rustc.unwrap.SimplifyCfg-elaborate-drops.after.mir
<|endoftext|>


<commit_before>#![recursion_limit="128"]

use futures::{Poll, pending, pin_mut, poll, join, try_join, select};
use futures::channel::{mpsc, oneshot};
use futures::executor::block_on;
use futures::future::{self, FutureExt};
use futures::stream::StreamExt;
use futures::sink::SinkExt;

#[test]
fn poll_and_pending() {
    let pending_once = async { pending!() };
    block_on(async {
        pin_mut!(pending_once);
        assert_eq!(Poll::Pending, poll!(&mut pending_once));
        assert_eq!(Poll::Ready(()), poll!(&mut pending_once));
    });
}

#[test]
fn join() {
    let (tx1, rx1) = oneshot::channel::<i32>();
    let (tx2, rx2) = oneshot::channel::<i32>();

    let fut = async {
        let res = join!(rx1, rx2);
        assert_eq!((Ok(1), Ok(2)), res);
    };

    block_on(async {
        pin_mut!(fut);
        assert_eq!(Poll::Pending, poll!(&mut fut));
        tx1.send(1).unwrap();
        assert_eq!(Poll::Pending, poll!(&mut fut));
        tx2.send(2).unwrap();
        assert_eq!(Poll::Ready(()), poll!(&mut fut));
    });
}

#[test]
fn select() {
    let (tx1, rx1) = oneshot::channel::<i32>();
    let (_tx2, rx2) = oneshot::channel::<i32>();
    tx1.send(1).unwrap();
    let mut ran = false;
    block_on(async {
        select! {
            res = rx1.fuse() => {
                assert_eq!(Ok(1), res);
                ran = true;
            },
            _ = rx2.fuse() => unreachable!(),
        }
    });
    assert!(ran);
}

#[test]
fn select_streams() {
    let (mut tx1, rx1) = mpsc::channel::<i32>(1);
    let (mut tx2, rx2) = mpsc::channel::<i32>(1);
    let mut rx1 = rx1.fuse();
    let mut rx2 = rx2.fuse();
    let mut ran = false;
    let mut total = 0;
    block_on(async {
        let mut tx1_opt;
        let mut tx2_opt;
        select! {
            _ = rx1.next() => panic!(),
            _ = rx2.next() => panic!(),
            default => {
                tx1.send(2).await.unwrap();
                tx2.send(3).await.unwrap();
                tx1_opt = Some(tx1);
                tx2_opt = Some(tx2);
            }
            complete => panic!(),
        }
        loop {
            select! {
                // runs first and again after default
                x = rx1.next() => if let Some(x) = x { total += x; },
                // runs second and again after default
                x = rx2.next()  => if let Some(x) = x { total += x; },
                // runs third
                default => {
                    assert_eq!(total, 5);
                    ran = true;
                    drop(tx1_opt.take().unwrap());
                    drop(tx2_opt.take().unwrap());
                },
                // runs last
                complete => break,
            };
        }
    });
    assert!(ran);
}

#[test]
fn select_can_move_uncompleted_futures() {
    let (tx1, rx1) = oneshot::channel::<i32>();
    let (tx2, rx2) = oneshot::channel::<i32>();
    tx1.send(1).unwrap();
    tx2.send(2).unwrap();
    let mut ran = false;
    let mut rx1 = rx1.fuse();
    let mut rx2 = rx2.fuse();
    block_on(async {
        select! {
            res = rx1 => {
                assert_eq!(Ok(1), res);
                assert_eq!(Ok(2), rx2.await);
                ran = true;
            },
            res = rx2 => {
                assert_eq!(Ok(2), res);
                assert_eq!(Ok(1), rx1.await);
                ran = true;
            },
        }
    });
    assert!(ran);
}

#[test]
fn select_nested() {
    let mut outer_fut = future::ready(1);
    let mut inner_fut = future::ready(2);
    let res = block_on(async {
        select! {
            x = outer_fut => {
                select! {
                    y = inner_fut => x + y,
                }
            }
        }
    });
    assert_eq!(res, 3);
}

#[test]
fn select_size() {
    let fut = async {
        let mut ready = future::ready(0i32);
        select! {
            _ = ready => {},
        }
    };
    assert_eq!(::std::mem::size_of_val(&fut), 24);

    let fut = async {
        let mut ready1 = future::ready(0i32);
        let mut ready2 = future::ready(0i32);
        select! {
            _ = ready1 => {},
            _ = ready2 => {},
        }
    };
    assert_eq!(::std::mem::size_of_val(&fut), 40);
}

#[test]
fn join_size() {
    let fut = async {
        let ready = future::ready(0i32);
        join!(ready)
    };
    assert_eq!(::std::mem::size_of_val(&fut), 16);

    let fut = async {
        let ready1 = future::ready(0i32);
        let ready2 = future::ready(0i32);
        join!(ready1, ready2)
    };
    assert_eq!(::std::mem::size_of_val(&fut), 32);
}

#[test]
fn try_join_size() {
    let fut = async {
        let ready = future::ready(Ok::<i32, i32>(0));
        try_join!(ready)
    };
    assert_eq!(::std::mem::size_of_val(&fut), 16);

    let fut = async {
        let ready1 = future::ready(Ok::<i32, i32>(0));
        let ready2 = future::ready(Ok::<i32, i32>(0));
        try_join!(ready1, ready2)
    };
    assert_eq!(::std::mem::size_of_val(&fut), 32);
}

#[test]
fn join_doesnt_require_unpin() {
    let _ = async {
        join!(async {}, async {})
    };
}

#[test]
fn try_join_doesnt_require_unpin() {
    let _ = async {
        try_join!(
            async { Ok::<(), ()>(()) },
            async { Ok::<(), ()>(()) },
        )
    };
}
<commit_msg>Update asserted size of join! and try_join!<commit_after>#![recursion_limit="128"]

use futures::{Poll, pending, pin_mut, poll, join, try_join, select};
use futures::channel::{mpsc, oneshot};
use futures::executor::block_on;
use futures::future::{self, FutureExt};
use futures::stream::StreamExt;
use futures::sink::SinkExt;

#[test]
fn poll_and_pending() {
    let pending_once = async { pending!() };
    block_on(async {
        pin_mut!(pending_once);
        assert_eq!(Poll::Pending, poll!(&mut pending_once));
        assert_eq!(Poll::Ready(()), poll!(&mut pending_once));
    });
}

#[test]
fn join() {
    let (tx1, rx1) = oneshot::channel::<i32>();
    let (tx2, rx2) = oneshot::channel::<i32>();

    let fut = async {
        let res = join!(rx1, rx2);
        assert_eq!((Ok(1), Ok(2)), res);
    };

    block_on(async {
        pin_mut!(fut);
        assert_eq!(Poll::Pending, poll!(&mut fut));
        tx1.send(1).unwrap();
        assert_eq!(Poll::Pending, poll!(&mut fut));
        tx2.send(2).unwrap();
        assert_eq!(Poll::Ready(()), poll!(&mut fut));
    });
}

#[test]
fn select() {
    let (tx1, rx1) = oneshot::channel::<i32>();
    let (_tx2, rx2) = oneshot::channel::<i32>();
    tx1.send(1).unwrap();
    let mut ran = false;
    block_on(async {
        select! {
            res = rx1.fuse() => {
                assert_eq!(Ok(1), res);
                ran = true;
            },
            _ = rx2.fuse() => unreachable!(),
        }
    });
    assert!(ran);
}

#[test]
fn select_streams() {
    let (mut tx1, rx1) = mpsc::channel::<i32>(1);
    let (mut tx2, rx2) = mpsc::channel::<i32>(1);
    let mut rx1 = rx1.fuse();
    let mut rx2 = rx2.fuse();
    let mut ran = false;
    let mut total = 0;
    block_on(async {
        let mut tx1_opt;
        let mut tx2_opt;
        select! {
            _ = rx1.next() => panic!(),
            _ = rx2.next() => panic!(),
            default => {
                tx1.send(2).await.unwrap();
                tx2.send(3).await.unwrap();
                tx1_opt = Some(tx1);
                tx2_opt = Some(tx2);
            }
            complete => panic!(),
        }
        loop {
            select! {
                // runs first and again after default
                x = rx1.next() => if let Some(x) = x { total += x; },
                // runs second and again after default
                x = rx2.next()  => if let Some(x) = x { total += x; },
                // runs third
                default => {
                    assert_eq!(total, 5);
                    ran = true;
                    drop(tx1_opt.take().unwrap());
                    drop(tx2_opt.take().unwrap());
                },
                // runs last
                complete => break,
            };
        }
    });
    assert!(ran);
}

#[test]
fn select_can_move_uncompleted_futures() {
    let (tx1, rx1) = oneshot::channel::<i32>();
    let (tx2, rx2) = oneshot::channel::<i32>();
    tx1.send(1).unwrap();
    tx2.send(2).unwrap();
    let mut ran = false;
    let mut rx1 = rx1.fuse();
    let mut rx2 = rx2.fuse();
    block_on(async {
        select! {
            res = rx1 => {
                assert_eq!(Ok(1), res);
                assert_eq!(Ok(2), rx2.await);
                ran = true;
            },
            res = rx2 => {
                assert_eq!(Ok(2), res);
                assert_eq!(Ok(1), rx1.await);
                ran = true;
            },
        }
    });
    assert!(ran);
}

#[test]
fn select_nested() {
    let mut outer_fut = future::ready(1);
    let mut inner_fut = future::ready(2);
    let res = block_on(async {
        select! {
            x = outer_fut => {
                select! {
                    y = inner_fut => x + y,
                }
            }
        }
    });
    assert_eq!(res, 3);
}

#[test]
fn select_size() {
    let fut = async {
        let mut ready = future::ready(0i32);
        select! {
            _ = ready => {},
        }
    };
    assert_eq!(::std::mem::size_of_val(&fut), 24);

    let fut = async {
        let mut ready1 = future::ready(0i32);
        let mut ready2 = future::ready(0i32);
        select! {
            _ = ready1 => {},
            _ = ready2 => {},
        }
    };
    assert_eq!(::std::mem::size_of_val(&fut), 40);
}

#[test]
fn join_size() {
    let fut = async {
        let ready = future::ready(0i32);
        join!(ready)
    };
    assert_eq!(::std::mem::size_of_val(&fut), 16);

    let fut = async {
        let ready1 = future::ready(0i32);
        let ready2 = future::ready(0i32);
        join!(ready1, ready2)
    };
    assert_eq!(::std::mem::size_of_val(&fut), 28);
}

#[test]
fn try_join_size() {
    let fut = async {
        let ready = future::ready(Ok::<i32, i32>(0));
        try_join!(ready)
    };
    assert_eq!(::std::mem::size_of_val(&fut), 16);

    let fut = async {
        let ready1 = future::ready(Ok::<i32, i32>(0));
        let ready2 = future::ready(Ok::<i32, i32>(0));
        try_join!(ready1, ready2)
    };
    assert_eq!(::std::mem::size_of_val(&fut), 28);
}

#[test]
fn join_doesnt_require_unpin() {
    let _ = async {
        join!(async {}, async {})
    };
}

#[test]
fn try_join_doesnt_require_unpin() {
    let _ = async {
        try_join!(
            async { Ok::<(), ()>(()) },
            async { Ok::<(), ()>(()) },
        )
    };
}
<|endoftext|>


<commit_before>//! Utilities for interacting with tasks implemented on the Rosetta Code wiki.

use std::collections::HashMap;

use lazy_static::lazy_static;
use percent_encoding::{self, define_encode_set, QUERY_ENCODE_SET};
use regex::Regex;
use reqwest::Url;
use serde::Deserialize;

lazy_static! {
    /// Extracts code from the first Rust section from Rosetta Code wiki markup.
    static ref RUST_WIKI_SECTION_RE: Regex =
        Regex::new(r"==\{\{header\|[Rr]ust\}\}==(?s:.*?)<lang [Rr]ust>((?s:.*?))</lang>").unwrap();
}

define_encode_set! {
    /// Encoding set used for Rosetta Code URLs.
    ///
    /// The wiki generally encodes characters found in the query encode set, as well as some
    /// additional characters.
    pub ROSETTA_ENCODE_SET = [QUERY_ENCODE_SET] | { '+' }
}

/// Represents a task implemented on the Rosetta Code wiki.
#[derive(Debug, Clone)]
pub struct RemoteTask {
    title: String,
    url: Url,
    source: Option<String>,
}

impl RemoteTask {
    /// Returns the title of the task.
    pub fn title(&self) -> String {
        self.title.clone()
    }

    /// Returns the URL to the task on the wiki.
    pub fn url(&self) -> Url {
        self.url.clone()
    }

    /// If the task contains a Rust implementation on the wiki, this field will contain the first
    /// Rust code block of that section. Otherwise, returns `None`.
    pub fn source(&self) -> Option<String> {
        self.source.clone()
    }
}

#[derive(Debug, Deserialize)]
pub struct Response {
    pub query: Pages,
}

/// Intermediate container in the query API response.
#[derive(Debug, Deserialize)]
pub struct Pages {
    pub pages: HashMap<i32, Page>,
}

/// Individual page in the query API response.
#[derive(Debug, Deserialize)]
pub struct Page {
    #[serde(rename = "pageid")]
    pub id: i32,

    pub title: String,

    #[serde(default)]
    pub revisions: Vec<Revision>,
}

#[derive(Debug, Deserialize)]
pub struct Revision {
    #[serde(rename = "*")]
    pub content: String,
}

/// Transforms a URL-encoded task title from the wiki to a human-readable task title.
pub fn decode_title(title: &str) -> String {
    let title = title.replace('_', " ").into_bytes();
    let decoded = percent_encoding::percent_decode(&title);
    String::from_utf8(decoded.collect()).unwrap()
}

/// Transforms a human-readable task title to the form used in a wiki URL.
pub fn encode_title(title: &str) -> String {
    let snake_case_title = title.replace(' ', "_").into_bytes();
    let encoded = percent_encoding::percent_encode(&snake_case_title, ROSETTA_ENCODE_SET);
    encoded.collect()
}

pub fn parse_tasks(response: &Response) -> Vec<RemoteTask> {
    response
        .query
        .pages
        .values()
        .map(|page| {
            let mut source = None;
            if !page.revisions.is_empty() {
                source = RUST_WIKI_SECTION_RE
                    .captures(&page.revisions[0].content)
                    .map(|captures| captures.get(1).unwrap())
                    .map(|m| m.as_str().to_owned());
            }

            let title = page.title.clone();
            let url = Url::parse(&format!(
                "http://rosettacode.org/wiki/{}",
                encode_title(&title)
            ))
            .unwrap();

            RemoteTask { title, url, source }
        })
        .collect()
}

#[cfg(test)]
mod tests {
    #[test]
    fn encode() {
        use super::encode_title;
        assert_eq!(
            encode_title("K-means++ clustering"),
            "K-means%2B%2B_clustering"
        );
    }

    #[test]
    fn decode() {
        use super::decode_title;
        assert_eq!(
            decode_title("K-means%2B%2B_clustering"),
            "K-means++ clustering"
        );
    }

    #[test]
    fn encode_decode() {
        const TITLE: &str = "Penney's game";

        assert_eq!(super::decode_title(&super::encode_title(TITLE)), TITLE);
    }
}
<commit_msg>Handle 0 length revisions better<commit_after>//! Utilities for interacting with tasks implemented on the Rosetta Code wiki.

use std::collections::HashMap;

use lazy_static::lazy_static;
use percent_encoding::{self, define_encode_set, QUERY_ENCODE_SET};
use regex::Regex;
use reqwest::Url;
use serde::Deserialize;

lazy_static! {
    /// Extracts code from the first Rust section from Rosetta Code wiki markup.
    static ref RUST_WIKI_SECTION_RE: Regex =
        Regex::new(r"==\{\{header\|[Rr]ust\}\}==(?s:.*?)<lang [Rr]ust>((?s:.*?))</lang>").unwrap();
}

define_encode_set! {
    /// Encoding set used for Rosetta Code URLs.
    ///
    /// The wiki generally encodes characters found in the query encode set, as well as some
    /// additional characters.
    pub ROSETTA_ENCODE_SET = [QUERY_ENCODE_SET] | { '+' }
}

/// Represents a task implemented on the Rosetta Code wiki.
#[derive(Debug, Clone)]
pub struct RemoteTask {
    title: String,
    url: Url,
    source: Option<String>,
}

impl RemoteTask {
    /// Returns the title of the task.
    pub fn title(&self) -> String {
        self.title.clone()
    }

    /// Returns the URL to the task on the wiki.
    pub fn url(&self) -> Url {
        self.url.clone()
    }

    /// If the task contains a Rust implementation on the wiki, this field will contain the first
    /// Rust code block of that section. Otherwise, returns `None`.
    pub fn source(&self) -> Option<String> {
        self.source.clone()
    }
}

#[derive(Debug, Deserialize)]
pub struct Response {
    pub query: Pages,
}

/// Intermediate container in the query API response.
#[derive(Debug, Deserialize)]
pub struct Pages {
    pub pages: HashMap<i32, Page>,
}

/// Individual page in the query API response.
#[derive(Debug, Deserialize)]
pub struct Page {
    #[serde(rename = "pageid")]
    pub id: i32,

    pub title: String,

    #[serde(default)]
    pub revisions: Vec<Revision>,
}

#[derive(Debug, Deserialize)]
pub struct Revision {
    #[serde(rename = "*")]
    pub content: String,
}

/// Transforms a URL-encoded task title from the wiki to a human-readable task title.
pub fn decode_title(title: &str) -> String {
    let title = title.replace('_', " ").into_bytes();
    let decoded = percent_encoding::percent_decode(&title);
    String::from_utf8(decoded.collect()).unwrap()
}

/// Transforms a human-readable task title to the form used in a wiki URL.
pub fn encode_title(title: &str) -> String {
    let snake_case_title = title.replace(' ', "_").into_bytes();
    let encoded = percent_encoding::percent_encode(&snake_case_title, ROSETTA_ENCODE_SET);
    encoded.collect()
}

pub fn parse_tasks(response: &Response) -> Vec<RemoteTask> {
    response
        .query
        .pages
        .values()
        .map(|page| {
            let source = if !page.revisions.is_empty() {
                RUST_WIKI_SECTION_RE
                    .captures(&page.revisions[0].content)
                    .map(|captures| captures.get(1).unwrap())
                    .map(|m| m.as_str().to_owned())
            } else {
                None
            };

            let title = page.title.clone();
            let url = Url::parse(&format!(
                "http://rosettacode.org/wiki/{}",
                encode_title(&title)
            ))
            .unwrap();

            RemoteTask { title, url, source }
        })
        .collect()
}

#[cfg(test)]
mod tests {
    #[test]
    fn encode() {
        use super::encode_title;
        assert_eq!(
            encode_title("K-means++ clustering"),
            "K-means%2B%2B_clustering"
        );
    }

    #[test]
    fn decode() {
        use super::decode_title;
        assert_eq!(
            decode_title("K-means%2B%2B_clustering"),
            "K-means++ clustering"
        );
    }

    #[test]
    fn encode_decode() {
        const TITLE: &str = "Penney's game";

        assert_eq!(super::decode_title(&super::encode_title(TITLE)), TITLE);
    }
}
<|endoftext|>


<commit_before>pub use self::DecodeError::*;
use std::fmt;

const BASE: u128 = 62;
const MAX_DECODE_LEN: usize = 111;
const ALPHABET: [u8; BASE as usize] = [
    b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'A', b'B', b'C', b'D', b'E', b'F',
    b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', b'P', b'Q', b'R', b'S', b'T', b'U', b'V',
    b'W', b'X', b'Y', b'Z', b'a', b'b', b'c', b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l',
    b'm', b'n', b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', b'x', b'y', b'z',
];

pub enum DecodeError {
    InvalidBase62Byte(char, usize),
    ArithmeticOverflow,
}

impl fmt::Debug for DecodeError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            InvalidBase62Byte(ch, idx) => {
                write!(f, "Invalid character '{}' at position {}", ch, idx)
            }
            ArithmeticOverflow => write!(f, "Decode result is too large"),
        }
    }
}

impl fmt::Display for DecodeError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self, f)
    }
}

///Encode any uint as base64.
///Returns a String.
///
///# Example
///
///```rust
///extern crate base62;
///
///fn main() {
///    let b62 = base62::encode(1337u32);
///    println!("{}", b62);
///}
///```
#[must_use]
pub fn encode<T: Into<u128>>(num: T) -> String {
    let mut num = num.into();
    if num == 0 {
        return "0".to_owned();
    }
    let mut bytes: [u8; MAX_DECODE_LEN] = [0; MAX_DECODE_LEN];

    let mut i: usize = 0;
    loop {
        if num == 0 {
            break;
        }
        i += 1;

        bytes[MAX_DECODE_LEN - i] = ALPHABET[(num % BASE) as usize];
        num /= BASE;
    }

    String::from_utf8(bytes[MAX_DECODE_LEN - i..MAX_DECODE_LEN].to_vec()).unwrap()
}

///Decode from string reference as octets.
///Returns a Result containing a u128 which can be downcasted to any other uint.
///
///# Example
///
///```rust
///extern crate base62;
///
///fn main() {
///    let bytes = base62::decode("rustlang").unwrap();
///    println!("{:?}", bytes);
///}
///```
pub fn decode<T: AsRef<[u8]>>(input: T) -> Result<u128, DecodeError> {
    let mut result = 0;
    let input = input.as_ref();

    for (i, c) in input.iter().rev().enumerate() {
        let num = BASE.checked_pow(i as u32).ok_or(ArithmeticOverflow)?;
        match ALPHABET.binary_search(&c) {
            Ok(v) => match (v as u128).checked_mul(num) {
                Some(z) => result += z,
                None => return Err(ArithmeticOverflow),
            },
            Err(_e) => {
                return Err(InvalidBase62Byte(c.to_owned() as char, input.len() - i));
            }
        }
    }

    Ok(result)
}

#[cfg(test)]
mod tests {
    use crate::base62;
    use quickcheck::TestResult;

    quickcheck! {
        fn encode_decode(xs: u128) -> bool {
            let encoded = base62::encode(xs);
            xs == base62::decode(&encoded).unwrap()
        }
    }

    quickcheck! {
        fn decode_good(xs: String) -> TestResult {
            if xs.chars().all(|c| c.is_ascii() && base62::ALPHABET.binary_search(&(c as u8)).is_ok()) && !xs.is_empty() {
                return TestResult::from_bool(base62::decode(&xs).is_ok());
            } else {
                TestResult::discard()
            }
        }
    }

    quickcheck! {
        fn decode_bad(xs: String) -> TestResult {
            if xs.chars().all(|c| c.is_ascii() && base62::ALPHABET.binary_search(&(c as u8)).is_ok()) {
                TestResult::discard()
            } else {
                return TestResult::from_bool(base62::decode(&xs).is_err());
            }
        }
    }

    #[test]
    fn test_encode() {
        assert_eq!(base62::encode(u128::MAX), "7n42DGM5Tflk9n8mt7Fhc7");
        assert_eq!(base62::encode(0u8), "0");
    }

    #[test]
    fn test_decode() {
        assert_eq!(base62::decode("7n42DGM5Tflk9n8mt7Fhc7").unwrap(), u128::MAX);
        assert_eq!(base62::decode("").unwrap(), 0);
    }

    #[test]
    fn test_decode_invalid_char() {
        assert!(base62::decode("ds{Z455f").is_err());
    }

    #[test]
    fn test_decode_long_string() {
        assert!(base62::decode("7n42DGM5Tflk9n8mt7Fhc7B").is_err());
    }
}
<commit_msg>simplify stupid code<commit_after>pub use self::DecodeError::*;
use std::fmt;

const BASE: u128 = 62;
const MAX_DECODED_LEN: usize = 111;
const ALPHABET: [u8; BASE as usize] = [
    b'0', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'9', b'A', b'B', b'C', b'D', b'E', b'F',
    b'G', b'H', b'I', b'J', b'K', b'L', b'M', b'N', b'O', b'P', b'Q', b'R', b'S', b'T', b'U', b'V',
    b'W', b'X', b'Y', b'Z', b'a', b'b', b'c', b'd', b'e', b'f', b'g', b'h', b'i', b'j', b'k', b'l',
    b'm', b'n', b'o', b'p', b'q', b'r', b's', b't', b'u', b'v', b'w', b'x', b'y', b'z',
];

pub enum DecodeError {
    InvalidBase62Byte(char, usize),
    ArithmeticOverflow,
}

impl fmt::Debug for DecodeError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            InvalidBase62Byte(ch, idx) => {
                write!(f, "Invalid character '{}' at position {}", ch, idx)
            }
            ArithmeticOverflow => write!(f, "Decode result is too large"),
        }
    }
}

impl fmt::Display for DecodeError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self, f)
    }
}

///Encode any uint as base64.
///Returns a String.
///
///# Example
///
///```rust
///extern crate base62;
///
///fn main() {
///    let b62 = base62::encode(1337u32);
///    println!("{}", b62);
///}
///```
#[must_use]
pub fn encode<T: Into<u128>>(num: T) -> String {
    let mut num = num.into();
    if num == 0 {
        return "0".to_owned();
    }
    let mut bytes: [u8; MAX_DECODED_LEN] = [0; MAX_DECODED_LEN];

    let mut i: usize = MAX_DECODED_LEN;
    loop {
        if num == 0 {
            break;
        }
        i -= 1;

        bytes[i] = ALPHABET[(num % BASE) as usize];
        num /= BASE;
    }

    String::from_utf8(bytes[i..MAX_DECODED_LEN].to_vec()).unwrap()
}

///Decode from string reference as octets.
///Returns a Result containing a u128 which can be downcasted to any other uint.
///
///# Example
///
///```rust
///extern crate base62;
///
///fn main() {
///    let bytes = base62::decode("rustlang").unwrap();
///    println!("{:?}", bytes);
///}
///```
pub fn decode<T: AsRef<[u8]>>(input: T) -> Result<u128, DecodeError> {
    let mut result = 0;
    let input = input.as_ref();

    for (i, c) in input.iter().rev().enumerate() {
        let num = BASE.checked_pow(i as u32).ok_or(ArithmeticOverflow)?;
        match ALPHABET.binary_search(&c) {
            Ok(v) => match (v as u128).checked_mul(num) {
                Some(z) => result += z,
                None => return Err(ArithmeticOverflow),
            },
            Err(_e) => {
                return Err(InvalidBase62Byte(c.to_owned() as char, input.len() - i));
            }
        }
    }

    Ok(result)
}

#[cfg(test)]
mod tests {
    use crate::base62;
    use quickcheck::TestResult;

    quickcheck! {
        fn encode_decode(xs: u128) -> bool {
            let encoded = base62::encode(xs);
            xs == base62::decode(&encoded).unwrap()
        }
    }

    quickcheck! {
        fn decode_good(xs: String) -> TestResult {
            if xs.chars().all(|c| c.is_ascii() && base62::ALPHABET.binary_search(&(c as u8)).is_ok()) && !xs.is_empty() {
                return TestResult::from_bool(base62::decode(&xs).is_ok());
            } else {
                TestResult::discard()
            }
        }
    }

    quickcheck! {
        fn decode_bad(xs: String) -> TestResult {
            if xs.chars().all(|c| c.is_ascii() && base62::ALPHABET.binary_search(&(c as u8)).is_ok()) {
                TestResult::discard()
            } else {
                return TestResult::from_bool(base62::decode(&xs).is_err());
            }
        }
    }

    #[test]
    fn test_encode() {
        assert_eq!(base62::encode(u128::MAX), "7n42DGM5Tflk9n8mt7Fhc7");
        assert_eq!(base62::encode(0u8), "0");
    }

    #[test]
    fn test_decode() {
        assert_eq!(base62::decode("7n42DGM5Tflk9n8mt7Fhc7").unwrap(), u128::MAX);
        assert_eq!(base62::decode("").unwrap(), 0);
    }

    #[test]
    fn test_decode_invalid_char() {
        assert!(base62::decode("ds{Z455f").is_err());
    }

    #[test]
    fn test_decode_long_string() {
        assert!(base62::decode("7n42DGM5Tflk9n8mt7Fhc7B").is_err());
    }
}
<|endoftext|>


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

extern crate gltf;

use std::{fs, io, path};

fn try_import(path: &path::Path) {
    let _ = gltf::import(&path).map_err(|err| {
        println!("{:?}: {:#?}", path, err);
        panic!();
    });
}

fn run() -> io::Result<()> {
    let sample_dir_path = path::Path::new("./glTF-Sample-Models/2.0");
    for entry in fs::read_dir(&sample_dir_path)? {
        let entry = entry?;
        let metadata = entry.metadata()?;
        if metadata.is_dir() {
            let entry_path = entry.path();
            if let Some(file_name) = entry_path.file_name() {
                if file_name.to_string_lossy() == "MetalRoughSpheres" {
                    // TODO: Remove once this model has been fixed.
                    // See https://github.com/KhronosGroup/glTF-Sample-Models/issues/68 for details.
                    continue;
                }
                let mut gltf_path = entry_path.join("glTF").join(file_name);
                gltf_path.set_extension("gltf");
                try_import(&gltf_path);
            }
        }
    }
    Ok(())
}

#[test]
fn import() {
    // Import all 'standard' glTF in the glTF-Sample-Models/2.0 directory.
    run().expect("No I/O errors");

    // Minimal example taken from https://github.com/javagl/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_003_MinimalGltfFile.md
    try_import(path::Path::new("tests/minimal.gltf"));
}

<commit_msg>Renamed import test<commit_after><|endoftext|>