<commit_before>///! Basic commands tests.
use super::{assert_cursor, assert_line, assert_line_with_initial, init_editor};
use config::EditMode;
use consts::KeyPress;
use error::ReadlineError;

#[test]
fn home_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("", ""),
            &[KeyPress::Home, KeyPress::Enter],
            ("", ""),
        );
        assert_cursor(
            *mode,
            ("Hi", ""),
            &[KeyPress::Home, KeyPress::Enter],
            ("", "Hi"),
        );
    }
}

#[test]
fn end_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(*mode, ("", ""), &[KeyPress::End, KeyPress::Enter], ("", ""));
        assert_cursor(
            *mode,
            ("H", "i"),
            &[KeyPress::End, KeyPress::Enter],
            ("Hi", ""),
        );
        assert_cursor(
            *mode,
            ("", "Hi"),
            &[KeyPress::End, KeyPress::Enter],
            ("Hi", ""),
        );
    }
}

#[test]
fn left_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("Hi", ""),
            &[KeyPress::Left, KeyPress::Enter],
            ("H", "i"),
        );
        assert_cursor(
            *mode,
            ("H", "i"),
            &[KeyPress::Left, KeyPress::Enter],
            ("", "Hi"),
        );
        assert_cursor(
            *mode,
            ("", "Hi"),
            &[KeyPress::Left, KeyPress::Enter],
            ("", "Hi"),
        );
    }
}

#[test]
fn right_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("", ""),
            &[KeyPress::Right, KeyPress::Enter],
            ("", ""),
        );
        assert_cursor(
            *mode,
            ("", "Hi"),
            &[KeyPress::Right, KeyPress::Enter],
            ("H", "i"),
        );
        assert_cursor(
            *mode,
            ("B", "ye"),
            &[KeyPress::Right, KeyPress::Enter],
            ("By", "e"),
        );
        assert_cursor(
            *mode,
            ("H", "i"),
            &[KeyPress::Right, KeyPress::Enter],
            ("Hi", ""),
        );
    }
}

#[test]
fn enter_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_line(*mode, &[KeyPress::Enter], "");
        assert_line(*mode, &[KeyPress::Char('a'), KeyPress::Enter], "a");
        assert_line_with_initial(*mode, ("Hi", ""), &[KeyPress::Enter], "Hi");
        assert_line_with_initial(*mode, ("", "Hi"), &[KeyPress::Enter], "Hi");
        assert_line_with_initial(*mode, ("H", "i"), &[KeyPress::Enter], "Hi");
    }
}

#[test]
fn newline_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_line(*mode, &[KeyPress::Ctrl('J')], "");
        assert_line(*mode, &[KeyPress::Char('a'), KeyPress::Ctrl('J')], "a");
    }
}

#[test]
fn eof_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        let mut editor = init_editor(*mode, &[KeyPress::Ctrl('D')]);
        let err = editor.readline(">>");
        assert_matches!(err, Err(ReadlineError::Eof));
    }
    assert_line(
        EditMode::Emacs,
        &[KeyPress::Char('a'), KeyPress::Ctrl('D'), KeyPress::Enter],
        "a",
    );
    assert_line(
        EditMode::Vi,
        &[KeyPress::Char('a'), KeyPress::Ctrl('D')],
        "a",
    );
    assert_line_with_initial(
        EditMode::Emacs,
        ("", "Hi"),
        &[KeyPress::Ctrl('D'), KeyPress::Enter],
        "i",
    );
    assert_line_with_initial(EditMode::Vi, ("", "Hi"), &[KeyPress::Ctrl('D')], "Hi");
}

#[test]
fn interrupt_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        let mut editor = init_editor(*mode, &[KeyPress::Ctrl('C')]);
        let err = editor.readline(">>");
        assert_matches!(err, Err(ReadlineError::Interrupted));

        let mut editor = init_editor(*mode, &[KeyPress::Ctrl('C')]);
        let err = editor.readline_with_initial(">>", ("Hi", ""));
        assert_matches!(err, Err(ReadlineError::Interrupted));
    }
}

#[test]
fn delete_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("a", ""),
            &[KeyPress::Delete, KeyPress::Enter],
            ("a", ""),
        );
        assert_cursor(
            *mode,
            ("", "a"),
            &[KeyPress::Delete, KeyPress::Enter],
            ("", ""),
        );
    }
}

#[test]
fn ctrl_t() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("a", "b"),
            &[KeyPress::Ctrl('T'), KeyPress::Enter],
            ("ba", ""),
        );
        assert_cursor(
            *mode,
            ("ab", "cd"),
            &[KeyPress::Ctrl('T'), KeyPress::Enter],
            ("acb", "d"),
        );
    }
}

#[test]
fn ctrl_u() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("start of line ", "end"),
            &[KeyPress::Ctrl('U'), KeyPress::Enter],
            ("", "end"),
        );
        assert_cursor(
            *mode,
            ("", "end"),
            &[KeyPress::Ctrl('U'), KeyPress::Enter],
            ("", "end"),
        );
    }
}

#[test]
fn ctrl_v() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("", ""),
            &[KeyPress::Ctrl('V'), KeyPress::Char('\t'), KeyPress::Enter],
            ("\t", ""),
        );
    }
}

#[test]
fn ctrl_w() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("Hello, ", "world"),
            &[KeyPress::Ctrl('W'), KeyPress::Enter],
            ("", "world"),
        );
        assert_cursor(
            *mode,
            ("Hello, world.", ""),
            &[KeyPress::Ctrl('W'), KeyPress::Enter],
            ("Hello, ", ""),
        );
    }
}

#[test]
fn ctrl_y() {
    for mode in &[EditMode::Emacs /* FIXME, EditMode::Vi */] {
        assert_cursor(
            *mode,
            ("Hello, ", "world"),
            &[KeyPress::Ctrl('W'), KeyPress::Ctrl('Y'), KeyPress::Enter],
            ("Hello, ", "world"),
        );
    }
}

#[test]
fn ctrl__() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("Hello, ", "world"),
            &[KeyPress::Ctrl('W'), KeyPress::Ctrl('_'), KeyPress::Enter],
            ("Hello, ", "world"),
        );
    }
}
<commit_msg>Tests: vi command mode with common keys<commit_after>///! Basic commands tests.
use super::{assert_cursor, assert_line, assert_line_with_initial, init_editor};
use config::EditMode;
use consts::KeyPress;
use error::ReadlineError;

#[test]
fn home_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("", ""),
            &[KeyPress::Home, KeyPress::Enter],
            ("", ""),
        );
        assert_cursor(
            *mode,
            ("Hi", ""),
            &[KeyPress::Home, KeyPress::Enter],
            ("", "Hi"),
        );
        if *mode == EditMode::Vi {
            // vi command mode
            assert_cursor(
                *mode,
                ("Hi", ""),
                &[KeyPress::Esc, KeyPress::Home, KeyPress::Enter],
                ("", "Hi"),
            );
        }
    }
}

#[test]
fn end_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(*mode, ("", ""), &[KeyPress::End, KeyPress::Enter], ("", ""));
        assert_cursor(
            *mode,
            ("H", "i"),
            &[KeyPress::End, KeyPress::Enter],
            ("Hi", ""),
        );
        assert_cursor(
            *mode,
            ("", "Hi"),
            &[KeyPress::End, KeyPress::Enter],
            ("Hi", ""),
        );
        if *mode == EditMode::Vi {
            // vi command mode
            assert_cursor(
                *mode,
                ("", "Hi"),
                &[KeyPress::Esc, KeyPress::End, KeyPress::Enter],
                ("Hi", ""),
            );
        }
    }
}

#[test]
fn left_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("Hi", ""),
            &[KeyPress::Left, KeyPress::Enter],
            ("H", "i"),
        );
        assert_cursor(
            *mode,
            ("H", "i"),
            &[KeyPress::Left, KeyPress::Enter],
            ("", "Hi"),
        );
        assert_cursor(
            *mode,
            ("", "Hi"),
            &[KeyPress::Left, KeyPress::Enter],
            ("", "Hi"),
        );
        if *mode == EditMode::Vi {
            // vi command mode
            assert_cursor(
                *mode,
                ("Bye", ""),
                &[KeyPress::Esc, KeyPress::Left, KeyPress::Enter],
                ("B", "ye"),
            );
        }
    }
}

#[test]
fn right_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("", ""),
            &[KeyPress::Right, KeyPress::Enter],
            ("", ""),
        );
        assert_cursor(
            *mode,
            ("", "Hi"),
            &[KeyPress::Right, KeyPress::Enter],
            ("H", "i"),
        );
        assert_cursor(
            *mode,
            ("B", "ye"),
            &[KeyPress::Right, KeyPress::Enter],
            ("By", "e"),
        );
        assert_cursor(
            *mode,
            ("H", "i"),
            &[KeyPress::Right, KeyPress::Enter],
            ("Hi", ""),
        );
        if *mode == EditMode::Vi {
            // vi command mode
            assert_cursor(
                *mode,
                ("", "Hi"),
                &[KeyPress::Esc, KeyPress::Right, KeyPress::Enter],
                ("H", "i"),
            );
        }
    }
}

#[test]
fn enter_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_line(*mode, &[KeyPress::Enter], "");
        assert_line(*mode, &[KeyPress::Char('a'), KeyPress::Enter], "a");
        assert_line_with_initial(*mode, ("Hi", ""), &[KeyPress::Enter], "Hi");
        assert_line_with_initial(*mode, ("", "Hi"), &[KeyPress::Enter], "Hi");
        assert_line_with_initial(*mode, ("H", "i"), &[KeyPress::Enter], "Hi");
        if *mode == EditMode::Vi {
            // vi command mode
            assert_line(*mode, &[KeyPress::Esc, KeyPress::Enter], "");
            assert_line(
                *mode,
                &[KeyPress::Char('a'), KeyPress::Esc, KeyPress::Enter],
                "a",
            );
            assert_line_with_initial(*mode, ("Hi", ""), &[KeyPress::Esc, KeyPress::Enter], "Hi");
            assert_line_with_initial(*mode, ("", "Hi"), &[KeyPress::Esc, KeyPress::Enter], "Hi");
            assert_line_with_initial(*mode, ("H", "i"), &[KeyPress::Esc, KeyPress::Enter], "Hi");
        }
    }
}

#[test]
fn newline_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_line(*mode, &[KeyPress::Ctrl('J')], "");
        assert_line(*mode, &[KeyPress::Char('a'), KeyPress::Ctrl('J')], "a");
        if *mode == EditMode::Vi {
            // vi command mode
            assert_line(*mode, &[KeyPress::Esc, KeyPress::Ctrl('J')], "");
            assert_line(
                *mode,
                &[KeyPress::Char('a'), KeyPress::Esc, KeyPress::Ctrl('J')],
                "a",
            );
        }
    }
}

#[test]
fn eof_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        let mut editor = init_editor(*mode, &[KeyPress::Ctrl('D')]);
        let err = editor.readline(">>");
        assert_matches!(err, Err(ReadlineError::Eof));
    }
    assert_line(
        EditMode::Emacs,
        &[KeyPress::Char('a'), KeyPress::Ctrl('D'), KeyPress::Enter],
        "a",
    );
    assert_line(
        EditMode::Vi,
        &[KeyPress::Char('a'), KeyPress::Ctrl('D')],
        "a",
    );
    assert_line(
        EditMode::Vi,
        &[KeyPress::Char('a'), KeyPress::Esc, KeyPress::Ctrl('D')],
        "a",
    );
    assert_line_with_initial(
        EditMode::Emacs,
        ("", "Hi"),
        &[KeyPress::Ctrl('D'), KeyPress::Enter],
        "i",
    );
    assert_line_with_initial(EditMode::Vi, ("", "Hi"), &[KeyPress::Ctrl('D')], "Hi");
    assert_line_with_initial(
        EditMode::Vi,
        ("", "Hi"),
        &[KeyPress::Esc, KeyPress::Ctrl('D')],
        "Hi",
    );
}

#[test]
fn interrupt_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        let mut editor = init_editor(*mode, &[KeyPress::Ctrl('C')]);
        let err = editor.readline(">>");
        assert_matches!(err, Err(ReadlineError::Interrupted));

        let mut editor = init_editor(*mode, &[KeyPress::Ctrl('C')]);
        let err = editor.readline_with_initial(">>", ("Hi", ""));
        assert_matches!(err, Err(ReadlineError::Interrupted));
        if *mode == EditMode::Vi {
            // vi command mode
            let mut editor = init_editor(*mode, &[KeyPress::Esc, KeyPress::Ctrl('C')]);
            let err = editor.readline_with_initial(">>", ("Hi", ""));
            assert_matches!(err, Err(ReadlineError::Interrupted));
        }
    }
}

#[test]
fn delete_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("a", ""),
            &[KeyPress::Delete, KeyPress::Enter],
            ("a", ""),
        );
        assert_cursor(
            *mode,
            ("", "a"),
            &[KeyPress::Delete, KeyPress::Enter],
            ("", ""),
        );
        if *mode == EditMode::Vi {
            // vi command mode
            assert_cursor(
                *mode,
                ("", "a"),
                &[KeyPress::Esc, KeyPress::Delete, KeyPress::Enter],
                ("", ""),
            );
        }
    }
}

#[test]
fn ctrl_t() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("a", "b"),
            &[KeyPress::Ctrl('T'), KeyPress::Enter],
            ("ba", ""),
        );
        assert_cursor(
            *mode,
            ("ab", "cd"),
            &[KeyPress::Ctrl('T'), KeyPress::Enter],
            ("acb", "d"),
        );
        if *mode == EditMode::Vi {
            // vi command mode
            assert_cursor(
                *mode,
                ("ab", ""),
                &[KeyPress::Esc, KeyPress::Ctrl('T'), KeyPress::Enter],
                ("ba", ""),
            );
        }
    }
}

#[test]
fn ctrl_u() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("start of line ", "end"),
            &[KeyPress::Ctrl('U'), KeyPress::Enter],
            ("", "end"),
        );
        assert_cursor(
            *mode,
            ("", "end"),
            &[KeyPress::Ctrl('U'), KeyPress::Enter],
            ("", "end"),
        );
        if *mode == EditMode::Vi {
            // vi command mode
            assert_cursor(
                *mode,
                ("start of line ", "end"),
                &[KeyPress::Esc, KeyPress::Ctrl('U'), KeyPress::Enter],
                ("", " end"),
            );
        }
    }
}

#[test]
fn ctrl_v() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("", ""),
            &[KeyPress::Ctrl('V'), KeyPress::Char('\t'), KeyPress::Enter],
            ("\t", ""),
        );
        if *mode == EditMode::Vi {
            // vi command mode
            assert_cursor(
                *mode,
                ("", ""),
                &[
                    KeyPress::Esc,
                    KeyPress::Ctrl('V'),
                    KeyPress::Char('\t'),
                    KeyPress::Enter,
                ],
                ("\t", ""),
            );
        }
    }
}

#[test]
fn ctrl_w() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("Hello, ", "world"),
            &[KeyPress::Ctrl('W'), KeyPress::Enter],
            ("", "world"),
        );
        assert_cursor(
            *mode,
            ("Hello, world.", ""),
            &[KeyPress::Ctrl('W'), KeyPress::Enter],
            ("Hello, ", ""),
        );
        if *mode == EditMode::Vi {
            // vi command mode
            assert_cursor(
                *mode,
                ("Hello, world.", ""),
                &[KeyPress::Esc, KeyPress::Ctrl('W'), KeyPress::Enter],
                ("Hello, ", "."),
            );
        }
    }
}

#[test]
fn ctrl_y() {
    for mode in &[EditMode::Emacs /* FIXME, EditMode::Vi */] {
        assert_cursor(
            *mode,
            ("Hello, ", "world"),
            &[KeyPress::Ctrl('W'), KeyPress::Ctrl('Y'), KeyPress::Enter],
            ("Hello, ", "world"),
        );
    }
}

#[test]
fn ctrl__() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_cursor(
            *mode,
            ("Hello, ", "world"),
            &[KeyPress::Ctrl('W'), KeyPress::Ctrl('_'), KeyPress::Enter],
            ("Hello, ", "world"),
        );
        if *mode == EditMode::Vi {
            // vi command mode
            assert_cursor(
                *mode,
                ("Hello, ", "world"),
                &[
                    KeyPress::Esc,
                    KeyPress::Ctrl('W'),
                    KeyPress::Ctrl('_'),
                    KeyPress::Enter,
                ],
                ("Hello,", " world"),
            );
        }
    }
}
<|endoftext|>


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

use super::address::*;
use super::treenode::*;
use super::basictree::*;

///
/// Represents which of the root's references have changed
///
pub enum TreeChangeType {
    /// The node's child reference has been replaced
    Child,

    /// The node's sibling reference has been replaced
    Sibling
}

///
/// A change represents an alteration to the tree
///
pub struct TreeChange {
    /// The address of the node matching the root of the change
    ///
    /// The address is relative to an imaginary node that is the parent of the real root node. This makes it possible to
    /// replace the entire tree by setting this to `TreeAddress::Here` and the change_type to `TreeChangeType::Child`.
    /// The real root node can be addressed at `TreeAddress::ChildAtIndex(0)`
    root: TreeAddress,

    /// Which of the root's references have changed
    change_type: TreeChangeType,

    /// The tree that should replace the changed reference. The last node in this tree (depth-first) will be given the same sibling as the last node in the replacement range
    replacement_tree: Option<TreeRef>
}

impl TreeChange {
    ///
    /// Creates a new tree change
    ///
    pub fn new<TAddress: ToTreeAddress, TNode: ToTreeNode>(root: &TAddress, change_type: TreeChangeType, replacement_tree: Option<&TNode>) -> TreeChange {
        TreeChange { root: root.to_tree_address(), change_type: change_type, replacement_tree: replacement_tree.map(|x| x.to_tree_node()) }
    }

    ///
    /// Performs a replacement on a basic tree node
    ///
    #[inline]
    fn perform_replacement(node: &BasicTree, change_type: &TreeChangeType, replacement_tree: &Option<TreeRef>) {
        match *change_type {
            TreeChangeType::Child => {
                match *replacement_tree {
                    Some(ref new_child)     => node.set_child_ref(new_child.clone()),
                    None                    => node.clear_child()
                }
            },

            TreeChangeType::Sibling => {
                match *replacement_tree {
                    Some(ref new_sibling)   => node.set_sibling_ref(new_sibling.clone()),
                    None                    => node.clear_child()
                }
            }
        }
    }

    ///
    /// Applies a change to a tree, generating a new tree
    ///
    fn perform_apply(original_tree: &TreeRef, address: &TreeAddress, change_type: &TreeChangeType, replacement_tree: &Option<TreeRef>) -> TreeRef {
        match *address {
            TreeAddress::Here => {
                let new_node = BasicTree::from(original_tree);
                TreeChange::perform_replacement(&new_node, change_type, replacement_tree);

                Rc::new(new_node)
            },

            TreeAddress::ChildAtIndex(child_index, ref child_address) => {
                // Copy the siblings into a stack
                let mut siblings    = vec![];
                let mut current     = original_tree.get_child_ref();

                for _ in 0..child_index {
                    siblings.push(current.clone().unwrap_or_else(|| Rc::new(BasicTree::new("", ()))));

                    current = current.and_then(|x| x.get_sibling_ref());
                }

                // Replace the child matching this item
                let child_tree  = current.clone().unwrap_or_else(|| Rc::new(BasicTree::new("", ())));
                let new_child   = TreeChange::perform_apply(&child_tree, &*child_address, change_type, replacement_tree);

                current = Some(new_child);

                // Pop siblings to generate the new child item
                while let Some(sibling) = siblings.pop() {
                    match current {
                        Some(next_sibling)  => current = Some(Rc::new(BasicTree::from_with_sibling(sibling, next_sibling))),
                        None                => current = Some(sibling),
                    }
                }

                Rc::new(BasicTree::from_with_child(original_tree, current.unwrap()))
            },

            TreeAddress::ChildWithTag(ref child_tag, ref child_address) => {
                // Copy the siblings into a stack
                let mut siblings    = vec![];
                let mut current     = original_tree.get_child_ref();

                while current.is_some() {
                    if let Some(ref child_ref) = current {
                        // Always true, but it isn't clear how to make while let work here when we need to update the pointer (because it's always borrowed in the loop block)
                        if child_ref.get_tag() == child_tag {
                            break;
                        }

                        siblings.push(child_ref.clone());
                    }

                    current = current.and_then(|x| x.get_sibling_ref());
                }

                // Replace the child matching this item
                let child_tree  = current.clone().unwrap_or_else(|| Rc::new(BasicTree::new("", ())));
                let new_child   = TreeChange::perform_apply(&child_tree, &*child_address, change_type, replacement_tree);

                current = Some(new_child);

                // Pop siblings to generate the new child item
                while let Some(sibling) = siblings.pop() {
                    match current {
                        Some(next_sibling)  => current = Some(Rc::new(BasicTree::from_with_sibling(sibling, next_sibling))),
                        None                => current = Some(sibling),
                    }
                }

                Rc::new(BasicTree::from_with_child(original_tree, current.unwrap()))
            }
        }
    }

    ///
    /// Creates a new tree from an old tree with this change added to it
    ///
    #[inline]
    pub fn apply(&self, original_tree: &TreeRef) -> TreeRef {
        // For simplicity, we actualise the 'imaginary' root
        let imaginary_root      = tree!("", original_tree).to_tree_node();
        let new_imaginary_root  = TreeChange::perform_apply(&imaginary_root, &self.root, &self.change_type, &self.replacement_tree);

        // Result is the child of the imaginary node (or an empty node if the entire tree is deleted)
        new_imaginary_root.get_child_ref().unwrap_or_else(|| "".to_tree_node())
    }

    ///
    /// Converts the root address to one that's relative to the tree being changed
    ///
    /// The root address starts at an imaginary 'true' root (this makes it possible to specify a change that replaces the entire tree)
    ///
    #[inline]
    fn address_relative_to_tree_root(&self) -> TreeAddress {
        match self.root {
            TreeAddress::Here                           => TreeAddress::Here,
            TreeAddress::ChildAtIndex(0, ref address)   => (**address).clone(),
            _                                           => TreeAddress::Here
        }
    }

    ///
    /// Returns whether or not this change covers the specified address (or false if this cannot be determined)
    ///
    pub fn applies_to(&self, address: &TreeAddress) -> Option<bool> {
        let relative_root = self.address_relative_to_tree_root();

        match self.change_type {
            // If the child has changed, then anything that's a child of the root address is changed
            TreeChangeType::Child => relative_root.is_parent_of(address).map(|is_parent| { is_parent && relative_root != *address }),

            // If the sibling has changed, then it's the parent address that's changed
            TreeChangeType::Sibling => relative_root.parent().is_parent_of(address)
        }
    }
}

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

    #[test]
    fn can_apply_simple_change_tagged() {
        let initial_tree    = tree!("test", ("one", 1), ("two", 2), ("three", 3));
        let change_two      = TreeChange::new(&("test", "one"), TreeChangeType::Sibling, Some(&("replaced", 4)));
        let changed_tree    = change_two.apply(&initial_tree);

        assert!(changed_tree.get_child_ref_at("one").unwrap().get_value().to_int(0) == 1);
        assert!(changed_tree.get_child_ref_at("replaced").unwrap().get_value().to_int(0) == 4);
        assert!(changed_tree.get_child_ref_at("replaced").unwrap().get_sibling_ref().is_none());
        assert!(changed_tree.get_child_ref_at("two").is_none());
        assert!(changed_tree.get_child_ref_at("three").is_none());
    }

    #[test]
    fn can_apply_simple_change_indexed() {
        let initial_tree    = tree!("test", ("one", 1), ("two", 2), ("three", 3));
        let change_two      = TreeChange::new(&(0, 1), TreeChangeType::Sibling, Some(&("replaced", 4)));
        let changed_tree    = change_two.apply(&initial_tree);

        assert!(changed_tree.get_child_ref_at(0).unwrap().get_value().to_int(0) == 1);
        assert!(changed_tree.get_child_ref_at(1).unwrap().get_value().to_int(0) == 2);
        assert!(changed_tree.get_child_ref_at(2).unwrap().get_value().to_int(0) == 4);
        assert!(changed_tree.get_child_ref_at(2).unwrap().get_sibling_ref().is_none());
        assert!(changed_tree.get_child_ref_at(3).is_none());
    }

    #[test]
    fn can_apply_child_change_tagged() {
        let initial_tree    = tree!("test", ("one", 1), ("two", 2), ("three", 3));
        let change_two      = TreeChange::new(&("test", "two").to_tree_address(), TreeChangeType::Child, Some(&("new_child", 4)));
        let changed_tree    = change_two.apply(&initial_tree);

        assert!(!changed_tree.get_child_ref_at(("two", "new_child").to_tree_address()).is_none());

        assert!(changed_tree.get_child_ref_at(("two", "new_child").to_tree_address()).unwrap().get_value().to_int(0) == 4);
        assert!(changed_tree.get_child_ref_at(("two", "new_child").to_tree_address()).unwrap().get_sibling_ref().is_none());

        assert!(!changed_tree.get_child_ref_at("one").is_none());
        assert!(!changed_tree.get_child_ref_at("two").is_none());
        assert!(!changed_tree.get_child_ref_at("three").is_none());
        assert!(changed_tree.get_child_ref_at("two").unwrap().get_value().to_int(0) == 2);
    }

    #[test]
    fn can_apply_child_change_indexed() {
        let initial_tree    = tree!("test", ("one", 1), ("two", 2), ("three", 3));
        let change_two      = TreeChange::new(&(0, 1).to_tree_address(), TreeChangeType::Child, Some(&("new_child", 4)));
        let changed_tree    = change_two.apply(&initial_tree);

        assert!(!changed_tree.get_child_ref_at((1, 0).to_tree_address()).is_none());

        assert!(changed_tree.get_child_ref_at((1, 0).to_tree_address()).unwrap().get_value().to_int(0) == 4);
        assert!(changed_tree.get_child_ref_at((1, 0).to_tree_address()).unwrap().get_sibling_ref().is_none());

        assert!(!changed_tree.get_child_ref_at(0).is_none());
        assert!(!changed_tree.get_child_ref_at(1).is_none());
        assert!(!changed_tree.get_child_ref_at(2).is_none());
        assert!(changed_tree.get_child_ref_at(1).unwrap().get_value().to_int(0) == 2);
    }

    #[test]
    fn true_root_applies_to_everything() {
        // The child of address 0 represents the entire tree
        let change = TreeChange::new(&0.to_tree_address(), TreeChangeType::Child, Some(&("new_child", 4)));

        // Note that the tree change applies to (0, 1) but it's relative to an imaginary root
        assert!(change.applies_to(&().to_tree_address()).unwrap());
        assert!(change.applies_to(&(1).to_tree_address()).unwrap());
        assert!(change.applies_to(&(1, 2).to_tree_address()).unwrap());
    }

    #[test]
    fn child_change_applies_to_child_tree() {
        let change = TreeChange::new(&(0, 1).to_tree_address(), TreeChangeType::Child, Some(&("new_child", 4)));

        // Note that the tree change applies to (0, 1) but it's relative to an imaginary root
        assert!(change.applies_to(&(1, 2).to_tree_address()).unwrap());
    }

    #[test]
    fn child_change_does_not_apply_to_parent() {
        let change = TreeChange::new(&(0, 1).to_tree_address(), TreeChangeType::Child, Some(&("new_child", 4)));

        assert!(!change.applies_to(&1.to_tree_address()).unwrap());
    }

    #[test]
    fn child_change_does_not_apply_to_other_tree() {
        let change = TreeChange::new(&(0, 1).to_tree_address(), TreeChangeType::Child, Some(&("new_child", 4)));

        assert!(!change.applies_to(&(2, 2).to_tree_address()).unwrap());
    }

    #[test]
    fn sibling_change_applies_to_parent() {
        let change = TreeChange::new(&(0, (1, 2)).to_tree_address(), TreeChangeType::Sibling, Some(&("new_child", 4)));

        assert!(change.applies_to(&1.to_tree_address()).unwrap());
    }

    #[test]
    fn sibling_change_does_not_apply_to_different_parent() {
        let change = TreeChange::new(&(0, (1, 2)).to_tree_address(), TreeChangeType::Sibling, Some(&("new_child", 4)));

        assert!(!change.applies_to(&2.to_tree_address()).unwrap());
    }

    #[test]
    fn sibling_change_does_not_apply_to_grandparent() {
        let change = TreeChange::new(&(0, (1, (2, 3))).to_tree_address(), TreeChangeType::Sibling, Some(&("new_child", 4)));

        assert!(!change.applies_to(&1.to_tree_address()).unwrap());
    }
}
<commit_msg>Thought of a bunch of extra cases that need to be tested to ensure that the applies_to function works correctly.<commit_after>use std::rc::*;

use super::address::*;
use super::treenode::*;
use super::basictree::*;

///
/// Represents which of the root's references have changed
///
pub enum TreeChangeType {
    /// The node's child reference has been replaced
    Child,

    /// The node's sibling reference has been replaced
    Sibling
}

///
/// A change represents an alteration to the tree
///
pub struct TreeChange {
    /// The address of the node matching the root of the change
    ///
    /// The address is relative to an imaginary node that is the parent of the real root node. This makes it possible to
    /// replace the entire tree by setting this to `TreeAddress::Here` and the change_type to `TreeChangeType::Child`.
    /// The real root node can be addressed at `TreeAddress::ChildAtIndex(0)`
    root: TreeAddress,

    /// Which of the root's references have changed
    change_type: TreeChangeType,

    /// The tree that should replace the changed reference. The last node in this tree (depth-first) will be given the same sibling as the last node in the replacement range
    replacement_tree: Option<TreeRef>
}

impl TreeChange {
    ///
    /// Creates a new tree change
    ///
    pub fn new<TAddress: ToTreeAddress, TNode: ToTreeNode>(root: &TAddress, change_type: TreeChangeType, replacement_tree: Option<&TNode>) -> TreeChange {
        TreeChange { root: root.to_tree_address(), change_type: change_type, replacement_tree: replacement_tree.map(|x| x.to_tree_node()) }
    }

    ///
    /// Performs a replacement on a basic tree node
    ///
    #[inline]
    fn perform_replacement(node: &BasicTree, change_type: &TreeChangeType, replacement_tree: &Option<TreeRef>) {
        match *change_type {
            TreeChangeType::Child => {
                match *replacement_tree {
                    Some(ref new_child)     => node.set_child_ref(new_child.clone()),
                    None                    => node.clear_child()
                }
            },

            TreeChangeType::Sibling => {
                match *replacement_tree {
                    Some(ref new_sibling)   => node.set_sibling_ref(new_sibling.clone()),
                    None                    => node.clear_child()
                }
            }
        }
    }

    ///
    /// Applies a change to a tree, generating a new tree
    ///
    fn perform_apply(original_tree: &TreeRef, address: &TreeAddress, change_type: &TreeChangeType, replacement_tree: &Option<TreeRef>) -> TreeRef {
        match *address {
            TreeAddress::Here => {
                let new_node = BasicTree::from(original_tree);
                TreeChange::perform_replacement(&new_node, change_type, replacement_tree);

                Rc::new(new_node)
            },

            TreeAddress::ChildAtIndex(child_index, ref child_address) => {
                // Copy the siblings into a stack
                let mut siblings    = vec![];
                let mut current     = original_tree.get_child_ref();

                for _ in 0..child_index {
                    siblings.push(current.clone().unwrap_or_else(|| Rc::new(BasicTree::new("", ()))));

                    current = current.and_then(|x| x.get_sibling_ref());
                }

                // Replace the child matching this item
                let child_tree  = current.clone().unwrap_or_else(|| Rc::new(BasicTree::new("", ())));
                let new_child   = TreeChange::perform_apply(&child_tree, &*child_address, change_type, replacement_tree);

                current = Some(new_child);

                // Pop siblings to generate the new child item
                while let Some(sibling) = siblings.pop() {
                    match current {
                        Some(next_sibling)  => current = Some(Rc::new(BasicTree::from_with_sibling(sibling, next_sibling))),
                        None                => current = Some(sibling),
                    }
                }

                Rc::new(BasicTree::from_with_child(original_tree, current.unwrap()))
            },

            TreeAddress::ChildWithTag(ref child_tag, ref child_address) => {
                // Copy the siblings into a stack
                let mut siblings    = vec![];
                let mut current     = original_tree.get_child_ref();

                while current.is_some() {
                    if let Some(ref child_ref) = current {
                        // Always true, but it isn't clear how to make while let work here when we need to update the pointer (because it's always borrowed in the loop block)
                        if child_ref.get_tag() == child_tag {
                            break;
                        }

                        siblings.push(child_ref.clone());
                    }

                    current = current.and_then(|x| x.get_sibling_ref());
                }

                // Replace the child matching this item
                let child_tree  = current.clone().unwrap_or_else(|| Rc::new(BasicTree::new("", ())));
                let new_child   = TreeChange::perform_apply(&child_tree, &*child_address, change_type, replacement_tree);

                current = Some(new_child);

                // Pop siblings to generate the new child item
                while let Some(sibling) = siblings.pop() {
                    match current {
                        Some(next_sibling)  => current = Some(Rc::new(BasicTree::from_with_sibling(sibling, next_sibling))),
                        None                => current = Some(sibling),
                    }
                }

                Rc::new(BasicTree::from_with_child(original_tree, current.unwrap()))
            }
        }
    }

    ///
    /// Creates a new tree from an old tree with this change added to it
    ///
    #[inline]
    pub fn apply(&self, original_tree: &TreeRef) -> TreeRef {
        // For simplicity, we actualise the 'imaginary' root
        let imaginary_root      = tree!("", original_tree).to_tree_node();
        let new_imaginary_root  = TreeChange::perform_apply(&imaginary_root, &self.root, &self.change_type, &self.replacement_tree);

        // Result is the child of the imaginary node (or an empty node if the entire tree is deleted)
        new_imaginary_root.get_child_ref().unwrap_or_else(|| "".to_tree_node())
    }

    ///
    /// Converts the root address to one that's relative to the tree being changed
    ///
    /// The root address starts at an imaginary 'true' root (this makes it possible to specify a change that replaces the entire tree)
    ///
    #[inline]
    fn address_relative_to_tree_root(&self) -> TreeAddress {
        match self.root {
            TreeAddress::Here                           => TreeAddress::Here,
            TreeAddress::ChildAtIndex(0, ref address)   => (**address).clone(),
            _                                           => TreeAddress::Here
        }
    }

    ///
    /// Returns whether or not this change covers the specified address (or false if this cannot be determined)
    ///
    pub fn applies_to(&self, address: &TreeAddress) -> Option<bool> {
        let relative_root = self.address_relative_to_tree_root();

        match self.change_type {
            // If the child has changed, then anything that's a child of the root address is changed
            TreeChangeType::Child => relative_root.is_parent_of(address).map(|is_parent| { is_parent && relative_root != *address }),

            // If the sibling has changed, then it's the parent address that's changed
            TreeChangeType::Sibling => relative_root.parent().is_parent_of(address)
        }
    }
}

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

    #[test]
    fn can_apply_simple_change_tagged() {
        let initial_tree    = tree!("test", ("one", 1), ("two", 2), ("three", 3));
        let change_two      = TreeChange::new(&("test", "one"), TreeChangeType::Sibling, Some(&("replaced", 4)));
        let changed_tree    = change_two.apply(&initial_tree);

        assert!(changed_tree.get_child_ref_at("one").unwrap().get_value().to_int(0) == 1);
        assert!(changed_tree.get_child_ref_at("replaced").unwrap().get_value().to_int(0) == 4);
        assert!(changed_tree.get_child_ref_at("replaced").unwrap().get_sibling_ref().is_none());
        assert!(changed_tree.get_child_ref_at("two").is_none());
        assert!(changed_tree.get_child_ref_at("three").is_none());
    }

    #[test]
    fn can_apply_simple_change_indexed() {
        let initial_tree    = tree!("test", ("one", 1), ("two", 2), ("three", 3));
        let change_two      = TreeChange::new(&(0, 1), TreeChangeType::Sibling, Some(&("replaced", 4)));
        let changed_tree    = change_two.apply(&initial_tree);

        assert!(changed_tree.get_child_ref_at(0).unwrap().get_value().to_int(0) == 1);
        assert!(changed_tree.get_child_ref_at(1).unwrap().get_value().to_int(0) == 2);
        assert!(changed_tree.get_child_ref_at(2).unwrap().get_value().to_int(0) == 4);
        assert!(changed_tree.get_child_ref_at(2).unwrap().get_sibling_ref().is_none());
        assert!(changed_tree.get_child_ref_at(3).is_none());
    }

    #[test]
    fn can_apply_child_change_tagged() {
        let initial_tree    = tree!("test", ("one", 1), ("two", 2), ("three", 3));
        let change_two      = TreeChange::new(&("test", "two").to_tree_address(), TreeChangeType::Child, Some(&("new_child", 4)));
        let changed_tree    = change_two.apply(&initial_tree);

        assert!(!changed_tree.get_child_ref_at(("two", "new_child").to_tree_address()).is_none());

        assert!(changed_tree.get_child_ref_at(("two", "new_child").to_tree_address()).unwrap().get_value().to_int(0) == 4);
        assert!(changed_tree.get_child_ref_at(("two", "new_child").to_tree_address()).unwrap().get_sibling_ref().is_none());

        assert!(!changed_tree.get_child_ref_at("one").is_none());
        assert!(!changed_tree.get_child_ref_at("two").is_none());
        assert!(!changed_tree.get_child_ref_at("three").is_none());
        assert!(changed_tree.get_child_ref_at("two").unwrap().get_value().to_int(0) == 2);
    }

    #[test]
    fn can_apply_child_change_indexed() {
        let initial_tree    = tree!("test", ("one", 1), ("two", 2), ("three", 3));
        let change_two      = TreeChange::new(&(0, 1).to_tree_address(), TreeChangeType::Child, Some(&("new_child", 4)));
        let changed_tree    = change_two.apply(&initial_tree);

        assert!(!changed_tree.get_child_ref_at((1, 0).to_tree_address()).is_none());

        assert!(changed_tree.get_child_ref_at((1, 0).to_tree_address()).unwrap().get_value().to_int(0) == 4);
        assert!(changed_tree.get_child_ref_at((1, 0).to_tree_address()).unwrap().get_sibling_ref().is_none());

        assert!(!changed_tree.get_child_ref_at(0).is_none());
        assert!(!changed_tree.get_child_ref_at(1).is_none());
        assert!(!changed_tree.get_child_ref_at(2).is_none());
        assert!(changed_tree.get_child_ref_at(1).unwrap().get_value().to_int(0) == 2);
    }

    #[test]
    fn true_root_applies_to_everything() {
        // The child of address 0 represents the entire tree
        let change = TreeChange::new(&0.to_tree_address(), TreeChangeType::Child, Some(&("new_child", 4)));

        // Note that the tree change applies to (0, 1) but it's relative to an imaginary root
        assert!(change.applies_to(&().to_tree_address()).unwrap());
        assert!(change.applies_to(&(1).to_tree_address()).unwrap());
        assert!(change.applies_to(&(1, 2).to_tree_address()).unwrap());
    }

    #[test]
    fn child_change_applies_to_child_tree() {
        let change = TreeChange::new(&(0, 1).to_tree_address(), TreeChangeType::Child, Some(&("new_child", 4)));

        // Note that the tree change applies to (0, 1) but it's relative to an imaginary root
        assert!(change.applies_to(&(1, 2).to_tree_address()).unwrap());
        assert!(change.applies_to(&(1, (2, 3)).to_tree_address()).unwrap());
    }

    #[test]
    fn child_change_applies_to_everything_up_to_root() {
        let change = TreeChange::new(&(0, (1, 2)).to_tree_address(), TreeChangeType::Child, Some(&("new_child", 4)));

        assert!(change.applies_to(&(1, 2).to_tree_address()).unwrap());
        assert!(change.applies_to(&1.to_tree_address()).unwrap());
        assert!(change.applies_to(&().to_tree_address()).unwrap());
    }

    #[test]
    fn child_change_does_not_apply_to_sibling() {
        let change = TreeChange::new(&(0, (1, 2)).to_tree_address(), TreeChangeType::Child, Some(&("new_child", 4)));

        assert!(!change.applies_to(&(1, 1).to_tree_address()).unwrap());
        assert!(!change.applies_to(&2.to_tree_address()).unwrap());
    }

    #[test]
    fn child_change_does_not_apply_to_other_tree() {
        let change = TreeChange::new(&(0, 1).to_tree_address(), TreeChangeType::Child, Some(&("new_child", 4)));

        assert!(!change.applies_to(&(2, 2).to_tree_address()).unwrap());
    }

    #[test]
    fn sibling_change_applies_to_parent() {
        let change = TreeChange::new(&(0, (1, 2)).to_tree_address(), TreeChangeType::Sibling, Some(&("new_child", 4)));

        assert!(change.applies_to(&1.to_tree_address()).unwrap());
    }

    #[test]
    fn sibling_change_applies_to_sibling() {
        let change = TreeChange::new(&(0, (1, 2)).to_tree_address(), TreeChangeType::Sibling, Some(&("new_child", 4)));

        assert!(change.applies_to(&(1, 3).to_tree_address()).unwrap());
    }

    #[test]
    fn sibling_change_applies_to_child() {
        let change = TreeChange::new(&(0, (1, 2)).to_tree_address(), TreeChangeType::Sibling, Some(&("new_child", 4)));

        assert!(change.applies_to(&(1, (2, 3)).to_tree_address()).unwrap());
    }

    #[test]
    fn sibling_change_does_not_apply_to_parent_sibling() {
        let change = TreeChange::new(&(0, (1, 2)).to_tree_address(), TreeChangeType::Sibling, Some(&("new_child", 4)));

        assert!(!change.applies_to(&2.to_tree_address()).unwrap());
    }

    #[test]
    fn sibling_change_applies_to_everything_up_to_root() {
        let change = TreeChange::new(&(0, (1, (2, 3))).to_tree_address(), TreeChangeType::Sibling, Some(&("new_child", 4)));

        assert!(!change.applies_to(&(0, (1, 2)).to_tree_address()).unwrap());
        assert!(!change.applies_to(&(0, 1).to_tree_address()).unwrap());
        assert!(!change.applies_to(&1.to_tree_address()).unwrap());
        assert!(!change.applies_to(&().to_tree_address()).unwrap());
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::Read;
use std::marker::PhantomData;
use std::mem;
use std::sync::atomic;

use kernel32;
use winapi;

use consts::{self, KeyPress};
use ::error;
use ::Result;
use SIGWINCH;

pub type Handle = winapi::HANDLE;
pub type Mode = winapi::DWORD;
pub const STDIN_FILENO: winapi::DWORD = winapi::STD_INPUT_HANDLE;
pub const STDOUT_FILENO: winapi::DWORD = winapi::STD_OUTPUT_HANDLE;

fn get_std_handle(fd: winapi::DWORD) -> Result<winapi::HANDLE> {
    let handle = unsafe { kernel32::GetStdHandle(fd) };
    if handle == winapi::INVALID_HANDLE_VALUE {
        try!(Err(io::Error::last_os_error()));
    } else if handle.is_null() {
        try!(Err(io::Error::new(io::ErrorKind::Other,
                                "no stdio handle available for this process")));
    }
    Ok(handle)
}

#[macro_export]
macro_rules! check {
    ($funcall:expr) => {
        {
        let rc = unsafe { $funcall };
        if rc == 0 {
            try!(Err(io::Error::last_os_error()));
        }
        rc
        }
    };
}

/// Try to get the number of columns in the current terminal, or assume 80 if it fails.
pub fn get_columns(handle: Handle) -> usize {
    let mut info = unsafe { mem::zeroed() };
    match unsafe { kernel32::GetConsoleScreenBufferInfo(handle, &mut info) } {
        0 => 80,
        _ => info.dwSize.X as usize,
    }
}

/// Checking for an unsupported TERM in windows is a no-op
pub fn is_unsupported_term() -> bool {
    false
}

pub fn get_console_mode(handle: winapi::HANDLE) -> Result<Mode> {
    let mut original_mode = 0;
    check!(kernel32::GetConsoleMode(handle, &mut original_mode));
    Ok(original_mode)
}

/// Return whether or not STDIN, STDOUT or STDERR is a TTY
pub fn is_a_tty(fd: winapi::DWORD) -> bool {
    let handle = get_std_handle(fd);
    match handle {
        Ok(handle) => {
            // If this function doesn't fail then fd is a TTY
            get_console_mode(handle).is_ok()
        }
        Err(_) => false,
    }
}

/// Enable raw mode for the TERM
pub fn enable_raw_mode() -> Result<Mode> {
    let handle = try!(get_std_handle(STDIN_FILENO));
    let original_mode = try!(get_console_mode(handle));
    let raw = original_mode &
              !(winapi::wincon::ENABLE_LINE_INPUT | winapi::wincon::ENABLE_ECHO_INPUT |
                winapi::wincon::ENABLE_PROCESSED_INPUT);
    check!(kernel32::SetConsoleMode(handle, raw));
    Ok(original_mode)
}

/// Disable Raw mode for the term
pub fn disable_raw_mode(original_mode: Mode) -> Result<()> {
    let handle = try!(get_std_handle(STDIN_FILENO));
    check!(kernel32::SetConsoleMode(handle, original_mode));
    Ok(())
}

pub fn stdout_handle() -> Result<Handle> {
    let handle = try!(get_std_handle(STDOUT_FILENO));
    Ok(handle)
}

/// Console input reader
pub struct RawReader<R> {
    handle: winapi::HANDLE,
    buf: Option<u16>,
    phantom: PhantomData<R>,
}

impl<R: Read> RawReader<R> {
    pub fn new(_: R) -> Result<RawReader<R>> {
        let handle = try!(get_std_handle(STDIN_FILENO));
        Ok(RawReader {
            handle: handle,
            buf: None,
            phantom: PhantomData,
        })
    }

    pub fn next_key(&mut self, _: bool) -> Result<KeyPress> {
        use std::char::decode_utf16;

        let mut rec: winapi::INPUT_RECORD = unsafe { mem::zeroed() };
        let mut count = 0;
        let mut esc_seen = false;
        loop {
            // TODO GetNumberOfConsoleInputEvents
            check!(kernel32::ReadConsoleInputW(self.handle,
                                               &mut rec,
                                               1 as winapi::DWORD,
                                               &mut count));

            // TODO ENABLE_WINDOW_INPUT ???
            if rec.EventType == winapi::WINDOW_BUFFER_SIZE_EVENT {
                SIGWINCH.store(true, atomic::Ordering::SeqCst);
                return Err(error::ReadlineError::WindowResize);
            } else if rec.EventType != winapi::KEY_EVENT {
                continue;
            }
            let key_event = unsafe { rec.KeyEvent() };
            // writeln!(io::stderr(), "key_event: {:?}", key_event).unwrap();
            if key_event.bKeyDown == 0 &&
               key_event.wVirtualKeyCode != winapi::VK_MENU as winapi::WORD {
                continue;
            }

            let ctrl = key_event.dwControlKeyState &
                       (winapi::LEFT_CTRL_PRESSED | winapi::RIGHT_CTRL_PRESSED) !=
                       0;
            let meta = (key_event.dwControlKeyState &
                        (winapi::LEFT_ALT_PRESSED | winapi::RIGHT_ALT_PRESSED) !=
                        0) || esc_seen;

            let utf16 = key_event.UnicodeChar;
            if utf16 == 0 {
                match key_event.wVirtualKeyCode as i32 {
                    winapi::VK_LEFT => return Ok(KeyPress::Left),
                    winapi::VK_RIGHT => return Ok(KeyPress::Right),
                    winapi::VK_UP => return Ok(KeyPress::Up),
                    winapi::VK_DOWN => return Ok(KeyPress::Down),
                    winapi::VK_DELETE => return Ok(KeyPress::Delete),
                    winapi::VK_HOME => return Ok(KeyPress::Home),
                    winapi::VK_END => return Ok(KeyPress::End),
                    _ => continue,
                };
            } else if utf16 == 27 {
                esc_seen = true;
                continue;
            } else {
                // TODO How to support surrogate pair ?
                self.buf = Some(utf16);
                let orc = decode_utf16(self).next();
                if orc.is_none() {
                    return Err(error::ReadlineError::Eof);
                }
                let c = try!(orc.unwrap());
                if meta {
                    match c {
                        'b' | 'B' => return Ok(KeyPress::Meta('B')),
                        'c' | 'C' => return Ok(KeyPress::Meta('C')),
                        'd' | 'D' => return Ok(KeyPress::Meta('D')),
                        'f' | 'F' => return Ok(KeyPress::Meta('F')),
                        'l' | 'L' => return Ok(KeyPress::Meta('L')),
                        't' | 'T' => return Ok(KeyPress::Meta('T')),
                        'u' | 'U' => return Ok(KeyPress::Meta('U')),
                        'y' | 'Y' => return Ok(KeyPress::Meta('Y')),
                        _ => return Ok(KeyPress::UNKNOWN_ESC_SEQ),
                    }
                } else {
                    return Ok(consts::char_to_key_press(c));
                }
            }
        }
    }
}

impl<R: Read> Iterator for RawReader<R> {
    type Item = u16;

    fn next(&mut self) -> Option<u16> {
        let buf = self.buf;
        self.buf = None;
        buf
    }
}
<commit_msg>Fix visibility issue in windows module<commit_after>use std::io;
use std::io::Read;
use std::marker::PhantomData;
use std::mem;
use std::sync::atomic;

use kernel32;
use winapi;

use consts::{self, KeyPress};
use ::error;
use ::Result;
use SIGWINCH;

pub type Handle = winapi::HANDLE;
pub type Mode = winapi::DWORD;
pub const STDIN_FILENO: winapi::DWORD = winapi::STD_INPUT_HANDLE;
pub const STDOUT_FILENO: winapi::DWORD = winapi::STD_OUTPUT_HANDLE;

fn get_std_handle(fd: winapi::DWORD) -> Result<winapi::HANDLE> {
    let handle = unsafe { kernel32::GetStdHandle(fd) };
    if handle == winapi::INVALID_HANDLE_VALUE {
        try!(Err(io::Error::last_os_error()));
    } else if handle.is_null() {
        try!(Err(io::Error::new(io::ErrorKind::Other,
                                "no stdio handle available for this process")));
    }
    Ok(handle)
}

#[macro_export]
macro_rules! check {
    ($funcall:expr) => {
        {
        let rc = unsafe { $funcall };
        if rc == 0 {
            try!(Err(io::Error::last_os_error()));
        }
        rc
        }
    };
}

/// Try to get the number of columns in the current terminal, or assume 80 if it fails.
pub fn get_columns(handle: Handle) -> usize {
    let mut info = unsafe { mem::zeroed() };
    match unsafe { kernel32::GetConsoleScreenBufferInfo(handle, &mut info) } {
        0 => 80,
        _ => info.dwSize.X as usize,
    }
}

/// Checking for an unsupported TERM in windows is a no-op
pub fn is_unsupported_term() -> bool {
    false
}

fn get_console_mode(handle: winapi::HANDLE) -> Result<Mode> {
    let mut original_mode = 0;
    check!(kernel32::GetConsoleMode(handle, &mut original_mode));
    Ok(original_mode)
}

/// Return whether or not STDIN, STDOUT or STDERR is a TTY
pub fn is_a_tty(fd: winapi::DWORD) -> bool {
    let handle = get_std_handle(fd);
    match handle {
        Ok(handle) => {
            // If this function doesn't fail then fd is a TTY
            get_console_mode(handle).is_ok()
        }
        Err(_) => false,
    }
}

/// Enable raw mode for the TERM
pub fn enable_raw_mode() -> Result<Mode> {
    let handle = try!(get_std_handle(STDIN_FILENO));
    let original_mode = try!(get_console_mode(handle));
    let raw = original_mode &
              !(winapi::wincon::ENABLE_LINE_INPUT | winapi::wincon::ENABLE_ECHO_INPUT |
                winapi::wincon::ENABLE_PROCESSED_INPUT);
    check!(kernel32::SetConsoleMode(handle, raw));
    Ok(original_mode)
}

/// Disable Raw mode for the term
pub fn disable_raw_mode(original_mode: Mode) -> Result<()> {
    let handle = try!(get_std_handle(STDIN_FILENO));
    check!(kernel32::SetConsoleMode(handle, original_mode));
    Ok(())
}

pub fn stdout_handle() -> Result<Handle> {
    let handle = try!(get_std_handle(STDOUT_FILENO));
    Ok(handle)
}

/// Console input reader
pub struct RawReader<R> {
    handle: winapi::HANDLE,
    buf: Option<u16>,
    phantom: PhantomData<R>,
}

impl<R: Read> RawReader<R> {
    pub fn new(_: R) -> Result<RawReader<R>> {
        let handle = try!(get_std_handle(STDIN_FILENO));
        Ok(RawReader {
            handle: handle,
            buf: None,
            phantom: PhantomData,
        })
    }

    pub fn next_key(&mut self, _: bool) -> Result<KeyPress> {
        use std::char::decode_utf16;

        let mut rec: winapi::INPUT_RECORD = unsafe { mem::zeroed() };
        let mut count = 0;
        let mut esc_seen = false;
        loop {
            // TODO GetNumberOfConsoleInputEvents
            check!(kernel32::ReadConsoleInputW(self.handle,
                                               &mut rec,
                                               1 as winapi::DWORD,
                                               &mut count));

            // TODO ENABLE_WINDOW_INPUT ???
            if rec.EventType == winapi::WINDOW_BUFFER_SIZE_EVENT {
                SIGWINCH.store(true, atomic::Ordering::SeqCst);
                return Err(error::ReadlineError::WindowResize);
            } else if rec.EventType != winapi::KEY_EVENT {
                continue;
            }
            let key_event = unsafe { rec.KeyEvent() };
            // writeln!(io::stderr(), "key_event: {:?}", key_event).unwrap();
            if key_event.bKeyDown == 0 &&
               key_event.wVirtualKeyCode != winapi::VK_MENU as winapi::WORD {
                continue;
            }

            let ctrl = key_event.dwControlKeyState &
                       (winapi::LEFT_CTRL_PRESSED | winapi::RIGHT_CTRL_PRESSED) !=
                       0;
            let meta = (key_event.dwControlKeyState &
                        (winapi::LEFT_ALT_PRESSED | winapi::RIGHT_ALT_PRESSED) !=
                        0) || esc_seen;

            let utf16 = key_event.UnicodeChar;
            if utf16 == 0 {
                match key_event.wVirtualKeyCode as i32 {
                    winapi::VK_LEFT => return Ok(KeyPress::Left),
                    winapi::VK_RIGHT => return Ok(KeyPress::Right),
                    winapi::VK_UP => return Ok(KeyPress::Up),
                    winapi::VK_DOWN => return Ok(KeyPress::Down),
                    winapi::VK_DELETE => return Ok(KeyPress::Delete),
                    winapi::VK_HOME => return Ok(KeyPress::Home),
                    winapi::VK_END => return Ok(KeyPress::End),
                    _ => continue,
                };
            } else if utf16 == 27 {
                esc_seen = true;
                continue;
            } else {
                // TODO How to support surrogate pair ?
                self.buf = Some(utf16);
                let orc = decode_utf16(self).next();
                if orc.is_none() {
                    return Err(error::ReadlineError::Eof);
                }
                let c = try!(orc.unwrap());
                if meta {
                    match c {
                        'b' | 'B' => return Ok(KeyPress::Meta('B')),
                        'c' | 'C' => return Ok(KeyPress::Meta('C')),
                        'd' | 'D' => return Ok(KeyPress::Meta('D')),
                        'f' | 'F' => return Ok(KeyPress::Meta('F')),
                        'l' | 'L' => return Ok(KeyPress::Meta('L')),
                        't' | 'T' => return Ok(KeyPress::Meta('T')),
                        'u' | 'U' => return Ok(KeyPress::Meta('U')),
                        'y' | 'Y' => return Ok(KeyPress::Meta('Y')),
                        _ => return Ok(KeyPress::UNKNOWN_ESC_SEQ),
                    }
                } else {
                    return Ok(consts::char_to_key_press(c));
                }
            }
        }
    }
}

impl<R: Read> Iterator for RawReader<R> {
    type Item = u16;

    fn next(&mut self) -> Option<u16> {
        let buf = self.buf;
        self.buf = None;
        buf
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 Jeffery Olson
//
// Licensed under the 3-Clause BSD License, see LICENSE.txt
// at the top-level of this repository.
// This file may not be copied, modified, or distributed
// except according to those terms.
use sdl2::event::Event;

use super::super::ui::{UiFont, UiBox};
use super::{ActiveView, PassiveView, DisplayViewContext};

pub struct TextInputDialogView<'a, TFont:'a, TBox:'a> {
    input_state: String,
    preface: Vec<String>,
    prompt: String,
    cursor: String,
    bg_color: (u8, u8, u8),
    coords: (int, int),
    box_size: (uint, uint),
    text_gap: uint,
    ui_font: &'a TFont,
    ui_box: &'a TBox
}

pub struct DisplayClearerPassiveView {
    bg_color: (u8, u8, u8)
}

impl<'a, TFont: UiFont, TBox: UiBox> TextInputDialogView<'a, TFont, TBox> {
    pub fn new(ui_font: &'a TFont, ui_box: &'a TBox, seed_state: Option<String>,
           preface: Vec<String>, prompt: String, cursor: String, bg_color: (u8,u8,u8),
           coords: (int, int), text_gap: uint)
    -> TextInputDialogView<'a, TFont, TBox> {
        TextInputDialogView {
            input_state: match seed_state { Some(i) => i, None => "".to_string() },
            preface: preface,
            prompt: prompt,
            cursor: cursor,
            bg_color: bg_color,
            coords: coords,
            box_size: (0,0),
            text_gap: text_gap,
            ui_font: ui_font,
            ui_box: ui_box
        }
    }
}
impl<'a, TViewCtx: DisplayViewContext, TFont: UiFont, TBox: UiBox>
        ActiveView<TViewCtx, String> for TextInputDialogView<'a, TFont, TBox> {
    fn active_update<'a>(
        &'a mut self,
        _ctx: &TViewCtx,
        _events: &[Event],
        _ms_time: u64,
        _passives: & mut Vec<&mut PassiveView<TViewCtx> >) -> Option<String> {
        //
        Some("#YOLO".to_string())
    }
}

impl<'a, TViewCtx: DisplayViewContext, TFont: UiFont, TBox: UiBox>
        PassiveView<TViewCtx> for TextInputDialogView<'a, TFont, TBox> {
    fn passive_update(&mut self, _ctx: &TViewCtx, _t: u64) {
    }
}

impl DisplayClearerPassiveView {
    pub fn new(bgc: (u8, u8, u8)) -> DisplayClearerPassiveView {
        DisplayClearerPassiveView { bg_color: bgc }
    }
}
impl<TViewCtx: DisplayViewContext> PassiveView<TViewCtx> for DisplayClearerPassiveView {
    fn passive_update(&mut self, ctx: &TViewCtx, _time: u64) {
        let display = ctx.get_display();
        display.set_draw_color(self.bg_color);
        match display.renderer.clear() {
            Err(e) => fail!("Display Clearer.update(): failed to clear display: {}", e),
            _ => {}
        }
    }
}
impl<TViewCtx: DisplayViewContext> ActiveView<TViewCtx, ()>
        for DisplayClearerPassiveView {
    fn active_update<'a>(&'a mut self, _ctx: &TViewCtx, _e: &[Event], _t: u64,
              _p: &mut Vec<&mut PassiveView<TViewCtx> >)
        -> Option<()> {
            fail!("this should never be called.");
    }
}
<commit_msg>working on getting the textinputdialogview into shape<commit_after>// Copyright 2013-2014 Jeffery Olson
//
// Licensed under the 3-Clause BSD License, see LICENSE.txt
// at the top-level of this repository.
// This file may not be copied, modified, or distributed
// except according to those terms.
use sdl2::event::{Event, QuitEvent, KeyDownEvent, NoEvent, TextEditingEvent, TextInputEvent};
use sdl2::keyboard::{start_text_input, stop_text_input};
use sdl2::keycode::*;

use super::super::ui::{UiFont, UiBox};
use super::{ActiveView, PassiveView, DisplayViewContext};

pub struct TextInputDialogView<'a, TFont:'a, TBox:'a> {
    input_state: String,
    preface: &'a [String],
    prompt: String,
    cursor: String,
    bg_color: (u8, u8, u8),
    coords: (int, int),
    box_size: (uint, uint),
    text_gap: uint,
    ui_font: &'a TFont,
    ui_box: &'a TBox,
    started: bool
}

pub struct DisplayClearerPassiveView {
    bg_color: (u8, u8, u8)
}

impl<'a, TFont: UiFont, TBox: UiBox> TextInputDialogView<'a, TFont, TBox> {
    pub fn new(
        ui_font: &'a TFont,
        ui_box: &'a TBox,
        seed_state: Option<String>,
        preface: &'a [String],
        prompt: String,
        cursor: String,
        bg_color: (u8,u8,u8),
        coords: (int, int),
        text_gap: uint)
        -> TextInputDialogView<'a, TFont, TBox> {
            TextInputDialogView {
            input_state: match seed_state { Some(i) => i, None => "".to_string() },
            preface: preface,
            prompt: prompt,
            cursor: cursor,
            bg_color: bg_color,
            coords: coords,
            box_size: (0,0),
            text_gap: text_gap,
            ui_font: ui_font,
            ui_box: ui_box,
            started: false
        }
    }
}
impl<'a, TViewCtx: DisplayViewContext, TFont: UiFont, TBox: UiBox>
        ActiveView<TViewCtx, String> for TextInputDialogView<'a, TFont, TBox> {
    fn active_update<'a>(
        &'a mut self,
        _ctx: &TViewCtx,
        events: &[Event],
        _ms_time: u64,
        _passives: & mut Vec<&mut PassiveView<TViewCtx> >) -> Option<String> {
        //
        if !self.started {
            self.started = true;
            // call into SDL2 start text editing stuff
            start_text_input();
        }
        let mut out = None;
        for event in events.iter() {
            match *event {
                TextInputEvent(_, _, ref txt) => {
                    out = None;
                    println!("TextInputEvent: {}", txt);
                    break;
                },
                TextEditingEvent(_, _, ref txt, start, length) => {
                    out = None;
                    println!("TextEditingEvent: {}", txt);
                    break;
                },
                KeyDownEvent(_, _, key, _, _) =>
                    match key {
                        ReturnKey => {
                            out = Some("YOLO".to_string());
                            println!("done editing text?");
                            stop_text_input();
                            break;
                        },
                        key => {
                            println!("pressed {} key", key);
                            out = None;
                            break;
                        }
                    },
                _ => {}
            }
        }
        out
    }
}

impl<'a, TViewCtx: DisplayViewContext, TFont: UiFont, TBox: UiBox>
        PassiveView<TViewCtx> for TextInputDialogView<'a, TFont, TBox> {
    fn passive_update(&mut self, _ctx: &TViewCtx, _t: u64) {
        // should never be passive, because the active_update() impl
        // doesn't yield_to() any other views, so we can put the logic
        // there
    }
}

impl DisplayClearerPassiveView {
    pub fn new(bgc: (u8, u8, u8)) -> DisplayClearerPassiveView {
        DisplayClearerPassiveView { bg_color: bgc }
    }
}

impl<TViewCtx: DisplayViewContext> PassiveView<TViewCtx> for DisplayClearerPassiveView {
    fn passive_update(&mut self, ctx: &TViewCtx, _time: u64) {
        let display = ctx.get_display();
        display.set_draw_color(self.bg_color);
        match display.renderer.clear() {
            Err(e) => fail!("Display Clearer.update(): failed to clear display: {}", e),
            _ => {}
        }
    }
}

impl<TViewCtx: DisplayViewContext> ActiveView<TViewCtx, ()>
        for DisplayClearerPassiveView {
    fn active_update<'a>(&'a mut self, _ctx: &TViewCtx, _e: &[Event], _t: u64,
              _p: &mut Vec<&mut PassiveView<TViewCtx> >)
        -> Option<()> {
            fail!("this should never be called.");
    }
}
<|endoftext|>


<commit_before>extern crate tar;
extern crate flate2;

use std::fs::File;
use std::io::{BufReader, Read, Write};
use std::path::Path;

use self::tar::Archive;
use self::flate2::read::GzDecoder;

fn extract_tar(input: &Path, output: &Path) {
    let file = File::open(input).unwrap();
    let mut archive = Archive::new(file);
    archive.unpack(output).unwrap();
}

fn extract_gz(input: &Path, output: &Path) {
    let file = File::open(input).unwrap();
    let buffer = BufReader::new(file);
    let archive = GzDecoder::new(buffer).unwrap();

    let mut buffer = File::create(output).unwrap();
    for byte in archive.bytes() {
        buffer.write(byte.unwrap());
    }
}<commit_msg>Fixed an error<commit_after>extern crate tar;
extern crate flate2;

use std::fs::File;
use std::io::{BufReader, Read, Write};
use std::path::Path;

use self::tar::Archive;
use self::flate2::read::GzDecoder;

fn extract_tar(input: &Path, output: &Path) {
    let file = File::open(input).unwrap();
    let mut archive = Archive::new(file);
    archive.unpack(output).unwrap();
}

fn extract_gz(input: &Path, output: &Path) {
    let file = File::open(input).unwrap();
    let buffer = BufReader::new(file);
    let archive = GzDecoder::new(buffer).unwrap();

    let mut buffer = File::create(output).unwrap();
    for byte in archive.bytes() {
        buffer.write(&[byte.unwrap()]);
    }
}

<|endoftext|>


<commit_before>use calx_alg::{compact_bits_by_2, noise, spread_bits_by_2};
use calx_grid::{Dir6, GridNode, HexGeom};
use euclid::{Vector2D, vec2};
use std::num::Wrapping;
use std::ops::{Add, Sub};
use terraform::TerrainQuery;

pub const SECTOR_WIDTH: i32 = 40;
pub const SECTOR_HEIGHT: i32 = 22;

/// Unambiguous location in the game world.
#[derive(Copy, Eq, PartialEq, Clone, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
pub struct Location {
    pub x: i8,
    pub y: i8,
    pub z: i8,
}

/// The type for a unique location in the game world.
///
/// IMPORTANT: Be careful where you use the simple "location + vec" algebra. That does not take
/// portals into account, and will usually cause unwanted effects near them in high-level code.
/// Most high-level logic should use `Location::jump` to displace locations. This will correctly
/// traverse portals.
impl Location {
    pub fn origin() -> Location { Location { x: 0, y: 0, z: 0 } }

    pub fn new(x: i8, y: i8, z: i8) -> Location { Location { x, y, z } }

    /// Construct a Location from a Morton code representation.
    ///
    /// Use the representation generated with `to_morton`. The odd low 16 bits are compacted to x
    /// value, the even low 16 bits to z and the first 8 of the high 16 bits become z.
    pub fn from_morton(morton_code: u32) -> Location {
        let xy = morton_code & 0xffff_ffff;
        let x = compact_bits_by_2(xy) as u8;
        let y = compact_bits_by_2(xy >> 1) as u8;
        let z = (morton_code >> 16) as u8;

        unsafe {
            Location {
                x: ::std::mem::transmute(x),
                y: ::std::mem::transmute(y),
                z: ::std::mem::transmute(z),
            }
        }
    }

    /// Turn the Location to a Morton code value.
    ///
    /// Spatially close locations are often numerically close in Morton codes, these are useful for
    /// quadtree-like structures.
    pub fn to_morton(&self) -> u32 {
        let mut ret = 0;
        let x: u8 = unsafe { ::std::mem::transmute(self.x) };
        let y: u8 = unsafe { ::std::mem::transmute(self.y) };
        let z: u8 = unsafe { ::std::mem::transmute(self.z) };
        ret ^= spread_bits_by_2(x as u32);
        ret ^= spread_bits_by_2(y as u32) << 1;
        ret ^= (z as u32) << 16;
        ret
    }

    /// Vector pointing from this location into the other one if the locations
    /// are on the same Euclidean plane.
    pub fn v2_at(&self, other: Location) -> Option<Vector2D<i32>> {
        if self.z != other.z {
            return None;
        }
        Some(
            vec2(other.x as i32, other.y as i32) - vec2(self.x as i32, self.y as i32),
        )
    }

    /// Hex distance from this location to the other one, if applicable.
    pub fn distance_from(&self, other: Location) -> Option<i32> {
        if let Some(v) = self.v2_at(other) {
            Some(v.hex_dist())
        } else {
            None
        }
    }

    /// Distance that defaults to max integer value for separate zones.
    ///
    /// Can be used for situations that want a straightforward metric function like A* search.
    pub fn metric_distance(&self, other: Location) -> i32 {
        self.distance_from(other).unwrap_or(i32::max_value())
    }

    pub fn dir6_towards(&self, other: Location) -> Option<Dir6> {
        if let Some(v) = self.v2_at(other) {
            Some(Dir6::from_v2(v))
        } else {
            None
        }
    }

    /// A pseudorandom value in [-1.0, 1.0] corresponding to this specific location.
    ///
    /// Is always the same for the same `Location`.
    pub fn noise(&self) -> f32 { noise(self.x as i32 + self.y as i32 * 59 + self.z as i32 * 919) }

    /// Offset location and follow any portals in target site.
    pub fn jump<T: TerrainQuery, V: Into<Vector2D<i32>> + Sized>(
        self,
        ctx: &T,
        offset: V,
    ) -> Location {
        let loc = self + offset.into();
        ctx.portal(loc).unwrap_or(loc)
    }

    /// Return `Sector` this location is in.
    pub fn sector(self) -> Sector {
        let (u, v) = self.to_rect_coords();

        Sector::new(
            (u as f32 / SECTOR_WIDTH as f32).floor() as i8,
            (v as f32 / SECTOR_HEIGHT as f32).floor() as i8,
            self.z,
        )
    }

    /// Map location's x, y to rectangular (offset) coordinates.
    pub fn to_rect_coords(self) -> (i32, i32) {
        let u = self.x as i32 - self.y as i32;
        let v = ((self.x as f32 + self.y as f32) / 2.0).floor() as i32;
        (u, v)
    }

    pub fn from_rect_coords(u: i32, v: i32, z: i8) -> Location {
        // Yeah I don't know either how you're supposed to come up with the right ceil/floor
        // juggling, just tweaked it around until it passed all the unit tests.
        let half_u = u as f32 / 2.0;
        Location::new(
            (half_u.ceil() as i32 + v) as i8,
            (v - half_u.floor() as i32) as i8,
            z,
        )
    }
}

impl<V: Into<Vector2D<i32>>> Add<V> for Location {
    type Output = Location;
    fn add(self, other: V) -> Location {
        let other = other.into();
        Location {
            x: (self.x as i32 + other.x) as i8,
            y: (self.y as i32 + other.y) as i8,
            z: self.z,
        }
    }
}

impl Add<Portal> for Location {
    type Output = Location;
    fn add(self, other: Portal) -> Location {
        Location {
            x: (Wrapping(self.x) + Wrapping(other.dx)).0,
            y: (Wrapping(self.y) + Wrapping(other.dy)).0,
            z: other.z,
        }
    }
}

impl<V: Into<Vector2D<i32>>> Sub<V> for Location {
    type Output = Location;
    fn sub(self, other: V) -> Location {
        let other = other.into();
        Location {
            x: (self.x as i32 - other.x) as i8,
            y: (self.y as i32 - other.y) as i8,
            z: self.z,
        }
    }
}

impl GridNode for Location {
    fn neighbors(&self) -> Vec<Location> { Dir6::iter().map(|d| *self + d.to_v2()).collect() }
}

#[derive(Copy, Eq, PartialEq, Clone, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
pub struct Portal {
    pub dx: i8,
    pub dy: i8,
    pub z: i8,
}

impl Portal {
    pub fn new(from: Location, to: Location) -> Portal {
        Portal {
            dx: (Wrapping(to.x) - Wrapping(from.x)).0,
            dy: (Wrapping(to.y) - Wrapping(from.y)).0,
            z: to.z,
        }
    }
}

impl Add<Portal> for Portal {
    type Output = Portal;
    fn add(self, other: Portal) -> Portal {
        Portal {
            dx: (Wrapping(self.dx) + Wrapping(other.dx)).0,
            dy: (Wrapping(self.dy) + Wrapping(other.dy)).0,
            z: other.z,
        }
    }
}

/// Non-scrolling screen.
///
/// A sector represents a rectangular chunk of locations that fit on the visual screen. Sector
/// coordinates form their own sector space that tiles the location space with sectors.
#[derive(Copy, Eq, PartialEq, Clone, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
pub struct Sector {
    pub x: i8,
    pub y: i8,
    pub z: i8,
}

impl Sector {
    pub fn new(x: i8, y: i8, z: i8) -> Sector { Sector { x, y, z } }

    pub fn origin(self) -> Location { self.rect_coord_loc(0, 0) }

    pub fn rect_coord_loc(self, u: i32, v: i32) -> Location {
        Location::from_rect_coords(
            self.x as i32 * SECTOR_WIDTH + u,
            self.y as i32 * SECTOR_HEIGHT + v,
            self.z,
        )
    }

    /// Center location for this sector.
    ///
    /// Usually you want the camera positioned here.
    pub fn center(self) -> Location {
        // XXX: If the width/height are even (as they currently are), there isn't a centered cell.
        self.rect_coord_loc(SECTOR_WIDTH / 2 - 1, SECTOR_HEIGHT / 2 - 1)
    }

    // TODO: Use impl Trait instead of box for return type once it's stable.
    pub fn iter(self) -> Box<Iterator<Item = Location>> {
        let n = SECTOR_WIDTH * SECTOR_HEIGHT;
        let pitch = SECTOR_WIDTH;
        Box::new((0..n).map(
            move |i| self.rect_coord_loc(i % pitch, i / pitch),
        ))
    }
}

#[cfg(test)]
mod test {
    use super::{Location, Sector};
    use euclid::vec2;

    #[test]
    fn test_wraparound() {
        let l1 = Location::new(0, 0, 0);
        let l2 = l1 + vec2(300, 300);
        assert_eq!((44, 44), (l2.x, l2.y));
    }

    #[test]
    fn test_morton() {
        use rand::{self, Rng};
        let mut rng = rand::thread_rng();

        for _ in 0..1000 {
            let x = rng.gen::<u32>() & 0xff_ffff;
            assert_eq!(x, Location::from_morton(x).to_morton());
        }
    }

    #[test]
    fn test_location_to_sector() {
        let s = Sector::new(0, 0, 0);
        assert_eq!(s.origin(), Location::new(0, 0, 0));

        // Sector division near origin
        assert_eq!(Location::new(0, 0, 0).sector(), Sector::new(0, 0, 0));
        assert_eq!(Location::new(-1, -1, 0).sector(), Sector::new(0, -1, 0));
        assert_eq!(Location::new(0, 1, 0).sector(), Sector::new(-1, 0, 0));
        assert_eq!(Location::new(-1, 0, 0).sector(), Sector::new(-1, -1, 0));

        for y in -100..100 {
            for x in -100..100 {
                let loc = Location::new(x, y, 0);
                let (u, v) = loc.to_rect_coords();
                assert_eq!(
                    loc,
                    Location::from_rect_coords(u, v, loc.z),
                    "u: {}, v: {}",
                    u,
                    v
                );

                assert!(
                    loc.sector().iter().find(|&x| x == loc).is_some(),
                    format!("{:?} not found in sector {:?}", loc, loc.sector())
                );
            }
        }
    }

    #[test]
    fn test_sector_iter() {
        let s = Sector::new(0, 0, 0);

        for loc in s.iter() {
            assert_eq!(s, loc.sector(), "Location: {:?}", loc);
        }
    }
}
<commit_msg>Sector metric<commit_after>use calx_alg::{compact_bits_by_2, noise, spread_bits_by_2};
use calx_grid::{Dir6, GridNode, HexGeom};
use euclid::{Vector2D, vec2};
use std::num::Wrapping;
use std::ops::{Add, Sub};
use terraform::TerrainQuery;

pub const SECTOR_WIDTH: i32 = 40;
pub const SECTOR_HEIGHT: i32 = 22;

/// Unambiguous location in the game world.
#[derive(Copy, Eq, PartialEq, Clone, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
pub struct Location {
    pub x: i8,
    pub y: i8,
    pub z: i8,
}

/// The type for a unique location in the game world.
///
/// IMPORTANT: Be careful where you use the simple "location + vec" algebra. That does not take
/// portals into account, and will usually cause unwanted effects near them in high-level code.
/// Most high-level logic should use `Location::jump` to displace locations. This will correctly
/// traverse portals.
impl Location {
    pub fn origin() -> Location { Location { x: 0, y: 0, z: 0 } }

    pub fn new(x: i8, y: i8, z: i8) -> Location { Location { x, y, z } }

    /// Construct a Location from a Morton code representation.
    ///
    /// Use the representation generated with `to_morton`. The odd low 16 bits are compacted to x
    /// value, the even low 16 bits to z and the first 8 of the high 16 bits become z.
    pub fn from_morton(morton_code: u32) -> Location {
        let xy = morton_code & 0xffff_ffff;
        let x = compact_bits_by_2(xy) as u8;
        let y = compact_bits_by_2(xy >> 1) as u8;
        let z = (morton_code >> 16) as u8;

        unsafe {
            Location {
                x: ::std::mem::transmute(x),
                y: ::std::mem::transmute(y),
                z: ::std::mem::transmute(z),
            }
        }
    }

    /// Turn the Location to a Morton code value.
    ///
    /// Spatially close locations are often numerically close in Morton codes, these are useful for
    /// quadtree-like structures.
    pub fn to_morton(&self) -> u32 {
        let mut ret = 0;
        let x: u8 = unsafe { ::std::mem::transmute(self.x) };
        let y: u8 = unsafe { ::std::mem::transmute(self.y) };
        let z: u8 = unsafe { ::std::mem::transmute(self.z) };
        ret ^= spread_bits_by_2(x as u32);
        ret ^= spread_bits_by_2(y as u32) << 1;
        ret ^= (z as u32) << 16;
        ret
    }

    /// Vector pointing from this location into the other one if the locations
    /// are on the same Euclidean plane.
    pub fn v2_at(&self, other: Location) -> Option<Vector2D<i32>> {
        if self.z != other.z {
            return None;
        }
        Some(
            vec2(other.x as i32, other.y as i32) - vec2(self.x as i32, self.y as i32),
        )
    }

    /// Hex distance from this location to the other one, if applicable.
    pub fn distance_from(&self, other: Location) -> Option<i32> {
        if let Some(v) = self.v2_at(other) {
            Some(v.hex_dist())
        } else {
            None
        }
    }

    /// Distance that defaults to max integer value for separate zones.
    ///
    /// Can be used for situations that want a straightforward metric function like A* search.
    pub fn metric_distance(&self, other: Location) -> i32 {
        self.distance_from(other).unwrap_or(i32::max_value())
    }

    pub fn dir6_towards(&self, other: Location) -> Option<Dir6> {
        if let Some(v) = self.v2_at(other) {
            Some(Dir6::from_v2(v))
        } else {
            None
        }
    }

    /// A pseudorandom value in [-1.0, 1.0] corresponding to this specific location.
    ///
    /// Is always the same for the same `Location`.
    pub fn noise(&self) -> f32 { noise(self.x as i32 + self.y as i32 * 59 + self.z as i32 * 919) }

    /// Offset location and follow any portals in target site.
    pub fn jump<T: TerrainQuery, V: Into<Vector2D<i32>> + Sized>(
        self,
        ctx: &T,
        offset: V,
    ) -> Location {
        let loc = self + offset.into();
        ctx.portal(loc).unwrap_or(loc)
    }

    /// Return `Sector` this location is in.
    pub fn sector(self) -> Sector {
        let (u, v) = self.to_rect_coords();

        Sector::new(
            (u as f32 / SECTOR_WIDTH as f32).floor() as i8,
            (v as f32 / SECTOR_HEIGHT as f32).floor() as i8,
            self.z,
        )
    }

    /// Map location's x, y to rectangular (offset) coordinates.
    pub fn to_rect_coords(self) -> (i32, i32) {
        let u = self.x as i32 - self.y as i32;
        let v = ((self.x as f32 + self.y as f32) / 2.0).floor() as i32;
        (u, v)
    }

    pub fn from_rect_coords(u: i32, v: i32, z: i8) -> Location {
        // Yeah I don't know either how you're supposed to come up with the right ceil/floor
        // juggling, just tweaked it around until it passed all the unit tests.
        let half_u = u as f32 / 2.0;
        Location::new(
            (half_u.ceil() as i32 + v) as i8,
            (v - half_u.floor() as i32) as i8,
            z,
        )
    }
}

impl<V: Into<Vector2D<i32>>> Add<V> for Location {
    type Output = Location;
    fn add(self, other: V) -> Location {
        let other = other.into();
        Location {
            x: (self.x as i32 + other.x) as i8,
            y: (self.y as i32 + other.y) as i8,
            z: self.z,
        }
    }
}

impl Add<Portal> for Location {
    type Output = Location;
    fn add(self, other: Portal) -> Location {
        Location {
            x: (Wrapping(self.x) + Wrapping(other.dx)).0,
            y: (Wrapping(self.y) + Wrapping(other.dy)).0,
            z: other.z,
        }
    }
}

impl<V: Into<Vector2D<i32>>> Sub<V> for Location {
    type Output = Location;
    fn sub(self, other: V) -> Location {
        let other = other.into();
        Location {
            x: (self.x as i32 - other.x) as i8,
            y: (self.y as i32 - other.y) as i8,
            z: self.z,
        }
    }
}

impl GridNode for Location {
    fn neighbors(&self) -> Vec<Location> { Dir6::iter().map(|d| *self + d.to_v2()).collect() }
}

#[derive(Copy, Eq, PartialEq, Clone, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
pub struct Portal {
    pub dx: i8,
    pub dy: i8,
    pub z: i8,
}

impl Portal {
    pub fn new(from: Location, to: Location) -> Portal {
        Portal {
            dx: (Wrapping(to.x) - Wrapping(from.x)).0,
            dy: (Wrapping(to.y) - Wrapping(from.y)).0,
            z: to.z,
        }
    }
}

impl Add<Portal> for Portal {
    type Output = Portal;
    fn add(self, other: Portal) -> Portal {
        Portal {
            dx: (Wrapping(self.dx) + Wrapping(other.dx)).0,
            dy: (Wrapping(self.dy) + Wrapping(other.dy)).0,
            z: other.z,
        }
    }
}

/// Non-scrolling screen.
///
/// A sector represents a rectangular chunk of locations that fit on the visual screen. Sector
/// coordinates form their own sector space that tiles the location space with sectors.
#[derive(Copy, Eq, PartialEq, Clone, Hash, PartialOrd, Ord, Debug, Serialize, Deserialize)]
pub struct Sector {
    pub x: i8,
    pub y: i8,
    pub z: i8,
}

impl Sector {
    pub fn new(x: i8, y: i8, z: i8) -> Sector { Sector { x, y, z } }

    pub fn origin(self) -> Location { self.rect_coord_loc(0, 0) }

    pub fn rect_coord_loc(self, u: i32, v: i32) -> Location {
        Location::from_rect_coords(
            self.x as i32 * SECTOR_WIDTH + u,
            self.y as i32 * SECTOR_HEIGHT + v,
            self.z,
        )
    }

    /// Center location for this sector.
    ///
    /// Usually you want the camera positioned here.
    pub fn center(self) -> Location {
        // XXX: If the width/height are even (as they currently are), there isn't a centered cell.
        self.rect_coord_loc(SECTOR_WIDTH / 2 - 1, SECTOR_HEIGHT / 2 - 1)
    }

    // TODO: Use impl Trait instead of box for return type once it's stable.
    pub fn iter(self) -> Box<Iterator<Item = Location>> {
        let n = SECTOR_WIDTH * SECTOR_HEIGHT;
        let pitch = SECTOR_WIDTH;
        Box::new((0..n).map(
            move |i| self.rect_coord_loc(i % pitch, i / pitch),
        ))
    }

    pub fn taxicab_distance(self, other: Sector) -> i32 {
        ((self.x as i32) - (other.x as i32)).abs() +
        ((self.y as i32) - (other.y as i32)).abs() +
        ((self.z as i32) - (other.z as i32)).abs()
    }
}

#[cfg(test)]
mod test {
    use super::{Location, Sector};
    use euclid::vec2;

    #[test]
    fn test_wraparound() {
        let l1 = Location::new(0, 0, 0);
        let l2 = l1 + vec2(300, 300);
        assert_eq!((44, 44), (l2.x, l2.y));
    }

    #[test]
    fn test_morton() {
        use rand::{self, Rng};
        let mut rng = rand::thread_rng();

        for _ in 0..1000 {
            let x = rng.gen::<u32>() & 0xff_ffff;
            assert_eq!(x, Location::from_morton(x).to_morton());
        }
    }

    #[test]
    fn test_location_to_sector() {
        let s = Sector::new(0, 0, 0);
        assert_eq!(s.origin(), Location::new(0, 0, 0));

        // Sector division near origin
        assert_eq!(Location::new(0, 0, 0).sector(), Sector::new(0, 0, 0));
        assert_eq!(Location::new(-1, -1, 0).sector(), Sector::new(0, -1, 0));
        assert_eq!(Location::new(0, 1, 0).sector(), Sector::new(-1, 0, 0));
        assert_eq!(Location::new(-1, 0, 0).sector(), Sector::new(-1, -1, 0));

        for y in -100..100 {
            for x in -100..100 {
                let loc = Location::new(x, y, 0);
                let (u, v) = loc.to_rect_coords();
                assert_eq!(
                    loc,
                    Location::from_rect_coords(u, v, loc.z),
                    "u: {}, v: {}",
                    u,
                    v
                );

                assert!(
                    loc.sector().iter().find(|&x| x == loc).is_some(),
                    format!("{:?} not found in sector {:?}", loc, loc.sector())
                );
            }
        }
    }

    #[test]
    fn test_sector_iter() {
        let s = Sector::new(0, 0, 0);

        for loc in s.iter() {
            assert_eq!(s, loc.sector(), "Location: {:?}", loc);
        }
    }

    #[test]
    fn test_distance() {
        let s = Sector::new(1, 2, 3);
        assert_eq!(s.taxicab_distance(s), 0);
        assert_eq!(s.taxicab_distance(Sector::new(3, 2, 1)), 4);
        assert_eq!(Sector::new(3, 2, 1).taxicab_distance(s), 4);
    }
}
<|endoftext|>