<commit_before>use simple_linked_list::SimpleLinkedList;

#[test]
fn test_new_list_is_empty() {
    let list: SimpleLinkedList<u32> = SimpleLinkedList::new();
    assert_eq!(list.len(), 0, "list's length must be 0");
}

#[test]
#[ignore]
fn test_push_increments_length() {
    let mut list: SimpleLinkedList<u32> = SimpleLinkedList::new();
    list.push(1);
    assert_eq!(list.len(), 1, "list's length must be 1");
    list.push(2);
    assert_eq!(list.len(), 2, "list's length must be 2");
}

#[test]
#[ignore]
fn test_pop_decrements_length() {
    let mut list: SimpleLinkedList<u32> = SimpleLinkedList::new();
    list.push(1);
    list.push(2);
    list.pop();
    assert_eq!(list.len(), 1, "list's length must be 1");
    list.pop();
    assert_eq!(list.len(), 0, "list's length must be 0");
}

#[test]
#[ignore]
fn test_pop_returns_last_added_element() {
    let mut list: SimpleLinkedList<u32> = SimpleLinkedList::new();
    list.push(1);
    list.push(2);
    assert_eq!(list.pop(), Some(2), "Element must be 2");
    assert_eq!(list.pop(), Some(1), "Element must be 1");
    assert_eq!(list.pop(), None, "No element should be contained in list");
}

#[test]
#[ignore]
fn test_peek_returns_head_element() {
    let mut list: SimpleLinkedList<u32> = SimpleLinkedList::new();
    assert_eq!(list.peek(), None, "No element should be contained in list");
    list.push(2);
    assert_eq!(list.peek(), Some(&2), "Element must be 2");
    assert_eq!(list.peek(), Some(&2), "Element must be still 2");
}

#[test]
#[ignore]
fn test_from_slice() {
    let array = ["1", "2", "3", "4"];
    let mut list = SimpleLinkedList::from(array.as_ref());
    assert_eq!(list.pop(), Some("4"));
    assert_eq!(list.pop(), Some("3"));
    assert_eq!(list.pop(), Some("2"));
    assert_eq!(list.pop(), Some("1"));
}

#[test]
#[ignore]
fn test_reverse() {
    let mut list: SimpleLinkedList<u32> = SimpleLinkedList::new();
    list.push(1);
    list.push(2);
    list.push(3);
    let mut rev_list = list.rev();
    assert_eq!(rev_list.pop(), Some(1));
    assert_eq!(rev_list.pop(), Some(2));
    assert_eq!(rev_list.pop(), Some(3));
    assert_eq!(rev_list.pop(), None);
}

#[test]
#[ignore]
fn test_into_vector() {
    let mut v = Vec::new();
    let mut s = SimpleLinkedList::new();
    for i in 1..4 {
        v.push(i);
        s.push(i);
    }
    let s_as_vec: Vec<i32> = s.into();
    assert_eq!(v, s_as_vec);
}
<commit_msg>simple-linked-list: test_peek_returns_head_element tests head element<commit_after>use simple_linked_list::SimpleLinkedList;

#[test]
fn test_new_list_is_empty() {
    let list: SimpleLinkedList<u32> = SimpleLinkedList::new();
    assert_eq!(list.len(), 0, "list's length must be 0");
}

#[test]
#[ignore]
fn test_push_increments_length() {
    let mut list: SimpleLinkedList<u32> = SimpleLinkedList::new();
    list.push(1);
    assert_eq!(list.len(), 1, "list's length must be 1");
    list.push(2);
    assert_eq!(list.len(), 2, "list's length must be 2");
}

#[test]
#[ignore]
fn test_pop_decrements_length() {
    let mut list: SimpleLinkedList<u32> = SimpleLinkedList::new();
    list.push(1);
    list.push(2);
    list.pop();
    assert_eq!(list.len(), 1, "list's length must be 1");
    list.pop();
    assert_eq!(list.len(), 0, "list's length must be 0");
}

#[test]
#[ignore]
fn test_pop_returns_last_added_element() {
    let mut list: SimpleLinkedList<u32> = SimpleLinkedList::new();
    list.push(1);
    list.push(2);
    assert_eq!(list.pop(), Some(2), "Element must be 2");
    assert_eq!(list.pop(), Some(1), "Element must be 1");
    assert_eq!(list.pop(), None, "No element should be contained in list");
}

#[test]
#[ignore]
fn test_peek_returns_head_element() {
    let mut list: SimpleLinkedList<u32> = SimpleLinkedList::new();
    assert_eq!(list.peek(), None, "No element should be contained in list");
    list.push(2);
    assert_eq!(list.peek(), Some(&2), "Element must be 2");
    assert_eq!(list.peek(), Some(&2), "Element must be still 2");
    list.push(3);
    assert_eq!(list.peek(), Some(&3), "Head element is now 3");
    assert_eq!(list.pop(), Some(3), "Element must be 3");
    assert_eq!(list.peek(), Some(&2), "Head element is now 2");
    assert_eq!(list.pop(), Some(2), "Element must be 2");
    assert_eq!(list.peek(), None, "No element should be contained in list");
}

#[test]
#[ignore]
fn test_from_slice() {
    let array = ["1", "2", "3", "4"];
    let mut list = SimpleLinkedList::from(array.as_ref());
    assert_eq!(list.pop(), Some("4"));
    assert_eq!(list.pop(), Some("3"));
    assert_eq!(list.pop(), Some("2"));
    assert_eq!(list.pop(), Some("1"));
}

#[test]
#[ignore]
fn test_reverse() {
    let mut list: SimpleLinkedList<u32> = SimpleLinkedList::new();
    list.push(1);
    list.push(2);
    list.push(3);
    let mut rev_list = list.rev();
    assert_eq!(rev_list.pop(), Some(1));
    assert_eq!(rev_list.pop(), Some(2));
    assert_eq!(rev_list.pop(), Some(3));
    assert_eq!(rev_list.pop(), None);
}

#[test]
#[ignore]
fn test_into_vector() {
    let mut v = Vec::new();
    let mut s = SimpleLinkedList::new();
    for i in 1..4 {
        v.push(i);
        s.push(i);
    }
    let s_as_vec: Vec<i32> = s.into();
    assert_eq!(v, s_as_vec);
}
<|endoftext|>


<commit_before>use std::kinds::marker::ContravariantLifetime;
use std::mem;

use runtime::Object;
use {class, Id, IdVector, IntoIdVector, Owned, Ownership, Shared, ShareId};
use super::{INSCopying, INSObject};

pub struct NSRange {
	pub location: uint,
	pub length: uint,
}

pub struct NSEnumerator<'a, T> {
	id: Id<Object>,
	marker: ContravariantLifetime<'a>,
}

impl<'a, T> NSEnumerator<'a, T> {
	pub unsafe fn from_ptr(ptr: *mut Object) -> NSEnumerator<'a, T> {
		NSEnumerator { id: Id::from_ptr(ptr), marker: ContravariantLifetime }
	}
}

impl<'a, T> Iterator<&'a T> for NSEnumerator<'a, T> {
	fn next(&mut self) -> Option<&'a T> {
		unsafe {
			let obj = msg_send![self.id nextObject] as *mut T;
			if obj.is_null() {
				None
			} else {
				Some(&*obj)
			}
		}
	}
}

pub trait INSArray<T: INSObject, O: Ownership> : INSObject {
	fn count(&self) -> uint {
		let result = unsafe {
			msg_send![self count]
		};
		result as uint
	}

	fn object_at(&self, index: uint) -> &T {
		unsafe {
			let result = msg_send![self objectAtIndex:index] as *mut T;
			&*result
		}
	}

	fn object_enumerator(&self) -> NSEnumerator<T> {
		unsafe {
			let result = msg_send![self objectEnumerator];
			NSEnumerator::from_ptr(result)
		}
	}

	unsafe fn from_refs(refs: &[&T]) -> Id<Self> {
		let cls = class::<Self>();
		let obj = msg_send![cls alloc];
		let obj = msg_send![obj initWithObjects:refs.as_ptr() count:refs.len()];
		Id::from_retained_ptr(obj as *mut Self)
	}

	fn from_vec(vec: Vec<Id<T, O>>) -> Id<Self> {
		let refs = vec.as_refs_slice();
		unsafe {
			INSArray::from_refs(refs)
		}
	}

	fn objects_in_range(&self, start: uint, len: uint) -> Vec<&T> {
		let vec: Vec<*mut T> = Vec::from_elem(len, RawPtr::null());
		let range = NSRange { location: start, length: len };
		unsafe {
			msg_send![self getObjects:vec.as_ptr() range:range];
			mem::transmute(vec)
		}
	}

	fn to_vec(&self) -> Vec<&T> {
		self.objects_in_range(0, self.count())
	}

	fn into_vec(array: Id<Self>) -> Vec<Id<T, O>> {
		let vec = array.to_vec();
		unsafe {
			vec.into_id_vec()
		}
	}
}

pub trait INSOwnedArray<T: INSObject> : INSArray<T, Owned> {
	fn mut_object_at(&mut self, index: uint) -> &mut T {
		unsafe {
			let result = msg_send![self objectAtIndex:index] as *mut T;
			&mut *result
		}
	}
}

pub trait INSSharedArray<T: INSObject> : INSArray<T, Shared> {
	fn shared_object_at(&self, index: uint) -> ShareId<T> {
		let obj = self.object_at(index);
		unsafe {
			Id::from_ptr(obj as *const _ as *mut T)
		}
	}

	fn from_slice(slice: &[ShareId<T>]) -> Id<Self> {
		let refs = slice.as_refs_slice();
		unsafe {
			INSArray::from_refs(refs)
		}
	}

	fn to_shared_vec(&self) -> Vec<ShareId<T>> {
		let vec = self.to_vec();
		unsafe {
			vec.into_id_vec()
		}
	}
}

object_struct!(NSArray<T>)

impl<T: INSObject> INSArray<T, Owned> for NSArray<T> { }

impl<T: INSObject> INSOwnedArray<T> for NSArray<T> { }

impl<T> INSCopying<NSArray<T>> for NSArray<T> { }

impl<T: INSObject> Collection for NSArray<T> {
	fn len(&self) -> uint {
		self.count()
	}
}

impl<T: INSObject> Index<uint, T> for NSArray<T> {
	fn index(&self, index: &uint) -> &T {
		self.object_at(*index)
	}
}

pub trait INSMutableArray<T: INSObject, O: Ownership> : INSArray<T, O> {
	fn add_object(&mut self, obj: Id<T, O>) {
		unsafe {
			msg_send![self addObject:obj];
		}
	}

	fn insert_object_at(&mut self, index: uint, obj: Id<T, O>) {
		unsafe {
			msg_send![self insertObject:obj atIndex:index];
		}
	}

	fn remove_object_at(&mut self, index: uint) {
		unsafe {
			msg_send![self removeObjectAtIndex:index];
		}
	}
}

object_struct!(NSMutableArray<T>)

impl<T: INSObject> INSArray<T, Owned> for NSMutableArray<T> { }

impl<T: INSObject> INSOwnedArray<T> for NSMutableArray<T> { }

impl<T: INSObject> INSMutableArray<T, Owned> for NSMutableArray<T> { }

impl<T: INSObject> Collection for NSMutableArray<T> {
	fn len(&self) -> uint {
		self.count()
	}
}

#[cfg(test)]
mod tests {
	use {Id};
	use foundation::{INSObject, NSObject};
	use super::{INSArray, INSMutableArray, NSArray, NSMutableArray};

	fn sample_array(len: uint) -> Id<NSArray<NSObject>> {
		let vec: Vec<Id<NSObject>> = Vec::from_fn(len, |_| INSObject::new());
		INSArray::from_vec(vec)
	}

	#[test]
	fn test_count() {
		let empty_array: Id<NSArray<NSObject>> = INSObject::new();
		assert!(empty_array.count() == 0);

		let array = sample_array(4);
		assert!(array.count() == 4);
	}

	#[test]
	fn test_object_at() {
		let array = sample_array(4);
		assert!(array.object_at(0) != array.object_at(3));
	}

	#[test]
	fn test_object_enumerator() {
		let array = sample_array(4);

		assert!(array.object_enumerator().count() == 4);
		assert!(array.object_enumerator()
		             .enumerate()
		             .all(|(i, obj)| obj == array.object_at(i)));
	}

	#[test]
	fn test_objects_in_range() {
		let array = sample_array(4);

		let middle_objs = array.objects_in_range(1, 2);
		assert!(middle_objs.len() == 2);
		assert!(*middle_objs.get(0) == array.object_at(1));
		assert!(*middle_objs.get(1) == array.object_at(2));

		let empty_objs = array.objects_in_range(1, 0);
		assert!(empty_objs.len() == 0);

		let all_objs = array.objects_in_range(0, 4);
		assert!(all_objs.len() == 4);
	}

	#[test]
	fn test_into_vec() {
		let array = sample_array(4);

		let vec = INSArray::into_vec(array);
		assert!(vec.len() == 4);
	}

	#[test]
	fn test_add_object() {
		let mut array: Id<NSMutableArray<NSObject>> = INSObject::new();
		let obj: Id<NSObject> = INSObject::new();
		array.deref_mut().add_object(obj);

		assert!(array.len() == 1);
		assert!(array.object_at(0) == array.object_at(0));
	}
}
<commit_msg>Added first and last_object INSArray methods.<commit_after>use std::kinds::marker::ContravariantLifetime;
use std::mem;

use runtime::Object;
use {class, Id, IdVector, IntoIdVector, Owned, Ownership, Shared, ShareId};
use super::{INSCopying, INSObject};

pub struct NSRange {
	pub location: uint,
	pub length: uint,
}

pub struct NSEnumerator<'a, T> {
	id: Id<Object>,
	marker: ContravariantLifetime<'a>,
}

impl<'a, T> NSEnumerator<'a, T> {
	pub unsafe fn from_ptr(ptr: *mut Object) -> NSEnumerator<'a, T> {
		NSEnumerator { id: Id::from_ptr(ptr), marker: ContravariantLifetime }
	}
}

impl<'a, T> Iterator<&'a T> for NSEnumerator<'a, T> {
	fn next(&mut self) -> Option<&'a T> {
		unsafe {
			let obj = msg_send![self.id nextObject] as *mut T;
			if obj.is_null() {
				None
			} else {
				Some(&*obj)
			}
		}
	}
}

pub trait INSArray<T: INSObject, O: Ownership> : INSObject {
	fn count(&self) -> uint {
		let result = unsafe {
			msg_send![self count]
		};
		result as uint
	}

	fn object_at(&self, index: uint) -> &T {
		unsafe {
			let obj = msg_send![self objectAtIndex:index] as *const T;
			&*obj
		}
	}

	fn first_object(&self) -> Option<&T> {
		unsafe {
			let obj = msg_send![self firstObject] as *const T;
			if obj.is_null() {
				None
			} else {
				Some(&*obj)
			}
		}
	}

	fn last_object(&self) -> Option<&T> {
		unsafe {
			let obj = msg_send![self lastObject] as *const T;
			if obj.is_null() {
				None
			} else {
				Some(&*obj)
			}
		}
	}

	fn object_enumerator(&self) -> NSEnumerator<T> {
		unsafe {
			let result = msg_send![self objectEnumerator];
			NSEnumerator::from_ptr(result)
		}
	}

	unsafe fn from_refs(refs: &[&T]) -> Id<Self> {
		let cls = class::<Self>();
		let obj = msg_send![cls alloc];
		let obj = msg_send![obj initWithObjects:refs.as_ptr() count:refs.len()];
		Id::from_retained_ptr(obj as *mut Self)
	}

	fn from_vec(vec: Vec<Id<T, O>>) -> Id<Self> {
		let refs = vec.as_refs_slice();
		unsafe {
			INSArray::from_refs(refs)
		}
	}

	fn objects_in_range(&self, start: uint, len: uint) -> Vec<&T> {
		let vec: Vec<*mut T> = Vec::from_elem(len, RawPtr::null());
		let range = NSRange { location: start, length: len };
		unsafe {
			msg_send![self getObjects:vec.as_ptr() range:range];
			mem::transmute(vec)
		}
	}

	fn to_vec(&self) -> Vec<&T> {
		self.objects_in_range(0, self.count())
	}

	fn into_vec(array: Id<Self>) -> Vec<Id<T, O>> {
		let vec = array.to_vec();
		unsafe {
			vec.into_id_vec()
		}
	}
}

pub trait INSOwnedArray<T: INSObject> : INSArray<T, Owned> {
	fn mut_object_at(&mut self, index: uint) -> &mut T {
		unsafe {
			let result = msg_send![self objectAtIndex:index] as *mut T;
			&mut *result
		}
	}
}

pub trait INSSharedArray<T: INSObject> : INSArray<T, Shared> {
	fn shared_object_at(&self, index: uint) -> ShareId<T> {
		let obj = self.object_at(index);
		unsafe {
			Id::from_ptr(obj as *const _ as *mut T)
		}
	}

	fn from_slice(slice: &[ShareId<T>]) -> Id<Self> {
		let refs = slice.as_refs_slice();
		unsafe {
			INSArray::from_refs(refs)
		}
	}

	fn to_shared_vec(&self) -> Vec<ShareId<T>> {
		let vec = self.to_vec();
		unsafe {
			vec.into_id_vec()
		}
	}
}

object_struct!(NSArray<T>)

impl<T: INSObject> INSArray<T, Owned> for NSArray<T> { }

impl<T: INSObject> INSOwnedArray<T> for NSArray<T> { }

impl<T> INSCopying<NSArray<T>> for NSArray<T> { }

impl<T: INSObject> Collection for NSArray<T> {
	fn len(&self) -> uint {
		self.count()
	}
}

impl<T: INSObject> Index<uint, T> for NSArray<T> {
	fn index(&self, index: &uint) -> &T {
		self.object_at(*index)
	}
}

pub trait INSMutableArray<T: INSObject, O: Ownership> : INSArray<T, O> {
	fn add_object(&mut self, obj: Id<T, O>) {
		unsafe {
			msg_send![self addObject:obj];
		}
	}

	fn insert_object_at(&mut self, index: uint, obj: Id<T, O>) {
		unsafe {
			msg_send![self insertObject:obj atIndex:index];
		}
	}

	fn remove_object_at(&mut self, index: uint) {
		unsafe {
			msg_send![self removeObjectAtIndex:index];
		}
	}
}

object_struct!(NSMutableArray<T>)

impl<T: INSObject> INSArray<T, Owned> for NSMutableArray<T> { }

impl<T: INSObject> INSOwnedArray<T> for NSMutableArray<T> { }

impl<T: INSObject> INSMutableArray<T, Owned> for NSMutableArray<T> { }

impl<T: INSObject> Collection for NSMutableArray<T> {
	fn len(&self) -> uint {
		self.count()
	}
}

#[cfg(test)]
mod tests {
	use {Id};
	use foundation::{INSObject, NSObject};
	use super::{INSArray, INSMutableArray, NSArray, NSMutableArray};

	fn sample_array(len: uint) -> Id<NSArray<NSObject>> {
		let vec: Vec<Id<NSObject>> = Vec::from_fn(len, |_| INSObject::new());
		INSArray::from_vec(vec)
	}

	#[test]
	fn test_count() {
		let empty_array: Id<NSArray<NSObject>> = INSObject::new();
		assert!(empty_array.count() == 0);

		let array = sample_array(4);
		assert!(array.count() == 4);
	}

	#[test]
	fn test_object_at() {
		let array = sample_array(4);
		assert!(array.object_at(0) != array.object_at(3));
		assert!(array.first_object().unwrap() == array.object_at(0));
		assert!(array.last_object().unwrap() == array.object_at(3));

		let empty_array: Id<NSArray<NSObject>> = INSObject::new();
		assert!(empty_array.first_object().is_none());
		assert!(empty_array.last_object().is_none());
	}

	#[test]
	fn test_object_enumerator() {
		let array = sample_array(4);

		assert!(array.object_enumerator().count() == 4);
		assert!(array.object_enumerator()
		             .enumerate()
		             .all(|(i, obj)| obj == array.object_at(i)));
	}

	#[test]
	fn test_objects_in_range() {
		let array = sample_array(4);

		let middle_objs = array.objects_in_range(1, 2);
		assert!(middle_objs.len() == 2);
		assert!(*middle_objs.get(0) == array.object_at(1));
		assert!(*middle_objs.get(1) == array.object_at(2));

		let empty_objs = array.objects_in_range(1, 0);
		assert!(empty_objs.len() == 0);

		let all_objs = array.objects_in_range(0, 4);
		assert!(all_objs.len() == 4);
	}

	#[test]
	fn test_into_vec() {
		let array = sample_array(4);

		let vec = INSArray::into_vec(array);
		assert!(vec.len() == 4);
	}

	#[test]
	fn test_add_object() {
		let mut array: Id<NSMutableArray<NSObject>> = INSObject::new();
		let obj: Id<NSObject> = INSObject::new();
		array.deref_mut().add_object(obj);

		assert!(array.len() == 1);
		assert!(array.object_at(0) == array.object_at(0));
	}
}
<|endoftext|>


<commit_before>fn make_vec() -> Vec<u8> {
    let mut v = Vec::with_capacity(4);
    v.push(1);
    v.push(2);
    v
}

fn make_vec_macro() -> Vec<u8> {
    vec![1, 2]
}

fn make_vec_macro_repeat() -> Vec<u8> {
    vec![42; 5]
}

fn make_vec_macro_repeat_zeroed() -> Vec<u8> {
    vec![0; 7]
}

fn vec_into_iter() -> u8 {
    vec![1, 2, 3, 4]
        .into_iter()
        .map(|x| x * x)
        .fold(0, |x, y| x + y)
}

fn vec_into_iter_rev() -> u8 {
    vec![1, 2, 3, 4]
        .into_iter()
        .map(|x| x * x)
        .fold(0, |x, y| x + y)
}

fn vec_into_iter_zst() -> usize {
    vec![[0u64; 0], [0u64; 0]]
        .into_iter()
        .rev()
        .map(|x| x.len())
        .sum()
}

fn vec_into_iter_rev_zst() -> usize {
    vec![[0u64; 0], [0u64; 0]]
        .into_iter()
        .rev()
        .map(|x| x.len())
        .sum()
}

fn vec_iter_and_mut() {
    let mut v = vec![1,2,3,4];
    for i in v.iter_mut() {
        *i += 1;
    }
    assert_eq!(v.iter().sum::<i32>(), 2+3+4+5);
}

fn vec_iter_and_mut_rev() {
    let mut v = vec![1,2,3,4];
    for i in v.iter_mut().rev() {
        *i += 1;
    }
    assert_eq!(v.iter().sum::<i32>(), 2+3+4+5);
}

fn vec_reallocate() -> Vec<u8> {
    let mut v = vec![1, 2];
    v.push(3);
    v.push(4);
    v.push(5);
    v
}

fn vec_push_ptr_stable() {
    let mut v = Vec::with_capacity(10);
    v.push(0);
    let v0 = unsafe { &*(&v[0] as *const _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay.
    v.push(1);
    let _val = *v0;
}

fn vec_extend_ptr_stable() {
    let mut v = Vec::with_capacity(10);
    v.push(0);
    let v0 = unsafe { &*(&v[0] as *const _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay.
    // `slice::Iter` (with `T: Copy`) specialization
    v.extend(&[1]);
    let _val = *v0;
    // `vec::IntoIter` specialization
    v.extend(vec![2]);
    let _val = *v0;
    // `TrustedLen` specialization
    v.extend(std::iter::once(3));
    let _val = *v0;
    // base case
    v.extend(std::iter::once(3).filter(|_| true));
    let _val = *v0;
}

fn vec_truncate_ptr_stable() {
    let mut v = vec![0; 10];
    let v0 = unsafe { &*(&v[0] as *const _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay.
    v.truncate(5);
    let _val = *v0;
}

fn main() {
    assert_eq!(vec_reallocate().len(), 5);

    assert_eq!(vec_into_iter(), 30);
    assert_eq!(vec_into_iter_rev(), 30);
    vec_iter_and_mut();
    assert_eq!(vec_into_iter_zst(), 0);
    assert_eq!(vec_into_iter_rev_zst(), 0);
    vec_iter_and_mut_rev();

    assert_eq!(make_vec().capacity(), 4);
    assert_eq!(make_vec_macro(), [1, 2]);
    assert_eq!(make_vec_macro_repeat(), [42; 5]);
    assert_eq!(make_vec_macro_repeat_zeroed(), [0; 7]);

    // Test interesting empty slice comparison
    // (one is a real pointer, one an integer pointer).
    assert_eq!((200..-5).step_by(1).collect::<Vec<isize>>(), []);

    vec_push_ptr_stable();
    vec_extend_ptr_stable();
    vec_truncate_ptr_stable();
}
<commit_msg>use mutable reference<commit_after>fn make_vec() -> Vec<u8> {
    let mut v = Vec::with_capacity(4);
    v.push(1);
    v.push(2);
    v
}

fn make_vec_macro() -> Vec<u8> {
    vec![1, 2]
}

fn make_vec_macro_repeat() -> Vec<u8> {
    vec![42; 5]
}

fn make_vec_macro_repeat_zeroed() -> Vec<u8> {
    vec![0; 7]
}

fn vec_into_iter() -> u8 {
    vec![1, 2, 3, 4]
        .into_iter()
        .map(|x| x * x)
        .fold(0, |x, y| x + y)
}

fn vec_into_iter_rev() -> u8 {
    vec![1, 2, 3, 4]
        .into_iter()
        .map(|x| x * x)
        .fold(0, |x, y| x + y)
}

fn vec_into_iter_zst() -> usize {
    vec![[0u64; 0], [0u64; 0]]
        .into_iter()
        .rev()
        .map(|x| x.len())
        .sum()
}

fn vec_into_iter_rev_zst() -> usize {
    vec![[0u64; 0], [0u64; 0]]
        .into_iter()
        .rev()
        .map(|x| x.len())
        .sum()
}

fn vec_iter_and_mut() {
    let mut v = vec![1,2,3,4];
    for i in v.iter_mut() {
        *i += 1;
    }
    assert_eq!(v.iter().sum::<i32>(), 2+3+4+5);
}

fn vec_iter_and_mut_rev() {
    let mut v = vec![1,2,3,4];
    for i in v.iter_mut().rev() {
        *i += 1;
    }
    assert_eq!(v.iter().sum::<i32>(), 2+3+4+5);
}

fn vec_reallocate() -> Vec<u8> {
    let mut v = vec![1, 2];
    v.push(3);
    v.push(4);
    v.push(5);
    v
}

fn vec_push_ptr_stable() {
    let mut v = Vec::with_capacity(10);
    v.push(0);
    let v0 = unsafe { &mut *(&mut v[0] as *mut _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay.
    v.push(1);
    let _val = *v0;
}

fn vec_extend_ptr_stable() {
    let mut v = Vec::with_capacity(10);
    v.push(0);
    let v0 = unsafe { &mut *(&mut v[0] as *mut _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay.
    // `slice::Iter` (with `T: Copy`) specialization
    v.extend(&[1]);
    let _val = *v0;
    // `vec::IntoIter` specialization
    v.extend(vec![2]);
    let _val = *v0;
    // `TrustedLen` specialization
    v.extend(std::iter::once(3));
    let _val = *v0;
    // base case
    v.extend(std::iter::once(3).filter(|_| true));
    let _val = *v0;
}

fn vec_truncate_ptr_stable() {
    let mut v = vec![0; 10];
    let v0 = unsafe { &mut *(&mut v[0] as *mut _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay.
    v.truncate(5);
    let _val = *v0;
}

fn main() {
    assert_eq!(vec_reallocate().len(), 5);

    assert_eq!(vec_into_iter(), 30);
    assert_eq!(vec_into_iter_rev(), 30);
    vec_iter_and_mut();
    assert_eq!(vec_into_iter_zst(), 0);
    assert_eq!(vec_into_iter_rev_zst(), 0);
    vec_iter_and_mut_rev();

    assert_eq!(make_vec().capacity(), 4);
    assert_eq!(make_vec_macro(), [1, 2]);
    assert_eq!(make_vec_macro_repeat(), [42; 5]);
    assert_eq!(make_vec_macro_repeat_zeroed(), [0; 7]);

    // Test interesting empty slice comparison
    // (one is a real pointer, one an integer pointer).
    assert_eq!((200..-5).step_by(1).collect::<Vec<isize>>(), []);

    vec_push_ptr_stable();
    vec_extend_ptr_stable();
    vec_truncate_ptr_stable();
}
<|endoftext|>


<commit_before>use std::collections::{BTreeMap, HashMap};
use std::io::Read;

use serde_derive::{Deserialize, Serialize};
use snap::read::FrameDecoder;

use pueue_lib::log::{get_log_file_handle, read_last_lines};
use pueue_lib::network::message::TaskLogMessage;
use pueue_lib::settings::Settings;
use pueue_lib::task::Task;

/// This is the output struct used for
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct TaskLog {
    pub task: Task,
    pub output: String,
}

pub fn print_log_json(
    task_log_messages: BTreeMap<usize, TaskLogMessage>,
    settings: &Settings,
    lines: Option<usize>,
) {
    let mut tasks: BTreeMap<usize, Task> = BTreeMap::new();
    let mut task_log: BTreeMap<usize, String> = BTreeMap::new();
    // Convert the TaskLogMessage into a proper JSON serializable format.
    // Output in TaskLogMessages, if it exists, is compressed.
    // We need to decompress and convert to normal strings.
    for (id, message) in task_log_messages {
        tasks.insert(id, message.task);

        if settings.client.read_local_logs {
            let output = get_local_log(settings, id, lines);
            task_log.insert(id, output);
        } else {
            let output = get_remote_log(message.output);
            task_log.insert(id, output);
        }
    }

    // Now assemble the final struct that will be returned
    let mut json = BTreeMap::new();
    for (id, mut task) in tasks {
        let (id, output) = task_log.remove_entry(&id).unwrap();

        task.envs = HashMap::new();
        json.insert(id, TaskLog { task, output });
    }

    println!("{}", serde_json::to_string(&json).unwrap());
}

/// Read logs directly from local files for a specific task.
fn get_local_log(settings: &Settings, id: usize, lines: Option<usize>) -> String {
    let mut file = match get_log_file_handle(id, &settings.shared.pueue_directory()) {
        Ok(file) => file,
        Err(err) => {
            return format!("(Pueue error) Failed to get log file handle: {err}");
        }
    };

    let output = if let Some(lines) = lines {
        read_last_lines(&mut file, lines)
    } else {
        let mut output = String::new();
        if let Err(error) = file.read_to_string(&mut output) {
            output.push_str(&format!(
                "(Pueue error) Failed to read local log output file: {error:?}"
            ))
        };

        output
    };

    output
}

/// Read logs from from compressed remote logs.
/// If logs don't exist, an empty string will be returned.
fn get_remote_log(output_bytes: Option<Vec<u8>>) -> String {
    let output = if let Some(bytes) = output_bytes {
        let mut decoder = FrameDecoder::new(&bytes[..]);
        let mut output = String::new();
        if let Err(error) = decoder.read_to_string(&mut output) {
            output.push_str(&format!(
                "(Pueue error) Failed to decompress remote log output: {error:?}"
            ))
        }
        output
    } else {
        String::new()
    };

    output
}
<commit_msg>fix: v1.62 Clippy issues<commit_after>use std::collections::{BTreeMap, HashMap};
use std::fmt::Write;
use std::io::Read;

use serde_derive::{Deserialize, Serialize};
use snap::read::FrameDecoder;

use pueue_lib::log::{get_log_file_handle, read_last_lines};
use pueue_lib::network::message::TaskLogMessage;
use pueue_lib::settings::Settings;
use pueue_lib::task::Task;

/// This is the output struct used for
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct TaskLog {
    pub task: Task,
    pub output: String,
}

pub fn print_log_json(
    task_log_messages: BTreeMap<usize, TaskLogMessage>,
    settings: &Settings,
    lines: Option<usize>,
) {
    let mut tasks: BTreeMap<usize, Task> = BTreeMap::new();
    let mut task_log: BTreeMap<usize, String> = BTreeMap::new();
    // Convert the TaskLogMessage into a proper JSON serializable format.
    // Output in TaskLogMessages, if it exists, is compressed.
    // We need to decompress and convert to normal strings.
    for (id, message) in task_log_messages {
        tasks.insert(id, message.task);

        if settings.client.read_local_logs {
            let output = get_local_log(settings, id, lines);
            task_log.insert(id, output);
        } else {
            let output = get_remote_log(message.output);
            task_log.insert(id, output);
        }
    }

    // Now assemble the final struct that will be returned
    let mut json = BTreeMap::new();
    for (id, mut task) in tasks {
        let (id, output) = task_log.remove_entry(&id).unwrap();

        task.envs = HashMap::new();
        json.insert(id, TaskLog { task, output });
    }

    println!("{}", serde_json::to_string(&json).unwrap());
}

/// Read logs directly from local files for a specific task.
fn get_local_log(settings: &Settings, id: usize, lines: Option<usize>) -> String {
    let mut file = match get_log_file_handle(id, &settings.shared.pueue_directory()) {
        Ok(file) => file,
        Err(err) => {
            return format!("(Pueue error) Failed to get log file handle: {err}");
        }
    };

    let output = if let Some(lines) = lines {
        read_last_lines(&mut file, lines)
    } else {
        let mut output = String::new();
        if let Err(error) = file.read_to_string(&mut output) {
            let _ = write!(
                output,
                "(Pueue error) Failed to read local log output file: {error:?}"
            );
        };

        output
    };

    output
}

/// Read logs from from compressed remote logs.
/// If logs don't exist, an empty string will be returned.
fn get_remote_log(output_bytes: Option<Vec<u8>>) -> String {
    let output = if let Some(bytes) = output_bytes {
        let mut decoder = FrameDecoder::new(&bytes[..]);
        let mut output = String::new();
        if let Err(error) = decoder.read_to_string(&mut output) {
            let _ = write!(
                output,
                "(Pueue error) Failed to decompress remote log output: {error:?}"
            );
        }
        output
    } else {
        String::new()
    };

    output
}
<|endoftext|>


<commit_before>use Result as tantivy_Error;
use combine::*;
use collector::Collector;
use core::searcher::Searcher;
use common::TimerTree;
use query::{Query, MultiTermQuery};
use schema::{Schema, FieldType, Term, Field};
use analyzer::SimpleTokenizer;
use analyzer::StreamingIterator;
use DocAddress;
use query::Explanation;
use query::Occur;

#[derive(Debug)]
pub enum ParsingError {
    SyntaxError,
    FieldDoesNotExist(String),
    ExpectedU32(String, String),
}

pub struct QueryParser {
    schema: Schema,
    default_fields: Vec<Field>,
}

#[derive(Eq, PartialEq, Debug)]
pub enum StandardQuery {
    MultiTerm(MultiTermQuery),
}

impl StandardQuery {
    pub fn num_terms(&self,) -> usize {
        match self {
            &StandardQuery::MultiTerm(ref q) => {
                q.num_terms()
            }
        }
    }
}

impl Query for StandardQuery {
    fn search<C: Collector>(&self, searcher: &Searcher, collector: &mut C) -> tantivy_Error<TimerTree> {
        match *self {
            StandardQuery::MultiTerm(ref q) => {
                q.search(searcher, collector)
            }
        }
    }

    fn explain(
        &self,
        searcher: &Searcher,
        doc_address: &DocAddress) -> tantivy_Error<Explanation> {
        match self {
            &StandardQuery::MultiTerm(ref q) => q.explain(searcher, doc_address)
        }
    }
}

fn compute_terms(field: Field, text: &str) -> Vec<Term> {
    let tokenizer = SimpleTokenizer::new();
    let mut tokens = Vec::new();
    let mut token_it = tokenizer.tokenize(text);
    loop {
        match token_it.next() {
            Some(token_str) => {
                tokens.push(Term::from_field_text(field, token_str));
            }
            None => { break; }
        }
    }
    tokens
}

impl QueryParser {
    pub fn new(schema: Schema,
               default_fields: Vec<Field>) -> QueryParser {
        QueryParser {
            schema: schema,
            default_fields: default_fields,
        }
    }

    fn transform_field_and_value(&self, field: Field, val: &str) -> Result<Vec<Term>, ParsingError> {
        let field_entry = self.schema.get_field_entry(field);
        Ok(match field_entry.field_type() {
            &FieldType::Str(_) => {
                compute_terms(field, val)
            },
            &FieldType::U32(_) => {
                let u32_parsed: u32 = try!(val
                    .parse::<u32>()
                    .map_err(|_| {
                        ParsingError::ExpectedU32(field_entry.name().clone(), String::from(val))
                    })
                );
                vec!(Term::from_field_u32(field, u32_parsed))
            }
        })
    }

    fn transform_literal(&self, literal: Literal) -> Result<Vec<Term>, ParsingError> {
        match literal {
            Literal::DefaultField(val) => {
                let mut terms = Vec::new();
                for &field in &self.default_fields {
                    let extra_terms = try!(self.transform_field_and_value(field, &val));
                    terms.extend_from_slice(&extra_terms);
                }
                Ok(terms)
            },
            Literal::WithField(field_name, val) => {
                match self.schema.get_field(&field_name) {
                    Some(field) => {
                        let terms = try!(self.transform_field_and_value(field, &val));
                        Ok(terms)
                    },
                    None => Err(ParsingError::FieldDoesNotExist(field_name))
                }
            }
        }
    }

    pub fn parse_query(&self, query: &str) -> Result<StandardQuery, ParsingError> {
        match parser(query_language).parse(query.trim()) {
            Ok(literals) => {
                let mut terms_result: Vec<(Occur, Term)> = Vec::new();
                for (occur, literal) in literals.0 {
                    let literal_terms = try!(self.transform_literal(literal));
                    terms_result
                        .extend(literal_terms
                        .into_iter()
                        .map(|term| (occur, term) ));
                }
                Ok(
                    StandardQuery::MultiTerm(
                        MultiTermQuery::from(terms_result)
                    )
                )
            }
            Err(_) => {
                Err(ParsingError::SyntaxError)
            }
        }
    }

}

#[derive(Debug, Eq, PartialEq)]
pub enum Literal {
    WithField(String, String),
    DefaultField(String),
}

// TODO handle as a specific case, having a single MUST_NOT term

pub fn query_language(input: State<&str>) -> ParseResult<Vec<(Occur, Literal)>, &str>
{
    let literal = || {
        let term_val = || {
            let word = many1(satisfy(|c: char| c.is_alphanumeric()));
            let phrase =
                (char('"'), many1(satisfy(|c| c != '"')), char('"'),)
                .map(|(_, s, _)| s);
            phrase.or(word)
        };

        let field = many1(letter());
        let term_query = (field, char(':'), term_val())
            .map(|(field,_, value)| Literal::WithField(field, value));
        let term_default_field = term_val().map(Literal::DefaultField);

        let occur = optional(char('-').or(char('+')))
            .map(|opt_c| {
                match opt_c {
                    Some('-') => Occur::MustNot,
                    Some('+') => Occur::Must,
                    _ => Occur::Should,
                }
            });
        (occur, try(term_query).or(term_default_field))
    };

    (sep_by(literal(), spaces()), eof())
    .map(|(first, _)| first)
    .parse_state(input)
}

#[cfg(test)]
mod tests {

    use combine::*;
    use schema::*;
    use query::MultiTermQuery;
    use query::Occur;
    use super::*;

    #[test]
    pub fn test_query_grammar() {
        let mut grammar_parser = parser(query_language);
        assert_eq!(grammar_parser.parse("abc:toto").unwrap().0,
            vec!(
                (Occur::Should, Literal::WithField(String::from("abc"), String::from("toto")))
            )
        );
        assert_eq!(
            grammar_parser.parse("\"some phrase query\"").unwrap().0,
            vec!(
                (Occur::Should, Literal::DefaultField(String::from("some phrase query"))),
            )
        );
        assert_eq!(
            grammar_parser.parse("field:\"some phrase query\"").unwrap().0,
            vec!(
                (Occur::Should, Literal::WithField(String::from("field"), String::from("some phrase query")))
        ));
        assert_eq!(grammar_parser.parse("field:\"some phrase query\" field:toto a").unwrap().0,
            vec!(
                (Occur::Should, Literal::WithField(String::from("field"), String::from("some phrase query"))),
                (Occur::Should, Literal::WithField(String::from("field"), String::from("toto"))),
                (Occur::Should, Literal::DefaultField(String::from("a"))),
            ));
        assert_eq!(grammar_parser.parse("field:\"a ! b\"").unwrap().0,
            vec!(
                (Occur::Should, Literal::WithField(String::from("field"), String::from("a ! b"))),
            ));
        assert_eq!(grammar_parser.parse("field:a9e3").unwrap().0,
            vec!(
                (Occur::Should, Literal::WithField(String::from("field"), String::from("a9e3")),)
            ));
        assert_eq!(grammar_parser.parse("a9e3").unwrap().0,
            vec!(
                (Occur::Should, Literal::DefaultField(String::from("a9e3"))),
            ));
        assert_eq!(grammar_parser.parse("field:タンタイビーって早い").unwrap().0,
            vec!(
                (Occur::Should, Literal::WithField(String::from("field"), String::from("タンタイビーって早い"))),
            ));
    }

    #[test]
    pub fn test_query_grammar_with_occur() {
        let mut query_parser = parser(query_language);
        assert_eq!(query_parser.parse("+abc:toto").unwrap().0,
            vec!(
                (Occur::Must, Literal::WithField(String::from("abc"), String::from("toto")))
            )
        );
        assert_eq!(query_parser.parse("+field:\"some phrase query\" -field:toto a").unwrap().0,
            vec!(
                (Occur::Must, Literal::WithField(String::from("field"), String::from("some phrase query"))),
                (Occur::MustNot, Literal::WithField(String::from("field"), String::from("toto"))),
                (Occur::Should, Literal::DefaultField(String::from("a"))),
            ));
    }

    #[test]
    pub fn test_invalid_queries() {
        let mut query_parser = parser(query_language);
        println!("{:?}", query_parser.parse("ab!c:"));
        assert!(query_parser.parse("ab!c:").is_err());
        assert!(query_parser.parse("").is_ok());
        assert!(query_parser.parse(":fval").is_err());
        assert!(query_parser.parse("field:").is_err());
        assert!(query_parser.parse(":field").is_err());
        assert!(query_parser.parse("f:@e!e").is_err());
        assert!(query_parser.parse("f:@e!e").is_err());
    }

    #[test]
    pub fn test_query_parser() {
        let mut schema_builder = SchemaBuilder::new();
        let text_field = schema_builder.add_text_field("text", STRING);
        let title_field = schema_builder.add_text_field("title", STRING);
        let author_field = schema_builder.add_text_field("author", STRING);
        let query_parser = QueryParser::new(schema_builder.build(), vec!(text_field, author_field));
        assert!(query_parser.parse_query("a:b").is_err());
        {
            let terms = vec!(Term::from_field_text(title_field, "abctitle"));
            let query = StandardQuery::MultiTerm(MultiTermQuery::from(terms));
            assert_eq!(
                query_parser.parse_query("title:abctitle").unwrap(),
                query
            );
        }
        {
            let terms = vec!(
                Term::from_field_text(text_field, "abctitle"),
                Term::from_field_text(author_field, "abctitle"),
            );
            let query = StandardQuery::MultiTerm(MultiTermQuery::from(terms));
            assert_eq!(
                query_parser.parse_query("abctitle").unwrap(),
                query
            );
        }
        {
            let terms = vec!(Term::from_field_text(title_field, "abctitle"));
            let query = StandardQuery::MultiTerm(MultiTermQuery::from(terms));
            assert_eq!(
                query_parser.parse_query("title:abctitle   ").unwrap(),
                query
            );
            assert_eq!(
                query_parser.parse_query("    title:abctitle").unwrap(),
                query
            );
        }
    }

}
<commit_msg>NOBUG Added unit test<commit_after>use Result as tantivy_Error;
use combine::*;
use collector::Collector;
use core::searcher::Searcher;
use common::TimerTree;
use query::{Query, MultiTermQuery};
use schema::{Schema, FieldType, Term, Field};
use analyzer::SimpleTokenizer;
use analyzer::StreamingIterator;
use DocAddress;
use query::Explanation;
use query::Occur;

#[derive(Debug)]
pub enum ParsingError {
    SyntaxError,
    FieldDoesNotExist(String),
    ExpectedU32(String, String),
}

pub struct QueryParser {
    schema: Schema,
    default_fields: Vec<Field>,
}

#[derive(Eq, PartialEq, Debug)]
pub enum StandardQuery {
    MultiTerm(MultiTermQuery),
}

impl StandardQuery {
    pub fn num_terms(&self,) -> usize {
        match self {
            &StandardQuery::MultiTerm(ref q) => {
                q.num_terms()
            }
        }
    }
}

impl Query for StandardQuery {
    fn search<C: Collector>(&self, searcher: &Searcher, collector: &mut C) -> tantivy_Error<TimerTree> {
        match *self {
            StandardQuery::MultiTerm(ref q) => {
                q.search(searcher, collector)
            }
        }
    }

    fn explain(
        &self,
        searcher: &Searcher,
        doc_address: &DocAddress) -> tantivy_Error<Explanation> {
        match self {
            &StandardQuery::MultiTerm(ref q) => q.explain(searcher, doc_address)
        }
    }
}

fn compute_terms(field: Field, text: &str) -> Vec<Term> {
    let tokenizer = SimpleTokenizer::new();
    let mut tokens = Vec::new();
    let mut token_it = tokenizer.tokenize(text);
    loop {
        match token_it.next() {
            Some(token_str) => {
                tokens.push(Term::from_field_text(field, token_str));
            }
            None => { break; }
        }
    }
    tokens
}

impl QueryParser {
    pub fn new(schema: Schema,
               default_fields: Vec<Field>) -> QueryParser {
        QueryParser {
            schema: schema,
            default_fields: default_fields,
        }
    }

    fn transform_field_and_value(&self, field: Field, val: &str) -> Result<Vec<Term>, ParsingError> {
        let field_entry = self.schema.get_field_entry(field);
        Ok(match field_entry.field_type() {
            &FieldType::Str(_) => {
                compute_terms(field, val)
            },
            &FieldType::U32(_) => {
                let u32_parsed: u32 = try!(val
                    .parse::<u32>()
                    .map_err(|_| {
                        ParsingError::ExpectedU32(field_entry.name().clone(), String::from(val))
                    })
                );
                vec!(Term::from_field_u32(field, u32_parsed))
            }
        })
    }

    fn transform_literal(&self, literal: Literal) -> Result<Vec<Term>, ParsingError> {
        match literal {
            Literal::DefaultField(val) => {
                let mut terms = Vec::new();
                for &field in &self.default_fields {
                    let extra_terms = try!(self.transform_field_and_value(field, &val));
                    terms.extend_from_slice(&extra_terms);
                }
                Ok(terms)
            },
            Literal::WithField(field_name, val) => {
                match self.schema.get_field(&field_name) {
                    Some(field) => {
                        let terms = try!(self.transform_field_and_value(field, &val));
                        Ok(terms)
                    },
                    None => Err(ParsingError::FieldDoesNotExist(field_name))
                }
            }
        }
    }

    pub fn parse_query(&self, query: &str) -> Result<StandardQuery, ParsingError> {
        match parser(query_language).parse(query.trim()) {
            Ok(literals) => {
                let mut terms_result: Vec<(Occur, Term)> = Vec::new();
                for (occur, literal) in literals.0 {
                    let literal_terms = try!(self.transform_literal(literal));
                    terms_result
                        .extend(literal_terms
                        .into_iter()
                        .map(|term| (occur, term) ));
                }
                Ok(
                    StandardQuery::MultiTerm(
                        MultiTermQuery::from(terms_result)
                    )
                )
            }
            Err(_) => {
                Err(ParsingError::SyntaxError)
            }
        }
    }

}

#[derive(Debug, Eq, PartialEq)]
pub enum Literal {
    WithField(String, String),
    DefaultField(String),
}

// TODO handle as a specific case, having a single MUST_NOT term

pub fn query_language(input: State<&str>) -> ParseResult<Vec<(Occur, Literal)>, &str>
{
    let literal = || {
        let term_val = || {
            let word = many1(satisfy(|c: char| c.is_alphanumeric()));
            let phrase =
                (char('"'), many1(satisfy(|c| c != '"')), char('"'),)
                .map(|(_, s, _)| s);
            phrase.or(word)
        };

        let field = many1(letter());
        let term_query = (field, char(':'), term_val())
            .map(|(field,_, value)| Literal::WithField(field, value));
        let term_default_field = term_val().map(Literal::DefaultField);

        let occur = optional(char('-').or(char('+')))
            .map(|opt_c| {
                match opt_c {
                    Some('-') => Occur::MustNot,
                    Some('+') => Occur::Must,
                    _ => Occur::Should,
                }
            });
        (occur, try(term_query).or(term_default_field))
    };

    (sep_by(literal(), spaces()), eof())
    .map(|(first, _)| first)
    .parse_state(input)
}

#[cfg(test)]
mod tests {

    use combine::*;
    use schema::*;
    use query::MultiTermQuery;
    use query::Occur;
    use super::*;

    #[test]
    pub fn test_query_grammar() {
        let mut grammar_parser = parser(query_language);
        assert_eq!(grammar_parser.parse("abc:toto").unwrap().0,
            vec!(
                (Occur::Should, Literal::WithField(String::from("abc"), String::from("toto")))
            )
        );
        assert_eq!(grammar_parser.parse("+toto").unwrap().0,
            vec!(
                (Occur::Must, Literal::DefaultField(String::from("toto")))
            )
        );
        assert_eq!(
            grammar_parser.parse("\"some phrase query\"").unwrap().0,
            vec!(
                (Occur::Should, Literal::DefaultField(String::from("some phrase query"))),
            )
        );
        assert_eq!(
            grammar_parser.parse("field:\"some phrase query\"").unwrap().0,
            vec!(
                (Occur::Should, Literal::WithField(String::from("field"), String::from("some phrase query")))
        ));
        assert_eq!(grammar_parser.parse("field:\"some phrase query\" field:toto a").unwrap().0,
            vec!(
                (Occur::Should, Literal::WithField(String::from("field"), String::from("some phrase query"))),
                (Occur::Should, Literal::WithField(String::from("field"), String::from("toto"))),
                (Occur::Should, Literal::DefaultField(String::from("a"))),
            ));
        assert_eq!(grammar_parser.parse("field:\"a ! b\"").unwrap().0,
            vec!(
                (Occur::Should, Literal::WithField(String::from("field"), String::from("a ! b"))),
            ));
        assert_eq!(grammar_parser.parse("field:a9e3").unwrap().0,
            vec!(
                (Occur::Should, Literal::WithField(String::from("field"), String::from("a9e3")),)
            ));
        assert_eq!(grammar_parser.parse("a9e3").unwrap().0,
            vec!(
                (Occur::Should, Literal::DefaultField(String::from("a9e3"))),
            ));
        assert_eq!(grammar_parser.parse("field:タンタイビーって早い").unwrap().0,
            vec!(
                (Occur::Should, Literal::WithField(String::from("field"), String::from("タンタイビーって早い"))),
            ));
    }

    #[test]
    pub fn test_query_grammar_with_occur() {
        let mut query_parser = parser(query_language);
        assert_eq!(query_parser.parse("+abc:toto").unwrap().0,
            vec!(
                (Occur::Must, Literal::WithField(String::from("abc"), String::from("toto")))
            )
        );
        assert_eq!(query_parser.parse("+field:\"some phrase query\" -field:toto a").unwrap().0,
            vec!(
                (Occur::Must, Literal::WithField(String::from("field"), String::from("some phrase query"))),
                (Occur::MustNot, Literal::WithField(String::from("field"), String::from("toto"))),
                (Occur::Should, Literal::DefaultField(String::from("a"))),
            ));
    }

    #[test]
    pub fn test_invalid_queries() {
        let mut query_parser = parser(query_language);
        println!("{:?}", query_parser.parse("ab!c:"));
        assert!(query_parser.parse("ab!c:").is_err());
        assert!(query_parser.parse("").is_ok());
        assert!(query_parser.parse(":fval").is_err());
        assert!(query_parser.parse("field:").is_err());
        assert!(query_parser.parse(":field").is_err());
        assert!(query_parser.parse("f:@e!e").is_err());
        assert!(query_parser.parse("f:@e!e").is_err());
    }

    #[test]
    pub fn test_query_parser() {
        let mut schema_builder = SchemaBuilder::new();
        let text_field = schema_builder.add_text_field("text", STRING);
        let title_field = schema_builder.add_text_field("title", STRING);
        let author_field = schema_builder.add_text_field("author", STRING);
        let query_parser = QueryParser::new(schema_builder.build(), vec!(text_field, author_field));
        assert!(query_parser.parse_query("a:b").is_err());
        {
            let terms = vec!(Term::from_field_text(title_field, "abctitle"));
            let query = StandardQuery::MultiTerm(MultiTermQuery::from(terms));
            assert_eq!(
                query_parser.parse_query("title:abctitle").unwrap(),
                query
            );
        }
        {
            let terms = vec!(
                Term::from_field_text(text_field, "abctitle"),
                Term::from_field_text(author_field, "abctitle"),
            );
            let query = StandardQuery::MultiTerm(MultiTermQuery::from(terms));
            assert_eq!(
                query_parser.parse_query("abctitle").unwrap(),
                query
            );
        }
        {
            let terms = vec!(Term::from_field_text(title_field, "abctitle"));
            let query = StandardQuery::MultiTerm(MultiTermQuery::from(terms));
            assert_eq!(
                query_parser.parse_query("title:abctitle   ").unwrap(),
                query
            );
            assert_eq!(
                query_parser.parse_query("    title:abctitle").unwrap(),
                query
            );
        }
    }

}
<|endoftext|>


<commit_before>use std::cell::{RefCell, Ref, Cell};
use std::io::SeekFrom;
use std::io::prelude::*;
use std::mem;
use std::path::Path;

use curl::easy::{Easy, List};
use git2;
use rustc_serialize::hex::ToHex;
use serde_json;
use url::Url;

use core::{PackageId, SourceId};
use ops;
use sources::git;
use sources::registry::{RegistryData, RegistryConfig, INDEX_LOCK};
use util::network;
use util::{FileLock, Filesystem, LazyCell};
use util::{Config, CargoResult, ChainError, human, Sha256, ToUrl};
use util::errors::HttpError;

pub struct RemoteRegistry<'cfg> {
    index_path: Filesystem,
    cache_path: Filesystem,
    source_id: SourceId,
    config: &'cfg Config,
    handle: LazyCell<RefCell<Easy>>,
    tree: RefCell<Option<git2::Tree<'static>>>,
    repo: LazyCell<git2::Repository>,
    head: Cell<Option<git2::Oid>>,
}

impl<'cfg> RemoteRegistry<'cfg> {
    pub fn new(source_id: &SourceId, config: &'cfg Config, name: &str)
               -> RemoteRegistry<'cfg> {
        RemoteRegistry {
            index_path: config.registry_index_path().join(name),
            cache_path: config.registry_cache_path().join(name),
            source_id: source_id.clone(),
            config: config,
            tree: RefCell::new(None),
            handle: LazyCell::new(),
            repo: LazyCell::new(),
            head: Cell::new(None),
        }
    }

    fn easy(&self) -> CargoResult<&RefCell<Easy>> {
        self.handle.get_or_try_init(|| {
            ops::http_handle(self.config).map(RefCell::new)
        })
    }

    fn repo(&self) -> CargoResult<&git2::Repository> {
        self.repo.get_or_try_init(|| {
            let path = self.index_path.clone().into_path_unlocked();

            match git2::Repository::open(&path) {
                Ok(repo) => Ok(repo),
                Err(_) => {
                    self.index_path.create_dir()?;
                    let lock = self.index_path.open_rw(Path::new(INDEX_LOCK),
                                                       self.config,
                                                       "the registry index")?;
                    let _ = lock.remove_siblings();
                    Ok(git2::Repository::init_bare(&path)?)
                }
            }
        })
    }

    fn head(&self) -> CargoResult<git2::Oid> {
        if self.head.get().is_none() {
            let oid = self.repo()?.refname_to_id("refs/remotes/origin/master")?;
            self.head.set(Some(oid));
        }
        Ok(self.head.get().unwrap())
    }

    fn tree(&self) -> CargoResult<Ref<git2::Tree>> {
        {
            let tree = self.tree.borrow();
            if tree.is_some() {
                return Ok(Ref::map(tree, |s| s.as_ref().unwrap()))
            }
        }
        let repo = self.repo()?;
        let commit = repo.find_commit(self.head()?)?;
        let tree = commit.tree()?;

        // Unfortunately in libgit2 the tree objects look like they've got a
        // reference to the repository object which means that a tree cannot
        // outlive the repository that it came from. Here we want to cache this
        // tree, though, so to accomplish this we transmute it to a static
        // lifetime.
        //
        // Note that we don't actually hand out the static lifetime, instead we
        // only return a scoped one from this function. Additionally the repo
        // we loaded from (above) lives as long as this object
        // (`RemoteRegistry`) so we then just need to ensure that the tree is
        // destroyed first in the destructor, hence the destructor on
        // `RemoteRegistry` below.
        let tree = unsafe {
            mem::transmute::<git2::Tree, git2::Tree<'static>>(tree)
        };
        *self.tree.borrow_mut() = Some(tree);
        Ok(Ref::map(self.tree.borrow(), |s| s.as_ref().unwrap()))
    }
}

impl<'cfg> RegistryData for RemoteRegistry<'cfg> {
    fn index_path(&self) -> &Filesystem {
        &self.index_path
    }

    fn load(&self, _root: &Path, path: &Path) -> CargoResult<Vec<u8>> {
        // Note that the index calls this method and the filesystem is locked
        // in the index, so we don't need to worry about an `update_index`
        // happening in a different process.
        let repo = self.repo()?;
        let tree = self.tree()?;
        let entry = tree.get_path(path)?;
        let object = entry.to_object(&repo)?;
        let blob = match object.as_blob() {
            Some(blob) => blob,
            None => bail!("path `{}` is not a blob in the git repo", path.display()),
        };
        Ok(blob.content().to_vec())
    }

    fn config(&mut self) -> CargoResult<Option<RegistryConfig>> {
        self.repo()?; // create intermediate dirs and initialize the repo
        let _lock = self.index_path.open_ro(Path::new(INDEX_LOCK),
                                            self.config,
                                            "the registry index")?;
        let json = self.load(Path::new(""), Path::new("config.json"))?;
        let config = serde_json::from_slice(&json)?;
        Ok(Some(config))
    }

    fn update_index(&mut self) -> CargoResult<()> {
        // Ensure that we'll actually be able to acquire an HTTP handle later on
        // once we start trying to download crates. This will weed out any
        // problems with `.cargo/config` configuration related to HTTP.
        //
        // This way if there's a problem the error gets printed before we even
        // hit the index, which may not actually read this configuration.
        ops::http_handle(self.config)?;

        let repo = self.repo()?;
        let _lock = self.index_path.open_rw(Path::new(INDEX_LOCK),
                                            self.config,
                                            "the registry index")?;
        self.config.shell().status("Updating",
             format!("registry `{}`", self.source_id.url()))?;

        if self.source_id.url().host_str() == Some("github.com") {
            if let Ok(oid) = self.head() {
                let mut handle = self.easy()?.borrow_mut();
                debug!("attempting github fast path for {}",
                       self.source_id.url());
                if github_up_to_date(&mut handle, self.source_id.url(), &oid) {
                    return Ok(())
                }
                debug!("fast path failed, falling back to a git fetch");
            }
        }

        // git fetch origin master
        let url = self.source_id.url().to_string();
        let refspec = "refs/heads/master:refs/remotes/origin/master";
        git::fetch(&repo, &url, refspec, self.config).chain_error(|| {
            human(format!("failed to fetch `{}`", url))
        })?;
        self.head.set(None);
        *self.tree.borrow_mut() = None;
        Ok(())
    }

    fn download(&mut self, pkg: &PackageId, checksum: &str)
                -> CargoResult<FileLock> {
        let filename = format!("{}-{}.crate", pkg.name(), pkg.version());
        let path = Path::new(&filename);

        // Attempt to open an read-only copy first to avoid an exclusive write
        // lock and also work with read-only filesystems. Note that we check the
        // length of the file like below to handle interrupted downloads.
        //
        // If this fails then we fall through to the exclusive path where we may
        // have to redownload the file.
        if let Ok(dst) = self.cache_path.open_ro(path, self.config, &filename) {
            let meta = dst.file().metadata()?;
            if meta.len() > 0 {
                return Ok(dst)
            }
        }
        let mut dst = self.cache_path.open_rw(path, self.config, &filename)?;
        let meta = dst.file().metadata()?;
        if meta.len() > 0 {
            return Ok(dst)
        }
        self.config.shell().status("Downloading", pkg)?;

        let config = self.config()?.unwrap();
        let mut url = config.dl.to_url()?;
        url.path_segments_mut().unwrap()
            .push(pkg.name())
            .push(&pkg.version().to_string())
            .push("download");

        // TODO: don't download into memory, but ensure that if we ctrl-c a
        //       download we should resume either from the start or the middle
        //       on the next time
        let url = url.to_string();
        let mut handle = self.easy()?.borrow_mut();
        handle.get(true)?;
        handle.url(&url)?;
        handle.follow_location(true)?;
        let mut state = Sha256::new();
        let mut body = Vec::new();
        network::with_retry(self.config, || {
            state = Sha256::new();
            body = Vec::new();
            {
                let mut handle = handle.transfer();
                handle.write_function(|buf| {
                    state.update(buf);
                    body.extend_from_slice(buf);
                    Ok(buf.len())
                })?;
                handle.perform()?;
            }
            let code = handle.response_code()?;
            if code != 200 && code != 0 {
                let url = handle.effective_url()?.unwrap_or(&url);
                Err(HttpError::Not200(code, url.to_string()))
            } else {
                Ok(())
            }
        })?;

        // Verify what we just downloaded
        if state.finish().to_hex() != checksum {
            bail!("failed to verify the checksum of `{}`", pkg)
        }

        dst.write_all(&body)?;
        dst.seek(SeekFrom::Start(0))?;
        Ok(dst)
    }
}

impl<'cfg> Drop for RemoteRegistry<'cfg> {
    fn drop(&mut self) {
        // Just be sure to drop this before our other fields
        self.tree.borrow_mut().take();
    }
}

/// Updating the index is done pretty regularly so we want it to be as fast as
/// possible. For registries hosted on github (like the crates.io index) there's
/// a fast path available to use [1] to tell us that there's no updates to be
/// made.
///
/// This function will attempt to hit that fast path and verify that the `oid`
/// is actually the current `master` branch of the repository. If `true` is
/// returned then no update needs to be performed, but if `false` is returned
/// then the standard update logic still needs to happen.
///
/// [1]: https://developer.github.com/v3/repos/commits/#get-the-sha-1-of-a-commit-reference
///
/// Note that this function should never cause an actual failure because it's
/// just a fast path. As a result all errors are ignored in this function and we
/// just return a `bool`. Any real errors will be reported through the normal
/// update path above.
fn github_up_to_date(handle: &mut Easy, url: &Url, oid: &git2::Oid) -> bool {
    macro_rules! try {
        ($e:expr) => (match $e {
            Some(e) => e,
            None => return false,
        })
    }

    // This expects github urls in the form `github.com/user/repo` and nothing
    // else
    let mut pieces = try!(url.path_segments());
    let username = try!(pieces.next());
    let repo = try!(pieces.next());
    if pieces.next().is_some() {
        return false
    }

    let url = format!("https://api.github.com/repos/{}/{}/commits/master",
                      username, repo);
    try!(handle.get(true).ok());
    try!(handle.url(&url).ok());
    try!(handle.useragent("cargo").ok());
    let mut headers = List::new();
    try!(headers.append("Accept: application/vnd.github.3.sha").ok());
    try!(headers.append(&format!("If-None-Match: \"{}\"", oid)).ok());
    try!(handle.http_headers(headers).ok());
    try!(handle.perform().ok());

    try!(handle.response_code().ok()) == 304
}
<commit_msg>Auto merge of #4051 - alexcrichton:fix-flaky-test, r=alexcrichton<commit_after>use std::cell::{RefCell, Ref, Cell};
use std::io::SeekFrom;
use std::io::prelude::*;
use std::mem;
use std::path::Path;

use curl::easy::{Easy, List};
use git2;
use rustc_serialize::hex::ToHex;
use serde_json;
use url::Url;

use core::{PackageId, SourceId};
use ops;
use sources::git;
use sources::registry::{RegistryData, RegistryConfig, INDEX_LOCK};
use util::network;
use util::{FileLock, Filesystem, LazyCell};
use util::{Config, CargoResult, ChainError, human, Sha256, ToUrl};
use util::errors::HttpError;

pub struct RemoteRegistry<'cfg> {
    index_path: Filesystem,
    cache_path: Filesystem,
    source_id: SourceId,
    config: &'cfg Config,
    handle: LazyCell<RefCell<Easy>>,
    tree: RefCell<Option<git2::Tree<'static>>>,
    repo: LazyCell<git2::Repository>,
    head: Cell<Option<git2::Oid>>,
}

impl<'cfg> RemoteRegistry<'cfg> {
    pub fn new(source_id: &SourceId, config: &'cfg Config, name: &str)
               -> RemoteRegistry<'cfg> {
        RemoteRegistry {
            index_path: config.registry_index_path().join(name),
            cache_path: config.registry_cache_path().join(name),
            source_id: source_id.clone(),
            config: config,
            tree: RefCell::new(None),
            handle: LazyCell::new(),
            repo: LazyCell::new(),
            head: Cell::new(None),
        }
    }

    fn easy(&self) -> CargoResult<&RefCell<Easy>> {
        self.handle.get_or_try_init(|| {
            ops::http_handle(self.config).map(RefCell::new)
        })
    }

    fn repo(&self) -> CargoResult<&git2::Repository> {
        self.repo.get_or_try_init(|| {
            let path = self.index_path.clone().into_path_unlocked();

            // Fast path without a lock
            if let Ok(repo) = git2::Repository::open(&path) {
                return Ok(repo)
            }

            // Ok, now we need to lock and try the whole thing over again.
            let lock = self.index_path.open_rw(Path::new(INDEX_LOCK),
                                               self.config,
                                               "the registry index")?;
            match git2::Repository::open(&path) {
                Ok(repo) => Ok(repo),
                Err(_) => {
                    let _ = lock.remove_siblings();
                    Ok(git2::Repository::init_bare(&path)?)
                }
            }
        })
    }

    fn head(&self) -> CargoResult<git2::Oid> {
        if self.head.get().is_none() {
            let oid = self.repo()?.refname_to_id("refs/remotes/origin/master")?;
            self.head.set(Some(oid));
        }
        Ok(self.head.get().unwrap())
    }

    fn tree(&self) -> CargoResult<Ref<git2::Tree>> {
        {
            let tree = self.tree.borrow();
            if tree.is_some() {
                return Ok(Ref::map(tree, |s| s.as_ref().unwrap()))
            }
        }
        let repo = self.repo()?;
        let commit = repo.find_commit(self.head()?)?;
        let tree = commit.tree()?;

        // Unfortunately in libgit2 the tree objects look like they've got a
        // reference to the repository object which means that a tree cannot
        // outlive the repository that it came from. Here we want to cache this
        // tree, though, so to accomplish this we transmute it to a static
        // lifetime.
        //
        // Note that we don't actually hand out the static lifetime, instead we
        // only return a scoped one from this function. Additionally the repo
        // we loaded from (above) lives as long as this object
        // (`RemoteRegistry`) so we then just need to ensure that the tree is
        // destroyed first in the destructor, hence the destructor on
        // `RemoteRegistry` below.
        let tree = unsafe {
            mem::transmute::<git2::Tree, git2::Tree<'static>>(tree)
        };
        *self.tree.borrow_mut() = Some(tree);
        Ok(Ref::map(self.tree.borrow(), |s| s.as_ref().unwrap()))
    }
}

impl<'cfg> RegistryData for RemoteRegistry<'cfg> {
    fn index_path(&self) -> &Filesystem {
        &self.index_path
    }

    fn load(&self, _root: &Path, path: &Path) -> CargoResult<Vec<u8>> {
        // Note that the index calls this method and the filesystem is locked
        // in the index, so we don't need to worry about an `update_index`
        // happening in a different process.
        let repo = self.repo()?;
        let tree = self.tree()?;
        let entry = tree.get_path(path)?;
        let object = entry.to_object(&repo)?;
        let blob = match object.as_blob() {
            Some(blob) => blob,
            None => bail!("path `{}` is not a blob in the git repo", path.display()),
        };
        Ok(blob.content().to_vec())
    }

    fn config(&mut self) -> CargoResult<Option<RegistryConfig>> {
        self.repo()?; // create intermediate dirs and initialize the repo
        let _lock = self.index_path.open_ro(Path::new(INDEX_LOCK),
                                            self.config,
                                            "the registry index")?;
        let json = self.load(Path::new(""), Path::new("config.json"))?;
        let config = serde_json::from_slice(&json)?;
        Ok(Some(config))
    }

    fn update_index(&mut self) -> CargoResult<()> {
        // Ensure that we'll actually be able to acquire an HTTP handle later on
        // once we start trying to download crates. This will weed out any
        // problems with `.cargo/config` configuration related to HTTP.
        //
        // This way if there's a problem the error gets printed before we even
        // hit the index, which may not actually read this configuration.
        ops::http_handle(self.config)?;

        let repo = self.repo()?;
        let _lock = self.index_path.open_rw(Path::new(INDEX_LOCK),
                                            self.config,
                                            "the registry index")?;
        self.config.shell().status("Updating",
             format!("registry `{}`", self.source_id.url()))?;
        let mut needs_fetch = true;

        if self.source_id.url().host_str() == Some("github.com") {
            if let Ok(oid) = self.head() {
                let mut handle = self.easy()?.borrow_mut();
                debug!("attempting github fast path for {}",
                       self.source_id.url());
                if github_up_to_date(&mut handle, self.source_id.url(), &oid) {
                    needs_fetch = false;
                } else {
                    debug!("fast path failed, falling back to a git fetch");
                }
            }
        }

        if needs_fetch {
            // git fetch origin master
            let url = self.source_id.url().to_string();
            let refspec = "refs/heads/master:refs/remotes/origin/master";
            git::fetch(&repo, &url, refspec, self.config).chain_error(|| {
                human(format!("failed to fetch `{}`", url))
            })?;
        }
        self.head.set(None);
        *self.tree.borrow_mut() = None;
        Ok(())
    }

    fn download(&mut self, pkg: &PackageId, checksum: &str)
                -> CargoResult<FileLock> {
        let filename = format!("{}-{}.crate", pkg.name(), pkg.version());
        let path = Path::new(&filename);

        // Attempt to open an read-only copy first to avoid an exclusive write
        // lock and also work with read-only filesystems. Note that we check the
        // length of the file like below to handle interrupted downloads.
        //
        // If this fails then we fall through to the exclusive path where we may
        // have to redownload the file.
        if let Ok(dst) = self.cache_path.open_ro(path, self.config, &filename) {
            let meta = dst.file().metadata()?;
            if meta.len() > 0 {
                return Ok(dst)
            }
        }
        let mut dst = self.cache_path.open_rw(path, self.config, &filename)?;
        let meta = dst.file().metadata()?;
        if meta.len() > 0 {
            return Ok(dst)
        }
        self.config.shell().status("Downloading", pkg)?;

        let config = self.config()?.unwrap();
        let mut url = config.dl.to_url()?;
        url.path_segments_mut().unwrap()
            .push(pkg.name())
            .push(&pkg.version().to_string())
            .push("download");

        // TODO: don't download into memory, but ensure that if we ctrl-c a
        //       download we should resume either from the start or the middle
        //       on the next time
        let url = url.to_string();
        let mut handle = self.easy()?.borrow_mut();
        handle.get(true)?;
        handle.url(&url)?;
        handle.follow_location(true)?;
        let mut state = Sha256::new();
        let mut body = Vec::new();
        network::with_retry(self.config, || {
            state = Sha256::new();
            body = Vec::new();
            {
                let mut handle = handle.transfer();
                handle.write_function(|buf| {
                    state.update(buf);
                    body.extend_from_slice(buf);
                    Ok(buf.len())
                })?;
                handle.perform()?;
            }
            let code = handle.response_code()?;
            if code != 200 && code != 0 {
                let url = handle.effective_url()?.unwrap_or(&url);
                Err(HttpError::Not200(code, url.to_string()))
            } else {
                Ok(())
            }
        })?;

        // Verify what we just downloaded
        if state.finish().to_hex() != checksum {
            bail!("failed to verify the checksum of `{}`", pkg)
        }

        dst.write_all(&body)?;
        dst.seek(SeekFrom::Start(0))?;
        Ok(dst)
    }
}

impl<'cfg> Drop for RemoteRegistry<'cfg> {
    fn drop(&mut self) {
        // Just be sure to drop this before our other fields
        self.tree.borrow_mut().take();
    }
}

/// Updating the index is done pretty regularly so we want it to be as fast as
/// possible. For registries hosted on github (like the crates.io index) there's
/// a fast path available to use [1] to tell us that there's no updates to be
/// made.
///
/// This function will attempt to hit that fast path and verify that the `oid`
/// is actually the current `master` branch of the repository. If `true` is
/// returned then no update needs to be performed, but if `false` is returned
/// then the standard update logic still needs to happen.
///
/// [1]: https://developer.github.com/v3/repos/commits/#get-the-sha-1-of-a-commit-reference
///
/// Note that this function should never cause an actual failure because it's
/// just a fast path. As a result all errors are ignored in this function and we
/// just return a `bool`. Any real errors will be reported through the normal
/// update path above.
fn github_up_to_date(handle: &mut Easy, url: &Url, oid: &git2::Oid) -> bool {
    macro_rules! try {
        ($e:expr) => (match $e {
            Some(e) => e,
            None => return false,
        })
    }

    // This expects github urls in the form `github.com/user/repo` and nothing
    // else
    let mut pieces = try!(url.path_segments());
    let username = try!(pieces.next());
    let repo = try!(pieces.next());
    if pieces.next().is_some() {
        return false
    }

    let url = format!("https://api.github.com/repos/{}/{}/commits/master",
                      username, repo);
    try!(handle.get(true).ok());
    try!(handle.url(&url).ok());
    try!(handle.useragent("cargo").ok());
    let mut headers = List::new();
    try!(headers.append("Accept: application/vnd.github.3.sha").ok());
    try!(headers.append(&format!("If-None-Match: \"{}\"", oid)).ok());
    try!(handle.http_headers(headers).ok());
    try!(handle.perform().ok());

    try!(handle.response_code().ok()) == 304
}
<|endoftext|>


<commit_before>//! Block by block CAST

use std::{default, iter, fmt};
use std::collections::LinkedList;

use super::c_simple;
use super::c_simple::{CAST, CASTNode};
use frontend::radeco_containers::RadecoFunction;
use petgraph::graph::{Graph, NodeIndex, EdgeIndex};
use petgraph::visit::EdgeRef;
use petgraph::EdgeDirection;
use petgraph::Direction;

#[derive(Debug, Clone, PartialEq)]
enum SimpleCASTNode {
    Action(ActionNode),
    Value(ValueNode),
}

#[derive(Debug, Clone, PartialEq)]
enum ActionNode {
    Assignment,
    Call,
    Return,
    If,
    Goto,
}

// TODO
#[derive(Debug, Clone, PartialEq)]
enum ValueNode {
    /// The string is the name of variable
    Variable(String),
    Constant,
}

#[derive(Debug, Clone, PartialEq)]
enum SimpleCASTEdge {
    Action(ActionEdge),
    Value(ValueEdge),
}

#[derive(Debug, Clone, PartialEq)]
enum ActionEdge {
    IfThen,
    IfElse,
    FuncCall,
    FuncRet,
    Normal,
}

#[derive(Debug, Clone, PartialEq)]
enum ValueEdge {
    AssignSrc,
    AssignDst,
    Arg(u8),
    GotoDst,
}

struct SimpleCAST {
    /// Name of function of this AST
    fname: String,
    entry: NodeIndex,
    ast: Graph<SimpleCASTNode, SimpleCASTEdge>,
}

impl SimpleCASTNode {
    fn is_exit(&self) -> bool {
        match self {
            &SimpleCASTNode::Action(ActionNode::Return) => true,
            _ => false,
        }
    }
}

impl SimpleCAST {

    fn next_actions(&self, idx: NodeIndex) -> Vec<NodeIndex> {
        self.ast.edges_directed(idx, Direction::Outgoing)
            .into_iter()
            .filter_map(|e| {
                match e.weight() {
                    &SimpleCASTEdge::Action(_) => Some(e.target()),
                    _ => None,
                }
            }).collect()
    }

    /// Returns a pair (IfThen, IfElse)
    fn branch(&self, idx: NodeIndex) -> Option<(NodeIndex, Option<NodeIndex>)> {
        if self.ast.node_weight(idx) != Some(&SimpleCASTNode::Action(ActionNode::If)) {
            return None;
        }
        let ns = self.next_actions(idx);
        // TODO This implementation is not correct
        // specify node by matching IfThen, IfElse
        if ns.len() == 2 {
            Some((ns[0], Some(ns[1])))
        } else if ns.len() <= 1 {
            Some((ns[0], None))
        } else {
            radeco_warn!("ns.len() should return less than or equal 2");
            None
        }
    }

    /// Returns destination of goto statement
    fn goto(&self, idx: NodeIndex) -> Option<NodeIndex> {
        if self.ast.node_weight(idx) != Some(&SimpleCASTNode::Action(ActionNode::Goto))  {
            return None;
        };
        let goto_dsts = self.ast.edges_directed(idx, Direction::Outgoing)
            .into_iter()
            .filter_map(|e| {
                match e.weight() {
                    &SimpleCASTEdge::Value(ValueEdge::GotoDst) => Some(e.target()),
                    _ => None,
                }
            }).collect::<Vec<_>>();
        if goto_dsts.len() != 1 {
            radeco_warn!("Destination of Goto has more than 1 labels");
            return None;
        };
        goto_dsts.first().map(|n| n.clone())
    }

    /// Returns a pair (Dst, Src) which represents Dst = Src
    fn assignment(&self, idx: NodeIndex) -> Option<(NodeIndex, NodeIndex)> {
        if self.ast.node_weight(idx) != Some(&SimpleCASTNode::Action(ActionNode::Assignment)) {
            return None;
        }
        let src = self.ast.edges_directed(idx, Direction::Outgoing)
            .into_iter()
            .filter(|e| e.weight() == &SimpleCASTEdge::Value(ValueEdge::AssignSrc))
            .map(|e| e.target())
            .next();
        let dst = self.ast.edges_directed(idx, Direction::Outgoing)
            .into_iter()
            .filter(|e| e.weight() == &SimpleCASTEdge::Value(ValueEdge::AssignDst))
            .map(|e| e.target())
            .next();
        if src.is_some() && dst.is_some() {
            return None;
        }
        Some((dst.unwrap(), src.unwrap()))
    }

    /// Returns arguments of function call
    fn args_call(&self, idx: NodeIndex) -> Option<Vec<NodeIndex>> {
        if self.ast.node_weight(idx) != Some(&SimpleCASTNode::Action(ActionNode::Call)) {
            return None;
        }
        let mut args = self.ast.edges_directed(idx, Direction::Outgoing)
            .into_iter()
            .filter_map(|e| {
                match e.weight() {
                    &SimpleCASTEdge::Value(ValueEdge::Arg(o)) => Some((o, e.target())),
                    _ => None,
                }
            }).collect::<Vec<_>>();
        args.sort_by_key(|k| k.0);
        let ret = args.into_iter()
            .map(|(_, b)| b)
            .collect();
        Some(ret)
    }

    fn to_c_ast(&self) -> CAST {
        let mut c_ast = CAST::new(&self.fname);
        let mut queue = LinkedList::new();
        queue.push_back(self.entry);
        while let Some(current_node) = queue.pop_front() {
            // XXX ?
            for n in self.next_actions(current_node) {
                queue.push_back(n);
            }
            match self.ast.node_weight(current_node) {
                Some(&SimpleCASTNode::Action(ActionNode::Assignment)) => {
                    if let Some((dst, src)) = self.assignment(current_node) {
                        // TODO insert node
                    } else {
                        // TODO
                        radeco_err!("Something wrong");
                    }
                },
                Some(&SimpleCASTNode::Action(ActionNode::Call)) => {
                    let args = self.args_call(current_node);
                    // TODO insert node, args
                },
                Some(&SimpleCASTNode::Action(ActionNode::Return)) => {
                    // TODO insert node
                },
                Some(&SimpleCASTNode::Action(ActionNode::If)) => {
                    // TODO insert node
                    if let Some((if_then, if_else)) = self.branch(current_node) {
                        // TODO
                    }
                },
                Some(&SimpleCASTNode::Action(ActionNode::Goto)) => {
                    if let Some(dst) = self.goto(current_node) {
                        // TODO insert label, gotos
                    }
                },
                _ => {},
            };
        }
        c_ast
    }

}
<commit_msg>Fix SimpleCAST::branch<commit_after>//! Block by block CAST

use std::{default, iter, fmt};
use std::collections::LinkedList;

use super::c_simple;
use super::c_simple::{CAST, CASTNode};
use frontend::radeco_containers::RadecoFunction;
use petgraph::graph::{Graph, NodeIndex, EdgeIndex, Edges, EdgeReference};
use petgraph::visit::EdgeRef;
use petgraph::{EdgeDirection, Direction, Directed};

#[derive(Debug, Clone, PartialEq)]
enum SimpleCASTNode {
    Action(ActionNode),
    Value(ValueNode),
}

#[derive(Debug, Clone, PartialEq)]
enum ActionNode {
    Assignment,
    Call,
    Return,
    If,
    Goto,
}

// TODO
#[derive(Debug, Clone, PartialEq)]
enum ValueNode {
    /// The string is the name of variable
    Variable(String),
    Constant,
}

#[derive(Debug, Clone, PartialEq)]
enum SimpleCASTEdge {
    Action(ActionEdge),
    Value(ValueEdge),
}

#[derive(Debug, Clone, PartialEq)]
enum ActionEdge {
    IfThen,
    IfElse,
    FuncCall,
    FuncRet,
    Normal,
}

#[derive(Debug, Clone, PartialEq)]
enum ValueEdge {
    AssignSrc,
    AssignDst,
    Arg(u8),
    GotoDst,
}

struct SimpleCAST {
    /// Name of function of this AST
    fname: String,
    entry: NodeIndex,
    ast: Graph<SimpleCASTNode, SimpleCASTEdge>,
}

impl SimpleCASTNode {
    fn is_exit(&self) -> bool {
        match self {
            &SimpleCASTNode::Action(ActionNode::Return) => true,
            _ => false,
        }
    }
}

/// Returns nodes which is connected with given type of edge
fn neighbors_by_edge(edges: &Vec<EdgeReference<SimpleCASTEdge>>, ty: &SimpleCASTEdge) -> Vec<NodeIndex> {
    edges.iter().filter(|e| (*e).weight() == ty)
        .map(|e| e.target())
        .collect()
}

impl SimpleCAST {

    fn next_actions(&self, idx: NodeIndex) -> Vec<NodeIndex> {
        self.ast.edges_directed(idx, Direction::Outgoing)
            .into_iter()
            .filter_map(|e| {
                match e.weight() {
                    &SimpleCASTEdge::Action(_) => Some(e.target()),
                    _ => None,
                }
            }).collect()
    }

    /// Returns a pair (IfThen, IfElse)
    fn branch(&self, idx: NodeIndex) -> Option<(NodeIndex, Option<NodeIndex>)> {
        if self.ast.node_weight(idx) != Some(&SimpleCASTNode::Action(ActionNode::If)) {
            return None;
        }
        let ns = self.ast.edges_directed(idx, Direction::Outgoing).into_iter().collect();
        let if_then = neighbors_by_edge(&ns, &SimpleCASTEdge::Action(ActionEdge::IfThen))
            .first().map(|e| e.clone());
        let if_else = neighbors_by_edge(&ns, &SimpleCASTEdge::Action(ActionEdge::IfElse))
            .first().map(|e| e.clone());
        if if_then.is_some() {
            Some((if_then.unwrap(), if_else))
        } else {
            None
        }
    }

    /// Returns destination of goto statement
    fn goto(&self, idx: NodeIndex) -> Option<NodeIndex> {
        if self.ast.node_weight(idx) != Some(&SimpleCASTNode::Action(ActionNode::Goto))  {
            return None;
        };
        let goto_dsts = self.ast.edges_directed(idx, Direction::Outgoing)
            .into_iter()
            .filter_map(|e| {
                match e.weight() {
                    &SimpleCASTEdge::Value(ValueEdge::GotoDst) => Some(e.target()),
                    _ => None,
                }
            }).collect::<Vec<_>>();
        if goto_dsts.len() != 1 {
            radeco_warn!("Destination of Goto has more than 1 labels");
            return None;
        };
        goto_dsts.first().map(|n| n.clone())
    }

    /// Returns a pair (Dst, Src) which represents Dst = Src
    fn assignment(&self, idx: NodeIndex) -> Option<(NodeIndex, NodeIndex)> {
        if self.ast.node_weight(idx) != Some(&SimpleCASTNode::Action(ActionNode::Assignment)) {
            return None;
        }
        let ns = self.ast.edges_directed(idx, Direction::Outgoing).into_iter().collect();
        let src = neighbors_by_edge(&ns, &SimpleCASTEdge::Value(ValueEdge::AssignSrc))
            .first().map(|e| e.clone());
        let dst = neighbors_by_edge(&ns, &SimpleCASTEdge::Value(ValueEdge::AssignDst))
            .first().map(|e| e.clone());
        if src.is_some() && dst.is_some() {
            return None;
        }
        Some((dst.unwrap(), src.unwrap()))
    }

    /// Returns arguments of function call
    fn args_call(&self, idx: NodeIndex) -> Option<Vec<NodeIndex>> {
        if self.ast.node_weight(idx) != Some(&SimpleCASTNode::Action(ActionNode::Call)) {
            return None;
        }
        let mut args = self.ast.edges_directed(idx, Direction::Outgoing)
            .into_iter()
            .filter_map(|e| {
                match e.weight() {
                    &SimpleCASTEdge::Value(ValueEdge::Arg(o)) => Some((o, e.target())),
                    _ => None,
                }
            }).collect::<Vec<_>>();
        args.sort_by_key(|k| k.0);
        let ret = args.into_iter()
            .map(|(_, b)| b)
            .collect();
        Some(ret)
    }

    fn to_c_ast(&self) -> CAST {
        let mut c_ast = CAST::new(&self.fname);
        let mut queue = LinkedList::new();
        queue.push_back(self.entry);
        while let Some(current_node) = queue.pop_front() {
            // XXX ?
            for n in self.next_actions(current_node) {
                queue.push_back(n);
            }
            match self.ast.node_weight(current_node) {
                Some(&SimpleCASTNode::Action(ActionNode::Assignment)) => {
                    if let Some((dst, src)) = self.assignment(current_node) {
                        // TODO insert node
                    } else {
                        // TODO
                        radeco_err!("Something wrong");
                    }
                },
                Some(&SimpleCASTNode::Action(ActionNode::Call)) => {
                    let args = self.args_call(current_node);
                    // TODO insert node, args
                },
                Some(&SimpleCASTNode::Action(ActionNode::Return)) => {
                    // TODO insert node
                },
                Some(&SimpleCASTNode::Action(ActionNode::If)) => {
                    // TODO insert node
                    if let Some((if_then, if_else)) = self.branch(current_node) {
                        // TODO
                    }
                },
                Some(&SimpleCASTNode::Action(ActionNode::Goto)) => {
                    if let Some(dst) = self.goto(current_node) {
                        // TODO insert label, gotos
                    }
                },
                _ => {},
            };
        }
        c_ast
    }

}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![feature(borrow_state)]
#![feature(box_raw)]
#![feature(box_syntax)]
#![feature(convert)]
#![feature(core_intrinsics)]
#![feature(filling_drop)]
#![feature(iter_arith)]
#![feature(link_args)]
#![feature(negate_unsigned)]
#![feature(plugin)]
#![feature(str_utf16)]
#![feature(thread_local)]
#![feature(unicode)]
#![feature(unsafe_no_drop_flag)]

#![allow(non_camel_case_types)]

#![plugin(plugins)]

#[macro_use]
extern crate log;

extern crate servo;
extern crate compositing;

extern crate azure;
extern crate euclid;
extern crate gfx;
extern crate gleam;
extern crate glutin_app;
extern crate js;
extern crate layers;
extern crate png;
extern crate rustc_unicode;
extern crate script;
extern crate script_traits;

extern crate net;
extern crate msg;
extern crate util;
extern crate style;
extern crate stb_image;

extern crate libc;
extern crate url as std_url;

#[cfg(target_os="macos")]
#[link_args="-Xlinker -undefined -Xlinker dynamic_lookup"]
extern { }

#[cfg(target_os="macos")]
extern crate cgl;
#[cfg(target_os="macos")]
extern crate cocoa;
#[cfg(target_os="macos")]
extern crate core_foundation;
#[cfg(target_os="macos")]
extern crate core_graphics;
#[cfg(target_os="macos")]
extern crate core_text;
#[cfg(target_os="macos")]
#[macro_use]
extern crate objc;
#[cfg(target_os="linux")] extern crate x11;

// Must come first.
pub mod macros;

pub mod browser;
pub mod browser_host;
pub mod command_line;
pub mod cookie;
pub mod core;
pub mod drag_data;
pub mod eutil;
pub mod frame;
pub mod interfaces;
pub mod print_settings;
pub mod process_message;
pub mod render_handler;
pub mod request;
pub mod request_context;
pub mod response;
pub mod stream;
pub mod string;
pub mod string_list;
pub mod string_map;
pub mod string_multimap;
pub mod stubs;
pub mod switches;
pub mod task;
pub mod types;
pub mod urlrequest;
pub mod v8;
pub mod values;
pub mod window;
pub mod wrappers;
pub mod xml_reader;
pub mod zip_reader;
<commit_msg>Auto merge of #6485 - Ms2ger:thread_local, r=metajack<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![feature(borrow_state)]
#![feature(box_raw)]
#![feature(box_syntax)]
#![feature(convert)]
#![feature(core_intrinsics)]
#![feature(filling_drop)]
#![feature(iter_arith)]
#![feature(link_args)]
#![feature(negate_unsigned)]
#![feature(plugin)]
#![feature(str_utf16)]
#![feature(unicode)]
#![feature(unsafe_no_drop_flag)]

#![allow(non_camel_case_types)]

#![plugin(plugins)]

#[macro_use]
extern crate log;

extern crate servo;
extern crate compositing;

extern crate azure;
extern crate euclid;
extern crate gfx;
extern crate gleam;
extern crate glutin_app;
extern crate js;
extern crate layers;
extern crate png;
extern crate rustc_unicode;
extern crate script;
extern crate script_traits;

extern crate net;
extern crate msg;
extern crate util;
extern crate style;
extern crate stb_image;

extern crate libc;
extern crate url as std_url;

#[cfg(target_os="macos")]
#[link_args="-Xlinker -undefined -Xlinker dynamic_lookup"]
extern { }

#[cfg(target_os="macos")]
extern crate cgl;
#[cfg(target_os="macos")]
extern crate cocoa;
#[cfg(target_os="macos")]
extern crate core_foundation;
#[cfg(target_os="macos")]
extern crate core_graphics;
#[cfg(target_os="macos")]
extern crate core_text;
#[cfg(target_os="macos")]
#[macro_use]
extern crate objc;
#[cfg(target_os="linux")] extern crate x11;

// Must come first.
pub mod macros;

pub mod browser;
pub mod browser_host;
pub mod command_line;
pub mod cookie;
pub mod core;
pub mod drag_data;
pub mod eutil;
pub mod frame;
pub mod interfaces;
pub mod print_settings;
pub mod process_message;
pub mod render_handler;
pub mod request;
pub mod request_context;
pub mod response;
pub mod stream;
pub mod string;
pub mod string_list;
pub mod string_map;
pub mod string_multimap;
pub mod stubs;
pub mod switches;
pub mod task;
pub mod types;
pub mod urlrequest;
pub mod v8;
pub mod values;
pub mod window;
pub mod wrappers;
pub mod xml_reader;
pub mod zip_reader;
<|endoftext|>


<commit_before>import geom::*;
import comm::*;
import layout::display_list::*;

enum msg {
    draw(display_list),
    exit(comm::chan<()>)
}

fn renderer(osmain: chan<osmain::msg>) -> chan<msg> {
    task::spawn_listener::<msg> {|po|
        listen {|draw_target_ch|
            osmain.send(osmain::get_draw_target(draw_target_ch));
            let draw_target = draw_target_ch.recv();

            let mut exit_confirm_ch = none;
            loop {
                alt po.recv() {
                  draw(display_list) {

                    draw_display_list(draw_target, display_list);

                    listen {|draw_ch|
                        osmain.send(osmain::draw(draw_ch));
                        draw_ch.recv();
                    }
                  }
                  exit(response_ch) {
                    exit_confirm_ch = some(response_ch);
                    break;
                  }
                }
            }

            assert exit_confirm_ch.is_some();
            exit_confirm_ch.get().send(());
        }
    }
}

fn draw_display_list(
    draw_target: AzDrawTargetRef,
    display_list: display_list
) {
    clear(draw_target);

    for display_list.each {|item|
        let bounds = (*item).bounds;

        let red_color = {
            r: 1f as AzFloat,
            g: 0f as AzFloat,
            b: 0f as AzFloat,
            a: 0.5f as AzFloat
        };
        let red_pattern = AzCreateColorPattern(ptr::addr_of(red_color));

        let red_rect = {
            x: au_to_int(bounds.origin.x) as AzFloat,
            y: au_to_int(bounds.origin.y) as AzFloat,
            width: au_to_int(bounds.size.width) as AzFloat,
            height: au_to_int(bounds.size.height) as AzFloat
        };
        AzDrawTargetFillRect(
            draw_target,
            ptr::addr_of(red_rect),
            unsafe { unsafe::reinterpret_cast(red_pattern) }
        );

        AzReleaseColorPattern(red_pattern);
    }
}

fn clear(draw_target: AzDrawTargetRef) {

    let black_color = {
        r: 0f as AzFloat,
        g: 0f as AzFloat,
        b: 0f as AzFloat,
        a: 1f as AzFloat
    };
    let black_pattern = AzCreateColorPattern(ptr::addr_of(black_color));

    let black_rect = {
        x: 0 as AzFloat,
        y: 0 as AzFloat,
        width: 800 as AzFloat,
        height: 600 as AzFloat,
    };

    AzDrawTargetFillRect(
        draw_target,
        ptr::addr_of(black_rect),
        unsafe { unsafe::reinterpret_cast(black_pattern) }
    );

}<commit_msg>More cleanup in renderer<commit_after>import geom::*;
import comm::*;
import layout::display_list::*;

enum msg {
    draw(display_list),
    exit(comm::chan<()>)
}

fn renderer(osmain: chan<osmain::msg>) -> chan<msg> {
    task::spawn_listener::<msg> {|po|
        listen {|draw_target_ch|
            osmain.send(osmain::get_draw_target(draw_target_ch));
            let draw_target = draw_target_ch.recv();

            loop {
                alt po.recv() {
                  draw(display_list) {

                    draw_display_list(draw_target, display_list);

                    listen {|draw_ch|
                        osmain.send(osmain::draw(draw_ch));
                        draw_ch.recv();
                    }
                  }
                  exit(response_ch) {
                    response_ch.send(());
                    break;
                  }
                }
            }
        }
    }
}

fn draw_display_list(
    draw_target: AzDrawTargetRef,
    display_list: display_list
) {
    clear(draw_target);

    for display_list.each {|item|
        let bounds = (*item).bounds;

        let red_color = {
            r: 1f as AzFloat,
            g: 0f as AzFloat,
            b: 0f as AzFloat,
            a: 0.5f as AzFloat
        };
        let red_pattern = AzCreateColorPattern(ptr::addr_of(red_color));

        let red_rect = {
            x: au_to_int(bounds.origin.x) as AzFloat,
            y: au_to_int(bounds.origin.y) as AzFloat,
            width: au_to_int(bounds.size.width) as AzFloat,
            height: au_to_int(bounds.size.height) as AzFloat
        };
        AzDrawTargetFillRect(
            draw_target,
            ptr::addr_of(red_rect),
            unsafe { unsafe::reinterpret_cast(red_pattern) }
        );

        AzReleaseColorPattern(red_pattern);
    }
}

fn clear(draw_target: AzDrawTargetRef) {

    let black_color = {
        r: 0f as AzFloat,
        g: 0f as AzFloat,
        b: 0f as AzFloat,
        a: 1f as AzFloat
    };
    let black_pattern = AzCreateColorPattern(ptr::addr_of(black_color));

    let black_rect = {
        x: 0 as AzFloat,
        y: 0 as AzFloat,
        width: 800 as AzFloat,
        height: 600 as AzFloat,
    };

    AzDrawTargetFillRect(
        draw_target,
        ptr::addr_of(black_rect),
        unsafe { unsafe::reinterpret_cast(black_pattern) }
    );

}<|endoftext|>