<commit_before>#![allow(dead_code)]

use std::collections::BTreeSet;
use std::fmt::{self, Display};
use parse::NextPrev;

#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Range(pub char, pub char);

impl fmt::Display for Range {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.0, self.1)
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Set(BTreeSet<Range>);

impl fmt::Display for Set {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let Set(ref set) = *self;
        let len = BTreeSet::len(set);

        for (count, s) in set.iter().enumerate() {
            if count < len - 1 { try!(write!(f, "{}, ", s)) }
            else { return write!(f, "{}", s) }
        }

        Ok(())
    }
}

impl Set {
    pub fn new() -> Self { Set(BTreeSet::new()) }
    pub fn insert(&mut self, value: Range) {
        let mut ret = BTreeSet::new();
        // value is a complete subset of one of the other ranges.
        let mut subset = false;

        // Borrowing self blocks later operation. Add a new scope.
        {   let Set(ref set) = *self;

            let Range(mut min_val, mut max_val) = value;
            if min_val > max_val { panic!("First value cannot be greater than the second.") }

            // Loop over set adding old disjoint pieces and supersets back.
            // When partially overlapped, expand value to the union. At the
            // end, insert union after it has been fully expanded.
            for &Range(min, max) in &*set {
                // value overlaps at the beginning.
                if min_val < min && max_val >= min && max_val < max { max_val = max }
                // value overlaps at the end.
                else if min_val > min && min_val <= max && max_val > max { min_val = min }
                // value is entirely contained between min and max. Insert original
                // into new array because new is a subset.
                else if min_val >= min && max_val <= max {
                    ret.insert(Range(min, max));
                    subset = true;
                }
                // value is a superset to the current so don't add current.
                else if min_val < min && max_val > max {}
                // value is disjoint with current so add current.
                else { ret.insert(Range(min, max)); }
            }

            // Insert value only when it's not a subset.
            if !subset { ret.insert(Range(min_val, max_val)); }
        }

        *self = Set(ret);
    }
    pub fn remove(&mut self, value: Range) {
        let mut ret = BTreeSet::new();

        // Borrowing self blocks later modification. Make a new scope to contain it.
        {   let Set(ref set) = *self;

            let Range(min_val, max_val) = value;
            if min_val > max_val { panic!("First value cannot be greater than the second.") }

            // Loop over set inserting whatever doesn't intersect.
            for &Range(min, max) in &*set {
                // value overlaps at the beginning.
                if min_val <= min && max_val >= min && max_val < max { ret.insert(Range(max_val.next(), max)); }
                // value overlaps at the end.
                else if min_val > min && min_val <= max && max_val >= max { ret.insert(Range(min, min_val.prev())); }
                // value is entirely contained between min and max. Split set
                // into two pieces.
                else if min_val > min && max_val < max {
                    ret.insert(Range(min, min_val.prev()));
                    ret.insert(Range(max_val.next(), max));

                    // Current piece was a superset so value cannot be anywhere else.
                    break;
                // value is a superset to the current so don't add current.
                } else if min_val <= min && max_val >= max {}
                // value is disjoint with current so add current.
                else { ret.insert(Range(min, max)); }
            }
        }

        *self = Set(ret)
    }
    // 123 + 345 = 12345.
    pub fn union(&self, value: &Self) -> Self {
        let mut ret = self.clone();

        // Loop over the btreeset of Range(char, char).
        for &x in &value.0 { ret.insert(x) }

        ret
    }
    // Intersection of `A` & `B` is `A - (A - B)`: 123 & 345 = 3.
    pub fn intersection(&self, value: &Self) -> Self {
        let diff = self.difference(value);

        self.difference(&diff)
    }
    // 123 - 345 = 12.
    pub fn difference(&self, value: &Self) -> Self {
        let mut ret = self.clone();

        for &x in &value.0 { ret.remove(x) }

        ret
    }
    // `A` ^ `B` is `(A + B) - (A & B)`: 123 ^ 345 = 1245.
    pub fn symmetric_difference(&self, value: &Self) -> Self {
        let union = self.union(value);
        let intersection = self.intersection(value);

        union.difference(&intersection)
    }
}

#[cfg(test)]
mod test {
    use super::{Range, Set};

    fn generate(vec: Vec<(char, char)>) -> Set {
        let mut set = Set::new();

        for (a, b) in vec {
            set.insert(Range(a, b));
        }

        set
    }
    #[test]
    fn insert_partial_overlap() {
        let set1 = generate(vec![('3', '5'), ('4', '6')]);
        let set2 = generate(vec![('3', '5'), ('1', '4')]);

        let other1 = generate(vec![('3', '6')]);
        let other2 = generate(vec![('1', '5')]);

        assert_eq!(other1, set1);
        assert_eq!(other2, set2);
    }
    #[test]
    fn insert_subset() {
        let set1 = generate(vec![('1', '5'), ('2', '3')]); // Complete overlap.
        let set2 = generate(vec![('1', '5'), ('1', '3')]); // Left is exact.
        let set3 = generate(vec![('1', '5'), ('2', '5')]); // Right is exact.
        let set4 = generate(vec![('1', '5'), ('1', '5')]); // Both are exact.

        let other = generate(vec![('1', '5')]);

        assert_eq!(set1, other);
        assert_eq!(set2, other);
        assert_eq!(set3, other);
        assert_eq!(set4, other);
    }
    #[test]
    fn insert_superset() {
        let set   = generate(vec![('3', '5'), ('2', '6')]);
        let other = generate(vec![('2', '6')]);

        assert_eq!(other, set);
    }
    #[test]
    #[should_panic]
    fn panic_on_decreasing_order() {
        generate(vec![('5', '3')]);
    }
    #[test]
    fn set_union() {
        let set1 = generate(vec![('1', '4'), ('5', '6')]);
        let set2 = generate(vec![('0', '5'), ('8', '9')]);

        let union = set1.union(&set2);

        let other = generate(vec![('0', '6'), ('8', '9')]);
        assert_eq!(union, other);
    }
    #[test]
    fn remove_partial_overlap() {
        let mut set1 = generate(vec![('5', '9')]);
        set1.remove(Range('3', '6')); // beginnings different.

        let mut set2 = generate(vec![('5', '9')]);
        set2.remove(Range('5', '6')); // beginnings same.

        let mut set3 = generate(vec![('2', '6')]);
        set3.remove(Range('5', '9')); // end different.

        let mut set4 = generate(vec![('2', '6')]);
        set4.remove(Range('5', '6')); // end same.

        let other12 = generate(vec![('7', '9')]);
        let other34 = generate(vec![('2', '4')]);

        assert_eq!(set1, other12);
        assert_eq!(set2, other12);
        assert_eq!(set3, other34);
        assert_eq!(set4, other34);
    }
    #[test]
    fn remove_subset() {
        let mut set = generate(vec![('1', '9')]);
        set.remove(Range('3', '6'));

        let other = generate(vec![('1', '2'), ('7', '9')]);

        assert_eq!(set, other);
    }
    #[test]
    fn remove_superset() {
        let mut set = generate(vec![('5', '6')]);
        set.remove(Range('3', '8'));

        let other = generate(vec![]);
        assert_eq!(set, other);
    }
    #[test]
    fn remove_disjoint() {
        let mut set = generate(vec![('2', '3')]);
        set.remove(Range('6', '8'));

        let other = generate(vec![('2', '3')]);
        assert_eq!(set, other);
    }
    #[test]
    fn set_difference() {
        let set1 = generate(vec![('2', '7')]);
        let set2 = generate(vec![('0', '1'),   // disjoint left
                                 ('1', '2'),   // partial overlap left
                                 ('4', '5'),   // subset
                                 ('7', '8'),   // partial overlap right
                                 ('9', '9')]); // disjoint right
        let letters1 = generate(vec![('c', 'e')]);
        let letters2 = generate(vec![('a', 'g')]); // superset

        let difference_set     = set1.difference(&set2);
        let difference_letters = letters1.difference(&letters2);

        let other_set     = generate(vec![('3', '3'), ('6', '6')]);
        let other_letters = generate(vec![]);

        assert_eq!(difference_set, other_set);
        assert_eq!(difference_letters, other_letters);
    }
    #[test]
    fn set_intersection_partial_overlap() {
        let set   = generate(vec![('2', '7')]);
        let left  = generate(vec![('0', '3')]);
        let right = generate(vec![('6', '8')]);

        let intersection_left  = set.intersection(&left);
        let intersection_right = set.intersection(&right);

        let other_left  = generate(vec![('2', '3')]);
        let other_right = generate(vec![('6', '7')]);

        assert_eq!(intersection_left, other_left);
        assert_eq!(intersection_right, other_right);
    }
    #[test]
    fn set_intersection_subset() {
        let set = generate(vec![('2', '7')]);

        let subset      = generate(vec![('3', '6')]);
        let exact_left  = generate(vec![('2', '6')]);
        let exact_right = generate(vec![('3', '7')]);

        let intersection_subset = set.intersection(&subset);
        let intersection_left   = set.intersection(&exact_left);
        let intersection_right  = set.intersection(&exact_right);
        let intersection_both   = set.intersection(&set);

        assert_eq!(intersection_subset, subset);
        assert_eq!(intersection_left, exact_left);
        assert_eq!(intersection_right, exact_right);
        assert_eq!(intersection_both, set);
    }
    #[test]
    fn set_intersection_superset() {
        let set      = generate(vec![('2', '7')]);
        let superset = generate(vec![('1', '8')]);

        let intersection = set.intersection(&superset);

        let other = generate(vec![('2', '7')]);
        assert_eq!(intersection, other);
    }
    #[test]
    fn set_intersection_disjoint() {
        let set = generate(vec![('3', '4')]);

        let low  = generate(vec![('1', '2')]);
        let high = generate(vec![('5', '6')]);

        let intersection_low  = set.intersection(&low);
        let intersection_high = set.intersection(&high);

        let other_low  = generate(vec![]);
        let other_high = generate(vec![]);

        assert_eq!(intersection_low, other_low);
        assert_eq!(intersection_high, other_high);
    }
    #[test]
    fn set_symmetric_difference_partial_overlap() {
        let set = generate(vec![('3', '6')]);

        let low  = generate(vec![('1', '4')]);
        let high = generate(vec![('5', '9')]);

        let sym_dif_low  = set.symmetric_difference(&low);
        let sym_dif_high = set.symmetric_difference(&high);

        let other_low  = generate(vec![('1', '2'), ('5', '6')]);
        let other_high = generate(vec![('3', '4'), ('7', '9')]);

        assert_eq!(sym_dif_low, other_low);
        assert_eq!(sym_dif_high, other_high);
    }
    #[test]
    fn set_symmetric_difference_subset() {
        let set = generate(vec![('2', '7')]);

        let subset      = generate(vec![('3', '6')]);
        let exact_left  = generate(vec![('2', '6')]);
        let exact_right = generate(vec![('3', '7')]);

        let sym_dif_subset = set.symmetric_difference(&subset);
        let sym_dif_left   = set.symmetric_difference(&exact_left);
        let sym_dif_right  = set.symmetric_difference(&exact_right);
        let sym_dif_both   = set.symmetric_difference(&set);

        let other_subset = generate(vec![('2', '2'), ('7', '7')]);
        let other_left   = generate(vec![('7', '7')]);
        let other_right  = generate(vec![('2', '2')]);
        let other_both   = generate(vec![]);

        assert_eq!(sym_dif_subset, other_subset);
        assert_eq!(sym_dif_left, other_left);
        assert_eq!(sym_dif_right, other_right);
        assert_eq!(sym_dif_both, other_both);
    }
    #[test]
    fn set_symmetric_difference_superset() {
        let set      = generate(vec![('2', '7')]);
        let superset = generate(vec![('1', '8')]);

        let sym_dif = set.symmetric_difference(&superset);

        let other = generate(vec![('1', '1'), ('8', '8')]);
        assert_eq!(sym_dif, other);
    }
    fn set_symmetric_difference_disjoint() {
        let set = generate(vec![('3', '4')]);

        let low  = generate(vec![('1', '2')]);
        let high = generate(vec![('5', '6')]);

        let sym_dif_low  = set.symmetric_difference(&low);
        let sym_dif_high = set.symmetric_difference(&high);

        let other_low  = generate(vec![('1', '4')]);
        let other_high = generate(vec![('3', '6')]);

        assert_eq!(sym_dif_low, other_low);
        assert_eq!(sym_dif_high, other_high);
    }
}
<commit_msg>Add some docs to range_set<commit_after>#![allow(dead_code)]

//! A set library to aid character set manipulation.
//!
//! `range_set` aims to make it easier to handle set manipulation for characters
//! over ranges. For example, a unicode library may expose character ranges such
//! as `('0', '9')` as a sequence of digits. If I was already later state I would
//! like to add the sequence of digits: `('1', '3')`, it would consider them as
//! distinct and store both. This is a nuisance. It should recognize that `1-3`
//! is encased inside `0-9` and leave it as is.
//!
//! It provides the standard set operations: union, intersection, difference,
//! and symmetric difference.

use std::collections::BTreeSet;
use std::fmt::{self, Display};
use parse::NextPrev;

#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Range(pub char, pub char);

impl fmt::Display for Range {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.0, self.1)
    }
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Set(BTreeSet<Range>);

impl fmt::Display for Set {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let Set(ref set) = *self;
        let len = BTreeSet::len(set);

        for (count, s) in set.iter().enumerate() {
            if count < len - 1 { try!(write!(f, "{}, ", s)) }
            else { return write!(f, "{}", s) }
        }

        Ok(())
    }
}

impl Set {
    pub fn new() -> Self { Set(BTreeSet::new()) }
    pub fn insert(&mut self, value: Range) {
        let mut ret = BTreeSet::new();
        // value is a complete subset of one of the other ranges.
        let mut subset = false;

        // Borrowing self blocks later operation. Add a new scope.
        {   let Set(ref set) = *self;

            let Range(mut min_val, mut max_val) = value;
            if min_val > max_val { panic!("First value cannot be greater than the second.") }

            // Loop over set adding old disjoint pieces and supersets back.
            // When partially overlapped, expand value to the union. At the
            // end, insert union after it has been fully expanded.
            for &Range(min, max) in &*set {
                // value overlaps at the beginning.
                if min_val < min && max_val >= min && max_val < max { max_val = max }
                // value overlaps at the end.
                else if min_val > min && min_val <= max && max_val > max { min_val = min }
                // value is entirely contained between min and max. Insert original
                // into new array because new is a subset.
                else if min_val >= min && max_val <= max {
                    ret.insert(Range(min, max));
                    subset = true;
                }
                // value is a superset to the current so don't add current.
                else if min_val < min && max_val > max {}
                // value is disjoint with current so add current.
                else { ret.insert(Range(min, max)); }
            }

            // Insert value only when it's not a subset.
            if !subset { ret.insert(Range(min_val, max_val)); }
        }

        *self = Set(ret);
    }
    pub fn remove(&mut self, value: Range) {
        let mut ret = BTreeSet::new();

        // Borrowing self blocks later modification. Make a new scope to contain it.
        {   let Set(ref set) = *self;

            let Range(min_val, max_val) = value;
            if min_val > max_val { panic!("First value cannot be greater than the second.") }

            // Loop over set inserting whatever doesn't intersect.
            for &Range(min, max) in &*set {
                // value overlaps at the beginning.
                if min_val <= min && max_val >= min && max_val < max { ret.insert(Range(max_val.next(), max)); }
                // value overlaps at the end.
                else if min_val > min && min_val <= max && max_val >= max { ret.insert(Range(min, min_val.prev())); }
                // value is entirely contained between min and max. Split set
                // into two pieces.
                else if min_val > min && max_val < max {
                    ret.insert(Range(min, min_val.prev()));
                    ret.insert(Range(max_val.next(), max));

                    // Current piece was a superset so value cannot be anywhere else.
                    break;
                // value is a superset to the current so don't add current.
                } else if min_val <= min && max_val >= max {}
                // value is disjoint with current so add current.
                else { ret.insert(Range(min, max)); }
            }
        }

        *self = Set(ret)
    }
    // 123 + 345 = 12345.
    pub fn union(&self, value: &Self) -> Self {
        let mut ret = self.clone();

        // Loop over the btreeset of Range(char, char).
        for &x in &value.0 { ret.insert(x) }

        ret
    }
    // Intersection of `A` & `B` is `A - (A - B)`: 123 & 345 = 3.
    pub fn intersection(&self, value: &Self) -> Self {
        let diff = self.difference(value);

        self.difference(&diff)
    }
    // 123 - 345 = 12.
    pub fn difference(&self, value: &Self) -> Self {
        let mut ret = self.clone();

        for &x in &value.0 { ret.remove(x) }

        ret
    }
    // `A` ^ `B` is `(A + B) - (A & B)`: 123 ^ 345 = 1245.
    pub fn symmetric_difference(&self, value: &Self) -> Self {
        let union = self.union(value);
        let intersection = self.intersection(value);

        union.difference(&intersection)
    }
}

#[cfg(test)]
mod test {
    use super::{Range, Set};

    fn generate(vec: Vec<(char, char)>) -> Set {
        let mut set = Set::new();

        for (a, b) in vec {
            set.insert(Range(a, b));
        }

        set
    }
    #[test]
    fn insert_partial_overlap() {
        let set1 = generate(vec![('3', '5'), ('4', '6')]);
        let set2 = generate(vec![('3', '5'), ('1', '4')]);

        let other1 = generate(vec![('3', '6')]);
        let other2 = generate(vec![('1', '5')]);

        assert_eq!(other1, set1);
        assert_eq!(other2, set2);
    }
    #[test]
    fn insert_subset() {
        let set1 = generate(vec![('1', '5'), ('2', '3')]); // Complete overlap.
        let set2 = generate(vec![('1', '5'), ('1', '3')]); // Left is exact.
        let set3 = generate(vec![('1', '5'), ('2', '5')]); // Right is exact.
        let set4 = generate(vec![('1', '5'), ('1', '5')]); // Both are exact.

        let other = generate(vec![('1', '5')]);

        assert_eq!(set1, other);
        assert_eq!(set2, other);
        assert_eq!(set3, other);
        assert_eq!(set4, other);
    }
    #[test]
    fn insert_superset() {
        let set   = generate(vec![('3', '5'), ('2', '6')]);
        let other = generate(vec![('2', '6')]);

        assert_eq!(other, set);
    }
    #[test]
    #[should_panic]
    fn panic_on_decreasing_order() {
        generate(vec![('5', '3')]);
    }
    #[test]
    fn set_union() {
        let set1 = generate(vec![('1', '4'), ('5', '6')]);
        let set2 = generate(vec![('0', '5'), ('8', '9')]);

        let union = set1.union(&set2);

        let other = generate(vec![('0', '6'), ('8', '9')]);
        assert_eq!(union, other);
    }
    #[test]
    fn remove_partial_overlap() {
        let mut set1 = generate(vec![('5', '9')]);
        set1.remove(Range('3', '6')); // beginnings different.

        let mut set2 = generate(vec![('5', '9')]);
        set2.remove(Range('5', '6')); // beginnings same.

        let mut set3 = generate(vec![('2', '6')]);
        set3.remove(Range('5', '9')); // end different.

        let mut set4 = generate(vec![('2', '6')]);
        set4.remove(Range('5', '6')); // end same.

        let other12 = generate(vec![('7', '9')]);
        let other34 = generate(vec![('2', '4')]);

        assert_eq!(set1, other12);
        assert_eq!(set2, other12);
        assert_eq!(set3, other34);
        assert_eq!(set4, other34);
    }
    #[test]
    fn remove_subset() {
        let mut set = generate(vec![('1', '9')]);
        set.remove(Range('3', '6'));

        let other = generate(vec![('1', '2'), ('7', '9')]);

        assert_eq!(set, other);
    }
    #[test]
    fn remove_superset() {
        let mut set = generate(vec![('5', '6')]);
        set.remove(Range('3', '8'));

        let other = generate(vec![]);
        assert_eq!(set, other);
    }
    #[test]
    fn remove_disjoint() {
        let mut set = generate(vec![('2', '3')]);
        set.remove(Range('6', '8'));

        let other = generate(vec![('2', '3')]);
        assert_eq!(set, other);
    }
    #[test]
    fn set_difference() {
        let set1 = generate(vec![('2', '7')]);
        let set2 = generate(vec![('0', '1'),   // disjoint left
                                 ('1', '2'),   // partial overlap left
                                 ('4', '5'),   // subset
                                 ('7', '8'),   // partial overlap right
                                 ('9', '9')]); // disjoint right
        let letters1 = generate(vec![('c', 'e')]);
        let letters2 = generate(vec![('a', 'g')]); // superset

        let difference_set     = set1.difference(&set2);
        let difference_letters = letters1.difference(&letters2);

        let other_set     = generate(vec![('3', '3'), ('6', '6')]);
        let other_letters = generate(vec![]);

        assert_eq!(difference_set, other_set);
        assert_eq!(difference_letters, other_letters);
    }
    #[test]
    fn set_intersection_partial_overlap() {
        let set   = generate(vec![('2', '7')]);
        let left  = generate(vec![('0', '3')]);
        let right = generate(vec![('6', '8')]);

        let intersection_left  = set.intersection(&left);
        let intersection_right = set.intersection(&right);

        let other_left  = generate(vec![('2', '3')]);
        let other_right = generate(vec![('6', '7')]);

        assert_eq!(intersection_left, other_left);
        assert_eq!(intersection_right, other_right);
    }
    #[test]
    fn set_intersection_subset() {
        let set = generate(vec![('2', '7')]);

        let subset      = generate(vec![('3', '6')]);
        let exact_left  = generate(vec![('2', '6')]);
        let exact_right = generate(vec![('3', '7')]);

        let intersection_subset = set.intersection(&subset);
        let intersection_left   = set.intersection(&exact_left);
        let intersection_right  = set.intersection(&exact_right);
        let intersection_both   = set.intersection(&set);

        assert_eq!(intersection_subset, subset);
        assert_eq!(intersection_left, exact_left);
        assert_eq!(intersection_right, exact_right);
        assert_eq!(intersection_both, set);
    }
    #[test]
    fn set_intersection_superset() {
        let set      = generate(vec![('2', '7')]);
        let superset = generate(vec![('1', '8')]);

        let intersection = set.intersection(&superset);

        let other = generate(vec![('2', '7')]);
        assert_eq!(intersection, other);
    }
    #[test]
    fn set_intersection_disjoint() {
        let set = generate(vec![('3', '4')]);

        let low  = generate(vec![('1', '2')]);
        let high = generate(vec![('5', '6')]);

        let intersection_low  = set.intersection(&low);
        let intersection_high = set.intersection(&high);

        let other_low  = generate(vec![]);
        let other_high = generate(vec![]);

        assert_eq!(intersection_low, other_low);
        assert_eq!(intersection_high, other_high);
    }
    #[test]
    fn set_symmetric_difference_partial_overlap() {
        let set = generate(vec![('3', '6')]);

        let low  = generate(vec![('1', '4')]);
        let high = generate(vec![('5', '9')]);

        let sym_dif_low  = set.symmetric_difference(&low);
        let sym_dif_high = set.symmetric_difference(&high);

        let other_low  = generate(vec![('1', '2'), ('5', '6')]);
        let other_high = generate(vec![('3', '4'), ('7', '9')]);

        assert_eq!(sym_dif_low, other_low);
        assert_eq!(sym_dif_high, other_high);
    }
    #[test]
    fn set_symmetric_difference_subset() {
        let set = generate(vec![('2', '7')]);

        let subset      = generate(vec![('3', '6')]);
        let exact_left  = generate(vec![('2', '6')]);
        let exact_right = generate(vec![('3', '7')]);

        let sym_dif_subset = set.symmetric_difference(&subset);
        let sym_dif_left   = set.symmetric_difference(&exact_left);
        let sym_dif_right  = set.symmetric_difference(&exact_right);
        let sym_dif_both   = set.symmetric_difference(&set);

        let other_subset = generate(vec![('2', '2'), ('7', '7')]);
        let other_left   = generate(vec![('7', '7')]);
        let other_right  = generate(vec![('2', '2')]);
        let other_both   = generate(vec![]);

        assert_eq!(sym_dif_subset, other_subset);
        assert_eq!(sym_dif_left, other_left);
        assert_eq!(sym_dif_right, other_right);
        assert_eq!(sym_dif_both, other_both);
    }
    #[test]
    fn set_symmetric_difference_superset() {
        let set      = generate(vec![('2', '7')]);
        let superset = generate(vec![('1', '8')]);

        let sym_dif = set.symmetric_difference(&superset);

        let other = generate(vec![('1', '1'), ('8', '8')]);
        assert_eq!(sym_dif, other);
    }
    fn set_symmetric_difference_disjoint() {
        let set = generate(vec![('3', '4')]);

        let low  = generate(vec![('1', '2')]);
        let high = generate(vec![('5', '6')]);

        let sym_dif_low  = set.symmetric_difference(&low);
        let sym_dif_high = set.symmetric_difference(&high);

        let other_low  = generate(vec![('1', '4')]);
        let other_high = generate(vec![('3', '6')]);

        assert_eq!(sym_dif_low, other_low);
        assert_eq!(sym_dif_high, other_high);
    }
}
<|endoftext|>


<commit_before>extern crate regex;

mod matching;
mod support;
mod tokens;
mod lexer;
mod files;
mod symbol_table;
mod plp;
mod compiler;

use std::vec::Vec;
use tokens::*;
use symbol_table::symbol_table::*;
use lexer::*;
use support::*;
use compiler::*;

fn main()
{
    let source_file = "sampleData/BasicArithmatic.java";
    let lex_output_file = "sampleData/output/stable/BasicArithmatic.java.lexed";
    let preprocessed_output_file = "sampleData/output/stable/BasicArithmatic.java.preprocessed";

    let mut tokens: Vec<Token> = lex_file(source_file);

    println!("\n\nFound Tokens:");
    tokens.print_to(lex_output_file, true);

    remove_meta(&mut tokens);
    println!("\n\nPerged Tokens:");
    tokens.print_to(preprocessed_output_file, true);

    let mut symbols_table: SymbolTable = SymbolTable {signature: "", return_type:"", package_path: ""};
    let class_structure = parse_class(&tokens, 1, &mut symbols_table);

    if tokens[0].value != "class"
    {
        panic!("Unexpected token: {}: {}", tokens[0].value, tokens[0].name);
    }

    let (last_index, asm_string) = compile_class(&tokens, 1);
}

fn parse_class(tokens: &Vec<Token>, start_index: usize, symbols_table: &mut SymbolTable) -> ClassStructure
{
    let mut class_structure: ClassStructure = ClassStructure::new();

    println!("\n<------------ Parse Class --------------->");
    let mut min_value = 0;
    let mut skip_amount = 0;

    for (index, token) in tokens.iter().enumerate()
    {
        if min_value != 0
        {
            min_value -= 1;
            continue;
        }
        //Static Variable/Method/Class
        if token.name == "mod.access"
        {
            skip_amount = 3;
            if tokens[index + skip_amount].name.starts_with("operator")
            {
                println!("------Incoming Static Variable Decl!");

                let low = index + 1;
                let high = find_next(tokens, low, ";").unwrap() + 1;

                class_structure.static_variables.push((low, high));

                min_value =  low;
                min_value -= index;
            }
            else if tokens[index + skip_amount].name == "identifier"
            {
                //TODO account for final
                println!("------Incoming Static Variable Decl!");

                let low = index + 2;
                let high = find_next(tokens, low, ";").unwrap() + 1;
                class_structure.static_variables.push((low, high));

                min_value =  low;
                min_value -= index;
            }
            else if tokens[index + 1].name.starts_with("construct")
            {
                if tokens[index + skip_amount].name.starts_with("control")
                {
                    println!("------Incoming Static Class Decl!");
                    // TODO: verify this index starts past the first open brace
                    min_value = identify_body_bounds(tokens, index, ("{", "}")).unwrap();
                    class_structure.static_classes.push((index + 2, min_value));
                    min_value -= index;
                }
                else
                {
                    panic!("Unsupported or Unexpected token: {} + {}.", tokens[index + skip_amount].value, tokens[index + skip_amount].name);
                }

            }
            else if tokens[index + skip_amount].name.starts_with("control")
            {
                println!("------Incoming Static Method Decl!");
                // TODO: verify this index starts past the first open brace
                min_value = identify_body_bounds(tokens, index, ("{", "}")).unwrap();
                class_structure.static_methods.push((index + 1, min_value));
                min_value -=  index;
            }
            else
            {
                panic!("Unsupported or Unexpected token: {}: {}.", tokens[index + skip_amount].value, tokens[index + skip_amount].name);
            }

        }
        //Non-Static Variable/Method/Class
        else if token.name.starts_with("construct")
        {
            skip_amount = 2;
            if tokens[index + skip_amount].name.starts_with("control")
            {
                println!("------Incoming Non-Static Class Decl!");
                let index_after_brace = index + skip_amount + 1;
                min_value = identify_body_bounds(tokens, index_after_brace, ("{", "}")).unwrap();
                class_structure.non_static_classes.push((index + 1, min_value));
                //TODO parse_class(tokens, index, symbols_table);
                min_value = 0;
            }
            else
            {
                panic!("Unsupported or Unexpected token: {} + {}.", tokens[index + skip_amount].value, tokens[index + skip_amount].name);
            }
        }
        //Non-Static Variable/Method/Class
        else if token.name == "type"
        {
            skip_amount = 2;

            if tokens[index + skip_amount].name.starts_with("control")
            {
                println!("------Incoming Non-Static Method Decl!");
                // TODO: verify this index starts past the first open brace
                min_value = identify_body_bounds(tokens, index, ("{", "}")).unwrap();
                class_structure.non_static_methods.push((index, min_value));
                min_value -= index;
                //check for control
            }
            else if tokens[index + skip_amount].name.starts_with("operator")
            {
                println!("------Incoming Non-Static Variable Decl!");
                min_value =  find_next(tokens, index, ";").unwrap();
                class_structure.non_static_variables.push((index, min_value));
                min_value -= index;
            }
        }
        println!("\tIndex: {} | Token -> {} : {}", index, token.value, token.name );
        //deal with parameters
    }
    println!("\n<---------------- Static Variables --------------->");
    for &(start, end) in class_structure.static_variables.iter()
    {
        println!("Start/End {}/{}", start, end);
    }

    println!("\n<---------------- Static Classes ----------------->");
    for &(start, end) in class_structure.static_classes.iter()
    {
        println!("Start/End {}/{}", start, end);
    }

    println!("\n<---------------- Static Methods ----------------->");
    for &(start, end) in class_structure.static_methods.iter()
    {
        println!("Start/End {}/{}", start, end);
    }

    println!("\n<---------------- Non-Static Variables --------------->");
    for &(start, end) in class_structure.non_static_variables.iter()
    {
        println!("Start/End {}/{}", start, end);
    }

    println!("\n<---------------- Non-Static Classes ----------------->");
    for &(start, end) in class_structure.non_static_classes.iter()
    {
        println!("Start/End {}/{}", start, end);
    }

    println!("\n<---------------- Non-Static Methods ----------------->");
    for &(start, end) in class_structure.non_static_methods.iter()
    {
        println!("Start/End {}/{}", start, end);
    }
    println!("\n");

    class_structure
}

/// Removes all meta tokens from the give Vector
/// Meta tokens include:
/// * comments
/// * imports
/// * permission modifiers (public, private, protected)
///
/// Note that in future versions, imports will not be removed.
fn remove_meta(tokens: &mut Vec<Token>)
{
    // Indecies of tokens vector to be removed
    let mut invalid_indecies: Vec<usize> = Vec::new();

    let mut min_index: usize = 0;
    for (index, token) in tokens.iter().enumerate()
    {
        // Allow forward skipping (by setting min_index)
        if index < min_index
        {
            invalid_indecies.push(index);
        }
        // Remove imports
        else if token.name == "special.import"
        {
            invalid_indecies.push(index);
            min_index = index + 2; // skip the next token (semi-colon)
        }
        // Remove comments
        else if token.name.starts_with("comment")
        {
            invalid_indecies.push(index);
        }
        // Remove all permission modifiers (public, private, protected)
        else if token.name == "mod.permission"
        {
            invalid_indecies.push(index);
        }
    }

    // count := how many indecies have already been removed
    // index := the index in the original tokens vector that should be removed
    for (count, index) in invalid_indecies.iter().enumerate()
    {
        // "index" refers to the index before any others were removed. Therefore, it must be offset by the number of removed tokens
        tokens.remove(index - count);
    }
}
<commit_msg>current stable member block implementation<commit_after>extern crate regex;

mod matching;
mod support;
mod tokens;
mod lexer;
mod files;
mod symbol_table;
mod plp;
mod compiler;

use std::vec::Vec;
use tokens::*;
use symbol_table::symbol_table::*;
use lexer::*;
use support::*;
use compiler::*;

fn main()
{
    let source_file = "sampleData/BasicArithmatic.java";
    let lex_output_file = "sampleData/output/stable/BasicArithmatic.java.lexed";
    let preprocessed_output_file = "sampleData/output/stable/BasicArithmatic.java.preprocessed";

    let mut tokens: Vec<Token> = lex_file(source_file);

    println!("\n\nFound Tokens:");
    tokens.print_to(lex_output_file, true);

    remove_meta(&mut tokens);
    println!("\n\nPerged Tokens:");
    tokens.print_to(preprocessed_output_file, true);

    let mut symbols_table: SymbolTable = SymbolTable {signature: "", return_type:"", package_path: ""};
    let class_structure = parse_class(&tokens, 1, &mut symbols_table);

    if tokens[0].value != "class"
    {
        panic!("Unexpected token: {}: {}", tokens[0].value, tokens[0].name);
    }

    let (last_index, asm_string) = compile_class(&tokens, 1);
}

fn parse_class(tokens: &Vec<Token>, start_index: usize, symbols_table: &mut SymbolTable) -> ClassStructure
{
    let mut class_structure: ClassStructure = ClassStructure::new();

    println!("\n<------------ Parse Class --------------->");
    let mut min_value = 0;
    let mut skip_amount = 0;

    for (index, token) in tokens.iter().enumerate()
    {
        if min_value != 0
        {
            min_value -= 1;
            continue;
        }
        //Static Variable/Method/Class
        if token.name == "mod.access"
        {
            skip_amount = 3;
            if tokens[index + skip_amount].name.starts_with("operator")
            {
                //TODO account for final
                println!("------Incoming Static Variable Decl!");

                let low = index + 1;
                let high = find_next(tokens, low, ";").unwrap() + 1;

                class_structure.static_variables.push(MemberBlock (low, high, tokens[index + 2].value.clone()));

                min_value =  low;
                min_value -= index;
            }
            else if tokens[index + skip_amount].name == "identifier"
            {
                //TODO account for final
                println!("------Incoming Static Variable Decl!");

                let low = index + 2;
                let high = find_next(tokens, low, ";").unwrap() + 1;
                class_structure.static_variables.push(MemberBlock (low, high, tokens[index + 3].value.clone()));

                min_value =  low;
                min_value -= index;
            }
            else if tokens[index + 1].name.starts_with("construct")
            {
                if tokens[index + skip_amount].name.starts_with("control")
                {
                    //TODO account for final
                    println!("------Incoming Static Class Decl!");
                    let starting_point = find_next(tokens, index, "{").unwrap() + 1;
                    min_value = identify_body_bounds(tokens, starting_point, ("{", "}")).unwrap() + 1;
                    class_structure.static_classes.push(MemberBlock (starting_point - 1, min_value, tokens[index + 2].value.clone()));
                    min_value -= index + 1;
                }
                else
                {
                    panic!("Unsupported or Unexpected token: {} + {}.", tokens[index + skip_amount].value, tokens[index + skip_amount].name);
                }
            }
            else if tokens[index + skip_amount].name.starts_with("control")
            {
                //TODO account for final
                println!("------Incoming Static Method Decl!");
                let starting_point = find_next(tokens, index, "{").unwrap() + 1;
                min_value = identify_body_bounds(tokens, starting_point, ("{", "}")).unwrap() + 1;
                class_structure.static_methods.push(MemberBlock (starting_point - 1, min_value, tokens[index + 2].value.clone()));
                min_value -=  index + 1;
            }
            else
            {
                panic!("Unsupported or Unexpected token: {}: {}.", tokens[index + skip_amount].value, tokens[index + skip_amount].name);
            }

        }
        //Non-Static Variable/Method/Class
        else if token.name.starts_with("construct")
        {
            skip_amount = 2;
            if tokens[index + skip_amount].name.starts_with("control")
            {
                //TODO account for final
                println!("------Incoming Non-Static Class Decl!");
                let index_after_brace = index + skip_amount + 1;
                min_value = identify_body_bounds(tokens, index_after_brace, ("{", "}")).unwrap() + 1;
                class_structure.non_static_classes.push(MemberBlock (index_after_brace - 1, min_value, tokens[index + 1].value.clone()));
                //TODO parse_class(tokens, index, symbols_table);
                min_value = 0;
            }
            else
            {
                panic!("Unsupported or Unexpected token: {} + {}.", tokens[index + skip_amount].value, tokens[index + skip_amount].name);
            }
        }
        //Non-Static Variable/Method/Class
        else if token.name == "type"
        {
            skip_amount = 2;

            if tokens[index + skip_amount].name.starts_with("control")
            {
                //TODO account for final
                println!("------Incoming Non-Static Method Decl!");
                let starting_point = find_next(tokens, index, "{").unwrap() + 1;
                min_value = identify_body_bounds(tokens, starting_point, ("{", "}")).unwrap() + 1;
                class_structure.non_static_methods.push(MemberBlock (starting_point - 1, min_value, tokens[index + 1].value.clone()));
                min_value -= index + 1;
                //check for control
            }
            else if tokens[index + skip_amount].name.starts_with("operator")
            {
                //TODO account for final
                println!("------Incoming Non-Static Variable Decl!");
                min_value =  find_next(tokens, index, ";").unwrap() + 1;
                class_structure.non_static_variables.push(MemberBlock (index, min_value, tokens[index + 1].value.clone()));
                min_value -= index + 1;
            }
        }
        println!("\tIndex: {} | Token -> {} : {}", index, token.value, token.name );
        //deal with parameters
    }
    println!("\n<---------------- Static Variables --------------->");
    for member_block in class_structure.static_variables.iter()
    {
        println!("Start/End {}/{}: {}", member_block.0, member_block.1, member_block.2);
    }

    println!("\n<---------------- Static Classes ----------------->");
    for member_block in class_structure.static_classes.iter()
    {
        println!("Start/End {}/{}: {}", member_block.0, member_block.1, member_block.2);
    }

    println!("\n<---------------- Static Methods ----------------->");
    for member_block in class_structure.static_methods.iter()
    {
        println!("Start/End {}/{}: {}", member_block.0, member_block.1, member_block.2);
    }

    println!("\n<---------------- Non-Static Variables --------------->");
    for member_block in class_structure.non_static_variables.iter()
    {
        println!("Start/End {}/{}: {}", member_block.0, member_block.1, member_block.2);
    }

    println!("\n<---------------- Non-Static Classes ----------------->");
    for member_block in class_structure.non_static_classes.iter()
    {
        println!("Start/End {}/{}: {}", member_block.0, member_block.1, member_block.2);
    }

    println!("\n<---------------- Non-Static Methods ----------------->");
    for member_block in class_structure.non_static_methods.iter()
    {
        println!("Start/End {}/{}: {}", member_block.0, member_block.1, member_block.2);
    }
    println!("\n");

    class_structure
}

/// Removes all meta tokens from the give Vector
/// Meta tokens include:
/// * comments
/// * imports
/// * permission modifiers (public, private, protected)
///
/// Note that in future versions, imports will not be removed.
fn remove_meta(tokens: &mut Vec<Token>)
{
    // Indecies of tokens vector to be removed
    let mut invalid_indecies: Vec<usize> = Vec::new();

    let mut min_index: usize = 0;
    for (index, token) in tokens.iter().enumerate()
    {
        // Allow forward skipping (by setting min_index)
        if index < min_index
        {
            invalid_indecies.push(index);
        }
        // Remove imports
        else if token.name == "special.import"
        {
            invalid_indecies.push(index);
            min_index = index + 2; // skip the next token (semi-colon)
        }
        // Remove comments
        else if token.name.starts_with("comment")
        {
            invalid_indecies.push(index);
        }
        // Remove all permission modifiers (public, private, protected)
        else if token.name == "mod.permission"
        {
            invalid_indecies.push(index);
        }
    }

    // count := how many indecies have already been removed
    // index := the index in the original tokens vector that should be removed
    for (count, index) in invalid_indecies.iter().enumerate()
    {
        // "index" refers to the index before any others were removed. Therefore, it must be offset by the number of removed tokens
        tokens.remove(index - count);
    }
}
<|endoftext|>


<commit_before>use std::libc::*;
use std::ptr::is_null;
use std::vec::raw::from_buf_raw;

#[link(name="stb")]
extern {
    fn stbi_load_from_memory(
        buffer: *c_uchar, len: c_int, x: *mut c_int, y: *mut c_int,
        comp: *mut c_int, req_comp: c_int) -> *c_uchar;
}

pub struct Image {
    width: uint,
    height: uint,
    bpp: uint,
    pixels: ~[u8],
}

impl Image {
    pub fn new(data: &[u8]) -> Option<Image> {
        unsafe {
            let mut w = 0 as c_int;
            let mut h = 0 as c_int;
            let mut bpp = 0 as c_int;

            let buffer = stbi_load_from_memory(
                data.as_ptr(), data.len() as c_int,
                &mut w, &mut h, &mut bpp, 0);

            if is_null(buffer) {
                return None
            }

            let ret = Some(Image{
                width: w as uint,
                height: h as uint,
                bpp: bpp as uint,
                pixels: from_buf_raw(buffer, (w * h * bpp) as uint)
            });
            free(buffer as *mut c_void);
            ret
        }
    }
}
<commit_msg>STB image writing<commit_after>use std::libc::*;
use std::ptr::is_null;
use std::vec::raw::from_buf_raw;
use std::vec;

#[link(name="stb")]
extern {
    fn stbi_load_from_memory(
        buffer: *c_uchar, len: c_int, x: *mut c_int, y: *mut c_int,
        comp: *mut c_int, req_comp: c_int) -> *c_uchar;

    fn stbi_write_png(
	filename: *c_char, w: c_int, h: c_int, comp: c_int,
	data: *c_void, stride_in_bytes: c_int);
}

pub struct Image {
    width: uint,
    height: uint,
    bpp: uint,
    pixels: ~[u8],
}

impl Image {
    pub fn load(data: &[u8]) -> Option<Image> {
        unsafe {
            let mut w = 0 as c_int;
            let mut h = 0 as c_int;
            let mut bpp = 0 as c_int;

            let buffer = stbi_load_from_memory(
                data.as_ptr(), data.len() as c_int,
                &mut w, &mut h, &mut bpp, 0);

            if is_null(buffer) {
                return None
            }

            let ret = Some(Image{
                width: w as uint,
                height: h as uint,
                bpp: bpp as uint,
                pixels: from_buf_raw(buffer, (w * h * bpp) as uint)
            });
            free(buffer as *mut c_void);
            ret
        }
    }

    pub fn new(width: uint, height: uint, bpp: uint) -> Image {
	assert!(bpp <= 4);
	Image{
	    width: width,
	    height: height,
	    bpp: bpp,
	    pixels: vec::from_elem(width * height * bpp, 0u8),
	}
    }

    pub fn save_png(&self, path: &str) {
	unsafe {
	    path.to_c_str().with_ref(|bytes| {
		stbi_write_png(
		    bytes, self.width as c_int, self.height as c_int,
		    self.bpp as c_int, self.pixels.as_ptr() as *c_void, 0);
	    })
	}
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 James R. Garrison
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate libc;
extern crate num;

use self::libc::{c_char, c_double, c_float, c_int, c_uint};
use std::ffi::CString;

#[link(name = "arpack")]
extern {

    // single precision symmetric

    fn ssaupd_(ido: *mut c_int,
               bmat: *const c_char,
               n: *const c_int,
               which: *const c_char,
               nev: *const c_int,
               tol: *const c_float,
               resid: *mut c_float,
               ncv: *const c_int,
               v: *mut c_float,
               ldv: *const c_int,
               iparam: *mut c_int,
               ipntr: *mut c_int,
               workd: *mut c_float,
               workl: *mut c_float,
               lworkl: *const c_int,
               info: *mut c_int);

    fn sseupd_(rvec: *const c_int,
               howmny: *const c_char,
               select: *mut c_int,
               d: *mut c_float,
               z: *mut c_float,
               ldz: *const c_int,
               sigma: *const c_float,
               bmat: *const c_char,
               n: *const c_int,
               which: *const c_char,
               nev: *const c_int,
               tol: *const c_float,
               resid: *mut c_float,
               ncv: *const c_int,
               v: *mut c_float,
               ldv: *const c_int,
               iparam: *mut c_int,
               ipntr: *mut c_int,
               workd: *mut c_float,
               workl: *mut c_float,
               lworkl: *const c_int,
               ierr: *mut c_int);

    // double precision symmetric

    fn dsaupd_(ido: *mut c_int,
               bmat: *const c_char,
               n: *const c_int,
               which: *const c_char,
               nev: *const c_int,
               tol: *const c_double,
               resid: *mut c_double,
               ncv: *const c_int,
               v: *mut c_double,
               ldv: *const c_int,
               iparam: *mut c_int,
               ipntr: *mut c_int,
               workd: *mut c_double,
               workl: *mut c_double,
               lworkl: *const c_int,
               info: *mut c_int);

    fn dseupd_(rvec: *const c_int,
               howmny: *const c_char,
               select: *mut c_int,
               d: *mut c_double,
               z: *mut c_double,
               ldz: *const c_int,
               sigma: *const c_double,
               bmat: *const c_char,
               n: *const c_int,
               which: *const c_char,
               nev: *const c_int,
               tol: *const c_double,
               resid: *mut c_double,
               ncv: *const c_int,
               v: *mut c_double,
               ldv: *const c_int,
               iparam: *mut c_int,
               ipntr: *mut c_int,
               workd: *mut c_double,
               workl: *mut c_double,
               lworkl: *const c_int,
               ierr: *mut c_int);

}

pub enum Which {
    LargestMagnitude,
    SmallestMagnitude,
    LargestAlgebraic,
    SmallestAlgebraic,
    BothEnds,
}

fn which_to_str(which: Which) -> &'static str {
    match which {
        Which::LargestMagnitude => "LM",
        Which::SmallestMagnitude => "SM",
        Which::LargestAlgebraic => "LA",
        Which::SmallestAlgebraic => "SA",
        Which::BothEnds => "BE",
    }
}

// note: evals may potentially be modified even if there is an error.
fn dsaupd<F>(n: c_int,
             nev: c_int,
             mv_multiply: F,
             evals: &mut Vec<c_double>,
             evecs: Option<&mut Vec<c_double>>)
        where F : Fn(&[c_double]) -> Vec<c_double> {
    assert!(nev > 0);
    assert!(nev < n);

    let mut ido: c_int = 0;
    let bmat = CString::new("I").unwrap(); // not configurable, for now
    let which = CString::new(which_to_str(Which::SmallestAlgebraic)).unwrap();
    let tol: c_double = 0.0;
    let mut resid = vec![0.0 as c_double; n as usize];
    let ncv = {
        let possible_ncv: c_int = 4 * nev;
        if possible_ncv > n {
            n
        } else {
            possible_ncv
        }
    };
    let ldv: c_int = n;
    let mut v = vec![0.0 as c_double; (ldv * ncv) as usize];
    let mut iparam = vec![1 as c_int, 0, 3 * n, 0, 0, 0, 1, 0, 0, 0, 0];
    // fixme: may wish to tune iparam[2] differently.
    let mut ipntr = vec![0 as c_int; 11];
    let mut workd = vec![0.0 as c_double; 3 * n as usize];
    let lworkl: c_int = ncv * (ncv + 8);
    let mut workl = vec![0.0 as c_double; lworkl as usize];
    let mut info: c_int = 0;

    loop {
        unsafe {
            dsaupd_(&mut ido, bmat.as_ptr(), &n, which.as_ptr(), &nev, &tol,
                    resid.as_mut_ptr(), &ncv, v.as_mut_ptr(), &ldv,
                    iparam.as_mut_ptr(), ipntr.as_mut_ptr(), workd.as_mut_ptr(),
                    workl.as_mut_ptr(), &lworkl, &mut info);
        }

        if ido != 1 && ido != -1 {
            break;
        }

        // fixme: seems overkill
        let output = {
            let in_slice = workd.slice((ipntr[0] - 1) as c_uint,
                                       (ipntr[0] - 1 + n) as c_uint);
            mv_multiply(in_slice)
        };
        let out_slice = workd.mut_slice((ipntr[1] - 1) as c_uint,
                                        (ipntr[1] - 1 + n) as c_uint);
        out_slice.clone_from_slice(output.as_slice());
    }

    if info < 0 {
        // fixme: return error using enum
        return;
    }

    let rvec: c_int = match evecs {
        Some(ref evecs) => 1,
        None => 0
    };
    let mut select = vec![0 as c_int; ncv as usize];
    evals.clear(); // called ``d`` in arpack
    evals.resize(nev as usize, 0.0);
    let sigma: c_double = 0.0;
    let mut ierr: c_int = 0;

    let howmny = CString::new("A").unwrap();
    unsafe {
        dseupd_(&rvec, howmny.as_ptr(), select.as_mut_ptr(), evals.as_mut_ptr(),
                v.as_mut_ptr(), &ldv, &sigma, bmat.as_ptr(),
	        &n, which.as_ptr(), &nev, &tol, resid.as_mut_ptr(), &ncv, v.as_mut_ptr(), &ldv,
	        iparam.as_mut_ptr(), ipntr.as_mut_ptr(), workd.as_mut_ptr(), workl.as_mut_ptr(), &lworkl, &mut ierr);
    }

    if ierr != 0 {
        // fixme: return error code
        return;
    }

    match evecs {
        Some(evecs) => {
            // copy the vector.  fixme: seems overkill.
            evecs.clear();
            evecs.resize((nev * n) as usize, 0.0);
            evecs.as_mut_slice().clone_from_slice(v.as_slice());
        },
        None => ()
    };
}

#[cfg(test)]
mod tests {

    extern crate libc;
    extern crate test;

    use super::dsaupd;
    use self::test::Bencher;
    use self::libc::c_double;

    #[test]
    fn test_dsaupd() {
        let mut evals: Vec<c_double> = Vec::new();
        let mut evecs: Vec<c_double> = Vec::new();
        dsaupd(8, 2, |slice: &[c_double]| {
            // FIXME: this is probably more involved than necessary
            slice.to_vec().move_iter().map(|i| 2.0 * i).collect()
        }, &mut evals, Some(&mut evecs));
    }

    #[bench]
    fn benchmark_dsaupd(b: &mut Bencher) {
        b.iter(|| test_dsaupd());
    }

}
<commit_msg>Use new slice syntax<commit_after>// Copyright 2014 James R. Garrison
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate libc;
extern crate num;

use self::libc::{c_char, c_double, c_float, c_int, c_uint};
use std::ffi::CString;

#[link(name = "arpack")]
extern {

    // single precision symmetric

    fn ssaupd_(ido: *mut c_int,
               bmat: *const c_char,
               n: *const c_int,
               which: *const c_char,
               nev: *const c_int,
               tol: *const c_float,
               resid: *mut c_float,
               ncv: *const c_int,
               v: *mut c_float,
               ldv: *const c_int,
               iparam: *mut c_int,
               ipntr: *mut c_int,
               workd: *mut c_float,
               workl: *mut c_float,
               lworkl: *const c_int,
               info: *mut c_int);

    fn sseupd_(rvec: *const c_int,
               howmny: *const c_char,
               select: *mut c_int,
               d: *mut c_float,
               z: *mut c_float,
               ldz: *const c_int,
               sigma: *const c_float,
               bmat: *const c_char,
               n: *const c_int,
               which: *const c_char,
               nev: *const c_int,
               tol: *const c_float,
               resid: *mut c_float,
               ncv: *const c_int,
               v: *mut c_float,
               ldv: *const c_int,
               iparam: *mut c_int,
               ipntr: *mut c_int,
               workd: *mut c_float,
               workl: *mut c_float,
               lworkl: *const c_int,
               ierr: *mut c_int);

    // double precision symmetric

    fn dsaupd_(ido: *mut c_int,
               bmat: *const c_char,
               n: *const c_int,
               which: *const c_char,
               nev: *const c_int,
               tol: *const c_double,
               resid: *mut c_double,
               ncv: *const c_int,
               v: *mut c_double,
               ldv: *const c_int,
               iparam: *mut c_int,
               ipntr: *mut c_int,
               workd: *mut c_double,
               workl: *mut c_double,
               lworkl: *const c_int,
               info: *mut c_int);

    fn dseupd_(rvec: *const c_int,
               howmny: *const c_char,
               select: *mut c_int,
               d: *mut c_double,
               z: *mut c_double,
               ldz: *const c_int,
               sigma: *const c_double,
               bmat: *const c_char,
               n: *const c_int,
               which: *const c_char,
               nev: *const c_int,
               tol: *const c_double,
               resid: *mut c_double,
               ncv: *const c_int,
               v: *mut c_double,
               ldv: *const c_int,
               iparam: *mut c_int,
               ipntr: *mut c_int,
               workd: *mut c_double,
               workl: *mut c_double,
               lworkl: *const c_int,
               ierr: *mut c_int);

}

pub enum Which {
    LargestMagnitude,
    SmallestMagnitude,
    LargestAlgebraic,
    SmallestAlgebraic,
    BothEnds,
}

fn which_to_str(which: Which) -> &'static str {
    match which {
        Which::LargestMagnitude => "LM",
        Which::SmallestMagnitude => "SM",
        Which::LargestAlgebraic => "LA",
        Which::SmallestAlgebraic => "SA",
        Which::BothEnds => "BE",
    }
}

// note: evals may potentially be modified even if there is an error.
fn dsaupd<F>(n: c_int,
             nev: c_int,
             mv_multiply: F,
             evals: &mut Vec<c_double>,
             evecs: Option<&mut Vec<c_double>>)
        where F : Fn(&[c_double]) -> Vec<c_double> {
    assert!(nev > 0);
    assert!(nev < n);

    let mut ido: c_int = 0;
    let bmat = CString::new("I").unwrap(); // not configurable, for now
    let which = CString::new(which_to_str(Which::SmallestAlgebraic)).unwrap();
    let tol: c_double = 0.0;
    let mut resid = vec![0.0 as c_double; n as usize];
    let ncv = {
        let possible_ncv: c_int = 4 * nev;
        if possible_ncv > n {
            n
        } else {
            possible_ncv
        }
    };
    let ldv: c_int = n;
    let mut v = vec![0.0 as c_double; (ldv * ncv) as usize];
    let mut iparam = vec![1 as c_int, 0, 3 * n, 0, 0, 0, 1, 0, 0, 0, 0];
    // fixme: may wish to tune iparam[2] differently.
    let mut ipntr = vec![0 as c_int; 11];
    let mut workd = vec![0.0 as c_double; 3 * n as usize];
    let lworkl: c_int = ncv * (ncv + 8);
    let mut workl = vec![0.0 as c_double; lworkl as usize];
    let mut info: c_int = 0;

    loop {
        unsafe {
            dsaupd_(&mut ido, bmat.as_ptr(), &n, which.as_ptr(), &nev, &tol,
                    resid.as_mut_ptr(), &ncv, v.as_mut_ptr(), &ldv,
                    iparam.as_mut_ptr(), ipntr.as_mut_ptr(), workd.as_mut_ptr(),
                    workl.as_mut_ptr(), &lworkl, &mut info);
        }

        if ido != 1 && ido != -1 {
            break;
        }

        // fixme: seems overkill
        let output = {
            let in_slice = &workd[((ipntr[0] - 1) as usize)..((ipntr[0] - 1 + n) as usize)];
            mv_multiply(in_slice)
        };
        let out_slice = &mut workd[((ipntr[1] - 1) as usize)..((ipntr[1] - 1 + n) as usize)];
        out_slice.clone_from_slice(output.as_slice());
    }

    if info < 0 {
        // fixme: return error using enum
        return;
    }

    let rvec: c_int = match evecs {
        Some(ref evecs) => 1,
        None => 0
    };
    let mut select = vec![0 as c_int; ncv as usize];
    evals.clear(); // called ``d`` in arpack
    evals.resize(nev as usize, 0.0);
    let sigma: c_double = 0.0;
    let mut ierr: c_int = 0;

    let howmny = CString::new("A").unwrap();
    unsafe {
        dseupd_(&rvec, howmny.as_ptr(), select.as_mut_ptr(), evals.as_mut_ptr(),
                v.as_mut_ptr(), &ldv, &sigma, bmat.as_ptr(),
	        &n, which.as_ptr(), &nev, &tol, resid.as_mut_ptr(), &ncv, v.as_mut_ptr(), &ldv,
	        iparam.as_mut_ptr(), ipntr.as_mut_ptr(), workd.as_mut_ptr(), workl.as_mut_ptr(), &lworkl, &mut ierr);
    }

    if ierr != 0 {
        // fixme: return error code
        return;
    }

    match evecs {
        Some(evecs) => {
            // copy the vector.  fixme: seems overkill.
            evecs.clear();
            evecs.resize((nev * n) as usize, 0.0);
            evecs.as_mut_slice().clone_from_slice(v.as_slice());
        },
        None => ()
    };
}

#[cfg(test)]
mod tests {

    extern crate libc;
    extern crate test;

    use super::dsaupd;
    use self::test::Bencher;
    use self::libc::c_double;

    #[test]
    fn test_dsaupd() {
        let mut evals: Vec<c_double> = Vec::new();
        let mut evecs: Vec<c_double> = Vec::new();
        dsaupd(8, 2, |slice: &[c_double]| {
            // FIXME: this is probably more involved than necessary
            slice.to_vec().move_iter().map(|i| 2.0 * i).collect()
        }, &mut evals, Some(&mut evecs));
    }

    #[bench]
    fn benchmark_dsaupd(b: &mut Bencher) {
        b.iter(|| test_dsaupd());
    }

}
<|endoftext|>


<commit_before>#[test]
use std::iterator::IteratorUtil;
#[test]
use std::num::{Zero, One};
#[test]
use std::rand::{random};
#[test]
use std::cmp::ApproxEq;
#[test]
use vec::{Vec1, Vec2, Vec3, Vec4, Vec5, Vec6};
#[test]
use traits::basis::Basis;
#[test]
use traits::cross::Cross;
#[test]
use traits::dot::Dot;
#[test]
use traits::norm::Norm;
#[test]
use traits::iterable::{Iterable, IterableMut};
#[test]
use traits::scalar_op::{ScalarMul, ScalarDiv, ScalarAdd, ScalarSub};

macro_rules! test_iterator_impl(
  ($t: ty, $n: ty) => (
    for 10000.times
    {
      let v: $t      = random();
      let mut mv: $t = v.clone();
      let n: $n      = random();

      let nv: $t = v.iter().transform(|e| e * n).collect();

      for mv.mut_iter().advance |e|
      { *e = *e * n }

      assert!(nv == mv && nv == v.scalar_mul(&n));
    }
  )
)

macro_rules! test_commut_dot_impl(
  ($t: ty) => (
    for 10000.times
    {
      let v1 : $t = random();
      let v2 : $t = random();

      assert!(v1.dot(&v2).approx_eq(&v2.dot(&v1)));
    }
  );
)

macro_rules! test_scalar_op_impl(
  ($t: ty, $n: ty) => (
    for 10000.times
    {
      let v1 : $t = random();
      let n  : $n = random();

      assert!(v1.scalar_mul(&n).scalar_div(&n).approx_eq(&v1));
      assert!(v1.scalar_div(&n).scalar_mul(&n).approx_eq(&v1));
      assert!(v1.scalar_sub(&n).scalar_add(&n).approx_eq(&v1));
      assert!(v1.scalar_add(&n).scalar_sub(&n).approx_eq(&v1));

      let mut v1 : $t = random();
      let v0 : $t = v1.clone();
      let n  : $n = random();

      v1.scalar_mul_inplace(&n);
      v1.scalar_div_inplace(&n);

      assert!(v1.approx_eq(&v0));
    }
  );
)

macro_rules! test_basis_impl(
  ($t: ty) => (
    for 10000.times
    {
      do Basis::canonical_basis::<$t> |e1|
      {
        do Basis::canonical_basis::<$t> |e2|
        { assert!(e1 == e2 || e1.dot(&e2).approx_eq(&Zero::zero())) }

        assert!(e1.norm().approx_eq(&One::one()));
      }
    }
  );
)

macro_rules! test_subspace_basis_impl(
  ($t: ty) => (
    for 10000.times
    {
      let v : $t   = random();
      let v1       = v.normalized();

      do v1.orthonormal_subspace_basis() |e1|
      {
        // check vectors are orthogonal to v1
        assert!(v1.dot(&e1).approx_eq(&Zero::zero()));
        // check vectors form an orthonormal basis
        assert!(e1.norm().approx_eq(&One::one()));
        // check vectors form an ortogonal basis
        do v1.orthonormal_subspace_basis() |e2|
        { assert!(e1 == e2 || e1.dot(&e2).approx_eq(&Zero::zero())) }
      }
    }
  );
)

#[test]
fn test_cross_vec3()
{
  for 10000.times
  {
    let v1 : Vec3<f64> = random();
    let v2 : Vec3<f64> = random();
    let v3 : Vec3<f64> = v1.cross(&v2);

    assert!(v3.dot(&v2).approx_eq(&Zero::zero()));
    assert!(v3.dot(&v1).approx_eq(&Zero::zero()));
  }
}

#[test]
fn test_commut_dot_nvec()
{ test_commut_dot_impl!(Vec6<f64>); }

#[test]
fn test_commut_dot_vec3()
{ test_commut_dot_impl!(Vec3<f64>); }

#[test]
fn test_commut_dot_vec2()
{ test_commut_dot_impl!(Vec2<f64>); }

#[test]
fn test_commut_dot_vec1()
{ test_commut_dot_impl!(Vec1<f64>); }

#[test]
fn test_basis_vec1()
{ test_basis_impl!(Vec1<f64>); }

#[test]
fn test_basis_vec2()
{ test_basis_impl!(Vec2<f64>); }

#[test]
fn test_basis_vec3()
{ test_basis_impl!(Vec3<f64>); }

#[test]
fn test_basis_vec4()
{ test_basis_impl!(Vec4<f64>); }

#[test]
fn test_basis_vec5()
{ test_basis_impl!(Vec5<f64>); }

#[test]
fn test_basis_vec6()
{ test_basis_impl!(Vec6<f64>); }

#[test]
fn test_subspace_basis_vec1()
{ test_subspace_basis_impl!(Vec1<f64>); }

#[test]
fn test_subspace_basis_vec2()
{ test_subspace_basis_impl!(Vec2<f64>); }

#[test]
fn test_subspace_basis_vec3()
{ test_subspace_basis_impl!(Vec3<f64>); }

#[test]
fn test_subspace_basis_vec4()
{ test_subspace_basis_impl!(Vec4<f64>); }

#[test]
fn test_subspace_basis_vec5()
{ test_subspace_basis_impl!(Vec5<f64>); }

#[test]
fn test_subspace_basis_vec6()
{ test_subspace_basis_impl!(Vec6<f64>); }

#[test]
fn test_scalar_op_vec1()
{ test_scalar_op_impl!(Vec1<f64>, f64); }

#[test]
fn test_scalar_op_vec2()
{ test_scalar_op_impl!(Vec2<f64>, f64); }

#[test]
fn test_scalar_op_vec3()
{ test_scalar_op_impl!(Vec3<f64>, f64); }

#[test]
fn test_scalar_op_vec4()
{ test_scalar_op_impl!(Vec4<f64>, f64); }

#[test]
fn test_scalar_op_vec5()
{ test_scalar_op_impl!(Vec5<f64>, f64); }

#[test]
fn test_scalar_op_vec6()
{ test_scalar_op_impl!(Vec6<f64>, f64); }

#[test]
fn test_iterator_vec1()
{ test_iterator_impl!(Vec1<f64>, f64); }

#[test]
fn test_iterator_vec2()
{ test_iterator_impl!(Vec2<f64>, f64); }

#[test]
fn test_iterator_vec3()
{ test_iterator_impl!(Vec3<f64>, f64); }

#[test]
fn test_iterator_vec4()
{ test_iterator_impl!(Vec4<f64>, f64); }

#[test]
fn test_iterator_vec5()
{ test_iterator_impl!(Vec5<f64>, f64); }

#[test]
fn test_iterator_vec6()
{ test_iterator_impl!(Vec6<f64>, f64); }
<commit_msg>Add tests for vec0.<commit_after>#[test]
use std::iterator::IteratorUtil;
#[test]
use std::num::{Zero, One};
#[test]
use std::rand::{random};
#[test]
use std::cmp::ApproxEq;
#[test]
use vec::{Vec0, Vec1, Vec2, Vec3, Vec4, Vec5, Vec6};
#[test]
use traits::basis::Basis;
#[test]
use traits::cross::Cross;
#[test]
use traits::dot::Dot;
#[test]
use traits::norm::Norm;
#[test]
use traits::iterable::{Iterable, IterableMut};
#[test]
use traits::scalar_op::{ScalarMul, ScalarDiv, ScalarAdd, ScalarSub};

macro_rules! test_iterator_impl(
  ($t: ty, $n: ty) => (
    for 10000.times
    {
      let v: $t      = random();
      let mut mv: $t = v.clone();
      let n: $n      = random();

      let nv: $t = v.iter().transform(|e| e * n).collect();

      for mv.mut_iter().advance |e|
      { *e = *e * n }

      assert!(nv == mv && nv == v.scalar_mul(&n));
    }
  )
)

macro_rules! test_commut_dot_impl(
  ($t: ty) => (
    for 10000.times
    {
      let v1 : $t = random();
      let v2 : $t = random();

      assert!(v1.dot(&v2).approx_eq(&v2.dot(&v1)));
    }
  );
)

macro_rules! test_scalar_op_impl(
  ($t: ty, $n: ty) => (
    for 10000.times
    {
      let v1 : $t = random();
      let n  : $n = random();

      assert!(v1.scalar_mul(&n).scalar_div(&n).approx_eq(&v1));
      assert!(v1.scalar_div(&n).scalar_mul(&n).approx_eq(&v1));
      assert!(v1.scalar_sub(&n).scalar_add(&n).approx_eq(&v1));
      assert!(v1.scalar_add(&n).scalar_sub(&n).approx_eq(&v1));

      let mut v1 : $t = random();
      let v0 : $t = v1.clone();
      let n  : $n = random();

      v1.scalar_mul_inplace(&n);
      v1.scalar_div_inplace(&n);

      assert!(v1.approx_eq(&v0));
    }
  );
)

macro_rules! test_basis_impl(
  ($t: ty) => (
    for 10000.times
    {
      do Basis::canonical_basis::<$t> |e1|
      {
        do Basis::canonical_basis::<$t> |e2|
        { assert!(e1 == e2 || e1.dot(&e2).approx_eq(&Zero::zero())) }

        assert!(e1.norm().approx_eq(&One::one()));
      }
    }
  );
)

macro_rules! test_subspace_basis_impl(
  ($t: ty) => (
    for 10000.times
    {
      let v : $t   = random();
      let v1       = v.normalized();

      do v1.orthonormal_subspace_basis() |e1|
      {
        // check vectors are orthogonal to v1
        assert!(v1.dot(&e1).approx_eq(&Zero::zero()));
        // check vectors form an orthonormal basis
        assert!(e1.norm().approx_eq(&One::one()));
        // check vectors form an ortogonal basis
        do v1.orthonormal_subspace_basis() |e2|
        { assert!(e1 == e2 || e1.dot(&e2).approx_eq(&Zero::zero())) }
      }
    }
  );
)

#[test]
fn test_cross_vec3()
{
  for 10000.times
  {
    let v1 : Vec3<f64> = random();
    let v2 : Vec3<f64> = random();
    let v3 : Vec3<f64> = v1.cross(&v2);

    assert!(v3.dot(&v2).approx_eq(&Zero::zero()));
    assert!(v3.dot(&v1).approx_eq(&Zero::zero()));
  }
}

#[test]
fn test_commut_dot_vec0()
{ test_commut_dot_impl!(Vec0<f64>); }

#[test]
fn test_commut_dot_vec1()
{ test_commut_dot_impl!(Vec1<f64>); }

#[test]
fn test_commut_dot_vec2()
{ test_commut_dot_impl!(Vec2<f64>); }

#[test]
fn test_commut_dot_vec3()
{ test_commut_dot_impl!(Vec3<f64>); }

#[test]
fn test_commut_dot_vec4()
{ test_commut_dot_impl!(Vec4<f64>); }

#[test]
fn test_commut_dot_vec5()
{ test_commut_dot_impl!(Vec5<f64>); }

#[test]
fn test_commut_dot_vec6()
{ test_commut_dot_impl!(Vec6<f64>); }

#[test]
fn test_basis_vec0()
{ test_basis_impl!(Vec0<f64>); }

#[test]
fn test_basis_vec1()
{ test_basis_impl!(Vec1<f64>); }

#[test]
fn test_basis_vec2()
{ test_basis_impl!(Vec2<f64>); }

#[test]
fn test_basis_vec3()
{ test_basis_impl!(Vec3<f64>); }

#[test]
fn test_basis_vec4()
{ test_basis_impl!(Vec4<f64>); }

#[test]
fn test_basis_vec5()
{ test_basis_impl!(Vec5<f64>); }

#[test]
fn test_basis_vec6()
{ test_basis_impl!(Vec6<f64>); }

#[test]
fn test_subspace_basis_vec0()
{ test_subspace_basis_impl!(Vec0<f64>); }

#[test]
fn test_subspace_basis_vec1()
{ test_subspace_basis_impl!(Vec1<f64>); }

#[test]
fn test_subspace_basis_vec2()
{ test_subspace_basis_impl!(Vec2<f64>); }

#[test]
fn test_subspace_basis_vec3()
{ test_subspace_basis_impl!(Vec3<f64>); }

#[test]
fn test_subspace_basis_vec4()
{ test_subspace_basis_impl!(Vec4<f64>); }

#[test]
fn test_subspace_basis_vec5()
{ test_subspace_basis_impl!(Vec5<f64>); }

#[test]
fn test_subspace_basis_vec6()
{ test_subspace_basis_impl!(Vec6<f64>); }

#[test]
fn test_scalar_op_vec0()
{ test_scalar_op_impl!(Vec0<f64>, f64); }

#[test]
fn test_scalar_op_vec1()
{ test_scalar_op_impl!(Vec1<f64>, f64); }

#[test]
fn test_scalar_op_vec2()
{ test_scalar_op_impl!(Vec2<f64>, f64); }

#[test]
fn test_scalar_op_vec3()
{ test_scalar_op_impl!(Vec3<f64>, f64); }

#[test]
fn test_scalar_op_vec4()
{ test_scalar_op_impl!(Vec4<f64>, f64); }

#[test]
fn test_scalar_op_vec5()
{ test_scalar_op_impl!(Vec5<f64>, f64); }

#[test]
fn test_scalar_op_vec6()
{ test_scalar_op_impl!(Vec6<f64>, f64); }

#[test]
fn test_iterator_vec0()
{ test_iterator_impl!(Vec0<f64>, f64); }

#[test]
fn test_iterator_vec1()
{ test_iterator_impl!(Vec1<f64>, f64); }

#[test]
fn test_iterator_vec2()
{ test_iterator_impl!(Vec2<f64>, f64); }

#[test]
fn test_iterator_vec3()
{ test_iterator_impl!(Vec3<f64>, f64); }

#[test]
fn test_iterator_vec4()
{ test_iterator_impl!(Vec4<f64>, f64); }

#[test]
fn test_iterator_vec5()
{ test_iterator_impl!(Vec5<f64>, f64); }

#[test]
fn test_iterator_vec6()
{ test_iterator_impl!(Vec6<f64>, f64); }
<|endoftext|>


<commit_before>//! Structs and functions for working with statuses and timelines.
use std::collections::HashMap;
use auth;
use links;
use common::*;

mod structs;

pub use self::structs::*;

///Lookup a single tweet by numeric ID.
pub fn show(id: i64, con_token: &auth::Token, access_token: &auth::Token)
    -> WebResponse<Tweet>
{
    let mut params = HashMap::new();
    add_param(&mut params, "id", id.to_string());

    let mut resp = try!(auth::get(links::statuses::SHOW, con_token, access_token, Some(&params)));

    parse_response(&mut resp)
}

///Lookup the most recent 100 (or fewer) retweets of the given tweet.
///
///Use the `count` parameter to indicate how many retweets you would like to retrieve. If `count`
///is 0 or greater than 100, 100 will be given to Twitter.
pub fn retweets_of(id: i64, count: u32, con_token: &auth::Token, access_token: &auth::Token)
    -> WebResponse<Vec<Tweet>>
{
    let mut params = HashMap::new();

    if count == 0 || count > 100 {
        add_param(&mut params, "count", 100.to_string());
    }
    else {
        add_param(&mut params, "count", count.to_string());
    }

    let url = format!("{}/{}.json", links::statuses::RETWEETS_OF_STEM, id);

    let mut resp = try!(auth::get(&url, con_token, access_token, Some(&params)));

    parse_response(&mut resp)
}
<commit_msg>tweak docs of tweet::retweets_of<commit_after>//! Structs and functions for working with statuses and timelines.
use std::collections::HashMap;
use auth;
use links;
use common::*;

mod structs;

pub use self::structs::*;

///Lookup a single tweet by numeric ID.
pub fn show(id: i64, con_token: &auth::Token, access_token: &auth::Token)
    -> WebResponse<Tweet>
{
    let mut params = HashMap::new();
    add_param(&mut params, "id", id.to_string());

    let mut resp = try!(auth::get(links::statuses::SHOW, con_token, access_token, Some(&params)));

    parse_response(&mut resp)
}

///Lookup the most recent 100 (or fewer) retweets of the given tweet.
///
///Use the `count` parameter to indicate how many retweets you would like to retrieve. If `count`
///is 0 or greater than 100, it will be defaulted to 100 before making the call.
pub fn retweets_of(id: i64, count: u32, con_token: &auth::Token, access_token: &auth::Token)
    -> WebResponse<Vec<Tweet>>
{
    let mut params = HashMap::new();

    if count == 0 || count > 100 {
        add_param(&mut params, "count", 100.to_string());
    }
    else {
        add_param(&mut params, "count", count.to_string());
    }

    let url = format!("{}/{}.json", links::statuses::RETWEETS_OF_STEM, id);

    let mut resp = try!(auth::get(&url, con_token, access_token, Some(&params)));

    parse_response(&mut resp)
}
<|endoftext|>


<commit_before>#![allow(unused,dead_code)]

extern crate tokio_uds;

use futures;
use futures::future::Future;
use futures::stream::Stream;
use futures::unsync::oneshot::{channel, Receiver, Sender};
use std;
use std::io::Result as IoResult;
use std::io::{Read, Write};
use std::net::SocketAddr;
use tokio_core::reactor::Handle;
use tokio_io::{AsyncRead, AsyncWrite};

use std::cell::RefCell;
use std::rc::Rc;

use std::fs::File;
use std::path::{Path, PathBuf};

use self::tokio_uds::{UnixDatagram, UnixListener, UnixStream};

use super::{box_up_err, peer_err_s, wouldblock, BoxedNewPeerFuture, BoxedNewPeerStream, Peer};
use super::{multi, once, Options, PeerConstructor, ProgramState, Specifier};

#[derive(Debug, Clone)]
pub struct UnixConnect(pub PathBuf);
impl Specifier for UnixConnect {
    fn construct(&self, h: &Handle, _: &mut ProgramState, _opts: Rc<Options>) -> PeerConstructor {
        once(unix_connect_peer(h, &self.0))
    }
    specifier_boilerplate!(noglobalstate singleconnect no_subspec typ=Other);
}

#[derive(Debug, Clone)]
pub struct UnixListen(pub PathBuf);
impl Specifier for UnixListen {
    fn construct(&self, h: &Handle, _: &mut ProgramState, opts: Rc<Options>) -> PeerConstructor {
        multi(unix_listen_peer(h, &self.0, opts))
    }
    specifier_boilerplate!(noglobalstate multiconnect no_subspec typ=Other);
}

#[derive(Debug, Clone)]
pub struct UnixDgram(pub PathBuf, pub PathBuf);
impl Specifier for UnixDgram {
    fn construct(&self, h: &Handle, _: &mut ProgramState, opts: Rc<Options>) -> PeerConstructor {
        once(dgram_peer(h, &self.0, &self.1, opts))
    }
    specifier_boilerplate!(noglobalstate singleconnect no_subspec typ=Other);
}

fn to_abstract(x: &str) -> PathBuf {
    format!("\x00{}", x).into()
}

#[derive(Debug, Clone)]
pub struct AbstractConnect(pub String);
impl Specifier for AbstractConnect {
    fn construct(&self, h: &Handle, _: &mut ProgramState, _opts: Rc<Options>) -> PeerConstructor {
        once(unix_connect_peer(h, &to_abstract(&self.0)))
    }
    specifier_boilerplate!(noglobalstate singleconnect no_subspec typ=Other);
}

#[derive(Debug, Clone)]
pub struct AbstractListen(pub String);
impl Specifier for AbstractListen {
    fn construct(&self, h: &Handle, _: &mut ProgramState, _opts: Rc<Options>) -> PeerConstructor {
        multi(unix_listen_peer(
            h,
            &to_abstract(&self.0),
            Rc::new(Default::default()),
        ))
    }
    specifier_boilerplate!(noglobalstate multiconnect no_subspec typ=Other);
}

#[derive(Debug, Clone)]
pub struct AbstractDgram(pub String, pub String);
impl Specifier for AbstractDgram {
    fn construct(&self, h: &Handle, _: &mut ProgramState, opts: Rc<Options>) -> PeerConstructor {
        #[cfg(not(feature = "workaround1"))]
        {
            once(dgram_peer(
                h,
                &to_abstract(&self.0),
                &to_abstract(&self.1),
                opts,
            ))
        }
        #[cfg(feature = "workaround1")]
        {
            once(dgram_peer_workaround(
                h,
                &to_abstract(&self.0),
                &to_abstract(&self.1),
                opts,
            ))
        }
    }
    specifier_boilerplate!(noglobalstate singleconnect no_subspec typ=Other);
}

// based on https://github.com/tokio-rs/tokio-core/blob/master/examples/proxy.rs
#[derive(Clone)]
struct MyUnixStream(Rc<UnixStream>, bool);

impl Read for MyUnixStream {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        (&*self.0).read(buf)
    }
}

impl Write for MyUnixStream {
    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
        (&*self.0).write(buf)
    }

    fn flush(&mut self) -> IoResult<()> {
        Ok(())
    }
}

impl AsyncRead for MyUnixStream {}

impl AsyncWrite for MyUnixStream {
    fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {
        try!(self.0.shutdown(std::net::Shutdown::Write));
        Ok(().into())
    }
}

impl Drop for MyUnixStream {
    fn drop(&mut self) {
        let i_am_read_part = self.1;
        if i_am_read_part {
            let _ = self.0.shutdown(std::net::Shutdown::Read);
        }
    }
}

pub fn unix_connect_peer(handle: &Handle, addr: &Path) -> BoxedNewPeerFuture {
    Box::new(futures::future::result(
        UnixStream::connect(&addr, handle)
            .map(|x| {
                info!("Connected to a unix socket");
                let x = Rc::new(x);
                Peer::new(
                    MyUnixStream(x.clone(), true),
                    MyUnixStream(x.clone(), false),
                )
            })
            .map_err(box_up_err),
    )) as BoxedNewPeerFuture
}

pub fn unix_listen_peer(handle: &Handle, addr: &Path, opts: Rc<Options>) -> BoxedNewPeerStream {
    if opts.unlink_unix_socket {
        let _ = ::std::fs::remove_file(addr);
    };
    let bound = match UnixListener::bind(&addr, handle) {
        Ok(x) => x,
        Err(e) => return peer_err_s(e),
    };
    // TODO: chmod
    Box::new(
        bound
            .incoming()
            .map(|(x, _addr)| {
                info!("Incoming unix socket connection");
                let x = Rc::new(x);
                Peer::new(
                    MyUnixStream(x.clone(), true),
                    MyUnixStream(x.clone(), false),
                )
            })
            .map_err(|e| box_up_err(e)),
    ) as BoxedNewPeerStream
}

struct DgramPeer {
    s: UnixDatagram,
    oneshot_mode: bool,
}

#[derive(Clone)]
struct DgramPeerHandle(Rc<RefCell<DgramPeer>>);

pub fn dgram_peer(
    handle: &Handle,
    bindaddr: &Path,
    connectaddr: &Path,
    opts: Rc<Options>,
) -> BoxedNewPeerFuture {
    Box::new(futures::future::result(
        UnixDatagram::bind(bindaddr, handle)
            .and_then(|x| {
                x.connect(connectaddr)?;

                let h1 = DgramPeerHandle(Rc::new(RefCell::new(DgramPeer {
                    s: x,
                    oneshot_mode: opts.udp_oneshot_mode,
                })));
                let h2 = h1.clone();
                Ok(Peer::new(h1, h2))
            })
            .map_err(box_up_err),
    )) as BoxedNewPeerFuture
}

#[cfg(feature = "workaround1")]
extern crate libc;
#[cfg(feature = "workaround1")]
pub fn dgram_peer_workaround(
    handle: &Handle,
    bindaddr: &Path,
    connectaddr: &Path,
    opts: Rc<Options>,
) -> BoxedNewPeerFuture {
    info!("Workaround method for getting abstract datagram socket");
    fn getfd(bindaddr: &Path, connectaddr: &Path) -> Option<i32> {
        use self::libc::{bind, c_char, connect, sa_family_t, sockaddr, sockaddr_un, socket,
                         socklen_t, AF_UNIX, SOCK_DGRAM};
        use std::mem::{size_of, transmute};
        use std::os::unix::ffi::OsStrExt;
        unsafe {
            let s = socket(AF_UNIX, SOCK_DGRAM, 0);
            if s == -1 {
                return None;
            }
            {
                let mut sa = sockaddr_un {
                    sun_family: AF_UNIX as sa_family_t,
                    sun_path: [0; 108],
                };
                let bp: &[c_char] = transmute(bindaddr.as_os_str().as_bytes());
                let l = 108.min(bp.len());
                sa.sun_path[..l].copy_from_slice(&bp[..l]);
                let sa_len = l + size_of::<sa_family_t>();
                let ret = bind(s, transmute(&sa), sa_len as socklen_t);
                if ret == -1 {
                    return None;
                }
            }
            {
                let mut sa = sockaddr_un {
                    sun_family: AF_UNIX as sa_family_t,
                    sun_path: [0; 108],
                };
                let bp: &[c_char] = transmute(connectaddr.as_os_str().as_bytes());
                let l = 108.min(bp.len());
                sa.sun_path[..l].copy_from_slice(&bp[..l]);
                let sa_len = l + size_of::<sa_family_t>();
                let ret = connect(s, transmute(&sa), sa_len as socklen_t);
                if ret == -1 {
                    return None;
                }
            }
            Some(s)
        }
    }
    fn getpeer(
        handle: &Handle,
        bindaddr: &Path,
        connectaddr: &Path,
        opts: Rc<Options>,
    ) -> Result<Peer, Box<::std::error::Error>> {
        if let Some(fd) = getfd(bindaddr, connectaddr) {
            let s: ::std::os::unix::net::UnixDatagram =
                unsafe { ::std::os::unix::io::FromRawFd::from_raw_fd(fd) };
            let ss = UnixDatagram::from_datagram(s, handle)?;
            let h1 = DgramPeerHandle(Rc::new(RefCell::new(DgramPeer {
                s: ss,
                oneshot_mode: opts.udp_oneshot_mode,
            })));
            let h2 = h1.clone();
            Ok(Peer::new(h1, h2))
        } else {
            Err("Failed to get, bind or connect socket")?
        }
    }
    Box::new(futures::future::result({
        getpeer(handle, bindaddr, connectaddr, opts)
    })) as BoxedNewPeerFuture
}

impl Read for DgramPeerHandle {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        let mut p = self.0.borrow_mut();
        p.s.recv(buf)
    }
}

impl Write for DgramPeerHandle {
    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
        let mut p = self.0.borrow_mut();
        p.s.send(buf)
    }

    fn flush(&mut self) -> IoResult<()> {
        Ok(())
    }
}

impl AsyncRead for DgramPeerHandle {}

impl AsyncWrite for DgramPeerHandle {
    fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {
        Ok(().into())
    }
}
<commit_msg>Cleanup unix_peer a bit<commit_after>extern crate tokio_uds;

use futures;
use futures::stream::Stream;
use std;
use std::io::Result as IoResult;
use std::io::{Read, Write};
use tokio_core::reactor::Handle;
use tokio_io::{AsyncRead, AsyncWrite};

use std::cell::RefCell;
use std::rc::Rc;

use std::path::{Path, PathBuf};

use self::tokio_uds::{UnixDatagram, UnixListener, UnixStream};

use super::{box_up_err, peer_err_s, BoxedNewPeerFuture, BoxedNewPeerStream, Peer};
use super::{multi, once, Options, PeerConstructor, ProgramState, Specifier};

#[derive(Debug, Clone)]
pub struct UnixConnect(pub PathBuf);
impl Specifier for UnixConnect {
    fn construct(&self, h: &Handle, _: &mut ProgramState, _opts: Rc<Options>) -> PeerConstructor {
        once(unix_connect_peer(h, &self.0))
    }
    specifier_boilerplate!(noglobalstate singleconnect no_subspec typ=Other);
}

#[derive(Debug, Clone)]
pub struct UnixListen(pub PathBuf);
impl Specifier for UnixListen {
    fn construct(&self, h: &Handle, _: &mut ProgramState, opts: Rc<Options>) -> PeerConstructor {
        multi(unix_listen_peer(h, &self.0, opts))
    }
    specifier_boilerplate!(noglobalstate multiconnect no_subspec typ=Other);
}

#[derive(Debug, Clone)]
pub struct UnixDgram(pub PathBuf, pub PathBuf);
impl Specifier for UnixDgram {
    fn construct(&self, h: &Handle, _: &mut ProgramState, opts: Rc<Options>) -> PeerConstructor {
        once(dgram_peer(h, &self.0, &self.1, opts))
    }
    specifier_boilerplate!(noglobalstate singleconnect no_subspec typ=Other);
}

fn to_abstract(x: &str) -> PathBuf {
    format!("\x00{}", x).into()
}

#[derive(Debug, Clone)]
pub struct AbstractConnect(pub String);
impl Specifier for AbstractConnect {
    fn construct(&self, h: &Handle, _: &mut ProgramState, _opts: Rc<Options>) -> PeerConstructor {
        once(unix_connect_peer(h, &to_abstract(&self.0)))
    }
    specifier_boilerplate!(noglobalstate singleconnect no_subspec typ=Other);
}

#[derive(Debug, Clone)]
pub struct AbstractListen(pub String);
impl Specifier for AbstractListen {
    fn construct(&self, h: &Handle, _: &mut ProgramState, _opts: Rc<Options>) -> PeerConstructor {
        multi(unix_listen_peer(
            h,
            &to_abstract(&self.0),
            Rc::new(Default::default()),
        ))
    }
    specifier_boilerplate!(noglobalstate multiconnect no_subspec typ=Other);
}

#[derive(Debug, Clone)]
pub struct AbstractDgram(pub String, pub String);
impl Specifier for AbstractDgram {
    fn construct(&self, h: &Handle, _: &mut ProgramState, opts: Rc<Options>) -> PeerConstructor {
        #[cfg(not(feature = "workaround1"))]
        {
            once(dgram_peer(
                h,
                &to_abstract(&self.0),
                &to_abstract(&self.1),
                opts,
            ))
        }
        #[cfg(feature = "workaround1")]
        {
            once(dgram_peer_workaround(
                h,
                &to_abstract(&self.0),
                &to_abstract(&self.1),
                opts,
            ))
        }
    }
    specifier_boilerplate!(noglobalstate singleconnect no_subspec typ=Other);
}

// based on https://github.com/tokio-rs/tokio-core/blob/master/examples/proxy.rs
#[derive(Clone)]
struct MyUnixStream(Rc<UnixStream>, bool);

impl Read for MyUnixStream {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        (&*self.0).read(buf)
    }
}

impl Write for MyUnixStream {
    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
        (&*self.0).write(buf)
    }

    fn flush(&mut self) -> IoResult<()> {
        Ok(())
    }
}

impl AsyncRead for MyUnixStream {}

impl AsyncWrite for MyUnixStream {
    fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {
        try!(self.0.shutdown(std::net::Shutdown::Write));
        Ok(().into())
    }
}

impl Drop for MyUnixStream {
    fn drop(&mut self) {
        let i_am_read_part = self.1;
        if i_am_read_part {
            let _ = self.0.shutdown(std::net::Shutdown::Read);
        }
    }
}

pub fn unix_connect_peer(handle: &Handle, addr: &Path) -> BoxedNewPeerFuture {
    Box::new(futures::future::result(
        UnixStream::connect(&addr, handle)
            .map(|x| {
                info!("Connected to a unix socket");
                let x = Rc::new(x);
                Peer::new(
                    MyUnixStream(x.clone(), true),
                    MyUnixStream(x.clone(), false),
                )
            })
            .map_err(box_up_err),
    )) as BoxedNewPeerFuture
}

pub fn unix_listen_peer(handle: &Handle, addr: &Path, opts: Rc<Options>) -> BoxedNewPeerStream {
    if opts.unlink_unix_socket {
        let _ = ::std::fs::remove_file(addr);
    };
    let bound = match UnixListener::bind(&addr, handle) {
        Ok(x) => x,
        Err(e) => return peer_err_s(e),
    };
    // TODO: chmod
    Box::new(
        bound
            .incoming()
            .map(|(x, _addr)| {
                info!("Incoming unix socket connection");
                let x = Rc::new(x);
                Peer::new(
                    MyUnixStream(x.clone(), true),
                    MyUnixStream(x.clone(), false),
                )
            })
            .map_err(|e| box_up_err(e)),
    ) as BoxedNewPeerStream
}

struct DgramPeer {
    s: UnixDatagram,
    #[allow(unused)]
    oneshot_mode: bool, // TODO
}

#[derive(Clone)]
struct DgramPeerHandle(Rc<RefCell<DgramPeer>>);

pub fn dgram_peer(
    handle: &Handle,
    bindaddr: &Path,
    connectaddr: &Path,
    opts: Rc<Options>,
) -> BoxedNewPeerFuture {
    Box::new(futures::future::result(
        UnixDatagram::bind(bindaddr, handle)
            .and_then(|x| {
                x.connect(connectaddr)?;

                let h1 = DgramPeerHandle(Rc::new(RefCell::new(DgramPeer {
                    s: x,
                    oneshot_mode: opts.udp_oneshot_mode,
                })));
                let h2 = h1.clone();
                Ok(Peer::new(h1, h2))
            })
            .map_err(box_up_err),
    )) as BoxedNewPeerFuture
}

#[cfg(feature = "workaround1")]
extern crate libc;
#[cfg(feature = "workaround1")]
pub fn dgram_peer_workaround(
    handle: &Handle,
    bindaddr: &Path,
    connectaddr: &Path,
    opts: Rc<Options>,
) -> BoxedNewPeerFuture {
    info!("Workaround method for getting abstract datagram socket");
    fn getfd(bindaddr: &Path, connectaddr: &Path) -> Option<i32> {
        use self::libc::{bind, c_char, connect, sa_family_t, sockaddr, sockaddr_un, socket,
                         socklen_t, AF_UNIX, SOCK_DGRAM};
        use std::mem::{size_of, transmute};
        use std::os::unix::ffi::OsStrExt;
        unsafe {
            let s = socket(AF_UNIX, SOCK_DGRAM, 0);
            if s == -1 {
                return None;
            }
            {
                let mut sa = sockaddr_un {
                    sun_family: AF_UNIX as sa_family_t,
                    sun_path: [0; 108],
                };
                let bp: &[c_char] = transmute(bindaddr.as_os_str().as_bytes());
                let l = 108.min(bp.len());
                sa.sun_path[..l].copy_from_slice(&bp[..l]);
                let sa_len = l + size_of::<sa_family_t>();
                let ret = bind(s, transmute(&sa), sa_len as socklen_t);
                if ret == -1 {
                    return None;
                }
            }
            {
                let mut sa = sockaddr_un {
                    sun_family: AF_UNIX as sa_family_t,
                    sun_path: [0; 108],
                };
                let bp: &[c_char] = transmute(connectaddr.as_os_str().as_bytes());
                let l = 108.min(bp.len());
                sa.sun_path[..l].copy_from_slice(&bp[..l]);
                let sa_len = l + size_of::<sa_family_t>();
                let ret = connect(s, transmute(&sa), sa_len as socklen_t);
                if ret == -1 {
                    return None;
                }
            }
            Some(s)
        }
    }
    fn getpeer(
        handle: &Handle,
        bindaddr: &Path,
        connectaddr: &Path,
        opts: Rc<Options>,
    ) -> Result<Peer, Box<::std::error::Error>> {
        if let Some(fd) = getfd(bindaddr, connectaddr) {
            let s: ::std::os::unix::net::UnixDatagram =
                unsafe { ::std::os::unix::io::FromRawFd::from_raw_fd(fd) };
            let ss = UnixDatagram::from_datagram(s, handle)?;
            let h1 = DgramPeerHandle(Rc::new(RefCell::new(DgramPeer {
                s: ss,
                oneshot_mode: opts.udp_oneshot_mode,
            })));
            let h2 = h1.clone();
            Ok(Peer::new(h1, h2))
        } else {
            Err("Failed to get, bind or connect socket")?
        }
    }
    Box::new(futures::future::result({
        getpeer(handle, bindaddr, connectaddr, opts)
    })) as BoxedNewPeerFuture
}

impl Read for DgramPeerHandle {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        let p = self.0.borrow_mut();
        p.s.recv(buf)
    }
}

impl Write for DgramPeerHandle {
    fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
        let p = self.0.borrow_mut();
        p.s.send(buf)
    }

    fn flush(&mut self) -> IoResult<()> {
        Ok(())
    }
}

impl AsyncRead for DgramPeerHandle {}

impl AsyncWrite for DgramPeerHandle {
    fn shutdown(&mut self) -> futures::Poll<(), std::io::Error> {
        Ok(().into())
    }
}
<|endoftext|>