<commit_before>//! A naive implementation of left-leaning red-black trees
//! that are isomorphic to 2-3 trees. This implementation
//! borrows heavily from https://www.cs.princeton.edu/~rs/talks/LLRB/LLRB.pdf
//! and https://github.com/rcatolino/rbtree-rust.
//! Debug assertions borrow heavily from the implementations
//! at http://algs4.cs.princeton.edu/33balanced.

// I have spent a lot of hours trying all possible ways to
// implement this data structure. Most of the attemps
// led to confusing compilation errors. The heart of the
// issue is how to represent the Option<Box<Node>>.

// I tried using the newtype pattern
// https://doc.rust-lang.org/book/structs.html#tuple-structs.
// I (and others) had difficulty writing the
// destructuring lets correctly. See
// https://www.reddit.com/r/rust/comments/2cmjfn/how_to_do_typedefsnewtypes

// I tried creating a struct with a single field
// but had trouble accessing the field correctly
// ("let", "let ref", "let mut", "let ref mut").
// In addition the dummy field obfuscated the implementation.

// I tried using a type alias but then it's not
// possible to implement Display and Debug.

// Eventually I settled on using no abstraction for
// Option<Box<Node>>. The implementation became
// much easier to write.

// Also the implementation became much easier after I
// saw from rcatolino that some methods should be defined
// on a trait that wraps Box<Node> and other method
// should be defined on a trait that wraps Option<Box<Node>>.

use std::cmp::Ordering;
use std::fmt;
use std::mem;

#[derive(PartialEq, Eq, Copy, Clone)]
enum Color {
    Red,
    Black,
}

// This instance of the newtype pattern
// https://doc.rust-lang.org/book/structs.html#tuple-structs
// is used only for fmt::Display and fmt::Debug.
struct Link<'a>(&'a Option<Box<Node>>);

pub struct LLRBTree {
    root: Option<Box<Node>>,
}

struct Node {
    key: i32,
    val: i32,
    color: Color,
    left: Option<Box<Node>>,
    right: Option<Box<Node>>,
}

impl LLRBTree {
    pub fn new() -> Self {
        LLRBTree { root: None }
    }

    pub fn get(&self, key: i32) -> Option<i32> {
        self.root.get(key)
    }

    pub fn insert(&mut self, key: i32, value: i32) -> Option<i32> {
        let prev = self.root.insert(key, value);
        self.root.set_color(Color::Black);
        debug_assert!(self.check());
        prev
    }

    pub fn remove_min(&mut self) -> Option<i32> {
        if self.root.is_none() {
            None
        } else {
            if !self.root.left().is_red() && !self.root.right().is_red() {
                self.root.set_color(Color::Red);
            }
            let min = self.root.remove_min();
            if self.root.is_some() {
                self.root.set_color(Color::Black);
            }
            debug_assert!(self.check());
            min
        }
    }

    fn is_bst(&self) -> bool {
        self.root.is_bst(None, None)
    }

    fn is_23(&self) -> bool {
        self.root.is_23(true)
    }

    fn is_balanced(&self) -> bool {
        let mut black = 0;
        let mut next = &self.root;
        loop {
            match next {
                &None => break,
                &Some(ref node) => {
                    if !node.is_red() {
                        black += 1;
                    }
                    next = &node.left;
                }
            }
        }
        self.root.is_balanced(black)
    }

    fn check(&self) -> bool {
        debug_assert!(self.is_bst(), "Not a binary search tree");
        debug_assert!(self.is_23(), "Not a 2-3 tree");
        debug_assert!(self.is_balanced(), "Not balanced");
        true
    }
}

impl fmt::Display for LLRBTree {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", Link(&self.root))
    }
}

impl fmt::Debug for LLRBTree {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", Link(&self.root))
    }
}

impl Node {
    fn new(key: i32, val: i32) -> Self {
        Node {
            key: key,
            val: val,
            color: Color::Red,
            left: None,
            right: None,
        }
    }
}

trait BoxNode {
    fn is_red(&self) -> bool;
    fn left_rotate(&mut self);
    fn right_rotate(&mut self);
    fn flip_colors(&mut self);
    fn move_red_to_left(&mut self);
    fn move_red_to_right(&mut self);
    fn post_insert_balance(&mut self);
    fn post_remove_balance(&mut self);
}

impl BoxNode for Box<Node> {
    fn is_red(&self) -> bool {
        self.color == Color::Red
    }

    fn left_rotate(&mut self) {
        debug_assert!(self.right.is_red());
        let mut child = self.right.take().unwrap();
        mem::swap(self, &mut child);
        mem::swap(&mut child.right, &mut self.left);
        self.color = child.color;
        child.color = Color::Red;
        self.left = Some(child);
    }

    fn right_rotate(&mut self) {
        debug_assert!(self.left.is_red());
        let mut child = self.left.take().unwrap();
        mem::swap(self, &mut child);
        mem::swap(&mut child.left, &mut self.right);
        self.color = child.color;
        child.color = Color::Red;
        self.right = Some(child);
    }

    fn flip_colors(&mut self) {
        debug_assert!(self.left.is_some());
        debug_assert!(self.right.is_some());
        debug_assert!(self.color != self.left.color());
        debug_assert!(self.color != self.right.color());
        self.color.flip();
        self.left.mutate().color.flip();
        self.right.mutate().color.flip();
    }

    // Assuming that self is red and both self.left and self.left.left
    // are black, make self.left or one of its children red.
    fn move_red_to_left(&mut self) {
        debug_assert!(self.is_red());
        debug_assert!(!self.left.is_red());
        debug_assert!(!self.left.left().is_red());
        self.flip_colors();
        if self.right.left().is_red() {
            self.right.mutate().right_rotate();
            self.left_rotate();
            self.flip_colors();
        }
    }

    // Assuming that self is red and both self.right and self.right.left
    // are black, make self.right or one of its children red.
    fn move_red_to_right(&mut self) {
        debug_assert!(self.is_red());
        debug_assert!(!self.right.is_red());
        debug_assert!(!self.right.left().is_red());
        self.flip_colors();
        if self.left.left().is_red() {
            self.right_rotate();
            self.flip_colors();
        }
    }

    fn post_insert_balance(&mut self) {
        if !self.left.is_red() && self.right.is_red() {
            self.left_rotate();
        }
        if self.left.is_red() && self.left.left().is_red() {
            self.right_rotate();
        }
        if self.left.is_red() && self.right.is_red() {
            self.flip_colors();
        }
    }

    fn post_remove_balance(&mut self) {
        if self.right.is_red() {
            self.left_rotate();
        }
        if self.left.is_red() && self.left.left().is_red() {
            self.right_rotate();
        }
        if self.left.is_red() && self.right.is_red() {
            self.flip_colors();
        }
    }
}

trait OptionBoxNode {
    fn get(&self, key: i32) -> Option<i32>;
    fn is_red(&self) -> bool;
    fn color(&self) -> Color;
    fn insert(&mut self, key: i32, val: i32) -> Option<i32>;
    fn reference(&self) -> &Box<Node>;
    fn mutate(&mut self) -> &mut Box<Node>;
    fn left(&self) -> &Option<Box<Node>>;
    fn right(&self) -> &Option<Box<Node>>;
    fn set_color(&mut self, color: Color);
    fn remove_min(&mut self) -> Option<i32>;
    fn is_bst(&self, min: Option<i32>, max: Option<i32>) -> bool;
    fn is_23(&self, root: bool) -> bool;
    fn is_balanced(&self, black: i32) -> bool;
}

impl OptionBoxNode for Option<Box<Node>> {
    fn get(&self, key: i32) -> Option<i32> {
        match *self {
            None => None,
            Some(ref node) => {
                match key.cmp(&node.key) {
                    Ordering::Equal => Some(node.val),
                    Ordering::Less => node.left.get(key),
                    Ordering::Greater => node.right.get(key),
                }
            }
        }
    }

    fn is_red(&self) -> bool {
        match *self {
            None => false,
            Some(ref node) => node.is_red(),
        }
    }

    fn color(&self) -> Color {
        self.as_ref().unwrap().color
    }

    fn insert(&mut self, key: i32, value: i32) -> Option<i32> {
        let prev = match *self {
            None => {
                *self = new_leaf(key, value);
                None
            }
            Some(ref mut node) => {
                match key.cmp(&node.key) {
                    Ordering::Equal => {
                        let prev = node.val;
                        node.val = value;
                        Some(prev)
                    }
                    Ordering::Less => node.left.insert(key, value),
                    Ordering::Greater => node.right.insert(key, value),
                }
            }
        };
        self.mutate().post_insert_balance();
        prev
    }

    fn remove_min(&mut self) -> Option<i32> {
        if self.is_none() {
            None
        } else if self.reference().left.is_none() {
            Some(self.take().unwrap().key)
        } else {
            let node = self.mutate();
            if !node.left.is_red() && !node.left.left().is_red() {
                node.move_red_to_left();
            }
            let min = node.left.remove_min();
            node.post_remove_balance();
            min
        }
    }

    fn reference(&self) -> &Box<Node> {
        self.as_ref().unwrap()
    }

    fn mutate(&mut self) -> &mut Box<Node> {
        self.as_mut().unwrap()
    }

    fn left(&self) -> &Option<Box<Node>> {
        &self.as_ref().unwrap().left
    }

    fn right(&self) -> &Option<Box<Node>> {
        &self.as_ref().unwrap().right
    }

    fn set_color(&mut self, color: Color) {
        self.as_mut().unwrap().color = color;
    }

    fn is_bst(&self, min: Option<i32>, max: Option<i32>) -> bool {
        match *self {
            None => true,
            Some(ref node) => {
                if min.is_some() && node.key.cmp(&min.unwrap()) != Ordering::Greater {
                    return false;
                }
                if max.is_some() && node.key.cmp(&max.unwrap()) != Ordering::Less {
                    return false;
                }
                node.left.is_bst(min, Some(node.key)) && node.right.is_bst(Some(node.key), max)
            }
        }
    }

    fn is_23(&self, root: bool) -> bool {
        match *self {
            None => true,
            Some(ref node) => {
                if node.right.is_red() {
                    return false;
                }
                if !root && node.is_red() && node.left.is_red() {
                    return false;
                }
                node.left.is_23(false) && node.right.is_23(false)
            }
        }
    }

    fn is_balanced(&self, mut black: i32) -> bool {
        match *self {
            None => black == 0,
            Some(ref node) => {
                if !node.is_red() {
                    black -= 1;
                }
                node.left.is_balanced(black) && node.right.is_balanced(black)
            }
        }
    }
}

impl<'a> fmt::Display for Link<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let Link(ref link) = *self;
        match *link {
            &None => write!(f, "nil"),
            &Some(ref node) => {
                write!(f,
                       "({} {} {})",
                       node.key,
                       Link(&node.left),
                       Link(&node.right))
            }
        }
    }
}

impl<'a> fmt::Debug for Link<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let Link(ref link) = *self;
        match *link {
            &None => write!(f, "nil"),
            &Some(ref node) => {
                write!(f,
                       "({},{},{} {:?} {:?})",
                       node.key,
                       node.val,
                       node.color,
                       Link(&node.left),
                       Link(&node.right))
            }
        }
    }
}

impl Color {
    fn flip(&mut self) {
        match *self {
            Color::Red => *self = Color::Black,
            Color::Black => *self = Color::Red,
        }
    }
}

impl fmt::Display for Color {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Color::Red => write!(f, "red"),
            Color::Black => write!(f, "black"),
        }
    }
}

fn new_leaf(key: i32, val: i32) -> Option<Box<Node>> {
    Some(Box::new(Node::new(key, val)))
}

#[test]
fn basic_construction() {
    let mut tree = LLRBTree::new();
    assert_eq!(tree.get(0), None);
    assert_eq!(tree.insert(0, 1), None);
    assert_eq!(tree.insert(0, 2), Some(1));
    assert_eq!(tree.get(0), Some(2));
}

#[test]
fn insert_sequence() {
    let mut tree = LLRBTree::new();
    for i in 0..256 {
        assert_eq!(tree.insert(i, i), None);
    }
    for i in 0..256 {
        assert_eq!(tree.get(i), Some(i));
    }
}

#[test]
fn remove_min() {
    let mut tree = LLRBTree::new();
    for i in 0..256 {
        assert_eq!(tree.insert(i, i), None);
    }
    for i in 0..256 {
        assert_eq!(tree.remove_min(), Some(i));
    }
    assert_eq!(tree.remove_min(), None);
}
<commit_msg>Remove unnecessary trait.<commit_after>//! A naive implementation of left-leaning red-black trees
//! that are isomorphic to 2-3 trees. This implementation
//! borrows heavily from https://www.cs.princeton.edu/~rs/talks/LLRB/LLRB.pdf
//! and https://github.com/rcatolino/rbtree-rust.
//! Debug assertions borrow heavily from the implementations
//! at http://algs4.cs.princeton.edu/33balanced.

// I have spent a lot of hours trying all possible ways to
// implement this data structure. Most of the attemps
// led to confusing compilation errors. The heart of the
// issue is how to represent the Option<Box<Node>>.

// I tried using the newtype pattern
// https://doc.rust-lang.org/book/structs.html#tuple-structs.
// I (and others) had difficulty writing the
// destructuring lets correctly. See
// https://www.reddit.com/r/rust/comments/2cmjfn/how_to_do_typedefsnewtypes

// I tried creating a struct with a single field
// but had trouble accessing the field correctly
// ("let", "let ref", "let mut", "let ref mut").
// In addition the dummy field obfuscated the implementation.

// I tried using a type alias but then it's not
// possible to implement Display and Debug.

// Eventually I settled on using no abstraction for
// Option<Box<Node>>. The implementation became
// much easier to write.

// Also the implementation became much easier after I
// saw from rcatolino that some methods should be defined
// on a trait that wraps Box<Node> and other method
// should be defined on a trait that wraps Option<Box<Node>>.

use std::cmp::Ordering;
use std::fmt;
use std::mem;

#[derive(PartialEq, Eq, Copy, Clone)]
enum Color {
    Red,
    Black,
}

// This instance of the newtype pattern
// https://doc.rust-lang.org/book/structs.html#tuple-structs
// is used only for fmt::Display and fmt::Debug.
struct Link<'a>(&'a Option<Box<Node>>);

pub struct LLRBTree {
    root: Option<Box<Node>>,
}

struct Node {
    key: i32,
    val: i32,
    color: Color,
    left: Option<Box<Node>>,
    right: Option<Box<Node>>,
}

impl LLRBTree {
    pub fn new() -> Self {
        LLRBTree { root: None }
    }

    pub fn get(&self, key: i32) -> Option<i32> {
        self.root.get(key)
    }

    pub fn insert(&mut self, key: i32, value: i32) -> Option<i32> {
        let prev = self.root.insert(key, value);
        self.root.set_color(Color::Black);
        debug_assert!(self.check());
        prev
    }

    pub fn remove_min(&mut self) -> Option<i32> {
        if self.root.is_none() {
            None
        } else {
            if !self.root.left().is_red() && !self.root.right().is_red() {
                self.root.set_color(Color::Red);
            }
            let min = self.root.remove_min();
            if self.root.is_some() {
                self.root.set_color(Color::Black);
            }
            debug_assert!(self.check());
            min
        }
    }

    fn is_bst(&self) -> bool {
        self.root.is_bst(None, None)
    }

    fn is_23(&self) -> bool {
        self.root.is_23(true)
    }

    fn is_balanced(&self) -> bool {
        let mut black = 0;
        let mut next = &self.root;
        loop {
            match next {
                &None => break,
                &Some(ref node) => {
                    if !node.is_red() {
                        black += 1;
                    }
                    next = &node.left;
                }
            }
        }
        self.root.is_balanced(black)
    }

    fn check(&self) -> bool {
        debug_assert!(self.is_bst(), "Not a binary search tree");
        debug_assert!(self.is_23(), "Not a 2-3 tree");
        debug_assert!(self.is_balanced(), "Not balanced");
        true
    }
}

impl fmt::Display for LLRBTree {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", Link(&self.root))
    }
}

impl fmt::Debug for LLRBTree {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", Link(&self.root))
    }
}

impl Node {
    fn new(key: i32, val: i32) -> Self {
        Node {
            key: key,
            val: val,
            color: Color::Red,
            left: None,
            right: None,
        }
    }
}

impl Node {
    fn is_red(&self) -> bool {
        self.color == Color::Red
    }

    fn left_rotate(&mut self) {
        debug_assert!(self.right.is_red());
        let mut child = self.right.take().unwrap();
        mem::swap(self, &mut child);
        mem::swap(&mut child.right, &mut self.left);
        self.color = child.color;
        child.color = Color::Red;
        self.left = Some(child);
    }

    fn right_rotate(&mut self) {
        debug_assert!(self.left.is_red());
        let mut child = self.left.take().unwrap();
        mem::swap(self, &mut child);
        mem::swap(&mut child.left, &mut self.right);
        self.color = child.color;
        child.color = Color::Red;
        self.right = Some(child);
    }

    fn flip_colors(&mut self) {
        debug_assert!(self.left.is_some());
        debug_assert!(self.right.is_some());
        debug_assert!(self.color != self.left.color());
        debug_assert!(self.color != self.right.color());
        self.color.flip();
        self.left.mutate().color.flip();
        self.right.mutate().color.flip();
    }

    // Assuming that self is red and both self.left and self.left.left
    // are black, make self.left or one of its children red.
    fn move_red_to_left(&mut self) {
        debug_assert!(self.is_red());
        debug_assert!(!self.left.is_red());
        debug_assert!(!self.left.left().is_red());
        self.flip_colors();
        if self.right.left().is_red() {
            self.right.mutate().right_rotate();
            self.left_rotate();
            self.flip_colors();
        }
    }

    // Assuming that self is red and both self.right and self.right.left
    // are black, make self.right or one of its children red.
    fn move_red_to_right(&mut self) {
        debug_assert!(self.is_red());
        debug_assert!(!self.right.is_red());
        debug_assert!(!self.right.left().is_red());
        self.flip_colors();
        if self.left.left().is_red() {
            self.right_rotate();
            self.flip_colors();
        }
    }

    fn post_insert_balance(&mut self) {
        if !self.left.is_red() && self.right.is_red() {
            self.left_rotate();
        }
        if self.left.is_red() && self.left.left().is_red() {
            self.right_rotate();
        }
        if self.left.is_red() && self.right.is_red() {
            self.flip_colors();
        }
    }

    fn post_remove_balance(&mut self) {
        if self.right.is_red() {
            self.left_rotate();
        }
        if self.left.is_red() && self.left.left().is_red() {
            self.right_rotate();
        }
        if self.left.is_red() && self.right.is_red() {
            self.flip_colors();
        }
    }
}

trait OptionBoxNode {
    fn get(&self, key: i32) -> Option<i32>;
    fn is_red(&self) -> bool;
    fn color(&self) -> Color;
    fn insert(&mut self, key: i32, val: i32) -> Option<i32>;
    fn reference(&self) -> &Box<Node>;
    fn mutate(&mut self) -> &mut Box<Node>;
    fn left(&self) -> &Option<Box<Node>>;
    fn right(&self) -> &Option<Box<Node>>;
    fn set_color(&mut self, color: Color);
    fn remove_min(&mut self) -> Option<i32>;
    fn is_bst(&self, min: Option<i32>, max: Option<i32>) -> bool;
    fn is_23(&self, root: bool) -> bool;
    fn is_balanced(&self, black: i32) -> bool;
}

impl OptionBoxNode for Option<Box<Node>> {
    fn get(&self, key: i32) -> Option<i32> {
        match *self {
            None => None,
            Some(ref node) => {
                match key.cmp(&node.key) {
                    Ordering::Equal => Some(node.val),
                    Ordering::Less => node.left.get(key),
                    Ordering::Greater => node.right.get(key),
                }
            }
        }
    }

    fn is_red(&self) -> bool {
        match *self {
            None => false,
            Some(ref node) => node.is_red(),
        }
    }

    fn color(&self) -> Color {
        self.as_ref().unwrap().color
    }

    fn insert(&mut self, key: i32, value: i32) -> Option<i32> {
        let prev = match *self {
            None => {
                *self = new_leaf(key, value);
                None
            }
            Some(ref mut node) => {
                match key.cmp(&node.key) {
                    Ordering::Equal => {
                        let prev = node.val;
                        node.val = value;
                        Some(prev)
                    }
                    Ordering::Less => node.left.insert(key, value),
                    Ordering::Greater => node.right.insert(key, value),
                }
            }
        };
        self.mutate().post_insert_balance();
        prev
    }

    fn remove_min(&mut self) -> Option<i32> {
        if self.is_none() {
            None
        } else if self.reference().left.is_none() {
            Some(self.take().unwrap().key)
        } else {
            let node = self.mutate();
            if !node.left.is_red() && !node.left.left().is_red() {
                node.move_red_to_left();
            }
            let min = node.left.remove_min();
            node.post_remove_balance();
            min
        }
    }

    fn reference(&self) -> &Box<Node> {
        self.as_ref().unwrap()
    }

    fn mutate(&mut self) -> &mut Box<Node> {
        self.as_mut().unwrap()
    }

    fn left(&self) -> &Option<Box<Node>> {
        &self.as_ref().unwrap().left
    }

    fn right(&self) -> &Option<Box<Node>> {
        &self.as_ref().unwrap().right
    }

    fn set_color(&mut self, color: Color) {
        self.as_mut().unwrap().color = color;
    }

    fn is_bst(&self, min: Option<i32>, max: Option<i32>) -> bool {
        match *self {
            None => true,
            Some(ref node) => {
                if min.is_some() && node.key.cmp(&min.unwrap()) != Ordering::Greater {
                    return false;
                }
                if max.is_some() && node.key.cmp(&max.unwrap()) != Ordering::Less {
                    return false;
                }
                node.left.is_bst(min, Some(node.key)) && node.right.is_bst(Some(node.key), max)
            }
        }
    }

    fn is_23(&self, root: bool) -> bool {
        match *self {
            None => true,
            Some(ref node) => {
                if node.right.is_red() {
                    return false;
                }
                if !root && node.is_red() && node.left.is_red() {
                    return false;
                }
                node.left.is_23(false) && node.right.is_23(false)
            }
        }
    }

    fn is_balanced(&self, mut black: i32) -> bool {
        match *self {
            None => black == 0,
            Some(ref node) => {
                if !node.is_red() {
                    black -= 1;
                }
                node.left.is_balanced(black) && node.right.is_balanced(black)
            }
        }
    }
}

impl<'a> fmt::Display for Link<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let Link(ref link) = *self;
        match *link {
            &None => write!(f, "nil"),
            &Some(ref node) => {
                write!(f,
                       "({} {} {})",
                       node.key,
                       Link(&node.left),
                       Link(&node.right))
            }
        }
    }
}

impl<'a> fmt::Debug for Link<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let Link(ref link) = *self;
        match *link {
            &None => write!(f, "nil"),
            &Some(ref node) => {
                write!(f,
                       "({},{},{} {:?} {:?})",
                       node.key,
                       node.val,
                       node.color,
                       Link(&node.left),
                       Link(&node.right))
            }
        }
    }
}

impl Color {
    fn flip(&mut self) {
        match *self {
            Color::Red => *self = Color::Black,
            Color::Black => *self = Color::Red,
        }
    }
}

impl fmt::Display for Color {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Color::Red => write!(f, "red"),
            Color::Black => write!(f, "black"),
        }
    }
}

fn new_leaf(key: i32, val: i32) -> Option<Box<Node>> {
    Some(Box::new(Node::new(key, val)))
}

#[test]
fn basic_construction() {
    let mut tree = LLRBTree::new();
    assert_eq!(tree.get(0), None);
    assert_eq!(tree.insert(0, 1), None);
    assert_eq!(tree.insert(0, 2), Some(1));
    assert_eq!(tree.get(0), Some(2));
}

#[test]
fn insert_sequence() {
    let mut tree = LLRBTree::new();
    for i in 0..256 {
        assert_eq!(tree.insert(i, i), None);
    }
    for i in 0..256 {
        assert_eq!(tree.get(i), Some(i));
    }
}

#[test]
fn remove_min() {
    let mut tree = LLRBTree::new();
    for i in 0..256 {
        assert_eq!(tree.insert(i, i), None);
    }
    for i in 0..256 {
        assert_eq!(tree.remove_min(), Some(i));
    }
    assert_eq!(tree.remove_min(), None);
}
<|endoftext|>


<commit_before>#![feature(lang_items)]
#![feature(asm)]
#![feature(const_fn)]
#![feature(unique)]
#![feature(alloc)]
#![no_std]

#[macro_use]
extern crate system;
extern crate spin;
extern crate selfalloc;
extern crate alloc;

#[macro_use]
mod vga_buffer;

use core::ops::{Deref};
use system::{CAddr, ChannelMessage};

/// Decode a code in the PS/2 scan code set 1 (legacy set).
///
/// Difference between set 1 and sets 2 & 3:
///   http://wiki.osdev.org/%228042%22_PS/2_Controller#Translation
///
/// Reference table:
///   http://www.computer-engineering.org/ps2keyboard/scancodes1.html
pub fn from_scancode_printable(code: usize) -> Option<char> {
    let printable = match code {
        0x1e => 'a',
        0x30 => 'b',
        0x2e => 'c',
        0x20 => 'd',
        0x12 => 'e',
        0x21 => 'f',
        0x22 => 'g',
        0x23 => 'h',
        0x17 => 'i',
        0x24 => 'j',
        0x25 => 'k',
        0x26 => 'l',
        0x32 => 'm',
        0x31 => 'n',
        0x18 => 'o',
        0x19 => 'p',
        0x10 => 'q',
        0x13 => 'r',
        0x1f => 's',
        0x14 => 't',
        0x16 => 'u',
        0x2f => 'v',
        0x11 => 'w',
        0x2d => 'x',
        0x15 => 'y',
        0x2c => 'z',
        0x0b => '0',
        0x02 => '1',
        0x03 => '2',
        0x04 => '3',
        0x05 => '4',
        0x06 => '5',
        0x07 => '6',
        0x08 => '7',
        0x09 => '8',
        0x0a => '9',
        0x29 => '`',
        0x0c => '-',
        0x0d => '=',
        0x2b => '\\',
        0x39 => ' ',
        0x1a => '[',
        0x1b => ']',
        0x27 => ';',
        0x28 => '\'',
        0x33 => ',',
        0x34 => '.',
        0x35 => '/',
        0x37 => '*', // Keypad
        0x4a => '-', // Keypad
        0x4e => '+', // Keypad
        _ => return None,
    };

    Some(printable)
}

pub fn from_scancode(code: usize) -> Key {
    if code == 0x1C {
        Key::Enter
    } else {
        let printable = from_scancode_printable(code);
        if printable.is_some() {
            Key::Printable(printable.unwrap())
        } else {
            Key::Nonprintable
        }
    }
}

#[derive(Eq, PartialEq, Clone)]
pub enum Key {
    Printable(char),
    Enter,
    Nonprintable
}

static mut IS_PARENT: bool = true;

#[lang="start"]
#[no_mangle]
fn start(_argc: isize, _argv: *const *const u8) {
    if unsafe { IS_PARENT } {
        unsafe { IS_PARENT = false; }
        parent_main();
    } else {
        child_main();
    }
    loop {};
}

fn parent_main() {
    unsafe { selfalloc::setup_allocator(CAddr::from(2), CAddr::from(3), 0x1000000000); }
    unsafe { system::set_task_buffer_addr(0x90001000); }

    // Test allocator
    {
        use alloc::boxed::Box;
        let heap_test = Box::new(42);
    }

    system_print!("parent rinit started.");
    system_print!("parent stack addr: 0x{:x}.",
                  system::task_buffer_addr() as usize);
    print!("Child entry should be at: 0x{:x} ({})\nChild stack pointer should be at: 0x{:x} ({})\n",
           start as *const () as usize, start as *const () as usize,
           0x70000000 + (0x1000 * 4 - 4), 0x70000000 + (0x1000 * 4 - 4));
    print!(">>> ");
    let mut lastkey = Key::Nonprintable;
    let mut command = [0u8; 32];
    let mut command_size = 0;
    while true {
        let key = from_scancode(system::channel_take_raw(CAddr::from(254)) as usize);
        if key == lastkey {
            continue;
        } else {
            lastkey = key.clone();
        }
        match key {
            Key::Printable(c) => {
                print!("{}", c);
                if command_size < 32 {
                    command[command_size] = c as u8;
                    command_size += 1;
                }
            }
            Key::Enter => {
                print!("\n");
                execute_command(::core::str::from_utf8(&command[0..command_size]).unwrap());
                command = [0u8; 32];
                command_size = 0;
            }
            _ => (),
        }
    }
}

fn start_child() {
    system::retype_task(CAddr::from(2), CAddr::from(249));
    system::task_set_stack_pointer(CAddr::from(249), 0x70000000 + (0x1000 * 4 - 4));
    system::task_set_instruction_pointer(CAddr::from(249), start as *const () as u64);
    system::task_set_cpool(CAddr::from(249), CAddr::from(0));
    system::task_set_top_page_table(CAddr::from(249), CAddr::from(3));
    system::task_set_buffer(CAddr::from(249), CAddr::from(250));
    system::task_set_active(CAddr::from(249));
}

fn child_main() {
    unsafe { system::set_task_buffer_addr(0x90003000); }

    system_print!("child rinit started.");
    system_print!("parent stack addr: 0x{:x}.",
                  system::task_buffer_addr() as usize);
    while true {
        let value: u64 = system::channel_take(CAddr::from(255));
        system_print!("Received from master: {:?}", value);
    }
}

fn parse_usize(s: &str, prefix: &str) -> Option<(usize, usize)> {
    if s.len() >= prefix.len() + 4 && &s[0..prefix.len()] == prefix {
        let st = &s[(prefix.len()+1)..s.len()];
        let mut split = st.split(' ');
        let o1: usize = split.next().unwrap().parse().unwrap();
        let o2: usize = split.next().unwrap().parse().unwrap();
        return Some((o1, o2));
    } else {
        return None;
    }
}

fn execute_command(s: &str) {
    if s == "list" {
        print!("Listing task cpool ...\n");
        system::cpool_list_debug();
    } else if s == "start child" {
        start_child();
        print!("Child started.\n");
    } else if s.len() >= 6 && &s[0..4] == "echo" {
        print!("{}\n", &s[5..s.len()]);
    } else if s.len() >= 6 && &s[0..8] == "send raw" {
        let value: u64 = (&s[9..s.len()]).parse().unwrap();
        system::channel_put(CAddr::from(255), value);
        print!("Sent raw to child through channel 255\n");
    } else if s.len() >= 6 && &s[0..8] == "send cap" {
        let value: u64 = (&s[9..s.len()]).parse().unwrap();
        system::channel_put_cap(CAddr::from(255), CAddr::from(value as u8));
        print!("Sent cap to child through channel 255\n");
    } else if let Some((source, target)) = parse_usize(s, "retype cpool") {
        system::retype_cpool(CAddr::from(source as u8), CAddr::from(target as u8));
        print!("Operation finished.\n");
    } else if let Some((source, target)) = parse_usize(s, "retype task") {
        system::retype_task(CAddr::from(source as u8), CAddr::from(target as u8));
        print!("Operation finished.\n");
    } else if let Some((target, ptr)) = parse_usize(s, "set stack") {
        system::task_set_stack_pointer(CAddr::from(target as u8), ptr as u64);
        print!("Operation finished.\n");
    } else if let Some((target, ptr)) = parse_usize(s, "set instruction") {
        system::task_set_instruction_pointer(CAddr::from(target as u8), ptr as u64);
        print!("Operation finished.\n");
    } else if let Some((target, cpool)) = parse_usize(s, "set cpool") {
        system::task_set_cpool(CAddr::from(target as u8), CAddr::from(cpool as u8));
        print!("Operation finished.\n");
    } else if let Some((target, table)) = parse_usize(s, "set table") {
        system::task_set_top_page_table(CAddr::from(target as u8), CAddr::from(table as u8));
        print!("Operation finished.\n");
    } else if let Some((target, buffer)) = parse_usize(s, "set buffer") {
        system::task_set_buffer(CAddr::from(target as u8), CAddr::from(buffer as u8));
        print!("Operation finished.\n");
    } else if let Some((target, status)) = parse_usize(s, "set active") {
        if status == 0 {
            system::task_set_inactive(CAddr::from(target as u8));
        } else {
            system::task_set_active(CAddr::from(target as u8));
        }
        print!("Operation finished.\n");
    } else {
        print!("Unknown command.\n");
    }
    print!(">>> ");
}

fn divide_by_zero() {
    unsafe {
        asm!("mov dx, 0; div dx" ::: "ax", "dx" : "volatile", "intel")
    }
}
<commit_msg>Add debug message for heap testing<commit_after>#![feature(lang_items)]
#![feature(asm)]
#![feature(const_fn)]
#![feature(unique)]
#![feature(alloc)]
#![no_std]

#[macro_use]
extern crate system;
extern crate spin;
extern crate selfalloc;
extern crate alloc;

#[macro_use]
mod vga_buffer;

use core::ops::{Deref};
use system::{CAddr, ChannelMessage};

/// Decode a code in the PS/2 scan code set 1 (legacy set).
///
/// Difference between set 1 and sets 2 & 3:
///   http://wiki.osdev.org/%228042%22_PS/2_Controller#Translation
///
/// Reference table:
///   http://www.computer-engineering.org/ps2keyboard/scancodes1.html
pub fn from_scancode_printable(code: usize) -> Option<char> {
    let printable = match code {
        0x1e => 'a',
        0x30 => 'b',
        0x2e => 'c',
        0x20 => 'd',
        0x12 => 'e',
        0x21 => 'f',
        0x22 => 'g',
        0x23 => 'h',
        0x17 => 'i',
        0x24 => 'j',
        0x25 => 'k',
        0x26 => 'l',
        0x32 => 'm',
        0x31 => 'n',
        0x18 => 'o',
        0x19 => 'p',
        0x10 => 'q',
        0x13 => 'r',
        0x1f => 's',
        0x14 => 't',
        0x16 => 'u',
        0x2f => 'v',
        0x11 => 'w',
        0x2d => 'x',
        0x15 => 'y',
        0x2c => 'z',
        0x0b => '0',
        0x02 => '1',
        0x03 => '2',
        0x04 => '3',
        0x05 => '4',
        0x06 => '5',
        0x07 => '6',
        0x08 => '7',
        0x09 => '8',
        0x0a => '9',
        0x29 => '`',
        0x0c => '-',
        0x0d => '=',
        0x2b => '\\',
        0x39 => ' ',
        0x1a => '[',
        0x1b => ']',
        0x27 => ';',
        0x28 => '\'',
        0x33 => ',',
        0x34 => '.',
        0x35 => '/',
        0x37 => '*', // Keypad
        0x4a => '-', // Keypad
        0x4e => '+', // Keypad
        _ => return None,
    };

    Some(printable)
}

pub fn from_scancode(code: usize) -> Key {
    if code == 0x1C {
        Key::Enter
    } else {
        let printable = from_scancode_printable(code);
        if printable.is_some() {
            Key::Printable(printable.unwrap())
        } else {
            Key::Nonprintable
        }
    }
}

#[derive(Eq, PartialEq, Clone)]
pub enum Key {
    Printable(char),
    Enter,
    Nonprintable
}

static mut IS_PARENT: bool = true;

#[lang="start"]
#[no_mangle]
fn start(_argc: isize, _argv: *const *const u8) {
    if unsafe { IS_PARENT } {
        unsafe { IS_PARENT = false; }
        parent_main();
    } else {
        child_main();
    }
    loop {};
}

fn parent_main() {
    unsafe { system::set_task_buffer_addr(0x90001000); }
    system_print!("parent rinit started.");

    // Test allocator
    unsafe { selfalloc::setup_allocator(CAddr::from(2), CAddr::from(3), 0x1000000000); }
    {
        use alloc::boxed::Box;
        let heap_test = Box::new(42);
        system_print!("testing heap: {:?}", heap_test);
    }

    system_print!("parent stack addr: 0x{:x}.",
                  system::task_buffer_addr() as usize);
    print!("Child entry should be at: 0x{:x} ({})\nChild stack pointer should be at: 0x{:x} ({})\n",
           start as *const () as usize, start as *const () as usize,
           0x70000000 + (0x1000 * 4 - 4), 0x70000000 + (0x1000 * 4 - 4));
    print!(">>> ");
    let mut lastkey = Key::Nonprintable;
    let mut command = [0u8; 32];
    let mut command_size = 0;
    while true {
        let key = from_scancode(system::channel_take_raw(CAddr::from(254)) as usize);
        if key == lastkey {
            continue;
        } else {
            lastkey = key.clone();
        }
        match key {
            Key::Printable(c) => {
                print!("{}", c);
                if command_size < 32 {
                    command[command_size] = c as u8;
                    command_size += 1;
                }
            }
            Key::Enter => {
                print!("\n");
                execute_command(::core::str::from_utf8(&command[0..command_size]).unwrap());
                command = [0u8; 32];
                command_size = 0;
            }
            _ => (),
        }
    }
}

fn start_child() {
    system::retype_task(CAddr::from(2), CAddr::from(249));
    system::task_set_stack_pointer(CAddr::from(249), 0x70000000 + (0x1000 * 4 - 4));
    system::task_set_instruction_pointer(CAddr::from(249), start as *const () as u64);
    system::task_set_cpool(CAddr::from(249), CAddr::from(0));
    system::task_set_top_page_table(CAddr::from(249), CAddr::from(3));
    system::task_set_buffer(CAddr::from(249), CAddr::from(250));
    system::task_set_active(CAddr::from(249));
}

fn child_main() {
    unsafe { system::set_task_buffer_addr(0x90003000); }

    system_print!("child rinit started.");
    system_print!("parent stack addr: 0x{:x}.",
                  system::task_buffer_addr() as usize);
    while true {
        let value: u64 = system::channel_take(CAddr::from(255));
        system_print!("Received from master: {:?}", value);
    }
}

fn parse_usize(s: &str, prefix: &str) -> Option<(usize, usize)> {
    if s.len() >= prefix.len() + 4 && &s[0..prefix.len()] == prefix {
        let st = &s[(prefix.len()+1)..s.len()];
        let mut split = st.split(' ');
        let o1: usize = split.next().unwrap().parse().unwrap();
        let o2: usize = split.next().unwrap().parse().unwrap();
        return Some((o1, o2));
    } else {
        return None;
    }
}

fn execute_command(s: &str) {
    if s == "list" {
        print!("Listing task cpool ...\n");
        system::cpool_list_debug();
    } else if s == "start child" {
        start_child();
        print!("Child started.\n");
    } else if s.len() >= 6 && &s[0..4] == "echo" {
        print!("{}\n", &s[5..s.len()]);
    } else if s.len() >= 6 && &s[0..8] == "send raw" {
        let value: u64 = (&s[9..s.len()]).parse().unwrap();
        system::channel_put(CAddr::from(255), value);
        print!("Sent raw to child through channel 255\n");
    } else if s.len() >= 6 && &s[0..8] == "send cap" {
        let value: u64 = (&s[9..s.len()]).parse().unwrap();
        system::channel_put_cap(CAddr::from(255), CAddr::from(value as u8));
        print!("Sent cap to child through channel 255\n");
    } else if let Some((source, target)) = parse_usize(s, "retype cpool") {
        system::retype_cpool(CAddr::from(source as u8), CAddr::from(target as u8));
        print!("Operation finished.\n");
    } else if let Some((source, target)) = parse_usize(s, "retype task") {
        system::retype_task(CAddr::from(source as u8), CAddr::from(target as u8));
        print!("Operation finished.\n");
    } else if let Some((target, ptr)) = parse_usize(s, "set stack") {
        system::task_set_stack_pointer(CAddr::from(target as u8), ptr as u64);
        print!("Operation finished.\n");
    } else if let Some((target, ptr)) = parse_usize(s, "set instruction") {
        system::task_set_instruction_pointer(CAddr::from(target as u8), ptr as u64);
        print!("Operation finished.\n");
    } else if let Some((target, cpool)) = parse_usize(s, "set cpool") {
        system::task_set_cpool(CAddr::from(target as u8), CAddr::from(cpool as u8));
        print!("Operation finished.\n");
    } else if let Some((target, table)) = parse_usize(s, "set table") {
        system::task_set_top_page_table(CAddr::from(target as u8), CAddr::from(table as u8));
        print!("Operation finished.\n");
    } else if let Some((target, buffer)) = parse_usize(s, "set buffer") {
        system::task_set_buffer(CAddr::from(target as u8), CAddr::from(buffer as u8));
        print!("Operation finished.\n");
    } else if let Some((target, status)) = parse_usize(s, "set active") {
        if status == 0 {
            system::task_set_inactive(CAddr::from(target as u8));
        } else {
            system::task_set_active(CAddr::from(target as u8));
        }
        print!("Operation finished.\n");
    } else {
        print!("Unknown command.\n");
    }
    print!(">>> ");
}

fn divide_by_zero() {
    unsafe {
        asm!("mov dx, 0; div dx" ::: "ax", "dx" : "volatile", "intel")
    }
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::path::PathBuf;
use std::fmt::{Debug, Formatter, Error as FmtError};
use std::result::Result as RResult;

use toml::Value;

use libimagerror::trace::trace_error;
use libimagstore::storeid::StoreId;
use libimagstore::hook::Hook;
use libimagstore::hook::result::HookResult;
use libimagstore::hook::accessor::{HookDataAccessor, HookDataAccessorProvider};
use libimagstore::hook::accessor::StoreIdAccessor;
use libimagutil::debug_result::*;

use vcs::git::error::GitHookErrorKind as GHEK;
use vcs::git::error::MapErrInto;
use vcs::git::runtime::Runtime as GRuntime;

pub struct StoreUnloadHook {
    storepath: PathBuf,

    runtime: GRuntime,
}

impl StoreUnloadHook {

    pub fn new(storepath: PathBuf) -> StoreUnloadHook {
        StoreUnloadHook {
            runtime: GRuntime::new(&storepath),
            storepath: storepath,
        }
    }

}

impl Debug for StoreUnloadHook {
    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        write!(fmt, "StoreUnloadHook(storepath={:?}, repository={}, cfg={:?})",
               self.storepath,
               (if self.runtime.has_repository() { "Some(_)" } else { "None" }),
               self.runtime.has_config())
    }
}

impl Hook for StoreUnloadHook {

    fn name(&self) -> &'static str {
        "stdhook_git_storeunload"
    }

    /// Set the configuration of the hook. See
    /// `libimagstorestdhook::vcs::git::runtime::Runtime::set_config()`.
    ///
    /// This function traces the error (using `trace_error()`) that
    /// `libimagstorestdhook::vcs::git::runtime::Runtime::set_config()`
    /// returns, if any.
    fn set_config(&mut self, config: &Value) {
        if let Err(e) = self.runtime.set_config(config) {
            trace_error(&e);
        }
    }

}

impl HookDataAccessorProvider for StoreUnloadHook {

    fn accessor(&self) -> HookDataAccessor {
        HookDataAccessor::StoreIdAccess(self)
    }
}

impl StoreIdAccessor for StoreUnloadHook {

    fn access(&self, id: &StoreId) -> HookResult<()> {
        use libimagerror::into::IntoError;
        use vcs::git::action::StoreAction;
        use vcs::git::config::commit_message;
        use vcs::git::error::MapIntoHookError;
        use vcs::git::util::fetch_index;
        use vcs::git::config::abort_on_repo_init_err;
        use vcs::git::config::is_enabled;
        use vcs::git::config::committing_is_enabled;
        use vcs::git::config::add_wt_changes_before_committing;

        use git2::StatusOptions;
        use git2::StatusShow;
        use git2::{STATUS_INDEX_NEW,
                   STATUS_INDEX_DELETED,
                   STATUS_INDEX_RENAMED,
                   STATUS_INDEX_MODIFIED};
        use git2::{STATUS_WT_NEW,
                   STATUS_WT_DELETED,
                   STATUS_WT_RENAMED,
                   STATUS_WT_MODIFIED};
        use git2::ADD_DEFAULT;

        let action = StoreAction::StoreUnload;
        let cfg    = try!(self.runtime.config_value_or_err(&action));

        if !is_enabled(cfg) {
            return Ok(())
        }

        if !self.runtime.has_repository() {
            debug!("[GIT STORE UNLOAD HOOK]: Runtime has no repository...");
            if try!(self.runtime.config_value_or_err(&action).map(|c| abort_on_repo_init_err(c))) {
                // Abort on repo init failure
                debug!("[GIT STORE UNLOAD HOOK]: Config says we should abort if we have no repository");
                debug!("[GIT STORE UNLOAD HOOK]: Returing Err(_)");
                return Err(GHEK::RepositoryInitError.into_error())
                    .map_err_into(GHEK::RepositoryError)
                    .map_into_hook_error()
            } else {
                debug!("[GIT STORE UNLOAD HOOK]: Config says it is okay to not have a repository");
                debug!("[GIT STORE UNLOAD HOOK]: Returing Ok(())");
                return Ok(())
            }
        }

        let _         = try!(self.runtime.ensure_cfg_branch_is_checked_out(&action));
        let repo      = try!(self.runtime.repository(&action));
        let mut index = try!(fetch_index(repo, &action));

        let mut status_options = StatusOptions::new();
        status_options.show(StatusShow::Workdir);
        status_options.include_untracked(true);
        let wt_dirty = try!(repo.statuses(Some(&mut status_options)).map(|statuses| {
            statuses.iter()
                .map(|s| s.status())
                .map(|s| {
                    debug!("STATUS_WT_NEW = {}", s == STATUS_WT_NEW);
                    debug!("STATUS_WT_MODIFIED = {}", s == STATUS_WT_MODIFIED);
                    debug!("STATUS_WT_DELETED = {}", s == STATUS_WT_DELETED);
                    debug!("STATUS_WT_RENAMED = {}", s == STATUS_WT_RENAMED);
                    s
                })
                .any(|s| s == STATUS_WT_NEW || s == STATUS_WT_MODIFIED || s == STATUS_WT_DELETED || s == STATUS_WT_RENAMED)
        }).map_err_into(GHEK::RepositoryError).map_into_hook_error());

        if wt_dirty {
            if add_wt_changes_before_committing(cfg) {
                debug!("Adding WT changes before committing.");
                try!(index.add_all(&["*"], ADD_DEFAULT, None)
                    .map_err_into(GHEK::RepositoryError)
                    .map_into_hook_error());
            } else {
                warn!("WT dirty, but adding files before committing on Drop disabled.");
                warn!("Continuing without adding changes to the index.");
            }
        } else {
            debug!("WT not dirty.");
        }

        let mut status_options = StatusOptions::new();
        status_options.show(StatusShow::Index);
        status_options.include_untracked(true);
        let index_dirty = try!(repo.statuses(Some(&mut status_options)).map(|statuses| {
            statuses.iter()
                .map(|s| s.status())
                .map(|s| {
                    debug!("STATUS_INDEX_NEW = {}", s == STATUS_INDEX_NEW);
                    debug!("STATUS_INDEX_MODIFIED = {}", s == STATUS_INDEX_MODIFIED);
                    debug!("STATUS_INDEX_DELETED = {}", s == STATUS_INDEX_DELETED);
                    debug!("STATUS_INDEX_RENAMED = {}", s == STATUS_INDEX_RENAMED);
                    s
                })
                .any(|s| s == STATUS_INDEX_NEW || s == STATUS_INDEX_MODIFIED || s == STATUS_INDEX_DELETED || s == STATUS_INDEX_RENAMED)
        }).map_err_into(GHEK::RepositoryError).map_into_hook_error());

        if index_dirty {
            debug!("INDEX DIRTY!");
        } else {
            debug!("INDEX CLEAN... not continuing!");
            return Ok(());
        }

        let signature = try!(
            repo.signature()
                .map_err_into(GHEK::MkSignature)
                .map_dbg_err_str("Failed to fetch signature")
                .map_dbg_str("[GIT STORE UNLOAD HOOK]: Fetched signature object")
                .map_into_hook_error()
        );

        let head = try!(
            repo.head()
                .map_err_into(GHEK::HeadFetchError)
                .map_dbg_err_str("Failed to fetch HEAD")
                .map_dbg_str("[GIT STORE UNLOAD HOOK]: Fetched HEAD")
                .map_into_hook_error()
        );

        let tree_id = try!(
            index.write_tree()
                .map_err_into(GHEK::RepositoryIndexWritingError)
                .map_dbg_err_str("Failed to write tree")
                .map_dbg_str("[GIT STORE UNLOAD HOOK]: Wrote index tree")
                .map_into_hook_error()
        );

        if !try!(committing_is_enabled(cfg)) {
            debug!("Committing not enabled. This is fine, returning now...");
            return Ok(())
        }

        let mut parents = Vec::new();
        {
            let commit = try!(
                repo.find_commit(head.target().unwrap())
                    .map_err_into(GHEK::RepositoryParentFetchingError)
                    .map_dbg_err_str("Failed to find commit HEAD")
                    .map_dbg_str("[GIT STORE UNLOAD HOOK]: Found commit HEAD")
                    .map_into_hook_error()
            );
            parents.push(commit);
        }

        // for converting from Vec<Commit> to Vec<&Commit>
        let parents = parents.iter().collect::<Vec<_>>();

        let tree = try!(
            repo.find_tree(tree_id)
                .map_err_into(GHEK::RepositoryParentFetchingError)
                .map_dbg_err_str("Failed to find tree")
                .map_dbg_str("[GIT STORE UNLOAD HOOK]: Found tree for index")
                .map_into_hook_error()
        );

        let message = try!(commit_message(&repo, cfg, action, &id)
                .map_dbg_err_str("Failed to get commit message")
                .map_dbg_str("[GIT STORE UNLOAD HOOK]: Got commit message"));

        try!(repo.commit(Some("HEAD"), &signature, &signature, &message, &tree, &parents)
            .map_dbg_str("Committed")
            .map_dbg_err_str("Failed to commit")
            .map_dbg_str("[GIT STORE UNLOAD HOOK]: Committed")
            .map_err_into(GHEK::RepositoryCommittingError)
            .map_into_hook_error()
        );

        index.write()
            .map_err_into(GHEK::RepositoryIndexWritingError)
            .map_dbg_err_str("Failed to write tree")
            .map_dbg_str("[GIT STORE UNLOAD HOOK]: Wrote index")
            .map_into_hook_error()
            .map(|_| ())
    }

}

<commit_msg>Refactor codebase to be more readable<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::path::PathBuf;
use std::fmt::{Debug, Formatter, Error as FmtError};
use std::result::Result as RResult;

use toml::Value;

use libimagerror::trace::trace_error;
use libimagstore::storeid::StoreId;
use libimagstore::hook::Hook;
use libimagstore::hook::result::HookResult;
use libimagstore::hook::accessor::{HookDataAccessor, HookDataAccessorProvider};
use libimagstore::hook::accessor::StoreIdAccessor;
use libimagutil::debug_result::*;

use vcs::git::error::GitHookErrorKind as GHEK;
use vcs::git::error::MapErrInto;
use vcs::git::runtime::Runtime as GRuntime;

pub struct StoreUnloadHook {
    storepath: PathBuf,

    runtime: GRuntime,
}

impl StoreUnloadHook {

    pub fn new(storepath: PathBuf) -> StoreUnloadHook {
        StoreUnloadHook {
            runtime: GRuntime::new(&storepath),
            storepath: storepath,
        }
    }

}

impl Debug for StoreUnloadHook {
    fn fmt(&self, fmt: &mut Formatter) -> RResult<(), FmtError> {
        write!(fmt, "StoreUnloadHook(storepath={:?}, repository={}, cfg={:?})",
               self.storepath,
               (if self.runtime.has_repository() { "Some(_)" } else { "None" }),
               self.runtime.has_config())
    }
}

impl Hook for StoreUnloadHook {

    fn name(&self) -> &'static str {
        "stdhook_git_storeunload"
    }

    /// Set the configuration of the hook. See
    /// `libimagstorestdhook::vcs::git::runtime::Runtime::set_config()`.
    ///
    /// This function traces the error (using `trace_error()`) that
    /// `libimagstorestdhook::vcs::git::runtime::Runtime::set_config()`
    /// returns, if any.
    fn set_config(&mut self, config: &Value) {
        if let Err(e) = self.runtime.set_config(config) {
            trace_error(&e);
        }
    }

}

impl HookDataAccessorProvider for StoreUnloadHook {

    fn accessor(&self) -> HookDataAccessor {
        HookDataAccessor::StoreIdAccess(self)
    }
}

impl StoreIdAccessor for StoreUnloadHook {

    fn access(&self, id: &StoreId) -> HookResult<()> {
        use libimagerror::into::IntoError;
        use vcs::git::action::StoreAction;
        use vcs::git::config::commit_message;
        use vcs::git::error::MapIntoHookError;
        use vcs::git::util::fetch_index;
        use vcs::git::config::abort_on_repo_init_err;
        use vcs::git::config::is_enabled;
        use vcs::git::config::committing_is_enabled;
        use vcs::git::config::add_wt_changes_before_committing;

        use git2::{ADD_DEFAULT,
                   StatusOptions,
                   Status,
                   StatusShow as STShow,
                   STATUS_INDEX_NEW as I_NEW,
                   STATUS_INDEX_DELETED as I_DEL,
                   STATUS_INDEX_RENAMED as I_REN,
                   STATUS_INDEX_MODIFIED as I_MOD,
                   STATUS_WT_NEW as WT_NEW,
                   STATUS_WT_DELETED as WT_DEL,
                   STATUS_WT_RENAMED as WT_REN,
                   STATUS_WT_MODIFIED as WT_MOD};

        let action = StoreAction::StoreUnload;
        let cfg    = try!(self.runtime.config_value_or_err(&action));

        if !is_enabled(cfg) {
            return Ok(())
        }

        if !self.runtime.has_repository() {
            debug!("[GIT STORE UNLOAD HOOK]: Runtime has no repository...");
            if try!(self.runtime.config_value_or_err(&action).map(|c| abort_on_repo_init_err(c))) {
                // Abort on repo init failure
                debug!("[GIT STORE UNLOAD HOOK]: Config says we should abort if we have no repository");
                debug!("[GIT STORE UNLOAD HOOK]: Returing Err(_)");
                return Err(GHEK::RepositoryInitError.into_error())
                    .map_err_into(GHEK::RepositoryError)
                    .map_into_hook_error()
            } else {
                debug!("[GIT STORE UNLOAD HOOK]: Config says it is okay to not have a repository");
                debug!("[GIT STORE UNLOAD HOOK]: Returing Ok(())");
                return Ok(())
            }
        }

        let _         = try!(self.runtime.ensure_cfg_branch_is_checked_out(&action));
        let repo      = try!(self.runtime.repository(&action));
        let mut index = try!(fetch_index(repo, &action));

        let check_dirty = |show: STShow, new: Status, modif: Status, del: Status, ren: Status| {
            let mut status_options = StatusOptions::new();
            status_options.show(show);
            status_options.include_untracked(true);

            repo.statuses(Some(&mut status_options))
                .map(|statuses| {
                    statuses.iter()
                        .map(|s| s.status())
                        .map(|s| {
                            debug!("STATUS_WT_NEW = {}",        s == new);
                            debug!("STATUS_WT_MODIFIED = {}",   s == modif);
                            debug!("STATUS_WT_DELETED = {}",    s == del);
                            debug!("STATUS_WT_RENAMED = {}",    s == ren);
                            s
                        })
                        .any(|s| s == new || s == modif || s == del || s == ren)
                })
                .map_err_into(GHEK::RepositoryError)
                .map_into_hook_error()
        };

        if try!(check_dirty(STShow::Workdir, WT_NEW, WT_MOD, WT_DEL, WT_REN)) {
            if add_wt_changes_before_committing(cfg) {
                debug!("Adding WT changes before committing.");
                try!(index.add_all(&["*"], ADD_DEFAULT, None)
                    .map_err_into(GHEK::RepositoryError)
                    .map_into_hook_error());
            } else {
                warn!("WT dirty, but adding files before committing on Drop disabled.");
                warn!("Continuing without adding changes to the index.");
            }
        } else {
            debug!("WT not dirty.");
        }

        if try!(check_dirty(STShow::Index, I_NEW, I_MOD, I_DEL, I_REN)) {
            debug!("INDEX DIRTY!");
        } else {
            debug!("INDEX CLEAN... not continuing!");
            return Ok(());
        }

        let signature = try!(
            repo.signature()
                .map_err_into(GHEK::MkSignature)
                .map_dbg_err_str("Failed to fetch signature")
                .map_dbg_str("[GIT STORE UNLOAD HOOK]: Fetched signature object")
                .map_into_hook_error()
        );

        let head = try!(
            repo.head()
                .map_err_into(GHEK::HeadFetchError)
                .map_dbg_err_str("Failed to fetch HEAD")
                .map_dbg_str("[GIT STORE UNLOAD HOOK]: Fetched HEAD")
                .map_into_hook_error()
        );

        let tree_id = try!(
            index.write_tree()
                .map_err_into(GHEK::RepositoryIndexWritingError)
                .map_dbg_err_str("Failed to write tree")
                .map_dbg_str("[GIT STORE UNLOAD HOOK]: Wrote index tree")
                .map_into_hook_error()
        );

        if !try!(committing_is_enabled(cfg)) {
            debug!("Committing not enabled. This is fine, returning now...");
            return Ok(())
        }

        let mut parents = Vec::new();
        {
            let commit = try!(
                repo.find_commit(head.target().unwrap())
                    .map_err_into(GHEK::RepositoryParentFetchingError)
                    .map_dbg_err_str("Failed to find commit HEAD")
                    .map_dbg_str("[GIT STORE UNLOAD HOOK]: Found commit HEAD")
                    .map_into_hook_error()
            );
            parents.push(commit);
        }

        // for converting from Vec<Commit> to Vec<&Commit>
        let parents = parents.iter().collect::<Vec<_>>();

        let tree = try!(
            repo.find_tree(tree_id)
                .map_err_into(GHEK::RepositoryParentFetchingError)
                .map_dbg_err_str("Failed to find tree")
                .map_dbg_str("[GIT STORE UNLOAD HOOK]: Found tree for index")
                .map_into_hook_error()
        );

        let message = try!(commit_message(&repo, cfg, action, &id)
                .map_dbg_err_str("Failed to get commit message")
                .map_dbg_str("[GIT STORE UNLOAD HOOK]: Got commit message"));

        try!(repo.commit(Some("HEAD"), &signature, &signature, &message, &tree, &parents)
            .map_dbg_str("Committed")
            .map_dbg_err_str("Failed to commit")
            .map_dbg_str("[GIT STORE UNLOAD HOOK]: Committed")
            .map_err_into(GHEK::RepositoryCommittingError)
            .map_into_hook_error()
        );

        index.write()
            .map_err_into(GHEK::RepositoryIndexWritingError)
            .map_dbg_err_str("Failed to write tree")
            .map_dbg_str("[GIT STORE UNLOAD HOOK]: Wrote index")
            .map_into_hook_error()
            .map(|_| ())
    }

}

<|endoftext|>


<commit_before>use super::{RemoteService, SeriesEntry, SeriesInfo};
use crate::err::Result;

pub struct Offline {}

impl Offline {
    pub fn new() -> Offline {
        Offline {}
    }
}

impl RemoteService for Offline {
    fn search_info_by_name(&self, _: &str) -> Result<Vec<SeriesInfo>> {
        unimplemented!()
    }

    fn search_info_by_id(&self, _: u32) -> Result<SeriesInfo> {
        unimplemented!()
    }

    fn get_list_entry(&self, _: u32) -> Result<Option<SeriesEntry>> {
        Ok(None)
    }

    fn update_list_entry(&self, _: &SeriesEntry) -> Result<()> {
        Ok(())
    }

    fn is_offline(&self) -> bool {
        true
    }
}
<commit_msg>[series] Return err::RunWithPrefetch for the search functions when using the offline remote service<commit_after>use super::{RemoteService, SeriesEntry, SeriesInfo};
use crate::err::{self, Result};

pub struct Offline {}

impl Offline {
    pub fn new() -> Offline {
        Offline {}
    }
}

impl RemoteService for Offline {
    fn search_info_by_name(&self, _: &str) -> Result<Vec<SeriesInfo>> {
        Err(err::Error::RunWithPrefetch {})
    }

    fn search_info_by_id(&self, _: u32) -> Result<SeriesInfo> {
        Err(err::Error::RunWithPrefetch {})
    }

    fn get_list_entry(&self, _: u32) -> Result<Option<SeriesEntry>> {
        Ok(None)
    }

    fn update_list_entry(&self, _: &SeriesEntry) -> Result<()> {
        Ok(())
    }

    fn is_offline(&self) -> bool {
        true
    }
}
<|endoftext|>


<commit_before>use std::cmp::{PartialEq, Eq};
use std::ops::{Add, Sub, Mul};

#[derive(Copy, Debug)]
pub struct Vector3 {
    pub x: f64,
    pub y: f64,
    pub z: f64,
}

impl Vector3 {
    pub fn new(_x: f64, _y: f64, _z: f64) -> Vector3 {
        Vector3 { x: _x, y: _y, z: _z }
    }

    pub fn length_square(&self) -> f64 {
        self.x.powi(2) + self.y.powi(2) + self.z.powi(2)
    }

    pub fn length(&self) -> f64 {
        self.length_square().sqrt()
    }

    pub fn normalize(&mut self) {
        let reciprocal_length = 1.0 / self.length();
        self.x *= reciprocal_length;
        self.y *= reciprocal_length;
        self.z *= reciprocal_length;
    }
}

impl Clone for Vector3 {
    fn clone(&self) -> Vector3 {
        Vector3 {
            x: self.x,
            y: self.y,
            z: self.z,
        }
    }
}

impl Add for Vector3 {
    type Output = Vector3;

    fn add(self, other: Vector3) -> Vector3 {
        Vector3 {
            x: self.x + other.x,
            y: self.y + other.y,
            z: self.z + other.z,
        }
    }
}

impl Sub for Vector3 {
    type Output = Vector3;

    fn sub(self, other: Vector3) -> Vector3 {
        Vector3 {
            x: self.x - other.x,
            y: self.y - other.y,
            z: self.z - other.z,
        }
    }
}

impl Mul<f64> for Vector3 {
    type Output = Vector3;

    fn mul(self, other: f64) -> Vector3 {
        Vector3 {
            x: self.x * other,
            y: self.y * other,
            z: self.z * other,
        }
    }
}

impl Mul<Vector3> for f64 {
    type Output = Vector3;

    fn mul(self, other: Vector3) -> Vector3 {
        Vector3 {
            x: self * other.x,
            y: self * other.y,
            z: self * other.z
        }
    }
}

impl Mul for Vector3 {
    type Output = f64;

    fn mul(self, other: Vector3) -> f64 {
        self.x * other.x + self.y * other.y + self.z * other.z
    }
}

impl PartialEq for Vector3 {
    fn eq(&self, other: &Vector3) -> bool {
        self.x == other.x && self.y == other.y && self.z == other.z
    }
}

impl Eq for Vector3 { }

#[cfg(test)]
mod test {
    use super::Vector3;

    #[test]
    fn test_length_square() {
        let v = Vector3::new(1.0, 2.0, 3.0);
        assert_eq!(v.length_square(), 14.0);
    }

    #[test]
    fn test_length() {
        let v = Vector3::new(1.0, 2.0, 3.0);
        assert_eq!(v.length(), 14_f64.sqrt());
    }

    #[test]
    fn test_normalize() {
        let mut v = Vector3::new(2.0, 0.0, 0.0);
        v.normalize();
        assert_eq!(v, Vector3::new(1.0, 0.0, 0.0));
    }

    #[test]
    fn test_add() {
        let v1 = Vector3::new(1.0, 2.0, 3.0);
        let v2 = Vector3::new(4.0, 5.0, 6.0);
        let sum = v1 + v2;
        assert_eq!(sum, Vector3::new(5.0, 7.0, 9.0));
    }

    #[test]
    fn test_sub() {
        let v1 = Vector3::new(1.0, 2.0, 3.0);
        let v2 = Vector3::new(4.0, 5.0, 6.0);
        let sub = v2 - v1;
        assert_eq!(sub, Vector3::new(3.0, 3.0, 3.0));
    }

    #[test]
    fn test_mul() {
        let v1 = Vector3::new(1.0, 2.0, 3.0);
        let v2 = Vector3::new(4.0, 5.0, 6.0);
        let v3 = Vector3::new(2.0, 4.0, 6.0);
        assert_eq!(v1 * v2, 32.0);
        assert_eq!(2.0 * v1, v3);
        assert_eq!(v1 * 2.0, v3);
    }

}
<commit_msg>module vector3<commit_after>use std::cmp::{PartialEq, Eq};
use std::ops::{Neg, Add, Sub, Mul, Div};

#[derive(Copy, Debug)]
pub struct Vector3 {
    pub x: f64,
    pub y: f64,
    pub z: f64,
}

impl Vector3 {
    pub fn new(_x: f64, _y: f64, _z: f64) -> Vector3 {
        Vector3 { x: _x, y: _y, z: _z }
    }

    pub fn length_square(&self) -> f64 {
        self.x.powi(2) + self.y.powi(2) + self.z.powi(2)
    }

    pub fn length(&self) -> f64 {
        self.length_square().sqrt()
    }

    pub fn normalize(&mut self) {
        let reciprocal_length = 1.0 / self.length();
        self.x *= reciprocal_length;
        self.y *= reciprocal_length;
        self.z *= reciprocal_length;
    }

    pub fn cross(&self, other: &Vector3) -> Vector3 {
        Vector3 {
            x: self.y * other.z - self.z * other.y,
            y: self.z * other.x - self.x * other.z,
            z: self.x * other.y - self.y * other.x,
        }
    }
}

impl Clone for Vector3 {
    fn clone(&self) -> Vector3 {
        Vector3 {
            x: self.x,
            y: self.y,
            z: self.z,
        }
    }
}

impl Neg for Vector3 {
    type Output = Vector3;

    fn neg(self) -> Vector3 {
        Vector3 {
            x: -self.x,
            y: -self.y,
            z: -self.z,
        }
    }
}

impl Add for Vector3 {
    type Output = Vector3;

    fn add(self, other: Vector3) -> Vector3 {
        Vector3 {
            x: self.x + other.x,
            y: self.y + other.y,
            z: self.z + other.z,
        }
    }
}

impl Sub for Vector3 {
    type Output = Vector3;

    fn sub(self, other: Vector3) -> Vector3 {
        Vector3 {
            x: self.x - other.x,
            y: self.y - other.y,
            z: self.z - other.z,
        }
    }
}

impl Mul<f64> for Vector3 {
    type Output = Vector3;

    fn mul(self, other: f64) -> Vector3 {
        Vector3 {
            x: self.x * other,
            y: self.y * other,
            z: self.z * other,
        }
    }
}

impl Mul<Vector3> for f64 {
    type Output = Vector3;

    fn mul(self, other: Vector3) -> Vector3 {
        Vector3 {
            x: self * other.x,
            y: self * other.y,
            z: self * other.z
        }
    }
}

impl Mul for Vector3 {
    type Output = f64;

    fn mul(self, other: Vector3) -> f64 {
        self.x * other.x + self.y * other.y + self.z * other.z
    }
}

impl Div<f64> for Vector3 {
    type Output = Vector3;

    fn div(self, other: f64) -> Vector3 {
        Vector3 {
            x: self.x / other,
            y: self.y / other,
            z: self.z / other,
        }
    }
}

impl PartialEq for Vector3 {
    fn eq(&self, other: &Vector3) -> bool {
        self.x == other.x && self.y == other.y && self.z == other.z
    }
}

impl Eq for Vector3 { }

#[cfg(test)]
mod test {
    use super::Vector3;

    #[test]
    fn test_length_square() {
        let v = Vector3::new(1.0, 2.0, 3.0);
        assert_eq!(v.length_square(), 14.0);
    }

    #[test]
    fn test_length() {
        let v = Vector3::new(1.0, 2.0, 3.0);
        assert_eq!(v.length(), 14_f64.sqrt());
    }

    #[test]
    fn test_normalize() {
        let mut v = Vector3::new(2.0, 0.0, 0.0);
        v.normalize();
        assert_eq!(v, Vector3::new(1.0, 0.0, 0.0));
    }

    #[test]
    fn test_cross() {
        let i = Vector3::new(1.0, 0.0, 0.0);
        let j = Vector3::new(0.0, 1.0, 0.0);
        let k = Vector3::new(0.0, 0.0, 1.0);

        assert_eq!(i.cross(&j), k);
        assert_eq!(j.cross(&i), -k);

        assert_eq!(j.cross(&k), i);
        assert_eq!(k.cross(&j), -i);

        assert_eq!(k.cross(&i), j);
        assert_eq!(i.cross(&k), -j);
    }

    #[test]
    fn test_neg() {
        let v = Vector3::new(1.0, 2.0, 3.0);
        assert_eq!(-v, Vector3::new(-1.0, -2.0, -3.0));
    }

    #[test]
    fn test_add() {
        let v1 = Vector3::new(1.0, 2.0, 3.0);
        let v2 = Vector3::new(4.0, 5.0, 6.0);
        let sum = v1 + v2;
        assert_eq!(sum, Vector3::new(5.0, 7.0, 9.0));
    }

    #[test]
    fn test_sub() {
        let v1 = Vector3::new(1.0, 2.0, 3.0);
        let v2 = Vector3::new(4.0, 5.0, 6.0);
        let sub = v2 - v1;
        assert_eq!(sub, Vector3::new(3.0, 3.0, 3.0));
    }

    #[test]
    fn test_mul() {
        let v1 = Vector3::new(1.0, 2.0, 3.0);
        let v2 = Vector3::new(4.0, 5.0, 6.0);
        let v3 = Vector3::new(2.0, 4.0, 6.0);
        assert_eq!(v1 * v2, 32.0);
        assert_eq!(2.0 * v1, v3);
        assert_eq!(v1 * 2.0, v3);
    }

    #[test]
    fn test_div() {
        let v = Vector3::new(2.0, 4.0, 6.0);
        assert_eq!(v / 2.0, Vector3::new(1.0, 2.0, 3.0));
    }

}
<|endoftext|>


<commit_before>use super::super::{Grid, Y, X, Coord};
use grid_loop::{Edge, GridLoopField};
use super::*;

use rand::Rng;

#[derive(Debug, Clone, Copy)]
pub struct Symmetry {
    pub dyad: bool,         // 180-degree symmetry
    pub tetrad: bool,       // 90-degree symmetry
    pub horizontal: bool,   // horizontal line symmetry
    pub vertical: bool,     // vertical line symmetry
}

pub fn generate<R: Rng>(has_clue: &Grid<bool>, dic: &Dictionary, rng: &mut R) -> Option<Grid<Clue>> {
    let height = has_clue.height();
    let width = has_clue.width();
    let max_step = height * width * 10;

    let mut current_problem = Grid::new(height, width, NO_CLUE);
    let mut prev_decided_edges = 0;
    let temperature = 5.0f64;

    let mut unplaced_clues = 0;
    for y in 0..height {
        for x in 0..width {
            if has_clue[(Y(y), X(x))] {
                unplaced_clues += 1;
            }
        }
    }

    let mut last_field = Field::new(&current_problem, dic);

    for _ in 0..max_step {
        let mut pos_cand = vec![];
        for y in 0..height {
            for x in 0..width {
                let cd = (Y(y), X(x));
                if has_clue[cd] && (current_problem[cd] == NO_CLUE || has_undecided_nearby(&last_field, cd)) {
                    pos_cand.push(cd);
                }
            }
        }

        rng.shuffle(&mut pos_cand);

        let mut updated = false;
        for &pos in &pos_cand {
            let prev_clue = current_problem[pos];
            let is_zero_ok = !has_zero_nearby(&current_problem, pos);

            let mut new_clue_cand = vec![];
            for c in (if is_zero_ok { 0 } else { 1 })..4 {
                let c = Clue(c);
                if c != prev_clue {
                    new_clue_cand.push(c);
                }
            }

            rng.shuffle(&mut new_clue_cand);

            for &c in &new_clue_cand {
                current_problem[pos] = c;

                let mut field = Field::new(&current_problem, dic);
                field.check_all_cell();

                let isok;
                let current_decided_edges;
                if field.inconsistent() {
                    isok = false;
                    current_decided_edges = -1;
                } else {
                    current_decided_edges = field.grid_loop().num_decided_edges();

                    if prev_decided_edges < current_decided_edges {
                        isok = true;
                    } else {
                        isok = rng.next_f64() < ((current_decided_edges - prev_decided_edges) as f64 / temperature).exp()
                    }
                }

                if isok {
                    updated = true;
                    prev_decided_edges = current_decided_edges;
                    if prev_clue == NO_CLUE {
                        unplaced_clues -= 1;
                    }

                    if field.fully_solved() && unplaced_clues == 0 {
                        return Some(current_problem);
                    }

                    last_field = field;
                    break;
                } else {
                    current_problem[pos] = prev_clue;
                }
            }

            if updated {
                break;
            }
        }
    }

    None
}

fn has_undecided_nearby(field: &Field, clue_pos: Coord) -> bool {
    let (Y(y), X(x)) = clue_pos;
    let y = y * 2 + 1;
    let x = x * 2 + 1;

    let neighbor_size: i32 = 7;
    for dy in -neighbor_size..(neighbor_size + 1) {
        let dx_max = neighbor_size - dy.abs();
        for dx in -dx_max..(dx_max + 1) {
            let y2 = y + dy;
            let x2 = x + dx;

            let cd = (Y(y2), X(x2));
            if (dy & 1) != (dx & 1) {
                if field.get_edge_safe(cd) == Edge::Undecided {
                    return true;
                }
            }
        }
    }
    false
}

fn has_zero_nearby(problem: &Grid<Clue>, (Y(y), X(x)): Coord) -> bool {
    for dy in -1..2 {
        for dx in -1..2 {
            let cd = (Y(y + dy), X(x + dx));
            if problem.is_valid_coord(cd) && problem[cd] == Clue(0) {
                return true;
            }
        }
    }
    false
}

pub fn generate_placement<R: Rng>(height: i32, width: i32, num_clues: i32, symmetry: Symmetry, rng: &mut R) -> Grid<bool> {
    let mut num_clues = num_clues;
    let mut symmetry = symmetry;

    symmetry.dyad |= symmetry.tetrad;
    symmetry.tetrad &= (height == width);

    let mut grp_ids = Grid::new(height, width, false);
    let mut last_id = 0;

    let mut clue_positions: Vec<Vec<Coord>> = vec![];

    for y in 0..height {
        for x in 0..width {
            if !grp_ids[(Y(y), X(x))] {
                let mut sto = vec![];
                update_grp(y, x, last_id, symmetry, &mut grp_ids, &mut sto);
                clue_positions.push(sto);
            }
        }
    }

    let mut ret = Grid::new(height, width, false);
    while clue_positions.len() > 0 && num_clues > 0 {
        let mut scores = vec![];
        let mut scores_total = 0.0f64;

        for pos in &clue_positions {
            let (Y(y), X(x)) = pos[0];
            let mut score_base = 0.0f64;

            for dy in -2..3 {
                for dx in -2..3 {
                    let cd2 = (Y(y + dy), X(x + dx));
                    if ret.is_valid_coord(cd2) && ret[cd2] {
                        let dist = dy.abs() + dx.abs();
                        score_base += 5.0f64 - (dist as f64);
                        if dist == 1 {
                            score_base += 2.0f64;
                        }
                    }
                }
            }

            let pos_score = 64.0f64 * 2.0f64.powf((16.0f64 - score_base) / 2.0f64) + 4.0f64;
            scores.push(pos_score);
            scores_total += pos_score;
        }

        let mut thresh = rng.gen_range(0.0f64, scores_total);
        for i in 0..clue_positions.len() {
            if thresh < scores[i] {
                for &c in &(clue_positions[i]) {
                    ret[c] = true;
                    num_clues -= 1;
                }
                clue_positions.swap_remove(i);
                break;
            } else {
                thresh -= scores[i];
            }
        }
    }

    ret
}

fn update_grp(y: i32, x: i32, id: i32, symmetry: Symmetry, grp_ids: &mut Grid<bool>, sto: &mut Vec<Coord>) {
    if grp_ids[(Y(y), X(x))] {
        return;
    }
    grp_ids[(Y(y), X(x))] = true;
    sto.push((Y(y), X(x)));

    if symmetry.tetrad {
        update_grp(grp_ids.height() - 1 - x, y, id, symmetry, grp_ids, sto);
    } else if symmetry.dyad {
        update_grp(grp_ids.height() - 1 - y, grp_ids.width() - 1 - x, id, symmetry, grp_ids, sto);
    }
    if symmetry.horizontal {
        update_grp(grp_ids.height() - 1 - y, x, id, symmetry, grp_ids, sto);
    }
    if symmetry.vertical {
        update_grp(y, grp_ids.width() - 1 - x, id, symmetry, grp_ids, sto);
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use rand;

    fn run_placement_test<R: Rng>(placement: Vec<Vec<bool>>, dic: &Dictionary, rng: &mut R) {
        let placement = ::common::vec_to_grid(&placement);
        let mut succeeded = false;

        for _ in 0..10 {
            let problem = generate(&placement, dic, rng);

            if let Some(problem) = problem {
                succeeded = true;

                assert_eq!(problem.height(), placement.height());
                assert_eq!(problem.width(), placement.width());

                for y in 0..placement.height() {
                    for x in 0..placement.width() {
                        let clue = problem[(Y(y), X(x))];
                        assert_eq!(placement[(Y(y), X(x))], clue != NO_CLUE);

                        if clue == Clue(0) {
                            for dy in -1..2 {
                                for dx in -1..2 {
                                    let y2 = y + dy;
                                    let x2 = x + dx;

                                    if 0 <= y2 && y2 < placement.height() && 0 <= x2 && x2 < placement.width() && (dy, dx) != (0, 0) {
                                        assert!(problem[(Y(y2), X(x2))] != Clue(0));
                                    }
                                }
                            }
                        }
                    }
                }

                let mut field = Field::new(&problem, &dic);
                field.check_all_cell();
                assert!(!field.inconsistent());
                assert!(field.fully_solved());

                break;
            }
        }

        assert!(succeeded);
    }

    #[test]
    fn test_generator() {
        let mut rng = rand::thread_rng();
        let dic = Dictionary::complete();

        run_placement_test(vec![
            vec![true , true , true , true , true ],
            vec![true , false, false, false, true ],
            vec![true , false, false, false, true ],
            vec![true , false, false, false, true ],
            vec![true , true , true , true , true ],
        ], &dic, &mut rng);

        run_placement_test(vec![
            vec![true , false, true , true , true ],
            vec![false, false, false, false, true ],
            vec![true , false, false, false, true ],
            vec![true , false, false, false, false],
            vec![true , true , true , false, true ],
        ], &dic, &mut rng);
    }
}
<commit_msg>Slitherlink: use common field to improve performance of generator<commit_after>use super::super::{Grid, Y, X, Coord};
use grid_loop::{Edge, GridLoopField};
use super::*;

use rand::Rng;

#[derive(Debug, Clone, Copy)]
pub struct Symmetry {
    pub dyad: bool,         // 180-degree symmetry
    pub tetrad: bool,       // 90-degree symmetry
    pub horizontal: bool,   // horizontal line symmetry
    pub vertical: bool,     // vertical line symmetry
}

pub fn generate<R: Rng>(has_clue: &Grid<bool>, dic: &Dictionary, rng: &mut R) -> Option<Grid<Clue>> {
    let height = has_clue.height();
    let width = has_clue.width();
    let max_step = height * width * 10;

    let mut current_problem = Grid::new(height, width, NO_CLUE);
    let mut prev_decided_edges = 0;
    let temperature = 5.0f64;

    let mut unplaced_clues = 0;
    for y in 0..height {
        for x in 0..width {
            if has_clue[(Y(y), X(x))] {
                unplaced_clues += 1;
            }
        }
    }

    let mut last_field = Field::new(&current_problem, dic);

    for _ in 0..max_step {
        let mut pos_cand = vec![];
        for y in 0..height {
            for x in 0..width {
                let cd = (Y(y), X(x));
                if has_clue[cd] && (current_problem[cd] == NO_CLUE || has_undecided_nearby(&last_field, cd)) {
                    pos_cand.push(cd);
                }
            }
        }

        rng.shuffle(&mut pos_cand);

        let mut updated = false;
        for &pos in &pos_cand {
            let prev_clue = current_problem[pos];
            let is_zero_ok = !has_zero_nearby(&current_problem, pos);

            let mut new_clue_cand = vec![];
            for c in (if is_zero_ok { 0 } else { 1 })..4 {
                let c = Clue(c);
                if c != prev_clue {
                    new_clue_cand.push(c);
                }
            }

            rng.shuffle(&mut new_clue_cand);

            let mut common;
            if prev_clue == NO_CLUE {
                common = last_field.clone();
            } else {
                current_problem[pos] = NO_CLUE;
                common = Field::new(&current_problem, dic);
                common.check_all_cell();
            }

            for &c in &new_clue_cand {
                current_problem[pos] = c;

                let mut field = common.clone();
                field.add_clue(pos, c);

                let isok;
                let current_decided_edges;
                if field.inconsistent() {
                    isok = false;
                    current_decided_edges = -1;
                } else {
                    current_decided_edges = field.grid_loop().num_decided_edges();

                    if prev_decided_edges < current_decided_edges {
                        isok = true;
                    } else {
                        isok = rng.next_f64() < ((current_decided_edges - prev_decided_edges) as f64 / temperature).exp()
                    }
                }

                if isok {
                    updated = true;
                    prev_decided_edges = current_decided_edges;
                    if prev_clue == NO_CLUE {
                        unplaced_clues -= 1;
                    }

                    if field.fully_solved() && unplaced_clues == 0 {
                        return Some(current_problem);
                    }

                    last_field = field;
                    break;
                }
            }

            if updated {
                break;
            } else {
                current_problem[pos] = prev_clue;
            }
        }
    }

    None
}

fn has_undecided_nearby(field: &Field, clue_pos: Coord) -> bool {
    let (Y(y), X(x)) = clue_pos;
    let y = y * 2 + 1;
    let x = x * 2 + 1;

    let neighbor_size: i32 = 7;
    for dy in -neighbor_size..(neighbor_size + 1) {
        let dx_max = neighbor_size - dy.abs();
        for dx in -dx_max..(dx_max + 1) {
            let y2 = y + dy;
            let x2 = x + dx;

            let cd = (Y(y2), X(x2));
            if (dy & 1) != (dx & 1) {
                if field.get_edge_safe(cd) == Edge::Undecided {
                    return true;
                }
            }
        }
    }
    false
}

fn has_zero_nearby(problem: &Grid<Clue>, (Y(y), X(x)): Coord) -> bool {
    for dy in -1..2 {
        for dx in -1..2 {
            let cd = (Y(y + dy), X(x + dx));
            if problem.is_valid_coord(cd) && problem[cd] == Clue(0) {
                return true;
            }
        }
    }
    false
}

pub fn generate_placement<R: Rng>(height: i32, width: i32, num_clues: i32, symmetry: Symmetry, rng: &mut R) -> Grid<bool> {
    let mut num_clues = num_clues;
    let mut symmetry = symmetry;

    symmetry.dyad |= symmetry.tetrad;
    symmetry.tetrad &= (height == width);

    let mut grp_ids = Grid::new(height, width, false);
    let mut last_id = 0;

    let mut clue_positions: Vec<Vec<Coord>> = vec![];

    for y in 0..height {
        for x in 0..width {
            if !grp_ids[(Y(y), X(x))] {
                let mut sto = vec![];
                update_grp(y, x, last_id, symmetry, &mut grp_ids, &mut sto);
                clue_positions.push(sto);
            }
        }
    }

    let mut ret = Grid::new(height, width, false);
    while clue_positions.len() > 0 && num_clues > 0 {
        let mut scores = vec![];
        let mut scores_total = 0.0f64;

        for pos in &clue_positions {
            let (Y(y), X(x)) = pos[0];
            let mut score_base = 0.0f64;

            for dy in -2..3 {
                for dx in -2..3 {
                    let cd2 = (Y(y + dy), X(x + dx));
                    if ret.is_valid_coord(cd2) && ret[cd2] {
                        let dist = dy.abs() + dx.abs();
                        score_base += 5.0f64 - (dist as f64);
                        if dist == 1 {
                            score_base += 2.0f64;
                        }
                    }
                }
            }

            let pos_score = 64.0f64 * 2.0f64.powf((16.0f64 - score_base) / 2.0f64) + 4.0f64;
            scores.push(pos_score);
            scores_total += pos_score;
        }

        let mut thresh = rng.gen_range(0.0f64, scores_total);
        for i in 0..clue_positions.len() {
            if thresh < scores[i] {
                for &c in &(clue_positions[i]) {
                    ret[c] = true;
                    num_clues -= 1;
                }
                clue_positions.swap_remove(i);
                break;
            } else {
                thresh -= scores[i];
            }
        }
    }

    ret
}

fn update_grp(y: i32, x: i32, id: i32, symmetry: Symmetry, grp_ids: &mut Grid<bool>, sto: &mut Vec<Coord>) {
    if grp_ids[(Y(y), X(x))] {
        return;
    }
    grp_ids[(Y(y), X(x))] = true;
    sto.push((Y(y), X(x)));

    if symmetry.tetrad {
        update_grp(grp_ids.height() - 1 - x, y, id, symmetry, grp_ids, sto);
    } else if symmetry.dyad {
        update_grp(grp_ids.height() - 1 - y, grp_ids.width() - 1 - x, id, symmetry, grp_ids, sto);
    }
    if symmetry.horizontal {
        update_grp(grp_ids.height() - 1 - y, x, id, symmetry, grp_ids, sto);
    }
    if symmetry.vertical {
        update_grp(y, grp_ids.width() - 1 - x, id, symmetry, grp_ids, sto);
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use rand;

    fn run_placement_test<R: Rng>(placement: Vec<Vec<bool>>, dic: &Dictionary, rng: &mut R) {
        let placement = ::common::vec_to_grid(&placement);
        let mut succeeded = false;

        for _ in 0..10 {
            let problem = generate(&placement, dic, rng);

            if let Some(problem) = problem {
                succeeded = true;

                assert_eq!(problem.height(), placement.height());
                assert_eq!(problem.width(), placement.width());

                for y in 0..placement.height() {
                    for x in 0..placement.width() {
                        let clue = problem[(Y(y), X(x))];
                        assert_eq!(placement[(Y(y), X(x))], clue != NO_CLUE);

                        if clue == Clue(0) {
                            for dy in -1..2 {
                                for dx in -1..2 {
                                    let y2 = y + dy;
                                    let x2 = x + dx;

                                    if 0 <= y2 && y2 < placement.height() && 0 <= x2 && x2 < placement.width() && (dy, dx) != (0, 0) {
                                        assert!(problem[(Y(y2), X(x2))] != Clue(0));
                                    }
                                }
                            }
                        }
                    }
                }

                let mut field = Field::new(&problem, &dic);
                field.check_all_cell();
                assert!(!field.inconsistent());
                assert!(field.fully_solved());

                break;
            }
        }

        assert!(succeeded);
    }

    #[test]
    fn test_generator() {
        let mut rng = rand::thread_rng();
        let dic = Dictionary::complete();

        run_placement_test(vec![
            vec![true , true , true , true , true ],
            vec![true , false, false, false, true ],
            vec![true , false, false, false, true ],
            vec![true , false, false, false, true ],
            vec![true , true , true , true , true ],
        ], &dic, &mut rng);

        run_placement_test(vec![
            vec![true , false, true , true , true ],
            vec![false, false, false, false, true ],
            vec![true , false, false, false, true ],
            vec![true , false, false, false, false],
            vec![true , true , true , false, true ],
        ], &dic, &mut rng);
    }
}
<|endoftext|>