<commit_before>extern crate num;

use self::num::traits::Num;

use std::cmp;
use std::mem;
use std::fmt::Debug;
use std::ops::Range;

#[derive(PartialEq, Eq, Debug, Clone)]
pub struct IntervalTree<N, D> {
    root: Option<Node<N, D>>,
}

#[derive(PartialEq, Eq, Debug, Clone)]
pub struct Entry<'a, N: 'a, D: 'a> {
    data: &'a D,
    interval: &'a Range<N>,
}

pub struct IntervalTreeIterator<'a, N: 'a, D: 'a> {
    nodes: Vec<&'a Node<N, D>>,
    interval: Range<N>,
}

impl<'a, N: Debug + Num + Clone + Ord + 'a, D: Debug + 'a> Iterator for IntervalTreeIterator<'a, N, D> {
    type Item = Entry<'a, N, D>;

    fn next(&mut self) -> Option<Entry<'a, N, D>> {
        loop {
            let candidate = match self.nodes.pop() {
                None => return None,
                Some(node) => node,
            };
            if self.interval.end <= candidate.interval.start ||
               candidate.interval.end <= self.interval.start {
                // no overlap with current candidate, check his children
                if let Some(ref left) = candidate.left {
                    if left.max > self.interval.start {
                        self.nodes.push(left);
                    }
                }
                // TODO: make sure there isn't any unnecessary recursion here
                if let Some(ref right) = candidate.right {
                    self.nodes.push(right);
                }
            } else {
                if let Some(ref left) = candidate.left {
                    self.nodes.push(left);
                }
                if let Some(ref right) = candidate.right {
                    self.nodes.push(right);
                }
                let e = Entry {
                    data: &candidate.value,
                    interval: &candidate.interval,
                };
                return Some(e);
            }
        }
    }
}

impl<N: Debug + Num + Clone + Ord, D: Debug> IntervalTree<N, D> {
    pub fn new() -> Self {
        IntervalTree { root: None }
    }

    pub fn insert(&mut self, interval: Range<N>, data: D) {
        validate(&interval);
        match self.root {
            Some(ref mut n) => n.insert(interval, data),
            None => self.root = Some(Node::new(interval, data)),
        }
    }

    pub fn find(&self, interval: Range<N>) -> IntervalTreeIterator<N, D> {
        validate(&interval);
        match self.root {
            Some(ref n) => {
                n.find_iter(interval)
            }
            None => {
                let empty_nodes = vec![];
                IntervalTreeIterator {
                    nodes: empty_nodes,
                    interval: interval,
                }
            }
        }

    }

    pub fn find_any(&self, interval: &Range<N>) -> Option<(&Range<N>, &D)> {
        validate(&interval);
        match self.root {
            Some(ref n) => {
                let mut result = vec![];
                n.find(interval, true, &mut result);
                result.pop()
            }
            None => None,
        }
    }

    pub fn find_all(&self, interval: &Range<N>) -> Vec<(&Range<N>, &D)> {
        validate(&interval);
        match self.root {
            Some(ref n) => {
                let mut result = vec![];
                n.find(interval, true, &mut result);
                result
            }
            None => vec![],
        }
    }
}

fn validate<N: Ord + Debug>(interval: &Range<N>) {
    if interval.start >= interval.end {
        panic!("Expected interval.end > interval.start, got: ({:?})",
               interval);
    }
}

#[derive(PartialEq, Eq, Debug, Clone)]
pub struct Node<N, D> {
    // actual interval data
    interval: Range<N>,
    value: D,
    // tree metadata
    max: N,
    height: i64,
    left: Option<Box<Node<N, D>>>,
    right: Option<Box<Node<N, D>>>,
}

impl<N: Debug + Num + Clone + Ord, D: Debug> Node<N, D> {
    pub fn new(interval: Range<N>, data: D) -> Self {
        let max = interval.end.clone();
        Node {
            interval: interval,
            max: max,
            height: 1,
            value: data,
            left: None,
            right: None,
        }
    }

    pub fn insert(&mut self, interval: Range<N>, data: D) {
        if interval.start <= self.interval.start {
            if let Some(ref mut son) = self.left {
                son.insert(interval, data);
            } else {
                self.left = Some(Box::new(Node::new(interval, data)));
            }
        } else {
            if let Some(ref mut son) = self.right {
                son.insert(interval, data);
            } else {
                self.right = Some(Box::new(Node::new(interval, data)));
            }
        }
        self.repair();
    }

    pub fn find_iter<'a>(&'a self, interval: Range<N>) -> IntervalTreeIterator<'a, N, D> {
        let nodes = vec![self];
        IntervalTreeIterator {
            nodes: nodes,
            interval: interval,
        }
    }

    pub fn find<'a>(&'a self,
                    interval: &Range<N>,
                    only_one: bool,
                    result: &mut Vec<(&'a Range<N>, &'a D)>) {
        if interval.end <= self.interval.start || self.interval.end <= interval.start {
            // no overlap with current node, recur into children
            if let Some(ref left) = self.left {
                if left.max > interval.start {
                    left.find(interval, only_one, result);
                    return;
                }
            }
            if let Some(ref right) = self.right {
                right.find(interval, only_one, result);
                return;
            }
        } else {
            result.push((&self.interval, &self.value));
            if only_one {
                return;
            } else {
                if let Some(ref left) = self.left {
                    left.find(interval, only_one, result);
                }
                if let Some(ref right) = self.right {
                    right.find(interval, only_one, result);
                }
            }
        }
    }

    fn update_height(&mut self) {
        let ref left_h = self.left.as_ref().map_or(0, |n| n.height);
        let ref right_h = self.right.as_ref().map_or(0, |n| n.height);
        self.height = 1 + cmp::max(*left_h, *right_h);
    }

    fn update_max(&mut self) {
        self.max = self.interval.end.clone();
        if let Some(ref n) = self.left {
            if self.max < n.max {
                self.max = n.max.clone();
            }
        }
        if let Some(ref n) = self.right {
            if self.max < n.max {
                self.max = n.max.clone();
            }
        }
    }

    fn repair(&mut self) {
        let ref left_h = self.left.as_ref().map_or(0, |n| n.height);
        let ref right_h = self.right.as_ref().map_or(0, |n| n.height);
        // each case - update both height and max
        if (left_h - right_h).abs() <= 1 {
            self.update_height();
            self.update_max();
        } else if right_h > left_h {
            {
                let mut right =
                    self.right.as_mut().expect("Invalid tree: leaf is taller than its sibling.");
                let ref right_left_h = right.left.as_ref().map_or(0, |n| n.height);
                let ref right_right_h = right.right.as_ref().map_or(0, |n| n.height);
                if right_left_h > right_right_h {
                    right.rotate_right();
                }
            }
            self.rotate_left();
        } else {
            {
                let mut left =
                    self.left.as_mut().expect("Invalid tree: leaf is taller than its sibling.");
                let ref left_right_h = left.right.as_ref().map_or(0, |n| n.height);
                let ref left_left_h = left.left.as_ref().map_or(0, |n| n.height);
                if left_right_h > left_left_h {
                    println!("double rot");
                    left.rotate_left();
                }
            }
            self.rotate_right();
        }
    }

    fn rotate_left(&mut self) {
        let mut new_root = self.right.take().unwrap();
        let t1 = self.left.take();
        let t2 = new_root.left.take();
        let t3 = new_root.right.take();
        swap_interval_data(self, &mut *new_root);

        new_root.left = t1;
        new_root.right = t2;
        new_root.update_height();
        new_root.update_max();

        self.right = t3;
        self.left = Some(new_root);
        self.update_height();
        self.update_max();
    }

    fn rotate_right(&mut self) {
        let mut new_root = self.left.take().unwrap();
        let t1 = new_root.left.take();
        let t2 = new_root.right.take();
        let t3 = self.right.take();
        swap_interval_data(self, &mut *new_root);

        new_root.left = t2;
        new_root.right = t3;
        new_root.update_height();
        new_root.update_max();

        self.left = t1;
        self.right = Some(new_root);
        self.update_height();
        self.update_max();
    }
}

fn swap_interval_data<N, D>(node_1: &mut Node<N, D>, node_2: &mut Node<N, D>) {
    mem::swap(&mut node_1.value, &mut node_2.value);
    mem::swap(&mut node_1.interval, &mut node_2.interval);
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::cmp;
    use std::ops::Range;

    fn validate(node: &Node<i64, String>) {
        validate_height(node);
        validate_intervals(node);
        validate_string_metadata(node);
        node.left.as_ref().map(|n| validate(n));
        node.right.as_ref().map(|n| validate(n));
    }

    fn validate_height(node: &Node<i64, String>) {
        let ref left_height = node.left.as_ref().map_or(0, |n| n.height);
        let ref right_height = node.right.as_ref().map_or(0, |n| n.height);
        assert!((left_height - right_height).abs() <= 1);
        assert_eq!(node.height, cmp::max(left_height, right_height) + 1)
    }

    fn validate_intervals(node: &Node<i64, String>) {
        let mut reached_maximum: bool = false;
        if node.interval.end == node.max {
            reached_maximum = true;
        }
        if let Some(ref son) = node.left {
            if !(son.max <= node.max) {
                panic!("left max invariant violated:\n{:?} -> {:?}", node, son);
            }
            if !(son.interval.start <= node.interval.start) {
                panic!("left ord invariant violated\n{:?} -> {:?}", node, son);
            }
            if node.max == son.max {
                reached_maximum = true;
            }
        }
        if let Some(ref son) = node.right {
            if !(son.max <= node.max) {
                panic!("right max invariant violated\n{:?} -> {:?}", node, son);
            }

            if !(son.interval.start >= node.interval.start) {
                panic!("right ord invariant violated\n{:?} -> {:?}", node, son);
            }
            if node.max == son.max {
                reached_maximum = true;
            }
        }
        if !reached_maximum {
            panic!("maximum invariant violated: {:?}", node);
        }
    }

    fn validate_string_metadata(node: &Node<i64, String>) {
        let mut name: String = "".to_string();
        name.push_str(&node.interval.start.to_string());
        name.push_str(":");
        name.push_str(&node.interval.end.to_string());
        if name != node.value {
            panic!("Invalid metadata for node {:?}", node);
        }
    }

    fn insert_and_validate(tree: &mut IntervalTree<i64, String>, start: i64, end: i64) {
        let mut name: String = "".to_string();
        name.push_str(&start.to_string());
        name.push_str(":");
        name.push_str(&end.to_string());
        tree.insert((start..end), name);
        if let Some(ref n) = tree.root {
            validate(n);
        }
    }

    fn assert_intersection(tree: &IntervalTree<i64, String>,
                           target: Range<i64>,
                           expected_bounds: Range<i64>) {
        let mut expected_data: String = "".to_string();
        expected_data.push_str(&expected_bounds.start.to_string());
        expected_data.push_str(":");
        expected_data.push_str(&expected_bounds.end.to_string());
        if let Some((actual_bounds, actual_data)) = tree.find_any(&target) {
            assert_eq!(&expected_data.to_string(), actual_data);
            assert_eq!(&expected_bounds, actual_bounds);
        } else {
            panic!("Expected to find {:?} in the tree", expected_bounds);
        }
    }

    #[test]
    fn test_insertion_and_intersection() {
        let mut tree: IntervalTree<i64, String> = IntervalTree::new();
        tree.insert((50..51), "50:51".to_string());
        assert_eq!(tree.find_any(&(49..50)), None);
        assert_intersection(&tree, (49..55), (50..51));
        assert_eq!(tree.find_any(&(51..55)), None);
        assert_eq!(tree.find_any(&(52..55)), None);
        assert_eq!(tree.find_any(&(40..45)), None);
        insert_and_validate(&mut tree, 80, 81);
        assert_intersection(&tree, (80..83), (80..81));
        assert_eq!(tree.find_any(&(82..83)), None);
        insert_and_validate(&mut tree, 30, 35);
        assert_intersection(&tree, (25..33), (30..35));
        assert_eq!(tree.find_any(&(42..43)), None);
        assert_eq!(tree.find_any(&(35..36)), None);
        assert_eq!(tree.find_any(&(22..29)), None);
        insert_and_validate(&mut tree, 70, 77);
        assert_intersection(&tree, (75..79), (70..77));
        assert_eq!(tree.find_any(&(62..68)), None);
        assert_intersection(&tree, (75..77), (70..77));
        assert_eq!(tree.find_any(&(78..79)), None);
        assert_intersection(&tree, (49..51), (50..51));
        assert_intersection(&tree, (49..55), (50..51));
        assert_eq!(tree.find_any(&(51..55)), None);
        assert_eq!(tree.find_any(&(52..55)), None);
        assert_eq!(tree.find_any(&(40..45)), None);
        insert_and_validate(&mut tree, 101, 102);
        insert_and_validate(&mut tree, 103, 104);
        insert_and_validate(&mut tree, 105, 106);
        insert_and_validate(&mut tree, 107, 108);
        insert_and_validate(&mut tree, 111, 112);
        insert_and_validate(&mut tree, 113, 114);
        insert_and_validate(&mut tree, 115, 116);
        insert_and_validate(&mut tree, 117, 118);
        insert_and_validate(&mut tree, 119, 129);
        assert_eq!(tree.find_any(&(112..113)), None);
        assert_eq!(tree.find_any(&(108..109)), None);
        assert_intersection(&tree, (106..108), (107..108));
    }
}
<commit_msg>Remove non-iterator querying<commit_after>extern crate num;

use self::num::traits::Num;

use std::cmp;
use std::mem;
use std::fmt::Debug;
use std::ops::Range;

#[derive(PartialEq, Eq, Debug, Clone)]
pub struct IntervalTree<N, D> {
    root: Option<Node<N, D>>,
}

#[derive(PartialEq, Eq, Debug, Clone)]
pub struct Entry<'a, N: 'a, D: 'a> {
    data: &'a D,
    interval: &'a Range<N>,
}

pub struct IntervalTreeIterator<'a, N: 'a, D: 'a> {
    nodes: Vec<&'a Node<N, D>>,
    interval: Range<N>,
}

impl<'a, N: Debug + Num + Clone + Ord + 'a, D: Debug + 'a> Iterator for IntervalTreeIterator<'a, N, D> {
    type Item = Entry<'a, N, D>;

    fn next(&mut self) -> Option<Entry<'a, N, D>> {
        loop {
            let candidate = match self.nodes.pop() {
                None => return None,
                Some(node) => node,
            };
            if self.interval.end <= candidate.interval.start ||
               candidate.interval.end <= self.interval.start {
                // no overlap with current candidate, check his children
                if let Some(ref left) = candidate.left {
                    if left.max > self.interval.start {
                        self.nodes.push(left);
                    }
                }
                // TODO: make sure there isn't any unnecessary recursion here
                if let Some(ref right) = candidate.right {
                    self.nodes.push(right);
                }
            } else {
                if let Some(ref left) = candidate.left {
                    self.nodes.push(left);
                }
                if let Some(ref right) = candidate.right {
                    self.nodes.push(right);
                }
                let e = Entry {
                    data: &candidate.value,
                    interval: &candidate.interval,
                };
                return Some(e);
            }
        }
    }
}

impl<N: Debug + Num + Clone + Ord, D: Debug> IntervalTree<N, D> {
    pub fn new() -> Self {
        IntervalTree { root: None }
    }

    pub fn insert(&mut self, interval: Range<N>, data: D) {
        validate(&interval);
        match self.root {
            Some(ref mut n) => n.insert(interval, data),
            None => self.root = Some(Node::new(interval, data)),
        }
    }

    pub fn find(&self, interval: &Range<N>) -> IntervalTreeIterator<N, D> {
        validate(&interval);
        match self.root {
            Some(ref n) => {
                n.find_iter(interval.clone())
            }
            None => {
                let empty_nodes = vec![];
                IntervalTreeIterator {
                    nodes: empty_nodes,
                    interval: interval.clone(),
                }
            }
        }

    }
}

fn validate<N: Ord + Debug>(interval: &Range<N>) {
    if interval.start >= interval.end {
        panic!("Expected interval.end > interval.start, got: ({:?})",
               interval);
    }
}

#[derive(PartialEq, Eq, Debug, Clone)]
pub struct Node<N, D> {
    // actual interval data
    interval: Range<N>,
    value: D,
    // tree metadata
    max: N,
    height: i64,
    left: Option<Box<Node<N, D>>>,
    right: Option<Box<Node<N, D>>>,
}

impl<N: Debug + Num + Clone + Ord, D: Debug> Node<N, D> {
    pub fn new(interval: Range<N>, data: D) -> Self {
        let max = interval.end.clone();
        Node {
            interval: interval,
            max: max,
            height: 1,
            value: data,
            left: None,
            right: None,
        }
    }

    pub fn insert(&mut self, interval: Range<N>, data: D) {
        if interval.start <= self.interval.start {
            if let Some(ref mut son) = self.left {
                son.insert(interval, data);
            } else {
                self.left = Some(Box::new(Node::new(interval, data)));
            }
        } else {
            if let Some(ref mut son) = self.right {
                son.insert(interval, data);
            } else {
                self.right = Some(Box::new(Node::new(interval, data)));
            }
        }
        self.repair();
    }

    pub fn find_iter<'a>(&'a self, interval: Range<N>) -> IntervalTreeIterator<'a, N, D> {
        let nodes = vec![self];
        IntervalTreeIterator {
            nodes: nodes,
            interval: interval,
        }
    }

    fn update_height(&mut self) {
        let ref left_h = self.left.as_ref().map_or(0, |n| n.height);
        let ref right_h = self.right.as_ref().map_or(0, |n| n.height);
        self.height = 1 + cmp::max(*left_h, *right_h);
    }

    fn update_max(&mut self) {
        self.max = self.interval.end.clone();
        if let Some(ref n) = self.left {
            if self.max < n.max {
                self.max = n.max.clone();
            }
        }
        if let Some(ref n) = self.right {
            if self.max < n.max {
                self.max = n.max.clone();
            }
        }
    }

    fn repair(&mut self) {
        let ref left_h = self.left.as_ref().map_or(0, |n| n.height);
        let ref right_h = self.right.as_ref().map_or(0, |n| n.height);
        // each case - update both height and max
        if (left_h - right_h).abs() <= 1 {
            self.update_height();
            self.update_max();
        } else if right_h > left_h {
            {
                let mut right =
                    self.right.as_mut().expect("Invalid tree: leaf is taller than its sibling.");
                let ref right_left_h = right.left.as_ref().map_or(0, |n| n.height);
                let ref right_right_h = right.right.as_ref().map_or(0, |n| n.height);
                if right_left_h > right_right_h {
                    right.rotate_right();
                }
            }
            self.rotate_left();
        } else {
            {
                let mut left =
                    self.left.as_mut().expect("Invalid tree: leaf is taller than its sibling.");
                let ref left_right_h = left.right.as_ref().map_or(0, |n| n.height);
                let ref left_left_h = left.left.as_ref().map_or(0, |n| n.height);
                if left_right_h > left_left_h {
                    println!("double rot");
                    left.rotate_left();
                }
            }
            self.rotate_right();
        }
    }

    fn rotate_left(&mut self) {
        let mut new_root = self.right.take().unwrap();
        let t1 = self.left.take();
        let t2 = new_root.left.take();
        let t3 = new_root.right.take();
        swap_interval_data(self, &mut *new_root);

        new_root.left = t1;
        new_root.right = t2;
        new_root.update_height();
        new_root.update_max();

        self.right = t3;
        self.left = Some(new_root);
        self.update_height();
        self.update_max();
    }

    fn rotate_right(&mut self) {
        let mut new_root = self.left.take().unwrap();
        let t1 = new_root.left.take();
        let t2 = new_root.right.take();
        let t3 = self.right.take();
        swap_interval_data(self, &mut *new_root);

        new_root.left = t2;
        new_root.right = t3;
        new_root.update_height();
        new_root.update_max();

        self.left = t1;
        self.right = Some(new_root);
        self.update_height();
        self.update_max();
    }
}

fn swap_interval_data<N, D>(node_1: &mut Node<N, D>, node_2: &mut Node<N, D>) {
    mem::swap(&mut node_1.value, &mut node_2.value);
    mem::swap(&mut node_1.interval, &mut node_2.interval);
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::cmp;
    use std::ops::Range;

    fn validate(node: &Node<i64, String>) {
        validate_height(node);
        validate_intervals(node);
        validate_string_metadata(node);
        node.left.as_ref().map(|n| validate(n));
        node.right.as_ref().map(|n| validate(n));
    }

    fn validate_height(node: &Node<i64, String>) {
        let ref left_height = node.left.as_ref().map_or(0, |n| n.height);
        let ref right_height = node.right.as_ref().map_or(0, |n| n.height);
        assert!((left_height - right_height).abs() <= 1);
        assert_eq!(node.height, cmp::max(left_height, right_height) + 1)
    }

    fn validate_intervals(node: &Node<i64, String>) {
        let mut reached_maximum: bool = false;
        if node.interval.end == node.max {
            reached_maximum = true;
        }
        if let Some(ref son) = node.left {
            if !(son.max <= node.max) {
                panic!("left max invariant violated:\n{:?} -> {:?}", node, son);
            }
            if !(son.interval.start <= node.interval.start) {
                panic!("left ord invariant violated\n{:?} -> {:?}", node, son);
            }
            if node.max == son.max {
                reached_maximum = true;
            }
        }
        if let Some(ref son) = node.right {
            if !(son.max <= node.max) {
                panic!("right max invariant violated\n{:?} -> {:?}", node, son);
            }

            if !(son.interval.start >= node.interval.start) {
                panic!("right ord invariant violated\n{:?} -> {:?}", node, son);
            }
            if node.max == son.max {
                reached_maximum = true;
            }
        }
        if !reached_maximum {
            panic!("maximum invariant violated: {:?}", node);
        }
    }

    fn validate_string_metadata(node: &Node<i64, String>) {
        let mut name: String = "".to_string();
        name.push_str(&node.interval.start.to_string());
        name.push_str(":");
        name.push_str(&node.interval.end.to_string());
        if name != node.value {
            panic!("Invalid metadata for node {:?}", node);
        }
    }

    fn insert_and_validate(tree: &mut IntervalTree<i64, String>, start: i64, end: i64) {
        let mut name: String = "".to_string();
        name.push_str(&start.to_string());
        name.push_str(":");
        name.push_str(&end.to_string());
        tree.insert((start..end), name);
        if let Some(ref n) = tree.root {
            validate(n);
        }
    }

    fn make_entry_tuples(intervals: Vec<Range<i64>>) -> Vec<(Range<i64>, String)>{
        let mut entries = vec![];
        for interval in intervals {
            let mut data: String = "".to_string();
            data.push_str(&interval.start.to_string());
            data.push_str(":");
            data.push_str(&interval.end.to_string());
            entries.push((interval, data));
        }
        entries.sort_by(|x1, x2| x1.1.cmp(&x2.1));
        entries
    }

    fn assert_intersections(tree: &IntervalTree<i64, String>,
                           target: Range<i64>,
                           expected_results: Vec<Range<i64>>) {
        let mut actual_entries : Vec<Entry<i64, String>> = tree.find(&target).collect();
        actual_entries.sort_by(|x1, x2| x1.data.cmp(&x2.data));
        let expected_entries = make_entry_tuples(expected_results);
        assert_eq!(actual_entries.len(), expected_entries.len());
        for (actual, expected) in actual_entries.iter().zip(expected_entries.iter()) {
            assert_eq!(actual.interval, &expected.0);
            assert_eq!(actual.data, &expected.1);
        }
    }

    fn assert_not_found(tree: &IntervalTree<i64, String>,
                        target: Range<i64>) {
        assert_intersections(tree, target, vec![]);
    }

    #[test]
    fn test_insertion_and_intersection() {
        let mut tree: IntervalTree<i64, String> = IntervalTree::new();
        tree.insert((50..51), "50:51".to_string());
        assert_not_found(&tree, (49..50));
        assert_intersections(&tree, (49..55), vec![(50..51)]);
        assert_not_found(&tree, (51..55));
        assert_not_found(&tree, (52..55));
        assert_not_found(&tree, (40..45));
        insert_and_validate(&mut tree, 80, 81);
        assert_intersections(&tree, (80..83), vec![(80..81)]);
        assert_not_found(&tree, (82..83));
        insert_and_validate(&mut tree, 30, 35);
        assert_intersections(&tree, (25..33), vec![(30..35)]);
        assert_not_found(&tree, (42..43));
        assert_not_found(&tree, (35..36));
        assert_not_found(&tree, (22..29));
        insert_and_validate(&mut tree, 70, 77);
        assert_intersections(&tree, (75..79), vec![(70..77)]);
        assert_not_found(&tree, (62..68));
        assert_intersections(&tree, (75..77), vec![(70..77)]);
        assert_not_found(&tree, (78..79));
        assert_intersections(&tree, (49..51), vec![(50..51)]);
        assert_intersections(&tree, (49..55), vec![(50..51)]);
        assert_not_found(&tree, (51..55));
        assert_not_found(&tree, (52..55));
        assert_not_found(&tree, (40..45));
        insert_and_validate(&mut tree, 101, 102);
        insert_and_validate(&mut tree, 103, 104);
        insert_and_validate(&mut tree, 105, 106);
        insert_and_validate(&mut tree, 107, 108);
        insert_and_validate(&mut tree, 111, 112);
        insert_and_validate(&mut tree, 113, 114);
        insert_and_validate(&mut tree, 115, 116);
        insert_and_validate(&mut tree, 117, 118);
        insert_and_validate(&mut tree, 119, 129);
        assert_not_found(&tree, (112..113));
        assert_not_found(&tree, (108..109));
        assert_intersections(&tree, (106..108), vec![(107..108)]);
    }
}
<|endoftext|>


<commit_before>//! FIXME: write short doc here

use std::{collections::HashSet, fmt::Write, path::Path, time::Instant};

use hir::{
    db::{DefDatabase, HirDatabase},
    AssocItem, Crate, HasSource, HirDisplay, ModuleDef,
};
use hir_def::FunctionId;
use hir_ty::{Ty, TypeWalk};
use ra_db::SourceDatabaseExt;
use ra_syntax::AstNode;

use crate::{progress_report::ProgressReport, Result, Verbosity};

pub fn run(
    verbosity: Verbosity,
    memory_usage: bool,
    path: &Path,
    only: Option<&str>,
    with_deps: bool,
) -> Result<()> {
    let db_load_time = Instant::now();
    let (mut host, roots) = ra_batch::load_cargo(path)?;
    let db = host.raw_database();
    println!("Database loaded, {} roots, {:?}", roots.len(), db_load_time.elapsed());
    let analysis_time = Instant::now();
    let mut num_crates = 0;
    let mut visited_modules = HashSet::new();
    let mut visit_queue = Vec::new();

    let members =
        roots
            .into_iter()
            .filter_map(|(source_root_id, project_root)| {
                if with_deps || project_root.is_member() {
                    Some(source_root_id)
                } else {
                    None
                }
            })
            .collect::<HashSet<_>>();

    for krate in Crate::all(db) {
        let module = krate.root_module(db).expect("crate without root module");
        let file_id = module.definition_source(db).file_id;
        if members.contains(&db.file_source_root(file_id.original_file(db))) {
            num_crates += 1;
            visit_queue.push(module);
        }
    }

    println!("Crates in this dir: {}", num_crates);
    let mut num_decls = 0;
    let mut funcs = Vec::new();
    while let Some(module) = visit_queue.pop() {
        if visited_modules.insert(module) {
            visit_queue.extend(module.children(db));

            for decl in module.declarations(db) {
                num_decls += 1;
                if let ModuleDef::Function(f) = decl {
                    funcs.push(f);
                }
            }

            for impl_block in module.impl_blocks(db) {
                for item in impl_block.items(db) {
                    num_decls += 1;
                    if let AssocItem::Function(f) = item {
                        funcs.push(f);
                    }
                }
            }
        }
    }
    println!("Total modules found: {}", visited_modules.len());
    println!("Total declarations: {}", num_decls);
    println!("Total functions: {}", funcs.len());
    println!("Item Collection: {:?}, {}", analysis_time.elapsed(), ra_prof::memory_usage());

    let inference_time = Instant::now();
    let mut bar = match verbosity {
        Verbosity::Verbose | Verbosity::Normal => ProgressReport::new(funcs.len() as u64),
        Verbosity::Quiet => ProgressReport::hidden(),
    };

    bar.tick();
    let mut num_exprs = 0;
    let mut num_exprs_unknown = 0;
    let mut num_exprs_partially_unknown = 0;
    let mut num_type_mismatches = 0;
    for f in funcs {
        let name = f.name(db);
        let mut msg = format!("processing: {}", name);
        if verbosity.is_verbose() {
            let src = f.source(db);
            let original_file = src.file_id.original_file(db);
            let path = db.file_relative_path(original_file);
            let syntax_range = src.value.syntax().text_range();
            write!(msg, " ({:?} {})", path, syntax_range).unwrap();
        }
        bar.set_message(&msg);
        if let Some(only_name) = only {
            if name.to_string() != only_name {
                continue;
            }
        }
        let f_id = FunctionId::from(f);
        let body = db.body(f_id.into());
        let inference_result = db.infer(f_id.into());
        for (expr_id, _) in body.exprs.iter() {
            let ty = &inference_result[expr_id];
            num_exprs += 1;
            if let Ty::Unknown = ty {
                num_exprs_unknown += 1;
            } else {
                let mut is_partially_unknown = false;
                ty.walk(&mut |ty| {
                    if let Ty::Unknown = ty {
                        is_partially_unknown = true;
                    }
                });
                if is_partially_unknown {
                    num_exprs_partially_unknown += 1;
                }
            }
            if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) {
                num_type_mismatches += 1;
                if verbosity.is_verbose() {
                    let (_, sm) = db.body_with_source_map(f_id.into());
                    let src = sm.expr_syntax(expr_id);
                    if let Some(src) = src {
                        // FIXME: it might be nice to have a function (on Analysis?) that goes from Source<T> -> (LineCol, LineCol) directly
                        let original_file = src.file_id.original_file(db);
                        let path = db.file_relative_path(original_file);
                        let line_index = host.analysis().file_line_index(original_file).unwrap();
                        let text_range = src.value.either(
                            |it| it.syntax_node_ptr().range(),
                            |it| it.syntax_node_ptr().range(),
                        );
                        let (start, end) = (
                            line_index.line_col(text_range.start()),
                            line_index.line_col(text_range.end()),
                        );
                        bar.println(format!(
                            "{} {}:{}-{}:{}: Expected {}, got {}",
                            path,
                            start.line + 1,
                            start.col_utf16,
                            end.line + 1,
                            end.col_utf16,
                            mismatch.expected.display(db),
                            mismatch.actual.display(db)
                        ));
                    } else {
                        bar.println(format!(
                            "{}: Expected {}, got {}",
                            name,
                            mismatch.expected.display(db),
                            mismatch.actual.display(db)
                        ));
                    }
                }
            }
        }
        bar.inc(1);
    }
    bar.finish_and_clear();
    println!("Total expressions: {}", num_exprs);
    println!(
        "Expressions of unknown type: {} ({}%)",
        num_exprs_unknown,
        if num_exprs > 0 { (num_exprs_unknown * 100 / num_exprs) } else { 100 }
    );
    println!(
        "Expressions of partially unknown type: {} ({}%)",
        num_exprs_partially_unknown,
        if num_exprs > 0 { (num_exprs_partially_unknown * 100 / num_exprs) } else { 100 }
    );
    println!("Type mismatches: {}", num_type_mismatches);
    println!("Inference: {:?}, {}", inference_time.elapsed(), ra_prof::memory_usage());
    println!("Total: {:?}, {}", analysis_time.elapsed(), ra_prof::memory_usage());

    if memory_usage {
        drop(db);
        for (name, bytes) in host.per_query_memory_usage() {
            println!("{:>8} {}", bytes, name)
        }
        let before = ra_prof::memory_usage();
        drop(host);
        println!("leftover: {}", before.allocated - ra_prof::memory_usage().allocated)
    }

    Ok(())
}
<commit_msg>Dropping a reference does nothing.<commit_after>//! FIXME: write short doc here

use std::{collections::HashSet, fmt::Write, path::Path, time::Instant};

use hir::{
    db::{DefDatabase, HirDatabase},
    AssocItem, Crate, HasSource, HirDisplay, ModuleDef,
};
use hir_def::FunctionId;
use hir_ty::{Ty, TypeWalk};
use ra_db::SourceDatabaseExt;
use ra_syntax::AstNode;

use crate::{progress_report::ProgressReport, Result, Verbosity};

pub fn run(
    verbosity: Verbosity,
    memory_usage: bool,
    path: &Path,
    only: Option<&str>,
    with_deps: bool,
) -> Result<()> {
    let db_load_time = Instant::now();
    let (mut host, roots) = ra_batch::load_cargo(path)?;
    let db = host.raw_database();
    println!("Database loaded, {} roots, {:?}", roots.len(), db_load_time.elapsed());
    let analysis_time = Instant::now();
    let mut num_crates = 0;
    let mut visited_modules = HashSet::new();
    let mut visit_queue = Vec::new();

    let members =
        roots
            .into_iter()
            .filter_map(|(source_root_id, project_root)| {
                if with_deps || project_root.is_member() {
                    Some(source_root_id)
                } else {
                    None
                }
            })
            .collect::<HashSet<_>>();

    for krate in Crate::all(db) {
        let module = krate.root_module(db).expect("crate without root module");
        let file_id = module.definition_source(db).file_id;
        if members.contains(&db.file_source_root(file_id.original_file(db))) {
            num_crates += 1;
            visit_queue.push(module);
        }
    }

    println!("Crates in this dir: {}", num_crates);
    let mut num_decls = 0;
    let mut funcs = Vec::new();
    while let Some(module) = visit_queue.pop() {
        if visited_modules.insert(module) {
            visit_queue.extend(module.children(db));

            for decl in module.declarations(db) {
                num_decls += 1;
                if let ModuleDef::Function(f) = decl {
                    funcs.push(f);
                }
            }

            for impl_block in module.impl_blocks(db) {
                for item in impl_block.items(db) {
                    num_decls += 1;
                    if let AssocItem::Function(f) = item {
                        funcs.push(f);
                    }
                }
            }
        }
    }
    println!("Total modules found: {}", visited_modules.len());
    println!("Total declarations: {}", num_decls);
    println!("Total functions: {}", funcs.len());
    println!("Item Collection: {:?}, {}", analysis_time.elapsed(), ra_prof::memory_usage());

    let inference_time = Instant::now();
    let mut bar = match verbosity {
        Verbosity::Verbose | Verbosity::Normal => ProgressReport::new(funcs.len() as u64),
        Verbosity::Quiet => ProgressReport::hidden(),
    };

    bar.tick();
    let mut num_exprs = 0;
    let mut num_exprs_unknown = 0;
    let mut num_exprs_partially_unknown = 0;
    let mut num_type_mismatches = 0;
    for f in funcs {
        let name = f.name(db);
        let mut msg = format!("processing: {}", name);
        if verbosity.is_verbose() {
            let src = f.source(db);
            let original_file = src.file_id.original_file(db);
            let path = db.file_relative_path(original_file);
            let syntax_range = src.value.syntax().text_range();
            write!(msg, " ({:?} {})", path, syntax_range).unwrap();
        }
        bar.set_message(&msg);
        if let Some(only_name) = only {
            if name.to_string() != only_name {
                continue;
            }
        }
        let f_id = FunctionId::from(f);
        let body = db.body(f_id.into());
        let inference_result = db.infer(f_id.into());
        for (expr_id, _) in body.exprs.iter() {
            let ty = &inference_result[expr_id];
            num_exprs += 1;
            if let Ty::Unknown = ty {
                num_exprs_unknown += 1;
            } else {
                let mut is_partially_unknown = false;
                ty.walk(&mut |ty| {
                    if let Ty::Unknown = ty {
                        is_partially_unknown = true;
                    }
                });
                if is_partially_unknown {
                    num_exprs_partially_unknown += 1;
                }
            }
            if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) {
                num_type_mismatches += 1;
                if verbosity.is_verbose() {
                    let (_, sm) = db.body_with_source_map(f_id.into());
                    let src = sm.expr_syntax(expr_id);
                    if let Some(src) = src {
                        // FIXME: it might be nice to have a function (on Analysis?) that goes from Source<T> -> (LineCol, LineCol) directly
                        let original_file = src.file_id.original_file(db);
                        let path = db.file_relative_path(original_file);
                        let line_index = host.analysis().file_line_index(original_file).unwrap();
                        let text_range = src.value.either(
                            |it| it.syntax_node_ptr().range(),
                            |it| it.syntax_node_ptr().range(),
                        );
                        let (start, end) = (
                            line_index.line_col(text_range.start()),
                            line_index.line_col(text_range.end()),
                        );
                        bar.println(format!(
                            "{} {}:{}-{}:{}: Expected {}, got {}",
                            path,
                            start.line + 1,
                            start.col_utf16,
                            end.line + 1,
                            end.col_utf16,
                            mismatch.expected.display(db),
                            mismatch.actual.display(db)
                        ));
                    } else {
                        bar.println(format!(
                            "{}: Expected {}, got {}",
                            name,
                            mismatch.expected.display(db),
                            mismatch.actual.display(db)
                        ));
                    }
                }
            }
        }
        bar.inc(1);
    }
    bar.finish_and_clear();
    println!("Total expressions: {}", num_exprs);
    println!(
        "Expressions of unknown type: {} ({}%)",
        num_exprs_unknown,
        if num_exprs > 0 { (num_exprs_unknown * 100 / num_exprs) } else { 100 }
    );
    println!(
        "Expressions of partially unknown type: {} ({}%)",
        num_exprs_partially_unknown,
        if num_exprs > 0 { (num_exprs_partially_unknown * 100 / num_exprs) } else { 100 }
    );
    println!("Type mismatches: {}", num_type_mismatches);
    println!("Inference: {:?}, {}", inference_time.elapsed(), ra_prof::memory_usage());
    println!("Total: {:?}, {}", analysis_time.elapsed(), ra_prof::memory_usage());

    if memory_usage {
        for (name, bytes) in host.per_query_memory_usage() {
            println!("{:>8} {}", bytes, name)
        }
        let before = ra_prof::memory_usage();
        drop(host);
        println!("leftover: {}", before.allocated - ra_prof::memory_usage().allocated)
    }

    Ok(())
}
<|endoftext|>


<commit_before>//! A map of all publicly exported items in a crate.

use crate::{
    db::DefDatabase,
    item_scope::ItemInNs,
    path::{ModPath, PathKind},
    visibility::Visibility,
    ModuleDefId, ModuleId,
};
use ra_db::CrateId;
use rustc_hash::FxHashMap;
use std::{collections::hash_map::Entry, sync::Arc};

/// A map from publicly exported items to the path needed to import/name them from a downstream
/// crate.
///
/// Reexports of items are taken into account, ie. if something is exported under multiple
/// names, the one with the shortest import path will be used.
///
/// Note that all paths are relative to the containing crate's root, so the crate name still needs
/// to be prepended to the `ModPath` before the path is valid.
#[derive(Debug, Eq, PartialEq)]
pub struct ImportMap {
    map: FxHashMap<ItemInNs, ModPath>,
}

impl ImportMap {
    pub fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<Self> {
        let _p = ra_prof::profile("import_map_query");
        let def_map = db.crate_def_map(krate);
        let mut import_map = FxHashMap::with_capacity_and_hasher(64, Default::default());

        // We look only into modules that are public(ly reexported), starting with the crate root.
        let empty = ModPath { kind: PathKind::Plain, segments: vec![] };
        let root = ModuleId { krate, local_id: def_map.root };
        let mut worklist = vec![(root, empty)];
        while let Some((module, mod_path)) = worklist.pop() {
            let ext_def_map;
            let mod_data = if module.krate == krate {
                &def_map[module.local_id]
            } else {
                // The crate might reexport a module defined in another crate.
                ext_def_map = db.crate_def_map(module.krate);
                &ext_def_map[module.local_id]
            };

            let visible_items = mod_data.scope.entries().filter_map(|(name, per_ns)| {
                let per_ns = per_ns.filter_visibility(|vis| vis == Visibility::Public);
                if per_ns.is_none() {
                    None
                } else {
                    Some((name, per_ns))
                }
            });

            for (name, per_ns) in visible_items {
                let mk_path = || {
                    let mut path = mod_path.clone();
                    path.segments.push(name.clone());
                    path
                };

                for item in per_ns.iter_items() {
                    let path = mk_path();
                    match import_map.entry(item) {
                        Entry::Vacant(entry) => {
                            entry.insert(path);
                        }
                        Entry::Occupied(mut entry) => {
                            // If the new path is shorter, prefer that one.
                            if path.len() < entry.get().len() {
                                *entry.get_mut() = path;
                            } else {
                                continue;
                            }
                        }
                    }

                    // If we've just added a path to a module, descend into it.
                    if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() {
                        worklist.push((mod_id, mk_path()));
                    }
                }
            }
        }

        Arc::new(Self { map: import_map })
    }

    /// Returns the `ModPath` needed to import/mention `item`, relative to this crate's root.
    pub fn path_of(&self, item: ItemInNs) -> Option<&ModPath> {
        self.map.get(&item)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::test_db::TestDB;
    use insta::assert_snapshot;
    use ra_db::fixture::WithFixture;
    use ra_db::SourceDatabase;

    fn import_map(ra_fixture: &str) -> String {
        let db = TestDB::with_files(ra_fixture);
        let crate_graph = db.crate_graph();

        let import_maps: Vec<_> = crate_graph
            .iter()
            .filter_map(|krate| {
                let cdata = &crate_graph[krate];
                let name = cdata.display_name.as_ref()?;

                let map = db.import_map(krate);

                let mut importable_paths: Vec<_> = map
                    .map
                    .iter()
                    .map(|(item, modpath)| {
                        let ns = match item {
                            ItemInNs::Types(_) => "t",
                            ItemInNs::Values(_) => "v",
                            ItemInNs::Macros(_) => "m",
                        };
                        format!("- {} ({})", modpath, ns)
                    })
                    .collect();

                importable_paths.sort();
                let importable_paths = importable_paths.join("\n");

                Some(format!("{}:\n{}", name, importable_paths))
            })
            .collect();

        import_maps.join("\n")
    }

    #[test]
    fn smoke() {
        let map = import_map(
            r"
            //- /main.rs crate:main deps:lib

            mod private {
                pub use lib::Pub;
                pub struct InPrivateModule;
            }

            pub mod publ1 {
                use lib::Pub;
            }

            pub mod real_pub {
                pub use lib::Pub;
            }
            pub mod real_pu2 { // same path length as above
                pub use lib::Pub;
            }

            //- /lib.rs crate:lib
            pub struct Pub {}
            pub struct Pub2; // t + v
            struct Priv;
        ",
        );

        assert_snapshot!(map, @r###"
        main:
        - publ1 (t)
        - real_pu2 (t)
        - real_pub (t)
        - real_pub::Pub (t)
        lib:
        - Pub (t)
        - Pub2 (t)
        - Pub2 (v)
        "###);
    }

    #[test]
    fn prefers_shortest_path() {
        let map = import_map(
            r"
            //- /main.rs crate:main

            pub mod sub {
                pub mod subsub {
                    pub struct Def {}
                }

                pub use super::sub::subsub::Def;
            }
        ",
        );

        assert_snapshot!(map, @r###"
        main:
        - sub (t)
        - sub::Def (t)
        - sub::subsub (t)
        "###);
    }

    #[test]
    fn type_reexport_cross_crate() {
        // Reexports need to be visible from a crate, even if the original crate exports the item
        // at a shorter path.
        let map = import_map(
            r"
            //- /main.rs crate:main deps:lib
            pub mod m {
                pub use lib::S;
            }
            //- /lib.rs crate:lib
            pub struct S;
        ",
        );

        assert_snapshot!(map, @r###"
        main:
        - m (t)
        - m::S (t)
        - m::S (v)
        lib:
        - S (t)
        - S (v)
        "###);
    }

    #[test]
    fn macro_reexport() {
        let map = import_map(
            r"
            //- /main.rs crate:main deps:lib
            pub mod m {
                pub use lib::pub_macro;
            }
            //- /lib.rs crate:lib
            #[macro_export]
            macro_rules! pub_macro {
                () => {};
            }
        ",
        );

        assert_snapshot!(map, @r###"
        main:
        - m (t)
        - m::pub_macro (m)
        lib:
        - pub_macro (m)
        "###);
    }

    #[test]
    fn module_reexport() {
        // Reexporting modules from a dependency adds all contents to the import map.
        let map = import_map(
            r"
            //- /main.rs crate:main deps:lib
            pub use lib::module as reexported_module;
            //- /lib.rs crate:lib
            pub mod module {
                pub struct S;
            }
        ",
        );

        assert_snapshot!(map, @r###"
        main:
        - reexported_module (t)
        - reexported_module::S (t)
        - reexported_module::S (v)
        lib:
        - module (t)
        - module::S (t)
        - module::S (v)
        "###);
    }

    #[test]
    fn cyclic_module_reexport() {
        // Reexporting modules from a dependency adds all contents to the import map.
        let map = import_map(
            r"
            //- /lib.rs crate:lib
            pub mod module {
                pub struct S;
                pub use super::sub::*;
            }

            pub mod sub {
                pub use super::module;
            }
        ",
        );

        assert_snapshot!(map, @r###"
        lib:
        - module (t)
        - module::S (t)
        - module::S (v)
        - sub (t)
        "###);
    }

    #[test]
    fn private_macro() {
        let map = import_map(
            r"
            //- /lib.rs crate:lib
            macro_rules! private_macro {
                () => {};
            }
        ",
        );

        assert_snapshot!(map, @r###"
        lib:
        "###);
    }
}
<commit_msg>Fix wrong comment<commit_after>//! A map of all publicly exported items in a crate.

use crate::{
    db::DefDatabase,
    item_scope::ItemInNs,
    path::{ModPath, PathKind},
    visibility::Visibility,
    ModuleDefId, ModuleId,
};
use ra_db::CrateId;
use rustc_hash::FxHashMap;
use std::{collections::hash_map::Entry, sync::Arc};

/// A map from publicly exported items to the path needed to import/name them from a downstream
/// crate.
///
/// Reexports of items are taken into account, ie. if something is exported under multiple
/// names, the one with the shortest import path will be used.
///
/// Note that all paths are relative to the containing crate's root, so the crate name still needs
/// to be prepended to the `ModPath` before the path is valid.
#[derive(Debug, Eq, PartialEq)]
pub struct ImportMap {
    map: FxHashMap<ItemInNs, ModPath>,
}

impl ImportMap {
    pub fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<Self> {
        let _p = ra_prof::profile("import_map_query");
        let def_map = db.crate_def_map(krate);
        let mut import_map = FxHashMap::with_capacity_and_hasher(64, Default::default());

        // We look only into modules that are public(ly reexported), starting with the crate root.
        let empty = ModPath { kind: PathKind::Plain, segments: vec![] };
        let root = ModuleId { krate, local_id: def_map.root };
        let mut worklist = vec![(root, empty)];
        while let Some((module, mod_path)) = worklist.pop() {
            let ext_def_map;
            let mod_data = if module.krate == krate {
                &def_map[module.local_id]
            } else {
                // The crate might reexport a module defined in another crate.
                ext_def_map = db.crate_def_map(module.krate);
                &ext_def_map[module.local_id]
            };

            let visible_items = mod_data.scope.entries().filter_map(|(name, per_ns)| {
                let per_ns = per_ns.filter_visibility(|vis| vis == Visibility::Public);
                if per_ns.is_none() {
                    None
                } else {
                    Some((name, per_ns))
                }
            });

            for (name, per_ns) in visible_items {
                let mk_path = || {
                    let mut path = mod_path.clone();
                    path.segments.push(name.clone());
                    path
                };

                for item in per_ns.iter_items() {
                    let path = mk_path();
                    match import_map.entry(item) {
                        Entry::Vacant(entry) => {
                            entry.insert(path);
                        }
                        Entry::Occupied(mut entry) => {
                            // If the new path is shorter, prefer that one.
                            if path.len() < entry.get().len() {
                                *entry.get_mut() = path;
                            } else {
                                continue;
                            }
                        }
                    }

                    // If we've just added a path to a module, descend into it.
                    if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() {
                        worklist.push((mod_id, mk_path()));
                    }
                }
            }
        }

        Arc::new(Self { map: import_map })
    }

    /// Returns the `ModPath` needed to import/mention `item`, relative to this crate's root.
    pub fn path_of(&self, item: ItemInNs) -> Option<&ModPath> {
        self.map.get(&item)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::test_db::TestDB;
    use insta::assert_snapshot;
    use ra_db::fixture::WithFixture;
    use ra_db::SourceDatabase;

    fn import_map(ra_fixture: &str) -> String {
        let db = TestDB::with_files(ra_fixture);
        let crate_graph = db.crate_graph();

        let import_maps: Vec<_> = crate_graph
            .iter()
            .filter_map(|krate| {
                let cdata = &crate_graph[krate];
                let name = cdata.display_name.as_ref()?;

                let map = db.import_map(krate);

                let mut importable_paths: Vec<_> = map
                    .map
                    .iter()
                    .map(|(item, modpath)| {
                        let ns = match item {
                            ItemInNs::Types(_) => "t",
                            ItemInNs::Values(_) => "v",
                            ItemInNs::Macros(_) => "m",
                        };
                        format!("- {} ({})", modpath, ns)
                    })
                    .collect();

                importable_paths.sort();
                let importable_paths = importable_paths.join("\n");

                Some(format!("{}:\n{}", name, importable_paths))
            })
            .collect();

        import_maps.join("\n")
    }

    #[test]
    fn smoke() {
        let map = import_map(
            r"
            //- /main.rs crate:main deps:lib

            mod private {
                pub use lib::Pub;
                pub struct InPrivateModule;
            }

            pub mod publ1 {
                use lib::Pub;
            }

            pub mod real_pub {
                pub use lib::Pub;
            }
            pub mod real_pu2 { // same path length as above
                pub use lib::Pub;
            }

            //- /lib.rs crate:lib
            pub struct Pub {}
            pub struct Pub2; // t + v
            struct Priv;
        ",
        );

        assert_snapshot!(map, @r###"
        main:
        - publ1 (t)
        - real_pu2 (t)
        - real_pub (t)
        - real_pub::Pub (t)
        lib:
        - Pub (t)
        - Pub2 (t)
        - Pub2 (v)
        "###);
    }

    #[test]
    fn prefers_shortest_path() {
        let map = import_map(
            r"
            //- /main.rs crate:main

            pub mod sub {
                pub mod subsub {
                    pub struct Def {}
                }

                pub use super::sub::subsub::Def;
            }
        ",
        );

        assert_snapshot!(map, @r###"
        main:
        - sub (t)
        - sub::Def (t)
        - sub::subsub (t)
        "###);
    }

    #[test]
    fn type_reexport_cross_crate() {
        // Reexports need to be visible from a crate, even if the original crate exports the item
        // at a shorter path.
        let map = import_map(
            r"
            //- /main.rs crate:main deps:lib
            pub mod m {
                pub use lib::S;
            }
            //- /lib.rs crate:lib
            pub struct S;
        ",
        );

        assert_snapshot!(map, @r###"
        main:
        - m (t)
        - m::S (t)
        - m::S (v)
        lib:
        - S (t)
        - S (v)
        "###);
    }

    #[test]
    fn macro_reexport() {
        let map = import_map(
            r"
            //- /main.rs crate:main deps:lib
            pub mod m {
                pub use lib::pub_macro;
            }
            //- /lib.rs crate:lib
            #[macro_export]
            macro_rules! pub_macro {
                () => {};
            }
        ",
        );

        assert_snapshot!(map, @r###"
        main:
        - m (t)
        - m::pub_macro (m)
        lib:
        - pub_macro (m)
        "###);
    }

    #[test]
    fn module_reexport() {
        // Reexporting modules from a dependency adds all contents to the import map.
        let map = import_map(
            r"
            //- /main.rs crate:main deps:lib
            pub use lib::module as reexported_module;
            //- /lib.rs crate:lib
            pub mod module {
                pub struct S;
            }
        ",
        );

        assert_snapshot!(map, @r###"
        main:
        - reexported_module (t)
        - reexported_module::S (t)
        - reexported_module::S (v)
        lib:
        - module (t)
        - module::S (t)
        - module::S (v)
        "###);
    }

    #[test]
    fn cyclic_module_reexport() {
        // A cyclic reexport does not hang.
        let map = import_map(
            r"
            //- /lib.rs crate:lib
            pub mod module {
                pub struct S;
                pub use super::sub::*;
            }

            pub mod sub {
                pub use super::module;
            }
        ",
        );

        assert_snapshot!(map, @r###"
        lib:
        - module (t)
        - module::S (t)
        - module::S (v)
        - sub (t)
        "###);
    }

    #[test]
    fn private_macro() {
        let map = import_map(
            r"
            //- /lib.rs crate:lib
            macro_rules! private_macro {
                () => {};
            }
        ",
        );

        assert_snapshot!(map, @r###"
        lib:
        "###);
    }
}
<|endoftext|>


<commit_before>use slack::{Event, RtmClient, EventHandler, Message};
use router::{Router,Rule};

pub struct TelescreenHandler {
    router: Router,
}

impl TelescreenHandler {
    pub fn new(router: Router) -> TelescreenHandler {
        TelescreenHandler { router: router }
    }

    pub fn send_message(&self, cli: &RtmClient, source_channel_id: &str, unwrapped_source_user_name: &str, source_text: &str) {
        let channel_name = self.get_channel_name_from_id(cli, source_channel_id);

        let unwrapped_channel_name = match channel_name {
            None => { warn!("No channel: {:?}", source_channel_id); return },
            Some(c) => c,
        };

        let rules: &Vec<Rule> = self.router.rules.as_ref();
        for rule in rules {
            if rule.regex.is_match(unwrapped_channel_name) {
                let dest_channel_id = cli.start_response().channels.as_ref()
                    .and_then(|channels| {
                        channels.iter().find(|chan| match chan.name {
                            None => false,
                            Some(ref name) => name == &(rule.destination),
                        })
                    })
                    .and_then(|chan| chan.id.as_ref());

                let dest_channel_id_unwrap = match dest_channel_id {
                    None => { warn!("No channel: {:?}", dest_channel_id); return },
                    Some(c) => c,
                };

                if unwrapped_channel_name != &(rule.destination) {
                    let message = format!("{:} [ <#{}> ]: {:}", unwrapped_source_user_name, source_channel_id, source_text);
                    info!("MESSAGE: {:?}", message);
                    let _ = cli.sender().send_message(&dest_channel_id_unwrap, &message);
                }
            }
        }
    }

    fn get_channel_name_from_id<'a>(&self, cli: &'a RtmClient, channel_id: &str) -> Option<&'a String> {
        cli.start_response().channels.as_ref()
            .and_then(|channels| {
                channels.iter().find(|chan| match chan.id {
                    None => false,
                    Some(ref id) => { id == channel_id },
                })
            })
            .and_then(|chan| chan.name.as_ref())
    }
}

#[allow(unused_variables)]
impl EventHandler for TelescreenHandler {
    fn on_event(&mut self, cli: &RtmClient, event: Event) {
        debug!("EVENT: {:?}", event);

        match event {
            Event::Message(event) => {
                match *event {
                    Message::Standard(message) => {
                        let source_user_id = match message.user {
                            None => { warn!("No user: {:?}", message.user); return },
                            Some(u) => u,
                        };
                        let source_channel_id = match message.channel {
                            None => { warn!("No channel: {:?}", message.channel); return },
                            Some(c) => c,
                        };
                        let source_text = match message.text {
                            None => { warn!("No text: {:?}", message.text); return },
                            Some(t) => t,
                        };

                        let source_user_name = cli.start_response()
                            .users
                            .as_ref()
                            .and_then(|users| {
                                users.iter().find(|user| match user.id {
                                    None => false,
                                    Some(ref name) => name.to_string() == source_user_id,
                                })
                            }).and_then(|user| user.name.as_ref());

                        let unwrapped_source_user_name = match source_user_name {
                            None => { warn!("No user: {:?}", source_user_name); return },
                            Some(t) => t,
                        };

                        self.send_message(cli, &source_channel_id, unwrapped_source_user_name, &source_text);
                    },
                    _ => { /* noop */ },
                }
            },
            _ => { /* noop */ },
        }
    }

    fn on_close(&mut self, cli: &RtmClient) {
        info!("Disconnected");
    }

    fn on_connect(&mut self, cli: &RtmClient) {
        info!("Connected");
    }
}
<commit_msg>Add new lines on post comments<commit_after>use slack::{Event, RtmClient, EventHandler, Message};
use router::{Router,Rule};

pub struct TelescreenHandler {
    router: Router,
}

impl TelescreenHandler {
    pub fn new(router: Router) -> TelescreenHandler {
        TelescreenHandler { router: router }
    }

    pub fn send_message(&self, cli: &RtmClient, source_channel_id: &str, unwrapped_source_user_name: &str, source_text: &str) {
        let channel_name = self.get_channel_name_from_id(cli, source_channel_id);

        let unwrapped_channel_name = match channel_name {
            None => { warn!("No channel: {:?}", source_channel_id); return },
            Some(c) => c,
        };

        let rules: &Vec<Rule> = self.router.rules.as_ref();
        for rule in rules {
            if rule.regex.is_match(unwrapped_channel_name) {
                let dest_channel_id = cli.start_response().channels.as_ref()
                    .and_then(|channels| {
                        channels.iter().find(|chan| match chan.name {
                            None => false,
                            Some(ref name) => name == &(rule.destination),
                        })
                    })
                    .and_then(|chan| chan.id.as_ref());

                let dest_channel_id_unwrap = match dest_channel_id {
                    None => { warn!("No channel: {:?}", dest_channel_id); return },
                    Some(c) => c,
                };

                if unwrapped_channel_name != &(rule.destination) {
                    let message = format!("{:} [ <#{}> ]:\n{:}", unwrapped_source_user_name, source_channel_id, source_text);
                    info!("MESSAGE: {:?}", message);
                    let _ = cli.sender().send_message(&dest_channel_id_unwrap, &message);
                }
            }
        }
    }

    fn get_channel_name_from_id<'a>(&self, cli: &'a RtmClient, channel_id: &str) -> Option<&'a String> {
        cli.start_response().channels.as_ref()
            .and_then(|channels| {
                channels.iter().find(|chan| match chan.id {
                    None => false,
                    Some(ref id) => { id == channel_id },
                })
            })
            .and_then(|chan| chan.name.as_ref())
    }
}

#[allow(unused_variables)]
impl EventHandler for TelescreenHandler {
    fn on_event(&mut self, cli: &RtmClient, event: Event) {
        debug!("EVENT: {:?}", event);

        match event {
            Event::Message(event) => {
                match *event {
                    Message::Standard(message) => {
                        let source_user_id = match message.user {
                            None => { warn!("No user: {:?}", message.user); return },
                            Some(u) => u,
                        };
                        let source_channel_id = match message.channel {
                            None => { warn!("No channel: {:?}", message.channel); return },
                            Some(c) => c,
                        };
                        let source_text = match message.text {
                            None => { warn!("No text: {:?}", message.text); return },
                            Some(t) => t,
                        };

                        let source_user_name = cli.start_response()
                            .users
                            .as_ref()
                            .and_then(|users| {
                                users.iter().find(|user| match user.id {
                                    None => false,
                                    Some(ref name) => name.to_string() == source_user_id,
                                })
                            }).and_then(|user| user.name.as_ref());

                        let unwrapped_source_user_name = match source_user_name {
                            None => { warn!("No user: {:?}", source_user_name); return },
                            Some(t) => t,
                        };

                        self.send_message(cli, &source_channel_id, unwrapped_source_user_name, &source_text);
                    },
                    _ => { /* noop */ },
                }
            },
            _ => { /* noop */ },
        }
    }

    fn on_close(&mut self, cli: &RtmClient) {
        info!("Disconnected");
    }

    fn on_connect(&mut self, cli: &RtmClient) {
        info!("Connected");
    }
}
<|endoftext|>


<commit_before>use std::convert::TryInto;
use std::sync::Arc;

use gfx;
use gfx::traits::FactoryExt;
use gfx_core;
use memmap::Mmap;
use vec_map::VecMap;

use coordinates::CoordinateSystem;
use runtime_texture::{TextureArray, TextureFormat};
use terrain::quadtree::{Node, NodeId};

#[derive(Clone, Copy, PartialEq, PartialOrd, Serialize, Deserialize)]
pub struct Priority(f32);
impl Priority {
    pub fn cutoff() -> Self {
        Priority(1.0)
    }
    pub fn none() -> Self {
        Priority(-1.0)
    }
    pub fn from_f32(value: f32) -> Self {
        assert!(value.is_finite());
        Priority(value)
    }
}
impl Eq for Priority {}
impl Ord for Priority {
    fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
        self.partial_cmp(other).unwrap()
    }
}

pub const NUM_LAYERS: usize = 5;

#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub(crate) enum LayerType {
    Heights = 0,
    Colors = 1,
    Normals = 2,
    Splats = 3,
    Foliage = 4,
}
impl LayerType {
    pub fn cache_size(&self) -> u16 {
        match *self {
            LayerType::Heights => 512,
            LayerType::Colors => 256,
            LayerType::Normals => 256,
            LayerType::Splats => 32,
            LayerType::Foliage => 64,
        }
    }
    pub fn index(&self) -> usize {
        *self as usize
    }
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub(crate) struct ByteRange {
    pub offset: usize,
    pub length: usize,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub(crate) enum PayloadType {
    Texture {
        /// Number of samples in each dimension, per tile.
        resolution: u32,
        /// Number of samples outside the tile on each side.
        border_size: u32,
        /// Format used by this layer.
        format: TextureFormat,
    },
    InstancedMesh {
        /// Actual mesh that is being instanced.
        mesh: MeshDescriptor,
        /// Texture map for the mesh.
        texture: TextureDescriptor,
        /// Maximum number of instances in any tile.
        max_instances: usize,
    },
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub(crate) struct LayerParams {
    /// What kind of layer this is. There can be at most one of each layer type in a file.
    pub layer_type: LayerType,
    /// Where each tile is located in the file.
    pub tile_locations: Vec<ByteRange>,
    /// What kind of data is stored in this layer.
    pub payload_type: PayloadType,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub(crate) struct NoiseParams {
    pub offset: usize,
    pub resolution: u32,
    pub format: TextureFormat,
    pub bytes: usize,
    pub wavelength: f32,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub(crate) struct MeshDescriptor {
    pub offset: usize,
    pub bytes: usize,
    pub num_vertices: usize,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub(crate) struct TextureDescriptor {
    pub offset: usize,
    pub resolution: u32,
    pub format: TextureFormat,
    pub bytes: usize,
}

#[derive(Serialize, Deserialize)]
pub(crate) struct TileHeader {
    pub layers: Vec<LayerParams>,
    pub noise: NoiseParams,
    pub nodes: Vec<Node>,
    pub planet_mesh: MeshDescriptor,
    pub planet_mesh_texture: TextureDescriptor,
    pub system: CoordinateSystem,
}

gfx_vertex_struct!(MeshInstance {
    position: [f32; 3] = "vPosition",
    color: [f32; 3] = "vColor",
    rotation: f32 = "vRotation",
    scale: f32 = "vScale",
    normal: [f32; 3] = "vNormal",
    padding1: f32 = "vPadding1",
    padding2: [f32; 4] = "vPadding2",
});

enum PayloadSet<R: gfx::Resources> {
    Texture {
        texture: TextureArray<R>,
        resolution: u16,
    },
    InstancedMesh {
        buffer: gfx::handle::Buffer<R, MeshInstance>,
        max_elements_per_slot: usize,
    },
}

pub(crate) struct TileCache<R: gfx::Resources> {
    /// Maximum number of slots in this `TileCache`.
    size: usize,
    /// Actually contents of the cache.
    slots: Vec<(Priority, NodeId)>,
    /// Which index each node is at in the cache (if any).
    reverse: VecMap<usize>,
    /// Nodes that should be added to the cache.
    missing: Vec<(Priority, NodeId)>,
    /// Smallest priority among all nodes in the cache.
    min_priority: Priority,

    /// Resolution of each tile in this cache.
    layer_params: LayerParams,

    payloads: PayloadSet<R>,

    /// Section of memory map that holds the data for this layer.
    data_file: Arc<Mmap>,
}
impl<R: gfx::Resources> TileCache<R> {
    pub fn new<F: gfx::Factory<R>>(
        params: LayerParams,
        data_file: Arc<Mmap>,
        factory: &mut F,
    ) -> Self {
        let cache_size = params.layer_type.cache_size();
        let payloads = match params.payload_type {
            PayloadType::Texture {
                resolution, format, ..
            } => PayloadSet::Texture {
                texture: TextureArray::new(format, resolution as u16, cache_size, factory),
                resolution: resolution.try_into().unwrap(),
            },
            PayloadType::InstancedMesh { max_instances, .. } => PayloadSet::InstancedMesh {
                buffer: factory.create_constant_buffer(max_instances * cache_size as usize),
                max_elements_per_slot: max_instances,
            },
        };

        Self {
            size: cache_size as usize,
            slots: Vec::new(),
            reverse: VecMap::new(),
            missing: Vec::new(),
            min_priority: Priority::none(),
            layer_params: params,
            data_file,
            payloads,
        }
    }

    pub fn update_priorities(&mut self, nodes: &mut Vec<Node>) {
        for &mut (ref mut priority, id) in self.slots.iter_mut() {
            *priority = nodes[id].priority();
        }

        self.min_priority = self
            .slots
            .iter()
            .map(|s| s.0)
            .min()
            .unwrap_or(Priority::none());
    }

    pub fn add_missing(&mut self, element: (Priority, NodeId)) {
        if element.0 > self.min_priority || self.slots.len() < self.size {
            self.missing.push(element);
        }
    }

    pub fn load_missing<C: gfx_core::command::Buffer<R>>(
        &mut self,
        nodes: &mut Vec<Node>,
        encoder: &mut gfx::Encoder<R, C>,
    ) {
        while !self.missing.is_empty() && self.slots.len() < self.size {
            let m = self.missing.pop().unwrap();
            let index = self.slots.len();
            self.slots.push(m.clone());
            self.reverse.insert(m.1.index(), index);
            self.load(&mut nodes[m.1], index, encoder);
        }

        if !self.missing.is_empty() {
            let mut possible: Vec<_> = self
                .slots
                .iter()
                .cloned()
                .chain(self.missing.iter().cloned())
                .collect();
            possible.sort();

            // Anything >= to cutoff should be included.
            let cutoff = possible[possible.len() - self.size];

            let mut index = 0;
            while let Some(m) = self.missing.pop() {
                if cutoff >= m {
                    continue;
                }

                // Find the next element to evict.
                while self.slots[index] >= cutoff {
                    index += 1;
                }

                self.reverse.remove(self.slots[index].1.index());
                self.reverse.insert(m.1.index(), index);
                self.slots[index] = m.clone();
                self.load(&mut nodes[m.1], index, encoder);
                index += 1;
            }
        }
    }

    fn load<C: gfx_core::command::Buffer<R>>(
        &mut self,
        node: &mut Node,
        slot: usize,
        encoder: &mut gfx::Encoder<R, C>,
    ) {
        let tile = node.tile_indices[self.layer_params.layer_type.index()].unwrap() as usize;
        let offset = self.layer_params.tile_locations[tile].offset;
        let length = self.layer_params.tile_locations[tile].length;
        let data = &self.data_file[offset..(offset + length)];

        match self.payloads {
            PayloadSet::Texture {
                ref mut texture,
                resolution,
            } => texture.update_layer(
                slot as u16,
                resolution,
                gfx::memory::cast_slice(data),
                encoder,
            ),
            PayloadSet::InstancedMesh {
                ref buffer,
                max_elements_per_slot,
            } => encoder
                .update_buffer(
                    buffer,
                    gfx::memory::cast_slice(data),
                    max_elements_per_slot * slot,
                ).unwrap(),
        }
    }

    pub fn contains(&self, id: NodeId) -> bool {
        self.reverse.contains_key(id.index())
    }

    pub fn get_slot(&self, id: NodeId) -> Option<usize> {
        self.reverse.get(id.index()).cloned()
    }

    pub fn get_texture_view_r8(&self) -> Option<&gfx_core::handle::ShaderResourceView<R, f32>> {
        match self.payloads {
            PayloadSet::Texture {
                texture: TextureArray::R8 { ref view, .. },
                ..
            } => Some(view),
            _ => None,
        }
    }

    pub fn get_texture_view_f32(&self) -> Option<&gfx_core::handle::ShaderResourceView<R, f32>> {
        match self.payloads {
            PayloadSet::Texture {
                texture: TextureArray::F32 { ref view, .. },
                ..
            } => Some(view),
            _ => None,
        }
    }

    pub fn get_texture_view_rgba8(
        &self,
    ) -> Option<&gfx_core::handle::ShaderResourceView<R, [f32; 4]>> {
        match self.payloads {
            PayloadSet::Texture {
                texture: TextureArray::RGBA8 { ref view, .. },
                ..
            } => Some(view),
            _ => None,
        }
    }

    pub fn get_texture_view_srgba(
        &self,
    ) -> Option<&gfx_core::handle::ShaderResourceView<R, [f32; 4]>> {
        match self.payloads {
            PayloadSet::Texture {
                texture: TextureArray::SRGBA { ref view, .. },
                ..
            } => Some(view),
            _ => None,
        }
    }

    pub fn get_buffer(&self) -> Option<&gfx::handle::Buffer<R, MeshInstance>> {
        match self.payloads {
            PayloadSet::InstancedMesh { ref buffer, .. } => Some(buffer),
            _ => None,
        }
    }

    pub fn get_instance_offset(&self, slot: usize) -> usize {
        if let PayloadSet::InstancedMesh {
            max_elements_per_slot,
            ..
        } = self.payloads
        {
            slot * max_elements_per_slot
        } else {
            unreachable!()
        }
    }

    pub fn get_instance_count(&self, node: &Node) -> usize {
        let tile = node.tile_indices[self.layer_params.layer_type.index()].unwrap() as usize;
        let length = self.layer_params.tile_locations[tile].length;
        (length as usize / ::std::mem::size_of::<MeshInstance>())
    }

    pub fn resolution(&self) -> u32 {
        match self.layer_params.payload_type {
            PayloadType::Texture { resolution, .. } => resolution,
            _ => unreachable!(),
        }
    }

    pub fn border(&self) -> u32 {
        match self.layer_params.payload_type {
            PayloadType::Texture { border_size, .. } => border_size,
            _ => unreachable!(),
        }
    }

    pub fn get_texel(&self, node: &Node, x: usize, y: usize) -> &[u8] {
        if let PayloadType::Texture {
            border_size,
            resolution,
            format,
        } = self.layer_params.payload_type
        {
            let tile = node.tile_indices[self.layer_params.layer_type.index()].unwrap() as usize;
            let offset = self.layer_params.tile_locations[tile].offset;
            let length = self.layer_params.tile_locations[tile].length;
            let tile_data = &self.data_file[offset..(offset + length)];
            let bytes_per_texel = format.bytes_per_texel();
            let border = border_size as usize;
            let index = ((x + border) + (y + border) * resolution as usize) * bytes_per_texel;
            &tile_data[index..(index + bytes_per_texel)]
        } else {
            unreachable!()
        }
    }
}

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

    #[test]
    fn mesh_instance_size() {
        assert_eq!(mem::size_of::<MeshInstance>(), 32);
    }
}
<commit_msg>Fix test<commit_after>use std::convert::TryInto;
use std::sync::Arc;

use gfx;
use gfx::traits::FactoryExt;
use gfx_core;
use memmap::Mmap;
use vec_map::VecMap;

use coordinates::CoordinateSystem;
use runtime_texture::{TextureArray, TextureFormat};
use terrain::quadtree::{Node, NodeId};

#[derive(Clone, Copy, PartialEq, PartialOrd, Serialize, Deserialize)]
pub struct Priority(f32);
impl Priority {
    pub fn cutoff() -> Self {
        Priority(1.0)
    }
    pub fn none() -> Self {
        Priority(-1.0)
    }
    pub fn from_f32(value: f32) -> Self {
        assert!(value.is_finite());
        Priority(value)
    }
}
impl Eq for Priority {}
impl Ord for Priority {
    fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
        self.partial_cmp(other).unwrap()
    }
}

pub const NUM_LAYERS: usize = 5;

#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub(crate) enum LayerType {
    Heights = 0,
    Colors = 1,
    Normals = 2,
    Splats = 3,
    Foliage = 4,
}
impl LayerType {
    pub fn cache_size(&self) -> u16 {
        match *self {
            LayerType::Heights => 512,
            LayerType::Colors => 256,
            LayerType::Normals => 256,
            LayerType::Splats => 32,
            LayerType::Foliage => 64,
        }
    }
    pub fn index(&self) -> usize {
        *self as usize
    }
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub(crate) struct ByteRange {
    pub offset: usize,
    pub length: usize,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub(crate) enum PayloadType {
    Texture {
        /// Number of samples in each dimension, per tile.
        resolution: u32,
        /// Number of samples outside the tile on each side.
        border_size: u32,
        /// Format used by this layer.
        format: TextureFormat,
    },
    InstancedMesh {
        /// Actual mesh that is being instanced.
        mesh: MeshDescriptor,
        /// Texture map for the mesh.
        texture: TextureDescriptor,
        /// Maximum number of instances in any tile.
        max_instances: usize,
    },
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub(crate) struct LayerParams {
    /// What kind of layer this is. There can be at most one of each layer type in a file.
    pub layer_type: LayerType,
    /// Where each tile is located in the file.
    pub tile_locations: Vec<ByteRange>,
    /// What kind of data is stored in this layer.
    pub payload_type: PayloadType,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub(crate) struct NoiseParams {
    pub offset: usize,
    pub resolution: u32,
    pub format: TextureFormat,
    pub bytes: usize,
    pub wavelength: f32,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub(crate) struct MeshDescriptor {
    pub offset: usize,
    pub bytes: usize,
    pub num_vertices: usize,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub(crate) struct TextureDescriptor {
    pub offset: usize,
    pub resolution: u32,
    pub format: TextureFormat,
    pub bytes: usize,
}

#[derive(Serialize, Deserialize)]
pub(crate) struct TileHeader {
    pub layers: Vec<LayerParams>,
    pub noise: NoiseParams,
    pub nodes: Vec<Node>,
    pub planet_mesh: MeshDescriptor,
    pub planet_mesh_texture: TextureDescriptor,
    pub system: CoordinateSystem,
}

gfx_vertex_struct!(MeshInstance {
    position: [f32; 3] = "vPosition",
    color: [f32; 3] = "vColor",
    rotation: f32 = "vRotation",
    scale: f32 = "vScale",
    normal: [f32; 3] = "vNormal",
    padding1: f32 = "vPadding1",
    padding2: [f32; 4] = "vPadding2",
});

enum PayloadSet<R: gfx::Resources> {
    Texture {
        texture: TextureArray<R>,
        resolution: u16,
    },
    InstancedMesh {
        buffer: gfx::handle::Buffer<R, MeshInstance>,
        max_elements_per_slot: usize,
    },
}

pub(crate) struct TileCache<R: gfx::Resources> {
    /// Maximum number of slots in this `TileCache`.
    size: usize,
    /// Actually contents of the cache.
    slots: Vec<(Priority, NodeId)>,
    /// Which index each node is at in the cache (if any).
    reverse: VecMap<usize>,
    /// Nodes that should be added to the cache.
    missing: Vec<(Priority, NodeId)>,
    /// Smallest priority among all nodes in the cache.
    min_priority: Priority,

    /// Resolution of each tile in this cache.
    layer_params: LayerParams,

    payloads: PayloadSet<R>,

    /// Section of memory map that holds the data for this layer.
    data_file: Arc<Mmap>,
}
impl<R: gfx::Resources> TileCache<R> {
    pub fn new<F: gfx::Factory<R>>(
        params: LayerParams,
        data_file: Arc<Mmap>,
        factory: &mut F,
    ) -> Self {
        let cache_size = params.layer_type.cache_size();
        let payloads = match params.payload_type {
            PayloadType::Texture {
                resolution, format, ..
            } => PayloadSet::Texture {
                texture: TextureArray::new(format, resolution as u16, cache_size, factory),
                resolution: resolution.try_into().unwrap(),
            },
            PayloadType::InstancedMesh { max_instances, .. } => PayloadSet::InstancedMesh {
                buffer: factory.create_constant_buffer(max_instances * cache_size as usize),
                max_elements_per_slot: max_instances,
            },
        };

        Self {
            size: cache_size as usize,
            slots: Vec::new(),
            reverse: VecMap::new(),
            missing: Vec::new(),
            min_priority: Priority::none(),
            layer_params: params,
            data_file,
            payloads,
        }
    }

    pub fn update_priorities(&mut self, nodes: &mut Vec<Node>) {
        for &mut (ref mut priority, id) in self.slots.iter_mut() {
            *priority = nodes[id].priority();
        }

        self.min_priority = self
            .slots
            .iter()
            .map(|s| s.0)
            .min()
            .unwrap_or(Priority::none());
    }

    pub fn add_missing(&mut self, element: (Priority, NodeId)) {
        if element.0 > self.min_priority || self.slots.len() < self.size {
            self.missing.push(element);
        }
    }

    pub fn load_missing<C: gfx_core::command::Buffer<R>>(
        &mut self,
        nodes: &mut Vec<Node>,
        encoder: &mut gfx::Encoder<R, C>,
    ) {
        while !self.missing.is_empty() && self.slots.len() < self.size {
            let m = self.missing.pop().unwrap();
            let index = self.slots.len();
            self.slots.push(m.clone());
            self.reverse.insert(m.1.index(), index);
            self.load(&mut nodes[m.1], index, encoder);
        }

        if !self.missing.is_empty() {
            let mut possible: Vec<_> = self
                .slots
                .iter()
                .cloned()
                .chain(self.missing.iter().cloned())
                .collect();
            possible.sort();

            // Anything >= to cutoff should be included.
            let cutoff = possible[possible.len() - self.size];

            let mut index = 0;
            while let Some(m) = self.missing.pop() {
                if cutoff >= m {
                    continue;
                }

                // Find the next element to evict.
                while self.slots[index] >= cutoff {
                    index += 1;
                }

                self.reverse.remove(self.slots[index].1.index());
                self.reverse.insert(m.1.index(), index);
                self.slots[index] = m.clone();
                self.load(&mut nodes[m.1], index, encoder);
                index += 1;
            }
        }
    }

    fn load<C: gfx_core::command::Buffer<R>>(
        &mut self,
        node: &mut Node,
        slot: usize,
        encoder: &mut gfx::Encoder<R, C>,
    ) {
        let tile = node.tile_indices[self.layer_params.layer_type.index()].unwrap() as usize;
        let offset = self.layer_params.tile_locations[tile].offset;
        let length = self.layer_params.tile_locations[tile].length;
        let data = &self.data_file[offset..(offset + length)];

        match self.payloads {
            PayloadSet::Texture {
                ref mut texture,
                resolution,
            } => texture.update_layer(
                slot as u16,
                resolution,
                gfx::memory::cast_slice(data),
                encoder,
            ),
            PayloadSet::InstancedMesh {
                ref buffer,
                max_elements_per_slot,
            } => encoder
                .update_buffer(
                    buffer,
                    gfx::memory::cast_slice(data),
                    max_elements_per_slot * slot,
                ).unwrap(),
        }
    }

    pub fn contains(&self, id: NodeId) -> bool {
        self.reverse.contains_key(id.index())
    }

    pub fn get_slot(&self, id: NodeId) -> Option<usize> {
        self.reverse.get(id.index()).cloned()
    }

    pub fn get_texture_view_r8(&self) -> Option<&gfx_core::handle::ShaderResourceView<R, f32>> {
        match self.payloads {
            PayloadSet::Texture {
                texture: TextureArray::R8 { ref view, .. },
                ..
            } => Some(view),
            _ => None,
        }
    }

    pub fn get_texture_view_f32(&self) -> Option<&gfx_core::handle::ShaderResourceView<R, f32>> {
        match self.payloads {
            PayloadSet::Texture {
                texture: TextureArray::F32 { ref view, .. },
                ..
            } => Some(view),
            _ => None,
        }
    }

    pub fn get_texture_view_rgba8(
        &self,
    ) -> Option<&gfx_core::handle::ShaderResourceView<R, [f32; 4]>> {
        match self.payloads {
            PayloadSet::Texture {
                texture: TextureArray::RGBA8 { ref view, .. },
                ..
            } => Some(view),
            _ => None,
        }
    }

    pub fn get_texture_view_srgba(
        &self,
    ) -> Option<&gfx_core::handle::ShaderResourceView<R, [f32; 4]>> {
        match self.payloads {
            PayloadSet::Texture {
                texture: TextureArray::SRGBA { ref view, .. },
                ..
            } => Some(view),
            _ => None,
        }
    }

    pub fn get_buffer(&self) -> Option<&gfx::handle::Buffer<R, MeshInstance>> {
        match self.payloads {
            PayloadSet::InstancedMesh { ref buffer, .. } => Some(buffer),
            _ => None,
        }
    }

    pub fn get_instance_offset(&self, slot: usize) -> usize {
        if let PayloadSet::InstancedMesh {
            max_elements_per_slot,
            ..
        } = self.payloads
        {
            slot * max_elements_per_slot
        } else {
            unreachable!()
        }
    }

    pub fn get_instance_count(&self, node: &Node) -> usize {
        let tile = node.tile_indices[self.layer_params.layer_type.index()].unwrap() as usize;
        let length = self.layer_params.tile_locations[tile].length;
        (length as usize / ::std::mem::size_of::<MeshInstance>())
    }

    pub fn resolution(&self) -> u32 {
        match self.layer_params.payload_type {
            PayloadType::Texture { resolution, .. } => resolution,
            _ => unreachable!(),
        }
    }

    pub fn border(&self) -> u32 {
        match self.layer_params.payload_type {
            PayloadType::Texture { border_size, .. } => border_size,
            _ => unreachable!(),
        }
    }

    pub fn get_texel(&self, node: &Node, x: usize, y: usize) -> &[u8] {
        if let PayloadType::Texture {
            border_size,
            resolution,
            format,
        } = self.layer_params.payload_type
        {
            let tile = node.tile_indices[self.layer_params.layer_type.index()].unwrap() as usize;
            let offset = self.layer_params.tile_locations[tile].offset;
            let length = self.layer_params.tile_locations[tile].length;
            let tile_data = &self.data_file[offset..(offset + length)];
            let bytes_per_texel = format.bytes_per_texel();
            let border = border_size as usize;
            let index = ((x + border) + (y + border) * resolution as usize) * bytes_per_texel;
            &tile_data[index..(index + bytes_per_texel)]
        } else {
            unreachable!()
        }
    }
}

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

    #[test]
    fn mesh_instance_size() {
        assert_eq!(mem::size_of::<MeshInstance>(), 64);
    }
}
<|endoftext|>