<commit_before>use std::rc::Rc;
use std::cell::RefCell;
use std::collections::HashMap;
use std::ops::Deref;
use std::marker::PhantomData;

// What does this do? You'll never guess!
type HeapId<'a> = PhantomData<std::cell::Cell<&'a mut ()>>;

// Pair is the only type that is actually allocated inside the heap (private)
struct Pair<'a> {
    mark: bool,
    head: XValue<'a>,
    tail: XValue<'a>
}

// Values inside the heap (GC heap-to-heap cross-references) (private)
enum XValue<'a> { Null, Int(i32), Str(Rc<String>), Pair(*mut Pair<'a>, HeapId<'a>) }

// The heap is (for now) just a big Vec of Pairs
pub struct Heap<'a> {
    id: HeapId<'a>,
    storage: Vec<Pair<'a>>,
    freelist: *mut Pair<'a>,
    pins: RefCell<HashMap<*mut Pair<'a>, usize>>
}

pub const HEAP_SIZE: usize = 10000;

pub fn with_heap<F, O>(f: F) -> O
    where F: for<'a> FnOnce(Heap<'a>) -> O
{
    f(Heap::new())
}

impl<'a> Heap<'a> {
    fn new() -> Heap<'a> {
        // Allocate with the full capacity so that allocated Pairs never move
        let mut h = Heap {
            id: PhantomData,
            storage: Vec::with_capacity(HEAP_SIZE),
            freelist: std::ptr::null_mut(),
            pins: RefCell::new(HashMap::new())
        };
        for i in 0 .. HEAP_SIZE {
            h.storage.push(Pair {
                mark: false,
                head: XValue::Null,
                tail: XValue::Null
            });
            let p = &mut h.storage[i] as *mut Pair<'a>;
            unsafe {
                h.add_to_free_list(p);
            }
        }
        h
    }

    fn pin(&self, p: *mut Pair<'a>) {
        let mut pins = self.pins.borrow_mut();
        let entry = pins.entry(p).or_insert(0);
        *entry += 1;
    }

    fn unpin(&self, p: *mut Pair<'a>) {
        let mut pins = self.pins.borrow_mut();
        if {
            let entry = pins.entry(p).or_insert(0);
            assert!(*entry != 0);
            *entry -= 1;
            *entry == 0
        } {
            pins.remove(&p);
        }
    }

    unsafe fn add_to_free_list(&mut self, p: *mut Pair<'a>) {
        let listp: *mut *mut Pair<'a> = std::mem::transmute(p);
        *listp = self.freelist;
        assert_eq!(*listp, self.freelist);
        self.freelist = p;
    }

    pub fn try_alloc(&mut self, pair: (Value<'a>, Value<'a>)) -> Option<PairRoot<'a>> {
        if self.freelist.is_null() {
            unsafe {
                self.gc();
            }
            if self.freelist.is_null() {
                return None;
            }
        }

        let p = self.freelist;
        unsafe {
            let listp: *mut *mut Pair<'a> = std::mem::transmute(p);
            self.freelist = *listp;

            let (h, t) = pair;
            *p = Pair {
                mark: false,
                head: value_to_heap(h),
                tail: value_to_heap(t)
            };
            Some(PairRoot::new(self, p))
        }
    }

    pub fn alloc(&mut self, pair: (Value<'a>, Value<'a>)) -> PairRoot<'a> {
        self.try_alloc(pair).expect("out of memory (gc did not collect anything)")
    }

    pub fn alloc_null(&mut self) -> PairRoot<'a> {
        self.alloc((Value::Null, Value::Null))
    }

    unsafe fn mark(p: *mut Pair<'a>) {
        if !p.is_null() && !(*p).mark {
            (*p).mark = true;
            Heap::mark_value(&(*p).head);
            Heap::mark_value(&(*p).tail);
        }
    }

    unsafe fn mark_value(v: &XValue<'a>) {
        match v {
            &XValue::Pair(p, _) => Heap::mark(p),
            _ => {}
        }
    }

    unsafe fn gc(&mut self) {
        // clear mark bits
        for p in &mut self.storage {
            p.mark = false;
        }

        // mark phase
        for (&p, _) in self.pins.borrow().deref() {
            Heap::mark(p);
        }

        // sweep phase
        self.freelist = std::ptr::null_mut();
        for i in 0 .. HEAP_SIZE {
            let p = &mut self.storage[i] as *mut Pair<'a>;
            if !(*p).mark {
                self.add_to_free_list(p);
            }
        }
    }

    #[cfg(test)]
    pub fn force_gc(&mut self) {
        unsafe { self.gc(); }
    }
}

// === Values outside the heap that may refer to heap values

// Handle to a Pair that lives in the heap.
#[allow(raw_pointer_derive)]
#[derive(Debug, PartialEq)]
pub struct PairRoot<'a>(*mut Pair<'a>, *const Heap<'a>, HeapId<'a>);

impl<'a> Drop for PairRoot<'a> {
    fn drop(&mut self) {
        unsafe {
            (*self.1).unpin(self.0);
        }
    }
}

impl<'a> Clone for PairRoot<'a> {
    fn clone(&self) -> PairRoot<'a> {
        let p = self.0;
        let heap = self.1;
        unsafe {
            (*heap).pin(p);
        }
        PairRoot(p, heap, self.2)
    }
}

impl<'a> PairRoot<'a> {
    unsafe fn new(heap: &Heap<'a>, p: *mut Pair<'a>) -> PairRoot<'a> {
        heap.pin(p);
        PairRoot(p, heap as *const Heap<'a>, heap.id)
    }

    pub fn head(&self) -> Value<'a> {
        let p = self.0;
        unsafe { value_from_heap(&*self.1, &(*p).head) }
    }

    pub fn tail(&self) -> Value<'a> {
        let p = self.0;
        unsafe { value_from_heap(&*self.1, &(*p).tail) }
    }

    pub fn set_head(&self, v: Value<'a>) {
        let p = self.0;
        unsafe { (*p).head = value_to_heap(v); }
    }

    pub fn set_tail(&self, v: Value<'a>) {
        let p = self.0;
        unsafe { (*p).tail = value_to_heap(v); }
    }

    #[cfg(test)]
    pub fn address(&self) -> usize {
        unsafe { std::mem::transmute(self.0) }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum Value<'a> {
    Null,
    Int(i32),
    Str(Rc<String>),  // <-- equality is by value
    Pair(PairRoot<'a>)  // <-- equality is by pointer
}

// === Getting data into and out of the heap

fn value_to_heap<'a>(v: Value<'a>) -> XValue<'a> {
    match v {
        Value::Null => XValue::Null,
        Value::Int(n) => XValue::Int(n),
        Value::Str(rcstr) => XValue::Str(rcstr),
        Value::Pair(PairRoot(p, _, heap_id)) => XValue::Pair(p, heap_id)
    }
}

unsafe fn value_from_heap<'a>(heap: &Heap<'a>, v: &XValue<'a>) -> Value<'a> {
    match v {
        &XValue::Null => Value::Null,
        &XValue::Int(n) => Value::Int(n),
        &XValue::Str(ref rcstr) => Value::Str(rcstr.clone()),
        &XValue::Pair(p, _) => Value::Pair(PairRoot::new(heap, p))
    }
}

#[cfg(test)]
mod test {
    use super::with_heap;
    use super::Value;
    use super::HEAP_SIZE;
    use std::rc::Rc;

    /// Test that a Heap can at least allocate two objects.
    #[test]
    fn can_allocate_twice() {
        with_heap(|mut heap| {
            let obj1 = heap.alloc((Value::Int(1), Value::Null));
            let obj2 = heap.alloc((Value::Int(2), Value::Null));
            assert_eq!(obj1.head(), Value::Int(1));
            assert_eq!(obj2.head(), Value::Int(2));
        });
    }

    /// Test that rooted objects are not collected and reused.
    #[test]
    fn root_is_not_recycled() {
        with_heap(|mut heap| {
            // Create and root one object.
            let root = heap.alloc((Value::Int(1), Value::Str(Rc::new("hello world".to_string()))));

            // Subsequent allocations never return root.
            for _ in 0 .. HEAP_SIZE * 2 {
                let tmp = heap.alloc_null();
                assert!(tmp != root);
            }
        });
    }

    /// Test try_alloc()'s behavior when the heap is full and every Object is
    /// reachable.
    #[test]
    fn full_heap() {
        with_heap(|mut heap| {
            // Fill up the heap by allocating HEAP_SIZE objects.
            let mut v = Value::Null;
            for _ in 0 .. HEAP_SIZE {
                v = Value::Pair(heap.alloc((Value::Null, v)));
            }

            // The whole heap is reachable.  Now try_alloc() should return null every
            // time it's called.
            for _ in 0 .. 4 {
                assert_eq!(heap.try_alloc((Value::Null, Value::Null)), None);
            }
        });
    }

    /// Test allocate()'s behavior when the heap is only almost full.
    #[test]
    fn nearly_full_heap() {
        with_heap(|mut heap| {
            // Make the heap nearly full by allocating (HEAP_SIZE - 1) objects.
            let mut v = Value::Null;
            for _ in 0 .. HEAP_SIZE - 1 {
                v = Value::Pair(heap.alloc((Value::Null, v)));
            }

            // Now the entire heap is reachable except for one Object.  We should
            // be able to call allocate() successfully, repeatedly.  It returns
            // that one object every time it's called!
            let last = heap.alloc_null().address();
            for _ in 0 .. 10 {
                assert_eq!(heap.alloc_null().address(), last);
            }
        });
    }

    /// Test that objects reachable from a root's `.head` or `.tail` are not
    /// collected.
    #[test]
    fn reachable_objects_not_collected() {
        with_heap(|mut heap| {
            let obj1 = heap.alloc_null();
            let (p2, p3, p4, p5);
            {
                let obj2 = heap.alloc_null();
                p2 = obj2.address();
                obj1.set_head(Value::Pair(obj2.clone()));
                let obj3 = heap.alloc_null();
                p3 = obj3.address();
                obj1.set_tail(Value::Pair(obj3));
                let obj4 = heap.alloc_null();
                p4 = obj4.address();
                obj2.set_head(Value::Pair(obj4));
                let obj5 = heap.alloc_null();
                p5 = obj5.address();
                obj2.set_tail(Value::Pair(obj5));
            }

            heap.force_gc();

            let h = match obj1.head() {
                Value::Pair(p) => p,
                _ => panic!("expected pair in obj1.head")
            };
            assert_eq!(h.address(), p2);

            let t = match obj1.tail() {
                Value::Pair(p) => p,
                _ => panic!("expected pair in obj1.tail")
            };
            assert_eq!(t.address(), p3);

            let hh = match h.head() {
                Value::Pair(p) => p,
                _ => panic!("expected pair in obj1.head.head")
            };
            assert_eq!(hh.address(), p4);

            let ht = match h.tail() {
                Value::Pair(p) => p,
                _ => panic!("expected pair in obj1.head.tail")
            };
            assert_eq!(ht.address(), p5);
        });
    }

    /// Test that the GC is not confused by an object that contains pointers to
    /// itself.
    #[test]
    fn root_self_references() {
        with_heap(|mut heap| {
            // Create a root object that contains pointers to itself.
            let root = heap.alloc_null();
            root.set_head(Value::Pair(root.clone()));
            root.set_tail(Value::Pair(root.clone()));

            heap.force_gc();

            // After GC, the root object should be unchanged.
            assert_eq!(root.head(), Value::Pair(root.clone()));
            assert_eq!(root.tail(), Value::Pair(root.clone()));
        });
    }

    /// Test that the GC is not confused by cycles in the reachable object graph.
    #[test]
    fn test_root_cycle() {
        with_heap(|mut heap| {
            // Set up obj1 and obj2 to point to each other.
            let obj1 = heap.alloc_null();
            let obj2 = heap.alloc((Value::Pair(obj1.clone()),
                                   Value::Pair(obj1.clone())));  // obj2 points to obj1
            obj1.set_head(Value::Pair(obj2.clone()));  // and vice versa
            obj1.set_tail(Value::Pair(obj2.clone()));

            heap.force_gc();

            // After GC, the two objects are unchanged.
            assert_eq!(obj1.head(), Value::Pair(obj2.clone()));
            assert_eq!(obj1.tail(), Value::Pair(obj2.clone()));
            assert_eq!(obj2.head(), Value::Pair(obj1.clone()));
            assert_eq!(obj2.tail(), Value::Pair(obj1.clone()));
        });
    }

    /// Test that the GC is not confused by cycles that are garbage.
    #[test]
    fn unreachable_cycle() {
        with_heap(|mut heap| {
            // Make a cycle.
            let (p1, p2);
            {
                let obj1 = heap.alloc_null();
                p1 = obj1.address();
                let obj2 = heap.alloc_null();
                p2 = obj2.address();
                obj2.set_tail(Value::Pair(obj1.clone()));
                obj1.set_tail(Value::Pair(obj2.clone()));
            }  // Make the cycle unreachable.

            // Allocation should eventually recycle both objects.
            let mut recycled1 = 0;
            let mut recycled2 = 0;
            let mut root = Value::Null;
            for _ in 0 .. HEAP_SIZE {
                let p = heap.alloc((Value::Null, root));
                root = Value::Pair(p.clone());
                if p.address() == p1 {
                    recycled1 += 1;
                }
                if p.address() == p2 {
                    recycled2 += 1;
                }
            }
            assert_eq!(recycled1, 1);
            assert_eq!(recycled2, 1);
        });
    }

    /*
    /// Test that you can't share values across separate heaps.
    #[test]
    fn bug_swapping() {
        with_heap(|mut heap1| {
            with_heap(|mut heap2| {
                let obj1 = heap1.alloc_null();  // error: cannot infer an appropriate lifetime parameter
                let obj2 = heap2.alloc((Value::Null, Value::Pair(obj1)));
                heap1.force_gc();
                heap2.force_gc();
            });
        });
    }
    */
}
<commit_msg>A few more tests.<commit_after>use std::rc::Rc;
use std::cell::RefCell;
use std::collections::HashMap;
use std::ops::Deref;
use std::marker::PhantomData;

// What does this do? You'll never guess!
type HeapId<'a> = PhantomData<std::cell::Cell<&'a mut ()>>;

// Pair is the only type that is actually allocated inside the heap (private)
struct Pair<'a> {
    mark: bool,
    head: XValue<'a>,
    tail: XValue<'a>
}

// Values inside the heap (GC heap-to-heap cross-references) (private)
enum XValue<'a> { Null, Int(i32), Str(Rc<String>), Pair(*mut Pair<'a>, HeapId<'a>) }

// The heap is (for now) just a big Vec of Pairs
pub struct Heap<'a> {
    id: HeapId<'a>,
    storage: Vec<Pair<'a>>,
    freelist: *mut Pair<'a>,
    pins: RefCell<HashMap<*mut Pair<'a>, usize>>
}

pub const HEAP_SIZE: usize = 10000;

pub fn with_heap<F, O>(f: F) -> O
    where F: for<'a> FnOnce(Heap<'a>) -> O
{
    f(Heap::new())
}

impl<'a> Heap<'a> {
    fn new() -> Heap<'a> {
        // Allocate with the full capacity so that allocated Pairs never move
        let mut h = Heap {
            id: PhantomData,
            storage: Vec::with_capacity(HEAP_SIZE),
            freelist: std::ptr::null_mut(),
            pins: RefCell::new(HashMap::new())
        };
        for i in 0 .. HEAP_SIZE {
            h.storage.push(Pair {
                mark: false,
                head: XValue::Null,
                tail: XValue::Null
            });
            let p = &mut h.storage[i] as *mut Pair<'a>;
            unsafe {
                h.add_to_free_list(p);
            }
        }
        h
    }

    fn pin(&self, p: *mut Pair<'a>) {
        let mut pins = self.pins.borrow_mut();
        let entry = pins.entry(p).or_insert(0);
        *entry += 1;
    }

    fn unpin(&self, p: *mut Pair<'a>) {
        let mut pins = self.pins.borrow_mut();
        if {
            let entry = pins.entry(p).or_insert(0);
            assert!(*entry != 0);
            *entry -= 1;
            *entry == 0
        } {
            pins.remove(&p);
        }
    }

    unsafe fn add_to_free_list(&mut self, p: *mut Pair<'a>) {
        let listp: *mut *mut Pair<'a> = std::mem::transmute(p);
        *listp = self.freelist;
        assert_eq!(*listp, self.freelist);
        self.freelist = p;
    }

    pub fn try_alloc(&mut self, pair: (Value<'a>, Value<'a>)) -> Option<PairRoot<'a>> {
        if self.freelist.is_null() {
            unsafe {
                self.gc();
            }
            if self.freelist.is_null() {
                return None;
            }
        }

        let p = self.freelist;
        unsafe {
            let listp: *mut *mut Pair<'a> = std::mem::transmute(p);
            self.freelist = *listp;

            let (h, t) = pair;
            *p = Pair {
                mark: false,
                head: value_to_heap(h),
                tail: value_to_heap(t)
            };
            Some(PairRoot::new(self, p))
        }
    }

    pub fn alloc(&mut self, pair: (Value<'a>, Value<'a>)) -> PairRoot<'a> {
        self.try_alloc(pair).expect("out of memory (gc did not collect anything)")
    }

    pub fn alloc_null(&mut self) -> PairRoot<'a> {
        self.alloc((Value::Null, Value::Null))
    }

    unsafe fn mark(p: *mut Pair<'a>) {
        if !p.is_null() && !(*p).mark {
            (*p).mark = true;
            Heap::mark_value(&(*p).head);
            Heap::mark_value(&(*p).tail);
        }
    }

    unsafe fn mark_value(v: &XValue<'a>) {
        match v {
            &XValue::Pair(p, _) => Heap::mark(p),
            _ => {}
        }
    }

    unsafe fn gc(&mut self) {
        // clear mark bits
        for p in &mut self.storage {
            p.mark = false;
        }

        // mark phase
        for (&p, _) in self.pins.borrow().deref() {
            Heap::mark(p);
        }

        // sweep phase
        self.freelist = std::ptr::null_mut();
        for i in 0 .. HEAP_SIZE {
            let p = &mut self.storage[i] as *mut Pair<'a>;
            if !(*p).mark {
                self.add_to_free_list(p);
            }
        }
    }

    #[cfg(test)]
    pub fn force_gc(&mut self) {
        unsafe { self.gc(); }
    }
}

// === Values outside the heap that may refer to heap values

// Handle to a Pair that lives in the heap.
#[allow(raw_pointer_derive)]
#[derive(Debug, PartialEq)]
pub struct PairRoot<'a>(*mut Pair<'a>, *const Heap<'a>, HeapId<'a>);

impl<'a> Drop for PairRoot<'a> {
    fn drop(&mut self) {
        unsafe {
            (*self.1).unpin(self.0);
        }
    }
}

impl<'a> Clone for PairRoot<'a> {
    fn clone(&self) -> PairRoot<'a> {
        let p = self.0;
        let heap = self.1;
        unsafe {
            (*heap).pin(p);
        }
        PairRoot(p, heap, self.2)
    }
}

impl<'a> PairRoot<'a> {
    unsafe fn new(heap: &Heap<'a>, p: *mut Pair<'a>) -> PairRoot<'a> {
        heap.pin(p);
        PairRoot(p, heap as *const Heap<'a>, heap.id)
    }

    pub fn head(&self) -> Value<'a> {
        let p = self.0;
        unsafe { value_from_heap(&*self.1, &(*p).head) }
    }

    pub fn tail(&self) -> Value<'a> {
        let p = self.0;
        unsafe { value_from_heap(&*self.1, &(*p).tail) }
    }

    pub fn set_head(&self, v: Value<'a>) {
        let p = self.0;
        unsafe { (*p).head = value_to_heap(v); }
    }

    pub fn set_tail(&self, v: Value<'a>) {
        let p = self.0;
        unsafe { (*p).tail = value_to_heap(v); }
    }

    #[cfg(test)]
    pub fn address(&self) -> usize {
        unsafe { std::mem::transmute(self.0) }
    }
}

#[derive(Debug, Clone, PartialEq)]
pub enum Value<'a> {
    Null,
    Int(i32),
    Str(Rc<String>),  // <-- equality is by value
    Pair(PairRoot<'a>)  // <-- equality is by pointer
}

// === Getting data into and out of the heap

fn value_to_heap<'a>(v: Value<'a>) -> XValue<'a> {
    match v {
        Value::Null => XValue::Null,
        Value::Int(n) => XValue::Int(n),
        Value::Str(rcstr) => XValue::Str(rcstr),
        Value::Pair(PairRoot(p, _, heap_id)) => XValue::Pair(p, heap_id)
    }
}

unsafe fn value_from_heap<'a>(heap: &Heap<'a>, v: &XValue<'a>) -> Value<'a> {
    match v {
        &XValue::Null => Value::Null,
        &XValue::Int(n) => Value::Int(n),
        &XValue::Str(ref rcstr) => Value::Str(rcstr.clone()),
        &XValue::Pair(p, _) => Value::Pair(PairRoot::new(heap, p))
    }
}

#[cfg(test)]
mod test {
    use super::with_heap;
    use super::Value;
    use super::HEAP_SIZE;
    use std::rc::Rc;

    /// Test that a Heap can at least allocate two objects.
    #[test]
    fn can_allocate_twice() {
        with_heap(|mut heap| {
            let obj1 = heap.alloc((Value::Int(1), Value::Null));
            let obj2 = heap.alloc((Value::Int(2), Value::Null));
            assert_eq!(obj1.head(), Value::Int(1));
            assert_eq!(obj2.head(), Value::Int(2));
        });
    }

    /// Test that rooted objects are not collected and reused.
    #[test]
    fn root_is_not_recycled() {
        with_heap(|mut heap| {
            // Create and root one object.
            let root = heap.alloc((Value::Int(1), Value::Str(Rc::new("hello world".to_string()))));

            // Subsequent allocations never return root.
            for _ in 0 .. HEAP_SIZE * 2 {
                let tmp = heap.alloc_null();
                assert!(tmp != root);
            }
        });
    }

    /// Test try_alloc()'s behavior when the heap is full and every Object is
    /// reachable.
    #[test]
    fn full_heap() {
        with_heap(|mut heap| {
            // Fill up the heap by allocating HEAP_SIZE objects.
            let mut v = Value::Null;
            for _ in 0 .. HEAP_SIZE {
                v = Value::Pair(heap.alloc((Value::Null, v)));
            }

            // The whole heap is reachable.  Now try_alloc() should return null every
            // time it's called.
            for _ in 0 .. 4 {
                assert_eq!(heap.try_alloc((Value::Null, Value::Null)), None);
            }
        });
    }

    /// Test allocate()'s behavior when the heap is only almost full.
    #[test]
    fn nearly_full_heap() {
        with_heap(|mut heap| {
            // Make the heap nearly full by allocating (HEAP_SIZE - 1) objects.
            let mut v = Value::Null;
            for _ in 0 .. HEAP_SIZE - 1 {
                v = Value::Pair(heap.alloc((Value::Null, v)));
            }

            // Now the entire heap is reachable except for one Object.  We should
            // be able to call allocate() successfully, repeatedly.  It returns
            // that one object every time it's called!
            let last = heap.alloc_null().address();
            for _ in 0 .. 10 {
                assert_eq!(heap.alloc_null().address(), last);
            }
        });
    }

    /// Test that objects reachable from a root's `.head` or `.tail` are not
    /// collected.
    #[test]
    fn reachable_objects_not_collected() {
        with_heap(|mut heap| {
            let obj1 = heap.alloc_null();
            let (p2, p3, p4, p5);
            {
                let obj2 = heap.alloc_null();
                p2 = obj2.address();
                obj1.set_head(Value::Pair(obj2.clone()));
                let obj3 = heap.alloc_null();
                p3 = obj3.address();
                obj1.set_tail(Value::Pair(obj3));
                let obj4 = heap.alloc_null();
                p4 = obj4.address();
                obj2.set_head(Value::Pair(obj4));
                let obj5 = heap.alloc_null();
                p5 = obj5.address();
                obj2.set_tail(Value::Pair(obj5));
            }

            heap.force_gc();

            let h = match obj1.head() {
                Value::Pair(p) => p,
                _ => panic!("expected pair in obj1.head")
            };
            assert_eq!(h.address(), p2);

            let t = match obj1.tail() {
                Value::Pair(p) => p,
                _ => panic!("expected pair in obj1.tail")
            };
            assert_eq!(t.address(), p3);

            let hh = match h.head() {
                Value::Pair(p) => p,
                _ => panic!("expected pair in obj1.head.head")
            };
            assert_eq!(hh.address(), p4);

            let ht = match h.tail() {
                Value::Pair(p) => p,
                _ => panic!("expected pair in obj1.head.tail")
            };
            assert_eq!(ht.address(), p5);
        });
    }

    /// Test that the GC is not confused by an object that contains pointers to
    /// itself.
    #[test]
    fn root_self_references() {
        with_heap(|mut heap| {
            // Create a root object that contains pointers to itself.
            let root = heap.alloc_null();
            root.set_head(Value::Pair(root.clone()));
            root.set_tail(Value::Pair(root.clone()));

            heap.force_gc();

            // After GC, the root object should be unchanged.
            assert_eq!(root.head(), Value::Pair(root.clone()));
            assert_eq!(root.tail(), Value::Pair(root.clone()));
        });
    }

    /// Test that the GC is not confused by cycles in the reachable object graph.
    #[test]
    fn test_root_cycle() {
        with_heap(|mut heap| {
            // Set up obj1 and obj2 to point to each other.
            let obj1 = heap.alloc_null();
            let obj2 = heap.alloc((Value::Pair(obj1.clone()),
                                   Value::Pair(obj1.clone())));  // obj2 points to obj1
            obj1.set_head(Value::Pair(obj2.clone()));  // and vice versa
            obj1.set_tail(Value::Pair(obj2.clone()));

            heap.force_gc();

            // After GC, the two objects are unchanged.
            assert_eq!(obj1.head(), Value::Pair(obj2.clone()));
            assert_eq!(obj1.tail(), Value::Pair(obj2.clone()));
            assert_eq!(obj2.head(), Value::Pair(obj1.clone()));
            assert_eq!(obj2.tail(), Value::Pair(obj1.clone()));
        });
    }

    /// Test that the GC is not confused by cycles that are garbage.
    #[test]
    fn unreachable_cycle() {
        with_heap(|mut heap| {
            // Make a cycle.
            let (p1, p2);
            {
                let obj1 = heap.alloc_null();
                p1 = obj1.address();
                let obj2 = heap.alloc_null();
                p2 = obj2.address();
                obj2.set_tail(Value::Pair(obj1.clone()));
                obj1.set_tail(Value::Pair(obj2.clone()));
            }  // Make the cycle unreachable.

            // Allocation should eventually recycle both objects.
            let mut recycled1 = 0;
            let mut recycled2 = 0;
            let mut root = Value::Null;
            for _ in 0 .. HEAP_SIZE {
                let p = heap.alloc((Value::Null, root));
                root = Value::Pair(p.clone());
                if p.address() == p1 {
                    recycled1 += 1;
                }
                if p.address() == p2 {
                    recycled2 += 1;
                }
            }
            assert_eq!(recycled1, 1);
            assert_eq!(recycled2, 1);
        });
    }

    // Tests that you can't share values across separate heaps.
    // Try uncommenting the tests below: if any of them compile successfully,
    // consider it a test failure!
    /*
    #[test]
    fn bug_swapping() {
        with_heap(|heap1| {
            with_heap(|mut heap2| {
                let obj1 = heap1.alloc_null();  // error: cannot infer an appropriate lifetime parameter
                let obj2 = heap2.alloc((Value::Null, Value::Pair(obj1)));
            });
        });
    }

    #[test]
    fn bug_swapping_2() {
        let heap1 = with_heap(|h| h);  // error: cannot infer an appropriate lifetime
        let heap2 = with_heap(|h| h);
        let obj1 = heap1.alloc_null();
        let obj2 = heap2.alloc((Value::Null, Value::Pair(obj1)));
    }

    #[test]
    fn bug_swapping_3() {
        with_heap(|heap1| {
            let heap2 = with_heap(|h| h);  // error: cannot infer an appropriate lifetime
            let obj1 = heap1.alloc_null();
            let obj2 = heap2.alloc((Value::Null, Value::Pair(obj1)));
        });
    }
    */
}
<|endoftext|>


<commit_before>extern crate izhikevich_neurons;
extern crate gnuplot;

use izhikevich_neurons::{Config, State, Num};
use gnuplot::{Figure, Caption, Color, AxesCommon};

type NeuronId = u32;
type SynapseId = u32;
type TimeStep = u32;
type Delay = u8;

const MAX_DELAY: u8 = 40;

struct Synapse {
    _pre_neuron: NeuronId,
    post_neuron: NeuronId,
    delay: Delay,
    weight: Num,
    _last_spike: TimeStep,
    // ... learning parameters
}

struct Neuron {
    state: State,
    config: Config,
    i_ext: Num,
    i_inp: Num,
    pre_synapses: Vec<SynapseId>,
    post_synapses: Vec<SynapseId>,
}

struct Network {
    neurons: Vec<Neuron>,
    synapses: Vec<Synapse>,
}

impl Network {
    fn new() -> Network {
        Network {
            neurons: Vec::new(),
            synapses: Vec::new()
        }
    }

    fn create_neuron(&mut self, config: Config) -> NeuronId {
        let neuron = Neuron {
            state: State::new(),
            config: config,
            i_ext: 0.0,
            i_inp: 0.0,
            pre_synapses: Vec::new(),
            post_synapses: Vec::new(),
        };
        let neuron_id = self.neurons.len() as u32;
        self.neurons.push(neuron);
        return neuron_id;
    }

    fn connect(&mut self, pre_neuron: NeuronId, post_neuron: NeuronId, delay: Delay, weight: Num) -> SynapseId {
        assert!((pre_neuron as usize) < self.neurons.len());
        assert!((post_neuron as usize) < self.neurons.len());
        assert!(delay > 0);
        assert!(delay <= MAX_DELAY);

        let synapse = Synapse {
            _pre_neuron: pre_neuron,
            post_neuron: post_neuron,
            delay: delay,
            weight: weight,
            _last_spike: 0, // XXX
        };
        let synapse_id = self.synapses.len() as u32;

        self.synapses.push(synapse);
        self.neurons[pre_neuron as usize].post_synapses.push(synapse_id);
        self.neurons[post_neuron as usize].pre_synapses.push(synapse_id);

        return synapse_id;
    }
}

fn main() {
    const PARAMS : &'static [(&'static str, &'static str)] = &[
        ("Neuron 1 [7 pA current 200..700ms]", "blue"),
        //("Neuron 2 [2.69 pA current 200..700ms]", 2.69, "red"),
        ("Neuron 2 [0.0 pA current 200..700ms]", "red"),
        //("Neuron 3 [2.7 pA current 200..700ms]", 2.7, "green")
    ];

    let mut network = Network::new();

    let n1 = network.create_neuron(Config::regular_spiking());
    let n2 = network.create_neuron(Config::regular_spiking());
    //let n3 = network.create_neuron(Config::regular_spiking());

    let external_inputs: &[(NeuronId, TimeStep, Num)] = &[
        (n1, 200, 7.0),
        (n1, 701, 0.0)
    ];

    // We use a cyclic buffer
    // We use (time_step % MAX_DELAY) as index into the futures_spike array
    let mut future_spikes: Vec<Vec<SynapseId>> = (0..MAX_DELAY as usize).map(|_| Vec::new()).collect();

    let _ = network.connect(n1, n2, 10, 7.0);
    let _ = network.connect(n1, n2, 5, 7.0);
    let _ = network.connect(n1, n2, 2, 7.0);
    let _ = network.connect(n1, n2, 2, 7.0);
    let _ = network.connect(n2, n2, 40, 17.0);
    let _ = network.connect(n2, n2, 40, 7.0);

    let mut states: Vec<_> = PARAMS.iter().map(|_| Vec::new()).collect();

    let mut time_step: TimeStep = 0;

    while time_step <= 1_000 {
        // record current state
        for (i, neuron) in network.neurons.iter().enumerate() {
            states[i].push(neuron.state);
        }
        time_step += 1;

        // Clear all input currents
        for neuron in network.neurons.iter_mut() {
            neuron.i_inp = 0.0;
        }

        // get all synapse input
        {
            let current_spikes = &mut future_spikes[(time_step % (MAX_DELAY as TimeStep)) as usize];
            for &syn_fired in current_spikes.iter() {
                println!("time: {}. input from synapse: {}", time_step, syn_fired);
                let (weight, post_neuron) = {
                    let syn = &network.synapses[syn_fired as usize];
                    (syn.weight, syn.post_neuron)
                };
                network.neurons[post_neuron as usize].i_inp += weight;
            }
            current_spikes.clear();
        }
        // set external inputs
        for &(n_id, at, current) in external_inputs {
            if time_step == at {
                network.neurons[n_id as usize].i_ext = current;
            }
        }

        // update state
        for (i, mut neuron) in network.neurons.iter_mut().enumerate() {
            let syn_i = neuron.i_ext + neuron.i_inp;

            let (new_state, fired) = neuron.state.step_1ms(syn_i, &neuron.config);
            neuron.state = new_state;
            if fired {
                println!("Neuron {} fired at {} ms", i, time_step);
                for &syn_id in neuron.post_synapses.iter() {
                    let future = time_step + network.synapses[syn_id as usize].delay as TimeStep;
                    future_spikes[future as usize % MAX_DELAY as usize].push(syn_id);
                }
            }
        }
    }

    {
        let mut fg = Figure::new();
        {
            let mut diag = fg.axes2d().
                set_x_label("time (ms)", &[]).
                set_y_label("membrane potential v (mV)", &[]);
            for (i, &p) in PARAMS.iter().enumerate() {
                diag.lines(states[i].iter().enumerate().map(|(i, _)| i as f32), states[i].iter().map(|s| s.potential()), &[Caption(p.0), Color(p.1)]);
            }
        }
        fg.show();
    }

    /*
    let mut fg = Figure::new();
    {
        let mut diag = fg.axes2d().
            set_x_label("membrane potential v (mV)", &[]).
            set_y_label("recovery variable u", &[]);
        for (i, &p) in PARAMS.iter().enumerate() {
            diag.lines(states[i].iter().map(|s| s.potential()), states[i].iter().map(|s| s.recovery()), &[Caption(p.0), Color(p.2)]);
        }
    }
    fg.show();
    */

}
<commit_msg>Partial implement STDP<commit_after>extern crate izhikevich_neurons;
extern crate gnuplot;

use izhikevich_neurons::{Config, State, Num};
use gnuplot::{Figure, Caption, Color, AxesCommon};

type NeuronId = u32;
type SynapseId = u32;
type TimeStep = u32;
type Delay = u8;

const MAX_DELAY: u8 = 40;

const STDP_FIRE_RESET: Num = 0.1;
const STDP_DECAY: Num = 0.95;

struct Synapse {
    pre_neuron: NeuronId,
    post_neuron: NeuronId,
    delay: Delay,
    weight: Num,

    // efficiacy derivative used for STDP
    eff_d: Num,

    _last_spike: TimeStep,
    // ... learning parameters
}

struct Neuron {
    state: State,
    config: Config,
    i_ext: Num,
    i_inp: Num,

    // XXX: Have a list of `active` synapses, which are active
    // once a neuron fires on it. The `active` synapses track
    // themselves, once they become inactive. Use a similar
    // `decay` process as for STDP for the action potential,
    // so that the shape of the spike is less sharp. A high
    // decay rate can simulate the old behaviour.

    // Spike-Time Dependent Plasticity
    //
    // when a neuron fires, we set this value to STDP_FIRE_RESET
    // (0.1 for example), and during every time-step we decay
    // it by STDP_DECAY e.g. 0.95.
    stdp: Num,

    // XXX: Rename to Connection and incoming/outgoing?
    pre_synapses: Vec<SynapseId>,
    post_synapses: Vec<SynapseId>,
}

struct Network {
    neurons: Vec<Neuron>,
    synapses: Vec<Synapse>,
}

impl Network {
    fn new() -> Network {
        Network {
            neurons: Vec::new(),
            synapses: Vec::new()
        }
    }

    fn create_neuron(&mut self, config: Config) -> NeuronId {
        let neuron = Neuron {
            state: State::new(),
            config: config,
            stdp: 0.0,
            i_ext: 0.0,
            i_inp: 0.0,
            pre_synapses: Vec::new(),
            post_synapses: Vec::new(),
        };
        let neuron_id = self.neurons.len() as u32;
        self.neurons.push(neuron);
        return neuron_id;
    }

    fn connect(&mut self, pre_neuron: NeuronId, post_neuron: NeuronId, delay: Delay, weight: Num) -> SynapseId {
        assert!((pre_neuron as usize) < self.neurons.len());
        assert!((post_neuron as usize) < self.neurons.len());
        assert!(delay > 0);
        assert!(delay <= MAX_DELAY);

        let synapse = Synapse {
            pre_neuron: pre_neuron,
            post_neuron: post_neuron,
            delay: delay,
            weight: weight,
            eff_d: 0.0,
            _last_spike: 0, // XXX
        };
        let synapse_id = self.synapses.len() as u32;

        self.synapses.push(synapse);
        self.neurons[pre_neuron as usize].post_synapses.push(synapse_id);
        self.neurons[post_neuron as usize].pre_synapses.push(synapse_id);

        return synapse_id;
    }

    fn update_state(&mut self, time_step: TimeStep, future_spikes: &mut Vec<Vec<SynapseId>>) {
        //for (i, mut neuron) in network.neurons.iter_mut().enumerate() {
        for i in 0 .. self.neurons.len() {
            let syn_i = self.neurons[i].i_ext + self.neurons[i].i_inp;

            let (new_state, fired) = self.neurons[i].state.step_1ms(syn_i, &self.neurons[i].config);
            self.neurons[i].state = new_state;

            // decay STDP
            self.neurons[i].stdp *= STDP_DECAY;

            if fired {
                // Reset the neurons STDP to a high value.
                self.neurons[i].stdp = STDP_FIRE_RESET;

                println!("Neuron {} fired at {} ms", i, time_step);
                for &syn_id in self.neurons[i].post_synapses.iter() {
                    let future = time_step + self.synapses[syn_id as usize].delay as TimeStep;
                    future_spikes[future as usize % MAX_DELAY as usize].push(syn_id);
                }

                // Excite the synapses that might have led to the firing of the underlying neuron.
                // We do this by adding the synapses pre_neuron's STDP value to the synapses eff_d
                // (efficacy derivative) value.
                //
                // We do not update the synapses weight value immediatly, but only once very while
                // (TODO), so that STDP reflects more LTP (Long Term Potentiation).
                for &syn_id in self.neurons[i].pre_synapses.iter() {
                    let stdp = self.neurons[self.synapses[syn_id as usize].pre_neuron as usize].stdp;
                    self.synapses[syn_id as usize].eff_d += stdp;
                }
            }
        }
    }

}

fn main() {
    const PARAMS : &'static [(&'static str, &'static str)] = &[
        ("Neuron 1 [7 pA current 200..700ms]", "blue"),
        //("Neuron 2 [2.69 pA current 200..700ms]", 2.69, "red"),
        ("Neuron 2 [0.0 pA current 200..700ms]", "red"),
        //("Neuron 3 [2.7 pA current 200..700ms]", 2.7, "green")
    ];

    let mut network = Network::new();

    let n1 = network.create_neuron(Config::regular_spiking());
    let n2 = network.create_neuron(Config::regular_spiking());
    //let n3 = network.create_neuron(Config::regular_spiking());

    let external_inputs: &[(NeuronId, TimeStep, Num)] = &[
        (n1, 200, 7.0),
        (n1, 701, 0.0)
    ];

    // We use a cyclic buffer
    // We use (time_step % MAX_DELAY) as index into the futures_spike array
    let mut future_spikes: Vec<Vec<SynapseId>> = (0..MAX_DELAY as usize).map(|_| Vec::new()).collect();

    let _ = network.connect(n1, n2, 10, 7.0);
    let _ = network.connect(n1, n2, 5, 7.0);
    let _ = network.connect(n1, n2, 2, 7.0);
    let _ = network.connect(n1, n2, 2, 7.0);
    let _ = network.connect(n2, n2, 40, 17.0);
    let _ = network.connect(n2, n2, 40, 7.0);

    let mut states: Vec<_> = PARAMS.iter().map(|_| Vec::new()).collect();

    let mut time_step: TimeStep = 0;

    while time_step <= 1_000 {
        // record current state
        for (i, neuron) in network.neurons.iter().enumerate() {
            states[i].push(neuron.state);
        }
        time_step += 1;

        // Clear all input currents
        for neuron in network.neurons.iter_mut() {
            neuron.i_inp = 0.0;
        }

        // get all synapse input
        {
            let current_spikes = &mut future_spikes[(time_step % (MAX_DELAY as TimeStep)) as usize];
            for &syn_fired in current_spikes.iter() {
                println!("time: {}. input from synapse: {}", time_step, syn_fired);
                let (weight, post_neuron) = {
                    let syn = &network.synapses[syn_fired as usize];
                    (syn.weight, syn.post_neuron)
                };
                network.neurons[post_neuron as usize].i_inp += weight;
            }
            current_spikes.clear();
        }

        // set external inputs
        for &(n_id, at, current) in external_inputs {
            if time_step == at {
                network.neurons[n_id as usize].i_ext = current;
            }
        }

        network.update_state(time_step, &mut future_spikes);
    }

    {
        let mut fg = Figure::new();
        {
            let mut diag = fg.axes2d().
                set_x_label("time (ms)", &[]).
                set_y_label("membrane potential v (mV)", &[]);
            for (i, &p) in PARAMS.iter().enumerate() {
                diag.lines(states[i].iter().enumerate().map(|(i, _)| i as f32), states[i].iter().map(|s| s.potential()), &[Caption(p.0), Color(p.1)]);
            }
        }
        fg.show();
    }

    /*
    let mut fg = Figure::new();
    {
        let mut diag = fg.axes2d().
            set_x_label("membrane potential v (mV)", &[]).
            set_y_label("recovery variable u", &[]);
        for (i, &p) in PARAMS.iter().enumerate() {
            diag.lines(states[i].iter().map(|s| s.potential()), states[i].iter().map(|s| s.recovery()), &[Caption(p.0), Color(p.2)]);
        }
    }
    fg.show();
    */

}
<|endoftext|>


<commit_before>#![feature(trace_macros)]
trace_macros!(true);

macro_rules! define_binary_op {
    ($name:ident, $trt:ident, $func:ident) => {
        pub fn $name<A, B>(a: A, b: B) -> <A as ::std::ops::$trt<B>>::Output
            where A: ::std::ops::$trt<B>
        {
            a.$func(b)
        }
    };

    ($($name:ident, $trt:ident, $func:ident);*) => {
        $(define_binary_op!($name, $trt, $func);)*
    }
}

macro_rules! define_unary_op {
    ($name:ident, $trt:ident, $func:ident) => {
        pub fn $name<A>(a: A) -> <A as ::std::ops::$trt>::Output
            where A: ::std::ops::$trt
        {
            a.$func()
        }
    };

    ($($name:ident, $trt:ident, $func:ident);*) => {
        $(define_unary_op!($name, $trt, $func);)*
    }
}

define_binary_op!(_add, Add   , add;
                  _and, BitAnd, bitand;
                  _or , BitOr , bitor;
                  _xor, BitXor, bitxor;
                  _div, Div   , div;
                  _mul, Mul   , mul;
                  _rem, Rem   , rem;
                  _shl, Shl   , shl;
                  _shr, Shr   , shr;
                  _sub, Sub   , sub);
define_unary_op!( _neg, Neg   , neg;
                  _not, Not   , not);

pub fn _eq<A, B>(a: A, b: B) -> bool
    where A: ::std::cmp::PartialEq<B>
{
    a == b
}

#[macro_export] macro_rules! lisp {
    // lambda
    ((lambda ($(($argn:ident $argt:ty))* -> $ret:ty) $body:tt)) => {
        |$($argn:$argt),*| -> $ret { lisp!($body) }
    };

    // special forms
    ((_if: $cond:tt $yes:tt $no:tt)) => {
        if lisp!($cond) { lisp!($yes) } else { lisp!($no) }
    };
    ((_while: $cond:tt $body:tt)) => {
        while lisp!($cond) { lisp!($body) }
    };
    ((_rust: $body:block)) => {
        { $body }
    };

    // call function
    (($name:expr)) => {
        (lisp!($name))()
    };
    (($name:path : $($arg:tt)*)) => {
        (lisp!($name))($(lisp!($arg)),*)
    };

    // one expression
    ($e:expr) => ($e);

    // empty
    () => (());
}

<commit_msg>lets and comparison builtins<commit_after>#![feature(trace_macros)]
//trace_macros!(true);

use std::ops;
use std::cmp;

macro_rules! define_binary_op {
    ($name:ident, $md:ident::$trt:ident, $func:ident) => {
        pub fn $name<A, B>(a: A, b: B) -> <A as $md::$trt<B>>::Output
            where A: $md::$trt<B>
        {
            a.$func(b)
        }
    };

    ($($name:ident, $md:ident::$trt:ident, $func:ident);*) => {
        $(define_binary_op!($name, $md::$trt, $func);)*
    }
}

macro_rules! define_unary_op {
    ($name:ident, $md:ident::$trt:ident, $func:ident) => {
        pub fn $name<A>(a: A) -> <A as $md::$trt>::Output
            where A: $md::$trt
        {
            a.$func()
        }
    };

    ($($name:ident, $md:ident::$trt:ident, $func:ident);*) => {
        $(define_unary_op!($name, $md::$trt, $func);)*
    }
}

macro_rules! define_comparison_op {
    ($name:ident, $md:ident::$trt:ident, $func:ident) => {
        pub fn $name<A, B>(a: A, b: B) -> bool
            where A: $md::$trt<B>
        {
            a.$func(&b)
        }
    };

    ($($name:ident, $md:ident::$trt:ident, $func:ident);*) => {
        $(define_comparison_op!($name, $md::$trt, $func);)*
    }
}

define_binary_op!(_add, ops::Add   , add;
                  _and, ops::BitAnd, bitand;
                  _or , ops::BitOr , bitor;
                  _xor, ops::BitXor, bitxor;
                  _div, ops::Div   , div;
                  _mul, ops::Mul   , mul;
                  _rem, ops::Rem   , rem;
                  _shl, ops::Shl   , shl;
                  _shr, ops::Shr   , shr;
                  _sub, ops::Sub   , sub);
define_unary_op!( _neg, ops::Neg   , neg;
                  _not, ops::Not   , not);

define_comparison_op!(
                  _eq, cmp::PartialEq , eq;
                  _ne, cmp::PartialEq , ne;
                  _gt, cmp::PartialOrd, gt;
                  _lt, cmp::PartialOrd, lt;
                  _ge, cmp::PartialOrd, ge;
                  _le, cmp::PartialOrd, le);

#[macro_export] macro_rules! lisp {
    // lambda
    ((lambda ($(($argn:ident $argt:ty))* -> $ret:ty) $($body:tt)*)) => {
        |$($argn:$argt),*| -> $ret { $(lisp!($body));* }
    };

    // special forms
    ((_if: $cond:tt $yes:tt $no:tt)) => {
        if lisp!($cond) { lisp!($yes) } else { lisp!($no) }
    };
    ((_while: $cond:tt $($body:tt)*)) => {
        while lisp!($cond) { $(lisp!($body));* }
    };

    // variables
    ((_let: mut $var:ident $val:tt)) => {
        let mut $var = lisp!($val);
    };
    ((_let: $var:ident $val:tt)) => {
        let $var = lisp!($val);
    };
    ((_set: $var:ident $val:tt)) => {
        $var = lisp!($val);
    };

    // escape hatch
    ((_rust: $body:block)) => {
        { $body }
    };

    // call function
    (($name:expr)) => {
        (lisp!($name))()
    };
    (($name:path : $($arg:tt)*)) => {
        (lisp!($name))($(lisp!($arg)),*)
    };

    // one expression
    ($e:expr) => ($e);

    // empty
    () => (());
}

<|endoftext|>


<commit_before>#[macro_use]
mod game;

use std::cell::{RefCell, RefMut};

extern crate gfx_device_gl;
extern crate piston_window;

use game::{Config, ConfigBuilder, Menu, MenuResult, Game, GameOver, GameWindow, Scene, SceneResult};

fn main() {
    let mut window = GameWindow::new(450, 600, "TetRS");
    let config = ConfigBuilder::new()
        .grid_size((10, 22))
        .grid_offset(10.0)
        .tile_size(29.0)
        .shadow(false)
        .ui_color([1.0; 4])
        .build();

    let main_menu = RefCell::new(create_main_menu(config, &window));
    let pause_menu = RefCell::new(create_pause_menu(config, &window));

    let game = RefCell::new(Game::new(config, window.piston_window.factory.clone()));
    let gameover = RefCell::new(GameOver::new(config, window.piston_window.factory.clone()));

    let mut scene: RefMut<Scene> = main_menu.borrow_mut();

    while let Some(e) = window.next() {

        let scene_result = scene.process(&e);

        match scene_result {
            SceneResult::MainMenu => {
                scene = main_menu.borrow_mut();
            }
            SceneResult::NewGame => {
                game.borrow_mut().reset();
                scene = game.borrow_mut();
            }
            SceneResult::PauseGame => {
                scene = pause_menu.borrow_mut();
            }
            SceneResult::ResumeGame => {
                game.borrow_mut().unpause();
                scene = game.borrow_mut();
            }
            SceneResult::GameOver => {
                scene = gameover.borrow_mut();
            }
            SceneResult::Quit => break,
            _ => (),
        };

        scene.render(&mut window, &e);
    }
}

fn create_main_menu(config: Config, window: &GameWindow) -> Menu {
    menu![
        (config, window.piston_window.factory.clone()),
        "New Game" => MenuResult::NewGame,
        "Quit" => MenuResult::Quit
    ]
}

fn create_pause_menu(config: Config, window: &GameWindow) -> Menu {
    menu![
        (config, window.piston_window.factory.clone()),
        "Resume" => MenuResult::ResumeGame,
        "New Game" => MenuResult::NewGame,
        "Main Manu" => MenuResult::MainMenu
    ]
}<commit_msg>Slight cleanup<commit_after>#[macro_use]
mod game;

use std::cell::{RefCell, RefMut};

extern crate gfx_device_gl;
extern crate piston_window;

use game::{Config, ConfigBuilder, Menu, MenuResult, Game, GameOver, GameWindow, Scene, SceneResult};

fn main() {
    let mut window = GameWindow::new(450, 600, "TetRS");
    let config = ConfigBuilder::new()
        .grid_size((10, 22))
        .grid_offset(10.0)
        .tile_size(29.0)
        .shadow(false)
        .ui_color([1.0; 4])
        .build();

    let main_menu = RefCell::new(create_main_menu(config, &window));
    let pause_menu = RefCell::new(create_pause_menu(config, &window));

    let game = RefCell::new(Game::new(config, window.piston_window.factory.clone()));
    let gameover = RefCell::new(GameOver::new(config, window.piston_window.factory.clone()));

    let mut scene: RefMut<Scene> = main_menu.borrow_mut();

    while let Some(e) = window.next() {
        match scene.process(&e) {
            SceneResult::MainMenu => {
                scene = main_menu.borrow_mut();
            }
            SceneResult::NewGame => {
                game.borrow_mut().reset();
                scene = game.borrow_mut();
            }
            SceneResult::PauseGame => {
                scene = pause_menu.borrow_mut();
            }
            SceneResult::ResumeGame => {
                game.borrow_mut().unpause();
                scene = game.borrow_mut();
            }
            SceneResult::GameOver => {
                scene = gameover.borrow_mut();
            }
            SceneResult::Quit => break,
            _ => (),
        };

        scene.render(&mut window, &e);
    }
}

fn create_main_menu(config: Config, window: &GameWindow) -> Menu {
    menu![
        (config, window.piston_window.factory.clone()),
        "New Game" => MenuResult::NewGame,
        "Quit" => MenuResult::Quit
    ]
}

fn create_pause_menu(config: Config, window: &GameWindow) -> Menu {
    menu![
        (config, window.piston_window.factory.clone()),
        "Resume" => MenuResult::ResumeGame,
        "New Game" => MenuResult::NewGame,
        "Main Manu" => MenuResult::MainMenu
    ]
}<|endoftext|>


<commit_before>#[cfg(not(windows))]
compile_error!("This demo only runs on Windows.");

extern crate directcomposition;
extern crate winit;

use directcomposition::DirectComposition;
use winit::os::windows::WindowExt;

fn main() {
    let mut events_loop = winit::EventsLoop::new();
    let window = winit::WindowBuilder::new()
        .with_title("Hello, world!")
        .with_dimensions(1024, 768)
        .build(&events_loop)
        .unwrap();

    let composition = direct_composition_from_window(&window);

    let visual1 = composition.create_d3d_visual(300, 200).unwrap();
    visual1.set_offset_x(100.).unwrap();
    visual1.set_offset_y(50.).unwrap();

    let visual2 = composition.create_d3d_visual(400, 300).unwrap();
    let mut offset_y = 100.;
    visual2.set_offset_x(200.).unwrap();
    visual2.set_offset_y(offset_y).unwrap();

    composition.commit().unwrap();

    let mut green = 0.5;
    visual1.render_and_present_solid_frame(&composition, &[0., 0.2, 0.4, 1.]).unwrap();
    visual2.render_and_present_solid_frame(&composition, &[0., green, 0., 0.5]).unwrap();

    events_loop.run_forever(|event| {
        if let winit::Event::WindowEvent { event, .. } = event {
            match event {
                winit::WindowEvent::Closed => {
                    return winit::ControlFlow::Break
                }
                winit::WindowEvent::MouseWheel { delta, .. } => {
                    let dy = match delta {
                        winit::MouseScrollDelta::LineDelta(_, dy) => dy,
                        winit::MouseScrollDelta::PixelDelta(_, dy) => dy,
                    };
                    offset_y = (offset_y - 10. * dy).max(0.).min(468.);

                    visual2.set_offset_y(offset_y).unwrap();
                    composition.commit().unwrap();
                }
                winit::WindowEvent::MouseInput {
                    button: winit::MouseButton::Left,
                    state: winit::ElementState::Pressed,
                    ..
                } => {
                    green += 0.1;
                    green %= 1.;
                    visual2.render_and_present_solid_frame(
                        &composition, &[0., green, 0., 0.5]
                    ).unwrap();
                }
                _ => {}
            }
        }
        winit::ControlFlow::Continue
    });
}

fn direct_composition_from_window(window: &winit::Window) -> DirectComposition {
    unsafe {
        DirectComposition::new(window.get_hwnd() as _).unwrap()
    }
}
<commit_msg>Make sure we can keep rendering both visuals<commit_after>#[cfg(not(windows))]
compile_error!("This demo only runs on Windows.");

extern crate directcomposition;
extern crate winit;

use directcomposition::DirectComposition;
use winit::os::windows::WindowExt;

fn main() {
    let mut events_loop = winit::EventsLoop::new();
    let window = winit::WindowBuilder::new()
        .with_title("Hello, world!")
        .with_dimensions(1024, 768)
        .build(&events_loop)
        .unwrap();

    let composition = direct_composition_from_window(&window);

    let visual1 = composition.create_d3d_visual(300, 200).unwrap();
    visual1.set_offset_x(100.).unwrap();
    visual1.set_offset_y(50.).unwrap();

    let visual2 = composition.create_d3d_visual(400, 300).unwrap();
    let mut offset_y = 100.;
    visual2.set_offset_x(200.).unwrap();
    visual2.set_offset_y(offset_y).unwrap();

    composition.commit().unwrap();

    let mut rgba1 = [0., 0.2, 0.4, 1.];
    let mut rgba2 = [0., 0.5, 0., 0.5];
    visual1.render_and_present_solid_frame(&composition, &rgba1).unwrap();
    visual2.render_and_present_solid_frame(&composition, &rgba2).unwrap();

    let mut clicks: u32 = 0;

    events_loop.run_forever(|event| {
        if let winit::Event::WindowEvent { event, .. } = event {
            match event {
                winit::WindowEvent::Closed => {
                    return winit::ControlFlow::Break
                }
                winit::WindowEvent::MouseWheel { delta, .. } => {
                    let dy = match delta {
                        winit::MouseScrollDelta::LineDelta(_, dy) => dy,
                        winit::MouseScrollDelta::PixelDelta(_, dy) => dy,
                    };
                    offset_y = (offset_y - 10. * dy).max(0.).min(468.);

                    visual2.set_offset_y(offset_y).unwrap();
                    composition.commit().unwrap();
                }
                winit::WindowEvent::MouseInput {
                    button: winit::MouseButton::Left,
                    state: winit::ElementState::Pressed,
                    ..
                } => {
                    clicks += 1;
                    let (rgba, visual) = if clicks % 2 == 0 {
                        (&mut rgba1, &visual1)
                    } else {
                        (&mut rgba2, &visual2)
                    };
                    rgba[1] += 0.1;
                    rgba[1] %= 1.;
                    visual.render_and_present_solid_frame(&composition, &rgba).unwrap();
                }
                _ => {}
            }
        }
        winit::ControlFlow::Continue
    });
}

fn direct_composition_from_window(window: &winit::Window) -> DirectComposition {
    unsafe {
        DirectComposition::new(window.get_hwnd() as _).unwrap()
    }
}
<|endoftext|>


<commit_before>#![feature(custom_derive)]

extern crate hyper;
extern crate rustc_serialize;
extern crate scoped_threadpool;
extern crate csv;

use std::fs;
use std::sync::Arc;
use std::path::Path;
use std::fs::File;
use std::io::{Read, Write};
use std::collections::{HashSet, HashMap};

use hyper::client::{Client, Response, RequestBuilder};
use hyper::header::{Accept, Connection, qitem};
use hyper::mime::{Mime, TopLevel, SubLevel};

use rustc_serialize::json;

use scoped_threadpool::Pool;

#[derive(Clone)]
struct MyClient {
    client : Arc<Client>,
    app_id : String,
    app_key : String,
    cache_dir : String,
}

#[derive(Clone, Debug, RustcDecodable)]
struct Line {
    id : String,
    name : String,
    modeName : String,
    routeSections : Vec<RouteSection>
}

#[derive(Clone, Debug, RustcDecodable)]
struct RouteSection {
    name : String,
    direction : String,
    originator : String,
    destination : String,
    timetable : Option<TimeTable>,
}

#[derive(Clone, Debug, RustcDecodable)]
struct Interval {
    stopId : String,
    timeToArrival: f64,
}

#[derive(Clone, Debug, RustcDecodable)]
struct StationInterval {
    id : i64,
    intervals : Vec<Interval>
}

#[derive(Clone, Debug, RustcDecodable)]
struct KnownJourney {
    intervalId : i64,
    hour : String,
    minute : String,
}

#[derive(Clone, Debug, RustcDecodable)]
struct Schedule {
    name : String,
    knownJourneys : Vec<KnownJourney>,
}

#[derive(Clone, Debug, RustcDecodable)]
struct TimeTable {
    stationIntervals : Vec<StationInterval>,
    schedules : Vec<Schedule>,
}

#[derive(Clone, Debug, RustcDecodable)]
struct RoutesTimeTables {
    routes : Vec<TimeTable>,
}

#[derive(Debug, RustcDecodable)]
struct TimeTableResponse {
    timetable : RoutesTimeTables,
}

impl MyClient {
    fn new() -> MyClient {
        let cachePath : &Path = Path::new("./cache");
        fs::create_dir(cachePath);
        return MyClient{
            client : Arc::new(Client::new()),
            app_id : String::new(),
            app_key : String::new(),
            cache_dir : String::from("./cache"),
        }
    }

    fn get(&self, endpoint : &str) -> String {
        match self.cache_get(endpoint) {
            Some(body) => body,
            None => self.remote_get(endpoint)
        }
    }

    fn remote_get(&self, endpoint : &str) -> String {
        let req_uri = format!("https://api.tfl.gov.uk{}?app_id={}&app_key={}", endpoint, self.app_id, self.app_key);
        let mut body = String::new();
        let mut resp = self.client.get(&req_uri)
            .header(Accept(vec![
                qitem(Mime(TopLevel::Application,
                    SubLevel::Ext("json".to_owned()), vec![])),
            ]))
            .send().unwrap();
        resp.read_to_string(&mut body).unwrap();
        self.cache_put(endpoint, body)
    }

    fn cache_fname(&self, endpoint : &str) -> String {
        let fname = String::from(endpoint);
        let fname0 = fname.replace("/", "_");
        self.cache_dir.clone() + "/" + &fname0
    }

    fn cache_put(&self, endpoint : &str, body : String) -> String {
        let mut f = File::create(self.cache_fname(endpoint)).unwrap();
        f.write_all(body.as_bytes());
        body
    }

    fn cache_get(&self, endpoint : &str) -> Option<String> {
        let mut body = String::new();
        match File::open(self.cache_fname(endpoint)) {
            Ok(ref mut f) => {
                f.read_to_string(&mut body);
                Some(body)
            },
            Err(_) => None,
        }
    }
}

fn get_lines(client : &MyClient) -> Vec<Line> {
    let body = client.get("/line/route");
    json::decode(&body).unwrap()
}

fn get_timetable(client : &MyClient, line_id : &str, originator: &str, destination : &str) -> Option<TimeTable> {
    let req_uri = format!("/line/{}/timetable/{}/to/{}", line_id, originator, destination);
    let body = client.get(&req_uri);
    match json::decode::<TimeTableResponse>(&body) {
        Ok(ttresp) =>  Some(ttresp.timetable.routes[0].clone()),
        Err(err) => {
            println!("Error decoding timetable {}", err);
            None
        },
    }
}

fn route_section_id(line : &Line, section : &RouteSection) -> String {
    return line.id.clone() + " " + &section.originator + " to " + &section.destination;
}

fn write_agency(gtfs_path : &str) {
    let fname = format!("{}/{}", gtfs_path, "/agency.txt");
    let fpath = Path::new(&fname);
    let mut wtr = csv::Writer::from_file(fpath).unwrap();
    let records = vec![
        ("agency_id","agency_name","agency_url","agency_timezone"),
        ("tfl","Transport For London","https://tfl.gov.uk","Europe/London")
    ];
    for record in records {
        wtr.encode(record);
    }
}

fn route_type(line : &Line) -> &'static str {
    match &line.modeName[..] {
        "dlr" | "tram" => "0",
        "tube" | "overground" => "1",
        "national-rail" | "tflrail" => "2",
        "bus" => "3",
        "river-tour" | "river-bus" => "4",
        "cable-car" => "5",
        _ => {
            println!("Missing line modeName match: {}", line.modeName);
            ""
        },
    }
}

fn write_routes(gtfs_path : &str, lines : &Vec<Line>) {
    let fname = format!("{}/{}", gtfs_path, "/routes.txt");
    let fpath = Path::new(&fname);
    let mut wtr = csv::Writer::from_file(fpath).unwrap();
    let records = vec![
        ("agency_id","agency_name","agency_url","agency_timezone"),
        ("tfl","Transport For London","https://tfl.gov.uk","Europe/London")
    ];
    wtr.encode(("route_id", "agency_id", "route_short_name", "route_long_name", "route_type"));

    for line in lines.into_iter() {
        wtr.encode((&line.id, "tfl", &line.name, "", route_type(&line)));
    }
}

fn write_stops(gtfs_path : &str, lines : &Vec<Line>) {
}

fn write_calendar(gtfs_path : &str) {
}

fn write_trips(gtfs_path : &str, lines : &Vec<Line>) {
}

fn write_stop_times(gtfs_path : &str, lines : &Vec<Line>) {
}

fn write_gtfs(lines : &Vec<Line>) {
        let gtfs_path : &Path = Path::new("./gtfs");
        let gtfs_path_str = gtfs_path.to_str().unwrap();
        fs::create_dir(gtfs_path_str);
        write_agency(gtfs_path_str);
        write_routes(gtfs_path_str, lines);
        write_stops(gtfs_path_str, lines);
        write_calendar(gtfs_path_str);
        write_trips(gtfs_path_str, lines);
        write_stop_times(gtfs_path_str, lines);
}

fn main() {
    // Fetch data
    let client = Arc::new(MyClient::new());
    let mut lines = get_lines(&client);
    let mut pool = Pool::new(10);

    pool.scoped(|scope| {
        for line in &mut lines {
            let client = client.clone();
            scope.execute(move || {
                for route_section in &mut line.routeSections {
                    println!("Getting Timetable for Line: {}, Route Section: {} ...", line.name, route_section.name);
                    route_section.timetable = get_timetable(&client, &line.id, &route_section.originator, &route_section.destination);
                }
            });
        }
    });

    // Generate a report
    let mut line_count = 0;
    let mut line_ids : HashSet<String> = HashSet::new();
    let mut route_section_count = 0;
    let mut route_section_ids: HashSet<String> = HashSet::new();
    let mut schedule_names: HashSet<String> = HashSet::new();
    for line in &lines {
        println!("{}, Duplicate: {}", line.id, line_ids.contains(&line.id));
        for route_section in &line.routeSections {
            let has_timetable = match route_section.timetable {
                Some(ref timetable) => {
                    for schedule in &timetable.schedules {
                        schedule_names.insert(schedule.name.clone());
                    }
                    true
                },
                None => false,
            };
            let id = route_section_id(&line, &route_section);
            println!("\t{}, Has Timetable: {}, Duplicate: {}", id, has_timetable, route_section_ids.contains(&id));
            route_section_ids.insert(id.clone());
            route_section_count += 1;
        }
        line_count += 1;
        line_ids.insert(line.id.clone());
    }
    println!("Duplicate Lines: {}, Duplicate Route Sections: {}", line_count-line_ids.len(), route_section_count-route_section_ids.len());

    println!("Schedule Names:");
    for schedule_name in &schedule_names {
        println!("\t{}", schedule_name);
    }

    // Generate CSV files from fetched data
    write_gtfs(&lines);
}
<commit_msg>Write out stops.txt<commit_after>#![feature(custom_derive)]

extern crate hyper;
extern crate rustc_serialize;
extern crate scoped_threadpool;
extern crate csv;

use std::fs;
use std::sync::Arc;
use std::path::Path;
use std::fs::File;
use std::io::{Read, Write};
use std::collections::{HashSet, HashMap};

use hyper::client::{Client, Response, RequestBuilder};
use hyper::header::{Accept, Connection, qitem};
use hyper::mime::{Mime, TopLevel, SubLevel};

use rustc_serialize::json;

use scoped_threadpool::Pool;

#[derive(Clone)]
struct MyClient {
    client : Arc<Client>,
    app_id : String,
    app_key : String,
    cache_dir : String,
}

#[derive(Clone, Debug, RustcDecodable)]
struct Line {
    id : String,
    name : String,
    modeName : String,
    routeSections : Vec<RouteSection>,
    stops : Option<Vec<Stop>>,
}

#[derive(Clone, Debug, RustcDecodable)]
struct Stop {
    naptanId : String,
    commonName : String,
    lat : f64,
    lon : f64,
}

#[derive(Clone, Debug, RustcDecodable)]
struct RouteSection {
    name : String,
    direction : String,
    originator : String,
    destination : String,
    timetable : Option<TimeTable>,
}

#[derive(Clone, Debug, RustcDecodable)]
struct Interval {
    stopId : String,
    timeToArrival: f64,
}

#[derive(Clone, Debug, RustcDecodable)]
struct StationInterval {
    id : i64,
    intervals : Vec<Interval>
}

#[derive(Clone, Debug, RustcDecodable)]
struct KnownJourney {
    intervalId : i64,
    hour : String,
    minute : String,
}

#[derive(Clone, Debug, RustcDecodable)]
struct Schedule {
    name : String,
    knownJourneys : Vec<KnownJourney>,
}

#[derive(Clone, Debug, RustcDecodable)]
struct TimeTable {
    stationIntervals : Vec<StationInterval>,
    schedules : Vec<Schedule>,
}

#[derive(Clone, Debug, RustcDecodable)]
struct RoutesTimeTables {
    routes : Vec<TimeTable>,
}

#[derive(Debug, RustcDecodable)]
struct TimeTableResponse {
    timetable : RoutesTimeTables,
}

impl MyClient {
    fn new() -> MyClient {
        let cachePath : &Path = Path::new("./cache");
        fs::create_dir(cachePath);
        return MyClient{
            client : Arc::new(Client::new()),
            app_id : String::new(),
            app_key : String::new(),
            cache_dir : String::from("./cache"),
        }
    }

    fn get(&self, endpoint : &str) -> String {
        match self.cache_get(endpoint) {
            Some(body) => body,
            None => self.remote_get(endpoint)
        }
    }

    fn remote_get(&self, endpoint : &str) -> String {
        let req_uri = format!("https://api.tfl.gov.uk{}?app_id={}&app_key={}", endpoint, self.app_id, self.app_key);
        let mut body = String::new();
        let mut resp = self.client.get(&req_uri)
            .header(Accept(vec![
                qitem(Mime(TopLevel::Application,
                    SubLevel::Ext("json".to_owned()), vec![])),
            ]))
            .send().unwrap();
        resp.read_to_string(&mut body).unwrap();
        self.cache_put(endpoint, body)
    }

    fn cache_fname(&self, endpoint : &str) -> String {
        let fname = String::from(endpoint);
        let fname0 = fname.replace("/", "_");
        self.cache_dir.clone() + "/" + &fname0
    }

    fn cache_put(&self, endpoint : &str, body : String) -> String {
        let mut f = File::create(self.cache_fname(endpoint)).unwrap();
        f.write_all(body.as_bytes());
        body
    }

    fn cache_get(&self, endpoint : &str) -> Option<String> {
        let mut body = String::new();
        match File::open(self.cache_fname(endpoint)) {
            Ok(ref mut f) => {
                f.read_to_string(&mut body);
                Some(body)
            },
            Err(_) => None,
        }
    }
}

fn get_lines(client : &MyClient) -> Vec<Line> {
    let body = client.get("/line/route");
    json::decode(&body).unwrap()
}

fn get_timetable(client : &MyClient, line_id : &str, originator: &str, destination : &str) -> Option<TimeTable> {
    let req_uri = format!("/line/{}/timetable/{}/to/{}", line_id, originator, destination);
    let body = client.get(&req_uri);
    match json::decode::<TimeTableResponse>(&body) {
        Ok(ttresp) =>  Some(ttresp.timetable.routes[0].clone()),
        Err(err) => {
            println!("Error decoding timetable {}", err);
            None
        },
    }
}

fn get_stops(client : &MyClient, line_id : &str) -> Vec<Stop> {
    let req_uri = format!("/line/{}/stoppoints", line_id);
    let body = client.get(&req_uri);
    match json::decode::<Vec<Stop>>(&body) {
        Ok(stops) => stops,
        Err(err) => {
            println!("Error decoding stops: {}", err);
            Vec::<Stop>::new()
        }
    }
}

fn route_section_id(line : &Line, section : &RouteSection) -> String {
    return line.id.clone() + " " + &section.originator + " to " + &section.destination;
}

fn write_agency(gtfs_path : &str) {
    let fname = format!("{}/{}", gtfs_path, "/agency.txt");
    let fpath = Path::new(&fname);
    let mut wtr = csv::Writer::from_file(fpath).unwrap();
    let records = vec![
        ("agency_id","agency_name","agency_url","agency_timezone"),
        ("tfl","Transport For London","https://tfl.gov.uk","Europe/London")
    ];
    for record in records {
        wtr.encode(record);
    }
}

fn route_type(line : &Line) -> &'static str {
    match &line.modeName[..] {
        "dlr" | "tram" => "0",
        "tube" | "overground" => "1",
        "national-rail" | "tflrail" => "2",
        "bus" => "3",
        "river-tour" | "river-bus" => "4",
        "cable-car" => "5",
        _ => {
            println!("Missing line modeName match: {}", line.modeName);
            ""
        },
    }
}

fn write_routes(gtfs_path : &str, lines : &Vec<Line>) {
    let fname = format!("{}/{}", gtfs_path, "/routes.txt");
    let fpath = Path::new(&fname);
    let mut wtr = csv::Writer::from_file(fpath).unwrap();
    wtr.encode(("route_id", "agency_id", "route_short_name", "route_long_name", "route_type"));
    for line in lines.into_iter() {
        wtr.encode((&line.id, "tfl", &line.name, "", route_type(&line)));
    }
}

fn write_stops(gtfs_path : &str, lines : &Vec<Line>) {
    let fname = format!("{}/{}", gtfs_path, "/stops.txt");
    let fpath = Path::new(&fname);
    let mut wtr = csv::Writer::from_file(fpath).unwrap();
    let mut written_stops = HashSet::<String>::new();
    wtr.encode(("stop_id", "stop_name", "stop_lat", "stop_lon"));
    for line in lines {
        let stops = line.stops.as_ref().unwrap();
        for stop in stops {
            match written_stops.contains(&stop.naptanId) {
                true => (),
                false => {
                    wtr.encode((stop.naptanId.clone(), stop.commonName.clone(), stop.lat, stop.lon));
                    written_stops.insert(stop.naptanId.clone());
                },
            };
        }
    }
}

fn write_calendar(gtfs_path : &str) {
}

fn write_trips(gtfs_path : &str, lines : &Vec<Line>) {
}

fn write_stop_times(gtfs_path : &str, lines : &Vec<Line>) {
}

fn write_gtfs(lines : &Vec<Line>) {
        let gtfs_path : &Path = Path::new("./gtfs");
        let gtfs_path_str = gtfs_path.to_str().unwrap();
        fs::create_dir(gtfs_path_str);
        write_agency(gtfs_path_str);
        write_routes(gtfs_path_str, lines);
        write_stops(gtfs_path_str, lines);
        write_calendar(gtfs_path_str);
        write_trips(gtfs_path_str, lines);
        write_stop_times(gtfs_path_str, lines);
}

fn main() {
    // Fetch data
    let client = Arc::new(MyClient::new());
    let mut lines = get_lines(&client);
    let mut pool = Pool::new(10);

    pool.scoped(|scope| {
        for line in &mut lines {
            let client = client.clone();
            scope.execute(move || {
                line.stops = Some(get_stops(&client, &line.id));
                for route_section in &mut line.routeSections {
                    println!("Getting Timetable for Line: {}, Route Section: {} ...", line.name, route_section.name);
                    route_section.timetable = get_timetable(&client, &line.id, &route_section.originator, &route_section.destination);
                }
            });
        }
    });

    // Generate a report
    let mut line_count = 0;
    let mut line_ids : HashSet<String> = HashSet::new();
    let mut route_section_count = 0;
    let mut route_section_ids: HashSet<String> = HashSet::new();
    let mut schedule_names: HashSet<String> = HashSet::new();
    for line in &lines {
        println!("{}, Duplicate: {}", line.id, line_ids.contains(&line.id));
        for route_section in &line.routeSections {
            let has_timetable = match route_section.timetable {
                Some(ref timetable) => {
                    for schedule in &timetable.schedules {
                        schedule_names.insert(schedule.name.clone());
                    }
                    true
                },
                None => false,
            };
            let id = route_section_id(&line, &route_section);
            println!("\t{}, Has Timetable: {}, Duplicate: {}", id, has_timetable, route_section_ids.contains(&id));
            route_section_ids.insert(id.clone());
            route_section_count += 1;
        }
        line_count += 1;
        line_ids.insert(line.id.clone());
    }
    println!("Duplicate Lines: {}, Duplicate Route Sections: {}", line_count-line_ids.len(), route_section_count-route_section_ids.len());

    println!("Schedule Names:");
    for schedule_name in &schedule_names {
        println!("\t{}", schedule_name);
    }

    // Generate CSV files from fetched data
    write_gtfs(&lines);
}
<|endoftext|>


<commit_before>#[macro_use] extern crate clap;
#[macro_use] extern crate log;
#[macro_use] extern crate serde;
#[macro_use] extern crate serde_json;
#[macro_use] extern crate glob;
#[macro_use] extern crate uuid;
#[macro_use] extern crate regex;
extern crate config;

use cli::CliConfig;
use configuration::Configuration;
use runtime::{ImagLogger, Runtime};
use clap::App;
use module::Module;
use module::ModuleError;
use module::CommandEnv;
use module::bm::BMModule;
use storage::backend::StorageBackend;

mod cli;
mod configuration;
mod runtime;
mod module;
mod storage;
mod ui;

fn main() {
    let yaml = load_yaml!("../etc/cli.yml");
    let app = App::from_yaml(yaml);
    let config = CliConfig::new(app);
    let configuration = Configuration::new(&config);

    let logger = ImagLogger::init(&configuration, &config);
    debug!("Logger created!");

    debug!("CliConfig    : {:?}", &config);
    debug!("Configuration: {:?}", &configuration);

    let rt = Runtime::new(configuration, config);

    debug!("Runtime      : {:?}", &rt);

    if let Some(matches) = rt.config.cli_matches.subcommand_matches("bm") {
        let module            = BMModule::new(&rt);
        let commands          = module.get_commands(&rt);
        if let Some(command)  = matches.subcommand_name() {
            debug!("Subcommand: {}", command);

            let backend = StorageBackend::new(rt.get_rtp());

            let cmdenv = CommandEnv {
                rt: &rt,
                bk: &backend,
                matches: matches.subcommand_matches(command).unwrap(),
            };

            let result = match commands.get(command) {
                Some(f) => f(&module, cmdenv),
                None    => Err(ModuleError::new("No subcommand found")),
            };

            debug!("Result of command: {:?}", result);
        } else {
            debug!("No subcommand");
        }

        module.shutdown(&rt);
    } else {
        // Err(ModuleError::mk("No commandline call"))
        info!("No commandline call...")
    }

    info!("Hello, world!");
}
<commit_msg>Fix: Build StorageBackend with runtime<commit_after>#[macro_use] extern crate clap;
#[macro_use] extern crate log;
#[macro_use] extern crate serde;
#[macro_use] extern crate serde_json;
#[macro_use] extern crate glob;
#[macro_use] extern crate uuid;
#[macro_use] extern crate regex;
extern crate config;

use cli::CliConfig;
use configuration::Configuration;
use runtime::{ImagLogger, Runtime};
use clap::App;
use module::Module;
use module::ModuleError;
use module::CommandEnv;
use module::bm::BMModule;
use storage::backend::StorageBackend;

mod cli;
mod configuration;
mod runtime;
mod module;
mod storage;
mod ui;

fn main() {
    let yaml = load_yaml!("../etc/cli.yml");
    let app = App::from_yaml(yaml);
    let config = CliConfig::new(app);
    let configuration = Configuration::new(&config);

    let logger = ImagLogger::init(&configuration, &config);
    debug!("Logger created!");

    debug!("CliConfig    : {:?}", &config);
    debug!("Configuration: {:?}", &configuration);

    let rt = Runtime::new(configuration, config);

    debug!("Runtime      : {:?}", &rt);

    if let Some(matches) = rt.config.cli_matches.subcommand_matches("bm") {
        let module            = BMModule::new(&rt);
        let commands          = module.get_commands(&rt);
        if let Some(command)  = matches.subcommand_name() {
            debug!("Subcommand: {}", command);

            let backend = StorageBackend::new(&rt);

            let cmdenv = CommandEnv {
                rt: &rt,
                bk: &backend,
                matches: matches.subcommand_matches(command).unwrap(),
            };

            let result = match commands.get(command) {
                Some(f) => f(&module, cmdenv),
                None    => Err(ModuleError::new("No subcommand found")),
            };

            debug!("Result of command: {:?}", result);
        } else {
            debug!("No subcommand");
        }

        module.shutdown(&rt);
    } else {
        // Err(ModuleError::mk("No commandline call"))
        info!("No commandline call...")
    }

    info!("Hello, world!");
}
<|endoftext|>


<commit_before>#![feature(io)]
#![feature(path)]

extern crate hyper;
extern crate mime;
extern crate "rustc-serialize" as rustc_serialize;

pub mod algorithm;
pub mod collection;

pub use algorithm::{AlgorithmService,Algorithm,AlgorithmOutput};
pub use collection::{CollectionService,Collection,CollectionCreated};

use hyper::{Client, Url};
use hyper::client::RequestBuilder;
use hyper::header::{Accept, Authorization, ContentType, qitem};
use hyper::net::HttpConnector;
use mime::{Mime, TopLevel, SubLevel};
use rustc_serialize::{json};
use self::AlgorithmiaError::*;
use std::io;

pub static API_BASE_URL: &'static str = "https://api.algorithmia.com";

pub struct Service{
    api_key: String,
    // client: Client<HttpConnector<'c>>,
}

pub struct ApiClient<'c>{
    api_key: String,
    client: Client<HttpConnector<'c>>,
}

// pub type ApiError = String;

#[derive(Debug)]
pub enum AlgorithmiaError {
    ApiError(String),
    HttpError(hyper::HttpError),
    DecoderError(json::DecoderError),
    DecoderErrorWithContext(json::DecoderError, String),
    EncoderError(json::EncoderError),
    IoError(io::Error),
}

#[derive(RustcDecodable, Debug)]
pub struct ApiErrorResponse {
    pub error: String,
}

impl<'c> ApiClient<'c> {
    pub fn new(api_key: &str) -> ApiClient {
        ApiClient {
            api_key: api_key.to_string(),
            client: Client::new(),
        }
    }

    // Helper to inject API key
    pub fn get(&mut self, url: Url) -> RequestBuilder<'c, Url, HttpConnector> {
        // let client = self.client ;
        self.client.get(url)
            .header(Authorization(self.api_key.clone()))
    }

    // Helper to inject API key
    pub fn post(&mut self, url: Url) -> RequestBuilder<'c, Url, HttpConnector> {
        // let client = self.client;
        self.client.post(url)
            .header(Authorization(self.api_key.clone()))
    }

    // Helper to add the MIME type
    pub fn post_json(&mut self, url: Url) -> RequestBuilder<'c, Url, HttpConnector> {
        self.post(url)
            .header(ContentType(Mime(TopLevel::Application, SubLevel::Json, vec![])))
            .header(Accept(vec![qitem(Mime(TopLevel::Application, SubLevel::Json, vec![]))]))
    }
}

impl<'a, 'c> Service {
    pub fn new(api_key: &str) -> Service {
        Service {
            api_key: api_key.to_string(),
        }
    }

    pub fn api_client(&self) -> ApiClient<'c> {
        ApiClient {
            api_key: self.api_key.clone(),
            client: Client::new(),
        }
    }

    pub fn algorithm(self, user: &'a str, repo: &'a str) -> AlgorithmService<'a> {
        AlgorithmService {
            service: self,
            algorithm: Algorithm { user: user, repo: repo }
        }
    }

    pub fn collection(self, user: &'a str, name: &'a str) -> CollectionService<'a> {
        CollectionService {
            service: self,
            collection: Collection { user: user, name: name }
        }
    }

}

impl std::clone::Clone for Service {
    fn clone(&self) -> Service {
        Service {
            api_key: self.api_key.clone(),
            // client: Client::new(),
        }
    }
}

impl std::error::FromError<io::Error> for AlgorithmiaError {
    fn from_error(err: io::Error) -> AlgorithmiaError {
        IoError(err)
    }
}

impl std::error::FromError<hyper::HttpError> for AlgorithmiaError {
    fn from_error(err: hyper::HttpError) -> AlgorithmiaError {
        HttpError(err)
    }
}

impl std::error::FromError<json::DecoderError> for AlgorithmiaError {
    fn from_error(err: json::DecoderError) -> AlgorithmiaError {
        DecoderError(err)
    }
}

impl std::error::FromError<json::EncoderError> for AlgorithmiaError {
    fn from_error(err: json::EncoderError) -> AlgorithmiaError {
        EncoderError(err)
    }
}
<commit_msg>Code cleanup<commit_after>#![feature(io)]
#![feature(path)]

extern crate hyper;
extern crate mime;
extern crate "rustc-serialize" as rustc_serialize;

pub mod algorithm;
pub mod collection;

pub use algorithm::{AlgorithmService,Algorithm,AlgorithmOutput};
pub use collection::{CollectionService,Collection,CollectionCreated};

use hyper::{Client, Url};
use hyper::client::RequestBuilder;
use hyper::header::{Accept, Authorization, ContentType, qitem};
use hyper::net::HttpConnector;
use mime::{Mime, TopLevel, SubLevel};
use rustc_serialize::{json};
use self::AlgorithmiaError::*;
use std::io;

pub static API_BASE_URL: &'static str = "https://api.algorithmia.com";

pub struct Service{
    api_key: String,
}

pub struct ApiClient<'c>{
    api_key: String,
    client: Client<HttpConnector<'c>>,
}

#[derive(Debug)]
pub enum AlgorithmiaError {
    ApiError(String),
    HttpError(hyper::HttpError),
    DecoderError(json::DecoderError),
    DecoderErrorWithContext(json::DecoderError, String),
    EncoderError(json::EncoderError),
    IoError(io::Error),
}

#[derive(RustcDecodable, Debug)]
pub struct ApiErrorResponse {
    pub error: String,
}

impl<'a, 'c> Service {
    pub fn new(api_key: &str) -> Service {
        Service {
            api_key: api_key.to_string(),
        }
    }

    // Instantiate a new hyper client for each requests through this method
    pub fn api_client(&self) -> ApiClient<'c> {
        ApiClient {
            api_key: self.api_key.clone(),
            client: Client::new(),
        }
    }

    pub fn algorithm(self, user: &'a str, repo: &'a str) -> AlgorithmService<'a> {
        AlgorithmService {
            service: self,
            algorithm: Algorithm { user: user, repo: repo }
        }
    }

    pub fn collection(self, user: &'a str, name: &'a str) -> CollectionService<'a> {
        CollectionService {
            service: self,
            collection: Collection { user: user, name: name }
        }
    }

}

impl<'c> ApiClient<'c> {
    pub fn new(api_key: &str) -> ApiClient {
        ApiClient {
            api_key: api_key.to_string(),
            client: Client::new(),
        }
    }

    // Helper to inject API key
    pub fn get(&mut self, url: Url) -> RequestBuilder<'c, Url, HttpConnector> {
        // let client = self.client ;
        self.client.get(url)
            .header(Authorization(self.api_key.clone()))
    }

    // Helper to inject API key
    pub fn post(&mut self, url: Url) -> RequestBuilder<'c, Url, HttpConnector> {
        // let client = self.client;
        self.client.post(url)
            .header(Authorization(self.api_key.clone()))
    }

    // Helper to add the MIME type
    pub fn post_json(&mut self, url: Url) -> RequestBuilder<'c, Url, HttpConnector> {
        self.post(url)
            .header(ContentType(Mime(TopLevel::Application, SubLevel::Json, vec![])))
            .header(Accept(vec![qitem(Mime(TopLevel::Application, SubLevel::Json, vec![]))]))
    }
}

/*
* Trait implementations
*/
impl std::clone::Clone for Service {
    fn clone(&self) -> Service {
        Service {
            api_key: self.api_key.clone(),
        }
    }
}

impl std::error::FromError<io::Error> for AlgorithmiaError {
    fn from_error(err: io::Error) -> AlgorithmiaError {
        IoError(err)
    }
}

impl std::error::FromError<hyper::HttpError> for AlgorithmiaError {
    fn from_error(err: hyper::HttpError) -> AlgorithmiaError {
        HttpError(err)
    }
}

impl std::error::FromError<json::DecoderError> for AlgorithmiaError {
    fn from_error(err: json::DecoderError) -> AlgorithmiaError {
        DecoderError(err)
    }
}

impl std::error::FromError<json::EncoderError> for AlgorithmiaError {
    fn from_error(err: json::EncoderError) -> AlgorithmiaError {
        EncoderError(err)
    }
}
<|endoftext|>


<commit_before>extern crate enforcer;
extern crate rustc_serialize;
extern crate docopt;
extern crate glob;
#[macro_use] extern crate log;
extern crate env_logger;

use enforcer::check;
use std::fs::File;
use std::io::Read;
use docopt::Docopt;

const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const USAGE: &'static str = "
enforcer for code rules

Usage:
  enforcer [-g GLOB...] [-c|--clean] [--count]
  enforcer (-h | --help)
  enforcer (-v | --version)
  enforcer (-s | --status)

Options:
  -g GLOB       use these glob patterns (e.g. \"**/*.h\")
  -h --help     Show this screen.
  -v --version  Show version.
  -s --status   Show configuration status.
  --count       only count found entries
  -c --clean    clean up trailing whitespaces
";
#[derive(Debug, RustcDecodable)]
struct Args {
    flag_clean: bool,
    flag_g: Vec<String>,
    flag_version: bool,
    flag_status: bool,
    flag_count: bool,
}

#[allow(dead_code)]
fn main() {
    use glob::glob;
    env_logger::init().unwrap();

    let get_cfg = || -> check::EnforcerCfg {
        fn read_enforcer_config() -> std::io::Result<check::EnforcerCfg> {
            let mut cfg_file = try!(File::open(".enforcer"));
            let mut buffer = String::new();
            try!(cfg_file.read_to_string(&mut buffer));
            check::parse_config(&buffer[..])
        }
        read_enforcer_config()
            .unwrap_or(check::default_cfg())
    };

    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());

    if args.flag_version {
        println!("  Version: {}", VERSION);
        std::process::exit(0);
    }
    let enforcer_cfg = get_cfg();
    if args.flag_status {
        println!("  using this config: {:?}", enforcer_cfg);
        std::process::exit(0);
    }
    let cfg_ignores = enforcer_cfg.ignore;
    let cfg_globs = enforcer_cfg.globs;
    let pats = if args.flag_g.len() > 0 {
        args.flag_g
    } else {
        cfg_globs
    };

    let find_matches = || -> Vec<std::path::PathBuf> {
        let relevant = |pat: &str| -> Vec<std::path::PathBuf> {
            glob(&*pat) // -> Result<Paths, PatternError>
            .ok()   // -> Option<Paths>
            .expect(&format!("glob has problems with {}", pat)[..]) // -> Paths (Iterator ofer GlobResult)
            .filter_map(Result::ok) // ignore unreadable paths -> Iterator over PathBuf
            .filter(|x| !x.components()
                        .any(|y| check::is_unwanted(y, &cfg_ignores))).collect()
        };
        pats.iter().flat_map(|pat| relevant(&pat[..])).collect()
    };
    let mut checked_files: u32 = 0;
    let mut had_tabs: u32 = 0;
    let mut had_trailing_ws: u32 = 0;
    let mut had_illegals: u32 = 0;
    let paths = find_matches();
    for path in paths {
        if !check::is_dir(path.as_path()) {
            checked_files += 1;
            let r = check::check_path(path.as_path(), args.flag_clean, !args.flag_count)
                .ok()
                .expect(&format!("check_path for {:?} should work", path));
            if (r & check::HAS_TABS) > 0 { had_tabs += 1 }
            if (r & check::TRAILING_SPACES) > 0 { had_trailing_ws += 1 }
            if (r & check::HAS_ILLEGAL_CHARACTERS) > 0 { had_illegals += 1 }
        }
    }
    if had_tabs + had_illegals + had_trailing_ws > 0
    {
        println!("checked {} files (enforcer_errors!) [HAD_TABS:{}][ILLEGAL_CHARS:{}][TRAILING_SPACES:{}]",
                checked_files, had_tabs, had_illegals, had_trailing_ws);
        std::process::exit(1);
    }
    else
    {
        println!("checked {} files (enforcer_clean!)", checked_files);
        std::process::exit(0);
    }
}

<commit_msg>-n also works for count flag<commit_after>extern crate enforcer;
extern crate rustc_serialize;
extern crate docopt;
extern crate glob;
#[macro_use] extern crate log;
extern crate env_logger;

use enforcer::check;
use std::fs::File;
use std::io::Read;
use docopt::Docopt;

const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const USAGE: &'static str = "
enforcer for code rules

Usage:
  enforcer [-g GLOB...] [-c|--clean] [-n|--count]
  enforcer (-h | --help)
  enforcer (-v | --version)
  enforcer (-s | --status)

Options:
  -g GLOB       use these glob patterns (e.g. \"**/*.h\")
  -h --help     Show this screen.
  -v --version  Show version.
  -s --status   Show configuration status.
  -n --count    only count found entries
  -c --clean    clean up trailing whitespaces
";
#[derive(Debug, RustcDecodable)]
struct Args {
    flag_clean: bool,
    flag_g: Vec<String>,
    flag_version: bool,
    flag_status: bool,
    flag_count: bool,
}

#[allow(dead_code)]
fn main() {
    use glob::glob;
    env_logger::init().unwrap();

    let get_cfg = || -> check::EnforcerCfg {
        fn read_enforcer_config() -> std::io::Result<check::EnforcerCfg> {
            let mut cfg_file = try!(File::open(".enforcer"));
            let mut buffer = String::new();
            try!(cfg_file.read_to_string(&mut buffer));
            check::parse_config(&buffer[..])
        }
        read_enforcer_config()
            .unwrap_or(check::default_cfg())
    };

    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());

    if args.flag_version {
        println!("  Version: {}", VERSION);
        std::process::exit(0);
    }
    let enforcer_cfg = get_cfg();
    if args.flag_status {
        println!("  using this config: {:?}", enforcer_cfg);
        std::process::exit(0);
    }
    let cfg_ignores = enforcer_cfg.ignore;
    let cfg_globs = enforcer_cfg.globs;
    let pats = if args.flag_g.len() > 0 {
        args.flag_g
    } else {
        cfg_globs
    };

    let find_matches = || -> Vec<std::path::PathBuf> {
        let relevant = |pat: &str| -> Vec<std::path::PathBuf> {
            glob(&*pat) // -> Result<Paths, PatternError>
            .ok()   // -> Option<Paths>
            .expect(&format!("glob has problems with {}", pat)[..]) // -> Paths (Iterator ofer GlobResult)
            .filter_map(Result::ok) // ignore unreadable paths -> Iterator over PathBuf
            .filter(|x| !x.components()
                        .any(|y| check::is_unwanted(y, &cfg_ignores))).collect()
        };
        pats.iter().flat_map(|pat| relevant(&pat[..])).collect()
    };
    let mut checked_files: u32 = 0;
    let mut had_tabs: u32 = 0;
    let mut had_trailing_ws: u32 = 0;
    let mut had_illegals: u32 = 0;
    let paths = find_matches();
    for path in paths {
        if !check::is_dir(path.as_path()) {
            checked_files += 1;
            let r = check::check_path(path.as_path(), args.flag_clean, !args.flag_count)
                .ok()
                .expect(&format!("check_path for {:?} should work", path));
            if (r & check::HAS_TABS) > 0 { had_tabs += 1 }
            if (r & check::TRAILING_SPACES) > 0 { had_trailing_ws += 1 }
            if (r & check::HAS_ILLEGAL_CHARACTERS) > 0 { had_illegals += 1 }
        }
    }
    if args.flag_count {
        println!("enforcer-error-count: {}", had_tabs + had_illegals + had_trailing_ws);
    }
    if had_tabs + had_illegals + had_trailing_ws > 0
    {
        println!("checked {} files (enforcer_errors!) [HAD_TABS:{}][ILLEGAL_CHARS:{}][TRAILING_SPACES:{}]",
                checked_files, had_tabs, had_illegals, had_trailing_ws);
        std::process::exit(1);
    }
    else
    {
        println!("checked {} files (enforcer_clean!)", checked_files);
        std::process::exit(0);
    }
}

<|endoftext|>


<commit_before>#![crate_id = "iron-router"]
#![license = "MIT"]
//#![deny(missing_doc)]
#![deny(unused_result, unused_result, unnecessary_qualification,
        non_camel_case_types, unused_variable, unnecessary_typecast)]
#![feature(phase, globs, macro_rules)]

extern crate http;
extern crate iron;
extern crate regex;
#[phase(plugin, link)] extern crate log;
#[phase(plugin)] extern crate regex_macros;

#[cfg(test)] extern crate test;

pub use router::Router;
pub use router::Handler;
pub use router::params::Params;

mod router;

<commit_msg>(fix) Removed macro_rules feature flag.<commit_after>#![crate_id = "iron-router"]
#![license = "MIT"]
//#![deny(missing_doc)]
#![deny(unused_result, unused_result, unnecessary_qualification,
        non_camel_case_types, unused_variable, unnecessary_typecast)]
#![feature(phase, globs)]

extern crate http;
extern crate iron;
extern crate regex;
#[phase(plugin, link)] extern crate log;
#[phase(plugin)] extern crate regex_macros;

#[cfg(test)] extern crate test;

pub use router::Router;
pub use router::Handler;
pub use router::params::Params;

mod router;

<|endoftext|>