<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::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use dom::bindings::codegen::Bindings::CloseEventBinding;
use dom::bindings::codegen::Bindings::CloseEventBinding::CloseEventMethods;
use dom::bindings::codegen::InheritTypes::EventCast;
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JSRef,Temporary, Rootable};
use dom::bindings::utils::reflect_dom_object;
use dom::event::{Event, EventTypeId, EventBubbles, EventCancelable};
use script_task::ScriptChan;
use std::borrow::ToOwned;
use std::cell::Cell;
use util::str::DOMString;

#[dom_struct]
pub struct CloseEvent{
    event: Event,
    wasClean: Cell<bool>,
    code: Cell<u16>,
    reason: DOMRefCell<DOMString>
}

#[derive(PartialEq)]
pub enum Clean {
    Clean,
    NotClean
}

impl CloseEvent{
    pub fn new_inherited(type_id: EventTypeId) -> CloseEvent{
        CloseEvent{
            event: Event::new_inherited(type_id),
            wasClean: Cell::new(false),
            code: Cell::new(0),
            reason: DOMRefCell::new("".to_owned())
        }
    }

    pub fn new(global: GlobalRef,
               type_: DOMString,
               bubbles: EventBubbles,
               cancelable: EventCancelable,
               wasClean: bool,
               code: u16,
               reason: DOMString) -> Temporary<CloseEvent> {
        let ev = reflect_dom_object(box CloseEvent::new_inherited(EventTypeId::CloseEvent),
                                    global,
                                    CloseEventBinding::Wrap);
		let ev = ev.root();
        let event: JSRef<Event> = EventCast::from_ref(ev.r());
        event.InitEvent(type_,
                        bubbles == EventBubbles::Bubbles,
                        cancelable == EventCancelable::Cancelable);
        let ev = ev.r();
        ev.wasClean.set(wasClean);
        ev.code.set(code);
        *ev.reason.borrow_mut() = reason;
        Temporary::from_rooted(ev)
    }

    pub fn Constructor(global: GlobalRef,
                       type_: DOMString,
                       init: &CloseEventBinding::CloseEventInit) -> Fallible<Temporary<CloseEvent>> {
        let clean_status = init.wasClean.unwrap_or();
        let cd = init.code.unwrap_or(0);
        let rsn = match init.reason.as_ref() {
            Some(reason) => reason.clone(),
            None => "".to_owned(),
        };
        let bubbles = if init.parent.bubbles { EventBubbles::Bubbles } else { EventBubbles::DoesNotBubble };
        let cancelable = if init.parent.cancelable { EventCancelable::Cancelable } else { EventCancelable::NotCancelable };
        Ok(CloseEvent::new(global, type_, bubbles, cancelable, clean_status, cd, rsn))
    }
}

impl<'a> CloseEventMethods for JSRef<'a, CloseEvent>{
    fn WasClean(self) -> bool {
        self.wasClean.get()
    }

    fn Code(self) -> u16 {
        self.code.get()
    }

    fn Reason(self) -> DOMString {
        let reason = self.reason.borrow();
        reason.clone()
    }
}
<commit_msg>Cleaned up closeevent.rs some more.<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::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::EventBinding::EventMethods;
use dom::bindings::codegen::Bindings::CloseEventBinding;
use dom::bindings::codegen::Bindings::CloseEventBinding::CloseEventMethods;
use dom::bindings::codegen::InheritTypes::EventCast;
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JSRef,Temporary, Rootable};
use dom::bindings::utils::reflect_dom_object;
use dom::event::{Event, EventTypeId, EventBubbles, EventCancelable};
use script_task::ScriptChan;
use std::borrow::ToOwned;
use std::cell::Cell;
use util::str::DOMString;

#[dom_struct]
pub struct CloseEvent{
    event: Event,
    wasClean: Cell<bool>,
    code: Cell<u16>,
    reason: DOMRefCell<DOMString>
}

impl CloseEvent{
    pub fn new_inherited(type_id: EventTypeId) -> CloseEvent{
        CloseEvent{
            event: Event::new_inherited(type_id),
            wasClean: Cell::new(true),
            code: Cell::new(0),
            reason: DOMRefCell::new("".to_owned())
        }
    }

    pub fn new(global: GlobalRef,
               type_: DOMString,
               bubbles: EventBubbles,
               cancelable: EventCancelable,
               wasClean: bool,
               code: u16,
               reason: DOMString) -> Temporary<CloseEvent> {
        let ev = reflect_dom_object(box CloseEvent::new_inherited(EventTypeId::CloseEvent),
                                    global,
                                    CloseEventBinding::Wrap);
        let ev = ev.root();
        let event: JSRef<Event> = EventCast::from_ref(ev.r());
        event.InitEvent(type_,
                        bubbles == EventBubbles::Bubbles,
                        cancelable == EventCancelable::Cancelable);
        let ev = ev.r();
        ev.wasClean.set(wasClean);
        ev.code.set(code);
        *ev.reason.borrow_mut() = reason;
        Temporary::from_rooted(ev)
    }

    pub fn Constructor(global: GlobalRef,
                       type_: DOMString,
                       init: &CloseEventBinding::CloseEventInit) -> Fallible<Temporary<CloseEvent>> {
        let clean_status = init.wasClean.unwrap_or(true);
        let cd = init.code.unwrap_or(0);
        let rsn = match init.reason.as_ref() {
            Some(reason) => reason.clone(),
            None => "".to_owned(),
        };
        let bubbles = if init.parent.bubbles { EventBubbles::Bubbles } else { EventBubbles::DoesNotBubble };
        let cancelable = if init.parent.cancelable { EventCancelable::Cancelable } else { EventCancelable::NotCancelable };
        Ok(CloseEvent::new(global, type_, bubbles, cancelable, clean_status, cd, rsn))
    }
}

impl<'a> CloseEventMethods for JSRef<'a, CloseEvent>{
    fn WasClean(self) -> bool {
        self.wasClean.get()
    }

    fn Code(self) -> u16 {
        self.code.get()
    }

    fn Reason(self) -> DOMString {
        let reason = self.reason.borrow();
        reason.clone()
    }
}
<|endoftext|>


<commit_before>use crate::protocol::*;
use std::io::Read;
use xml::attribute::OwnedAttribute;
use xml::reader::ParserConfig;
use xml::reader::XmlEvent;
use xml::EventReader;

macro_rules! extract_from(
    ($it: expr => $pattern: pat => $result: expr) => (
        match $it.next() {
            Ok($pattern) => { $result },
            e => panic!("Ill-formed protocol file: {:?}", e)
        }
    )
);

macro_rules! extract_end_tag(
    ($it: expr => $tag: expr) => (
        extract_from!($it => XmlEvent::EndElement { name } => {
            assert!(name.local_name == $tag, "Ill-formed protocol file");
        });
    )
);

pub fn parse_stream<S: Read>(stream: S) -> Protocol {
    let mut reader =
        EventReader::new_with_config(stream, ParserConfig::new().trim_whitespace(true));
    reader.next().expect("Could not read from event reader");
    parse_protocol(reader)
}

fn parse_protocol<R: Read>(mut reader: EventReader<R>) -> Protocol {
    let mut protocol = extract_from!(
        reader => XmlEvent::StartElement { name, attributes, .. } => {
            assert!(name.local_name == "protocol", "Missing protocol toplevel tag");
            assert!(attributes[0].name.local_name == "name", "Protocol must have a name");
            Protocol::new(attributes[0].value.clone())
        }
    );

    loop {
        match reader.next() {
            Ok(XmlEvent::StartElement { name, attributes, .. }) => {
                match &name.local_name[..] {
                    "copyright" => {
                        // parse the copyright
                        let copyright = match reader.next() {
                            Ok(XmlEvent::Characters(copyright))
                            | Ok(XmlEvent::CData(copyright)) => copyright,
                            e => panic!("Ill-formed protocol file: {:?}", e),
                        };

                        extract_end_tag!(reader => "copyright");
                        protocol.copyright = Some(copyright);
                    }
                    "interface" => {
                        protocol.interfaces.push(parse_interface(&mut reader, attributes));
                    }
                    "description" => {
                        protocol.description = Some(parse_description(&mut reader, attributes));
                    }
                    _ => panic!(
                        "Ill-formed protocol file: unexpected token `{}` in protocol {}",
                        name.local_name, protocol.name
                    ),
                }
            }
            Ok(XmlEvent::EndElement { name }) => {
                assert!(
                    name.local_name == "protocol",
                    "Unexpected closing token `{}`",
                    name.local_name
                );
                break;
            }
            e => panic!("Ill-formed protocol file: {:?}", e),
        }
    }

    protocol
}

fn parse_interface<R: Read>(reader: &mut EventReader<R>, attrs: Vec<OwnedAttribute>) -> Interface {
    let mut interface = Interface::new();
    for attr in attrs {
        match &attr.name.local_name[..] {
            "name" => interface.name = attr.value,
            "version" => interface.version = attr.value.parse().unwrap(),
            _ => {}
        }
    }

    loop {
        match reader.next() {
            Ok(XmlEvent::StartElement { name, attributes, .. }) => match &name.local_name[..] {
                "description" => {
                    interface.description = Some(parse_description(reader, attributes))
                }
                "request" => interface.requests.push(parse_request(reader, attributes)),
                "event" => interface.events.push(parse_event(reader, attributes)),
                "enum" => interface.enums.push(parse_enum(reader, attributes)),
                _ => panic!("Unexpected tocken: `{}`", name.local_name),
            },
            Ok(XmlEvent::EndElement { ref name }) if name.local_name == "interface" => break,
            _ => {}
        }
    }

    interface
}

fn parse_description<R: Read>(
    reader: &mut EventReader<R>,
    attrs: Vec<OwnedAttribute>,
) -> (String, String) {
    let mut summary = String::new();
    for attr in attrs {
        if &attr.name.local_name[..] == "summary" {
            summary = attr.value.split_whitespace().collect::<Vec<_>>().join(" ");
        }
    }

    let description = match reader.next() {
        Ok(XmlEvent::Characters(txt)) => {
            extract_end_tag!(reader => "description");
            txt
        }
        Ok(XmlEvent::EndElement { ref name }) if name.local_name == "description" => String::new(),
        e => panic!("Ill-formed protocol file: {:?}", e),
    };

    (summary, description)
}

fn parse_request<R: Read>(reader: &mut EventReader<R>, attrs: Vec<OwnedAttribute>) -> Message {
    let mut request = Message::new();
    for attr in attrs {
        match &attr.name.local_name[..] {
            "name" => request.name = attr.value,
            "type" => request.typ = Some(parse_type(&attr.value)),
            "since" => request.since = attr.value.parse().unwrap(),
            _ => {}
        }
    }

    loop {
        match reader.next() {
            Ok(XmlEvent::StartElement { name, attributes, .. }) => match &name.local_name[..] {
                "description" => request.description = Some(parse_description(reader, attributes)),
                "arg" => request.args.push(parse_arg(reader, attributes)),
                _ => panic!("Unexpected tocken: `{}`", name.local_name),
            },
            Ok(XmlEvent::EndElement { ref name }) if name.local_name == "request" => break,
            _ => {}
        }
    }

    request
}

fn parse_enum<R: Read>(reader: &mut EventReader<R>, attrs: Vec<OwnedAttribute>) -> Enum {
    let mut enu = Enum::new();
    for attr in attrs {
        match &attr.name.local_name[..] {
            "name" => enu.name = attr.value,
            "since" => enu.since = attr.value.parse().unwrap(),
            "bitfield" => {
                if &attr.value[..] == "true" {
                    enu.bitfield = true
                }
            }
            _ => {}
        }
    }

    loop {
        match reader.next() {
            Ok(XmlEvent::StartElement { name, attributes, .. }) => match &name.local_name[..] {
                "description" => enu.description = Some(parse_description(reader, attributes)),
                "entry" => enu.entries.push(parse_entry(reader, attributes)),
                _ => panic!("Unexpected tocken: `{}`", name.local_name),
            },
            Ok(XmlEvent::EndElement { ref name }) if name.local_name == "enum" => break,
            _ => {}
        }
    }

    enu
}

fn parse_event<R: Read>(reader: &mut EventReader<R>, attrs: Vec<OwnedAttribute>) -> Message {
    let mut event = Message::new();
    for attr in attrs {
        match &attr.name.local_name[..] {
            "name" => event.name = attr.value,
            "since" => event.since = attr.value.parse().unwrap(),
            _ => {}
        }
    }

    loop {
        match reader.next() {
            Ok(XmlEvent::StartElement { name, attributes, .. }) => match &name.local_name[..] {
                "description" => event.description = Some(parse_description(reader, attributes)),
                "arg" => event.args.push(parse_arg(reader, attributes)),
                _ => panic!("Unexpected tocken: `{}`", name.local_name),
            },
            Ok(XmlEvent::EndElement { ref name }) if name.local_name == "event" => break,
            _ => {}
        }
    }

    event
}

fn parse_arg<R: Read>(reader: &mut EventReader<R>, attrs: Vec<OwnedAttribute>) -> Arg {
    let mut arg = Arg::new();
    for attr in attrs {
        match &attr.name.local_name[..] {
            "name" => arg.name = attr.value,
            "type" => arg.typ = parse_type(&attr.value),
            "summary" => {
                arg.summary = Some(attr.value.split_whitespace().collect::<Vec<_>>().join(" "))
            }
            "interface" => arg.interface = Some(attr.value),
            "allow-null" => {
                if attr.value == "true" {
                    arg.allow_null = true
                }
            }
            "enum" => arg.enum_ = Some(attr.value),
            _ => {}
        }
    }

    loop {
        match reader.next() {
            Ok(XmlEvent::StartElement { name, attributes, .. }) => match &name.local_name[..] {
                "description" => arg.description = Some(parse_description(reader, attributes)),
                _ => panic!("Unexpected tocken: `{}`", name.local_name),
            },
            Ok(XmlEvent::EndElement { ref name }) if name.local_name == "arg" => break,
            _ => {}
        }
    }

    arg
}

fn parse_type(txt: &str) -> Type {
    match txt {
        "int" => Type::Int,
        "uint" => Type::Uint,
        "fixed" => Type::Fixed,
        "string" => Type::String,
        "object" => Type::Object,
        "new_id" => Type::NewId,
        "array" => Type::Array,
        "fd" => Type::Fd,
        "destructor" => Type::Destructor,
        e => panic!("Unexpected type: {}", e),
    }
}

fn parse_entry<R: Read>(reader: &mut EventReader<R>, attrs: Vec<OwnedAttribute>) -> Entry {
    let mut entry = Entry::new();
    for attr in attrs {
        match &attr.name.local_name[..] {
            "name" => entry.name = attr.value,
            "value" => {
                entry.value = if attr.value.starts_with("0x") {
                    u32::from_str_radix(&attr.value[2..], 16).unwrap()
                } else {
                    attr.value.parse().unwrap()
                };
            }
            "since" => entry.since = attr.value.parse().unwrap(),
            "summary" => {
                entry.summary = Some(attr.value.split_whitespace().collect::<Vec<_>>().join(" "))
            }
            _ => {}
        }
    }

    loop {
        match reader.next() {
            Ok(XmlEvent::StartElement { name, attributes, .. }) => match &name.local_name[..] {
                "description" => entry.description = Some(parse_description(reader, attributes)),
                _ => panic!("Unexpected tocken: `{}`", name.local_name),
            },
            Ok(XmlEvent::EndElement { ref name }) if name.local_name == "entry" => break,
            _ => {}
        }
    }

    entry
}
<commit_msg>scanner: parse event type from xml<commit_after>use crate::protocol::*;
use std::io::Read;
use xml::attribute::OwnedAttribute;
use xml::reader::ParserConfig;
use xml::reader::XmlEvent;
use xml::EventReader;

macro_rules! extract_from(
    ($it: expr => $pattern: pat => $result: expr) => (
        match $it.next() {
            Ok($pattern) => { $result },
            e => panic!("Ill-formed protocol file: {:?}", e)
        }
    )
);

macro_rules! extract_end_tag(
    ($it: expr => $tag: expr) => (
        extract_from!($it => XmlEvent::EndElement { name } => {
            assert!(name.local_name == $tag, "Ill-formed protocol file");
        });
    )
);

pub fn parse_stream<S: Read>(stream: S) -> Protocol {
    let mut reader =
        EventReader::new_with_config(stream, ParserConfig::new().trim_whitespace(true));
    reader.next().expect("Could not read from event reader");
    parse_protocol(reader)
}

fn parse_protocol<R: Read>(mut reader: EventReader<R>) -> Protocol {
    let mut protocol = extract_from!(
        reader => XmlEvent::StartElement { name, attributes, .. } => {
            assert!(name.local_name == "protocol", "Missing protocol toplevel tag");
            assert!(attributes[0].name.local_name == "name", "Protocol must have a name");
            Protocol::new(attributes[0].value.clone())
        }
    );

    loop {
        match reader.next() {
            Ok(XmlEvent::StartElement { name, attributes, .. }) => {
                match &name.local_name[..] {
                    "copyright" => {
                        // parse the copyright
                        let copyright = match reader.next() {
                            Ok(XmlEvent::Characters(copyright))
                            | Ok(XmlEvent::CData(copyright)) => copyright,
                            e => panic!("Ill-formed protocol file: {:?}", e),
                        };

                        extract_end_tag!(reader => "copyright");
                        protocol.copyright = Some(copyright);
                    }
                    "interface" => {
                        protocol.interfaces.push(parse_interface(&mut reader, attributes));
                    }
                    "description" => {
                        protocol.description = Some(parse_description(&mut reader, attributes));
                    }
                    _ => panic!(
                        "Ill-formed protocol file: unexpected token `{}` in protocol {}",
                        name.local_name, protocol.name
                    ),
                }
            }
            Ok(XmlEvent::EndElement { name }) => {
                assert!(
                    name.local_name == "protocol",
                    "Unexpected closing token `{}`",
                    name.local_name
                );
                break;
            }
            e => panic!("Ill-formed protocol file: {:?}", e),
        }
    }

    protocol
}

fn parse_interface<R: Read>(reader: &mut EventReader<R>, attrs: Vec<OwnedAttribute>) -> Interface {
    let mut interface = Interface::new();
    for attr in attrs {
        match &attr.name.local_name[..] {
            "name" => interface.name = attr.value,
            "version" => interface.version = attr.value.parse().unwrap(),
            _ => {}
        }
    }

    loop {
        match reader.next() {
            Ok(XmlEvent::StartElement { name, attributes, .. }) => match &name.local_name[..] {
                "description" => {
                    interface.description = Some(parse_description(reader, attributes))
                }
                "request" => interface.requests.push(parse_request(reader, attributes)),
                "event" => interface.events.push(parse_event(reader, attributes)),
                "enum" => interface.enums.push(parse_enum(reader, attributes)),
                _ => panic!("Unexpected tocken: `{}`", name.local_name),
            },
            Ok(XmlEvent::EndElement { ref name }) if name.local_name == "interface" => break,
            _ => {}
        }
    }

    interface
}

fn parse_description<R: Read>(
    reader: &mut EventReader<R>,
    attrs: Vec<OwnedAttribute>,
) -> (String, String) {
    let mut summary = String::new();
    for attr in attrs {
        if &attr.name.local_name[..] == "summary" {
            summary = attr.value.split_whitespace().collect::<Vec<_>>().join(" ");
        }
    }

    let description = match reader.next() {
        Ok(XmlEvent::Characters(txt)) => {
            extract_end_tag!(reader => "description");
            txt
        }
        Ok(XmlEvent::EndElement { ref name }) if name.local_name == "description" => String::new(),
        e => panic!("Ill-formed protocol file: {:?}", e),
    };

    (summary, description)
}

fn parse_request<R: Read>(reader: &mut EventReader<R>, attrs: Vec<OwnedAttribute>) -> Message {
    let mut request = Message::new();
    for attr in attrs {
        match &attr.name.local_name[..] {
            "name" => request.name = attr.value,
            "type" => request.typ = Some(parse_type(&attr.value)),
            "since" => request.since = attr.value.parse().unwrap(),
            _ => {}
        }
    }

    loop {
        match reader.next() {
            Ok(XmlEvent::StartElement { name, attributes, .. }) => match &name.local_name[..] {
                "description" => request.description = Some(parse_description(reader, attributes)),
                "arg" => request.args.push(parse_arg(reader, attributes)),
                _ => panic!("Unexpected tocken: `{}`", name.local_name),
            },
            Ok(XmlEvent::EndElement { ref name }) if name.local_name == "request" => break,
            _ => {}
        }
    }

    request
}

fn parse_enum<R: Read>(reader: &mut EventReader<R>, attrs: Vec<OwnedAttribute>) -> Enum {
    let mut enu = Enum::new();
    for attr in attrs {
        match &attr.name.local_name[..] {
            "name" => enu.name = attr.value,
            "since" => enu.since = attr.value.parse().unwrap(),
            "bitfield" => {
                if &attr.value[..] == "true" {
                    enu.bitfield = true
                }
            }
            _ => {}
        }
    }

    loop {
        match reader.next() {
            Ok(XmlEvent::StartElement { name, attributes, .. }) => match &name.local_name[..] {
                "description" => enu.description = Some(parse_description(reader, attributes)),
                "entry" => enu.entries.push(parse_entry(reader, attributes)),
                _ => panic!("Unexpected tocken: `{}`", name.local_name),
            },
            Ok(XmlEvent::EndElement { ref name }) if name.local_name == "enum" => break,
            _ => {}
        }
    }

    enu
}

fn parse_event<R: Read>(reader: &mut EventReader<R>, attrs: Vec<OwnedAttribute>) -> Message {
    let mut event = Message::new();
    for attr in attrs {
        match &attr.name.local_name[..] {
            "name" => event.name = attr.value,
            "type" => event.typ = Some(parse_type(&attr.value)),
            "since" => event.since = attr.value.parse().unwrap(),
            _ => {}
        }
    }

    loop {
        match reader.next() {
            Ok(XmlEvent::StartElement { name, attributes, .. }) => match &name.local_name[..] {
                "description" => event.description = Some(parse_description(reader, attributes)),
                "arg" => event.args.push(parse_arg(reader, attributes)),
                _ => panic!("Unexpected tocken: `{}`", name.local_name),
            },
            Ok(XmlEvent::EndElement { ref name }) if name.local_name == "event" => break,
            _ => {}
        }
    }

    event
}

fn parse_arg<R: Read>(reader: &mut EventReader<R>, attrs: Vec<OwnedAttribute>) -> Arg {
    let mut arg = Arg::new();
    for attr in attrs {
        match &attr.name.local_name[..] {
            "name" => arg.name = attr.value,
            "type" => arg.typ = parse_type(&attr.value),
            "summary" => {
                arg.summary = Some(attr.value.split_whitespace().collect::<Vec<_>>().join(" "))
            }
            "interface" => arg.interface = Some(attr.value),
            "allow-null" => {
                if attr.value == "true" {
                    arg.allow_null = true
                }
            }
            "enum" => arg.enum_ = Some(attr.value),
            _ => {}
        }
    }

    loop {
        match reader.next() {
            Ok(XmlEvent::StartElement { name, attributes, .. }) => match &name.local_name[..] {
                "description" => arg.description = Some(parse_description(reader, attributes)),
                _ => panic!("Unexpected tocken: `{}`", name.local_name),
            },
            Ok(XmlEvent::EndElement { ref name }) if name.local_name == "arg" => break,
            _ => {}
        }
    }

    arg
}

fn parse_type(txt: &str) -> Type {
    match txt {
        "int" => Type::Int,
        "uint" => Type::Uint,
        "fixed" => Type::Fixed,
        "string" => Type::String,
        "object" => Type::Object,
        "new_id" => Type::NewId,
        "array" => Type::Array,
        "fd" => Type::Fd,
        "destructor" => Type::Destructor,
        e => panic!("Unexpected type: {}", e),
    }
}

fn parse_entry<R: Read>(reader: &mut EventReader<R>, attrs: Vec<OwnedAttribute>) -> Entry {
    let mut entry = Entry::new();
    for attr in attrs {
        match &attr.name.local_name[..] {
            "name" => entry.name = attr.value,
            "value" => {
                entry.value = if attr.value.starts_with("0x") {
                    u32::from_str_radix(&attr.value[2..], 16).unwrap()
                } else {
                    attr.value.parse().unwrap()
                };
            }
            "since" => entry.since = attr.value.parse().unwrap(),
            "summary" => {
                entry.summary = Some(attr.value.split_whitespace().collect::<Vec<_>>().join(" "))
            }
            _ => {}
        }
    }

    loop {
        match reader.next() {
            Ok(XmlEvent::StartElement { name, attributes, .. }) => match &name.local_name[..] {
                "description" => entry.description = Some(parse_description(reader, attributes)),
                _ => panic!("Unexpected tocken: `{}`", name.local_name),
            },
            Ok(XmlEvent::EndElement { ref name }) if name.local_name == "entry" => break,
            _ => {}
        }
    }

    entry
}
<|endoftext|>


<commit_before>//! Deserialize Named Binary Tag data to a Rust data structure.

use std::io;

use serde::de;
use flate2::read;

use raw;

use error::{Error, Result};

/// Decode an object from Named Binary Tag (NBT) format.
///
/// Note that only maps and structs can be decoded, because the NBT format does
/// not support bare types. Other types will return `Error::NoRootCompound`.
pub fn from_reader<R, T>(src: R) -> Result<T>
    where R: io::Read,
          T: de::DeserializeOwned,
{
    let mut decoder = Decoder::new(src);
    de::Deserialize::deserialize(&mut decoder)
}

/// Decode an object from Named Binary Tag (NBT) format.
///
/// Note that only maps and structs can be decoded, because the NBT format does
/// not support bare types. Other types will return `Error::NoRootCompound`.
pub fn from_gzip_reader<R, T>(src: R) -> Result<T>
    where R: io::Read,
          T: de::DeserializeOwned,
{
    let gzip = try!(read::GzDecoder::new(src));
    from_reader(gzip)
}

/// Decode an object from Named Binary Tag (NBT) format.
///
/// Note that only maps and structs can be decoded, because the NBT format does
/// not support bare types. Other types will return `Error::NoRootCompound`.
pub fn from_zlib_reader<R, T>(src: R) -> Result<T>
    where R: io::Read,
          T: de::DeserializeOwned,
{
    let zlib = read::ZlibDecoder::new(src);
    from_reader(zlib)
}

/// Decode objects from Named Binary Tag (NBT) format.
///
/// Note that only maps and structs can be decoded, because the NBT format does
/// not support bare types. Other types will return `Error::NoRootCompound`.
pub struct Decoder<R> {
    reader: R,
}

impl<R> Decoder<R> where R: io::Read {

    /// Create an NBT Decoder from a given `io::Read` source.
    pub fn new(src: R) -> Self {
        Decoder { reader: src }
    }
}

impl<'de: 'a, 'a, R: io::Read> de::Deserializer<'de> for &'a mut Decoder<R> {
    type Error = Error;

    fn deserialize_any<V>(self, _visitor: V) -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        // The decoder cannot deserialize types by default. It can only handle
        // maps and structs.
        Err(Error::NoRootCompound)
    }

    fn deserialize_struct<V>(self, _name: &'static str,
                             _fields: &'static [&'static str], visitor: V)
                             -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        self.deserialize_map(visitor)
    }

    fn deserialize_unit_struct<V>(self, _name: &'static str, visitor: V)
                                  -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        visitor.visit_unit()
    }

    /// Deserialize newtype structs by their underlying types.
    fn deserialize_newtype_struct<V>(self, _name: &'static str, visitor: V)
                                     -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        visitor.visit_newtype_struct(self)
    }

    fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        // Ignore the header (if there is one).
        let (tag, _) = try!(raw::emit_next_header(&mut self.reader));

        match tag {
            0x0a => visitor.visit_map(MapDecoder::new(self)),
            _ => Err(Error::NoRootCompound)
        }
    }

    forward_to_deserialize_any! {
        bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string bytes byte_buf
        unit seq tuple_struct tuple option enum identifier ignored_any
    }
}

/// Decoder for map-like types.
struct MapDecoder<'a, R: io::Read + 'a> {
    outer: &'a mut Decoder<R>,
    tag: Option<u8>,
}

impl<'a, R> MapDecoder<'a, R> where R: io::Read {

    fn new(outer: &'a mut Decoder<R>) -> Self {
        MapDecoder { outer: outer, tag: None }
    }
}

impl<'de: 'a, 'a, R: io::Read + 'a> de::MapAccess<'de> for MapDecoder<'a, R> {
    type Error = Error;

    fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
        where K: de::DeserializeSeed<'de>
    {
        let tag = try!(raw::read_bare_byte(&mut self.outer.reader));

        // NBT indicates the end of a compound type with a 0x00 tag.
        if tag == 0x00 {
            return Ok(None);
        }

        // Keep track of the tag so that we can decode the field correctly.
        self.tag = Some(tag as u8);

        // TODO: Enforce that keys must be String. This is a bit of a hack.
        let mut de = InnerDecoder { outer: self.outer, tag: 0x08 };

        Ok(Some(seed.deserialize(&mut de)?))
    }

    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
        where V: de::DeserializeSeed<'de>
    {
        let mut de = match self.tag {
            Some(tag) => InnerDecoder { outer: self.outer, tag: tag },
            None => unimplemented!(),
        };
        Ok(seed.deserialize(&mut de)?)
    }
}

/// Decoder for list-like types.
struct SeqDecoder<'a, R: io::Read + 'a> {
    outer: &'a mut Decoder<R>,
    tag: u8,
    length: i32,
    current: i32,
}

impl<'a, R> SeqDecoder<'a, R> where R: io::Read {

    fn list(outer: &'a mut Decoder<R>) -> Result<Self> {
        let tag = try!(raw::read_bare_byte(&mut outer.reader));
        let length = try!(raw::read_bare_int(&mut outer.reader));
        Ok(SeqDecoder { outer: outer, tag: tag as u8, length: length,
                        current: 0 })
    }

    fn byte_array(outer: &'a mut Decoder<R>) -> Result<Self> {
        let length = try!(raw::read_bare_int(&mut outer.reader));
        Ok(SeqDecoder { outer: outer, tag: 0x01, length: length,
                        current: 0 })
    }

    fn int_array(outer: &'a mut Decoder<R>) -> Result<Self> {
        let length = try!(raw::read_bare_int(&mut outer.reader));
        Ok(SeqDecoder { outer: outer, tag: 0x03, length: length,
                        current: 0 })
    }
}

impl<'de: 'a, 'a, R: io::Read + 'a> de::SeqAccess<'de> for SeqDecoder<'a, R> {
    type Error = Error;

    fn next_element_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
        where K: de::DeserializeSeed<'de>
    {
        if self.current == self.length {
            return Ok(None);
        }

        let mut de = InnerDecoder { outer: self.outer, tag: self.tag };
        let value = try!(seed.deserialize(&mut de));

        self.current += 1;

        Ok(Some(value))
    }

    /// We always know the length of an NBT list in advance.
    fn size_hint(&self) -> Option<usize> {
        Some(self.length as usize)
    }
}

/// Private inner decoder, for decoding raw (i.e. non-Compound) types.
struct InnerDecoder<'a, R: io::Read + 'a> {
    outer: &'a mut Decoder<R>,
    tag: u8,
}

impl<'a, 'b: 'a, 'de, R: io::Read> de::Deserializer<'de> for &'b mut InnerDecoder<'a, R> {
    type Error = Error;

    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        let ref mut outer = self.outer;

        match self.tag {
            0x01 => visitor.visit_i8(raw::read_bare_byte(&mut outer.reader)?),
            0x02 => visitor.visit_i16(raw::read_bare_short(&mut outer.reader)?),
            0x03 => visitor.visit_i32(raw::read_bare_int(&mut outer.reader)?),
            0x04 => visitor.visit_i64(raw::read_bare_long(&mut outer.reader)?),
            0x05 => visitor.visit_f32(raw::read_bare_float(&mut outer.reader)?),
            0x06 => visitor.visit_f64(raw::read_bare_double(&mut outer.reader)?),
            0x07 => visitor.visit_seq(SeqDecoder::byte_array(outer)?),
            0x08 => visitor.visit_string(raw::read_bare_string(&mut outer.reader)?),
            0x09 => visitor.visit_seq(SeqDecoder::list(outer)?),
            0x0a => visitor.visit_map(MapDecoder::new(outer)),
            0x0b => visitor.visit_seq(SeqDecoder::int_array(outer)?),
            t => Err(Error::InvalidTypeId(t)),
        }
    }

    /// Deserialize bool values from a byte. Fail if that byte is not 0 or 1.
    fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        match self.tag {
            0x01 => {
                let ref mut reader = self.outer.reader;
                let value = try!(raw::read_bare_byte(reader));
                match value {
                    0 => visitor.visit_bool(false),
                    1 => visitor.visit_bool(true),
                    b => Err(Error::NonBooleanByte(b)),
                }
            },
            _ => Err(Error::TagMismatch(self.tag, 0x01)),
        }
    }

    /// Interpret missing values as None.
    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        visitor.visit_some(self)
    }

    fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        visitor.visit_unit()
    }

    fn deserialize_unit_struct<V>(self, _name: &'static str, visitor: V)
                                  -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        visitor.visit_unit()
    }

    /// Deserialize newtype structs by their underlying types.
    fn deserialize_newtype_struct<V>(self, _name: &'static str, visitor: V)
                                     -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        visitor.visit_newtype_struct(self)
    }

    forward_to_deserialize_any! {
        u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string bytes byte_buf seq
        map tuple_struct struct tuple enum identifier ignored_any
    }
}
<commit_msg>Add serde support for deserializing long arrays<commit_after>//! Deserialize Named Binary Tag data to a Rust data structure.

use std::io;

use serde::de;
use flate2::read;

use raw;

use error::{Error, Result};

/// Decode an object from Named Binary Tag (NBT) format.
///
/// Note that only maps and structs can be decoded, because the NBT format does
/// not support bare types. Other types will return `Error::NoRootCompound`.
pub fn from_reader<R, T>(src: R) -> Result<T>
    where R: io::Read,
          T: de::DeserializeOwned,
{
    let mut decoder = Decoder::new(src);
    de::Deserialize::deserialize(&mut decoder)
}

/// Decode an object from Named Binary Tag (NBT) format.
///
/// Note that only maps and structs can be decoded, because the NBT format does
/// not support bare types. Other types will return `Error::NoRootCompound`.
pub fn from_gzip_reader<R, T>(src: R) -> Result<T>
    where R: io::Read,
          T: de::DeserializeOwned,
{
    let gzip = try!(read::GzDecoder::new(src));
    from_reader(gzip)
}

/// Decode an object from Named Binary Tag (NBT) format.
///
/// Note that only maps and structs can be decoded, because the NBT format does
/// not support bare types. Other types will return `Error::NoRootCompound`.
pub fn from_zlib_reader<R, T>(src: R) -> Result<T>
    where R: io::Read,
          T: de::DeserializeOwned,
{
    let zlib = read::ZlibDecoder::new(src);
    from_reader(zlib)
}

/// Decode objects from Named Binary Tag (NBT) format.
///
/// Note that only maps and structs can be decoded, because the NBT format does
/// not support bare types. Other types will return `Error::NoRootCompound`.
pub struct Decoder<R> {
    reader: R,
}

impl<R> Decoder<R> where R: io::Read {

    /// Create an NBT Decoder from a given `io::Read` source.
    pub fn new(src: R) -> Self {
        Decoder { reader: src }
    }
}

impl<'de: 'a, 'a, R: io::Read> de::Deserializer<'de> for &'a mut Decoder<R> {
    type Error = Error;

    fn deserialize_any<V>(self, _visitor: V) -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        // The decoder cannot deserialize types by default. It can only handle
        // maps and structs.
        Err(Error::NoRootCompound)
    }

    fn deserialize_struct<V>(self, _name: &'static str,
                             _fields: &'static [&'static str], visitor: V)
                             -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        self.deserialize_map(visitor)
    }

    fn deserialize_unit_struct<V>(self, _name: &'static str, visitor: V)
                                  -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        visitor.visit_unit()
    }

    /// Deserialize newtype structs by their underlying types.
    fn deserialize_newtype_struct<V>(self, _name: &'static str, visitor: V)
                                     -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        visitor.visit_newtype_struct(self)
    }

    fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        // Ignore the header (if there is one).
        let (tag, _) = try!(raw::emit_next_header(&mut self.reader));

        match tag {
            0x0a => visitor.visit_map(MapDecoder::new(self)),
            _ => Err(Error::NoRootCompound)
        }
    }

    forward_to_deserialize_any! {
        bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string bytes byte_buf
        unit seq tuple_struct tuple option enum identifier ignored_any
    }
}

/// Decoder for map-like types.
struct MapDecoder<'a, R: io::Read + 'a> {
    outer: &'a mut Decoder<R>,
    tag: Option<u8>,
}

impl<'a, R> MapDecoder<'a, R> where R: io::Read {

    fn new(outer: &'a mut Decoder<R>) -> Self {
        MapDecoder { outer: outer, tag: None }
    }
}

impl<'de: 'a, 'a, R: io::Read + 'a> de::MapAccess<'de> for MapDecoder<'a, R> {
    type Error = Error;

    fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
        where K: de::DeserializeSeed<'de>
    {
        let tag = try!(raw::read_bare_byte(&mut self.outer.reader));

        // NBT indicates the end of a compound type with a 0x00 tag.
        if tag == 0x00 {
            return Ok(None);
        }

        // Keep track of the tag so that we can decode the field correctly.
        self.tag = Some(tag as u8);

        // TODO: Enforce that keys must be String. This is a bit of a hack.
        let mut de = InnerDecoder { outer: self.outer, tag: 0x08 };

        Ok(Some(seed.deserialize(&mut de)?))
    }

    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
        where V: de::DeserializeSeed<'de>
    {
        let mut de = match self.tag {
            Some(tag) => InnerDecoder { outer: self.outer, tag: tag },
            None => unimplemented!(),
        };
        Ok(seed.deserialize(&mut de)?)
    }
}

/// Decoder for list-like types.
struct SeqDecoder<'a, R: io::Read + 'a> {
    outer: &'a mut Decoder<R>,
    tag: u8,
    length: i32,
    current: i32,
}

impl<'a, R> SeqDecoder<'a, R> where R: io::Read {

    fn list(outer: &'a mut Decoder<R>) -> Result<Self> {
        let tag = try!(raw::read_bare_byte(&mut outer.reader));
        let length = try!(raw::read_bare_int(&mut outer.reader));
        Ok(SeqDecoder { outer: outer, tag: tag as u8, length: length,
                        current: 0 })
    }

    fn byte_array(outer: &'a mut Decoder<R>) -> Result<Self> {
        let length = try!(raw::read_bare_int(&mut outer.reader));
        Ok(SeqDecoder { outer: outer, tag: 0x01, length: length,
                        current: 0 })
    }

    fn int_array(outer: &'a mut Decoder<R>) -> Result<Self> {
        let length = try!(raw::read_bare_int(&mut outer.reader));
        Ok(SeqDecoder { outer: outer, tag: 0x03, length: length,
                        current: 0 })
    }

    fn long_array(outer: &'a mut Decoder<R>) -> Result<Self> {
        let length = raw::read_bare_int(&mut outer.reader)?;
        Ok(SeqDecoder {
            outer,
            tag: 0x04,
            length,
            current: 0,
        })
    }
}

impl<'de: 'a, 'a, R: io::Read + 'a> de::SeqAccess<'de> for SeqDecoder<'a, R> {
    type Error = Error;

    fn next_element_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
        where K: de::DeserializeSeed<'de>
    {
        if self.current == self.length {
            return Ok(None);
        }

        let mut de = InnerDecoder { outer: self.outer, tag: self.tag };
        let value = try!(seed.deserialize(&mut de));

        self.current += 1;

        Ok(Some(value))
    }

    /// We always know the length of an NBT list in advance.
    fn size_hint(&self) -> Option<usize> {
        Some(self.length as usize)
    }
}

/// Private inner decoder, for decoding raw (i.e. non-Compound) types.
struct InnerDecoder<'a, R: io::Read + 'a> {
    outer: &'a mut Decoder<R>,
    tag: u8,
}

impl<'a, 'b: 'a, 'de, R: io::Read> de::Deserializer<'de> for &'b mut InnerDecoder<'a, R> {
    type Error = Error;

    fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        let ref mut outer = self.outer;

        match self.tag {
            0x01 => visitor.visit_i8(raw::read_bare_byte(&mut outer.reader)?),
            0x02 => visitor.visit_i16(raw::read_bare_short(&mut outer.reader)?),
            0x03 => visitor.visit_i32(raw::read_bare_int(&mut outer.reader)?),
            0x04 => visitor.visit_i64(raw::read_bare_long(&mut outer.reader)?),
            0x05 => visitor.visit_f32(raw::read_bare_float(&mut outer.reader)?),
            0x06 => visitor.visit_f64(raw::read_bare_double(&mut outer.reader)?),
            0x07 => visitor.visit_seq(SeqDecoder::byte_array(outer)?),
            0x08 => visitor.visit_string(raw::read_bare_string(&mut outer.reader)?),
            0x09 => visitor.visit_seq(SeqDecoder::list(outer)?),
            0x0a => visitor.visit_map(MapDecoder::new(outer)),
            0x0b => visitor.visit_seq(SeqDecoder::int_array(outer)?),
            0x0c => visitor.visit_seq(SeqDecoder::long_array(outer)?),
            t => Err(Error::InvalidTypeId(t)),
        }
    }

    /// Deserialize bool values from a byte. Fail if that byte is not 0 or 1.
    fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        match self.tag {
            0x01 => {
                let ref mut reader = self.outer.reader;
                let value = try!(raw::read_bare_byte(reader));
                match value {
                    0 => visitor.visit_bool(false),
                    1 => visitor.visit_bool(true),
                    b => Err(Error::NonBooleanByte(b)),
                }
            },
            _ => Err(Error::TagMismatch(self.tag, 0x01)),
        }
    }

    /// Interpret missing values as None.
    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        visitor.visit_some(self)
    }

    fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        visitor.visit_unit()
    }

    fn deserialize_unit_struct<V>(self, _name: &'static str, visitor: V)
                                  -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        visitor.visit_unit()
    }

    /// Deserialize newtype structs by their underlying types.
    fn deserialize_newtype_struct<V>(self, _name: &'static str, visitor: V)
                                     -> Result<V::Value>
        where V: de::Visitor<'de>
    {
        visitor.visit_newtype_struct(self)
    }

    forward_to_deserialize_any! {
        u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string bytes byte_buf seq
        map tuple_struct struct tuple enum identifier ignored_any
    }
}
<|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/. */

//! Tracking of pending loads in a document.
//! https://html.spec.whatwg.org/multipage/#the-end

use dom::bindings::js::JS;
use dom::document::Document;
use ipc_channel::ipc::IpcSender;
use msg::constellation_msg::{PipelineId, ReferrerPolicy};
use net_traits::{AsyncResponseTarget, CoreResourceMsg, PendingAsyncLoad};
use net_traits::{FetchResponseMsg, LoadContext, ResourceThreads, IpcSend};
use net_traits::request::RequestInit;
use std::thread;
use url::Url;

#[derive(JSTraceable, PartialEq, Clone, Debug, HeapSizeOf)]
pub enum LoadType {
    Image(Url),
    Script(Url),
    Subframe(Url),
    Stylesheet(Url),
    PageSource(Url),
    Media(Url),
}

impl LoadType {
    fn url(&self) -> &Url {
        match *self {
            LoadType::Image(ref url) |
            LoadType::Script(ref url) |
            LoadType::Subframe(ref url) |
            LoadType::Stylesheet(ref url) |
            LoadType::Media(ref url) |
            LoadType::PageSource(ref url) => url,
        }
    }

    fn to_load_context(&self) -> LoadContext {
        match *self {
            LoadType::Image(_) => LoadContext::Image,
            LoadType::Script(_) => LoadContext::Script,
            LoadType::Subframe(_) | LoadType::PageSource(_) => LoadContext::Browsing,
            LoadType::Stylesheet(_) => LoadContext::Style,
            LoadType::Media(_) => LoadContext::AudioVideo,
        }
    }
}

/// Canary value ensuring that manually added blocking loads (ie. ones that weren't
/// created via DocumentLoader::prepare_async_load) are always removed by the time
/// that the owner is destroyed.
#[derive(JSTraceable, HeapSizeOf)]
#[must_root]
pub struct LoadBlocker {
    /// The document whose load event is blocked by this object existing.
    doc: JS<Document>,
    /// The load that is blocking the document's load event.
    load: Option<LoadType>,
}

impl LoadBlocker {
    /// Mark the document's load event as blocked on this new load.
    pub fn new(doc: &Document, load: LoadType) -> LoadBlocker {
        doc.add_blocking_load(load.clone());
        LoadBlocker {
            doc: JS::from_ref(doc),
            load: Some(load),
        }
    }

    /// Remove this load from the associated document's list of blocking loads.
    pub fn terminate(blocker: &mut Option<LoadBlocker>) {
        if let Some(this) = blocker.as_mut() {
            this.doc.finish_load(this.load.take().unwrap());
        }
        *blocker = None;
    }

    /// Return the url associated with this load.
    pub fn url(&self) -> Option<&Url> {
        self.load.as_ref().map(LoadType::url)
    }
}

impl Drop for LoadBlocker {
    fn drop(&mut self) {
        if !thread::panicking() {
            debug_assert!(self.load.is_none());
        }
    }
}

#[derive(JSTraceable, HeapSizeOf)]
pub struct DocumentLoader {
    resource_threads: ResourceThreads,
    pipeline: Option<PipelineId>,
    blocking_loads: Vec<LoadType>,
    events_inhibited: bool,
}

impl DocumentLoader {
    pub fn new(existing: &DocumentLoader) -> DocumentLoader {
        DocumentLoader::new_with_threads(existing.resource_threads.clone(), None, None)
    }

    pub fn new_with_threads(resource_threads: ResourceThreads,
                            pipeline: Option<PipelineId>,
                            initial_load: Option<Url>) -> DocumentLoader {
        let initial_loads = initial_load.into_iter().map(LoadType::PageSource).collect();

        DocumentLoader {
            resource_threads: resource_threads,
            pipeline: pipeline,
            blocking_loads: initial_loads,
            events_inhibited: false,
        }
    }

    /// Add a load to the list of blocking loads.
    pub fn add_blocking_load(&mut self, load: LoadType) {
        self.blocking_loads.push(load);
    }

    /// Create a new pending network request, which can be initiated at some point in
    /// the future.
    pub fn prepare_async_load(&mut self,
                              load: LoadType,
                              referrer: &Document,
                              referrer_policy: Option<ReferrerPolicy>) -> PendingAsyncLoad {
        let context = load.to_load_context();
        let url = load.url().clone();
        self.add_blocking_load(load);
        PendingAsyncLoad::new(context,
                              self.resource_threads.sender(),
                              url,
                              self.pipeline,
                              referrer_policy.or(referrer.get_referrer_policy()),
                              Some(referrer.url().clone()))
    }

    /// Create and initiate a new network request.
    pub fn load_async(&mut self,
                      load: LoadType,
                      listener: AsyncResponseTarget,
                      referrer: &Document,
                      referrer_policy: Option<ReferrerPolicy>) {
        let pending = self.prepare_async_load(load, referrer, referrer_policy);
        pending.load_async(listener)
    }

    /// Initiate a new fetch.
    pub fn fetch_async(&mut self,
                       load: LoadType,
                       request: RequestInit,
                       fetch_target: IpcSender<FetchResponseMsg>) {
        self.add_blocking_load(load);
        self.resource_threads.sender().send(CoreResourceMsg::Fetch(request, fetch_target)).unwrap();
    }

    /// Mark an in-progress network request complete.
    pub fn finish_load(&mut self, load: &LoadType) {
        let idx = self.blocking_loads.iter().position(|unfinished| *unfinished == *load);
        self.blocking_loads.remove(idx.expect(&format!("unknown completed load {:?}", load)));
    }

    pub fn is_blocked(&self) -> bool {
        // TODO: Ensure that we report blocked if parsing is still ongoing.
        !self.blocking_loads.is_empty()
    }

    pub fn inhibit_events(&mut self) {
        self.events_inhibited = true;
    }

    pub fn events_inhibited(&self) -> bool {
        self.events_inhibited
    }

    pub fn resource_threads(&self) -> &ResourceThreads {
        &self.resource_threads
    }
}
<commit_msg>Inline prepare_async_load.<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/. */

//! Tracking of pending loads in a document.
//! https://html.spec.whatwg.org/multipage/#the-end

use dom::bindings::js::JS;
use dom::document::Document;
use ipc_channel::ipc::IpcSender;
use msg::constellation_msg::{PipelineId, ReferrerPolicy};
use net_traits::{AsyncResponseTarget, CoreResourceMsg, PendingAsyncLoad};
use net_traits::{FetchResponseMsg, LoadContext, ResourceThreads, IpcSend};
use net_traits::request::RequestInit;
use std::thread;
use url::Url;

#[derive(JSTraceable, PartialEq, Clone, Debug, HeapSizeOf)]
pub enum LoadType {
    Image(Url),
    Script(Url),
    Subframe(Url),
    Stylesheet(Url),
    PageSource(Url),
    Media(Url),
}

impl LoadType {
    fn url(&self) -> &Url {
        match *self {
            LoadType::Image(ref url) |
            LoadType::Script(ref url) |
            LoadType::Subframe(ref url) |
            LoadType::Stylesheet(ref url) |
            LoadType::Media(ref url) |
            LoadType::PageSource(ref url) => url,
        }
    }

    fn to_load_context(&self) -> LoadContext {
        match *self {
            LoadType::Image(_) => LoadContext::Image,
            LoadType::Script(_) => LoadContext::Script,
            LoadType::Subframe(_) | LoadType::PageSource(_) => LoadContext::Browsing,
            LoadType::Stylesheet(_) => LoadContext::Style,
            LoadType::Media(_) => LoadContext::AudioVideo,
        }
    }
}

/// Canary value ensuring that manually added blocking loads (ie. ones that weren't
/// created via DocumentLoader::{load_async, fetch_async}) are always removed by the time
/// that the owner is destroyed.
#[derive(JSTraceable, HeapSizeOf)]
#[must_root]
pub struct LoadBlocker {
    /// The document whose load event is blocked by this object existing.
    doc: JS<Document>,
    /// The load that is blocking the document's load event.
    load: Option<LoadType>,
}

impl LoadBlocker {
    /// Mark the document's load event as blocked on this new load.
    pub fn new(doc: &Document, load: LoadType) -> LoadBlocker {
        doc.add_blocking_load(load.clone());
        LoadBlocker {
            doc: JS::from_ref(doc),
            load: Some(load),
        }
    }

    /// Remove this load from the associated document's list of blocking loads.
    pub fn terminate(blocker: &mut Option<LoadBlocker>) {
        if let Some(this) = blocker.as_mut() {
            this.doc.finish_load(this.load.take().unwrap());
        }
        *blocker = None;
    }

    /// Return the url associated with this load.
    pub fn url(&self) -> Option<&Url> {
        self.load.as_ref().map(LoadType::url)
    }
}

impl Drop for LoadBlocker {
    fn drop(&mut self) {
        if !thread::panicking() {
            debug_assert!(self.load.is_none());
        }
    }
}

#[derive(JSTraceable, HeapSizeOf)]
pub struct DocumentLoader {
    resource_threads: ResourceThreads,
    pipeline: Option<PipelineId>,
    blocking_loads: Vec<LoadType>,
    events_inhibited: bool,
}

impl DocumentLoader {
    pub fn new(existing: &DocumentLoader) -> DocumentLoader {
        DocumentLoader::new_with_threads(existing.resource_threads.clone(), None, None)
    }

    pub fn new_with_threads(resource_threads: ResourceThreads,
                            pipeline: Option<PipelineId>,
                            initial_load: Option<Url>) -> DocumentLoader {
        let initial_loads = initial_load.into_iter().map(LoadType::PageSource).collect();

        DocumentLoader {
            resource_threads: resource_threads,
            pipeline: pipeline,
            blocking_loads: initial_loads,
            events_inhibited: false,
        }
    }

    /// Add a load to the list of blocking loads.
    pub fn add_blocking_load(&mut self, load: LoadType) {
        self.blocking_loads.push(load);
    }

    /// Create and initiate a new network request.
    pub fn load_async(&mut self,
                      load: LoadType,
                      listener: AsyncResponseTarget,
                      referrer: &Document,
                      referrer_policy: Option<ReferrerPolicy>) {
        let context = load.to_load_context();
        let url = load.url().clone();
        self.add_blocking_load(load);
        let pending = PendingAsyncLoad::new(context,
                                            self.resource_threads.sender(),
                                            url,
                                            self.pipeline,
                                            referrer_policy.or(referrer.get_referrer_policy()),
                                            Some(referrer.url().clone()));
        pending.load_async(listener)
    }

    /// Initiate a new fetch.
    pub fn fetch_async(&mut self,
                       load: LoadType,
                       request: RequestInit,
                       fetch_target: IpcSender<FetchResponseMsg>) {
        self.add_blocking_load(load);
        self.resource_threads.sender().send(CoreResourceMsg::Fetch(request, fetch_target)).unwrap();
    }

    /// Mark an in-progress network request complete.
    pub fn finish_load(&mut self, load: &LoadType) {
        let idx = self.blocking_loads.iter().position(|unfinished| *unfinished == *load);
        self.blocking_loads.remove(idx.expect(&format!("unknown completed load {:?}", load)));
    }

    pub fn is_blocked(&self) -> bool {
        // TODO: Ensure that we report blocked if parsing is still ongoing.
        !self.blocking_loads.is_empty()
    }

    pub fn inhibit_events(&mut self) {
        self.events_inhibited = true;
    }

    pub fn events_inhibited(&self) -> bool {
        self.events_inhibited
    }

    pub fn resource_threads(&self) -> &ResourceThreads {
        &self.resource_threads
    }
}
<|endoftext|>


<commit_before>/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Maciej Dziardziel <fiedzia@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE file
 * that was distributed with this source code.
 */

pub static DEFAULT_SIGNAL: usize = 15;

pub struct Signal<'a> {
    pub name: &'a str,
    pub value: usize,
}

/*

Linux Programmer's Manual

 1 HUP      2 INT      3 QUIT     4 ILL      5 TRAP     6 ABRT     7 BUS
 8 FPE      9 KILL    10 USR1    11 SEGV    12 USR2    13 PIPE    14 ALRM
15 TERM    16 STKFLT  17 CHLD    18 CONT    19 STOP    20 TSTP    21 TTIN
22 TTOU    23 URG     24 XCPU    25 XFSZ    26 VTALRM  27 PROF    28 WINCH
29 POLL    30 PWR     31 SYS

*/

#[cfg(target_os = "linux")]
pub static ALL_SIGNALS: [Signal<'static>; 31] = [
    Signal {
        name: "HUP",
        value: 1,
    },
    Signal {
        name: "INT",
        value: 2,
    },
    Signal {
        name: "QUIT",
        value: 3,
    },
    Signal {
        name: "ILL",
        value: 4,
    },
    Signal {
        name: "TRAP",
        value: 5,
    },
    Signal {
        name: "ABRT",
        value: 6,
    },
    Signal {
        name: "BUS",
        value: 7,
    },
    Signal {
        name: "FPE",
        value: 8,
    },
    Signal {
        name: "KILL",
        value: 9,
    },
    Signal {
        name: "USR1",
        value: 10,
    },
    Signal {
        name: "SEGV",
        value: 11,
    },
    Signal {
        name: "USR2",
        value: 12,
    },
    Signal {
        name: "PIPE",
        value: 13,
    },
    Signal {
        name: "ALRM",
        value: 14,
    },
    Signal {
        name: "TERM",
        value: 15,
    },
    Signal {
        name: "STKFLT",
        value: 16,
    },
    Signal {
        name: "CHLD",
        value: 17,
    },
    Signal {
        name: "CONT",
        value: 18,
    },
    Signal {
        name: "STOP",
        value: 19,
    },
    Signal {
        name: "TSTP",
        value: 20,
    },
    Signal {
        name: "TTIN",
        value: 21,
    },
    Signal {
        name: "TTOU",
        value: 22,
    },
    Signal {
        name: "URG",
        value: 23,
    },
    Signal {
        name: "XCPU",
        value: 24,
    },
    Signal {
        name: "XFSZ",
        value: 25,
    },
    Signal {
        name: "VTALRM",
        value: 26,
    },
    Signal {
        name: "PROF",
        value: 27,
    },
    Signal {
        name: "WINCH",
        value: 28,
    },
    Signal {
        name: "POLL",
        value: 29,
    },
    Signal {
        name: "PWR",
        value: 30,
    },
    Signal {
        name: "SYS",
        value: 31,
    },
];

/*

https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/signal.3.html

No    Name         Default Action       Description
1     SIGHUP       terminate process    terminal line hangup
2     SIGINT       terminate process    interrupt program
3     SIGQUIT      create core image    quit program
4     SIGILL       create core image    illegal instruction
5     SIGTRAP      create core image    trace trap
6     SIGABRT      create core image    abort program (formerly SIGIOT)
7     SIGEMT       create core image    emulate instruction executed
8     SIGFPE       create core image    floating-point exception
9     SIGKILL      terminate process    kill program
10    SIGBUS       create core image    bus error
11    SIGSEGV      create core image    segmentation violation
12    SIGSYS       create core image    non-existent system call invoked
13    SIGPIPE      terminate process    write on a pipe with no reader
14    SIGALRM      terminate process    real-time timer expired
15    SIGTERM      terminate process    software termination signal
16    SIGURG       discard signal       urgent condition present on socket
17    SIGSTOP      stop process         stop (cannot be caught or ignored)
18    SIGTSTP      stop process         stop signal generated from keyboard
19    SIGCONT      discard signal       continue after stop
20    SIGCHLD      discard signal       child status has changed
21    SIGTTIN      stop process         background read attempted from control terminal
22    SIGTTOU      stop process         background write attempted to control terminal
23    SIGIO        discard signal       I/O is possible on a descriptor (see fcntl(2))
24    SIGXCPU      terminate process    cpu time limit exceeded (see setrlimit(2))
25    SIGXFSZ      terminate process    file size limit exceeded (see setrlimit(2))
26    SIGVTALRM    terminate process    virtual time alarm (see setitimer(2))
27    SIGPROF      terminate process    profiling timer alarm (see setitimer(2))
28    SIGWINCH     discard signal       Window size change
29    SIGINFO      discard signal       status request from keyboard
30    SIGUSR1      terminate process    User defined signal 1
31    SIGUSR2      terminate process    User defined signal 2

*/

#[cfg(any(target_os = "macos", target_os = "freebsd"))]
pub static ALL_SIGNALS: [Signal<'static>; 31] = [
    Signal {
        name: "HUP",
        value: 1,
    },
    Signal {
        name: "INT",
        value: 2,
    },
    Signal {
        name: "QUIT",
        value: 3,
    },
    Signal {
        name: "ILL",
        value: 4,
    },
    Signal {
        name: "TRAP",
        value: 5,
    },
    Signal {
        name: "ABRT",
        value: 6,
    },
    Signal {
        name: "EMT",
        value: 7,
    },
    Signal {
        name: "FPE",
        value: 8,
    },
    Signal {
        name: "KILL",
        value: 9,
    },
    Signal {
        name: "BUS",
        value: 10,
    },
    Signal {
        name: "SEGV",
        value: 11,
    },
    Signal {
        name: "SYS",
        value: 12,
    },
    Signal {
        name: "PIPE",
        value: 13,
    },
    Signal {
        name: "ALRM",
        value: 14,
    },
    Signal {
        name: "TERM",
        value: 15,
    },
    Signal {
        name: "URG",
        value: 16,
    },
    Signal {
        name: "STOP",
        value: 17,
    },
    Signal {
        name: "TSTP",
        value: 18,
    },
    Signal {
        name: "CONT",
        value: 19,
    },
    Signal {
        name: "CHLD",
        value: 20,
    },
    Signal {
        name: "TTIN",
        value: 21,
    },
    Signal {
        name: "TTOU",
        value: 22,
    },
    Signal {
        name: "IO",
        value: 23,
    },
    Signal {
        name: "XCPU",
        value: 24,
    },
    Signal {
        name: "XFSZ",
        value: 25,
    },
    Signal {
        name: "VTALRM",
        value: 26,
    },
    Signal {
        name: "PROF",
        value: 27,
    },
    Signal {
        name: "WINCH",
        value: 28,
    },
    Signal {
        name: "INFO",
        value: 29,
    },
    Signal {
        name: "USR1",
        value: 30,
    },
    Signal {
        name: "USR2",
        value: 31,
    },
];

pub fn signal_by_name_or_value(signal_name_or_value: &str) -> Option<usize> {
    if signal_name_or_value == "0" {
        return Some(0);
    }
    for signal in &ALL_SIGNALS {
        let long_name = format!("SIG{}", signal.name);
        if signal.name == signal_name_or_value || (signal_name_or_value == signal.value.to_string())
            || (long_name == signal_name_or_value)
        {
            return Some(signal.value);
        }
    }
    None
}

#[inline(always)]
pub fn is_signal(num: usize) -> bool {
    num < ALL_SIGNALS.len()
}
<commit_msg>Add tests for signals (including failing test for `is_signal`<commit_after>/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Maciej Dziardziel <fiedzia@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE file
 * that was distributed with this source code.
 */

pub static DEFAULT_SIGNAL: usize = 15;

pub struct Signal<'a> {
    pub name: &'a str,
    pub value: usize,
}

/*

Linux Programmer's Manual

 1 HUP      2 INT      3 QUIT     4 ILL      5 TRAP     6 ABRT     7 BUS
 8 FPE      9 KILL    10 USR1    11 SEGV    12 USR2    13 PIPE    14 ALRM
15 TERM    16 STKFLT  17 CHLD    18 CONT    19 STOP    20 TSTP    21 TTIN
22 TTOU    23 URG     24 XCPU    25 XFSZ    26 VTALRM  27 PROF    28 WINCH
29 POLL    30 PWR     31 SYS

*/

#[cfg(target_os = "linux")]
pub static ALL_SIGNALS: [Signal<'static>; 31] = [
    Signal {
        name: "HUP",
        value: 1,
    },
    Signal {
        name: "INT",
        value: 2,
    },
    Signal {
        name: "QUIT",
        value: 3,
    },
    Signal {
        name: "ILL",
        value: 4,
    },
    Signal {
        name: "TRAP",
        value: 5,
    },
    Signal {
        name: "ABRT",
        value: 6,
    },
    Signal {
        name: "BUS",
        value: 7,
    },
    Signal {
        name: "FPE",
        value: 8,
    },
    Signal {
        name: "KILL",
        value: 9,
    },
    Signal {
        name: "USR1",
        value: 10,
    },
    Signal {
        name: "SEGV",
        value: 11,
    },
    Signal {
        name: "USR2",
        value: 12,
    },
    Signal {
        name: "PIPE",
        value: 13,
    },
    Signal {
        name: "ALRM",
        value: 14,
    },
    Signal {
        name: "TERM",
        value: 15,
    },
    Signal {
        name: "STKFLT",
        value: 16,
    },
    Signal {
        name: "CHLD",
        value: 17,
    },
    Signal {
        name: "CONT",
        value: 18,
    },
    Signal {
        name: "STOP",
        value: 19,
    },
    Signal {
        name: "TSTP",
        value: 20,
    },
    Signal {
        name: "TTIN",
        value: 21,
    },
    Signal {
        name: "TTOU",
        value: 22,
    },
    Signal {
        name: "URG",
        value: 23,
    },
    Signal {
        name: "XCPU",
        value: 24,
    },
    Signal {
        name: "XFSZ",
        value: 25,
    },
    Signal {
        name: "VTALRM",
        value: 26,
    },
    Signal {
        name: "PROF",
        value: 27,
    },
    Signal {
        name: "WINCH",
        value: 28,
    },
    Signal {
        name: "POLL",
        value: 29,
    },
    Signal {
        name: "PWR",
        value: 30,
    },
    Signal {
        name: "SYS",
        value: 31,
    },
];

/*

https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/signal.3.html

No    Name         Default Action       Description
1     SIGHUP       terminate process    terminal line hangup
2     SIGINT       terminate process    interrupt program
3     SIGQUIT      create core image    quit program
4     SIGILL       create core image    illegal instruction
5     SIGTRAP      create core image    trace trap
6     SIGABRT      create core image    abort program (formerly SIGIOT)
7     SIGEMT       create core image    emulate instruction executed
8     SIGFPE       create core image    floating-point exception
9     SIGKILL      terminate process    kill program
10    SIGBUS       create core image    bus error
11    SIGSEGV      create core image    segmentation violation
12    SIGSYS       create core image    non-existent system call invoked
13    SIGPIPE      terminate process    write on a pipe with no reader
14    SIGALRM      terminate process    real-time timer expired
15    SIGTERM      terminate process    software termination signal
16    SIGURG       discard signal       urgent condition present on socket
17    SIGSTOP      stop process         stop (cannot be caught or ignored)
18    SIGTSTP      stop process         stop signal generated from keyboard
19    SIGCONT      discard signal       continue after stop
20    SIGCHLD      discard signal       child status has changed
21    SIGTTIN      stop process         background read attempted from control terminal
22    SIGTTOU      stop process         background write attempted to control terminal
23    SIGIO        discard signal       I/O is possible on a descriptor (see fcntl(2))
24    SIGXCPU      terminate process    cpu time limit exceeded (see setrlimit(2))
25    SIGXFSZ      terminate process    file size limit exceeded (see setrlimit(2))
26    SIGVTALRM    terminate process    virtual time alarm (see setitimer(2))
27    SIGPROF      terminate process    profiling timer alarm (see setitimer(2))
28    SIGWINCH     discard signal       Window size change
29    SIGINFO      discard signal       status request from keyboard
30    SIGUSR1      terminate process    User defined signal 1
31    SIGUSR2      terminate process    User defined signal 2

*/

#[cfg(any(target_os = "macos", target_os = "freebsd"))]
pub static ALL_SIGNALS: [Signal<'static>; 31] = [
    Signal {
        name: "HUP",
        value: 1,
    },
    Signal {
        name: "INT",
        value: 2,
    },
    Signal {
        name: "QUIT",
        value: 3,
    },
    Signal {
        name: "ILL",
        value: 4,
    },
    Signal {
        name: "TRAP",
        value: 5,
    },
    Signal {
        name: "ABRT",
        value: 6,
    },
    Signal {
        name: "EMT",
        value: 7,
    },
    Signal {
        name: "FPE",
        value: 8,
    },
    Signal {
        name: "KILL",
        value: 9,
    },
    Signal {
        name: "BUS",
        value: 10,
    },
    Signal {
        name: "SEGV",
        value: 11,
    },
    Signal {
        name: "SYS",
        value: 12,
    },
    Signal {
        name: "PIPE",
        value: 13,
    },
    Signal {
        name: "ALRM",
        value: 14,
    },
    Signal {
        name: "TERM",
        value: 15,
    },
    Signal {
        name: "URG",
        value: 16,
    },
    Signal {
        name: "STOP",
        value: 17,
    },
    Signal {
        name: "TSTP",
        value: 18,
    },
    Signal {
        name: "CONT",
        value: 19,
    },
    Signal {
        name: "CHLD",
        value: 20,
    },
    Signal {
        name: "TTIN",
        value: 21,
    },
    Signal {
        name: "TTOU",
        value: 22,
    },
    Signal {
        name: "IO",
        value: 23,
    },
    Signal {
        name: "XCPU",
        value: 24,
    },
    Signal {
        name: "XFSZ",
        value: 25,
    },
    Signal {
        name: "VTALRM",
        value: 26,
    },
    Signal {
        name: "PROF",
        value: 27,
    },
    Signal {
        name: "WINCH",
        value: 28,
    },
    Signal {
        name: "INFO",
        value: 29,
    },
    Signal {
        name: "USR1",
        value: 30,
    },
    Signal {
        name: "USR2",
        value: 31,
    },
];

pub fn signal_by_name_or_value(signal_name_or_value: &str) -> Option<usize> {
    if signal_name_or_value == "0" {
        return Some(0);
    }
    for signal in &ALL_SIGNALS {
        let long_name = format!("SIG{}", signal.name);
        if signal.name == signal_name_or_value || (signal_name_or_value == signal.value.to_string())
            || (long_name == signal_name_or_value)
        {
            return Some(signal.value);
        }
    }
    None
}

#[inline(always)]
pub fn is_signal(num: usize) -> bool {
    num < ALL_SIGNALS.len()
}

#[test]
fn signals_all_contiguous() {
    for (i, signal) in ALL_SIGNALS.iter().enumerate() {
        assert_eq!(signal.value, i + 1);
    }
}

#[test]
fn signals_all_are_signal() {
    for signal in &ALL_SIGNALS {
        assert!(is_signal(signal.value));
    }
}

#[test]
fn signal_by_value() {
    assert_eq!(signal_by_name_or_value("0"), Some(0));
    for signal in &ALL_SIGNALS {
        assert_eq!(signal_by_name_or_value(&signal.value.to_string()), Some(signal.value));
    }
}

#[test]
fn signal_by_short_name() {
    for signal in &ALL_SIGNALS {
        assert_eq!(signal_by_name_or_value(signal.name), Some(signal.value));
    }
}

#[test]
fn signal_by_long_name() {
    for signal in &ALL_SIGNALS {
        assert_eq!(signal_by_name_or_value(&format!("SIG{}", signal.name)), Some(signal.value));
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::fs::File;
use std::io::{self, Read, Write};
use std::sync::Mutex;

use futures::{
    future::{self, Either},
    Future,
};

use vm::api::generic::{A, B};
use vm::api::{
    self, Array, Getable, OpaqueValue, OwnedFunction, TypedBytecode, Userdata, VmType, WithVM, IO,
};
use vm::gc::{Gc, Traverseable};
use vm::internal::ValuePrinter;
use vm::stack::{self, StackFrame};
use vm::thread::{RootedThread, Thread, ThreadInternal};
use vm::types::*;
use vm::{self, ExternModule, Result};

use compiler_pipeline::*;

use super::{Compiler, Error};

fn print(s: &str) -> IO<()> {
    print!("{}", s);
    IO::Value(())
}

fn println(s: &str) -> IO<()> {
    println!("{}", s);
    IO::Value(())
}

fn flush_stdout() -> IO<()> {
    match io::stdout().flush() {
        Ok(_) => IO::Value(()),
        Err(err) => IO::Exception(err.to_string()),
    }
}

fn eprint(s: &str) -> IO<()> {
    eprint!("{}", s);
    IO::Value(())
}

fn eprintln(s: &str) -> IO<()> {
    eprintln!("{}", s);
    IO::Value(())
}

struct GluonFile(Mutex<File>);

impl Userdata for GluonFile {}

impl fmt::Debug for GluonFile {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "File")
    }
}

impl VmType for GluonFile {
    type Type = GluonFile;
}

impl Traverseable for GluonFile {
    fn traverse(&self, _: &mut Gc) {}
}

fn open_file(s: &str) -> IO<GluonFile> {
    match File::open(s) {
        Ok(f) => IO::Value(GluonFile(Mutex::new(f))),
        Err(err) => IO::Exception(format!("{}", err)),
    }
}

fn read_file<'vm>(file: WithVM<'vm, &GluonFile>, count: usize) -> IO<Array<'vm, u8>> {
    let WithVM { vm, value: file } = file;
    let mut file = file.0.lock().unwrap();
    let mut buffer = Vec::with_capacity(count);
    unsafe {
        buffer.set_len(count);
        match file.read(&mut *buffer) {
            Ok(bytes_read) => match api::convert::<_, Array<u8>>(vm, &buffer[..bytes_read]) {
                Ok(v) => IO::Value(v),
                Err(err) => IO::Exception(format!("{}", err)),
            },
            Err(err) => IO::Exception(format!("{}", err)),
        }
    }
}

fn read_file_to_string(s: &str) -> IO<String> {
    let mut buffer = String::new();
    match File::open(s).and_then(|mut file| file.read_to_string(&mut buffer)) {
        Ok(_) => IO::Value(buffer),
        Err(err) => {
            use std::fmt::Write;
            buffer.clear();
            let _ = write!(&mut buffer, "{}", err);
            IO::Exception(buffer)
        }
    }
}

fn read_char() -> IO<char> {
    match io::stdin().bytes().next() {
        Some(result) => match result {
            Ok(b) => ::std::char::from_u32(b as u32)
                .map(IO::Value)
                .unwrap_or_else(|| IO::Exception("Not a valid char".into())),
            Err(err) => IO::Exception(format!("{}", err)),
        },
        None => IO::Exception("No read".into()),
    }
}

fn read_line() -> IO<String> {
    let mut buffer = String::new();
    match io::stdin().read_line(&mut buffer) {
        Ok(_) => IO::Value(buffer),
        Err(err) => {
            use std::fmt::Write;
            buffer.clear();
            let _ = write!(&mut buffer, "{}", err);
            IO::Exception(buffer)
        }
    }
}

/// IO a -> (String -> IO a) -> IO a
fn catch<'vm>(
    action: OpaqueValue<&'vm Thread, IO<A>>,
    mut catch: OwnedFunction<fn(String) -> IO<OpaqueValue<RootedThread, A>>>,
) -> impl Future<Item = IO<OpaqueValue<RootedThread, A>>, Error = vm::Error> {
    let vm = action.vm().root_thread();
    let frame_level = vm.context().frame_level();
    let mut action: OwnedFunction<fn(()) -> OpaqueValue<RootedThread, A>> =
        Getable::from_value(&vm, action.get_variant());

    action.call_fast_async(()).then(move |result| match result {
        Ok(value) => Either::A(future::ok(IO::Value(value))),
        Err(err) => {
            {
                let mut context = vm.context();
                {
                    let mut stack = context.stack_frame::<stack::State>();

                    if let Err(err) = ::vm::thread::reset_stack(stack, frame_level) {
                        return Either::A(future::ok(IO::Exception(err.to_string().into())));
                    }
                }

                let mut stack = context.stack_frame::<stack::State>();
                let len = stack.len();
                stack.pop_many(len - 2);
            }
            Either::B(catch.call_fast_async(format!("{}", err)).then(|result| {
                Ok(match result {
                    Ok(value) => value,
                    Err(err) => IO::Exception(format!("{}", err)),
                })
            }))
        }
    })
}

fn clear_frames<T>(mut err: Error, stack: StackFrame) -> IO<T> {
    let new_trace = match ::vm::thread::reset_stack(stack, 1) {
        Ok(x) => x,
        Err(err) => return IO::Exception(err.to_string()),
    };
    match err {
        // Ignore the stacktrace as we take a more specific range of the stack here
        Error::VM(vm::Error::Panic(_, ref mut trace)) => *trace = Some(new_trace),
        _ => (),
    }
    IO::Exception(err.to_string())
}

field_decl! { value, typ }

// Can't create a minimal reproduction for why this reports as being unused...
#[allow(dead_code)]
type RunExpr = record_type!{ value => String, typ => String };

fn run_expr(
    WithVM { vm, value: expr }: WithVM<&str>,
) -> impl Future<Item = IO<RunExpr>, Error = vm::Error> {
    let vm = vm.root_thread();

    let vm1 = vm.clone();
    expr.run_expr(&mut Compiler::new().run_io(true), vm1, "<top>", expr, None)
        .then(move |run_result| {
            let mut context = vm.context();
            let stack = context.stack_frame::<stack::State>();
            Ok(match run_result {
                Ok(execute_value) => {
                    let env = vm.global_env().get_env();
                    let typ = execute_value.typ;
                    IO::Value(record_no_decl!{
                        value => ValuePrinter::new(&*env, &typ, execute_value.value.get_variant()).width(80).to_string(),
                        typ => typ.to_string()
                    })
                }
                Err(err) => clear_frames(err, stack),
            })
        })
}

fn load_script(
    WithVM { vm, value: name }: WithVM<&str>,
    expr: &str,
) -> impl Future<Item = IO<String>, Error = vm::Error> {
    let vm1 = vm.root_thread();
    let vm = vm.root_thread();
    let name = name.to_string();
    expr.load_script(&mut Compiler::new(), vm1, &name, expr, None)
        .then(move |run_result| {
            let mut context = vm.context();
            let stack = context.stack_frame::<stack::State>();
            let io = match run_result {
                Ok(()) => IO::Value(format!("Loaded {}", name)),
                Err(err) => clear_frames(err, stack),
            };
            Ok(io)
        })
}

mod std {
    pub mod io {
        pub use io as prim;
    }
}

pub fn load(vm: &Thread) -> Result<ExternModule> {
    vm.register_type::<GluonFile>("File", &[])?;

    // flat_map f m : (a -> IO b) -> IO a -> IO b
    //     = f (m ())
    let flat_map = vec![
        // [f, m, ()]       Initial stack
        Call(1),     // [f, m_ret]       Call m ()
        PushInt(0),  // [f, m_ret, ()]   Add a dummy argument ()
        TailCall(2), /* [f_ret]          Call f m_ret () */
    ];

    type FlatMap = fn(fn(A) -> IO<B>, IO<A>) -> IO<B>;
    type Wrap = fn(A) -> IO<A>;

    let wrap = vec![Pop(1)];

    use self::std;

    // IO functions
    ExternModule::new(
        vm,
        record! {
            type File => GluonFile,
            flat_map => TypedBytecode::<FlatMap>::new("std.io.prim.flat_map", 3, flat_map),
            wrap => TypedBytecode::<Wrap>::new("std.io.prim.wrap", 2, wrap),
            open_file => primitive!(1, std::io::prim::open_file),
            read_file => primitive!(2, std::io::prim::read_file),
            read_file_to_string => primitive!(1, std::io::prim::read_file_to_string),
            read_char => primitive!(0, std::io::prim::read_char),
            read_line => primitive!(0, std::io::prim::read_line),
            print => primitive!(1, std::io::prim::print),
            println => primitive!(1, std::io::prim::println),
            flush_stdout => primitive!(0, std::io::prim::flush_stdout),
            eprint => primitive!(1, std::io::prim::eprint),
            eprintln => primitive!(1, std::io::prim::eprintln),
            catch => primitive!(2, async fn std::io::prim::catch),
            run_expr => primitive!(1, async fn std::io::prim::run_expr),
            load_script => primitive!(2, async fn std::io::prim::load_script),
        },
    )
}
<commit_msg>feat: Add io.read_file_to_array<commit_after>use std::fmt;
use std::fs::File;
use std::io::{self, Read, Write};
use std::sync::Mutex;

use futures::{
    future::{self, Either},
    Future,
};

use vm::api::generic::{A, B};
use vm::api::{
    self, Array, Getable, OpaqueValue, OwnedFunction, TypedBytecode, Userdata, VmType, WithVM, IO,
};
use vm::gc::{Gc, Traverseable};
use vm::internal::ValuePrinter;
use vm::stack::{self, StackFrame};
use vm::thread::{RootedThread, Thread, ThreadInternal};
use vm::types::*;
use vm::{self, ExternModule, Result};

use compiler_pipeline::*;

use super::{Compiler, Error};

fn print(s: &str) -> IO<()> {
    print!("{}", s);
    IO::Value(())
}

fn println(s: &str) -> IO<()> {
    println!("{}", s);
    IO::Value(())
}

fn flush_stdout() -> IO<()> {
    match io::stdout().flush() {
        Ok(_) => IO::Value(()),
        Err(err) => IO::Exception(err.to_string()),
    }
}

fn eprint(s: &str) -> IO<()> {
    eprint!("{}", s);
    IO::Value(())
}

fn eprintln(s: &str) -> IO<()> {
    eprintln!("{}", s);
    IO::Value(())
}

struct GluonFile(Mutex<File>);

impl Userdata for GluonFile {}

impl fmt::Debug for GluonFile {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "File")
    }
}

impl VmType for GluonFile {
    type Type = GluonFile;
}

impl Traverseable for GluonFile {
    fn traverse(&self, _: &mut Gc) {}
}

fn open_file(s: &str) -> IO<GluonFile> {
    match File::open(s) {
        Ok(f) => IO::Value(GluonFile(Mutex::new(f))),
        Err(err) => IO::Exception(format!("{}", err)),
    }
}

fn read_file<'vm>(file: WithVM<'vm, &GluonFile>, count: usize) -> IO<Array<'vm, u8>> {
    let WithVM { vm, value: file } = file;
    let mut file = file.0.lock().unwrap();
    let mut buffer = Vec::with_capacity(count);
    unsafe {
        buffer.set_len(count);
        match file.read(&mut *buffer) {
            Ok(bytes_read) => match api::convert::<_, Array<u8>>(vm, &buffer[..bytes_read]) {
                Ok(v) => IO::Value(v),
                Err(err) => IO::Exception(format!("{}", err)),
            },
            Err(err) => IO::Exception(format!("{}", err)),
        }
    }
}

fn read_file_to_array(s: &str) -> IO<Vec<u8>> {
    let mut buffer = Vec::new();
    match File::open(s).and_then(|mut file| file.read_to_end(&mut buffer)) {
        Ok(_) => IO::Value(buffer),
        Err(err) => IO::Exception(err.to_string()),
    }
}

fn read_file_to_string(s: &str) -> IO<String> {
    let mut buffer = String::new();
    match File::open(s).and_then(|mut file| file.read_to_string(&mut buffer)) {
        Ok(_) => IO::Value(buffer),
        Err(err) => {
            use std::fmt::Write;
            buffer.clear();
            let _ = write!(&mut buffer, "{}", err);
            IO::Exception(buffer)
        }
    }
}

fn read_char() -> IO<char> {
    match io::stdin().bytes().next() {
        Some(result) => match result {
            Ok(b) => ::std::char::from_u32(b as u32)
                .map(IO::Value)
                .unwrap_or_else(|| IO::Exception("Not a valid char".into())),
            Err(err) => IO::Exception(format!("{}", err)),
        },
        None => IO::Exception("No read".into()),
    }
}

fn read_line() -> IO<String> {
    let mut buffer = String::new();
    match io::stdin().read_line(&mut buffer) {
        Ok(_) => IO::Value(buffer),
        Err(err) => {
            use std::fmt::Write;
            buffer.clear();
            let _ = write!(&mut buffer, "{}", err);
            IO::Exception(buffer)
        }
    }
}

/// IO a -> (String -> IO a) -> IO a
fn catch<'vm>(
    action: OpaqueValue<&'vm Thread, IO<A>>,
    mut catch: OwnedFunction<fn(String) -> IO<OpaqueValue<RootedThread, A>>>,
) -> impl Future<Item = IO<OpaqueValue<RootedThread, A>>, Error = vm::Error> {
    let vm = action.vm().root_thread();
    let frame_level = vm.context().frame_level();
    let mut action: OwnedFunction<fn(()) -> OpaqueValue<RootedThread, A>> =
        Getable::from_value(&vm, action.get_variant());

    action.call_fast_async(()).then(move |result| match result {
        Ok(value) => Either::A(future::ok(IO::Value(value))),
        Err(err) => {
            {
                let mut context = vm.context();
                {
                    let mut stack = context.stack_frame::<stack::State>();

                    if let Err(err) = ::vm::thread::reset_stack(stack, frame_level) {
                        return Either::A(future::ok(IO::Exception(err.to_string().into())));
                    }
                }

                let mut stack = context.stack_frame::<stack::State>();
                let len = stack.len();
                stack.pop_many(len - 2);
            }
            Either::B(catch.call_fast_async(format!("{}", err)).then(|result| {
                Ok(match result {
                    Ok(value) => value,
                    Err(err) => IO::Exception(format!("{}", err)),
                })
            }))
        }
    })
}

fn clear_frames<T>(mut err: Error, stack: StackFrame) -> IO<T> {
    let new_trace = match ::vm::thread::reset_stack(stack, 1) {
        Ok(x) => x,
        Err(err) => return IO::Exception(err.to_string()),
    };
    match err {
        // Ignore the stacktrace as we take a more specific range of the stack here
        Error::VM(vm::Error::Panic(_, ref mut trace)) => *trace = Some(new_trace),
        _ => (),
    }
    IO::Exception(err.to_string())
}

field_decl! { value, typ }

// Can't create a minimal reproduction for why this reports as being unused...
#[allow(dead_code)]
type RunExpr = record_type!{ value => String, typ => String };

fn run_expr(
    WithVM { vm, value: expr }: WithVM<&str>,
) -> impl Future<Item = IO<RunExpr>, Error = vm::Error> {
    let vm = vm.root_thread();

    let vm1 = vm.clone();
    expr.run_expr(&mut Compiler::new().run_io(true), vm1, "<top>", expr, None)
        .then(move |run_result| {
            let mut context = vm.context();
            let stack = context.stack_frame::<stack::State>();
            Ok(match run_result {
                Ok(execute_value) => {
                    let env = vm.global_env().get_env();
                    let typ = execute_value.typ;
                    IO::Value(record_no_decl!{
                        value => ValuePrinter::new(&*env, &typ, execute_value.value.get_variant()).width(80).to_string(),
                        typ => typ.to_string()
                    })
                }
                Err(err) => clear_frames(err, stack),
            })
        })
}

fn load_script(
    WithVM { vm, value: name }: WithVM<&str>,
    expr: &str,
) -> impl Future<Item = IO<String>, Error = vm::Error> {
    let vm1 = vm.root_thread();
    let vm = vm.root_thread();
    let name = name.to_string();
    expr.load_script(&mut Compiler::new(), vm1, &name, expr, None)
        .then(move |run_result| {
            let mut context = vm.context();
            let stack = context.stack_frame::<stack::State>();
            let io = match run_result {
                Ok(()) => IO::Value(format!("Loaded {}", name)),
                Err(err) => clear_frames(err, stack),
            };
            Ok(io)
        })
}

mod std {
    pub mod io {
        pub use io as prim;
    }
}

pub fn load(vm: &Thread) -> Result<ExternModule> {
    vm.register_type::<GluonFile>("File", &[])?;

    // flat_map f m : (a -> IO b) -> IO a -> IO b
    //     = f (m ())
    let flat_map = vec![
        // [f, m, ()]       Initial stack
        Call(1),     // [f, m_ret]       Call m ()
        PushInt(0),  // [f, m_ret, ()]   Add a dummy argument ()
        TailCall(2), /* [f_ret]          Call f m_ret () */
    ];

    type FlatMap = fn(fn(A) -> IO<B>, IO<A>) -> IO<B>;
    type Wrap = fn(A) -> IO<A>;

    let wrap = vec![Pop(1)];

    use self::std;

    // IO functions
    ExternModule::new(
        vm,
        record! {
            type File => GluonFile,
            flat_map => TypedBytecode::<FlatMap>::new("std.io.prim.flat_map", 3, flat_map),
            wrap => TypedBytecode::<Wrap>::new("std.io.prim.wrap", 2, wrap),
            open_file => primitive!(1, std::io::prim::open_file),
            read_file => primitive!(2, std::io::prim::read_file),
            read_file_to_string => primitive!(1, std::io::prim::read_file_to_string),
            read_file_to_array => primitive!(1, std::io::prim::read_file_to_array),
            read_char => primitive!(0, std::io::prim::read_char),
            read_line => primitive!(0, std::io::prim::read_line),
            print => primitive!(1, std::io::prim::print),
            println => primitive!(1, std::io::prim::println),
            flush_stdout => primitive!(0, std::io::prim::flush_stdout),
            eprint => primitive!(1, std::io::prim::eprint),
            eprintln => primitive!(1, std::io::prim::eprintln),
            catch => primitive!(2, async fn std::io::prim::catch),
            run_expr => primitive!(1, async fn std::io::prim::run_expr),
            load_script => primitive!(2, async fn std::io::prim::load_script),
        },
    )
}
<|endoftext|>


<commit_before>use std::rc::Rc;
use std::io::{self, Read, Write};
use std::net::Shutdown;

use futures::prelude::*;
use tokio_io::{AsyncRead, AsyncWrite};
use tokio_io::io::shutdown;
use bytes::{Bytes, IntoBuf};
use h2::{self, server as h2s, client as h2c};
use tokio_core::net::TcpStream;

#[async]
pub fn copy_from_h2<
    W: AsyncWrite + 'static,
    B: Stream<Item = Bytes, Error = h2::Error> + 'static,
>(
    src: B,
    mut dst: W,
) -> Result<usize, h2::Error> {
    let mut counter = 0;
    #[async]
    for buf in src {
        let mut buf = buf.into_buf();
        let n = poll!(dst.write_buf(&mut buf))?;
        counter += n;
    }
    await!(shutdown(dst))?;
    Ok(counter)
}

pub trait SendData<B: IntoBuf> {
    fn send_data(&mut self, data: B, end_of_stream: bool) -> Result<(), h2::Error>;
}

impl<B: IntoBuf> SendData<B> for h2c::Stream<B> {
    fn send_data(&mut self, data: B, end_of_stream: bool) -> Result<(), h2::Error> {
        h2c::Stream::send_data(self, data, end_of_stream)
    }
}
impl<B: IntoBuf> SendData<B> for h2s::Stream<B> {
    fn send_data(&mut self, data: B, end_of_stream: bool) -> Result<(), h2::Error> {
        h2s::Stream::send_data(self, data, end_of_stream)
    }
}

#[async]
pub fn copy_to_h2<R: AsyncRead + 'static, H: SendData<Bytes> + 'static>(
    mut src: R,
    mut dst: H,
) -> Result<usize, h2::Error> {
    let mut counter = 0;
    let mut buf = Vec::with_capacity(2048);
    loop {
        let n = poll!(src.read_buf(&mut buf))?;
        if n == 0 {
            dst.send_data(Bytes::from(&buf[..n]), true)?;
            break;
        } else {
            dst.send_data(Bytes::from(&buf[..n]), false)?;
        }
        counter += n;
    }
    Ok(counter)
}

// This is a custom type used to have a custom implementation of the
// `AsyncWrite::shutdown` method which actually calls `TcpStream::shutdown` to
// notify the remote end that we're done writing.
#[derive(Clone)]
pub struct Socket(Rc<TcpStream>);

impl Socket {
    pub fn new(s: TcpStream) -> Socket {
        Socket(Rc::new(s))
    }
}

impl Read for Socket {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        (&*self.0).read(buf)
    }
}

impl Write for Socket {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        (&*self.0).write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl AsyncRead for Socket {}

impl AsyncWrite for Socket {
    fn shutdown(&mut self) -> Poll<(), io::Error> {
        try!(self.0.shutdown(Shutdown::Write));
        Ok(().into())
    }
}
<commit_msg>Add tests for `io::*`<commit_after>use std::rc::Rc;
use std::io::{self, Read, Write};
use std::net::Shutdown;

use futures::prelude::*;
use tokio_io::{AsyncRead, AsyncWrite};
use tokio_io::io::shutdown;
use bytes::{Bytes, IntoBuf};
use h2::{self, server as h2s, client as h2c};
use tokio_core::net::TcpStream;

#[async]
pub fn copy_from_h2<
    W: AsyncWrite + 'static,
    B: Stream<Item = Bytes, Error = h2::Error> + 'static,
>(
    src: B,
    mut dst: W,
) -> Result<usize, h2::Error> {
    let mut counter = 0;
    #[async]
    for buf in src {
        let mut buf = buf.into_buf();
        let n = poll!(dst.write_buf(&mut buf))?;
        counter += n;
    }
    await!(shutdown(dst))?;
    Ok(counter)
}

pub trait SendData<B: IntoBuf> {
    fn send_data(&mut self, data: B, end_of_stream: bool) -> Result<(), h2::Error>;
}

impl<B: IntoBuf> SendData<B> for h2c::Stream<B> {
    fn send_data(&mut self, data: B, end_of_stream: bool) -> Result<(), h2::Error> {
        h2c::Stream::send_data(self, data, end_of_stream)
    }
}
impl<B: IntoBuf> SendData<B> for h2s::Stream<B> {
    fn send_data(&mut self, data: B, end_of_stream: bool) -> Result<(), h2::Error> {
        h2s::Stream::send_data(self, data, end_of_stream)
    }
}

#[async]
pub fn copy_to_h2<R: AsyncRead + 'static, H: SendData<Bytes> + 'static>(
    mut src: R,
    mut dst: H,
) -> Result<usize, h2::Error> {
    let mut counter = 0;
    let mut buf = Vec::with_capacity(2048);
    loop {
        let n = poll!(src.read_buf(&mut buf))?;
        if n == 0 {
            dst.send_data(Bytes::from(&buf[..n]), true)?;
            break;
        } else {
            dst.send_data(Bytes::from(&buf[..n]), false)?;
        }
        counter += n;
    }
    Ok(counter)
}

// This is a custom type used to have a custom implementation of the
// `AsyncWrite::shutdown` method which actually calls `TcpStream::shutdown` to
// notify the remote end that we're done writing.
#[derive(Clone)]
pub struct Socket(Rc<TcpStream>);

impl Socket {
    pub fn new(s: TcpStream) -> Socket {
        Socket(Rc::new(s))
    }
}

impl Read for Socket {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        (&*self.0).read(buf)
    }
}

impl Write for Socket {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        (&*self.0).write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl AsyncRead for Socket {}

impl AsyncWrite for Socket {
    fn shutdown(&mut self) -> Poll<(), io::Error> {
        try!(self.0.shutdown(Shutdown::Write));
        Ok(().into())
    }
}

#[cfg(test)]
mod test {
    use std::io::Cursor;
    use std::rc::Rc;
    use std::cell::RefCell;

    use futures::prelude::*;
    use futures::stream::iter_ok;

    use super::*;

    #[derive(Clone)]
    struct Dst(Rc<RefCell<Cursor<Vec<u8>>>>);
    impl Write for Dst {
        fn write(&mut self, buf: &[u8]) -> ::std::io::Result<usize> {
            self.0.borrow_mut().write(buf)
        }
        fn flush(&mut self) -> ::std::io::Result<()> {
            self.0.borrow_mut().flush()
        }
    }
    impl AsyncWrite for Dst {
        fn shutdown(&mut self) -> Poll<(), ::std::io::Error> {
            Ok(().into())
        }
    }
    impl SendData<Bytes> for Dst {
        fn send_data(&mut self, data: Bytes, _end_of_stream: bool) -> Result<(), h2::Error> {
            self.0.borrow_mut().get_mut().extend(data);
            Ok(())
        }
    }

    #[test]
    fn test_copy_from_h2() {
        let dst = Dst(Rc::new(RefCell::new(Cursor::new(Vec::new()))));
        let src = iter_ok(vec![
            Bytes::from("123"),
            Bytes::from("456"),
            Bytes::from("789"),
        ]);
        let r = copy_from_h2(src, dst.clone()).wait().unwrap();
        assert_eq!(r, 9);
        assert_eq!(dst.0.borrow().get_ref(), b"123456789");
    }

    #[test]
    fn test_copy_to_h2() {
        let dst = Dst(Rc::new(RefCell::new(Cursor::new(Vec::new()))));
        let src: &[u8] = b"123456789";
        let r = copy_to_h2(src, dst.clone()).wait().unwrap();
        assert_eq!(r, 9);
        assert_eq!(dst.0.borrow().get_ref(), b"123456789");
    }
}
<|endoftext|>