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

use dom::bindings::codegen::Bindings::HTMLCollectionBinding;
use dom::bindings::codegen::Bindings::HTMLCollectionBinding::HTMLCollectionMethods;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, Root, MutNullableJS};
use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::bindings::str::DOMString;
use dom::bindings::trace::JSTraceable;
use dom::bindings::xmlname::namespace_from_domstring;
use dom::element::Element;
use dom::node::{Node, document_from_node};
use dom::window::Window;
use dom_struct::dom_struct;
use html5ever::{LocalName, QualName};
use servo_atoms::Atom;
use std::cell::Cell;
use style::str::split_html_space_chars;

pub trait CollectionFilter : JSTraceable {
    fn filter<'a>(&self, elem: &'a Element, root: &'a Node) -> bool;
}

// An optional u32, using maxint to represent None.
// It would be nicer just to use Option<u32> for this, but that would produce word
// alignment issues since Option<u32> uses 33 bits.
#[derive(Clone, Copy, JSTraceable, HeapSizeOf)]
struct OptionU32 {
    bits: u32,
}

impl OptionU32 {
    fn to_option(self) -> Option<u32> {
        if self.bits == u32::max_value() {
            None
        } else {
            Some(self.bits)
        }
    }

    fn some(bits: u32) -> OptionU32 {
        assert!(bits != u32::max_value());
        OptionU32 { bits: bits }
    }

    fn none() -> OptionU32 {
        OptionU32 { bits: u32::max_value() }
    }
}

#[dom_struct]
pub struct HTMLCollection {
    reflector_: Reflector,
    root: JS<Node>,
    #[ignore_heap_size_of = "Contains a trait object; can't measure due to #6870"]
    filter: Box<CollectionFilter + 'static>,
    // We cache the version of the root node and all its decendents,
    // the length of the collection, and a cursor into the collection.
    // FIXME: make the cached cursor element a weak pointer
    cached_version: Cell<u64>,
    cached_cursor_element: MutNullableJS<Element>,
    cached_cursor_index: Cell<OptionU32>,
    cached_length: Cell<OptionU32>,
}

impl HTMLCollection {
    #[allow(unrooted_must_root)]
    pub fn new_inherited(root: &Node, filter: Box<CollectionFilter + 'static>) -> HTMLCollection {
        HTMLCollection {
            reflector_: Reflector::new(),
            root: JS::from_ref(root),
            filter: filter,
            // Default values for the cache
            cached_version: Cell::new(root.inclusive_descendants_version()),
            cached_cursor_element: MutNullableJS::new(None),
            cached_cursor_index: Cell::new(OptionU32::none()),
            cached_length: Cell::new(OptionU32::none()),
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(window: &Window, root: &Node, filter: Box<CollectionFilter + 'static>) -> Root<HTMLCollection> {
        reflect_dom_object(box HTMLCollection::new_inherited(root, filter),
                           window, HTMLCollectionBinding::Wrap)
    }

    pub fn create(window: &Window, root: &Node,
                  filter: Box<CollectionFilter + 'static>) -> Root<HTMLCollection> {
        HTMLCollection::new(window, root, filter)
    }

    fn validate_cache(&self) {
        // Clear the cache if the root version is different from our cached version
        let cached_version = self.cached_version.get();
        let curr_version = self.root.inclusive_descendants_version();
        if curr_version != cached_version {
            // Default values for the cache
            self.cached_version.set(curr_version);
            self.cached_cursor_element.set(None);
            self.cached_length.set(OptionU32::none());
            self.cached_cursor_index.set(OptionU32::none());
        }
    }

    fn set_cached_cursor(&self, index: u32, element: Option<Root<Element>>) -> Option<Root<Element>> {
        if let Some(element) = element {
            self.cached_cursor_index.set(OptionU32::some(index));
            self.cached_cursor_element.set(Some(&element));
            Some(element)
        } else {
            None
        }
    }

    // https://dom.spec.whatwg.org/#concept-getelementsbytagname
    pub fn by_qualified_name(window: &Window, root: &Node, qualified_name: LocalName)
                             -> Root<HTMLCollection> {
        // case 1
        if qualified_name == local_name!("*") {
            #[derive(JSTraceable, HeapSizeOf)]
            struct AllFilter;
            impl CollectionFilter for AllFilter {
                fn filter(&self, _elem: &Element, _root: &Node) -> bool {
                    true
                }
            }
            return HTMLCollection::create(window, root, box AllFilter);
        }

        #[derive(JSTraceable, HeapSizeOf)]
        struct HtmlDocumentFilter {
            qualified_name: LocalName,
            ascii_lower_qualified_name: LocalName,
        }
        impl CollectionFilter for HtmlDocumentFilter {
            fn filter(&self, elem: &Element, root: &Node) -> bool {
                if root.is_in_html_doc() && elem.namespace() == &ns!(html) {    // case 2
                    HTMLCollection::match_element(elem, &self.ascii_lower_qualified_name)
                } else {    // case 2 and 3
                    HTMLCollection::match_element(elem, &self.qualified_name)
                }
            }
        }

        let filter = HtmlDocumentFilter {
            ascii_lower_qualified_name: qualified_name.to_ascii_lowercase(),
            qualified_name: qualified_name,
        };
        HTMLCollection::create(window, root, box filter)
    }

    fn match_element(elem: &Element, qualified_name: &LocalName) -> bool {
        match elem.prefix() {
            None => elem.local_name() == qualified_name,
            Some(prefix) => qualified_name.starts_with(&**prefix) &&
                qualified_name.find(":") == Some(prefix.len()) &&
                qualified_name.ends_with(&**elem.local_name()),
        }
    }

    pub fn by_tag_name_ns(window: &Window, root: &Node, tag: DOMString,
                          maybe_ns: Option<DOMString>) -> Root<HTMLCollection> {
        let local = LocalName::from(tag);
        let ns = namespace_from_domstring(maybe_ns);
        let qname = QualName::new(None, ns, local);
        HTMLCollection::by_qual_tag_name(window, root, qname)
    }

    pub fn by_qual_tag_name(window: &Window, root: &Node, qname: QualName) -> Root<HTMLCollection> {
        #[derive(JSTraceable, HeapSizeOf)]
        struct TagNameNSFilter {
            qname: QualName
        }
        impl CollectionFilter for TagNameNSFilter {
            fn filter(&self, elem: &Element, _root: &Node) -> bool {
                    ((self.qname.ns == namespace_url!("*")) || (self.qname.ns == *elem.namespace())) &&
                    ((self.qname.local == local_name!("*")) || (self.qname.local == *elem.local_name()))
            }
        }
        let filter = TagNameNSFilter {
            qname: qname
        };
        HTMLCollection::create(window, root, box filter)
    }

    pub fn by_class_name(window: &Window, root: &Node, classes: DOMString)
                         -> Root<HTMLCollection> {
        let class_atoms = split_html_space_chars(&classes).map(Atom::from).collect();
        HTMLCollection::by_atomic_class_name(window, root, class_atoms)
    }

    pub fn by_atomic_class_name(window: &Window, root: &Node, classes: Vec<Atom>)
                         -> Root<HTMLCollection> {
        #[derive(JSTraceable, HeapSizeOf)]
        struct ClassNameFilter {
            classes: Vec<Atom>
        }
        impl CollectionFilter for ClassNameFilter {
            fn filter(&self, elem: &Element, _root: &Node) -> bool {
                let case_sensitivity = document_from_node(elem)
                    .quirks_mode()
                    .classes_and_ids_case_sensitivity();
                self.classes.iter().all(|class| elem.has_class(class, case_sensitivity))
            }
        }
        let filter = ClassNameFilter {
            classes: classes
        };
        HTMLCollection::create(window, root, box filter)
    }

    pub fn children(window: &Window, root: &Node) -> Root<HTMLCollection> {
        #[derive(JSTraceable, HeapSizeOf)]
        struct ElementChildFilter;
        impl CollectionFilter for ElementChildFilter {
            fn filter(&self, elem: &Element, root: &Node) -> bool {
                root.is_parent_of(elem.upcast())
            }
        }
        HTMLCollection::create(window, root, box ElementChildFilter)
    }

    pub fn elements_iter_after<'a>(&'a self, after: &'a Node) -> impl Iterator<Item=Root<Element>> + 'a {
        // Iterate forwards from a node.
        HTMLCollectionElementsIter {
            node_iter: after.following_nodes(&self.root),
            root: Root::from_ref(&self.root),
            filter: &self.filter,
        }
    }

    pub fn elements_iter<'a>(&'a self) -> impl Iterator<Item=Root<Element>> + 'a {
        // Iterate forwards from the root.
        self.elements_iter_after(&*self.root)
    }

    pub fn elements_iter_before<'a>(&'a self, before: &'a Node) -> impl Iterator<Item=Root<Element>> + 'a {
        // Iterate backwards from a node.
        HTMLCollectionElementsIter {
            node_iter: before.preceding_nodes(&self.root),
            root: Root::from_ref(&self.root),
            filter: &self.filter,
        }
    }

    pub fn root_node(&self) -> Root<Node> {
        Root::from_ref(&self.root)
    }
}

// TODO: Make this generic, and avoid code duplication
struct HTMLCollectionElementsIter<'a, I> {
    node_iter: I,
    root: Root<Node>,
    filter: &'a Box<CollectionFilter>,
}

impl<'a, I: Iterator<Item=Root<Node>>> Iterator for HTMLCollectionElementsIter<'a, I> {
    type Item = Root<Element>;

    fn next(&mut self) -> Option<Self::Item> {
        let filter = &self.filter;
        let root = &self.root;
        self.node_iter.by_ref()
                      .filter_map(Root::downcast)
                      .filter(|element| filter.filter(&element, root))
                      .next()
    }
}

impl HTMLCollectionMethods for HTMLCollection {
    // https://dom.spec.whatwg.org/#dom-htmlcollection-length
    fn Length(&self) -> u32 {
        self.validate_cache();

        if let Some(cached_length) = self.cached_length.get().to_option() {
            // Cache hit
            cached_length
        } else {
            // Cache miss, calculate the length
            let length = self.elements_iter().count() as u32;
            self.cached_length.set(OptionU32::some(length));
            length
        }
    }

    // https://dom.spec.whatwg.org/#dom-htmlcollection-item
    fn Item(&self, index: u32) -> Option<Root<Element>> {
        self.validate_cache();

        if let Some(element) = self.cached_cursor_element.get() {
            // Cache hit, the cursor element is set
            if let Some(cached_index) = self.cached_cursor_index.get().to_option() {
                if cached_index == index {
                    // The cursor is the element we're looking for
                    Some(element)
                } else if cached_index < index {
                    // The cursor is before the element we're looking for
                    // Iterate forwards, starting at the cursor.
                    let offset = index - (cached_index + 1);
                    let node: Root<Node> = Root::upcast(element);
                    let mut iter = self.elements_iter_after(&node);
                    self.set_cached_cursor(index, iter.nth(offset as usize))
                } else {
                    // The cursor is after the element we're looking for
                    // Iterate backwards, starting at the cursor.
                    let offset = cached_index - (index + 1);
                    let node: Root<Node> = Root::upcast(element);
                    let mut iter = self.elements_iter_before(&node);
                    self.set_cached_cursor(index, iter.nth(offset as usize))
                }
            } else {
                // Cache miss
                // Iterate forwards through all the nodes
                self.set_cached_cursor(index, self.elements_iter().nth(index as usize))
            }
        } else {
            // Cache miss
            // Iterate forwards through all the nodes
            self.set_cached_cursor(index, self.elements_iter().nth(index as usize))
        }
    }

    // https://dom.spec.whatwg.org/#dom-htmlcollection-nameditem
    fn NamedItem(&self, key: DOMString) -> Option<Root<Element>> {
        // Step 1.
        if key.is_empty() {
            return None;
        }

        // Step 2.
        self.elements_iter().find(|elem| {
            elem.get_string_attribute(&local_name!("id")) == key ||
            (elem.namespace() == &ns!(html) && elem.get_string_attribute(&local_name!("name")) == key)
        })
    }

    // https://dom.spec.whatwg.org/#dom-htmlcollection-item
    fn IndexedGetter(&self, index: u32) -> Option<Root<Element>> {
        self.Item(index)
    }

    // check-tidy: no specs after this line
    fn NamedGetter(&self, name: DOMString) -> Option<Root<Element>> {
        self.NamedItem(name)
    }

    // https://dom.spec.whatwg.org/#interface-htmlcollection
    fn SupportedPropertyNames(&self) -> Vec<DOMString> {
        // Step 1
        let mut result = vec![];

        // Step 2
        for elem in self.elements_iter() {
            // Step 2.1
            let id_attr = elem.get_string_attribute(&local_name!("id"));
            if !id_attr.is_empty() && !result.contains(&id_attr) {
                result.push(id_attr)
            }
            // Step 2.2
            let name_attr = elem.get_string_attribute(&local_name!("name"));
            if !name_attr.is_empty() && !result.contains(&name_attr) && *elem.namespace() == ns!(html) {
                result.push(name_attr)
            }
        }

        // Step 3
        result
    }
}
<commit_msg>Auto merge of #17503 - frewsxcv:frewsxcv-return-node-list-2, r=mbrubeck<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::Bindings::HTMLCollectionBinding;
use dom::bindings::codegen::Bindings::HTMLCollectionBinding::HTMLCollectionMethods;
use dom::bindings::inheritance::Castable;
use dom::bindings::js::{JS, Root, MutNullableJS};
use dom::bindings::reflector::{Reflector, reflect_dom_object};
use dom::bindings::str::DOMString;
use dom::bindings::trace::JSTraceable;
use dom::bindings::xmlname::namespace_from_domstring;
use dom::element::Element;
use dom::node::{Node, document_from_node};
use dom::window::Window;
use dom_struct::dom_struct;
use html5ever::{LocalName, QualName};
use servo_atoms::Atom;
use std::cell::Cell;
use style::str::split_html_space_chars;

pub trait CollectionFilter : JSTraceable {
    fn filter<'a>(&self, elem: &'a Element, root: &'a Node) -> bool;
}

// An optional u32, using maxint to represent None.
// It would be nicer just to use Option<u32> for this, but that would produce word
// alignment issues since Option<u32> uses 33 bits.
#[derive(Clone, Copy, JSTraceable, HeapSizeOf)]
struct OptionU32 {
    bits: u32,
}

impl OptionU32 {
    fn to_option(self) -> Option<u32> {
        if self.bits == u32::max_value() {
            None
        } else {
            Some(self.bits)
        }
    }

    fn some(bits: u32) -> OptionU32 {
        assert!(bits != u32::max_value());
        OptionU32 { bits: bits }
    }

    fn none() -> OptionU32 {
        OptionU32 { bits: u32::max_value() }
    }
}

#[dom_struct]
pub struct HTMLCollection {
    reflector_: Reflector,
    root: JS<Node>,
    #[ignore_heap_size_of = "Contains a trait object; can't measure due to #6870"]
    filter: Box<CollectionFilter + 'static>,
    // We cache the version of the root node and all its decendents,
    // the length of the collection, and a cursor into the collection.
    // FIXME: make the cached cursor element a weak pointer
    cached_version: Cell<u64>,
    cached_cursor_element: MutNullableJS<Element>,
    cached_cursor_index: Cell<OptionU32>,
    cached_length: Cell<OptionU32>,
}

impl HTMLCollection {
    #[allow(unrooted_must_root)]
    pub fn new_inherited(root: &Node, filter: Box<CollectionFilter + 'static>) -> HTMLCollection {
        HTMLCollection {
            reflector_: Reflector::new(),
            root: JS::from_ref(root),
            filter: filter,
            // Default values for the cache
            cached_version: Cell::new(root.inclusive_descendants_version()),
            cached_cursor_element: MutNullableJS::new(None),
            cached_cursor_index: Cell::new(OptionU32::none()),
            cached_length: Cell::new(OptionU32::none()),
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(window: &Window, root: &Node, filter: Box<CollectionFilter + 'static>) -> Root<HTMLCollection> {
        reflect_dom_object(box HTMLCollection::new_inherited(root, filter),
                           window, HTMLCollectionBinding::Wrap)
    }

    pub fn create(window: &Window, root: &Node,
                  filter: Box<CollectionFilter + 'static>) -> Root<HTMLCollection> {
        HTMLCollection::new(window, root, filter)
    }

    fn validate_cache(&self) {
        // Clear the cache if the root version is different from our cached version
        let cached_version = self.cached_version.get();
        let curr_version = self.root.inclusive_descendants_version();
        if curr_version != cached_version {
            // Default values for the cache
            self.cached_version.set(curr_version);
            self.cached_cursor_element.set(None);
            self.cached_length.set(OptionU32::none());
            self.cached_cursor_index.set(OptionU32::none());
        }
    }

    fn set_cached_cursor(&self, index: u32, element: Option<Root<Element>>) -> Option<Root<Element>> {
        if let Some(element) = element {
            self.cached_cursor_index.set(OptionU32::some(index));
            self.cached_cursor_element.set(Some(&element));
            Some(element)
        } else {
            None
        }
    }

    // https://dom.spec.whatwg.org/#concept-getelementsbytagname
    pub fn by_qualified_name(window: &Window, root: &Node, qualified_name: LocalName)
                             -> Root<HTMLCollection> {
        // case 1
        if qualified_name == local_name!("*") {
            #[derive(JSTraceable, HeapSizeOf)]
            struct AllFilter;
            impl CollectionFilter for AllFilter {
                fn filter(&self, _elem: &Element, _root: &Node) -> bool {
                    true
                }
            }
            return HTMLCollection::create(window, root, box AllFilter);
        }

        #[derive(JSTraceable, HeapSizeOf)]
        struct HtmlDocumentFilter {
            qualified_name: LocalName,
            ascii_lower_qualified_name: LocalName,
        }
        impl CollectionFilter for HtmlDocumentFilter {
            fn filter(&self, elem: &Element, root: &Node) -> bool {
                if root.is_in_html_doc() && elem.namespace() == &ns!(html) {    // case 2
                    HTMLCollection::match_element(elem, &self.ascii_lower_qualified_name)
                } else {    // case 2 and 3
                    HTMLCollection::match_element(elem, &self.qualified_name)
                }
            }
        }

        let filter = HtmlDocumentFilter {
            ascii_lower_qualified_name: qualified_name.to_ascii_lowercase(),
            qualified_name: qualified_name,
        };
        HTMLCollection::create(window, root, box filter)
    }

    fn match_element(elem: &Element, qualified_name: &LocalName) -> bool {
        match elem.prefix() {
            None => elem.local_name() == qualified_name,
            Some(prefix) => qualified_name.starts_with(&**prefix) &&
                qualified_name.find(":") == Some(prefix.len()) &&
                qualified_name.ends_with(&**elem.local_name()),
        }
    }

    pub fn by_tag_name_ns(window: &Window, root: &Node, tag: DOMString,
                          maybe_ns: Option<DOMString>) -> Root<HTMLCollection> {
        let local = LocalName::from(tag);
        let ns = namespace_from_domstring(maybe_ns);
        let qname = QualName::new(None, ns, local);
        HTMLCollection::by_qual_tag_name(window, root, qname)
    }

    pub fn by_qual_tag_name(window: &Window, root: &Node, qname: QualName) -> Root<HTMLCollection> {
        #[derive(JSTraceable, HeapSizeOf)]
        struct TagNameNSFilter {
            qname: QualName
        }
        impl CollectionFilter for TagNameNSFilter {
            fn filter(&self, elem: &Element, _root: &Node) -> bool {
                    ((self.qname.ns == namespace_url!("*")) || (self.qname.ns == *elem.namespace())) &&
                    ((self.qname.local == local_name!("*")) || (self.qname.local == *elem.local_name()))
            }
        }
        let filter = TagNameNSFilter {
            qname: qname
        };
        HTMLCollection::create(window, root, box filter)
    }

    pub fn by_class_name(window: &Window, root: &Node, classes: DOMString)
                         -> Root<HTMLCollection> {
        let class_atoms = split_html_space_chars(&classes).map(Atom::from).collect();
        HTMLCollection::by_atomic_class_name(window, root, class_atoms)
    }

    pub fn by_atomic_class_name(window: &Window, root: &Node, classes: Vec<Atom>)
                         -> Root<HTMLCollection> {
        #[derive(JSTraceable, HeapSizeOf)]
        struct ClassNameFilter {
            classes: Vec<Atom>
        }
        impl CollectionFilter for ClassNameFilter {
            fn filter(&self, elem: &Element, _root: &Node) -> bool {
                let case_sensitivity = document_from_node(elem)
                    .quirks_mode()
                    .classes_and_ids_case_sensitivity();
                self.classes.iter().all(|class| elem.has_class(class, case_sensitivity))
            }
        }
        let filter = ClassNameFilter {
            classes: classes
        };
        HTMLCollection::create(window, root, box filter)
    }

    pub fn children(window: &Window, root: &Node) -> Root<HTMLCollection> {
        #[derive(JSTraceable, HeapSizeOf)]
        struct ElementChildFilter;
        impl CollectionFilter for ElementChildFilter {
            fn filter(&self, elem: &Element, root: &Node) -> bool {
                root.is_parent_of(elem.upcast())
            }
        }
        HTMLCollection::create(window, root, box ElementChildFilter)
    }

    pub fn elements_iter_after<'a>(&'a self, after: &'a Node) -> impl Iterator<Item=Root<Element>> + 'a {
        // Iterate forwards from a node.
        after.following_nodes(&self.root)
            .filter_map(Root::downcast)
            .filter(move |element| self.filter.filter(&element, &self.root))
    }

    pub fn elements_iter<'a>(&'a self) -> impl Iterator<Item=Root<Element>> + 'a {
        // Iterate forwards from the root.
        self.elements_iter_after(&*self.root)
    }

    pub fn elements_iter_before<'a>(&'a self, before: &'a Node) -> impl Iterator<Item=Root<Element>> + 'a {
        // Iterate backwards from a node.
        before.preceding_nodes(&self.root)
            .filter_map(Root::downcast)
            .filter(move |element| self.filter.filter(&element, &self.root))
    }

    pub fn root_node(&self) -> Root<Node> {
        Root::from_ref(&self.root)
    }
}

impl HTMLCollectionMethods for HTMLCollection {
    // https://dom.spec.whatwg.org/#dom-htmlcollection-length
    fn Length(&self) -> u32 {
        self.validate_cache();

        if let Some(cached_length) = self.cached_length.get().to_option() {
            // Cache hit
            cached_length
        } else {
            // Cache miss, calculate the length
            let length = self.elements_iter().count() as u32;
            self.cached_length.set(OptionU32::some(length));
            length
        }
    }

    // https://dom.spec.whatwg.org/#dom-htmlcollection-item
    fn Item(&self, index: u32) -> Option<Root<Element>> {
        self.validate_cache();

        if let Some(element) = self.cached_cursor_element.get() {
            // Cache hit, the cursor element is set
            if let Some(cached_index) = self.cached_cursor_index.get().to_option() {
                if cached_index == index {
                    // The cursor is the element we're looking for
                    Some(element)
                } else if cached_index < index {
                    // The cursor is before the element we're looking for
                    // Iterate forwards, starting at the cursor.
                    let offset = index - (cached_index + 1);
                    let node: Root<Node> = Root::upcast(element);
                    let mut iter = self.elements_iter_after(&node);
                    self.set_cached_cursor(index, iter.nth(offset as usize))
                } else {
                    // The cursor is after the element we're looking for
                    // Iterate backwards, starting at the cursor.
                    let offset = cached_index - (index + 1);
                    let node: Root<Node> = Root::upcast(element);
                    let mut iter = self.elements_iter_before(&node);
                    self.set_cached_cursor(index, iter.nth(offset as usize))
                }
            } else {
                // Cache miss
                // Iterate forwards through all the nodes
                self.set_cached_cursor(index, self.elements_iter().nth(index as usize))
            }
        } else {
            // Cache miss
            // Iterate forwards through all the nodes
            self.set_cached_cursor(index, self.elements_iter().nth(index as usize))
        }
    }

    // https://dom.spec.whatwg.org/#dom-htmlcollection-nameditem
    fn NamedItem(&self, key: DOMString) -> Option<Root<Element>> {
        // Step 1.
        if key.is_empty() {
            return None;
        }

        // Step 2.
        self.elements_iter().find(|elem| {
            elem.get_string_attribute(&local_name!("id")) == key ||
            (elem.namespace() == &ns!(html) && elem.get_string_attribute(&local_name!("name")) == key)
        })
    }

    // https://dom.spec.whatwg.org/#dom-htmlcollection-item
    fn IndexedGetter(&self, index: u32) -> Option<Root<Element>> {
        self.Item(index)
    }

    // check-tidy: no specs after this line
    fn NamedGetter(&self, name: DOMString) -> Option<Root<Element>> {
        self.NamedItem(name)
    }

    // https://dom.spec.whatwg.org/#interface-htmlcollection
    fn SupportedPropertyNames(&self) -> Vec<DOMString> {
        // Step 1
        let mut result = vec![];

        // Step 2
        for elem in self.elements_iter() {
            // Step 2.1
            let id_attr = elem.get_string_attribute(&local_name!("id"));
            if !id_attr.is_empty() && !result.contains(&id_attr) {
                result.push(id_attr)
            }
            // Step 2.2
            let name_attr = elem.get_string_attribute(&local_name!("name"));
            if !name_attr.is_empty() && !result.contains(&name_attr) && *elem.namespace() == ns!(html) {
                result.push(name_attr)
            }
        }

        // Step 3
        result
    }
}
<|endoftext|>


<commit_before>use std::convert::From;

use binding::string;
use types::{Value, ValueType};

use {Object, VerifiedObject};

/// `String`
#[derive(Debug, PartialEq)]
pub struct RString {
    value: Value,
}

impl RString {
    /// Creates a new instance of Ruby `String` containing given `string`.
    ///
    /// # Examples
    ///
    /// ```
    /// use ruru::{RString, VM};
    /// # VM::init();
    ///
    /// let string = RString::new("Hello, World!");
    ///
    /// assert_eq!(string.to_string(), "Hello, World!".to_string());
    /// ```
    ///
    /// Ruby:
    ///
    /// ```ruby
    /// str = 'Hello, World!'
    ///
    /// str == 'Hello, World!'
    /// ```
    pub fn new(string: &str) -> Self {
        Self::from(string::new(string))
    }

    /// Retrieves underlying Rust `String` from Ruby `String` object.
    ///
    /// # Examples
    ///
    /// ```
    /// use ruru::{RString, VM};
    /// # VM::init();
    ///
    /// let string = RString::new("Hello, World!");
    ///
    /// assert_eq!(string.to_string(), "Hello, World!".to_string());
    /// ```
    ///
    /// Ruby:
    ///
    /// ```ruby
    /// str = 'Hello, World!'
    ///
    /// str == 'Hello, World!'
    /// ```
    pub fn to_string(&self) -> String {
        string::value_to_string(self.value())
    }

    /// Retrieves underlying Rust `String` from Ruby `String` object.
    ///
    /// Unlike `to_string()` it does not perform any checks for internal null-bytes.
    ///
    /// This function may be used to safely get binary data from Ruby.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use ruru::{RString, VM};
    /// # VM::init();
    ///
    /// let string = RString::new("Hello,\0World!");
    ///
    /// assert_eq!(string.to_string_unchecked(), "Hello,\0World!".to_string());
    /// ```
    ///
    /// Ruby:
    ///
    /// ```ruby
    /// str = 'Hello,\0World!'
    ///
    /// str == 'Hello,\0World!'
    /// ```
    pub fn to_string_unchecked(&self) -> String {
        string::value_to_string_unchecked(self.value())
    }

    /// Retrieves underlying `&str` from Ruby `String` object.
    ///
    /// # Examples
    ///
    /// ```
    /// use ruru::{RString, VM};
    /// # VM::init();
    ///
    /// let string = RString::new("Hello, World!");
    ///
    /// assert_eq!(string.to_str(), "Hello, World!");
    /// ```
    ///
    /// Ruby:
    ///
    /// ```ruby
    /// str = 'Hello, World!'
    ///
    /// str == 'Hello, World!'
    /// ```
    pub fn to_str(&self) -> &str {
        let value = self.value();

        string::value_to_str(value)
    }

    /// Retrieves underlying `&str` from Ruby `String` object.
    ///
    /// Unlike `to_str()` it does not perform any checks for internal null-bytes.
    ///
    /// This function may be used to safely get binary data from Ruby.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use ruru::{RString, VM};
    /// # VM::init();
    ///
    /// let string = RString::new("Hello,\0World!");
    ///
    /// assert_eq!(string.to_str_unchecked(), "Hello,\0World!");
    /// ```
    ///
    /// Ruby:
    ///
    /// ```ruby
    /// str = 'Hello,\0World!'
    ///
    /// str == 'Hello,\0World!'
    /// ```
    pub fn to_str_unchecked(&self) -> &str {
        let value = self.value();

        string::value_to_str_unchecked(value)
    }

    /// Returns the length of the string in bytes
    ///
    /// # Examples
    ///
    /// ```
    /// use ruru::{RString, VM};
    /// # VM::init();
    ///
    /// let string = RString::new("Hello, World!");
    /// let utf8_string = RString::new("⓯");
    ///
    /// assert_eq!(string.bytesize(), 13);
    /// assert_eq!(utf8_string.bytesize(), 3);
    /// ```
    ///
    /// Ruby:
    ///
    /// ```ruby
    /// string = 'Hello, World!'
    /// utf8_string = '⓯'
    ///
    /// string.bytesize == 13
    /// utf8_string.bytesize == 3
    /// ```
    pub fn bytesize(&self) -> i64 {
        string::bytesize(self.value())
    }
}

impl From<Value> for RString {
    fn from(value: Value) -> Self {
        RString { value: value }
    }
}

impl Object for RString {
    #[inline]
    fn value(&self) -> Value {
        self.value
    }
}

impl VerifiedObject for RString {
    fn is_correct_type<T: Object>(object: &T) -> bool {
        object.value().ty() == ValueType::RString
    }

    fn error_message() -> &'static str {
        "Error converting to String"
    }
}
<commit_msg>Add From<String> for RString<commit_after>use std::convert::From;

use binding::string;
use types::{Value, ValueType};

use {Object, VerifiedObject};

/// `String`
#[derive(Debug, PartialEq)]
pub struct RString {
    value: Value,
}

impl RString {
    /// Creates a new instance of Ruby `String` containing given `string`.
    ///
    /// # Examples
    ///
    /// ```
    /// use ruru::{RString, VM};
    /// # VM::init();
    ///
    /// let string = RString::new("Hello, World!");
    ///
    /// assert_eq!(string.to_string(), "Hello, World!".to_string());
    /// ```
    ///
    /// Ruby:
    ///
    /// ```ruby
    /// str = 'Hello, World!'
    ///
    /// str == 'Hello, World!'
    /// ```
    pub fn new(string: &str) -> Self {
        Self::from(string::new(string))
    }

    /// Retrieves underlying Rust `String` from Ruby `String` object.
    ///
    /// # Examples
    ///
    /// ```
    /// use ruru::{RString, VM};
    /// # VM::init();
    ///
    /// let string = RString::new("Hello, World!");
    ///
    /// assert_eq!(string.to_string(), "Hello, World!".to_string());
    /// ```
    ///
    /// Ruby:
    ///
    /// ```ruby
    /// str = 'Hello, World!'
    ///
    /// str == 'Hello, World!'
    /// ```
    pub fn to_string(&self) -> String {
        string::value_to_string(self.value())
    }

    /// Retrieves underlying Rust `String` from Ruby `String` object.
    ///
    /// Unlike `to_string()` it does not perform any checks for internal null-bytes.
    ///
    /// This function may be used to safely get binary data from Ruby.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use ruru::{RString, VM};
    /// # VM::init();
    ///
    /// let string = RString::new("Hello,\0World!");
    ///
    /// assert_eq!(string.to_string_unchecked(), "Hello,\0World!".to_string());
    /// ```
    ///
    /// Ruby:
    ///
    /// ```ruby
    /// str = 'Hello,\0World!'
    ///
    /// str == 'Hello,\0World!'
    /// ```
    pub fn to_string_unchecked(&self) -> String {
        string::value_to_string_unchecked(self.value())
    }

    /// Retrieves underlying `&str` from Ruby `String` object.
    ///
    /// # Examples
    ///
    /// ```
    /// use ruru::{RString, VM};
    /// # VM::init();
    ///
    /// let string = RString::new("Hello, World!");
    ///
    /// assert_eq!(string.to_str(), "Hello, World!");
    /// ```
    ///
    /// Ruby:
    ///
    /// ```ruby
    /// str = 'Hello, World!'
    ///
    /// str == 'Hello, World!'
    /// ```
    pub fn to_str(&self) -> &str {
        let value = self.value();

        string::value_to_str(value)
    }

    /// Retrieves underlying `&str` from Ruby `String` object.
    ///
    /// Unlike `to_str()` it does not perform any checks for internal null-bytes.
    ///
    /// This function may be used to safely get binary data from Ruby.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use ruru::{RString, VM};
    /// # VM::init();
    ///
    /// let string = RString::new("Hello,\0World!");
    ///
    /// assert_eq!(string.to_str_unchecked(), "Hello,\0World!");
    /// ```
    ///
    /// Ruby:
    ///
    /// ```ruby
    /// str = 'Hello,\0World!'
    ///
    /// str == 'Hello,\0World!'
    /// ```
    pub fn to_str_unchecked(&self) -> &str {
        let value = self.value();

        string::value_to_str_unchecked(value)
    }

    /// Returns the length of the string in bytes
    ///
    /// # Examples
    ///
    /// ```
    /// use ruru::{RString, VM};
    /// # VM::init();
    ///
    /// let string = RString::new("Hello, World!");
    /// let utf8_string = RString::new("⓯");
    ///
    /// assert_eq!(string.bytesize(), 13);
    /// assert_eq!(utf8_string.bytesize(), 3);
    /// ```
    ///
    /// Ruby:
    ///
    /// ```ruby
    /// string = 'Hello, World!'
    /// utf8_string = '⓯'
    ///
    /// string.bytesize == 13
    /// utf8_string.bytesize == 3
    /// ```
    pub fn bytesize(&self) -> i64 {
        string::bytesize(self.value())
    }
}

impl From<Value> for RString {
    fn from(value: Value) -> Self {
        RString { value: value }
    }
}

impl From<String> for RString {
    fn from(string: String) -> Self {
        Self::new(string.as_str())
    }
}

impl Object for RString {
    #[inline]
    fn value(&self) -> Value {
        self.value
    }
}

impl VerifiedObject for RString {
    fn is_correct_type<T: Object>(object: &T) -> bool {
        object.value().ty() == ValueType::RString
    }

    fn error_message() -> &'static str {
        "Error converting to String"
    }
}
<|endoftext|>


<commit_before>use std::pin::Pin;
use std::task::{Context, Poll};

#[cfg(not(debug_assertions))]
use actix_http::http::HeaderValue;
use actix_service::{Service, Transform};
use actix_web::{dev::ServiceRequest, dev::ServiceResponse, Error};
use futures::future::{ok, Ready};
use futures::Future;
#[cfg(not(debug_assertions))]
use reqwest::header::{CACHE_CONTROL, EXPIRES};

use chrono::Duration;
#[cfg(not(debug_assertions))]
use chrono::Utc;

pub struct Caching {
    pub duration: Duration,
}

impl<S, B> Transform<S> for Caching
where
    S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
    S::Future: 'static,
    B: 'static,
{
    type Request = ServiceRequest;
    type Response = ServiceResponse<B>;
    type Error = Error;
    type InitError = ();
    type Transform = CachingMiddleware<S>;
    type Future = Ready<Result<Self::Transform, Self::InitError>>;

    fn new_transform(&self, service: S) -> Self::Future {
        ok(CachingMiddleware {
            service,
            duration: self.duration,
        })
    }
}

pub struct CachingMiddleware<S> {
    service: S,
    #[allow(dead_code)]
    duration: Duration,
}

impl<S, B> Service for CachingMiddleware<S>
where
    S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
    S::Future: 'static,
    B: 'static,
{
    type Request = ServiceRequest;
    type Response = ServiceResponse<B>;
    type Error = Error;
    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;

    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        self.service.poll_ready(cx)
    }

    fn call(&mut self, req: ServiceRequest) -> Self::Future {
        let fut = self.service.call(req);
        #[cfg(not(debug_assertions))]
        let duration = self.duration.clone();

        #[cfg(not(debug_assertions))]
        return Box::pin(async move {
            let dt = Utc::now() + duration;
            let mut res = fut.await?;
            let headers = res.headers_mut();
            let value = dt.format("%a, %d %b %Y %H:%M:%S GMT").to_string();

            headers.append(EXPIRES, HeaderValue::from_str(&value).unwrap());
            headers.append(CACHE_CONTROL, HeaderValue::from_static("public,max-age=31536000"));
            return Ok(res);
        });

        #[cfg(debug_assertions)]
        return Box::pin(async move {
            let res = fut.await?;
            Ok(res)
        });
    }
}
<commit_msg>rename parameter<commit_after>use std::pin::Pin;
use std::task::{Context, Poll};

#[cfg(not(debug_assertions))]
use actix_http::http::HeaderValue;
use actix_service::{Service, Transform};
use actix_web::{dev::ServiceRequest, dev::ServiceResponse, Error};
use futures::future::{ok, Ready};
use futures::Future;
#[cfg(not(debug_assertions))]
use reqwest::header::{CACHE_CONTROL, EXPIRES};

use chrono::Duration;
#[cfg(not(debug_assertions))]
use chrono::Utc;

pub struct Caching {
    pub duration: Duration,
}

impl<S, B> Transform<S> for Caching
where
    S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
    S::Future: 'static,
    B: 'static,
{
    type Request = ServiceRequest;
    type Response = ServiceResponse<B>;
    type Error = Error;
    type InitError = ();
    type Transform = CachingMiddleware<S>;
    type Future = Ready<Result<Self::Transform, Self::InitError>>;

    fn new_transform(&self, service: S) -> Self::Future {
        ok(CachingMiddleware {
            service,
            duration: self.duration,
        })
    }
}

pub struct CachingMiddleware<S> {
    service: S,
    #[allow(dead_code)]
    duration: Duration,
}

impl<S, B> Service for CachingMiddleware<S>
where
    S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
    S::Future: 'static,
    B: 'static,
{
    type Request = ServiceRequest;
    type Response = ServiceResponse<B>;
    type Error = Error;
    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;

    fn poll_ready(&mut self, ctx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        self.service.poll_ready(ctx)
    }

    fn call(&mut self, req: ServiceRequest) -> Self::Future {
        let fut = self.service.call(req);
        #[cfg(not(debug_assertions))]
        let duration = self.duration.clone();

        #[cfg(not(debug_assertions))]
        return Box::pin(async move {
            let dt = Utc::now() + duration;
            let mut res = fut.await?;
            let headers = res.headers_mut();
            let value = dt.format("%a, %d %b %Y %H:%M:%S GMT").to_string();

            headers.append(EXPIRES, HeaderValue::from_str(&value).unwrap());
            headers.append(CACHE_CONTROL, HeaderValue::from_static("public,max-age=31536000"));
            return Ok(res);
        });

        #[cfg(debug_assertions)]
        return Box::pin(async move {
            let res = fut.await?;
            Ok(res)
        });
    }
}
<|endoftext|>


<commit_before>use super::{
    return_value::ToReturnValue, trampoline_from_glib::TrampolineFromGlib,
    trampoline_to_glib::TrampolineToGlib,
};
use crate::{
    analysis::{
        bounds::{BoundType, Bounds},
        ffi_type::ffi_type,
        ref_mode::RefMode,
        rust_type::RustType,
        trampoline_parameters::*,
        trampolines::Trampoline,
        try_from_glib::TryFromGlib,
    },
    consts::TYPE_PARAMETERS_START,
    env::Env,
    library,
    nameutil::{use_glib_if_needed, use_gtk_type},
    traits::IntoString,
    writer::primitives::tabs,
};
use log::error;
use std::io::{Result, Write};

pub fn generate(
    w: &mut dyn Write,
    env: &Env,
    analysis: &Trampoline,
    in_trait: bool,
    indent: usize,
) -> Result<()> {
    let (self_bound, end) = if in_trait {
        (format!("{}, ", TYPE_PARAMETERS_START), "")
    } else {
        (String::new(), " {")
    };

    let prepend = tabs(indent);
    let params_str = trampoline_parameters(env, analysis);
    let func_str = func_string(env, analysis, None, true);
    let ret_str = trampoline_returns(env, analysis);

    writeln!(
        w,
        "{}unsafe extern \"C\" fn {}<{}F: {}>({}, f: {}){}{}",
        prepend,
        analysis.name,
        self_bound,
        func_str,
        params_str,
        use_glib_if_needed(env, "ffi::gpointer"),
        ret_str,
        end,
    )?;
    if in_trait {
        writeln!(
            w,
            "{0}\twhere {1}: IsA<{2}>\n{0}{{",
            prepend, TYPE_PARAMETERS_START, analysis.type_name
        )?;
    }
    writeln!(w, "{}\tlet f: &F = &*(f as *const F);", prepend)?;
    transformation_vars(w, env, analysis, &prepend)?;
    let call = trampoline_call_func(env, analysis, in_trait);
    writeln!(w, "{}\t{}", prepend, call)?;
    writeln!(w, "{}}}", prepend)?;

    Ok(())
}

pub fn func_string(
    env: &Env,
    analysis: &Trampoline,
    bound_replace: Option<(char, &str)>,
    closure: bool,
) -> String {
    let param_str = func_parameters(env, analysis, bound_replace, closure);
    let return_str = func_returns(env, analysis);

    if closure {
        let concurrency_str = match analysis.concurrency {
            // If an object can be Send to other threads, this means that
            // our callback will be called from whatever thread the object
            // is sent to. But it will only be ever owned by a single thread
            // at a time, so signals can only be emitted from one thread at
            // a time and Sync is not needed
            library::Concurrency::Send | library::Concurrency::SendUnique => " + Send",
            // If an object is Sync, it can be shared between threads, and as
            // such our callback can be called from arbitrary threads and needs
            // to be Send *AND* Sync
            library::Concurrency::SendSync => " + Send + Sync",
            library::Concurrency::None => "",
        };

        format!(
            "Fn({}){}{} + 'static",
            param_str, return_str, concurrency_str
        )
    } else {
        format!("({}){}", param_str, return_str,)
    }
}

fn func_parameters(
    env: &Env,
    analysis: &Trampoline,
    bound_replace: Option<(char, &str)>,
    closure: bool,
) -> String {
    let mut param_str = String::with_capacity(100);

    for (pos, par) in analysis.parameters.rust_parameters.iter().enumerate() {
        if pos > 0 {
            param_str.push_str(", ");
            if !closure {
                param_str.push_str(&format!("{}: ", par.name));
            }
        } else if !closure {
            param_str.push_str("&self");
            continue;
        }

        let s = func_parameter(env, par, &analysis.bounds, bound_replace);
        param_str.push_str(&s);
    }

    param_str
}

fn func_parameter(
    env: &Env,
    par: &RustParameter,
    bounds: &Bounds,
    bound_replace: Option<(char, &str)>,
) -> String {
    //TODO: restore mutable support
    //let mut_str = if par.ref_mode == RefMode::ByRefMut { "mut " } else { "" };
    let mut_str = "";
    let ref_mode = if par.ref_mode == RefMode::ByRefMut {
        RefMode::ByRef
    } else {
        par.ref_mode
    };

    match bounds.get_parameter_alias_info(&par.name) {
        Some((t, bound_type)) => match bound_type {
            BoundType::NoWrapper => unreachable!(),
            BoundType::IsA(_) => {
                if *par.nullable {
                    format!("Option<&{}{}>", mut_str, t)
                } else if let Some((from, to)) = bound_replace {
                    if from == t {
                        format!("&{}{}", mut_str, to)
                    } else {
                        format!("&{}{}", mut_str, t)
                    }
                } else {
                    format!("&{}{}", mut_str, t)
                }
            }
            BoundType::AsRef(_) => t.to_string(),
        },
        None => RustType::builder(env, par.typ)
            .direction(par.direction)
            .nullable(par.nullable)
            .ref_mode(ref_mode)
            .try_build_param()
            .into_string(),
    }
}

fn func_returns(env: &Env, analysis: &Trampoline) -> String {
    if analysis.ret.typ == Default::default() {
        String::new()
    } else if analysis.inhibit {
        " -> glib::signal::Inhibit".into()
    } else if let Some(return_type) =
        analysis
            .ret
            .to_return_value(env, &TryFromGlib::default(), true)
    {
        format!(" -> {}", return_type)
    } else {
        String::new()
    }
}

fn trampoline_parameters(env: &Env, analysis: &Trampoline) -> String {
    if analysis.is_notify {
        return format!(
            "{}, _param_spec: {}",
            trampoline_parameter(env, &analysis.parameters.c_parameters[0]),
            use_glib_if_needed(env, "ffi::gpointer"),
        );
    }

    let mut parameter_strs: Vec<String> = Vec::new();
    for par in &analysis.parameters.c_parameters {
        let par_str = trampoline_parameter(env, par);
        parameter_strs.push(par_str);
    }

    parameter_strs.join(", ")
}

fn trampoline_parameter(env: &Env, par: &CParameter) -> String {
    let ffi_type = ffi_type(env, par.typ, &par.c_type);
    format!("{}: {}", par.name, ffi_type.into_string())
}

fn trampoline_returns(env: &Env, analysis: &Trampoline) -> String {
    if analysis.ret.typ == Default::default() {
        String::new()
    } else {
        let ffi_type = ffi_type(env, analysis.ret.typ, &analysis.ret.c_type);
        format!(" -> {}", ffi_type.into_string())
    }
}

fn transformation_vars(
    w: &mut dyn Write,
    env: &Env,
    analysis: &Trampoline,
    prepend: &str,
) -> Result<()> {
    use crate::analysis::trampoline_parameters::TransformationType::*;
    for transform in &analysis.parameters.transformations {
        match transform.transformation {
            None => (),
            Borrow => (),
            TreePath => {
                let c_par = &analysis.parameters.c_parameters[transform.ind_c];
                writeln!(
                    w,
                    "{}\tlet {} = from_glib_full({}({}));",
                    prepend,
                    transform.name,
                    use_gtk_type(env, "ffi::gtk_tree_path_new_from_string"),
                    c_par.name
                )?;
            }
        }
    }
    Ok(())
}

fn trampoline_call_func(env: &Env, analysis: &Trampoline, in_trait: bool) -> String {
    let params = trampoline_call_parameters(env, analysis, in_trait);
    let ret = if analysis.ret.typ == Default::default() {
        String::new()
    } else {
        analysis.ret.trampoline_to_glib(env)
    };
    format!("f({}){}", params, ret)
}

fn trampoline_call_parameters(env: &Env, analysis: &Trampoline, in_trait: bool) -> String {
    let mut need_downcast = in_trait;
    let mut parameter_strs: Vec<String> = Vec::new();
    for (ind, par) in analysis.parameters.rust_parameters.iter().enumerate() {
        let transformation = match analysis.parameters.get(ind) {
            Some(transformation) => transformation,
            None => {
                error!("No transformation for {}", par.name);
                continue;
            }
        };
        let par_str = transformation.trampoline_from_glib(env, need_downcast, *par.nullable);
        parameter_strs.push(par_str);
        need_downcast = false; //Only downcast first parameter
    }

    parameter_strs.join(", ")
}
<commit_msg>codegen/trampoline: Replace `where T: IsA` with direct `<T: IsA>` bound<commit_after>use super::{
    return_value::ToReturnValue, trampoline_from_glib::TrampolineFromGlib,
    trampoline_to_glib::TrampolineToGlib,
};
use crate::{
    analysis::{
        bounds::{BoundType, Bounds},
        ffi_type::ffi_type,
        ref_mode::RefMode,
        rust_type::RustType,
        trampoline_parameters::*,
        trampolines::Trampoline,
        try_from_glib::TryFromGlib,
    },
    consts::TYPE_PARAMETERS_START,
    env::Env,
    library,
    nameutil::{use_glib_if_needed, use_gtk_type},
    traits::IntoString,
    writer::primitives::tabs,
};
use log::error;
use std::io::{Result, Write};

pub fn generate(
    w: &mut dyn Write,
    env: &Env,
    analysis: &Trampoline,
    in_trait: bool,
    indent: usize,
) -> Result<()> {
    let self_bound = in_trait
        .then(|| format!("{}: IsA<{}>, ", TYPE_PARAMETERS_START, analysis.type_name))
        .unwrap_or_default();

    let prepend = tabs(indent);
    let params_str = trampoline_parameters(env, analysis);
    let func_str = func_string(env, analysis, None, true);
    let ret_str = trampoline_returns(env, analysis);

    writeln!(
        w,
        "{}unsafe extern \"C\" fn {}<{}F: {}>({}, f: {}){} {{",
        prepend,
        analysis.name,
        self_bound,
        func_str,
        params_str,
        use_glib_if_needed(env, "ffi::gpointer"),
        ret_str,
    )?;
    writeln!(w, "{}\tlet f: &F = &*(f as *const F);", prepend)?;
    transformation_vars(w, env, analysis, &prepend)?;
    let call = trampoline_call_func(env, analysis, in_trait);
    writeln!(w, "{}\t{}", prepend, call)?;
    writeln!(w, "{}}}", prepend)?;

    Ok(())
}

pub fn func_string(
    env: &Env,
    analysis: &Trampoline,
    bound_replace: Option<(char, &str)>,
    closure: bool,
) -> String {
    let param_str = func_parameters(env, analysis, bound_replace, closure);
    let return_str = func_returns(env, analysis);

    if closure {
        let concurrency_str = match analysis.concurrency {
            // If an object can be Send to other threads, this means that
            // our callback will be called from whatever thread the object
            // is sent to. But it will only be ever owned by a single thread
            // at a time, so signals can only be emitted from one thread at
            // a time and Sync is not needed
            library::Concurrency::Send | library::Concurrency::SendUnique => " + Send",
            // If an object is Sync, it can be shared between threads, and as
            // such our callback can be called from arbitrary threads and needs
            // to be Send *AND* Sync
            library::Concurrency::SendSync => " + Send + Sync",
            library::Concurrency::None => "",
        };

        format!(
            "Fn({}){}{} + 'static",
            param_str, return_str, concurrency_str
        )
    } else {
        format!("({}){}", param_str, return_str,)
    }
}

fn func_parameters(
    env: &Env,
    analysis: &Trampoline,
    bound_replace: Option<(char, &str)>,
    closure: bool,
) -> String {
    let mut param_str = String::with_capacity(100);

    for (pos, par) in analysis.parameters.rust_parameters.iter().enumerate() {
        if pos > 0 {
            param_str.push_str(", ");
            if !closure {
                param_str.push_str(&format!("{}: ", par.name));
            }
        } else if !closure {
            param_str.push_str("&self");
            continue;
        }

        let s = func_parameter(env, par, &analysis.bounds, bound_replace);
        param_str.push_str(&s);
    }

    param_str
}

fn func_parameter(
    env: &Env,
    par: &RustParameter,
    bounds: &Bounds,
    bound_replace: Option<(char, &str)>,
) -> String {
    //TODO: restore mutable support
    //let mut_str = if par.ref_mode == RefMode::ByRefMut { "mut " } else { "" };
    let mut_str = "";
    let ref_mode = if par.ref_mode == RefMode::ByRefMut {
        RefMode::ByRef
    } else {
        par.ref_mode
    };

    match bounds.get_parameter_alias_info(&par.name) {
        Some((t, bound_type)) => match bound_type {
            BoundType::NoWrapper => unreachable!(),
            BoundType::IsA(_) => {
                if *par.nullable {
                    format!("Option<&{}{}>", mut_str, t)
                } else if let Some((from, to)) = bound_replace {
                    if from == t {
                        format!("&{}{}", mut_str, to)
                    } else {
                        format!("&{}{}", mut_str, t)
                    }
                } else {
                    format!("&{}{}", mut_str, t)
                }
            }
            BoundType::AsRef(_) => t.to_string(),
        },
        None => RustType::builder(env, par.typ)
            .direction(par.direction)
            .nullable(par.nullable)
            .ref_mode(ref_mode)
            .try_build_param()
            .into_string(),
    }
}

fn func_returns(env: &Env, analysis: &Trampoline) -> String {
    if analysis.ret.typ == Default::default() {
        String::new()
    } else if analysis.inhibit {
        " -> glib::signal::Inhibit".into()
    } else if let Some(return_type) =
        analysis
            .ret
            .to_return_value(env, &TryFromGlib::default(), true)
    {
        format!(" -> {}", return_type)
    } else {
        String::new()
    }
}

fn trampoline_parameters(env: &Env, analysis: &Trampoline) -> String {
    if analysis.is_notify {
        return format!(
            "{}, _param_spec: {}",
            trampoline_parameter(env, &analysis.parameters.c_parameters[0]),
            use_glib_if_needed(env, "ffi::gpointer"),
        );
    }

    let mut parameter_strs: Vec<String> = Vec::new();
    for par in &analysis.parameters.c_parameters {
        let par_str = trampoline_parameter(env, par);
        parameter_strs.push(par_str);
    }

    parameter_strs.join(", ")
}

fn trampoline_parameter(env: &Env, par: &CParameter) -> String {
    let ffi_type = ffi_type(env, par.typ, &par.c_type);
    format!("{}: {}", par.name, ffi_type.into_string())
}

fn trampoline_returns(env: &Env, analysis: &Trampoline) -> String {
    if analysis.ret.typ == Default::default() {
        String::new()
    } else {
        let ffi_type = ffi_type(env, analysis.ret.typ, &analysis.ret.c_type);
        format!(" -> {}", ffi_type.into_string())
    }
}

fn transformation_vars(
    w: &mut dyn Write,
    env: &Env,
    analysis: &Trampoline,
    prepend: &str,
) -> Result<()> {
    use crate::analysis::trampoline_parameters::TransformationType::*;
    for transform in &analysis.parameters.transformations {
        match transform.transformation {
            None => (),
            Borrow => (),
            TreePath => {
                let c_par = &analysis.parameters.c_parameters[transform.ind_c];
                writeln!(
                    w,
                    "{}\tlet {} = from_glib_full({}({}));",
                    prepend,
                    transform.name,
                    use_gtk_type(env, "ffi::gtk_tree_path_new_from_string"),
                    c_par.name
                )?;
            }
        }
    }
    Ok(())
}

fn trampoline_call_func(env: &Env, analysis: &Trampoline, in_trait: bool) -> String {
    let params = trampoline_call_parameters(env, analysis, in_trait);
    let ret = if analysis.ret.typ == Default::default() {
        String::new()
    } else {
        analysis.ret.trampoline_to_glib(env)
    };
    format!("f({}){}", params, ret)
}

fn trampoline_call_parameters(env: &Env, analysis: &Trampoline, in_trait: bool) -> String {
    let mut need_downcast = in_trait;
    let mut parameter_strs: Vec<String> = Vec::new();
    for (ind, par) in analysis.parameters.rust_parameters.iter().enumerate() {
        let transformation = match analysis.parameters.get(ind) {
            Some(transformation) => transformation,
            None => {
                error!("No transformation for {}", par.name);
                continue;
            }
        };
        let par_str = transformation.trampoline_from_glib(env, need_downcast, *par.nullable);
        parameter_strs.push(par_str);
        need_downcast = false; //Only downcast first parameter
    }

    parameter_strs.join(", ")
}
<|endoftext|>


<commit_before>//
// sprocketnes/input.rs
//
// Author: Patrick Walton
//

use mem::Mem;

use sdl::event::{DownKey, EscapeKey, LKey, LeftKey, RShiftKey, ReturnKey, RightKey, SKey, UpKey};
use sdl::event::{Key, KeyEvent, NoEvent, QuitEvent, XKey, ZKey};
use sdl::event;

//
// The "strobe state": the order in which the NES reads the buttons.
//

static STROBE_STATE_A: u8        = 0;
static STROBE_STATE_B: u8        = 1;
static STROBE_STATE_SELECT: u8   = 2;
static STROBE_STATE_START: u8    = 3;
static STROBE_STATE_UP: u8       = 4;
static STROBE_STATE_DOWN: u8     = 5;
static STROBE_STATE_LEFT: u8     = 6;
static STROBE_STATE_RIGHT: u8    = 7;

struct StrobeState(u8);

impl StrobeState {
    // Given a GamePadState structure, returns the state of the given button.
    fn get(&self, state: &GamePadState) -> bool {
        match **self {
            STROBE_STATE_A      => state.a,
            STROBE_STATE_B      => state.b,
            STROBE_STATE_SELECT => state.select,
            STROBE_STATE_START  => state.start,
            STROBE_STATE_UP     => state.up,
            STROBE_STATE_DOWN   => state.down,
            STROBE_STATE_LEFT   => state.left,
            STROBE_STATE_RIGHT  => state.right,
            _                   => fail!("shouldn't happen")
        }
    }

    fn next(&mut self) {
        *self = StrobeState((**self + 1) & 7);
    }

    fn reset(&mut self) {
        *self = StrobeState(STROBE_STATE_A);
    }
}

//
// The standard NES game pad state
//

pub struct GamePadState {
    left: bool,
    down: bool,
    up: bool,
    right: bool,
    a: bool,
    b: bool,
    select: bool,
    start: bool,

    strobe_state: StrobeState,
}

pub struct Input {
    gamepad_0: GamePadState
}

pub enum InputResult {
    Continue,   // Keep playing.
    Quit,       // Quit the emulator.
    SaveState,  // Save a state.
    LoadState,  // Load a state.
}

impl Input {
    pub fn new() -> Input {
        Input {
            gamepad_0: GamePadState {
                left: false,
                down: false,
                up: false,
                right: false,
                a: false,
                b: false,
                select: false,
                start: false,

                strobe_state: StrobeState(STROBE_STATE_A)
            }
        }
    }

    fn handle_gamepad_event(&mut self, key: Key, down: bool) {
        match key {
            LeftKey   => self.gamepad_0.left   = down,
            DownKey   => self.gamepad_0.down   = down,
            UpKey     => self.gamepad_0.up     = down,
            RightKey  => self.gamepad_0.right  = down,
            ZKey      => self.gamepad_0.a      = down,
            XKey      => self.gamepad_0.b      = down,
            RShiftKey => self.gamepad_0.select = down,
            ReturnKey => self.gamepad_0.start  = down,
            _         => {}
        }
    }

    pub fn check_input(&mut self) -> InputResult {
        loop {
            match event::poll_event() {
                NoEvent => break,
                KeyEvent(EscapeKey, _, _, _) => return Quit,
                KeyEvent(SKey, true, _, _) => return SaveState,
                KeyEvent(LKey, true, _, _) => return LoadState,
                KeyEvent(key, down, _, _) => self.handle_gamepad_event(key, down),
                QuitEvent => return Quit,
                _ => {}
            }
        }
        return Continue;
    }
}

impl Mem for Input {
    fn loadb(&mut self, addr: u16) -> u8 {
        if addr == 0x4016 {
            let result = self.gamepad_0.strobe_state.get(&self.gamepad_0) as u8;
            self.gamepad_0.strobe_state.next();
            result
        } else {
            0
        }
    }

    fn storeb(&mut self, addr: u16, _: u8) {
        if addr == 0x4016 {
            // FIXME: This is not really accurate; you're supposed to not reset until you see
            // 1 strobed than 0. But I doubt this will break anything.
            self.gamepad_0.strobe_state.reset();
        }
    }
}

<commit_msg>Update from single tuple struct for input.rs<commit_after>//
// sprocketnes/input.rs
//
// Author: Patrick Walton
//

use mem::Mem;

use sdl::event::{DownKey, EscapeKey, LKey, LeftKey, RShiftKey, ReturnKey, RightKey, SKey, UpKey};
use sdl::event::{Key, KeyEvent, NoEvent, QuitEvent, XKey, ZKey};
use sdl::event;

//
// The "strobe state": the order in which the NES reads the buttons.
//

static STROBE_STATE_A: u8        = 0;
static STROBE_STATE_B: u8        = 1;
static STROBE_STATE_SELECT: u8   = 2;
static STROBE_STATE_START: u8    = 3;
static STROBE_STATE_UP: u8       = 4;
static STROBE_STATE_DOWN: u8     = 5;
static STROBE_STATE_LEFT: u8     = 6;
static STROBE_STATE_RIGHT: u8    = 7;

struct StrobeState{ val: u8 }

impl Deref<u8> for StrobeState {
    fn deref<'a>(&'a self) -> &'a u8 {
        &self.val
    }
}

impl StrobeState {
    // Given a GamePadState structure, returns the state of the given button.
    fn get(&self, state: &GamePadState) -> bool {
        match **self {
            STROBE_STATE_A      => state.a,
            STROBE_STATE_B      => state.b,
            STROBE_STATE_SELECT => state.select,
            STROBE_STATE_START  => state.start,
            STROBE_STATE_UP     => state.up,
            STROBE_STATE_DOWN   => state.down,
            STROBE_STATE_LEFT   => state.left,
            STROBE_STATE_RIGHT  => state.right,
            _                   => fail!("shouldn't happen")
        }
    }

    fn next(&mut self) {
        *self = StrobeState{val: (**self + 1) & 7};
    }

    fn reset(&mut self) {
        *self = StrobeState{val: STROBE_STATE_A};
    }
}

//
// The standard NES game pad state
//

pub struct GamePadState {
    left: bool,
    down: bool,
    up: bool,
    right: bool,
    a: bool,
    b: bool,
    select: bool,
    start: bool,

    strobe_state: StrobeState,
}

pub struct Input {
    gamepad_0: GamePadState
}

pub enum InputResult {
    Continue,   // Keep playing.
    Quit,       // Quit the emulator.
    SaveState,  // Save a state.
    LoadState,  // Load a state.
}

impl Input {
    pub fn new() -> Input {
        Input {
            gamepad_0: GamePadState {
                left: false,
                down: false,
                up: false,
                right: false,
                a: false,
                b: false,
                select: false,
                start: false,

                strobe_state: StrobeState{val: STROBE_STATE_A}
            }
        }
    }

    fn handle_gamepad_event(&mut self, key: Key, down: bool) {
        match key {
            LeftKey   => self.gamepad_0.left   = down,
            DownKey   => self.gamepad_0.down   = down,
            UpKey     => self.gamepad_0.up     = down,
            RightKey  => self.gamepad_0.right  = down,
            ZKey      => self.gamepad_0.a      = down,
            XKey      => self.gamepad_0.b      = down,
            RShiftKey => self.gamepad_0.select = down,
            ReturnKey => self.gamepad_0.start  = down,
            _         => {}
        }
    }

    pub fn check_input(&mut self) -> InputResult {
        loop {
            match event::poll_event() {
                NoEvent => break,
                KeyEvent(EscapeKey, _, _, _) => return Quit,
                KeyEvent(SKey, true, _, _) => return SaveState,
                KeyEvent(LKey, true, _, _) => return LoadState,
                KeyEvent(key, down, _, _) => self.handle_gamepad_event(key, down),
                QuitEvent => return Quit,
                _ => {}
            }
        }
        return Continue;
    }
}

impl Mem for Input {
    fn loadb(&mut self, addr: u16) -> u8 {
        if addr == 0x4016 {
            let result = self.gamepad_0.strobe_state.get(&self.gamepad_0) as u8;
            self.gamepad_0.strobe_state.next();
            result
        } else {
            0
        }
    }

    fn storeb(&mut self, addr: u16, _: u8) {
        if addr == 0x4016 {
            // FIXME: This is not really accurate; you're supposed to not reset until you see
            // 1 strobed than 0. But I doubt this will break anything.
            self.gamepad_0.strobe_state.reset();
        }
    }
}

<|endoftext|>


<commit_before>use std::collections::HashMap;

use protobuf::descriptor::file_options;
use protobuf::descriptor::FileDescriptorProto;
use protobuf::reflect::FileDescriptor;
use protobuf_parse::ProtoPath;

use crate::compiler_plugin;
use crate::customize::ctx::CustomizeElemCtx;
use crate::customize::rustproto_proto::customize_from_rustproto_for_file;
use crate::gen::code_writer::CodeWriter;
use crate::gen::enums::EnumGen;
use crate::gen::extensions::write_extensions;
use crate::gen::file_descriptor::write_file_descriptor_data;
use crate::gen::inside::protobuf_crate_path;
use crate::gen::message::MessageGen;
use crate::gen::paths::proto_path_to_rust_mod;
use crate::gen::scope::FileScope;
use crate::gen::scope::RootScope;
use crate::proto_name_to_rs;

pub(crate) struct GenFileResult {
    pub(crate) compiler_plugin_result: compiler_plugin::GenResult,
    pub(crate) mod_name: String,
}

pub(crate) fn gen_file(
    file_descriptor: &FileDescriptor,
    _files_map: &HashMap<&ProtoPath, &FileDescriptor>,
    root_scope: &RootScope,
    parent_customize: &CustomizeElemCtx,
    parser: &str,
) -> anyhow::Result<GenFileResult> {
    let customize = parent_customize.child(
        &customize_from_rustproto_for_file(file_descriptor.proto().options.get_or_default()),
        file_descriptor,
    );

    let file_scope = FileScope { file_descriptor };
    let scope = file_scope.to_scope();
    let lite_runtime = customize.for_elem.lite_runtime.unwrap_or_else(|| {
        file_descriptor
            .proto()
            .options
            .get_or_default()
            .optimize_for()
            == file_options::OptimizeMode::LITE_RUNTIME
    });

    let v = CodeWriter::with(|w| {
        w.write_generated_by("rust-protobuf", env!("CARGO_PKG_VERSION"), parser);

        w.write_line("");
        w.write_line(&format!(
            "//! Generated file from `{}`",
            file_descriptor.proto().name()
        ));
        if customize.for_elem.inside_protobuf != Some(true) {
            w.write_line("");
            w.write_line("/// Generated files are compatible only with the same version");
            w.write_line("/// of protobuf runtime.");
            w.write_line(&format!(
                "const _PROTOBUF_VERSION_CHECK: () = {}::{};",
                protobuf_crate_path(&customize.for_elem),
                protobuf::VERSION_IDENT
            ));
        }

        static NESTED_TYPE_NUMBER: protobuf::rt::Lazy<i32> = protobuf::rt::Lazy::new();
        let message_type_number = *NESTED_TYPE_NUMBER.get(|| {
            protobuf::reflect::MessageDescriptor::for_type::<FileDescriptorProto>()
                .field_by_name("message_type")
                .expect("`message_type` must exist")
                .proto()
                .number()
        });

        let mut path = vec![message_type_number, 0];
        for (id, message) in scope.messages().iter().enumerate() {
            // ignore map entries, because they are not used in map fields
            if !message.is_map()? {
                path[1] = id as i32;

                w.write_line("");
                MessageGen::new(
                    file_descriptor,
                    message,
                    &root_scope,
                    &customize,
                    &path,
                    file_descriptor.proto().source_code_info.as_ref(),
                )?
                .write(w);
            }
        }

        static ENUM_TYPE_NUMBER: protobuf::rt::Lazy<i32> = protobuf::rt::Lazy::new();
        let enum_type_number = *ENUM_TYPE_NUMBER.get(|| {
            protobuf::reflect::MessageDescriptor::for_type::<FileDescriptorProto>()
                .field_by_name("enum_type")
                .expect("`enum_type` must exist")
                .proto()
                .number()
        });

        let mut path = vec![enum_type_number, 0];
        for (id, enum_type) in scope.enums().iter().enumerate() {
            path[1] = id as i32;

            w.write_line("");
            EnumGen::new(
                enum_type,
                &customize,
                root_scope,
                &path,
                file_descriptor.proto().source_code_info.as_ref(),
            )
            .write(w);
        }

        write_extensions(file_descriptor, &root_scope, w, &customize);

        if !lite_runtime {
            w.write_line("");
            write_file_descriptor_data(file_descriptor, &customize.for_elem, w);
        }

        Ok(())
    })?;

    Ok(GenFileResult {
        compiler_plugin_result: compiler_plugin::GenResult {
            name: proto_name_to_rs(file_descriptor.proto().name()),
            content: v.into_bytes(),
        },
        mod_name: proto_path_to_rust_mod(file_descriptor.proto().name()).into_string(),
    })
}
<commit_msg>Correctly detect lite_runtime option at file level<commit_after>use std::collections::HashMap;

use protobuf::descriptor::file_options;
use protobuf::descriptor::FileDescriptorProto;
use protobuf::reflect::FileDescriptor;
use protobuf_parse::ProtoPath;

use crate::compiler_plugin;
use crate::customize::ctx::CustomizeElemCtx;
use crate::customize::rustproto_proto::customize_from_rustproto_for_file;
use crate::gen::code_writer::CodeWriter;
use crate::gen::enums::EnumGen;
use crate::gen::extensions::write_extensions;
use crate::gen::file_descriptor::write_file_descriptor_data;
use crate::gen::inside::protobuf_crate_path;
use crate::gen::message::MessageGen;
use crate::gen::paths::proto_path_to_rust_mod;
use crate::gen::scope::FileScope;
use crate::gen::scope::RootScope;
use crate::proto_name_to_rs;

pub(crate) struct GenFileResult {
    pub(crate) compiler_plugin_result: compiler_plugin::GenResult,
    pub(crate) mod_name: String,
}

pub(crate) fn gen_file(
    file_descriptor: &FileDescriptor,
    _files_map: &HashMap<&ProtoPath, &FileDescriptor>,
    root_scope: &RootScope,
    parent_customize: &CustomizeElemCtx,
    parser: &str,
) -> anyhow::Result<GenFileResult> {
    let lite_runtime_from_builtin_option = file_descriptor
        .proto()
        .options
        .get_or_default()
        .optimize_for()
        == file_options::OptimizeMode::LITE_RUNTIME;

    let mut customize_from_proto =
        customize_from_rustproto_for_file(file_descriptor.proto().options.get_or_default());
    if customize_from_proto.lite_runtime.is_none()
        && parent_customize.for_elem.lite_runtime.is_none()
    {
        customize_from_proto.lite_runtime = Some(lite_runtime_from_builtin_option);
    }

    let customize = parent_customize.child(&customize_from_proto, file_descriptor);

    let file_scope = FileScope { file_descriptor };
    let scope = file_scope.to_scope();

    let lite_runtime = customize.for_elem.lite_runtime.unwrap_or(false);

    let v = CodeWriter::with(|w| {
        w.write_generated_by("rust-protobuf", env!("CARGO_PKG_VERSION"), parser);

        w.write_line("");
        w.write_line(&format!(
            "//! Generated file from `{}`",
            file_descriptor.proto().name()
        ));

        if customize.for_elem.lite_runtime.unwrap_or(false) {
            w.comment("Generated for lite runtime");
        }

        if customize.for_elem.inside_protobuf != Some(true) {
            w.write_line("");
            w.write_line("/// Generated files are compatible only with the same version");
            w.write_line("/// of protobuf runtime.");
            w.write_line(&format!(
                "const _PROTOBUF_VERSION_CHECK: () = {}::{};",
                protobuf_crate_path(&customize.for_elem),
                protobuf::VERSION_IDENT
            ));
        }

        static NESTED_TYPE_NUMBER: protobuf::rt::Lazy<i32> = protobuf::rt::Lazy::new();
        let message_type_number = *NESTED_TYPE_NUMBER.get(|| {
            protobuf::reflect::MessageDescriptor::for_type::<FileDescriptorProto>()
                .field_by_name("message_type")
                .expect("`message_type` must exist")
                .proto()
                .number()
        });

        let mut path = vec![message_type_number, 0];
        for (id, message) in scope.messages().iter().enumerate() {
            // ignore map entries, because they are not used in map fields
            if !message.is_map()? {
                path[1] = id as i32;

                w.write_line("");
                MessageGen::new(
                    file_descriptor,
                    message,
                    &root_scope,
                    &customize,
                    &path,
                    file_descriptor.proto().source_code_info.as_ref(),
                )?
                .write(w);
            }
        }

        static ENUM_TYPE_NUMBER: protobuf::rt::Lazy<i32> = protobuf::rt::Lazy::new();
        let enum_type_number = *ENUM_TYPE_NUMBER.get(|| {
            protobuf::reflect::MessageDescriptor::for_type::<FileDescriptorProto>()
                .field_by_name("enum_type")
                .expect("`enum_type` must exist")
                .proto()
                .number()
        });

        let mut path = vec![enum_type_number, 0];
        for (id, enum_type) in scope.enums().iter().enumerate() {
            path[1] = id as i32;

            w.write_line("");
            EnumGen::new(
                enum_type,
                &customize,
                root_scope,
                &path,
                file_descriptor.proto().source_code_info.as_ref(),
            )
            .write(w);
        }

        write_extensions(file_descriptor, &root_scope, w, &customize);

        if !lite_runtime {
            w.write_line("");
            write_file_descriptor_data(file_descriptor, &customize.for_elem, w);
        }

        Ok(())
    })?;

    Ok(GenFileResult {
        compiler_plugin_result: compiler_plugin::GenResult {
            name: proto_name_to_rs(file_descriptor.proto().name()),
            content: v.into_bytes(),
        },
        mod_name: proto_path_to_rust_mod(file_descriptor.proto().name()).into_string(),
    })
}
<|endoftext|>


<commit_before>use std::u32;
use std::sync::Arc;
use parking_lot::RwLock;
use elements::MemoryType;
use interpreter::Error;
use interpreter::module::check_limits;

/// Linear memory page size.
pub const LINEAR_MEMORY_PAGE_SIZE: u32 = 65536;
/// Maximal number of pages.
const LINEAR_MEMORY_MAX_PAGES: u32 = 65536;

/// Linear memory instance.
pub struct MemoryInstance {
	/// Linear memory buffer.
	buffer: RwLock<Vec<u8>>,
	/// Maximum buffer size.
	maximum_size: u32,
}

struct CheckedRegion<'a, B: 'a> where B: ::std::ops::Deref<Target=Vec<u8>> {
	buffer: &'a B,
	offset: usize,
	size: usize,
}

impl<'a, B: 'a> CheckedRegion<'a, B> where B: ::std::ops::Deref<Target=Vec<u8>> {
	fn range(&self) -> ::std::ops::Range<usize> {
		self.offset..self.offset+self.size
	}

	fn slice(&self) -> &[u8] {
		&self.buffer[self.range()]
	}
}

impl MemoryInstance {
	/// Create new linear memory instance.
	pub fn new(memory_type: &MemoryType) -> Result<Arc<Self>, Error> {
		check_limits(memory_type.limits())?;

		let maximum_size = match memory_type.limits().maximum() {
			Some(maximum_pages) if maximum_pages > LINEAR_MEMORY_MAX_PAGES =>
				return Err(Error::Memory(format!("maximum memory size must be at most {} pages", LINEAR_MEMORY_MAX_PAGES))),
			Some(maximum_pages) => maximum_pages.saturating_mul(LINEAR_MEMORY_PAGE_SIZE),
			None => u32::MAX,
		};
		let initial_size = calculate_memory_size(0, memory_type.limits().initial(), maximum_size)
			.ok_or(Error::Memory(format!("initial memory size must be at most {} pages", LINEAR_MEMORY_MAX_PAGES)))?;

		let memory = MemoryInstance {
			buffer: RwLock::new(Vec::with_capacity(initial_size as usize)),
			maximum_size: maximum_size,
		};
		if memory.grow(memory_type.limits().initial())? == u32::MAX {
			return Err(Error::Memory(format!("error initializing {}-bytes linear memory region", initial_size)));
		}

		Ok(Arc::new(memory))
	}

	/// Return linear memory size (in pages).
	pub fn size(&self) -> u32 {
		self.buffer.read().len() as u32 / LINEAR_MEMORY_PAGE_SIZE
	}

	/// Get data at given offset.
	pub fn get(&self, offset: u32, size: usize) -> Result<Vec<u8>, Error> {
		let buffer = self.buffer.read();
		let region = self.checked_region(&buffer, offset as usize, size)?;

		Ok(region.slice().to_vec())
	}

	/// Set data at given offset.
	pub fn set(&self, offset: u32, value: &[u8]) -> Result<(), Error> {
		let mut buffer = self.buffer.write();
		let range = self.checked_region(&buffer, offset as usize, value.len())?.range();

		buffer[range].copy_from_slice(value);

		Ok(())
	}

	/// Increases the size of the linear memory by given number of pages.
	/// Returns -1 if allocation fails or previous memory size, if succeeds.
	pub fn grow(&self, pages: u32) -> Result<u32, Error> {
		let mut buffer = self.buffer.write();
		let old_size = buffer.len() as u32;
		match calculate_memory_size(old_size, pages, self.maximum_size) {
			None => Ok(u32::MAX),
			Some(new_size) => {
				buffer.resize(new_size as usize, 0);
				Ok(old_size / LINEAR_MEMORY_PAGE_SIZE)
			},
		}
	}

	fn checked_region<'a, B>(&self, buffer: &'a B, offset: usize, size: usize) -> Result<CheckedRegion<'a, B>, Error>
		where B: ::std::ops::Deref<Target=Vec<u8>>
	{
		let end = offset.checked_add(size)
			.ok_or(Error::Memory(format!("trying to access memory block of size {} from offset {}", size, offset)))?;

		if end > buffer.len() {
			return Err(Error::Memory(format!("trying to access region [{}..{}] in memory [0..{}]", offset, end, buffer.len())));
		}

		Ok(CheckedRegion {
			buffer: buffer,
			offset: offset,
			size: size,
		})
	}

	/// Copy memory region
	pub fn copy(&self, src_offset: usize, dst_offset: usize, len: usize) -> Result<(), Error> {
		let buffer = self.buffer.write();

		let read_region = self.checked_region(&buffer, src_offset, len)?;
		let write_region = self.checked_region(&buffer, dst_offset, len)?;

		unsafe { ::std::ptr::copy(
			buffer[read_region.range()].as_ptr(),
			buffer[write_region.range()].as_ptr() as *mut _,
			len,
		)}

		Ok(())
	}

	/// Zero memory region
	pub fn zero(&self, offset: usize, len: usize) -> Result<(), Error> {
		let mut buffer = self.buffer.write();

		let range = self.checked_region(&buffer, offset, len)?.range();
		for val in &mut buffer[range] { *val = 0 }
		Ok(())
	}
}

fn calculate_memory_size(old_size: u32, additional_pages: u32, maximum_size: u32) -> Option<u32> {
	additional_pages
		.checked_mul(LINEAR_MEMORY_PAGE_SIZE)
		.and_then(|size| size.checked_add(old_size))
		.and_then(|size| if size > maximum_size {
			None
		} else {
			Some(size)
		})
}
<commit_msg>fixed test lags<commit_after>use std::u32;
use std::sync::Arc;
use parking_lot::RwLock;
use elements::MemoryType;
use interpreter::Error;
use interpreter::module::check_limits;

/// Linear memory page size.
pub const LINEAR_MEMORY_PAGE_SIZE: u32 = 65536;
/// Maximal number of pages.
const LINEAR_MEMORY_MAX_PAGES: u32 = 65536;

/// Linear memory instance.
pub struct MemoryInstance {
	/// Linear memory buffer.
	buffer: RwLock<Vec<u8>>,
	/// Maximum buffer size.
	maximum_size: u32,
}

struct CheckedRegion<'a, B: 'a> where B: ::std::ops::Deref<Target=Vec<u8>> {
	buffer: &'a B,
	offset: usize,
	size: usize,
}

impl<'a, B: 'a> CheckedRegion<'a, B> where B: ::std::ops::Deref<Target=Vec<u8>> {
	fn range(&self) -> ::std::ops::Range<usize> {
		self.offset..self.offset+self.size
	}

	fn slice(&self) -> &[u8] {
		&self.buffer[self.range()]
	}
}

impl MemoryInstance {
	/// Create new linear memory instance.
	pub fn new(memory_type: &MemoryType) -> Result<Arc<Self>, Error> {
		check_limits(memory_type.limits())?;

		let maximum_size = match memory_type.limits().maximum() {
			Some(maximum_pages) if maximum_pages > LINEAR_MEMORY_MAX_PAGES =>
				return Err(Error::Memory(format!("maximum memory size must be at most {} pages", LINEAR_MEMORY_MAX_PAGES))),
			Some(maximum_pages) => maximum_pages.saturating_mul(LINEAR_MEMORY_PAGE_SIZE),
			None => u32::MAX,
		};
		let initial_size = calculate_memory_size(0, memory_type.limits().initial(), maximum_size)
			.ok_or(Error::Memory(format!("initial memory size must be at most {} pages", LINEAR_MEMORY_MAX_PAGES)))?;

		let memory = MemoryInstance {
			buffer: RwLock::new(vec![0; initial_size as usize]),
			maximum_size: maximum_size,
		};
		if memory.grow(memory_type.limits().initial())? == u32::MAX {
			return Err(Error::Memory(format!("error initializing {}-bytes linear memory region", initial_size)));
		}

		Ok(Arc::new(memory))
	}

	/// Return linear memory size (in pages).
	pub fn size(&self) -> u32 {
		self.buffer.read().len() as u32 / LINEAR_MEMORY_PAGE_SIZE
	}

	/// Get data at given offset.
	pub fn get(&self, offset: u32, size: usize) -> Result<Vec<u8>, Error> {
		let buffer = self.buffer.read();
		let region = self.checked_region(&buffer, offset as usize, size)?;

		Ok(region.slice().to_vec())
	}

	/// Set data at given offset.
	pub fn set(&self, offset: u32, value: &[u8]) -> Result<(), Error> {
		let mut buffer = self.buffer.write();
		let range = self.checked_region(&buffer, offset as usize, value.len())?.range();

		buffer[range].copy_from_slice(value);

		Ok(())
	}

	/// Increases the size of the linear memory by given number of pages.
	/// Returns -1 if allocation fails or previous memory size, if succeeds.
	pub fn grow(&self, pages: u32) -> Result<u32, Error> {
		let mut buffer = self.buffer.write();
		let old_size = buffer.len() as u32;
		match calculate_memory_size(old_size, pages, self.maximum_size) {
			None => Ok(u32::MAX),
			Some(new_size) => {
				buffer.resize(new_size as usize, 0);
				Ok(old_size / LINEAR_MEMORY_PAGE_SIZE)
			},
		}
	}

	fn checked_region<'a, B>(&self, buffer: &'a B, offset: usize, size: usize) -> Result<CheckedRegion<'a, B>, Error>
		where B: ::std::ops::Deref<Target=Vec<u8>>
	{
		let end = offset.checked_add(size)
			.ok_or(Error::Memory(format!("trying to access memory block of size {} from offset {}", size, offset)))?;

		if end > buffer.len() {
			return Err(Error::Memory(format!("trying to access region [{}..{}] in memory [0..{}]", offset, end, buffer.len())));
		}

		Ok(CheckedRegion {
			buffer: buffer,
			offset: offset,
			size: size,
		})
	}

	/// Copy memory region
	pub fn copy(&self, src_offset: usize, dst_offset: usize, len: usize) -> Result<(), Error> {
		let buffer = self.buffer.write();

		let read_region = self.checked_region(&buffer, src_offset, len)?;
		let write_region = self.checked_region(&buffer, dst_offset, len)?;

		unsafe { ::std::ptr::copy(
			buffer[read_region.range()].as_ptr(),
			buffer[write_region.range()].as_ptr() as *mut _,
			len,
		)}

		Ok(())
	}

	/// Zero memory region
	pub fn zero(&self, offset: usize, len: usize) -> Result<(), Error> {
		let mut buffer = self.buffer.write();

		let range = self.checked_region(&buffer, offset, len)?.range();
		for val in &mut buffer[range] { *val = 0 }
		Ok(())
	}
}

fn calculate_memory_size(old_size: u32, additional_pages: u32, maximum_size: u32) -> Option<u32> {
	additional_pages
		.checked_mul(LINEAR_MEMORY_PAGE_SIZE)
		.and_then(|size| size.checked_add(old_size))
		.and_then(|size| if size > maximum_size {
			None
		} else {
			Some(size)
		})
}
<|endoftext|>


<commit_before>#![feature(question_mark)]

extern crate docopt;
extern crate lalrpop_intern;
extern crate graph_algorithms;
extern crate nll_repr;
extern crate rustc_serialize;

use docopt::Docopt;
use nll_repr::repr::*;
use std::env::args;
use std::error::Error;
use std::fs::File;
use std::io::Read;
use std::process;

#[macro_use] mod log;
mod env;
use self::env::Environment;
mod graph;
mod region;
mod regionck;
mod relate;
use self::graph::FuncGraph;

fn main() {
    let args: Args =
        Docopt::new(USAGE)
        .and_then(|d| d.argv(args()).decode())
        .unwrap_or_else(|e| e.exit());

    for input in &args.arg_inputs {
        match process_input(&args, input) {
            Ok(()) => { }
            Err(err) => {
                println!("{}: {}", input, err);
                process::exit(1);
            }
        }
    }
}

fn process_input(args: &Args, input: &str) -> Result<(), Box<Error>> {
    let ballast = Ballast::new();
    let mut arena = Arena::new(&ballast);
    let mut file_text = String::new();
    let mut file = try!(File::open(input));
    if file.read_to_string(&mut file_text).is_err() {
        return try!(Err(String::from("not UTF-8")));
    }
    let func = try!(Func::parse(&mut arena, &file_text));
    let graph = FuncGraph::new(func);
    graph::with_graph(&graph, || {
        let env = Environment::new(&graph);

        if args.flag_dominators {
            env.dump_dominators();
        }

        try!(regionck::region_check(&env));
        println!("{}: OK", input);
        Ok(())
    })
}

const USAGE: &'static str = "
Usage: nll [options] <inputs>...

Options:
  --help
  --dominators
  --post-dominators
";

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_inputs: Vec<String>,
    flag_dominators: bool,
    flag_post_dominators: bool,
    flag_help: bool,
}
<commit_msg>question-mark now stable<commit_after>extern crate docopt;
extern crate lalrpop_intern;
extern crate graph_algorithms;
extern crate nll_repr;
extern crate rustc_serialize;

use docopt::Docopt;
use nll_repr::repr::*;
use std::env::args;
use std::error::Error;
use std::fs::File;
use std::io::Read;
use std::process;

#[macro_use] mod log;
mod env;
use self::env::Environment;
mod graph;
mod region;
mod regionck;
mod relate;
use self::graph::FuncGraph;

fn main() {
    let args: Args =
        Docopt::new(USAGE)
        .and_then(|d| d.argv(args()).decode())
        .unwrap_or_else(|e| e.exit());

    for input in &args.arg_inputs {
        match process_input(&args, input) {
            Ok(()) => { }
            Err(err) => {
                println!("{}: {}", input, err);
                process::exit(1);
            }
        }
    }
}

fn process_input(args: &Args, input: &str) -> Result<(), Box<Error>> {
    let ballast = Ballast::new();
    let mut arena = Arena::new(&ballast);
    let mut file_text = String::new();
    let mut file = try!(File::open(input));
    if file.read_to_string(&mut file_text).is_err() {
        return try!(Err(String::from("not UTF-8")));
    }
    let func = try!(Func::parse(&mut arena, &file_text));
    let graph = FuncGraph::new(func);
    graph::with_graph(&graph, || {
        let env = Environment::new(&graph);

        if args.flag_dominators {
            env.dump_dominators();
        }

        try!(regionck::region_check(&env));
        println!("{}: OK", input);
        Ok(())
    })
}

const USAGE: &'static str = "
Usage: nll [options] <inputs>...

Options:
  --help
  --dominators
  --post-dominators
";

#[derive(Debug, RustcDecodable)]
struct Args {
    arg_inputs: Vec<String>,
    flag_dominators: bool,
    flag_post_dominators: bool,
    flag_help: bool,
}
<|endoftext|>


<commit_before>//! # Data structures that describe Syn's syntax tree.
//!
//! The Syn syntax tree is made up of more than 200 types. Occasionally it can
//! come up that you need to implement some behavior across them all.
//!
//! - For example [the Rust integration for AST Explorer][astexplorer] wants to
//!   turn a syntax tree from Syn into a JavaScript value understood by the
//!   platform's existing cross-language syntax tree visualization code.
//!
//!   [astexplorer]: https://astexplorer.net/#/gist/388150a52f74d45a355d2b5e865ded96/0c6d563f28d900472f699c21a1845ad20ae9927f
//!
//! - As another example from within Syn itself, the traits and implementations
//!   of the [`visit`], [`visit_mut`], and [`fold`] modules can be generated
//!   programmatically from a description of the syntax tree.
//!
//!   [`visit`]: https://docs.rs/syn/0.15/syn/visit/index.html
//!   [`visit_mut`]: https://docs.rs/syn/0.15/syn/visit_mut/index.html
//!   [`fold`]: https://docs.rs/syn/0.15/syn/fold/index.html
//!
//! To make this type of code as easy as possible to implement in any language,
//! every Syn release comes with a machine-readable description of that version
//! of the syntax tree as a JSON file [syn.json]. This `syn-codegen` crate
//! provides the canonical data structures for parsing and making use of the
//! representation in syn.json from Rust code.
//!
//! [syn.json]: https://raw.githubusercontent.com/dtolnay/syn/master/syn.json

use indexmap::IndexMap;
use semver::Version;
use serde::{Deserialize, Deserializer, Serialize};

use std::collections::{BTreeMap, BTreeSet};

#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct Definitions {
    /// The Syn version used to generate the introspection file.
    pub version: Version,
    pub types: Vec<Node>,
    pub tokens: BTreeMap<String, String>,
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct Node {
    pub ident: String,
    pub features: Features,
    #[serde(
        flatten,
        skip_serializing_if = "is_private",
        deserialize_with = "private_if_absent"
    )]
    pub data: Data,
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub enum Data {
    Private,
    #[serde(rename = "fields")]
    Struct(Fields),
    #[serde(rename = "variants")]
    Enum(Variants),
}

pub type Fields = IndexMap<String, Type>;
pub type Variants = IndexMap<String, Vec<Type>>;

#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Type {
    /// Type defined by `syn`
    Syn(String),

    /// Type defined in `std`.
    Std(String),

    /// Type external to `syn`
    #[serde(rename = "proc_macro2")]
    Ext(String),

    /// Token type
    Token(String),

    /// Token group
    Group(String),

    /// Punctuated list
    Punctuated(Punctuated),

    Option(Box<Type>),
    Box(Box<Type>),
    Vec(Box<Type>),
    Tuple(Vec<Type>),
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct Punctuated {
    pub element: Box<Type>,
    pub punct: String,
}

#[derive(Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct Features {
    pub any: BTreeSet<String>,
}

fn is_private(data: &Data) -> bool {
    match data {
        Data::Private => true,
        Data::Struct(_) | Data::Enum(_) => false,
    }
}

fn private_if_absent<'de, D>(deserializer: D) -> Result<Data, D::Error>
where
    D: Deserializer<'de>,
{
    let option = Option::deserialize(deserializer)?;
    Ok(option.unwrap_or(Data::Private))
}
<commit_msg>Document the syn-codegen data types<commit_after>//! # Data structures that describe Syn's syntax tree.
//!
//! The Syn syntax tree is made up of more than 200 types. Occasionally it can
//! come up that you need to implement some behavior across them all.
//!
//! - For example [the Rust integration for AST Explorer][astexplorer] wants to
//!   turn a syntax tree from Syn into a JavaScript value understood by the
//!   platform's existing cross-language syntax tree visualization code.
//!
//!   [astexplorer]: https://astexplorer.net/#/gist/388150a52f74d45a355d2b5e865ded96/0c6d563f28d900472f699c21a1845ad20ae9927f
//!
//! - As another example from within Syn itself, the traits and implementations
//!   of the [`visit`], [`visit_mut`], and [`fold`] modules can be generated
//!   programmatically from a description of the syntax tree.
//!
//!   [`visit`]: https://docs.rs/syn/0.15/syn/visit/index.html
//!   [`visit_mut`]: https://docs.rs/syn/0.15/syn/visit_mut/index.html
//!   [`fold`]: https://docs.rs/syn/0.15/syn/fold/index.html
//!
//! To make this type of code as easy as possible to implement in any language,
//! every Syn release comes with a machine-readable description of that version
//! of the syntax tree as a JSON file [syn.json]. This `syn-codegen` crate
//! provides the canonical data structures for parsing and making use of the
//! representation in syn.json from Rust code.
//!
//! [syn.json]: https://raw.githubusercontent.com/dtolnay/syn/master/syn.json

use indexmap::IndexMap;
use semver::Version;
use serde::{Deserialize, Deserializer, Serialize};

use std::collections::{BTreeMap, BTreeSet};

/// Top-level content of the syntax tree description.
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct Definitions {
    /// The Syn version whose syntax tree is described by this data.
    pub version: Version,

    /// Syntax tree types defined by Syn.
    pub types: Vec<Node>,

    /// Token types defined by Syn (keywords as well as punctuation).
    ///
    /// The keys in the map are the Rust type name for the token. The values in
    /// the map are the printed token representation.
    ///
    /// These tokens are accessible in the Syn public API as `syn::token::#name`
    /// or alternatively `syn::Token![#repr]`.
    pub tokens: BTreeMap<String, String>,
}

/// Syntax tree type defined by Syn.
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct Node {
    /// Name of the type.
    ///
    /// This type is accessible in the Syn public API as `syn::#name`.
    pub ident: String,

    /// Features behind which this type is cfg gated.
    pub features: Features,

    /// Content of the data structure.
    #[serde(
        flatten,
        skip_serializing_if = "is_private",
        deserialize_with = "private_if_absent"
    )]
    pub data: Data,
}

/// Content of a syntax tree data structure.
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub enum Data {
    /// This is an opaque type with no publicy accessible structure.
    Private,

    /// This type is a braced struct with named fields.
    #[serde(rename = "fields")]
    Struct(Fields),

    /// This type is an enum.
    #[serde(rename = "variants")]
    Enum(Variants),
}

/// Fields of a braced struct syntax tree node with named fields.
///
/// The keys in the map are the field names.
pub type Fields = IndexMap<String, Type>;

/// Variants of an enum syntax tree node.
///
/// The keys in the map are the variant names.
///
/// Variants are unit variants if they hold no data and tuple variants
/// otherwise. The Syn syntax tree does not make use of braced variants.
pub type Variants = IndexMap<String, Vec<Type>>;

/// Type of a struct field or tuple variant field in the syntax tree.
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Type {
    /// Syntax tree type defined by Syn.
    ///
    /// This name will match the ident of some `Node`.
    Syn(String),

    /// Type defined by the Rust language or standard library.
    ///
    /// All such types used by Syn are accessible in the Rust prelude and can be
    /// used without a qualifying path in most Rust code.
    Std(String),

    /// Type defined by proc-macro2.
    ///
    /// The type is accessible in the proc-macro2 public API as
    /// `proc_macro2::#name`.
    #[serde(rename = "proc_macro2")]
    Ext(String),

    /// Keyword or punctuation token type defined by Syn.
    ///
    /// This name will match one of the keys in the `tokens` map.
    Token(String),

    /// Grouping token defined by Syn.
    ///
    /// The type is accessible in the Syn public API as `syn::token::#name`.
    Group(String),

    /// Punctuated list.
    ///
    /// This refers to `syn::punctuated::Punctuated<T, P>` with the specified
    /// element type and punctuation.
    Punctuated(Punctuated),

    /// `std::option::Option`
    Option(Box<Type>),

    /// `std::boxed::Box`
    Box(Box<Type>),

    /// `std::vec::Vec`
    Vec(Box<Type>),

    /// Rust tuple with two or more fields.
    Tuple(Vec<Type>),
}

/// Type of a punctuated list.
///
/// This refers to `syn::punctuated::Punctuated<#element, #punct>`.
///
/// The punct string will match one of the keys in the `tokens` map.
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct Punctuated {
    pub element: Box<Type>,
    pub punct: String,
}

/// Features behind which a syntax tree type is cfg gated.
#[derive(Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct Features {
    /// Type is accessible if at least one of these features is enabled against
    /// the Syn dependency.
    pub any: BTreeSet<String>,
}

fn is_private(data: &Data) -> bool {
    match data {
        Data::Private => true,
        Data::Struct(_) | Data::Enum(_) => false,
    }
}

fn private_if_absent<'de, D>(deserializer: D) -> Result<Data, D::Error>
where
    D: Deserializer<'de>,
{
    let option = Option::deserialize(deserializer)?;
    Ok(option.unwrap_or(Data::Private))
}
<|endoftext|>