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

#![allow(unsafe_code, unrooted_must_root)]

use dom::attr::AttrHelpers;
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::codegen::InheritTypes::{CharacterDataCast, DocumentTypeCast};
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLScriptElementCast};
use dom::bindings::codegen::InheritTypes::{HTMLFormElementDerived, NodeCast};
use dom::bindings::codegen::InheritTypes::ProcessingInstructionCast;
use dom::bindings::js::{JS, JSRef, Temporary, OptionalRootable, Root};
use dom::bindings::js::RootedReference;
use dom::bindings::trace::RootedVec;
use dom::characterdata::CharacterDataHelpers;
use dom::comment::Comment;
use dom::document::{Document, DocumentHelpers};
use dom::document::{DocumentSource, IsHTMLDocument};
use dom::documenttype::DocumentType;
use dom::element::{Element, AttributeHandlers, ElementHelpers, ElementCreator};
use dom::htmlscriptelement::HTMLScriptElement;
use dom::htmlscriptelement::HTMLScriptElementHelpers;
use dom::node::{Node, NodeHelpers, NodeTypeId};
use dom::node::{document_from_node, window_from_node};
use dom::processinginstruction::ProcessingInstruction;
use dom::processinginstruction::ProcessingInstructionHelpers;
use dom::servohtmlparser;
use dom::servohtmlparser::{ServoHTMLParser, FragmentContext};
use dom::text::Text;
use parse::Parser;

use encoding::all::UTF_8;
use encoding::types::{Encoding, DecoderTrap};

use net_traits::{ProgressMsg, LoadResponse};
use util::str::DOMString;
use util::task_state;
use util::task_state::IN_HTML_PARSER;
use std::borrow::Cow;
use std::old_io::{Writer, IoResult};
use url::Url;
use html5ever::Attribute;
use html5ever::serialize::{Serializable, Serializer, AttrRef};
use html5ever::serialize::TraversalScope;
use html5ever::serialize::TraversalScope::{IncludeNode, ChildrenOnly};
use html5ever::tree_builder::{TreeSink, QuirksMode, NodeOrText, AppendNode, AppendText};
use string_cache::QualName;

use hyper::header::ContentType;
use hyper::mime::{Mime, TopLevel, SubLevel};

pub enum HTMLInput {
    InputString(String),
    InputUrl(LoadResponse),
}

trait SinkHelpers {
    fn get_or_create(&self, child: NodeOrText<JS<Node>>) -> Temporary<Node>;
}

impl SinkHelpers for servohtmlparser::Sink {
    fn get_or_create(&self, child: NodeOrText<JS<Node>>) -> Temporary<Node> {
        match child {
            AppendNode(n) => Temporary::new(n),
            AppendText(t) => {
                let doc = self.document.root();
                let text = Text::new(t, doc.r());
                NodeCast::from_temporary(text)
            }
        }
    }
}

impl<'a> TreeSink for servohtmlparser::Sink {
    type Handle = JS<Node>;
    fn get_document(&mut self) -> JS<Node> {
        let doc = self.document.root();
        let node: JSRef<Node> = NodeCast::from_ref(doc.r());
        JS::from_rooted(node)
    }

    fn same_node(&self, x: JS<Node>, y: JS<Node>) -> bool {
        x == y
    }

    fn elem_name(&self, target: JS<Node>) -> QualName {
        let node: Root<Node> = target.root();
        let elem: JSRef<Element> = ElementCast::to_ref(node.r())
            .expect("tried to get name of non-Element in HTML parsing");
        QualName {
            ns: elem.namespace().clone(),
            local: elem.local_name().clone(),
        }
    }

    fn create_element(&mut self, name: QualName, attrs: Vec<Attribute>)
            -> JS<Node> {
        let doc = self.document.root();
        let elem = Element::create(name, None, doc.r(),
                                   ElementCreator::ParserCreated).root();

        for attr in attrs.into_iter() {
            elem.r().set_attribute_from_parser(attr.name, attr.value, None);
        }

        let node: JSRef<Node> = NodeCast::from_ref(elem.r());
        JS::from_rooted(node)
    }

    fn create_comment(&mut self, text: String) -> JS<Node> {
        let doc = self.document.root();
        let comment = Comment::new(text, doc.r());
        let node: Root<Node> = NodeCast::from_temporary(comment).root();
        JS::from_rooted(node.r())
    }

    fn append_before_sibling(&mut self,
            sibling: JS<Node>,
            new_node: NodeOrText<JS<Node>>) -> Result<(), NodeOrText<JS<Node>>> {
        // If there is no parent, return the node to the parser.
        let sibling: Root<Node> = sibling.root();
        let parent = match sibling.r().parent_node() {
            Some(p) => p.root(),
            None => return Err(new_node),
        };

        let child = self.get_or_create(new_node).root();
        assert!(parent.r().InsertBefore(child.r(), Some(sibling.r())).is_ok());
        Ok(())
    }

    fn parse_error(&mut self, msg: Cow<'static, str>) {
        debug!("Parse error: {}", msg);
    }

    fn set_quirks_mode(&mut self, mode: QuirksMode) {
        let doc = self.document.root();
        doc.r().set_quirks_mode(mode);
    }

    fn append(&mut self, parent: JS<Node>, child: NodeOrText<JS<Node>>) {
        let parent: Root<Node> = parent.root();
        let child = self.get_or_create(child).root();

        // FIXME(#3701): Use a simpler algorithm and merge adjacent text nodes
        assert!(parent.r().AppendChild(child.r()).is_ok());
    }

    fn append_doctype_to_document(&mut self, name: String, public_id: String, system_id: String) {
        let doc = self.document.root();
        let doc_node: JSRef<Node> = NodeCast::from_ref(doc.r());
        let doctype = DocumentType::new(name, Some(public_id), Some(system_id), doc.r());
        let node: Root<Node> = NodeCast::from_temporary(doctype).root();

        assert!(doc_node.AppendChild(node.r()).is_ok());
    }

    fn add_attrs_if_missing(&mut self, target: JS<Node>, attrs: Vec<Attribute>) {
        let node: Root<Node> = target.root();
        let elem: JSRef<Element> = ElementCast::to_ref(node.r())
            .expect("tried to set attrs on non-Element in HTML parsing");
        for attr in attrs.into_iter() {
            elem.set_attribute_from_parser(attr.name, attr.value, None);
        }
    }

    fn remove_from_parent(&mut self, _target: JS<Node>) {
        error!("remove_from_parent not implemented!");
    }

    fn mark_script_already_started(&mut self, node: JS<Node>) {
        let node: Root<Node> = node.root();
        let script: Option<JSRef<HTMLScriptElement>> = HTMLScriptElementCast::to_ref(node.r());
        script.map(|script| script.mark_already_started());
    }

    fn complete_script(&mut self, node: JS<Node>) {
        let node: Root<Node> = node.root();
        let script: Option<JSRef<HTMLScriptElement>> = HTMLScriptElementCast::to_ref(node.r());
        script.map(|script| script.prepare());
    }

    fn reparent_children(&mut self, _node: JS<Node>, _new_parent: JS<Node>) {
        panic!("unimplemented")
    }
}

impl<'a> Serializable for JSRef<'a, Node> {
    fn serialize<'wr, Wr: Writer>(&self, serializer: &mut Serializer<'wr, Wr>,
                                  traversal_scope: TraversalScope) -> IoResult<()> {
        let node = *self;
        match (traversal_scope, node.type_id()) {
            (_, NodeTypeId::Element(..)) => {
                let elem: JSRef<Element> = ElementCast::to_ref(node).unwrap();
                let name = QualName::new(elem.namespace().clone(),
                                         elem.local_name().clone());
                if traversal_scope == IncludeNode {
                    let attrs = elem.attrs().iter().map(|at| {
                        let attr = at.root();
                        let qname = QualName::new(attr.r().namespace().clone(),
                                                  attr.r().local_name().clone());
                        let value = attr.r().value().clone();
                        (qname, value)
                    }).collect::<Vec<_>>();
                    let attr_refs = attrs.iter().map(|&(ref qname, ref value)| {
                        let ar: AttrRef = (&qname, value.as_slice());
                        ar
                    });
                    try!(serializer.start_elem(name.clone(), attr_refs));
                }

                for handle in node.children() {
                    let handle = handle.root();
                    try!(handle.r().serialize(serializer, IncludeNode));
                }

                if traversal_scope == IncludeNode {
                    try!(serializer.end_elem(name.clone()));
                }
                Ok(())
            },

            (ChildrenOnly, NodeTypeId::Document) => {
                for handle in node.children() {
                    let handle = handle.root();
                    try!(handle.r().serialize(serializer, IncludeNode));
                }
                Ok(())
            },

            (ChildrenOnly, _) => Ok(()),

            (IncludeNode, NodeTypeId::DocumentType) => {
                let doctype: JSRef<DocumentType> = DocumentTypeCast::to_ref(node).unwrap();
                serializer.write_doctype(doctype.name().as_slice())
            },

            (IncludeNode, NodeTypeId::Text) => {
                let cdata = CharacterDataCast::to_ref(node).unwrap();
                serializer.write_text(&cdata.data())
            },

            (IncludeNode, NodeTypeId::Comment) => {
                let cdata = CharacterDataCast::to_ref(node).unwrap();
                serializer.write_comment(&cdata.data())
            },

            (IncludeNode, NodeTypeId::ProcessingInstruction) => {
                let pi: JSRef<ProcessingInstruction> = ProcessingInstructionCast::to_ref(node).unwrap();
                let data = CharacterDataCast::from_ref(pi).data();
                serializer.write_processing_instruction(&pi.target(), &data)
            },

            (IncludeNode, NodeTypeId::DocumentFragment) => Ok(()),

            (IncludeNode, NodeTypeId::Document) => panic!("Can't serialize Document node itself"),
        }
    }
}

pub fn parse_html(document: JSRef<Document>,
                  input: HTMLInput,
                  url: &Url,
                  fragment_context: Option<FragmentContext>) {
    let parser = match fragment_context {
        None => ServoHTMLParser::new(Some(url.clone()), document).root(),
        Some(fc) => ServoHTMLParser::new_for_fragment(Some(url.clone()), document, fc).root(),
    };
    let parser: JSRef<ServoHTMLParser> = parser.r();

    let nested_parse = task_state::get().contains(task_state::IN_HTML_PARSER);
    if !nested_parse {
        task_state::enter(IN_HTML_PARSER);
    }

    fn parse_progress(parser: &JSRef<ServoHTMLParser>, url: &Url, load_response: &LoadResponse) {
        for msg in load_response.progress_port.iter() {
            match msg {
                ProgressMsg::Payload(data) => {
                    // FIXME: use Vec<u8> (html5ever #34)
                    let data = UTF_8.decode(data.as_slice(), DecoderTrap::Replace).unwrap();
                    parser.parse_chunk(data);
                }
                ProgressMsg::Done(Err(err)) => {
                    debug!("Failed to load page URL {}, error: {}", url.serialize(), err);
                    // TODO(Savago): we should send a notification to callers #5463.
                    break;
                }
                ProgressMsg::Done(Ok(())) => break,
            }
        }
    };

    match input {
        HTMLInput::InputString(s) => {
            parser.parse_chunk(s);
        }
        HTMLInput::InputUrl(load_response) => {
            match load_response.metadata.content_type {
                Some(ContentType(Mime(TopLevel::Image, _, _))) => {
                    let page = format!("", url.serialize());
                    parser.parse_chunk(page);
                },
                Some(ContentType(Mime(TopLevel::Text, SubLevel::Plain, _))) => {
                    // FIXME: When servo/html5ever#109 is fixed remove <plaintext> usage and
                    // replace with fix from that issue.

                    // text/plain documents require setting the tokenizer into PLAINTEXT mode.
                    // This is done by using a <plaintext> element as the html5ever tokenizer
                    // provides no other way to change to that state.
                    // Spec for text/plain handling is:
                    // https://html.spec.whatwg.org/multipage/#read-text
                    let page = format!("
\u{000A}<plaintext>");
                    parser.parse_chunk(page);
                    parse_progress(&parser, url, &load_response);
                },
                _ => {
                    parse_progress(&parser, url, &load_response);
                }
            }
        }
    }

    parser.finish();

    if !nested_parse {
        task_state::exit(IN_HTML_PARSER);
    }

    debug!("finished parsing");
}

// https://html.spec.whatwg.org/multipage/#parsing-html-fragments
pub fn parse_html_fragment(context_node: JSRef<Node>,
                           input: DOMString,
                           output: &mut RootedVec<JS<Node>>) {
    let window = window_from_node(context_node).root();
    let context_document = document_from_node(context_node).root();
    let url = context_document.r().url();

    // Step 1.
    let document = Document::new(window.r(), Some(url.clone()),
                                 IsHTMLDocument::HTMLDocument,
                                 None, None,
                                 DocumentSource::FromParser).root();

    // Step 2.
    document.r().set_quirks_mode(context_document.r().quirks_mode());

    // Step 11.
    let form = context_node.inclusive_ancestors()
                           .map(|element| element.root())
                           .find(|element| element.r().is_htmlformelement());
    let fragment_context = FragmentContext {
        context_elem: context_node,
        form_elem: form.r(),
    };
    parse_html(document.r(), HTMLInput::InputString(input), &url, Some(fragment_context));

    // Step 14.
    let root_element = document.r().GetDocumentElement().expect("no document element").root();
    let root_node: JSRef<Node> = NodeCast::from_ref(root_element.r());
    for child in root_node.children() {
        output.push(JS::from_rooted(child));
    }
}
<commit_msg>Auto merge of #5744 - dhananjay92:Issue#5738, r=Manishearth<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![allow(unsafe_code, unrooted_must_root)]

use dom::attr::AttrHelpers;
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use dom::bindings::codegen::Bindings::NodeBinding::NodeMethods;
use dom::bindings::codegen::InheritTypes::{CharacterDataCast, DocumentTypeCast};
use dom::bindings::codegen::InheritTypes::{ElementCast, HTMLScriptElementCast};
use dom::bindings::codegen::InheritTypes::{HTMLFormElementDerived, NodeCast};
use dom::bindings::codegen::InheritTypes::ProcessingInstructionCast;
use dom::bindings::js::{JS, JSRef, Temporary, OptionalRootable, Root};
use dom::bindings::js::RootedReference;
use dom::bindings::trace::RootedVec;
use dom::characterdata::CharacterDataHelpers;
use dom::comment::Comment;
use dom::document::{Document, DocumentHelpers};
use dom::document::{DocumentSource, IsHTMLDocument};
use dom::documenttype::DocumentType;
use dom::element::{Element, AttributeHandlers, ElementHelpers, ElementCreator};
use dom::htmlscriptelement::HTMLScriptElement;
use dom::htmlscriptelement::HTMLScriptElementHelpers;
use dom::node::{Node, NodeHelpers, NodeTypeId};
use dom::node::{document_from_node, window_from_node};
use dom::processinginstruction::ProcessingInstruction;
use dom::processinginstruction::ProcessingInstructionHelpers;
use dom::servohtmlparser;
use dom::servohtmlparser::{ServoHTMLParser, FragmentContext};
use dom::text::Text;
use parse::Parser;

use encoding::all::UTF_8;
use encoding::types::{Encoding, DecoderTrap};

use net_traits::{ProgressMsg, LoadResponse};
use util::str::DOMString;
use util::task_state;
use util::task_state::IN_HTML_PARSER;
use std::borrow::Cow;
use std::old_io::{Writer, IoResult};
use url::Url;
use html5ever::Attribute;
use html5ever::serialize::{Serializable, Serializer, AttrRef};
use html5ever::serialize::TraversalScope;
use html5ever::serialize::TraversalScope::{IncludeNode, ChildrenOnly};
use html5ever::tree_builder::{TreeSink, QuirksMode, NodeOrText, AppendNode, AppendText};
use string_cache::QualName;

use hyper::header::ContentType;
use hyper::mime::{Mime, TopLevel, SubLevel};

pub enum HTMLInput {
    InputString(String),
    InputUrl(LoadResponse),
}

trait SinkHelpers {
    fn get_or_create(&self, child: NodeOrText<JS<Node>>) -> Temporary<Node>;
}

impl SinkHelpers for servohtmlparser::Sink {
    fn get_or_create(&self, child: NodeOrText<JS<Node>>) -> Temporary<Node> {
        match child {
            AppendNode(n) => Temporary::new(n),
            AppendText(t) => {
                let doc = self.document.root();
                let text = Text::new(t, doc.r());
                NodeCast::from_temporary(text)
            }
        }
    }
}

impl<'a> TreeSink for servohtmlparser::Sink {
    type Handle = JS<Node>;
    fn get_document(&mut self) -> JS<Node> {
        let doc = self.document.root();
        let node: JSRef<Node> = NodeCast::from_ref(doc.r());
        JS::from_rooted(node)
    }

    fn same_node(&self, x: JS<Node>, y: JS<Node>) -> bool {
        x == y
    }

    fn elem_name(&self, target: JS<Node>) -> QualName {
        let node: Root<Node> = target.root();
        let elem: JSRef<Element> = ElementCast::to_ref(node.r())
            .expect("tried to get name of non-Element in HTML parsing");
        QualName {
            ns: elem.namespace().clone(),
            local: elem.local_name().clone(),
        }
    }

    fn create_element(&mut self, name: QualName, attrs: Vec<Attribute>)
            -> JS<Node> {
        let doc = self.document.root();
        let elem = Element::create(name, None, doc.r(),
                                   ElementCreator::ParserCreated).root();

        for attr in attrs.into_iter() {
            elem.r().set_attribute_from_parser(attr.name, attr.value, None);
        }

        let node: JSRef<Node> = NodeCast::from_ref(elem.r());
        JS::from_rooted(node)
    }

    fn create_comment(&mut self, text: String) -> JS<Node> {
        let doc = self.document.root();
        let comment = Comment::new(text, doc.r());
        let node: Root<Node> = NodeCast::from_temporary(comment).root();
        JS::from_rooted(node.r())
    }

    fn append_before_sibling(&mut self,
            sibling: JS<Node>,
            new_node: NodeOrText<JS<Node>>) -> Result<(), NodeOrText<JS<Node>>> {
        // If there is no parent, return the node to the parser.
        let sibling: Root<Node> = sibling.root();
        let parent = match sibling.r().parent_node() {
            Some(p) => p.root(),
            None => return Err(new_node),
        };

        let child = self.get_or_create(new_node).root();
        assert!(parent.r().InsertBefore(child.r(), Some(sibling.r())).is_ok());
        Ok(())
    }

    fn parse_error(&mut self, msg: Cow<'static, str>) {
        debug!("Parse error: {}", msg);
    }

    fn set_quirks_mode(&mut self, mode: QuirksMode) {
        let doc = self.document.root();
        doc.r().set_quirks_mode(mode);
    }

    fn append(&mut self, parent: JS<Node>, child: NodeOrText<JS<Node>>) {
        let parent: Root<Node> = parent.root();
        let child = self.get_or_create(child).root();

        // FIXME(#3701): Use a simpler algorithm and merge adjacent text nodes
        assert!(parent.r().AppendChild(child.r()).is_ok());
    }

    fn append_doctype_to_document(&mut self, name: String, public_id: String, system_id: String) {
        let doc = self.document.root();
        let doc_node: JSRef<Node> = NodeCast::from_ref(doc.r());
        let doctype = DocumentType::new(name, Some(public_id), Some(system_id), doc.r());
        let node: Root<Node> = NodeCast::from_temporary(doctype).root();

        assert!(doc_node.AppendChild(node.r()).is_ok());
    }

    fn add_attrs_if_missing(&mut self, target: JS<Node>, attrs: Vec<Attribute>) {
        let node: Root<Node> = target.root();
        let elem: JSRef<Element> = ElementCast::to_ref(node.r())
            .expect("tried to set attrs on non-Element in HTML parsing");
        for attr in attrs.into_iter() {
            elem.set_attribute_from_parser(attr.name, attr.value, None);
        }
    }

    fn remove_from_parent(&mut self, _target: JS<Node>) {
        error!("remove_from_parent not implemented!");
    }

    fn mark_script_already_started(&mut self, node: JS<Node>) {
        let node: Root<Node> = node.root();
        let script: Option<JSRef<HTMLScriptElement>> = HTMLScriptElementCast::to_ref(node.r());
        script.map(|script| script.mark_already_started());
    }

    fn complete_script(&mut self, node: JS<Node>) {
        let node: Root<Node> = node.root();
        let script: Option<JSRef<HTMLScriptElement>> = HTMLScriptElementCast::to_ref(node.r());
        script.map(|script| script.prepare());
    }

    fn reparent_children(&mut self, _node: JS<Node>, _new_parent: JS<Node>) {
        panic!("unimplemented")
    }
}

impl<'a> Serializable for JSRef<'a, Node> {
    fn serialize<'wr, Wr: Writer>(&self, serializer: &mut Serializer<'wr, Wr>,
                                  traversal_scope: TraversalScope) -> IoResult<()> {
        let node = *self;
        match (traversal_scope, node.type_id()) {
            (_, NodeTypeId::Element(..)) => {
                let elem: JSRef<Element> = ElementCast::to_ref(node).unwrap();
                let name = QualName::new(elem.namespace().clone(),
                                         elem.local_name().clone());
                if traversal_scope == IncludeNode {
                    let attrs = elem.attrs().iter().map(|at| {
                        let attr = at.root();
                        let qname = QualName::new(attr.r().namespace().clone(),
                                                  attr.r().local_name().clone());
                        let value = attr.r().value().clone();
                        (qname, value)
                    }).collect::<Vec<_>>();
                    let attr_refs = attrs.iter().map(|&(ref qname, ref value)| {
                        let ar: AttrRef = (&qname, value.as_slice());
                        ar
                    });
                    try!(serializer.start_elem(name.clone(), attr_refs));
                }

                for handle in node.children() {
                    let handle = handle.root();
                    try!(handle.r().serialize(serializer, IncludeNode));
                }

                if traversal_scope == IncludeNode {
                    try!(serializer.end_elem(name.clone()));
                }
                Ok(())
            },

            (ChildrenOnly, NodeTypeId::Document) => {
                for handle in node.children() {
                    let handle = handle.root();
                    try!(handle.r().serialize(serializer, IncludeNode));
                }
                Ok(())
            },

            (ChildrenOnly, _) => Ok(()),

            (IncludeNode, NodeTypeId::DocumentType) => {
                let doctype: JSRef<DocumentType> = DocumentTypeCast::to_ref(node).unwrap();
                serializer.write_doctype(doctype.name().as_slice())
            },

            (IncludeNode, NodeTypeId::Text) => {
                let cdata = CharacterDataCast::to_ref(node).unwrap();
                serializer.write_text(&cdata.data())
            },

            (IncludeNode, NodeTypeId::Comment) => {
                let cdata = CharacterDataCast::to_ref(node).unwrap();
                serializer.write_comment(&cdata.data())
            },

            (IncludeNode, NodeTypeId::ProcessingInstruction) => {
                let pi: JSRef<ProcessingInstruction> = ProcessingInstructionCast::to_ref(node).unwrap();
                let data = CharacterDataCast::from_ref(pi).data();
                serializer.write_processing_instruction(&pi.target(), &data)
            },

            (IncludeNode, NodeTypeId::DocumentFragment) => Ok(()),

            (IncludeNode, NodeTypeId::Document) => panic!("Can't serialize Document node itself"),
        }
    }
}

pub fn parse_html(document: JSRef<Document>,
                  input: HTMLInput,
                  url: &Url,
                  fragment_context: Option<FragmentContext>) {
    let parser = match fragment_context {
        None => ServoHTMLParser::new(Some(url.clone()), document).root(),
        Some(fc) => ServoHTMLParser::new_for_fragment(Some(url.clone()), document, fc).root(),
    };
    let parser: JSRef<ServoHTMLParser> = parser.r();

    let nested_parse = task_state::get().contains(task_state::IN_HTML_PARSER);
    if !nested_parse {
        task_state::enter(IN_HTML_PARSER);
    }

    fn parse_progress(parser: JSRef<ServoHTMLParser>, url: &Url, load_response: &LoadResponse) {
        for msg in load_response.progress_port.iter() {
            match msg {
                ProgressMsg::Payload(data) => {
                    // FIXME: use Vec<u8> (html5ever #34)
                    let data = UTF_8.decode(data.as_slice(), DecoderTrap::Replace).unwrap();
                    parser.parse_chunk(data);
                }
                ProgressMsg::Done(Err(err)) => {
                    debug!("Failed to load page URL {}, error: {}", url.serialize(), err);
                    // TODO(Savago): we should send a notification to callers #5463.
                    break;
                }
                ProgressMsg::Done(Ok(())) => break,
            }
        }
    };

    match input {
        HTMLInput::InputString(s) => {
            parser.parse_chunk(s);
        }
        HTMLInput::InputUrl(load_response) => {
            match load_response.metadata.content_type {
                Some(ContentType(Mime(TopLevel::Image, _, _))) => {
                    let page = format!("", url.serialize());
                    parser.parse_chunk(page);
                },
                Some(ContentType(Mime(TopLevel::Text, SubLevel::Plain, _))) => {
                    // FIXME: When servo/html5ever#109 is fixed remove <plaintext> usage and
                    // replace with fix from that issue.

                    // text/plain documents require setting the tokenizer into PLAINTEXT mode.
                    // This is done by using a <plaintext> element as the html5ever tokenizer
                    // provides no other way to change to that state.
                    // Spec for text/plain handling is:
                    // https://html.spec.whatwg.org/multipage/#read-text
                    let page = format!("
\u{000A}<plaintext>");
                    parser.parse_chunk(page);
                    parse_progress(parser, url, &load_response);
                },
                _ => {
                    parse_progress(parser, url, &load_response);
                }
            }
        }
    }

    parser.finish();

    if !nested_parse {
        task_state::exit(IN_HTML_PARSER);
    }

    debug!("finished parsing");
}

// https://html.spec.whatwg.org/multipage/#parsing-html-fragments
pub fn parse_html_fragment(context_node: JSRef<Node>,
                           input: DOMString,
                           output: &mut RootedVec<JS<Node>>) {
    let window = window_from_node(context_node).root();
    let context_document = document_from_node(context_node).root();
    let url = context_document.r().url();

    // Step 1.
    let document = Document::new(window.r(), Some(url.clone()),
                                 IsHTMLDocument::HTMLDocument,
                                 None, None,
                                 DocumentSource::FromParser).root();

    // Step 2.
    document.r().set_quirks_mode(context_document.r().quirks_mode());

    // Step 11.
    let form = context_node.inclusive_ancestors()
                           .map(|element| element.root())
                           .find(|element| element.r().is_htmlformelement());
    let fragment_context = FragmentContext {
        context_elem: context_node,
        form_elem: form.r(),
    };
    parse_html(document.r(), HTMLInput::InputString(input), &url, Some(fragment_context));

    // Step 14.
    let root_element = document.r().GetDocumentElement().expect("no document element").root();
    let root_node: JSRef<Node> = NodeCast::from_ref(root_element.r());
    for child in root_node.children() {
        output.push(JS::from_rooted(child));
    }
}
<|endoftext|>


<commit_before>
extern crate num_traits;
extern crate ndarray;
extern crate lapack;

use ndarray::prelude::*;
use lapack::fortran::*;
use num_traits::Zero;

pub trait Matrix: Sized {
    type Vector;
    // fn svd(self) -> (Self, Self::Vector, Self);
}

pub trait SquareMatrix: Matrix {
    // fn qr(self) -> (Self, Self);
    // fn lu(self) -> (Self, Self);
    // fn eig(self) -> (Self::Vector, Self);
    /// eigenvalue decomposition for Hermite matrix
    fn eigh(self) -> Option<(Self::Vector, Self)>;
}

impl<A> Matrix for Array<A, (Ix, Ix)> {
    type Vector = Array<A, Ix>;
}

pub trait Eigh: Sized {
    fn syev(i32, &mut [Self]) -> Option<Vec<Self>>;
}

impl Eigh for f64 {
    fn syev(n: i32, a: &mut [f64]) -> Option<Vec<f64>> {
        let mut w = vec![0.0; n as usize];
        let mut work = vec![0.0; 4 * n as usize];
        let mut info = 0;
        dsyev(b'V', b'U', n, a, n, &mut w, &mut work, 4 * n, &mut info);
        if info == 0 { Some(w) } else { None }
    }
}

impl Eigh for f32 {
    fn syev(n: i32, a: &mut [f32]) -> Option<Vec<f32>> {
        let mut w = vec![0.0; n as usize];
        let mut work = vec![0.0; 4 * n as usize];
        let mut info = 0;
        ssyev(b'V', b'U', n, a, n, &mut w, &mut work, 4 * n, &mut info);
        if info == 0 { Some(w) } else { None }
    }
}

impl<A> SquareMatrix for Array<A, (Ix, Ix)>
    where A: Eigh + Clone + Zero
{
    fn eigh(self) -> Option<(Self::Vector, Self)> {
        let rows = self.rows();
        let cols = self.cols();
        if rows != cols {
            return None;
        }
        assert_eq!(rows, cols);

        let mut a = self.into_raw_vec();
        let w = match Eigh::syev(rows as i32, &mut a) {
            Some(w) => w,
            None => return None,
        };

        let ea = Array::from_vec(w);
        let va = Array::from_vec(a).into_shape((rows, cols)).unwrap();
        Some((ea, va))
    }
}
<commit_msg>Remove unused assert<commit_after>
extern crate num_traits;
extern crate ndarray;
extern crate lapack;

use ndarray::prelude::*;
use lapack::fortran::*;
use num_traits::Zero;

pub trait Matrix: Sized {
    type Vector;
    // fn svd(self) -> (Self, Self::Vector, Self);
}

pub trait SquareMatrix: Matrix {
    // fn qr(self) -> (Self, Self);
    // fn lu(self) -> (Self, Self);
    // fn eig(self) -> (Self::Vector, Self);
    /// eigenvalue decomposition for Hermite matrix
    fn eigh(self) -> Option<(Self::Vector, Self)>;
}

impl<A> Matrix for Array<A, (Ix, Ix)> {
    type Vector = Array<A, Ix>;
}

pub trait Eigh: Sized {
    fn syev(i32, &mut [Self]) -> Option<Vec<Self>>;
}

impl Eigh for f64 {
    fn syev(n: i32, a: &mut [f64]) -> Option<Vec<f64>> {
        let mut w = vec![0.0; n as usize];
        let mut work = vec![0.0; 4 * n as usize];
        let mut info = 0;
        dsyev(b'V', b'U', n, a, n, &mut w, &mut work, 4 * n, &mut info);
        if info == 0 { Some(w) } else { None }
    }
}

impl Eigh for f32 {
    fn syev(n: i32, a: &mut [f32]) -> Option<Vec<f32>> {
        let mut w = vec![0.0; n as usize];
        let mut work = vec![0.0; 4 * n as usize];
        let mut info = 0;
        ssyev(b'V', b'U', n, a, n, &mut w, &mut work, 4 * n, &mut info);
        if info == 0 { Some(w) } else { None }
    }
}

impl<A> SquareMatrix for Array<A, (Ix, Ix)>
    where A: Eigh + Clone + Zero
{
    fn eigh(self) -> Option<(Self::Vector, Self)> {
        let rows = self.rows();
        let cols = self.cols();
        if rows != cols {
            return None;
        }

        let mut a = self.into_raw_vec();
        let w = match Eigh::syev(rows as i32, &mut a) {
            Some(w) => w,
            None => return None,
        };

        let ea = Array::from_vec(w);
        let va = Array::from_vec(a).into_shape((rows, cols)).unwrap();
        Some((ea, va))
    }
}
<|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/. */

//! Helper module to build up a selector safely and efficiently.
//!
//! Our selector representation is designed to optimize matching, and has
//! several requirements:
//! * All simple selectors and combinators are stored inline in the same buffer
//!   as Component instances.
//! * We store the top-level compound selectors from right to left, i.e. in
//!   matching order.
//! * We store the simple selectors for each combinator from left to right, so
//!   that we match the cheaper simple selectors first.
//!
//! Meeting all these constraints without extra memmove traffic during parsing
//! is non-trivial. This module encapsulates those details and presents an
//! easy-to-use API for the parser.

use parser::{Combinator, Component, SelectorImpl};
use servo_arc::{Arc, HeaderWithLength, ThinArc};
use sink::Push;
use smallvec::{self, SmallVec};
use std::cmp;
use std::iter;
use std::ops::{AddAssign, Add};
use std::ptr;
use std::slice;

/// Top-level SelectorBuilder struct. This should be stack-allocated by the
/// consumer and never moved (because it contains a lot of inline data that
/// would be slow to memmov).
///
/// After instantation, callers may call the push_simple_selector() and
/// push_combinator() methods to append selector data as it is encountered
/// (from left to right). Once the process is complete, callers should invoke
/// build(), which transforms the contents of the SelectorBuilder into a heap-
/// allocated Selector and leaves the builder in a drained state.
#[derive(Debug)]
pub struct SelectorBuilder<Impl: SelectorImpl> {
    /// The entire sequence of simple selectors, from left to right, without combinators.
    ///
    /// We make this large because the result of parsing a selector is fed into a new
    /// Arc-ed allocation, so any spilled vec would be a wasted allocation. Also,
    /// Components are large enough that we don't have much cache locality benefit
    /// from reserving stack space for fewer of them.
    simple_selectors: SmallVec<[Component<Impl>; 32]>,
    /// The combinators, and the length of the compound selector to their left.
    combinators: SmallVec<[(Combinator, usize); 16]>,
    /// The length of the current compount selector.
    current_len: usize,
}

impl<Impl: SelectorImpl> Default for SelectorBuilder<Impl> {
    #[inline(always)]
    fn default() -> Self {
        SelectorBuilder {
            simple_selectors: SmallVec::new(),
            combinators: SmallVec::new(),
            current_len: 0,
        }
    }
}

impl<Impl: SelectorImpl> Push<Component<Impl>> for SelectorBuilder<Impl> {
    fn push(&mut self, value: Component<Impl>) {
        self.push_simple_selector(value);
    }
}

impl<Impl: SelectorImpl> SelectorBuilder<Impl> {
    /// Pushes a simple selector onto the current compound selector.
    #[inline(always)]
    pub fn push_simple_selector(&mut self, ss: Component<Impl>) {
        debug_assert!(!ss.is_combinator());
        self.simple_selectors.push(ss);
        self.current_len += 1;
    }

    /// Completes the current compound selector and starts a new one, delimited
    /// by the given combinator.
    #[inline(always)]
    pub fn push_combinator(&mut self, c: Combinator) {
        self.combinators.push((c, self.current_len));
        self.current_len = 0;
    }

    /// Returns true if no simple selectors have ever been pushed to this builder.
    #[inline(always)]
    pub fn is_empty(&self) -> bool {
        self.simple_selectors.is_empty()
    }

    /// Returns true if combinators have ever been pushed to this builder.
    #[inline(always)]
    pub fn has_combinators(&self) -> bool {
        !self.combinators.is_empty()
    }

    /// Consumes the builder, producing a Selector.
    #[inline(always)]
    pub fn build(
        &mut self,
        parsed_pseudo: bool,
        parsed_slotted: bool,
    ) -> ThinArc<SpecificityAndFlags, Component<Impl>> {
        // Compute the specificity and flags.
        let mut spec = SpecificityAndFlags(specificity(&*self, self.simple_selectors.iter()));
        if parsed_pseudo {
            spec.0 |= HAS_PSEUDO_BIT;
        }

        if parsed_slotted {
            spec.0 |= HAS_SLOTTED_BIT;
        }

        self.build_with_specificity_and_flags(spec)
    }

    /// Builds with an explicit SpecificityAndFlags. This is separated from build() so
    /// that unit tests can pass an explicit specificity.
    #[inline(always)]
    pub fn build_with_specificity_and_flags(
        &mut self,
        spec: SpecificityAndFlags,
    ) -> ThinArc<SpecificityAndFlags, Component<Impl>> {
        // First, compute the total number of Components we'll need to allocate
        // space for.
        let full_len = self.simple_selectors.len() + self.combinators.len();

        // Create the header.
        let header = HeaderWithLength::new(spec, full_len);

        // Create the Arc using an iterator that drains our buffers.

        // Use a raw pointer to be able to call set_len despite "borrowing" the slice.
        // This is similar to SmallVec::drain, but we use a slice here because
        // we’re gonna traverse it non-linearly.
        let raw_simple_selectors: *const [Component<Impl>] = &*self.simple_selectors;
        unsafe {
            // Panic-safety: if SelectorBuilderIter is not iterated to the end,
            // some simple selectors will safely leak.
            self.simple_selectors.set_len(0)
        }
        let (rest, current) = split_from_end(unsafe { &*raw_simple_selectors }, self.current_len);
        let iter = SelectorBuilderIter {
            current_simple_selectors: current.iter(),
            rest_of_simple_selectors: rest,
            combinators: self.combinators.drain().rev(),
        };

        Arc::into_thin(Arc::from_header_and_iter(header, iter))
    }
}

struct SelectorBuilderIter<'a, Impl: SelectorImpl> {
    current_simple_selectors: slice::Iter<'a, Component<Impl>>,
    rest_of_simple_selectors: &'a [Component<Impl>],
    combinators: iter::Rev<smallvec::Drain<'a, (Combinator, usize)>>,
}

impl<'a, Impl: SelectorImpl> ExactSizeIterator for SelectorBuilderIter<'a, Impl> {
    fn len(&self) -> usize {
        self.current_simple_selectors.len() +
            self.rest_of_simple_selectors.len() +
            self.combinators.len()
    }
}

impl<'a, Impl: SelectorImpl> Iterator for SelectorBuilderIter<'a, Impl> {
    type Item = Component<Impl>;
    #[inline(always)]
    fn next(&mut self) -> Option<Self::Item> {
        if let Some(simple_selector_ref) = self.current_simple_selectors.next() {
            // Move a simple selector out of this slice iterator.
            // This is safe because we’ve called SmallVec::set_len(0) above,
            // so SmallVec::drop won’t drop this simple selector.
            unsafe { Some(ptr::read(simple_selector_ref)) }
        } else {
            self.combinators.next().map(|(combinator, len)| {
                let (rest, current) = split_from_end(self.rest_of_simple_selectors, len);
                self.rest_of_simple_selectors = rest;
                self.current_simple_selectors = current.iter();
                Component::Combinator(combinator)
            })
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.len(), Some(self.len()))
    }
}

fn split_from_end<T>(s: &[T], at: usize) -> (&[T], &[T]) {
    s.split_at(s.len() - at)
}

pub const HAS_PSEUDO_BIT: u32 = 1 << 30;
pub const HAS_SLOTTED_BIT: u32 = 1 << 31;

/// We use ten bits for each specificity kind (id, class, element), and the two
/// high bits for the pseudo and slotted flags.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct SpecificityAndFlags(pub u32);

impl SpecificityAndFlags {
    #[inline]
    pub fn specificity(&self) -> u32 {
        self.0 & !(HAS_PSEUDO_BIT | HAS_SLOTTED_BIT)
    }

    #[inline]
    pub fn has_pseudo_element(&self) -> bool {
        (self.0 & HAS_PSEUDO_BIT) != 0
    }

    #[inline]
    pub fn is_slotted(&self) -> bool {
        (self.0 & HAS_SLOTTED_BIT) != 0
    }
}

const MAX_10BIT: u32 = (1u32 << 10) - 1;

#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
struct Specificity {
    id_selectors: u32,
    class_like_selectors: u32,
    element_selectors: u32,
}

impl AddAssign for Specificity {
    #[inline]
    fn add_assign(&mut self, rhs: Self) {
        self.id_selectors += rhs.id_selectors;
        self.class_like_selectors += rhs.class_like_selectors;
        self.element_selectors += rhs.element_selectors;
    }
}

impl Add for Specificity {
    type Output = Specificity;

    fn add(self, rhs: Specificity) -> Specificity {
        Specificity {
            id_selectors: self.id_selectors + rhs.id_selectors,
            class_like_selectors: self.class_like_selectors + rhs.class_like_selectors,
            element_selectors: self.element_selectors + rhs.element_selectors,
        }
    }
}

impl Default for Specificity {
    fn default() -> Specificity {
        Specificity {
            id_selectors: 0,
            class_like_selectors: 0,
            element_selectors: 0,
        }
    }
}

impl From<u32> for Specificity {
    #[inline]
    fn from(value: u32) -> Specificity {
        assert!(value <= MAX_10BIT << 20 | MAX_10BIT << 10 | MAX_10BIT);
        Specificity {
            id_selectors: value >> 20,
            class_like_selectors: (value >> 10) & MAX_10BIT,
            element_selectors: value & MAX_10BIT,
        }
    }
}

impl From<Specificity> for u32 {
    #[inline]
    fn from(specificity: Specificity) -> u32 {
        cmp::min(specificity.id_selectors, MAX_10BIT) << 20 |
            cmp::min(specificity.class_like_selectors, MAX_10BIT) << 10 |
            cmp::min(specificity.element_selectors, MAX_10BIT)
    }
}

fn specificity<Impl>(builder: &SelectorBuilder<Impl>, iter: slice::Iter<Component<Impl>>) -> u32
where
    Impl: SelectorImpl,
{
    complex_selector_specificity(builder, iter).into()
}

fn complex_selector_specificity<Impl>(
    builder: &SelectorBuilder<Impl>,
    mut iter: slice::Iter<Component<Impl>>,
) -> Specificity
where
    Impl: SelectorImpl,
{
    fn simple_selector_specificity<Impl>(
        builder: &SelectorBuilder<Impl>,
        simple_selector: &Component<Impl>,
        specificity: &mut Specificity,
    ) where
        Impl: SelectorImpl,
    {
        match *simple_selector {
            Component::Combinator(ref combinator) => {
                unreachable!(
                    "Found combinator {:?} in simple selectors vector? {:?}",
                    combinator, builder,
                );
            },
            Component::PseudoElement(..) | Component::LocalName(..) => {
                specificity.element_selectors += 1
            },
            Component::Slotted(ref selector) => {
                specificity.element_selectors += 1;
                // Note that due to the way ::slotted works we only compete with
                // other ::slotted rules, so the above rule doesn't really
                // matter, but we do it still for consistency with other
                // pseudo-elements.
                //
                // See: https://github.com/w3c/csswg-drafts/issues/1915
                *specificity += Specificity::from(selector.specificity());
            },
            Component::Host(ref selector) => {
                specificity.class_like_selectors += 1;
                if let Some(ref selector) = *selector {
                    // See: https://github.com/w3c/csswg-drafts/issues/1915
                    *specificity += Specificity::from(selector.specificity());
                }
            },
            Component::ID(..) => {
                specificity.id_selectors += 1;
            },
            Component::Class(..) |
            Component::AttributeInNoNamespace { .. } |
            Component::AttributeInNoNamespaceExists { .. } |
            Component::AttributeOther(..) |
            Component::FirstChild |
            Component::LastChild |
            Component::OnlyChild |
            Component::Root |
            Component::Empty |
            Component::Scope |
            Component::NthChild(..) |
            Component::NthLastChild(..) |
            Component::NthOfType(..) |
            Component::NthLastOfType(..) |
            Component::FirstOfType |
            Component::LastOfType |
            Component::OnlyOfType |
            Component::NonTSPseudoClass(..) => {
                specificity.class_like_selectors += 1;
            },
            Component::ExplicitUniversalType |
            Component::ExplicitAnyNamespace |
            Component::ExplicitNoNamespace |
            Component::DefaultNamespace(..) |
            Component::Namespace(..) => {
                // Does not affect specificity
            },
            Component::Negation(ref negated) => {
                for ss in negated.iter() {
                    simple_selector_specificity(builder, &ss, specificity);
                }
            },
        }
    }

    let mut specificity = Default::default();
    for simple_selector in &mut iter {
        simple_selector_specificity(builder, &simple_selector, &mut specificity);
    }
    specificity
}
<commit_msg>style: Back out diagnostics for not being helpful enough at diagnosing.<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/. */

//! Helper module to build up a selector safely and efficiently.
//!
//! Our selector representation is designed to optimize matching, and has
//! several requirements:
//! * All simple selectors and combinators are stored inline in the same buffer
//!   as Component instances.
//! * We store the top-level compound selectors from right to left, i.e. in
//!   matching order.
//! * We store the simple selectors for each combinator from left to right, so
//!   that we match the cheaper simple selectors first.
//!
//! Meeting all these constraints without extra memmove traffic during parsing
//! is non-trivial. This module encapsulates those details and presents an
//! easy-to-use API for the parser.

use parser::{Combinator, Component, SelectorImpl};
use servo_arc::{Arc, HeaderWithLength, ThinArc};
use sink::Push;
use smallvec::{self, SmallVec};
use std::cmp;
use std::iter;
use std::ops::{AddAssign, Add};
use std::ptr;
use std::slice;

/// Top-level SelectorBuilder struct. This should be stack-allocated by the
/// consumer and never moved (because it contains a lot of inline data that
/// would be slow to memmov).
///
/// After instantation, callers may call the push_simple_selector() and
/// push_combinator() methods to append selector data as it is encountered
/// (from left to right). Once the process is complete, callers should invoke
/// build(), which transforms the contents of the SelectorBuilder into a heap-
/// allocated Selector and leaves the builder in a drained state.
#[derive(Debug)]
pub struct SelectorBuilder<Impl: SelectorImpl> {
    /// The entire sequence of simple selectors, from left to right, without combinators.
    ///
    /// We make this large because the result of parsing a selector is fed into a new
    /// Arc-ed allocation, so any spilled vec would be a wasted allocation. Also,
    /// Components are large enough that we don't have much cache locality benefit
    /// from reserving stack space for fewer of them.
    simple_selectors: SmallVec<[Component<Impl>; 32]>,
    /// The combinators, and the length of the compound selector to their left.
    combinators: SmallVec<[(Combinator, usize); 16]>,
    /// The length of the current compount selector.
    current_len: usize,
}

impl<Impl: SelectorImpl> Default for SelectorBuilder<Impl> {
    #[inline(always)]
    fn default() -> Self {
        SelectorBuilder {
            simple_selectors: SmallVec::new(),
            combinators: SmallVec::new(),
            current_len: 0,
        }
    }
}

impl<Impl: SelectorImpl> Push<Component<Impl>> for SelectorBuilder<Impl> {
    fn push(&mut self, value: Component<Impl>) {
        self.push_simple_selector(value);
    }
}

impl<Impl: SelectorImpl> SelectorBuilder<Impl> {
    /// Pushes a simple selector onto the current compound selector.
    #[inline(always)]
    pub fn push_simple_selector(&mut self, ss: Component<Impl>) {
        debug_assert!(!ss.is_combinator());
        self.simple_selectors.push(ss);
        self.current_len += 1;
    }

    /// Completes the current compound selector and starts a new one, delimited
    /// by the given combinator.
    #[inline(always)]
    pub fn push_combinator(&mut self, c: Combinator) {
        self.combinators.push((c, self.current_len));
        self.current_len = 0;
    }

    /// Returns true if no simple selectors have ever been pushed to this builder.
    #[inline(always)]
    pub fn is_empty(&self) -> bool {
        self.simple_selectors.is_empty()
    }

    /// Returns true if combinators have ever been pushed to this builder.
    #[inline(always)]
    pub fn has_combinators(&self) -> bool {
        !self.combinators.is_empty()
    }

    /// Consumes the builder, producing a Selector.
    #[inline(always)]
    pub fn build(
        &mut self,
        parsed_pseudo: bool,
        parsed_slotted: bool,
    ) -> ThinArc<SpecificityAndFlags, Component<Impl>> {
        // Compute the specificity and flags.
        let mut spec = SpecificityAndFlags(specificity(self.simple_selectors.iter()));
        if parsed_pseudo {
            spec.0 |= HAS_PSEUDO_BIT;
        }

        if parsed_slotted {
            spec.0 |= HAS_SLOTTED_BIT;
        }

        self.build_with_specificity_and_flags(spec)
    }

    /// Builds with an explicit SpecificityAndFlags. This is separated from build() so
    /// that unit tests can pass an explicit specificity.
    #[inline(always)]
    pub fn build_with_specificity_and_flags(
        &mut self,
        spec: SpecificityAndFlags,
    ) -> ThinArc<SpecificityAndFlags, Component<Impl>> {
        // First, compute the total number of Components we'll need to allocate
        // space for.
        let full_len = self.simple_selectors.len() + self.combinators.len();

        // Create the header.
        let header = HeaderWithLength::new(spec, full_len);

        // Create the Arc using an iterator that drains our buffers.

        // Use a raw pointer to be able to call set_len despite "borrowing" the slice.
        // This is similar to SmallVec::drain, but we use a slice here because
        // we’re gonna traverse it non-linearly.
        let raw_simple_selectors: *const [Component<Impl>] = &*self.simple_selectors;
        unsafe {
            // Panic-safety: if SelectorBuilderIter is not iterated to the end,
            // some simple selectors will safely leak.
            self.simple_selectors.set_len(0)
        }
        let (rest, current) = split_from_end(unsafe { &*raw_simple_selectors }, self.current_len);
        let iter = SelectorBuilderIter {
            current_simple_selectors: current.iter(),
            rest_of_simple_selectors: rest,
            combinators: self.combinators.drain().rev(),
        };

        Arc::into_thin(Arc::from_header_and_iter(header, iter))
    }
}

struct SelectorBuilderIter<'a, Impl: SelectorImpl> {
    current_simple_selectors: slice::Iter<'a, Component<Impl>>,
    rest_of_simple_selectors: &'a [Component<Impl>],
    combinators: iter::Rev<smallvec::Drain<'a, (Combinator, usize)>>,
}

impl<'a, Impl: SelectorImpl> ExactSizeIterator for SelectorBuilderIter<'a, Impl> {
    fn len(&self) -> usize {
        self.current_simple_selectors.len() +
            self.rest_of_simple_selectors.len() +
            self.combinators.len()
    }
}

impl<'a, Impl: SelectorImpl> Iterator for SelectorBuilderIter<'a, Impl> {
    type Item = Component<Impl>;
    #[inline(always)]
    fn next(&mut self) -> Option<Self::Item> {
        if let Some(simple_selector_ref) = self.current_simple_selectors.next() {
            // Move a simple selector out of this slice iterator.
            // This is safe because we’ve called SmallVec::set_len(0) above,
            // so SmallVec::drop won’t drop this simple selector.
            unsafe { Some(ptr::read(simple_selector_ref)) }
        } else {
            self.combinators.next().map(|(combinator, len)| {
                let (rest, current) = split_from_end(self.rest_of_simple_selectors, len);
                self.rest_of_simple_selectors = rest;
                self.current_simple_selectors = current.iter();
                Component::Combinator(combinator)
            })
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.len(), Some(self.len()))
    }
}

fn split_from_end<T>(s: &[T], at: usize) -> (&[T], &[T]) {
    s.split_at(s.len() - at)
}

pub const HAS_PSEUDO_BIT: u32 = 1 << 30;
pub const HAS_SLOTTED_BIT: u32 = 1 << 31;

/// We use ten bits for each specificity kind (id, class, element), and the two
/// high bits for the pseudo and slotted flags.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct SpecificityAndFlags(pub u32);

impl SpecificityAndFlags {
    #[inline]
    pub fn specificity(&self) -> u32 {
        self.0 & !(HAS_PSEUDO_BIT | HAS_SLOTTED_BIT)
    }

    #[inline]
    pub fn has_pseudo_element(&self) -> bool {
        (self.0 & HAS_PSEUDO_BIT) != 0
    }

    #[inline]
    pub fn is_slotted(&self) -> bool {
        (self.0 & HAS_SLOTTED_BIT) != 0
    }
}

const MAX_10BIT: u32 = (1u32 << 10) - 1;

#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
struct Specificity {
    id_selectors: u32,
    class_like_selectors: u32,
    element_selectors: u32,
}

impl AddAssign for Specificity {
    #[inline]
    fn add_assign(&mut self, rhs: Self) {
        self.id_selectors += rhs.id_selectors;
        self.class_like_selectors += rhs.class_like_selectors;
        self.element_selectors += rhs.element_selectors;
    }
}

impl Add for Specificity {
    type Output = Specificity;

    fn add(self, rhs: Specificity) -> Specificity {
        Specificity {
            id_selectors: self.id_selectors + rhs.id_selectors,
            class_like_selectors: self.class_like_selectors + rhs.class_like_selectors,
            element_selectors: self.element_selectors + rhs.element_selectors,
        }
    }
}

impl Default for Specificity {
    fn default() -> Specificity {
        Specificity {
            id_selectors: 0,
            class_like_selectors: 0,
            element_selectors: 0,
        }
    }
}

impl From<u32> for Specificity {
    #[inline]
    fn from(value: u32) -> Specificity {
        assert!(value <= MAX_10BIT << 20 | MAX_10BIT << 10 | MAX_10BIT);
        Specificity {
            id_selectors: value >> 20,
            class_like_selectors: (value >> 10) & MAX_10BIT,
            element_selectors: value & MAX_10BIT,
        }
    }
}

impl From<Specificity> for u32 {
    #[inline]
    fn from(specificity: Specificity) -> u32 {
        cmp::min(specificity.id_selectors, MAX_10BIT) << 20 |
            cmp::min(specificity.class_like_selectors, MAX_10BIT) << 10 |
            cmp::min(specificity.element_selectors, MAX_10BIT)
    }
}

fn specificity<Impl>(iter: slice::Iter<Component<Impl>>) -> u32
where
    Impl: SelectorImpl,
{
    complex_selector_specificity(iter).into()
}

fn complex_selector_specificity<Impl>(iter: slice::Iter<Component<Impl>>) -> Specificity
where
    Impl: SelectorImpl,
{
    fn simple_selector_specificity<Impl>(
        simple_selector: &Component<Impl>,
        specificity: &mut Specificity,
    ) where
        Impl: SelectorImpl,
    {
        match *simple_selector {
            Component::Combinator(..) => {
                unreachable!("Found combinator in simple selectors vector?");
            },
            Component::PseudoElement(..) | Component::LocalName(..) => {
                specificity.element_selectors += 1
            },
            Component::Slotted(ref selector) => {
                specificity.element_selectors += 1;
                // Note that due to the way ::slotted works we only compete with
                // other ::slotted rules, so the above rule doesn't really
                // matter, but we do it still for consistency with other
                // pseudo-elements.
                //
                // See: https://github.com/w3c/csswg-drafts/issues/1915
                *specificity += Specificity::from(selector.specificity());
            },
            Component::Host(ref selector) => {
                specificity.class_like_selectors += 1;
                if let Some(ref selector) = *selector {
                    // See: https://github.com/w3c/csswg-drafts/issues/1915
                    *specificity += Specificity::from(selector.specificity());
                }
            },
            Component::ID(..) => {
                specificity.id_selectors += 1;
            },
            Component::Class(..) |
            Component::AttributeInNoNamespace { .. } |
            Component::AttributeInNoNamespaceExists { .. } |
            Component::AttributeOther(..) |
            Component::FirstChild |
            Component::LastChild |
            Component::OnlyChild |
            Component::Root |
            Component::Empty |
            Component::Scope |
            Component::NthChild(..) |
            Component::NthLastChild(..) |
            Component::NthOfType(..) |
            Component::NthLastOfType(..) |
            Component::FirstOfType |
            Component::LastOfType |
            Component::OnlyOfType |
            Component::NonTSPseudoClass(..) => {
                specificity.class_like_selectors += 1;
            },
            Component::ExplicitUniversalType |
            Component::ExplicitAnyNamespace |
            Component::ExplicitNoNamespace |
            Component::DefaultNamespace(..) |
            Component::Namespace(..) => {
                // Does not affect specificity
            },
            Component::Negation(ref negated) => {
                for ss in negated.iter() {
                    simple_selector_specificity(&ss, specificity);
                }
            },
        }
    }

    let mut specificity = Default::default();
    for simple_selector in iter {
        simple_selector_specificity(&simple_selector, &mut specificity);
    }
    specificity
}
<|endoftext|>


<commit_before>#![feature(convert, clone_from_slice)]

extern crate ladspa;
extern crate mio;
extern crate rustc_serialize;
extern crate bincode;

mod receive;
mod transmit;
mod packet;

#[cfg(test)]
mod test;

use ladspa::PluginDescriptor;

use receive::Receiver;
use transmit::Transmitter;

const BASE_PORT: u16 = 21300;

#[no_mangle]
pub extern "C" fn get_ladspa_descriptor(index: u64) -> Option<PluginDescriptor> {
    match index {
        0 => Some(Transmitter::get_descriptor()),
        1 => Some(Receiver::get_descriptor()),
        _ => None,
    }
}
<commit_msg>fix warning<commit_after>#![feature(clone_from_slice)]
#[cfg_attr(test, feature(convert))]

extern crate ladspa;
extern crate mio;
extern crate rustc_serialize;
extern crate bincode;

mod receive;
mod transmit;
mod packet;

#[cfg(test)]
mod test;

use ladspa::PluginDescriptor;

use receive::Receiver;
use transmit::Transmitter;

const BASE_PORT: u16 = 21300;

#[no_mangle]
pub extern "C" fn get_ladspa_descriptor(index: u64) -> Option<PluginDescriptor> {
    match index {
        0 => Some(Transmitter::get_descriptor()),
        1 => Some(Receiver::get_descriptor()),
        _ => None,
    }
}
<|endoftext|>


<commit_before>#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

use libc::{c_int, c_char};
use std::ffi::{CString, CStr};
use std::borrow::{Cow};
use std::ptr;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::process::{Command, Stdio};
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::fmt;
use openssl::sign::Verifier;
use openssl::pkey::PKey;
use openssl::hash::MessageDigest;
use bindings::*;
use toml::Value;
use uuid::Uuid;

extern crate libc;
extern crate openssl;
extern crate toml;
extern crate uuid;

pub mod bindings;

fn get_user(pamh: *mut pam_handle_t, prompt: Option<&str>) -> Result<Cow<str>, i32> {
    let mut c_user: *const c_char = ptr::null();
    let c_prompt = match prompt {
        Some(prompt_str) => CString::new(prompt_str).unwrap().as_ptr(),
        None => ptr::null(),
    };
    let err;
    unsafe {
        err = pam_get_user(pamh, &mut c_user, c_prompt);
    }
    match err {
        PAM_SUCCESS => unsafe {
            let c_user_str = CStr::from_ptr(c_user);
            Ok(c_user_str.to_string_lossy())
        },
        err => Err(err),
    }
}

#[derive(Debug)]
enum ConfigError {
    Io(io::Error),
    Toml(toml::de::Error),
    MissingField(String),
    InvalidValueType(String),
}

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

impl From<toml::de::Error> for ConfigError {
    fn from(err: toml::de::Error) -> ConfigError {
        ConfigError::Toml(err)
    }
}

impl fmt::Display for ConfigError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ConfigError::Io(ref ioerr) => write!(f, "{}", ioerr),
            ConfigError::Toml(_) => write!(f, "TOML format error"),
            ConfigError::MissingField(_) => write!(f, "field: 'authenticator_path' is not found"),
            ConfigError::InvalidValueType(_) => write!(f, "field: 'authenticator_path' has an invalid value type"),
        }
    }
}

fn get_authenticator_path() -> Result<String, ConfigError> {
    let mut config_file = File::open("/etc/pam_wsl_hello/config")?;
    let mut config = String::new();
    config_file.read_to_string(&mut config)?;

    let config_value = config.parse::<Value>()?;
    let authenticator_path = config_value.get("authenticator_path")
        .ok_or(ConfigError::MissingField("authenticator_path".to_owned()))?
        .as_str()
        .ok_or(ConfigError::InvalidValueType("authenticator_path".to_owned()))?;
    Ok(authenticator_path.to_owned())
}

#[derive(Debug)]
enum HelloAuthenticationError {
    GetUserError(i32),
    ConfigError(ConfigError),
    PublicKeyFileError(io::Error),
    Io(io::Error),
    InvalidPublicKey(openssl::error::ErrorStack),
    OpenSSLError(openssl::error::ErrorStack),
    AuthenticatorLaunchError(io::Error),
    AuthenticatorConnectionError(io::Error),
    AuthenticatorSignalled,
    HelloAuthenticationFail(String),
    SignAuthenticationFail,
}

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

impl From<ConfigError> for HelloAuthenticationError {
    fn from(err: ConfigError) -> HelloAuthenticationError {
        HelloAuthenticationError::ConfigError(err)
    }
}

impl fmt::Display for HelloAuthenticationError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            HelloAuthenticationError::ConfigError(ref err) => {
                write!(f, "config error; {}", err)
            },
            HelloAuthenticationError::PublicKeyFileError(ref err) => {
                match err.kind() {
                   io::ErrorKind::NotFound => {
                       write!(f, "cannot find the credential public key for this user")
                   },
                   _ => {
                       write!(f, "{}", err)
                   },
                }
            },
            HelloAuthenticationError::Io(ref err) => {
                write!(f, "{}", err)
            },
            HelloAuthenticationError::InvalidPublicKey(_) => {
                write!(f, "the pem file of the public key is invalid")
            },
            HelloAuthenticationError::AuthenticatorLaunchError(ref err) => {
                write!(f, "cannot launch Windows Hello; {}", err)
            },
            HelloAuthenticationError::AuthenticatorConnectionError(ref err) => {
                write!(f, "cannot communicate with Windows Hello; {}", err)
            },
            HelloAuthenticationError::HelloAuthenticationFail(ref msg) => {
                write!(f, "authentication failed; {}", msg)
            },
            HelloAuthenticationError::SignAuthenticationFail => {
                write!(f, "the result of signature verification of the credential is failure")
            },
            ref err => {
                write!(f, "internal error; {:?}", err)
            }
        }
    }
}

fn authenticate_via_hello(pamh: *mut pam_handle_t) -> Result<i32, HelloAuthenticationError> {

    let user_name = get_user(pamh, None).map_err(|e| HelloAuthenticationError::GetUserError(e))?;
    let credential_key_name = format!("pam_wsl_hello_{}", user_name);

    let mut hello_public_key_file = File::open(format!("/etc/pam_wsl_hello/public_keys/{}.pem", credential_key_name)).map_err(|io| HelloAuthenticationError::PublicKeyFileError(io))?;
    let mut key_str = String::new();
    hello_public_key_file.read_to_string(&mut key_str)?;
    let hello_public_key = PKey::public_key_from_pem(key_str.as_bytes()).map_err(|e| HelloAuthenticationError::InvalidPublicKey(e))?;

    let challenge = format!("pam_wsl_hello:{}:{}", user_name, Uuid::new_v4());

    // Since there seems to be a bug that C# applications cannot read from pipes on WSL,
    // we create a temporary file to redirect
    let challenge_tmpfile_path = &format!("/tmp/{}", challenge);
    {
        let mut challenge_tmpfile = File::create(challenge_tmpfile_path)?;
        challenge_tmpfile.write_all(challenge.as_bytes())?;
    }
    let challenge_tmpfile = File::open(challenge_tmpfile_path)?;
    let challenge_tmpfile_in = unsafe {Stdio::from_raw_fd(challenge_tmpfile.as_raw_fd())};

    let authenticator_path = get_authenticator_path()?;
    let authenticator = Command::new(&authenticator_path)
        .arg(credential_key_name)
        .current_dir("/mnt/c")
        .stdin(challenge_tmpfile_in)
        .stdout(Stdio::piped())
        .spawn()
        .map_err(|e| HelloAuthenticationError::AuthenticatorLaunchError(e))?;

    let output = authenticator
        .wait_with_output()
        .map_err(|e| HelloAuthenticationError::AuthenticatorConnectionError(e))?;
    match output.status.code() {
        Some(code) if code == 0 => {/* Success */},
        Some(_) => return Err(HelloAuthenticationError::HelloAuthenticationFail(String::from_utf8(output.stdout)
                                                                                .unwrap_or("invalid utf8 output".to_string()))),
        None => return Err(HelloAuthenticationError::AuthenticatorSignalled),
    }
    let signature = output.stdout;

    let mut verifier = Verifier::new(MessageDigest::sha256(), &hello_public_key).unwrap();
    verifier.update(challenge.as_bytes()).map_err(|e| HelloAuthenticationError::OpenSSLError(e))?;

    match verifier.finish(&signature).map_err(|e| HelloAuthenticationError::OpenSSLError(e))? {
        true => Ok(PAM_SUCCESS),
        false => Err(HelloAuthenticationError::SignAuthenticationFail),
    }
}

#[no_mangle]
pub fn pam_sm_authenticate(
    pamh: *mut pam_handle_t,
    flags: c_int,
    _: c_int,
    _: *mut *const c_char,
) -> c_int {
    let res = authenticate_via_hello(pamh);
    if res.is_ok() {
        return res.unwrap()
    }
    let err = res.unwrap_err();
    if (flags & PAM_SILENT) == 0 {
        println!("WSL Hello error: {}", err);
    }
    match err {
        HelloAuthenticationError::PublicKeyFileError(ref err)
            if err.kind() == io::ErrorKind::NotFound  => PAM_USER_UNKNOWN,
        HelloAuthenticationError::AuthenticatorLaunchError(_) => PAM_AUTHINFO_UNAVAIL,
        HelloAuthenticationError::AuthenticatorConnectionError(_) => PAM_AUTHINFO_UNAVAIL,
        HelloAuthenticationError::AuthenticatorSignalled => PAM_AUTHINFO_UNAVAIL,
        _ => PAM_AUTH_ERR,
    }
}

#[no_mangle]
#[allow(unused_variables)]
pub fn pam_sm_setcred(
    pamh: *mut pam_handle_t,
    flags: ::std::os::raw::c_int,
    argc: ::std::os::raw::c_int,
    argv: *mut *const ::std::os::raw::c_char,
) -> ::std::os::raw::c_int {
    PAM_IGNORE
}

#[no_mangle]
#[allow(unused_variables)]
pub fn pam_sm_acct_mgmt(
    pamh: *mut pam_handle_t,
    flags: ::std::os::raw::c_int,
    argc: ::std::os::raw::c_int,
    argv: *mut *const ::std::os::raw::c_char,
) -> ::std::os::raw::c_int {
    PAM_IGNORE
}

#[no_mangle]
#[allow(unused_variables)]
pub fn pam_sm_open_session(
    pamh: *mut pam_handle_t,
    flags: ::std::os::raw::c_int,
    argc: ::std::os::raw::c_int,
    argv: *mut *const ::std::os::raw::c_char,
) -> ::std::os::raw::c_int {
    PAM_IGNORE
}

#[no_mangle]
#[allow(unused_variables)]
pub fn pam_sm_close_session(
    pamh: *mut pam_handle_t,
    flags: ::std::os::raw::c_int,
    argc: ::std::os::raw::c_int,
    argv: *mut *const ::std::os::raw::c_char,
) -> ::std::os::raw::c_int {
    PAM_IGNORE
}

#[no_mangle]
#[allow(unused_variables)]
pub fn pam_sm_chauthtok(
    pamh: *mut pam_handle_t,
    flags: ::std::os::raw::c_int,
    argc: ::std::os::raw::c_int,
    argv: *mut *const ::std::os::raw::c_char,
) -> ::std::os::raw::c_int {
    PAM_IGNORE
}
<commit_msg>Remove the temporary file and prevent overwriting<commit_after>#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

use libc::{c_int, c_char};
use std::ffi::{CString, CStr};
use std::borrow::{Cow};
use std::ptr;
use std::fs;
use std::fs::{File, OpenOptions};
use std::io;
use std::io::SeekFrom;
use std::io::prelude::*;
use std::process::{Command, Stdio};
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::fmt;
use openssl::sign::Verifier;
use openssl::pkey::PKey;
use openssl::hash::MessageDigest;
use bindings::*;
use toml::Value;
use uuid::Uuid;

extern crate libc;
extern crate openssl;
extern crate toml;
extern crate uuid;

pub mod bindings;

fn get_user(pamh: *mut pam_handle_t, prompt: Option<&str>) -> Result<Cow<str>, i32> {
    let mut c_user: *const c_char = ptr::null();
    let c_prompt = match prompt {
        Some(prompt_str) => CString::new(prompt_str).unwrap().as_ptr(),
        None => ptr::null(),
    };
    let err;
    unsafe {
        err = pam_get_user(pamh, &mut c_user, c_prompt);
    }
    match err {
        PAM_SUCCESS => unsafe {
            let c_user_str = CStr::from_ptr(c_user);
            Ok(c_user_str.to_string_lossy())
        },
        err => Err(err),
    }
}

#[derive(Debug)]
enum ConfigError {
    Io(io::Error),
    Toml(toml::de::Error),
    MissingField(String),
    InvalidValueType(String),
}

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

impl From<toml::de::Error> for ConfigError {
    fn from(err: toml::de::Error) -> ConfigError {
        ConfigError::Toml(err)
    }
}

impl fmt::Display for ConfigError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ConfigError::Io(ref ioerr) => write!(f, "{}", ioerr),
            ConfigError::Toml(_) => write!(f, "TOML format error"),
            ConfigError::MissingField(_) => write!(f, "field: 'authenticator_path' is not found"),
            ConfigError::InvalidValueType(_) => write!(f, "field: 'authenticator_path' has an invalid value type"),
        }
    }
}

fn get_authenticator_path() -> Result<String, ConfigError> {
    let mut config_file = File::open("/etc/pam_wsl_hello/config")?;
    let mut config = String::new();
    config_file.read_to_string(&mut config)?;

    let config_value = config.parse::<Value>()?;
    let authenticator_path = config_value.get("authenticator_path")
        .ok_or(ConfigError::MissingField("authenticator_path".to_owned()))?
        .as_str()
        .ok_or(ConfigError::InvalidValueType("authenticator_path".to_owned()))?;
    Ok(authenticator_path.to_owned())
}

#[derive(Debug)]
enum HelloAuthenticationError {
    GetUserError(i32),
    ConfigError(ConfigError),
    PublicKeyFileError(io::Error),
    Io(io::Error),
    InvalidPublicKey(openssl::error::ErrorStack),
    OpenSSLError(openssl::error::ErrorStack),
    AuthenticatorLaunchError(io::Error),
    AuthenticatorConnectionError(io::Error),
    AuthenticatorSignalled,
    HelloAuthenticationFail(String),
    SignAuthenticationFail,
}

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

impl From<ConfigError> for HelloAuthenticationError {
    fn from(err: ConfigError) -> HelloAuthenticationError {
        HelloAuthenticationError::ConfigError(err)
    }
}

impl fmt::Display for HelloAuthenticationError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            HelloAuthenticationError::ConfigError(ref err) => {
                write!(f, "config error; {}", err)
            },
            HelloAuthenticationError::PublicKeyFileError(ref err) => {
                match err.kind() {
                   io::ErrorKind::NotFound => {
                       write!(f, "cannot find the credential public key for this user")
                   },
                   _ => {
                       write!(f, "{}", err)
                   },
                }
            },
            HelloAuthenticationError::Io(ref err) => {
                write!(f, "{}", err)
            },
            HelloAuthenticationError::InvalidPublicKey(_) => {
                write!(f, "the pem file of the public key is invalid")
            },
            HelloAuthenticationError::AuthenticatorLaunchError(ref err) => {
                write!(f, "cannot launch Windows Hello; {}", err)
            },
            HelloAuthenticationError::AuthenticatorConnectionError(ref err) => {
                write!(f, "cannot communicate with Windows Hello; {}", err)
            },
            HelloAuthenticationError::HelloAuthenticationFail(ref msg) => {
                write!(f, "authentication failed; {}", msg)
            },
            HelloAuthenticationError::SignAuthenticationFail => {
                write!(f, "the result of signature verification of the credential is failure")
            },
            ref err => {
                write!(f, "internal error; {:?}", err)
            }
        }
    }
}

fn authenticate_via_hello(pamh: *mut pam_handle_t) -> Result<i32, HelloAuthenticationError> {

    let user_name = get_user(pamh, None).map_err(|e| HelloAuthenticationError::GetUserError(e))?;
    let credential_key_name = format!("pam_wsl_hello_{}", user_name);

    let mut hello_public_key_file = File::open(format!("/etc/pam_wsl_hello/public_keys/{}.pem", credential_key_name)).map_err(|io| HelloAuthenticationError::PublicKeyFileError(io))?;
    let mut key_str = String::new();
    hello_public_key_file.read_to_string(&mut key_str)?;
    let hello_public_key = PKey::public_key_from_pem(key_str.as_bytes()).map_err(|e| HelloAuthenticationError::InvalidPublicKey(e))?;

    let challenge = format!("pam_wsl_hello:{}:{}", user_name, Uuid::new_v4());

    let auth_res;
    let challenge_tmpfile_path = &format!("/tmp/{}", challenge);
    {
        // Since there seems to be a bug that C# applications cannot read from pipes on WSL,
        // we create a temporary file to redirect
        let mut challenge_tmpfile = OpenOptions::new().write(true)
            .read(true)
            .create_new(true)
            .open(challenge_tmpfile_path)?;
        challenge_tmpfile.write_all(challenge.as_bytes())?;
        challenge_tmpfile.seek(SeekFrom::Start(0))?;
        let challenge_tmpfile_in = unsafe {Stdio::from_raw_fd(challenge_tmpfile.as_raw_fd())};

        let authenticator_path = get_authenticator_path()?;
        let authenticator = Command::new(&authenticator_path)
            .arg(credential_key_name)
            .current_dir("/mnt/c")
            .stdin(challenge_tmpfile_in)
            .stdout(Stdio::piped())
            .spawn()
            .map_err(|e| HelloAuthenticationError::AuthenticatorLaunchError(e))?;

        auth_res = authenticator
            .wait_with_output()
            .map_err(|e| HelloAuthenticationError::AuthenticatorConnectionError(e))?;
    }
    fs::remove_file(challenge_tmpfile_path)?;

    match auth_res.status.code() {
        Some(code) if code == 0 => {/* Success */},
        Some(_) => return Err(HelloAuthenticationError::HelloAuthenticationFail(String::from_utf8(auth_res.stdout)
                                                                                .unwrap_or("invalid utf8 output".to_string()))),
        None => return Err(HelloAuthenticationError::AuthenticatorSignalled),
    }
    let signature = auth_res.stdout;

    let mut verifier = Verifier::new(MessageDigest::sha256(), &hello_public_key).unwrap();
    verifier.update(challenge.as_bytes()).map_err(|e| HelloAuthenticationError::OpenSSLError(e))?;

    match verifier.finish(&signature).map_err(|e| HelloAuthenticationError::OpenSSLError(e))? {
        true => Ok(PAM_SUCCESS),
        false => Err(HelloAuthenticationError::SignAuthenticationFail),
    }
}

#[no_mangle]
pub fn pam_sm_authenticate(
    pamh: *mut pam_handle_t,
    flags: c_int,
    _: c_int,
    _: *mut *const c_char,
) -> c_int {
    let res = authenticate_via_hello(pamh);
    if res.is_ok() {
        return res.unwrap()
    }
    let err = res.unwrap_err();
    if (flags & PAM_SILENT) == 0 {
        println!("WSL Hello error: {}", err);
    }
    match err {
        HelloAuthenticationError::PublicKeyFileError(ref err)
            if err.kind() == io::ErrorKind::NotFound  => PAM_USER_UNKNOWN,
        HelloAuthenticationError::AuthenticatorLaunchError(_) => PAM_AUTHINFO_UNAVAIL,
        HelloAuthenticationError::AuthenticatorConnectionError(_) => PAM_AUTHINFO_UNAVAIL,
        HelloAuthenticationError::AuthenticatorSignalled => PAM_AUTHINFO_UNAVAIL,
        _ => PAM_AUTH_ERR,
    }
}

#[no_mangle]
#[allow(unused_variables)]
pub fn pam_sm_setcred(
    pamh: *mut pam_handle_t,
    flags: ::std::os::raw::c_int,
    argc: ::std::os::raw::c_int,
    argv: *mut *const ::std::os::raw::c_char,
) -> ::std::os::raw::c_int {
    PAM_IGNORE
}

#[no_mangle]
#[allow(unused_variables)]
pub fn pam_sm_acct_mgmt(
    pamh: *mut pam_handle_t,
    flags: ::std::os::raw::c_int,
    argc: ::std::os::raw::c_int,
    argv: *mut *const ::std::os::raw::c_char,
) -> ::std::os::raw::c_int {
    PAM_IGNORE
}

#[no_mangle]
#[allow(unused_variables)]
pub fn pam_sm_open_session(
    pamh: *mut pam_handle_t,
    flags: ::std::os::raw::c_int,
    argc: ::std::os::raw::c_int,
    argv: *mut *const ::std::os::raw::c_char,
) -> ::std::os::raw::c_int {
    PAM_IGNORE
}

#[no_mangle]
#[allow(unused_variables)]
pub fn pam_sm_close_session(
    pamh: *mut pam_handle_t,
    flags: ::std::os::raw::c_int,
    argc: ::std::os::raw::c_int,
    argv: *mut *const ::std::os::raw::c_char,
) -> ::std::os::raw::c_int {
    PAM_IGNORE
}

#[no_mangle]
#[allow(unused_variables)]
pub fn pam_sm_chauthtok(
    pamh: *mut pam_handle_t,
    flags: ::std::os::raw::c_int,
    argc: ::std::os::raw::c_int,
    argv: *mut *const ::std::os::raw::c_char,
) -> ::std::os::raw::c_int {
    PAM_IGNORE
}
<|endoftext|>


<commit_before>// Use actual greek variable names rather than latin (namely ρ vs. rho)
#![feature(non_ascii_idents)]
// redesign
#![feature(hash)]
// pending
#![feature(core)]
// use variable names from paper, namely registers M
#![allow(non_snake_case)]

#![crate_name = "basic-hll"]
#![crate_type = "lib"]

/* -------------------- std libs ------------------- */
use std::cmp;
use std::fmt;
use std::hash::{ hash, Hash, SipHasher };
use std::iter;
use std::num::{ Int, Float };
/* ------------------------------------------------- */

/* -------------------- helpers -------------------- */

fn alpha (m: usize) -> f64 {
    match m {
        16 => 0.673,
        32 => 0.697,
        64 => 0.709,
        _  => 0.7213/(1f64 + 1.079/(m as f64))
    }
}

fn leftmost_one_bit (v: u64) -> usize {
    let mut counter: usize = 0;
    let mut shiftable = v;

    while shiftable > 0 {
        shiftable >>= 1;
        counter += 1;
    }

    64 - counter
}

/* ------------------------------------------------- */

/* --------------- hyper log log ------------------- */

pub struct HLL {
    alpha: f64,
    b: usize,
    m: usize,
    M: Vec<u8>,
    // [!] this is pretty much a hack until I can think of something
    //     better to do for the monoid instance. Basically we need the
    //     zero value to always satisfy the left and right identity laws
    //     but because you need to have the number of registers be
    //     equivalent to do addition, it implies you need a distinct
    //     monoid instance per HLL configuration (i.e. an HLL of 4
    //     registers has a distinct zero from a HLL of 16).
    //
    //     Because I can't really do dependent types in rust, we instead
    //     have a distinguished zero element, that is allowed to bypass
    //     the assertions on the equivalent sizes...
    //
    //     For reference, Ed Kmett's haskell implementation actually does
    //     use higher kinded types and some tricky reflection to make the
    //     monoid instance be parameterised by a config type that is itself
    //     typed to a Peano natural encoded type. Twitter's algebird instance
    //     declares a separate class that encapsulates the notion of
    //     a "HyperLogLogMonoid" instance, and instances of that class are
    //     instantiated with the register size (i.e. the 'instance' for monoid
    //     is just an 'instance' of the class, for two interpretations of
    //     'instance').
    isZero: bool
}

impl HLL {
    pub fn one_hundred_twenty_eight () -> HLL {
        HLL::ctor(0.09192)
    }

    pub fn ctor(error: f64) -> HLL {
        assert!(error > 0.0 && error < 1.0);
        // error = 1.04 / sqrt(m)
        let m = Float::floor((1.04/error) * (1.04/error)) as usize;
        let b = Float::log2(m as f64) as usize;

        HLL {
            alpha: alpha(m),
            b: b,
            m: m,
            M: iter::repeat(0u8).take(m).collect(),
            isZero: false
        }
    }

    pub fn insert<T: Hash>(&mut self, val: &T) {
        let hash = hash::<T, SipHasher>(val);

        // j is the first b many bits
        let j = (hash >> (64 - self.b)) as usize;
        // w is the remaining bits (i.e. b -> 64)
        let w = hash & (Int::pow(2, 64 - self.b) - 1);
        let ρ = leftmost_one_bit(w) as u8;

        self.M[j] = cmp::max(self.M[j], ρ);
    }

    pub fn count(&self) -> f64 {
        self.range_correction(self.raw_estimate())
    }

    fn raw_estimate(&self) -> f64 {
        let sum: f64 = self.M.iter().fold (0.0, |p, &r| p + 2.0f64.powi(-(r as i32)));

        self.alpha as f64 * Int::pow(self.m, 2) as f64 * (1.0 / sum)
    }

    fn empty_registers (&self) -> usize {
        self.M.iter().filter(|&r| *r == 0).count()
    }

    fn range_correction(&self, e: f64) -> f64 {
        let twoTo32: f64 = 2.0f64.powi(32) as f64;

        // small range correction
        if e <= (5.0*(self.m as f64))/2.0 {
            let v  = self.empty_registers() as f64;
            let fm = self.m as f64;

            return match v {
                0.0 => e,
                _   => fm * (fm / v).ln()
            }
        }

        // medium range (no) correction
        if e <= twoTo32/30.0 {
            return e;
        }

        -twoTo32 * (1.0 - e/twoTo32).ln()
    }

    pub fn registers(&self) -> Vec<u8> {
        self.M.clone()
    }

    pub fn clone (&self) -> HLL {
        HLL {
            alpha: self.alpha,
            b: self.b,
            m: self.m,
            M: self.M.clone(),
            isZero: self.isZero
        }
    }

    pub fn empty () -> HLL {
        HLL {
            alpha: 0.0,
            m: 0,
            b: 0,
            M: Vec::new(),
            isZero: true
        }
    }

}

/* ------------------------------------------------- */

/* --------------- trait instances ----------------- */

impl std::fmt::Display for HLL {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "α: {}, b: {}, m: {}", self.alpha, self.b, self.m)
    }
}

impl std::fmt::Debug for HLL {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "α: {}, b: {}, m: {}", self.alpha, self.b, self.m)
    }
}

impl std::cmp::Eq for HLL {}
impl std::cmp::PartialEq for HLL {
    fn eq(&self, other: &HLL) -> bool {
           self.alpha  == other.alpha
        && self.m      == other.m
        && self.b      == other.b
        && self.M      == other.M
        && self.isZero == other.isZero
    }
}

fn mergeRegisters (first: &Vec<u8>, second: &Vec<u8>) -> Vec<u8> {
    // TODO -- isn't this just zipWith max?
    let mut res: Vec<u8> = Vec::new();
    let mut zipper = first.iter().zip(second.iter());
    loop {
        match zipper.next() {
            None => return res,
            Some ((f, s)) => res.push(*cmp::max(f, s))
        }
    }
}

impl std::ops::Add<HLL> for HLL {
    type Output = HLL;

    fn add(self, other: HLL) -> HLL {
        // [!] gross...
        if self.isZero { return other.clone(); }
        if other.isZero { return self.clone(); }

        assert!(self.alpha == other.alpha);
        assert!(self.b == other.b);
        assert!(self.m == other.m);

        HLL {
            alpha: self.alpha,
            b: self.b,
            m: self.m,
            M: mergeRegisters(&self.M, &other.M),
            isZero: false
        }
    }
}

impl<'a> std::ops::Add<&'a HLL> for  HLL {
    type Output = HLL;

    fn add(self, other: &HLL) -> HLL {
        // [!] gross...
        if self.isZero { return other.clone(); }
        if other.isZero { return self.clone(); }

        assert!(self.alpha == other.alpha);
        assert!(self.b == other.b);
        assert!(self.m == other.m);

        HLL {
            alpha: self.alpha,
            b: self.b,
            m: self.m,
            M: mergeRegisters(&self.M, &other.M),
            isZero: false
        }
    }
}

/* ------------------------------------------------- */
<commit_msg>Update to nightly (pow takes u32, not usize)<commit_after>// Use actual greek variable names rather than latin (namely ρ vs. rho)
#![feature(non_ascii_idents)]
// redesign
#![feature(hash)]
// pending
#![feature(core)]
// use variable names from paper, namely registers M
#![allow(non_snake_case)]

#![crate_name = "basic-hll"]
#![crate_type = "lib"]

/* -------------------- std libs ------------------- */
use std::cmp;
use std::fmt;
use std::hash::{ hash, Hash, SipHasher };
use std::iter;
use std::num::{ Int, Float };
/* ------------------------------------------------- */

/* -------------------- helpers -------------------- */

fn alpha (m: usize) -> f64 {
    match m {
        16 => 0.673,
        32 => 0.697,
        64 => 0.709,
        _  => 0.7213/(1f64 + 1.079/(m as f64))
    }
}

fn leftmost_one_bit (v: u64) -> usize {
    let mut counter: usize = 0;
    let mut shiftable = v;

    while shiftable > 0 {
        shiftable >>= 1;
        counter += 1;
    }

    64 - counter
}

/* ------------------------------------------------- */

/* --------------- hyper log log ------------------- */

pub struct HLL {
    alpha: f64,
    b: u32,
    m: usize,
    M: Vec<u8>,
    // [!] this is pretty much a hack until I can think of something
    //     better to do for the monoid instance. Basically we need the
    //     zero value to always satisfy the left and right identity laws
    //     but because you need to have the number of registers be
    //     equivalent to do addition, it implies you need a distinct
    //     monoid instance per HLL configuration (i.e. an HLL of 4
    //     registers has a distinct zero from a HLL of 16).
    //
    //     Because I can't really do dependent types in rust, we instead
    //     have a distinguished zero element, that is allowed to bypass
    //     the assertions on the equivalent sizes...
    //
    //     For reference, Ed Kmett's haskell implementation actually does
    //     use higher kinded types and some tricky reflection to make the
    //     monoid instance be parameterised by a config type that is itself
    //     typed to a Peano natural encoded type. Twitter's algebird instance
    //     declares a separate class that encapsulates the notion of
    //     a "HyperLogLogMonoid" instance, and instances of that class are
    //     instantiated with the register size (i.e. the 'instance' for monoid
    //     is just an 'instance' of the class, for two interpretations of
    //     'instance').
    isZero: bool
}

impl HLL {
    pub fn one_hundred_twenty_eight () -> HLL {
        HLL::ctor(0.09192)
    }

    pub fn ctor(error: f64) -> HLL {
        assert!(error > 0.0 && error < 1.0);
        // error = 1.04 / sqrt(m)
        let m = Float::floor((1.04/error) * (1.04/error)) as usize;
        let b = Float::log2(m as f64) as u32;

        HLL {
            alpha: alpha(m),
            b: b,
            m: m,
            M: iter::repeat(0u8).take(m).collect(),
            isZero: false
        }
    }

    pub fn insert<T: Hash>(&mut self, val: &T) {
        let hash = hash::<T, SipHasher>(val);

        // j is the first b many bits
        let j = (hash >> (64 - self.b)) as usize;
        // w is the remaining bits (i.e. b -> 64)
        let w = hash & (Int::pow(2, 64u32 - self.b) - 1);
        let ρ = leftmost_one_bit(w) as u8;

        self.M[j] = cmp::max(self.M[j], ρ);
    }

    pub fn count(&self) -> f64 {
        self.range_correction(self.raw_estimate())
    }

    fn raw_estimate(&self) -> f64 {
        let sum: f64 = self.M.iter().fold (0.0, |p, &r| p + 2.0f64.powi(-(r as i32)));

        self.alpha as f64 * Int::pow(self.m, 2) as f64 * (1.0 / sum)
    }

    fn empty_registers (&self) -> usize {
        self.M.iter().filter(|&r| *r == 0).count()
    }

    fn range_correction(&self, e: f64) -> f64 {
        let twoTo32: f64 = 2.0f64.powi(32) as f64;

        // small range correction
        if e <= (5.0*(self.m as f64))/2.0 {
            let v  = self.empty_registers() as f64;
            let fm = self.m as f64;

            return match v {
                0.0 => e,
                _   => fm * (fm / v).ln()
            }
        }

        // medium range (no) correction
        if e <= twoTo32/30.0 {
            return e;
        }

        -twoTo32 * (1.0 - e/twoTo32).ln()
    }

    pub fn registers(&self) -> Vec<u8> {
        self.M.clone()
    }

    pub fn clone (&self) -> HLL {
        HLL {
            alpha: self.alpha,
            b: self.b,
            m: self.m,
            M: self.M.clone(),
            isZero: self.isZero
        }
    }

    pub fn empty () -> HLL {
        HLL {
            alpha: 0.0,
            m: 0,
            b: 0,
            M: Vec::new(),
            isZero: true
        }
    }

}

/* ------------------------------------------------- */

/* --------------- trait instances ----------------- */

impl std::fmt::Display for HLL {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "α: {}, b: {}, m: {}", self.alpha, self.b, self.m)
    }
}

impl std::fmt::Debug for HLL {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "α: {}, b: {}, m: {}", self.alpha, self.b, self.m)
    }
}

impl std::cmp::Eq for HLL {}
impl std::cmp::PartialEq for HLL {
    fn eq(&self, other: &HLL) -> bool {
           self.alpha  == other.alpha
        && self.m      == other.m
        && self.b      == other.b
        && self.M      == other.M
        && self.isZero == other.isZero
    }
}

fn mergeRegisters (first: &Vec<u8>, second: &Vec<u8>) -> Vec<u8> {
    // TODO -- isn't this just zipWith max?
    let mut res: Vec<u8> = Vec::new();
    let mut zipper = first.iter().zip(second.iter());
    loop {
        match zipper.next() {
            None => return res,
            Some ((f, s)) => res.push(*cmp::max(f, s))
        }
    }
}

impl std::ops::Add<HLL> for HLL {
    type Output = HLL;

    fn add(self, other: HLL) -> HLL {
        // [!] gross...
        if self.isZero { return other.clone(); }
        if other.isZero { return self.clone(); }

        assert!(self.alpha == other.alpha);
        assert!(self.b == other.b);
        assert!(self.m == other.m);

        HLL {
            alpha: self.alpha,
            b: self.b,
            m: self.m,
            M: mergeRegisters(&self.M, &other.M),
            isZero: false
        }
    }
}

impl<'a> std::ops::Add<&'a HLL> for  HLL {
    type Output = HLL;

    fn add(self, other: &HLL) -> HLL {
        // [!] gross...
        if self.isZero { return other.clone(); }
        if other.isZero { return self.clone(); }

        assert!(self.alpha == other.alpha);
        assert!(self.b == other.b);
        assert!(self.m == other.m);

        HLL {
            alpha: self.alpha,
            b: self.b,
            m: self.m,
            M: mergeRegisters(&self.M, &other.M),
            isZero: false
        }
    }
}

/* ------------------------------------------------- */
<|endoftext|>