<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 cssparser::RGBA;
use dom::attr::{Attr, AttrValue};
use dom::bindings::codegen::Bindings::HTMLTableElementBinding;
use dom::bindings::codegen::Bindings::HTMLTableElementBinding::HTMLTableElementMethods;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{LayoutJS, Root, RootedReference};
use dom::document::Document;
use dom::element::{AttributeMutation, Element, RawLayoutElementHelpers};
use dom::htmlelement::HTMLElement;
use dom::htmltablecaptionelement::HTMLTableCaptionElement;
use dom::htmltablesectionelement::HTMLTableSectionElement;
use dom::node::{Node, document_from_node};
use dom::virtualmethods::VirtualMethods;
use std::cell::Cell;
use string_cache::Atom;
use util::str::{self, DOMString, LengthOrPercentageOrAuto};

#[dom_struct]
pub struct HTMLTableElement {
    htmlelement: HTMLElement,
    background_color: Cell<Option<RGBA>>,
    border: Cell<Option<u32>>,
    cellspacing: Cell<Option<u32>>,
}

impl HTMLTableElement {
    fn new_inherited(localName: Atom, prefix: Option<DOMString>, document: &Document)
                     -> HTMLTableElement {
        HTMLTableElement {
            htmlelement: HTMLElement::new_inherited(localName, prefix, document),
            background_color: Cell::new(None),
            border: Cell::new(None),
            cellspacing: Cell::new(None),
        }
    }

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

    pub fn get_border(&self) -> Option<u32> {
        self.border.get()
    }
}

impl HTMLTableElementMethods for HTMLTableElement {
    // https://html.spec.whatwg.org/multipage/#dom-table-caption
    fn GetCaption(&self) -> Option<Root<HTMLTableCaptionElement>> {
        self.upcast::<Node>().children().filter_map(Root::downcast).next()
    }

    // https://html.spec.whatwg.org/multipage/#dom-table-caption
    fn SetCaption(&self, new_caption: Option<&HTMLTableCaptionElement>) {
        if let Some(ref caption) = self.GetCaption() {
            caption.upcast::<Node>().remove_self();
        }

        if let Some(caption) = new_caption {
            let node = self.upcast::<Node>();
            node.InsertBefore(caption.upcast(), node.GetFirstChild().r())
                .expect("Insertion failed");
        }
    }

    // https://html.spec.whatwg.org/multipage/#dom-table-createcaption
    fn CreateCaption(&self) -> Root<HTMLElement> {
        let caption = match self.GetCaption() {
            Some(caption) => caption,
            None => {
                let caption = HTMLTableCaptionElement::new(atom!("caption"),
                                                           None,
                                                           document_from_node(self).r());
                self.SetCaption(Some(caption.r()));
                caption
            }
        };
        Root::upcast(caption)
    }

    // https://html.spec.whatwg.org/multipage/#dom-table-deletecaption
    fn DeleteCaption(&self) {
        if let Some(caption) = self.GetCaption() {
            caption.upcast::<Node>().remove_self();
        }
    }

    // https://html.spec.whatwg.org/multipage/#dom-table-createtbody
    fn CreateTBody(&self) -> Root<HTMLTableSectionElement> {
        let tbody = HTMLTableSectionElement::new(atom!("tbody"),
                                                 None,
                                                 document_from_node(self).r());
        let node = self.upcast::<Node>();
        let last_tbody =
            node.rev_children()
                .filter_map(Root::downcast::<Element>)
                .find(|n| n.is::<HTMLTableSectionElement>() && n.local_name() == &atom!("tbody"));
        let reference_element =
            last_tbody.and_then(|t| t.upcast::<Node>().GetNextSibling());

        node.InsertBefore(tbody.upcast(), reference_element.r())
            .expect("Insertion failed");
        tbody
    }

    // https://html.spec.whatwg.org/multipage/#dom-table-bgcolor
    make_getter!(BgColor, "bgcolor");

    // https://html.spec.whatwg.org/multipage/#dom-table-bgcolor
    make_setter!(SetBgColor, "bgcolor");

    // https://html.spec.whatwg.org/multipage/#dom-table-width
    make_getter!(Width, "width");

    // https://html.spec.whatwg.org/multipage/#dom-table-width
    make_nonzero_dimension_setter!(SetWidth, "width");
}

pub trait HTMLTableElementLayoutHelpers {
    fn get_background_color(&self) -> Option<RGBA>;
    fn get_border(&self) -> Option<u32>;
    fn get_cellspacing(&self) -> Option<u32>;
    fn get_width(&self) -> LengthOrPercentageOrAuto;
}

impl HTMLTableElementLayoutHelpers for LayoutJS<HTMLTableElement> {
    #[allow(unsafe_code)]
    fn get_background_color(&self) -> Option<RGBA> {
        unsafe {
            (*self.unsafe_get()).background_color.get()
        }
    }

    #[allow(unsafe_code)]
    fn get_border(&self) -> Option<u32> {
        unsafe {
            (*self.unsafe_get()).border.get()
        }
    }

    #[allow(unsafe_code)]
    fn get_cellspacing(&self) -> Option<u32> {
        unsafe {
            (*self.unsafe_get()).cellspacing.get()
        }
    }

    #[allow(unsafe_code)]
    fn get_width(&self) -> LengthOrPercentageOrAuto {
        unsafe {
            (*self.upcast::<Element>().unsafe_get())
                .get_attr_for_layout(&ns!(), &atom!("width"))
                .map(AttrValue::as_dimension)
                .cloned()
                .unwrap_or(LengthOrPercentageOrAuto::Auto)
        }
    }
}

impl VirtualMethods for HTMLTableElement {
    fn super_type(&self) -> Option<&VirtualMethods> {
        Some(self.upcast::<HTMLElement>() as &VirtualMethods)
    }

    fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
        self.super_type().unwrap().attribute_mutated(attr, mutation);
        match *attr.local_name() {
            atom!("bgcolor") => {
                self.background_color.set(mutation.new_value(attr).and_then(|value| {
                    str::parse_legacy_color(&value).ok()
                }));
            },
            atom!("border") => {
                // According to HTML5 § 14.3.9, invalid values map to 1px.
                self.border.set(mutation.new_value(attr).map(|value| {
                    str::parse_unsigned_integer(value.chars()).unwrap_or(1)
                }));
            }
            atom!("cellspacing") => {
                self.cellspacing.set(mutation.new_value(attr).and_then(|value| {
                    str::parse_unsigned_integer(value.chars())
                }));
            },
            _ => {},
        }
    }

    fn parse_plain_attribute(&self, local_name: &Atom, value: DOMString) -> AttrValue {
        match *local_name {
            atom!("border") => AttrValue::from_u32(value, 1),
            atom!("width") => AttrValue::from_nonzero_dimension(value),
            _ => self.super_type().unwrap().parse_plain_attribute(local_name, value),
        }
    }
}
<commit_msg>Auto merge of #9111 - frewsxcv:rm-parsed-attr, r=nox<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 cssparser::RGBA;
use dom::attr::{Attr, AttrValue};
use dom::bindings::codegen::Bindings::HTMLTableElementBinding;
use dom::bindings::codegen::Bindings::HTMLTableElementBinding::HTMLTableElementMethods;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{LayoutJS, Root, RootedReference};
use dom::document::Document;
use dom::element::{AttributeMutation, Element, RawLayoutElementHelpers};
use dom::htmlelement::HTMLElement;
use dom::htmltablecaptionelement::HTMLTableCaptionElement;
use dom::htmltablesectionelement::HTMLTableSectionElement;
use dom::node::{Node, document_from_node};
use dom::virtualmethods::VirtualMethods;
use std::cell::Cell;
use string_cache::Atom;
use util::str::{self, DOMString, LengthOrPercentageOrAuto};

#[dom_struct]
pub struct HTMLTableElement {
    htmlelement: HTMLElement,
    border: Cell<Option<u32>>,
    cellspacing: Cell<Option<u32>>,
}

impl HTMLTableElement {
    fn new_inherited(localName: Atom, prefix: Option<DOMString>, document: &Document)
                     -> HTMLTableElement {
        HTMLTableElement {
            htmlelement: HTMLElement::new_inherited(localName, prefix, document),
            border: Cell::new(None),
            cellspacing: Cell::new(None),
        }
    }

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

    pub fn get_border(&self) -> Option<u32> {
        self.border.get()
    }
}

impl HTMLTableElementMethods for HTMLTableElement {
    // https://html.spec.whatwg.org/multipage/#dom-table-caption
    fn GetCaption(&self) -> Option<Root<HTMLTableCaptionElement>> {
        self.upcast::<Node>().children().filter_map(Root::downcast).next()
    }

    // https://html.spec.whatwg.org/multipage/#dom-table-caption
    fn SetCaption(&self, new_caption: Option<&HTMLTableCaptionElement>) {
        if let Some(ref caption) = self.GetCaption() {
            caption.upcast::<Node>().remove_self();
        }

        if let Some(caption) = new_caption {
            let node = self.upcast::<Node>();
            node.InsertBefore(caption.upcast(), node.GetFirstChild().r())
                .expect("Insertion failed");
        }
    }

    // https://html.spec.whatwg.org/multipage/#dom-table-createcaption
    fn CreateCaption(&self) -> Root<HTMLElement> {
        let caption = match self.GetCaption() {
            Some(caption) => caption,
            None => {
                let caption = HTMLTableCaptionElement::new(atom!("caption"),
                                                           None,
                                                           document_from_node(self).r());
                self.SetCaption(Some(caption.r()));
                caption
            }
        };
        Root::upcast(caption)
    }

    // https://html.spec.whatwg.org/multipage/#dom-table-deletecaption
    fn DeleteCaption(&self) {
        if let Some(caption) = self.GetCaption() {
            caption.upcast::<Node>().remove_self();
        }
    }

    // https://html.spec.whatwg.org/multipage/#dom-table-createtbody
    fn CreateTBody(&self) -> Root<HTMLTableSectionElement> {
        let tbody = HTMLTableSectionElement::new(atom!("tbody"),
                                                 None,
                                                 document_from_node(self).r());
        let node = self.upcast::<Node>();
        let last_tbody =
            node.rev_children()
                .filter_map(Root::downcast::<Element>)
                .find(|n| n.is::<HTMLTableSectionElement>() && n.local_name() == &atom!("tbody"));
        let reference_element =
            last_tbody.and_then(|t| t.upcast::<Node>().GetNextSibling());

        node.InsertBefore(tbody.upcast(), reference_element.r())
            .expect("Insertion failed");
        tbody
    }

    // https://html.spec.whatwg.org/multipage/#dom-table-bgcolor
    make_getter!(BgColor, "bgcolor");

    // https://html.spec.whatwg.org/multipage/#dom-table-bgcolor
    make_legacy_color_setter!(SetBgColor, "bgcolor");

    // https://html.spec.whatwg.org/multipage/#dom-table-width
    make_getter!(Width, "width");

    // https://html.spec.whatwg.org/multipage/#dom-table-width
    make_nonzero_dimension_setter!(SetWidth, "width");
}

pub trait HTMLTableElementLayoutHelpers {
    fn get_background_color(&self) -> Option<RGBA>;
    fn get_border(&self) -> Option<u32>;
    fn get_cellspacing(&self) -> Option<u32>;
    fn get_width(&self) -> LengthOrPercentageOrAuto;
}

impl HTMLTableElementLayoutHelpers for LayoutJS<HTMLTableElement> {
    #[allow(unsafe_code)]
    fn get_background_color(&self) -> Option<RGBA> {
        unsafe {
            (*self.upcast::<Element>().unsafe_get())
                .get_attr_for_layout(&ns!(), &atom!("bgcolor"))
                .and_then(AttrValue::as_color)
                .cloned()
        }
    }

    #[allow(unsafe_code)]
    fn get_border(&self) -> Option<u32> {
        unsafe {
            (*self.unsafe_get()).border.get()
        }
    }

    #[allow(unsafe_code)]
    fn get_cellspacing(&self) -> Option<u32> {
        unsafe {
            (*self.unsafe_get()).cellspacing.get()
        }
    }

    #[allow(unsafe_code)]
    fn get_width(&self) -> LengthOrPercentageOrAuto {
        unsafe {
            (*self.upcast::<Element>().unsafe_get())
                .get_attr_for_layout(&ns!(), &atom!("width"))
                .map(AttrValue::as_dimension)
                .cloned()
                .unwrap_or(LengthOrPercentageOrAuto::Auto)
        }
    }
}

impl VirtualMethods for HTMLTableElement {
    fn super_type(&self) -> Option<&VirtualMethods> {
        Some(self.upcast::<HTMLElement>() as &VirtualMethods)
    }

    fn attribute_mutated(&self, attr: &Attr, mutation: AttributeMutation) {
        self.super_type().unwrap().attribute_mutated(attr, mutation);
        match *attr.local_name() {
            atom!("border") => {
                // According to HTML5 § 14.3.9, invalid values map to 1px.
                self.border.set(mutation.new_value(attr).map(|value| {
                    str::parse_unsigned_integer(value.chars()).unwrap_or(1)
                }));
            }
            atom!("cellspacing") => {
                self.cellspacing.set(mutation.new_value(attr).and_then(|value| {
                    str::parse_unsigned_integer(value.chars())
                }));
            },
            _ => {},
        }
    }

    fn parse_plain_attribute(&self, local_name: &Atom, value: DOMString) -> AttrValue {
        match *local_name {
            atom!("border") => AttrValue::from_u32(value, 1),
            atom!("width") => AttrValue::from_nonzero_dimension(value),
            atom!("bgcolor") => AttrValue::from_legacy_color(value),
            _ => self.super_type().unwrap().parse_plain_attribute(local_name, value),
        }
    }
}
<|endoftext|>


<commit_before>use super::{Message,Name,Label};
use super::{read_dns_message,read_dns_question,read_dns_resource_record,read_dns_name};

use std::str;
static NET1_RS: &'static [u8] = include_bytes!("../../tests/packets/net1-rs.bin");

fn check_std_response_norecurse(m: &Message, q: usize, a: usize, n: usize, x: usize) {
    assert_eq!(m.flags, 0x8000);
    assert_eq!(m.questions.len(), q);
    assert_eq!(m.answers.len(), a);
    assert_eq!(m.nameservers.len(), n);
    assert_eq!(m.additionals.len(), x);
}

#[test]
fn test_label_create() {
    // Maximum label length is 63 octets
    let l63 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".as_bytes();
    let l64 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".as_bytes();
    let l0 = "".as_bytes();
    assert!(Label::from_slice(l63).is_ok());
    assert!(Label::from_slice(l64).is_err());
}

#[test]
fn test_label_eq() {
    let l1 = Label::from_slice("cat".as_bytes()).ok().unwrap();
    let l2 = Label::from_slice("Cat".as_bytes()).ok().unwrap();
    let l3 = Label::from_slice("CAT".as_bytes()).ok().unwrap();
    let l4 = Label::from_slice("cat1".as_bytes()).ok().unwrap();
    let l5 = Label::from_slice("cat2".as_bytes()).ok().unwrap();
    let l6 = Label::from_slice("Cat1".as_bytes()).ok().unwrap();

    // Case insensitivity tests
    assert_eq!(l1, l2);
    assert_eq!(l2, l3);
    assert_eq!(l1, l3);
    assert_eq!(l4, l6);

    // Basic inequality tests
    assert!(l4 != l5);
    assert!(l5 != l6);

    let mut b1 = [0x63u8, 0x61, 0x74, 0x31];
    let mut b2 = [0x63u8, 0x61, 0x74, 0x31];
    for i in 0..256usize {
        let x = i as u8;
        let y = if x > 0 { x - 1 } else { 255 };
        b1[3] = x;
        b2[3] = y;
        assert!(Label::from_slice(&b1) != Label::from_slice(&b2));
        b2[3] = x;
        assert!(Label::from_slice(&b1) == Label::from_slice(&b2));
    }
}
#[test]
fn test_label_ord() {
    let l = Label::from_slice("CAt".as_bytes()).ok().unwrap();
    let l0 = Label::from_slice("Cat".as_bytes()).ok().unwrap();
    let l1 = Label::from_slice("Cat1".as_bytes()).ok().unwrap();
    let l2 = Label::from_slice("cat1".as_bytes()).ok().unwrap();
    let l3 = Label::from_slice("cat2".as_bytes()).ok().unwrap();

    // Test ordering (DNSSEC canonical)
    assert!(l < l0);
    assert!(l0 < l1);
    assert!(l1 < l2);
    assert!(l2 < l3);
    assert!(l1 < l3);

    let mut b1 = [0x63u8, 0x61, 0x74, 0x00];
    let mut b2 = [0x63u8, 0x61, 0x74, 0x01];
    let mut b3 = [0x63u8, 0x61, 0x74, 0x02];
    let l1 = Label::from_slice(&b1).ok().unwrap();
    let l2 = Label::from_slice(&b2).ok().unwrap();
    let l3 = Label::from_slice(&b3).ok().unwrap();

    // Test ordering (DNSSEC canonical)
    assert!(l1 < l2);
    assert!(l2 < l3);
    assert!(l1 < l3);
}

#[test]
fn test_name_ord() {
    // ---> Begin RFC4034 testcases
    let n1 = "\x07axample\x00".as_bytes();
    let n2 = "\x07EXAMPLE\x00".as_bytes();
    let n3 = "\x01a\x07example\x00".as_bytes();
    let n4 = "\x08yljkjljk\x01a\x07example\x00".as_bytes();
    let n5 = "\x01Z\x01a\x07example\x00".as_bytes();
    let n6 = "\x04zABC\x01a\x07example\x00".as_bytes();
    let n7 = "\x01z\x07example\x00".as_bytes();
    let n8 = "\x01\x01\x01z\x07example\x00".as_bytes();
    let n9 = "\x01*\x01z\x07example\x00".as_bytes();
    let v = vec!(n1, n2, n3, n4, n5, n6, n7, n8, n9);
    let mut v2 = v.iter().map( |x| -> Name {
        read_dns_name(*x, &mut 0).ok().unwrap()
    }
    );
    let mut this = v2.next().unwrap();
    let mut that = v2.next().unwrap();
    while let Some(next) = v2.next() {
        this = that;
        that = next;
        assert!(this < that);
    }
    let n1 = "\x01*\x01z\x07example\x00".as_bytes();
    let n2 = "\x01\x01\x01z\x07example\x00".as_bytes();
    let n3 = "\x01z\x07example\x00".as_bytes();
    let n4 = "\x04zABC\x01a\x07example\x00".as_bytes();
    let n5 = "\x01Z\x01a\x07example\x00".as_bytes();
    let n6 = "\x08yljkjljk\x01a\x07example\x00".as_bytes();
    let n7 = "\x01a\x07example\x00".as_bytes();
    let n8 = "\x07EXAMPLE\x00".as_bytes();
    let n9 = "\x07axample\x00".as_bytes();
    let v = vec!(n1, n2, n3, n4, n5, n6, n7, n8, n9);
    let mut v2 = v.iter().map( |x| -> Name {
        read_dns_name(*x, &mut 0).ok().unwrap()
    }
    );
    let mut this = v2.next().unwrap();
    let mut that = v2.next().unwrap();
    while let Some(next) = v2.next() {
        this = that;
        that = next;
        assert!(this > that);
    }
    // <--- End RFC4034 testcases

    let mut v3 = vec!(
        "\x01A\x00".as_bytes(),
        "\x01a\x00".as_bytes(),
        "\x01b\x00".as_bytes(),
        "\x01c\x00".as_bytes(),
        "\x01d\x00".as_bytes(),
        "\x01c\x01d\x00".as_bytes(),
        "\x01B\x01c\x01d\x00".as_bytes(),
        "\x01b\x01C\x01d\x00".as_bytes(),
        "\x01b\x01c\x01d\x00".as_bytes(),
        "\x01\x10\x01b\x01c\x01d\x00".as_bytes(),
        "\x01\x11\x01b\x01c\x01d\x00".as_bytes(),
        "\x01\x12\x01b\x01c\x01d\x00".as_bytes(),
        "\x01\x13\x01b\x01c\x01d\x00".as_bytes(),
        "\x01\x14\x01b\x01c\x01d\x00".as_bytes(),
        );
    let mut v4 = v3.iter().map( |x| -> Name {
        //println!("{}", read_dns_name(*x, &mut 0));
        read_dns_name(*x, &mut 0).ok().unwrap()
    }
    );
    let mut this = v4.next().unwrap();
    let mut that = v4.next().unwrap();
    assert!(this < that);
    while let Some(next) = v4.next() {
        this = that;
        that = next;
        assert!(this < that);
    }

    let mut v5 = vec!(
        "\x01\x14\x01b\x01c\x01d\x00".as_bytes(),
        "\x01\x13\x01b\x01c\x01d\x00".as_bytes(),
        "\x01\x12\x01b\x01c\x01d\x00".as_bytes(),
        "\x01\x11\x01b\x01c\x01d\x00".as_bytes(),
        "\x01\x10\x01b\x01c\x01d\x00".as_bytes(),
        "\x01b\x01c\x01d\x00".as_bytes(),
        "\x01b\x01C\x01d\x00".as_bytes(),
        "\x01B\x01c\x01d\x00".as_bytes(),
        "\x01c\x01d\x00".as_bytes(),
        "\x01d\x00".as_bytes(),
        "\x01c\x00".as_bytes(),
        "\x01b\x00".as_bytes(),
        "\x01a\x00".as_bytes(),
        "\x01A\x00".as_bytes(),
        );
    let mut v6 = v5.iter().map( |x| -> Name {
        //println!("{}", read_dns_name(*x, &mut 0));
        read_dns_name(*x, &mut 0).ok().unwrap()
    }
    );
    let mut this = v6.next().unwrap();
    let mut that = v6.next().unwrap();
    assert!(this > that);
    while let Some(next) = v6.next() {
        this = that;
        that = next;
        assert!(this > that);
    }

    read_dns_name(n1, &mut 0).ok().unwrap();
}

#[test]
fn test_read_dns_message() {
    let m = match read_dns_message(NET1_RS) {
        Ok(x) => x,
        Err(e) => { println!("err: {}",e); panic!("FAIL"); },
    };
    assert_eq!(m.id, 0xe1c9);
    assert_eq!(m.flags, 0x8000);

    let q = m.questions[0].clone();
    assert_eq!(format!("{}",q.qname).as_str(), "net.");

    check_std_response_norecurse(&m, 1, 0, 13, 15);

    let mut a_ct: usize = 0;
    for a in m.nameservers.iter() {
        assert_eq!(a.rttl, 172800);

        let n = Name::from_rdata(a).ok().unwrap().to_string();
        if n.as_str() == "a.gtld-servers.net." { a_ct += 1; }
        if n.as_str() == "b.gtld-servers.net." { a_ct += 1; }
        if n.as_str() == "c.gtld-servers.net." { a_ct += 1; }
        if n.as_str() == "d.gtld-servers.net." { a_ct += 1; }
        if n.as_str() == "e.gtld-servers.net." { a_ct += 1; }
        if n.as_str() == "f.gtld-servers.net." { a_ct += 1; }
        if n.as_str() == "g.gtld-servers.net." { a_ct += 1; }
        if n.as_str() == "h.gtld-servers.net." { a_ct += 1; }
        if n.as_str() == "i.gtld-servers.net." { a_ct += 1; }
        if n.as_str() == "j.gtld-servers.net." { a_ct += 1; }
        if n.as_str() == "k.gtld-servers.net." { a_ct += 1; }
        if n.as_str() == "l.gtld-servers.net." { a_ct += 1; }
        if n.as_str() == "m.gtld-servers.net." { a_ct += 1; }
    }
    assert_eq!(a_ct, 13);
}

#[test]
fn test_bounds_checks() {
    let m = read_dns_message(&NET1_RS[0..NET1_RS.len()-2]).err();
}
<commit_msg>Clean compile 'cargo test'<commit_after>use super::{Message,Name,Label};
use super::{read_dns_message,read_dns_name};

static NET1_RS: &'static [u8] = include_bytes!("../../tests/packets/net1-rs.bin");

fn check_std_response_norecurse(m: &Message, q: usize, a: usize, n: usize, x: usize) {
    assert_eq!(m.flags, 0x8000);
    assert_eq!(m.questions.len(), q);
    assert_eq!(m.answers.len(), a);
    assert_eq!(m.nameservers.len(), n);
    assert_eq!(m.additionals.len(), x);
}

#[test]
fn test_label_create() {
    // Maximum label length is 63 octets
    let l63 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".as_bytes();
    let l64 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".as_bytes();
    assert!(Label::from_slice(l63).is_ok());
    assert!(Label::from_slice(l64).is_err());
}

#[test]
fn test_label_eq() {
    let l1 = Label::from_slice("cat".as_bytes()).ok().unwrap();
    let l2 = Label::from_slice("Cat".as_bytes()).ok().unwrap();
    let l3 = Label::from_slice("CAT".as_bytes()).ok().unwrap();
    let l4 = Label::from_slice("cat1".as_bytes()).ok().unwrap();
    let l5 = Label::from_slice("cat2".as_bytes()).ok().unwrap();
    let l6 = Label::from_slice("Cat1".as_bytes()).ok().unwrap();

    // Case insensitivity tests
    assert_eq!(l1, l2);
    assert_eq!(l2, l3);
    assert_eq!(l1, l3);
    assert_eq!(l4, l6);

    // Basic inequality tests
    assert!(l4 != l5);
    assert!(l5 != l6);

    let mut b1 = [0x63u8, 0x61, 0x74, 0x31];
    let mut b2 = [0x63u8, 0x61, 0x74, 0x31];
    for i in 0..256usize {
        let x = i as u8;
        let y = if x > 0 { x - 1 } else { 255 };
        b1[3] = x;
        b2[3] = y;
        assert!(Label::from_slice(&b1) != Label::from_slice(&b2));
        b2[3] = x;
        assert!(Label::from_slice(&b1) == Label::from_slice(&b2));
    }
}
#[test]
fn test_label_ord() {
    let l = Label::from_slice("CAt".as_bytes()).ok().unwrap();
    let l0 = Label::from_slice("Cat".as_bytes()).ok().unwrap();
    let l1 = Label::from_slice("Cat1".as_bytes()).ok().unwrap();
    let l2 = Label::from_slice("cat1".as_bytes()).ok().unwrap();
    let l3 = Label::from_slice("cat2".as_bytes()).ok().unwrap();

    // Test ordering (DNSSEC canonical)
    assert!(l < l0);
    assert!(l0 < l1);
    assert!(l1 < l2);
    assert!(l2 < l3);
    assert!(l1 < l3);

    let b1 = [0x63u8, 0x61, 0x74, 0x00];
    let b2 = [0x63u8, 0x61, 0x74, 0x01];
    let b3 = [0x63u8, 0x61, 0x74, 0x02];
    let l1 = Label::from_slice(&b1).ok().unwrap();
    let l2 = Label::from_slice(&b2).ok().unwrap();
    let l3 = Label::from_slice(&b3).ok().unwrap();

    // Test ordering (DNSSEC canonical)
    assert!(l1 < l2);
    assert!(l2 < l3);
    assert!(l1 < l3);
}

#[test]
fn test_name_ord() {
    // ---> Begin RFC4034 testcases
    let n1 = "\x07axample\x00".as_bytes();
    let n2 = "\x07EXAMPLE\x00".as_bytes();
    let n3 = "\x01a\x07example\x00".as_bytes();
    let n4 = "\x08yljkjljk\x01a\x07example\x00".as_bytes();
    let n5 = "\x01Z\x01a\x07example\x00".as_bytes();
    let n6 = "\x04zABC\x01a\x07example\x00".as_bytes();
    let n7 = "\x01z\x07example\x00".as_bytes();
    let n8 = "\x01\x01\x01z\x07example\x00".as_bytes();
    let n9 = "\x01*\x01z\x07example\x00".as_bytes();
    let v = vec!(n1, n2, n3, n4, n5, n6, n7, n8, n9);
    let mut v2 = v.iter().map( |x| -> Name {
        read_dns_name(*x, &mut 0).ok().unwrap()
    }
    );
    let mut this = v2.next().unwrap();
    let mut that = v2.next().unwrap();
    assert!(this < that);
    while let Some(next) = v2.next() {
        this = that;
        that = next;
        assert!(this < that);
    }
    let n1 = "\x01*\x01z\x07example\x00".as_bytes();
    let n2 = "\x01\x01\x01z\x07example\x00".as_bytes();
    let n3 = "\x01z\x07example\x00".as_bytes();
    let n4 = "\x04zABC\x01a\x07example\x00".as_bytes();
    let n5 = "\x01Z\x01a\x07example\x00".as_bytes();
    let n6 = "\x08yljkjljk\x01a\x07example\x00".as_bytes();
    let n7 = "\x01a\x07example\x00".as_bytes();
    let n8 = "\x07EXAMPLE\x00".as_bytes();
    let n9 = "\x07axample\x00".as_bytes();
    let v = vec!(n1, n2, n3, n4, n5, n6, n7, n8, n9);
    let mut v2 = v.iter().map( |x| -> Name {
        read_dns_name(*x, &mut 0).ok().unwrap()
    }
    );
    let mut this = v2.next().unwrap();
    let mut that = v2.next().unwrap();
    assert!(this > that);
    while let Some(next) = v2.next() {
        this = that;
        that = next;
        assert!(this > that);
    }
    // <--- End RFC4034 testcases

    let v3 = vec!(
        "\x01A\x00".as_bytes(),
        "\x01a\x00".as_bytes(),
        "\x01b\x00".as_bytes(),
        "\x01c\x00".as_bytes(),
        "\x01d\x00".as_bytes(),
        "\x01c\x01d\x00".as_bytes(),
        "\x01B\x01c\x01d\x00".as_bytes(),
        "\x01b\x01C\x01d\x00".as_bytes(),
        "\x01b\x01c\x01d\x00".as_bytes(),
        "\x01\x10\x01b\x01c\x01d\x00".as_bytes(),
        "\x01\x11\x01b\x01c\x01d\x00".as_bytes(),
        "\x01\x12\x01b\x01c\x01d\x00".as_bytes(),
        "\x01\x13\x01b\x01c\x01d\x00".as_bytes(),
        "\x01\x14\x01b\x01c\x01d\x00".as_bytes(),
        );
    let mut v4 = v3.iter().map( |x| -> Name {
        //println!("{}", read_dns_name(*x, &mut 0));
        read_dns_name(*x, &mut 0).ok().unwrap()
    }
    );
    let mut this = v4.next().unwrap();
    let mut that = v4.next().unwrap();
    assert!(this < that);
    while let Some(next) = v4.next() {
        this = that;
        that = next;
        assert!(this < that);
    }

    let v5 = vec!(
        "\x01\x14\x01b\x01c\x01d\x00".as_bytes(),
        "\x01\x13\x01b\x01c\x01d\x00".as_bytes(),
        "\x01\x12\x01b\x01c\x01d\x00".as_bytes(),
        "\x01\x11\x01b\x01c\x01d\x00".as_bytes(),
        "\x01\x10\x01b\x01c\x01d\x00".as_bytes(),
        "\x01b\x01c\x01d\x00".as_bytes(),
        "\x01b\x01C\x01d\x00".as_bytes(),
        "\x01B\x01c\x01d\x00".as_bytes(),
        "\x01c\x01d\x00".as_bytes(),
        "\x01d\x00".as_bytes(),
        "\x01c\x00".as_bytes(),
        "\x01b\x00".as_bytes(),
        "\x01a\x00".as_bytes(),
        "\x01A\x00".as_bytes(),
        );
    let mut v6 = v5.iter().map( |x| -> Name {
        //println!("{}", read_dns_name(*x, &mut 0));
        read_dns_name(*x, &mut 0).ok().unwrap()
    }
    );
    let mut this = v6.next().unwrap();
    let mut that = v6.next().unwrap();
    assert!(this > that);
    while let Some(next) = v6.next() {
        this = that;
        that = next;
        assert!(this > that);
    }

    read_dns_name(n1, &mut 0).ok().unwrap();
}

#[test]
fn test_read_dns_message() {
    let m = match read_dns_message(NET1_RS) {
        Ok(x) => x,
        Err(e) => { println!("err: {}",e); panic!("FAIL"); },
    };
    assert_eq!(m.id, 0xe1c9);
    assert_eq!(m.flags, 0x8000);

    let q = m.questions[0].clone();
    assert_eq!(format!("{}",q.qname).as_str(), "net.");

    check_std_response_norecurse(&m, 1, 0, 13, 15);

    let mut a_ct: usize = 0;
    for a in m.nameservers.iter() {
        assert_eq!(a.rttl, 172800);

        let n = Name::from_rdata(a).ok().unwrap().to_string();
        if n.as_str() == "a.gtld-servers.net." { a_ct += 1; }
        if n.as_str() == "b.gtld-servers.net." { a_ct += 1; }
        if n.as_str() == "c.gtld-servers.net." { a_ct += 1; }
        if n.as_str() == "d.gtld-servers.net." { a_ct += 1; }
        if n.as_str() == "e.gtld-servers.net." { a_ct += 1; }
        if n.as_str() == "f.gtld-servers.net." { a_ct += 1; }
        if n.as_str() == "g.gtld-servers.net." { a_ct += 1; }
        if n.as_str() == "h.gtld-servers.net." { a_ct += 1; }
        if n.as_str() == "i.gtld-servers.net." { a_ct += 1; }
        if n.as_str() == "j.gtld-servers.net." { a_ct += 1; }
        if n.as_str() == "k.gtld-servers.net." { a_ct += 1; }
        if n.as_str() == "l.gtld-servers.net." { a_ct += 1; }
        if n.as_str() == "m.gtld-servers.net." { a_ct += 1; }
    }
    assert_eq!(a_ct, 13);
}

#[test]
fn test_bounds_checks() {
    let _ = read_dns_message(&NET1_RS[0..NET1_RS.len()-2]).err();
}
<|endoftext|>


<commit_before>use std::fmt::{Show,Formatter};
use std::fmt;
use std::hash::Hasher;
use std::hash::sip::SipHasher;
use std::str;

use core::source::{Source, SourceId, GitKind, Location, Remote, Local};
use core::{Package,PackageId,Summary};
use util::{CargoResult, Config, to_hex};
use sources::PathSource;
use sources::git::utils::{GitReference,GitRemote,Master,Other};

/* TODO: Refactor GitSource to delegate to a PathSource
 */
pub struct GitSource<'a, 'b> {
    remote: GitRemote,
    reference: GitReference,
    db_path: Path,
    checkout_path: Path,
    path_source: PathSource,
    config: &'a mut Config<'b>
}

impl<'a, 'b> GitSource<'a, 'b> {
    pub fn new<'a, 'b>(source_id: &SourceId, config: &'a mut Config<'b>) -> GitSource<'a, 'b> {
        assert!(source_id.is_git(), "id is not git, id={}", source_id);

        let reference = match source_id.kind {
            GitKind(ref reference) => reference,
            _ => fail!("Not a git source; id={}", source_id)
        };

        let remote = GitRemote::new(source_id.get_location());
        let ident = ident(source_id.get_location());

        let db_path = config.git_db_path()
            .join(ident.as_slice());

        let checkout_path = config.git_checkout_path()
            .join(ident.as_slice()).join(reference.as_slice());

        let path_source = PathSource::new(&checkout_path, source_id);

        GitSource {
            remote: remote,
            reference: GitReference::for_str(reference.as_slice()),
            db_path: db_path,
            checkout_path: checkout_path,
            path_source: path_source,
            config: config
        }
    }

    pub fn get_namespace<'a>(&'a self) -> &'a Location {
        self.remote.get_location()
    }
}

fn ident(location: &Location) -> String {
    let hasher = SipHasher::new_with_keys(0,0);

    // FIXME: this really should be able to not use to_str() everywhere, but the
    //        compiler seems to currently ask for static lifetimes spuriously.
    //        Perhaps related to rust-lang/rust#15144
    let ident = match *location {
        Local(ref path) => {
            let last = path.components().last().unwrap();
            str::from_utf8(last).unwrap().to_str()
        }
        Remote(ref url) => url.path.as_slice().split('/').last().unwrap().to_str()
    };

    let ident = if ident.as_slice() == "" {
        "_empty".to_string()
    } else {
        ident
    };

    format!("{}-{}", ident, to_hex(hasher.hash(&location.to_str())))
}

impl<'a, 'b> Show for GitSource<'a, 'b> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        try!(write!(f, "git repo at {}", self.remote.get_location()));

        match self.reference {
            Master => Ok(()),
            Other(ref reference) => write!(f, " ({})", reference)
        }
    }
}

impl<'a, 'b> Source for GitSource<'a, 'b> {
    fn update(&mut self) -> CargoResult<()> {
        let should_update = self.config.update_remotes() || {
            !self.remote.has_ref(&self.db_path, self.reference.as_slice()).is_ok()
        };

        let repo = if should_update {
            try!(self.config.shell().status("Updating",
                format!("git repository `{}`", self.remote.get_location())));

            log!(5, "updating git source `{}`", self.remote);
            try!(self.remote.checkout(&self.db_path))
        } else {
            self.remote.db_at(&self.db_path)
        };

        try!(repo.copy_to(self.reference.as_slice(), &self.checkout_path));

        self.path_source.update()
    }

    fn list(&self) -> CargoResult<Vec<Summary>> {
        self.path_source.list()
    }

    fn download(&self, _: &[PackageId]) -> CargoResult<()> {
        // TODO: assert! that the PackageId is contained by the source
        Ok(())
    }

    fn get(&self, ids: &[PackageId]) -> CargoResult<Vec<Package>> {
        log!(5, "getting packages for package ids `{}` from `{}`", ids, self.remote);
        self.path_source.get(ids)
    }

    fn fingerprint(&self, _pkg: &Package) -> CargoResult<String> {
        let db = self.remote.db_at(&self.db_path);
        db.rev_for(self.reference.as_slice())
    }
}

#[cfg(test)]
mod test {
    use url;
    use url::Url;
    use core::source::Remote;
    use super::ident;

    #[test]
    pub fn test_url_to_path_ident_with_path() {
        let ident = ident(&Remote(url("https://github.com/carlhuda/cargo")));
        assert_eq!(ident.as_slice(), "cargo-0eed735c8ffd7c88");
    }

    #[test]
    pub fn test_url_to_path_ident_without_path() {
        let ident = ident(&Remote(url("https://github.com")));
        assert_eq!(ident.as_slice(), "_empty-fc065c9b6b16fc00");
    }

    fn url(s: &str) -> Url {
        url::from_str(s).unwrap()
    }
}
<commit_msg>Revert "Merge pull request #89 from rust-lang/revert-88-fix"<commit_after>use std::fmt::{Show,Formatter};
use std::fmt;
use std::hash::Hasher;
use std::hash::sip::SipHasher;
use std::str;

use core::source::{Source, SourceId, GitKind, Location, Remote, Local};
use core::{Package,PackageId,Summary};
use util::{CargoResult, Config, to_hex};
use sources::PathSource;
use sources::git::utils::{GitReference,GitRemote,Master,Other};

/* TODO: Refactor GitSource to delegate to a PathSource
 */
pub struct GitSource<'a, 'b> {
    remote: GitRemote,
    reference: GitReference,
    db_path: Path,
    checkout_path: Path,
    path_source: PathSource,
    config: &'a mut Config<'b>
}

impl<'a, 'b> GitSource<'a, 'b> {
    pub fn new<'a, 'b>(source_id: &SourceId, config: &'a mut Config<'b>) -> GitSource<'a, 'b> {
        assert!(source_id.is_git(), "id is not git, id={}", source_id);

        let reference = match source_id.kind {
            GitKind(ref reference) => reference,
            _ => fail!("Not a git source; id={}", source_id)
        };

        let remote = GitRemote::new(source_id.get_location());
        let ident = ident(source_id.get_location());

        let db_path = config.git_db_path()
            .join(ident.as_slice());

        let checkout_path = config.git_checkout_path()
            .join(ident.as_slice()).join(reference.as_slice());

        let path_source = PathSource::new(&checkout_path, source_id);

        GitSource {
            remote: remote,
            reference: GitReference::for_str(reference.as_slice()),
            db_path: db_path,
            checkout_path: checkout_path,
            path_source: path_source,
            config: config
        }
    }

    pub fn get_namespace<'a>(&'a self) -> &'a Location {
        self.remote.get_location()
    }
}

fn ident(location: &Location) -> String {
    let hasher = SipHasher::new_with_keys(0,0);

    // FIXME: this really should be able to not use to_str() everywhere, but the
    //        compiler seems to currently ask for static lifetimes spuriously.
    //        Perhaps related to rust-lang/rust#15144
    let ident = match *location {
        Local(ref path) => {
            let last = path.components().last().unwrap();
            str::from_utf8(last).unwrap().to_str()
        }
        Remote(ref url) => {
            let path = canonicalize_url(url.path.as_slice());
            path.as_slice().split('/').last().unwrap().to_str()
        }
    };

    let ident = if ident.as_slice() == "" {
        "_empty".to_string()
    } else {
        ident
    };

    let location = canonicalize_url(location.to_str().as_slice());

    format!("{}-{}", ident, to_hex(hasher.hash(&location.as_slice())))
}

fn strip_trailing_slash<'a>(path: &'a str) -> &'a str {
    // Remove the trailing '/' so that 'split' doesn't give us
    // an empty string, making '../foo/' and '../foo' both
    // result in the name 'foo' (#84)
    if path.as_bytes().last() != Some(&('/' as u8)) {
        path.clone()
    } else {
        path.slice(0, path.len() - 1)
    }
}

// Some hacks and heuristics for making equivalent URLs hash the same
fn canonicalize_url(url: &str) -> String {
    let url = strip_trailing_slash(url);

    // HACKHACK: For github URL's specifically just lowercase
    // everything.  GitHub traits both the same, but they hash
    // differently, and we're gonna be hashing them. This wants a more
    // general solution, and also we're almost certainly not using the
    // same case conversion rules that GitHub does. (#84)

    let lower_url = url.chars().map(|c|c.to_lowercase()).collect::<String>();
    let url = if lower_url.as_slice().contains("github.com") {
        lower_url
    } else {
        url.to_string()
    };

    // Repos generally can be accessed with or w/o '.git'
    let url = if !url.as_slice().ends_with(".git") {
        url
    } else {
        url.as_slice().slice(0, url.len() - 4).to_string()
    };

    return url;
}

impl<'a, 'b> Show for GitSource<'a, 'b> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        try!(write!(f, "git repo at {}", self.remote.get_location()));

        match self.reference {
            Master => Ok(()),
            Other(ref reference) => write!(f, " ({})", reference)
        }
    }
}

impl<'a, 'b> Source for GitSource<'a, 'b> {
    fn update(&mut self) -> CargoResult<()> {
        let should_update = self.config.update_remotes() || {
            !self.remote.has_ref(&self.db_path, self.reference.as_slice()).is_ok()
        };

        let repo = if should_update {
            try!(self.config.shell().status("Updating",
                format!("git repository `{}`", self.remote.get_location())));

            log!(5, "updating git source `{}`", self.remote);
            try!(self.remote.checkout(&self.db_path))
        } else {
            self.remote.db_at(&self.db_path)
        };

        try!(repo.copy_to(self.reference.as_slice(), &self.checkout_path));

        self.path_source.update()
    }

    fn list(&self) -> CargoResult<Vec<Summary>> {
        self.path_source.list()
    }

    fn download(&self, _: &[PackageId]) -> CargoResult<()> {
        // TODO: assert! that the PackageId is contained by the source
        Ok(())
    }

    fn get(&self, ids: &[PackageId]) -> CargoResult<Vec<Package>> {
        log!(5, "getting packages for package ids `{}` from `{}`", ids, self.remote);
        self.path_source.get(ids)
    }

    fn fingerprint(&self, _pkg: &Package) -> CargoResult<String> {
        let db = self.remote.db_at(&self.db_path);
        db.rev_for(self.reference.as_slice())
    }
}

#[cfg(test)]
mod test {
    use url;
    use url::Url;
    use core::source::Remote;
    use super::ident;

    #[test]
    pub fn test_url_to_path_ident_with_path() {
        let ident = ident(&Remote(url("https://github.com/carlhuda/cargo")));
        assert_eq!(ident.as_slice(), "cargo-0eed735c8ffd7c88");
    }

    #[test]
    pub fn test_url_to_path_ident_without_path() {
        let ident = ident(&Remote(url("https://github.com")));
        assert_eq!(ident.as_slice(), "_empty-fc065c9b6b16fc00");
    }

    #[test]
    fn test_canonicalize_idents_by_stripping_trailing_url_slash() {
        let ident1 = ident(&Remote(url("https://github.com/PistonDevelopers/piston/")));
        let ident2 = ident(&Remote(url("https://github.com/PistonDevelopers/piston")));
        assert_eq!(ident1, ident2);
    }

    #[test]
    fn test_canonicalize_idents_by_lowercasing_github_urls() {
        let ident1 = ident(&Remote(url("https://github.com/PistonDevelopers/piston")));
        let ident2 = ident(&Remote(url("https://github.com/pistondevelopers/piston")));
        assert_eq!(ident1, ident2);
    }

    #[test]
    fn test_canonicalize_idents_by_stripping_dot_git() {
        let ident1 = ident(&Remote(url("https://github.com/PistonDevelopers/piston")));
        let ident2 = ident(&Remote(url("https://github.com/PistonDevelopers/piston.git")));
        assert_eq!(ident1, ident2);
    }

    fn url(s: &str) -> Url {
        url::from_str(s).unwrap()
    }
}
<|endoftext|>


<commit_before>use super::generate;

#[test]
fn partial_overlap() {
    let set = generate(vec![('3', '6')]);

    let low  = generate(vec![('1', '4')]);
    let high = generate(vec![('5', '9')]);

    let sym_dif_low  = set.symmetric_difference(&low);
    let sym_dif_high = set.symmetric_difference(&high);

    let other_low  = generate(vec![('1', '2'), ('5', '6')]);
    let other_high = generate(vec![('3', '4'), ('7', '9')]);

    assert_eq!(sym_dif_low, other_low);
    assert_eq!(sym_dif_high, other_high);
}
#[test]
fn subset() {
    let set = generate(vec![('2', '7')]);

    let subset      = generate(vec![('3', '6')]);
    let exact_left  = generate(vec![('2', '6')]);
    let exact_right = generate(vec![('3', '7')]);

    let sym_dif_subset = set.symmetric_difference(&subset);
    let sym_dif_left   = set.symmetric_difference(&exact_left);
    let sym_dif_right  = set.symmetric_difference(&exact_right);
    let sym_dif_both   = set.symmetric_difference(&set);

    let other_subset = generate(vec![('2', '2'), ('7', '7')]);
    let other_left   = generate(vec![('7', '7')]);
    let other_right  = generate(vec![('2', '2')]);
    let other_both   = generate(vec![]);

    assert_eq!(sym_dif_subset, other_subset);
    assert_eq!(sym_dif_left, other_left);
    assert_eq!(sym_dif_right, other_right);
    assert_eq!(sym_dif_both, other_both);
}
#[test]
fn superset() {
    let set      = generate(vec![('2', '7')]);
    let superset = generate(vec![('1', '8')]);

    let sym_dif = set.symmetric_difference(&superset);

    let other = generate(vec![('1', '1'), ('8', '8')]);
    assert_eq!(sym_dif, other);
}
/*#[test]
fn disjoint() {
    let set = generate(vec![('3', '4')]);

    let low  = generate(vec![('1', '2')]);
    let high = generate(vec![('5', '6')]);

    let sym_dif_low  = set.symmetric_difference(&low);
    let sym_dif_high = set.symmetric_difference(&high);

    let other_low  = generate(vec![('1', '4')]);
    let other_high = generate(vec![('3', '6')]);

    assert_eq!(sym_dif_low, other_low);
    assert_eq!(sym_dif_high, other_high);
}*/
<commit_msg>Update range_set symmetric_difference tests<commit_after>use super::generate;

#[test]
fn partial_overlap() {
    let set = generate(vec![('3', '6')]);

    let low  = generate(vec![('1', '4')]);
    let high = generate(vec![('5', '9')]);

    let other_low  = generate(vec![('1', '2'), ('5', '6')]);
    let other_high = generate(vec![('3', '4'), ('7', '9')]);

    assert_eq!(set.symmetric_difference(&low), other_low);
    assert_eq!(set.symmetric_difference(&high), other_high);
}
#[test]
fn subset() {
    let set = generate(vec![('2', '7')]);

    let subset      = generate(vec![('3', '6')]);
    let exact_left  = generate(vec![('2', '6')]);
    let exact_right = generate(vec![('3', '7')]);

    let other_subset = generate(vec![('2', '2'), ('7', '7')]);
    let other_left   = generate(vec![('7', '7')]);
    let other_right  = generate(vec![('2', '2')]);
    let other_both   = generate(vec![]);

    assert_eq!(set.symmetric_difference(&subset), other_subset);
    assert_eq!(set.symmetric_difference(&exact_left), other_left);
    assert_eq!(set.symmetric_difference(&exact_right), other_right);
    assert_eq!(set.symmetric_difference(&set), other_both);
}
#[test]
fn superset() {
    let set      = generate(vec![('2', '7')]);
    let superset = generate(vec![('1', '8')]);

    let other = generate(vec![('1', '1'), ('8', '8')]);
    assert_eq!(set.symmetric_difference(&superset), other);
}
#[test]
fn disjoint() {
    let set = generate(vec![('4', '5')]);

    let low  = generate(vec![('1', '2')]);
    let high = generate(vec![('7', '8')]);

    let other_low  = generate(vec![('1', '2'), ('4', '5')]);
    let other_high = generate(vec![('4', '5'), ('7', '8')]);

    assert_eq!(set.symmetric_difference(&low), other_low);
    assert_eq!(set.symmetric_difference(&high), other_high);
}
#[test]
fn disjoint_extend() {
    let set = generate(vec![('3', '4')]);

    let low  = generate(vec![('1', '2')]);
    let high = generate(vec![('5', '6')]);

    let other_low  = generate(vec![('1', '4')]);
    let other_high = generate(vec![('3', '6')]);

    assert_eq!(set.symmetric_difference(&low), other_low);
    assert_eq!(set.symmetric_difference(&high), other_high);
}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! Sampling from random distributions.
//!
//! This is a generalization of `Rand` to allow parameters to control the
//! exact properties of the generated values, e.g. the mean and standard
//! deviation of a normal distribution. The `Sample` trait is the most
//! general, and allows for generating values that change some state
//! internally. The `IndependentSample` trait is for generating values
//! that do not need to record state.

use core::num::Float;
use core::marker::PhantomData;

use {Rng, Rand};

pub use self::range::Range;
pub use self::gamma::{Gamma, ChiSquared, FisherF, StudentT};
pub use self::normal::{Normal, LogNormal};
pub use self::exponential::Exp;

pub mod range;
pub mod gamma;
pub mod normal;
pub mod exponential;

/// Types that can be used to create a random instance of `Support`.
pub trait Sample<Support> {
    /// Generate a random value of `Support`, using `rng` as the
    /// source of randomness.
    fn sample<R: Rng>(&mut self, rng: &mut R) -> Support;
}

/// `Sample`s that do not require keeping track of state.
///
/// Since no state is recorded, each sample is (statistically)
/// independent of all others, assuming the `Rng` used has this
/// property.
// FIXME maybe having this separate is overkill (the only reason is to
// take &self rather than &mut self)? or maybe this should be the
// trait called `Sample` and the other should be `DependentSample`.
pub trait IndependentSample<Support>: Sample<Support> {
    /// Generate a random value.
    fn ind_sample<R: Rng>(&self, &mut R) -> Support;
}

/// A wrapper for generating types that implement `Rand` via the
/// `Sample` & `IndependentSample` traits.
pub struct RandSample<Sup> {
    _marker: PhantomData<Sup>,
}

impl<Sup> RandSample<Sup> {
    pub fn new() -> RandSample<Sup> {
        RandSample { _marker: PhantomData }
    }
}

impl<Sup: Rand> Sample<Sup> for RandSample<Sup> {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> Sup {
        self.ind_sample(rng)
    }
}

impl<Sup: Rand> IndependentSample<Sup> for RandSample<Sup> {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> Sup {
        rng.gen()
    }
}

/// A value with a particular weight for use with `WeightedChoice`.
pub struct Weighted<T> {
    /// The numerical weight of this item
    pub weight: usize,
    /// The actual item which is being weighted
    pub item: T,
}

/// A distribution that selects from a finite collection of weighted items.
///
/// Each item has an associated weight that influences how likely it
/// is to be chosen: higher weight is more likely.
///
/// The `Clone` restriction is a limitation of the `Sample` and
/// `IndependentSample` traits. Note that `&T` is (cheaply) `Clone` for
/// all `T`, as is `usize`, so one can store references or indices into
/// another vector.
pub struct WeightedChoice<'a, T: 'a> {
    items: &'a mut [Weighted<T>],
    weight_range: Range<usize>,
}

impl<'a, T: Clone> WeightedChoice<'a, T> {
    /// Create a new `WeightedChoice`.
    ///
    /// Panics if:
    /// - `v` is empty
    /// - the total weight is 0
    /// - the total weight is larger than a `usize` can contain.
    pub fn new(items: &'a mut [Weighted<T>]) -> WeightedChoice<'a, T> {
        // strictly speaking, this is subsumed by the total weight == 0 case
        assert!(!items.is_empty(),
                "WeightedChoice::new called with no items");

        let mut running_total = 0_usize;

        // we convert the list from individual weights to cumulative
        // weights so we can binary search. This *could* drop elements
        // with weight == 0 as an optimisation.
        for item in &mut *items {
            running_total = match running_total.checked_add(item.weight) {
                Some(n) => n,
                None => panic!("WeightedChoice::new called with a total weight larger than a \
                                usize can contain"),
            };

            item.weight = running_total;
        }
        assert!(running_total != 0,
                "WeightedChoice::new called with a total weight of 0");

        WeightedChoice {
            items: items,
            // we're likely to be generating numbers in this range
            // relatively often, so might as well cache it
            weight_range: Range::new(0, running_total),
        }
    }
}

impl<'a, T: Clone> Sample<T> for WeightedChoice<'a, T> {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> T {
        self.ind_sample(rng)
    }
}

impl<'a, T: Clone> IndependentSample<T> for WeightedChoice<'a, T> {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> T {
        // we want to find the first element that has cumulative
        // weight > sample_weight, which we do by binary since the
        // cumulative weights of self.items are sorted.

        // choose a weight in [0, total_weight)
        let sample_weight = self.weight_range.ind_sample(rng);

        // short circuit when it's the first item
        if sample_weight < self.items[0].weight {
            return self.items[0].item.clone();
        }

        let mut idx = 0;
        let mut modifier = self.items.len();

        // now we know that every possibility has an element to the
        // left, so we can just search for the last element that has
        // cumulative weight <= sample_weight, then the next one will
        // be "it". (Note that this greatest element will never be the
        // last element of the vector, since sample_weight is chosen
        // in [0, total_weight) and the cumulative weight of the last
        // one is exactly the total weight.)
        while modifier > 1 {
            let i = idx + modifier / 2;
            if self.items[i].weight <= sample_weight {
                // we're small, so look to the right, but allow this
                // exact element still.
                idx = i;
                // we need the `/ 2` to round up otherwise we'll drop
                // the trailing elements when `modifier` is odd.
                modifier += 1;
            } else {
                // otherwise we're too big, so go left. (i.e. do
                // nothing)
            }
            modifier /= 2;
        }
        return self.items[idx + 1].item.clone();
    }
}

mod ziggurat_tables;

/// Sample a random number using the Ziggurat method (specifically the
/// ZIGNOR variant from Doornik 2005). Most of the arguments are
/// directly from the paper:
///
/// * `rng`: source of randomness
/// * `symmetric`: whether this is a symmetric distribution, or one-sided with P(x < 0) = 0.
/// * `X`: the $x_i$ abscissae.
/// * `F`: precomputed values of the PDF at the $x_i$, (i.e. $f(x_i)$)
/// * `F_DIFF`: precomputed values of $f(x_i) - f(x_{i+1})$
/// * `pdf`: the probability density function
/// * `zero_case`: manual sampling from the tail when we chose the
///    bottom box (i.e. i == 0)
// the perf improvement (25-50%) is definitely worth the extra code
// size from force-inlining.
#[inline(always)]
fn ziggurat<R: Rng, P, Z>(rng: &mut R,
                          symmetric: bool,
                          x_tab: ziggurat_tables::ZigTable,
                          f_tab: ziggurat_tables::ZigTable,
                          mut pdf: P,
                          mut zero_case: Z)
                          -> f64
    where P: FnMut(f64) -> f64,
          Z: FnMut(&mut R, f64) -> f64
{
    const SCALE: f64 = (1u64 << 53) as f64;
    loop {
        // reimplement the f64 generation as an optimisation suggested
        // by the Doornik paper: we have a lot of precision-space
        // (i.e. there are 11 bits of the 64 of a u64 to use after
        // creating a f64), so we might as well reuse some to save
        // generating a whole extra random number. (Seems to be 15%
        // faster.)
        //
        // This unfortunately misses out on the benefits of direct
        // floating point generation if an RNG like dSMFT is
        // used. (That is, such RNGs create floats directly, highly
        // efficiently and overload next_f32/f64, so by not calling it
        // this may be slower than it would be otherwise.)
        // FIXME: investigate/optimise for the above.
        let bits: u64 = rng.gen();
        let i = (bits & 0xff) as usize;
        let f = (bits >> 11) as f64 / SCALE;

        // u is either U(-1, 1) or U(0, 1) depending on if this is a
        // symmetric distribution or not.
        let u = if symmetric {
            2.0 * f - 1.0
        } else {
            f
        };
        let x = u * x_tab[i];

        let test_x = if symmetric {
            x.abs()
        } else {
            x
        };

        // algebraically equivalent to |u| < x_tab[i+1]/x_tab[i] (or u < x_tab[i+1]/x_tab[i])
        if test_x < x_tab[i + 1] {
            return x;
        }
        if i == 0 {
            return zero_case(rng, u);
        }
        // algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1
        if f_tab[i + 1] + (f_tab[i] - f_tab[i + 1]) * rng.gen::<f64>() < pdf(x) {
            return x;
        }
    }
}

#[cfg(test)]
mod tests {
    use std::prelude::v1::*;

    use {Rng, Rand};
    use super::{RandSample, WeightedChoice, Weighted, Sample, IndependentSample};

    #[derive(PartialEq, Debug)]
    struct ConstRand(usize);
    impl Rand for ConstRand {
        fn rand<R: Rng>(_: &mut R) -> ConstRand {
            ConstRand(0)
        }
    }

    // 0, 1, 2, 3, ...
    struct CountingRng {
        i: u32,
    }
    impl Rng for CountingRng {
        fn next_u32(&mut self) -> u32 {
            self.i += 1;
            self.i - 1
        }
        fn next_u64(&mut self) -> u64 {
            self.next_u32() as u64
        }
    }

    #[test]
    fn test_rand_sample() {
        let mut rand_sample = RandSample::<ConstRand>::new();

        assert_eq!(rand_sample.sample(&mut ::test::rng()), ConstRand(0));
        assert_eq!(rand_sample.ind_sample(&mut ::test::rng()), ConstRand(0));
    }
    #[test]
    fn test_weighted_choice() {
        // this makes assumptions about the internal implementation of
        // WeightedChoice, specifically: it doesn't reorder the items,
        // it doesn't do weird things to the RNG (so 0 maps to 0, 1 to
        // 1, internally; modulo a modulo operation).

        macro_rules! t {
            ($items:expr, $expected:expr) => {{
                let mut items = $items;
                let wc = WeightedChoice::new(&mut items);
                let expected = $expected;

                let mut rng = CountingRng { i: 0 };

                for &val in &expected {
                    assert_eq!(wc.ind_sample(&mut rng), val)
                }
            }}
        }

        t!(vec!(Weighted {
               weight: 1,
               item: 10,
           }),
           [10]);

        // skip some
        t!(vec!(Weighted {
                    weight: 0,
                    item: 20,
                },
                Weighted {
                    weight: 2,
                    item: 21,
                },
                Weighted {
                    weight: 0,
                    item: 22,
                },
                Weighted {
                    weight: 1,
                    item: 23,
                }),
           [21, 21, 23]);

        // different weights
        t!(vec!(Weighted {
                    weight: 4,
                    item: 30,
                },
                Weighted {
                    weight: 3,
                    item: 31,
                }),
           [30, 30, 30, 30, 31, 31, 31]);

        // check that we're binary searching
        // correctly with some vectors of odd
        // length.
        t!(vec!(Weighted {
                    weight: 1,
                    item: 40,
                },
                Weighted {
                    weight: 1,
                    item: 41,
                },
                Weighted {
                    weight: 1,
                    item: 42,
                },
                Weighted {
                    weight: 1,
                    item: 43,
                },
                Weighted {
                    weight: 1,
                    item: 44,
                }),
           [40, 41, 42, 43, 44]);
        t!(vec!(Weighted {
                    weight: 1,
                    item: 50,
                },
                Weighted {
                    weight: 1,
                    item: 51,
                },
                Weighted {
                    weight: 1,
                    item: 52,
                },
                Weighted {
                    weight: 1,
                    item: 53,
                },
                Weighted {
                    weight: 1,
                    item: 54,
                },
                Weighted {
                    weight: 1,
                    item: 55,
                },
                Weighted {
                    weight: 1,
                    item: 56,
                }),
           [50, 51, 52, 53, 54, 55, 56]);
    }

    #[test]
    #[should_panic]
    fn test_weighted_choice_no_items() {
        WeightedChoice::<isize>::new(&mut []);
    }
    #[test]
    #[should_panic]
    fn test_weighted_choice_zero_weight() {
        WeightedChoice::new(&mut [Weighted {
                                      weight: 0,
                                      item: 0,
                                  },
                                  Weighted {
                                      weight: 0,
                                      item: 1,
                                  }]);
    }
    #[test]
    #[should_panic]
    fn test_weighted_choice_weight_overflows() {
        let x = (!0) as usize / 2; // x + x + 2 is the overflow
        WeightedChoice::new(&mut [Weighted {
                                      weight: x,
                                      item: 0,
                                  },
                                  Weighted {
                                      weight: 1,
                                      item: 1,
                                  },
                                  Weighted {
                                      weight: x,
                                      item: 2,
                                  },
                                  Weighted {
                                      weight: 1,
                                      item: 3,
                                  }]);
    }
}
<commit_msg>Tests fixup<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// 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.

//! Sampling from random distributions.
//!
//! This is a generalization of `Rand` to allow parameters to control the
//! exact properties of the generated values, e.g. the mean and standard
//! deviation of a normal distribution. The `Sample` trait is the most
//! general, and allows for generating values that change some state
//! internally. The `IndependentSample` trait is for generating values
//! that do not need to record state.

use core::num::Float;
use core::marker::PhantomData;

use {Rng, Rand};

pub use self::range::Range;
pub use self::gamma::{Gamma, ChiSquared, FisherF, StudentT};
pub use self::normal::{Normal, LogNormal};
pub use self::exponential::Exp;

pub mod range;
pub mod gamma;
pub mod normal;
pub mod exponential;

/// Types that can be used to create a random instance of `Support`.
pub trait Sample<Support> {
    /// Generate a random value of `Support`, using `rng` as the
    /// source of randomness.
    fn sample<R: Rng>(&mut self, rng: &mut R) -> Support;
}

/// `Sample`s that do not require keeping track of state.
///
/// Since no state is recorded, each sample is (statistically)
/// independent of all others, assuming the `Rng` used has this
/// property.
// FIXME maybe having this separate is overkill (the only reason is to
// take &self rather than &mut self)? or maybe this should be the
// trait called `Sample` and the other should be `DependentSample`.
pub trait IndependentSample<Support>: Sample<Support> {
    /// Generate a random value.
    fn ind_sample<R: Rng>(&self, &mut R) -> Support;
}

/// A wrapper for generating types that implement `Rand` via the
/// `Sample` & `IndependentSample` traits.
pub struct RandSample<Sup> {
    _marker: PhantomData<Sup>,
}

impl<Sup> RandSample<Sup> {
    pub fn new() -> RandSample<Sup> {
        RandSample { _marker: PhantomData }
    }
}

impl<Sup: Rand> Sample<Sup> for RandSample<Sup> {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> Sup {
        self.ind_sample(rng)
    }
}

impl<Sup: Rand> IndependentSample<Sup> for RandSample<Sup> {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> Sup {
        rng.gen()
    }
}

/// A value with a particular weight for use with `WeightedChoice`.
pub struct Weighted<T> {
    /// The numerical weight of this item
    pub weight: usize,
    /// The actual item which is being weighted
    pub item: T,
}

/// A distribution that selects from a finite collection of weighted items.
///
/// Each item has an associated weight that influences how likely it
/// is to be chosen: higher weight is more likely.
///
/// The `Clone` restriction is a limitation of the `Sample` and
/// `IndependentSample` traits. Note that `&T` is (cheaply) `Clone` for
/// all `T`, as is `usize`, so one can store references or indices into
/// another vector.
pub struct WeightedChoice<'a, T: 'a> {
    items: &'a mut [Weighted<T>],
    weight_range: Range<usize>,
}

impl<'a, T: Clone> WeightedChoice<'a, T> {
    /// Create a new `WeightedChoice`.
    ///
    /// Panics if:
    /// - `v` is empty
    /// - the total weight is 0
    /// - the total weight is larger than a `usize` can contain.
    pub fn new(items: &'a mut [Weighted<T>]) -> WeightedChoice<'a, T> {
        // strictly speaking, this is subsumed by the total weight == 0 case
        assert!(!items.is_empty(),
                "WeightedChoice::new called with no items");

        let mut running_total = 0_usize;

        // we convert the list from individual weights to cumulative
        // weights so we can binary search. This *could* drop elements
        // with weight == 0 as an optimisation.
        for item in &mut *items {
            running_total = match running_total.checked_add(item.weight) {
                Some(n) => n,
                None => panic!("WeightedChoice::new called with a total weight larger than a \
                                usize can contain"),
            };

            item.weight = running_total;
        }
        assert!(running_total != 0,
                "WeightedChoice::new called with a total weight of 0");

        WeightedChoice {
            items: items,
            // we're likely to be generating numbers in this range
            // relatively often, so might as well cache it
            weight_range: Range::new(0, running_total),
        }
    }
}

impl<'a, T: Clone> Sample<T> for WeightedChoice<'a, T> {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> T {
        self.ind_sample(rng)
    }
}

impl<'a, T: Clone> IndependentSample<T> for WeightedChoice<'a, T> {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> T {
        // we want to find the first element that has cumulative
        // weight > sample_weight, which we do by binary since the
        // cumulative weights of self.items are sorted.

        // choose a weight in [0, total_weight)
        let sample_weight = self.weight_range.ind_sample(rng);

        // short circuit when it's the first item
        if sample_weight < self.items[0].weight {
            return self.items[0].item.clone();
        }

        let mut idx = 0;
        let mut modifier = self.items.len();

        // now we know that every possibility has an element to the
        // left, so we can just search for the last element that has
        // cumulative weight <= sample_weight, then the next one will
        // be "it". (Note that this greatest element will never be the
        // last element of the vector, since sample_weight is chosen
        // in [0, total_weight) and the cumulative weight of the last
        // one is exactly the total weight.)
        while modifier > 1 {
            let i = idx + modifier / 2;
            if self.items[i].weight <= sample_weight {
                // we're small, so look to the right, but allow this
                // exact element still.
                idx = i;
                // we need the `/ 2` to round up otherwise we'll drop
                // the trailing elements when `modifier` is odd.
                modifier += 1;
            } else {
                // otherwise we're too big, so go left. (i.e. do
                // nothing)
            }
            modifier /= 2;
        }
        return self.items[idx + 1].item.clone();
    }
}

mod ziggurat_tables;

/// Sample a random number using the Ziggurat method (specifically the
/// ZIGNOR variant from Doornik 2005). Most of the arguments are
/// directly from the paper:
///
/// * `rng`: source of randomness
/// * `symmetric`: whether this is a symmetric distribution, or one-sided with P(x < 0) = 0.
/// * `X`: the $x_i$ abscissae.
/// * `F`: precomputed values of the PDF at the $x_i$, (i.e. $f(x_i)$)
/// * `F_DIFF`: precomputed values of $f(x_i) - f(x_{i+1})$
/// * `pdf`: the probability density function
/// * `zero_case`: manual sampling from the tail when we chose the
///    bottom box (i.e. i == 0)

// the perf improvement (25-50%) is definitely worth the extra code
// size from force-inlining.
#[inline(always)]
fn ziggurat<R: Rng, P, Z>(rng: &mut R,
                          symmetric: bool,
                          x_tab: ziggurat_tables::ZigTable,
                          f_tab: ziggurat_tables::ZigTable,
                          mut pdf: P,
                          mut zero_case: Z)
                          -> f64
    where P: FnMut(f64) -> f64,
          Z: FnMut(&mut R, f64) -> f64
{
    const SCALE: f64 = (1u64 << 53) as f64;
    loop {
        // reimplement the f64 generation as an optimisation suggested
        // by the Doornik paper: we have a lot of precision-space
        // (i.e. there are 11 bits of the 64 of a u64 to use after
        // creating a f64), so we might as well reuse some to save
        // generating a whole extra random number. (Seems to be 15%
        // faster.)
        //
        // This unfortunately misses out on the benefits of direct
        // floating point generation if an RNG like dSMFT is
        // used. (That is, such RNGs create floats directly, highly
        // efficiently and overload next_f32/f64, so by not calling it
        // this may be slower than it would be otherwise.)
        // FIXME: investigate/optimise for the above.
        let bits: u64 = rng.gen();
        let i = (bits & 0xff) as usize;
        let f = (bits >> 11) as f64 / SCALE;

        // u is either U(-1, 1) or U(0, 1) depending on if this is a
        // symmetric distribution or not.
        let u = if symmetric {
            2.0 * f - 1.0
        } else {
            f
        };
        let x = u * x_tab[i];

        let test_x = if symmetric {
            x.abs()
        } else {
            x
        };

        // algebraically equivalent to |u| < x_tab[i+1]/x_tab[i] (or u < x_tab[i+1]/x_tab[i])
        if test_x < x_tab[i + 1] {
            return x;
        }
        if i == 0 {
            return zero_case(rng, u);
        }
        // algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1
        if f_tab[i + 1] + (f_tab[i] - f_tab[i + 1]) * rng.gen::<f64>() < pdf(x) {
            return x;
        }
    }
}

#[cfg(test)]
mod tests {
    use std::prelude::v1::*;

    use {Rng, Rand};
    use super::{RandSample, WeightedChoice, Weighted, Sample, IndependentSample};

    #[derive(PartialEq, Debug)]
    struct ConstRand(usize);
    impl Rand for ConstRand {
        fn rand<R: Rng>(_: &mut R) -> ConstRand {
            ConstRand(0)
        }
    }

    // 0, 1, 2, 3, ...
    struct CountingRng {
        i: u32,
    }
    impl Rng for CountingRng {
        fn next_u32(&mut self) -> u32 {
            self.i += 1;
            self.i - 1
        }
        fn next_u64(&mut self) -> u64 {
            self.next_u32() as u64
        }
    }

    #[test]
    fn test_rand_sample() {
        let mut rand_sample = RandSample::<ConstRand>::new();

        assert_eq!(rand_sample.sample(&mut ::test::rng()), ConstRand(0));
        assert_eq!(rand_sample.ind_sample(&mut ::test::rng()), ConstRand(0));
    }
    #[test]
    #[rustfmt_skip]
    fn test_weighted_choice() {
        // this makes assumptions about the internal implementation of
        // WeightedChoice, specifically: it doesn't reorder the items,
        // it doesn't do weird things to the RNG (so 0 maps to 0, 1 to
        // 1, internally; modulo a modulo operation).

        macro_rules! t {
            ($items:expr, $expected:expr) => {{
                let mut items = $items;
                let wc = WeightedChoice::new(&mut items);
                let expected = $expected;

                let mut rng = CountingRng { i: 0 };

                for &val in &expected {
                    assert_eq!(wc.ind_sample(&mut rng), val)
                }
            }}
        }

        t!(vec!(Weighted { weight: 1, item: 10 }),
           [10]);

        // skip some
        t!(vec!(Weighted { weight: 0, item: 20 },
                Weighted { weight: 2, item: 21 },
                Weighted { weight: 0, item: 22 },
                Weighted { weight: 1, item: 23 }),
           [21, 21, 23]);

        // different weights
        t!(vec!(Weighted { weight: 4, item: 30 },
                Weighted { weight: 3, item: 31 }),
           [30, 30, 30, 30, 31, 31, 31]);

        // check that we're binary searching
        // correctly with some vectors of odd
        // length.
        t!(vec!(Weighted { weight: 1, item: 40 },
                Weighted { weight: 1, item: 41 },
                Weighted { weight: 1, item: 42 },
                Weighted { weight: 1, item: 43 },
                Weighted { weight: 1, item: 44 }),
           [40, 41, 42, 43, 44]);
        t!(vec!(Weighted { weight: 1, item: 50 },
                Weighted { weight: 1, item: 51 },
                Weighted { weight: 1, item: 52 },
                Weighted { weight: 1, item: 53 },
                Weighted { weight: 1, item: 54 },
                Weighted { weight: 1, item: 55 },
                Weighted { weight: 1, item: 56 }),
           [50, 51, 52, 53, 54, 55, 56]);
    }

    #[test]
    #[should_panic]
    fn test_weighted_choice_no_items() {
        WeightedChoice::<isize>::new(&mut []);
    }
    #[test]
    #[should_panic]
    #[rustfmt_skip]
    fn test_weighted_choice_zero_weight() {
        WeightedChoice::new(&mut [Weighted { weight: 0, item: 0 },
                                  Weighted { weight: 0, item: 1 }]);
    }
    #[test]
    #[should_panic]
    #[rustfmt_skip]
    fn test_weighted_choice_weight_overflows() {
        let x = (!0) as usize / 2; // x + x + 2 is the overflow
        WeightedChoice::new(&mut [Weighted { weight: x, item: 0 },
                                  Weighted { weight: 1, item: 1 },
                                  Weighted { weight: x, item: 2 },
                                  Weighted { weight: 1, item: 3 }]);
    }
}
<|endoftext|>


<commit_before>/// The underlying OsString/OsStr implementation on Windows is a
/// wrapper around the "WTF-8" encoding; see the `wtf8` module for more.
use crate::borrow::Cow;
use crate::fmt;
use crate::mem;
use crate::rc::Rc;
use crate::sync::Arc;
use crate::sys_common::wtf8::{Wtf8, Wtf8Buf};
use crate::sys_common::{AsInner, FromInner, IntoInner};

#[derive(Clone, Hash)]
pub struct Buf {
    pub inner: Wtf8Buf,
}

impl IntoInner<Wtf8Buf> for Buf {
    fn into_inner(self) -> Wtf8Buf {
        self.inner
    }
}

impl FromInner<Wtf8Buf> for Buf {
    fn from_inner(inner: Wtf8Buf) -> Self {
        Buf { inner }
    }
}

impl AsInner<Wtf8> for Buf {
    fn as_inner(&self) -> &Wtf8 {
        &self.inner
    }
}

impl fmt::Debug for Buf {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(self.as_slice(), formatter)
    }
}

impl fmt::Display for Buf {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(self.as_slice(), formatter)
    }
}

pub struct Slice {
    pub inner: Wtf8,
}

impl fmt::Debug for Slice {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(&self.inner, formatter)
    }
}

impl fmt::Display for Slice {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&self.inner, formatter)
    }
}

impl Buf {
    pub fn with_capacity(capacity: usize) -> Buf {
        Buf { inner: Wtf8Buf::with_capacity(capacity) }
    }

    pub fn clear(&mut self) {
        self.inner.clear()
    }

    pub fn capacity(&self) -> usize {
        self.inner.capacity()
    }

    pub fn from_string(s: String) -> Buf {
        Buf { inner: Wtf8Buf::from_string(s) }
    }

    pub fn as_slice(&self) -> &Slice {
        // Safety: Slice is just a wrapper for Wtf8,
        // and as_slice returns &Wtf8. Therefore,
        // transmute &Wtf8 to &Slice is safe.
        unsafe { mem::transmute(self.inner.as_slice()) }
    }

    pub fn as_mut_slice(&mut self) -> &mut Slice {
        // Safety: Slice is just a wrapper for Wtf8,
        // and as_slice returns &Wtf8. Therefore,
        // transmute &mut Wtf8 to &mut Slice is safe.
        unsafe { mem::transmute(self.inner.as_mut_slice()) }
    }

    pub fn into_string(self) -> Result<String, Buf> {
        self.inner.into_string().map_err(|buf| Buf { inner: buf })
    }

    pub fn push_slice(&mut self, s: &Slice) {
        self.inner.push_wtf8(&s.inner)
    }

    pub fn reserve(&mut self, additional: usize) {
        self.inner.reserve(additional)
    }

    pub fn reserve_exact(&mut self, additional: usize) {
        self.inner.reserve_exact(additional)
    }

    pub fn shrink_to_fit(&mut self) {
        self.inner.shrink_to_fit()
    }

    #[inline]
    pub fn shrink_to(&mut self, min_capacity: usize) {
        self.inner.shrink_to(min_capacity)
    }

    #[inline]
    pub fn into_box(self) -> Box<Slice> {
        unsafe { mem::transmute(self.inner.into_box()) }
    }

    #[inline]
    pub fn from_box(boxed: Box<Slice>) -> Buf {
        let inner: Box<Wtf8> = unsafe { mem::transmute(boxed) };
        Buf { inner: Wtf8Buf::from_box(inner) }
    }

    #[inline]
    pub fn into_arc(&self) -> Arc<Slice> {
        self.as_slice().into_arc()
    }

    #[inline]
    pub fn into_rc(&self) -> Rc<Slice> {
        self.as_slice().into_rc()
    }
}

impl Slice {
    #[inline]
    pub fn from_str(s: &str) -> &Slice {
        unsafe { mem::transmute(Wtf8::from_str(s)) }
    }

    pub fn to_str(&self) -> Option<&str> {
        self.inner.as_str()
    }

    pub fn to_string_lossy(&self) -> Cow<'_, str> {
        self.inner.to_string_lossy()
    }

    pub fn to_owned(&self) -> Buf {
        let mut buf = Wtf8Buf::with_capacity(self.inner.len());
        buf.push_wtf8(&self.inner);
        Buf { inner: buf }
    }

    #[inline]
    pub fn into_box(&self) -> Box<Slice> {
        unsafe { mem::transmute(self.inner.into_box()) }
    }

    pub fn empty_box() -> Box<Slice> {
        unsafe { mem::transmute(Wtf8::empty_box()) }
    }

    #[inline]
    pub fn into_arc(&self) -> Arc<Slice> {
        let arc = self.inner.into_arc();
        unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Slice) }
    }

    #[inline]
    pub fn into_rc(&self) -> Rc<Slice> {
        let rc = self.inner.into_rc();
        unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) }
    }
}
<commit_msg>corrections on safety comments<commit_after>/// The underlying OsString/OsStr implementation on Windows is a
/// wrapper around the "WTF-8" encoding; see the `wtf8` module for more.
use crate::borrow::Cow;
use crate::fmt;
use crate::mem;
use crate::rc::Rc;
use crate::sync::Arc;
use crate::sys_common::wtf8::{Wtf8, Wtf8Buf};
use crate::sys_common::{AsInner, FromInner, IntoInner};

#[derive(Clone, Hash)]
pub struct Buf {
    pub inner: Wtf8Buf,
}

impl IntoInner<Wtf8Buf> for Buf {
    fn into_inner(self) -> Wtf8Buf {
        self.inner
    }
}

impl FromInner<Wtf8Buf> for Buf {
    fn from_inner(inner: Wtf8Buf) -> Self {
        Buf { inner }
    }
}

impl AsInner<Wtf8> for Buf {
    fn as_inner(&self) -> &Wtf8 {
        &self.inner
    }
}

impl fmt::Debug for Buf {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(self.as_slice(), formatter)
    }
}

impl fmt::Display for Buf {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(self.as_slice(), formatter)
    }
}

pub struct Slice {
    pub inner: Wtf8,
}

impl fmt::Debug for Slice {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Debug::fmt(&self.inner, formatter)
    }
}

impl fmt::Display for Slice {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&self.inner, formatter)
    }
}

impl Buf {
    pub fn with_capacity(capacity: usize) -> Buf {
        Buf { inner: Wtf8Buf::with_capacity(capacity) }
    }

    pub fn clear(&mut self) {
        self.inner.clear()
    }

    pub fn capacity(&self) -> usize {
        self.inner.capacity()
    }

    pub fn from_string(s: String) -> Buf {
        Buf { inner: Wtf8Buf::from_string(s) }
    }

    pub fn as_slice(&self) -> &Slice {
        // Safety: Slice is just a wrapper for Wtf8,
        // and as_slice returns &Wtf8. Therefore,
        // transmuting &Wtf8 to &Slice is safe.
        unsafe { mem::transmute(self.inner.as_slice()) }
    }

    pub fn as_mut_slice(&mut self) -> &mut Slice {
        // Safety: Slice is just a wrapper for Wtf8,
        // and as_mut_slice returns &mut Wtf8. Therefore,
        // transmuting &mut Wtf8 to &mut Slice is safe.
        unsafe { mem::transmute(self.inner.as_mut_slice()) }
    }

    pub fn into_string(self) -> Result<String, Buf> {
        self.inner.into_string().map_err(|buf| Buf { inner: buf })
    }

    pub fn push_slice(&mut self, s: &Slice) {
        self.inner.push_wtf8(&s.inner)
    }

    pub fn reserve(&mut self, additional: usize) {
        self.inner.reserve(additional)
    }

    pub fn reserve_exact(&mut self, additional: usize) {
        self.inner.reserve_exact(additional)
    }

    pub fn shrink_to_fit(&mut self) {
        self.inner.shrink_to_fit()
    }

    #[inline]
    pub fn shrink_to(&mut self, min_capacity: usize) {
        self.inner.shrink_to(min_capacity)
    }

    #[inline]
    pub fn into_box(self) -> Box<Slice> {
        unsafe { mem::transmute(self.inner.into_box()) }
    }

    #[inline]
    pub fn from_box(boxed: Box<Slice>) -> Buf {
        let inner: Box<Wtf8> = unsafe { mem::transmute(boxed) };
        Buf { inner: Wtf8Buf::from_box(inner) }
    }

    #[inline]
    pub fn into_arc(&self) -> Arc<Slice> {
        self.as_slice().into_arc()
    }

    #[inline]
    pub fn into_rc(&self) -> Rc<Slice> {
        self.as_slice().into_rc()
    }
}

impl Slice {
    #[inline]
    pub fn from_str(s: &str) -> &Slice {
        unsafe { mem::transmute(Wtf8::from_str(s)) }
    }

    pub fn to_str(&self) -> Option<&str> {
        self.inner.as_str()
    }

    pub fn to_string_lossy(&self) -> Cow<'_, str> {
        self.inner.to_string_lossy()
    }

    pub fn to_owned(&self) -> Buf {
        let mut buf = Wtf8Buf::with_capacity(self.inner.len());
        buf.push_wtf8(&self.inner);
        Buf { inner: buf }
    }

    #[inline]
    pub fn into_box(&self) -> Box<Slice> {
        unsafe { mem::transmute(self.inner.into_box()) }
    }

    pub fn empty_box() -> Box<Slice> {
        unsafe { mem::transmute(Wtf8::empty_box()) }
    }

    #[inline]
    pub fn into_arc(&self) -> Arc<Slice> {
        let arc = self.inner.into_arc();
        unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Slice) }
    }

    #[inline]
    pub fn into_rc(&self) -> Rc<Slice> {
        let rc = self.inner.into_rc();
        unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) }
    }
}
<|endoftext|>