<commit_before>use super::*;

use diesel::connection::Connection;

pub fn archive_comments(connections: &sqlite::Connections, ids: &[&str]) -> Result<()> {
    let mut repo_err = None;
    let connection = connections.exclusive()?;
    Ok(connection
        .transaction::<_, diesel::result::Error, _>(|| {
            usecases::archive_comments(&*connection, ids).map_err(|err| {
                warn!("Failed to archive {} comments: {}", ids.len(), err);
                repo_err = Some(err);
                diesel::result::Error::RollbackTransaction
            })
        })
        .map_err(|err| {
            if let Some(repo_err) = repo_err {
                repo_err
            } else {
                RepoError::from(err).into()
            }
        })?)
}
<commit_msg>Add basic tests for archiving comments<commit_after>use super::*;

use diesel::connection::Connection;

pub fn archive_comments(connections: &sqlite::Connections, ids: &[&str]) -> Result<()> {
    let mut repo_err = None;
    let connection = connections.exclusive()?;
    Ok(connection
        .transaction::<_, diesel::result::Error, _>(|| {
            usecases::archive_comments(&*connection, ids).map_err(|err| {
                warn!("Failed to archive {} comments: {}", ids.len(), err);
                repo_err = Some(err);
                diesel::result::Error::RollbackTransaction
            })
        })
        .map_err(|err| {
            if let Some(repo_err) = repo_err {
                repo_err
            } else {
                RepoError::from(err).into()
            }
        })?)
}

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

    fn archive_comments(fixture: &EnvFixture, ids: &[&str]) -> super::Result<()> {
        super::archive_comments(
            &fixture.db_connections,
            ids,
        )
    }

    #[test]
    fn should_archive_multiple_comments_only_once() {
        let fixture = EnvFixture::new();

        let entry_ids = vec![
            fixture.create_entry(0.into()),
            fixture.create_entry(1.into()),
        ];
        let rating_comment_ids = vec![
            fixture.create_rating(new_entry_rating(
                0,
                &entry_ids[0],
                RatingContext::Diversity,
                RatingValue::new(-1),
            )),
            fixture.create_rating(new_entry_rating(
                1,
                &entry_ids[0],
                RatingContext::Fairness,
                RatingValue::new(0),
            )),
            fixture.create_rating(new_entry_rating(
                2,
                &entry_ids[1],
                RatingContext::Transparency,
                RatingValue::new(1),
            )),
            fixture.create_rating(new_entry_rating(
                3,
                &entry_ids[1],
                RatingContext::Renewable,
                RatingValue::new(2),
            )),
        ];

        assert!(fixture.entry_exists(&entry_ids[0]));
        assert!(fixture.entry_exists(&entry_ids[1]));
        assert!(fixture.rating_exists(&rating_comment_ids[0].0));
        assert!(fixture.rating_exists(&rating_comment_ids[1].0));
        assert!(fixture.rating_exists(&rating_comment_ids[2].0));
        assert!(fixture.rating_exists(&rating_comment_ids[3].0));

        assert!(fixture.comment_exists(&rating_comment_ids[0].1));
        assert!(fixture.comment_exists(&rating_comment_ids[1].1));
        assert!(fixture.comment_exists(&rating_comment_ids[2].1));
        assert!(fixture.comment_exists(&rating_comment_ids[3].1));

        // Archive comments 1 and 2
        assert!(archive_comments(
            &fixture,
            &vec![&*rating_comment_ids[1].1, &*rating_comment_ids[2].1]
        )
        .is_ok());

        // Entries and ratings still exist
        assert!(fixture.entry_exists(&entry_ids[0]));
        assert!(fixture.entry_exists(&entry_ids[1]));
        assert!(fixture.rating_exists(&rating_comment_ids[0].0));
        assert!(fixture.rating_exists(&rating_comment_ids[1].0));
        assert!(fixture.rating_exists(&rating_comment_ids[2].0));
        assert!(fixture.rating_exists(&rating_comment_ids[3].0));

        // Comments 1 and 2 disappeared
        assert!(fixture.comment_exists(&rating_comment_ids[0].1));
        assert!(!fixture.comment_exists(&rating_comment_ids[1].1));
        assert!(!fixture.comment_exists(&rating_comment_ids[2].1));
        assert!(fixture.comment_exists(&rating_comment_ids[3].1));

        // Try to archive comments 0 and 1 (already archived)
        assert_not_found(archive_comments(
            &fixture,
            &vec![&*rating_comment_ids[0].1, &*rating_comment_ids[1].1],
        ));

        // No changes due to rollback
        assert!(fixture.entry_exists(&entry_ids[0]));
        assert!(fixture.entry_exists(&entry_ids[1]));
        assert!(fixture.rating_exists(&rating_comment_ids[0].0));
        assert!(fixture.rating_exists(&rating_comment_ids[1].0));
        assert!(fixture.rating_exists(&rating_comment_ids[2].0));
        assert!(fixture.rating_exists(&rating_comment_ids[3].0));
        assert!(fixture.comment_exists(&rating_comment_ids[0].1));
        assert!(!fixture.comment_exists(&rating_comment_ids[1].1));
        assert!(!fixture.comment_exists(&rating_comment_ids[2].1));
        assert!(fixture.comment_exists(&rating_comment_ids[3].1));

        // Archive remaining comments
        assert!(archive_comments(
            &fixture,
            &vec![&*rating_comment_ids[0].1, &*rating_comment_ids[3].1]
        )
        .is_ok());

        // Entries and ratings still exist
        assert!(fixture.entry_exists(&entry_ids[0]));
        assert!(fixture.entry_exists(&entry_ids[1]));
        assert!(fixture.rating_exists(&rating_comment_ids[0].0));
        assert!(fixture.rating_exists(&rating_comment_ids[1].0));
        assert!(fixture.rating_exists(&rating_comment_ids[2].0));
        assert!(fixture.rating_exists(&rating_comment_ids[3].0));

        // All comments disappeared
        assert!(!fixture.comment_exists(&rating_comment_ids[0].1));
        assert!(!fixture.comment_exists(&rating_comment_ids[1].1));
        assert!(!fixture.comment_exists(&rating_comment_ids[2].1));
        assert!(!fixture.comment_exists(&rating_comment_ids[3].1));
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::prelude::*;
use std::io::stdout;
use std::mem;
use std::ptr;
#[cfg(not(use_memcpy_in_gc))]
use std::slice;

use super::value;
use value::{Value, SIZEOF_PAIR, HEADER_TAG, PAIR_HEADER};
#[cfg(debug_assertions)]
use value::Tags;
/// An allocator for RustyScheme objects
pub trait Allocator {
    /// Allocates a vector
    fn alloc_vector(&mut self, &[Value]) -> value::Vector;

    /// Allocates a pair
    fn alloc_pair(&mut self, car: Value, cdr: Value);

    /// Allocates a closure
    fn alloc_closure(&mut self, bytecode: &value::BCO, upvalues: &[Value]) -> value::Closure;

    /// Allocates a record
    fn alloc_record(&mut self,
                    descriptor: &value::RecordDescriptor,
                    fields: &[Value])
                    -> value::Record;

    /// Allocates a hash table
    fn alloc_hash_table(&mut self, size: usize) -> value::HashTable;

    /// Allocates a port
    fn alloc_port(&mut self, File) -> value::IOPort;

    /// Allocates a rustdata, which contains an arbitrary Rust object
    fn alloc_rustdata<T>(&mut self, object: &T) -> value::RustData;

// /// Allocates a boxed float on the top of the stack.
// fn alloc_float(&mut self, float: f64) -> value::Float;
}
#[derive(Debug)]
pub struct Heap {
    tospace: Vec<Value>,
    fromspace: Vec<Value>,
    pub stack: self::Stack,
}

/// Consistency checks on the whole heap (in debug mode only) – sloooow.
#[cfg(debug_assertions)]
unsafe fn consistency_check(heap: &Vec<Value>) {
    let assert_in_heap = |heap: &Vec<_>, ptr: usize| {
        assert!(ptr >= heap.as_ptr() as usize);
        let upper_limit = heap.as_ptr() as usize + heap.capacity()*size_of!(Value);
        assert!(ptr < upper_limit,
                "Heap pointer out of range: {} >= {}", ptr, upper_limit)
    };
    let mut index = 0;
    while index < heap.len() {
        let mut current = heap[index];
        let len = current.contents as usize & !HEADER_TAG;
        assert!(len > 0);
        index += 1;
        for _ in 1..len {
            current = heap[index];
            match current.tag() {
                Tags::Num | Tags::Num2 => {
                    assert!(current.contents & 0b11 == 0);
                }
                Tags::Pair => {
                    assert!(current.contents & 0b111 == 0b111);
                    assert!((*Ptr_Val!(current)).contents == PAIR_HEADER);
                    for i in 1..3 {
                        assert_in_heap(heap, Ptr_Val!(current).offset(i)
                                       as usize)
                    }
                }
                Tags::Vector => {
                    assert!(len > 0);
                    for i in 1..len {
                        assert_in_heap(heap, Ptr_Val!(current) as usize + i)
                    }
                }
                _ => unimplemented!(),
            }
            index += 1;
        }
    }
}
#[cfg(not(debug_assertions))]
unsafe fn consistency_check(_heap: &Vec<Value>) {}

/// Relocates a `Value` in the heap.
///
/// This function relocates a `Value` in the Scheme heap.  It takes two
/// arguments: `current`, the `Value` being relocated, and `end`, the current
/// end of tospace.
///
/// This function takes raw pointers because of aliasing concerns.
unsafe fn relocate(current: *mut Value, tospace: &mut Vec<Value>) {
    let size_of_value: usize = size_of!(Value);
    (*current).size().map(|size| {
        // pointer to head of object being copied
        let pointer = Ptr_Val!(*current);

        // Assert that the object header is nonzero.
        debug_assert!((*pointer).contents != 0,
                      "internal error: copy_value: invalid object header size");
        if (*pointer).contents == HEADER_TAG {
            // Forwarding pointer detected (this header tag is otherwise absurd,
            // since no object can have a size of zero).
            *current = *pointer.offset(1)
        } else {
            // End pointer
            let end = tospace.as_mut_ptr().offset(tospace.len() as isize);

            if cfg!(use_memcpy_in_gc) {
                debug_assert!(end as usize & 0b111 == 0);
                // The amount to copy
                let amount_to_copy = (size * size_of_value + 0b111) & !0b111;
                debug_assert!(end as usize + amount_to_copy <=
                              tospace.as_ptr() as usize + tospace.capacity());
                debug_assert!(pointer as usize >= end as usize + amount_to_copy ||
                              pointer as usize + amount_to_copy <= end as usize);
                ptr::copy_nonoverlapping(pointer, end, amount_to_copy);
                *current = Value { contents: end as usize | (*current).raw_tag() };
                let len = tospace.len();
                tospace.set_len(len + amount_to_copy / size_of_value);
            } else {
                let amount_to_copy = ((size * size_of_value + 0b111) & !0b111) / size_of_value;
                debug_assert!(amount_to_copy > 0);
                debug_assert!(end as usize & 0b111 == 0);
                *current = Value { contents: end as usize | ((*current).contents & 0b111) };
                tospace.extend(slice::from_raw_parts(pointer, amount_to_copy));
            }
        }
    });
}

/// Process the heap.
unsafe fn scavange_heap(tospace: &mut Vec<Value>) {
    let mut offset: isize = 0;
    let current = tospace.as_mut_ptr();
    while offset < tospace.len() as isize {
        let size = (*current.offset(offset)).contents & !HEADER_TAG;
        assert!(size > 0);
        offset += 1;
        if !(*current).leafp() {
            for _ in 1..size {
                relocate(current.offset(offset), tospace);
                offset += 1
            }
        }
    }
}

unsafe fn scavange_stack(stack: &mut Vec<Value>, tospace: &mut Vec<Value>) {
    for i in stack.iter_mut() {
        relocate(i, tospace);
    }
}

fn collect(heap: &mut Heap) {
    println!("Initiated garbage collection");
    unsafe {
        consistency_check(&heap.tospace);
        println!("Completed first consistency check");
        mem::swap(&mut heap.tospace, &mut heap.fromspace);
        heap.tospace.reserve(heap.fromspace.len() + heap.fromspace.len()/2);
        println!("Fromspace size is {}", heap.fromspace.len() + heap.fromspace.len() / 2);
        heap.tospace.resize(0, Value{contents:0});
        println!("Tospace resized to {}", heap.tospace.capacity());
        let _ = stdout().flush();
        scavange_stack(&mut heap.stack, &mut heap.tospace);
        println!("Stack scavanged");
        scavange_heap(&mut heap.tospace);
        println!("Heap scavanged");
        consistency_check(&heap.tospace);
        println!("Completed second consistency check");
        //heap.fromspace.resize(0, Value{contents: 0});
    }
}

#[derive(Debug)]
pub struct Stack {
    pub innards: Vec<value::Value>,
}
#[cfg(none)]
impl ::std::ops::Index<usize> for Stack {
    type Output = value::Value;
    fn index(&self, other: u8) -> &value::Value {
        let val: usize = other.into();
        &self.innards[val]
    }
}

use std::ops::{Deref, DerefMut};
impl Deref for Stack {
    type Target = Vec<value::Value>;
    fn deref(&self) -> &Vec<value::Value> {
        &self.innards
    }
}

impl DerefMut for Stack {
    fn deref_mut<'a>(&'a mut self) -> &'a mut Vec<value::Value> {
        &mut self.innards
    }
}

impl Heap {
    /// Allocates a Scheme pair, which must be rooted by the caller.
    pub fn alloc_pair(&mut self, car: Value, cdr: Value) {
        let tospace_space = self.tospace.capacity() - self.tospace.len();
        if tospace_space < SIZEOF_PAIR {
            collect(self);
        }
        self.tospace.push(Value { contents: PAIR_HEADER });
        self.tospace.push(car);
        self.tospace.push(cdr);
        let len = self.tospace.len() - 3;
        let new_value = Value {
            contents: unsafe {
                self.tospace.as_ptr().offset(len as isize) as usize | value::PAIR_TAG
            },
        };
        self.stack.push(new_value);
        println!("Allocated a pair");
    }
    pub fn new(size: usize) -> Self {
        Heap {
            fromspace: Vec::with_capacity(size),
            tospace: Vec::with_capacity(size),
            stack: Stack { innards: Vec::with_capacity(1 << 16) },
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use value::*;
    const ZERO: Value = Value { contents: 0 };
    #[test]
    fn can_allocate_objects() {
        let mut heap = Heap::new(1 << 4);
        super::collect(&mut heap);
        println!("HEADER_TAG = {:x}, PAIR_TAG = {:x}, SIZEOF_PAIR = {:x}",
                 HEADER_TAG,
                 PAIR_HEADER,
                 SIZEOF_PAIR);
        heap.alloc_pair(ZERO, ZERO);
        //println!("{:?}", heap);
        for _ in 1..((1 << 8)) {
            let old_pair = heap.stack[0];
            heap.alloc_pair(old_pair, old_pair);
            assert_eq!(heap.stack.len(), 2);
            assert_eq!(heap.stack[1].tag(), Tags::Pair);
            heap.stack[0] = heap.stack.pop().unwrap();
            let assert_valid = |heap: &Heap| {
                let new_pair = heap.stack[0];
                assert_eq!(heap.stack[0].tag(), Tags::Pair);
                assert_eq!(new_pair.size(), Some(3));
                if let EnumValue::Pair(ptr) = new_pair.enum_type() {
                    assert_eq!((unsafe { (*ptr).car.get().tag() }), Tags::Pair);
                    assert_eq!((unsafe { (*ptr).cdr.get().tag() }), Tags::Pair);
                } else {
                    unreachable!()
                }
            };
            assert_valid(&heap);
            super::collect(&mut heap);
            assert_valid(&heap);
            // assert!(heap.tospace.len() >= 3*i)
        }
        // assert!(heap.fromspace.capacity() > 3* (1 << 20));
        //println!("{:?}", heap);
        {
            super::collect(&mut heap);
        }
    }
}
<commit_msg>THE GC NOW WORKS!<commit_after>use std::fs::File;
use std::io::prelude::*;
use std::io::stdout;
use std::mem;
use std::ptr;
use std::slice;

use super::value;
use value::{Value, SIZEOF_PAIR, HEADER_TAG, PAIR_HEADER};
#[cfg(debug_assertions)]
use value::Tags;
/// An allocator for RustyScheme objects
pub trait Allocator {
    /// Allocates a vector
    fn alloc_vector(&mut self, &[Value]) -> value::Vector;

    /// Allocates a pair
    fn alloc_pair(&mut self, car: Value, cdr: Value);

    /// Allocates a closure
    fn alloc_closure(&mut self, bytecode: &value::BCO, upvalues: &[Value]) -> value::Closure;

    /// Allocates a record
    fn alloc_record(&mut self,
                    descriptor: &value::RecordDescriptor,
                    fields: &[Value])
                    -> value::Record;

    /// Allocates a hash table
    fn alloc_hash_table(&mut self, size: usize) -> value::HashTable;

    /// Allocates a port
    fn alloc_port(&mut self, File) -> value::IOPort;

    /// Allocates a rustdata, which contains an arbitrary Rust object
    fn alloc_rustdata<T>(&mut self, object: &T) -> value::RustData;

// /// Allocates a boxed float on the top of the stack.
// fn alloc_float(&mut self, float: f64) -> value::Float;
}
#[derive(Debug)]
pub struct Heap {
    tospace: Vec<Value>,
    fromspace: Vec<Value>,
    pub stack: self::Stack,
}

/// Consistency checks on the whole heap (in debug mode only) – sloooow.
#[cfg(debug_assertions)]
unsafe fn consistency_check(heap: &Vec<Value>) {
    let assert_in_heap = |heap: &Vec<_>, ptr: usize| {
        assert!(ptr >= heap.as_ptr() as usize);
        let upper_limit = heap.as_ptr() as usize + heap.capacity()*size_of!(Value);
        assert!(ptr < upper_limit,
                "Heap pointer out of range: {} >= {}", ptr, upper_limit)
    };
    let mut index = 0;
    while index < heap.len() {
        let mut current = heap[index];
        let len = current.contents as usize & !HEADER_TAG;
        assert!(len > 0);
        index += 1;
        for _ in 1..len {
            current = heap[index];
            match current.tag() {
                Tags::Num | Tags::Num2 => {
                    assert!(current.contents & 0b11 == 0);
                }
                Tags::Pair => {
                    assert!(current.contents & 0b111 == 0b111);
                    assert!((*Ptr_Val!(current)).contents == PAIR_HEADER);
                    for i in 1..3 {
                        assert_in_heap(heap, Ptr_Val!(current).offset(i)
                                       as usize)
                    }
                }
                Tags::Vector => {
                    assert!(len > 0);
                    for i in 1..len {
                        assert_in_heap(heap, Ptr_Val!(current) as usize + i)
                    }
                }
                _ => unimplemented!(),
            }
            index += 1;
        }
    }
}
#[cfg(not(debug_assertions))]
unsafe fn consistency_check(_heap: &Vec<Value>) {}

/// Relocates a `Value` in the heap.
///
/// This function relocates a `Value` in the Scheme heap.  It takes two
/// arguments: `current`, the `Value` being relocated, and `end`, the current
/// end of tospace.
///
/// This function takes raw pointers because of aliasing concerns.
unsafe fn relocate(current: *mut Value,
                   tospace: &mut Vec<Value>,
                   fromspace: &mut Vec<Value>) {
    let size_of_value: usize = size_of!(Value);
    (*current).size().map(|size| {
        // pointer to head of object being copied
        let pointer = Ptr_Val!(*current);

        // Assert that the object header is nonzero.
        debug_assert!((*pointer).contents != 0,
                      "internal error: copy_value: invalid object header size");
        if (*pointer).contents == HEADER_TAG {
            // Forwarding pointer detected (this header tag is otherwise absurd,
            // since no object can have a size of zero).
            *current = *pointer.offset(1)
        } else {
            // End pointer
            let end = tospace.as_mut_ptr().offset(tospace.len() as isize);

            if cfg!(feature = "memcpy_gc") {
                debug_assert!(end as usize & 0b111 == 0);
                // The amount to copy
                let amount_to_copy = (size * size_of_value + 0b111) & !0b111;
                debug_assert!(end as usize + amount_to_copy <=
                              tospace.as_ptr() as usize + tospace.capacity());
                debug_assert!(pointer as usize >= end as usize + amount_to_copy ||
                              pointer as usize + amount_to_copy <= end as usize);
                ptr::copy_nonoverlapping(pointer, end, amount_to_copy);
                *current = Value { contents: end as usize | (*current).raw_tag() };
                let len = tospace.len();
                tospace.set_len(len + amount_to_copy / size_of_value);
            } else {
                let amount_to_copy = ((size * size_of_value + 0b111) & !0b111) / size_of_value;

                // Check that the amount to copy is reasonable
                debug_assert!(amount_to_copy > 0);

                // Check that the end pointer is aligned
                debug_assert!(end as usize & 0b111 == 0);

                let ptr = Ptr_Val!(*current);

                // Check that the pointer really is to tospace
                debug_assert!((ptr as usize) <
                              (fromspace.as_ptr() as usize +
                               fromspace.len()*size_of!(usize)));
                debug_assert!(ptr as usize >= fromspace.as_ptr() as usize);
                // NOTE: this MUST come before replacing the old object with
                // a forwarding pointer – otherwise, this replacement will
                // clobber the copied object's header!
                tospace.extend(slice::from_raw_parts(pointer, amount_to_copy));
                *ptr = Value{ contents: HEADER_TAG, };
                *current = Value { contents: end as usize |
                                        ((*current).contents & 0b111) };
                *ptr.offset(1) = Value{ contents: end as usize };
                *ptr.offset(1) = *current;
            }
        }
    });
}

/// Process the heap.
unsafe fn scavange_heap(tospace: &mut Vec<Value>, fromspace: &mut Vec<Value>) {
    let mut offset: isize = 0;
    let current = tospace.as_mut_ptr();
    while offset < tospace.len() as isize {
        let size = (*current.offset(offset)).contents & !HEADER_TAG;
        assert!(size > 0);
        offset += 1;
        if !(*current).leafp() {
            for _ in 1..size {
                relocate(current.offset(offset), tospace, fromspace);
                offset += 1
            }
        }
    }
}

unsafe fn scavange_stack(stack: &mut Vec<Value>,
                         tospace: &mut Vec<Value>,
                         fromspace: &mut Vec<Value>) {
    for i in stack.iter_mut() {
        relocate(i, tospace, fromspace);
    }
}

fn collect(heap: &mut Heap) {
    println!("Initiated garbage collection");
    unsafe {
        consistency_check(&heap.tospace);
        println!("Completed first consistency check");
        mem::swap(&mut heap.tospace, &mut heap.fromspace);
        heap.tospace.reserve(heap.fromspace.len() + heap.fromspace.len()/2);
        println!("Fromspace size is {}", heap.fromspace.len() + heap.fromspace.len() / 2);
        heap.tospace.resize(0, Value{contents:0});
        println!("Tospace resized to {}", heap.tospace.capacity());
        let _ = stdout().flush();
        scavange_stack(&mut heap.stack, &mut heap.tospace, &mut heap.fromspace);
        println!("Stack scavanged");
        scavange_heap(&mut heap.tospace, &mut heap.fromspace);
        println!("Heap scavanged");
        consistency_check(&heap.tospace);
        println!("Completed second consistency check");
        heap.fromspace.resize(0, Value{contents: 0});
    }
}

#[derive(Debug)]
pub struct Stack {
    pub innards: Vec<value::Value>,
}
#[cfg(none)]
impl ::std::ops::Index<usize> for Stack {
    type Output = value::Value;
    fn index(&self, other: u8) -> &value::Value {
        let val: usize = other.into();
        &self.innards[val]
    }
}

use std::ops::{Deref, DerefMut};
impl Deref for Stack {
    type Target = Vec<value::Value>;
    fn deref(&self) -> &Vec<value::Value> {
        &self.innards
    }
}

impl DerefMut for Stack {
    fn deref_mut<'a>(&'a mut self) -> &'a mut Vec<value::Value> {
        &mut self.innards
    }
}

impl Heap {
    /// Allocates a Scheme pair, which must be rooted by the caller.
    pub fn alloc_pair(&mut self, car: Value, cdr: Value) {
        let tospace_space = self.tospace.capacity() - self.tospace.len();
        if tospace_space < SIZEOF_PAIR {
            collect(self);
        }
        self.tospace.push(Value { contents: PAIR_HEADER });
        self.tospace.push(car);
        self.tospace.push(cdr);
        let len = self.tospace.len() - 3;
        let new_value = Value {
            contents: unsafe {
                self.tospace.as_ptr().offset(len as isize) as usize | value::PAIR_TAG
            },
        };
        self.stack.push(new_value);
        println!("Allocated a pair");
    }
    pub fn new(size: usize) -> Self {
        Heap {
            fromspace: Vec::with_capacity(size),
            tospace: Vec::with_capacity(size),
            stack: Stack { innards: Vec::with_capacity(1 << 16) },
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use value::*;
    const ZERO: Value = Value { contents: 0 };
    #[test]
    fn can_allocate_objects() {
        let mut heap = Heap::new(1 << 4);
        super::collect(&mut heap);
        println!("HEADER_TAG = {:x}, PAIR_TAG = {:x}, SIZEOF_PAIR = {:x}",
                 HEADER_TAG,
                 PAIR_HEADER,
                 SIZEOF_PAIR);
        heap.alloc_pair(ZERO, ZERO);
        //println!("{:?}", heap);
        for i in 1..((1 << 11)) {
            let old_pair = heap.stack[0];
            heap.alloc_pair(old_pair, old_pair);
            assert_eq!(heap.stack.len(), 2);
            assert_eq!(heap.stack[1].tag(), Tags::Pair);
            heap.stack[0] = heap.stack.pop().unwrap();
            let assert_valid = |heap: &Heap| {
                let new_pair = heap.stack[0];
                assert_eq!(heap.stack[0].tag(), Tags::Pair);
                assert_eq!(new_pair.size(), Some(3));
                if let EnumValue::Pair(ptr) = new_pair.enum_type() {
                    assert_eq!((unsafe { (*ptr).car.get().tag() }), Tags::Pair);
                    assert_eq!((unsafe { (*ptr).cdr.get().tag() }), Tags::Pair);
                } else {
                    unreachable!()
                }
            };
            assert_valid(&heap);
            super::collect(&mut heap);
            assert_valid(&heap);
            assert!(heap.tospace.len() >= 3*i)
        }
        heap.stack.pop();
        assert!(heap.stack.len() == 0);
        // assert!(heap.fromspace.capacity() > 3* (1 << 20));
        //println!("{:?}", heap);
        {
            super::collect(&mut heap);
            assert!(heap.tospace.len() == 0);
        }
    }
}
<|endoftext|>


<commit_before>use libc;
use std::str::FromStr;
use std::cmp::{self,Ord};
use std::sync::Mutex;
use std::fmt::{Arguments,format};
use std::io::{stdout,Stdout,Write};
use std::ascii::AsciiExt;
use std::net::{SocketAddr,UdpSocket};
use std::net::TcpStream;
use mio_uds::UnixDatagram;

lazy_static! {
  pub static ref LOGGER: Mutex<Logger> = Mutex::new(Logger::new());
  pub static ref PID:    i32           = unsafe { libc::getpid() };
  pub static ref TAG:    String        = LOGGER.lock().unwrap().tag.clone();
}

pub struct Logger {
  pub directives: Vec<LogDirective>,
  pub backend:    LoggerBackend,
  pub tag:        String,
}

impl Logger {
  pub fn new() -> Logger {
    Logger {
      directives: vec!(LogDirective {
        name:  None,
        level: LogLevelFilter::Error,
      }),
      backend: LoggerBackend::Stdout(stdout()),
      tag:     "WAAAAAAAH".to_string()
    }
  }

  pub fn init(tag: String, spec: &str, backend: LoggerBackend) {
    let directives = parse_logging_spec(spec);
    if let Ok(ref mut logger) = LOGGER.lock() {
      logger.set_directives(directives);
      logger.backend = backend;
      logger.tag     = tag;
    }
    //trying to init the logger tag
    let ref t = *TAG;
  }

  pub fn log<'a>(&mut self, meta: &LogMetadata, args: Arguments) {
    if self.enabled(meta) {
      match self.backend {
        LoggerBackend::Stdout(ref mut stdout) => {
          stdout.write_fmt(args);
        },
        //FIXME: should have a buffer to write to instead of allocating a string
        LoggerBackend::Unix(ref mut socket) => {
          socket.send(format(args).as_bytes());
        },
        //FIXME: should have a buffer to write to instead of allocating a string
        LoggerBackend::Udp(ref mut socket, ref address) => {
          socket.send_to(format(args).as_bytes(), address);
        }
        LoggerBackend::Tcp(ref mut socket) => {
          socket.write_fmt(args);
        },
      }
    }
  }

  pub fn set_directives(&mut self, directives: Vec<LogDirective>) {
    self.directives = directives;
  }

  fn enabled(&self, meta: &LogMetadata) -> bool {
    // Search for the longest match, the vector is assumed to be pre-sorted.
    for directive in self.directives.iter().rev() {
      match directive.name {
        Some(ref name) if !meta.target.starts_with(&**name) => {},
        Some(..) | None => {
          return meta.level <= directive.level
        }
      }
    }
    false
  }
}

pub enum LoggerBackend {
  Stdout(Stdout),
  Unix(UnixDatagram),
  Udp(UdpSocket, SocketAddr),
  Tcp(TcpStream)
}

#[repr(usize)]
#[derive(Copy, Eq, Debug)]
pub enum LogLevel {
    /// The "error" level.
    ///
    /// Designates very serious errors.
    Error = 1, // This way these line up with the discriminants for LogLevelFilter below
    /// The "warn" level.
    ///
    /// Designates hazardous situations.
    Warn,
    /// The "info" level.
    ///
    /// Designates useful information.
    Info,
    /// The "debug" level.
    ///
    /// Designates lower priority information.
    Debug,
    /// The "trace" level.
    ///
    /// Designates very low priority, often extremely verbose, information.
    Trace,
}

static LOG_LEVEL_NAMES: [&'static str; 6] = ["OFF", "ERROR", "WARN", "INFO",
                                             "DEBUG", "TRACE"];

impl Clone for LogLevel {
    #[inline]
    fn clone(&self) -> LogLevel {
        *self
    }
}

impl PartialEq for LogLevel {
    #[inline]
    fn eq(&self, other: &LogLevel) -> bool {
        *self as usize == *other as usize
    }
}

impl PartialEq<LogLevelFilter> for LogLevel {
    #[inline]
    fn eq(&self, other: &LogLevelFilter) -> bool {
        *self as usize == *other as usize
    }
}

impl PartialOrd for LogLevel {
    #[inline]
    fn partial_cmp(&self, other: &LogLevel) -> Option<cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialOrd<LogLevelFilter> for LogLevel {
    #[inline]
    fn partial_cmp(&self, other: &LogLevelFilter) -> Option<cmp::Ordering> {
        Some((*self as usize).cmp(&(*other as usize)))
    }
}

impl Ord for LogLevel {
    #[inline]
    fn cmp(&self, other: &LogLevel) -> cmp::Ordering {
        (*self as usize).cmp(&(*other as usize))
    }
}

impl LogLevel {
    fn from_usize(u: usize) -> Option<LogLevel> {
        match u {
            1 => Some(LogLevel::Error),
            2 => Some(LogLevel::Warn),
            3 => Some(LogLevel::Info),
            4 => Some(LogLevel::Debug),
            5 => Some(LogLevel::Trace),
            _ => None
        }
    }

    /// Returns the most verbose logging level.
    #[inline]
    pub fn max() -> LogLevel {
        LogLevel::Trace
    }

    /// Converts the `LogLevel` to the equivalent `LogLevelFilter`.
    #[inline]
    pub fn to_log_level_filter(&self) -> LogLevelFilter {
        LogLevelFilter::from_usize(*self as usize).unwrap()
    }
}

#[repr(usize)]
#[derive(Copy, Eq, Debug)]
pub enum LogLevelFilter {
    Off,
    Error,
    Warn,
    Info,
    Debug,
    Trace,
}

impl Clone for LogLevelFilter {
    #[inline]
    fn clone(&self) -> LogLevelFilter {
        *self
    }
}

impl PartialEq for LogLevelFilter {
    #[inline]
    fn eq(&self, other: &LogLevelFilter) -> bool {
        *self as usize == *other as usize
    }
}

impl PartialEq<LogLevel> for LogLevelFilter {
    #[inline]
    fn eq(&self, other: &LogLevel) -> bool {
        other.eq(self)
    }
}

impl PartialOrd for LogLevelFilter {
    #[inline]
    fn partial_cmp(&self, other: &LogLevelFilter) -> Option<cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialOrd<LogLevel> for LogLevelFilter {
    #[inline]
    fn partial_cmp(&self, other: &LogLevel) -> Option<cmp::Ordering> {
        other.partial_cmp(self).map(|x| x.reverse())
    }
}

impl Ord for LogLevelFilter {
    #[inline]
    fn cmp(&self, other: &LogLevelFilter) -> cmp::Ordering {
        (*self as usize).cmp(&(*other as usize))
    }
}

impl FromStr for LogLevelFilter {
    type Err = ();
    fn from_str(level: &str) -> Result<LogLevelFilter, ()> {
        ok_or(LOG_LEVEL_NAMES.iter()
                    .position(|&name| name.eq_ignore_ascii_case(level))
                    .map(|p| LogLevelFilter::from_usize(p).unwrap()), ())
    }
}

impl LogLevelFilter {
    fn from_usize(u: usize) -> Option<LogLevelFilter> {
        match u {
            0 => Some(LogLevelFilter::Off),
            1 => Some(LogLevelFilter::Error),
            2 => Some(LogLevelFilter::Warn),
            3 => Some(LogLevelFilter::Info),
            4 => Some(LogLevelFilter::Debug),
            5 => Some(LogLevelFilter::Trace),
            _ => None
        }
    }
    /// Returns the most verbose logging level filter.
    #[inline]
    pub fn max() -> LogLevelFilter {
        LogLevelFilter::Trace
    }

    /// Converts `self` to the equivalent `LogLevel`.
    ///
    /// Returns `None` if `self` is `LogLevelFilter::Off`.
    #[inline]
    pub fn to_log_level(&self) -> Option<LogLevel> {
        LogLevel::from_usize(*self as usize)
    }
}

/// Metadata about a log message.
pub struct LogMetadata {
  pub level:  LogLevel,
  pub target: &'static str,
}

pub struct LogDirective {
    name:  Option<String>,
    level: LogLevelFilter,
}

fn ok_or<T, E>(t: Option<T>, e: E) -> Result<T, E> {
    match t {
        Some(t) => Ok(t),
        None => Err(e),
    }
}

pub fn parse_logging_spec(spec: &str) -> Vec<LogDirective> {
    let mut dirs = Vec::new();

    let mut parts = spec.split('/');
    let mods = parts.next();
    let _    = parts.next();
    if parts.next().is_some() {
        println!("warning: invalid logging spec '{}', \
                 ignoring it (too many '/'s)", spec);
        return dirs;
    }
    mods.map(|m| { for s in m.split(',') {
        if s.len() == 0 { continue }
        let mut parts = s.split('=');
        let (log_level, name) = match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) {
            (Some(part0), None, None) => {
                // if the single argument is a log-level string or number,
                // treat that as a global fallback
                match part0.parse() {
                    Ok(num) => (num, None),
                    Err(_) => (LogLevelFilter::max(), Some(part0)),
                }
            }
            (Some(part0), Some(""), None) => (LogLevelFilter::max(), Some(part0)),
            (Some(part0), Some(part1), None) => {
                match part1.parse() {
                    Ok(num) => (num, Some(part0)),
                    _ => {
                        println!("warning: invalid logging spec '{}', \
                                 ignoring it", part1);
                        continue
                    }
                }
            },
            _ => {
                println!("warning: invalid logging spec '{}', \
                         ignoring it", s);
                continue
            }
        };
        dirs.push(LogDirective {
            name: name.map(|s| s.to_string()),
            level: log_level,
        });
    }});

    return dirs;
}

#[macro_export]
macro_rules! log {
    (target: $target:expr, $lvl:expr, $format:expr, $level_tag:expr, $($arg:tt)+) => ({
      use $crate::logging::LOGGER;
      static _META: $crate::logging::LogMetadata = $crate::logging::LogMetadata {
          level:  $lvl,
          target: module_path!(),
      };
      {
        //FIXME: we will lose logs in multithreading like this
        if let Ok(mut logger) = LOGGER.try_lock() {
          logger.log(
            &_META,
            format_args!(
              concat!("{}\t{}\t{}\t{}\t{}\t", $format, '\n'),
              ::time::now_utc().rfc3339(), ::time::precise_time_ns(), *$crate::logging::PID,
              $level_tag, *$crate::logging::TAG, $($arg)+));
        }
      }
    });
    (target: $target:expr, $lvl:expr, $format:expr, $level_tag:expr) => ({
      use $crate::logging::LOGGER;
      static _META: $crate::logging::LogMetadata = $crate::logging::LogMetadata {
          level:  $lvl,
          target: module_path!(),
      };
      {
        //FIXME: we will lose logs in multithreading like this
        if let Ok(mut logger) = LOGGER.try_lock() {
          logger.log(
            &_META,
            format_args!(
              concat!("{}\t{}\t{}\t{}\t{}\t", $format, '\n'),
              ::time::now_utc().rfc3339(), ::time::precise_time_ns(), *$crate::logging::PID,
              $level_tag, *$crate::logging::TAG));
        }
      }
    });
    ($lvl:expr, $($arg:tt)+) => (log!(target: module_path!(), $lvl, $($arg)+));
}

#[macro_export]
macro_rules! error {
    ($format:expr, $($arg:tt)*) => {
        log!($crate::logging::LogLevel::Error, $format, "ERROR", $($arg)*);
    };
    ($format:expr) => {
        log!($crate::logging::LogLevel::Error, $format, "ERROR");
    };
}

#[macro_export]
macro_rules! warn {
    ($format:expr, $($arg:tt)*) => {
        use time;
        use logging::PID;
        log!($crate::logging::LogLevel::Warn, $format, "WARN", $($arg)*);
    };
    ($format:expr) => {
        log!($crate::logging::LogLevel::Warn, $format, "WARN");
    }
}

#[macro_export]
macro_rules! info {
    ($format:expr, $($arg:tt)*) => {
        log!($crate::logging::LogLevel::Info, $format, "INFO", $($arg)*);
    };
    ($format:expr) => {
        log!($crate::logging::LogLevel::Info, $format, "INFO");
    }
}

#[macro_export]
macro_rules! debug {
    ($format:expr, $($arg:tt)*) => {
        #[cfg(debug_assertions)]
        log!($crate::logging::LogLevel::Debug, concat!("{}\t", $format),
          "DEBUG", module_path!(), $($arg)*);
    };
    ($format:expr) => {
        #[cfg(debug_assertions)]
        log!($crate::logging::LogLevel::Debug, concat!("{}\t", $format),
          "DEBUG", module_path!());
    }
}

#[macro_export]
macro_rules! trace {
    ($format:expr, $($arg:tt)*) => (
        #[cfg(debug_assertions)]
        log!($crate::logging::LogLevel::Trace, concat!("{}\t", $format),
          "TRACE", module_path!(), $($arg)*);
    );
    ($format:expr) => (
        #[cfg(debug_assertions)]
        log!($crate::logging::LogLevel::Trace, concat!("{}\t", $format),
          "TRACE", module_path!());
    )
}

#[macro_export]
macro_rules! setup_test_logger {
  () => (
    $crate::logging::Logger::init(module_path!().to_string(), "error", $crate::logging::LoggerBackend::Stdout(::std::io::stdout()));
  );
}
<commit_msg>use thread local storage to hold the logger instance<commit_after>use libc;
use std::str::FromStr;
 use std::cell::RefCell;
use std::cmp::{self,Ord};
use std::sync::Mutex;
use std::fmt::{Arguments,format};
use std::io::{stdout,Stdout,Write};
use std::ascii::AsciiExt;
use std::net::{SocketAddr,UdpSocket};
use std::net::TcpStream;
use mio_uds::UnixDatagram;

thread_local! {
  pub static LOGGER: RefCell<Logger> = RefCell::new(Logger::new());
}

pub struct Logger {
  pub directives: Vec<LogDirective>,
  pub backend:    LoggerBackend,
  pub tag:        String,
  pub pid:        i32,
}

impl Logger {
  pub fn new() -> Logger {
    Logger {
      directives: vec!(LogDirective {
        name:  None,
        level: LogLevelFilter::Error,
      }),
      backend: LoggerBackend::Stdout(stdout()),
      tag:     "SOZU".to_string(),
      pid:     0,
    }
  }

  pub fn init(tag: String, spec: &str, backend: LoggerBackend) {
    let directives = parse_logging_spec(spec);
    LOGGER.with(|l| {
      let ref mut logger = *l.borrow_mut();
      logger.set_directives(directives);
      logger.backend = backend;
      logger.tag     = tag;
      logger.pid     = unsafe { libc::getpid() };
    });
  }

  pub fn log<'a>(&mut self, meta: &LogMetadata, args: Arguments) {
    if self.enabled(meta) {
      match self.backend {
        LoggerBackend::Stdout(ref mut stdout) => {
          stdout.write_fmt(args);
        },
        //FIXME: should have a buffer to write to instead of allocating a string
        LoggerBackend::Unix(ref mut socket) => {
          socket.send(format(args).as_bytes());
        },
        //FIXME: should have a buffer to write to instead of allocating a string
        LoggerBackend::Udp(ref mut socket, ref address) => {
          socket.send_to(format(args).as_bytes(), address);
        }
        LoggerBackend::Tcp(ref mut socket) => {
          socket.write_fmt(args);
        },
      }
    }
  }

  pub fn set_directives(&mut self, directives: Vec<LogDirective>) {
    self.directives = directives;
  }

  fn enabled(&self, meta: &LogMetadata) -> bool {
    // Search for the longest match, the vector is assumed to be pre-sorted.
    for directive in self.directives.iter().rev() {
      match directive.name {
        Some(ref name) if !meta.target.starts_with(&**name) => {},
        Some(..) | None => {
          return meta.level <= directive.level
        }
      }
    }
    false
  }
}

pub enum LoggerBackend {
  Stdout(Stdout),
  Unix(UnixDatagram),
  Udp(UdpSocket, SocketAddr),
  Tcp(TcpStream)
}

#[repr(usize)]
#[derive(Copy, Eq, Debug)]
pub enum LogLevel {
    /// The "error" level.
    ///
    /// Designates very serious errors.
    Error = 1, // This way these line up with the discriminants for LogLevelFilter below
    /// The "warn" level.
    ///
    /// Designates hazardous situations.
    Warn,
    /// The "info" level.
    ///
    /// Designates useful information.
    Info,
    /// The "debug" level.
    ///
    /// Designates lower priority information.
    Debug,
    /// The "trace" level.
    ///
    /// Designates very low priority, often extremely verbose, information.
    Trace,
}

static LOG_LEVEL_NAMES: [&'static str; 6] = ["OFF", "ERROR", "WARN", "INFO",
                                             "DEBUG", "TRACE"];

impl Clone for LogLevel {
    #[inline]
    fn clone(&self) -> LogLevel {
        *self
    }
}

impl PartialEq for LogLevel {
    #[inline]
    fn eq(&self, other: &LogLevel) -> bool {
        *self as usize == *other as usize
    }
}

impl PartialEq<LogLevelFilter> for LogLevel {
    #[inline]
    fn eq(&self, other: &LogLevelFilter) -> bool {
        *self as usize == *other as usize
    }
}

impl PartialOrd for LogLevel {
    #[inline]
    fn partial_cmp(&self, other: &LogLevel) -> Option<cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialOrd<LogLevelFilter> for LogLevel {
    #[inline]
    fn partial_cmp(&self, other: &LogLevelFilter) -> Option<cmp::Ordering> {
        Some((*self as usize).cmp(&(*other as usize)))
    }
}

impl Ord for LogLevel {
    #[inline]
    fn cmp(&self, other: &LogLevel) -> cmp::Ordering {
        (*self as usize).cmp(&(*other as usize))
    }
}

impl LogLevel {
    fn from_usize(u: usize) -> Option<LogLevel> {
        match u {
            1 => Some(LogLevel::Error),
            2 => Some(LogLevel::Warn),
            3 => Some(LogLevel::Info),
            4 => Some(LogLevel::Debug),
            5 => Some(LogLevel::Trace),
            _ => None
        }
    }

    /// Returns the most verbose logging level.
    #[inline]
    pub fn max() -> LogLevel {
        LogLevel::Trace
    }

    /// Converts the `LogLevel` to the equivalent `LogLevelFilter`.
    #[inline]
    pub fn to_log_level_filter(&self) -> LogLevelFilter {
        LogLevelFilter::from_usize(*self as usize).unwrap()
    }
}

#[repr(usize)]
#[derive(Copy, Eq, Debug)]
pub enum LogLevelFilter {
    Off,
    Error,
    Warn,
    Info,
    Debug,
    Trace,
}

impl Clone for LogLevelFilter {
    #[inline]
    fn clone(&self) -> LogLevelFilter {
        *self
    }
}

impl PartialEq for LogLevelFilter {
    #[inline]
    fn eq(&self, other: &LogLevelFilter) -> bool {
        *self as usize == *other as usize
    }
}

impl PartialEq<LogLevel> for LogLevelFilter {
    #[inline]
    fn eq(&self, other: &LogLevel) -> bool {
        other.eq(self)
    }
}

impl PartialOrd for LogLevelFilter {
    #[inline]
    fn partial_cmp(&self, other: &LogLevelFilter) -> Option<cmp::Ordering> {
        Some(self.cmp(other))
    }
}

impl PartialOrd<LogLevel> for LogLevelFilter {
    #[inline]
    fn partial_cmp(&self, other: &LogLevel) -> Option<cmp::Ordering> {
        other.partial_cmp(self).map(|x| x.reverse())
    }
}

impl Ord for LogLevelFilter {
    #[inline]
    fn cmp(&self, other: &LogLevelFilter) -> cmp::Ordering {
        (*self as usize).cmp(&(*other as usize))
    }
}

impl FromStr for LogLevelFilter {
    type Err = ();
    fn from_str(level: &str) -> Result<LogLevelFilter, ()> {
        ok_or(LOG_LEVEL_NAMES.iter()
                    .position(|&name| name.eq_ignore_ascii_case(level))
                    .map(|p| LogLevelFilter::from_usize(p).unwrap()), ())
    }
}

impl LogLevelFilter {
    fn from_usize(u: usize) -> Option<LogLevelFilter> {
        match u {
            0 => Some(LogLevelFilter::Off),
            1 => Some(LogLevelFilter::Error),
            2 => Some(LogLevelFilter::Warn),
            3 => Some(LogLevelFilter::Info),
            4 => Some(LogLevelFilter::Debug),
            5 => Some(LogLevelFilter::Trace),
            _ => None
        }
    }
    /// Returns the most verbose logging level filter.
    #[inline]
    pub fn max() -> LogLevelFilter {
        LogLevelFilter::Trace
    }

    /// Converts `self` to the equivalent `LogLevel`.
    ///
    /// Returns `None` if `self` is `LogLevelFilter::Off`.
    #[inline]
    pub fn to_log_level(&self) -> Option<LogLevel> {
        LogLevel::from_usize(*self as usize)
    }
}

/// Metadata about a log message.
pub struct LogMetadata {
  pub level:  LogLevel,
  pub target: &'static str,
}

pub struct LogDirective {
    name:  Option<String>,
    level: LogLevelFilter,
}

fn ok_or<T, E>(t: Option<T>, e: E) -> Result<T, E> {
    match t {
        Some(t) => Ok(t),
        None => Err(e),
    }
}

pub fn parse_logging_spec(spec: &str) -> Vec<LogDirective> {
    let mut dirs = Vec::new();

    let mut parts = spec.split('/');
    let mods = parts.next();
    let _    = parts.next();
    if parts.next().is_some() {
        println!("warning: invalid logging spec '{}', \
                 ignoring it (too many '/'s)", spec);
        return dirs;
    }
    mods.map(|m| { for s in m.split(',') {
        if s.len() == 0 { continue }
        let mut parts = s.split('=');
        let (log_level, name) = match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) {
            (Some(part0), None, None) => {
                // if the single argument is a log-level string or number,
                // treat that as a global fallback
                match part0.parse() {
                    Ok(num) => (num, None),
                    Err(_) => (LogLevelFilter::max(), Some(part0)),
                }
            }
            (Some(part0), Some(""), None) => (LogLevelFilter::max(), Some(part0)),
            (Some(part0), Some(part1), None) => {
                match part1.parse() {
                    Ok(num) => (num, Some(part0)),
                    _ => {
                        println!("warning: invalid logging spec '{}', \
                                 ignoring it", part1);
                        continue
                    }
                }
            },
            _ => {
                println!("warning: invalid logging spec '{}', \
                         ignoring it", s);
                continue
            }
        };
        dirs.push(LogDirective {
            name: name.map(|s| s.to_string()),
            level: log_level,
        });
    }});

    return dirs;
}

#[macro_export]
macro_rules! log {
    (__inner__ $target:expr, $lvl:expr, $format:expr, $level_tag:expr,
     [$($transformed_args:ident),*], [$first_ident:ident $(, $other_idents:ident)*], $first_arg:expr $(, $other_args:expr)*) => ({
      let $first_ident = &$first_arg;
      log!(__inner__ $target, $lvl, $format, $level_tag, [$($transformed_args,)* $first_ident], [$($other_idents),*] $(, $other_args)*);
    });

    (__inner__ $target:expr, $lvl:expr, $format:expr, $level_tag:expr,
     [$($final_args:ident),*], [$($idents:ident),*]) => ({
      static _META: $crate::logging::LogMetadata = $crate::logging::LogMetadata {
          level:  $lvl,
          target: module_path!(),
      };
      {
        $crate::logging::LOGGER.with(|l| {
          l.borrow_mut().log(
            &_META,
            format_args!(
              concat!("{}\t{}\t{}\t{}\t{}\t", $format, '\n'),
              ::time::now_utc().rfc3339(), ::time::precise_time_ns(), l.borrow().pid,
              $level_tag, l.borrow().tag $(, $final_args)*)
          );
        });
      }
    });
    ($lvl:expr, $format:expr, $level_tag:expr $(, $args:expr)+) => {
      log!(__inner__ module_path!(), $lvl, $format, $level_tag, [], [a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v]
                  $(, $args)+)
    };
    ($lvl:expr, $format:expr, $level_tag:expr) => {
      log!(__inner__ module_path!(), $lvl, $format, $level_tag, [], [a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v])
    };
}

#[macro_export]
macro_rules! error {
    ($format:expr, $($arg:tt)*) => {
        log!($crate::logging::LogLevel::Error, $format, "ERROR", $($arg)*);
    };
    ($format:expr) => {
        log!($crate::logging::LogLevel::Error, $format, "ERROR");
    };
}

#[macro_export]
macro_rules! warn {
    ($format:expr, $($arg:tt)*) => {
        use time;
        log!($crate::logging::LogLevel::Warn, $format, "WARN", $($arg)*);
    };
    ($format:expr) => {
        log!($crate::logging::LogLevel::Warn, $format, "WARN");
    }
}

#[macro_export]
macro_rules! info {
    ($format:expr, $($arg:tt)*) => {
        log!($crate::logging::LogLevel::Info, $format, "INFO", $($arg)*);
    };
    ($format:expr) => {
        log!($crate::logging::LogLevel::Info, $format, "INFO");
    }
}

#[macro_export]
macro_rules! debug {
    ($format:expr, $($arg:tt)*) => {
        #[cfg(debug_assertions)]
        log!($crate::logging::LogLevel::Debug, concat!("{}\t", $format),
          "DEBUG", {module_path!()}, $($arg)*);
    };
    ($format:expr) => {
        #[cfg(debug_assertions)]
        log!($crate::logging::LogLevel::Debug, concat!("{}\t", $format),
          "DEBUG", {module_path!()});
    }
}

#[macro_export]
macro_rules! trace {
    ($format:expr, $($arg:tt)*) => (
        #[cfg(debug_assertions)]
        log!($crate::logging::LogLevel::Trace, concat!("{}\t", $format),
          "TRACE", module_path!(), $($arg)*);
    );
    ($format:expr) => (
        #[cfg(debug_assertions)]
        log!($crate::logging::LogLevel::Trace, concat!("{}\t", $format),
          "TRACE", module_path!());
    )
}

#[macro_export]
macro_rules! setup_test_logger {
  () => (
    $crate::logging::Logger::init(module_path!().to_string(), "error", $crate::logging::LoggerBackend::Stdout(::std::io::stdout()));
  );
}
<|endoftext|>


<commit_before>use std::fs::Metadata;
use std::path::Path;
use std::time::SystemTime;
use super::Timestamp;

/// TODO: FIXME.
pub trait GetTime {
    /// TODO: FIXME.
    fn last_modification(&self) -> Result<Timestamp, ()>;

    /// TODO: FIXME.
    fn last_access(&self) -> Result<Timestamp, ()>;

    /// TODO: FIXME.
    fn creation(&self) -> Result<Timestamp, ()>;
}

impl GetTime for Metadata {
    fn last_modification(&self) -> Result<Timestamp, ()> {
        unimplemented!()
    }

    fn last_access(&self) -> Result<Timestamp, ()> {
        unimplemented!()
    }

    fn creation(&self) -> Result<Timestamp, ()> {
        unimplemented!()
    }
}

impl GetTime for Path {
    fn last_modification(&self) -> Result<Timestamp, ()> {
        unimplemented!()
    }

    fn last_access(&self) -> Result<Timestamp, ()> {
        unimplemented!()
    }

    fn creation(&self) -> Result<Timestamp, ()> {
        unimplemented!()
    }
}

impl GetTime for str {
    fn last_modification(&self) -> Result<Timestamp, ()> {
        unimplemented!()
    }

    fn last_access(&self) -> Result<Timestamp, ()> {
        unimplemented!()
    }

    fn creation(&self) -> Result<Timestamp, ()> {
        unimplemented!()
    }
}

fn convert_time(time: &SystemTime) {
}
<commit_msg>Work in progress<commit_after>use std::fs::Metadata;
use std::path::Path;
use std::time::{SystemTime, SystemTimeError, UNIX_EPOCH, Duration};
use super::Timestamp;

/// TODO: FIXME.
pub trait GetTime {
    /// TODO: FIXME.
    fn last_modification(&self) -> Result<Timestamp, ()>;

    /// TODO: FIXME.
    fn last_access(&self) -> Result<Timestamp, ()>;

    /// TODO: FIXME.
    fn creation(&self) -> Result<Timestamp, ()>;
}

impl GetTime for Metadata {
    fn last_modification(&self) -> Result<Timestamp, ()> {
        unimplemented!()
    }

    fn last_access(&self) -> Result<Timestamp, ()> {
        unimplemented!()
    }

    fn creation(&self) -> Result<Timestamp, ()> {
        unimplemented!()
    }
}

impl GetTime for Path {
    fn last_modification(&self) -> Result<Timestamp, ()> {
        unimplemented!()
    }

    fn last_access(&self) -> Result<Timestamp, ()> {
        unimplemented!()
    }

    fn creation(&self) -> Result<Timestamp, ()> {
        unimplemented!()
    }
}

impl GetTime for str {
    fn last_modification(&self) -> Result<Timestamp, ()> {
        unimplemented!()
    }

    fn last_access(&self) -> Result<Timestamp, ()> {
        unimplemented!()
    }

    fn creation(&self) -> Result<Timestamp, ()> {
        unimplemented!()
    }
}

fn convert_time(time: &SystemTime) -> Result<Duration, SystemTimeError> {
    time.duration_since(UNIX_EPOCH)
}
<|endoftext|>


<commit_before>use std::cmp;

use lz77::LongestMatch;
use util::{ZOPFLI_CACHE_LENGTH, ZOPFLI_MAX_MATCH, ZOPFLI_MIN_MATCH};

// Cache used by ZopfliFindLongestMatch to remember previously found length/dist
// values.
// This is needed because the squeeze runs will ask these values multiple times for
// the same position.
// Uses large amounts of memory, since it has to remember the distance belonging
// to every possible shorter-than-the-best length (the so called "sublen" array).
pub struct ZopfliLongestMatchCache {
    length: Vec<u16>,
    dist: Vec<u16>,
    sublen: Vec<u8>,
}

impl ZopfliLongestMatchCache {
    pub fn new(blocksize: usize) -> ZopfliLongestMatchCache {
        ZopfliLongestMatchCache {
            /* length > 0 and dist 0 is invalid combination, which indicates on purpose
            that this cache value is not filled in yet. */
            length: vec![1; blocksize],
            dist: vec![0; blocksize],
            /* Rather large amount of memory. */
            sublen: vec![0; ZOPFLI_CACHE_LENGTH * blocksize * 3],
        }
    }

    fn length_at(&self, pos: usize) -> u16 {
        self.length[pos]
    }

    fn dist_at(&self, pos: usize) -> u16 {
        self.dist[pos]
    }

    fn store_length_at(&mut self, pos: usize, val: u16) {
        self.length[pos] = val;
    }

    fn store_dist_at(&mut self, pos: usize, val: u16) {
        self.dist[pos] = val;
    }

    /// Returns the length up to which could be stored in the cache.
    fn max_sublen(&self, pos: usize) -> u32 {
        let start = ZOPFLI_CACHE_LENGTH * pos * 3;
        if self.sublen[start + 1] == 0 && self.sublen[start + 2] == 0 {
            return 0;  // No sublen cached.
        }
        self.sublen[start + ((ZOPFLI_CACHE_LENGTH - 1) * 3)] as u32 + 3
    }

    /// Stores sublen array in the cache.
    fn store_sublen(&mut self, sublen: &[u16], pos: usize, length: usize) {
        if length < 3 {
            return;
        }

        let start = ZOPFLI_CACHE_LENGTH * pos * 3;
        let mut i = 3;
        let mut j = 0;
        let mut bestlength = 0;
        while i <= length {
            if i == length || sublen[i] != sublen[i + 1] {
                self.sublen[start + (j * 3)] = (i - 3) as u8;
                self.sublen[start + (j * 3 + 1)] = sublen[i].wrapping_rem(256) as u8;
                self.sublen[start + (j * 3 + 2)] = ((sublen[i] >> 8)).wrapping_rem(256) as u8;
                bestlength = i as u32;
                j += 1;
                if j >= ZOPFLI_CACHE_LENGTH {
                    break;
                }
            }
            i += 1;
        }

        if j < ZOPFLI_CACHE_LENGTH {
            assert!(bestlength == length as u32);
            self.sublen[start + ((ZOPFLI_CACHE_LENGTH - 1) * 3)] = (bestlength - 3) as u8;
        } else {
            assert!(bestlength <= length as u32);
        }
        assert!(bestlength == self.max_sublen(pos));
    }

    /// Extracts sublen array from the cache.
    fn fetch_sublen(&self, pos: usize, length: usize, sublen: &mut [u16]) {
        if length < 3 {
            return;
        }

        let start = ZOPFLI_CACHE_LENGTH * pos * 3;
        let maxlength = self.max_sublen(pos) as usize;
        let mut prevlength = 0;

        for j in 0..ZOPFLI_CACHE_LENGTH {
            let length = self.sublen[start + (j * 3)] as usize + 3;
            let dist = self.sublen[start + (j * 3 + 1)] as u16 + 256 * self.sublen[start + (j * 3 + 2)] as u16;

            let mut i = prevlength;
            while i <= length {
                sublen[i] = dist;
                i += 1;
            }
            if length == maxlength {
                break;
            }
            prevlength = length + 1;
        }
    }
}

pub trait Cache {
    fn try_get(&self, pos: usize, limit: usize, sublen: &mut Option<&mut [u16]>, blockstart: usize) -> LongestMatch;
    fn store(&mut self, pos: usize, limit: usize, sublen: &mut Option<&mut [u16]>, distance: u16, length: u16, blockstart: usize);
}

pub struct NoCache;

impl Cache for NoCache {
    fn try_get(&self, _: usize, limit: usize, _: &mut Option<&mut [u16]>, _: usize) -> LongestMatch {
        LongestMatch::new(limit)
    }

    fn store(&mut self, _: usize, _: usize, _: &mut Option<&mut [u16]>, _: u16, _: u16, _: usize) {
        // Nowhere to store
    }
}

impl Cache for ZopfliLongestMatchCache {
    fn try_get(&self, pos: usize, mut limit: usize, sublen: &mut Option<&mut [u16]>, blockstart: usize) -> LongestMatch {
        let mut longest_match = LongestMatch::new(limit);

        /* The LMC cache starts at the beginning of the block rather than the
        beginning of the whole array. */
        let lmcpos = pos - blockstart;

        /* Length > 0 and dist 0 is invalid combination, which indicates on purpose
        that this cache value is not filled in yet. */
        let length_lmcpos = self.length_at(lmcpos);
        let dist_lmcpos = self.dist_at(lmcpos);
        let cache_available = length_lmcpos == 0 || dist_lmcpos != 0;
        let max_sublen = self.max_sublen(lmcpos);
        let limit_ok_for_cache = limit == ZOPFLI_MAX_MATCH || length_lmcpos <= limit as u16 || ( sublen.is_some() && max_sublen >= limit as u32);

        if limit_ok_for_cache && cache_available {
            if sublen.is_none() || length_lmcpos as u32 <= max_sublen {
                let length = cmp::min(length_lmcpos, limit as u16);
                let distance;
                if let &mut Some(ref mut subl) = sublen {
                    self.fetch_sublen(lmcpos, length as usize, subl);
                    distance = subl[length as usize];

                    if limit == ZOPFLI_MAX_MATCH && length >= ZOPFLI_MIN_MATCH as u16 {
                        assert!(subl[length as usize] == dist_lmcpos);
                    }
                } else {
                    distance = dist_lmcpos;
                }
                longest_match.distance = distance;
                longest_match.length = length;
                longest_match.from_cache = true;
                return longest_match;
            }
            /* Can't use much of the cache, since the "sublens" need to be calculated,
            but at least we already know when to stop. */
            limit = length_lmcpos as usize;
            longest_match.limit = limit;
        }

        longest_match
    }

    fn store(&mut self, pos: usize, limit: usize, sublen: &mut Option<&mut [u16]>, distance: u16, length: u16, blockstart: usize) {
        if let &mut Some(ref mut subl) = sublen {
            /* Length > 0 and dist 0 is invalid combination, which indicates on purpose
            that this cache value is not filled in yet. */
            let lmcpos = pos - blockstart;
            let cache_available = self.length_at(lmcpos) == 0 || self.dist_at(lmcpos) != 0;

            if limit == ZOPFLI_MAX_MATCH && !cache_available {
                assert!(self.length_at(lmcpos) == 1 && self.dist_at(lmcpos) == 0);
                if length < ZOPFLI_MIN_MATCH as u16 {
                    self.store_dist_at(lmcpos, 0);
                    self.store_length_at(lmcpos, 0);
                } else {
                    self.store_dist_at(lmcpos, distance);
                    self.store_length_at(lmcpos, length);
                }
                assert!(!(self.length_at(lmcpos) == 1 && self.dist_at(lmcpos) == 0));
                self.store_sublen(subl, lmcpos, length as usize);
            }
        }
    }
}
<commit_msg>Remove unnecessary parens<commit_after>use std::cmp;

use lz77::LongestMatch;
use util::{ZOPFLI_CACHE_LENGTH, ZOPFLI_MAX_MATCH, ZOPFLI_MIN_MATCH};

// Cache used by ZopfliFindLongestMatch to remember previously found length/dist
// values.
// This is needed because the squeeze runs will ask these values multiple times for
// the same position.
// Uses large amounts of memory, since it has to remember the distance belonging
// to every possible shorter-than-the-best length (the so called "sublen" array).
pub struct ZopfliLongestMatchCache {
    length: Vec<u16>,
    dist: Vec<u16>,
    sublen: Vec<u8>,
}

impl ZopfliLongestMatchCache {
    pub fn new(blocksize: usize) -> ZopfliLongestMatchCache {
        ZopfliLongestMatchCache {
            /* length > 0 and dist 0 is invalid combination, which indicates on purpose
            that this cache value is not filled in yet. */
            length: vec![1; blocksize],
            dist: vec![0; blocksize],
            /* Rather large amount of memory. */
            sublen: vec![0; ZOPFLI_CACHE_LENGTH * blocksize * 3],
        }
    }

    fn length_at(&self, pos: usize) -> u16 {
        self.length[pos]
    }

    fn dist_at(&self, pos: usize) -> u16 {
        self.dist[pos]
    }

    fn store_length_at(&mut self, pos: usize, val: u16) {
        self.length[pos] = val;
    }

    fn store_dist_at(&mut self, pos: usize, val: u16) {
        self.dist[pos] = val;
    }

    /// Returns the length up to which could be stored in the cache.
    fn max_sublen(&self, pos: usize) -> u32 {
        let start = ZOPFLI_CACHE_LENGTH * pos * 3;
        if self.sublen[start + 1] == 0 && self.sublen[start + 2] == 0 {
            return 0;  // No sublen cached.
        }
        self.sublen[start + ((ZOPFLI_CACHE_LENGTH - 1) * 3)] as u32 + 3
    }

    /// Stores sublen array in the cache.
    fn store_sublen(&mut self, sublen: &[u16], pos: usize, length: usize) {
        if length < 3 {
            return;
        }

        let start = ZOPFLI_CACHE_LENGTH * pos * 3;
        let mut i = 3;
        let mut j = 0;
        let mut bestlength = 0;
        while i <= length {
            if i == length || sublen[i] != sublen[i + 1] {
                self.sublen[start + (j * 3)] = (i - 3) as u8;
                self.sublen[start + (j * 3 + 1)] = sublen[i].wrapping_rem(256) as u8;
                self.sublen[start + (j * 3 + 2)] = (sublen[i] >> 8).wrapping_rem(256) as u8;
                bestlength = i as u32;
                j += 1;
                if j >= ZOPFLI_CACHE_LENGTH {
                    break;
                }
            }
            i += 1;
        }

        if j < ZOPFLI_CACHE_LENGTH {
            assert!(bestlength == length as u32);
            self.sublen[start + ((ZOPFLI_CACHE_LENGTH - 1) * 3)] = (bestlength - 3) as u8;
        } else {
            assert!(bestlength <= length as u32);
        }
        assert!(bestlength == self.max_sublen(pos));
    }

    /// Extracts sublen array from the cache.
    fn fetch_sublen(&self, pos: usize, length: usize, sublen: &mut [u16]) {
        if length < 3 {
            return;
        }

        let start = ZOPFLI_CACHE_LENGTH * pos * 3;
        let maxlength = self.max_sublen(pos) as usize;
        let mut prevlength = 0;

        for j in 0..ZOPFLI_CACHE_LENGTH {
            let length = self.sublen[start + (j * 3)] as usize + 3;
            let dist = self.sublen[start + (j * 3 + 1)] as u16 + 256 * self.sublen[start + (j * 3 + 2)] as u16;

            let mut i = prevlength;
            while i <= length {
                sublen[i] = dist;
                i += 1;
            }
            if length == maxlength {
                break;
            }
            prevlength = length + 1;
        }
    }
}

pub trait Cache {
    fn try_get(&self, pos: usize, limit: usize, sublen: &mut Option<&mut [u16]>, blockstart: usize) -> LongestMatch;
    fn store(&mut self, pos: usize, limit: usize, sublen: &mut Option<&mut [u16]>, distance: u16, length: u16, blockstart: usize);
}

pub struct NoCache;

impl Cache for NoCache {
    fn try_get(&self, _: usize, limit: usize, _: &mut Option<&mut [u16]>, _: usize) -> LongestMatch {
        LongestMatch::new(limit)
    }

    fn store(&mut self, _: usize, _: usize, _: &mut Option<&mut [u16]>, _: u16, _: u16, _: usize) {
        // Nowhere to store
    }
}

impl Cache for ZopfliLongestMatchCache {
    fn try_get(&self, pos: usize, mut limit: usize, sublen: &mut Option<&mut [u16]>, blockstart: usize) -> LongestMatch {
        let mut longest_match = LongestMatch::new(limit);

        /* The LMC cache starts at the beginning of the block rather than the
        beginning of the whole array. */
        let lmcpos = pos - blockstart;

        /* Length > 0 and dist 0 is invalid combination, which indicates on purpose
        that this cache value is not filled in yet. */
        let length_lmcpos = self.length_at(lmcpos);
        let dist_lmcpos = self.dist_at(lmcpos);
        let cache_available = length_lmcpos == 0 || dist_lmcpos != 0;
        let max_sublen = self.max_sublen(lmcpos);
        let limit_ok_for_cache = limit == ZOPFLI_MAX_MATCH || length_lmcpos <= limit as u16 || ( sublen.is_some() && max_sublen >= limit as u32);

        if limit_ok_for_cache && cache_available {
            if sublen.is_none() || length_lmcpos as u32 <= max_sublen {
                let length = cmp::min(length_lmcpos, limit as u16);
                let distance;
                if let &mut Some(ref mut subl) = sublen {
                    self.fetch_sublen(lmcpos, length as usize, subl);
                    distance = subl[length as usize];

                    if limit == ZOPFLI_MAX_MATCH && length >= ZOPFLI_MIN_MATCH as u16 {
                        assert!(subl[length as usize] == dist_lmcpos);
                    }
                } else {
                    distance = dist_lmcpos;
                }
                longest_match.distance = distance;
                longest_match.length = length;
                longest_match.from_cache = true;
                return longest_match;
            }
            /* Can't use much of the cache, since the "sublens" need to be calculated,
            but at least we already know when to stop. */
            limit = length_lmcpos as usize;
            longest_match.limit = limit;
        }

        longest_match
    }

    fn store(&mut self, pos: usize, limit: usize, sublen: &mut Option<&mut [u16]>, distance: u16, length: u16, blockstart: usize) {
        if let &mut Some(ref mut subl) = sublen {
            /* Length > 0 and dist 0 is invalid combination, which indicates on purpose
            that this cache value is not filled in yet. */
            let lmcpos = pos - blockstart;
            let cache_available = self.length_at(lmcpos) == 0 || self.dist_at(lmcpos) != 0;

            if limit == ZOPFLI_MAX_MATCH && !cache_available {
                assert!(self.length_at(lmcpos) == 1 && self.dist_at(lmcpos) == 0);
                if length < ZOPFLI_MIN_MATCH as u16 {
                    self.store_dist_at(lmcpos, 0);
                    self.store_length_at(lmcpos, 0);
                } else {
                    self.store_dist_at(lmcpos, distance);
                    self.store_length_at(lmcpos, length);
                }
                assert!(!(self.length_at(lmcpos) == 1 && self.dist_at(lmcpos) == 0));
                self.store_sublen(subl, lmcpos, length as usize);
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Defines the `SearchExecutor` trait.

use std::time::Duration;
use std::sync::Arc;
use std::sync::mpsc::{Sender, Receiver, TryRecvError};
use uci::SetOption;
use moves::Move;
use value::*;
use depth::*;
use hash_table::*;
use search_node::SearchNode;

/// Parameters describing a search.
///
/// **Important note:** `lower_bound` and `upper_bound` fields
/// together give the interval within which an as precise as possible
/// evaluation is required. If during the search is determined that
/// the exact evaluation is outside of this interval, the search may
/// return a value that is closer to the the interval bounds than the
/// exact evaluation, but always staying on the correct side of the
/// interval (i.e. "fail-soft" semantics).
#[derive(Clone, Debug)]
pub struct SearchParams<T: SearchNode> {
    /// A number identifying the search.
    pub search_id: usize,

    /// The root position for the search.
    pub position: T,

    /// The requested search depth.
    ///
    /// Should be between `0` and `DEPTH_MAX`.
    pub depth: Depth,

    /// The lower bound for the search.
    ///
    /// Should be no lesser than `VALUE_MIN`.
    pub lower_bound: Value,

    /// The upper bound for the search.
    ///
    /// Should be greater than `lower_bound`, but no greater than
    /// `VALUE_MAX`.
    pub upper_bound: Value,

    /// Restricts the analysis to the supplied list of moves only.
    ///
    /// * All moves in the list should be legal.
    ///
    /// * The same move should not occur more than once.
    ///
    /// * If the root position is final, the supplied list of moves
    ///   should be empty.
    ///
    /// The behavior of the search is *undefined* if the root position
    /// is not final, but `searchmoves` is empty.
    pub searchmoves: Vec<Move>,
}

/// A progress report from a search.
#[derive(Clone, Debug)]
pub struct SearchReport<T> {
    /// The ID assigned to the search.
    ///
    /// Should be the same for all reports from a given search.
    pub search_id: usize,

    /// The number of positions searched so far.
    ///
    /// Should be no lesser than the value sent in the previous
    /// report.
    pub searched_nodes: u64,

    /// The search depth completed so far.
    ///
    /// Should be no lesser than `0`. Also, no lesser than the value
    /// sent in the previous report, and no greater than the requested
    /// search depth. If the search has not been forcefully stopped,
    /// the last reported `depth` should be the requested search
    /// depth.
    ///
    /// **Note:** Depth-first searches should send `0` in all reports
    /// except the last one.
    pub depth: Depth,

    /// The evaluation of the root position so far, or `VALUE_UNKNOWN`
    /// if not available.
    ///
    /// If the search has not been forcefully stopped, the last report
    /// should contain the calculated final evaluation.
    ///
    /// **Note:** Depth-first searches should send `VALUE_UNKNOWN` in
    /// all reports except the last one.
    pub value: Value,

    /// Whether the search is done.
    ///
    /// Should be `false` for all reports except the last one.
    pub done: bool,

    /// Auxiliary data.
    ///
    /// For example, this may contain calculated principal
    /// variation(s).
    pub data: T,
}

/// A trait for executing consecutive searches in different starting
/// positions.
///
/// Chess programs must rely on some type of search in order to play
/// reasonably. Searching involves looking ahead at different move
/// sequences and evaluating the positions after making the
/// moves. Normally, this is done by traversing and min-maxing a
/// tree-like data-structure by some algorithm. To implement your own
/// search algorithm, you must define a type that implements the
/// `SearchExecutor` trait.
///
/// There are two types of searches that should be distinguished:
///
/// * **Depth-first search.**
///
///   Starts at the root and explores as far as possible along each
///   branch before backtracking.
///
/// * **Iterative deepening search.**
///
///   A depth-first search is executed with a depth of one ply, then
///   the depth is incremented and another search is executed. This
///   process is repeated until the search is terminated or the
///   requested search depth is reached. In case of a terminated
///   search, the engine can always fall back to the move selected in
///   the last iteration of the search.
///
///   You can use `stock::Deepening` to turn a depth-first searcher
///   into a deepening searcher.
///
/// Here is what the engine does on each move:
///
/// 1. Calls `start_search`.
///
/// 2. Continues calling `wait_report` and `try_recv_report`
///    periodically, until the returned report indicates that the
///    search is done.
///
/// 3. Obtains the principal variation(s) from search reports, or
///    directly from the transposition table.
pub trait SearchExecutor: SetOption {
    /// The type of transposition (hash) table that the implementation
    /// works with.
    type HashTable: HashTable;

    /// The type of search node that the implementation works with.
    type SearchNode: SearchNode;

    /// The type of auxiliary data that search progress reports carry.
    type ReportData;

    /// Creates a new instance.
    ///
    /// `tt` gives a transposition table for the new search executor
    /// to work with.
    fn new(tt: Arc<Self::HashTable>) -> Self;

    /// Starts a new search.
    ///
    /// This method must not block the current thread. After calling
    /// `start_search`, `wait_report` and `try_recv_report` will be
    /// called periodically until the returned report indicates that
    /// the search is done. A new search will not be started until the
    /// previous search is done.
    ///
    /// **Important note:** The executing search must send periodic
    /// reports, informing about its current progress. Also, the
    /// executing search must continuously update the transposition
    /// table so that, at each moment, it contains the results of the
    /// work done so far.
    fn start_search(&mut self, params: SearchParams<Self::SearchNode>);

    /// Waits until a search progress report is available, timing out
    /// after a specified duration or earlier.
    fn wait_report(&self, timeout_after: Duration);

    /// Attempts to return a search progress report without blocking.
    fn try_recv_report(&mut self) -> Result<SearchReport<Self::ReportData>, TryRecvError>;

    /// Sends a message to the currently executing search.
    ///
    /// The message format is not specified, but the implementation
    /// **must** meet the following requirements:
    ///
    /// * Unrecognized messages are ignored.
    ///
    /// * The message `"TERMINATE"` is recognized as a request to
    ///   terminate the current search.
    ///
    /// * Receiving two or more termination requests for the same
    ///   search does not cause any problems.
    ///
    /// **Note:** Normally, after sending one or more `"TERMINATE"`
    /// messages, `wait_report` and `try_recv_report` methods will
    /// continue to be called periodically until the returned report
    /// indicates that the search is done.
    fn send_message(&mut self, msg: &str);
}

pub trait Search: SetOption {
    /// The type of transposition (hash) table that the implementation
    /// works with.
    type HashTable: HashTable;

    /// The type of search node that the implementation works with.
    type SearchNode: SearchNode;

    /// The type of auxiliary data that search progress reports carry.
    type ReportData;

    /// Creates a new instance.
    ///
    /// `tt` gives a transposition table for the new search executor
    /// to work with.
    fn start(tt: Arc<Self::HashTable>,
             messages_from: Receiver<&str>,
             reports_to: Sender<SearchReport<Self::ReportData>>,
             params: SearchParams<Self::SearchNode>);
}
<commit_msg>implement StdSearchExecutor<commit_after>//! Defines the `SearchExecutor` trait.

use std::time::Duration;
use std::cell::RefCell;
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver, TryRecvError};
use uci::{SetOption, OptionDescription};
use moves::Move;
use value::*;
use depth::*;
use hash_table::*;
use search_node::SearchNode;

/// Parameters describing a search.
///
/// **Important note:** `lower_bound` and `upper_bound` fields
/// together give the interval within which an as precise as possible
/// evaluation is required. If during the search is determined that
/// the exact evaluation is outside of this interval, the search may
/// return a value that is closer to the the interval bounds than the
/// exact evaluation, but always staying on the correct side of the
/// interval (i.e. "fail-soft" semantics).
#[derive(Clone, Debug)]
pub struct SearchParams<T: SearchNode> {
    /// A number identifying the search.
    pub search_id: usize,

    /// The root position for the search.
    pub position: T,

    /// The requested search depth.
    ///
    /// Should be between `0` and `DEPTH_MAX`.
    pub depth: Depth,

    /// The lower bound for the search.
    ///
    /// Should be no lesser than `VALUE_MIN`.
    pub lower_bound: Value,

    /// The upper bound for the search.
    ///
    /// Should be greater than `lower_bound`, but no greater than
    /// `VALUE_MAX`.
    pub upper_bound: Value,

    /// Restricts the analysis to the supplied list of moves only.
    ///
    /// * All moves in the list should be legal.
    ///
    /// * The same move should not occur more than once.
    ///
    /// * If the root position is final, the supplied list of moves
    ///   should be empty.
    ///
    /// The behavior of the search is *undefined* if the root position
    /// is not final, but `searchmoves` is empty.
    pub searchmoves: Vec<Move>,
}

/// A progress report from a search.
#[derive(Clone, Debug)]
pub struct SearchReport<T> {
    /// The ID assigned to the search.
    ///
    /// Should be the same for all reports from a given search.
    pub search_id: usize,

    /// The number of positions searched so far.
    ///
    /// Should be no lesser than the value sent in the previous
    /// report.
    pub searched_nodes: u64,

    /// The search depth completed so far.
    ///
    /// Should be no lesser than `0`. Also, no lesser than the value
    /// sent in the previous report, and no greater than the requested
    /// search depth. If the search has not been forcefully stopped,
    /// the last reported `depth` should be the requested search
    /// depth.
    ///
    /// **Note:** Depth-first searches should send `0` in all reports
    /// except the last one.
    pub depth: Depth,

    /// The evaluation of the root position so far, or `VALUE_UNKNOWN`
    /// if not available.
    ///
    /// If the search has not been forcefully stopped, the last report
    /// should contain the calculated final evaluation.
    ///
    /// **Note:** Depth-first searches should send `VALUE_UNKNOWN` in
    /// all reports except the last one.
    pub value: Value,

    /// Whether the search is done.
    ///
    /// Should be `false` for all reports except the last one.
    pub done: bool,

    /// Auxiliary data.
    ///
    /// For example, this may contain calculated principal
    /// variation(s).
    pub data: T,
}

/// A trait for executing consecutive searches in different starting
/// positions.
///
/// Chess programs must rely on some type of search in order to play
/// reasonably. Searching involves looking ahead at different move
/// sequences and evaluating the positions after making the
/// moves. Normally, this is done by traversing and min-maxing a
/// tree-like data-structure by some algorithm. To implement your own
/// search algorithm, you must define a type that implements the
/// `SearchExecutor` trait.
///
/// There are two types of searches that should be distinguished:
///
/// * **Depth-first search.**
///
///   Starts at the root and explores as far as possible along each
///   branch before backtracking.
///
/// * **Iterative deepening search.**
///
///   A depth-first search is executed with a depth of one ply, then
///   the depth is incremented and another search is executed. This
///   process is repeated until the search is terminated or the
///   requested search depth is reached. In case of a terminated
///   search, the engine can always fall back to the move selected in
///   the last iteration of the search.
///
///   You can use `stock::Deepening` to turn a depth-first searcher
///   into a deepening searcher.
///
/// Here is what the engine does on each move:
///
/// 1. Calls `start_search`.
///
/// 2. Continues calling `wait_report` and `try_recv_report`
///    periodically, until the returned report indicates that the
///    search is done.
///
/// 3. Obtains the principal variation(s) from search reports, or
///    directly from the transposition table.
pub trait SearchExecutor: SetOption {
    /// The type of transposition (hash) table that the implementation
    /// works with.
    type HashTable: HashTable;

    /// The type of search node that the implementation works with.
    type SearchNode: SearchNode;

    /// The type of auxiliary data that search progress reports carry.
    type ReportData;

    /// Creates a new instance.
    ///
    /// `tt` gives a transposition table for the new search executor
    /// to work with.
    fn new(tt: Arc<Self::HashTable>) -> Self;

    /// Starts a new search.
    ///
    /// This method must not block the current thread. After calling
    /// `start_search`, `wait_report` and `try_recv_report` will be
    /// called periodically until the returned report indicates that
    /// the search is done. A new search will not be started until the
    /// previous search is done.
    ///
    /// **Important note:** The executing search must send periodic
    /// reports, informing about its current progress. Also, the
    /// executing search must continuously update the transposition
    /// table so that, at each moment, it contains the results of the
    /// work done so far.
    fn start_search(&mut self, params: SearchParams<Self::SearchNode>);

    /// Waits until a search progress report is available, timing out
    /// after a specified duration or earlier.
    fn wait_report(&self, timeout_after: Duration);

    /// Attempts to return a search progress report without blocking.
    fn try_recv_report(&mut self) -> Result<SearchReport<Self::ReportData>, TryRecvError>;

    /// Sends a message to the currently executing search.
    ///
    /// The message format is not specified, but the implementation
    /// **must** meet the following requirements:
    ///
    /// * Unrecognized messages are ignored.
    ///
    /// * The message `"TERMINATE"` is recognized as a request to
    ///   terminate the current search.
    ///
    /// * Receiving two or more termination requests for the same
    ///   search does not cause any problems.
    ///
    /// **Note:** Normally, after sending one or more `"TERMINATE"`
    /// messages, `wait_report` and `try_recv_report` methods will
    /// continue to be called periodically until the returned report
    /// indicates that the search is done.
    fn send_message(&mut self, msg: &str);
}

pub trait Search: SetOption {
    /// The type of transposition (hash) table that the implementation
    /// works with.
    type HashTable: HashTable;

    /// The type of search node that the implementation works with.
    type SearchNode: SearchNode;

    /// The type of auxiliary data that search progress reports carry.
    type ReportData;

    /// Creates a new instance.
    ///
    /// `tt` gives a transposition table for the new search executor
    /// to work with.
    fn start(tt: Arc<Self::HashTable>,
             messages_from: Receiver<String>,
             reports_to: Sender<SearchReport<Self::ReportData>>,
             params: SearchParams<Self::SearchNode>);
}

struct StdSearchExecutor<T: Search> {
    tt: Arc<T::HashTable>,
    messages_tx: Sender<String>,
    reports_rx: Receiver<SearchReport<T::ReportData>>,
    reports_tx: Sender<SearchReport<T::ReportData>>,
    pending_report: RefCell<Option<SearchReport<T::ReportData>>>,
}

impl<T: Search> SearchExecutor for StdSearchExecutor<T> {
    type HashTable = T::HashTable;

    type SearchNode = T::SearchNode;

    type ReportData = T::ReportData;

    fn new(tt: Arc<Self::HashTable>) -> Self {
        let (messages_tx, _) = channel();
        let (reports_tx, reports_rx) = channel();
        Self {
            tt: tt,
            messages_tx: messages_tx,
            reports_rx: reports_rx,
            reports_tx: reports_tx,
            pending_report: RefCell::new(None),
        }
    }

    fn start_search(&mut self, params: SearchParams<Self::SearchNode>) {
        let (messages_tx, messages_rx) = channel();
        self.messages_tx = messages_tx;
        T::start(self.tt.clone(), messages_rx, self.reports_tx.clone(), params);
    }

    fn wait_report(&self, timeout_after: Duration) {
        let mut report = self.pending_report.borrow_mut();
        if report.is_none() {
            *report = self.reports_rx.recv_timeout(timeout_after).ok();
        }
    }

    fn try_recv_report(&mut self) -> Result<SearchReport<Self::ReportData>, TryRecvError> {
        self.pending_report
            .borrow_mut()
            .take()
            .ok_or(TryRecvError::Empty)
            .or_else(|_| self.reports_rx.try_recv())
    }

    fn send_message(&mut self, msg: &str) {
        self.messages_tx.send(msg.to_string()).unwrap();
    }
}

impl<T: Search> SetOption for StdSearchExecutor<T> {
    fn options() -> Vec<(String, OptionDescription)> {
        T::options()
    }

    fn set_option(name: &str, value: &str) {
        T::set_option(name, value);
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::fs;
use std::env;
use std::time;
use std::path::Path;
use std::io::{Read, Write, Seek};

use uuid::Uuid;
use chan;
use sha1::Sha1;
use clap::{App, AppSettings};

use CliResult;

#[cfg(not(windows))]
use chan_signal::{notify, Signal};

pub struct TempFile {
    f: fs::File,
}

impl TempFile {
    pub fn new() -> io::Result<TempFile> {
        let mut path = env::temp_dir();
        path.push(Uuid::new_v4().to_hyphenated_string());
        let f = fs::OpenOptions::new()
            .read(true)
            .write(true)
            .create(true)
            .open(&path).unwrap();
        let _ = fs::remove_file(&path);
        Ok(TempFile {
            f: f
        })
    }

    pub fn open(&self) -> fs::File {
        let mut f = self.f.try_clone().unwrap();
        let _ = f.seek(io::SeekFrom::Start(0));
        f
    }
}

#[cfg(not(windows))]
pub fn run_or_interrupt<F>(f: F) -> Option<Signal>
    where F: FnOnce() -> (), F: Send + 'static
{
    let run = |_sdone: chan::Sender<()>| f();
    let signal = notify(&[Signal::INT, Signal::TERM]);
    let (sdone, rdone) = chan::sync(0);
    ::std::thread::spawn(move || run(sdone));

    let mut rv = None;

    chan_select! {
        signal.recv() -> signal => { rv = signal; },
        rdone.recv() => {}
    }

    rv
}

pub fn make_subcommand<'a, 'b: 'a>(name: &str) -> App<'a, 'b> {
    App::new(name)
        .setting(AppSettings::UnifiedHelpMessage)
        .setting(AppSettings::DisableVersion)
}

pub fn get_sha1_checksum(path: &Path) -> CliResult<String> {
    let mut sha = Sha1::new();
    let mut f = fs::File::open(path)?;
    let mut buf = [0u8; 16384];
    loop {
        let read = f.read(&mut buf)?;
        if read == 0 {
            break;
        }
        sha.update(&buf[..read]);
    }
    Ok(sha.hexdigest())
}

pub fn is_writable<P: AsRef<Path>>(path: P) -> bool {
    fs::OpenOptions::new().write(true).open(&path).map(|_| true).unwrap_or(false)
}

pub fn set_executable_mode<P: AsRef<Path>>(path: P) -> io::Result<()> {
    #[cfg(not(windows))]
    fn exec(path: &Path) -> io::Result<()> {
        use std::os::unix::fs::PermissionsExt;
        let mut perm = fs::metadata(&tmp_path)?.permissions();
        perm.set_mode(0o755);
        fs::set_permissions(&tmp_path, perm)
    }

    #[cfg(windows)]
    fn exec(path: &Path) -> io::Result<()> {
        Ok(())
    }

    exec(path)
}

pub fn prompt_to_continue(message: &str) -> io::Result<bool> {
    loop {
        print!("{} [y/n] ", message);
        io::stdout().flush()?;

        let mut buf = String::new();
        io::stdin().read_line(&mut buf)?;
        let input = buf.trim();

        if input == "y" {
            return Ok(true);
        } else if input == "n" {
            return Ok(false);
        }
        println!("invalid input!");
    }
}

pub fn prompt(message: &str) -> io::Result<String> {
    loop {
        print!("{}: ", message);
        io::stdout().flush()?;
        let mut buf = String::new();
        io::stdin().read_line(&mut buf)?;
        let input = buf.trim();
        if input.len() > 0 {
            return Ok(input.to_owned());
        }
    }
}

pub fn to_timestamp(tm: time::SystemTime) -> f64 {
    let duration = tm.duration_since(time::UNIX_EPOCH).unwrap();
    (duration.as_secs() as f64) + (duration.subsec_nanos() as f64 / 1e09)
}
<commit_msg>Fixed bad variable name<commit_after>use std::io;
use std::fs;
use std::env;
use std::time;
use std::path::Path;
use std::io::{Read, Write, Seek};

use uuid::Uuid;
use chan;
use sha1::Sha1;
use clap::{App, AppSettings};

use CliResult;

#[cfg(not(windows))]
use chan_signal::{notify, Signal};

pub struct TempFile {
    f: fs::File,
}

impl TempFile {
    pub fn new() -> io::Result<TempFile> {
        let mut path = env::temp_dir();
        path.push(Uuid::new_v4().to_hyphenated_string());
        let f = fs::OpenOptions::new()
            .read(true)
            .write(true)
            .create(true)
            .open(&path).unwrap();
        let _ = fs::remove_file(&path);
        Ok(TempFile {
            f: f
        })
    }

    pub fn open(&self) -> fs::File {
        let mut f = self.f.try_clone().unwrap();
        let _ = f.seek(io::SeekFrom::Start(0));
        f
    }
}

#[cfg(not(windows))]
pub fn run_or_interrupt<F>(f: F) -> Option<Signal>
    where F: FnOnce() -> (), F: Send + 'static
{
    let run = |_sdone: chan::Sender<()>| f();
    let signal = notify(&[Signal::INT, Signal::TERM]);
    let (sdone, rdone) = chan::sync(0);
    ::std::thread::spawn(move || run(sdone));

    let mut rv = None;

    chan_select! {
        signal.recv() -> signal => { rv = signal; },
        rdone.recv() => {}
    }

    rv
}

pub fn make_subcommand<'a, 'b: 'a>(name: &str) -> App<'a, 'b> {
    App::new(name)
        .setting(AppSettings::UnifiedHelpMessage)
        .setting(AppSettings::DisableVersion)
}

pub fn get_sha1_checksum(path: &Path) -> CliResult<String> {
    let mut sha = Sha1::new();
    let mut f = fs::File::open(path)?;
    let mut buf = [0u8; 16384];
    loop {
        let read = f.read(&mut buf)?;
        if read == 0 {
            break;
        }
        sha.update(&buf[..read]);
    }
    Ok(sha.hexdigest())
}

pub fn is_writable<P: AsRef<Path>>(path: P) -> bool {
    fs::OpenOptions::new().write(true).open(&path).map(|_| true).unwrap_or(false)
}

/// Set the mode of a path to 755 if we're on a Unix machine, otherwise
/// don't do anything with the given path.
pub fn set_executable_mode<P: AsRef<Path>>(path: P) -> io::Result<()> {
    #[cfg(not(windows))]
    fn exec<P: AsRef<Path>>(path: P) -> io::Result<()> {
        use std::os::unix::fs::PermissionsExt;
        let mut perm = fs::metadata(&path)?.permissions();
        perm.set_mode(0o755);
        fs::set_permissions(&path, perm)
    }

    #[cfg(windows)]
    fn exec<P: AsRef<Path>>(path: P) -> io::Result<()> {
        Ok(())
    }

    exec(path)
}

pub fn prompt_to_continue(message: &str) -> io::Result<bool> {
    loop {
        print!("{} [y/n] ", message);
        io::stdout().flush()?;

        let mut buf = String::new();
        io::stdin().read_line(&mut buf)?;
        let input = buf.trim();

        if input == "y" {
            return Ok(true);
        } else if input == "n" {
            return Ok(false);
        }
        println!("invalid input!");
    }
}

pub fn prompt(message: &str) -> io::Result<String> {
    loop {
        print!("{}: ", message);
        io::stdout().flush()?;
        let mut buf = String::new();
        io::stdin().read_line(&mut buf)?;
        let input = buf.trim();
        if input.len() > 0 {
            return Ok(input.to_owned());
        }
    }
}

pub fn to_timestamp(tm: time::SystemTime) -> f64 {
    let duration = tm.duration_since(time::UNIX_EPOCH).unwrap();
    (duration.as_secs() as f64) + (duration.subsec_nanos() as f64 / 1e09)
}
<|endoftext|>


<commit_before>use wlroots_sys::{wlr_input_device, wlr_pointer};

/// A wlr_input_device that is guaranteed to be a pointer.
pub struct PointerHandle {
    /// The device that refers to this pointer
    device: *mut wlr_input_device,
    /// The underlying pointer data
    pointer: *mut wlr_pointer
}

impl PointerHandle {
    /// Tries to convert an input device to a pointer
    ///
    /// Returns none if it is of a different input varient.
    pub unsafe fn from_input_device(device: *mut wlr_input_device) -> Option<Self> {
        use wlroots_sys::wlr_input_device_type::*;
        match (*device).type_ {
            WLR_INPUT_DEVICE_POINTER => {
                let pointer = (*device).__bindgen_anon_1.pointer;
                Some(PointerHandle { device, pointer })
            }
            _ => None,
        }
    }

    /// Gets the wlr_input_device associated with this Pointer
    pub unsafe fn input_device(&self) -> *mut wlr_input_device {
        self.device
    }

    pub unsafe fn pointer(&self) -> *mut wlr_pointer {
        self.pointer
    }
}
<commit_msg>PointerHandle::from_input_device pub to crate only<commit_after>use wlroots_sys::{wlr_input_device, wlr_pointer};

/// A wlr_input_device that is guaranteed to be a pointer.
pub struct PointerHandle {
    /// The device that refers to this pointer
    device: *mut wlr_input_device,
    /// The underlying pointer data
    pointer: *mut wlr_pointer
}

impl PointerHandle {
    /// Tries to convert an input device to a pointer
    ///
    /// Returns none if it is of a different input varient.
    pub(crate) unsafe fn from_input_device(device: *mut wlr_input_device) -> Option<Self> {
        use wlroots_sys::wlr_input_device_type::*;
        match (*device).type_ {
            WLR_INPUT_DEVICE_POINTER => {
                let pointer = (*device).__bindgen_anon_1.pointer;
                Some(PointerHandle { device, pointer })
            }
            _ => None,
        }
    }

    /// Gets the wlr_input_device associated with this Pointer
    pub unsafe fn input_device(&self) -> *mut wlr_input_device {
        self.device
    }

    pub unsafe fn pointer(&self) -> *mut wlr_pointer {
        self.pointer
    }
}
<|endoftext|>