<commit_before>use bytes::{BufMut, BytesMut};
use futures::Poll;
use std::io;

use super::IoStream;

const LW_BUFFER_SIZE: usize = 4096;
const HW_BUFFER_SIZE: usize = 32_768;

pub fn read_from_io<T: IoStream>(
    io: &mut T, buf: &mut BytesMut,
) -> Poll<usize, io::Error> {
    if buf.remaining_mut() < LW_BUFFER_SIZE {
        buf.reserve(HW_BUFFER_SIZE);
    }
    io.read_buf(buf)
}
<commit_msg>Revert "remove unnecessary use of unsafe in read_from_io"<commit_after>use bytes::{BufMut, BytesMut};
use futures::{Async, Poll};
use std::io;

use super::IoStream;

const LW_BUFFER_SIZE: usize = 4096;
const HW_BUFFER_SIZE: usize = 32_768;

pub fn read_from_io<T: IoStream>(
    io: &mut T, buf: &mut BytesMut,
) -> Poll<usize, io::Error> {
    unsafe {
        if buf.remaining_mut() < LW_BUFFER_SIZE {
            buf.reserve(HW_BUFFER_SIZE);
        }
        match io.read(buf.bytes_mut()) {
            Ok(n) => {
                buf.advance_mut(n);
                Ok(Async::Ready(n))
            }
            Err(e) => {
                if e.kind() == io::ErrorKind::WouldBlock {
                    Ok(Async::NotReady)
                } else {
                    Err(e)
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use service::parse_and_build_page_url;
use page::Page;

#[test]
fn convert_ssh_url() {
    let p = Page::Open;
    for &(repo, expected) in &[
        ("ssh://git@github.com:22/user/repo.git", "https://github.com/user/repo"),
        ("ssh://git@bitbucket.org:22/user/repo.git", "https://bitbucket.org/user/repo"),
    ] {
        assert_eq!(parse_and_build_page_url(&repo.to_string(), &p, &None).unwrap(), expected);
    }
}

#[test]
fn parse_and_build_open_page() {
    let p = Page::Open;
    for &(repo, expected) in &[
        ("https://github.com/user/repo.git", "https://github.com/user/repo"),
        ("https://bitbucket.org/user/repo.git", "https://bitbucket.org/user/repo"),
        ("https://github.somewhere.com/user/repo.git", "https://github.somewhere.com/user/repo"),
        ("https://gitlab.com/user/repo.git", "https://gitlab.com/user/repo"),
    ] {
        assert_eq!(parse_and_build_page_url(&repo.to_string(), &p, &None).unwrap(), expected);
    }
}

#[test]
fn parse_and_build_open_branch_page() {
    let p = Page::Open;
    for &(repo, expected) in &[
        ("https://github.com/user/repo.git", "https://github.com/user/repo/tree/dev"),
        ("https://bitbucket.org/user/repo.git", "https://bitbucket.org/user/repo/branch/dev"),
        ("https://github.somewhere.com/user/repo.git", "https://github.somewhere.com/user/repo/tree/dev"),
        ("https://gitlab.com/user/repo.git", "https://gitlab.com/user/repo/tree/dev"),
    ] {
        assert_eq!(parse_and_build_page_url(&repo.to_string(), &p, &Some("dev".to_string())).unwrap(), expected);
    }
}

#[test]
fn parse_and_build_commit_page() {
    let p = Page::Commit {
        hash: "90601f1037142605a32426f9ece0c07d479b9cc5".to_string(),
    };
    for &(repo, expected) in &[
        ("https://github.com/user/repo.git", "https://github.com/user/repo/commit/90601f1037142605a32426f9ece0c07d479b9cc5"),
        ("https://bitbucket.org/user/repo.git", "https://bitbucket.org/user/repo/commits/90601f1037142605a32426f9ece0c07d479b9cc5"),
        ("https://github.somewhere.com/user/repo.git", "https://github.somewhere.com/user/repo/commit/90601f1037142605a32426f9ece0c07d479b9cc5"),
        ("https://gitlab.com/user/repo.git", "https://gitlab.com/user/repo/commit/90601f1037142605a32426f9ece0c07d479b9cc5"),
    ] {
        assert_eq!(parse_and_build_page_url(&repo.to_string(), &p, &None).unwrap(), expected);
    }
}

#[test]
fn parse_and_build_diff_page() {
    let p = Page::Diff {
        lhs: "561848bad7164d7568658456088b107ec9efd9f3".to_string(),
        rhs: "90601f1037142605a32426f9ece0c07d479b9cc5".to_string(),
    };
    for &(repo, expected) in &[
        ("https://github.com/user/repo.git", "https://github.com/user/repo/compare/561848bad7164d7568658456088b107ec9efd9f3...90601f1037142605a32426f9ece0c07d479b9cc5"),
        ("https://github.somewhere.com/user/repo.git", "https://github.somewhere.com/user/repo/compare/561848bad7164d7568658456088b107ec9efd9f3...90601f1037142605a32426f9ece0c07d479b9cc5"),
        ("https://gitlab.com/user/repo.git", "https://gitlab.com/user/repo/compare/561848bad7164d7568658456088b107ec9efd9f3...90601f1037142605a32426f9ece0c07d479b9cc5"),
    ] {
        assert_eq!(parse_and_build_page_url(&repo.to_string(), &p, &None).unwrap(), expected);
    }
    assert!(parse_and_build_page_url(&"https://bitbucket.org/user/repo".to_string(), &p, &None).is_err(), "bitbucket does not support diff page");
}

#[test]
fn parse_and_build_file_page() {
    let p = Page::FileOrDir {
        relative_path: "src/main.rs".to_string(),
        hash: "561848bad7164d7568658456088b107ec9efd9f3".to_string(),
        line: None,
    };
    for &(repo, expected) in &[
        ("https://github.com/user/repo.git", "https://github.com/user/repo/blob/561848bad7164d7568658456088b107ec9efd9f3/src/main.rs"),
        ("https://bitbucket.org/user/repo.git", "https://bitbucket.org/user/repo/src/561848bad7164d7568658456088b107ec9efd9f3/src/main.rs"),
        ("https://github.somewhere.com/user/repo.git", "https://github.somewhere.com/user/repo/blob/561848bad7164d7568658456088b107ec9efd9f3/src/main.rs"),
        ("https://gitlab.com/user/repo.git", "https://gitlab.com/user/repo/blob/561848bad7164d7568658456088b107ec9efd9f3/src/main.rs"),
    ] {
        assert_eq!(parse_and_build_page_url(&repo.to_string(), &p, &None).unwrap(), expected);
    }
}

#[test]
fn parse_and_build_file_page_with_line_number() {
    let p = Page::FileOrDir {
        relative_path: "src/main.rs".to_string(),
        hash: "561848bad7164d7568658456088b107ec9efd9f3".to_string(),
        line: Some(12),
    };
    for &(repo, expected) in &[
        ("https://github.com/user/repo.git", "https://github.com/user/repo/blob/561848bad7164d7568658456088b107ec9efd9f3/src/main.rs#L12"),
        ("https://bitbucket.org/user/repo.git", "https://bitbucket.org/user/repo/src/561848bad7164d7568658456088b107ec9efd9f3/src/main.rs#main.rs-12"),
        ("https://github.somewhere.com/user/repo.git", "https://github.somewhere.com/user/repo/blob/561848bad7164d7568658456088b107ec9efd9f3/src/main.rs#L12"),
        ("https://gitlab.com/user/repo.git", "https://gitlab.com/user/repo/blob/561848bad7164d7568658456088b107ec9efd9f3/src/main.rs#L12"),
    ] {
        assert_eq!(parse_and_build_page_url(&repo.to_string(), &p, &None).unwrap(), expected);
    }
}
<commit_msg>add test cases for invalid URLs<commit_after>use service::parse_and_build_page_url;
use page::Page;

#[test]
fn convert_ssh_url() {
    let p = Page::Open;
    for &(repo, expected) in &[
        ("ssh://git@github.com:22/user/repo.git", "https://github.com/user/repo"),
        ("ssh://git@bitbucket.org:22/user/repo.git", "https://bitbucket.org/user/repo"),
    ] {
        assert_eq!(parse_and_build_page_url(&repo.to_string(), &p, &None).unwrap(), expected);
    }
}

#[test]
fn parse_and_build_open_page() {
    let p = Page::Open;
    for &(repo, expected) in &[
        ("https://github.com/user/repo.git", "https://github.com/user/repo"),
        ("https://bitbucket.org/user/repo.git", "https://bitbucket.org/user/repo"),
        ("https://github.somewhere.com/user/repo.git", "https://github.somewhere.com/user/repo"),
        ("https://gitlab.com/user/repo.git", "https://gitlab.com/user/repo"),
    ] {
        assert_eq!(parse_and_build_page_url(&repo.to_string(), &p, &None).unwrap(), expected);
    }
}

#[test]
fn parse_and_build_open_branch_page() {
    let p = Page::Open;
    for &(repo, expected) in &[
        ("https://github.com/user/repo.git", "https://github.com/user/repo/tree/dev"),
        ("https://bitbucket.org/user/repo.git", "https://bitbucket.org/user/repo/branch/dev"),
        ("https://github.somewhere.com/user/repo.git", "https://github.somewhere.com/user/repo/tree/dev"),
        ("https://gitlab.com/user/repo.git", "https://gitlab.com/user/repo/tree/dev"),
    ] {
        assert_eq!(parse_and_build_page_url(&repo.to_string(), &p, &Some("dev".to_string())).unwrap(), expected);
    }
}

#[test]
fn parse_and_build_commit_page() {
    let p = Page::Commit {
        hash: "90601f1037142605a32426f9ece0c07d479b9cc5".to_string(),
    };
    for &(repo, expected) in &[
        ("https://github.com/user/repo.git", "https://github.com/user/repo/commit/90601f1037142605a32426f9ece0c07d479b9cc5"),
        ("https://bitbucket.org/user/repo.git", "https://bitbucket.org/user/repo/commits/90601f1037142605a32426f9ece0c07d479b9cc5"),
        ("https://github.somewhere.com/user/repo.git", "https://github.somewhere.com/user/repo/commit/90601f1037142605a32426f9ece0c07d479b9cc5"),
        ("https://gitlab.com/user/repo.git", "https://gitlab.com/user/repo/commit/90601f1037142605a32426f9ece0c07d479b9cc5"),
    ] {
        assert_eq!(parse_and_build_page_url(&repo.to_string(), &p, &None).unwrap(), expected);
    }
}

#[test]
fn parse_and_build_diff_page() {
    let p = Page::Diff {
        lhs: "561848bad7164d7568658456088b107ec9efd9f3".to_string(),
        rhs: "90601f1037142605a32426f9ece0c07d479b9cc5".to_string(),
    };
    for &(repo, expected) in &[
        ("https://github.com/user/repo.git", "https://github.com/user/repo/compare/561848bad7164d7568658456088b107ec9efd9f3...90601f1037142605a32426f9ece0c07d479b9cc5"),
        ("https://github.somewhere.com/user/repo.git", "https://github.somewhere.com/user/repo/compare/561848bad7164d7568658456088b107ec9efd9f3...90601f1037142605a32426f9ece0c07d479b9cc5"),
        ("https://gitlab.com/user/repo.git", "https://gitlab.com/user/repo/compare/561848bad7164d7568658456088b107ec9efd9f3...90601f1037142605a32426f9ece0c07d479b9cc5"),
    ] {
        assert_eq!(parse_and_build_page_url(&repo.to_string(), &p, &None).unwrap(), expected);
    }
    assert!(parse_and_build_page_url(&"https://bitbucket.org/user/repo".to_string(), &p, &None).is_err(), "bitbucket does not support diff page");
}

#[test]
fn parse_and_build_file_page() {
    let p = Page::FileOrDir {
        relative_path: "src/main.rs".to_string(),
        hash: "561848bad7164d7568658456088b107ec9efd9f3".to_string(),
        line: None,
    };
    for &(repo, expected) in &[
        ("https://github.com/user/repo.git", "https://github.com/user/repo/blob/561848bad7164d7568658456088b107ec9efd9f3/src/main.rs"),
        ("https://bitbucket.org/user/repo.git", "https://bitbucket.org/user/repo/src/561848bad7164d7568658456088b107ec9efd9f3/src/main.rs"),
        ("https://github.somewhere.com/user/repo.git", "https://github.somewhere.com/user/repo/blob/561848bad7164d7568658456088b107ec9efd9f3/src/main.rs"),
        ("https://gitlab.com/user/repo.git", "https://gitlab.com/user/repo/blob/561848bad7164d7568658456088b107ec9efd9f3/src/main.rs"),
    ] {
        assert_eq!(parse_and_build_page_url(&repo.to_string(), &p, &None).unwrap(), expected);
    }
}

#[test]
fn parse_and_build_file_page_with_line_number() {
    let p = Page::FileOrDir {
        relative_path: "src/main.rs".to_string(),
        hash: "561848bad7164d7568658456088b107ec9efd9f3".to_string(),
        line: Some(12),
    };
    for &(repo, expected) in &[
        ("https://github.com/user/repo.git", "https://github.com/user/repo/blob/561848bad7164d7568658456088b107ec9efd9f3/src/main.rs#L12"),
        ("https://bitbucket.org/user/repo.git", "https://bitbucket.org/user/repo/src/561848bad7164d7568658456088b107ec9efd9f3/src/main.rs#main.rs-12"),
        ("https://github.somewhere.com/user/repo.git", "https://github.somewhere.com/user/repo/blob/561848bad7164d7568658456088b107ec9efd9f3/src/main.rs#L12"),
        ("https://gitlab.com/user/repo.git", "https://gitlab.com/user/repo/blob/561848bad7164d7568658456088b107ec9efd9f3/src/main.rs#L12"),
    ] {
        assert_eq!(parse_and_build_page_url(&repo.to_string(), &p, &None).unwrap(), expected);
    }
}

#[test]
fn invalid_repo_url() {
    for repo in &[
        "https://github.com.git",
        "https://github.com/user.git",
        "https://unknown.hosting_service.com/user/repo.git",
    ] {
        assert!(parse_and_build_page_url(&repo.to_string(), &Page::Open, &None).is_err(), "{} must be invalid", repo);
    }
}
<|endoftext|>


<commit_before>use std::rc::*;

use super::treenode::*;

///
/// Represents the address of a node relative to another node
///
#[derive(Clone)]
pub enum TreeAddress {
    /// Selects this node
    Here,

    /// Selects a child of this node by index, then selects a new address from there
    ChildAtIndex(usize, Box<TreeAddress>),

    /// Selects a child of this node by tag name, then selects a new address from there
    ChildWithTag(String, Box<TreeAddress>),
}

impl TreeNodeIndex for TreeAddress {
    fn lookup_index(&self, parent_node: &Rc<TreeNode>) -> Option<Rc<TreeNode>> {
        match *self {
            TreeAddress::Here => Some(parent_node.to_owned()),

            TreeAddress::ChildAtIndex(ref pos, ref next) => {
                (*pos).lookup_index(parent_node).and_then(|new_parent| {
                    (*next).lookup_index(&new_parent)
                })
            },

            TreeAddress::ChildWithTag(ref name, ref next) => {
                (&**name).lookup_index(parent_node).and_then(|new_parent| {
                    (*next).lookup_index(&new_parent)
                })
            }
        }
    }
}

impl PartialEq for TreeAddress {
    fn eq(&self, other: &TreeAddress) -> bool {
        match *self {
            TreeAddress::Here => {
                match *other {
                    TreeAddress::Here   => true,
                    _                   => false
                }
            },

            TreeAddress::ChildAtIndex(self_index, ref self_child) => {
                match *other {
                    TreeAddress::ChildAtIndex(rhs_index, ref rhs_child) => self_index == rhs_index && self_child == rhs_child,
                    _                                                   => false
                }
            },

            TreeAddress::ChildWithTag(ref self_tag, ref self_child) => {
                match *other {
                    TreeAddress::ChildWithTag(ref rhs_tag, ref rhs_child)   => self_tag == rhs_tag && self_child == rhs_child,
                    _                                                       => false
                }
            }
        }
    }
}

impl Eq for TreeAddress {}

impl TreeAddress {
    ///
    /// Returns whether or not address is a parent of this address, or the same address
    ///
    /// Will return None if the two addresses are in incompatible formats (eg, if a tag needs to match up against an indexed address)
    ///
    pub fn is_parent_of(&self, address: &TreeAddress) -> Option<bool> {
        match *self {
            // 'Here' is the root address, the parent of everything (including itself)
            TreeAddress::Here => Some(true),

            // Child addresses must match
            TreeAddress::ChildAtIndex(self_index, ref self_child) => {
                match *address {
                    TreeAddress::ChildAtIndex(address_index, ref address_child) => {
                        if self_index == address_index {
                            self_child.is_parent_of(address_child)
                        } else {
                            Some(false)
                        }
                    },

                    TreeAddress::Here   => Some(false),
                    _                   => None
                }
            },

            TreeAddress::ChildWithTag(ref self_tag, ref self_child) => {
                match *address {
                    TreeAddress::ChildWithTag(ref address_tag, ref address_child) => {
                        if *self_tag == *address_tag {
                            self_child.is_parent_of(address_child)
                        } else {
                            Some(false)
                        }
                    },

                    TreeAddress::Here   => Some(false),
                    _                   => None
                }
            }
        }
    }

    ///
    /// Returns whether or not address is a child of this address or the same address
    ///
    #[inline]
    pub fn is_child_of(&self, address: &TreeAddress) -> Option<bool> {
        address.is_parent_of(self)
    }

    ///
    /// Transforms this address to a new address that is relative to a particular parent address (or None if the addresses
    /// are in different formats or if parent_address is not a parent of this address)
    ///
    pub fn relative_to(&self, parent_address: &TreeAddress) -> Option<TreeAddress> {
        match *self {
            // Here is a root address, so it doesn't match the parent
            TreeAddress::Here => None,

            // Strip out child addresses
            TreeAddress::ChildAtIndex(self_index, ref self_child) => {
                match *parent_address {
                    // 'Here' is a parent of everything
                    TreeAddress::Here => Some(self.to_owned()),

                    // We carry on down the tree if we get a matching ChildAtIndex address
                    TreeAddress::ChildAtIndex(parent_index, ref parent_child) => {
                        if self_index == parent_index {
                            self_child.relative_to(parent_child)
                        } else {
                            None
                        }
                    },

                    // Other address types count as mismatched (we don't know the tree structure, so we can't match tags against indexes)
                    _ => None
                }
            },

            TreeAddress::ChildWithTag(ref self_tag, ref self_child) => {
                match *parent_address {
                    // 'Here' is a parent of everything
                    TreeAddress::Here => Some(self.to_owned()),

                    // We carry on down the tree if we get a matching ChildWithTag address
                    TreeAddress::ChildWithTag(ref parent_tag, ref parent_child) => {
                        if self_tag == parent_tag {
                            self_child.relative_to(parent_child)
                        } else {
                            None
                        }
                    },

                    // Other address types count as mismatched (we don't know the tree structure, so we can't match tags against indexes)
                    _ => None
                }
            }
        }
    }
}

///
/// Structure representing a shorthand address
///
/// This has `TreeNodeIndex` implemented on it, so `treenode.get_child_ref_at(Addr(0, ()))` will work
///
pub struct Addr<TFirst: ToTreeAddress, TSecond: ToTreeAddress>(TFirst, TSecond);

///
/// Trait that is implemented by types that can be converted to tree addresses
///
pub trait ToTreeAddress {
    fn to_tree_address(&self) -> TreeAddress;
    fn to_tree_address_then(&self, then: TreeAddress) -> TreeAddress;
}

impl ToTreeAddress for () {
    #[inline]
    fn to_tree_address(&self) -> TreeAddress {
        TreeAddress::Here
    }

    #[inline]
    fn to_tree_address_then(&self, then: TreeAddress) -> TreeAddress {
        then
    }
}

impl ToTreeAddress for usize {
    #[inline]
    fn to_tree_address(&self) -> TreeAddress {
        TreeAddress::ChildAtIndex(*self, Box::new(TreeAddress::Here))
    }

    #[inline]
    fn to_tree_address_then(&self, then: TreeAddress) -> TreeAddress {
        TreeAddress::ChildAtIndex(*self, Box::new(then))
    }
}

impl<'a> ToTreeAddress for &'a str {
    #[inline]
    fn to_tree_address(&self) -> TreeAddress {
        TreeAddress::ChildWithTag((*self).to_string(), Box::new(TreeAddress::Here))
    }

    #[inline]
    fn to_tree_address_then(&self, then: TreeAddress) -> TreeAddress {
        TreeAddress::ChildWithTag((*self).to_string(), Box::new(then))
    }
}

impl ToTreeAddress for TreeAddress {
    #[inline]
    fn to_tree_address(&self) -> TreeAddress {
        (*self).to_owned()
    }

    fn to_tree_address_then(&self, then: TreeAddress) -> TreeAddress {
        match *self {
            TreeAddress::Here                                   => then,
            TreeAddress::ChildAtIndex(ref index, ref old_then)  => TreeAddress::ChildAtIndex(*index, Box::new((*old_then).to_tree_address_then(then))),
            TreeAddress::ChildWithTag(ref tag, ref old_then)    => TreeAddress::ChildWithTag((*tag).to_owned(), Box::new((*old_then).to_tree_address_then(then)))
        }
    }
}

impl<TFirst: ToTreeAddress, TSecond: ToTreeAddress> ToTreeAddress for (TFirst, TSecond) {
    #[inline]
    fn to_tree_address(&self) -> TreeAddress {
        let (ref first, ref second) = *self;

        first.to_tree_address_then(second.to_tree_address())
    }

    #[inline]
    fn to_tree_address_then(&self, then: TreeAddress) -> TreeAddress {
        self.to_tree_address().to_tree_address_then(then)
    }
}

impl<TFirst: ToTreeAddress, TSecond: ToTreeAddress> ToTreeAddress for Addr<TFirst, TSecond> {
    #[inline]
    fn to_tree_address(&self) -> TreeAddress {
        let Addr(ref first, ref second) = *self;

        first.to_tree_address_then(second.to_tree_address())
    }

    #[inline]
    fn to_tree_address_then(&self, then: TreeAddress) -> TreeAddress {
        self.to_tree_address().to_tree_address_then(then)
    }
}

impl<TFirst: ToTreeAddress, TSecond: ToTreeAddress> TreeNodeIndex for Addr<TFirst, TSecond> {
    #[inline]
    fn lookup_index(&self, parent_node: &Rc<TreeNode>) -> Option<Rc<TreeNode>> {
        let Addr(ref first, ref second) = *self;

        first.to_tree_address_then(second.to_tree_address()).lookup_index(parent_node)
    }
}

#[cfg(test)]
mod treeaddress_test {
    use super::super::super::tree::*;

    #[test]
    fn lookup_here() {
        let some_tree = tree!("Here", "There", "Everywhere");

        assert!(some_tree.get_child_ref_at(TreeAddress::Here).unwrap().get_tag() == "Here");
    }

    #[test]
    fn lookup_child() {
        let some_tree = tree!("Here", "There", "Everywhere");

        assert!(some_tree.get_child_ref_at(Addr(0, ())).unwrap().get_tag() == "There");
        assert!(some_tree.get_child_ref_at(Addr(1, ())).unwrap().get_tag() == "Everywhere");
    }

    #[test]
    fn lookup_tag() {
        let some_tree = tree!("Here", "There", "Everywhere");

        assert!(some_tree.get_child_ref_at(Addr("There", ())).unwrap().get_tag() == "There");
        assert!(some_tree.get_child_ref_at(Addr("Everywhere", ())).unwrap().get_tag() == "Everywhere");
    }

    #[test]
    fn lookup_grandchild() {
        let some_tree = tree!("Here", tree!("There", "Everywhere"));

        assert!(some_tree.get_child_ref_at(Addr("There", (0, ()))).unwrap().get_tag() == "Everywhere");
    }

    #[test]
    fn address_after_address() {
        let some_tree = tree!("Here", tree!("There", tree!("Everywhere", "Also here")));

        // Address formed of a complicated address with an extra address appended
        let everywhere_address = Addr("There", ("Everywhere", ()));
        assert!(some_tree.get_child_ref_at(Addr(everywhere_address, (0, ()))).unwrap().get_tag() == "Also here");
    }

    #[test]
    fn here_is_parent_of_here() {
        let here        = ().to_tree_address();
        let is_parent   = here.is_parent_of(&here);
        let is_child    = here.is_child_of(&here);

        assert!(is_parent.unwrap());
        assert!(is_child.unwrap());
    }

    #[test]
    fn here_is_parent_of_anything() {
        let here        = ().to_tree_address();
        let there       = (0, (1, 2)).to_tree_address();
        let is_parent   = here.is_parent_of(&there);
        let is_child    = here.is_child_of(&there);

        assert!(is_parent.unwrap());
        assert!(!is_child.unwrap());
    }

    #[test]
    fn nothing_is_parent_of_here() {
        let here        = ().to_tree_address();
        let there       = (0, (1, 2)).to_tree_address();
        let is_parent   = there.is_parent_of(&here);
        let is_child    = there.is_child_of(&here);

        assert!(!is_parent.unwrap());
        assert!(is_child.unwrap());
    }

    #[test]
    fn same_address_is_parent() {
        let here        = (0, (1, 2)).to_tree_address();
        let there       = (0, (1, 2)).to_tree_address();
        let is_parent   = here.is_parent_of(&there);
        let is_child    = here.is_child_of(&there);

        assert!(is_parent.unwrap());
        assert!(is_child.unwrap());
    }

    #[test]
    fn indexed_parent() {
        let here        = (0, 1).to_tree_address();
        let there       = (0, (1, 2)).to_tree_address();
        let is_parent   = here.is_parent_of(&there);
        let is_child    = here.is_child_of(&there);

        assert!(is_parent.unwrap());
        assert!(!is_child.unwrap());
    }

    #[test]
    fn bad_indexed_parent() {
        let here        = (1, 0).to_tree_address();
        let there       = (0, (1, 2)).to_tree_address();
        let is_parent   = here.is_parent_of(&there);
        let is_child    = here.is_child_of(&there);

        assert!(!is_parent.unwrap());
        assert!(!is_child.unwrap());
    }

    #[test]
    fn tagged_parent() {
        let here        = ("first", "second").to_tree_address();
        let there       = ("first", ("second", "third")).to_tree_address();
        let is_parent   = here.is_parent_of(&there);
        let is_child    = here.is_child_of(&there);

        assert!(is_parent.unwrap());
        assert!(!is_child.unwrap());
    }

    #[test]
    fn bad_tagged_parent() {
        let here        = ("other tag", "second").to_tree_address();
        let there       = ("first", ("second", "third")).to_tree_address();
        let is_parent   = here.is_parent_of(&there);
        let is_child    = here.is_child_of(&there);

        assert!(!is_parent.unwrap());
        assert!(!is_child.unwrap());
    }

    #[test]
    fn different_address_types_cant_be_checked() {
        let indexed         = 1.to_tree_address();
        let tagged          = "tag".to_tree_address();

        assert!(indexed.is_parent_of(&tagged).is_none());
        assert!(tagged.is_parent_of(&indexed).is_none());
    }

    #[test]
    fn can_get_relative_address_with_indexes() {
        let address     = (1, (2, (3, 4))).to_tree_address();
        let relativeTo  = (1, 2).to_tree_address();
        let expected    = (3, 4).to_tree_address();

        assert!(address.relative_to(&relativeTo).unwrap() == expected);
    }

    #[test]
    fn can_get_relative_address_with_tags() {
        let address     = ("one", ("two", ("three", "four"))).to_tree_address();
        let relativeTo  = ("one", "two").to_tree_address();
        let expected    = ("three", "four").to_tree_address();

        assert!(address.relative_to(&relativeTo).unwrap() == expected);
    }

    #[test]
    fn relative_to_wrong_address_is_none() {
        let address     = (1, (2, (3, 4))).to_tree_address();
        let relativeTo  = (3, 4).to_tree_address();

        assert!(address.relative_to(&relativeTo).is_none());
    }

    #[test]
    fn relative_to_here_is_none() {
        let address     = ().to_tree_address();
        let relativeTo  = (3, 4).to_tree_address();

        assert!(address.relative_to(&relativeTo).is_none());
    }
}
<commit_msg>Fix warnings: naming<commit_after>use std::rc::*;

use super::treenode::*;

///
/// Represents the address of a node relative to another node
///
#[derive(Clone)]
pub enum TreeAddress {
    /// Selects this node
    Here,

    /// Selects a child of this node by index, then selects a new address from there
    ChildAtIndex(usize, Box<TreeAddress>),

    /// Selects a child of this node by tag name, then selects a new address from there
    ChildWithTag(String, Box<TreeAddress>),
}

impl TreeNodeIndex for TreeAddress {
    fn lookup_index(&self, parent_node: &Rc<TreeNode>) -> Option<Rc<TreeNode>> {
        match *self {
            TreeAddress::Here => Some(parent_node.to_owned()),

            TreeAddress::ChildAtIndex(ref pos, ref next) => {
                (*pos).lookup_index(parent_node).and_then(|new_parent| {
                    (*next).lookup_index(&new_parent)
                })
            },

            TreeAddress::ChildWithTag(ref name, ref next) => {
                (&**name).lookup_index(parent_node).and_then(|new_parent| {
                    (*next).lookup_index(&new_parent)
                })
            }
        }
    }
}

impl PartialEq for TreeAddress {
    fn eq(&self, other: &TreeAddress) -> bool {
        match *self {
            TreeAddress::Here => {
                match *other {
                    TreeAddress::Here   => true,
                    _                   => false
                }
            },

            TreeAddress::ChildAtIndex(self_index, ref self_child) => {
                match *other {
                    TreeAddress::ChildAtIndex(rhs_index, ref rhs_child) => self_index == rhs_index && self_child == rhs_child,
                    _                                                   => false
                }
            },

            TreeAddress::ChildWithTag(ref self_tag, ref self_child) => {
                match *other {
                    TreeAddress::ChildWithTag(ref rhs_tag, ref rhs_child)   => self_tag == rhs_tag && self_child == rhs_child,
                    _                                                       => false
                }
            }
        }
    }
}

impl Eq for TreeAddress {}

impl TreeAddress {
    ///
    /// Returns whether or not address is a parent of this address, or the same address
    ///
    /// Will return None if the two addresses are in incompatible formats (eg, if a tag needs to match up against an indexed address)
    ///
    pub fn is_parent_of(&self, address: &TreeAddress) -> Option<bool> {
        match *self {
            // 'Here' is the root address, the parent of everything (including itself)
            TreeAddress::Here => Some(true),

            // Child addresses must match
            TreeAddress::ChildAtIndex(self_index, ref self_child) => {
                match *address {
                    TreeAddress::ChildAtIndex(address_index, ref address_child) => {
                        if self_index == address_index {
                            self_child.is_parent_of(address_child)
                        } else {
                            Some(false)
                        }
                    },

                    TreeAddress::Here   => Some(false),
                    _                   => None
                }
            },

            TreeAddress::ChildWithTag(ref self_tag, ref self_child) => {
                match *address {
                    TreeAddress::ChildWithTag(ref address_tag, ref address_child) => {
                        if *self_tag == *address_tag {
                            self_child.is_parent_of(address_child)
                        } else {
                            Some(false)
                        }
                    },

                    TreeAddress::Here   => Some(false),
                    _                   => None
                }
            }
        }
    }

    ///
    /// Returns whether or not address is a child of this address or the same address
    ///
    #[inline]
    pub fn is_child_of(&self, address: &TreeAddress) -> Option<bool> {
        address.is_parent_of(self)
    }

    ///
    /// Transforms this address to a new address that is relative to a particular parent address (or None if the addresses
    /// are in different formats or if parent_address is not a parent of this address)
    ///
    pub fn relative_to(&self, parent_address: &TreeAddress) -> Option<TreeAddress> {
        match *self {
            // Here is a root address, so it doesn't match the parent
            TreeAddress::Here => None,

            // Strip out child addresses
            TreeAddress::ChildAtIndex(self_index, ref self_child) => {
                match *parent_address {
                    // 'Here' is a parent of everything
                    TreeAddress::Here => Some(self.to_owned()),

                    // We carry on down the tree if we get a matching ChildAtIndex address
                    TreeAddress::ChildAtIndex(parent_index, ref parent_child) => {
                        if self_index == parent_index {
                            self_child.relative_to(parent_child)
                        } else {
                            None
                        }
                    },

                    // Other address types count as mismatched (we don't know the tree structure, so we can't match tags against indexes)
                    _ => None
                }
            },

            TreeAddress::ChildWithTag(ref self_tag, ref self_child) => {
                match *parent_address {
                    // 'Here' is a parent of everything
                    TreeAddress::Here => Some(self.to_owned()),

                    // We carry on down the tree if we get a matching ChildWithTag address
                    TreeAddress::ChildWithTag(ref parent_tag, ref parent_child) => {
                        if self_tag == parent_tag {
                            self_child.relative_to(parent_child)
                        } else {
                            None
                        }
                    },

                    // Other address types count as mismatched (we don't know the tree structure, so we can't match tags against indexes)
                    _ => None
                }
            }
        }
    }
}

///
/// Structure representing a shorthand address
///
/// This has `TreeNodeIndex` implemented on it, so `treenode.get_child_ref_at(Addr(0, ()))` will work
///
pub struct Addr<TFirst: ToTreeAddress, TSecond: ToTreeAddress>(TFirst, TSecond);

///
/// Trait that is implemented by types that can be converted to tree addresses
///
pub trait ToTreeAddress {
    fn to_tree_address(&self) -> TreeAddress;
    fn to_tree_address_then(&self, then: TreeAddress) -> TreeAddress;
}

impl ToTreeAddress for () {
    #[inline]
    fn to_tree_address(&self) -> TreeAddress {
        TreeAddress::Here
    }

    #[inline]
    fn to_tree_address_then(&self, then: TreeAddress) -> TreeAddress {
        then
    }
}

impl ToTreeAddress for usize {
    #[inline]
    fn to_tree_address(&self) -> TreeAddress {
        TreeAddress::ChildAtIndex(*self, Box::new(TreeAddress::Here))
    }

    #[inline]
    fn to_tree_address_then(&self, then: TreeAddress) -> TreeAddress {
        TreeAddress::ChildAtIndex(*self, Box::new(then))
    }
}

impl<'a> ToTreeAddress for &'a str {
    #[inline]
    fn to_tree_address(&self) -> TreeAddress {
        TreeAddress::ChildWithTag((*self).to_string(), Box::new(TreeAddress::Here))
    }

    #[inline]
    fn to_tree_address_then(&self, then: TreeAddress) -> TreeAddress {
        TreeAddress::ChildWithTag((*self).to_string(), Box::new(then))
    }
}

impl ToTreeAddress for TreeAddress {
    #[inline]
    fn to_tree_address(&self) -> TreeAddress {
        (*self).to_owned()
    }

    fn to_tree_address_then(&self, then: TreeAddress) -> TreeAddress {
        match *self {
            TreeAddress::Here                                   => then,
            TreeAddress::ChildAtIndex(ref index, ref old_then)  => TreeAddress::ChildAtIndex(*index, Box::new((*old_then).to_tree_address_then(then))),
            TreeAddress::ChildWithTag(ref tag, ref old_then)    => TreeAddress::ChildWithTag((*tag).to_owned(), Box::new((*old_then).to_tree_address_then(then)))
        }
    }
}

impl<TFirst: ToTreeAddress, TSecond: ToTreeAddress> ToTreeAddress for (TFirst, TSecond) {
    #[inline]
    fn to_tree_address(&self) -> TreeAddress {
        let (ref first, ref second) = *self;

        first.to_tree_address_then(second.to_tree_address())
    }

    #[inline]
    fn to_tree_address_then(&self, then: TreeAddress) -> TreeAddress {
        self.to_tree_address().to_tree_address_then(then)
    }
}

impl<TFirst: ToTreeAddress, TSecond: ToTreeAddress> ToTreeAddress for Addr<TFirst, TSecond> {
    #[inline]
    fn to_tree_address(&self) -> TreeAddress {
        let Addr(ref first, ref second) = *self;

        first.to_tree_address_then(second.to_tree_address())
    }

    #[inline]
    fn to_tree_address_then(&self, then: TreeAddress) -> TreeAddress {
        self.to_tree_address().to_tree_address_then(then)
    }
}

impl<TFirst: ToTreeAddress, TSecond: ToTreeAddress> TreeNodeIndex for Addr<TFirst, TSecond> {
    #[inline]
    fn lookup_index(&self, parent_node: &Rc<TreeNode>) -> Option<Rc<TreeNode>> {
        let Addr(ref first, ref second) = *self;

        first.to_tree_address_then(second.to_tree_address()).lookup_index(parent_node)
    }
}

#[cfg(test)]
mod treeaddress_test {
    use super::super::super::tree::*;

    #[test]
    fn lookup_here() {
        let some_tree = tree!("Here", "There", "Everywhere");

        assert!(some_tree.get_child_ref_at(TreeAddress::Here).unwrap().get_tag() == "Here");
    }

    #[test]
    fn lookup_child() {
        let some_tree = tree!("Here", "There", "Everywhere");

        assert!(some_tree.get_child_ref_at(Addr(0, ())).unwrap().get_tag() == "There");
        assert!(some_tree.get_child_ref_at(Addr(1, ())).unwrap().get_tag() == "Everywhere");
    }

    #[test]
    fn lookup_tag() {
        let some_tree = tree!("Here", "There", "Everywhere");

        assert!(some_tree.get_child_ref_at(Addr("There", ())).unwrap().get_tag() == "There");
        assert!(some_tree.get_child_ref_at(Addr("Everywhere", ())).unwrap().get_tag() == "Everywhere");
    }

    #[test]
    fn lookup_grandchild() {
        let some_tree = tree!("Here", tree!("There", "Everywhere"));

        assert!(some_tree.get_child_ref_at(Addr("There", (0, ()))).unwrap().get_tag() == "Everywhere");
    }

    #[test]
    fn address_after_address() {
        let some_tree = tree!("Here", tree!("There", tree!("Everywhere", "Also here")));

        // Address formed of a complicated address with an extra address appended
        let everywhere_address = Addr("There", ("Everywhere", ()));
        assert!(some_tree.get_child_ref_at(Addr(everywhere_address, (0, ()))).unwrap().get_tag() == "Also here");
    }

    #[test]
    fn here_is_parent_of_here() {
        let here        = ().to_tree_address();
        let is_parent   = here.is_parent_of(&here);
        let is_child    = here.is_child_of(&here);

        assert!(is_parent.unwrap());
        assert!(is_child.unwrap());
    }

    #[test]
    fn here_is_parent_of_anything() {
        let here        = ().to_tree_address();
        let there       = (0, (1, 2)).to_tree_address();
        let is_parent   = here.is_parent_of(&there);
        let is_child    = here.is_child_of(&there);

        assert!(is_parent.unwrap());
        assert!(!is_child.unwrap());
    }

    #[test]
    fn nothing_is_parent_of_here() {
        let here        = ().to_tree_address();
        let there       = (0, (1, 2)).to_tree_address();
        let is_parent   = there.is_parent_of(&here);
        let is_child    = there.is_child_of(&here);

        assert!(!is_parent.unwrap());
        assert!(is_child.unwrap());
    }

    #[test]
    fn same_address_is_parent() {
        let here        = (0, (1, 2)).to_tree_address();
        let there       = (0, (1, 2)).to_tree_address();
        let is_parent   = here.is_parent_of(&there);
        let is_child    = here.is_child_of(&there);

        assert!(is_parent.unwrap());
        assert!(is_child.unwrap());
    }

    #[test]
    fn indexed_parent() {
        let here        = (0, 1).to_tree_address();
        let there       = (0, (1, 2)).to_tree_address();
        let is_parent   = here.is_parent_of(&there);
        let is_child    = here.is_child_of(&there);

        assert!(is_parent.unwrap());
        assert!(!is_child.unwrap());
    }

    #[test]
    fn bad_indexed_parent() {
        let here        = (1, 0).to_tree_address();
        let there       = (0, (1, 2)).to_tree_address();
        let is_parent   = here.is_parent_of(&there);
        let is_child    = here.is_child_of(&there);

        assert!(!is_parent.unwrap());
        assert!(!is_child.unwrap());
    }

    #[test]
    fn tagged_parent() {
        let here        = ("first", "second").to_tree_address();
        let there       = ("first", ("second", "third")).to_tree_address();
        let is_parent   = here.is_parent_of(&there);
        let is_child    = here.is_child_of(&there);

        assert!(is_parent.unwrap());
        assert!(!is_child.unwrap());
    }

    #[test]
    fn bad_tagged_parent() {
        let here        = ("other tag", "second").to_tree_address();
        let there       = ("first", ("second", "third")).to_tree_address();
        let is_parent   = here.is_parent_of(&there);
        let is_child    = here.is_child_of(&there);

        assert!(!is_parent.unwrap());
        assert!(!is_child.unwrap());
    }

    #[test]
    fn different_address_types_cant_be_checked() {
        let indexed         = 1.to_tree_address();
        let tagged          = "tag".to_tree_address();

        assert!(indexed.is_parent_of(&tagged).is_none());
        assert!(tagged.is_parent_of(&indexed).is_none());
    }

    #[test]
    fn can_get_relative_address_with_indexes() {
        let address     = (1, (2, (3, 4))).to_tree_address();
        let relative_to = (1, 2).to_tree_address();
        let expected    = (3, 4).to_tree_address();

        assert!(address.relative_to(&relative_to).unwrap() == expected);
    }

    #[test]
    fn can_get_relative_address_with_tags() {
        let address     = ("one", ("two", ("three", "four"))).to_tree_address();
        let relative_to = ("one", "two").to_tree_address();
        let expected    = ("three", "four").to_tree_address();

        assert!(address.relative_to(&relative_to).unwrap() == expected);
    }

    #[test]
    fn relative_to_wrong_address_is_none() {
        let address     = (1, (2, (3, 4))).to_tree_address();
        let relative_to = (3, 4).to_tree_address();

        assert!(address.relative_to(&relative_to).is_none());
    }

    #[test]
    fn relative_to_here_is_none() {
        let address     = ().to_tree_address();
        let relative_to = (3, 4).to_tree_address();

        assert!(address.relative_to(&relative_to).is_none());
    }
}
<|endoftext|>


<commit_before>use std::collections::hash_map::HashMap;
use std::collections::hash_set::HashSet;
use std::fmt::{Display, Formatter, Error};
use std::string::String;
use std::vec::Vec;

use alloc_box::AllocBox;
use super::binding::UniqueBinding;
use super::js_var::{JsVar, JsKey, JsType, JsPtrEnum};

macro_rules! ptr_type_mismatch {
    ($tag:expr, $ptr:expr) => {
        panic!("Pointer type mismatch: expected {:?} but received {:?}", $tag, $ptr);
    }
}

pub type JsProto = Option<Box<JsObjStruct>>;

#[derive(Clone, Debug)]
pub struct JsObjStruct {
    pub proto: JsProto,
    pub name: String,
    pub dict: HashMap<JsKey, JsVar>,
}

impl JsObjStruct {
    #[allow(unused_variables)]
    pub fn new(proto: JsProto, name: &str, kv_tuples: Vec<(JsKey, JsVar, Option<JsPtrEnum>)>,
               allocator: &mut AllocBox) -> JsObjStruct {
        let proto_vec : Vec<_> = match proto {
            Some(ref obj) => obj.clone().dict.into_iter().map(|(key, var)| {
                let ptr = allocator.find_id(&var.unique).map(|ptr| ptr.borrow().clone());
                (key, JsVar::new(var.t), ptr)
            }).collect(),
            None => Vec::new(),
        };

        JsObjStruct {
            proto: proto,
            name: String::from(name),
            dict: proto_vec.into_iter().chain(kv_tuples.into_iter()).map(|(k, v, ptr)| {
                match v.t {
                    JsType::JsPtr(ref tag) => match ptr {
                        Some(ptr) => {
                            if tag.eq_ptr_type(&ptr) {
                                println!("HERE");
                                allocator.alloc(v.unique.clone(), ptr)
                                    .expect("Unable to allocate!"); // TODO better error handling
                            } else {
                                ptr_type_mismatch!(tag, ptr);
                            }
                        },
                        None => ptr_type_mismatch!(tag, None::<JsPtrEnum>),
                    },
                    _ => match ptr {
                        Some(ptr) => ptr_type_mismatch!(None::<JsPtrEnum>, ptr),
                        None => {},
                    },
                }
                (k, v)
            }).collect()
        }
    }

    pub fn add_key(&mut self, obj_binding: &UniqueBinding, k: JsKey, v: JsVar,
                   ptr: Option<JsPtrEnum>, allocator: &mut AllocBox) {
        if let Some(var) = self.dict.get(&k) {
            match var.t {
                JsType::JsPtr(_) => { allocator.condemn(var.unique.clone()).expect("Unable to whiten!") },
                _ => {}
            }
        }
        /*if let Some(ptr) = ptr {
            allocator.alloc(v.unique.clone(), ptr).expect("Unable to allocate!"); // TODO better error handling
        }*/

        match allocator.find_id(obj_binding) {
            Some(ref ptr) => match &mut *(ptr.borrow_mut()) {
                &mut JsPtrEnum::JsObj(ref mut obj) => obj.dict.insert(k.clone(), v.clone()),
                _ => panic!("Binding does not belong to an object!"),
            },
            None => panic!("No pointer with matching binding found!"),
        };

        self.dict.insert(k, v);
    }

    pub fn remove_key(&mut self, obj_binding: &UniqueBinding, k: &JsKey, allocator: &mut AllocBox)
        -> Option<(JsVar, Option<JsPtrEnum>)>{
        let var_opt = match &mut *(allocator.find_id(obj_binding).expect("No pointer with matching binding found!").borrow_mut()) {
            &mut JsPtrEnum::JsObj(ref mut obj) => obj.dict.remove(k),
            _ => panic!("Binding does not belong to an object!"),
        };

        if let Some(var) = var_opt {
            let ptr = allocator.find_id(&var.unique).map(|s| s.borrow().clone());

            if ptr.is_some() {
                allocator.condemn(var.unique.clone()).expect("Unable to whiten!");
            }

            let _ = self.dict.remove(k);
            Some((var, ptr))
        } else {
            None
        }
    }

    pub fn get_children(&self) -> HashSet<UniqueBinding> {
        let mut bindings = HashSet::new();
        for v in self.dict.values() {
            match v.t {
                JsType::JsPtr(_) => { bindings.insert(v.unique.clone()); },
                _ => (),
            }
        }
        bindings
    }
}

impl Display for JsObjStruct {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        try!(write!(fmt, "{{ "));

        for (i, (ref key, ref val)) in self.dict.iter().enumerate() {
            if i != 0 {
                try!(write!(fmt, ", "));
            }

            try!(write!(fmt, "{}: {}", key, val));
        }

        write!(fmt, " }}")
    }
}
<commit_msg>Remove printout from js_obj<commit_after>use std::collections::hash_map::HashMap;
use std::collections::hash_set::HashSet;
use std::fmt::{Display, Formatter, Error};
use std::string::String;
use std::vec::Vec;

use alloc_box::AllocBox;
use super::binding::UniqueBinding;
use super::js_var::{JsVar, JsKey, JsType, JsPtrEnum};

macro_rules! ptr_type_mismatch {
    ($tag:expr, $ptr:expr) => {
        panic!("Pointer type mismatch: expected {:?} but received {:?}", $tag, $ptr);
    }
}

pub type JsProto = Option<Box<JsObjStruct>>;

#[derive(Clone, Debug)]
pub struct JsObjStruct {
    pub proto: JsProto,
    pub name: String,
    pub dict: HashMap<JsKey, JsVar>,
}

impl JsObjStruct {
    #[allow(unused_variables)]
    pub fn new(proto: JsProto, name: &str, kv_tuples: Vec<(JsKey, JsVar, Option<JsPtrEnum>)>,
               allocator: &mut AllocBox) -> JsObjStruct {
        let proto_vec : Vec<_> = match proto {
            Some(ref obj) => obj.clone().dict.into_iter().map(|(key, var)| {
                let ptr = allocator.find_id(&var.unique).map(|ptr| ptr.borrow().clone());
                (key, JsVar::new(var.t), ptr)
            }).collect(),
            None => Vec::new(),
        };

        JsObjStruct {
            proto: proto,
            name: String::from(name),
            dict: proto_vec.into_iter().chain(kv_tuples.into_iter()).map(|(k, v, ptr)| {
                match v.t {
                    JsType::JsPtr(ref tag) => match ptr {
                        Some(ptr) => {
                            if tag.eq_ptr_type(&ptr) {
                                allocator.alloc(v.unique.clone(), ptr)
                                    .expect("Unable to allocate!"); // TODO better error handling
                            } else {
                                ptr_type_mismatch!(tag, ptr);
                            }
                        },
                        None => ptr_type_mismatch!(tag, None::<JsPtrEnum>),
                    },
                    _ => match ptr {
                        Some(ptr) => ptr_type_mismatch!(None::<JsPtrEnum>, ptr),
                        None => {},
                    },
                }
                (k, v)
            }).collect()
        }
    }

    pub fn add_key(&mut self, obj_binding: &UniqueBinding, k: JsKey, v: JsVar,
                   ptr: Option<JsPtrEnum>, allocator: &mut AllocBox) {
        if let Some(var) = self.dict.get(&k) {
            match var.t {
                JsType::JsPtr(_) => { allocator.condemn(var.unique.clone()).expect("Unable to whiten!") },
                _ => {}
            }
        }
        /*if let Some(ptr) = ptr {
            allocator.alloc(v.unique.clone(), ptr).expect("Unable to allocate!"); // TODO better error handling
        }*/

        match allocator.find_id(obj_binding) {
            Some(ref ptr) => match &mut *(ptr.borrow_mut()) {
                &mut JsPtrEnum::JsObj(ref mut obj) => obj.dict.insert(k.clone(), v.clone()),
                _ => panic!("Binding does not belong to an object!"),
            },
            None => panic!("No pointer with matching binding found!"),
        };

        self.dict.insert(k, v);
    }

    pub fn remove_key(&mut self, obj_binding: &UniqueBinding, k: &JsKey, allocator: &mut AllocBox)
        -> Option<(JsVar, Option<JsPtrEnum>)>{
        let var_opt = match &mut *(allocator.find_id(obj_binding).expect("No pointer with matching binding found!").borrow_mut()) {
            &mut JsPtrEnum::JsObj(ref mut obj) => obj.dict.remove(k),
            _ => panic!("Binding does not belong to an object!"),
        };

        if let Some(var) = var_opt {
            let ptr = allocator.find_id(&var.unique).map(|s| s.borrow().clone());

            if ptr.is_some() {
                allocator.condemn(var.unique.clone()).expect("Unable to whiten!");
            }

            let _ = self.dict.remove(k);
            Some((var, ptr))
        } else {
            None
        }
    }

    pub fn get_children(&self) -> HashSet<UniqueBinding> {
        let mut bindings = HashSet::new();
        for v in self.dict.values() {
            match v.t {
                JsType::JsPtr(_) => { bindings.insert(v.unique.clone()); },
                _ => (),
            }
        }
        bindings
    }
}

impl Display for JsObjStruct {
    fn fmt(&self, mut fmt: &mut Formatter) -> Result<(), Error> {
        try!(write!(fmt, "{{ "));

        for (i, (ref key, ref val)) in self.dict.iter().enumerate() {
            if i != 0 {
                try!(write!(fmt, ", "));
            }

            try!(write!(fmt, "{}: {}", key, val));
        }

        write!(fmt, " }}")
    }
}
<|endoftext|>


<commit_before>use cache::Cache;
use client_query::*;
use coarsetime::Instant;
use dns;
use mio::*;
use std::io;
use std::net::UdpSocket;
use std::sync::Arc;
use std::sync::mpsc;
use std::thread;
use super::EdgeDNSContext;
use varz::Varz;

use super::{DNS_MAX_UDP_SIZE, DNS_QUERY_MIN_SIZE, DNS_QUERY_MAX_SIZE};

pub struct UdpListener {
    socket: UdpSocket,
    resolver_tx: channel::SyncSender<ClientQuery>,
    service_ready_tx: mpsc::SyncSender<u8>,
    cache: Cache,
    varz: Arc<Varz>,
}

impl UdpListener {
    fn run(mut self) -> io::Result<()> {
        debug!("udp listener socket={:?}", self.socket);
        self.service_ready_tx.send(0).unwrap();
        let mut packet = [0u8; DNS_MAX_UDP_SIZE];
        loop {
            let (count, client_addr) =
                self.socket.recv_from(&mut packet).expect("UDP socket error");
            self.varz.client_queries_udp.inc();
            if count < DNS_QUERY_MIN_SIZE || count > DNS_QUERY_MAX_SIZE {
                info!("Short query using UDP");
                self.varz.client_queries_errors.inc();
                continue;
            }
            let packet = &packet[..count];
            let normalized_question = match dns::normalize(packet, true) {
                Ok(normalized_question) => normalized_question,
                Err(e) => {
                    debug!("Error while parsing the question: {}", e);
                    self.varz.client_queries_errors.inc();
                    continue;
                }
            };
            let cache_entry = self.cache.get2(&normalized_question);
            if let Some(mut cache_entry) = cache_entry {
                if !cache_entry.is_expired() {
                    self.varz.client_queries_cached.inc();
                    if cache_entry.packet.len() > normalized_question.payload_size as usize {
                        debug!("cached, but has to be truncated");
                        let packet = dns::build_tc_packet(&normalized_question).unwrap();
                        let _ = self.socket.send_to(&packet, &client_addr);
                        continue;
                    }
                    debug!("cached");
                    dns::set_tid(&mut cache_entry.packet, normalized_question.tid);
                    dns::overwrite_qname(&mut cache_entry.packet, &normalized_question.qname);
                    let _ = self.socket.send_to(&cache_entry.packet, &client_addr);
                    continue;
                }
                debug!("expired");
                self.varz.client_queries_expired.inc();
            }
            let client_query = ClientQuery {
                proto: ClientQueryProtocol::UDP,
                client_tok: None,
                client_addr: Some(client_addr),
                tcpclient_tx: None,
                normalized_question: normalized_question,
                ts: Instant::recent(),
            };
            let _ = self.resolver_tx.send(client_query);
        }
    }

    pub fn spawn(edgedns_context: &EdgeDNSContext,
                 resolver_tx: channel::SyncSender<ClientQuery>,
                 service_ready_tx: mpsc::SyncSender<u8>)
                 -> io::Result<(thread::JoinHandle<()>)> {
        let udp_socket = edgedns_context.udp_socket
            .try_clone()
            .expect("Unable to clone the UDP listening socket");
        let udp_listener = UdpListener {
            socket: udp_socket,
            resolver_tx: resolver_tx,
            service_ready_tx: service_ready_tx,
            cache: edgedns_context.cache.clone(),
            varz: edgedns_context.varz.clone(),
        };
        let udp_listener_th = thread::Builder::new()
            .name("udp_listener".to_string())
            .spawn(move || {
                udp_listener.run().expect("Unable to spawn a UDP listener");
            })
            .unwrap();
        info!("UDP listener is ready");
        Ok((udp_listener_th))
    }
}
<commit_msg>Cargo fmt<commit_after>use cache::Cache;
use client_query::*;
use coarsetime::Instant;
use dns;
use mio::*;
use std::io;
use std::net::UdpSocket;
use std::sync::Arc;
use std::sync::mpsc;
use std::thread;
use super::EdgeDNSContext;
use varz::Varz;

use super::{DNS_MAX_UDP_SIZE, DNS_QUERY_MIN_SIZE, DNS_QUERY_MAX_SIZE};

pub struct UdpListener {
    socket: UdpSocket,
    resolver_tx: channel::SyncSender<ClientQuery>,
    service_ready_tx: mpsc::SyncSender<u8>,
    cache: Cache,
    varz: Arc<Varz>,
}

impl UdpListener {
    fn run(mut self) -> io::Result<()> {
        debug!("udp listener socket={:?}", self.socket);
        self.service_ready_tx.send(0).unwrap();
        let mut packet = [0u8; DNS_MAX_UDP_SIZE];
        loop {
            let (count, client_addr) =
                self.socket.recv_from(&mut packet).expect("UDP socket error");
            self.varz.client_queries_udp.inc();
            if count < DNS_QUERY_MIN_SIZE || count > DNS_QUERY_MAX_SIZE {
                info!("Short query using UDP");
                self.varz.client_queries_errors.inc();
                continue;
            }
            let packet = &packet[..count];
            let normalized_question = match dns::normalize(packet, true) {
                Ok(normalized_question) => normalized_question,
                Err(e) => {
                    debug!("Error while parsing the question: {}", e);
                    self.varz.client_queries_errors.inc();
                    continue;
                }
            };
            let cache_entry = self.cache.get2(&normalized_question);
            if let Some(mut cache_entry) = cache_entry {
                if !cache_entry.is_expired() {
                    self.varz.client_queries_cached.inc();
                    if cache_entry.packet.len() > normalized_question.payload_size as usize {
                        debug!("cached, but has to be truncated");
                        let packet = dns::build_tc_packet(&normalized_question).unwrap();
                        let _ = self.socket.send_to(&packet, &client_addr);
                        continue;
                    }
                    debug!("cached");
                    dns::set_tid(&mut cache_entry.packet, normalized_question.tid);
                    dns::overwrite_qname(&mut cache_entry.packet, &normalized_question.qname);
                    let _ = self.socket.send_to(&cache_entry.packet, &client_addr);
                    continue;
                }
                debug!("expired");
                self.varz.client_queries_expired.inc();
            }
            let client_query = ClientQuery {
                proto: ClientQueryProtocol::UDP,
                client_tok: None,
                client_addr: Some(client_addr),
                tcpclient_tx: None,
                normalized_question: normalized_question,
                ts: Instant::recent(),
            };
            let _ = self.resolver_tx.send(client_query);
        }
    }

    pub fn spawn(edgedns_context: &EdgeDNSContext,
                 resolver_tx: channel::SyncSender<ClientQuery>,
                 service_ready_tx: mpsc::SyncSender<u8>)
                 -> io::Result<(thread::JoinHandle<()>)> {
        let udp_socket = edgedns_context.udp_socket
            .try_clone()
            .expect("Unable to clone the UDP listening socket");
        let udp_listener = UdpListener {
            socket: udp_socket,
            resolver_tx: resolver_tx,
            service_ready_tx: service_ready_tx,
            cache: edgedns_context.cache.clone(),
            varz: edgedns_context.varz.clone(),
        };
        let udp_listener_th = thread::Builder::new()
            .name("udp_listener".to_string())
            .spawn(move || { udp_listener.run().expect("Unable to spawn a UDP listener"); })
            .unwrap();
        info!("UDP listener is ready");
        Ok((udp_listener_th))
    }
}
<|endoftext|>


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

use rocksdb::{DB, Options};
use rocksdb::rocksdb_ffi::DBCFHandle;

pub fn get_cf_handle<'a>(db: &'a DB, cf: &str) -> Result<&'a DBCFHandle, String> {
    db.cf_handle(cf)
        .ok_or_else(|| format!("cf {} not found.", cf))
}

pub fn open(path: &str, cfs: &[&str]) -> Result<DB, String> {
    let mut opts = Options::new();
    opts.create_if_missing(false);
    let mut cfs_opts = vec![];
    for _ in 0..cfs.len() {
        cfs_opts.push(Options::new());
    }
    open_opt(&opts, path, cfs, cfs_opts)
}

pub fn open_opt(opts: &Options,
                path: &str,
                cfs: &[&str],
                cfs_opts: Vec<Options>)
                -> Result<DB, String> {
    let cfs_ref_opts: Vec<&Options> = cfs_opts.iter().collect();
    DB::open_cf(opts, path, cfs, &cfs_ref_opts)
}

pub fn new_engine(path: &str, cfs: &[&str]) -> Result<DB, String> {
    let opts = Options::new();
    let mut cfs_opts = vec![];
    for _ in 0..cfs.len() {
        cfs_opts.push(Options::new());
    }
    new_engine_opt(opts, path, cfs, cfs_opts)
}

pub fn new_engine_opt(mut opts: Options,
                      path: &str,
                      cfs: &[&str],
                      cfs_opts: Vec<Options>)
                      -> Result<DB, String> {
    // Currently we support 1) Create new db. 2) Open a db with CFs we want. 3) Open db with no
    // CF.
    // TODO: Support open db with incomplete CFs.

    // opts is used as Rocksdb's DBOptions when call DB::open_cf
    opts.create_if_missing(false);
    let cfs_ref_opts: Vec<&Options> = cfs_opts.iter().collect();
    match DB::open_cf(&opts, path, cfs, &cfs_ref_opts) {
        Ok(db) => return Ok(db),
        Err(e) => warn!("open rocksdb fail: {}", e),
    }

    // opts is used as Rocksdb's Options(include DBOptions and ColumnFamilyOptions)
    // when call DB::open
    opts.create_if_missing(true);
    let mut db = match DB::open(&opts, path) {
        Ok(db) => db,
        Err(e) => return Err(e),
    };
    for (&cf, &cf_opts) in cfs.iter().zip(&cfs_ref_opts) {
        if cf == "default" {
            continue;
        }
        if let Err(e) = db.create_cf(cf, cf_opts) {
            return Err(e);
        }
    }
    Ok(db)
}
<commit_msg>util: remove unnecessary log. (#972)<commit_after>// Copyright 2016 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

use rocksdb::{DB, Options};
use rocksdb::rocksdb_ffi::DBCFHandle;

pub fn get_cf_handle<'a>(db: &'a DB, cf: &str) -> Result<&'a DBCFHandle, String> {
    db.cf_handle(cf)
        .ok_or_else(|| format!("cf {} not found.", cf))
}

pub fn open(path: &str, cfs: &[&str]) -> Result<DB, String> {
    let mut opts = Options::new();
    opts.create_if_missing(false);
    let mut cfs_opts = vec![];
    for _ in 0..cfs.len() {
        cfs_opts.push(Options::new());
    }
    open_opt(&opts, path, cfs, cfs_opts)
}

pub fn open_opt(opts: &Options,
                path: &str,
                cfs: &[&str],
                cfs_opts: Vec<Options>)
                -> Result<DB, String> {
    let cfs_ref_opts: Vec<&Options> = cfs_opts.iter().collect();
    DB::open_cf(opts, path, cfs, &cfs_ref_opts)
}

pub fn new_engine(path: &str, cfs: &[&str]) -> Result<DB, String> {
    let opts = Options::new();
    let mut cfs_opts = vec![];
    for _ in 0..cfs.len() {
        cfs_opts.push(Options::new());
    }
    new_engine_opt(opts, path, cfs, cfs_opts)
}

pub fn new_engine_opt(mut opts: Options,
                      path: &str,
                      cfs: &[&str],
                      cfs_opts: Vec<Options>)
                      -> Result<DB, String> {
    // Currently we support 1) Create new db. 2) Open a db with CFs we want. 3) Open db with no
    // CF.
    // TODO: Support open db with incomplete CFs.

    // opts is used as Rocksdb's DBOptions when call DB::open_cf
    opts.create_if_missing(false);
    let cfs_ref_opts: Vec<&Options> = cfs_opts.iter().collect();
    if let Ok(db) = DB::open_cf(&opts, path, cfs, &cfs_ref_opts) {
        return Ok(db);
    }

    // opts is used as Rocksdb's Options(include DBOptions and ColumnFamilyOptions)
    // when call DB::open
    opts.create_if_missing(true);
    let mut db = match DB::open(&opts, path) {
        Ok(db) => db,
        Err(e) => return Err(e),
    };
    for (&cf, &cf_opts) in cfs.iter().zip(&cfs_ref_opts) {
        if cf == "default" {
            continue;
        }
        if let Err(e) = db.create_cf(cf, cf_opts) {
            return Err(e);
        }
    }
    Ok(db)
}
<|endoftext|>


<commit_before>use sdl2::pixels::Color;
use game::data::Rectangle;
use game::{Game};
use game::constants::{BULLET_W, BULLET_H, BULLET_SPEED};
use views::{Orientation, Point};

#[derive(Clone, Debug)]
pub struct Bullet {
  pub rect: Rectangle,
  pub direction: Orientation
}

impl Bullet {
  pub fn new(point: Rectangle, orientation: Orientation) -> Bullet {
    let mut correction = Point { x: 0.0, y: 0.0 };
    match orientation {
      Orientation::Right => {
        correction.x = point.x + 55.0;
        correction.y = point.y + 5.0;
      },
      Orientation::UpRight => {
        correction.x = point.x + 50.0;
        correction.y = point.y + 5.0;
      },
      Orientation::Up => {
        correction.x = point.x + 48.0;
        correction.y = point.y;
      },
      Orientation::UpLeft => {
        correction.x = point.x + 50.0;
        correction.y = point.y + 10.0;
      },
      Orientation::Left => {
        correction.x = point.x + 40.0;
        correction.y = point.y + 5.0;
      },
      Orientation::DownLeft => {
        correction.x = point.x + 40.0;
        correction.y = point.y;
      },
      Orientation::Down => {
        correction.x = point.x + 30.0;
        correction.y = point.y + 20.0;
      },
      Orientation::DownRight => {
        correction.x = point.x + 60.0;
        correction.y = point.y + 20.0;
      }
    }

    Bullet {
      rect: Rectangle {
        x: correction.x,
        y: correction.y,
        w: BULLET_W,
        h: BULLET_H,
      },
      direction: orientation
    }
  }
}

pub trait Projectile {
  fn update(self: Box<Self>, game: &mut Game, dt: f64) -> Option<Box<Projectile>>;

  fn render(&self, game: &mut Game);

  fn rect(&self) -> Rectangle;
}

impl Projectile for Bullet {
  fn update(mut self: Box<Self>, game: &mut Game, dt: f64) -> Option<Box<Projectile>> {
    let (w, h) = game.output_size();

    match self.direction {
      Orientation::Right => {
        self.rect.x += BULLET_SPEED * dt;
      },
      Orientation::UpRight => {
        self.rect.x += BULLET_SPEED * dt / 2.0;
        self.rect.y -= BULLET_SPEED * dt;
      },
      Orientation::Up => {
        self.rect.y -= BULLET_SPEED * dt / 2.0;
      },
      Orientation::UpLeft => {
        self.rect.x -= BULLET_SPEED * dt / 2.0;
        self.rect.y -= BULLET_SPEED * dt;
      },
      Orientation::Left => {
        self.rect.x -= BULLET_SPEED * dt;
      },
      Orientation::DownLeft => {
        self.rect.x -= BULLET_SPEED * dt;
        self.rect.y += BULLET_SPEED * dt / 2.0;
      },
      Orientation::Down => {
        self.rect.y += BULLET_SPEED * dt;
      },
      Orientation::DownRight => {
        self.rect.x += BULLET_SPEED * dt;
        self.rect.y += BULLET_SPEED * dt / 2.0;
      }
    }

    if self.rect.x > w || self.rect.x < 0.0 ||
      self.rect.y > h || self.rect.y < 0.0 {
      None
    } else {
      Some(self)
    }
  }

  fn render(&self, game: &mut Game) {
    game.renderer.set_draw_color(Color::RGBA(50, 50, 50, 0));
    game.renderer.fill_rect(self.rect.to_sdl().unwrap());
  }

  fn rect(&self) -> Rectangle {
    self.rect
  }
}
<commit_msg>Fix UpLeft and UpRight bullet directions<commit_after>use sdl2::pixels::Color;
use game::data::Rectangle;
use game::{Game};
use game::constants::{BULLET_W, BULLET_H, BULLET_SPEED};
use views::{Orientation, Point};

#[derive(Clone, Debug)]
pub struct Bullet {
  pub rect: Rectangle,
  pub direction: Orientation
}

impl Bullet {
  pub fn new(point: Rectangle, orientation: Orientation) -> Bullet {
    let mut correction = Point { x: 0.0, y: 0.0 };
    match orientation {
      Orientation::Right => {
        correction.x = point.x + 55.0;
        correction.y = point.y + 5.0;
      },
      Orientation::UpRight => {
        correction.x = point.x + 50.0;
        correction.y = point.y + 5.0;
      },
      Orientation::Up => {
        correction.x = point.x + 48.0;
        correction.y = point.y;
      },
      Orientation::UpLeft => {
        correction.x = point.x + 50.0;
        correction.y = point.y + 10.0;
      },
      Orientation::Left => {
        correction.x = point.x + 40.0;
        correction.y = point.y + 5.0;
      },
      Orientation::DownLeft => {
        correction.x = point.x + 40.0;
        correction.y = point.y;
      },
      Orientation::Down => {
        correction.x = point.x + 30.0;
        correction.y = point.y + 20.0;
      },
      Orientation::DownRight => {
        correction.x = point.x + 60.0;
        correction.y = point.y + 20.0;
      }
    }

    Bullet {
      rect: Rectangle {
        x: correction.x,
        y: correction.y,
        w: BULLET_W,
        h: BULLET_H,
      },
      direction: orientation
    }
  }
}

pub trait Projectile {
  fn update(self: Box<Self>, game: &mut Game, dt: f64) -> Option<Box<Projectile>>;

  fn render(&self, game: &mut Game);

  fn rect(&self) -> Rectangle;
}

impl Projectile for Bullet {
  fn update(mut self: Box<Self>, game: &mut Game, dt: f64) -> Option<Box<Projectile>> {
    let (w, h) = game.output_size();

    match self.direction {
      Orientation::Right => {
        self.rect.x += BULLET_SPEED * dt;
      },
      Orientation::UpRight => {
        self.rect.x += BULLET_SPEED * dt;
        self.rect.y -= BULLET_SPEED * dt / 2.0;
      },
      Orientation::Up => {
        self.rect.y -= BULLET_SPEED * dt / 2.0;
      },
      Orientation::UpLeft => {
        self.rect.x -= BULLET_SPEED * dt;
        self.rect.y -= BULLET_SPEED * dt / 2.0;
      },
      Orientation::Left => {
        self.rect.x -= BULLET_SPEED * dt;
      },
      Orientation::DownLeft => {
        self.rect.x -= BULLET_SPEED * dt;
        self.rect.y += BULLET_SPEED * dt / 2.0;
      },
      Orientation::Down => {
        self.rect.y += BULLET_SPEED * dt;
      },
      Orientation::DownRight => {
        self.rect.x += BULLET_SPEED * dt;
        self.rect.y += BULLET_SPEED * dt / 2.0;
      }
    }

    if self.rect.x > w || self.rect.x < 0.0 ||
      self.rect.y > h || self.rect.y < 0.0 {
      None
    } else {
      Some(self)
    }
  }

  fn render(&self, game: &mut Game) {
    game.renderer.set_draw_color(Color::RGBA(50, 50, 50, 0));
    game.renderer.fill_rect(self.rect.to_sdl().unwrap());
  }

  fn rect(&self) -> Rectangle {
    self.rect
  }
}
<|endoftext|>


<commit_before>use webcore::value::Reference;
use webcore::try_from::TryInto;
use webcore::reference_type::ReferenceType;
use webapi::event_target::EventTarget;
use webapi::window::Window;

/// The `IEvent` interface represents any event which takes place in the DOM; some
/// are user-generated (such as mouse or keyboard events), while others are
/// generated by APIs (such as events that indicate an animation has finished
/// running, a video has been paused, and so forth). There are many types of event,
/// some of which use other interfaces based on the main `IEvent` interface. `IEvent`
/// itself contains the properties and methods which are common to all events.
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event)
// https://dom.spec.whatwg.org/#event
pub trait IEvent: ReferenceType {
    /// Indicates whether this event bubbles upward through the DOM.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event)
    // https://dom.spec.whatwg.org/#ref-for-dom-event-bubbles%E2%91%A0
    #[inline]
    fn bubbles( &self ) -> bool {
        js!(
            return @{self.as_ref()}.bubbles;
        ).try_into().unwrap()
    }

    /// A historical alias to `Event.stopPropagation()`.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/cancelBubble)
    // https://dom.spec.whatwg.org/#ref-for-dom-event-cancelbubble
    #[inline]
    fn cancel_bubble( &self ) -> bool {
        js!(
            return @{self.as_ref()}.cancelBubble;
        ).try_into().unwrap()
    }

    /// A historical alias to `Event.stopPropagation()`.
    /// Setting this to `true` before returning from an event handler will stop propagation
    /// of the event.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/cancelBubble)
    // https://dom.spec.whatwg.org/#ref-for-dom-event-cancelbubble
    #[inline]
    fn set_cancel_bubble( &self, value: bool ) {
        js! { @(no_return)
            @{self.as_ref()}.cancelBubble = @{value};
        }
    }

    /// Indicates whether the event is cancelable.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/cancelable)
    // https://dom.spec.whatwg.org/#ref-for-dom-event-cancelable
    #[inline]
    fn cancelable( &self ) -> bool {
        js!(
            return @{self.as_ref()}.cancelable;
        ).try_into().unwrap()
    }

    /// A reference to the currently registered target of this event.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/currentTarget)
    // https://dom.spec.whatwg.org/#ref-for-dom-event-currenttarget%E2%91%A0
    #[inline]
    fn current_target( &self ) -> Option< EventTarget > {
        js!(
            return @{self.as_ref()}.currentTarget;
        ).try_into().ok()
    }

    /// Indicates whether `preventDefault` has been called on this event.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/defaultPrevented)
    // https://dom.spec.whatwg.org/#ref-for-dom-event-defaultprevented
    #[inline]
    fn default_prevented( &self ) -> bool {
        js!(
            return @{self.as_ref()}.defaultPrevented;
        ).try_into().unwrap()
    }

    /// Indicates which phase of event flow is currently being evaluated.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/eventPhase)
    // https://dom.spec.whatwg.org/#ref-for-dom-event-eventphase%E2%91%A1
    fn event_phase( &self ) -> EventPhase {
        match js!(
            return @{self.as_ref()}.eventPhase;
        ).try_into().unwrap() {
            0 => EventPhase::None,
            1 => EventPhase::Capturing,
            2 => EventPhase::AtTarget,
            3 => EventPhase::Bubbling,
            _ => unreachable!("Unexpected EventPhase type"),
        }
    }

    /// Prevents any further listeners from being called for this event.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/stopImmediatePropagation)
    #[inline]
    fn stop_immediate_propagation( &self ) {
        js! { @(no_return)
            @{self.as_ref()}.stopImmediatePropagation();
        }
    }

    /// Stops the propagation of this event to descendants in the DOM.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/stopPropagation)
    // https://dom.spec.whatwg.org/#ref-for-dom-event-stopimmediatepropagation
    #[inline]
    fn stop_propagation( &self ) {
        js! { @(no_return)
            @{self.as_ref()}.stopPropagation();
        }
    }

    /// Returns a reference to the target to which this event was originally registered.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/target)
    // https://dom.spec.whatwg.org/#ref-for-dom-event-target%E2%91%A1
    #[inline]
    fn target( &self ) -> Option< EventTarget > {
        js!(
            return @{self.as_ref()}.target;
        ).try_into().ok()
    }

    /// Returns the time in milliseconds at which this event was created.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/timeStamp)
    // https://dom.spec.whatwg.org/#ref-for-dom-event-timestamp
    #[inline]
    fn time_stamp( &self ) -> Option< f64 > {
        js!(
            return @{self.as_ref()}.timeStamp;
        ).try_into().ok()
    }

    /// Indicates whether the event was generated by a user action.
    // https://dom.spec.whatwg.org/#ref-for-dom-event-istrusted
    #[inline]
    fn is_trusted( &self ) -> bool {
        js!(
            return @{self.as_ref()}.isTrusted;
        ).try_into().unwrap()
    }

    /// Returns a string containing the type of event. It is set when
    /// the event is constructed and is the name commonly used to refer
    /// to the specific event.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/type)
    // https://dom.spec.whatwg.org/#ref-for-dom-event-type%E2%91%A1
    #[inline]
    fn event_type( &self ) -> String {
        js!(
            return @{self.as_ref()}.type;
        ).try_into().unwrap()
    }

    /// Cancels the event if it is cancelable, without
    /// stopping further propagation of the event.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
    // https://dom.spec.whatwg.org/#ref-for-dom-event-preventdefault%E2%91%A0
    #[inline]
    fn prevent_default( &self ) {
        js! { @(no_return)
            @{self.as_ref()}.preventDefault();
        }
    }
}

/// Indicates the phase of event flow during event proessing.
// https://dom.spec.whatwg.org/#dom-event-eventphase
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum EventPhase {
    /// No event is currently being processed.
    None,
    /// The event is being propagated down through the target's ancestors.
    Capturing,
    /// The target is currently processing the event.
    AtTarget,
    /// The event is propagating back up through the target's ancestors.
    Bubbling,
}

/// A trait representing a concrete event type.
pub trait ConcreteEvent: IEvent {
    /// A string representing the event type.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/type)
    const EVENT_TYPE: &'static str;
}

/// A reference to a JavaScript object which implements the [IEvent](trait.IEvent.html)
/// interface.
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event)
// https://dom.spec.whatwg.org/#event
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "Event")]
pub struct Event( Reference );

impl IEvent for Event {}

/// The `IUiEvent` interface represents simple user interface events.
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/UIEvent)
// https://w3c.github.io/uievents/#uievent
pub trait IUiEvent: IEvent {
    /// Provides the current click count for this event, if applicable.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/detail)
    // https://w3c.github.io/uievents/#dom-uievent-detail
    #[inline]
    fn detail( &self ) -> i32 {
        js!(
            return @{self.as_ref()}.detail;
        ).try_into().unwrap()
    }

    /// Returns the `WindowProxy` that generated the event.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/view)
    // https://w3c.github.io/uievents/#dom-uievent-view
    #[inline]
    fn view( &self ) -> Option< Window > {
        js!(
            return @{self.as_ref()}.view;
        ).try_into().ok()
    }
}

/// A reference to a JavaScript object which implements the [IUiEvent](trait.IUiEvent.html)
/// interface.
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/UIEvent)
// https://w3c.github.io/uievents/#uievent
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "UIEvent")]
#[reference(subclass_of(Event))]
pub struct UiEvent( Reference );

impl IEvent for UiEvent {}
impl IUiEvent for UiEvent {}

#[cfg(all(test, feature = "web_test"))]
mod tests {
    use super::*;

    #[test]
    fn test_event() {
        let event: Event = js!(
            return new Event("dummy")
        ).try_into().unwrap();

        assert_eq!( event.event_type(), "dummy" );
        assert_eq!( event.bubbles(), false );
        assert!( !event.cancel_bubble() );
        assert!( !event.cancelable(), false );
        assert!( event.current_target().is_none() );
        assert!( !event.default_prevented() );
        assert_eq!( event.event_phase(), EventPhase::None );
        assert!( event.target().is_none() );
        assert!( event.time_stamp().is_some() );
        assert!( !event.is_trusted() );

        event.stop_immediate_propagation();
        event.stop_propagation();
    }

    #[test]
    fn test_ui_event() {
        use webapi::events::mouse::ClickEvent;

        let event: UiEvent = js!(
            return new UIEvent(
                @{ClickEvent::EVENT_TYPE},
                {
                    detail: 1,
                }
            )
        ).try_into().unwrap();
        assert_eq!( event.event_type(), ClickEvent::EVENT_TYPE );
        assert_eq!( event.detail(), 1 );
        assert!( event.view().is_none() );
    }
}
<commit_msg>Add `BeforeUnloadEvent` and `UnloadEvent` (#344)<commit_after>use webcore::value::Reference;
use webcore::try_from::TryInto;
use webcore::reference_type::ReferenceType;
use webapi::event_target::EventTarget;
use webapi::window::Window;

/// The `IEvent` interface represents any event which takes place in the DOM; some
/// are user-generated (such as mouse or keyboard events), while others are
/// generated by APIs (such as events that indicate an animation has finished
/// running, a video has been paused, and so forth). There are many types of event,
/// some of which use other interfaces based on the main `IEvent` interface. `IEvent`
/// itself contains the properties and methods which are common to all events.
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event)
// https://dom.spec.whatwg.org/#event
pub trait IEvent: ReferenceType {
    /// Indicates whether this event bubbles upward through the DOM.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event)
    // https://dom.spec.whatwg.org/#ref-for-dom-event-bubbles%E2%91%A0
    #[inline]
    fn bubbles( &self ) -> bool {
        js!(
            return @{self.as_ref()}.bubbles;
        ).try_into().unwrap()
    }

    /// A historical alias to `Event.stopPropagation()`.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/cancelBubble)
    // https://dom.spec.whatwg.org/#ref-for-dom-event-cancelbubble
    #[inline]
    fn cancel_bubble( &self ) -> bool {
        js!(
            return @{self.as_ref()}.cancelBubble;
        ).try_into().unwrap()
    }

    /// A historical alias to `Event.stopPropagation()`.
    /// Setting this to `true` before returning from an event handler will stop propagation
    /// of the event.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/cancelBubble)
    // https://dom.spec.whatwg.org/#ref-for-dom-event-cancelbubble
    #[inline]
    fn set_cancel_bubble( &self, value: bool ) {
        js! { @(no_return)
            @{self.as_ref()}.cancelBubble = @{value};
        }
    }

    /// Indicates whether the event is cancelable.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/cancelable)
    // https://dom.spec.whatwg.org/#ref-for-dom-event-cancelable
    #[inline]
    fn cancelable( &self ) -> bool {
        js!(
            return @{self.as_ref()}.cancelable;
        ).try_into().unwrap()
    }

    /// A reference to the currently registered target of this event.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/currentTarget)
    // https://dom.spec.whatwg.org/#ref-for-dom-event-currenttarget%E2%91%A0
    #[inline]
    fn current_target( &self ) -> Option< EventTarget > {
        js!(
            return @{self.as_ref()}.currentTarget;
        ).try_into().ok()
    }

    /// Indicates whether `preventDefault` has been called on this event.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/defaultPrevented)
    // https://dom.spec.whatwg.org/#ref-for-dom-event-defaultprevented
    #[inline]
    fn default_prevented( &self ) -> bool {
        js!(
            return @{self.as_ref()}.defaultPrevented;
        ).try_into().unwrap()
    }

    /// Indicates which phase of event flow is currently being evaluated.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/eventPhase)
    // https://dom.spec.whatwg.org/#ref-for-dom-event-eventphase%E2%91%A1
    fn event_phase( &self ) -> EventPhase {
        match js!(
            return @{self.as_ref()}.eventPhase;
        ).try_into().unwrap() {
            0 => EventPhase::None,
            1 => EventPhase::Capturing,
            2 => EventPhase::AtTarget,
            3 => EventPhase::Bubbling,
            _ => unreachable!("Unexpected EventPhase type"),
        }
    }

    /// Prevents any further listeners from being called for this event.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/stopImmediatePropagation)
    #[inline]
    fn stop_immediate_propagation( &self ) {
        js! { @(no_return)
            @{self.as_ref()}.stopImmediatePropagation();
        }
    }

    /// Stops the propagation of this event to descendants in the DOM.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/stopPropagation)
    // https://dom.spec.whatwg.org/#ref-for-dom-event-stopimmediatepropagation
    #[inline]
    fn stop_propagation( &self ) {
        js! { @(no_return)
            @{self.as_ref()}.stopPropagation();
        }
    }

    /// Returns a reference to the target to which this event was originally registered.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/target)
    // https://dom.spec.whatwg.org/#ref-for-dom-event-target%E2%91%A1
    #[inline]
    fn target( &self ) -> Option< EventTarget > {
        js!(
            return @{self.as_ref()}.target;
        ).try_into().ok()
    }

    /// Returns the time in milliseconds at which this event was created.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/timeStamp)
    // https://dom.spec.whatwg.org/#ref-for-dom-event-timestamp
    #[inline]
    fn time_stamp( &self ) -> Option< f64 > {
        js!(
            return @{self.as_ref()}.timeStamp;
        ).try_into().ok()
    }

    /// Indicates whether the event was generated by a user action.
    // https://dom.spec.whatwg.org/#ref-for-dom-event-istrusted
    #[inline]
    fn is_trusted( &self ) -> bool {
        js!(
            return @{self.as_ref()}.isTrusted;
        ).try_into().unwrap()
    }

    /// Returns a string containing the type of event. It is set when
    /// the event is constructed and is the name commonly used to refer
    /// to the specific event.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/type)
    // https://dom.spec.whatwg.org/#ref-for-dom-event-type%E2%91%A1
    #[inline]
    fn event_type( &self ) -> String {
        js!(
            return @{self.as_ref()}.type;
        ).try_into().unwrap()
    }

    /// Cancels the event if it is cancelable, without
    /// stopping further propagation of the event.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
    // https://dom.spec.whatwg.org/#ref-for-dom-event-preventdefault%E2%91%A0
    #[inline]
    fn prevent_default( &self ) {
        js! { @(no_return)
            @{self.as_ref()}.preventDefault();
        }
    }
}

/// Indicates the phase of event flow during event proessing.
// https://dom.spec.whatwg.org/#dom-event-eventphase
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum EventPhase {
    /// No event is currently being processed.
    None,
    /// The event is being propagated down through the target's ancestors.
    Capturing,
    /// The target is currently processing the event.
    AtTarget,
    /// The event is propagating back up through the target's ancestors.
    Bubbling,
}

/// A trait representing a concrete event type.
pub trait ConcreteEvent: IEvent {
    /// A string representing the event type.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event/type)
    const EVENT_TYPE: &'static str;
}

/// A reference to a JavaScript object which implements the [IEvent](trait.IEvent.html)
/// interface.
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Event)
// https://dom.spec.whatwg.org/#event
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "Event")]
pub struct Event( Reference );

impl IEvent for Event {}

/// The `BeforeUnload` event fires when the window is about to be unloaded (to close the page or
/// follow a link). If the event propagation is cancelled, the browser will present the user with
/// a confirmation dialog allowing them to stay on the page or continue.
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event)
// https://html.spec.whatwg.org/multipage/indices.html#event-beforeunload
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "BeforeUnloadEvent")]
pub struct BeforeUnloadEvent( Reference );

impl IEvent for BeforeUnloadEvent {}

/// The `Unload` event fires when the window has been unloaded and is no longer visible. This event
/// can't be cancelled.
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/Window/unload_event)
// https://html.spec.whatwg.org/multipage/indices.html#event-unload
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "UnloadEvent")]
pub struct UnloadEvent( Reference );

impl IEvent for UnloadEvent {}

/// The `IUiEvent` interface represents simple user interface events.
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/UIEvent)
// https://w3c.github.io/uievents/#uievent
pub trait IUiEvent: IEvent {
    /// Provides the current click count for this event, if applicable.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/detail)
    // https://w3c.github.io/uievents/#dom-uievent-detail
    #[inline]
    fn detail( &self ) -> i32 {
        js!(
            return @{self.as_ref()}.detail;
        ).try_into().unwrap()
    }

    /// Returns the `WindowProxy` that generated the event.
    ///
    /// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/view)
    // https://w3c.github.io/uievents/#dom-uievent-view
    #[inline]
    fn view( &self ) -> Option< Window > {
        js!(
            return @{self.as_ref()}.view;
        ).try_into().ok()
    }
}

/// A reference to a JavaScript object which implements the [IUiEvent](trait.IUiEvent.html)
/// interface.
///
/// [(JavaScript docs)](https://developer.mozilla.org/en-US/docs/Web/API/UIEvent)
// https://w3c.github.io/uievents/#uievent
#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
#[reference(instance_of = "UIEvent")]
#[reference(subclass_of(Event))]
pub struct UiEvent( Reference );

impl IEvent for UiEvent {}
impl IUiEvent for UiEvent {}

#[cfg(all(test, feature = "web_test"))]
mod tests {
    use super::*;

    #[test]
    fn test_event() {
        let event: Event = js!(
            return new Event("dummy")
        ).try_into().unwrap();

        assert_eq!( event.event_type(), "dummy" );
        assert_eq!( event.bubbles(), false );
        assert!( !event.cancel_bubble() );
        assert!( !event.cancelable(), false );
        assert!( event.current_target().is_none() );
        assert!( !event.default_prevented() );
        assert_eq!( event.event_phase(), EventPhase::None );
        assert!( event.target().is_none() );
        assert!( event.time_stamp().is_some() );
        assert!( !event.is_trusted() );

        event.stop_immediate_propagation();
        event.stop_propagation();
    }

    #[test]
    fn test_ui_event() {
        use webapi::events::mouse::ClickEvent;

        let event: UiEvent = js!(
            return new UIEvent(
                @{ClickEvent::EVENT_TYPE},
                {
                    detail: 1,
                }
            )
        ).try_into().unwrap();
        assert_eq!( event.event_type(), ClickEvent::EVENT_TYPE );
        assert_eq!( event.detail(), 1 );
        assert!( event.view().is_none() );
    }
}
<|endoftext|>


<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use aptos_api_types::{
    X_APTOS_CHAIN_ID, X_APTOS_EPOCH, X_APTOS_LEDGER_TIMESTAMP, X_APTOS_LEDGER_VERSION,
};

#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub struct State {
    pub chain_id: u8,
    pub epoch: u64,
    pub version: u64,
    pub timestamp_usecs: u64,
    pub oldest_ledger_version: Option<u64>,
}

impl State {
    pub fn from_headers(headers: &reqwest::header::HeaderMap) -> anyhow::Result<Self> {
        let maybe_chain_id = headers
            .get(X_APTOS_CHAIN_ID)
            .and_then(|h| h.to_str().ok())
            .and_then(|s| s.parse().ok());
        let maybe_version = headers
            .get(X_APTOS_LEDGER_VERSION)
            .and_then(|h| h.to_str().ok())
            .and_then(|s| s.parse().ok());
        let maybe_timestamp = headers
            .get(X_APTOS_LEDGER_TIMESTAMP)
            .and_then(|h| h.to_str().ok())
            .and_then(|s| s.parse().ok());
        let maybe_epoch = headers
            .get(X_APTOS_EPOCH)
            .and_then(|h| h.to_str().ok())
            .and_then(|s| s.parse().ok());
        // TODO: Why doesn't the constant work?
        let oldest_ledger_version = headers
            .get("X-Aptos-Ledger-Oldest-Version")
            .and_then(|h| h.to_str().ok())
            .and_then(|s| s.parse().ok());

        let state = if let (Some(chain_id), Some(version), Some(timestamp_usecs), Some(epoch)) =
            (maybe_chain_id, maybe_version, maybe_timestamp, maybe_epoch)
        {
            Self {
                chain_id,
                epoch,
                version,
                timestamp_usecs,
                oldest_ledger_version,
            }
        } else {
            todo!()
        };

        Ok(state)
    }
}
<commit_msg>Return error in error path when determining State from API headers (#1763)<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use aptos_api_types::{
    X_APTOS_CHAIN_ID, X_APTOS_EPOCH, X_APTOS_LEDGER_TIMESTAMP, X_APTOS_LEDGER_VERSION,
};

#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub struct State {
    pub chain_id: u8,
    pub epoch: u64,
    pub version: u64,
    pub timestamp_usecs: u64,
    pub oldest_ledger_version: Option<u64>,
}

impl State {
    pub fn from_headers(headers: &reqwest::header::HeaderMap) -> anyhow::Result<Self> {
        let maybe_chain_id = headers
            .get(X_APTOS_CHAIN_ID)
            .and_then(|h| h.to_str().ok())
            .and_then(|s| s.parse().ok());
        let maybe_version = headers
            .get(X_APTOS_LEDGER_VERSION)
            .and_then(|h| h.to_str().ok())
            .and_then(|s| s.parse().ok());
        let maybe_timestamp = headers
            .get(X_APTOS_LEDGER_TIMESTAMP)
            .and_then(|h| h.to_str().ok())
            .and_then(|s| s.parse().ok());
        let maybe_epoch = headers
            .get(X_APTOS_EPOCH)
            .and_then(|h| h.to_str().ok())
            .and_then(|s| s.parse().ok());
        // TODO: Why doesn't the constant work?
        let oldest_ledger_version = headers
            .get("X-Aptos-Ledger-Oldest-Version")
            .and_then(|h| h.to_str().ok())
            .and_then(|s| s.parse().ok());

        let state = if let (Some(chain_id), Some(version), Some(timestamp_usecs), Some(epoch)) =
            (maybe_chain_id, maybe_version, maybe_timestamp, maybe_epoch)
        {
            Self {
                chain_id,
                epoch,
                version,
                timestamp_usecs,
                oldest_ledger_version,
            }
        } else {
            anyhow::bail!(
                "Failed to build State from headers due to missing values in response. \
                Chain ID: {:?}, Version: {:?}, Timestamp: {:?}, Epoch: {:?}, Oldest Ledger Version: {:?}",
                maybe_chain_id,
                maybe_version,
                maybe_timestamp,
                maybe_epoch,
                oldest_ledger_version,
            )
        };

        Ok(state)
    }
}
<|endoftext|>