Documentation
extern crate interval_tree;

use interval_tree::segmentpoint::{SegmentPointTree};

fn main() {
    // In this example, I will show how to use the segment-point 
    // tree to implement a data structure for storing intervals
    // and answering queries about them. Each interval has a 
    // beginning, end (ints) and weight (also, intervals have no 
    // "holes" - they cover all numbers greater or equal to beginning
    // and smaller or equal to end). The beginning and end must be
    // within bounds supported upon the construction of the tree
    // Each query has one argument: point P. The answer to the 
    // query should be the sum of all intervals containg point P.
    // 
    // A naive approach would be to represent the interval as
    // an array, then upon inserting segment [p, q] with weight w,
    // the insert would be something like:
    //
    // for i in (p..q):
    //     interval[i] += w;
    // 
    // Querying would be simple returning value of array in given
    // point.
    // 
    // The problem with this solution is that each insert is
    // O(interval length), which may not be great (though insert
    // is O(1)). Using the tree below, both insert and query are
    // O(log max interval length)
    //
    //
    // Those are bounds within which all inserts and queries
    // must be contained. It shouldn't be a problem to have
    // a tree of bounds [-10^9, 10^9] - the nodes are constructed
    // lazily upon insertion of nodes.
    //

    let bounds = (2, 11);

    // Initial value of every point inside bounds
    let initial_value = 0;

    // Function to "combine" interval in each point - just
    // sum them. 
    let f = Box::new(|x: &i64, y: &i64| x + y);

    // We will use a segment-point tree - the one where
    // we put segments, and ask about points.
    let mut t = SegmentPointTree::new(bounds.0, bounds.1, initial_value, f);

    // the segment looks now like this:
    // positions: | 2| 3| 4| 5| 6| 7| 8| 9|10|11|  
    //   weights: | 0| 0| 0| 0| 0| 0| 0| 0| 0| 0|

    // store segment (1, 5) of weight 1:
    t.insert(3, 7, 1);

    // the segment looks now like this:
    // positions: | 2| 3| 4| 5| 6| 7| 8| 9|10|11|  
    //   weights: | 0| 1| 1| 1| 1| 1| 0| 0| 0| 0|

    assert_eq!(t.query(2), Some(0));
    assert_eq!(t.query(4), Some(1));
    assert_eq!(t.query(5), Some(1));
    assert_eq!(t.query(9), Some(0));

    // (15, 21) is not inside (2, 11), so this would panic:
    // t.insert(15, 21, 1);
    // (-2, 1) is als not inside (2, 11), so this would panic, too:
    // t.insert(-2, 1, 1);


    // store more segments:

    t.insert(2, 4, 1);
    // positions: | 2| 3| 4| 5| 6| 7| 8| 9|10|11|  
    //   weights: | 1| 2| 2| 1| 1| 1| 0| 0| 0| 0|

    assert_eq!(t.query(2), Some(1));
    assert_eq!(t.query(4), Some(2));
    assert_eq!(t.query(5), Some(1));
    assert_eq!(t.query(9), Some(0));

    t.insert(7, 9, 5);
    // positions: | 2| 3| 4| 5| 6| 7| 8| 9|10|11|  
    //   weights: | 1| 2| 2| 1| 1| 6| 5| 5| 0| 0|

    assert_eq!(t.query(2), Some(1));
    assert_eq!(t.query(4), Some(2));
    assert_eq!(t.query(5), Some(1));
    assert_eq!(t.query(7), Some(6));
    assert_eq!(t.query(9), Some(5));
   
    // querying outside range will yield None
    assert_eq!(t.query(-10), None);
    assert_eq!(t.query(10000), None);

    println!("All asserts OK.");
}